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.
 
 
 
 
 

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