283 |
284 |
284 # XXX deprecates |
285 # XXX deprecates |
285 def values_and_attributes(self, form, field): |
286 def values_and_attributes(self, form, field): |
286 return self.values(form, field), self.attributes(form, field) |
287 return self.values(form, field), self.attributes(form, field) |
287 |
288 |
288 @deprecated('[3.6] use values_and_attributes') |
|
289 def _render_attrs(self, form, field): |
|
290 """return html tag name, attributes and a list of values for the field |
|
291 """ |
|
292 values, attrs = self.values_and_attributes(form, field) |
|
293 return field.input_name(form, self.suffix), values, attrs |
|
294 |
|
295 |
289 |
296 class Input(FieldWidget): |
290 class Input(FieldWidget): |
297 """abstract widget class for <input> tag based widgets""" |
291 """abstract widget class for <input> tag based widgets""" |
298 type = None |
292 type = None |
299 |
293 |
433 class Select(FieldWidget): |
427 class Select(FieldWidget): |
434 """Simple <select>, for field having a specific vocabulary. Will return |
428 """Simple <select>, for field having a specific vocabulary. Will return |
435 an unicode string, or a list of unicode strings. |
429 an unicode string, or a list of unicode strings. |
436 """ |
430 """ |
437 vocabulary_widget = True |
431 vocabulary_widget = True |
438 default_size = 5 |
432 default_size = 10 |
439 |
433 |
440 def __init__(self, attrs=None, multiple=False, **kwargs): |
434 def __init__(self, attrs=None, multiple=False, **kwargs): |
441 super(Select, self).__init__(attrs, **kwargs) |
435 super(Select, self).__init__(attrs, **kwargs) |
442 self._multiple = multiple |
436 self._multiple = multiple |
443 |
437 |
457 if optgroup_opened: |
451 if optgroup_opened: |
458 options.append(u'</optgroup>') |
452 options.append(u'</optgroup>') |
459 oattrs.setdefault('label', label or '') |
453 oattrs.setdefault('label', label or '') |
460 options.append(u'<optgroup %s>' % uilib.sgml_attributes(oattrs)) |
454 options.append(u'<optgroup %s>' % uilib.sgml_attributes(oattrs)) |
461 optgroup_opened = True |
455 optgroup_opened = True |
462 elif value in curvalues: |
456 elif self.value_selected(value, curvalues): |
463 options.append(tags.option(label, value=value, |
457 options.append(tags.option(label, value=value, |
464 selected='selected', **oattrs)) |
458 selected='selected', **oattrs)) |
465 else: |
459 else: |
466 options.append(tags.option(label, value=value, **oattrs)) |
460 options.append(tags.option(label, value=value, **oattrs)) |
467 if optgroup_opened: |
461 if optgroup_opened: |
472 else: |
466 else: |
473 size = u'1' |
467 size = u'1' |
474 attrs['size'] = size |
468 attrs['size'] = size |
475 return tags.select(name=field.input_name(form, self.suffix), |
469 return tags.select(name=field.input_name(form, self.suffix), |
476 multiple=self._multiple, options=options, **attrs) |
470 multiple=self._multiple, options=options, **attrs) |
|
471 |
|
472 def value_selected(self, value, curvalues): |
|
473 return value in curvalues |
|
474 |
|
475 |
|
476 class InOutWidget(Select): |
|
477 needs_js = ('cubicweb.widgets.js', ) |
|
478 default_size = 10 |
|
479 template = """ |
|
480 <table id="%(widgetid)s"> |
|
481 <tr> |
|
482 <td>%(inoutinput)s</td> |
|
483 <td><div style="margin-bottom:3px">%(addinput)s</div> |
|
484 <div>%(removeinput)s</div> |
|
485 </td> |
|
486 <td>%(resinput)s</td> |
|
487 </tr> |
|
488 </table> |
|
489 """ |
|
490 add_button = ('<input type="button" id="cwinoutadd" class="wdgButton cwinoutadd" ' |
|
491 'value=">>" size="10" />') |
|
492 remove_button = ('<input type="button" class="wdgButton cwinoutremove" ' |
|
493 'value="<<" size="10" />') |
|
494 |
|
495 def __init__(self, *args, **kwargs): |
|
496 super(InOutWidget, self).__init__(*args, **kwargs) |
|
497 self._multiple = True |
|
498 |
|
499 def render_select(self, form, field, name, selected=False): |
|
500 values, attrs = self.values_and_attributes(form, field) |
|
501 options = [] |
|
502 inputs = [] |
|
503 for option in field.vocabulary(form): |
|
504 try: |
|
505 label, value, _oattrs = option |
|
506 except ValueError: |
|
507 label, value = option |
|
508 if selected: |
|
509 # add values |
|
510 if value in values: |
|
511 options.append(tags.option(label, value=value)) |
|
512 # add hidden inputs |
|
513 inputs.append(tags.input(value=value, |
|
514 name=field.dom_id(form), |
|
515 type="hidden")) |
|
516 else: |
|
517 options.append(tags.option(label, value=value)) |
|
518 if 'size' not in attrs: |
|
519 attrs['size'] = self.default_size |
|
520 if 'id' in attrs : |
|
521 attrs.pop('id') |
|
522 return tags.select(name=name, multiple=self._multiple, id=name, |
|
523 options=options, **attrs) + '\n'.join(inputs) |
|
524 |
|
525 |
|
526 def _render(self, form, field, renderer): |
|
527 domid = field.dom_id(form) |
|
528 jsnodes = {'widgetid': domid, |
|
529 'from': 'from_' + domid, |
|
530 'to': 'to_' + domid} |
|
531 form._cw.add_onload(u'$(cw.jqNode("%s")).cwinoutwidget("%s", "%s");' |
|
532 % (jsnodes['widgetid'], jsnodes['from'], jsnodes['to'])) |
|
533 field.required = True |
|
534 return (self.template % |
|
535 {'widgetid': jsnodes['widgetid'], |
|
536 # helpinfo select tag |
|
537 'inoutinput' : self.render_select(form, field, jsnodes['from']), |
|
538 # select tag with resultats |
|
539 'resinput' : self.render_select(form, field, jsnodes['to'], selected=True), |
|
540 'addinput' : self.add_button % jsnodes, |
|
541 'removeinput': self.remove_button % jsnodes |
|
542 }) |
|
543 |
|
544 class BitSelect(Select): |
|
545 """Select widget for IntField using a vocabulary with bit masks as values. |
|
546 |
|
547 See also :class:`~cubicweb.web.facet.BitFieldFacet`. |
|
548 """ |
|
549 def __init__(self, attrs=None, multiple=True, **kwargs): |
|
550 super(BitSelect, self).__init__(attrs, multiple=multiple, **kwargs) |
|
551 |
|
552 def value_selected(self, value, curvalues): |
|
553 mask = reduce(lambda x, y: int(x) | int(y), curvalues, 0) |
|
554 return int(value) & mask |
|
555 |
|
556 def process_field_data(self, form, field): |
|
557 """Return process posted value(s) for widget and return something |
|
558 understandable by the associated `field`. That value may be correctly |
|
559 typed or a string that the field may parse. |
|
560 """ |
|
561 val = super(BitSelect, self).process_field_data(form, field) |
|
562 if isinstance(val, list): |
|
563 val = reduce(lambda x, y: int(x) | int(y), val, 0) |
|
564 elif val: |
|
565 val = int(val) |
|
566 else: |
|
567 val = 0 |
|
568 return val |
477 |
569 |
478 |
570 |
479 class CheckBox(Input): |
571 class CheckBox(Input): |
480 """Simple <input type='checkbox'>, for field having a specific |
572 """Simple <input type='checkbox'>, for field having a specific |
481 vocabulary. One input will be generated for each possible value. |
573 vocabulary. One input will be generated for each possible value. |
732 default_settings = {} |
824 default_settings = {} |
733 |
825 |
734 def __init__(self, *args, **kwargs): |
826 def __init__(self, *args, **kwargs): |
735 self.autocomplete_settings = kwargs.pop('autocomplete_settings', |
827 self.autocomplete_settings = kwargs.pop('autocomplete_settings', |
736 self.default_settings) |
828 self.default_settings) |
737 try: |
829 self.autocomplete_initfunc = kwargs.pop('autocomplete_initfunc') |
738 self.autocomplete_initfunc = kwargs.pop('autocomplete_initfunc') |
|
739 except KeyError: |
|
740 warn('[3.6] use autocomplete_initfunc argument of %s constructor ' |
|
741 'instead of relying on autocomplete_initfuncs dictionary on ' |
|
742 'the entity class' % self.__class__.__name__, |
|
743 DeprecationWarning) |
|
744 self.autocomplete_initfunc = None |
|
745 super(AutoCompletionWidget, self).__init__(*args, **kwargs) |
830 super(AutoCompletionWidget, self).__init__(*args, **kwargs) |
746 |
831 |
747 def values(self, form, field): |
832 def values(self, form, field): |
748 values = super(AutoCompletionWidget, self).values(form, field) |
833 values = super(AutoCompletionWidget, self).values(form, field) |
749 if not values: |
834 if not values: |
761 % (domid, json_dumps(data), |
846 % (domid, json_dumps(data), |
762 json_dumps(self.autocomplete_settings))) |
847 json_dumps(self.autocomplete_settings))) |
763 return super(AutoCompletionWidget, self)._render(form, field, renderer) |
848 return super(AutoCompletionWidget, self)._render(form, field, renderer) |
764 |
849 |
765 def _get_url(self, entity, field): |
850 def _get_url(self, entity, field): |
766 if self.autocomplete_initfunc is None: |
851 fname = self.autocomplete_initfunc |
767 # XXX for bw compat |
|
768 fname = entity.autocomplete_initfuncs[field.name] |
|
769 else: |
|
770 fname = self.autocomplete_initfunc |
|
771 return entity._cw.build_url('json', fname=fname, mode='remote', |
852 return entity._cw.build_url('json', fname=fname, mode='remote', |
772 pageid=entity._cw.pageid) |
853 pageid=entity._cw.pageid) |
773 |
854 |
774 |
855 |
775 |
856 |
776 class StaticFileAutoCompletionWidget(AutoCompletionWidget): |
857 class StaticFileAutoCompletionWidget(AutoCompletionWidget): |
777 """XXX describe me""" |
858 """XXX describe me""" |
778 wdgtype = 'StaticFileSuggestField' |
859 wdgtype = 'StaticFileSuggestField' |
779 |
860 |
780 def _get_url(self, entity, field): |
861 def _get_url(self, entity, field): |
781 if self.autocomplete_initfunc is None: |
862 return entity._cw.data_url(self.autocomplete_initfunc) |
782 # XXX for bw compat |
|
783 fname = entity.autocomplete_initfuncs[field.name] |
|
784 else: |
|
785 fname = self.autocomplete_initfunc |
|
786 return entity._cw.data_url(fname) |
|
787 |
863 |
788 |
864 |
789 class RestrictedAutoCompletionWidget(AutoCompletionWidget): |
865 class RestrictedAutoCompletionWidget(AutoCompletionWidget): |
790 """XXX describe me""" |
866 """XXX describe me""" |
791 default_settings = {'mustMatch': True} |
867 default_settings = {'mustMatch': True} |
1013 return '<a id="%(domid)s" href="%(href)s">'\ |
1089 return '<a id="%(domid)s" href="%(href)s">'\ |
1014 '<img src="%(imgsrc)s" alt="%(label)s"/>%(label)s</a>' % { |
1090 '<img src="%(imgsrc)s" alt="%(label)s"/>%(label)s</a>' % { |
1015 'label': label, 'imgsrc': imgsrc, |
1091 'label': label, 'imgsrc': imgsrc, |
1016 'domid': self.domid, 'href': self.href} |
1092 'domid': self.domid, 'href': self.href} |
1017 |
1093 |
1018 class InOutWidget(Select): |
|
1019 needs_js = ('cubicweb.widgets.js', ) |
|
1020 template = """ |
|
1021 <table id="%(widgetid)s"> |
|
1022 <tr><td>%(inoutinput)s</td> |
|
1023 <td><div style="margin-bottom:3px">%(addinput)s</div> <div>%(removeinput)s</div></td> |
|
1024 <td>%(resinput)s</td></tr> |
|
1025 </table> |
|
1026 """ |
|
1027 add_button = """<input type="button" id="cwinoutadd" class="wdgButton cwinoutadd" value=">>" size="10" />""" |
|
1028 remove_button ="""<input type="button" class="wdgButton cwinoutremove" value="<<" size="10" />""" |
|
1029 |
|
1030 def __init__(self, attrs=None): |
|
1031 super(InOutWidget, self).__init__(attrs, multiple=True) |
|
1032 |
|
1033 def render_select(self, form, field, name, selected=False): |
|
1034 values, attrs = self.values_and_attributes(form, field) |
|
1035 options = [] |
|
1036 inputs = [] |
|
1037 for _option in field.vocabulary(form): |
|
1038 try: |
|
1039 label, value, oattrs = _option |
|
1040 except ValueError: |
|
1041 label, value = _option |
|
1042 if selected: |
|
1043 # add values |
|
1044 if value in values: |
|
1045 options.append(tags.option(label, value=value)) |
|
1046 # add hidden inputs |
|
1047 inputs.append(tags.input(value=value, name=field.dom_id(form), type="hidden")) |
|
1048 else: |
|
1049 options.append(tags.option(label, value=value)) |
|
1050 if 'size' not in attrs: |
|
1051 attrs['size'] = 5 |
|
1052 if 'id' in attrs : |
|
1053 attrs.pop('id') |
|
1054 return tags.select(name=name, multiple=self._multiple, id=name, |
|
1055 options=options, **attrs) + '\n'.join(inputs) |
|
1056 |
|
1057 |
|
1058 def _render(self, form, field, renderer): |
|
1059 domid = field.dom_id(form) |
|
1060 jsnodes = {'widgetid': domid, 'from': 'from_' + domid, 'to': 'to_' + domid} |
|
1061 form._cw.add_onload(u'$(cw.jqNode("%s")).cwinoutwidget("%s", "%s");' |
|
1062 % (jsnodes['widgetid'], jsnodes['from'], jsnodes['to'])) |
|
1063 field.required=True |
|
1064 return self.template % {'widgetid': jsnodes['widgetid'], |
|
1065 'inoutinput' : self.render_select(form, field, jsnodes['from']), # helpinfo select tag |
|
1066 'resinput' : self.render_select(form, field, jsnodes['to'], selected=True), # select tag with resultats |
|
1067 'addinput' : self.add_button % jsnodes, |
|
1068 'removeinput': self.remove_button % jsnodes |
|
1069 } |
|