2
0

page_editing_interface.rst 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. Customising the editing interface
  2. =================================
  3. .. _customising_the_tabbed_interface:
  4. Customising the tabbed interface
  5. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  6. .. versionadded:: 1.0
  7. As standard, Wagtail organises panels for pages into three tabs: 'Content', 'Promote' and 'Settings'. For snippets Wagtail puts all panels into one page. Depending on the requirements of your site, you may wish to customise this for specific page types or snippets - for example, adding an additional tab for sidebar content. This can be done by specifying an ``edit_handler`` attribute on the page or snippet model. For example:
  8. .. code-block:: python
  9. from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList
  10. class BlogPage(Page):
  11. # field definitions omitted
  12. content_panels = [
  13. FieldPanel('title', classname="full title"),
  14. FieldPanel('date'),
  15. FieldPanel('body', classname="full"),
  16. ]
  17. sidebar_content_panels = [
  18. SnippetChooserPanel('advert'),
  19. InlinePanel('related_links', label="Related links"),
  20. ]
  21. edit_handler = TabbedInterface([
  22. ObjectList(content_panels, heading='Content'),
  23. ObjectList(sidebar_content_panels, heading='Sidebar content'),
  24. ObjectList(Page.promote_panels, heading='Promote'),
  25. ObjectList(Page.settings_panels, heading='Settings', classname="settings"),
  26. ])
  27. .. _rich-text:
  28. Rich Text (HTML)
  29. ~~~~~~~~~~~~~~~~
  30. Wagtail provides a general-purpose WYSIWYG editor for creating rich text content (HTML) and embedding media such as images, video, and documents. To include this in your models, use the :class:`~wagtail.wagtailcore.fields.RichTextField` function when defining a model field:
  31. .. code-block:: python
  32. from wagtail.wagtailcore.fields import RichTextField
  33. from wagtail.wagtailadmin.edit_handlers import FieldPanel
  34. class BookPage(Page):
  35. book_text = RichTextField()
  36. content_panels = Page.content_panels + [
  37. FieldPanel('body', classname="full"),
  38. ]
  39. :class:`~wagtail.wagtailcore.fields.RichTextField` inherits from Django's basic ``TextField`` field, so you can pass any field parameters into :class:`~wagtail.wagtailcore.fields.RichTextField` as if using a normal Django field. This field does not need a special panel and can be defined with ``FieldPanel``.
  40. However, template output from :class:`~wagtail.wagtailcore.fields.RichTextField` is special and need to be filtered to preserve embedded content. See :ref:`rich-text-filter`.
  41. If you're interested in extending the capabilities of the Wagtail WYSIWYG editor (``hallo.js``), See :ref:`extending_wysiwyg`.
  42. .. _extending_wysiwyg:
  43. Extending the WYSIWYG Editor (``hallo.js``)
  44. -------------------------------------------
  45. To inject JavaScript into the Wagtail page editor, see the :ref:`insert_editor_js <insert_editor_js>` hook. Once you have the hook in place and your ``hallo.js`` plugin loads into the Wagtail page editor, use the following JavaScript to register the plugin with ``hallo.js``.
  46. .. code-block:: javascript
  47. registerHalloPlugin(name, opts);
  48. ``hallo.js`` plugin names are prefixed with the ``"IKS."`` namespace, but the ``name`` you pass into ``registerHalloPlugin()`` should be without the prefix. ``opts`` is an object passed into the plugin.
  49. For information on developing custom ``hallo.js`` plugins, see the project's page: https://github.com/bergie/hallo
  50. .. _rich_text_image_formats:
  51. Image Formats in the Rich Text Editor
  52. -------------------------------------
  53. On loading, Wagtail will search for any app with the file ``image_formats.py`` and execute the contents. This provides a way to customise the formatting options shown to the editor when inserting images in the :class:`~wagtail.wagtailcore.fields.RichTextField` editor.
  54. As an example, add a "thumbnail" format:
  55. .. code-block:: python
  56. # image_formats.py
  57. from wagtail.wagtailimages.formats import Format, register_image_format
  58. register_image_format(Format('thumbnail', 'Thumbnail', 'richtext-image thumbnail', 'max-120x120'))
  59. To begin, import the ``Format`` class, ``register_image_format`` function, and optionally ``unregister_image_format`` function. To register a new ``Format``, call the ``register_image_format`` with the ``Format`` object as the argument. The ``Format`` class takes the following constructor arguments:
  60. ``name``
  61. The unique key used to identify the format. To unregister this format, call ``unregister_image_format`` with this string as the only argument.
  62. ``label``
  63. The label used in the chooser form when inserting the image into the :class:`~wagtail.wagtailcore.fields.RichTextField`.
  64. ``classnames``
  65. The string to assign to the ``class`` attribute of the generated ``<img>`` tag.
  66. .. note::
  67. Any class names you provide must have CSS rules matching them written separately, as part of the front end CSS code. Specifying a ``classnames`` value of ``left`` will only ensure that class is output in the generated markup, it won't cause the image to align itself left.
  68. ``filter_spec``
  69. The string specification to create the image rendition. For more, see the :ref:`image_tag`.
  70. To unregister, call ``unregister_image_format`` with the string of the ``name`` of the ``Format`` as the only argument.
  71. .. _custom_edit_handler_forms:
  72. Customising generated forms
  73. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  74. .. class:: wagtail.wagtailadmin.forms.WagtailAdminModelForm
  75. .. class:: wagtail.wagtailadmin.forms.WagtailAdminPageForm
  76. Wagtail automatically generates forms using the panels configured on the model.
  77. By default, this form subclasses :class:`~wagtail.wagtailadmin.forms.WagtailAdminModelForm`,
  78. or :class:`~wagtail.wagtailadmin.forms.WagtailAdminPageForm` for pages.
  79. A custom base form class can be configured by setting the :attr:`base_form_class` attribute on any model.
  80. Custom forms for snippets must subclass :class:`~wagtail.wagtailadmin.forms.WagtailAdminModelForm`,
  81. and custom forms for pages must subclass :class:`~wagtail.wagtailadmin.forms.WagtailAdminPageForm`.
  82. This can be used to add non-model fields to the form, to automatically generate field content,
  83. or to add custom validation logic for your models:
  84. .. code-block:: python
  85. from django import forms
  86. from wagtail.wagtailadmin.edit_handlers import FieldPanel
  87. from wagtail.wagtailadmin.forms import WagtailAdminPageForm
  88. from wagtail.wagtailcore.models import Page
  89. class EventPageForm(WagtailAdminPageForm):
  90. address = forms.CharField()
  91. def clean(self):
  92. cleaned_data = super(EventPageForm, self).clean()
  93. # Make sure that the event starts before it ends
  94. start_date = cleaned_data['start_date']
  95. end_date = cleaned_data['end_date']
  96. if start_date and end_date and start_date > end_date:
  97. self.add_error('end_date', 'The end date must be after the start date')
  98. return cleaned_data
  99. def save(self, commit=True):
  100. page = super(EventPageForm, self).save(commit=False)
  101. # Update the duration field from the submitted dates
  102. page.duration = (page.end_date - page.start_date).days
  103. # Fetch the location by geocoding the address
  104. page.location = geocoder.get_coordinates(self.cleaned_data['address'])
  105. if commit:
  106. page.save()
  107. return page
  108. class EventPage(Page):
  109. start_date = models.DateField()
  110. end_date = models.DateField()
  111. duration = models.IntegerField()
  112. location = models.CharField()
  113. content_panels = [
  114. FieldPanel('given_name'),
  115. FieldPanel('family_name'),
  116. FieldPanel('bio'),
  117. ]
  118. base_form_class = EventPageForm
  119. Wagtail will generate a new subclass of this form for the model,
  120. adding any fields defined in ``panels`` or ``content_panels``.
  121. Any fields already defined on the model will not be overridden by these automatically added fields,
  122. so the form field for a model field can be overridden by adding it to the custom form.