Skip to content

Instantly share code, notes, and snippets.

@dopry
Created November 11, 2022 04:32
Show Gist options
  • Save dopry/8811ad9443b1cecafec019d0ae2af4dd to your computer and use it in GitHub Desktop.
Save dopry/8811ad9443b1cecafec019d0ae2af4dd to your computer and use it in GitHub Desktop.
Wagtail Tags Block
// static/js/admin/admin-tag-blocks-widget-adapter.js
// inspired by:
// see: https://stackoverflow.com/questions/70359932/wagtail-how-to-get-tags-to-work-with-telepath-tags-in-streamfield
// copied and adapted from
// see: https://github.com/wagtail/wagtail/blob/v4.0.1/client/src/entrypoints/admin/telepath/widgets.js
class BoundTagItWidget {
constructor(element, name, idForLabel, initialState, parentCapabilities) {
var selector = ':input[name="' + name + '"]';
this.input = element.find(selector).addBack(selector); // find, including element itself
this.idForLabel = idForLabel;
this.setState(initialState);
this.parentCapabilities = parentCapabilities || new Map();
}
getValue() {
return this.input.val();
}
getState() {
return this.input.val();
}
setState(state) {
// see: https://github.com/aehlke/tag-it
// need to add the tags using the tagit method
state.split(",").forEach((tag) => {
$(this.input).tagit("createTag", tag);
});
}
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();
}
setCapabilityOptions(capability, options) {
Object.assign(this.parentCapabilities.get(capability), options);
}
}
class AdminTagsBlockWidget {
constructor(html, idPattern) {
this.html = html;
this.idPattern = idPattern;
}
boundWidgetClass = BoundTagItWidget;
render(placeholder, name, id, initialState, parentCapabilities) {
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,
parentCapabilities
);
}
}
window.telepath.register(
"TagsBlock.widgets.TagsBlockAdminWidget",
AdminTagsBlockWidget
);
from django import forms
from wagtail.blocks import FieldBlock
from .widgets import TagsBlockAdminWidget
class TagsBlock(FieldBlock):
"""
Basic Stream Block that will use the Wagtail tags system.
Stores the tags as simple strings only.
"""
def __init__(self, required=False, help_text=None, **kwargs):
# TODO: add configuration options
# note - required=False is critical if you are adding this block to an existing streamfield (or you can set up your manual migrations to avoid this need)
self.field = forms.CharField(widget=TagsBlockAdminWidget, required=False)
super().__init__(**kwargs)
from wagtail.admin.widgets import AdminTagWidget
from wagtail.telepath import register
from wagtail.widget_adapters import WidgetAdapter
class TagsBlockAdminWidget(AdminTagWidget):
pass
class AdminTagsBlockWidgetAdapter(WidgetAdapter):
js_constructor = "typenetwork.widgets.TagsBlockAdminWidget"
class Media:
js = [
"wagtailadmin/js/vendor/tag-it.js",
"js/admin/admin-tag-blocks-widget-adapter.js",
]
register(AdminTagsBlockWidgetAdapter(), TagsBlockAdminWidget)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment