diff --git a/docs/ZMI.rst b/docs/ZMI.rst index 8f37c2fbbc..c04152a32c 100644 --- a/docs/ZMI.rst +++ b/docs/ZMI.rst @@ -28,3 +28,30 @@ value should be one of the names listed on `available icons`_. .. _`zmi.icons` : https://github.com/zopefoundation/zmi.icons .. _`available icons` : http://htmlpreview.github.io/?https://github.com/zopefoundation/zmi.icons/blob/master/zmi/icons/resources/demo.html + +Use custom icons +++++++++++++++++ + +To use custom icons (which are not part of `zmi.icons`), you need to subscribe +to ``App.interfaces.IRenderZMIEvent`` to need your resources. + +Example from `Products.CMFCore/Products/CMFCore/zmi.py`:: + + import App.interfaces + import cmf.icons + import zope.component + + + @zope.component.adapter(App.interfaces.IRenderZMIEvent) + def load_assets(event): + """Load the CMS icons for the ZMI.""" + cmf.icons.cmf_icons.need() + +The subscriber is registered in +`Products.CMFCore/Products/CMFCore/event.zcml` like this:: + + + +You can can `need` arbitrary fanstatic resources in the event subscriber, not +only icon fonts, but also custom CSS and JavaScript. diff --git a/src/App/Management.py b/src/App/Management.py index bfdf2ef7b9..4b1417c058 100644 --- a/src/App/Management.py +++ b/src/App/Management.py @@ -18,13 +18,13 @@ from AccessControl.class_init import InitializeClass from AccessControl.Permissions import view_management_screens from App.interfaces import INavigation +from App.interfaces import RenderZMIEvent from App.special_dtml import DTMLFile from ExtensionClass import Base from six.moves.urllib.parse import quote, unquote from zExceptions import Redirect from zope.interface import implementer -import js.bootstrap -import zmi.icons +import zope.event try: from html import escape @@ -156,13 +156,11 @@ class Navigation(Base): manage_form_title._setFuncSignature( varnames=('form_title', 'help_product', 'help_topic')) - _manage_page_header = DTMLFile('dtml/manage_page_header', globals()) security.declareProtected(view_management_screens, 'manage_page_header') def manage_page_header(self, *args, **kw): """manage_page_header.""" - js.bootstrap.bootstrap.need() - zmi.icons.zmi_icons.need() + zope.event.notify(RenderZMIEvent()) return self._manage_page_header(*args, **kw) security.declarePublic('manage_zmi_logout') diff --git a/src/App/interfaces.py b/src/App/interfaces.py index 06d09ddb2e..5a0841ad04 100644 --- a/src/App/interfaces.py +++ b/src/App/interfaces.py @@ -15,6 +15,7 @@ from zope.interface import Attribute from zope.interface import Interface +from zope.interface import implementer class INavigation(Interface): @@ -30,3 +31,12 @@ def manage_zmi_logout(REQUEST, RESPONSE): """Logout current user""" INavigation.setTaggedValue('manage_page_style.css', Attribute(""" """)) + + +class IRenderZMIEvent(Interface): + """ZMI is rendered.""" + + +@implementer(IRenderZMIEvent) +class RenderZMIEvent(object): + """Event fired when the ZMI is rendered.""" diff --git a/src/Zope2/App/configure.zcml b/src/Zope2/App/configure.zcml index e99c1debfb..20a872e11e 100644 --- a/src/Zope2/App/configure.zcml +++ b/src/Zope2/App/configure.zcml @@ -17,4 +17,7 @@ + + diff --git a/src/Zope2/App/zmi.py b/src/Zope2/App/zmi.py new file mode 100644 index 0000000000..4b9b81d9fa --- /dev/null +++ b/src/Zope2/App/zmi.py @@ -0,0 +1,27 @@ +############################################################################## +# +# Copyright (c) 2018 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## + +from __future__ import absolute_import + +import App.interfaces +import js.bootstrap +import zmi.icons +import zope.component + + +@zope.component.adapter(App.interfaces.IRenderZMIEvent) +def load_assets(event): + """Load the static assets needed to render the ZMI.""" + js.bootstrap.bootstrap.need() + zmi.icons.zmi_icons.need()