[Checkins] SVN: zc.site/trunk/src/zc/site/ Initial import. A
grab-bag that needs some rearrangement. Currently includes
zc.table columns useful for search results,
an "addLocalUtility" function that is currently a dependency for some
other packages, and some other bits.
Gary Poster
gary at zope.com
Tue Aug 15 17:23:28 EDT 2006
Log message for revision 69544:
Initial import. A grab-bag that needs some rearrangement. Currently includes zc.table columns useful for search results, an "addLocalUtility" function that is currently a dependency for some other packages, and some other bits.
Changed:
A zc.site/trunk/src/zc/site/__init__.py
A zc.site/trunk/src/zc/site/browser/
A zc.site/trunk/src/zc/site/browser/__init__.py
A zc.site/trunk/src/zc/site/browser/addSelect.pt
A zc.site/trunk/src/zc/site/browser/configure.zcml
A zc.site/trunk/src/zc/site/configure.zcml
A zc.site/trunk/src/zc/site/i18n.py
A zc.site/trunk/src/zc/site/search.py
A zc.site/trunk/src/zc/site/search.txt
A zc.site/trunk/src/zc/site/tests.py
A zc.site/trunk/src/zc/site/utils.py
-=-
Added: zc.site/trunk/src/zc/site/__init__.py
===================================================================
--- zc.site/trunk/src/zc/site/__init__.py 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/__init__.py 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1 @@
+#
Added: zc.site/trunk/src/zc/site/browser/__init__.py
===================================================================
--- zc.site/trunk/src/zc/site/browser/__init__.py 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/browser/__init__.py 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1 @@
+#
Added: zc.site/trunk/src/zc/site/browser/addSelect.pt
===================================================================
--- zc.site/trunk/src/zc/site/browser/addSelect.pt 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/browser/addSelect.pt 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,47 @@
+<metal:block define-macro="standard_add">
+ <tal:block define="adding nocall:context/@@+|nothing;"
+ condition="nocall:adding">
+ <span tal:define="addingInfo adding/addingInfo;" class="createSelect"
+ tal:condition="addingInfo"
+ i18n:domain="zc.site">
+ <span i18n:translate="">Create New:</span>
+ <tal:block
+ define="has_custom_add_view adding/hasCustomAddView;
+ names_required adding/nameAllowed"
+ condition="adding/isSingleMenuItem">
+ <tal:block define="info python:addingInfo[0];">
+ <input type="submit" name="container_add_button"
+ class="submit"
+ tal:attributes="value info/title" i18n:attributes="value" />
+ <input type="text" name="single_new_value" id="focusid"
+ tal:condition="python:names_required and not has_custom_add_view"
+ />
+ <input type="hidden" name="single_type_name"
+ value=""
+ tal:attributes="value info/action"
+ />
+ </tal:block>
+ </tal:block>
+ <tal:block condition="not: adding/isSingleMenuItem">
+ <script type="text/javascript">
+ function zcAddSelect(elem) {
+ var index = elem.selectedIndex;
+ var value = elem.options[index].value;
+ if (value) {
+ location.href = "@@+/action.html?type_name=" + value;
+ }
+ }
+ </script>
+ <select onchange="zcAddSelect(this);"
+ name="zc-addSelect-type" id="zc-addSelect-type">
+ <option value='' i18n:translate="">-- Select --</option>
+ <tal:block repeat="info addingInfo">
+ <option i18n:translate=""
+ tal:attributes="value info/action"
+ tal:content="info/title">Option</option>
+ </tal:block>
+ </select>
+ </tal:block>
+ </span>
+ </tal:block>
+</metal:block>
Added: zc.site/trunk/src/zc/site/browser/configure.zcml
===================================================================
--- zc.site/trunk/src/zc/site/browser/configure.zcml 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/browser/configure.zcml 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,14 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:zc="http://namespaces.zope.com/zc"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zc.site">
+
+<browser:page
+ for="*"
+ name="container_add"
+ permission="zope.Public"
+ template="addSelect.pt"
+ />
+
+</configure>
Added: zc.site/trunk/src/zc/site/configure.zcml
===================================================================
--- zc.site/trunk/src/zc/site/configure.zcml 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/configure.zcml 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,15 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+ <include package=".browser" />
+
+ <class class=".search.ReadStatusColumn">
+ <require
+ permission="zope.Public"
+ interface="zc.table.interfaces.IColumn
+ zc.table.interfaces.ISortableColumn"
+ />
+ </class>
+
+ <class class=".search.TypeColumn">
+ <require like_class=".search.ReadStatusColumn"/>
+ </class>
+</configure>
Added: zc.site/trunk/src/zc/site/i18n.py
===================================================================
--- zc.site/trunk/src/zc/site/i18n.py 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/i18n.py 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,32 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Visible Source
+# License, Version 1.0 (ZVSL). A copy of the ZVSL 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
+#
+##############################################################################
+"""I18N support for the site package.
+
+This defines a `MessageFactory` for the I18N domain for the site
+package. This is normally used with this import::
+
+ from i18n import MessageFactory as _
+
+The factory is then used normally. Two examples::
+
+ text = _('some internationalized text')
+ text = _('helpful-descriptive-message-id', 'default text')
+"""
+__docformat__ = "reStructuredText"
+
+
+from zope import i18nmessageid
+
+MessageFactory = _ = i18nmessageid.MessageFactory("zc.site")
Added: zc.site/trunk/src/zc/site/search.py
===================================================================
--- zc.site/trunk/src/zc/site/search.py 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/search.py 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,227 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Visible Source
+# License, Version 1.0 (ZVSL). A copy of the ZVSL 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.
+#
+##############################################################################
+"""
+Search support classes.
+
+These classes are used to support handling and presenting search
+results. Results must be sets of int ids.
+
+"""
+__docformat__ = "reStructuredText"
+
+import zope.i18n
+import zope.formlib.form
+import zope.copypastemove.interfaces
+
+from zope.app import zapi
+
+import zc.readcatalog.utils
+import zc.table.column
+
+from zc.site.i18n import _
+
+
+# Specialized column types
+
+UNKNOWN_TYPE = _('unknown_type-title', 'Unknown')
+
+
+class ReadStatusColumn(zc.table.column.SortingColumn):
+
+ def renderCell(self, item, formatter):
+ return zope.i18n.translate(
+ zc.readcatalog.utils.readStatus(
+ formatter.context.getObject(item),
+ formatter.request.principal.id))
+
+ getSortKey = renderCell
+
+
+class TypeColumn(zc.table.column.SortingColumn):
+
+ types = () # types should be sequence of (interface, message
+ # id) tuple pairs
+
+ unknown_type = UNKNOWN_TYPE
+
+ def __init__(self, title, types, name=None):
+ self.types = types
+ super(TypeColumn, self).__init__(title, name)
+
+ def renderCell(self, item, formatter):
+ obj = formatter.context.getObject(item)
+ for i, msg in self.types:
+ if i.providedBy(obj):
+ return zope.i18n.translate(msg,
+ default=msg,
+ context=formatter.request)
+ return zope.i18n.translate(self.unknown_type,
+ context=formatter.request)
+
+ getSortKey = renderCell
+
+
+class SelectionColumn(zc.table.column.SelectionColumn):
+
+ """Specialized selection column for use with search results.
+
+ This provides a default idgetter implementation suitable for use
+ with intids.
+
+ """
+
+ # It is important that the column selection provide only items that
+ # are in the search results. This ensures that security filters are
+ # honored and that objects cannot be accessed simply by crafting a
+ # request that references the int id of an object that should not be
+ # referencable by the current user.
+
+ # One expected improvement is to control whether the selection box
+ # for each item is enabled or disabled based on whether the object
+ # can be copied.
+
+ def __init__(self, idgetter=None, field=None, prefix=None, getter=None,
+ setter=None, title=None, name='', hide_header=False):
+ if idgetter is None:
+ idgetter = lambda item: "%s_selected" % item
+ super(SelectionColumn, self).__init__(
+ idgetter, field=field, prefix=prefix,
+ getter=getter, setter=setter, title=title, name=name,
+ hide_header=hide_header)
+
+
+# Action for use in forms:
+
+class CopySelectionError(zope.app.form.interfaces.WidgetInputError):
+
+ def __init__(self, msg):
+ zope.app.form.interfaces.WidgetInputError.__init__(
+ self, u"selected", u"Selected", msg)
+
+ def doc(self):
+ return self.errors
+
+class UncopyableSelectionError(CopySelectionError):
+ """Exception raised when an entry is selected that can't be copied."""
+
+class NoItemsSelectedError(CopySelectionError):
+ """Exception raised when no entry is selected for copying."""
+
+ def __init__(self):
+ CopySelectionError.__init__(
+ self, _("No items selected for copying."))
+
+
+class SelectionToClipboard(zope.formlib.form.Action):
+ """Action that can copy selected items to the clipboard.
+
+ The constructor needs to get the selection column that should be
+ used as the basis for determining which items to copy.
+
+ """
+
+ def __init__(self, *args, **kw):
+ """Initialize the action.
+
+ Additional keyword arguments are accepted:
+
+ `column` is the `SelectionColumn` that should be used as the
+ selection discriminator. This is required.
+
+ `items` is a callable that should be used to get the set of
+ items that needs to be passed to the selection column's
+ `getSelected()` method. The callable will be passed the form
+ as an argument. This is required.
+
+ `key` is the key that should be used in the data dictionary.
+ The default is 'selected-objects'.
+
+ """
+ self._selection_column = kw.pop("column")
+ self._selection_name = kw.pop("key", "selected-objects")
+ self._form_items = kw.pop("items")
+ if not kw.get("label"):
+ kw["label"] = _("zc-searchportlet-copy-selection-button",
+ default="Copy")
+ if not kw.get("name"):
+ kw["name"] = "copy"
+ super(SelectionToClipboard, self).__init__(*args, **kw)
+
+ def available(self):
+ # Only show this action if there is anything to select from.
+ items = self._form_items(self.form)
+ if not items:
+ return False
+ it = iter(items)
+ try:
+ it.next()
+ except StopIteration:
+ return False
+ else:
+ return True
+
+ def validate(self, data):
+ """Check that selected objects can be copied.
+
+ If any objects can't be copied, return
+ UncopyableSelectionError instances for each.
+
+ Add a list of selected, copyable objects to `data` using the
+ key passed to the constructor.
+
+ """
+ items = []
+ errors = []
+ selected = self._selection_column.getSelected(
+ self._form_items(self.form), self.form.request)
+
+ for uid in selected:
+ ob = self.form.getObject(uid)
+ copier = zope.copypastemove.interfaces.IObjectCopier(ob)
+ if copier.copyable():
+ items.append(ob)
+ else:
+ m = {"name": ob.__name__}
+ title = zope.app.container.browser.contents.getDCTitle(ob)
+ if title:
+ msg = _(
+ "Object '${name}' (${title}) cannot be copied")
+ m["title"] = title
+ else:
+ msg = _("Object '${name}' cannot be copied")
+ msg.mapping.update(m)
+ errors.append(UncopyableSelectionError(msg))
+ data[self._selection_name] = items
+ if not (errors or items):
+ # No errors, but no items selected:
+ errors.append(NoItemsSelectedError())
+ return errors
+
+ def success(self, data):
+ """Copy the selected objects to the clipboard."""
+ items = data[self._selection_name]
+ clipboard = zope.app.container.browser.contents.getPrincipalClipboard(
+ self.form.request)
+ clipboard.clearContents()
+ paths = [zapi.getPath(ob) for ob in items]
+ clipboard.addItems('copy', paths)
+ # Provide positive feedback that we've copied something;
+ # `paths` will not be empty since `validate()` returns an
+ # error in that case.
+ if len(paths) == 1:
+ self.form.status = _("One item copied to the clipboard.")
+ else:
+ self.form.status = _("${count} items copied to the clipboard.",
+ mapping={"count": str(len(paths))})
Added: zc.site/trunk/src/zc/site/search.txt
===================================================================
--- zc.site/trunk/src/zc/site/search.txt 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/search.txt 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,48 @@
+=======================================
+Copying Search Results to the Clipboard
+=======================================
+
+.. NOTE: This is all tutorial, not a test (for now).
+
+The `zc.site.search` module includes tools to support copying search
+results to the clipboard, which can be used for both portlet and
+non-portlet uses of searching. The support provided requires that
+search results are represented by sets of int ids and are presented
+using a table formatter based on `zc.table`.
+
+There are two pieces needed to make use of this support.
+
+A column of checkboxes is used to allow the user to select specific
+search results; this can be included in the column set for the table
+like any other column (though it is commonly placed first). This can
+be included very simply::
+
+ >>> import zc.searchportlet.portlet
+ >>> import zc.searchportlet.table
+ >>> import zc.searchportlet.view
+ >>> import zc.site.search
+
+ >>> class MySearchPortlet(zc.searchportlet.portlet.AbstractPortlet):
+ ... columns = (
+ ... zc.site.search.SelectionColumn(),
+ ... zc.searchportlet.table.TitleColumn(u'Title'),
+ ... )
+
+The form used to display and work with search results needs to have an
+action that checks the selection and performs the copy to the
+clipboard. The constructor for the action needs the column provided
+in the column set and a callable that can return the items in the
+result set as keyword arguments::
+
+ >>> class MySearchPortletNormalView(
+ ... zc.searchportlet.view.AbstractNormalView):
+ ...
+ ... # Make a copy of the base actions so we can modify it:
+ ... actions = zc.searchportlet.view.AbstractNormalView.actions[:]
+ ...
+ ... actions.append(
+ ... zc.site.search.SelectionToClipboard(
+ ... column=MySearchPortlet.columns[0],
+ ... items=lambda form: form.items))
+
+And that's all you need to support copying of search results.
Property changes on: zc.site/trunk/src/zc/site/search.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: zc.site/trunk/src/zc/site/tests.py
===================================================================
--- zc.site/trunk/src/zc/site/tests.py 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/tests.py 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Visible Source
+# License, Version 1.0 (ZVSL). A copy of the ZVSL 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.
+#
+##############################################################################
+"""site package test runner
+
+$$
+"""
+
+import unittest
+from zope.testing import doctest
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('search.txt'),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zc.site/trunk/src/zc/site/utils.py
===================================================================
--- zc.site/trunk/src/zc/site/utils.py 2006-08-15 21:19:32 UTC (rev 69543)
+++ zc.site/trunk/src/zc/site/utils.py 2006-08-15 21:23:27 UTC (rev 69544)
@@ -0,0 +1,36 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Visible Source
+# License, Version 1.0 (ZVSL). A copy of the ZVSL 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.
+#
+##############################################################################
+"""site utils
+
+$Id: utils.py 12899 2006-07-26 21:57:37Z benji $
+"""
+import zope.component.interfaces
+import zope.app.container.interfaces
+import zope.event
+import zope.lifecycleevent
+import zope.app.component.interfaces.registration
+
+# from a site, to get to the default package, the incantation is
+# site.getSiteManager()['default']
+
+def addLocalUtility(package, utility, interface=None,
+ name='', name_in_container='', comment=u''):
+ chooser = zope.app.container.interfaces.INameChooser(package)
+ name_in_container = chooser.chooseName(name_in_container, utility)
+ zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(utility))
+ package[name_in_container] = utility
+ # really want IComponentRegistry, but that is not set up in Zope 3 ATM
+ registry = zope.component.interfaces.IComponentLookup(package)
+ registry.registerUtility(utility, interface, name, comment)
More information about the Checkins
mailing list