Package: collective.z3cform.chosen
ContentsCreditsCompaniesAuthorsContributorsDescriptionChosen widgetcollective.z3cform.chosen InstallationChangelog1.2.2 (2021-04-20)1.2.1 (2014-09-25)1.2 (2014-06-03)1.1 (2013-06-04)1.0 (2012-06-06)CreditsCompaniesPlanet Makina CorpusContact usAuthorskiorky  <kiorky@cryptelium.net>ContributorsDescriptionThis package contains 4 widgets for z3cform using thechosenandajaxchosenlibraries.A single valued widget for chosenA multi valued widget for chosenA single valued widget for ajaxchosenA multi valued widget for ajaxchosenRepository :githubChosen widgetcollective.chosen.widget provides an autocomplete widget based on the
jQuery Autocomplete widget.>>> from collective.z3cform.chosen import AjaxChosenFieldWidget
>>> from collective.z3cform.chosen import AjaxChosenMultiFieldWidget
>>> from collective.z3cform.chosen import ChosenFieldWidget
>>> from collective.z3cform.chosen import ChosenMultiFieldWidgetFirst, we need a vocabulary to search. This is shamelessly stolen from
z3c.formwidget.query, which we extend.>>> from zope.interface import implements
>>> from z3c.formwidget.query.interfaces import IQuerySource
>>> from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm>>> class ItalianCities(object):
...     implements(IQuerySource)
...
...     vocabulary = SimpleVocabulary((
...         SimpleTerm(u'bologna',  'bologna', u'Bologna'),
...         SimpleTerm(u'palermo',  'palermo', u'Palermo'),
...         SimpleTerm(u'sorrento', 'sorrento', u'Sorrento'),
...         SimpleTerm(u'torino', 'torino', u'Torino')))
...
...     def __init__(self, context):
...         self.context = context
...
...     __contains__ = vocabulary.__contains__
...     __iter__ = vocabulary.__iter__
...     getTerm = vocabulary.getTerm
...     getTermByToken = vocabulary.getTermByToken
...
...     def search(self, query_string):
...         return [v
...                 for v in self
...          if query_string.lower() in v.value.lower()]>>> from zope.schema.interfaces import IContextSourceBinder>>> class ItalianCitiesSourceBinder(object):
...     implements(IContextSourceBinder)
...
...     def __call__(self, context):
...         return ItalianCities(context)Then, we will set up a simple test form and context.>>> from zope.interface import alsoProvides
>>> from OFS.SimpleItem import SimpleItem
>>> from Testing.makerequest import makerequest
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> from z3c.form.interfaces import IFormLayer>>> def make_request(path, form={}):
...     app = SimpleItem('')
...     request = makerequest(app).REQUEST
...     request.form.update(form)
...     alsoProvides(request, IFormLayer)
...     alsoProvides(request, IAttributeAnnotatable)
...     request._script = path.split('/')
...     request._steps = []
...     request._resetURLS()
...     return request>>> from zope.interface import Interface
>>> from zope import schema
>>> from z3c.form import form, field, button
>>> from plone.z3cform.layout import wrap_form>>> class ICities(Interface):
...     afavourite_city = schema.Choice(title=u"Favourite city",
...                                    source=ItalianCitiesSourceBinder(), required=False)
...     avisited_cities = schema.List(title=u"Visited cities",
...                                  value_type=schema.Choice(title=u"Selection",
...                                                           source=ItalianCitiesSourceBinder()))
...     favourite_city = schema.Choice(title=u"Favourite city",
...                                    source=ItalianCitiesSourceBinder())
...     visited_cities = schema.List(title=u"Visited cities",
...                                  value_type=schema.Choice(title=u"Selection",
...                                                           source=ItalianCitiesSourceBinder()))>>> from z3c.form.interfaces import IFieldsForm
>>> from zope.interface import implements
>>> class CitiesForm(form.Form):
...     implements(ICities)
...     fields = field.Fields(ICities)
...     fields['afavourite_city'].widgetFactory = AjaxChosenFieldWidget
...     fields['avisited_cities'].widgetFactory = AjaxChosenMultiFieldWidget
...     fields['favourite_city'].widgetFactory = ChosenFieldWidget
...     fields['visited_cities'].widgetFactory = ChosenMultiFieldWidget
...
...     @button.buttonAndHandler(u'Apply')
...     def handleApply(self, action):
...         data, errors = self.extractData()
...         print "Submitted data:", data>>> form_view = wrap_form(CitiesForm)>>> from zope.component import provideAdapter
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from zope.interface import Interface>>> provideAdapter(adapts=(ICities, IBrowserRequest),
...                provides=Interface,
...                factory=form_view,
...                name=u"cities-form")>>> from OFS.SimpleItem import SimpleItem
>>> class Bar(SimpleItem):
...     implements(ICities)
...
...     def __init__(self, id):
...         self.id = id
...         self.favourite_city = None
...         self.visited_cities = []
...         self.afavourite_city = None
...         self.avisited_cities = []
...     def absolute_url(self):
...         return 'http://foo/bar'Let us now look up the form and attempt to render the widget.>>> from zope.component import getMultiAdapter
>>> context = Bar('bar')Simulates traversal:>>> request = make_request('bar/@@cities-form')
>>> from Testing.makerequest import makerequest
>>> context = makerequest(context)
>>> form_view = getMultiAdapter((context, request), name=u"cities-form")
>>> form_view.__name__ = 'cities-form'Simulates partial rendering:>>> form = form_view.form_instance
>>> form.__name__ = 'cities-form'
>>> form.update()>>> print form.widgets['favourite_city'].render().replace("...", "") # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
<BLANKLINE>
<script type="text/javascript">    (function($) {
        $().ready(function() {
            $('#form-widgets-favourite_city-select').data('klass','chosen-selection-widget required choice-field').data('title','None');
            $('#form-widgets-favourite_city-select').chosen({
                allow_single_deselect: false,
                no_results_text: 'No results found',
                width: '280px'
            });
<BLANKLINE>
            $('#formfield-form-widgets-favourite_city').find('.chzn-container, .chzn-results, .chzn-drop').css({'min-width': '180px'});
        });
    })(jQuery);
    </script>
<div id="form-widgets-favourite_city-chosen" class="chosen-selection-widget required choice-field">
  <select data-placeholder="Select a value" id="form-widgets-favourite_city-select" name="form.widgets.favourite_city:list" onselect="" style="" >
<BLANKLINE>
      <option id="form-widgets-favourite_city-novalue" value="(nothing)" selected="selected">Select a value</option>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-0" value="bologna">Bologna</option>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-1" value="palermo">Palermo</option>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-2" value="sorrento">Sorrento</option>
<BLANKLINE>
<BLANKLINE>
      <option id="form-widgets-favourite_city-3" value="torino">Torino</option>
<BLANKLINE>
  </select>
  <input name="form.widgets.favourite_city-empty-marker" type="hidden" value="1" />
</div>
<BLANKLINE>We can see that the rendered JavaScript is expecting to call a view for ajax widgets
like this:>>> widget = form.widgets['afavourite_city']
>>> context.REQUEST._script = 'bar/@@cities-form/++widget++form.widgets.avisited_cities/@@chosen-autocomplete-search'.split('/')
>>> context.REQUEST._resetURLS()
>>> context.REQUEST.form['term'] = 'or'
>>> search_view = getMultiAdapter((widget, context.REQUEST), name=u'chosen-autocomplete-search')The results are a json tuple list of tokens:>>> print search_view()
[["sorrento","Sorrento"],["torino","Torino"]]At first we didnt set anything in the request, we are missing fields>>> form.update()
>>> data, errors = form.extractData()
>>> len(errors)
3
>>> form.request.form.update({
...  "form.buttons.apply" : "Apply",
...  "form.widgets.visited_cities" : ["palermo", "bologna"],
...  "form.widgets.avisited_cities" : ["palermo", "bologna"],
...  "form.widgets.afavourite_city" :"bologna",
...  "form.widgets.favourite_city" : "palermo",
... })
>>> form.update() # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
Submitted data:...
>>> data, errors = form.extractData()
>>> items = data.items()
>>> items.sort(key=lambda x:x[0])
>>> pprint(items)
[('afavourite_city', u'bologna'),
 ('avisited_cities', [u'palermo', u'bologna']),
 ('favourite_city', u'palermo'),
 ('visited_cities', [u'palermo', u'bologna'])]Our values are marked as selected>>> results = form.render().replace('...', '')
>>> False not in [
... (it in results)
... for it in ['id="form-widgets-visited_cities-0" value="bologna" selected="selected">Bologna',
...            'id="form-widgets-visited_cities-1" value="palermo" selected="selected">Palermo']]
TrueOur widget also handle display mode>>> form.widgets['favourite_city'].mode = 'display'
>>> print form.widgets['favourite_city'].render().strip()
 <span id="form-widgets-favourite_city" class="chosen-selection-widget required choice-field" style=""><span class="selected-option">Palermo</span></span>>>> form.widgets['visited_cities'].mode = 'display'
>>> print form.widgets['visited_cities'].render().strip()
<span id="form-widgets-visited_cities" class="chosen-multiselection-widget required list-field" style=""><span class="selected-option">Palermo</span>, <span class="selected-option">Bologna</span></span>Our widget also handle hidden mode>>> form.widgets['favourite_city'].mode = 'hidden'
>>> print form.widgets['favourite_city'].render().strip()
<input id="form-widgets-favourite_city-1" name="form.widgets.favourite_city:list" value="palermo" class="hidden-widget" type="hidden" />
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<input name="form.widgets.favourite_city-empty-marker" type="hidden" value="1" />>>> form.widgets['visited_cities'].mode = 'hidden'
>>> print form.widgets['visited_cities'].render().strip()
<input id="form-widgets-visited_cities-0" name="form.widgets.visited_cities:list" value="bologna" class="hidden-widget" type="hidden" />
<BLANKLINE>
<BLANKLINE>
  <input id="form-widgets-visited_cities-1" name="form.widgets.visited_cities:list" value="palermo" class="hidden-widget" type="hidden" />
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<BLANKLINE>
<input name="form.widgets.visited_cities-empty-marker" type="hidden" value="1" />collective.z3cform.chosen InstallationTo install collective.z3cform.chosen, follow thisdocumentation.Changelog1.2.2 (2021-04-20)Do not translate the no value token to avoid an error when translated.
[mpeeters]Added needed ajax parameter for corresponding collective.js.chosen
[cedricmessiant, sgeulette]1.2.1 (2014-09-25)Widget works when the field is initially hidden (for instance in an overlay).
[thomasdesvenain]Pyflakes, pep8, unused code removed, etc.
[thomasdesvenain]1.2 (2014-06-03)Set width, and apply as chosen parameter rather than styling widgets with a
specific width; doing so ensures chosen will set a valid width when it’s
initialized off-screen or when the element applied to it is invisible.
[damilgra]Updated french translations.
[cedricmessiant]1.1 (2013-06-04)buildout, tests & travis [kiorky]Change prompt message and update French translations.
Fix bug for no value in List fields.
[cedricmessiant]1.0 (2012-06-06)Initial release [kiorky]