[packaging] 3.8 depends on lgc 0.50 (new argument to dot generator in lgc.graph)
"""some base form classes for CubicWeb web client:organization: Logilab:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""__docformat__="restructuredtext en"fromwarningsimportwarnfromlogilab.common.decoratorsimporticlassmethodfromlogilab.common.compatimportanyfromlogilab.common.deprecationimportdeprecatedfromcubicwebimporttyped_eidfromcubicweb.selectorsimportnon_final_entity,match_kwargs,one_line_rsetfromcubicweb.webimportuicfg,form,formwidgetsasfwdgsfromcubicweb.web.formfieldsimportStringField,relvoc_unrelated,guess_fieldclassFieldsForm(form.Form):"""base class for fields based forms. The following attributes may be either set on subclasses or given on form selection to customize the generated form: * `needs_js`: sequence of javascript files that should be added to handle this form (through `req.add_js`) * `needs_css`: sequence of css files that should be added to handle this form (through `req.add_css`) * `domid`: value for the "id" attribute of the <form> tag * `action`: value for the "action" attribute of the <form> tag * `onsubmit`: value for the "onsubmit" attribute of the <form> tag * `cssclass`: value for the "class" attribute of the <form> tag * `cssstyle`: value for the "style" attribute of the <form> tag * `cwtarget`: value for the "cubicweb:target" attribute of the <form> tag * `redirect_path`: relative to redirect to after submitting the form * `copy_nav_params`: flag telling if navigation paramenters should be copied back in hidden input * `form_buttons`: form buttons sequence (button widgets instances) * `form_renderer_id`: id of the form renderer to use to render the form * `fieldsets_in_order`: fieldset name sequence, to control order """__regid__='base'# attributes overrideable by subclasses or through __init__needs_js=('cubicweb.ajax.js','cubicweb.edition.js',)needs_css=('cubicweb.form.css',)action=Noneonsubmit="return freezeFormButtons('%(domid)s');"cssclass=Nonecssstyle=Nonecwtarget=Noneredirect_path=Noneform_buttons=Noneform_renderer_id='default'fieldsets_in_order=None@propertydefneeds_multipart(self):"""true if the form needs enctype=multipart/form-data"""returnany(field.needs_multipartforfieldinself.fields)defadd_hidden(self,name,value=None,**kwargs):"""add an hidden field to the form"""kwargs.setdefault('ignore_req_params',True)kwargs.setdefault('widget',fwdgs.HiddenInput)field=StringField(name=name,value=value,**kwargs)if'id'inkwargs:# by default, hidden input don't set id attribute. If one is# explicitly specified, ensure it will be setfield.widget.setdomid=Trueself.append_field(field)returnfielddefadd_media(self):"""adds media (CSS & JS) required by this widget"""ifself.needs_js:self._cw.add_js(self.needs_js)ifself.needs_css:self._cw.add_css(self.needs_css)defrender(self,formvalues=None,rendervalues=None,renderer=None,**kwargs):"""render this form, using the renderer given in args or the default FormRenderer() """ifrendervaluesisnotNone:warn('[3.6] rendervalues argument is deprecated, all named arguments will be given instead',DeprecationWarning,stacklevel=2)kwargs=rendervaluesself.build_context(formvalues)ifrendererisNone:renderer=self.default_renderer()returnrenderer.render(self,kwargs)defdefault_renderer(self):returnself._cw.vreg['formrenderers'].select(self.form_renderer_id,self._cw,rset=self.cw_rset,row=self.cw_row,col=self.cw_color0)formvalues=Nonedefbuild_context(self,formvalues=None):"""build form context values (the .context attribute which is a dictionary with field instance as key associated to a dictionary containing field 'name' (qualified), 'id', 'value' (for display, always a string). """ifself.formvaluesisnotNone:return# already builtself.formvalues=formvaluesor{}# use a copy in case fields are modified while context is build (eg# __linkto handling for instance)forfieldinself.fields[:]:forfieldinfield.actual_fields(self):field.form_init(self)@deprecated('[3.6] use .add_hidden(name, value, **kwargs)')defform_add_hidden(self,name,value=None,**kwargs):returnself.add_hidden(name,value,**kwargs)@deprecated('[3.6] use .render(formvalues, **rendervalues)')defform_render(self,**values):"""render this form, using the renderer given in args or the default FormRenderer() """self.build_context(values)renderer=values.pop('renderer',None)ifrendererisNone:renderer=self.default_renderer()returnrenderer.render(self,values)_AFF=uicfg.autoform_field_AFF_KWARGS=uicfg.autoform_field_kwargsclassEntityFieldsForm(FieldsForm):__regid__='base'__select__=(match_kwargs('entity')|(one_line_rset()&non_final_entity()))internal_fields=FieldsForm.internal_fields+('__type','eid','__maineid')domid='entityForm'@iclassmethoddeffield_by_name(cls_or_self,name,role=None,eschema=None):"""return field with the given name and role. If field is not explicitly defined for the form but `eclass` is specified, guess_field will be called. """try:returnsuper(EntityFieldsForm,cls_or_self).field_by_name(name,role)exceptform.FieldNotFound:ifeschemaisNoneorroleisNoneornotnameineschema.schema:raiserschema=eschema.schema.rschema(name)# XXX use a sample target type. Document this.tschemas=rschema.targets(eschema,role)fieldcls=_AFF.etype_get(eschema,rschema,role,tschemas[0])kwargs=_AFF_KWARGS.etype_get(eschema,rschema,role,tschemas[0])ifkwargsisNone:kwargs={}iffieldcls:ifnotisinstance(fieldcls,type):returnfieldcls# already and instancereturnfieldcls(name=name,role=role,eidparam=True,**kwargs)field=guess_field(eschema,rschema,role,eidparam=True,**kwargs)iffieldisNone:raisereturnfielddef__init__(self,_cw,rset=None,row=None,col=None,**kwargs):try:self.edited_entity=kwargs.pop('entity')exceptKeyError:self.edited_entity=rset.complete_entity(rowor0,color0)msg=kwargs.pop('submitmsg',None)super(EntityFieldsForm,self).__init__(_cw,rset,row,col,**kwargs)self.add_hidden('__type',self.edited_entity.__regid__,eidparam=True)self.add_hidden('eid',self.edited_entity.eid)ifkwargs.get('mainform',True):# mainform default to true in parentself.add_hidden(u'__maineid',self.edited_entity.eid)# If we need to directly attach the new object to another oneifself._cw.list_form_param('__linkto'):forlinktoinself._cw.list_form_param('__linkto'):self.add_hidden('__linkto',linkto)ifmsg:msg='%s%s'%(msg,self._cw._('and linked'))else:msg=self._cw._('entity linked')ifmsg:self.add_hidden('__message',msg)defsession_key(self):"""return the key that may be used to store / retreive data about a previous post which failed because of a validation error """ifself.force_session_keyisnotNone:returnself.force_session_key# XXX if this is a json request, suppose we should redirect to the# entity primary viewifself._cw.json_requestandself.edited_entity.has_eid():return'%s#%s'%(self.edited_entity.absolute_url(),self.domid)# XXX we should not consider some url parameters that may lead to# different url after a validation errorreturn'%s#%s'%(self._cw.url(),self.domid)defbuild_context(self,formvalues=None):ifself.formvaluesisnotNone:return# already builtsuper(EntityFieldsForm,self).build_context(formvalues)edited=set()forfieldinself.fields:iffield.eidparam:edited.add(field.role_name())self.add_hidden('_cw_edited_fields',u','.join(edited),eidparam=True)defdefault_renderer(self):returnself._cw.vreg['formrenderers'].select(self.form_renderer_id,self._cw,rset=self.cw_rset,row=self.cw_row,col=self.cw_col,entity=self.edited_entity)defshould_display_add_new_relation_link(self,rschema,existant,card):returnFalse# controller side method (eg POST reception handling)defactual_eid(self,eid):# should be either an int (existant entity) or a variable (to be# created entity)asserteidoreid==0,repr(eid)# 0 is a valid eidtry:returntyped_eid(eid)exceptValueError:try:returnself._cw.data['eidmap'][eid]exceptKeyError:self._cw.data['eidmap'][eid]=NonereturnNonedefeditable_relations(self):return()@deprecated('[3.6] use cw.web.formfields.relvoc_unrelated function')defsubject_relation_vocabulary(self,rtype,limit=None):"""defaut vocabulary method for the given relation, looking for relation's object entities (i.e. self is the subject) """returnrelvoc_unrelated(self.edited_entity,rtype,'subject',limit=None)@deprecated('[3.6] use cw.web.formfields.relvoc_unrelated function')defobject_relation_vocabulary(self,rtype,limit=None):returnrelvoc_unrelated(self.edited_entity,rtype,'object',limit=None)classCompositeFormMixIn(object):"""form composed of sub-forms"""__regid__='composite'form_renderer_id=__regid__def__init__(self,*args,**kwargs):super(CompositeFormMixIn,self).__init__(*args,**kwargs)self.forms=[]defadd_subform(self,subform):"""mark given form as a subform and append it"""subform.parent_form=selfself.forms.append(subform)defbuild_context(self,formvalues=None):super(CompositeFormMixIn,self).build_context(formvalues)forforminself.forms:form.build_context(formvalues)classCompositeForm(CompositeFormMixIn,FieldsForm):passclassCompositeEntityForm(CompositeFormMixIn,EntityFieldsForm):pass# XXX why is this class necessary?