Package tdi :: Package tools :: Package htmlform :: Module _main
[frames] | no frames]

Source Code for Module tdi.tools.htmlform._main

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