Wagtail:如何定义自定义块的 js_initializer,以便子块的 js_initializer 也可以 运行?
Wagtail: How does one define a custom Block's js_initializer so that subblocks' js_initializers also run?
我最初是在 wagtail 问题队列上问这个问题的,我猜这是错误的地方。 (尽管我确实认为这是 documentation 中的错误。)
无论如何,我的问题是我有一个自定义 StructBlock
class,其中使用了 ListBlock
。我需要在我的自定义 class 上定义一个 js_initializer()
方法,它会导致表单触发我自己的初始化程序 和 ListBlock
的初始化程序。
我最初的尝试,基于 docs,看起来像这样:
# my_blocks.py
class ImageGalleryBlock(blocks.StructBlock):
images = ListBlock(ImageChooserBlock(label='Image'))
def js_initializer(self):
return "ImageGallery"
@property
def media(self):
return forms.Media(
js=['app/js/admin/image-gallery.js']
)
# image-gallery.js
function ImageGallery(prefix) {
// Set up the Image Gallery block's custom form behavior...
}
这使 ImageGallery()
函数成为 运行,但没有 运行 ListBlock
的初始化程序,因此 none 的按钮起作用了。
在 wagtail 问题队列中,有人建议我尝试这样的操作:
def js_initializer(self):
initializer_js = super(HeadingBlock, self).js_initializer()
my_custom_js = 'ImageGallery("%s")' % self.definition_prefix
if initializer_js:
# child blocks have custom JS initializers and need to be used
return '%s,\n%s' % (initializer_js, my_custom_js)
return my_custom_js
# image-gallery.js
function ImageGallery(prefix) {
var init_image_gallery = function(element_prefix) {
// Do stuff...
};
return init_image_gallery;
}
我不得不对最初的建议进行一些改进以使 ImageGallery()
部分起作用,但它仍然没有 运行 ListBlock
初始化程序。
下面是为 ImageGalleryBlock
生成的初始化代码:
{
'name': ('ImageGalleryBlock'),
'initializer': (StructBlock({
'images': (ListBlock({
'definitionPrefix': ('blockdef-63')
}))
}),
ImageGallery("blockdef-91"))
},
我觉得我真正需要做的是向传递给 StructBlock
的字典添加另一个键,但我不知道如何做。
一个js_initializer
方法returns一个Javascript表达式,在页面加载时计算一次,并吐出一个函数;每次将块插入表单时都会调用此初始化函数,传递 ID 前缀以标识应接收 Javascript 行为的 HTML 元素。重要的是要理解这是一个两步过程 - 页面加载的初始评估(通常采用函数调用的形式 returns 第二步中要使用的函数),以及调用初始化函数对于表单上的每个块。
每当一个块充当其他块的包装器时,就像 StructBlock 所做的那样,它负责确保对其子块执行此合同:当它自己的 js_initializer
在页面加载时被评估时,子块js_initializer
s 也需要在那个时候被评估,当它的初始化函数被调用时,它会调用那些子初始化函数。
通过子类化 StructBlock 并覆盖 js_initializer
,您实际上是在 StructBlock 周围添加了另一层包装:您的新 js_initializer
需要评估为一个函数,该函数既调用 StructBlock 的初始化函数,又执行您的自定义图片库设置。方法如下:
图片-gallery.js:
/* ImageGallery gets called once on startup; the function it returns will
be called whenever we need to set up an image gallery block on the form */
function ImageGallery(parentInitializer) {
return function(elementPrefix) {
/* call the original StructBlock initializer */
parentInitializer(elementPrefix);
/* do whatever JS setup you need for the image gallery behaviour */
$('#' + elementPrefix + '-gallery').doStuff();
};
}
my_blocks.py:
class ImageGalleryBlock(blocks.StructBlock):
images = ListBlock(ImageChooserBlock(label='Image'))
def js_initializer(self):
parent_initializer = super(ImageGalleryBlock, self).js_initializer()
return "ImageGallery(%s)" % parent_initializer
@property
def media(self):
# need to pull in StructBlock's own js code as well as our own
return super(ImageGalleryBlock, self).media + forms.Media(
js=['app/js/admin/image-gallery.js']
)
我最初是在 wagtail 问题队列上问这个问题的,我猜这是错误的地方。 (尽管我确实认为这是 documentation 中的错误。)
无论如何,我的问题是我有一个自定义 StructBlock
class,其中使用了 ListBlock
。我需要在我的自定义 class 上定义一个 js_initializer()
方法,它会导致表单触发我自己的初始化程序 和 ListBlock
的初始化程序。
我最初的尝试,基于 docs,看起来像这样:
# my_blocks.py
class ImageGalleryBlock(blocks.StructBlock):
images = ListBlock(ImageChooserBlock(label='Image'))
def js_initializer(self):
return "ImageGallery"
@property
def media(self):
return forms.Media(
js=['app/js/admin/image-gallery.js']
)
# image-gallery.js
function ImageGallery(prefix) {
// Set up the Image Gallery block's custom form behavior...
}
这使 ImageGallery()
函数成为 运行,但没有 运行 ListBlock
的初始化程序,因此 none 的按钮起作用了。
在 wagtail 问题队列中,有人建议我尝试这样的操作:
def js_initializer(self):
initializer_js = super(HeadingBlock, self).js_initializer()
my_custom_js = 'ImageGallery("%s")' % self.definition_prefix
if initializer_js:
# child blocks have custom JS initializers and need to be used
return '%s,\n%s' % (initializer_js, my_custom_js)
return my_custom_js
# image-gallery.js
function ImageGallery(prefix) {
var init_image_gallery = function(element_prefix) {
// Do stuff...
};
return init_image_gallery;
}
我不得不对最初的建议进行一些改进以使 ImageGallery()
部分起作用,但它仍然没有 运行 ListBlock
初始化程序。
下面是为 ImageGalleryBlock
生成的初始化代码:
{
'name': ('ImageGalleryBlock'),
'initializer': (StructBlock({
'images': (ListBlock({
'definitionPrefix': ('blockdef-63')
}))
}),
ImageGallery("blockdef-91"))
},
我觉得我真正需要做的是向传递给 StructBlock
的字典添加另一个键,但我不知道如何做。
一个js_initializer
方法returns一个Javascript表达式,在页面加载时计算一次,并吐出一个函数;每次将块插入表单时都会调用此初始化函数,传递 ID 前缀以标识应接收 Javascript 行为的 HTML 元素。重要的是要理解这是一个两步过程 - 页面加载的初始评估(通常采用函数调用的形式 returns 第二步中要使用的函数),以及调用初始化函数对于表单上的每个块。
每当一个块充当其他块的包装器时,就像 StructBlock 所做的那样,它负责确保对其子块执行此合同:当它自己的 js_initializer
在页面加载时被评估时,子块js_initializer
s 也需要在那个时候被评估,当它的初始化函数被调用时,它会调用那些子初始化函数。
通过子类化 StructBlock 并覆盖 js_initializer
,您实际上是在 StructBlock 周围添加了另一层包装:您的新 js_initializer
需要评估为一个函数,该函数既调用 StructBlock 的初始化函数,又执行您的自定义图片库设置。方法如下:
图片-gallery.js:
/* ImageGallery gets called once on startup; the function it returns will
be called whenever we need to set up an image gallery block on the form */
function ImageGallery(parentInitializer) {
return function(elementPrefix) {
/* call the original StructBlock initializer */
parentInitializer(elementPrefix);
/* do whatever JS setup you need for the image gallery behaviour */
$('#' + elementPrefix + '-gallery').doStuff();
};
}
my_blocks.py:
class ImageGalleryBlock(blocks.StructBlock):
images = ListBlock(ImageChooserBlock(label='Image'))
def js_initializer(self):
parent_initializer = super(ImageGalleryBlock, self).js_initializer()
return "ImageGallery(%s)" % parent_initializer
@property
def media(self):
# need to pull in StructBlock's own js code as well as our own
return super(ImageGalleryBlock, self).media + forms.Media(
js=['app/js/admin/image-gallery.js']
)