Le repo des sources pour le site web des JM2L
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

171 line
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'))