Home | Trees | Indices | Help |
|
---|
|
1 # -*- coding: ascii -*- 2 # 3 # Copyright 2007 - 2012 4 # Andr\xe9 Malo or his licensors, as applicable 5 # 6 # Licensed under the Apache License, Version 2.0 (the "License"); 7 # you may not use this file except in compliance with the License. 8 # You may obtain a copy of the License at 9 # 10 # http://www.apache.org/licenses/LICENSE-2.0 11 # 12 # Unless required by applicable law or agreed to in writing, software 13 # distributed under the License is distributed on an "AS IS" BASIS, 14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 # See the License for the specific language governing permissions and 16 # limitations under the License. 17 """ 18 ===================== 19 HTML forms reloaded 20 ===================== 21 22 Form helper classes. 23 """ 24 __author__ = u"Andr\xe9 Malo" 25 __docformat__ = "restructuredtext en" 26 __all__ = ['normalize_newlines', 'normalize_whitespaces', 'HTMLForm'] 27 28 import re as _re 29 30 from tdi.tools.htmlform._adapters import NullParameterAdapter 31 from tdi.tools.htmlform._input_field_generator import make_input 32 3335 """ Make newline normalizer """ 36 SUB_U = _re.compile(ur'\r?\n|\r').sub 37 SUB_S = _re.compile(r'\r?\n|\r').sub 38 def normalize_newlines(value): # pylint: disable = W0621 39 """ 40 Normalize the newlines of a string 41 42 All newlines are converted to \\n. 43 44 :Parameters: 45 `value` : ``basestring`` 46 The text to normalize 47 48 :Return: The normalized value, the type depends on the input type 49 :Rtype: ``basestring`` 50 """ 51 if isinstance(value, unicode): 52 subber, repl = SUB_U, u"\n" 53 else: 54 subber, repl = SUB_S, "\n" 55 return subber(repl, value)56 return normalize_newlines 57 normalize_newlines = normalize_newlines() 58 5961 """ Make whitespace normalizer """ 62 SUB_U = _re.compile(ur'\s').sub 63 SUB_S = _re.compile(r'\s').sub 64 def normalize_whitespaces(value): # pylint: disable = W0621 65 """ 66 Normalize the whitespaces of a string 67 68 All whitespaces are converted to regular space. 69 70 :Parameters: 71 `value` : ``basestring`` 72 The text to normalize 73 74 :Return: The normalized value, the type depends on the input type 75 :Rtype: ``basestring`` 76 """ 77 if isinstance(value, unicode): 78 subber, repl = SUB_U, u" " 79 else: 80 subber, repl = SUB_S, " " 81 return subber(repl, value)82 return normalize_whitespaces 83 normalize_whitespaces = normalize_whitespaces() 84 8587 """ 88 HTML form helper class 89 90 :IVariables: 91 `_action` : ``basestring`` 92 form action 93 94 `_method` : ``basestring`` 95 form method 96 97 `_param` : `ParameterAdapterInterface` 98 Parameter adapter 99 100 `_upload` : ``bool`` 101 Upload form? 102 103 `_charset` : ``basestring`` 104 Accepted character set for submission 105 106 `_xhtml` : ``bool`` 107 Use XHTML attributes (vs. short attributes)? 108 109 `_pre_proc` : `PreProcInterface` 110 Pre set node processing callable 111 112 `_post_proc` : `PostProcInterface` 113 Post set node processing callable 114 """ 115 # pylint: disable = R0912, R0913 116174 178 param = property(param, doc="Parameter adapter the form is using") 179 183 is_xhtml = property(is_xhtml, doc="XHTML flag setting of the form") 184 188 is_upload = property(is_upload, doc="Upload flag setting of the form") 189 193 accept_charset = property(accept_charset, 194 doc="Accepted charset of the form" 195 ) 196 200 action = property(action, doc="Configured form action") 201 205 method = property(method, doc="Configured form method") 206 207 normalize_newlines = staticmethod(normalize_newlines) 208 normalize_whitespaces = staticmethod(normalize_whitespaces) 209117 - def __init__(self, action=None, method='get', param=None, upload=False, 118 accept_charset='utf-8', xhtml=True, pre_proc=None, 119 post_proc=None):120 """ 121 Initialization 122 123 If you set `upload` to ``True``, the method will be ignored and 124 be set to ``post`` automatically. 125 126 :Parameters: 127 `action` : ``basestring`` 128 Form action URL 129 130 `method` : ``basestring`` 131 form submission method 132 133 `param` : `ParameterAdapterInterface` 134 Parameter adapter. If unset or ``None``, no values 135 will be taken out of the request. This is useful for initial 136 requests showing empty forms as there will be no special handling 137 required for this case. 138 139 `upload` : ``bool`` 140 Is this an upload form? 141 142 `accept_charset` : ``basestring`` 143 Accepted charset(s) for submission, if there are multiple charsets 144 given, they have to be unique and space separated. 145 146 `xhtml` : ``bool`` 147 Use XHTML attributes (vs. short attributes)? 148 149 `pre_proc` : `PreProcInterface` 150 Pre set node processing callable 151 152 `post_proc` : `PostProcInterface` 153 Post set node processing callable 154 """ 155 # pylint: disable = R0913 156 self._action = action 157 self._method = upload and 'post' or method 158 if param is None: 159 param = NullParameterAdapter() 160 self._param = param 161 self._upload = upload 162 self._charset = accept_charset 163 self._xhtml = bool(xhtml) 164 if pre_proc is None: 165 pre_proc_ = None 166 else: 167 def pre_proc_(method, node, *args): 168 """ Pre proc wrapper """ 169 node, kwargs = pre_proc(method, node, dict(args)) 170 return (node,) + tuple([kwargs.get(key, val) 171 for key, val in args])172 self._pre_proc = pre_proc_ 173 self._post_proc = post_proc210 - def form(self, node, hidden=None, hidden_="hidden", autocomplete=None, 211 novalidate=None, raw=False):212 """ 213 Fill in the form starttag 214 215 The following attributes are possibly set: 216 - ``action`` (only if it's not ``None``) 217 - ``method`` 218 - ``accept-charset`` (only if it's not ``None``) 219 - ``enctype`` (only on upload forms) 220 - ``autocomplete`` 221 - ``novalidate`` 222 223 Rendering hidden fields 224 ~~~~~~~~~~~~~~~~~~~~~~~ 225 226 You can use this method to set a list of hidden fields at once. 227 It iterates over `hidden` and multiplies the node named by `hidden_` 228 accordingly. 229 230 The `hidden` iterable contains tuples of variable length, namely 231 from 1 to 3, like:: 232 233 [ 234 ('foo', 'bar'), 235 ('zonk', '"plop"', True), 236 ('x',), 237 ] 238 239 If `hidden` is empty, the hidden node will be deleted. 240 241 Field item tuples 242 ----------------- 243 244 The first (and maybe only) item is the name of the field. This 245 is always set unconditionally. 246 247 The second item is the value of the field. If the field does not 248 have a value at all - the second and third items are left out, 249 leaving the name only. 250 If the value is ``None`` it's taken out of the request and filled 251 into the field. The third parameter is ignored in this case. If the 252 name does not appear in the request, the field is skipped (not 253 rendered). If the request contains more than one value under 254 that name, a hidden field is generated for each of them. 255 In all other cases the value is written into the ``value`` attribute. 256 257 The third item determines whether the value should be treated 258 as raw or not. If it's unset, the `raw` parameter of the method 259 applies. 260 261 :Parameters: 262 `node` : `tdi.nodetree.Node` 263 The ``<form>`` node 264 265 `hidden` : iterable 266 Hidden fields to set. If unset or ``None``, no hidden 267 fields are touched. If it's an empty list, the hidden node is 268 removed. 269 270 `hidden_` : ``basestring`` 271 Name of the hidden field node, relative to the form 272 `node` (dotted notation) 273 274 `autocomplete` : ``bool`` 275 Set the default autocomplete state of the form (HTML5). If omitted 276 or ``None``, any autocomplete attribute present won't be touched. 277 278 `novalidate` : ``bool`` 279 Set the default novalidate attribute of the form (HTML5). If 280 omitted or ``None``, any novalidate attribute present won't be 281 touched. 282 283 `raw` : ``bool`` 284 Default "rawness" value for the hidden field list 285 """ 286 # pylint: disable = R0912 287 pre_proc = self._pre_proc 288 if pre_proc is not None: 289 node, hidden, hidden_, raw = pre_proc('form', node, 290 ('hidden', hidden), ('hidden_', hidden_), ('raw', raw), 291 ) 292 293 if self._action is not None: 294 node[u'action'] = self._action 295 node[u'method'] = self._method 296 if self._charset is not None: 297 node[u'accept-charset'] = self._charset 298 if autocomplete is not None: 299 node[u'autocomplete'] = autocomplete and u'on' or u'off' 300 if self._upload: 301 node[u'enctype'] = u'multipart/form-data' 302 if novalidate is not None: 303 if novalidate: 304 node[u'novalidate'] = self._xhtml and u'novalidate' or None 305 else: 306 del node[u'novalidate'] 307 308 post_proc = self._post_proc 309 if post_proc is not None: 310 post_proc('form', node, dict( 311 hidden=hidden, hidden_=hidden_, raw=raw 312 )) 313 314 if hidden is not None: 315 partnodes = hidden_.split('.') 316 partnodes.reverse() 317 hiddennode = node(partnodes.pop()) 318 while partnodes: 319 hiddennode = hiddennode(partnodes.pop()) 320 321 # hidden fields 322 param = self._param 323 filtered = [] 324 for field in hidden: 325 name, value, thisraw = field[0], field[1:2], field[2:3] 326 if value: 327 value = value[0] 328 if value is None: 329 rval = param.getlist(name) 330 filtered.extend([(name, val, False) for val in rval]) 331 else: 332 filtered.append((name, value, (thisraw or [raw])[0])) 333 else: 334 filtered.append((name, None, None)) 335 for subnode, param in hiddennode.iterate(filtered): 336 self.hidden(subnode, *param)337 379 380 text = make_input('text', '', 381 'name', 'value', 'maxlength', 'readonly', 'disabled', 'required', 382 'autocomplete', 'placeholder', 'list', 'pattern', 'dirname', 383 'autofocus', 'raw', 384 ) 385 search = make_input('search', '(HTML5)', 386 'name', 'value', 'maxlength', 'readonly', 'disabled', 'required', 387 'autocomplete', 'placeholder', 'list', 'pattern', 388 'dirname', 'autofocus', 'raw', 389 ) 390 tel = make_input('tel', '(HTML5)', 391 'name', 'value', 'maxlength', 'readonly', 'disabled', 'required', 392 'autocomplete', 'placeholder', 'list', 'pattern', 'autofocus', 'raw', 393 ) 394 url = make_input('url', '(HTML5)', 395 'name', 'value', 'maxlength', 'readonly', 'disabled', 'required', 396 'autocomplete', 'placeholder', 'list', 'pattern', 'autofocus', 'raw', 397 ) 398 email = make_input('email', '(HTML5)', 399 'name', 'value', 'maxlength', 'readonly', 'disabled', 'required', 400 'autocomplete', 'placeholder', 'list', 'pattern', 401 'multiple', 'autofocus', 'raw', 402 ) 403 password = make_input('password', '', 404 'name', 'maxlength', 'readonly', 'disabled', 'required', 405 'autocomplete', 'placeholder', 'pattern', 'autofocus', 406 ) 407 datetime = make_input('datetime', '(HTML5)\n\n ' 408 '(e.g. ``1979-10-14T12:00:00.001-04:00``)', 409 'name', 'value', 'readonly', 'disabled', 'required', 'autocomplete', 410 'list', 'max', 'min', 'step', 'autofocus', 'raw', 411 ) 412 date = make_input('date', '(HTML5)\n\n (e.g. ``1979-10-14``)', 413 'name', 'value', 'readonly', 'disabled', 'required', 'autocomplete', 414 'list', 'max', 'min', 'step', 'autofocus', 'raw', 415 ) 416 month = make_input('month', '(HTML5)\n\n (e.g. ``1979-10``)', 417 'name', 'value', 'readonly', 'disabled', 'required', 'autocomplete', 418 'list', 'max', 'min', 'step', 'autofocus', 'raw', 419 ) 420 week = make_input('week', '(HTML5)\n\n (e.g. ``1979-W42``)', 421 'name', 'value', 'readonly', 'disabled', 'required', 'autocomplete', 422 'list', 'max', 'min', 'step', 'autofocus', 'raw', 423 ) 424 time = make_input('time', '(HTML5)\n\n (e.g. ``12:00:00.001``)', 425 'name', 'value', 'readonly', 'disabled', 'required', 'autocomplete', 426 'list', 'max', 'min', 'step', 'autofocus', 'raw', 427 ) 428 datetime_local = make_input('datetime-local', '(HTML5)\n\n ' 429 '(e.g. ``1979-10-14T12:00:00.001``)', 430 'name', 'value', 'readonly', 'disabled', 'required', 'autocomplete', 431 'list', 'max', 'min', 'step', 'autofocus', 'raw', 432 ) 433 number = make_input('number', '(HTML5)', 434 'name', 'value', 'readonly', 'disabled', 'required', 'autocomplete', 435 'placeholder', 'list', 'max', 'min', 'step', 'autofocus', 'raw', 436 ) 437 range = make_input('range', '(HTML5)', 438 'name', 'value', 'disabled', 'autocomplete', 'list', 'max', 439 'autofocus', 'min', 'step', 'raw', 440 ) 441 color = make_input('color', '(HTML5)\n\n (e.g. ``#D4D0C8``)', 442 'name', 'value', 'disabled', 'autocomplete', 'list', 'raw', 443 'autofocus', 444 ) 445 checkbox = make_input('checkbox', '', 446 'name', 'value', 'disabled', 'required', 'selected', 'autofocus', 447 value_default=u'1', multi_selected=True, 448 ) 449 radio = make_input('radio', '', 450 'name', 'value', 'disabled', 'required', 'selected', 'autofocus', 451 value_default=None, multi_selected=False, 452 ) 453 file = make_input('file', '', 454 'name', 'accept', 'disabled', 'required', 'multiple', 'autofocus', 455 assert_upload=True, 456 ) 457 submit = make_input('submit', '', 458 'name', 'value', 'disabled', 'action', 'enctype', 'method', 459 'novalidate', 'target', 'autofocus', 460 simple_value=True, name_optional=True, 461 ) 462 image = make_input('image', '', 463 'name', 'disabled', 'alt', 'src', 'width', 'height', 'action', 464 'enctype', 'method', 'novalidate', 'target', 'autofocus', 465 name_optional=True, 466 ) 467 reset = make_input('reset', '', 468 'value', 'disabled', 'autofocus', 469 simple_value=True, 470 ) 471 button = make_input('button', '', 472 'name', 'value', 'disabled', 'autofocus', 473 simple_value=True, name_optional=True, 474 ) 475476 - def textarea(self, node, name, value=None, maxlength=None, readonly=None, 477 disabled=None, required=None, placeholder=None, dirname=None, 478 autofocus=None, raw=False):479 """ 480 Render a 'textarea' input control 481 482 :Parameters: 483 `node` : `tdi.nodetree.Node` 484 The 'textarea' node 485 486 `name` : ``basestring`` 487 The name of the 'textarea' field 488 489 `value` : ``basestring`` 490 Optional value. If ``None``, it's taken out of the request. If 491 it does not appear in the request, it's treated like an empty 492 string. The `raw` parameter is ignored in this case. 493 494 `maxlength` : ``int`` 495 Maximum length. If omitted or ``None``, the attribute is 496 *deleted*. 497 498 `readonly` : ``bool`` 499 Readonly field? If unset or ``None``, the attribute is left 500 untouched. 501 502 `disabled` : ``bool`` 503 Disabled field? If unset or ``None``, the attribute is left 504 untouched. 505 506 `required` : ``bool`` 507 Required field? (HTML5). If omitted or ``None``, the attribute 508 is left untouched. 509 510 `placeholder` : ``basestring`` 511 Placeholder value (HTML5). If omitted or ``None``, the 512 attribute is left untouched. 513 514 `dirname` : ``basestring`` 515 Direction submission name (HTML5). If omitted or ``None``, the 516 attribute is left untouched. 517 518 `autofocus` : ``bool`` 519 Set autofocus? (HTML5). If omitted or ``None``, the attribute 520 is left untouched. 521 522 `raw` : ``bool`` 523 Is the value to be treated raw? 524 """ 525 pre_proc = self._pre_proc 526 if pre_proc is not None: 527 ( 528 node, name, value, maxlength, readonly, disabled, 529 required, placeholder, dirname, autofocus, raw 530 ) = pre_proc('textarea', node, 531 ('name', name), ('value', value), ('maxlength', 532 maxlength), ('readonly', readonly), ('disabled', 533 disabled), ('required', required), ('placeholder', 534 placeholder), ('dirname', dirname), ('autofocus', 535 autofocus), ('raw', raw) 536 ) 537 538 if name is not None: 539 node[u'name'] = name 540 if readonly is not None: 541 if readonly: 542 node[u'readonly'] = self._xhtml and u'readonly' or None 543 else: 544 del node[u'readonly'] 545 if disabled is not None: 546 if disabled: 547 node[u'disabled'] = self._xhtml and u'disabled' or None 548 else: 549 del node[u'disabled'] 550 if required is not None: 551 if required: 552 node[u'required'] = self._xhtml and u'required' or None 553 else: 554 del node[u'required'] 555 if autofocus is not None: 556 if autofocus: 557 node[u'autofocus'] = self._xhtml and u'autofocus' or None 558 else: 559 del node[u'autofocus'] 560 if placeholder is not None: 561 node[u'placeholder'] = placeholder 562 if dirname is not None: 563 node[u'dirname'] = dirname 564 if value is None: 565 value, raw = self._param.getfirst(name, u''), False 566 if not raw: 567 value = self.normalize_newlines(value).rstrip() 568 if maxlength is not None: 569 value = value[:int(maxlength)] 570 node[u'maxlength'] = unicode(maxlength) 571 else: 572 del node[u'maxlength'] 573 if raw: 574 node.raw.content = value 575 else: 576 node.content = value 577 578 post_proc = self._post_proc 579 if post_proc is not None: 580 post_proc('textarea', node, dict( 581 name=name, value=value, maxlength=maxlength, 582 readonly=readonly, disabled=disabled, required=required, 583 placeholder=placeholder, dirname=dirname, 584 autofocus=autofocus, raw=raw 585 ))586587 - def select(self, node, name, options=None, selected=None, option="option", 588 disabled=None, required=None, autofocus=None, multiple=False):589 r""" 590 Render a 'select' input control 591 592 This method actually renders two nodes, namely the ``select`` 593 element and the ``option`` element:: 594 595 <select tdi="node"> 596 <option tdi="*option">foo</option> 597 </select> 598 599 The option node is repeated as necessary (matching the entries of 600 the `options` parameter). If `options` is empty, the whole ``select`` 601 node is emptied. The option is usually flagged with an asterisk, so 602 it doesn't trigger an automatic render-method call. 603 604 :Parameters: 605 `node` : `tdi.nodetree.Node` 606 The 'select' input node 607 608 `name` : ``basestring`` 609 The name of the 'select' field 610 611 `options` : iterable 612 The list of option values. Each item is expected to 613 be a 2-tuple of the option value and its description. The value 614 is what's put into the option's ``value`` attribute and submitted 615 by the browser if the option is selected. The description is the 616 visible part of the option. If the value is ``None``, it's treated 617 unset and the description is submitted as selected value instead. 618 If `options` is ``None``, only the ``select`` element will be 619 touched. 620 621 `selected` : ``basestring`` or iterable 622 The pre-selected value. If it's unset or ``None``, it's 623 taken out of the request. If it does not appear in the request, 624 there just won't be any pre-selected option. If `multiple` is 625 true, `selected` is expected to be an *iterable* of 626 ``basestring``\s. 627 628 `option` : ``str`` 629 The node of the ``option`` node, relative to the 630 ``select`` node. The parameter is expected in dotted notation. 631 632 `disabled` : ``bool`` 633 Disabled field? If unset or ``None``, the attribute is left 634 untouched. 635 636 `required` : ``bool`` 637 Required field? (HTML5). If omitted or ``None``, the attribute 638 is left untouched. 639 640 `autofocus` : ``bool`` 641 Set autofocus? (HTML5). If omitted or ``None``, the attribute 642 is left untouched. 643 644 `multiple` : ``bool`` 645 Is it a multiselect box? `selected` is expected to 646 be an ``iterable`` containing multiple selected values in this 647 case. 648 """ 649 # pylint: disable = R0914 650 # (too many local variables. well.) 651 652 pre_proc = self._pre_proc 653 if pre_proc is not None: 654 ( 655 node, name, options, selected, option, disabled, 656 required, autofocus, multiple 657 ) = pre_proc('select', node, 658 ('name', name), ('options', options), ('selected', 659 selected), ('option', option), ('disabled', 660 disabled), ('required', required), ('autofocus', 661 autofocus), ('multiple', multiple) 662 ) 663 664 if name is not None: 665 node[u'name'] = name 666 if disabled is not None: 667 if disabled: 668 node[u'disabled'] = self._xhtml and u'disabled' or None 669 else: 670 del node[u'disabled'] 671 if required is not None: 672 if required: 673 node[u'required'] = self._xhtml and u'required' or None 674 else: 675 del node[u'required'] 676 if autofocus is not None: 677 if autofocus: 678 node[u'autofocus'] = self._xhtml and u'autofocus' or None 679 else: 680 del node[u'autofocus'] 681 682 if options is not None: 683 options = list(options) 684 partnodes = option.split('.') 685 partnodes.reverse() 686 optnode = node(partnodes.pop()) 687 while partnodes: 688 optnode = optnode(partnodes.pop()) 689 if multiple: 690 node[u'multiple'] = self._xhtml and u'multiple' or None 691 if options is not None: 692 if selected is None: 693 selected = self._param.getlist(name) 694 selected_ = dict([(item, None) for item in selected]) 695 else: 696 del node[u'multiple'] # just in case 697 if options is not None: 698 if selected is None: 699 selected = self._param.getfirst(name) 700 selected_ = {selected: None} 701 702 post_proc = self._post_proc 703 if post_proc is not None: 704 post_proc('select', node, dict( 705 name=name, options=options, selected=selected, 706 option=option, disabled=disabled, required=required, 707 autofocus=autofocus, multiple=multiple 708 )) 709 710 if options is not None: 711 for subnode, tup in optnode.iterate(options): 712 value, desc, disabled = tup[0], tup[1], tup[2:] 713 if value is not None: 714 is_selected = unicode(value) in selected_ 715 else: 716 is_selected = unicode(desc) in selected_ 717 self.option(subnode, value, 718 description=desc, 719 selected=is_selected, 720 disabled=disabled and disabled[0] or None, 721 )722723 - def multiselect(self, node, name, options=None, selected=None, 724 option="option", disabled=None, required=None, 725 autofocus=None):726 """ 727 :Deprecated: Use ``select`` with a true ``multiple`` argument instead. 728 """ 729 pre_proc = self._pre_proc 730 if pre_proc is not None: 731 ( 732 node, name, options, selected, option, disabled, 733 required, autofocus 734 ) = pre_proc('multiselect', node, 735 ('name', name), ('options', options), ('selected', 736 selected), ('option', option), ('disabled', 737 disabled), ('required', required), ('autofocus', 738 autofocus) 739 ) 740 741 if name is not None: 742 node[u'name'] = name 743 if disabled is not None: 744 if disabled: 745 node[u'disabled'] = self._xhtml and u'disabled' or None 746 else: 747 del node[u'disabled'] 748 if required is not None: 749 if required: 750 node[u'required'] = self._xhtml and u'required' or None 751 else: 752 del node[u'required'] 753 if autofocus is not None: 754 if autofocus: 755 node[u'autofocus'] = self._xhtml and u'autofocus' or None 756 else: 757 del node[u'autofocus'] 758 759 if options is not None: 760 options = list(options) 761 partnodes = option.split('.') 762 partnodes.reverse() 763 optnode = node(partnodes.pop()) 764 while partnodes: 765 optnode = optnode(partnodes.pop()) 766 node[u'multiple'] = self._xhtml and u'multiple' or None 767 if options is not None: 768 if selected is None: 769 selected = self._param.getlist(name) 770 selected_ = dict([(item, None) for item in selected]) 771 772 post_proc = self._post_proc 773 if post_proc is not None: 774 post_proc('multiselect', node, dict( 775 name=name, options=options, selected=selected, 776 option=option, disabled=disabled, required=required, 777 autofocus=autofocus 778 )) 779 780 if options is not None: 781 for subnode, tup in optnode.iterate(options): 782 value, desc, disabled = tup[0], tup[1], tup[2:] 783 if value is not None: 784 is_selected = unicode(value) in selected_ 785 else: 786 is_selected = unicode(desc) in selected_ 787 self.option(subnode, value, 788 description=desc, 789 selected=is_selected, 790 disabled=disabled and disabled[0] or None, 791 )792794 """ 795 Render a 'datalist' element (especially its options) 796 797 This method actually renders two nodes, namely the ``datalist`` 798 element and the ``option`` element:: 799 800 <datalist tdi="node"> 801 <option tdi="*option" /> 802 </datalist> 803 804 The option node is repeated as necessary (matching the entries of 805 the `options` parameter). If `options` is empty, the whole 806 ``datalist`` node is emptied. The option is usually flagged with an 807 asterisk, so it doesn't trigger an automatic render-method call. 808 809 :Parameters: 810 `node` : `tdi.nodetree.Node` 811 The 'datalist' node 812 813 `id` : ``basestring`` 814 The ``id`` attribute of the 'datalist' field. If omitted or 815 ``None``, the attribute is left untouched. 816 817 `options` : iterable 818 The list of option values. Each item is expected to 819 be a 2-tuple of the option value and its description. The value 820 is what's put into the option's ``value`` attribute. The 821 description is the visible part of the option and put into the 822 'label' attribute. If the value is ``None``, it's treated as 823 unset. If `options` is ``None``, only the ``datalist`` element 824 will be touched. 825 826 `option` : ``str`` 827 The node of the ``option`` node, relative to the 828 ``select`` node. The parameter is expected in dotted notation. 829 """ 830 # pylint: disable = C0103, W0622 831 832 pre_proc = self._pre_proc 833 if pre_proc is not None: 834 ( 835 node, id, options, option 836 ) = pre_proc('datalist', node, 837 ('id', id), ('options', options), ('option', option) 838 ) 839 840 if id is not None: 841 node[u'id'] = id 842 843 if options is not None: 844 options = list(options) 845 partnodes = option.split('.') 846 partnodes.reverse() 847 optnode = node(partnodes.pop()) 848 while partnodes: 849 optnode = optnode(partnodes.pop()) 850 851 post_proc = self._post_proc 852 if post_proc is not None: 853 post_proc('datalist', node, dict( 854 id=id, options=options, option=option 855 )) 856 857 if options is not None: 858 for subnode, tup in optnode.iterate(options): 859 value, desc, disabled = tup[0], tup[1], tup[2:] 860 self.option(subnode, value, 861 label=desc, 862 disabled=disabled and disabled[0] or None 863 )864865 - def option(self, node, value, description=None, selected=None, 866 disabled=None, label=None):867 """ 868 Render a single option 869 870 :Parameters: 871 `node` : `tdi.nodetree.Node` 872 The option node 873 874 `value` : ``basestring`` 875 The option value, if ``None``, the attribute will be 876 removed. 877 878 `description` : ``basestring`` 879 The visible part of the option. If omitted or ``None``, the 880 element's content is left untouched. 881 882 `selected` : ``bool`` 883 Is the option selected? If unset or ``None`` the 884 attribute will be left untouched. 885 886 `disabled` : ``bool`` 887 Is this option disabled? If unset or ``None``, the 888 attribute will be left untouched. 889 890 `label` : ``basestring`` 891 Label attribute (HTML5). If omitted or ``None``, any existing 892 attribute is deleted. 893 """ 894 pre_proc = self._pre_proc 895 if pre_proc is not None: 896 ( 897 node, value, description, selected, disabled, label 898 ) = pre_proc('option', node, 899 ('value', value), ('description', description), 900 ('selected', selected), ('disabled', disabled), ('label', 901 label) 902 ) 903 904 if value is None: 905 del node[u'value'] 906 else: 907 node[u'value'] = value 908 if label is None: 909 del node[u'label'] 910 else: 911 node[u'label'] = label 912 if selected is not None: 913 if selected: 914 node[u'selected'] = self._xhtml and u'selected' or None 915 else: 916 del node[u'selected'] 917 if disabled is not None: 918 if disabled: 919 node[u'disabled'] = self._xhtml and u'disabled' or None 920 else: 921 del node[u'disabled'] 922 if description is not None: 923 node.content = description 924 925 post_proc = self._post_proc 926 if post_proc is not None: 927 post_proc('option', node, dict( 928 value=value, description=description, selected=selected, 929 disabled=disabled, label=label, 930 ))931932 - def keygen(self, node, name, keytype=None, challenge=None, disabled=None, 933 autofocus=None):934 """ 935 Render a 'keygen' input control 936 937 :Parameters: 938 `node` : `tdi.nodetree.Node` 939 The 'keygen' node 940 941 `name` : ``basestring`` 942 The name of the 'keygen' field 943 944 `keytype` : ``basestring`` 945 Optional keytype. If omitted or ``None``, the attribute is left 946 untouched. 947 948 `challenge` : ``basestring`` 949 Optional challenge value. If omitted or ``None``, the attribute is 950 left untouched. 951 952 `disabled` : ``bool`` 953 Disabled field? If unset or ``None``, the attribute is left 954 untouched. 955 956 `autofocus` : ``bool`` 957 Set autofocus? (HTML5). If omitted or ``None``, the attribute 958 is left untouched. 959 """ 960 pre_proc = self._pre_proc 961 if pre_proc is not None: 962 ( 963 node, name, keytype, challenge, disabled, autofocus 964 ) = pre_proc('keygen', node, 965 ('name', name), ('keytype', keytype), ('challenge', 966 challenge), ('disabled', disabled), ('autofocus', 967 autofocus) 968 ) 969 970 if name is not None: 971 node[u'name'] = name 972 if disabled is not None: 973 if disabled: 974 node[u'disabled'] = self._xhtml and u'disabled' or None 975 else: 976 del node[u'disabled'] 977 if autofocus is not None: 978 if autofocus: 979 node[u'autofocus'] = self._xhtml and u'autofocus' or None 980 else: 981 del node[u'autofocus'] 982 if keytype is not None: 983 node[u'keytype'] = keytype 984 if challenge is not None: 985 node[u'challenge'] = challenge 986 987 post_proc = self._post_proc 988 if post_proc is not None: 989 post_proc('keygen', node, dict( 990 name=name, keytype=keytype, challenge=challenge, 991 disabled=disabled, autofocus=autofocus 992 ))993
Home | Trees | Indices | Help |
|
---|