[CMF-checkins] SVN: CMF/branches/tseaver-viewification/CMFDefault/browser/ - added decode and memoize decorator functions to utils

Yvo Schubbe y.2006_ at wcm-solutions.de
Tue Jan 31 12:47:30 EST 2006


Log message for revision 41515:
  - added decode and memoize decorator functions to utils
  - added ViewBase to utils
  - refactored FormViewBase to make it more helpful for folder_contents and to get rid of setStatus
  - updated document and link edit views

Changed:
  U   CMF/branches/tseaver-viewification/CMFDefault/browser/documentviews.py
  U   CMF/branches/tseaver-viewification/CMFDefault/browser/linkviews.py
  U   CMF/branches/tseaver-viewification/CMFDefault/browser/templates/document_edit.pt
  U   CMF/branches/tseaver-viewification/CMFDefault/browser/templates/link_edit.pt
  U   CMF/branches/tseaver-viewification/CMFDefault/browser/utils.py

-=-
Modified: CMF/branches/tseaver-viewification/CMFDefault/browser/documentviews.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/browser/documentviews.py	2006-01-31 17:37:30 UTC (rev 41514)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/documentviews.py	2006-01-31 17:47:30 UTC (rev 41515)
@@ -21,7 +21,9 @@
 from Products.CMFDefault.utils import MessageID as _
 from Products.CMFDefault.utils import scrubHTML
 
+from utils import decode
 from utils import FormViewBase
+from utils import memoize
 
 
 class DocumentEditView(FormViewBase):
@@ -29,56 +31,66 @@
     """ Edit view for IMutableDocument.
     """
 
-    _BUTTONS = ({'name': 'change',
-                 'value': _(u'Change'),
-                 'transform': ('validateTextFile', 'validateHTML', 'update'),
+    _BUTTONS = ({'id': 'change',
+                 'title': _(u'Change'),
+                 'transform': ('validateTextFile', 'validateHTML',
+                               'document_edit_control'),
                  'redirect': ('context', 'object/edit')},
-                {'name': 'change_and_view',
-                 'value': _(u'Change and View'),
-                 'transform': ('validateTextFile', 'validateHTML', 'update'),
+                {'id': 'change_and_view',
+                 'title': _(u'Change and View'),
+                 'transform': ('validateTextFile', 'validateHTML',
+                               'document_edit_control'),
                  'redirect': ('context', 'object/view')})
 
-    def title(self):
-        return self.context.Title()
+    #helpers
 
-    def description(self):
-        return self.context.Description()
+    @memoize
+    def _getHiddenVars(self):
+        belt = self.request.form.get('SafetyBelt', self.context.SafetyBelt())
+        return {'SafetyBelt': belt}
 
-    def SafetyBelt(self):
-        return self.request.form.get('SafetyBelt', self.context.SafetyBelt())
+    # interface
 
+    @memoize
     def text_format(self):
         return self.request.form.get('text_format', self.context.text_format)
 
+    @memoize
+    @decode
     def text(self):
         return self.request.form.get('text', self.context.EditableBody())
 
+    # validators
+
     def validateTextFile(self, file='', **kw):
         try:
             upload = file.read()
         except AttributeError:
-            return self.setStatus(True)
+            return True
         else:
             if upload:
-                return self.setStatus(True, text=upload)
+                self.request.form['text'] = upload
+                return True
             else:
-                return self.setStatus(True)
+                return True
 
     def validateHTML(self, text, description='', **kw):
         try:
-            description = scrubHTML(description)
-            text = scrubHTML(text)
-            return self.setStatus(True, text=text, description=description)
+            self.request.form['description'] = scrubHTML(description)
+            self.request.form['text'] = scrubHTML(text)
+            return True
         except IllegalHTML, errmsg:
-            return self.setStatus(False, errmsg)
+            return False, errmsg
 
-    def update(self, text_format, text, SafetyBelt='', **kw):
+    # controllers
+
+    def document_edit_control(self, text_format, text, SafetyBelt='', **kw):
         context = self.context
         if text_format != context.text_format or text != context.text:
             try:
                 context.edit(text_format, text, safety_belt=SafetyBelt)
-                return self.setStatus(True, _(u'Document changed.'))
+                return True, _(u'Document changed.')
             except (ResourceLockedError, EditingConflict), errmsg:
-                return self.setStatus(False, errmsg)
+                return False, errmsg
         else:
-            return self.setStatus(False, _(u'Nothing to change.'))
+            return False, _(u'Nothing to change.')

Modified: CMF/branches/tseaver-viewification/CMFDefault/browser/linkviews.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/browser/linkviews.py	2006-01-31 17:37:30 UTC (rev 41514)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/linkviews.py	2006-01-31 17:47:30 UTC (rev 41515)
@@ -138,47 +138,38 @@
 #
 import urlparse
 
-from Products.CMFDefault.exceptions import EditingConflict
 from Products.CMFDefault.exceptions import ResourceLockedError
 from Products.CMFDefault.utils import MessageID as _
 
+from utils import decode
 from utils import FormViewBase
+from utils import memoize
 
+
 class IllegalURL(ValueError):
     pass
 
+
 class LinkEditView(FormViewBase):
 
-    """ Edit view for IMutableDocument.
+    """ Edit view for IMutableLink.
     """
 
-    # XXX: _BUTTONS should become configurable
-    _BUTTONS = ({'name': 'change',
-                 'value': _(u'Change'),
-                 'transform': ('validateURL', 'update'),
+    _BUTTONS = ({'id': 'change',
+                 'title': _(u'Change'),
+                 'transform': ('validateURL', 'link_edit_control'),
                  'redirect': ('context', 'object/edit'),
                 },
-                {'name': 'change_and_view',
-                 'value': _(u'Change and View'),
-                 'transform': ('validateURL', 'update'),
+                {'id': 'change_and_view',
+                 'title': _(u'Change and View'),
+                 'transform': ('validateURL', 'link_edit_control'),
                  'redirect': ('context', 'object/view'),
                 },
                )
 
-    def remote_url(self):
-        if 'remote_url' in self.request.form:
-            return self.request['remote_url']
-        else:
-            return self.context.remote_url
+    # helpers
 
-    def validateURL(self, remote_url='', **kw):
-        try:
-            remote_url = self._normalizeURL(remote_url)
-        except IllegalURL, errmsg:
-            return self.setStatus(False, errmsg)
-        else:
-            return self.setStatus(True, remote_url=remote_url)
-
+    @memoize
     def _normalizeURL(self, remote_url):
         tokens = urlparse.urlparse( remote_url, 'http' )
         if tokens[0] == 'http':
@@ -197,13 +188,33 @@
             url = urlparse.urlunparse(tokens)
         return url
 
-    def update(self, remote_url, **kw):
+    # interface
+
+    @memoize
+    @decode
+    def remote_url(self):
+        return self.request.form.get('remote_url', self.context.remote_url)
+
+    # validators
+
+    def validateURL(self, remote_url='', **kw):
+        try:
+            remote_url = self._normalizeURL(remote_url)
+        except IllegalURL, errmsg:
+            return False, errmsg
+        else:
+            self.request.form[remote_url] = remote_url
+            return True
+
+    # controllers
+
+    def link_edit_control(self, remote_url, **kw):
         context = self.context
         if remote_url != context.remote_url:
             try:
-                context.remote_url = remote_url
-                return self.setStatus(True, _(u'Link changed.'))
-            except (ResourceLockedError, EditingConflict), errmsg:
-                return self.setStatus(False, errmsg)
+                context.edit(remote_url=remote_url)
+                return True, _(u'Link changed.')
+            except ResourceLockedError, errmsg:
+                return False, errmsg
         else:
-            return self.setStatus(False, _(u'Nothing to change.'))
+            return False, _(u'Nothing to change.')

Modified: CMF/branches/tseaver-viewification/CMFDefault/browser/templates/document_edit.pt
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/browser/templates/document_edit.pt	2006-01-31 17:37:30 UTC (rev 41514)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/templates/document_edit.pt	2006-01-31 17:47:30 UTC (rev 41515)
@@ -7,12 +7,9 @@
 </metal:slot>
 
 <metal:slot metal:fill-slot="body" i18n:domain="cmf_default">
-<div class="Desktop">
-
 <form action="document_edit_form" method="post" enctype="multipart/form-data"
-   tal:attributes="action request/ACTUAL_URL">
- <input type="hidden" name="SafetyBelt" value=""
-    tal:attributes="value view/SafetyBelt" />
+   tal:attributes="action view/form_action"
+><metal:macro metal:use-macro="context/@@form_widget/hidden_vars" />
 <table class="FormLayout">
  <tr>
   <th i18n:translate="">Title</th>
@@ -57,8 +54,6 @@
  </tr>
 </table>
 </form>
-
-</div>
 </metal:slot>
 
 </body>

Modified: CMF/branches/tseaver-viewification/CMFDefault/browser/templates/link_edit.pt
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/browser/templates/link_edit.pt	2006-01-31 17:37:30 UTC (rev 41514)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/templates/link_edit.pt	2006-01-31 17:47:30 UTC (rev 41515)
@@ -3,24 +3,22 @@
 
 <metal:slot metal:fill-slot="header" i18n:domain="cmf_default">
 <h1 i18n:translate="">Edit: <tal:span
-    tal:content="context/Title" i18n:name="obj_title">Title</tal:span></h1>
+    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">
-
 <form action="link_edit_form" method="post"
-   tal:attributes="action request/ACTUAL_URL">
+   tal:attributes="action view/form_action">
 <table class="FormLayout">
  <tr>
   <th i18n:translate="">Title</th>
-  <td tal:content="context/Title">Title</td>
+  <td tal:content="view/title">Title</td>
  </tr>
  <tr>
   <th i18n:translate="">URL</th>
   <td>
    <input type="text" name="remote_url" value=""
-          tal:attributes="value view/remote_url" />
+      tal:attributes="value view/remote_url" />
   </td>
  </tr>
  <tr>
@@ -31,8 +29,6 @@
  </tr>
 </table>
 </form>
-
-</div>
 </metal:slot>
 
 </body>

Modified: CMF/branches/tseaver-viewification/CMFDefault/browser/utils.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/browser/utils.py	2006-01-31 17:37:30 UTC (rev 41514)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/utils.py	2006-01-31 17:47:30 UTC (rev 41515)
@@ -1,53 +1,161 @@
+##############################################################################
+#
+# Copyright (c) 2005 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 ZTUtils import make_query
 
 from Products.CMFCore.utils import getToolByName
+from Products.CMFDefault.utils import html_marshal
+from Products.CMFDefault.utils import toUnicode
+from Products.CMFDefault.utils import MessageID as _
 
 
-class FormViewBase:
+def decode(meth):
+    def decoded_meth(self, *args, **kw):
+        return toUnicode(meth(self, *args, **kw), self._getDefaultCharset())
+    return decoded_meth
 
-    def __call__(self, **kw):
-        form = self.request.form
-        for button in self._BUTTONS:
-            if button['name'] in form:
-                for transform in button['transform']:
-                    if not getattr(self, transform)(**form):
-                        return self.index()
-                if self.setRedirect(*button['redirect']):
-                    return
-        return self.index()
+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
 
-    def listButtonInfos(self):
-        return self._BUTTONS
 
-    def setStatus(self, success, message='', **kw):
-        if message:
-            self.request.other['portal_status_message'] = message
-        if kw:
-            for k, v in kw.items():
-                self.request.form[k] = v
+class ViewBase:
 
-        return success
+    # helpers
 
-    def setRedirect(self, provider_id, action_path, **kw):
-        utool = getToolByName(self.context, 'portal_url')
-        portal_url = utool()
+    @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=''):
         if provider_id == 'context':
             provider = self.context
         else:
-            provider = getToolByName(self.context, provider_id)
+            provider = self._getTool(provider_id)
         try:
             target = provider.getActionInfo(action_path)['url']
         except ValueError:
-            target = portal_url
+            target = self._getPortalURL()
 
+        kw = {}
         message = self.request.other.get('portal_status_message', '')
-        kw['portal_status_message'] = message
-        for k, v in kw.items():
-            if not v:
-                del kw[k]
+        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)



More information about the CMF-checkins mailing list