Changeset 7852
- Timestamp:
- 12 Mar 2012, 16:49:10 (13 years ago)
- Location:
- main/waeup.kofa/trunk/src/waeup/kofa
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py
r7828 r7852 798 798 self.browser.getControl(name="form.lastname").value = 'Tester' 799 799 self.browser.getControl(name="form.email").value = 'xx@yy.zz' 800 self.browser.getControl(name="form.phone.country").value = '234'800 self.browser.getControl(name="form.phone.country").value = ['+234'] 801 801 self.browser.getControl(name="form.phone.area").value = '555' 802 self.browser.getControl(name="form.phone.ext ension").value = '6666666'802 self.browser.getControl(name="form.phone.ext").value = '6666666' 803 803 self.browser.getControl("Get login credentials").click() 804 804 self.assertEqual(self.browser.url, -
main/waeup.kofa/trunk/src/waeup/kofa/widgets/phonewidget.py
r7848 r7852 44 44 from zope.schema.interfaces import RequiredMissing 45 45 46 class IPhoneData(Interface):47 """A schema used to generate a Phone widget."""48 49 country = schema.TextLine(50 title=u'Country Code',51 description=u'The country code of the phone number.',52 min_length=1,53 constraint=re.compile(r'^[0-9]+$').search,54 default=u'234', # int. code for nigeria55 required=True)56 57 area = schema.TextLine(58 title=u'Area Code',59 description=u'The area code of the phone number.',60 min_length=1,61 constraint=re.compile(r'^[0-9]+$').search,62 required=True)63 64 extension = schema.TextLine(65 title=u'Direct Line',66 description=u'The direct line of the phone number.',67 min_length=3,68 constraint=re.compile(r'^[0-9]{3,}$').search,69 required=True)70 71 class PhoneWidgetData(object):72 """Phone number data"""73 implements(IPhoneData)74 75 country = None76 area = None77 extension = None78 79 def __init__(self, context=None, number=None):80 """Set countrycode, areacode, and extension line from number.81 """82 self.context = context83 if number is None:84 return85 # handle other types than strings.86 if not isinstance(number, basestring):87 number = str(number)88 parts = number.split('-', 2)89 if len(parts) == 2:90 parts = [None,] + parts91 elif len(parts) == 0:92 return93 elif len(parts) == 1:94 parts = [None, None] + parts95 self.country, self.area, self.extension = parts96 return97 98 @property99 def number(self):100 """Return a valid phone number string of format ``<IC>-<AC>-<EL>``.101 102 where <IC> is the country code (digits only), <AC> is the area103 code and <EL> is the extension line.104 """105 return u'-'.join(106 (self.country or '', self.area or '', self.extension))107 108 109 class PhoneWidget(SimpleInputWidget):110 """Phone Number Widget"""111 implements(IBrowserWidget, IInputWidget)112 113 template = ViewPageTemplateFile('phonewidget.pt')114 _prefix = 'field.'115 _error = None116 widgets = {}117 118 # See zope.formlib.interfaces.IWidget119 name = None120 visible = True121 122 def __init__(self, field, request):123 super(PhoneWidget, self).__init__(field, request)124 value = field.query(field.context)125 self._generateSubWidgets()126 return127 128 def _generateSubWidgets(self):129 """Create the three subwidgets.130 """131 value = self.context.query(self.context.context)132 # We have to modify the adapter according to our own133 # 'required' state. Some ugly workaround134 adapter = copy.deepcopy(IPhoneData)135 for name in 'country', 'area', 'extension':136 adapter[name].required = self.required137 adapters = {adapter: PhoneWidgetData(self, value)}138 self.widgets = form.setUpEditWidgets(139 form.FormFields(IPhoneData),140 self.name, value, self.request, adapters=adapters)141 # The displayWidth cant'be set142 # because it is overridden by Bootstrap css classes143 #self.widgets['country'].displayWidth = 3144 #self.widgets['area'].displayWidth = 5145 #self.widgets['extension'].displayWidth = 10146 # We have to set the cssClass attributes147 self.widgets['country'].cssClass = 'span2'148 self.widgets['area'].cssClass = 'span2'149 self.widgets['extension'].cssClass = 'span3'150 151 return152 153 def setRenderedValue(self, value):154 """See zope.formlib.interfaces.IWidget"""155 if isinstance(value, unicode) and '-' in value:156 country, area, extension = value.split('-', 2)157 self.widgets['country'].setRenderedValue(country)158 self.widgets['area'].setRenderedValue(area)159 self.widgets['extension'].setRenderedValue(extension)160 return161 return162 163 def setPrefix(self, prefix):164 """See zope.formlib.interfaces.IWidget"""165 # Set the prefix locally166 if not prefix.endswith("."):167 prefix += '.'168 self._prefix = prefix169 self.name = prefix + self.context.__name__170 # Now distribute it to the sub-widgets171 self._generateSubWidgets()172 return173 174 def getInputValue(self):175 """See zope.formlib.interfaces.IInputWidget"""176 self._error = None177 try:178 result = u'-'.join((179 self.widgets['country'].getInputValue(),180 self.widgets['area'].getInputValue(),181 self.widgets['extension'].getInputValue() ))182 return result183 except TypeError:184 if self.required:185 return self._missing186 return None187 except ValueError, v:188 self._error = WidgetInputError(189 self.context.__name__, self.label, _(v))190 raise self._error191 except WidgetInputError, e:192 self._error = e193 raise e194 195 def applyChanges(self, content):196 """See zope.formlib.interfaces.IInputWidget"""197 field = self.context198 new_value = self.getInputValue()199 old_value = field.query(content, self)200 # The selection has not changed201 if new_value == old_value:202 return False203 field.set(content, new_value)204 return True205 206 def hasInput(self):207 """See zope.formlib.interfaces.IInputWidget"""208 return (self.widgets['country'].hasInput() and209 (self.widgets['area'].hasInput() and210 self.widgets['extension'].hasInput()))211 212 213 def hasValidInput(self):214 """See zope.formlib.interfaces.IInputWidget"""215 return (self.widgets['country'].hasValidInput() and216 self.widgets['area'].hasValidInput() and217 self.widgets['extension'].hasValidInput())218 219 220 def hidden(self):221 """See zope.formlib.interfaces.IBrowserWidget"""222 output = []223 output.append(self.widgets['country'].hidden())224 output.append(self.widgets['area'].hidden())225 output.append(self.widgets['extension'].hidden())226 return '\n'.join(output)227 228 229 def error(self):230 """See zope.formlib.interfaces.IBrowserWidget"""231 if self._error:232 return getMultiAdapter(233 (self._error, self.request),234 IWidgetInputErrorView).snippet()235 country_error = self.widgets['country'].error()236 if country_error:237 return country_error238 area_error = self.widgets['area'].error()239 if area_error:240 return area_error241 extension_error = self.widgets['extension'].error()242 if extension_error:243 return extension_error244 return ""245 246 def __call__(self):247 """See zope.formlib.interfaces.IBrowserWidget"""248 return self.template()249 46 250 47 from zc.sourcefactory.contextual import BasicContextualSourceFactory … … 282 79 RE_NUMBERS_AND_HYPHENS = re.compile('^[\d\-]+$') 283 80 284 class PhoneWidget 2(TextWidget):81 class PhoneWidget(TextWidget): 285 82 286 83 subwidget_names = ('country', 'area', 'ext') … … 358 155 For the extension line we silently allow slashes as well. 359 156 """ 360 result = super(PhoneWidget 2, self)._toFieldValue(input)157 result = super(PhoneWidget, self)._toFieldValue(input) 361 158 parts = input.split('-', 2) 362 159 if '' in parts and self.context.required: -
main/waeup.kofa/trunk/src/waeup/kofa/widgets/tests/test_phonewidget.py
r7849 r7852 39 39 from waeup.kofa.widgets.phonewidget import PhoneWidget 40 40 41 import zope.formlib 42 from zope import schema 43 from zope.formlib.tests.test_functional_objectwidget import ( 44 Test, PlacelessSetup, VerifyResults, traversingSetUp, xmlconfig, 45 PageTemplate, os, DefaultTraversable 46 ) 47 from zope.formlib.tests.test_functional_textwidget import( 48 FunctionalWidgetTestCase, patternExists) 49 from zope.formlib.widgets import TextWidget 50 from zope.component import adapts 51 from zope.interface import implements 52 from zope.traversing.interfaces import ITraversable 53 from waeup.kofa.widgets.phonewidget import PhoneWidget, PhonePrefixes 54 41 55 # Dummy content 42 56 class ISampleContent(Interface): … … 68 82 self.baz = None 69 83 70 class PhoneWidgetTests(unittest.TestCase):71 # Tests for phone widget72 84 73 def setUp(self):74 placefulSetUp()75 76 # register TextLine views (so that subwidgets can be rendered)77 provideAdapter(78 TextWidget, (ITextLine, IDefaultBrowserLayer), IInputWidget)79 # errors in forms80 provideAdapter(81 WidgetInputErrorView, (IWidgetInputError, IDefaultBrowserLayer),82 IWidgetInputErrorView)83 84 # setup some sample content to bind to (only neccessary for85 # some of the tests)86 self.content = SampleContent()87 self.field = ISampleContent['foo']88 self.field = self.field.bind(self.content)89 self.field_nonreq = ISampleContent['bar']90 self.field_nonreq = self.field_nonreq.bind(self.content)91 self.field_w_default = ISampleContent['baz']92 self.field_w_default = self.field_w_default.bind(self.content)93 94 # create an empty request. We need one to create a widget95 self.request = TestRequest()96 self.widget = PhoneWidget(self.field, self.request)97 self.widget_nonreq = PhoneWidget(self.field_nonreq, self.request)98 return99 100 def tearDown(self):101 placefulTearDown()102 return103 104 def test_ifaces(self):105 # make sure we fullfill interface contracts106 verify.verifyClass(IBrowserWidget, PhoneWidget)107 verify.verifyClass(IInputWidget, PhoneWidget)108 verify.verifyObject(IBrowserWidget, self.widget)109 verify.verifyObject(IInputWidget, self.widget)110 return111 112 def test_attribs_set(self):113 # make sure the public attributes are set correctly114 self.assertEqual(self.widget.name, 'field.foo')115 self.assertEqual(self.widget.label, u'Phone')116 self.assertEqual(self.widget.hint, u'Phone number')117 self.assertEqual(self.widget.visible, True)118 self.assertEqual(self.widget.required, True)119 self.assertEqual(self.widget_nonreq.required, False)120 return121 122 def test_subwidgets_exist(self):123 # make sure we have three sub widgets124 sub_widget1 = self.widget.widgets['country']125 sub_widget2 = self.widget.widgets['area']126 sub_widget3 = self.widget.widgets['extension']127 self.assertTrue(isinstance(sub_widget1, TextWidget))128 self.assertTrue(isinstance(sub_widget2, TextWidget))129 self.assertTrue(isinstance(sub_widget3, TextWidget))130 return131 132 def test_set_rendered_value(self):133 # make sure we render values correctly134 self.widget.setRenderedValue(u'123-456-1234567')135 self.assertEqual(136 self.widget(),137 (u'+ <input class="span2 textType" id="field.foo.country"'138 u' name="field.foo.country" size="20" type="text" value="123" '139 u' />'140 u' -\n'141 u'<input class="span2 textType" id="field.foo.area"'142 u' name="field.foo.area" size="20" type="text" value="456" '143 u' />'144 u' -\n'145 u'<input class="span3 textType" id="field.foo.extension"'146 u' name="field.foo.extension" size="20" type="text"'147 u' value="1234567" />\n'))148 return149 150 def test_set_prefix_default(self):151 # prefix determines the name of widget and its subwidgets.152 self.assertEqual(self.widget.name, 'field.foo')153 self.assertEqual(self.widget.widgets['country'].name,154 'field.foo.country')155 self.assertEqual(self.widget.widgets['area'].name,156 'field.foo.area')157 self.assertEqual(self.widget.widgets['extension'].name,158 'field.foo.extension')159 return160 161 def test_set_prefix_changed(self):162 # when we set the prefix, widget names change163 self.widget.setPrefix('test.')164 self.assertEqual(self.widget.name, 'test.foo')165 self.assertEqual(self.widget.widgets['country'].name,166 'test.foo.country')167 self.assertEqual(self.widget.widgets['area'].name,168 'test.foo.area')169 self.assertEqual(self.widget.widgets['extension'].name,170 'test.foo.extension')171 return172 173 def test_set_prefix_changed_no_dot(self):174 # when we try to set a name without trailing dot, one will be175 # inserted automatically176 self.widget.setPrefix('test')177 self.assertEqual(self.widget.name, 'test.foo')178 self.assertEqual(self.widget.widgets['country'].name,179 'test.foo.country')180 self.assertEqual(self.widget.widgets['area'].name,181 'test.foo.area')182 self.assertEqual(self.widget.widgets['extension'].name,183 'test.foo.extension')184 return185 186 def test_get_input_value(self):187 # we get a string when we want the input value188 request = TestRequest(189 form={190 'field.foo.country': '123',191 'field.foo.area': '456',192 'field.foo.extension': '12345'193 })194 widget = PhoneWidget(self.field, request)195 value = widget.getInputValue()196 self.assertEqual(value, '123-456-12345')197 return198 199 def test_get_input_value_invalid(self):200 # we get errors when valid data is sent201 request = TestRequest(202 form={203 'field.foo.country': 'not-a-number',204 'field.foo.area': '456',205 'field.foo.extension': '12345',206 })207 widget = PhoneWidget(self.field, request)208 self.assertRaises(209 WidgetInputError,210 widget.getInputValue)211 return212 213 def test_apply_changes(self):214 # we can apply passed-in numbers to content objects. The215 # widget is smart enough to detect whether the values really216 # changed.217 class Content(object):218 field = None219 content = Content()220 request = TestRequest(form={221 'field.foo.country': '123',222 'field.foo.area': '456',223 'field.foo.extension': '7890'})224 widget = PhoneWidget(self.field, request)225 result1 = widget.applyChanges(content)226 result2 = widget.applyChanges(content)227 self.assertEqual(result1, True)228 self.assertEqual(content.foo, u'123-456-7890')229 self.assertEqual(result2, False)230 return231 232 def test_has_input(self):233 # we can check whether there is input without actually validating.234 request = TestRequest(form={235 'field.foo.country': '123'})236 widget = PhoneWidget(self.field, request)237 result = widget.hasInput()238 self.assertEqual(result, False)239 240 request = TestRequest(form={241 'field.foo.area': '123'})242 widget = PhoneWidget(self.field, request)243 result = widget.hasInput()244 self.assertEqual(result, False)245 246 request = TestRequest(form={247 'field.foo.extension': '123567'})248 widget = PhoneWidget(self.field, request)249 result = widget.hasInput()250 self.assertEqual(result, False)251 252 request = TestRequest(form={253 'field.foo.country': '123',254 'field.foo.area': '456',255 'field.foo.extension': '7890'})256 widget = PhoneWidget(self.field, request)257 result = widget.hasInput()258 self.assertEqual(result, True)259 260 self.assertEqual(self.widget.hasInput(), False)261 return262 263 def test_has_valid_input(self):264 # we can check for input also including validation265 request = TestRequest(form={266 'field.foo.country': '123'})267 widget = PhoneWidget(self.field, request)268 result = widget.hasValidInput()269 self.assertEqual(result, False)270 271 request = TestRequest(form={272 'field.foo.area': '123'})273 widget = PhoneWidget(self.field, request)274 result = widget.hasValidInput()275 self.assertEqual(result, False)276 277 request = TestRequest(form={278 'field.foo.extension': '123567'})279 widget = PhoneWidget(self.field, request)280 result = widget.hasValidInput()281 self.assertEqual(result, False)282 283 request = TestRequest(form={284 'field.foo.country': '123',285 'field.foo.area': '456',286 'field.foo.extension': '7890'})287 widget = PhoneWidget(self.field, request)288 result = widget.hasValidInput()289 self.assertEqual(result, True)290 291 self.assertEqual(self.widget.hasValidInput(), False)292 return293 294 def test_hidden(self):295 # we can render output as hidden field(s)296 self.widget.setRenderedValue(u'123-456-1234567')297 self.assertEqual(298 self.widget.hidden(),299 (u'<input class="span2 hiddenType" id="field.foo.country"'300 u' name="field.foo.country" type="hidden" value="123" '301 u' />'302 u'\n'303 u'<input class="span2 hiddenType" id="field.foo.area"'304 u' name="field.foo.area" type="hidden" value="456" '305 u' />'306 u'\n'307 u'<input class="span3 hiddenType" id="field.foo.extension"'308 u' name="field.foo.extension" type="hidden"'309 u' value="1234567" />'))310 return311 312 def test_error_extension(self):313 # the widget can handle input errors in extension subwidget314 315 # extension field too short316 request = TestRequest(form={317 'field.foo.country': '123',318 'field.foo.area': '456',319 'field.foo.extension': '0'})320 widget = PhoneWidget(self.field, request)321 try:322 widget.getInputValue()323 self.fail('No error raised')324 except WidgetInputError, e:325 pass326 self.assertEqual(327 e.__repr__(),328 ("WidgetInputError("329 "'extension', u'Direct Line', ConstraintNotSatisfied(u'0'))"))330 self.assertEqual(331 widget.error(),332 u'<span class="error">Constraint not satisfied</span>')333 return334 335 336 def test_error_area(self):337 # the widget can handle input errors in area code subwidget338 339 # area code contains illegal chars340 request = TestRequest(form={341 'field.foo.country': '123',342 'field.foo.area': 'no-number',343 'field.foo.extension': '12345'})344 widget = PhoneWidget(self.field, request)345 try:346 widget.getInputValue()347 self.fail('No error raised')348 except WidgetInputError, e:349 pass350 self.assertEqual(351 e.__repr__(),352 ("WidgetInputError("353 "'area', u'Area Code', ConstraintNotSatisfied(u'no-number'))"))354 self.assertEqual(355 widget.error(),356 u'<span class="error">Constraint not satisfied</span>')357 return358 359 def test_error_country(self):360 # the widget can handle input errors in country code subwidget361 362 # invalid country code363 request = TestRequest(form={364 'field.foo.country': 'XXX',365 'field.foo.area': '456',366 'field.foo.extension': '12345'})367 widget = PhoneWidget(self.field, request)368 try:369 widget.getInputValue()370 self.fail('No error raised')371 except WidgetInputError, e:372 pass373 self.assertEqual(374 e.__repr__(),375 ("WidgetInputError("376 "'country', u'Country Code', ConstraintNotSatisfied(u'XXX'))"))377 self.assertEqual(378 widget.error(),379 u'<span class="error">Constraint not satisfied</span>')380 return381 382 def test_render_wo_data(self):383 # when no data was submitted, the content data will be displayed384 request = TestRequest(form={})385 self.content.foo = u'11-222-3333'386 widget = PhoneWidget(self.field, request)387 self.assertEqual(388 widget(),389 (u'+ <input class="span2 textType" id="field.foo.country"'390 u' name="field.foo.country" size="20" type="text" value="11" '391 u' />'392 u' -\n'393 u'<input class="span2 textType" id="field.foo.area"'394 u' name="field.foo.area" size="20" type="text" value="222" '395 u' />'396 u' -\n'397 u'<input class="span3 textType" id="field.foo.extension"'398 u' name="field.foo.extension" size="20" type="text"'399 u' value="3333" />\n'))400 return401 402 def test_render_with_data(self):403 # when data was in the request, it will override any content value404 request = TestRequest(form={405 'field.foo.country': '11',406 'field.foo.area': '222',407 'field.foo.extension': '3333'})408 self.content.foo = u'22-333-4444'409 widget = PhoneWidget(self.field, request)410 self.assertEqual(411 widget(),412 (u'+ <input class="span2 textType" id="field.foo.country"'413 u' name="field.foo.country" size="20" type="text" value="11" '414 u' />'415 u' -\n'416 u'<input class="span2 textType" id="field.foo.area"'417 u' name="field.foo.area" size="20" type="text" value="222" '418 u' />'419 u' -\n'420 u'<input class="span3 textType" id="field.foo.extension"'421 u' name="field.foo.extension" size="20" type="text"'422 u' value="3333" />\n'))423 return424 425 def test_render_changed_prefix(self):426 # when the prefix is changed, the subwidgets will reflect that427 # properly. This tests a regression: if setPrefix was called428 # on the phone widget, the subwidgets were already assuming429 # that there is no data in the request430 request = TestRequest(form={431 'field.foo.country': '11',432 'field.foo.area': '222',433 'field.foo.extension': '3333'})434 self.content.foo = u'22-333-4444'435 widget = PhoneWidget(self.field, request)436 # when setting a wrong prefix (not in the form), subwidgets437 # will display the content values assuming (correctly) there438 # is no data sent for them in the request.439 widget.setPrefix('not-existent.')440 self.assertTrue('value="4444"' in widget())441 # when setting the right prefix, subwidgets will display the442 # sent form values and not the content values.443 widget.setPrefix('field.')444 self.assertTrue('value="3333"' in widget())445 return446 447 def test_render_changed_prefix(self):448 # when the prefix is changed, the subwidgets will reflect that449 # properly. This tests a regression: if setPrefix was called450 # on the phone widget, the subwidgets were already assuming451 # that there is no data in the request452 request = TestRequest(form={453 'field.foo.country': '11',454 'field.foo.area': '222',455 'field.foo.extension': '3333'})456 self.content.foo = u'22-333-4444'457 widget = PhoneWidget(self.field, request)458 # when setting a wrong prefix (not in the form), subwidgets459 # will display the content values assuming (correctly) there460 # is no data sent for them in the request.461 widget.setPrefix('not-existent.')462 self.assertTrue('value="4444"' in widget())463 # when setting the right prefix, subwidgets will display the464 # sent form values and not the content values.465 widget.setPrefix('field.')466 self.assertTrue('value="3333"' in widget())467 return468 469 def test_non_required_no_input(self):470 # if the bound field requires no input phone widget will cope471 # with that.472 class Content(object):473 field = None474 475 content = Content()476 request = TestRequest(form={477 'field.bar.country': '',478 'field.bar.area': '',479 'field.bar.extension': '',480 })481 widget = PhoneWidget(self.field_nonreq, request)482 result1 = widget.applyChanges(content)483 result2 = widget.getInputValue()484 self.assertEqual(result1, True)485 # without input we get None486 self.assertTrue(content.bar is None)487 self.assertTrue(result2 is None)488 return489 490 def test_set_rendered_with_empty_context_value(self):491 # if we set empty string as rendered value, empty fields are492 # displayed.493 self.widget.setRenderedValue(u'')494 self.assertEqual(495 self.widget(),496 (u'+ <input class="span2 textType" id="field.foo.country"'497 u' name="field.foo.country" size="20" type="text" value="" '498 u' />'499 u' -\n'500 u'<input class="span2 textType" id="field.foo.area"'501 u' name="field.foo.area" size="20" type="text" value="" '502 u' />'503 u' -\n'504 u'<input class="span3 textType" id="field.foo.extension"'505 u' name="field.foo.extension" size="20" type="text"'506 u' value="" />\n'))507 return508 509 import zope.formlib510 from zope import schema511 from zope.formlib.tests.test_functional_objectwidget import (512 Test, PlacelessSetup, VerifyResults, traversingSetUp, xmlconfig,513 PageTemplate, os, DefaultTraversable514 )515 from zope.formlib.tests.test_functional_textwidget import(516 FunctionalWidgetTestCase, patternExists)517 from zope.formlib.widgets import TextWidget518 from zope.component import adapts519 from zope.interface import implements520 from zope.traversing.interfaces import ITraversable521 from waeup.kofa.widgets.phonewidget import PhoneWidget2, PhonePrefixes522 85 523 86 class SampleForm(form.EditForm): 524 87 form_fields = form.fields(ISampleContent) 525 form_fields['foo'].custom_widget = PhoneWidget 2526 form_fields['bar'].custom_widget = PhoneWidget 2527 form_fields['baz'].custom_widget = PhoneWidget 288 form_fields['foo'].custom_widget = PhoneWidget 89 form_fields['bar'].custom_widget = PhoneWidget 90 form_fields['baz'].custom_widget = PhoneWidget 528 91 529 class PhoneWidget 2Tests(FunctionalWidgetTestCase):92 class PhoneWidgetTests(FunctionalWidgetTestCase): 530 93 531 94 widgets = [ … … 536 99 537 100 def setUp(self): 538 super(PhoneWidget 2Tests, self).setUp()101 super(PhoneWidgetTests, self).setUp() 539 102 # register the phone prefixes utility 540 103 self.gsm = getGlobalSiteManager()
Note: See TracChangeset for help on using the changeset viewer.