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