跳转到主要内容

为Zope3提供的即用菜单

项目描述

本软件包提供了一个基于视图组件的“即用”菜单实现,适用于Zope 3。

即用菜单

z3c.menu.ready2go软件包提供了一个菜单实现,允许您基于内容提供者和视图组件实现菜单。

首先,让我们设置默认菜单项模板

>>> import os
>>> import zope.component
>>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
>>> from zope.publisher.interfaces.browser import IBrowserView
>>> from z3c.template.interfaces import IContentTemplate
>>> from z3c.template.template import TemplateFactory
>>> import z3c.menu.ready2go
>>> baseDir = os.path.split(z3c.menu.ready2go.__file__)[0]
>>> itemTemplate = os.path.join(baseDir, 'item.pt')
>>> itemTemplateFactory = TemplateFactory(itemTemplate, 'text/html')
>>> zope.component.provideAdapter(itemTemplateFactory,
...     (IBrowserView, IDefaultBrowserLayer), IContentTemplate)

上下文菜单项

现在我们为我们的IContextMenu注册一个上下文菜单项。

>>> import zope.component
>>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
>>> from z3c.menu.ready2go.item import ContextMenuItem
>>> class MyContextMenuItem(ContextMenuItem):
...     viewName = 'context.html'
...     weight = 1

现在我们需要为我们的菜单项设置安全检查器。

>>> from zope.security.checker import NamesChecker, defineChecker
>>> viewletChecker = NamesChecker(('update', 'render'))
>>> defineChecker(MyContextMenuItem, viewletChecker)

然后我们为IContextMenu配置我们的菜单项。这通常是通过viewlet ZCML指令完成的。

>>> zope.component.provideAdapter(
...     MyContextMenuItem,
...     (zope.interface.Interface, IDefaultBrowserLayer,
...     IBrowserView, IContextMenu),
...     IViewlet, name='My Context')

现在让我们再次渲染上下文菜单。你可以看到我们有一个菜单项。另一个重要点是,此类上下文菜单项实现的URL指向视图的上下文。

>>> contextMenu.update()
>>> print(contextMenu.render())
<li>
  <a href="http://127.0.0.1/site/content/context.html"><span>My Context</span></a>
</li>

让我们将视图__name__设置为context.html。这将表明视图提供了与我们的上下文菜单需要渲染的所选名称相同的名称。

>>> view.__name__ = 'context.html'

现在再次尝试,看看上下文菜单项是否以选中状态渲染。

>>> contextMenu.update()
>>> print(contextMenu.render())
<li class="selected">
  <a href="http://127.0.0.1/site/content/context.html"><span>My Context</span></a>
</li>

此外,让我们检查即使我们提供了@@context.html表单中的viewName,菜单项是否也标记为选中。

>>> MyContextMenuItem.viewName = '@@context.html'
>>> contextMenu.update()
>>> print(contextMenu.render())
<li class="selected">
  <a href="http://127.0.0.1/site/content/@@context.html"><span>My Context</span></a>
</li>

好的,将viewName改回context.html,以便进行进一步测试。

>>> MyContextMenuItem.viewName = 'context.html'

现在添加第二个上下文菜单项,并检查我们是否可以使用通常为空字符串的cssInActive参数。

>>> class InActiveMenuItem(ContextMenuItem):
...     viewName = 'inActive.html'
...     cssInActive = 'inActive'
...     weight = 2
>>> defineChecker(InActiveMenuItem, viewletChecker)
>>> zope.component.provideAdapter(
...     InActiveMenuItem,
...     (zope.interface.Interface, IDefaultBrowserLayer,
...     IBrowserView, IContextMenu),
...     IViewlet, name='In Active')

现在更新并再次渲染。

>>> contextMenu.update()
>>> print(contextMenu.render())
<li class="selected">
  <a href="http://127.0.0.1/site/content/context.html"><span>My Context</span></a>
</li>
<li class="inActive">
  <a href="http://127.0.0.1/site/content/inActive.html"><span>In Active</span></a>
</li>

添加菜单

添加菜单可用于为每个上下文提供任何类型的添加表单的链接。这允许我们提供独立的添加表单链接,不管使用的是哪个表单框架。现在让我们定义一个简单的指向添加表单URL的AddMenuItem。注意;添加表单及其URL在此测试中不存在。这也意味着如果配置了添加菜单项,不能保证存在表单。

>>> from z3c.menu.ready2go.item import AddMenuItem
>>> class MyAddMenuItem(AddMenuItem):
...
...     viewName = 'addSomething.html'

现在我们需要为我们的菜单项设置安全检查器。

>>> from zope.security.checker import NamesChecker, defineChecker
>>> viewletChecker = NamesChecker(('update', 'render'))
>>> defineChecker(MyAddMenuItem, viewletChecker)

然后我们为IAddMenu配置我们的菜单项。这通常是通过viewlet ZCML指令完成的。

>>> zope.component.provideAdapter(
...     MyAddMenuItem,
...     (zope.interface.Interface, IDefaultBrowserLayer,
...     IBrowserView, IAddMenu),
...     IViewlet, name='My AddMenu')

现在我们可以更新并渲染我们的添加菜单。

>>> addMenu.update()
>>> print(addMenu.render())
<li>
  <a href="http://127.0.0.1/site/content/addSomething.html"><span>My AddMenu</span></a>
</li>

EmptyMenuManager

有一个空的菜单管理器,可以用来覆盖现有的菜单管理器。

>>> from z3c.menu.ready2go.manager import EmptyMenuManager
>>> emptyMenu = EmptyMenuManager(None, None, None)

我们的空菜单管理器实现了IMenuManager

>>> interfaces.IMenuManager.providedBy(emptyMenu)
True

这个空菜单管理器在渲染时始终返回空字符串。

>>> emptyMenu.update()
>>> emptyMenu.render()
''

特殊用途案例

由于Zope的内部机制,我们有一些特殊的用例。其中一个重要部分是,我们的菜单高度依赖于上下文及其到Zope应用程序根的__parent__链。这不是Zope默认设置所支持的。一部分是集成不良的应用程序控制部分,它伪造了一个根对象,这个根对象不知道从ZODB的真实根(例如应用程序根)的真实子对象。现在我们将向您展示,如果得到这样一个伪造的根,我们的菜单默认不会显示任何项目,这会破坏我们的菜单结构。

让我们定义一个不知道任何__parent__的对象。

>>> nirvana = Content()
>>> nirvanaView = View(nirvana, request)

现在我们可以检查在将无父对象的环境上下文更新并渲染菜单后,菜单会发生什么。您可以看到,全局菜单不包含任何菜单项。这是因为全局菜单项试图通过上下文到根的__parent__链遍历以找到根,而我们不支持我们的无父对象中的任何父对象。

>>> globalMenu = GlobalMenu(nirvana, request, nirvanaView)
>>> globalMenu.update()
>>> globalMenu.render()
''

由于无父对象,SiteMenu也不包含任何菜单项。

>>> siteMenu = SiteMenu(nirvana, request, nirvanaView)
>>> siteMenu.update()
>>> siteMenu.render()
''
>>> contextMenu = ContextMenu(nirvana, request, nirvanaView)
>>> contextMenu.update()
>>> contextMenu.render()
''
>>> addMenu = AddMenu(nirvana, request, nirvanaView)
>>> addMenu.update()
>>> addMenu.render()
''

Z3C菜单指令

展示如何使用菜单指令。注册指令的元配置。

首先,让我们设置我们的默认菜单项模板。

>>> import os
>>> import zope.component
>>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
>>> from zope.publisher.interfaces.browser import IBrowserView
>>> from z3c.template.interfaces import IContentTemplate
>>> from z3c.template.template import TemplateFactory
>>> import z3c.menu.ready2go
>>> baseDir = os.path.split(z3c.menu.ready2go.__file__)[0]
>>> itemTemplate = os.path.join(baseDir, 'item.pt')
>>> itemTemplateFactory = TemplateFactory(itemTemplate, 'text/html')
>>> zope.component.provideAdapter(itemTemplateFactory,
...     (IBrowserView, IDefaultBrowserLayer), IContentTemplate)
>>> import sys
>>> from zope.configuration import xmlconfig
>>> import z3c.menu.ready2go
>>> context = xmlconfig.file('meta.zcml', z3c.menu.ready2go)

我们需要注册我们的检查适配器,该适配器可以检查菜单项是否被选中。

>>> import zope.component
>>> from z3c.menu.ready2go import checker
>>> zope.component.provideAdapter(checker.ContextSelectedChecker)

让我们定义一个内容对象。

>>> from z3c.menu.ready2go import testing
>>> sampleContent = testing.Sample('Sample Content')

现在将内容对象添加到我们的站点根。

>>> root['sample'] = sampleContent

现在我们可以定义我们的测试菜单管理器。

>>> from zope.viewlet.manager import ViewletManager
>>> from z3c.menu.ready2go import manager
>>> FirstMenu = ViewletManager('left', testing.IFirstMenu,
...     bases=(manager.MenuManager,))
>>> SecondMenu = ViewletManager('left', testing.ISecondMenu,
...     bases=(manager.MenuManager,))

我们还需要一个了解其父级的视图。

>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> firstView = testing.FirstView(sampleContent, request)
>>> testing.IFirstView.providedBy(firstView)
True
>>> secondView = testing.SecondView(sampleContent, request)
>>> testing.ISecondView.providedBy(secondView)
True

如您所见,如果访问页面,菜单不会被选中。

>>> firstMenu = FirstMenu(sampleContent, request, firstView)
>>> testing.IFirstMenu.providedBy(firstMenu)
True
>>> firstMenu.update()
>>> firstMenu.render()
''
>>> secondMenu = SecondMenu(sampleContent, request, secondView)
>>> testing.ISecondMenu.providedBy(secondMenu)
True
>>> secondMenu.update()
>>> secondMenu.render()
''

现在我们需要为第一个菜单一些菜单项。

>>> from zope.publisher.interfaces.browser import IBrowserView
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from zope.viewlet.interfaces import IViewlet
>>> zope.component.provideAdapter(
...     testing.FirstMenuItem,
...     (zope.interface.Interface, IBrowserRequest,
...     IBrowserView, testing.IFirstMenu),
...     IViewlet, name='First Menu')
>>> zope.component.provideAdapter(
...     testing.SecondMenuItem,
...     (zope.interface.Interface, IBrowserRequest,
...     IBrowserView, testing.IFirstMenu),
...     IViewlet, name='Second Menu')

我们需要为第二个菜单一些菜单项。

>>> zope.component.provideAdapter(
...     testing.FirstMenuItem,
...     (zope.interface.Interface, IBrowserRequest,
...     IBrowserView, testing.ISecondMenu),
...     IViewlet, name='First Menu')
>>> zope.component.provideAdapter(
...     testing.SecondMenuItem,
...     (zope.interface.Interface, IBrowserRequest,
...     IBrowserView, testing.ISecondMenu),
...     IViewlet, name='Second Menu')

现在再次渲染菜单管理器,您可以看到我们得到了一些菜单项。但是您可以看到这些菜单项没有被选中。

>>> firstMenu = FirstMenu(sampleContent, request, firstView)
>>> firstMenu.update()
>>> print(firstMenu.render())
<li>
  <a><span>First Menu</span></a>
</li>
<li>
  <a><span>Second Menu</span></a>
</li>
>>> secondMenu = SecondMenu(sampleContent, request, firstView)
>>> secondMenu.update()
>>> print(secondMenu.render())
<li>
  <a><span>First Menu</span></a>
</li>
<li>
  <a><span>Second Menu</span></a>
</li>

现在我们可以为我们的页面注册一个菜单选择器,如果我们访问页面,则将其渲染为选中状态。

>>> context = xmlconfig.string("""
... <configure
...     xmlns:z3c="http://namespaces.zope.org/z3c">
...   <z3c:menuSelector
...       view=".testing.IFirstView"
...       manager=".testing.IFirstMenu"
...       menu=".testing.FirstMenuItem"
...       />
... </configure>
... """, context)

在为第一个视图和第一个菜单注册了菜单选择器后,我们将看到第一个菜单在第一个菜单上被渲染为选中状态。

>>> firstMenu = FirstMenu(sampleContent, request, firstView)
>>> firstMenu.update()
>>> print(firstMenu.render())
<li class="selected">
  <a><span>First Menu</span></a>
</li>
<li>
  <a><span>Second Menu</span></a>
</li>

但不在第二个菜单上。

>>> secondMenu = SecondMenu(sampleContent, request, firstView)
>>> secondMenu.update()
>>> print(secondMenu.render())
<li>
  <a><span>First Menu</span></a>
</li>
<li>
  <a><span>Second Menu</span></a>
</li>

变更记录

2.0 (2023-02-07)

  • 支持Python 3.8、3.9、3.10、3.11。

  • 放弃对Python 2.7、3.5、3.6的支持。

  • 放弃对已弃用的python setup.py test的支持。

1.1.0 (2018-10-09)

  • 支持Python 3.7。

  • 删除所有弃用警告。

1.0.0 (2017-04-17)

  • 将Python支持锁定在2.7、3.5、3.6和PyPy上。

1.0.0a1 (2013-03-03)

  • 添加了对Python 3.3的支持。

  • 由于zope.testbrowser尚未移植,将zope.testbrowser测试更改为WebTest

  • 将已弃用的zope.interface.implements使用替换为等效的zope.interface.implementer装饰器。

  • 放弃对Python 2.4和2.5的支持。

0.8.0 (2010-07-12)

  • zope.app.pagetemplate测试依赖项替换为zope.browserpage,因为所需的metaconfigure.registerType最近已移至那里,而没有留下BBB导入。

0.7.1 (2009-12-26)

  • 通过声明z3c MessageFactory本地,取消对z3c.i18n的依赖。

  • 使用python doctest模块代替已弃用的zope.testing.doctestunit

0.7.0 (2009-11-30)

  • 调整依赖项和导入,以反映zope包的变化。

0.6.0 (2009-02-07)

  • zope.app.component替换为zope.site

  • zope.app.container替换为zope.container

  • zope.app.pagetemplate仅是一个测试依赖项。

0.5.1 (2009-01-04)

  • 添加了对以@@开头的viewNames的支持。现在它们被ViewNameSelectedChecker正确处理。

  • 在Pypi主页上添加了文档。

0.5.0 (2008-04-11)

  • bugfix:修复了cssInActive的使用。这已被破坏,并导致不使用cssInActive CSS类参数。

  • 增加了更多测试,现在覆盖率达到100%

  • 使ISiteMenu仅对ISite有效,而不是对IContainmentRoot有效

  • 使用z3c.template模式使模板可插拔

  • 初始发布

项目详情


下载文件

下载适合您平台的应用程序文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源代码分发

z3c.menu.ready2go-2.0.tar.gz (26.5 kB 查看哈希值)

上传时间 源代码

构建分发

z3c.menu.ready2go-2.0-py3-none-any.whl (27.3 kB 查看哈希值)

上传时间 Python 3

支持