|
- try:
- from html import escape
- except ImportError:
- from cgi import escape
-
- #from wtforms import widgets
- from wtforms.widgets import HTMLString, html_params
- from wtforms.fields.core import Field
- from wtforms.compat import text_type, izip
-
- class MySelect(object):
- """
- Renders a select field.
-
- If `multiple` is True, then the `size` property should be specified on
- rendering to make the field useful.
-
- The field must provide an `iter_choices()` method which the widget will
- call on rendering; this method must yield tuples of
- `(value, label, selected)`.
- """
- def __init__(self, multiple=False):
- self.multiple = multiple
-
- def __call__(self, field, **kwargs):
- kwargs.setdefault('id', field.id)
- if self.multiple:
- kwargs['multiple'] = True
- html = ['<select %s>' % html_params(name=field.name, **kwargs)]
- last_group = None
- for group, val, label, selected in field.iter_choices():
- if group is None:
- html.append(self.render_option(val, label, selected))
- elif last_group != group:
- html.append(self.render_optgroup(last_group, group))
- html.append(self.render_option(val, label, selected))
- last_group=group
- else:
- html.append(self.render_option(val, label, selected))
- if last_group:
- html.append(self.render_optgroup(last_group, None))
- html.append('</select>')
- return HTMLString(''.join(html))
-
- @classmethod
- def render_option(cls, value, label, selected, **kwargs):
- if value is True:
- # Handle the special case of a 'True' value.
- value = text_type(value)
-
- options = dict(kwargs, value=value)
- if selected:
- options['selected'] = True
- return HTMLString('<option %s>%s</option>' % (html_params(**options), escape(text_type(label), quote=False)))
-
- @classmethod
- def render_optgroup(cls, previous_label, label, **kwargs):
- options = dict(kwargs)
- if previous_label is None:
- return HTMLString('<optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False)))
- elif label is None:
- return HTMLString('</optgroup>')
- else:
- return HTMLString('</optgroup><optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False)))
-
-
- class MyOption(object):
- """
- Renders the individual option from a select field.
-
- This is just a convenience for various custom rendering situations, and an
- option by itself does not constitute an entire field.
- """
- def __call__(self, field, **kwargs):
- return MySelect.render_option(field._value(), field.label.text, field.checked, **kwargs)
-
-
- class MySelectFieldBase(Field):
- #option_widget = widgets.Option()
- option_widget = MyOption()
-
- """
- Base class for fields which can be iterated to produce options.
-
- This isn't a field, but an abstract base class for fields which want to
- provide this functionality.
- """
- def __init__(self, label=None, validators=None, option_widget=None, **kwargs):
- super(MySelectFieldBase, self).__init__(label, validators, **kwargs)
-
- if option_widget is not None:
- self.option_widget = option_widget
-
- def iter_choices(self):
- """
- Provides data for choice widget rendering. Must return a sequence or
- iterable of (value, label, selected) tuples.
- """
- raise NotImplementedError()
-
- def __iter__(self):
- opts = dict(widget=self.option_widget, _name=self.name, _form=None, _meta=self.meta)
- for i, (value, label, checked) in enumerate(self.iter_choices()):
- opt = self._Option(label=label, id='%s-%d' % (self.id, i), **opts)
- opt.process(None, value)
- opt.checked = checked
- yield opt
-
- class _Option(Field):
- checked = False
-
- def _value(self):
- return text_type(self.data)
-
-
- class MySelectField(MySelectFieldBase):
- #widget = widgets.Select()
- widget = MySelect()
-
- def __init__(self, label=None, validators=None, coerce=text_type, choices=None, **kwargs):
- super(MySelectField, self).__init__(label, validators, **kwargs)
- self.coerce = coerce
- self.choices = choices
-
- def iter_choices(self):
- for choiceA, choiceB in self.choices:
- if isinstance(choiceB, (tuple, list)):
- # We should consider choiceA as an optgroup label
- group_label = choiceA
- for value, label in choiceB:
- yield (group_label, value, label, self.coerce(value) == self.data)
- else:
- value, label = choiceA, choiceB
- # Not an optgroup, let's fallback to classic usage
- yield (None, value, label, self.coerce(value) == self.data)
-
- def process_data(self, value):
- try:
- self.data = self.coerce(value)
- except (ValueError, TypeError):
- self.data = None
-
- def process_formdata(self, valuelist):
- if valuelist:
- try:
- self.data = self.coerce(valuelist[0])
- except ValueError:
- raise ValueError(self.gettext('Invalid Choice: could not coerce'))
-
- def pre_validate(self, form):
- for choiceA, choiceB in self.choices:
- if isinstance(choiceB, (tuple, list)):
- for value, label in choiceB:
- if self.data == value:
- break
- if self.data == value:
- break
- else:
- value, label = choiceA, choiceB
- if self.data == value:
- break
- else:
- raise ValueError(self.gettext('Not a valid choice'))
|