diff --git a/docs/advanced_topics/customisation/page_editing_interface.rst b/docs/advanced_topics/customisation/page_editing_interface.rst index 1b2262950b..8ba225a48a 100644 --- a/docs/advanced_topics/customisation/page_editing_interface.rst +++ b/docs/advanced_topics/customisation/page_editing_interface.rst @@ -96,7 +96,6 @@ The process for creating new features is described in the following pages: * :doc:`../../extending/rich_text_internals` * :doc:`../../extending/extending_draftail` -* :doc:`../../extending/extending_hallo` .. _rich_text_image_formats: diff --git a/docs/extending/extending_hallo.rst b/docs/extending/extending_hallo.rst deleted file mode 100644 index 7636569830..0000000000 --- a/docs/extending/extending_hallo.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. _extending_hallo: - -Extending the Hallo Editor -========================== - -.. warning:: - **As of Wagtail 2.0, the hallo.js editor is deprecated.** We have no intentions to remove it from Wagtail as of yet, but it will no longer receive bug fixes. Please be aware of the `known hallo.js issues `_ should you want to keep using it. - - To use hallo.js on Wagtail 2.x, add the following to your settings: - - .. code-block:: python - - WAGTAILADMIN_RICH_TEXT_EDITORS = { - 'default': { - 'WIDGET': 'wagtail.admin.rich_text.HalloRichTextArea' - } - } - -The legacy hallo.js editor’s functionality can be extended through plugins. For information on developing custom ``hallo.js`` plugins, see the project's page: https://github.com/bergie/hallo - -Once the plugin has been created, it should be registered through the feature registry's ``register_editor_plugin(editor, feature_name, plugin)`` method. For a ``hallo.js`` plugin, the ``editor`` parameter should always be ``'hallo'``. - -A plugin ``halloblockquote``, implemented in ``myapp/js/hallo-blockquote.js``, that adds support for the ``
`` tag, would be registered under the feature name ``block-quote`` as follows: - -.. code-block:: python - - from wagtail.admin.rich_text import HalloPlugin - from wagtail.core import hooks - - @hooks.register('register_rich_text_features') - def register_embed_feature(features): - features.register_editor_plugin( - 'hallo', 'block-quote', - HalloPlugin( - name='halloblockquote', - js=['myapp/js/hallo-blockquote.js'], - ) - ) - -The constructor for ``HalloPlugin`` accepts the following keyword arguments: - -* ``name`` - the plugin name as defined in the JavaScript code. ``hallo.js`` plugin names are prefixed with the ``"IKS."`` namespace, but the name passed here should be without the prefix. -* ``options`` - a dictionary (or other JSON-serialisable object) of options to be passed to the JavaScript plugin code on initialisation -* ``js`` - a list of JavaScript files to be imported for this plugin, defined in the same way as a :doc:`Django form media ` definition -* ``css`` - a dictionary of CSS files to be imported for this plugin, defined in the same way as a :doc:`Django form media ` definition -* ``order`` - an index number (default 100) specifying the order in which plugins should be listed, which in turn determines the order buttons will appear in the toolbar - -When writing the front-end code for the plugin, Wagtail’s Hallo implementation offers two extension points: - -* In JavaScript, use the ``[data-hallo-editor]`` attribute selector to target the editor, eg. ``var editor = document.querySelector('[data-hallo-editor]');``. -* In CSS, use the ``.halloeditor`` class selector. - - -.. _whitelisting_rich_text_elements: - -Whitelisting rich text elements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -After extending the editor to support a new HTML element, you'll need to add it to the whitelist of permitted elements - Wagtail's standard behaviour is to strip out unrecognised elements, to prevent editors from inserting styles and scripts (either deliberately, or inadvertently through copy-and-paste) that the developer didn't account for. - -Elements can be added to the whitelist through the feature registry's ``register_converter_rule(converter, feature_name, ruleset)`` method. When the ``hallo.js`` editor is in use, the ``converter`` parameter should always be ``'editorhtml'``. - -The following code will add the ``
`` element to the whitelist whenever the ``block-quote`` feature is active: - -.. code-block:: python - - from wagtail.admin.rich_text.converters.editor_html import WhitelistRule - from wagtail.core.whitelist import allow_without_attributes - - @hooks.register('register_rich_text_features') - def register_blockquote_feature(features): - features.register_converter_rule('editorhtml', 'block-quote', [ - WhitelistRule('blockquote', allow_without_attributes), - ]) - -``WhitelistRule`` is passed the element name, and a callable which will perform some kind of manipulation of the element whenever it is encountered. This callable receives the element as a `BeautifulSoup `_ Tag object. - -The ``wagtail.core.whitelist`` module provides a few helper functions to assist in defining these handlers: ``allow_without_attributes``, a handler which preserves the element but strips out all of its attributes, and ``attribute_rule`` which accepts a dict specifying how to handle each attribute, and returns a handler function. This dict will map attribute names to either True (indicating that the attribute should be kept), False (indicating that it should be dropped), or a callable (which takes the initial attribute value and returns either a final value for the attribute, or None to drop the attribute). diff --git a/docs/extending/index.rst b/docs/extending/index.rst index fb555056ec..c39e76b4d7 100644 --- a/docs/extending/index.rst +++ b/docs/extending/index.rst @@ -18,5 +18,4 @@ This section describes the various mechanisms that can be used to integrate your customising_group_views rich_text_internals extending_draftail - extending_hallo custom_bulk_actions diff --git a/docs/extending/rich_text_internals.rst b/docs/extending/rich_text_internals.rst index 56cb949384..31ecff0b8a 100644 --- a/docs/extending/rich_text_internals.rst +++ b/docs/extending/rich_text_internals.rst @@ -199,7 +199,7 @@ This method allows you to register a custom handler deriving from ``wagtail.core Editor widgets -------------- -The editor interface used on rich text fields can be configured with the :ref:`WAGTAILADMIN_RICH_TEXT_EDITORS ` setting. Wagtail provides two editor implementations: ``wagtail.admin.rich_text.DraftailRichTextArea`` (the `Draftail `_ editor based on `Draft.js `_) and ``wagtail.admin.rich_text.HalloRichTextArea`` (deprecated, based on `Hallo.js `_). +The editor interface used on rich text fields can be configured with the :ref:`WAGTAILADMIN_RICH_TEXT_EDITORS ` setting. Wagtail provides an implementation: ``wagtail.admin.rich_text.DraftailRichTextArea`` (the `Draftail `_ editor based on `Draft.js `_). It is possible to create your own rich text editor implementation. At minimum, a rich text editor is a Django :class:`~django.forms.Widget` subclass whose constructor accepts an ``options`` keyword argument (a dictionary of editor-specific configuration options sourced from the ``OPTIONS`` field in ``WAGTAILADMIN_RICH_TEXT_EDITORS``), and which consumes and produces string data in the HTML-like format described above. @@ -207,7 +207,7 @@ Typically, a rich text widget also receives a ``features`` list, passed from eit There is a standard set of recognised feature identifiers as listed under :ref:`rich_text_features`, but this is not a definitive list; feature identifiers are only defined by convention, and it is up to each editor widget to determine which features it will recognise, and adapt its behaviour accordingly. Individual editor widgets might implement fewer or more features than the default set, either as built-in functionality or through a plugin mechanism if the editor widget has one. -For example, a third-party Wagtail extension might introduce ``table`` as a new rich text feature, and provide implementations for the Draftail and Hallo editors (which both provide a plugin mechanism). In this case, the third-party extension will not be aware of your custom editor widget, and so the widget will not know how to handle the ``table`` feature identifier. Editor widgets should silently ignore any feature identifiers that they do not recognise. +For example, a third-party Wagtail extension might introduce ``table`` as a new rich text feature, and provide implementations for the Draftail editor (which provides a plugin mechanism). In this case, the third-party extension will not be aware of your custom editor widget, and so the widget will not know how to handle the ``table`` feature identifier. Editor widgets should silently ignore any feature identifiers that they do not recognise. The ``default_features`` attribute of the feature registry is a list of feature identifiers to be used whenever an explicit feature list has not been given in ``RichTextField`` / ``RichTextBlock`` or ``WAGTAILADMIN_RICH_TEXT_EDITORS``. This list can be modified within the ``register_rich_text_features`` hook to make new features enabled by default, and retrieved by calling ``get_default_features()``. @@ -245,13 +245,13 @@ Editor plugins Rich text editors often provide a plugin mechanism to allow extending the editor with new functionality. The ``register_editor_plugin`` method provides a standardised way for ``register_rich_text_features`` hooks to define plugins to be pulled in to the editor when a given rich text feature is enabled. -``register_editor_plugin`` is passed an editor name (a string uniquely identifying the editor widget - Wagtail uses the identifiers ``draftail`` and ``hallo`` for its built-in editors), a feature identifier, and a plugin definition object. This object is specific to the editor widget and can be any arbitrary value, but will typically include a :doc:`Django form media ` definition referencing the plugin's JavaScript code - which will then be merged into the editor widget's own media definition - along with any relevant configuration options to be passed when instantiating the editor. +``register_editor_plugin`` is passed an editor name (a string uniquely identifying the editor widget - Wagtail uses the identifier ``draftail`` for the built-in editor), a feature identifier, and a plugin definition object. This object is specific to the editor widget and can be any arbitrary value, but will typically include a :doc:`Django form media ` definition referencing the plugin's JavaScript code - which will then be merged into the editor widget's own media definition - along with any relevant configuration options to be passed when instantiating the editor. .. method:: FeatureRegistry.get_editor_plugin(editor_name, feature_name) Within the editor widget, the plugin definition for a given feature can be retrieved via the ``get_editor_plugin`` method, passing the editor's own identifier string and the feature identifier. This will return ``None`` if no matching plugin has been registered. -For details of the plugin formats for Wagtail's built-in editors, see :doc:`./extending_draftail` and :doc:`./extending_hallo`. +For details of the plugin formats for Wagtail's built-in editors, see :doc:`./extending_draftail`. .. _rich_text_format_converters: @@ -259,7 +259,7 @@ For details of the plugin formats for Wagtail's built-in editors, see :doc:`./ex Format converters ----------------- -Editor widgets will often be unable to work directly with Wagtail's rich text format, and require conversion to their own native format. For Draftail, this is a JSON-based format known as ContentState (see `How Draft.js Represents Rich Text Data `_). Hallo.js and other editors based on HTML's ``contentEditable`` mechanism require valid HTML, and so Wagtail uses a convention referred to as "editor HTML", where the additional data required on link and embed elements is stored in ``data-`` attributes, for example: ``Contact us``. +Editor widgets will often be unable to work directly with Wagtail's rich text format, and require conversion to their own native format. For Draftail, this is a JSON-based format known as ContentState (see `How Draft.js Represents Rich Text Data `_). Editors based on HTML's ``contentEditable`` mechanism require valid HTML, and so Wagtail uses a convention referred to as "editor HTML", where the additional data required on link and embed elements is stored in ``data-`` attributes, for example: ``Contact us``. Wagtail provides two utility classes, ``wagtail.admin.rich_text.converters.contentstate.ContentstateConverter`` and ``wagtail.admin.rich_text.converters.editor_html.EditorHTMLConverter``, to perform conversions between rich text format and the native editor formats. These classes are independent of any editor widget, and distinct from the rewriting process that happens when rendering rich text onto a template. @@ -271,7 +271,7 @@ As with editor plugins, the behaviour of a converter class can vary according to ``register_editor_plugin`` is passed a converter name (a string uniquely identifying the converter class - Wagtail uses the identifiers ``contentstate`` and ``editorhtml``), a feature identifier, and a rule definition object. This object is specific to the converter and can be any arbitrary value. -For details of the rule definition format for the ``contentstate`` and ``editorhtml`` converters, see :doc:`./extending_draftail` and :doc:`./extending_hallo` respectively. +For details of the rule definition format for the ``contentstate`` converter, see :doc:`./extending_draftail`. .. method:: FeatureRegistry.get_converter_rule(converter_name, feature_name) diff --git a/docs/reference/settings.rst b/docs/reference/settings.rst index 849c01224c..63383822b2 100644 --- a/docs/reference/settings.rst +++ b/docs/reference/settings.rst @@ -820,16 +820,16 @@ Rich text 'features': ['h2', 'bold', 'italic', 'link', 'document-link'] } }, - 'legacy': { - 'WIDGET': 'wagtail.admin.rich_text.HalloRichTextArea', + 'secondary': { + 'WIDGET': 'some.external.RichTextEditor', } } -Customise the behaviour of rich text fields. By default, ``RichTextField`` and ``RichTextBlock`` use the configuration given under the ``'default'`` key, but this can be overridden on a per-field basis through the ``editor`` keyword argument, e.g. ``body = RichTextField(editor='legacy')``. Within each configuration block, the following fields are recognised: +Customise the behaviour of rich text fields. By default, ``RichTextField`` and ``RichTextBlock`` use the configuration given under the ``'default'`` key, but this can be overridden on a per-field basis through the ``editor`` keyword argument, e.g. ``body = RichTextField(editor='secondary')``. Within each configuration block, the following fields are recognised: - * ``WIDGET``: The rich text widget implementation to use. Wagtail provides two implementations: ``wagtail.admin.rich_text.DraftailRichTextArea`` (a modern extensible editor which enforces well-structured markup) and ``wagtail.admin.rich_text.HalloRichTextArea`` (deprecated; works directly at the HTML level). Other widgets may be provided by third-party packages. + * ``WIDGET``: The rich text widget implementation to use. Wagtail provides ``wagtail.admin.rich_text.DraftailRichTextArea`` (a modern extensible editor which enforces well-structured markup). Other widgets may be provided by third-party packages. - * ``OPTIONS``: Configuration options to pass to the widget. Recognised options are widget-specific, but both ``DraftailRichTextArea`` and ``HalloRichTextArea`` accept a ``features`` list indicating the active rich text features (see :ref:`rich_text_features`). + * ``OPTIONS``: Configuration options to pass to the widget. Recognised options are widget-specific, but ``DraftailRichTextArea`` accept a ``features`` list indicating the active rich text features (see :ref:`rich_text_features`). If a ``'default'`` editor is not specified, rich text fields that do not specify an ``editor`` argument will use the Draftail editor with the default feature set enabled.