[CMF-checkins] SVN: CMF/trunk/CMFDefault/ - replaced metadata forms by formlib based forms

Yvo Schubbe y.2006_ at wcm-solutions.de
Tue Dec 19 13:22:49 EST 2006


Log message for revision 71606:
  - replaced metadata forms by formlib based forms

Changed:
  U   CMF/trunk/CMFDefault/browser/TODO.txt
  U   CMF/trunk/CMFDefault/browser/configure.zcml
  U   CMF/trunk/CMFDefault/browser/metadata.py
  A   CMF/trunk/CMFDefault/browser/metadata.txt
  D   CMF/trunk/CMFDefault/browser/templates/metadata_edit.pt
  D   CMF/trunk/CMFDefault/browser/templates/metadata_minimal_edit.pt
  U   CMF/trunk/CMFDefault/browser/tests.py
  U   CMF/trunk/CMFDefault/formlib/tests.py
  U   CMF/trunk/CMFDefault/formlib/widgets.py
  A   CMF/trunk/CMFDefault/formlib/widgets.txt
  U   CMF/trunk/CMFDefault/locales/cmf_default.pot
  U   CMF/trunk/CMFDefault/skins/zpt_generic/zpt_stylesheet.css

-=-
Modified: CMF/trunk/CMFDefault/browser/TODO.txt
===================================================================
--- CMF/trunk/CMFDefault/browser/TODO.txt	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/browser/TODO.txt	2006-12-19 18:22:49 UTC (rev 71606)
@@ -37,15 +37,15 @@
 
   [x] IMutableMinimalDublinCore @@properties.html:
 
-      folder_edit_form.py -> MetadataMinimalEditView
-      folder_edit_template.pt -> templates/metadata_minimal_edit.pt
-      folder_edit_control.py -> MetadataMinimalEditView.edit_control
+      folder_edit_form.py -> MinimalMetadataEditView
+      folder_edit_template.pt -> formlib based
+      folder_edit_control.py -> formlib based
 
   [x] IMutableDublinCore @@properties.html:
 
       metadata_edit_form.py -> MetadataEditView
-      metadata_edit_template.pt -> templates/metadata_edit.pt
-      metadata_edit_control.py -> MetadataEditView.edit_control
+      metadata_edit_template.pt -> formlib based
+      metadata_edit_control.py -> formlib based
 
   [x] IDocument @@view.html:
 

Modified: CMF/trunk/CMFDefault/browser/configure.zcml
===================================================================
--- CMF/trunk/CMFDefault/browser/configure.zcml	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/browser/configure.zcml	2006-12-19 18:22:49 UTC (rev 71606)
@@ -20,21 +20,23 @@
       permission="cmf.ListFolderContents"
       />
 
+  <adapter factory=".metadata.MinimalMetadataSchemaAdapter"/>
+
   <browser:page
       for="Products.CMFCore.interfaces.IMutableMinimalDublinCore"
       layer="..interfaces.ICMFDefaultSkin"
       name="properties.html"
-      class=".metadata.MetadataMinimalEditView"
-      template="templates/metadata_minimal_edit.pt"
+      class=".metadata.MinimalMetadataEditView"
       permission="zope2.ManageProperties"
       />
 
+  <adapter factory=".metadata.MetadataSchemaAdapter"/>
+
   <browser:page
       for="Products.CMFCore.interfaces.IMutableDublinCore"
       layer="..interfaces.ICMFDefaultSkin"
       name="properties.html"
       class=".metadata.MetadataEditView"
-      template="templates/metadata_edit.pt"
       permission="cmf.ModifyPortalContent"
       />
 

Modified: CMF/trunk/CMFDefault/browser/metadata.py
===================================================================
--- CMF/trunk/CMFDefault/browser/metadata.py	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/browser/metadata.py	2006-12-19 18:22:49 UTC (rev 71606)
@@ -16,194 +16,252 @@
 """
 
 from Acquisition import aq_self
+from zope.app.form.browser import DatetimeI18nWidget
+from zope.component import adapts
+from zope.formlib import form
+from zope.interface import implements
+from zope.interface import Interface
+from zope.schema import Choice
+from zope.schema import Datetime
+from zope.schema import Set
+from zope.schema import Text
+from zope.schema import TextLine
+from zope.schema import Tuple
+from zope.schema import URI
 
-from Products.CMFDefault.exceptions import ResourceLockedError
+from Products.CMFCore.interfaces import IMutableDublinCore
+from Products.CMFCore.interfaces import IMutableMinimalDublinCore
+from Products.CMFCore.utils import getToolByName
+from Products.CMFDefault.formlib.form import ContentEditFormBase
+from Products.CMFDefault.formlib.schema import ProxyFieldProperty
+from Products.CMFDefault.formlib.schema import SchemaAdapterBase
+from Products.CMFDefault.formlib.vocabulary import SimpleVocabulary
+from Products.CMFDefault.formlib.widgets import SubjectInputWidget
+from Products.CMFDefault.formlib.widgets import TupleTextAreaWidget
 from Products.CMFDefault.utils import Message as _
 
-from utils import decode
-from utils import FormViewBase
-from utils import memoize
+available_settings = [
+        ('off', False, _(u'Off')),
+        ('on', True, _(u'On')) ]
 
 
-class MetadataMinimalEditView(FormViewBase):
+class IMinimalMetadataSchema(Interface):
 
-    """Edit view for IMutableMinimalDublinCore.
+    """Schema for minimal metadata views.
     """
 
-    _BUTTONS = ({'id': 'change',
-                 'title': _(u'Change'),
-                 'transform': ('edit_control',),
-                 'redirect': ('portal_types', 'object/edit')},
-                {'id': 'change_and_view',
-                 'title': _(u'Change and View'),
-                 'transform': ('edit_control',),
-                 'redirect': ('portal_types', 'object/view')})
+    title = TextLine(
+        title=_(u'Title'),
+        required=False,
+        missing_value=u'')
 
-    # interface
+    description = Text(
+        title=_(u'Description'),
+        required=False,
+        missing_value=u'')
 
-    @memoize
-    @decode
-    def title(self):
-        return self.request.form.get('title', self.context.Title())
 
-    @memoize
-    @decode
-    def description(self):
-        return self.request.form.get('description',
-                                     self.context.Description())
+class IMetadataSchema(Interface):
 
-    # controllers
+    """Schema for metadata views.
+    """
 
-    def edit_control(self, title, description, **kw):
-        context = self.context
-        if title!=context.Title() or description != context.Description():
-            context.edit(title=title, description=description)
-            return True, _(u'Metadata changed.')
-        else:
-            return False, _(u'Nothing to change.')
+    allow_discussion = Choice(
+        title=_(u'Enable Discussion?'),
+        required=False,
+        vocabulary=SimpleVocabulary.fromTitleItems(available_settings))
 
+    identifier = URI(
+        title=_(u'Identifier'),
+        readonly=True)
 
-class MetadataEditView(MetadataMinimalEditView):
+    title = TextLine(
+        title=_(u'Title'),
+        required=False,
+        missing_value=u'')
 
-    """Edit view for IMutableDublinCore.
+    description = Text(
+        title=_(u'Description'),
+        required=False,
+        missing_value=u'')
+
+    subject = Set(
+        title=_(u'Subject'),
+        required=False,
+        missing_value=set(),
+        value_type=TextLine())
+
+    contributors = Tuple(
+        title=_(u'Contributors'),
+        required=False,
+        missing_value=(),
+        value_type=TextLine())
+
+    created = Datetime(
+        title=_(u'Creation Date'),
+        readonly=True)
+
+    modified = Datetime(
+        title=_(u'Last Modified Date'),
+        readonly=True)
+
+    effective = Datetime(
+        title=_(u'Effective Date'),
+        required=False
+        )
+
+    expires = Datetime(
+        title=_(u'Expiration Date'),
+        required=False
+        )
+
+    format = TextLine(
+        title=_(u'Format'),
+        required=False,
+        missing_value=u'')
+
+    language = TextLine(
+        title=_(u'Language'),
+        required=False,
+        missing_value=u'')
+
+    rights = TextLine(
+        title=_(u'Rights'),
+        required=False,
+        missing_value=u'')
+
+
+class MinimalMetadataSchemaAdapter(SchemaAdapterBase):
+
+    """Adapter for IMutableMinimalDublinCore.
     """
 
-    _BUTTONS = ({'id': 'change',
-                 'title': _(u'Change'),
-                 'transform': ('edit_control',),
-                 'redirect': ('portal_types', 'object/metadata')},
-                {'id': 'change_and_edit',
-                 'title': _(u'Change and Edit'),
-                 'transform': ('edit_control',),
-                 'redirect': ('portal_types', 'object/edit')},
-                {'id': 'change_and_view',
-                 'title': _(u'Change and View'),
-                 'transform': ('edit_control',),
-                 'redirect': ('portal_types', 'object/view')})
+    adapts(IMutableMinimalDublinCore)
+    implements(IMinimalMetadataSchema)
 
-    #helpers
+    title = ProxyFieldProperty(IMetadataSchema['title'], 'Title', 'setTitle')
+    description = ProxyFieldProperty(IMetadataSchema['description'],
+                                     'Description', 'setDescription')
 
-    def _tuplify(self, value):
-        if isinstance(value, basestring):
-            value = (value,)
-        return tuple([ i for i in value if i ])
 
-    # interface
+class MetadataSchemaAdapter(SchemaAdapterBase):
 
-    @memoize
-    @decode
-    def allow_discussion(self):
-        context = aq_self(self.context)
-        allow_discussion = getattr(context, 'allow_discussion', None)
-        if allow_discussion is not None:
-            allow_discussion = bool(allow_discussion)
-        return allow_discussion
+    """Adapter for IMutableDublinCore.
+    """
 
-    @memoize
-    @decode
-    def identifier(self):
-        return self.context.Identifier()
+    adapts(IMutableDublinCore)
+    implements(IMetadataSchema)
 
-    @memoize
-    @decode
-    def subject(self):
-        subjects = self.request.form.get('subject', self.context.Subject())
-        return tuple(subjects)
+    _effective = ProxyFieldProperty(IMetadataSchema['effective'],
+                                    'effective', 'setEffectiveDate')
+    _expires = ProxyFieldProperty(IMetadataSchema['expires'],
+                                  'expires', 'setExpirationDate')
 
-    @memoize
-    @decode
-    def allowed_subjects(self):
-        mdtool = self._getTool('portal_metadata')
-        subjects = mdtool.listAllowedSubjects(self.context)
-        return tuple(subjects)
+    def _getEffective(self):
+        if self.context.EffectiveDate() == 'None':
+            return None
+        return self._effective
 
-    @memoize
-    @decode
-    def extra_subjects(self):
-        subjects = [ s for s
-                     in self.subject() if not s in self.allowed_subjects() ]
-        return tuple(subjects)
+    def _getExpires(self):
+        if self.context.ExpirationDate() == 'None':
+            return None
+        return self._expires
 
-    @memoize
-    @decode
-    def format(self):
-        return self.request.form.get('format', self.context.Format())
+    def _getAllowDiscussion(self):
+        context = aq_self(self.context)
+        return getattr(context, 'allow_discussion', None)
 
-    @memoize
-    @decode
-    def contributors(self):
-        return self.request.form.get('contributors',
-                                     self.context.Contributors())
+    def _setAllowDiscussion(self, value):
+        dtool = getToolByName(self.context, 'portal_discussion')
+        dtool.overrideDiscussionFor(self.context, value)
 
-    @memoize
-    @decode
-    def language(self):
-        return self.request.form.get('language', self.context.Language())
+    allow_discussion = property(_getAllowDiscussion, _setAllowDiscussion)
+    identifier = ProxyFieldProperty(IMetadataSchema['identifier'],
+                                    'Identifier')
+    title = ProxyFieldProperty(IMetadataSchema['title'], 'Title', 'setTitle')
+    description = ProxyFieldProperty(IMetadataSchema['description'],
+                                     'Description', 'setDescription')
+    subject = ProxyFieldProperty(IMetadataSchema['subject'],
+                                 'Subject', 'setSubject')
+    contributors = ProxyFieldProperty(IMetadataSchema['contributors'],
+                                      'listContributors', 'setContributors')
+    created = ProxyFieldProperty(IMetadataSchema['created'])
+    modified = ProxyFieldProperty(IMetadataSchema['modified'])
+    effective = property(_getEffective, _effective.__set__)
+    expires = property(_getExpires, _expires.__set__)
+    format = ProxyFieldProperty(IMetadataSchema['format'],
+                                     'Format', 'setFormat')
+    language = ProxyFieldProperty(IMetadataSchema['language'],
+                                     'Language', 'setLanguage')
+    rights = ProxyFieldProperty(IMetadataSchema['rights'],
+                                     'Rights', 'setRights')
 
-    @memoize
-    @decode
-    def rights(self):
-        return self.request.form.get('rights', self.context.Rights())
 
-    # controllers
+class MinimalMetadataEditView(ContentEditFormBase):
 
-    def edit_control(self, allow_discussion, title=None, subject=None,
-                     description=None, contributors=None, effective_date=None,
-                     expiration_date=None, format=None, language=None,
-                     rights=None, **kw):
-        context = self.context
-        dtool = self._getTool('portal_discussion')
+    """Edit view for IMutableMinimalDublinCore.
+    """
 
-        if title is None:
-            title = context.Title()
+    form_fields = form.FormFields(IMinimalMetadataSchema)
 
-        if subject is None:
-            subject = context.Subject()
-        else:
-            subject = self._tuplify(subject)
+    label = _(u'Properties')
 
-        if description is None:
-            description = context.Description()
+    def setUpWidgets(self, ignore_request=False):
+        super(MinimalMetadataEditView,
+              self).setUpWidgets(ignore_request=ignore_request)
+        self.widgets['description'].height = 4
 
-        if contributors is None:
-            contributors = context.Contributors()
-        else:
-            contributors = self._tuplify(contributors)
 
-        if effective_date is None:
-            effective_date = context.EffectiveDate()
+class MetadataEditView(ContentEditFormBase):
 
-        if expiration_date is None:
-            expiration_date = context.expires()
+    """Edit view for IMutableDublinCore.
+    """
 
-        if format is None:
-            format = context.Format()
+    actions = form.Actions(
+        form.Action(
+            name='change',
+            label=_(u'Change'),
+            validator='handle_validate',
+            success='handle_change_success',
+            failure='handle_failure'),
+        form.Action(
+            name='change_and_edit',
+            label=_(u'Change and Edit'),
+            validator='handle_validate',
+            success='handle_change_and_edit_success',
+            failure='handle_failure'),
+        form.Action(
+            name='change_and_view',
+            label=_(u'Change and View'),
+            validator='handle_validate',
+            success='handle_change_and_view_success',
+            failure='handle_failure'))
 
-        if language is None:
-            language = context.Language()
+    form_fields = form.FormFields(IMetadataSchema)
+    form_fields['subject'].custom_widget = SubjectInputWidget
+    form_fields['contributors'].custom_widget = TupleTextAreaWidget
+    form_fields['effective'].custom_widget = DatetimeI18nWidget
+    form_fields['expires'].custom_widget = DatetimeI18nWidget
 
-        if rights is None:
-            rights = context.Rights()
+    label = _(u'Properties')
 
-        if allow_discussion == 'default':
-            allow_discussion = None
-        elif allow_discussion == 'off':
-            allow_discussion = False
-        elif allow_discussion == 'on':
-            allow_discussion = True
-        dtool.overrideDiscussionFor(context, allow_discussion)
+    def setUpWidgets(self, ignore_request=False):
+        super(MetadataEditView,
+              self).setUpWidgets(ignore_request=ignore_request)
+        self.widgets['allow_discussion']._messageNoValue = _(u'Default')
+        self.widgets['description'].height = 4
+        self.widgets['subject'].split = True
+        self.widgets['contributors'].height = 6
+        self.widgets['contributors'].split = True
+        self.widgets['created'].split = True
+        self.widgets['modified'].split = True
+        self.widgets['effective'].split = True
+        self.widgets['expires'].split = True
 
-        try:
-            context.editMetadata( title=title
-                                , description=description
-                                , subject=subject
-                                , contributors=contributors
-                                , effective_date=effective_date
-                                , expiration_date=expiration_date
-                                , format=format
-                                , language=language
-                                , rights=rights
-                                )
-            return True, _(u'Metadata changed.')
-        except ResourceLockedError, errmsg:
-            return False, errmsg
+    def handle_change_success(self, action, data):
+        self._handle_success(action, data)
+        return self._setRedirect('portal_types', 'object/metadata')
+
+    def handle_change_and_edit_success(self, action, data):
+        self._handle_success(action, data)
+        return self._setRedirect('portal_types', 'object/edit')

Added: CMF/trunk/CMFDefault/browser/metadata.txt
===================================================================
--- CMF/trunk/CMFDefault/browser/metadata.txt	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/browser/metadata.txt	2006-12-19 18:22:49 UTC (rev 71606)
@@ -0,0 +1,37 @@
+Metadata Views
+--------------
+
+Set up content and user.
+
+    >>> from Products.CMFDefault.Document import Document 
+    >>> id = app.site._setObject('myContent', Document('myContent'))
+    >>> app.site.myContent._setPortalTypeName('Document')
+
+    >>> uf = app.site.acl_users
+    >>> uf._doAddUser('mgr', 'mgrpw', ['Manager'], [])
+
+Create the browser object we'll be using.
+
+    >>> from Products.Five.testbrowser import Browser
+    >>> browser = Browser()
+    >>> browser.handleErrors = False
+    >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+
+Use the edit form with valid input.
+
+    >>> browser.open('http://localhost/site/myContent/@@properties.html')
+    >>> '[[cmf_default][Properties]]' in browser.contents
+    True
+    >>> browser.getControl(name='form.allow_discussion').value = ('off',)
+    >>> browser.getControl(name='form.title').value = 'CONTENT TITLE'
+    >>> browser.getControl(name='form.description').value = 'CONTENT DESCRIPTION.'
+    >>> browser.getControl(name='form.subject').value = 'spam\neggs'
+    >>> browser.getControl(name='form.contributors').value = 'foo\nbar\nbaz'
+    >>> browser.getControl(name='form.effective').value = '2006 11 11  12:00:00 '
+    >>> browser.getControl(name='form.expires').value = '2007 11 11  12:00:00 '
+    >>> browser.getControl(name='form.format').value = 'text/html'
+    >>> browser.getControl(name='form.language').value = 'test'
+    >>> browser.getControl(name='form.rights').value = 'CONTENT RIGHTS'
+    >>> browser.getControl('[[cmf_default][Change]]').click()
+    >>> '[[cmf_default][[[cmf_default][Document]] changed.]]' in browser.contents
+    True


Property changes on: CMF/trunk/CMFDefault/browser/metadata.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Deleted: CMF/trunk/CMFDefault/browser/templates/metadata_edit.pt
===================================================================
--- CMF/trunk/CMFDefault/browser/templates/metadata_edit.pt	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/browser/templates/metadata_edit.pt	2006-12-19 18:22:49 UTC (rev 71606)
@@ -1,118 +0,0 @@
-<html metal:use-macro="context/@@standard_macros/page">
-<body>
-
-<metal:slot metal:fill-slot="body" i18n:domain="cmf_default">
-<h1 i18n:translate="">Resource Metadata: <tal:span
-    tal:content="view/title" i18n:name="obj_title">Title</tal:span></h1>
-
-<form action="metadata_edit_form" method="post"
-   tal:attributes="action view/form_action">
-<table class="FormLayout">
- <tr>
-  <th i18n:translate="">Enable Discussion?</th>
-  <td colspan="3">
-   <select name="allow_discussion">
-    <option value="default"
-       tal:attributes="selected python: view.allow_discussion() is None"
-       i18n:translate="">Default</option>
-    <option value="off"
-       tal:attributes="selected python: view.allow_discussion() is False"
-       i18n:translate="">Off</option>
-    <option value="on"
-       tal:attributes="selected python: view.allow_discussion() is True"
-       i18n:translate="">On</option>
-   </select>
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Identifier</th>
-  <td colspan="3">
-   <tal:span tal:content="view/identifier" />
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Title</th>
-  <td colspan="3">
-   <input type="text" name="title" value="" size="80"
-      tal:attributes="value view/title" />
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Description</th>
-  <td colspan="3">
-   <textarea name="description:text" rows="3" cols="80" wrap="soft"
-      tal:content="view/description"></textarea>
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Subject</th>
-  <td tal:define="subj_lines python: '\n'.join(view.extra_subjects())">
-   <textarea name="subject:lines" rows="3" cols="31"
-      tal:content="subj_lines"></textarea>
-   <br />
-   <select name="subject:list" multiple>
-    <option value=""
-       tal:repeat="subject view/allowed_subjects"
-       tal:attributes="value subject;
-                       selected python: subject in view.subject()"
-       tal:content="subject">
-    </option>
-   </select>
-  </td>
-  <th i18n:translate="">Contributors</th>
-  <td tal:define="contrib_lines python: '\n'.join(view.contributors())">
-   <textarea name="contributors:lines" rows="5" cols="31"
-      tal:content="contrib_lines"></textarea>
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Creation Date</th>
-  <td tal:content="context/CreationDate"></td>
-  <th i18n:translate="">Last Modified Date</th>
-  <td tal:content="context/ModificationDate"></td>
- </tr>
- <tr>
-  <th i18n:translate="">Effective Date</th>
-  <td>
-   <input type="text" name="effective_date" value=""
-      tal:attributes="value context/EffectiveDate" />
-  </td>
-  <th i18n:translate="">Expiration Date</th>
-  <td>
-   <input type="text" name="expiration_date" value=""
-      tal:attributes="value context/ExpirationDate" />
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Format</th>
-  <td colspan="3">
-   <input type="text" name="format" value=""
-      tal:attributes="value view/format" />
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Language</th>
-  <td colspan="3">
-   <input type="text" name="language" value=""
-      tal:attributes="value view/language" />
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Rights</th>
-  <td colspan="3">
-   <input type="text" name="rights" value=""
-      tal:attributes="value view/rights" />
-  </td>
- </tr>
- <tr>
-  <td>&nbsp;</td>
-  <td colspan="3">
-   <metal:macro metal:use-macro="context/@@form_widget/buttons" />
-  </td>
- </tr>
-</table>
-</form>
-</metal:slot>
-
-</body>
-</html>

Deleted: CMF/trunk/CMFDefault/browser/templates/metadata_minimal_edit.pt
===================================================================
--- CMF/trunk/CMFDefault/browser/templates/metadata_minimal_edit.pt	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/browser/templates/metadata_minimal_edit.pt	2006-12-19 18:22:49 UTC (rev 71606)
@@ -1,36 +0,0 @@
-<html metal:use-macro="context/@@standard_macros/page">
-<body>
-
-<metal:slot metal:fill-slot="body" i18n:domain="cmf_default">
-<h1 i18n:translate="">Edit: <tal:span
-    tal:content="view/title" i18n:name="obj_title">Title</tal:span></h1>
-
-<form action="folder_edit_form" method="post"
-   tal:attributes="action view/form_action">
-<table class="FormLayout">
- <tr>
-  <th i18n:translate="">Title</th>
-  <td>
-   <input type="text" name="title" value="" size="80"
-      tal:attributes="value view/title" />
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Description</th>
-  <td>
-   <textarea name="description:text" rows="3" cols="80" wrap="soft"
-      tal:content="view/description"></textarea>
-  </td>
- </tr>
- <tr>
-  <td>&nbsp;</td>
-  <td>
-   <metal:macro metal:use-macro="context/@@form_widget/buttons" />
-  </td>
- </tr>
-</table>
-</form>
-</metal:slot>
-
-</body>
-</html>

Modified: CMF/trunk/CMFDefault/browser/tests.py
===================================================================
--- CMF/trunk/CMFDefault/browser/tests.py	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/browser/tests.py	2006-12-19 18:22:49 UTC (rev 71606)
@@ -16,15 +16,21 @@
 """
 
 import unittest
-import Testing
+from Testing import ZopeTestCase
 from zope.testing import doctest
 
+from Products.CMFDefault.testing import FunctionalLayer
 
+
 def test_suite():
-    return unittest.TestSuite((
-        doctest.DocFileSuite('folder.txt',
-                             optionflags=doctest.NORMALIZE_WHITESPACE),
-        ))
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocFileSuite('folder.txt',
+                                    optionflags=doctest.NORMALIZE_WHITESPACE))
+    s = ZopeTestCase.FunctionalDocFileSuite('metadata.txt')
+    s.layer = FunctionalLayer
+    suite.addTest(s)
+    return suite
 
 if __name__ == '__main__':
-    unittest.main(defaultTest='test_suite')
+    from Products.CMFCore.testing import run
+    run(test_suite())

Modified: CMF/trunk/CMFDefault/formlib/tests.py
===================================================================
--- CMF/trunk/CMFDefault/formlib/tests.py	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/formlib/tests.py	2006-12-19 18:22:49 UTC (rev 71606)
@@ -21,10 +21,12 @@
 
 
 def test_suite():
-    return unittest.TestSuite((
-        doctest.DocFileSuite('schema.txt',
-                             optionflags=doctest.NORMALIZE_WHITESPACE),
-        ))
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocFileSuite('schema.txt',
+                                    optionflags=doctest.NORMALIZE_WHITESPACE))
+    suite.addTest(doctest.DocFileSuite('widgets.txt',
+                                    optionflags=doctest.NORMALIZE_WHITESPACE))
+    return suite
 
 if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')

Modified: CMF/trunk/CMFDefault/formlib/widgets.py
===================================================================
--- CMF/trunk/CMFDefault/formlib/widgets.py	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/formlib/widgets.py	2006-12-19 18:22:49 UTC (rev 71606)
@@ -15,14 +15,25 @@
 $Id$
 """
 
+from zope.app.form import InputWidget
+from zope.app.form.browser import BrowserWidget
+from zope.app.form.browser import MultiSelectSetWidget
 from zope.app.form.browser import TextWidget
+from zope.app.form.browser import TextAreaWidget
 from zope.app.form.interfaces import ConversionError
 from zope.app.form.interfaces import IInputWidget
 from zope.component import adapts
 from zope.interface import implementsOnly
 from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.schema import Set
+from zope.schema import Tuple
+from zope.schema.interfaces import ISet
+from zope.schema.interfaces import ITuple
+from zope.schema.interfaces import ITextLine
 
+from Products.CMFCore.utils import getToolByName
 from Products.CMFDefault.formlib.schema import IEmailLine
+from Products.CMFDefault.formlib.vocabulary import SimpleVocabulary
 from Products.CMFDefault.utils import Message as _
 
 
@@ -39,3 +50,91 @@
             return str(input.strip())
         except (AttributeError, UnicodeEncodeError), err:
             raise ConversionError(_(u'Invalid email address.'), err)
+
+
+class TupleTextAreaWidget(TextAreaWidget):
+
+    implementsOnly(IInputWidget)
+    adapts(ITuple, IBrowserRequest)
+
+    def _toFieldValue(self, input):
+        input = super(TupleTextAreaWidget, self)._toFieldValue(input)
+        if isinstance(input, basestring):
+            input = tuple([ l.strip()
+                            for l in input.splitlines() if l.strip() ])
+
+        if input == ():
+            return self.context.missing_value
+
+        return input
+
+    def _toFormValue(self, value):
+        if value is not None:
+            value = u'\n'.join(value)
+        return super(TupleTextAreaWidget, self)._toFormValue(value)
+
+
+class SubjectInputWidget(InputWidget, BrowserWidget):
+
+    implementsOnly(IInputWidget)
+    adapts(ISet, IBrowserRequest)
+
+    def __init__(self, context, request):
+        super(SubjectInputWidget, self).__init__(context, request)
+        self._widgets = {}
+        self._widget_keys = (1,)
+        self.vocabulary = ()
+        context = getattr(self.context.context, 'context',
+                          self.context.context)
+        mdtool = getToolByName(context, 'portal_metadata')
+        allowed_subjects = mdtool.listAllowedSubjects(context)
+        if allowed_subjects:
+            items = [ (str(v), unicode(v), unicode(v))
+                      for v in allowed_subjects ]
+            self.vocabulary = SimpleVocabulary.fromTitleItems(items)
+            self._widget_keys = (0, 1)
+
+    def _getWidget(self, i):
+        if i not in self._widgets:
+            if i == 0:
+                field = Set(__name__='1').bind(self.context)
+                widget = MultiSelectSetWidget(field, self.vocabulary,
+                                              self.request)
+                widget.setPrefix(self.name)
+                widget.empty_marker_name = widget.name + "-empty-marker"
+                widget.size = 3
+                self._widgets[0] = widget
+            elif i == 1:
+                field = Tuple(__name__='', required=False).bind(self.context)
+                widget = TupleTextAreaWidget(field, self.request)
+                widget.name = self.name
+                widget.height = self.vocabulary and 2 or 6
+                self._widgets[1] = widget
+        return self._widgets[i]
+
+    def getInputValue(self):
+        value = set()
+        for k in self._widget_keys:
+            value = set(self._getWidget(k).getInputValue() or ())|value
+        return value
+
+    def hasInput(self):
+        value = False
+        for k in self._widget_keys:
+            value = self._getWidget(k).hasInput() or value
+        return value
+
+    def __call__(self):
+        values = {0: [], 1: []}
+        if not self._renderedValueSet():
+            value = self.getInputValue()
+        else:
+            value = self._data
+        for item in value or ():
+            if item in self.vocabulary:
+                values[0].append(item)
+            else:
+                values[1].append(item)
+        for k in self._widget_keys:
+            self._getWidget(k).setRenderedValue(set(values[k]))
+        return '\n'.join([ self._getWidget(k)() for k in self._widget_keys ])

Added: CMF/trunk/CMFDefault/formlib/widgets.txt
===================================================================
--- CMF/trunk/CMFDefault/formlib/widgets.txt	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/formlib/widgets.txt	2006-12-19 18:22:49 UTC (rev 71606)
@@ -0,0 +1,126 @@
+Widgets
+
+
+  Testing TupleTextAreaWidget:
+
+    Set one up::
+
+      >>> class DummyRequest(dict):
+      ...     def __init__(self):
+      ...         self.form = {}
+      ...     def get(self, key):
+      ...         return self.form.get(key)
+      >>> request = DummyRequest()
+      >>> request.form['PREFIX.NAME'] = u'FOO \n BAR'
+
+      >>> from Products.CMFDefault.formlib.widgets import TupleTextAreaWidget
+      >>> from zope.schema import Tuple
+      >>> tuple_field = Tuple(__name__='NAME', title=u'FIELD TITLE',
+      ...                     required=False)
+
+      >>> widget = TupleTextAreaWidget(tuple_field, request)
+
+    IWidget::
+
+      >>> widget.name
+      'field.NAME'
+      >>> widget.label
+      u'FIELD TITLE'
+      >>> widget.hint
+      u''
+      >>> widget.visible
+      True
+      >>> widget.setRenderedValue(('BAZ',))
+      >>> widget.setRenderedValue(widget._data_marker)
+      >>> widget.setPrefix('PREFIX')
+      >>> widget.name
+      'PREFIX.NAME'
+
+    IInputWidget::
+
+      >>> widget.required
+      False
+      >>> widget.getInputValue()
+      (u'FOO', u'BAR')
+      >>> #widget.applyChanges(content)
+      >>> widget.hasInput()
+      True
+      >>> widget.hasValidInput()
+      True
+
+    IBrowserWidget::
+
+      >>> print widget()
+      <textarea cols="60" id="PREFIX.NAME" name="PREFIX.NAME" rows="15" >FOO
+      BAR</textarea>
+      >>> print widget.hidden()
+      <input class="hiddenType" id="PREFIX.NAME" name="PREFIX.NAME"
+      type="hidden" value="FOO BAR" />
+      >>> print widget.error()
+
+    Missing input:
+
+      >>> request.form['PREFIX.NAME'] = u' \n '
+      >>> print widget.getInputValue()
+      None
+
+
+  Testing SubjectInputWidget:
+
+    Set one up::
+
+      >>> class DummyTool:
+      ...     def listAllowedSubjects(self, context): return ('SPAM', 'EGGS')
+      >>> class DummyView: pass
+      >>> view = DummyView()
+      >>> view.portal_metadata = DummyTool()
+
+      >>> request = DummyRequest()
+      >>> request.form['PREFIX.NAME.1'] = ['EGGS']
+      >>> request.form['PREFIX.NAME'] = u'FOO \n BAR \n SPAM'
+
+      >>> from Products.CMFDefault.formlib.widgets import SubjectInputWidget
+      >>> from zope.schema import Set
+      >>> set_field = Set(__name__='NAME', title=u'FIELD TITLE').bind(view)
+
+      >>> widget = SubjectInputWidget(set_field, request)
+
+    IWidget::
+
+      >>> widget.name
+      'field.NAME'
+      >>> widget.label
+      u'FIELD TITLE'
+      >>> widget.hint
+      u''
+      >>> widget.visible
+      True
+      >>> widget.setRenderedValue(('BAZ',))
+      >>> widget.setRenderedValue(widget._data_marker)
+      >>> widget.setPrefix('PREFIX')
+      >>> widget.name
+      'PREFIX.NAME'
+
+    IInputWidget::
+
+      >>> widget.required
+      True
+      >>> widget.getInputValue()
+      set([u'EGGS', u'FOO', u'BAR', u'SPAM'])
+      >>> #widget.applyChanges(content)
+      >>> widget.hasInput()
+      True
+      >>> widget.hasValidInput()
+      True
+
+    IBrowserWidget::
+
+      >>> print widget()
+      <div>
+      <select id="PREFIX.NAME.1" multiple="multiple" name="PREFIX.NAME.1:list"
+      size="3" ><option selected="selected" value="SPAM">SPAM</option>
+      <option selected="selected" value="EGGS">EGGS</option></select>
+      <input name="PREFIX.NAME.1-empty-marker" type="hidden" value="1" />
+      </div>
+      <textarea cols="60" id="PREFIX.NAME" name="PREFIX.NAME"
+      rows="2" >FOO BAR</textarea>


Property changes on: CMF/trunk/CMFDefault/formlib/widgets.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: CMF/trunk/CMFDefault/locales/cmf_default.pot
===================================================================
--- CMF/trunk/CMFDefault/locales/cmf_default.pot	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/locales/cmf_default.pot	2006-12-19 18:22:49 UTC (rev 71606)
@@ -24,27 +24,27 @@
 msgid "The login name you selected is already in use or is not valid. Please choose another."
 msgstr ""
 
-#: CMFCore/WorkflowTool.py:234
-#: CMFCore/WorkflowTool.py:267
+#: CMFCore/WorkflowTool.py:225
+#: CMFCore/WorkflowTool.py:251
 msgid "No workflows found."
 msgstr ""
 
-#: CMFCore/WorkflowTool.py:241
+#: CMFCore/WorkflowTool.py:232
 #. Default: ""
 msgid "No workflow provides the '${action_id}' action."
 msgstr ""
 
-#: CMFCore/WorkflowTool.py:248
-#: CMFCore/WorkflowTool.py:287
+#: CMFCore/WorkflowTool.py:239
+#: CMFCore/WorkflowTool.py:271
 msgid "Requested workflow definition not found."
 msgstr ""
 
-#: CMFCore/WorkflowTool.py:277
+#: CMFCore/WorkflowTool.py:261
 #. Default: ""
 msgid "No workflow provides '${name}' information."
 msgstr ""
 
-#: CMFCore/WorkflowTool.py:292
+#: CMFCore/WorkflowTool.py:276
 #. Default: ""
 msgid "Could not get info: ${name}"
 msgstr ""
@@ -99,7 +99,6 @@
 #: CMFDefault/browser/folder.py:374
 #: CMFDefault/browser/folder.py:389
 #: CMFDefault/browser/folder.py:404
-#: CMFDefault/browser/metadata.py:63
 #: CMFDefault/browser/newsitem.py:53
 #: CMFDefault/formlib/form.py:144
 #: CMFDefault/skins/zpt_content/document_edit_control.py:14
@@ -116,8 +115,7 @@
 msgstr ""
 
 #: CMFDefault/browser/document.py:49
-#: CMFDefault/browser/metadata.py:34
-#: CMFDefault/browser/metadata.py:72
+#: CMFDefault/browser/metadata.py:223
 #: CMFDefault/formlib/form.py:100
 #: CMFDefault/skins/zpt_content/document_edit_form.py:34
 #: CMFDefault/skins/zpt_content/file_edit_form.py:25
@@ -134,8 +132,7 @@
 msgstr ""
 
 #: CMFDefault/browser/document.py:54
-#: CMFDefault/browser/metadata.py:38
-#: CMFDefault/browser/metadata.py:80
+#: CMFDefault/browser/metadata.py:235
 #: CMFDefault/formlib/form.py:106
 #: CMFDefault/skins/zpt_content/document_edit_form.py:35
 #: CMFDefault/skins/zpt_content/file_edit_form.py:26
@@ -152,9 +149,9 @@
 #: CMFDefault/browser/favorite.py:40
 #: CMFDefault/browser/link.py:42
 #: CMFDefault/browser/link.py:43
+#: CMFDefault/browser/metadata.py:54
+#: CMFDefault/browser/metadata.py:79
 #: CMFDefault/browser/templates/document_edit.pt:13
-#: CMFDefault/browser/templates/metadata_edit.pt:34
-#: CMFDefault/browser/templates/metadata_minimal_edit.pt:12
 #: CMFDefault/browser/templates/newsitem_edit.pt:12
 #: CMFDefault/skins/zpt_content/document_edit_template.pt:16
 #: CMFDefault/skins/zpt_content/file_edit_template.pt:15
@@ -371,18 +368,110 @@
 msgid "Delete"
 msgstr ""
 
-#: CMFDefault/browser/metadata.py:61
+#: CMFDefault/browser/metadata.py:101
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:72
+msgid "Creation Date"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:105
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:74
+msgid "Last Modified Date"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:109
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:78
+msgid "Effective Date"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:114
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:83
+msgid "Expiration Date"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:119
+#: CMFDefault/browser/templates/document_edit.pt:21
+#: CMFDefault/browser/templates/newsitem_edit.pt:16
+#: CMFDefault/skins/zpt_content/document_edit_template.pt:24
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:90
+#: CMFDefault/skins/zpt_content/newsitem_edit_template.pt:19
+#: CMFDefault/skins/zpt_generic/metadata_help.pt:124
+msgid "Format"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:124
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:97
+#: CMFDefault/skins/zpt_generic/metadata_help.pt:149
+msgid "Language"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:129
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:104
+#: CMFDefault/skins/zpt_generic/metadata_help.pt:199
+msgid "Rights"
+msgstr ""
+
 #: CMFDefault/browser/metadata.py:207
-#: CMFDefault/skins/zpt_content/folder_edit_control.py:7
-#: CMFDefault/skins/zpt_content/metadata_edit_control.py:67
-msgid "Metadata changed."
+#: CMFDefault/browser/metadata.py:246
+msgid "Properties"
 msgstr ""
 
-#: CMFDefault/browser/metadata.py:76
+#: CMFDefault/browser/metadata.py:229
 #: CMFDefault/skins/zpt_content/metadata_edit_form.py:50
 msgid "Change and Edit"
 msgstr ""
 
+#: CMFDefault/browser/metadata.py:251
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:18
+msgid "Default"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:44
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:21
+msgid "Off"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:45
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:24
+msgid "On"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:59
+#: CMFDefault/browser/metadata.py:84
+#: CMFDefault/browser/templates/document_edit.pt:17
+#: CMFDefault/skins/zpt_content/document_edit_template.pt:20
+#: CMFDefault/skins/zpt_content/file_edit_template.pt:19
+#: CMFDefault/skins/zpt_content/folder_edit_template.pt:22
+#: CMFDefault/skins/zpt_content/image_edit_template.pt:19
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:44
+#: CMFDefault/skins/zpt_generic/metadata_help.pt:52
+#: CMFDefault/skins/zpt_generic/search_form_template.pt:67
+#: CMFTopic/skins/zpt_topic/topic_edit_template.pt:22
+msgid "Description"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:70
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:15
+msgid "Enable Discussion?"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:75
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:31
+#: CMFDefault/skins/zpt_generic/metadata_help.pt:136
+msgid "Identifier"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:89
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:51
+#: CMFDefault/skins/zpt_generic/metadata_help.pt:39
+#: CMFDefault/skins/zpt_generic/search_form_template.pt:55
+msgid "Subject"
+msgstr ""
+
+#: CMFDefault/browser/metadata.py:95
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:65
+msgid "Contributors"
+msgstr ""
+
 #: CMFDefault/browser/newsitem.py:49
 #: CMFDefault/skins/zpt_content/newsitem_edit_control.py:11
 msgid "News Item changed."
@@ -404,30 +493,6 @@
 msgid "${DYNAMIC_CONTENT}"
 msgstr ""
 
-#: CMFDefault/browser/templates/document_edit.pt:17
-#: CMFDefault/browser/templates/metadata_edit.pt:41
-#: CMFDefault/browser/templates/metadata_minimal_edit.pt:19
-#: CMFDefault/skins/zpt_content/document_edit_template.pt:20
-#: CMFDefault/skins/zpt_content/file_edit_template.pt:19
-#: CMFDefault/skins/zpt_content/folder_edit_template.pt:22
-#: CMFDefault/skins/zpt_content/image_edit_template.pt:19
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:44
-#: CMFDefault/skins/zpt_generic/metadata_help.pt:52
-#: CMFDefault/skins/zpt_generic/search_form_template.pt:67
-#: CMFTopic/skins/zpt_topic/topic_edit_template.pt:22
-msgid "Description"
-msgstr ""
-
-#: CMFDefault/browser/templates/document_edit.pt:21
-#: CMFDefault/browser/templates/metadata_edit.pt:87
-#: CMFDefault/browser/templates/newsitem_edit.pt:16
-#: CMFDefault/skins/zpt_content/document_edit_template.pt:24
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:90
-#: CMFDefault/skins/zpt_content/newsitem_edit_template.pt:19
-#: CMFDefault/skins/zpt_generic/metadata_help.pt:124
-msgid "Format"
-msgstr ""
-
 #: CMFDefault/browser/templates/document_edit.pt:25
 #: CMFDefault/browser/templates/newsitem_edit.pt:20
 #: CMFDefault/skins/zpt_content/document_edit_template.pt:28
@@ -455,7 +520,6 @@
 msgstr ""
 
 #: CMFDefault/browser/templates/document_edit.pt:5
-#: CMFDefault/browser/templates/metadata_minimal_edit.pt:5
 #: CMFDefault/browser/templates/newsitem_edit.pt:5
 #: CMFDefault/skins/zpt_content/document_edit_template.pt:5
 #: CMFDefault/skins/zpt_content/file_edit_template.pt:5
@@ -517,81 +581,6 @@
 msgid "Link: ${link}"
 msgstr ""
 
-#: CMFDefault/browser/templates/metadata_edit.pt:101
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:104
-#: CMFDefault/skins/zpt_generic/metadata_help.pt:199
-msgid "Rights"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:12
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:15
-msgid "Enable Discussion?"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:15
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:18
-msgid "Default"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:18
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:21
-msgid "Off"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:21
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:24
-msgid "On"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:28
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:31
-#: CMFDefault/skins/zpt_generic/metadata_help.pt:136
-msgid "Identifier"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:48
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:51
-#: CMFDefault/skins/zpt_generic/metadata_help.pt:39
-#: CMFDefault/skins/zpt_generic/search_form_template.pt:55
-msgid "Subject"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:5
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:5
-msgid "Resource Metadata: ${obj_title}"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:62
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:65
-msgid "Contributors"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:69
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:72
-msgid "Creation Date"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:71
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:74
-msgid "Last Modified Date"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:75
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:78
-msgid "Effective Date"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:80
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:83
-msgid "Expiration Date"
-msgstr ""
-
-#: CMFDefault/browser/templates/metadata_edit.pt:94
-#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:97
-#: CMFDefault/skins/zpt_generic/metadata_help.pt:149
-msgid "Language"
-msgstr ""
-
 #: CMFDefault/browser/templates/newsitem_edit.pt:30
 #: CMFDefault/skins/zpt_content/newsitem_edit_template.pt:33
 msgid "Lead-in"
@@ -631,7 +620,7 @@
 msgstr ""
 
 #: CMFDefault/exceptions.py:68
-#: CMFDefault/formlib/widgets.py:41
+#: CMFDefault/formlib/widgets.py:52
 msgid "Invalid email address."
 msgstr ""
 
@@ -987,6 +976,11 @@
 msgid "Download File"
 msgstr ""
 
+#: CMFDefault/skins/zpt_content/folder_edit_control.py:7
+#: CMFDefault/skins/zpt_content/metadata_edit_control.py:67
+msgid "Metadata changed."
+msgstr ""
+
 #: CMFDefault/skins/zpt_content/image_edit_control.py:8
 msgid "Image changed."
 msgstr ""
@@ -999,6 +993,10 @@
 msgid "Link changed."
 msgstr ""
 
+#: CMFDefault/skins/zpt_content/metadata_edit_template.pt:5
+msgid "Resource Metadata: ${obj_title}"
+msgstr ""
+
 #: CMFDefault/skins/zpt_content/transition_form.pt:11
 msgid "Transition of ${objectid}."
 msgstr ""

Modified: CMF/trunk/CMFDefault/skins/zpt_generic/zpt_stylesheet.css
===================================================================
--- CMF/trunk/CMFDefault/skins/zpt_generic/zpt_stylesheet.css	2006-12-19 18:15:37 UTC (rev 71605)
+++ CMF/trunk/CMFDefault/skins/zpt_generic/zpt_stylesheet.css	2006-12-19 18:22:49 UTC (rev 71606)
@@ -461,7 +461,7 @@
 .widget select   { padding: 0 }
 .widget input.textType {
                    min-height: 30px; height: auto !important; height: 24px; }
-.widget.split input.textType { width: 236px; }
+.widget.split input.textType, .widget.split textarea { width: 236px; }
 .widget.split select { width: 244px; }
 .widget ul       { margin: 0 0 0 10px; padding: 0 0 0 10px;
                    list-style-type: disc; }



More information about the CMF-checkins mailing list