Le repo des sources pour le site web des JM2L
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

171 Zeilen
5.8 KiB

  1. try:
  2. from html import escape
  3. except ImportError:
  4. from cgi import escape
  5. # from wtforms import widgets
  6. from wtforms.widgets import html_params
  7. from wtforms.fields.core import Field
  8. from wtforms.compat import text_type, izip
  9. from markupsafe import Markup
  10. class MySelect(object):
  11. """
  12. Renders a select field.
  13. If `multiple` is True, then the `size` property should be specified on
  14. rendering to make the field useful.
  15. The field must provide an `iter_choices()` method which the widget will
  16. call on rendering; this method must yield tuples of
  17. `(value, label, selected)`.
  18. """
  19. def __init__(self, multiple=False):
  20. self.multiple = multiple
  21. def __call__(self, field, **kwargs):
  22. kwargs.setdefault('id', field.id)
  23. if self.multiple:
  24. kwargs['multiple'] = True
  25. html = ['<select %s>' % html_params(name=field.name, **kwargs)]
  26. last_group = None
  27. for group, val, label, selected in field.iter_choices():
  28. if group is None:
  29. html.append(self.render_option(val, label, selected))
  30. elif last_group != group:
  31. html.append(self.render_optgroup(last_group, group))
  32. html.append(self.render_option(val, label, selected))
  33. last_group = group
  34. else:
  35. html.append(self.render_option(val, label, selected))
  36. if last_group:
  37. html.append(self.render_optgroup(last_group, None))
  38. html.append('</select>')
  39. return Markup(''.join(html))
  40. @classmethod
  41. def render_option(cls, value, label, selected, **kwargs):
  42. if value is True:
  43. # Handle the special case of a 'True' value.
  44. value = text_type(value)
  45. options = dict(kwargs, value=value)
  46. if selected:
  47. options['selected'] = True
  48. return Markup('<option %s>%s</option>' % (html_params(**options), escape(text_type(label), quote=False)))
  49. @classmethod
  50. def render_optgroup(cls, previous_label, label, **kwargs):
  51. options = dict(kwargs)
  52. if previous_label is None:
  53. return Markup(
  54. '<optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False)))
  55. elif label is None:
  56. return Markup('</optgroup>')
  57. else:
  58. return Markup(
  59. '</optgroup><optgroup %s label="%s">' % (html_params(**options), escape(text_type(label), quote=False)))
  60. class MyOption(object):
  61. """
  62. Renders the individual option from a select field.
  63. This is just a convenience for various custom rendering situations, and an
  64. option by itself does not constitute an entire field.
  65. """
  66. def __call__(self, field, **kwargs):
  67. return MySelect.render_option(field._value(), field.label.text, field.checked, **kwargs)
  68. class MySelectFieldBase(Field):
  69. # option_widget = widgets.Option()
  70. option_widget = MyOption()
  71. """
  72. Base class for fields which can be iterated to produce options.
  73. This isn't a field, but an abstract base class for fields which want to
  74. provide this functionality.
  75. """
  76. def __init__(self, label=None, validators=None, option_widget=None, **kwargs):
  77. super(MySelectFieldBase, self).__init__(label, validators, **kwargs)
  78. if option_widget is not None:
  79. self.option_widget = option_widget
  80. def iter_choices(self):
  81. """
  82. Provides data for choice widget rendering. Must return a sequence or
  83. iterable of (value, label, selected) tuples.
  84. """
  85. raise NotImplementedError()
  86. def __iter__(self):
  87. opts = dict(widget=self.option_widget, _name=self.name, _form=None, _meta=self.meta)
  88. for i, (value, label, checked) in enumerate(self.iter_choices()):
  89. opt = self._Option(label=label, id='%s-%d' % (self.id, i), **opts)
  90. opt.process(None, value)
  91. opt.checked = checked
  92. yield opt
  93. class _Option(Field):
  94. checked = False
  95. def _value(self):
  96. return text_type(self.data)
  97. class MySelectField(MySelectFieldBase):
  98. # widget = widgets.Select()
  99. widget = MySelect()
  100. def __init__(self, label=None, validators=None, coerce=text_type, choices=None, **kwargs):
  101. super(MySelectField, self).__init__(label, validators, **kwargs)
  102. self.coerce = coerce
  103. self.choices = choices
  104. def iter_choices(self):
  105. for choiceA, choiceB in self.choices:
  106. if isinstance(choiceB, (tuple, list)):
  107. # We should consider choiceA as an optgroup label
  108. group_label = choiceA
  109. for value, label in choiceB:
  110. yield group_label, value, label, self.coerce(value) == self.data
  111. else:
  112. value, label = choiceA, choiceB
  113. # Not an optgroup, let's fallback to classic usage
  114. yield None, value, label, self.coerce(value) == self.data
  115. def process_data(self, value):
  116. try:
  117. self.data = self.coerce(value)
  118. except (ValueError, TypeError):
  119. self.data = None
  120. def process_formdata(self, valuelist):
  121. if valuelist:
  122. try:
  123. self.data = self.coerce(valuelist[0])
  124. except ValueError:
  125. raise ValueError(self.gettext('Invalid Choice: could not coerce'))
  126. def pre_validate(self, form):
  127. for choiceA, choiceB in self.choices:
  128. if isinstance(choiceB, (tuple, list)):
  129. for value, label in choiceB:
  130. if self.data == value:
  131. break
  132. if self.data == value:
  133. break
  134. else:
  135. value, label = choiceA, choiceB
  136. if self.data == value:
  137. break
  138. else:
  139. raise ValueError(self.gettext('Not a valid choice'))