diff --git a/README.rst b/README.rst index 7421b99..5c0a686 100644 --- a/README.rst +++ b/README.rst @@ -51,40 +51,21 @@ Usage To select a model from a remote API, respectively use ``RemoteModelChooserBlock`` and ``RemoteModelChooserPanel`` instead. -If you have `WagtailDraftail `_ installed, it will automatically register the ``ModelSource`` and ``RemoteModelSource`` to the JS. Refer to ``WagtailDraftail``'s `documentation `_ to hook it up properly. - -If you want your choosers to be available in draftail, put a unique 'draftail_type' into each chooser configuration, then put the DraftailJSRenderMixin into the Draftail rich text area widget class in your project. If you're on default wagtail, you can do that in settings/base.py like this: +If you want a chooser to be available in draftail, put a unique 'draftail_type' into its configuration dict in ``MODEL_CHOOSER_OPTIONS``, then add the chooser name to rich text features. You can do the latter either by adding it explicitly in a feature list like this: .. code:: python - WAGTAILADMIN_RICH_TEXT_EDITORS = { - "default": { - "WIDGET": "myproject.widgets.MyNewDraftailRichTextArea" - } - } + rich_text_block = RichTextBlock(features=["custom_model"]) -Then in myproject.widgets do this: - -.. code:: python - - from wagtailmodelchoosers.widgets import DraftailJSRenderMixin - - class MyNewDraftailRichTextArea(DraftailJSRenderMixin, DraftailRichTextArea): - pass - -Now the modelchoosers you define in ``MODEL_CHOOSER_OPTIONS`` (format described in next section) in your project settings are available as features in your rich text blocks, and you can pass them like this: - -.. code:: python - - rich_text_block = RichTextBlock(features="mymodel") - -If you want some of your models to be available in your rich text toolbar by default (so you don't have to construct feature lists), go to myproject.wagtail_hooks.py and add this for each model you want to be available: +Or adding it to the list of default features for all rich text blocks like this: .. code:: python @hooks.register("register_rich_text_features") def register_rich_text_features(features): - features.default_features.append("mymodel") + features.default_features.append("custom_model") + +Note: It's easy to confuse draftail_type with the chooser's name. See the Configuration section if you're not sure which is which. The only place you need to put the draftail_type is in settings. The value you put there gets passed into draftail as an entity type, so the blocks created by that modelchooser toolbar option have the block type equal to the draftail_type you declared. This is useful if you're doing something custom with the contentstate. Configuration ~~~~~~~~~~~~~ @@ -96,7 +77,7 @@ The ModelChooser and RemoteModelChooser share a similar base configuration and o .. code:: python MODEL_CHOOSERS_OPTIONS = { - 'navigation': { + 'navigation': { # The chooser name 'label': 'Navigation', # The label to use for buttons or modal title 'display': 'name', # The field to display when selecting an object 'list_display': [ # The fields to display in the chooser @@ -108,7 +89,7 @@ The ModelChooser and RemoteModelChooser share a similar base configuration and o 'fields_to_save': ['id'] + RATE_CHOOSER_DISPLAY_FIELDS, # ONLY FOR REMOTE: The remote objects fields to save to the DB. Leave empty to save the whole object. 'remote_endpoint': 'http://...' # ONLY FOR REMOTE: The remote API endpoint. 'pk_name': 'uuid', # The primary key name of the model - 'draftail_type': 'NAV', # Only add this if you want the model available in draftail. Must be unique. + 'draftail_type': 'NAV', # Only add this if you want the model available in draftail. Must be unique and can't clash with any default wagtail types. } } diff --git a/wagtailmodelchoosers/client/draftailmodelchoosers.js b/wagtailmodelchoosers/client/draftailmodelchoosers.js index 9680a4c..7b403ad 100644 --- a/wagtailmodelchoosers/client/draftailmodelchoosers.js +++ b/wagtailmodelchoosers/client/draftailmodelchoosers.js @@ -3,7 +3,7 @@ import DefaultDecorator from './DefaultDecorator'; const WrapDecorator = (entityData, decorator) => (...args) => decorator(entityData, ...args); -const modelChooserDraftailInit = (modelChooserEntityTypes, draftailOptions, widgetAttrIds) => { +const modelChooserDraftailInit = (draftailOptions, modelChooserEntityTypes, constructor) => { // Save entities for decorators to use. Doing this because I can't find a way to get entity type // data from within a decorator without saving it to contentstate, which ends up getting saved // to DB, which is unnecessary and breaks historical data. @@ -25,7 +25,7 @@ const modelChooserDraftailInit = (modelChooserEntityTypes, draftailOptions, widg window.draftail.registerPlugin(plugin); }); - window.draftail.initEditor(widgetAttrIds, draftailOptions, document.currentScript); + return new window.telepath.constructors[constructor](draftailOptions); }; -window.modelChooserDraftailInit = modelChooserDraftailInit; +window.telepath.register('modelChooserDraftailInit', modelChooserDraftailInit); diff --git a/wagtailmodelchoosers/templates/wagtailmodelchoosers/widgets/draftail_rich_text_area.html b/wagtailmodelchoosers/templates/wagtailmodelchoosers/widgets/draftail_rich_text_area.html deleted file mode 100644 index bbb9c4c..0000000 --- a/wagtailmodelchoosers/templates/wagtailmodelchoosers/widgets/draftail_rich_text_area.html +++ /dev/null @@ -1,4 +0,0 @@ -{% include 'django/forms/widgets/hidden.html' %} - diff --git a/wagtailmodelchoosers/wagtail_hooks.py b/wagtailmodelchoosers/wagtail_hooks.py index 17e502e..e69c298 100644 --- a/wagtailmodelchoosers/wagtail_hooks.py +++ b/wagtailmodelchoosers/wagtail_hooks.py @@ -7,6 +7,9 @@ from wagtail.admin.rich_text.converters.html_to_contentstate import InlineEntityElementHandler from wagtail.core import hooks from wagtail.core.rich_text import LinkHandler +from wagtail.core.widget_adapters import WidgetAdapter +from wagtail.core import telepath +from wagtail.admin.rich_text.editors.draftail import DraftailRichTextArea, DraftailRichTextAreaAdapter from wagtailmodelchoosers.views import ModelView, RemoteResourceView @@ -94,3 +97,25 @@ def register_rich_text_features(features): "to_database_format": {"entity_decorators": {draftail_type: _to}}, }, ) + + +class ModelChooserDraftailRichTextAreaAdapter(DraftailRichTextAreaAdapter): + js_constructor = "modelChooserDraftailInit" + + class Media: + js = ["wagtailmodelchoosers/draftailmodelchoosers.js"] + + def js_args(self, *args, **kwargs): + js_args = super().js_args(*args, **kwargs) + + # Give it all draftail types to register + f = "draftail_type" + js_args.append([c[f] for c in get_all_chooser_options().values() if f in c]) + + # Upstream's JS constructor to call with options + js_args.append(super().js_constructor) + + return js_args + + +telepath.register(ModelChooserDraftailRichTextAreaAdapter(), DraftailRichTextArea) diff --git a/wagtailmodelchoosers/widgets.py b/wagtailmodelchoosers/widgets.py index a5d3e81..1fc78d2 100644 --- a/wagtailmodelchoosers/widgets.py +++ b/wagtailmodelchoosers/widgets.py @@ -6,8 +6,6 @@ from django.forms import Media, widgets from django.template.loader import render_to_string from django.utils.functional import cached_property -from wagtail.admin.rich_text.editors.draftail import DraftailRichTextArea -from wagtail.admin.staticfiles import versioned_static from wagtail.utils.widgets import WidgetWithScript from .utils import first_non_empty, get_all_chooser_options @@ -209,20 +207,3 @@ def render_html(self, name, value, attrs): } return render_to_string(self.template_name, context) - - -class DraftailJSRenderMixin(DraftailRichTextArea): - template_name = "wagtailmodelchoosers/widgets/draftail_rich_text_area.html" - - @cached_property - def media(self): - return super().media + Media( - js=[versioned_static("wagtailmodelchoosers/draftailmodelchoosers.js")] - ) - - def get_context(self, *args, **kwargs): - context = super().get_context(*args, **kwargs) - f = "draftail_type" - met = [c[f] for c in get_all_chooser_options().values() if f in c] - context["modelchooser_entity_types"] = json.dumps(met) - return context