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

Yvo Schubbe <[email protected]>
Newsgroups gmane.comp.web.zope.cmf.cvs
Message-ID <20061219182249.F38C4203879__36131.8836840384$1166552581$gmane$org@mail.zope.org>
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; }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.