[CMF-checkins] SVN: CMF/trunk/CMFDefault/ viewification,
part 1 (merging from tseaver-viewification branch):
Yvo Schubbe
y.2006_ at wcm-solutions.de
Tue Feb 21 11:23:54 EST 2006
Log message for revision 41740:
viewification, part 1 (merging from tseaver-viewification branch):
- added 'decode' and 'memoize' decorator methods to utils
- added form utilities (FormViewBase, form_widget macros)
- added batch utilities (BatchViewBase, batch_widget macros)
- added folder views (index_html, folder_contents)
- added README.txt and TODO.txt
Changed:
A CMF/trunk/CMFDefault/browser/
A CMF/trunk/CMFDefault/browser/README.txt
A CMF/trunk/CMFDefault/browser/TODO.txt
A CMF/trunk/CMFDefault/browser/__init__.py
A CMF/trunk/CMFDefault/browser/configure.zcml
A CMF/trunk/CMFDefault/browser/folder.py
A CMF/trunk/CMFDefault/browser/templates/
A CMF/trunk/CMFDefault/browser/templates/batch_widgets.pt
A CMF/trunk/CMFDefault/browser/templates/folder.pt
A CMF/trunk/CMFDefault/browser/templates/folder_contents.pt
A CMF/trunk/CMFDefault/browser/templates/form_widgets.pt
A CMF/trunk/CMFDefault/browser/utils.py
U CMF/trunk/CMFDefault/configure.zcml
-=-
Added: CMF/trunk/CMFDefault/browser/README.txt
===================================================================
--- CMF/trunk/CMFDefault/browser/README.txt 2006-02-21 15:45:07 UTC (rev 41739)
+++ CMF/trunk/CMFDefault/browser/README.txt 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,25 @@
+Experimental Browser Views
+
+ This sub-package provides Zope 3-style browser views for some CMF content
+ interfaces. The views are disabled by default.
+
+ The content of this sub-package is experimental and might be refactored
+ without further notice. Documentation and unittests are still missing but
+ the views should work just as well as the corresponding skin methods.
+
+ See TODO.txt for a detailed list of converted skin methods.
+
+ Enabling the Browser Views
+
+ Either add this directive to your own ZCML files::
+
+ <include package="Products.CMFDefault.browser"/>
+
+ Or uncomment the include directive in CMFDefault's main configure.zcml.
+
+ Using the Browser Views
+
+ In an un-customized CMFDefault site you will notice no difference because
+ the browser views are just different in implementation, not in look and
+ feel. But the browser view machinery bypasses the CMF skin machinery, so
+ you will notice that TTW customizations no longer have any effect.
Property changes on: CMF/trunk/CMFDefault/browser/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: CMF/trunk/CMFDefault/browser/TODO.txt
===================================================================
--- CMF/trunk/CMFDefault/browser/TODO.txt 2006-02-21 15:45:07 UTC (rev 41739)
+++ CMF/trunk/CMFDefault/browser/TODO.txt 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,115 @@
+Converting skins to views:
+
+ [x] batch_widget:
+
+ batch_widgets.pt -> templates/batch_widgets.pt
+ getBatchItemInfos.py -> BatchViewBase.listItemInfos
+ getBatchNavigation.py -> BatchViewBase.navigation_previous
+ BatchViewBase.navigation_next
+
+ [x] form_widget:
+
+ form_widgets.pt -> templates/form_widgets.pt
+
+ [x] index_html:
+
+ index_html.py -> FolderView
+ index_html_template.pt -> folder.pt
+
+ [x] folder_contents:
+
+ folder_contents.py -> FolderContentsView
+ folder_contents_template.pt -> templates/folder_contents.pt
+ validateItemIds.py -> FolderContentsView.validateItemIds
+ validateClipboardData.py -> FolderContentsView.validateClipboardData
+ folder_cut_control.py -> FolderContentsView.cut_control
+ folder_copy_control.py -> FolderContentsView.copy_control
+ folder_paste_control.py -> FolderContentsView.paste_control
+ folder_delete_control.py -> FolderContentsView.delete_control
+ folder_sort_control.py -> FolderContentsView.sort_control
+ folder_up_control.py -> FolderContentsView.up_control
+ folder_down_control.py -> FolderContentsView.down_control
+ folder_top_control.py -> FolderContentsView.top_control
+ folder_bottom_control.py -> FolderContentsView.bottom_control
+
+ [ ] folder_edit_form:
+
+ folder_edit_form.py -> MetadataMinimalEditView
+ folder_edit_template.pt -> templates/metadata_minimal_edit.pt
+ folder_edit_control.py -> MetadataMinimalEditView.edit_control
+
+ [ ] metadata_edit_form:
+
+ metadata_edit_form.py -> MetadataEditView
+ metadata_edit_template.pt -> templates/metadata_edit.pt
+ metadata_edit_control.py -> MetadataEditView.edit_control
+
+ [ ] full_metadata_edit_form:
+
+ full_metadata_edit_form.py -> MetadataEditView
+ full_metadata_edit_template.pt -> templates/metadata_full_edit.pt
+ metadata_edit_control.py -> MetadataEditView.edit_control
+
+ [ ] document_view:
+
+ document_view.py -> DocumentView
+ document_view_template.pt -> document.pt
+
+ [ ] document_edit_form:
+
+ document_edit_form.py -> DocumentEditView
+ document_edit_template.pt -> templates/document_edit.pt
+ validateHTML.py -> DocumentEditView.validateHTML
+ validateTextFile.py -> DocumentEditView.validateTextFile
+ document_edit_control.py -> DocumentEditView.edit_control
+
+ [ ] newsitem_view:
+
+ newsitem_view.py -> DocumentView
+ document_view_template.pt -> document.pt
+
+ [ ] newsitem_edit_form:
+
+ newsitem_edit_form.py -> NewsItemEditView
+ newsitem_edit_template.pt -> templates/newsitem_edit.pt
+ validateHTML.py -> DocumentEditView.validateHTML
+ validateTextFile.py -> DocumentEditView.validateTextFile
+ newsitem_edit_control.py -> NewsItemEditView.edit_control
+
+ [ ] link_view:
+
+ link_view.py -> LinkView
+ link_view_template.pt -> templates/link.pt
+
+ [ ] link_edit_form:
+
+ link_edit_form.py -> LinkEditView
+ link_edit_template.pt -> templates/link_edit.pt
+ link_edit_control.py -> LinkEditView.edit_control
+
+ [ ] favorite_view:
+
+ favorite_view.py -> LinkView
+ link_view_template.pt -> templates/link.pt
+
+ [ ] file_view:
+
+ file_view.py -> FileView
+ file_view_template.pt -> templates/file.pt
+
+ [ ] file_edit_form:
+
+ file_edit_form.py -> FileEditView
+ file_edit_template.pt -> templates/file_edit.pt
+ file_edit_control.py -> FileEditView.edit_control
+
+ [ ] image_view:
+
+ image_view.py -> ImageView
+ image_view_template.pt -> templates/image.pt
+
+ [ ] image_edit_form:
+
+ image_edit_form.py -> ImageEditView
+ image_edit_template.pt -> templates/image_edit.pt
+ image_edit_control.py -> ImageEditView.edit_control
Property changes on: CMF/trunk/CMFDefault/browser/TODO.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: CMF/trunk/CMFDefault/browser/__init__.py
===================================================================
--- CMF/trunk/CMFDefault/browser/__init__.py 2006-02-21 15:45:07 UTC (rev 41739)
+++ CMF/trunk/CMFDefault/browser/__init__.py 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""CMFDefault browser views.
+
+$Id$
+"""
Property changes on: CMF/trunk/CMFDefault/browser/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: CMF/trunk/CMFDefault/browser/configure.zcml
===================================================================
--- CMF/trunk/CMFDefault/browser/configure.zcml 2006-02-21 15:45:07 UTC (rev 41739)
+++ CMF/trunk/CMFDefault/browser/configure.zcml 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,42 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:five="http://namespaces.zope.org/five">
+
+ <five:traversable class="Products.CMFCore.PortalFolder.PortalFolder"/>
+
+ <browser:page
+ for="Products.CMFCore.interfaces.IFolderish"
+ name="index_html"
+ class=".folder.FolderView"
+ template="templates/folder.pt"
+ permission="zope2.View"
+ layer="cmf"
+ />
+
+ <browser:page
+ for="Products.CMFCore.interfaces.IFolderish"
+ name="folder_contents"
+ class=".folder.FolderContentsView"
+ template="templates/folder_contents.pt"
+ permission="cmf.ListFolderContents"
+ layer="cmf"
+ />
+
+ <browser:page
+ for="*"
+ name="form_widget"
+ template="templates/form_widgets.pt"
+ permission="zope2.View"
+ layer="cmf"
+ />
+
+ <browser:page
+ for="*"
+ name="batch_widget"
+ template="templates/batch_widgets.pt"
+ permission="zope2.View"
+ layer="cmf"
+ />
+
+</configure>
Property changes on: CMF/trunk/CMFDefault/browser/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: CMF/trunk/CMFDefault/browser/folder.py
===================================================================
--- CMF/trunk/CMFDefault/browser/folder.py 2006-02-21 15:45:07 UTC (rev 41739)
+++ CMF/trunk/CMFDefault/browser/folder.py 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,400 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Browser views for folders.
+
+$Id$
+"""
+
+from DocumentTemplate import sequence
+from ZTUtils import LazyFilter
+from ZTUtils import make_query
+
+from Products.CMFDefault.exceptions import CopyError
+from Products.CMFDefault.exceptions import zExceptions_Unauthorized
+from Products.CMFDefault.permissions import AddPortalContent
+from Products.CMFDefault.permissions import DeleteObjects
+from Products.CMFDefault.permissions import ListFolderContents
+from Products.CMFDefault.permissions import ManageProperties
+from Products.CMFDefault.permissions import ViewManagementScreens
+from Products.CMFDefault.utils import Message as _
+
+from utils import BatchViewBase
+from utils import decode
+from utils import FormViewBase
+from utils import memoize
+
+
+class FolderView(BatchViewBase):
+
+ """View for IFolderish.
+ """
+
+ # helpers
+
+ @memoize
+ def _getItems(self):
+ (key, reverse) = self.context.getDefaultSorting()
+ items = self.context.contentValues()
+ items = sequence.sort(items,
+ ((key, 'cmp', reverse and 'desc' or 'asc'),))
+ return LazyFilter(items, skip='View')
+
+ # interface
+
+ @memoize
+ def has_local(self):
+ return 'local_pt' in self.context.objectIds()
+
+
+class FolderContentsView(BatchViewBase, FormViewBase):
+
+ """Contents view for IFolderish.
+ """
+
+ _BUTTONS = ({'id': 'items_new',
+ 'title': _(u'New...'),
+ 'permissions': (ViewManagementScreens, AddPortalContent),
+ 'conditions': ('checkAllowedContentTypes',),
+ 'redirect': ('portal_types', 'object/new')},
+ {'id': 'items_rename',
+ 'title': _(u'Rename...'),
+ 'permissions': (ViewManagementScreens, AddPortalContent),
+ 'conditions': ('checkItems', 'checkAllowedContentTypes'),
+ 'transform': ('validateItemIds',),
+ 'redirect': ('portal_types', 'object/rename_items',
+ 'b_start, ids, key, reverse')},
+ {'id': 'items_cut',
+ 'title': _(u'Cut'),
+ 'permissions': (ViewManagementScreens,),
+ 'conditions': ('checkItems',),
+ 'transform': ('validateItemIds', 'cut_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')},
+ {'id': 'items_copy',
+ 'title': _(u'Copy'),
+ 'permissions': (ViewManagementScreens,),
+ 'conditions': ('checkItems',),
+ 'transform': ('validateItemIds', 'copy_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')},
+ {'id': 'items_paste',
+ 'title': _(u'Paste'),
+ 'permissions': (ViewManagementScreens, AddPortalContent),
+ 'conditions': ('checkClipboardData',),
+ 'transform': ('validateClipboardData', 'paste_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')},
+ {'id': 'items_delete',
+ 'title': _(u'Delete'),
+ 'permissions': (ViewManagementScreens, DeleteObjects),
+ 'conditions': ('checkItems',),
+ 'transform': ('validateItemIds', 'delete_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')},
+ {'id': 'items_sort',
+ 'permissions': (ManageProperties,),
+ 'transform': ('sort_control',),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start')},
+ {'id': 'items_up',
+ 'permissions': (ManageProperties,),
+ 'transform': ('validateItemIds', 'up_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')},
+ {'id': 'items_down',
+ 'permissions': (ManageProperties,),
+ 'transform': ('validateItemIds', 'down_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')},
+ {'id': 'items_top',
+ 'permissions': (ManageProperties,),
+ 'transform': ('validateItemIds', 'top_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')},
+ {'id': 'items_bottom',
+ 'permissions': (ManageProperties,),
+ 'transform': ('validateItemIds', 'bottom_control'),
+ 'redirect': ('portal_types', 'object/folderContents',
+ 'b_start, key, reverse')})
+
+ # helpers
+
+ @memoize
+ def _getSorting(self):
+ key = self.request.form.get('key', None)
+ if key:
+ return (key, self.request.form.get('reverse', 0))
+ else:
+ return self.context.getDefaultSorting()
+
+ @memoize
+ def _isDefaultSorting(self):
+ return self._getSorting() == self.context.getDefaultSorting()
+
+ @memoize
+ def _getHiddenVars(self):
+ b_start = self._getBatchStart()
+ is_default = self._isDefaultSorting()
+ (key, reverse) = is_default and ('', 0) or self._getSorting()
+ return {'b_start': b_start, 'key': key, 'reverse': reverse}
+
+ @memoize
+ def _getItems(self):
+ (key, reverse) = self._getSorting()
+ self.context.filterCookie()
+ folderfilter = self.request.get('folderfilter', '')
+ filter = self.context.decodeFolderFilter(folderfilter)
+ items = self.context.listFolderContents(contentFilter=filter)
+ return sequence.sort(items,
+ ((key, 'cmp', reverse and 'desc' or 'asc'),))
+
+ # interface
+
+ @memoize
+ @decode
+ def up_info(self):
+ mtool = self._getTool('portal_membership')
+ allowed = mtool.checkPermission(ListFolderContents, self.context,
+ 'aq_parent')
+ if allowed:
+ up_obj = self.context.aq_inner.aq_parent
+ if hasattr(up_obj, 'portal_url'):
+ up_url = up_obj.getActionInfo('object/folderContents')['url']
+ return {'icon': '%s/UpFolder_icon.gif' % self._getPortalURL(),
+ 'id': up_obj.getId(),
+ 'url': up_url}
+ else:
+ return {'icon': '',
+ 'id': 'Root',
+ 'url': ''}
+ else:
+ return {}
+
+ @memoize
+ def listColumnInfos(self):
+ (key, reverse) = self._getSorting()
+ columns = ( {'key': 'Type',
+ 'title': _(u'Type'),
+ 'width': '20',
+ 'colspan': '2'}
+ , {'key': 'getId',
+ 'title': _(u'Name'),
+ 'width': '360',
+ 'colspan': None}
+ , {'key': 'modified',
+ 'title': _(u'Last Modified'),
+ 'width': '180',
+ 'colspan': None}
+ , {'key': 'position',
+ 'title': _(u'Position'),
+ 'width': '80',
+ 'colspan': None }
+ )
+ for column in columns:
+ if key == column['key'] and not reverse and key != 'position':
+ query = make_query(key=column['key'], reverse=1)
+ else:
+ query = make_query(key=column['key'])
+ column['url'] = '%s?%s' % (self._getViewURL(), query)
+ return tuple(columns)
+
+ @memoize
+ @decode
+ def listItemInfos(self):
+ b_start = self._getBatchStart()
+ (key, reverse) = self._getSorting()
+ batch_obj = self._getBatchObj()
+ items_manage_allowed = self._checkPermission(ViewManagementScreens)
+ portal_url = self._getPortalURL()
+
+ items = []
+ i = 1
+ for item in batch_obj:
+ item_icon = item.getIcon(1)
+ item_id = item.getId()
+ item_position = (key == 'position') and str(b_start + i) or '...'
+ i += 1
+ item_url = item.getActionInfo(('object/folderContents',
+ 'object/view'))['url']
+ items.append({'checkbox': items_manage_allowed and ('cb_%s' %
+ item_id) or '',
+ 'icon': item_icon and ('%s/%s' %
+ (portal_url, item_icon)) or '',
+ 'id': item_id,
+ 'modified': item.ModificationDate(),
+ 'position': item_position,
+ 'title': item.Title(),
+ 'type': item.Type() or None,
+ 'url': item_url})
+ return tuple(items)
+
+ @memoize
+ def listDeltas(self):
+ length = self._getBatchObj().sequence_length
+ deltas = range(1, min(5, length)) + range(5, length, 5)
+ return tuple(deltas)
+
+ @memoize
+ def is_orderable(self):
+ length = len(self._getBatchObj())
+ items_move_allowed = self._checkPermission(ManageProperties)
+ (key, reverse) = self._getSorting()
+ return items_move_allowed and (key == 'position') and length > 1
+
+ @memoize
+ def is_sortable(self):
+ items_move_allowed = self._checkPermission(ManageProperties)
+ return items_move_allowed and not self._isDefaultSorting()
+
+ # checkers
+
+ def checkAllowedContentTypes(self):
+ return bool(self.context.allowedContentTypes())
+
+ def checkClipboardData(self):
+ return bool(self.context.cb_dataValid())
+
+ def checkItems(self):
+ return bool(self._getItems())
+
+ # validators
+
+ def validateItemIds(self, ids=(), **kw):
+ if ids:
+ return True
+ else:
+ return False, _(u'Please select one or more items first.')
+
+ def validateClipboardData(self, **kw):
+ if self.context.cb_dataValid():
+ return True
+ else:
+ return False, _(u'Please copy or cut one or more items to paste '
+ u'first.')
+
+ # controllers
+
+ def cut_control(self, ids, **kw):
+ """Cut objects from a folder and copy to the clipboard.
+ """
+ try:
+ self.context.manage_cutObjects(ids, self.request)
+ if len(ids) == 1:
+ return True, _(u'Item cut.')
+ else:
+ return True, _(u'Items cut.')
+ except CopyError:
+ return False, _(u'CopyError: Cut failed.')
+ except zExceptions_Unauthorized:
+ return False, _(u'Unauthorized: Cut failed.')
+
+ def copy_control(self, ids, **kw):
+ """Copy objects from a folder to the clipboard.
+ """
+ try:
+ self.context.manage_copyObjects(ids, self.request)
+ if len(ids) == 1:
+ return True, _(u'Item copied.')
+ else:
+ return True, _(u'Items copied.')
+ except CopyError:
+ return False, _(u'CopyError: Copy failed.')
+
+ def paste_control(self, **kw):
+ """Paste objects to a folder from the clipboard.
+ """
+ try:
+ result = self.context.manage_pasteObjects(self.request['__cp'])
+ if len(result) == 1:
+ return True, _(u'Item pasted.')
+ else:
+ return True, _(u'Items pasted.')
+ except CopyError:
+ return False, _(u'CopyError: Paste failed.')
+ except zExceptions_Unauthorized:
+ return False, _(u'Unauthorized: Paste failed.')
+
+ def delete_control(self, ids, **kw):
+ """Delete objects from a folder.
+ """
+ self.context.manage_delObjects(list(ids))
+ if len(ids) == 1:
+ return True, _(u'Item deleted.')
+ else:
+ return True, _(u'Items deleted.')
+
+ def sort_control(self, key='position', reverse=0, **kw):
+ """Sort objects in a folder.
+ """
+ self.context.setDefaultSorting(key, reverse)
+ return True
+
+ def up_control(self, ids, delta, **kw):
+ subset_ids = [ obj.getId()
+ for obj in self.context.listFolderContents() ]
+ try:
+ attempt = self.context.moveObjectsUp(ids, delta,
+ subset_ids=subset_ids)
+ if attempt == 1:
+ return True, _(u'Item moved up.')
+ elif attempt > 1:
+ return True, _(u'Items moved up.')
+ else:
+ return False, _(u'Nothing to change.')
+ except ValueError:
+ return False, _(u'ValueError: Move failed.')
+
+ def down_control(self, ids, delta, **kw):
+ subset_ids = [ obj.getId()
+ for obj in self.context.listFolderContents() ]
+ try:
+ attempt = self.context.moveObjectsDown(ids, delta,
+ subset_ids=subset_ids)
+ if attempt == 1:
+ return True, _(u'Item moved down.')
+ elif attempt > 1:
+ return True, _(u'Items moved down.')
+ else:
+ return False, _(u'Nothing to change.')
+ except ValueError:
+ return False, _(u'ValueError: Move failed.')
+
+ def top_control(self, ids, **kw):
+ subset_ids = [ obj.getId()
+ for obj in self.context.listFolderContents() ]
+ try:
+ attempt = self.context.moveObjectsToTop(ids,
+ subset_ids=subset_ids)
+ if attempt == 1:
+ return True, _(u'Item moved to top.')
+ elif attempt > 1:
+ return True, _(u'Items moved to top.')
+ else:
+ return False, _(u'Nothing to change.')
+ except ValueError:
+ return False, _(u'ValueError: Move failed.')
+
+ def bottom_control(self, ids, **kw):
+ subset_ids = [ obj.getId()
+ for obj in self.context.listFolderContents() ]
+ try:
+ attempt = self.context.moveObjectsToBottom(ids,
+ subset_ids=subset_ids)
+ if attempt == 1:
+ return True, _(u'Item moved to bottom.')
+ elif attempt > 1:
+ return True, _(u'Items moved to bottom.')
+ else:
+ return False, _(u'Nothing to change.')
+ except ValueError:
+ return False, _(u'ValueError: Move failed.')
Property changes on: CMF/trunk/CMFDefault/browser/folder.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Copied: CMF/trunk/CMFDefault/browser/templates/batch_widgets.pt (from rev 41723, CMF/trunk/CMFDefault/skins/zpt_generic/batch_widgets.pt)
===================================================================
--- CMF/trunk/CMFDefault/skins/zpt_generic/batch_widgets.pt 2006-02-21 12:21:26 UTC (rev 41723)
+++ CMF/trunk/CMFDefault/browser/templates/batch_widgets.pt 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,54 @@
+<html>
+<body>
+
+ <metal:macro metal:define-macro="summary"
+ ><p class="BatchSummary" tal:condition="view/summary_length"
+ i18n:translate="">Found <span tal:replace="view/summary_length"
+ i18n:name="count">N</span> <span i18n:name="type"><span tal:omit-tag=""
+ tal:content="view/summary_type" i18n:translate="">ITEMS</span></span
+ ><tal:case tal:condition="python: view.summary_match() is not None"
+ > matching '<span tal:replace="view/summary_match" i18n:name="text"
+ >SEARCH TERM</span>'</tal:case>.</p
+ ><p class="BatchSummary" tal:condition="not:view/summary_length"
+ i18n:translate="">There are no items matching your specified criteria.</p
+></metal:macro>
+
+ <metal:macro metal:define-macro="listing">
+ <p class="BatchListing" tal:repeat="item_info view/listItemInfos"
+ ><a href="" tal:attributes="href item_info/url"
+ ><img src="" alt="" title="" border="0" width="16" height="16"
+ tal:attributes="src item_info/icon; alt item_info/type;
+ title item_info/type"
+ i18n:attributes="alt; title" /></a
+ ><tal:case tal:condition="item_info/title">
+ <a href="" tal:attributes="href item_info/url"
+ tal:content="item_info/title">TITLE</a></tal:case
+ ><tal:case tal:condition="item_info/description">
+ <br /><tal:span tal:content="item_info/description"
+ >DESCRIPTION</tal:span></tal:case
+ ><tal:case tal:condition="item_info/format">
+ <br /><span><tal:span tal:content="item_info/format" i18n:translate=""
+ >FORMAT</tal:span><tal:case tal:condition="item_info/size"
+ >, <tal:span tal:content="item_info/size">99.9 KB</tal:span></tal:case
+ ></span></tal:case></p
+></metal:macro>
+
+ <metal:macro metal:define-macro="navigation"
+ tal:define="prev_info view/navigation_previous;
+ next_info view/navigation_next"
+ ><p class="BatchNavigation" tal:condition="python: prev_info or next_info"
+ ><tal:case tal:condition="prev_info">
+ <a href="" tal:attributes="href prev_info/url"
+ tal:content="prev_info/title"
+ i18n:translate="">PREVIOUS N ITEMS</a></tal:case
+ ><tal:case tal:condition="python: prev_info and next_info">
+ </tal:case
+ ><tal:case tal:condition="next_info">
+ <a href="" tal:attributes="href next_info/url"
+ tal:content="next_info/title"
+ i18n:translate="">NEXT N ITEMS</a></tal:case
+ ></p
+></metal:macro>
+
+</body>
+</html>
Property changes on: CMF/trunk/CMFDefault/browser/templates/batch_widgets.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Copied: CMF/trunk/CMFDefault/browser/templates/folder.pt (from rev 41723, CMF/trunk/CMFDefault/skins/zpt_generic/index_html_template.pt)
===================================================================
--- CMF/trunk/CMFDefault/skins/zpt_generic/index_html_template.pt 2006-02-21 12:21:26 UTC (rev 41723)
+++ CMF/trunk/CMFDefault/browser/templates/folder.pt 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,38 @@
+<html metal:use-macro="context/@@standard_macros/page">
+<body>
+
+<metal:slot metal:fill-slot="header" i18n:domain="cmf_default"
+><tal:case tal:condition="not: view/has_local"
+><h1 id="DesktopTitle" tal:content="view/title">Page Title</h1>
+
+<div id="DesktopDescription" tal:content="view/description">Description
+ of the resource goes here, perhaps even wrapping lines; this is to make it
+ long enough to test.</div></tal:case
+><tal:case tal:condition="view/has_local"
+><div metal:use-macro="context/local_pt/macros/header | default">'local_pt'
+ header goes here.</div></tal:case
+></metal:slot>
+
+<metal:slot metal:fill-slot="body" i18n:domain="cmf_default">
+ <div id="content_well"
+ style="float: left; top: 0; width: 78%;">
+ <div tal:condition="not: view/has_local">
+
+<metal:macro metal:use-macro="context/@@batch_widget/listing" />
+<metal:macro metal:use-macro="context/@@batch_widget/navigation" />
+
+ </div>
+ <div tal:condition="view/has_local">
+ <div metal:use-macro="context/local_pt/macros/body | default">
+ 'local_pt' body goes here.
+ </div>
+ </div>
+ </div>
+ <div id="right_sidebar"
+ style="float: right; width: 20%">
+<tal:span tal:replace="structure context/news_box" />
+ </div>
+</metal:slot>
+
+</body>
+</html>
Copied: CMF/trunk/CMFDefault/browser/templates/folder_contents.pt (from rev 41723, CMF/trunk/CMFDefault/skins/zpt_generic/folder_contents_template.pt)
===================================================================
--- CMF/trunk/CMFDefault/skins/zpt_generic/folder_contents_template.pt 2006-02-21 12:21:26 UTC (rev 41723)
+++ CMF/trunk/CMFDefault/browser/templates/folder_contents.pt 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,96 @@
+<html metal:use-macro="context/@@standard_macros/page">
+<body>
+
+<metal:slot metal:fill-slot="header" i18n:domain="cmf_default">
+<h1 i18n:translate="">Folder Contents: <tal:span
+ tal:content="view/title" i18n:name="obj_title">Title</tal:span></h1>
+</metal:slot>
+
+<metal:slot metal:fill-slot="body" i18n:domain="cmf_default">
+<div class="Desktop">
+
+<p tal:define="up_info view/up_info" tal:condition="up_info"
+><tal:case tal:condition="up_info/url"
+ ><a href="" tal:attributes="href up_info/url"
+ ><img src="" alt="[Link]" border="0" tal:attributes="src up_info/icon"
+ i18n:attributes="alt" /></a>
+ <span tal:omit-tag="" i18n:translate="">Up to</span>
+ <a href="" tal:attributes="href up_info/url"
+ tal:content="up_info/id">ID</a></tal:case
+><tal:case tal:condition="not: up_info/url"
+ ><span class="mild" i18n:translate="">Root</span></tal:case></p>
+
+<form action="folder_contents" method="post"
+ tal:attributes="action view/form_action"
+><metal:macro metal:use-macro="context/@@form_widget/hidden_vars" />
+ <table class="BatchTable"
+ tal:condition="view/listItemInfos">
+ <thead>
+ <tr class="list-header">
+ <th width="80" tal:repeat="column_info view/listColumnInfos"
+ tal:attributes="width column_info/width; colspan column_info/colspan"
+ ><a href="" tal:attributes="href column_info/url"
+ tal:content="column_info/title">COLUMN TITLE</a></th>
+ </tr>
+ </thead>
+ <tbody tal:repeat="item_info view/listItemInfos">
+ <tr class="" tal:define="even repeat/item_info/even"
+ tal:attributes="class python: (even and 'row-hilite') or 'row-normal'">
+ <td width="5"
+ ><input type="checkbox" name="ids:list" value="" id=""
+ tal:attributes="value item_info/id; id item_info/checkbox"
+ tal:condition="item_info/checkbox" /></td>
+ <td
+ ><a href="" tal:attributes="href item_info/url"
+ tal:condition="item_info/icon"
+ ><img src="" alt="" border="0"
+ tal:attributes="src item_info/icon; alt item_info/type"
+ i18n:attributes="alt" /></a></td>
+ <td
+ ><a href="" tal:attributes="href item_info/url"
+ ><tal:span tal:content="item_info/id">ID</tal:span>
+ <tal:case tal:condition="item_info/title"
+ tal:content="string:(${item_info/title})">(Title)</tal:case
+ ></a></td>
+ <td
+ ><tal:span tal:content="item_info/modified">2001</tal:span></td>
+ <td
+ ><tal:span tal:content="item_info/position">1</tal:span></td>
+ </tr>
+ </tbody>
+ </table>
+ <metal:macro metal:use-macro="context/@@batch_widget/navigation" />
+ <metal:macro metal:use-macro="context/@@form_widget/buttons" />
+<tal:case tal:condition="python: view.is_orderable() or view.is_sortable()"
+> <div class="FormButtons"
+ ><tal:case tal:condition="view/is_orderable">
+ <input type="submit" name="items_up" value="Up"
+ i18n:attributes="value" />
+ /
+ <input type="submit" name="items_down" value="Down"
+ i18n:attributes="value" />
+ by
+ <select name="delta:int">
+ <option value=""
+ tal:repeat="delta view/listDeltas"
+ tal:attributes="value delta"
+ tal:content="delta">
+ </option>
+ </select>
+ <input type="submit" name="items_top" value="Top"
+ i18n:attributes="value" />
+ <input type="submit" name="items_bottom" value="Bottom"
+ i18n:attributes="value" /></tal:case
+ ><tal:case tal:condition="view/is_sortable">
+ <input type="submit" name="items_sort" value="Set Sorting as Default"
+ i18n:attributes="value" /></tal:case
+></div>
+</tal:case></form>
+
+<div tal:replace="structure context/folder_filter_form">Filter Form Here</div>
+
+</div>
+</metal:slot>
+
+</body>
+</html>
Copied: CMF/trunk/CMFDefault/browser/templates/form_widgets.pt (from rev 41723, CMF/trunk/CMFDefault/skins/zpt_generic/form_widgets.pt)
===================================================================
--- CMF/trunk/CMFDefault/skins/zpt_generic/form_widgets.pt 2006-02-21 12:21:26 UTC (rev 41723)
+++ CMF/trunk/CMFDefault/browser/templates/form_widgets.pt 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,19 @@
+<html>
+<body>
+
+<metal:macro metal:define-macro="hidden_vars">
+ <tal:loop tal:repeat="hidden_var view/listHiddenVarInfos"
+ ><input type="hidden" name="HiddenVarName" value=""
+ tal:attributes="name hidden_var/name; value hidden_var/value" /></tal:loop
+></metal:macro>
+
+ <metal:macro metal:define-macro="buttons"
+><div class="FormButtons">
+ <tal:loop tal:repeat="button view/listButtonInfos"
+ ><input type="submit" name="ButtonName" value="ButtonValue"
+ tal:attributes="name button/name; value button/value"
+ i18n:attributes="value" /></tal:loop></div
+></metal:macro>
+
+</body>
+</html>
Property changes on: CMF/trunk/CMFDefault/browser/templates/form_widgets.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: CMF/trunk/CMFDefault/browser/utils.py
===================================================================
--- CMF/trunk/CMFDefault/browser/utils.py 2006-02-21 15:45:07 UTC (rev 41739)
+++ CMF/trunk/CMFDefault/browser/utils.py 2006-02-21 16:23:53 UTC (rev 41740)
@@ -0,0 +1,270 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Browser view utilities.
+
+$Id$
+"""
+
+from Products.PythonScripts.standard import thousands_commas
+from ZTUtils import Batch
+from ZTUtils import make_query
+
+from Products.CMFCore.utils import getToolByName
+from Products.CMFDefault.utils import html_marshal
+from Products.CMFDefault.utils import Message as _
+from Products.CMFDefault.utils import toUnicode
+
+
+def decode(meth):
+ def decoded_meth(self, *args, **kw):
+ return toUnicode(meth(self, *args, **kw), self._getDefaultCharset())
+ return decoded_meth
+
+def memoize(meth):
+ def memoized_meth(self, *args):
+ if not hasattr(self, '__memo__'):
+ self.__memo__ = {}
+ sig = (meth, args)
+ if sig not in self.__memo__:
+ self.__memo__[sig] = meth(self, *args)
+ return self.__memo__[sig]
+ return memoized_meth
+
+
+class ViewBase:
+
+ # helpers
+
+ @memoize
+ def _getTool(self, name):
+ return getToolByName(self.context, name)
+
+ @memoize
+ def _checkPermission(self, permission):
+ mtool = self._getTool('portal_membership')
+ return mtool.checkPermission(permission, self.context)
+
+ @memoize
+ def _getPortalURL(self):
+ utool = self._getTool('portal_url')
+ return utool()
+
+ @memoize
+ def _getViewURL(self):
+ return self.request['ACTUAL_URL']
+
+ @memoize
+ def _getDefaultCharset(self):
+ ptool = self._getTool('portal_properties')
+ return ptool.getProperty('default_charset', None)
+
+ # interface
+
+ @memoize
+ @decode
+ def title(self):
+ return self.context.Title()
+
+ @memoize
+ @decode
+ def description(self):
+ return self.context.Description()
+
+
+class FormViewBase(ViewBase):
+
+ # helpers
+
+ def _setRedirect(self, provider_id, action_path, keys=''):
+ provider = self._getTool(provider_id)
+ try:
+ target = provider.getActionInfo(action_path, self.context)['url']
+ except ValueError:
+ target = self._getPortalURL()
+
+ kw = {}
+ message = self.request.other.get('portal_status_message', '')
+ if message:
+ kw['portal_status_message'] = message
+ for k in keys.split(','):
+ k = k.strip()
+ v = self.request.form.get(k, None)
+ if v:
+ kw[k] = v
+
+ query = kw and ( '?%s' % make_query(kw) ) or ''
+ self.request.RESPONSE.redirect( '%s%s' % (target, query) )
+
+ return True
+
+ # interface
+
+ def __call__(self, **kw):
+ form = self.request.form
+ for button in self._BUTTONS:
+ if button['id'] in form:
+ for permission in button.get('permissions', ()):
+ if not self._checkPermission(permission):
+ break
+ else:
+ for transform in button.get('transform', ()):
+ status = getattr(self, transform)(**form)
+ if isinstance(status, bool):
+ status = (status,)
+ if len(status) > 1:
+ self.request.other['portal_status_message'] = status[1]
+ if not status[0]:
+ return self.index()
+ if self._setRedirect(*button['redirect']):
+ return
+ return self.index()
+
+ @memoize
+ def form_action(self):
+ return self._getViewURL()
+
+ @memoize
+ def listButtonInfos(self):
+ form = self.request.form
+ buttons = []
+ for button in self._BUTTONS:
+ if button.get('title', None):
+ for permission in button.get('permissions', ()):
+ if not self._checkPermission(permission):
+ break
+ else:
+ for condition in button.get('conditions', ()):
+ if not getattr(self, condition)():
+ break
+ else:
+ buttons.append({'name': button['id'],
+ 'value': button['title']})
+ return tuple(buttons)
+
+ @memoize
+ @decode
+ def listHiddenVarInfos(self):
+ kw = self._getHiddenVars()
+ vars = [ {'name': name, 'value': value}
+ for name, value in html_marshal(**kw) ]
+ return tuple(vars)
+
+
+class BatchViewBase(ViewBase):
+
+ # helpers
+
+ _BATCH_SIZE = 25
+
+ @memoize
+ def _getBatchStart(self):
+ return self.request.form.get('b_start', 0)
+
+ @memoize
+ def _getBatchObj(self):
+ b_start = self._getBatchStart()
+ items = self._getItems()
+ return Batch(items, self._BATCH_SIZE, b_start, orphan=0)
+
+ @memoize
+ def _getHiddenVars(self):
+ return {}
+
+ @memoize
+ def _getNavigationURL(self, b_start):
+ target = self._getViewURL()
+ kw = self._getHiddenVars()
+
+ kw['b_start'] = b_start
+ for k, v in kw.items():
+ if not v or k == 'portal_status_message':
+ del kw[k]
+
+ query = kw and ('?%s' % make_query(kw)) or ''
+ return u'%s%s' % (target, query)
+
+ # interface
+
+ @memoize
+ @decode
+ def listItemInfos(self):
+ batch_obj = self._getBatchObj()
+ portal_url = self._getPortalURL()
+
+ items = []
+ for item in batch_obj:
+ item_description = item.Description()
+ item_icon = item.getIcon(1)
+ item_title = item.Title()
+ item_type = remote_type = item.Type()
+ if item_type == 'Favorite' and not item_icon == 'p_/broken':
+ item = item.getObject()
+ item_description = item_description or item.Description()
+ item_title = item_title or item.Title()
+ remote_type = item.Type()
+ is_file = remote_type in ('File', 'Image')
+ is_link = remote_type == 'Link'
+ items.append({'description': item_description,
+ 'format': is_file and item.Format() or '',
+ 'icon': item_icon and ('%s/%s' %
+ (portal_url, item_icon)) or '',
+ 'size': is_file and ('%0.0f kb' %
+ (item.get_size() / 1024.0)) or '',
+ 'title': item_title,
+ 'type': item_type,
+ 'url': is_link and item.getRemoteUrl() or
+ item.absolute_url()})
+ return tuple(items)
+
+ @memoize
+ def navigation_previous(self):
+ batch_obj = self._getBatchObj().previous
+ if batch_obj is None:
+ return None
+
+ length = len(batch_obj)
+ url = self._getNavigationURL(batch_obj.first)
+ if length == 1:
+ title = _(u'Previous item')
+ else:
+ title = _(u'Previous ${count} items', mapping={'count': length})
+ return {'title': title, 'url': url}
+
+ @memoize
+ def navigation_next(self):
+ batch_obj = self._getBatchObj().next
+ if batch_obj is None:
+ return None
+
+ length = len(batch_obj)
+ url = self._getNavigationURL(batch_obj.first)
+ if length == 1:
+ title = _(u'Next item')
+ else:
+ title = _(u'Next ${count} items', mapping={'count': length})
+ return {'title': title, 'url': url}
+
+ @memoize
+ def summary_length(self):
+ length = self._getBatchObj().sequence_length
+ return length and thousands_commas(length) or ''
+
+ @memoize
+ def summary_type(self):
+ length = self._getBatchObj().sequence_length
+ return (length == 1) and _(u'item') or _(u'items')
+
+ @memoize
+ @decode
+ def summary_match(self):
+ return self.request.form.get('SearchableText')
Property changes on: CMF/trunk/CMFDefault/browser/utils.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: CMF/trunk/CMFDefault/configure.zcml
===================================================================
--- CMF/trunk/CMFDefault/configure.zcml 2006-02-21 15:45:07 UTC (rev 41739)
+++ CMF/trunk/CMFDefault/configure.zcml 2006-02-21 16:23:53 UTC (rev 41740)
@@ -1,9 +1,10 @@
<configure
- xmlns="http://namespaces.zope.org/zope"
- >
+ xmlns="http://namespaces.zope.org/zope">
- <include
- package=".skin"
- />
+ <include package=".skin"/>
+ <!-- uncomment this to enable browser views
+ <include package=".browser"/>
+ -->
+
</configure>
More information about the CMF-checkins
mailing list