Changeset 7840


Ignore:
Timestamp:
11 Mar 2012, 18:47:20 (13 years ago)
Author:
uli
Message:

Some better suited phone widget. Yet not finished (validation missing).

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

Legend:

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

    r7811 r7840  
    2929
    3030"""
     31import grok
    3132import re
    3233import copy
     
    7677    extension = None
    7778
    78     def __init__(self, context, number=None):
     79    def __init__(self, context=None, number=None):
    7980        """Set countrycode, areacode, and extension line from number.
    8081        """
     
    246247        """See zope.formlib.interfaces.IBrowserWidget"""
    247248        return self.template()
     249
     250from zope.formlib.objectwidget import ObjectWidget
     251from zope.schema import Object
     252from waeup.kofa.widgets.objectwidget import KofaObjectWidget, ObjectWidgetView
     253from zc.sourcefactory.contextual import BasicContextualSourceFactory
     254
     255
     256
     257class KofaPhoneWidgetView(ObjectWidgetView):
     258    template = ViewPageTemplateFile('phonewidget2.pt')
     259
     260class PhoneWidget2(KofaObjectWidget):
     261
     262    _fake_value = None
     263
     264    def __init__(self, context, request, **kw):
     265        self._fake_context = Object(IPhoneData, __name__=context.__name__)
     266        super(PhoneWidget2, self).__init__(
     267            self._fake_context, request, PhoneWidgetData, **kw)
     268        return
     269
     270    def _to_fake_value(value):
     271        return PhoneWidgetData(None, value.number)
     272
     273    def _from_fake_value(value):
     274        return value.number
     275
     276    def _getView(self, request):
     277        return KofaPhoneWidgetView(self, request)
     278
     279from zope.formlib.textwidgets import TextWidget, renderElement
     280from zope.component import getUtility
     281from zope.interface import Invalid
     282from zope.formlib.interfaces import WidgetInputError, MissingInputError
     283
     284class IInternationalPhonePrefixes(Interface):
     285    """A dict of international phone number prefixes.
     286    """
     287
     288INT_PHONE_PREFIXES = {
     289        'Germany': '49',
     290        'Nigeria': '234',
     291        'U.S.': '1',
     292        }
     293
     294class PhonePrefixes(grok.GlobalUtility):
     295    grok.implements(IInternationalPhonePrefixes)
     296
     297    _data = INT_PHONE_PREFIXES.items()
     298
     299    def title_value_list(self):
     300        return sorted([('%s (+%s)' % (x,y), y)
     301                       for x,y in self._data])
     302
     303class PhoneWidget2(TextWidget):
     304
     305    subwidget_names = ('country', 'area', 'ext')
     306
     307    #_missing = '--'
     308
     309    def _renderPrefixWidget(self, value):
     310        prefixes = getUtility(
     311            IInternationalPhonePrefixes).title_value_list()
     312        options = []
     313        for ptitle, pval in prefixes:
     314            selected = ''
     315            if value == pval:
     316                selected = ' selected="selected" '
     317            options.append(
     318                '<option value="%s"%s>%s</option>' % (pval, selected, ptitle))
     319        options = '\n'.join(options)
     320        return '<select id="%s" name="%s" size="1" class="span4">\n%s\n</select>' % (
     321            '%s.%s' % (self.name, 'country'),
     322            '%s.%s' % (self.name, 'country'),
     323            options)
     324
     325    def __call__(self):
     326        value = self._getFormValue()
     327        if value is None or value == self.context.missing_value:
     328            value = ''
     329        if len(value.split('-')) < 2:
     330            value = '--' + value
     331        subvalues = value.split('-', 2)
     332
     333        kwargs = {'type': self.type,
     334                  'name': self.name,
     335                  'id': self.name,
     336                  'value': value,
     337                  'cssClass': self.cssClass,
     338                  'style': self.style,
     339                  'size': self.displayWidth,
     340                  'extra': self.extra}
     341        if self.displayMaxWidth:
     342            kwargs['maxlength'] = self.displayMaxWidth # TODO This is untested.
     343        fields = []
     344        for num, subname in enumerate(self.subwidget_names):
     345            if num == 0:
     346                select = self._renderPrefixWidget(subvalues[num])
     347                fields.append(select)
     348                continue
     349                print select
     350            kwargs.update(name = '%s.%s' % (self.name, subname))
     351            kwargs.update(id=kwargs['name'])
     352            # kwargs.update(cssClass = '%s %s' % (self.cssClass, 'span1'))
     353            kwargs.update(cssClass = '%s %s' % ('', 'span2'))
     354            kwargs.update(value = subvalues[num])
     355            fields.append(renderElement(self.tag, **kwargs))
     356        return '-'.join(fields)
     357
     358    def _getFormInput(self):
     359        """Returns current form input.
     360
     361        The value returned must be in a format that can be used as the 'input'
     362        argument to `_toFieldValue`.
     363
     364        The default implementation returns the form value that corresponds to
     365        the widget's name. Subclasses may override this method if their form
     366        input consists of more than one form element or use an alternative
     367        naming convention.
     368        """
     369        result = '-'.join(
     370            [self.request.get('%s.%s' % (self.name, name))
     371             for name in self.subwidget_names])
     372        return result
     373
     374    def hasInput(self):
     375        for name in self.subwidget_names:
     376            if '%s.%s' % (self.name, name) not in self.request.form:
     377                return False
     378        return True
  • main/waeup.kofa/trunk/src/waeup/kofa/widgets/tests/test_phonewidget.py

    r7811 r7840  
    2626# XXX: could we possibly get rid of zope.app.testing?
    2727from zope.app.testing.setup import placefulSetUp, placefulTearDown
    28 from zope.component import provideAdapter
     28from zope.component import provideAdapter, getGlobalSiteManager
     29from zope.formlib import form
    2930from zope.formlib.exception import WidgetInputErrorView
    3031from zope.formlib.interfaces import (
     
    4849        title = u'Phone',
    4950        description = u'Phone number (not required)',
    50         required = False,)
     51        required = False,
     52        missing_value = u'')
    5153
    5254    baz = schema.TextLine(
     
    5456        description = u'Required phone with a default',
    5557        required = True,
    56         default=u'234--')
     58        #default=u'234--'
     59        )
    5760
    5861class SampleContent:
    5962    implements(ISampleContent)
     63
     64    foo = None
     65    bar = 'bar'
     66    baz = None
    6067
    6168class PhoneWidgetTests(unittest.TestCase):
     
    497504             u' value=""  />\n'))
    498505        return
     506
     507import zope.formlib
     508from zope import schema
     509from zope.formlib.tests.test_functional_objectwidget import (
     510    Test, PlacelessSetup, VerifyResults, traversingSetUp, xmlconfig,
     511    PageTemplate, os, DefaultTraversable
     512    )
     513from zope.formlib.tests.test_functional_textwidget import(
     514    FunctionalWidgetTestCase, patternExists)
     515from zope.formlib.widgets import TextWidget
     516from zope.component import adapts
     517from zope.interface import implements
     518from zope.traversing.interfaces import ITraversable
     519from waeup.kofa.widgets.phonewidget import PhoneWidget2, PhonePrefixes
     520
     521class SampleForm(form.EditForm):
     522    form_fields = form.fields(ISampleContent)
     523    form_fields['foo'].custom_widget = PhoneWidget2
     524    form_fields['bar'].custom_widget = PhoneWidget2
     525    form_fields['baz'].custom_widget = PhoneWidget2
     526
     527class PhoneWidget2Tests(FunctionalWidgetTestCase):
     528
     529    widgets = [
     530        (ITextLine, TextWidget),
     531        ]
     532
     533    def setUp(self):
     534        super(PhoneWidget2Tests, self).setUp()
     535        self.gsm = getGlobalSiteManager()
     536        self.reg_prefixes = PhonePrefixes()
     537        self.gsm.registerUtility(self.reg_prefixes)
     538        return
     539
     540    def tearDown(self):
     541        self.gsm.unregisterUtility(self.reg_prefixes)
     542        return
     543
     544    def test_display_editform(self):
     545        content = SampleContent()
     546        request = TestRequest()
     547        html = SampleForm(content, request)()
     548        # foo.country, foo.area and foo.ext exist
     549        self.assert_(patternExists(
     550            '<select .* name="form.foo.country".*>', html))
     551        self.assert_(patternExists(
     552            '<input .* name="form.foo.area".* value="".*>', html))
     553        self.assert_(patternExists(
     554            '<input .* name="form.foo.ext".* value="".*>', html))
     555        return
     556
     557    def test_submit_editform(self):
     558        # we can submit an edit form
     559        content = SampleContent()
     560        request = TestRequest()
     561
     562        # submit edit view
     563        request.form['form.foo.country'] = u'123'
     564        request.form['form.foo.area'] = u'456'
     565        request.form['form.foo.ext'] = u'7890'
     566        request.form['form.actions.apply'] = u''
     567        SampleForm(content, request)()
     568
     569        # check new values in object
     570        self.assertEqual(content.foo, u'123-456-7890')
     571        return
     572
     573    def test_invalid_type(self):
     574        # there is no invalid type for textline-based input
     575        content = SampleContent()
     576        request = TestRequest()
     577
     578        # submit invalid type for text line
     579        request.form['form.foo.country'] = '123'
     580        request.form['form.foo.area'] = '456'
     581        request.form['form.foo.ext'] = '7890'
     582        request.form['form.actions.apply'] = u''
     583        html = SampleForm(content, request)()
     584
     585        # We don't have a invalid field value
     586        # since we convert the value to unicode
     587        self.assert_('Object is of wrong type.' not in html)
     588        return
     589
     590    def test_missing_value(self):
     591        content = SampleContent()
     592        request = TestRequest()
     593
     594        request.form['form.foo.country'] = u'123'
     595        request.form['form.foo.area'] = u'456'
     596        request.form['form.foo.ext'] = u'7890'
     597        request.form['form.bar.country'] = u''
     598        request.form['form.bar.area'] = u''
     599        request.form['form.bar.ext'] = u''
     600        request.form['form.baz.country'] = u''
     601        request.form['form.baz.area'] = u''
     602        request.form['form.baz.ext'] = u''
     603        request.form['form.actions.apply'] = u''
     604        SampleForm(content, request)()
     605
     606        # check new values in object
     607        self.assertEqual(content.foo, u'123-456-7890')
     608        self.assertEqual(content.bar, u'--') # default missing value
     609        self.assertEqual(content.baz, u'--')
     610        return
Note: See TracChangeset for help on using the changeset viewer.