source: main/waeup.sirp/trunk/src/waeup/sirp/widgets/phonewidget.py @ 7391

Last change on this file since 7391 was 7360, checked in by uli, 13 years ago

Set international code for nigeria as default. This does not work
properly yet.

File size: 7.5 KB
Line 
1##
2## phonewidget.py
3## $Id$
4##
5"""A phone number widget.
6
7This widget is an input widget (not made for display forms but for
8edit and add forms).
9
10It can be used for :class:`zope.schema.TextLine` fields but has to be
11requested by the form manually (otherwise the regular TextLine widget
12will be used for rendering).
13
14The code was mainly taken from usphone implementation in z3c.widget
15(which was designed for outdated zope.app.form (instead of
16zope.formlib or newer form libs). Therefore some modifications were
17neccessary and it might look a bit overloaded.
18
19If you use the PhoneWidget for rendering regular TextLine attributes
20(preferably in edit forms or add forms), the phone number is displayed
21by three input fields representing the international code, the area
22code and the extension line. All three fields require pure numbers as
23input and do not accept other chars.
24
25When the entered input is stored with a context object, it is stored
26as a single unicode string with the numbers divided by single hyphen.
27
28So, input <12>, <111>, <444> becomes the string ``'12-111-444'`` for
29the context object.
30
31"""
32import re
33from waeup.sirp import MessageFactory as _
34from zope import schema
35from zope.browserpage import ViewPageTemplateFile
36from zope.component import getMultiAdapter
37from zope.formlib import form
38from zope.formlib.interfaces import IBrowserWidget, IWidgetInputErrorView
39from zope.formlib.interfaces import IInputWidget, WidgetInputError
40from zope.formlib.widget import SimpleInputWidget
41from zope.interface import Interface, implements
42
43class IPhoneData(Interface):
44    """A schema used to generate a Phone widget."""
45
46    country = schema.TextLine(
47        title=_('Country Code'),
48        description=_('The country code of the phone number.'),
49        min_length=1,
50        constraint=re.compile(r'^[0-9]+$').search,
51        default=u'234', # int. code for nigeria
52        required=True)
53
54    area = schema.TextLine(
55        title=_('Area Code'),
56        description=_('The area code of the phone number.'),
57        min_length=1,
58        constraint=re.compile(r'^[0-9]+$').search,
59        required=True)
60
61    extension = schema.TextLine(
62        title=_('Direct Line'),
63        description=_('The direct line of the phone number.'),
64        min_length=3,
65        constraint=re.compile(r'^[0-9]{3,}$').search,
66        required=True)
67
68
69class PhoneWidgetData(object):
70    """Phone number data"""
71    implements(IPhoneData)
72
73    country = None
74    area = None
75    extension = None
76
77    def __init__(self, context, number=None):
78        """Set countrycode, areacode, and extension line from number.
79        """
80        self.context = context
81        if number is None:
82            return
83        # handle other types than strings.
84        if not isinstance(number, basestring):
85            number = str(number)
86        parts = number.split('-', 2)
87        if len(parts) == 2:
88            parts = [None,] + parts
89        elif len(parts) == 0:
90            return
91        elif len(parts) == 1:
92            parts = [None, None] + parts
93        self.country, self.area, self.extension = parts
94        return
95
96    @property
97    def number(self):
98        """Return a valid phone number string of format ``<IC>-<AC>-<EL>``.
99
100        where <IC> is the country code (digits only), <AC> is the area
101        code and <EL> is the extension line.
102        """
103        return u'-'.join(
104            (self.country or '', self.area or '', self.extension))
105
106
107class PhoneWidget(SimpleInputWidget):
108    """Phone Number Widget"""
109    implements(IBrowserWidget, IInputWidget)
110
111    template = ViewPageTemplateFile('phonewidget.pt')
112    _prefix = 'field.'
113    _error = None
114    widgets = {}
115
116    # See zope.formlib.interfaces.IWidget
117    name = None
118    visible = True
119
120    def __init__(self, field, request):
121        super(PhoneWidget, self).__init__(field, request)
122        value = field.query(field.context)
123        self._generateSubWidgets()
124        return
125
126    def _generateSubWidgets(self):
127        """Create the three subwidgets.
128        """
129        value = self.context.query(self.context.context)
130        adapters = {}
131        adapters[IPhoneData] = PhoneWidgetData(self, value)
132        self.widgets = form.setUpEditWidgets(
133            form.FormFields(IPhoneData),
134            self.name, value, self.request, adapters=adapters)
135        self.widgets['country'].displayWidth = 3
136        self.widgets['area'].displayWidth = 5
137        self.widgets['extension'].displayWidth = 10
138        return
139
140    def setRenderedValue(self, value):
141        """See zope.formlib.interfaces.IWidget"""
142        if isinstance(value, unicode):
143            country, area, extension = value.split('-')
144            self.widgets['country'].setRenderedValue(country)
145            self.widgets['area'].setRenderedValue(area)
146            self.widgets['extension'].setRenderedValue(extension)
147
148
149    def setPrefix(self, prefix):
150        """See zope.formlib.interfaces.IWidget"""
151        # Set the prefix locally
152        if not prefix.endswith("."):
153            prefix += '.'
154        self._prefix = prefix
155        self.name = prefix + self.context.__name__
156        # Now distribute it to the sub-widgets
157        self._generateSubWidgets()
158        return
159
160    def getInputValue(self):
161        """See zope.formlib.interfaces.IInputWidget"""
162        self._error = None
163        try:
164            return u'-'.join((
165                self.widgets['country'].getInputValue(),
166                self.widgets['area'].getInputValue(),
167                self.widgets['extension'].getInputValue() ))
168        except ValueError, v:
169            self._error = WidgetInputError(
170                self.context.__name__, self.label, _(v))
171            raise self._error
172        except WidgetInputError, e:
173            self._error = e
174            raise e
175
176    def applyChanges(self, content):
177        """See zope.formlib.interfaces.IInputWidget"""
178        field = self.context
179        new_value = self.getInputValue()
180        old_value = field.query(content, self)
181        # The selection has not changed
182        if new_value == old_value:
183            return False
184        field.set(content, new_value)
185        return True
186
187    def hasInput(self):
188        """See zope.formlib.interfaces.IInputWidget"""
189        return (self.widgets['country'].hasInput() and
190                (self.widgets['area'].hasInput() and
191                 self.widgets['extension'].hasInput()))
192
193
194    def hasValidInput(self):
195        """See zope.formlib.interfaces.IInputWidget"""
196        return (self.widgets['country'].hasValidInput() and
197            self.widgets['area'].hasValidInput() and
198            self.widgets['extension'].hasValidInput())
199
200
201    def hidden(self):
202        """See zope.formlib.interfaces.IBrowserWidget"""
203        output = []
204        output.append(self.widgets['country'].hidden())
205        output.append(self.widgets['area'].hidden())
206        output.append(self.widgets['extension'].hidden())
207        return '\n'.join(output)
208
209
210    def error(self):
211        """See zope.formlib.interfaces.IBrowserWidget"""
212        if self._error:
213            return getMultiAdapter(
214                (self._error, self.request),
215                IWidgetInputErrorView).snippet()
216        country_error = self.widgets['country'].error()
217        if country_error:
218            return country_error
219        area_error = self.widgets['area'].error()
220        if area_error:
221            return area_error
222        extension_error = self.widgets['extension'].error()
223        if extension_error:
224            return extension_error
225        return ""
226
227    def __call__(self):
228        """See zope.formlib.interfaces.IBrowserWidget"""
229        return self.template()
Note: See TracBrowser for help on using the repository browser.