Commit af06cf2d authored by sylvain.thenault@logilab.fr's avatar sylvain.thenault@logilab.fr
Browse files

add some documentation, backport *CompletionWidget

--HG--
branch : tls-sprint
parent 9c7cc717bb17
......@@ -11,14 +11,20 @@ from datetime import date
from cubicweb.common import tags
from cubicweb.web import stdmsgs
class FieldWidget(object):
"""abstract widget class"""
# javascript / css files required by the widget
needs_js = ()
needs_css = ()
# automatically set id and tabindex attributes ?
setdomid = True
settabindex = True
def __init__(self, attrs=None, setdomid=None, settabindex=None):
self.attrs = attrs or {}
if attrs is None:
attrs = {}
self.attrs = attrs
if setdomid is not None:
# override class's default value
self.setdomid = setdomid
......@@ -34,9 +40,14 @@ class FieldWidget(object):
form.req.add_css(self.needs_css)
def render(self, form, field):
"""render the widget for the given `field` of `form`.
To override in concrete class
"""
raise NotImplementedError
def _render_attrs(self, form, field):
"""return html tag name, attributes and a list of values for the field
"""
name = form.context[field]['name']
values = form.context[field]['value']
if not isinstance(values, (tuple, list)):
......@@ -50,9 +61,14 @@ class FieldWidget(object):
class Input(FieldWidget):
"""abstract widget class for <input> tag based widgets"""
type = None
def render(self, form, field):
"""render the widget for the given `field` of `form`.
Generate one <input> tag for each field's value
"""
self.add_media(form)
name, values, attrs = self._render_attrs(form, field)
inputs = [tags.input(name=name, value=value, type=self.type, **attrs)
......@@ -60,11 +76,17 @@ class Input(FieldWidget):
return u'\n'.join(inputs)
# basic html widgets ###########################################################
class TextInput(Input):
"""<input type='text'>"""
type = 'text'
class PasswordInput(Input):
"""<input type='password'> and its confirmation field (using
<field's name>-confirm as name)
"""
type = 'password'
def render(self, form, field):
......@@ -85,6 +107,7 @@ class PasswordInput(Input):
class FileInput(Input):
"""<input type='file'>"""
type = 'file'
def _render_attrs(self, form, field):
......@@ -94,16 +117,23 @@ class FileInput(Input):
class HiddenInput(Input):
"""<input type='hidden'>"""
type = 'hidden'
setdomid = False # by default, don't set id attribute on hidden input
settabindex = False
class ButtonInput(Input):
"""<input type='button'>
if you want a global form button, look at the Button, SubmitButton,
ResetButton and ImgButton classes below.
"""
type = 'button'
class TextArea(FieldWidget):
"""<textarea>"""
def render(self, form, field):
name, values, attrs = self._render_attrs(form, field)
attrs.setdefault('onkeypress', 'autogrow(this)')
......@@ -117,6 +147,7 @@ class TextArea(FieldWidget):
class FCKEditor(TextArea):
"""FCKEditor enabled <textarea>"""
def __init__(self, *args, **kwargs):
super(FCKEditor, self).__init__(*args, **kwargs)
self.attrs['cubicweb:type'] = 'wysiwyg'
......@@ -127,6 +158,7 @@ class FCKEditor(TextArea):
class Select(FieldWidget):
"""<select>, for field having a specific vocabulary"""
def __init__(self, attrs=None, multiple=False):
super(Select, self).__init__(attrs)
self.multiple = multiple
......@@ -144,6 +176,9 @@ class Select(FieldWidget):
class CheckBox(Input):
"""<input type='checkbox'>, for field having a specific vocabulary. One
input will be generated for each possible value.
"""
type = 'checkbox'
def render(self, form, field):
......@@ -161,8 +196,11 @@ class CheckBox(Input):
class Radio(Input):
"""<input type='radio'>, for field having a specific vocabulary. One
input will be generated for each possible value.
"""
type = 'radio'
setdomid = False
setdomid = False # by default, don't set id attribute on radio input
def render(self, form, field):
name, curvalues, attrs = self._render_attrs(form, field)
......@@ -178,7 +216,12 @@ class Radio(Input):
return '\n'.join(options)
# javascript widgets ###########################################################
class DateTimePicker(TextInput):
"""<input type='text' + javascript date/time picker for date or datetime
fields
"""
monthnames = ('january', 'february', 'march', 'april',
'may', 'june', 'july', 'august',
'september', 'october', 'november', 'december')
......@@ -219,7 +262,10 @@ class DateTimePicker(TextInput):
req._('calendar'), helperid) )
# ajax widgets ################################################################
class AjaxWidget(FieldWidget):
"""simple <div> based ajax widget"""
def __init__(self, wdgtype, inputid=None, **kwargs):
super(AjaxWidget, self).__init__(**kwargs)
self.attrs.setdefault('class', 'widget')
......@@ -233,8 +279,52 @@ class AjaxWidget(FieldWidget):
attrs = self._render_attrs(form, field)[-1]
return tags.div(**attrs)
class AutoCompletionWidget(TextInput):
"""ajax widget for StringField, proposing matching existing values as you
type.
"""
needs_js = ('cubicweb.widgets.js', 'jquery.autocomplete.js')
needs_css = ('jquery.autocomplete.css',)
wdgtype = 'SuggestField'
loadtype = 'auto'
def _render_attrs(self, form, field):
name, values, attrs = super(AutoCompletionWidget, self)._render_attrs(form, field)
if not values[0]:
values = (INTERNAL_FIELD_VALUE,)
try:
attrs['klass'] += ' widget'
except KeyError:
attrs['klass'] = 'widget'
attrs.setdefault('cubicweb:wdgtype', self.wdgtype)
attrs.setdefault('cubicweb:loadtype', self.loadtype)
# XXX entity form specific
attrs['cubicweb:dataurl'] = self._get_url(form.edited_entity)
return name, values, attrs
def _get_url(self, entity):
return entity.req.build_url('json', fname=entity.autocomplete_initfuncs[self.rschema],
pageid=entity.req.pageid, mode='remote')
class StaticFileAutoCompletionWidget(AutoCompletionWidget):
"""XXX describe me"""
wdgtype = 'StaticFileSuggestField'
def _get_url(self, entity):
return entity.req.datadir_url + entity.autocomplete_initfuncs[self.rschema]
class RestrictedAutoCompletionWidget(AutoCompletionWidget):
"""XXX describe me"""
wdgtype = 'RestrictedSuggestField'
# buttons ######################################################################
class Button(Input):
"""<input type='button'>, base class for global form buttons"""
type = 'button'
def __init__(self, label=stdmsgs.BUTTON_OK, attrs=None,
setdomid=None, settabindex=None,
......@@ -266,12 +356,21 @@ class Button(Input):
class SubmitButton(Button):
"""<input type='submit'>, main button to submit a form"""
type = 'submit'
class ResetButton(Button):
"""<input type='reset'>, main button to reset a form.
You usually don't want this.
"""
type = 'reset'
class ImgButton(object):
"""<img> wrapped into a <a> tag with href triggering something (usually a
javascript call)
"""
def __init__(self, domid, href, label, imgressource):
self.domid = domid
self.href = href
......@@ -283,5 +382,4 @@ class ImgButton(object):
return '<a id="%(domid)s" href="%(href)s"><img src="%(imgsrc)s" alt="%(label)s"/>%(label)s</a>' % self.__dict__
# XXX EntityLinkComboBoxWidget, AddComboBoxWidget, AutoCompletionWidget,
# StaticFileAutoCompletionWidget, RestrictedAutoCompletionWidget...
# XXX EntityLinkComboBoxWidget, AddComboBoxWidget, RawDynamicComboBoxWidget
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment