catch FieldNotFound instead of Exception in field_by_name, return the field if guessable
"""widget classes for form construction:organization: Logilab:copyright: 2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr"""__docformat__="restructuredtext en"fromdatetimeimportdatefromcubicweb.commonimporttagsclassFieldWidget(object):needs_js=()needs_css=()setdomid=Truesettabindex=Truedef__init__(self,attrs=None,setdomid=None,settabindex=None):self.attrs=attrsor{}ifsetdomidisnotNone:# override class's default valueself.setdomid=setdomidifsettabindexisnotNone:# override class's default valueself.settabindex=settabindexdefadd_media(self,form):"""adds media (CSS & JS) required by this widget"""ifself.needs_js:form.req.add_js(self.needs_js)ifself.needs_css:form.req.add_css(self.needs_css)defrender(self,form,field):raiseNotImplementedErrordef_render_attrs(self,form,field):name=form.context[field]['name']values=form.context[field]['value']ifnotisinstance(values,(tuple,list)):values=(values,)attrs=dict(self.attrs)ifself.setdomid:attrs['id']=form.context[field]['id']ifself.settabindexandnot'tabindex'inattrs:attrs['tabindex']=form.req.next_tabindex()returnname,values,attrsclassInput(FieldWidget):type=Nonedefrender(self,form,field):self.add_media(form)name,values,attrs=self._render_attrs(form,field)inputs=[tags.input(name=name,value=value,type=self.type,**attrs)forvalueinvalues]returnu'\n'.join(inputs)classTextInput(Input):type='text'classPasswordInput(Input):type='password'defrender(self,form,field):self.add_media(form)name,values,attrs=self._render_attrs(form,field)assertlen(values)==1id=attrs.pop('id')confirmname='%s-confirm:%s'%tuple(name.rsplit(':',1))inputs=[tags.input(name=name,value=values[0],type=self.type,id=id,**attrs),'<br/>',tags.input(name=confirmname,type=self.type,**attrs),' ',tags.span(form.req._('confirm password'),**{'class':'emphasis'})]returnu'\n'.join(inputs)classFileInput(Input):type='file'def_render_attrs(self,form,field):# ignore value which makes no sense here (XXX even on form validation error?)name,values,attrs=super(FileInput,self)._render_attrs(form,field)returnname,('',),attrsclassHiddenInput(Input):type='hidden'setdomid=False# by default, don't set id attribute on hidden inputsettabindex=FalseclassButtonInput(Input):type='button'classTextArea(FieldWidget):defrender(self,form,field):name,values,attrs=self._render_attrs(form,field)attrs.setdefault('onkeypress','autogrow(this)')ifnotvalues:value=u''eliflen(values)==1:value=values[0]else:raiseValueError('a textarea is not supposed to be multivalued')returntags.textarea(value,name=name,**attrs)classFCKEditor(TextArea):def__init__(self,*args,**kwargs):super(FCKEditor,self).__init__(*args,**kwargs)self.attrs['cubicweb:type']='wysiwyg'defrender(self,form,field):form.req.fckeditor_config()returnsuper(FCKEditor,self).render(form,field)classSelect(FieldWidget):def__init__(self,attrs=None,multiple=False):super(Select,self).__init__(attrs)self.multiple=multipledefrender(self,form,field):name,curvalues,attrs=self._render_attrs(form,field)options=[]forlabel,valueinfield.vocabulary(form):ifvalueincurvalues:options.append(tags.option(label,value=value,selected='selected'))else:options.append(tags.option(label,value=value))returntags.select(name=name,multiple=self.multiple,options=options,**attrs)classCheckBox(Input):type='checkbox'defrender(self,form,field):name,curvalues,attrs=self._render_attrs(form,field)options=[]forlabel,valueinfield.vocabulary(form):ifvalueincurvalues:tag=tags.input(name=name,value=value,type=self.type,checked='checked',**attrs)else:tag=tags.input(name=name,value=value,type=self.type,**attrs)options.append(tag+label)return'<br/>\n'.join(options)classRadio(Input):type='radio'setdomid=Falsedefrender(self,form,field):name,curvalues,attrs=self._render_attrs(form,field)options=[]forlabel,valueinfield.vocabulary(form):ifvalueincurvalues:options.append(tags.input(name=name,type=self.type,value=value,checked='checked',**attrs))else:options.append(tags.option(name=name,type=self.type,value=value,**attrs))options[-1]+=label+'<br/>'return'\n'.join(options)classDateTimePicker(TextInput):monthnames=('january','february','march','april','may','june','july','august','september','october','november','december')daynames=('monday','tuesday','wednesday','thursday','friday','saturday','sunday')needs_js=('cubicweb.ajax.js','cubicweb.calendar.js')needs_css=('cubicweb.calendar_popup.css',)@classmethoddefadd_localized_infos(cls,req):"""inserts JS variables defining localized months and days"""# import here to avoid dependancy from cubicweb-common to simplejson_=req._monthnames=[_(mname)formnameincls.monthnames]daynames=[_(dname)fordnameincls.daynames]req.html_headers.define_var('MONTHNAMES',monthnames)req.html_headers.define_var('DAYNAMES',daynames)defrender(self,form,field):txtwidget=super(DateTimePicker,self).render(form,field)self.add_localized_infos(form.req)cal_button=self._render_calendar_popup(form,field)returntxtwidget+cal_buttondef_render_calendar_popup(self,form,field):req=form.reqvalue=form.context[field]['rawvalue']inputid=form.context[field]['id']helperid='%shelper'%inputidifnotvalue:value=date.today()year,month=value.year,value.monthreturn(u"""<a onclick="toggleCalendar('%s', '%s', %s, %s);" class="calhelper"><img src="%s" title="%s" alt="" /></a><div class="calpopup hidden" id="%s"></div>"""%(helperid,inputid,year,month,req.external_resource('CALENDAR_ICON'),req._('calendar'),helperid))classAjaxWidget(FieldWidget):def__init__(self,wdgtype,inputid=None,**kwargs):super(AjaxWidget,self).__init__(**kwargs)self.attrs.setdefault('class','widget')self.attrs.setdefault('cubicweb:loadtype','auto')self.attrs['cubicweb:wdgtype']=wdgtypeifinputidisnotNone:self.attrs['cubicweb:inputid']=inputiddefrender(self,form,field):self.add_media(form)attrs=self._render_attrs(form,field)[-1]returntags.div(**attrs)