[Checkins] SVN: zope.browsermenu/trunk/ Initial import.
Dan Korostelev
nadako at gmail.com
Mon Aug 24 10:27:27 EDT 2009
Log message for revision 103151:
Initial import.
Changed:
_U zope.browsermenu/trunk/
A zope.browsermenu/trunk/CHANGES.txt
A zope.browsermenu/trunk/README.txt
A zope.browsermenu/trunk/bootstrap.py
A zope.browsermenu/trunk/buildout.cfg
A zope.browsermenu/trunk/setup.py
A zope.browsermenu/trunk/src/
A zope.browsermenu/trunk/src/zope/
A zope.browsermenu/trunk/src/zope/__init__.py
A zope.browsermenu/trunk/src/zope/browsermenu/
A zope.browsermenu/trunk/src/zope/browsermenu/__init__.py
A zope.browsermenu/trunk/src/zope/browsermenu/configure.zcml
A zope.browsermenu/trunk/src/zope/browsermenu/fields.py
A zope.browsermenu/trunk/src/zope/browsermenu/interfaces.py
A zope.browsermenu/trunk/src/zope/browsermenu/menu.py
A zope.browsermenu/trunk/src/zope/browsermenu/menu.txt
A zope.browsermenu/trunk/src/zope/browsermenu/meta.zcml
A zope.browsermenu/trunk/src/zope/browsermenu/metaconfigure.py
A zope.browsermenu/trunk/src/zope/browsermenu/metadirectives.py
A zope.browsermenu/trunk/src/zope/browsermenu/tests/
A zope.browsermenu/trunk/src/zope/browsermenu/tests/__init__.py
A zope.browsermenu/trunk/src/zope/browsermenu/tests/addmenuitems.zcml
A zope.browsermenu/trunk/src/zope/browsermenu/tests/menus-permissions.zcml
A zope.browsermenu/trunk/src/zope/browsermenu/tests/menus.zcml
A zope.browsermenu/trunk/src/zope/browsermenu/tests/test_addMenuItem.py
A zope.browsermenu/trunk/src/zope/browsermenu/tests/test_directives.py
A zope.browsermenu/trunk/src/zope/browsermenu/tests/test_fields.py
A zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menu.py
A zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menudirectives.py
-=-
Property changes on: zope.browsermenu/trunk
___________________________________________________________________
Added: svn:ignore
+ bin
coverage
develop-eggs
parts
.installed.cfg
Added: zope.browsermenu/trunk/CHANGES.txt
===================================================================
--- zope.browsermenu/trunk/CHANGES.txt (rev 0)
+++ zope.browsermenu/trunk/CHANGES.txt 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,8 @@
+=======
+CHANGES
+=======
+
+3.9.0 (unreleased)
+==================
+
+Initial release. This package was splitted off zope.app.publisher.
Property changes on: zope.browsermenu/trunk/CHANGES.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/README.txt
===================================================================
--- zope.browsermenu/trunk/README.txt (rev 0)
+++ zope.browsermenu/trunk/README.txt 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,10 @@
+========
+Overview
+========
+
+*This package is at present not reusable without depending on a large
+chunk of the Zope Toolkit and its assumptions. It is maintained by the*
+`Zope Toolkit project <http://docs.zope.org/zopetoolkit/>`_.
+
+This package provides an implementation of browser menus and ZCML directives
+for configuring them.
Property changes on: zope.browsermenu/trunk/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/bootstrap.py
===================================================================
--- zope.browsermenu/trunk/bootstrap.py (rev 0)
+++ zope.browsermenu/trunk/bootstrap.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation 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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 73800 2007-03-27 16:16:42Z dobe $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Property changes on: zope.browsermenu/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/buildout.cfg
===================================================================
--- zope.browsermenu/trunk/buildout.cfg (rev 0)
+++ zope.browsermenu/trunk/buildout.cfg 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,22 @@
+[buildout]
+develop = .
+parts = test coverage-test coverage-report pydev
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zope.browsermenu [test]
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = zope.browsermenu [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')
+
+[pydev]
+recipe = pb.recipes.pydev
+eggs = zope.browsermenu
Added: zope.browsermenu/trunk/setup.py
===================================================================
--- zope.browsermenu/trunk/setup.py (rev 0)
+++ zope.browsermenu/trunk/setup.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,60 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation 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.
+#
+##############################################################################
+"""zope.app.publisher setup
+"""
+from setuptools import setup, find_packages, Extension
+
+long_description = (open('README.txt').read() + '\n\n' +
+ open('CHANGES.txt').read())
+
+setup(name='zope.browsermenu',
+ version = '3.9.0dev',
+ url='http://pypi.python.org/pypi/zope.browsermenu/',
+ author='Zope Corporation and Contributors',
+ author_email='zope-dev at zope.org',
+ classifiers = ['Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Framework :: Zope3',
+ ],
+ description='Implementations and means for configuration of Zope 3-'
+ 'style views and resources.',
+ long_description=long_description,
+
+ packages=find_packages('src'),
+ package_dir={'': 'src'},
+
+ namespace_packages=['zope'],
+ include_package_data=True,
+ install_requires=['setuptools',
+ 'zope.component>=3.7.0',
+ 'zope.configuration',
+ 'zope.i18nmessageid',
+ 'zope.interface',
+ 'zope.pagetemplate>=3.5.0',
+ 'zope.publisher>=3.8.0',
+ 'zope.schema',
+ 'zope.security[untrustedpython]',
+ 'zope.traversing>3.7.0',
+ 'zope.browser',
+ ],
+ extras_require={
+ 'test': ['zope.testing'],
+ },
+
+ zip_safe = False,
+ )
Property changes on: zope.browsermenu/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/__init__.py
===================================================================
--- zope.browsermenu/trunk/src/zope/__init__.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/__init__.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+ import pkg_resources
+ pkg_resources.declare_namespace(__name__)
+except ImportError:
+ import pkgutil
+ __path__ = pkgutil.extend_path(__path__, __name__)
Property changes on: zope.browsermenu/trunk/src/zope/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/configure.zcml
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/configure.zcml (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/configure.zcml 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,14 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <interface interface=".interfaces.IMenuItemType" />
+
+ <view
+ for="*"
+ type="zope.publisher.interfaces.browser.IDefaultBrowserLayer"
+ name="view_get_menu"
+ factory=".menu.MenuAccessView"
+ allowed_interface=".interfaces.IMenuAccessView"
+ permission="zope.Public"
+ />
+
+</configure>
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/configure.zcml
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/src/zope/browsermenu/fields.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/fields.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/fields.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,109 @@
+#############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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.
+#
+##############################################################################
+"""Browser-Presentation related Fields.
+
+$Id: fields.py 100240 2009-05-22 16:33:41Z faassen $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.component import queryUtility
+from zope.component.interfaces import ComponentLookupError
+from zope.configuration.exceptions import ConfigurationError
+from zope.configuration.fields import GlobalObject
+from zope.schema import ValidationError
+
+from zope.browsermenu.interfaces import IMenuItemType
+
+
+class MenuField(GlobalObject):
+ r"""This fields represents a menu (item type).
+
+ Besides being able to look up the menu by importing it, we also try
+ to look up the name in the site manager.
+
+ >>> from zope.interface import directlyProvides
+ >>> from zope.interface.interface import InterfaceClass
+
+ >>> menu1 = InterfaceClass('menu1', (),
+ ... __doc__='Menu Item Type: menu1',
+ ... __module__='zope.app.menus')
+ >>> directlyProvides(menu1, IMenuItemType)
+
+ >>> menus = None
+ >>> class Resolver(object):
+ ... def resolve(self, path):
+ ... if path.startswith('zope.app.menus') and \
+ ... hasattr(menus, 'menu1') or \
+ ... path == 'zope.browsermenu.menus.menu1':
+ ... return menu1
+ ... raise ConfigurationError('menu1')
+
+ >>> field = MenuField()
+ >>> field = field.bind(Resolver())
+
+ Test 1: Import the menu
+ -----------------------
+
+ >>> field.fromUnicode('zope.browsermenu.menus.menu1') is menu1
+ True
+
+ Test 2: We have a shortcut name. Import the menu from `zope.app.menus1`.
+ ------------------------------------------------------------------------
+
+ >>> from types import ModuleType as module
+ >>> import sys
+ >>> menus = module('menus')
+ >>> old = sys.modules.get('zope.app.menus', None)
+ >>> sys.modules['zope.app.menus'] = menus
+ >>> setattr(menus, 'menu1', menu1)
+
+ >>> field.fromUnicode('menu1') is menu1
+ True
+
+ >>> if old is not None:
+ ... sys.modules['zope.app.menus'] = old
+
+ Test 3: Get the menu from the Site Manager
+ ------------------------------------------
+
+ >>> from zope.component import provideUtility
+ >>> provideUtility(menu1, IMenuItemType, 'menu1')
+
+ >>> field.fromUnicode('menu1') is menu1
+ True
+ """
+
+ def fromUnicode(self, u):
+ name = str(u.strip())
+
+ try:
+ value = queryUtility(IMenuItemType, name)
+ except ComponentLookupError:
+ # The component architecture is not up and running.
+ pass
+ else:
+ if value is not None:
+ self.validate(value)
+ return value
+
+ try:
+ value = self.context.resolve('zope.app.menus.'+name)
+ except ConfigurationError, v:
+ try:
+ value = self.context.resolve(name)
+ except ConfigurationError, v:
+ raise ValidationError(v)
+
+ self.validate(value)
+ return value
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/fields.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/interfaces.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/interfaces.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/interfaces.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,161 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation 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.
+#
+##############################################################################
+"""Browser-Specific Publisher interfaces
+
+$Id: browser.py 97455 2009-03-03 19:57:53Z nadako $
+"""
+from zope.i18nmessageid import ZopeMessageFactory as _
+from zope.interface import Interface, directlyProvides
+from zope.interface.interfaces import IInterface
+from zope.schema import TextLine, Text, URI, Int
+
+
+class IMenuItemType(IInterface):
+ """Menu item type
+
+ Menu item types are interfaces that define classes of
+ menu items.
+ """
+
+class AddMenu(Interface):
+ """Special menu for providing a list of addable objects."""
+
+directlyProvides(AddMenu, IMenuItemType)
+
+
+class IBrowserMenu(Interface):
+ """Menu
+
+ Menus are objects that can return a list of menu items they contain. How
+ they generate this list is up to them. Commonly, however, they will look
+ up adapters that provide the ``IBrowserMenuItem`` interface.
+ """
+
+ id = TextLine(
+ title=_("Menu Id"),
+ description=_("The id uniquely identifies this menu."),
+ required=True
+ )
+
+ title = TextLine(
+ title=_("Menu title"),
+ description=_("The title provides the basic label for the menu."),
+ required=False
+ )
+
+ description = Text(
+ title=_("Menu description"),
+ description=_("A description of the menu. This might be shown "
+ "on menu pages or in pop-up help for menus."),
+ required=False
+ )
+
+ def getMenuItems(object, request):
+ """Return a TAL-friendly list of menu items.
+
+ The object (acts like the context) and request can be used to select
+ the items that are available.
+ """
+
+
+class IBrowserMenuItem(Interface):
+ """Menu type
+
+ An interface that defines a menu.
+ """
+
+ title = TextLine(
+ title=_("Menu item title"),
+ description=_("The title provides the basic label for the menu item."),
+ required=True
+ )
+
+ description = Text(
+ title=_("Menu item description"),
+ description=_("A description of the menu item. This might be shown "
+ "on menu pages or in pop-up help for menu items."),
+ required=False
+ )
+
+ action = TextLine(
+ title=_("The URL to display if the item is selected"),
+ description=_("When a user selects a browser menu item, the URL"
+ "given in the action is displayed. The action is "
+ "usually given as a relative URL, relative to the "
+ "object the menu item is for."),
+ required=True
+ )
+
+ order = Int(
+ title=_("Menu item ordering hint"),
+ description=_("This attribute provides a hint for menu item ordering."
+ "Menu items will generally be sorted by the `for_`"
+ "attribute and then by the order.")
+ )
+
+ filter_string = TextLine(
+ title=_("A condition for displaying the menu item"),
+ description=_("The condition is given as a TALES expression. The "
+ "expression has access to the variables:\n"
+ "\n"
+ "context -- The object the menu is being displayed "
+ "for\n"
+ "\n"
+ "request -- The browser request\n"
+ "\n"
+ "nothing -- None\n"
+ "\n"
+ "The menu item will not be displayed if there is a \n"
+ "filter and the filter evaluates to a false value."),
+ required=False)
+
+ icon = URI(
+ title=_("Icon URI"),
+ description=_("URI of the icon representing this menu item"))
+
+ def available():
+ """Test whether the menu item should be displayed
+
+ A menu item might not be available for an object, for example
+ due to security limitations or constraints.
+ """
+
+class IBrowserSubMenuItem(IBrowserMenuItem):
+ """A menu item that points to a sub-menu."""
+
+ submenuId = TextLine(
+ title=_("Sub-Menu Id"),
+ description=_("The menu id of the menu that describes the "
+ "sub-menu below this item."),
+ required=True)
+
+ action = TextLine(
+ title=_("The URL to display if the item is selected"),
+ description=_("When a user selects a browser menu item, the URL "
+ "given in the action is displayed. The action is "
+ "usually given as a relative URL, relative to the "
+ "object the menu item is for."),
+ required=False
+ )
+
+
+class IMenuAccessView(Interface):
+ """View that provides access to menus"""
+
+ def __getitem__(menu_id):
+ """Get menu information
+
+ Return a sequence of dictionaries with labels and
+ actions, where actions are relative URLs.
+ """
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/interfaces.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/menu.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/menu.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/menu.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,199 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Menu Registration code.
+
+$Id: menu.py 100372 2009-05-25 19:31:23Z tseaver $
+"""
+__docformat__ = "reStructuredText"
+import sys
+
+from zope.component import getAdapters, getUtility
+from zope.interface import Interface, implements, providedBy
+from zope.interface.interfaces import IInterface
+from zope.pagetemplate.engine import Engine
+from zope.publisher.browser import BrowserView
+from zope.security import canAccess, checkPermission
+from zope.security.interfaces import Forbidden, Unauthorized
+from zope.security.proxy import removeSecurityProxy
+from zope.traversing.publicationtraverse import PublicationTraverser
+
+from zope.browsermenu.interfaces import IBrowserMenu, IMenuItemType
+from zope.browsermenu.interfaces import IBrowserMenuItem, IBrowserSubMenuItem
+from zope.browsermenu.interfaces import IMenuAccessView
+
+class BrowserMenu(object):
+ """Browser Menu"""
+ implements(IBrowserMenu)
+
+ def __init__(self, id, title=u'', description=u''):
+ self.id = id
+ self.title = title
+ self.description = description
+
+ def getMenuItemType(self):
+ return getUtility(IMenuItemType, self.id)
+
+ def getMenuItems(self, object, request):
+ """Return menu item entries in a TAL-friendly form."""
+
+ result = []
+ for name, item in getAdapters((object, request),
+ self.getMenuItemType()):
+ if item.available():
+ result.append(item)
+
+ # Now order the result. This is not as easy as it seems.
+ #
+ # (1) Look at the interfaces and put the more specific menu entries
+ # to the front.
+ # (2) Sort unambigious entries by order and then by title.
+ ifaces = list(providedBy(removeSecurityProxy(object)).__iro__)
+ max_key = len(ifaces)
+ def iface_index(item):
+ iface = item._for
+ if not iface:
+ iface = Interface
+ if IInterface.providedBy(iface):
+ return ifaces.index(iface)
+ if isinstance(removeSecurityProxy(object), item._for):
+ # directly specified for class, this goes first.
+ return -1
+ # no idea. This goes last.
+ return max_key
+ result = [(iface_index(item), item.order, item.title, item)
+ for item in result]
+ result.sort()
+
+ result = [
+ {'title': title,
+ 'description': item.description,
+ 'action': item.action,
+ 'selected': (item.selected() and u'selected') or u'',
+ 'icon': item.icon,
+ 'extra': item.extra,
+ 'submenu': (IBrowserSubMenuItem.providedBy(item) and
+ getMenu(item.submenuId, object, request)) or None}
+ for index, order, title, item in result]
+
+ return result
+
+
+class BrowserMenuItem(BrowserView):
+ """Browser Menu Item Class"""
+ implements(IBrowserMenuItem)
+
+ title = u''
+ description = u''
+ action = u''
+ extra = None
+ order = 0
+ permission = None
+ filter = None
+ icon = None
+ _for = Interface
+
+ def available(self):
+ # Make sure we have the permission needed to access the menu's action
+ if self.permission is not None:
+ # If we have an explicit permission, check that we
+ # can access it.
+ if not checkPermission(self.permission, self.context):
+ return False
+
+ elif self.action != u'':
+ # Otherwise, test access by attempting access
+ path = self.action
+ l = self.action.find('?')
+ if l >= 0:
+ path = self.action[:l]
+
+ traverser = PublicationTraverser()
+ try:
+ view = traverser.traverseRelativeURL(
+ self.request, self.context, path)
+ except (Unauthorized, Forbidden, LookupError):
+ return False
+ else:
+ # we're assuming that view pages are callable
+ # this is a pretty sound assumption
+ if not canAccess(view, '__call__'):
+ return False
+
+ # Make sure that we really want to see this menu item
+ if self.filter is not None:
+
+ try:
+ include = self.filter(Engine.getContext(
+ context = self.context,
+ nothing = None,
+ request = self.request,
+ modules = sys.modules,
+ ))
+ except Unauthorized:
+ return False
+ else:
+ if not include:
+ return False
+
+ return True
+
+ def selected(self):
+ request_url = self.request.getURL()
+
+ normalized_action = self.action
+ if self.action.startswith('@@'):
+ normalized_action = self.action[2:]
+
+ if request_url.endswith('/'+normalized_action):
+ return True
+ if request_url.endswith('/++view++'+normalized_action):
+ return True
+ if request_url.endswith('/@@'+normalized_action):
+ return True
+
+ return False
+
+
+class BrowserSubMenuItem(BrowserMenuItem):
+ """Browser Menu Item Base Class"""
+ implements(IBrowserSubMenuItem)
+
+ submenuId = None
+
+ def selected(self):
+ if self.action is u'':
+ return False
+ return super(BrowserSubMenuItem, self).selected()
+
+
+def getMenu(id, object, request):
+ """Return menu item entries in a TAL-friendly form."""
+ menu = getUtility(IBrowserMenu, id)
+ return menu.getMenuItems(object, request)
+
+
+def getFirstMenuItem(id, object, request):
+ """Get the first item of a menu."""
+ items = getMenu(id, object, request)
+ if items:
+ return items[0]
+ return None
+
+
+class MenuAccessView(BrowserView):
+ """A view allowing easy access to menus."""
+ implements(IMenuAccessView)
+
+ def __getitem__(self, menuId):
+ return getMenu(menuId, self.context, self.request)
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/menu.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/menu.txt
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/menu.txt (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/menu.txt 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,633 @@
+=============
+Browser Menus
+=============
+
+Browser menus are used to categorize browser actions, such as the views of a
+content component or the addable components of a container. In essence they
+provide the same functionality as menu bars in desktop application.
+
+ >>> from zope.browsermenu import menu, metaconfigure
+
+Menus are simple components that have an id, title and description. They also
+must provide a method called ``getMenuItems(object, request)`` that returns a
+TAL-friendly list of information dictionaries. We will see this in detail
+later. The default menu implementation, however, makes the menu be very
+transparent by identifying the menu through an interface. So let's define and
+register a simple edit menu:
+
+ >>> import zope.interface
+ >>> class EditMenu(zope.interface.Interface):
+ ... """This is an edit menu."""
+
+ >>> from zope.browsermenu.interfaces import IMenuItemType
+ >>> zope.interface.directlyProvides(EditMenu, IMenuItemType)
+
+ >>> from zope.component import provideUtility
+ >>> provideUtility(EditMenu, IMenuItemType, 'edit')
+
+Now we have to create and register the menu itself:
+
+ >>> from zope.browsermenu.interfaces import IBrowserMenu
+ >>> provideUtility(
+ ... menu.BrowserMenu('edit', u'Edit', u'Edit Menu'), IBrowserMenu, 'edit')
+
+Note that these steps seem like a lot of boilerplate, but all this work is
+commonly done for you via ZCML. An item in a menu is simply an adapter that
+provides. In the following section we will have a closer look at the browser
+menu item:
+
+``BrowserMenuItem`` class
+-------------------------
+
+The browser menu item represents an entry in the menu. Essentially, the menu
+item is a browser view of a content component. Thus we have to create a
+content component first:
+
+ >>> class IContent(zope.interface.Interface):
+ ... pass
+
+ >>> from zope.publisher.interfaces.browser import IBrowserPublisher
+ >>> from zope.security.interfaces import Unauthorized, Forbidden
+
+ >>> class Content(object):
+ ... zope.interface.implements(IContent, IBrowserPublisher)
+ ...
+ ... def foo(self):
+ ... pass
+ ...
+ ... def browserDefault(self, r):
+ ... return self, ()
+ ...
+ ... def publishTraverse(self, request, name):
+ ... if name.startswith('fb'):
+ ... raise Forbidden, name
+ ... if name.startswith('ua'):
+ ... raise Unauthorized, name
+ ... if name.startswith('le'):
+ ... raise LookupError, name
+ ... return self.foo
+
+We also implemented the ``IBrowserPublisher`` interface, because we want to
+make the object traversable, so that we can make availability checks later.
+
+Since the ``BrowserMenuItem`` is just a view, we can initiate it with an
+object and a request.
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> item = menu.BrowserMenuItem(Content(), TestRequest())
+
+Note that the menu item knows *nothing* about the menu itself. It purely
+depends on the adapter registration to determine in which menu it will
+appear. The advantage is that a menu item can be reused in several menus.
+
+Now we add a title, description, order and icon and see whether we can then
+access the value. Note that these assignments are always automatically done by
+the framework.
+
+ >>> item.title = u'Item 1'
+ >>> item.title
+ u'Item 1'
+
+ >>> item.description = u'This is Item 1.'
+ >>> item.description
+ u'This is Item 1.'
+
+ >>> item.order
+ 0
+ >>> item.order = 1
+ >>> item.order
+ 1
+
+ >>> item.icon is None
+ True
+ >>> item.icon = u'/@@/icon.png'
+ >>> item.icon
+ u'/@@/icon.png'
+
+Since there is no permission or view specified yet, the menu item should
+be available and not selected.
+
+ >>> item.available()
+ True
+ >>> item.selected()
+ False
+
+There are two ways to deny availability of a menu item: (1) the current
+user does not have the correct permission to access the action or the menu
+item itself, or (2) the filter returns ``False``, in which case the menu
+item should also not be shown.
+
+ >>> from zope.security.interfaces import IPermission
+ >>> from zope.security.permission import Permission
+ >>> perm = Permission('perm', 'Permission')
+ >>> provideUtility(perm, IPermission, 'perm')
+
+ >>> class ParticipationStub(object):
+ ... principal = 'principal'
+ ... interaction = None
+
+
+In the first case, the permission of the menu item was explicitely
+specified. Make sure that the user needs this permission to make the menu
+item available.
+
+ >>> item.permission = perm
+
+Now, we are not setting any user. This means that the menu item should be
+available.
+
+ >>> from zope.security.management import newInteraction, endInteraction
+ >>> endInteraction()
+ >>> newInteraction()
+ >>> item.available()
+ True
+
+Now we specify a principal that does not have the specified permission.
+
+ >>> endInteraction()
+ >>> newInteraction(ParticipationStub())
+ >>> item.available()
+ False
+
+In the second case, the permission is not explicitely defined and the
+availability is determined by the permission required to access the
+action.
+
+ >>> item.permission = None
+
+ All views starting with 'fb' are forbidden, the ones with 'ua' are
+ unauthorized and all others are allowed.
+
+ >>> item.action = u'fb'
+ >>> item.available()
+ False
+ >>> item.action = u'ua'
+ >>> item.available()
+ False
+ >>> item.action = u'a'
+ >>> item.available()
+ True
+
+Also, sometimes a menu item might be registered for a view that does not
+exist. In those cases the traversal mechanism raises a `TraversalError`, which
+is a special type of `LookupError`. All actions starting with `le` should
+raise this error:
+
+ >>> item.action = u'le'
+ >>> item.available()
+ False
+
+Now let's test filtering. If the filter is specified, it is assumed to be
+a TALES obejct.
+
+ >>> from zope.pagetemplate.engine import Engine
+ >>> item.action = u'a'
+ >>> item.filter = Engine.compile('not:context')
+ >>> item.available()
+ False
+ >>> item.filter = Engine.compile('context')
+ >>> item.available()
+ True
+
+Finally, make sure that the menu item can be selected.
+
+ >>> item.request = TestRequest(SERVER_URL='http://127.0.0.1/@@view.html',
+ ... PATH_INFO='/@@view.html')
+
+ >>> item.selected()
+ False
+ >>> item.action = u'view.html'
+ >>> item.selected()
+ True
+ >>> item.action = u'@@view.html'
+ >>> item.selected()
+ True
+ >>> item.request = TestRequest(
+ ... SERVER_URL='http://127.0.0.1/++view++view.html',
+ ... PATH_INFO='/++view++view.html')
+ >>> item.selected()
+ True
+ >>> item.action = u'otherview.html'
+ >>> item.selected()
+ False
+
+
+``BrowserSubMenuItem`` class
+----------------------------
+
+The menu framework also allows for submenus. Submenus can be inserted by
+creating a special menu item that simply points to another menu to be
+inserted:
+
+ >>> item = menu.BrowserSubMenuItem(Content(), TestRequest())
+
+The framework will always set the sub-menu automatically (we do it
+manually here):
+
+ >>> class SaveOptions(zope.interface.Interface):
+ ... "A sub-menu that describes available save options for the content."
+
+ >>> zope.interface.directlyProvides(SaveOptions, IMenuItemType)
+
+ >>> provideUtility(SaveOptions, IMenuItemType, 'save')
+ >>> provideUtility(menu.BrowserMenu('save', u'Save', u'Save Menu'),
+ ... IBrowserMenu, 'save')
+
+Now we can assign the sub-menu id to the menu item:
+
+ >>> item.submenuId = 'save'
+
+Also, the ``action`` attribute for the browser sub-menu item is optional,
+because you often do not want the item itself to represent something. The rest
+of the class is identical to the ``BrowserMenuItem`` class.
+
+
+Getting a Menu
+--------------
+
+Now that we know how the single menu item works, let's have a look at how menu
+items get put together to a menu. But let's first create some menu items and
+register them as adapters with the component architecture.
+
+Register the edit menu entries first. We use the menu item factory to create
+the items:
+
+ >>> from zope.component import provideAdapter
+ >>> from zope.publisher.interfaces.browser import IBrowserRequest
+
+ >>> undo = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Undo",
+ ... action="undo.html")
+ >>> provideAdapter(undo, (IContent, IBrowserRequest), EditMenu, 'undo')
+
+ >>> redo = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Redo",
+ ... action="redo.html", icon="/@@/redo.png")
+ >>> provideAdapter(redo, (IContent, IBrowserRequest), EditMenu, 'redo')
+
+ >>> save = metaconfigure.MenuItemFactory(menu.BrowserSubMenuItem, title="Save",
+ ... submenuId='save', order=2)
+ >>> provideAdapter(save, (IContent, IBrowserRequest), EditMenu, 'save')
+
+And now the save options:
+
+ >>> saveas = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Save as",
+ ... action="saveas.html")
+ >>> provideAdapter(saveas, (IContent, IBrowserRequest),
+ ... SaveOptions, 'saveas')
+
+ >>> saveall = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="Save all",
+ ... action="saveall.html")
+ >>> provideAdapter(saveall, (IContent, IBrowserRequest),
+ ... SaveOptions, 'saveall')
+
+Note that we can also register menu items for classes:
+
+
+ >>> new = metaconfigure.MenuItemFactory(menu.BrowserMenuItem, title="New",
+ ... action="new.html", _for=Content)
+ >>> provideAdapter(new, (Content, IBrowserRequest), EditMenu, 'new')
+
+
+The utility that is used to generate the menu into a TAL-friendly
+data-structure is ``getMenu()``::
+
+ getMenu(menuId, object, request)
+
+where ``menuId`` is the id originally specified for the menu. Let's look up the
+menu now:
+
+ >>> pprint(menu.getMenu('edit', Content(), TestRequest()))
+ [{'action': 'new.html',
+ 'description': u'',
+ 'extra': None,
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'New'},
+ {'action': 'redo.html',
+ 'description': u'',
+ 'extra': None,
+ 'icon': '/@@/redo.png',
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'Redo'},
+ {'action': 'undo.html',
+ 'description': u'',
+ 'extra': None,
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'Undo'},
+ {'action': u'',
+ 'description': u'',
+ 'extra': None,
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': [{'action': 'saveall.html',
+ 'description': u'',
+ 'extra': None,
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'Save all'},
+ {'action': 'saveas.html',
+ 'description': u'',
+ 'extra': None,
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'Save as'}],
+ 'title': 'Save'}]
+
+
+Custom ``IBrowserMenu`` Implementations
+---------------------------------------
+
+Until now we have only seen how to use the default menu implementation. Much
+of the above boilerplate was necessary just to support custom menus. But what
+could custom menus do? Sometimes menu items are dynamically generated based on
+a certain state of the object the menu is for. For example, you might want to
+show all items in a folder-like component. So first let's create this
+folder-like component:
+
+ >>> class Folderish(Content):
+ ... names = ['README.txt', 'logo.png', 'script.py']
+
+Now we create a menu using the names to create a menu:
+
+ >>> from zope.browsermenu.interfaces import IBrowserMenu
+
+ >>> class Items(object):
+ ... zope.interface.implements(IBrowserMenu)
+ ...
+ ... def __init__(self, id, title=u'', description=u''):
+ ... self.id = id
+ ... self.title = title
+ ... self.description = description
+ ...
+ ... def getMenuItems(self, object, request):
+ ... return [{'title': name,
+ ... 'description': None,
+ ... 'action': name + '/manage',
+ ... 'selected': u'',
+ ... 'icon': None,
+ ... 'extra': {},
+ ... 'submenu': None}
+ ... for name in object.names]
+
+and register it:
+
+ >>> provideUtility(Items('items', u'Items', u'Items Menu'),
+ ... IBrowserMenu, 'items')
+
+We can now get the menu items using the previously introduced API:
+
+ >>> pprint(menu.getMenu('items', Folderish(), TestRequest()))
+ [{'action': 'README.txt/manage',
+ 'description': None,
+ 'extra': {},
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'README.txt'},
+ {'action': 'logo.png/manage',
+ 'description': None,
+ 'extra': {},
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'logo.png'},
+ {'action': 'script.py/manage',
+ 'description': None,
+ 'extra': {},
+ 'icon': None,
+ 'selected': u'',
+ 'submenu': None,
+ 'title': 'script.py'}]
+
+
+``MenuItemFactory`` class
+-------------------------
+
+As you have seen above already, we have used the menu item factory to generate
+adapter factories for menu items. The factory needs a particular
+``IBrowserMenuItem`` class to instantiate. Here is an example using a dummy
+menu item class:
+
+ >>> class DummyBrowserMenuItem(object):
+ ... "a dummy factory for menu items"
+ ... def __init__(self, context, request):
+ ... self.context = context
+ ... self.request = request
+
+To instantiate this class, pass the factory and the other arguments as keyword
+arguments (every key in the arguments should map to an attribute of the menu
+item class). We use dummy values for this example.
+
+ >>> factory = metaconfigure.MenuItemFactory(
+ ... DummyBrowserMenuItem, title='Title', description='Description',
+ ... icon='Icon', action='Action', filter='Filter',
+ ... permission='zope.Public', extra='Extra', order='Order', _for='For')
+ >>> factory.factory is DummyBrowserMenuItem
+ True
+
+The "zope.Public" permission needs to be translated to ``CheckerPublic``.
+
+ >>> from zope.security.checker import CheckerPublic
+ >>> factory.kwargs['permission'] is CheckerPublic
+ True
+
+Call the factory with context and request to return the instance. We continue
+to use dummy values.
+
+ >>> item = factory('Context', 'Request')
+
+The returned value should be an instance of the ``DummyBrowserMenuItem``, and
+have all of the values we initially set on the factory.
+
+ >>> isinstance(item, DummyBrowserMenuItem)
+ True
+ >>> item.context
+ 'Context'
+ >>> item.request
+ 'Request'
+ >>> item.title
+ 'Title'
+ >>> item.description
+ 'Description'
+ >>> item.icon
+ 'Icon'
+ >>> item.action
+ 'Action'
+ >>> item.filter
+ 'Filter'
+ >>> item.permission is CheckerPublic
+ True
+ >>> item.extra
+ 'Extra'
+ >>> item.order
+ 'Order'
+ >>> item._for
+ 'For'
+
+If you pass a permission other than ``zope.Public`` to the
+``MenuItemFactory``, it should pass through unmodified.
+
+ >>> factory = metaconfigure.MenuItemFactory(
+ ... DummyBrowserMenuItem, title='Title', description='Description',
+ ... icon='Icon', action='Action', filter='Filter',
+ ... permission='another.Permission', extra='Extra', order='Order',
+ ... _for='For_')
+ >>> factory.kwargs['permission']
+ 'another.Permission'
+
+
+Directive Handlers
+------------------
+
+``menu`` Directive Handler
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Provides a new menu (item type).
+
+ >>> class Context(object):
+ ... info = u'doc'
+ ... def __init__(self):
+ ... self.actions = []
+ ...
+ ... def action(self, **kw):
+ ... self.actions.append(kw)
+
+Possibility 1: The Old Way
+++++++++++++++++++++++++++
+
+ >>> context = Context()
+ >>> metaconfigure.menuDirective(context, u'menu1', title=u'Menu 1')
+ >>> iface = context.actions[0]['args'][1]
+ >>> iface.getName()
+ u'menu1'
+
+ >>> import sys
+ >>> hasattr(sys.modules['zope.app.menus'], 'menu1')
+ True
+
+ >>> del sys.modules['zope.app.menus'].menu1
+
+Possibility 2: Just specify an interface
+++++++++++++++++++++++++++++++++++++++++
+
+ >>> class menu1(zope.interface.Interface):
+ ... pass
+
+ >>> context = Context()
+ >>> metaconfigure.menuDirective(context, interface=menu1)
+ >>> context.actions[0]['args'][1] is menu1
+ True
+
+Possibility 3: Specify an interface and an id
++++++++++++++++++++++++++++++++++++++++++++++
+
+ >>> context = Context()
+ >>> metaconfigure.menuDirective(context, id='menu1', interface=menu1)
+
+ >>> pprint([action['discriminator'] for action in context.actions])
+ [('browser', 'MenuItemType', '__builtin__.menu1'),
+ ('interface', '__builtin__.menu1'),
+ ('browser', 'MenuItemType', 'menu1'),
+ ('utility',
+ <InterfaceClass zope.browsermenu.interfaces.IBrowserMenu>,
+ 'menu1'),
+ None]
+
+Here are some disallowed configurations.
+
+ >>> context = Context()
+ >>> metaconfigure.menuDirective(context)
+ Traceback (most recent call last):
+ ...
+ ConfigurationError: You must specify the 'id' or 'interface' attribute.
+
+ >>> metaconfigure.menuDirective(context, title='Menu 1')
+ Traceback (most recent call last):
+ ...
+ ConfigurationError: You must specify the 'id' or 'interface' attribute.
+
+
+``menuItems`` Directive Handler
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Register several menu items for a particular menu.
+
+ >>> class TestMenuItemType(zope.interface.Interface):
+ ... pass
+
+ >>> class ITest(zope.interface.Interface):
+ ... pass
+
+ >>> context = Context()
+ >>> items = metaconfigure.menuItemsDirective(context, TestMenuItemType, ITest)
+ >>> context.actions
+ []
+ >>> items.menuItem(context, u'view.html', 'View')
+ >>> items.subMenuItem(context, SaveOptions, 'Save')
+
+ >>> disc = [action['discriminator'] for action in context.actions]
+ >>> disc.sort()
+ >>> pprint(disc[-2:])
+ [('adapter',
+ (<InterfaceClass __builtin__.ITest>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass __builtin__.TestMenuItemType>,
+ 'Save'),
+ ('adapter',
+ (<InterfaceClass __builtin__.ITest>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass __builtin__.TestMenuItemType>,
+ 'View')]
+
+Custom menu item classes
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+We can register menu items and sub menu items with custom classes instead
+of ones used by default. For that, we need to create an implementation
+of IBrowserMenuItem or IBrowserSubMenuItem.
+
+ >>> context = Context()
+ >>> items = metaconfigure.menuItemsDirective(context, TestMenuItemType, ITest)
+ >>> context.actions
+ []
+
+Let's create a custom menu item class that inherits standard BrowserMenuItem:
+
+ >>> class MyMenuItem(menu.BrowserMenuItem):
+ ... pass
+
+ >>> items.menuItem(context, u'view.html', 'View', item_class=MyMenuItem)
+
+Also create a custom sub menu item class inheriting standard BrowserSubMenuItem:
+
+ >>> class MySubMenuItem(menu.BrowserSubMenuItem):
+ ... pass
+
+ >>> items.subMenuItem(context, SaveOptions, 'Save', item_class=MySubMenuItem)
+
+ >>> actions = sorted(context.actions, key=lambda a:a['discriminator'])
+ >>> factories = [action['args'][1] for action in actions][-2:]
+
+ >>> factories[0].factory is MySubMenuItem
+ True
+
+ >>> factories[1].factory is MyMenuItem
+ True
+
+These directive will fail if you provide an item_class that does not
+implement IBrowserMenuItem/IBrowserSubMenuItem:
+
+ >>> items.menuItem(context, u'fail', 'Failed', item_class=object)
+ Traceback (most recent call last):
+ ...
+ ValueError: Item class (<type 'object'>) must implement IBrowserMenuItem
+
+ >>> items.subMenuItem(context, SaveOptions, 'Failed', item_class=object)
+ Traceback (most recent call last):
+ ...
+ ValueError: Item class (<type 'object'>) must implement IBrowserSubMenuItem
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/menu.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/src/zope/browsermenu/meta.zcml
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/meta.zcml (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/meta.zcml 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,49 @@
+<configure xmlns:meta="http://namespaces.zope.org/meta">
+
+ <meta:directives namespace="http://namespaces.zope.org/browser">
+
+ <meta:directive
+ name="menu"
+ schema=".metadirectives.IMenuDirective"
+ handler=".metaconfigure.menuDirective"
+ />
+
+ <meta:complexDirective
+ name="menuItems"
+ schema=".metadirectives.IMenuItemsDirective"
+ handler=".metaconfigure.menuItemsDirective"
+ >
+
+ <meta:subdirective
+ name="menuItem"
+ schema=".metadirectives.IMenuItemSubdirective"
+ />
+
+ <meta:subdirective
+ name="subMenuItem"
+ schema=".metadirectives.ISubMenuItemSubdirective"
+ />
+
+ </meta:complexDirective>
+
+ <meta:directive
+ name="menuItem"
+ schema=".metadirectives.IMenuItemDirective"
+ handler=".metaconfigure.menuItemDirective"
+ />
+
+ <meta:directive
+ name="subMenuItem"
+ schema=".metadirectives.ISubMenuItemDirective"
+ handler=".metaconfigure.subMenuItemDirective"
+ />
+
+ <meta:directive
+ name="addMenuItem"
+ schema=".metadirectives.IAddMenuItemDirective"
+ handler=".metaconfigure.addMenuItem"
+ />
+
+ </meta:directives>
+
+</configure>
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/meta.zcml
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/src/zope/browsermenu/metaconfigure.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/metaconfigure.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/metaconfigure.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,306 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Menu Directives Configuration Handlers
+
+$Id: menumeta.py 100372 2009-05-25 19:31:23Z tseaver $
+"""
+from zope.browser.interfaces import IAdding
+from zope.component import getGlobalSiteManager, getUtility
+from zope.component.interface import provideInterface
+from zope.component.zcml import adapter, proxify, utility
+from zope.configuration.exceptions import ConfigurationError
+from zope.interface import Interface
+from zope.interface.interface import InterfaceClass
+from zope.pagetemplate.engine import Engine
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.security.checker import InterfaceChecker, CheckerPublic
+from zope.security.metaconfigure import ClassDirective
+
+from zope.browsermenu.menu import BrowserMenu, BrowserMenuItem, BrowserSubMenuItem
+from zope.browsermenu.interfaces import IBrowserMenu, IMenuItemType
+from zope.browsermenu.interfaces import IBrowserMenuItem, IBrowserSubMenuItem
+from zope.browsermenu.interfaces import AddMenu
+
+# Create special modules that contain all menu item types
+from types import ModuleType as module
+import sys
+try:
+ import zope.app
+except ImportError: # we doesn't always have zope.app now
+ sys.modules['zope.app'] = module('app')
+menus = module('menus')
+sys.modules['zope.app.menus'] = menus
+
+
+_order_counter = {}
+
+
+def menuDirective(_context, id=None, class_=BrowserMenu, interface=None,
+ title=u'', description=u''):
+ """Registers a new browser menu."""
+ if id is None and interface is None:
+ raise ConfigurationError(
+ "You must specify the 'id' or 'interface' attribute.")
+
+ if interface is None:
+ if id in dir(menus):
+ # reuse existing interfaces for the id, without this we are not
+ # able to override menus.
+ interface = getattr(menus, id)
+ else:
+ interface = InterfaceClass(id, (),
+ __doc__='Menu Item Type: %s' %id,
+ __module__='zope.app.menus')
+ # Add the menu item type to the `menus` module.
+ # Note: We have to do this immediately, so that directives using the
+ # MenuField can find the menu item type.
+ setattr(menus, id, interface)
+ path = 'zope.app.menus.' + id
+ else:
+ path = interface.__module__ + '.' + interface.getName()
+
+ # If an id was specified, make this menu available under this id.
+ # Note that the menu will be still available under its path, since it
+ # is an adapter, and the `MenuField` can resolve paths as well.
+ if id is None:
+ id = path
+ else:
+ # Make the interface available in the `zope.app.menus` module, so
+ # that other directives can find the interface under the name
+ # before the CA is setup.
+ _context.action(
+ discriminator = ('browser', 'MenuItemType', path),
+ callable = provideInterface,
+ args = (path, interface, IMenuItemType, _context.info)
+ )
+ setattr(menus, id, interface)
+
+ # Register the layer interface as an interface
+ _context.action(
+ discriminator = ('interface', path),
+ callable = provideInterface,
+ args = (path, interface),
+ kw = {'info': _context.info}
+ )
+
+ # Register the menu item type interface as an IMenuItemType
+ _context.action(
+ discriminator = ('browser', 'MenuItemType', id),
+ callable = provideInterface,
+ args = (id, interface, IMenuItemType, _context.info)
+ )
+
+ # Register the menu as a utility
+ utility(_context, IBrowserMenu, class_(id, title, description), name=id)
+
+
+def menuItemDirective(_context, menu, for_,
+ action, title, description=u'', icon=None, filter=None,
+ permission=None, layer=IDefaultBrowserLayer, extra=None,
+ order=0, item_class=None):
+ """Register a single menu item."""
+ return menuItemsDirective(_context, menu, for_, layer).menuItem(
+ _context, action, title, description, icon, filter,
+ permission, extra, order, item_class)
+
+
+def subMenuItemDirective(_context, menu, for_, title, submenu,
+ action=u'', description=u'', icon=None, filter=None,
+ permission=None, layer=IDefaultBrowserLayer,
+ extra=None, order=0, item_class=None):
+ """Register a single sub-menu menu item."""
+ return menuItemsDirective(_context, menu, for_, layer).subMenuItem(
+ _context, submenu, title, description, action, icon, filter,
+ permission, extra, order, item_class)
+
+
+class MenuItemFactory(object):
+ """generic factory for menu items."""
+
+ def __init__(self, factory, **kwargs):
+ self.factory = factory
+ if 'permission' in kwargs and kwargs['permission'] == 'zope.Public':
+ kwargs['permission'] = CheckerPublic
+ self.kwargs = kwargs
+
+ def __call__(self, context, request):
+ item = self.factory(context, request)
+
+ for key, value in self.kwargs.items():
+ setattr(item, key, value)
+
+ if item.permission is not None:
+ checker = InterfaceChecker(IBrowserMenuItem, item.permission)
+ item = proxify(item, checker)
+
+ return item
+
+
+class menuItemsDirective(object):
+ """Register several menu items for a particular menu."""
+
+ menuItemClass = BrowserMenuItem
+ subMenuItemClass = BrowserSubMenuItem
+
+ def __init__(self, _context, menu, for_, layer=IDefaultBrowserLayer,
+ permission=None):
+ self.for_ = for_
+ self.menuItemType = menu
+ self.layer = layer
+ self.permission = permission
+
+ def menuItem(self, _context, action, title, description=u'',
+ icon=None, filter=None, permission=None, extra=None,
+ order=0, item_class=None):
+
+ if filter is not None:
+ filter = Engine.compile(filter)
+
+ if permission is None:
+ permission = self.permission
+
+ if order == 0:
+ order = _order_counter.get(self.for_, 1)
+ _order_counter[self.for_] = order + 1
+
+ if item_class is None:
+ item_class = self.menuItemClass
+
+ if not IBrowserMenuItem.implementedBy(item_class):
+ raise ValueError("Item class (%s) must implement IBrowserMenuItem" % item_class)
+
+ factory = MenuItemFactory(
+ item_class,
+ title=title, description=description, icon=icon, action=action,
+ filter=filter, permission=permission, extra=extra, order=order,
+ _for=self.for_)
+ adapter(_context, (factory,), self.menuItemType,
+ (self.for_, self.layer), name=title)
+
+ def subMenuItem(self, _context, submenu, title, description=u'',
+ action=u'', icon=None, filter=None, permission=None,
+ extra=None, order=0, item_class=None):
+
+ if filter is not None:
+ filter = Engine.compile(filter)
+
+ if permission is None:
+ permission = self.permission
+
+ if order == 0:
+ order = _order_counter.get(self.for_, 1)
+ _order_counter[self.for_] = order + 1
+
+ if item_class is None:
+ item_class = self.subMenuItemClass
+
+ if not IBrowserSubMenuItem.implementedBy(item_class):
+ raise ValueError("Item class (%s) must implement IBrowserSubMenuItem" % item_class)
+
+ factory = MenuItemFactory(
+ item_class,
+ title=title, description=description, icon=icon, action=action,
+ filter=filter, permission=permission, extra=extra, order=order,
+ _for=self.for_, submenuId=submenu)
+ adapter(_context, (factory,), self.menuItemType,
+ (self.for_, self.layer), name=title)
+
+ def __call__(self, _context):
+ # Nothing to do.
+ pass
+
+def _checkViewFor(for_=None, layer=None, view_name=None):
+ """Check if there is a view of that name registered for IAdding
+ and IBrowserRequest. If not raise a ConfigurationError
+
+ It will raise a ConfigurationError if :
+ o view=""
+ o if view_name is not registred
+ """
+
+ if view_name is None:
+ raise ConfigurationError(
+ "Within a addMenuItem directive the view attribut"
+ " is optional but can\'t be empty"
+ )
+
+ gsm = getGlobalSiteManager()
+ if gsm.adapters.lookup((for_, layer),
+ Interface, view_name) is None:
+ raise ConfigurationError(
+ "view name %s not found " %view_name
+ )
+
+def addMenuItem(_context, title, description='', menu=None, for_=None,
+ class_=None, factory=None, view=None, icon=None, filter=None,
+ permission=None, layer=IDefaultBrowserLayer, extra=None,
+ order=0, item_class=None):
+ """Create an add menu item for a given class or factory
+
+ As a convenience, a class can be provided, in which case, a
+ factory is automatically defined based on the class. In this
+ case, the factory id is based on the class name.
+
+ """
+
+ if for_ is not None:
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', for_)
+ )
+ forname = 'For' + for_.getName()
+ else:
+ for_ = IAdding
+ forname = ''
+
+ if menu is not None:
+ if isinstance(menu, (str, unicode)):
+ menu = getUtility(IMenuItemType, menu)
+ if menu is None:
+ raise ValueError("Missing menu id '%s'" % menu)
+
+ if class_ is None:
+ if factory is None:
+ raise ValueError("Must specify either class or factory")
+ else:
+ if factory is not None:
+ raise ValueError("Can't specify both class and factory")
+ if permission is None:
+ raise ValueError(
+ "A permission must be specified when a class is used")
+ factory = "BrowserAdd%s__%s.%s" % (
+ forname, class_.__module__, class_.__name__)
+ ClassDirective(_context, class_).factory(_context, id=factory)
+
+ extra = {'factory': factory}
+
+ if view:
+ action = view
+ # This action will check if the view exists
+ _context.action(
+ discriminator = None,
+ callable = _checkViewFor,
+ args = (for_, layer, view),
+ order=999999
+ )
+ else:
+ action = factory
+
+ if menu == None:
+ menu = AddMenu
+
+ return menuItemsDirective(_context, menu, for_, layer=layer).menuItem(
+ _context, action, title, description, icon, filter,
+ permission, extra, order, item_class)
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/metaconfigure.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/metadirectives.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/metadirectives.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/metadirectives.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,244 @@
+#############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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.
+#
+##############################################################################
+"""Browser configuration code
+
+This module defines the schemas for browser directives.
+
+$Id: metadirectives.py 103143 2009-08-24 12:28:19Z nadako $
+"""
+from zope.interface import Interface
+from zope.configuration.fields import GlobalObject, GlobalInterface
+from zope.configuration.fields import Tokens, Path, PythonIdentifier, MessageID
+from zope.schema import TextLine, Id, Int, Bool
+from zope.security.zcml import Permission
+
+from zope.component.zcml import IBasicViewInformation
+from zope.browsermenu.fields import MenuField
+
+
+class IMenuDirective(Interface):
+ """Define a browser menu"""
+
+ id = TextLine(
+ title=u"The name of the menu.",
+ description=u"This is, effectively, an id.",
+ required=False
+ )
+
+ title = MessageID(
+ title=u"Title",
+ description=u"A descriptive title for documentation purposes",
+ required=False
+ )
+
+ description = MessageID(
+ title=u"Description",
+ description=u"A description title of the menu.",
+ required=False
+ )
+
+ class_ = GlobalObject(
+ title=u"Menu Class",
+ description=u"The menu class used to generate the menu.",
+ required=False
+ )
+
+ interface = GlobalInterface(
+ title=u"The menu's interface.",
+ required=False
+ )
+
+
+class IMenuItemsDirective(Interface):
+ """
+ Define a group of browser menu items
+
+ This directive is useful when many menu items are defined for the
+ same interface and menu.
+ """
+
+ menu = MenuField(
+ title=u"Menu name",
+ description=u"The (name of the) menu the items are defined for",
+ required=True,
+ )
+
+ for_ = GlobalObject(
+ title=u"Interface",
+ description=u"The interface the menu items are defined for",
+ required=True
+ )
+
+ layer = GlobalInterface(
+ title=u"Layer",
+ description=u"The Layer for which the item is declared.",
+ required=False
+ )
+
+ permission = Permission(
+ title=u"The permission needed access the item",
+ description=u"""
+ This can usually be inferred by the system, however, doing so
+ may be expensive. When displaying a menu, the system tries to
+ traverse to the URLs given in each action to determine whether
+ the url is accessible to the current user. This can be
+ avoided if the permission is given explicitly.""",
+ required=False
+ )
+
+
+class IMenuItem(Interface):
+ """Common menu item configuration
+ """
+
+ title = MessageID(
+ title=u"Title",
+ description=u"The text to be displayed for the menu item",
+ required=True
+ )
+
+ description = MessageID(
+ title=u"A longer explanation of the menu item",
+ description=u"""
+ A UI may display this with the item or display it when the
+ user requests more assistance.""",
+ required=False
+ )
+
+ icon = TextLine(
+ title=u"Icon Path",
+ description=u"Path to the icon resource representing this menu item.",
+ required=False
+ )
+
+ permission = Permission(
+ title=u"The permission needed access the item",
+ description=u"""
+ This can usually be inferred by the system, however, doing so
+ may be expensive. When displaying a menu, the system tries to
+ traverse to the URLs given in each action to determine whether
+ the url is accessible to the current user. This can be
+ avoided if the permission is given explicitly.""",
+ required=False
+ )
+
+ filter = TextLine(
+ title=u"A condition for displaying the menu item",
+ description=u"""
+ The condition is given as a TALES expression. The expression
+ has access to the variables:
+
+ context -- The object the menu is being displayed for
+
+ request -- The browser request
+
+ nothing -- None
+
+ The menu item will not be displayed if there is a filter and
+ the filter evaluates to a false value.""",
+ required=False
+ )
+
+ order = Int(
+ title=u"Order",
+ description=u"A relative position of the menu item in the menu.",
+ required=False,
+ default=0
+ )
+
+ item_class = GlobalObject(
+ title=u"Menu item class",
+ description=u"""
+ A class to be used as a factory for creating menu item""",
+ required=False
+ )
+
+class IMenuItemSubdirective(IMenuItem):
+ """Define a menu item within a group of menu items"""
+
+ action = TextLine(
+ title=u"The relative url to use if the item is selected",
+ description=u"""
+ The url is relative to the object the menu is being displayed
+ for.""",
+ required=True
+ )
+
+class IMenuItemDirective(IMenuItemsDirective, IMenuItemSubdirective):
+ """Define one menu item"""
+
+class ISubMenuItemSubdirective(IMenuItem):
+ """Define a menu item that represents a a sub menu.
+
+ For a sub-menu menu item, the action is optional, this the item itself
+ might not represent a destination, but just an entry point to the sub menu.
+ """
+
+ action = TextLine(
+ title=u"The relative url to use if the item is selected",
+ description=u"""
+ The url is relative to the object the menu is being displayed
+ for.""",
+ required=False
+ )
+
+ submenu = TextLine(
+ title=u"Sub-Menu Id",
+ description=u"The menu that will be used to provide the sub-entries.",
+ required=True,
+ )
+
+class ISubMenuItemDirective(IMenuItemsDirective, ISubMenuItemSubdirective):
+ """Define one menu item"""
+
+class IAddMenuItemDirective(IMenuItem):
+ """Define an add-menu item"""
+
+ for_ = GlobalInterface(
+ title=u"Interface",
+ description=u"The interface the menu items are defined for",
+ required=False
+ )
+
+ class_ = GlobalObject(
+ title=u"Class",
+ description=u"""
+ A class to be used as a factory for creating new objects""",
+ required=False
+ )
+
+ factory = Id(
+ title=u"Factory",
+ description=u"A factory id for creating new objects",
+ required = False,
+ )
+
+ view = TextLine(
+ title=u"Custom view name",
+ description=u"The name of a custom add view",
+ required = False,
+ )
+
+ menu = MenuField(
+ title=u"Menu name",
+ description=u"The (name of the) menu the items are defined for",
+ required=False,
+ )
+
+ layer = GlobalInterface(
+ title=u"The layer the custom view is declared for",
+ description=u"The default layer for which the custom view is "
+ u"applicable. By default it is applied to all layers.",
+ required=False
+ )
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/metadirectives.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/addmenuitems.zcml
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/addmenuitems.zcml (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/addmenuitems.zcml 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,23 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zope">
+
+ <view
+ for="zope.browser.interfaces.IAdding"
+ type="zope.browsermenu.tests.test_addMenuItem.ILayerStub"
+ name="add2.html"
+ factory="zope.publisher.browser.BrowserPage"
+ permission="zope.Public"
+ allowed_interface="zope.publisher.interfaces.browser.IBrowserPage"
+ />
+
+ <browser:addMenuItem
+ class=".tests.test_menudirectives.I1"
+ title="Add menu Item"
+ view="add2.html"
+ permission="zope.Public"
+ layer="zope.browsermenu.tests.test_addMenuItem.ILayerStub"
+ />
+
+</configure>
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/addmenuitems.zcml
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/menus-permissions.zcml
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/menus-permissions.zcml (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/menus-permissions.zcml 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,19 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zope">
+
+ <permission id="zope.View" title="Test permission"/>
+
+ <browser:menu
+ id="test_id"
+ title="test menu" />
+
+ <browser:menuItems
+ menu="test_id"
+ for=".tests.test_menudirectives.I2"
+ permission="zope.View">
+ <browser:menuItem action="b1" title="b1" />
+ </browser:menuItems>
+
+</configure>
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/menus-permissions.zcml
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/menus.zcml
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/menus.zcml (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/menus.zcml 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,63 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zope">
+
+ <browser:menu
+ id="test_id"
+ title="test menu" />
+
+ <browser:menu
+ id="test_sub_id"
+ title="test sub menu 2" />
+
+ <browser:menuItems
+ menu="test_id"
+ for="zope.interface.Interface">
+ <browser:menuItem action="a1" title="t1" />
+ <browser:subMenuItem submenu="test_sub_id" title="s1" />
+ </browser:menuItems>
+
+ <browser:menuItems
+ menu="test_id"
+ for=".tests.test_menudirectives.I1">
+ <browser:menuItem action="a2" title="t2" />
+ </browser:menuItems>
+
+ <browser:menuItems
+ menu="test_id"
+ for=".tests.test_menudirectives.I11">
+ <browser:menuItem action="a3" title="t3" filter="context" />
+ <browser:menuItem action="a4" title="t4" filter="not:context" />
+ </browser:menuItems>
+
+ <browser:menuItems
+ menu="test_id"
+ for=".tests.test_menudirectives.I111">
+ <browser:menuItem action="a5" title="t5" />
+ <browser:menuItem action="a6" title="t6" />
+ <browser:menuItem action="f7" title="t7" />
+ <browser:menuItem action="u8" title="t8" />
+ </browser:menuItems>
+
+ <browser:menuItems
+ menu="test_id"
+ for=".tests.test_menudirectives.I12">
+ <browser:menuItem action="a9" title="t9" />
+ </browser:menuItems>
+
+ <browser:menuItems
+ menu="test_sub_id"
+ for=".tests.test_menudirectives.I111">
+ <browser:menuItem action="a10" title="t10" />
+ </browser:menuItems>
+
+ <browser:menuItems
+ menu="test_id"
+ for=".tests.test_menudirectives.I111"
+ layer=".tests.test_menudirectives.IMyLayer">
+ <browser:menuItem action="a11" title="t11" />
+ <browser:subMenuItem submenu="test_sub_id" title="s2" />
+ </browser:menuItems>
+
+</configure>
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/menus.zcml
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_addMenuItem.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/test_addMenuItem.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/test_addMenuItem.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,427 @@
+#############################################################################
+#
+# Copyright (c) 2003 Zope Corporation 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.
+#
+##############################################################################
+"""Test the addMenuItem directive
+
+>>> context = Context()
+>>> addMenuItem(context, class_=X, title="Add an X",
+... permission="zope.ManageContent")
+>>> context
+((('utility',
+ <InterfaceClass zope.component.interfaces.IFactory>,
+ 'BrowserAdd__zope.browsermenu.tests.test_addMenuItem.X'),
+ <function handler>,
+ ('registerUtility',
+ <Factory for <class 'zope.browsermenu.tests.test_addMenuItem.X'>>,
+ <InterfaceClass zope.component.interfaces.IFactory>,
+ 'BrowserAdd__zope.browsermenu.tests.test_addMenuItem.X'),
+ {'factory': None}),
+ (None,
+ <function provideInterface>,
+ ('zope.component.interfaces.IFactory',
+ <InterfaceClass zope.component.interfaces.IFactory>),
+ {}),
+ (('adapter',
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('', <InterfaceClass zope.browser.interfaces.IAdding>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ {}))
+
+$Id: test_addMenuItem.py 100126 2009-05-19 12:55:59Z faassen $
+"""
+
+import unittest
+from zope.testing.doctest import DocTestSuite
+import re
+import pprint
+import cStringIO
+from zope.interface import Interface
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.browsermenu.metaconfigure import addMenuItem
+
+atre = re.compile(' at [0-9a-fA-Fx]+')
+
+class IX(Interface):
+ pass
+
+class X(object):
+ pass
+
+class ILayerStub(IBrowserRequest):
+ pass
+
+class MenuStub(object):
+ pass
+
+
+class Context(object):
+ actions = ()
+ info = ''
+
+ def action(self, discriminator, callable, args=(), kw={}, order=0):
+ self.actions += ((discriminator, callable, args, kw), )
+
+ def __repr__(self):
+ stream = cStringIO.StringIO()
+ pprinter = pprint.PrettyPrinter(stream=stream, width=60)
+ pprinter.pprint(self.actions)
+ r = stream.getvalue()
+ return (''.join(atre.split(r))).strip()
+
+
+def test_w_factory():
+ """
+ >>> context = Context()
+ >>> addMenuItem(context, factory="x.y.z", title="Add an X",
+ ... permission="zope.ManageContent", description="blah blah",
+ ... filter="context/foo")
+ >>> context
+ ((('adapter',
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('', <InterfaceClass zope.browser.interfaces.IAdding>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ {}))
+ """
+
+def test_w_factory_and_view():
+ """
+ >>> context = Context()
+ >>> addMenuItem(context, factory="x.y.z", title="Add an X",
+ ... permission="zope.ManageContent", description="blah blah",
+ ... filter="context/foo", view="AddX")
+ >>> context
+ ((None,
+ <function _checkViewFor>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>,
+ 'AddX'),
+ {}),
+ (('adapter',
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('', <InterfaceClass zope.browser.interfaces.IAdding>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ {}))
+ """
+
+def test_w_factory_class_view():
+ """
+ >>> context = Context()
+ >>> addMenuItem(context, class_=X, title="Add an X",
+ ... permission="zope.ManageContent", description="blah blah",
+ ... filter="context/foo", view="AddX")
+ >>> import pprint
+ >>> context
+ ((('utility',
+ <InterfaceClass zope.component.interfaces.IFactory>,
+ 'BrowserAdd__zope.browsermenu.tests.test_addMenuItem.X'),
+ <function handler>,
+ ('registerUtility',
+ <Factory for <class 'zope.browsermenu.tests.test_addMenuItem.X'>>,
+ <InterfaceClass zope.component.interfaces.IFactory>,
+ 'BrowserAdd__zope.browsermenu.tests.test_addMenuItem.X'),
+ {'factory': None}),
+ (None,
+ <function provideInterface>,
+ ('zope.component.interfaces.IFactory',
+ <InterfaceClass zope.component.interfaces.IFactory>),
+ {}),
+ (None,
+ <function _checkViewFor>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>,
+ 'AddX'),
+ {}),
+ (('adapter',
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('', <InterfaceClass zope.browser.interfaces.IAdding>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ {}))
+ """
+
+def test_w_for_factory():
+ """
+ >>> context = Context()
+ >>> addMenuItem(context, for_=IX, factory="x.y.z", title="Add an X",
+ ... permission="zope.ManageContent", description="blah blah",
+ ... filter="context/foo")
+ >>> context
+ ((None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>),
+ {}),
+ (('adapter',
+ (<InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ {}))
+ """
+
+def test_w_factory_layer():
+ """
+ >>> context = Context()
+ >>> addMenuItem(context, factory="x.y.z", title="Add an X", layer=ILayerStub,
+ ... permission="zope.ManageContent", description="blah blah",
+ ... filter="context/foo")
+ >>> context
+ ((('adapter',
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.browsermenu.tests.test_addMenuItem.ILayerStub>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.browsermenu.tests.test_addMenuItem.ILayerStub>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('', <InterfaceClass zope.browser.interfaces.IAdding>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.tests.test_addMenuItem.ILayerStub>),
+ {}))
+ """
+
+def test_w_for_menu_factory():
+ """
+ >>> context = Context()
+ >>> addMenuItem(context, for_=IX, menu=MenuStub, factory="x.y.z", title="Add an X",
+ ... permission="zope.ManageContent", description="blah blah",
+ ... filter="context/foo")
+ >>> context
+ ((None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>),
+ {}),
+ (('adapter',
+ (<InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <class 'zope.browsermenu.tests.test_addMenuItem.MenuStub'>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <class 'zope.browsermenu.tests.test_addMenuItem.MenuStub'>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <class 'zope.browsermenu.tests.test_addMenuItem.MenuStub'>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.tests.test_addMenuItem.IX>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ {}))
+ """
+
+def test_w_factory_icon_extra_order():
+ """
+ >>> context = Context()
+ >>> addMenuItem(context, factory="x.y.z", title="Add an X",
+ ... permission="zope.ManageContent", description="blah blah",
+ ... filter="context/foo", icon=u'/@@/icon.png', extra='Extra',
+ ... order=99)
+ >>> context
+ ((('adapter',
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X'),
+ <function handler>,
+ ('registerAdapter',
+ <zope.browsermenu.metaconfigure.MenuItemFactory object>,
+ (<InterfaceClass zope.browser.interfaces.IAdding>,
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>,
+ 'Add an X',
+ ''),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.browsermenu.interfaces.AddMenu>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('', <InterfaceClass zope.browser.interfaces.IAdding>),
+ {}),
+ (None,
+ <function provideInterface>,
+ ('',
+ <InterfaceClass zope.publisher.interfaces.browser.IDefaultBrowserLayer>),
+ {}))
+ """
+
+from zope.configuration.xmlconfig import XMLConfig
+
+import zope.browsermenu
+import zope.component
+from zope.testing import cleanup
+
+class TestAddMenuItem(cleanup.CleanUp, unittest.TestCase):
+
+ def setUp(self):
+ super(TestAddMenuItem, self).setUp()
+ XMLConfig('meta.zcml', zope.component)()
+ XMLConfig('meta.zcml', zope.browsermenu)()
+
+ def test_addMenuItemDirectives(self):
+ XMLConfig('tests/addmenuitems.zcml', zope.browsermenu)()
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite(),
+ unittest.makeSuite(TestAddMenuItem),
+ ))
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_addMenuItem.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_directives.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/test_directives.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/test_directives.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,194 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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.
+#
+##############################################################################
+"""'browser' namespace directive tests
+
+$Id: test_directives.py 103143 2009-08-24 12:28:19Z nadako $
+"""
+
+import sys
+import os
+import unittest
+from cStringIO import StringIO
+
+from zope import component
+from zope.interface import Interface, implements, directlyProvides, providedBy
+
+import zope.security.management
+from zope.configuration.xmlconfig import xmlconfig, XMLConfig
+from zope.configuration.exceptions import ConfigurationError
+from zope.publisher.browser import TestRequest
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.interfaces.browser import IBrowserSkinType
+from zope.security.proxy import removeSecurityProxy, ProxyFactory
+from zope.security.permission import Permission
+from zope.security.interfaces import IPermission
+from zope.testing.doctest import DocTestSuite
+from zope.traversing.adapters import DefaultTraversable
+from zope.traversing.interfaces import ITraversable
+
+import zope.browsermenu
+from zope.component.testfiles.views import IC, V1, VZMI, R1, IV
+from zope.browsermenu.menu import getFirstMenuItem, BrowserMenu
+from zope.browsermenu.interfaces import IMenuItemType, IBrowserMenu
+from zope.testing import cleanup
+
+tests_path = os.path.join(
+ os.path.dirname(zope.browsermenu.__file__),
+ 'tests')
+
+template = """<configure
+ xmlns='http://namespaces.zope.org/zope'
+ xmlns:browser='http://namespaces.zope.org/browser'
+ i18n_domain='zope'>
+ %s
+ </configure>"""
+
+
+request = TestRequest()
+
+class M1(BrowserMenu):
+ pass
+
+class V2(V1, object):
+
+ def action(self):
+ return self.action2()
+
+ def action2(self):
+ return "done"
+
+class VT(V1, object):
+ def publishTraverse(self, request, name):
+ try:
+ return int(name)
+ except:
+ return super(VT, self).publishTraverse(request, name)
+
+class Ob(object):
+ implements(IC)
+
+ob = Ob()
+
+class NCV(object):
+ "non callable view"
+
+ def __init__(self, context, request):
+ pass
+
+class CV(NCV):
+ "callable view"
+ def __call__(self):
+ pass
+
+
+class C_w_implements(NCV):
+ implements(Interface)
+
+ def index(self):
+ return self
+
+class ITestMenu(Interface):
+ """Test menu."""
+
+directlyProvides(ITestMenu, IMenuItemType)
+
+
+class ITestLayer(IBrowserRequest):
+ """Test Layer."""
+
+class ITestSkin(ITestLayer):
+ """Test Skin."""
+
+
+class MyResource(object):
+
+ def __init__(self, request):
+ self.request = request
+
+
+class Test(cleanup.CleanUp, unittest.TestCase):
+
+ def setUp(self):
+ super(Test, self).setUp()
+ XMLConfig('meta.zcml', zope.browsermenu)()
+ component.provideAdapter(DefaultTraversable, (None,), ITraversable)
+
+ def tearDown(self):
+ if 'test_menu' in dir(sys.modules['zope.app.menus']):
+ delattr(sys.modules['zope.app.menus'], 'test_menu')
+ super(Test, self).tearDown()
+
+ def testMenuOverride(self):
+ self.assertEqual(
+ component.queryMultiAdapter((ob, request), name='test'),
+ None)
+
+ xmlconfig(StringIO(template % (
+ '''
+ <browser:menu
+ id="test_menu" title="Test menu" />
+ <browser:menuItem
+ action="@@test"
+ for="zope.component.testfiles.views.IC"
+ permission="zope.Public"
+ menu="test_menu"
+ title="Test View"
+ />
+ '''
+ )))
+ menu1 = component.getUtility(IBrowserMenu, 'test_menu')
+ menuItem1 = getFirstMenuItem('test_menu', ob, TestRequest())
+ xmlconfig(StringIO(template % (
+ '''
+ <browser:menu
+ id="test_menu" title="Test menu"
+ class="zope.browsermenu.tests.test_directives.M1" />
+ '''
+ )))
+ menu2 = component.getUtility(IBrowserMenu, 'test_menu')
+ menuItem2 = getFirstMenuItem('test_menu', ob, TestRequest())
+ self.assertNotEqual(menu1, menu2)
+ self.assertEqual(menuItem1, menuItem2)
+
+
+ def testMenuItemNeedsFor(self):
+ # <browser:menuItem> directive fails if no 'for' argument was provided
+ from zope.configuration.exceptions import ConfigurationError
+ self.assertRaises(ConfigurationError, xmlconfig, StringIO(template %
+ '''
+ <browser:menu
+ id="test_menu" title="Test menu" />
+ <browser:menuItem
+ title="Test Entry"
+ menu="test_menu"
+ action="@@test"
+ />
+ '''
+ ))
+
+ # it works, when the argument is there and a valid interface
+ xmlconfig(StringIO(template %
+ '''
+ <browser:menuItem
+ for="zope.component.testfiles.views.IC"
+ title="Test Entry"
+ menu="test_menu"
+ action="@@test"
+ />
+ '''
+ ))
+
+def test_suite():
+ return unittest.makeSuite(Test)
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_directives.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_fields.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/test_fields.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/test_fields.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Test fields.
+
+$Id: test_fields.py 29570 2005-03-18 22:53:37Z rogerineichen $
+"""
+import unittest
+from zope.testing import cleanup, doctest
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocTestSuite('zope.browsermenu.fields',
+ setUp=lambda test:cleanup.setUp(),
+ tearDown=lambda test:cleanup.tearDown()),
+ ))
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_fields.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menu.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menu.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menu.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Browser Menu Item Tests
+
+$Id: test_menu.py 29570 2005-03-18 22:53:37Z rogerineichen $
+"""
+import unittest
+from zope.testing import doctest, cleanup, doctestunit
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('../menu.txt',
+ setUp=lambda test:cleanup.setUp(),
+ tearDown=lambda test:cleanup.tearDown(),
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ ))
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menu.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
Added: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menudirectives.py
===================================================================
--- zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menudirectives.py (rev 0)
+++ zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menudirectives.py 2009-08-24 14:27:26 UTC (rev 103151)
@@ -0,0 +1,163 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation 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.
+#
+##############################################################################
+"""Browser Menu Directives Tests
+
+$Id: test_menudirectives.py 70102 2006-09-11 20:47:15Z ctheune $
+"""
+import unittest
+
+from zope.configuration.xmlconfig import XMLConfig
+from zope.interface import Interface, implements
+from zope.publisher.browser import TestRequest
+from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.browsermenu.interfaces import IBrowserMenu
+from zope.security.interfaces import Unauthorized, Forbidden
+import zope.component
+
+import zope.security
+
+from zope.testing import cleanup
+
+import zope.browsermenu
+
+
+template = """<configure
+ xmlns='http://namespaces.zope.org/zope'
+ xmlns:browser='http://namespaces.zope.org/browser'
+ i18n_domain='zope'>
+ %s
+ </configure>"""
+
+class I1(Interface): pass
+class I11(I1): pass
+class I12(I1): pass
+class I111(I11): pass
+
+
+class C1(object):
+ implements(I1)
+
+class I2(Interface): pass
+
+class C2(object):
+ implements(I2)
+
+class TestObject(object):
+ implements(IBrowserPublisher, I111)
+
+ def f(self):
+ pass
+
+ def browserDefault(self, r):
+ return self, ()
+
+ def publishTraverse(self, request, name):
+ if name[:1] == 'f':
+ raise Forbidden(name)
+ if name[:1] == 'u':
+ raise Unauthorized(name)
+ return self.f
+
+class IMyLayer(Interface):
+ pass
+
+class IMySkin(IMyLayer, IDefaultBrowserLayer):
+ pass
+
+
+class TestPermissions(cleanup.CleanUp, unittest.TestCase):
+
+ def setUp(self):
+ super(TestPermissions, self).setUp()
+ XMLConfig('meta.zcml', zope.browsermenu)()
+ XMLConfig('meta.zcml', zope.security)()
+
+ def testMenuItemsPermission(self):
+ XMLConfig('tests/menus-permissions.zcml', zope.browsermenu)()
+
+ menu = zope.component.getUtility(IBrowserMenu, 'test_id')
+ # This is a bit icky, but the menu hides too much stuff from us.
+ items = zope.component.getAdapters((C2(), TestRequest()),
+ menu.getMenuItemType())
+ item = list(items)[0][1]
+ self.assertEquals("zope.View", item.permission)
+
+
+class Test(cleanup.CleanUp, unittest.TestCase):
+
+ def setUp(self):
+ super(Test, self).setUp()
+ XMLConfig('meta.zcml', zope.browsermenu)()
+
+ def testMenusAndMenuItems(self):
+ XMLConfig('tests/menus.zcml', zope.browsermenu)()
+
+ menu = zope.browsermenu.menu.getMenu(
+ 'test_id', TestObject(), TestRequest())
+
+ def d(n):
+ return {'action': "a%s" % n,
+ 'title': "t%s" % n,
+ 'description': u'',
+ 'selected': '',
+ 'submenu': None,
+ 'icon': None,
+ 'extra': None}
+
+ self.assertEqual(menu[:-1], [d(5), d(6), d(3), d(2), d(1)])
+ self.assertEqual(
+ menu[-1],
+ {'submenu': [{'submenu': None,
+ 'description': u'',
+ 'extra': None,
+ 'selected': u'',
+ 'action': u'a10',
+ 'title': u't10',
+ 'icon': None}],
+ 'description': u'',
+ 'extra': None,
+ 'selected': u'',
+ 'action': u'',
+ 'title': u's1',
+ 'icon': None})
+
+ first = zope.browsermenu.menu.getFirstMenuItem(
+ 'test_id', TestObject(), TestRequest())
+
+ self.assertEqual(first, d(5))
+
+ def testMenuItemWithLayer(self):
+ XMLConfig('tests/menus.zcml', zope.browsermenu)()
+
+ menu = zope.browsermenu.menu.getMenu(
+ 'test_id', TestObject(), TestRequest())
+ self.assertEqual(len(menu), 6)
+
+ menu = zope.browsermenu.menu.getMenu(
+ 'test_id', TestObject(), TestRequest(skin=IMyLayer))
+ self.assertEqual(len(menu), 2)
+
+ menu = zope.browsermenu.menu.getMenu(
+ 'test_id', TestObject(), TestRequest(skin=IMySkin))
+ self.assertEqual(len(menu), 8)
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(Test),
+ unittest.makeSuite(TestPermissions),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: zope.browsermenu/trunk/src/zope/browsermenu/tests/test_menudirectives.py
___________________________________________________________________
Added: svn:keywords
+ Id,svn:eol-style=native
More information about the Checkins
mailing list