Changeset 8147


Ignore:
Timestamp:
13 Apr 2012, 16:51:25 (12 years ago)
Author:
uli
Message:

Improve datewidget to set date format from bound schema field.

Location:
main/waeup.kofa/trunk/src/waeup/kofa/widgets
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/widgets/datewidget.py

    r7668 r8147  
    2020"""
    2121from datetime import datetime
    22 from zope.formlib.i18n import _
    2322from zope.formlib.interfaces import ConversionError, IDisplayWidget
    24 from zope.formlib.textwidgets import (
    25     DateWidget, DateDisplayWidget, escape, DatetimeDisplayWidget)
     23from zope.formlib.textwidgets import DateWidget, DateDisplayWidget, escape
    2624from zope.formlib.widget import renderElement, CustomWidgetFactory
    2725from zope.interface import implements
    28 
    29 class FormattedDateWidget(DateWidget):
    30     """A date widget that supports different (and _explicit_) date formats.
    31 
    32     This is an input widget.
    33     """
    34     date_format = '%Y-%m-%d'
    35 
    36     def _toFieldValue(self, input):
    37         if input == self._missing:
    38             return self.context.missing_value
    39         else:
    40             try:
    41                 # In import files we can use the hash symbol at the end of a
    42                 # date string to avoid annoying automatic date transformation
    43                 # by Excel or Calc
    44                 input = input.strip('#')
    45                 value = datetime.strptime(input, self.date_format)
    46             except (ValueError, IndexError), v:
    47                 raise ConversionError("Invalid datetime data", v)
    48         return value.date()
    49 
    50     def _toFormValue(self, value):
    51         if value:
    52             value = value.strftime(self.date_format)
    53         return value
    54 
    55 class FormattedDateDisplayWidget(DateDisplayWidget):
    56     """A date widget that supports different (and _explicit_) date formats.
    57 
    58     This is a display widget.
    59     """
    60     date_format = '%Y-%m-%d'
    61     implements(IDisplayWidget)
    62    
    63     def __call__(self):
    64         if self._renderedValueSet():
    65             content = self._data
    66         else:
    67             content = self.context.default
    68         if content == self.context.missing_value:
    69             return ""
    70         content = content.strftime(self.date_format)
    71         return renderElement("span", contents=escape(content),
    72                              cssClass=self.cssClass)
    7326
    7427#: A dictionary of supported date formats.
     
    9952#: ``us-year``
    10053#:    middle endian format common in the U.S.: ``MM/DD/YYYY``
    101 #:   
     54#:
    10255#: For date display widgets there is naturally no difference between a
    10356#: year and non-year setting (you can for instance use 'le' or 'le-year'
     
    11366    'us-year':  ('datepicker-us-year', '%m/%d/%Y'),
    11467    }
     68
     69#: a dict containing tuples (<FORMAT>, <SHOW_YEAR>) as keys and
     70#: suitable CSS tags as values.
     71FORMATS_BY_VALUE = dict(
     72    [((val[1], 'year' in key), val[0]) for key, val in DATE_FORMATS.items()])
     73
     74class FormattedDateWidget(DateWidget):
     75    """A date widget that supports different (and _explicit_) date formats.
     76
     77    If the widget is bound to a schema field with respective
     78    attributes, it reads its `show_year` and `date_format` attributes
     79    (see waeup.kofa.schema.FormattedDate for an example) and sets a
     80    CSS tag according to these values.
     81
     82    The widget also accepts ISO format as a fallback, even if a
     83    different format was set. This should help with imports.
     84
     85    This is an input widget.
     86    """
     87    date_format = '%Y-%m-%d'
     88    show_year = False
     89
     90    def __init__(self, context, request, *args, **kw):
     91        # try to grab date_format and show_year from bound schema field.
     92        self.date_format = getattr(context, 'date_format', self.date_format)
     93        self.show_year = getattr(context, 'show_year', self.show_year)
     94        self.cssClass = FORMATS_BY_VALUE.get((
     95            self.date_format, self.show_year), self.cssClass)
     96        return super(FormattedDateWidget, self).__init__(
     97            context, request, *args, **kw)
     98
     99    def _toFieldValue(self, input):
     100        # In import files we can use the hash symbol at the end of a
     101        # date string to avoid annoying automatic date transformation
     102        # by Excel or Calc
     103        input = input.strip('#')
     104        if input == self._missing:
     105            return self.context.missing_value
     106        else:
     107            try:
     108                value = datetime.strptime(input, self.date_format)
     109            except (ValueError, IndexError), v:
     110                try:
     111                    # Try ISO format as fallback.
     112                    # This is needed for instance during imports.
     113                    value = datetime.strptime(
     114                        input, FormattedDateWidget.date_format)
     115                except (ValueError, IndexError), v:
     116                    raise ConversionError("Invalid datetime data", v)
     117        return value.date()
     118
     119    def _toFormValue(self, value):
     120        if value:
     121            value = value.strftime(self.date_format)
     122        return value
     123
     124class FormattedDateDisplayWidget(DateDisplayWidget):
     125    """A date widget that supports different (and _explicit_) date formats.
     126
     127    This is a display widget.
     128    """
     129    date_format = '%Y-%m-%d'
     130    implements(IDisplayWidget)
     131
     132    def __call__(self):
     133        if self._renderedValueSet():
     134            content = self._data
     135        else:
     136            content = self.context.default
     137        if content == self.context.missing_value:
     138            return ""
     139        content = content.strftime(self.date_format)
     140        return renderElement("span", contents=escape(content),
     141                             cssClass=self.cssClass)
     142
    115143def FriendlyDateWidget(format):
    116144    """Get a friendly date input widget for `format`.
    117145
    118146    This widget is suitable for edit and add forms.
    119    
     147
    120148    Valid `format` values are the keys of `DATE_FORMATS`
    121149    dict. Default is ``le`` (little endian; DD/MM/YYYY).
     
    134162
    135163    This widget is suitable for display forms.
    136    
     164
    137165    Valid `format` values are the keys of `DATE_FORMATS`
    138166    dict. Default is ``le`` (little endian; DD/MM/YYYY).
    139167
    140168    This widget is not rendered with a specialized CSS tag for
    141     enabling JavaScript datepickers. `css_class` is ignored which means 
     169    enabling JavaScript datepickers. `css_class` is ignored which means
    142170    there is nor difference between e.g. ``le`` and ``le-year``.`
    143171    """
     
    157185    This widget is not rendered with a specialized CSS tag for
    158186    enabling JavaScript datepickers. `css_class` is ignored which means
    159     there is nor difference between e.g. ``le`` and ``le-year``.`
     187    there is no difference between e.g. ``le`` and ``le-year``.`
    160188    """
    161189    css_class, date_format = DATE_FORMATS.get(format, DATE_FORMATS['le'])
  • main/waeup.kofa/trunk/src/waeup/kofa/widgets/tests/test_datewidget.py

    r7811 r8147  
    5555            ('type="text"', 'id="field.foo"', 'name="field.foo"',
    5656                'value="26/03/04"'))
     57
     58    def testProperties(self):
     59        self.assertEqual(self._widget.tag, 'input')
     60        self.assertEqual(self._widget.type, 'text')
     61        # By default the date format is ISO and the rendered CSS 'datepicker'
     62        self.assertEqual(self._widget.cssClass, 'datepicker')
     63        self.assertEqual(self._widget.extra, '')
    5764
    5865    def test_hasInput(self):
Note: See TracChangeset for help on using the changeset viewer.