Wagtail - 如何让标签与“telepath”(streamfield 中的标签)一起使用?

Wagtail - how to get tags to work with `telepath` (tags in streamfield)?

我可以在常规页面字段中使用标签,没有任何问题。当在块内(在流场内)使用标签时,UI 起作用并且标签被保存但是在管理中加载页面时当前页面标签不显示。 那是因为当前值不再在模板中,它在通过 telepath 加载的 JSON 中。

我可以确认标签已保存并存在于页面源中传递给 initBlockWidget 的数据中,但这些标签被忽略了。此外,如果我使用常规文本字段而不是标签小部件,我可以在管理员中看到保存的值。

这是我的代码(在 telepath 重构之前已经足够了)。

from wagtail.admin.widgets import AdminTagWidget

class TagBlock(TextBlock):
    @cached_property
    def field(self):
        field_kwargs = {"widget": AdminTagWidget()}
        field_kwargs.update(self.field_options)
        return forms.CharField(**field_kwargs)

我认为以下 link 是我需要以某种方式完成才能使其正常工作的内容:https://docs.wagtail.io/en/stable/reference/streamfield/widget_api.html#form-widget-client-side-api

我试过这个:

class AdminTagWidgetAdapter(WidgetAdapter):
    class Media:
        js = [
            "wagtailadmin/js/vendor/tag-it.js",
            "js/admin/admin-tag-widget-adapter.js",
        ]


register(AdminTagWidgetAdapter(), AdminTagWidget)

js/admin/admin-tag-widget-adapter.js下:

console.log("adapter"); // this shows up in the console


class BoundWidget { // copied from wagtail source code
    
    constructor(element, name, idForLabel, initialState) {
        var selector = ':input[name="' + name + '"]';
        this.input = element.find(selector).addBack(selector);  // find, including element itself
        this.idForLabel = idForLabel;
        this.setState(initialState);
    }
    getValue() {
        return this.input.val();
    }
    getState() {
        return this.input.val();
    }
    setState(state) {
        this.input.val(state);
    }
    getTextLabel(opts) {
        const val = this.getValue();
        if (typeof val !== 'string') return null;
        const maxLength = opts && opts.maxLength;
        if (maxLength && val.length > maxLength) {
            return val.substring(0, maxLength - 1) + '…';
        }
        return val;
    }
    focus() {
        this.input.focus();
    }
}

// my code here:

class AdminTagWidget {
    constructor(html, idPattern) {
        this.html = html;
        this.idPattern = idPattern;
    }

    boundWidgetClass = BoundWidget;

    render(placeholder, name, id, initialState) {
        console.log("RENDER", placeholder, name, id, initialState); // this does not show

        var html = this.html.replace(/__NAME__/g, name).replace(/__ID__/g, id);
        var idForLabel = this.idPattern.replace(/__ID__/g, id);
        var dom = $(html);
        $(placeholder).replaceWith(dom);
        // eslint-disable-next-line new-cap
        return new this.boundWidgetClass(dom, name, idForLabel, initialState);
    }
}
console.log("here") // does show in the console

// variants I've tried:
//window.telepath.register('wagtail.admin.widgets.tags.AdminTagWidget', AdminTagWidget);
//window.telepath.register('wagtail.widgets.AdminTagWidget', AdminTagWidget);
window.telepath.register('path.where.its.used.AdminTagWidget', AdminTagWidget)

我的自定义渲染方法的日志没有显示。似乎我没有在 window.telepath.register 中调用正确的路径,但我不知道字符串应该是什么...

我什至不确定这是否是正确的前进方向。


备注:

您的 WidgetAdapter class 需要一个 js_constructor 属性:

class AdminTagWidgetAdapter(WidgetAdapter):
    js_constructor = 'myapp.widgets.AdminTagWidget'

    class Media:
        js = [
            "wagtailadmin/js/vendor/tag-it.js",
            "js/admin/admin-tag-widget-adapter.js",
        ]

任何字符串值都可以在这里使用 - 它只需要唯一标识 class,因此建议使用点状模块式路径以避免与其他路径冲突。这然后匹配您传递给 Javascript 侧的 window.telepath.register 的字符串:

window.telepath.register('myapp.widgets.AdminTagWidget', AdminTagWidget)