Skip to content

Commit

Permalink
Add ability to add custom CSS and JavaScript to the ZMI.
Browse files Browse the repository at this point in the history
This requires using fanstatic resources in an event subscriber.
  • Loading branch information
Michael Howitz committed Feb 6, 2018
1 parent 8552fda commit 08a4fbf
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 5 deletions.
27 changes: 27 additions & 0 deletions docs/ZMI.rst
Expand Up @@ -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::

<subscriber
handler=".zmi.load_assets" />

You can can `need` arbitrary fanstatic resources in the event subscriber, not
only icon fonts, but also custom CSS and JavaScript.
8 changes: 3 additions & 5 deletions src/App/Management.py
Expand Up @@ -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
Expand Down Expand Up @@ -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')
Expand Down
10 changes: 10 additions & 0 deletions src/App/interfaces.py
Expand Up @@ -15,6 +15,7 @@

from zope.interface import Attribute
from zope.interface import Interface
from zope.interface import implementer


class INavigation(Interface):
Expand All @@ -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."""
3 changes: 3 additions & 0 deletions src/Zope2/App/configure.zcml
Expand Up @@ -17,4 +17,7 @@
<securityPolicy
component="AccessControl.security.SecurityPolicy" />

<subscriber
handler=".zmi.load_assets" />

</configure>
27 changes: 27 additions & 0 deletions 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()

0 comments on commit 08a4fbf

Please sign in to comment.