[Checkins] SVN: zmi.core/trunk/src/zmi/core/component/ Copy browser code from zope.app.component.
Yusei Tahara
yusei at domen.cx
Sun Jun 7 11:24:17 EDT 2009
Log message for revision 100690:
Copy browser code from zope.app.component.
Changed:
A zmi.core/trunk/src/zmi/core/component/__init__.py
A zmi.core/trunk/src/zmi/core/component/configure.zcml
A zmi.core/trunk/src/zmi/core/component/ftesting.zcml
A zmi.core/trunk/src/zmi/core/component/registration.pt
A zmi.core/trunk/src/zmi/core/component/registration.py
A zmi.core/trunk/src/zmi/core/component/site.txt
A zmi.core/trunk/src/zmi/core/component/siteregistration.pt
A zmi.core/trunk/src/zmi/core/component/tests.py
-=-
Added: zmi.core/trunk/src/zmi/core/component/__init__.py
===================================================================
--- zmi.core/trunk/src/zmi/core/component/__init__.py (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/__init__.py 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,165 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""View support for adding and configuring utilities and adapters.
+
+$Id: __init__.py 94095 2008-12-16 07:43:39Z nadako $
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.component
+from zope.exceptions.interfaces import UserError
+from zope.security.proxy import removeSecurityProxy
+from zope.publisher.browser import BrowserView
+from zope.component.interfaces import IFactory
+from zope.component.interface import searchInterface
+from zope.location.interfaces import ISite
+
+from zope.app.component.i18n import ZopeMessageFactory as _
+from zope.app.component.site import LocalSiteManager
+from zmi.core.container.adding import Adding
+
+class ComponentAdding(Adding):
+ """Adding subclass used for registerable components."""
+
+ menu_id = "add_component"
+
+ def add(self, content):
+ # Override so as to save a reference to the added object
+ self.added_object = super(ComponentAdding, self).add(content)
+ return self.added_object
+
+ def nextURL(self):
+ v = zope.component.queryMultiAdapter(
+ (self.added_object, self.request), name="registration.html")
+ if v is not None:
+ url = str(zope.component.getMultiAdapter(
+ (self.added_object, self.request), name='absolute_url'))
+ return url + "/@@registration.html"
+
+ return super(ComponentAdding, self).nextURL()
+
+ def action(self, type_name, id=''):
+ # For special case of that we want to redirect to another adding view
+ # (usually another menu such as AddUtility)
+ if type_name.startswith("../"):
+ # Special case
+ url = type_name
+ if id:
+ url += "?id=" + id
+ self.request.response.redirect(url)
+ return
+
+ # Call the superclass action() method.
+ # As a side effect, self.added_object is set by add() above.
+ super(ComponentAdding, self).action(type_name, id)
+
+ _addFilterInterface = None
+
+ def addingInfo(self):
+ # A site management folder can have many things. We only want
+ # things that implement a particular interface
+ info = super(ComponentAdding, self).addingInfo()
+ if self._addFilterInterface is None:
+ return info
+ out = []
+ for item in info:
+ extra = item.get('extra')
+ if extra:
+ factoryname = extra.get('factory')
+ if factoryname:
+ factory = zope.component.getUtility(IFactory, factoryname)
+ intf = factory.getInterfaces()
+ if not intf.extends(self._addFilterInterface):
+ # We only skip new addMenuItem style objects
+ # that don't implement our wanted interface.
+ continue
+
+ out.append(item)
+
+ return out
+
+
+class UtilityAdding(ComponentAdding):
+ """Adding subclass used for adding utilities."""
+
+ menu_id = None
+ title = _("Add Utility")
+
+ def nextURL(self):
+ v = zope.component.queryMultiAdapter(
+ (self.added_object, self.request), name="addRegistration.html")
+ if v is not None:
+ url = zope.component.absoluteURL(self.added_object, self.request)
+ return url + "/@@addRegistration.html"
+
+ return super(UtilityAdding, self).nextURL()
+
+
+class MakeSite(BrowserView):
+ """View for converting a possible site to a site."""
+
+ def addSiteManager(self):
+ """Convert a possible site to a site
+
+ >>> from zope.traversing.interfaces import IContainmentRoot
+ >>> from zope.interface import implements
+
+ >>> class PossibleSite(object):
+ ... implements(IContainmentRoot)
+ ... def setSiteManager(self, sm):
+ ... from zope.interface import directlyProvides
+ ... directlyProvides(self, ISite)
+
+
+ >>> folder = PossibleSite()
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> request = TestRequest()
+
+ Now we'll make our folder a site:
+
+ >>> MakeSite(folder, request).addSiteManager()
+
+ Now verify that we have a site:
+
+ >>> ISite.providedBy(folder)
+ 1
+
+ Note that we've also redirected the request:
+
+ >>> request.response.getStatus()
+ 302
+
+ >>> request.response.getHeader('location')
+ '++etc++site/@@SelectedManagementView.html'
+
+ If we try to do it again, we'll fail:
+
+ >>> MakeSite(folder, request).addSiteManager()
+ Traceback (most recent call last):
+ ...
+ UserError: This is already a site
+
+ """
+ if ISite.providedBy(self.context):
+ raise UserError(_(u'This is already a site'))
+
+ # We don't want to store security proxies (we can't,
+ # actually), so we have to remove proxies here before passing
+ # the context to the SiteManager.
+ bare = removeSecurityProxy(self.context)
+ sm = LocalSiteManager(bare)
+ self.context.setSiteManager(sm)
+ self.request.response.redirect(
+ "++etc++site/@@SelectedManagementView.html")
Added: zmi.core/trunk/src/zmi/core/component/configure.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/component/configure.zcml (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/configure.zcml 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,140 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ >
+
+<!-- Registration Managemenet -->
+
+ <browser:page
+ for="*"
+ name="registration.html"
+ permission="zope.ManageSite"
+ class=".registration.RegistrationView"
+ />
+
+ <browser:menuItem
+ menu="zmi_views"
+ title="Registration"
+ for="*"
+ action="@@registration.html"
+ order="999"
+ />
+
+ <browser:page
+ for="*"
+ name="addRegistration.html"
+ permission="zope.ManageSite"
+ class=".registration.AddUtilityRegistration"
+ />
+
+ <adapter factory=".registration.UtilityRegistrationDisplay" />
+ <adapter factory=".registration.UtilitySiteRegistrationDisplay" />
+
+<!-- Site Management Folder -->
+
+ <browser:addMenuItem
+ class="zope.app.component.site.SiteManagementFolder"
+ permission="zope.ManageSite"
+ title="Site-Management Folder"
+ />
+
+ <browser:page
+ for="zope.app.component.interfaces.ISiteManagementFolder"
+ permission="zope.ManageSite"
+ class="zope.app.container.browser.contents.JustContents"
+ name="index.html" attribute="index"
+ />
+
+ <browser:page
+ name="contents.html"
+ for="zope.app.component.interfaces.ISiteManagementFolder"
+ menu="zmi_views" title="Contents"
+ permission="zope.ManageSite"
+ class="zope.app.container.browser.contents.Contents"
+ attribute="contents"
+ />
+
+ <browser:view
+ name="+"
+ menu="zmi_actions" title="Add"
+ for="zope.app.component.interfaces.ISiteManagementFolder"
+ permission="zope.ManageSite"
+ class="zope.app.component.browser.ComponentAdding"
+ >
+ <browser:page name="index.html" attribute="index" />
+ <browser:page name="action.html" attribute="action" />
+ </browser:view>
+
+<!-- Site Manager navigation action -->
+
+ <browser:page
+ for="zope.location.interfaces.IPossibleSite"
+ name="addSiteManager.html"
+ permission="zope.ManageSite"
+ class=".MakeSite"
+ attribute="addSiteManager"
+ />
+
+ <browser:menuItem
+ menu="zmi_actions" title="Make a site"
+ for="zope.location.interfaces.IPossibleSite"
+ action="@@addSiteManager.html"
+ filter="python:
+ not modules['zope.location.interfaces'].ISite.providedBy(context)"
+ permission="zope.ManageSite"
+ />
+
+ <browser:menuItem
+ menu="zmi_actions"
+ title="Manage Site"
+ for="zope.location.interfaces.ISite"
+ action="++etc++site/@@SelectedManagementView.html"
+ permission="zope.ManageSite"
+ />
+
+<!-- SiteManager -->
+
+ <browser:page
+ name="contents.html"
+ for="zope.app.component.interfaces.ILocalSiteManager"
+ menu="zmi_views" title="Contents"
+ permission="zope.ManageSite"
+ class="zope.app.container.browser.contents.Contents"
+ attribute="contents" />
+
+ <browser:view
+ name="+"
+ menu="zmi_actions" title="Add Site Management Folder"
+ for="zope.app.component.interfaces.ILocalSiteManager"
+ permission="zope.ManageSite"
+ class="zope.app.container.browser.adding.Adding"
+ >
+ <browser:page name="index.html" attribute="index"/>
+ <browser:page name="action.html" attribute="action"/>
+ </browser:view>
+
+ <browser:pages
+ for="zope.app.component.interfaces.ILocalSiteManager"
+ permission="zope.ManageSite"
+ class="zope.app.container.browser.contents.JustContents"
+ >
+ <browser:page name="index.html" attribute="index" />
+ </browser:pages>
+
+ <browser:page
+ for="zope.app.component.interfaces.ILocalSiteManager"
+ name="registrations.html"
+ menu="zmi_views" title="Registrations"
+ permission="zope.ManageSite"
+ class=".registration.SiteRegistrationView"
+ />
+
+ <browser:menuItem
+ menu="zmi_views" title="Registration"
+ for="zope.app.component.interfaces.ILocalSiteManager"
+ action="@@registration.html"
+ filter="python:False"
+ permission="zope.ManageSite"
+ />
+
+</configure>
Added: zmi.core/trunk/src/zmi/core/component/ftesting.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/component/ftesting.zcml (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/ftesting.zcml 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,15 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zope"
+ >
+
+ <include package="zope.app.component" file="ftesting.zcml"/>
+
+ <browser:addMenuItem
+ class="zmi.core.component.tests.Sample"
+ permission="zope.ManageSite"
+ title="Sample"
+ />
+
+</configure>
Added: zmi.core/trunk/src/zmi/core/component/registration.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/component/registration.pt (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/registration.pt 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,57 @@
+<html metal:use-macro="context/@@standard_macros/view"
+ i18n:domain="zope">
+<body>
+<div metal:fill-slot="body">
+
+ <form action="@@addRegistration.html" method="get"
+ tal:condition="not:view/registrations">
+ <p i18n:translate="">This object isn't yet registered.</p>
+ <input type="submit" value="Register this object"
+ i18n:attributes="value register-button" />
+ </form>
+
+ <tal:block tal:condition="view/registrations">
+ <form action="" method="post" tal:attributes="action request/URL">
+ <p i18n:translate="">
+ This object is registered:
+ </p>
+ <table>
+ <tr tal:repeat="registration view/registrations">
+ <td>
+ <input type="checkbox"
+ class="noborder" name="ids:list"
+ tal:attributes="value registration/id;
+ id registration/id;"
+ />
+ </td>
+ <td tal:define="info registration/render">
+ <tal:block content="info/info">
+ zope.app.fooIFoo utility named bob
+ </tal:block>
+ <tal:block condition="info/comment">
+ <br />
+ <tal:block content="info/comment">
+ comment: needed a bob
+ </tal:block>
+ </tal:block>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>
+ <input type="submit" value="Unregister" name="deactivate"
+ i18n:attributes="value unregister-button" />
+ </td>
+ </tr>
+ </table>
+ </form>
+
+ <form action="@@addRegistration.html" method="get">
+ <input type="submit" value="Register this object again"
+ i18n:attributes="value register-again-button" />
+ </form>
+ </tal:block>
+
+</div>
+</body>
+</html>
Added: zmi.core/trunk/src/zmi/core/component/registration.py
===================================================================
--- zmi.core/trunk/src/zmi/core/component/registration.py (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/registration.py 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,267 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""General registry-related views
+
+$Id: registration.py 73635 2007-03-26 15:47:22Z dobe $
+"""
+import warnings
+
+from zope import interface, component, schema
+from zope.formlib import form
+from zope.publisher.browser import BrowserPage
+from zope.security.proxy import removeSecurityProxy
+import zope.component.interfaces
+import zope.publisher.interfaces.browser
+
+import zope.app.pagetemplate
+from zope.app.component.i18n import ZopeMessageFactory as _
+
+
+def _registrations(context, comp):
+ sm = component.getSiteManager(context)
+ for r in sm.registeredUtilities():
+ if r.component == comp or comp is None:
+ yield r
+ for r in sm.registeredAdapters():
+ if r.factory == comp or comp is None:
+ yield r
+ for r in sm.registeredSubscriptionAdapters():
+ if r.factory == comp or comp is None:
+ yield r
+ for r in sm.registeredHandlers():
+ if r.factory == comp or comp is None:
+ yield r
+
+class IRegistrationDisplay(interface.Interface):
+ """Display registration information
+ """
+
+ def id():
+ """Return an identifier suitable for use in mapping
+ """
+
+ def render():
+ "Return an HTML view of a registration object"
+
+ def unregister():
+ "Remove the registration by unregistering the component"
+
+class ISiteRegistrationDisplay(IRegistrationDisplay):
+ """Display registration information, including the component registered
+ """
+
+class RegistrationView(BrowserPage):
+
+ component.adapts(None, zope.publisher.interfaces.browser.IBrowserRequest)
+
+ render = zope.app.pagetemplate.ViewPageTemplateFile('registration.pt')
+
+ def registrations(self):
+ registrations = [
+ component.getMultiAdapter((r, self.request), IRegistrationDisplay)
+ for r in sorted(_registrations(self.context, self.context))
+ ]
+ return registrations
+
+ def update(self):
+ registrations = dict([(r.id(), r) for r in self.registrations()])
+ for id in self.request.form.get('ids', ()):
+ r = registrations.get(id)
+ if r is not None:
+ r.unregister()
+
+ def __call__(self):
+ self.update()
+ return self.render()
+
+class UtilityRegistrationDisplay(object):
+ """Utility Registration Details"""
+
+ component.adapts(zope.component.interfaces.IUtilityRegistration,
+ zope.publisher.interfaces.browser.IBrowserRequest)
+ interface.implements(IRegistrationDisplay)
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def provided(self):
+ provided = self.context.provided
+ return provided.__module__ + '.' + provided.__name__
+
+ def id(self):
+ return 'R' + (("%s %s" % (self.provided(), self.context.name))
+ .encode('utf8')
+ .encode('base64')
+ .replace('+', '_')
+ .replace('=', '')
+ .replace('\n', '')
+ )
+
+ def _comment(self):
+ comment = self.context.info or ''
+ if comment:
+ comment = _("comment: ${comment}", mapping={"comment": comment})
+ return comment
+
+ def _provided(self):
+ name = self.context.name
+ provided = self.provided()
+ if name:
+ info = _("${provided} utility named '${name}'",
+ mapping={"provided": provided, "name": name})
+ else:
+ info = _("${provided} utility",
+ mapping={"provided": provided})
+ return info
+
+ def render(self):
+ return {
+ "info": self._provided(),
+ "comment": self._comment()
+ }
+
+ def unregister(self):
+ self.context.registry.unregisterUtility(
+ self.context.component,
+ self.context.provided,
+ self.context.name,
+ )
+
+class SiteRegistrationView(RegistrationView):
+
+ render = zope.app.pagetemplate.ViewPageTemplateFile('siteregistration.pt')
+
+ def registrations(self):
+ registrations = [
+ component.getMultiAdapter((r, self.request),
+ ISiteRegistrationDisplay)
+ for r in sorted(_registrations(self.context, None))
+ ]
+ return registrations
+
+class UtilitySiteRegistrationDisplay(UtilityRegistrationDisplay):
+ """Utility Registration Details"""
+
+ interface.implementsOnly(ISiteRegistrationDisplay)
+
+ def render(self):
+ url = component.getMultiAdapter(
+ (self.context.component, self.request), name='absolute_url')
+ try:
+ url = url()
+ except TypeError:
+ url = ""
+
+ cname = getattr(self.context.component, '__name__', '')
+ if not cname:
+ cname = _("(unknown name)")
+ if url:
+ url += "/@@SelectedManagementView.html"
+
+ return {
+ "cname": cname,
+ "url": url,
+ "info": self._provided(),
+ "comment": self._comment()
+ }
+
+class AddUtilityRegistration(form.Form):
+ """View for registering utilities
+
+ Normally, the provided interface and name are input.
+
+ A subclass can provide an empty 'name' attribute if the component should
+ always be registered without a name.
+
+ A subclass can provide a 'provided' attribute if a component
+ should always be registered with the same interface.
+
+ """
+ component.adapts(None, zope.publisher.interfaces.browser.IBrowserRequest)
+
+ form_fields = form.Fields(
+ schema.Choice(
+ __name__ = 'provided',
+ title=_("Provided interface"),
+ description=_("The interface provided by the utility"),
+ vocabulary="Utility Component Interfaces",
+ required=True,
+ ),
+ schema.TextLine(
+ __name__ = 'name',
+ title=_("Register As"),
+ description=_("The name under which the utility will be known."),
+ required=False,
+ default=u'',
+ missing_value=u''
+ ),
+ schema.Text(
+ __name__ = 'comment',
+ title=_("Comment"),
+ required=False,
+ default=u'',
+ missing_value=u''
+ ),
+ )
+
+ name = provided = None
+
+ prefix = 'field' # in hopes of making old tests pass. :)
+
+ def __init__(self, context, request):
+ if self.name is not None:
+ self.form_fields = self.form_fields.omit('name')
+ if self.provided is not None:
+ self.form_fields = self.form_fields.omit('provided')
+ super(AddUtilityRegistration, self).__init__(context, request)
+
+ def update(self):
+ # hack to make work with old tests
+ if 'UPDATE_SUBMIT' in self.request.form:
+ warnings.warn(
+ "Old test needs to be updated.",
+ DeprecationWarning)
+ self.request.form['field.actions.register'] = 'Register'
+ self.request.form['field.comment'] = u''
+ super(AddUtilityRegistration, self).update()
+
+ @property
+ def label(self):
+ return _("Register a $classname",
+ mapping=dict(classname=self.context.__class__.__name__)
+ )
+
+ @form.action(_("Register"))
+ def register(self, action, data):
+ sm = component.getSiteManager(self.context)
+ name = self.name
+ if name is None:
+ name = data['name']
+ provided = self.provided
+ if provided is None:
+ provided = data['provided']
+
+ # We have to remove the security proxy to save the registration
+ sm.registerUtility(
+ removeSecurityProxy(self.context),
+ provided, name,
+ data['comment'] or '')
+
+ if 'UPDATE_SUBMIT' in self.request.form:
+ # Backward compat until 3.5
+ self.request.response.redirect('@@SelectedManagementView.html')
+ return
+
+ self.request.response.redirect('@@registration.html')
Added: zmi.core/trunk/src/zmi/core/component/site.txt
===================================================================
--- zmi.core/trunk/src/zmi/core/component/site.txt (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/site.txt 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,44 @@
+Managing a Site
+---------------
+
+Create the browser object we'll be using.
+
+ >>> from zope.testbrowser.testing import Browser
+ >>> browser = Browser()
+ >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+ >>> browser.open('http://localhost/manage')
+
+When we originally enter a Zope instance, there is only a root folder that is
+already a site:
+
+ >>> 'Manage Site' in browser.contents
+ True
+
+Let's now add a new folder called ``samplesite`` and make it a site:
+
+ >>> browser.getLink(url='folder.Folder').click()
+ >>> browser.getControl(name='new_value').value = 'samplesite'
+ >>> browser.getControl('Apply').click()
+
+ >>> browser.getLink('samplesite').click()
+ >>> browser.getLink('Make a site').click()
+
+We are automatically forwarded to the site manager of the site. The default
+site management folder is always available:
+
+ >>> 'default' in browser.contents
+ True
+
+Let's now delete the site again:
+
+ >>> browser.getLink('[top]').click()
+ >>> browser.getControl(name='ids:list').getControl(
+ ... value='samplesite').selected = True
+
+ >>> browser.handleErrors = False
+ >>> browser.getControl('Delete').click()
+
+The site should be gone now.
+
+ >>> 'samplesite' in browser.contents
+ False
Property changes on: zmi.core/trunk/src/zmi/core/component/site.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: zmi.core/trunk/src/zmi/core/component/siteregistration.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/component/siteregistration.pt (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/siteregistration.pt 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,63 @@
+<html metal:use-macro="context/@@standard_macros/view"
+ i18n:domain="zope">
+<body>
+<div metal:fill-slot="body">
+<form tal:attributes="action request/URL"
+ method="POST"
+ >
+ <div tal:condition="not:view/registrations">
+ <p i18n:translate="">Nothing is registered for this site.</p>
+ </div>
+ <div tal:condition="view/registrations">
+ <p i18n:translate="">
+ Registrations for this site:
+ </p>
+ <table>
+ <tr tal:repeat="registration view/registrations">
+ <td>
+ <input type="checkbox"
+ class="noborder" name="ids:list"
+ tal:attributes="value registration/id;
+ id registration/id;
+ "
+ />
+ </td>
+ <td tal:define="info registration/render">
+ <tal:block condition="info/url">
+ <a href="foo/bar" tal:attributes="href info/url"
+ tal:content="info/cname">foo/bar</a>
+ </tal:block>
+ <tal:block condition="not: info/url"
+ i18n:translate="">
+ <tal:block i18n:name="name" content="info/cname">
+ foo/bar
+ </tal:block>
+ (moved or deleted)
+ </tal:block>
+ <br />
+ <tal:block content="info/info">
+ zope.app.fooIFoo utility named bob
+ </tal:block>
+ <tal:block condition="info/comment">
+ <br />
+ <tal:block content="info/comment">
+ comment: needed a bob
+ </tal:block>
+ </tal:block>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>
+ <input type="submit" value="Unregister" name="deactivate"
+ i18n:attributes="value unregister-button" />
+ </td>
+ </tr>
+ </table>
+ </div>
+
+</form>
+
+</div>
+</body>
+</html>
Added: zmi.core/trunk/src/zmi/core/component/tests.py
===================================================================
--- zmi.core/trunk/src/zmi/core/component/tests.py (rev 0)
+++ zmi.core/trunk/src/zmi/core/component/tests.py 2009-06-07 15:24:17 UTC (rev 100690)
@@ -0,0 +1,49 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Registration functional tests
+
+$Id: tests.py 92115 2008-10-13 13:18:24Z sidnei $
+"""
+import os.path
+import unittest
+import zope.app.testing.functional
+from zope import interface
+from zope.app.component.testing import AppComponentLayer
+from zope.app.testing import functional
+from zope.testing import doctest
+
+AppComponentBrowserLayer = functional.ZCMLLayer(
+ os.path.join(os.path.dirname(__file__), 'ftesting.zcml'),
+ __name__, 'AppComponentBrowserLayer', allow_teardown=True)
+
+class ISampleBase(interface.Interface):
+ pass
+
+class ISample(ISampleBase):
+ pass
+
+class Sample:
+ interface.implements(ISample)
+
+
+def test_suite():
+ site = zope.app.testing.functional.FunctionalDocFileSuite(
+ "site.txt",
+ optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE)
+ site.layer = AppComponentBrowserLayer
+ return unittest.TestSuite((site,))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
More information about the Checkins
mailing list