inlineview is no more a 'category', needs specific handling
"""form renderers, responsible to layout a form to html:organization: Logilab:copyright: 2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr"""__docformat__="restructuredtext en"fromlogilab.commonimportdictattrfromlogilab.mtconverterimporthtml_escapefromsimplejsonimportdumpsfromcubicweb.commonimporttagsfromcubicweb.webimporteid_paramfromcubicweb.webimportformwidgetsasfwdgsfromcubicweb.web.widgetsimportcheckboxclassFormRenderer(object):"""basic renderer displaying fields in a two columns table label | value """button_bar_class=u'formButtonBar'def__init__(self,display_fields=None,display_label=True,display_help=True,button_bar_class=None):self.display_fields=display_fields# None -> all fieldsself.display_label=display_labelself.display_help=display_helpifbutton_bar_classisnotNone:self.button_bar_class=button_bar_class# renderer interface ######################################################defrender(self,form,values):form.add_media()data=[]w=data.appendw(self.open_form(form,values))w(u'<div id="progress">%s</div>'%form.req._('validating...'))w(u'<fieldset>')w(tags.input(type=u'hidden',name=u'__form_id',value=values.get('formvid',form.id)))ifform.redirect_path:w(tags.input(type='hidden',name='__redirectpath',value=form.redirect_path))self.render_fields(w,form,values)self.render_buttons(w,form)w(u'</fieldset>')w(u'</form>')errormsg=self.error_message(form)iferrormsg:data.insert(0,errormsg)return'\n'.join(data)defrender_label(self,form,field):label=form.req._(field.label)attrs={'for':form.context[field]['id']}iffield.required:attrs['class']='required'returntags.label(label,**attrs)defrender_help(self,form,field):help=[u'<br/>']descr=field.helpifdescr:help.append('<span class="helper">%s</span>'%form.req._(descr))example=field.example_format(form.req)ifexample:help.append('<span class="helper">(%s: %s)</span>'%(form.req._('sample format'),example))returnu' '.join(help)# specific methods (mostly to ease overriding) #############################deferror_message(self,form):"""return formatted error message This method should be called once inlined field errors has been consumed """req=form.reqerrex=req.data.get('formerrors')# get extra errorsiferrexisnotNone:errormsg=req._('please correct the following errors:')displayed=req.data['displayederrors']errors=sorted((field,err)forfield,errinerrex.errors.items()ifnotfieldindisplayed)iferrors:iflen(errors)>1:templstr='<li>%s</li>\n'else:templstr=' %s\n'forfield,errinerrors:iffieldisNone:errormsg+=templstr%errelse:errormsg+=templstr%'%s: %s'%(req._(field),err)iflen(errors)>1:errormsg='<ul>%s</ul>'%errormsgreturnu'<div class="errorMessage">%s</div>'%errormsgreturnu''defopen_form(self,form,values):ifform.form_needs_multipart:enctype='multipart/form-data'else:enctype='application/x-www-form-urlencoded'ifform.actionisNone:action=form.req.build_url('edit')else:action=form.actiontag=('<form action="%s" method="post" enctype="%s"'%(html_escape(actionor'#'),enctype))ifform.domid:tag+=' id="%s"'%form.domidifform.onsubmit:tag+=' onsubmit="%s"'%html_escape(form.onsubmit%dictattr(form))ifform.cssstyle:tag+=' style="%s"'%html_escape(form.cssstyle)ifform.cssclass:tag+=' class="%s"'%html_escape(form.cssclass)ifform.cwtarget:tag+=' cubicweb:target="%s"'%html_escape(form.cwtarget)returntag+'>'defdisplay_field(self,form,field):return(self.display_fieldsisNoneorfield.nameinself.display_fieldsorfield.nameinform.internal_fields)defrender_fields(self,w,form,values):form.form_build_context(values)fields=self._render_hidden_fields(w,form)iffields:self._render_fields(fields,w,form,values)self.render_child_forms(w,form,values)defrender_child_forms(self,w,form,values):# render forchildformingetattr(form,'forms',[]):self.render_fields(w,childform,values)def_render_hidden_fields(self,w,form):fields=form.fields[:]forfieldinform.fields:ifnotself.display_field(form,field):fields.remove(field)elifnotfield.is_visible():w(field.render(form,self))fields.remove(field)returnfieldsdef_render_fields(self,fields,w,form,values):w(u'<table id="%s" class="attributeForm" style="width:100%%;">')forfieldinfields:w(u'<tr>')ifself.display_label:w(u'<th class="labelCol">%s</th>'%self.render_label(form,field))error=form.form_field_error(field)iferror:w(u'<td class="error" style="width:100%;">')w(error)else:w(u'<td style="width:100%;">')w(field.render(form,self))ifself.display_help:w(self.render_help(form,field))w(u'</td></tr>')w(u'</table>')defrender_buttons(self,w,form):w(u'<table class="%s">\n<tr>\n'%self.button_bar_class)forbuttoninform.form_buttons():w(u'<td>%s</td>\n'%button)w(u'</tr></table>')classEntityCompositeFormRenderer(FormRenderer):"""specific renderer for multiple entities edition form (muledit)"""defrender_fields(self,w,form,values):ifnotform.is_subform:w(u'<table class="listing">')super(EntityCompositeFormRenderer,self).render_fields(w,form,values)ifnotform.is_subform:w(u'</table>')def_render_fields(self,fields,w,form,values):ifform.is_subform:entity=form.edited_entityvalues=form.req.data.get('formvalues',())qeid=eid_param('eid',entity.eid)cbsetstate="setCheckboxesState2('eid', %s, 'checked')"%html_escape(dumps(entity.eid))w(u'<tr class="%s">'%(entity.row%2andu'even'oru'odd'))# XXX turn this into a widget used on the eid fieldw(u'<td>%s</td>'%checkbox('eid',entity.eid,checked=qeidinvalues))forfieldinfields:error=form.form_field_error(field)iferror:w(u'<td class="error">')w(error)else:w(u'<td>')ifisinstance(field.widget,(fwdgs.Select,fwdgs.CheckBox,fwdgs.Radio)):field.widget.attrs['onchange']=cbsetstateelifisinstance(field.widget,fwdgs.Input):field.widget.attrs['onkeypress']=cbsetstatew(u'<div>%s</div>'%field.render(form,self))w(u'/<td>')else:# main form, display table headersw(u'<tr class="header">')w(u'<th align="left">%s</th>'%tags.input(type='checkbox',title=form.req._('toggle check boxes'),onclick="setCheckboxesState('eid', this.checked)"))forfieldinself.forms[0].fields:ifself.display_field(form,field)andfield.is_visible():w(u'<th>%s</th>'%form.req._(field.label))w(u'</tr>')classEntityFormRenderer(FormRenderer):"""specific renderer for entity edition form (edition)"""defrender(self,form,values):rendered=super(EntityFormRenderer,self).render(form,values)returnrendered+u'</div>'# close extra div introducted by open_formdefopen_form(self,form,values):attrs_fs_label=('<div class="iformTitle"><span>%s</span></div>'%form.req._('main informations'))attrs_fs_label+='<div class="formBody">'returnattrs_fs_label+super(EntityFormRenderer,self).open_form(form,values)defrender_fields(self,w,form,values):super(EntityFormRenderer,self).render_fields(w,form,values)self.inline_entities_form(w,form)ifform.edited_entity.has_eid():self.relations_form(w,form)def_render_fields(self,fields,w,form,values):ifnotform.edited_entity.has_eid()orform.edited_entity.has_perm('update'):super(EntityFormRenderer,self)._render_fields(fields,w,form,values)defrender_buttons(self,w,form):buttons=form.form_buttons()iflen(buttons)==3:w("""<table width="100%%"> <tbody> <tr><td align="center">%s </td><td style="align: right; width: 50%%;">%s%s </td></tr> </tbody> </table>"""%tuple(buttons))else:super(EntityFormRenderer,self).render_buttons(w,form)defrelations_form(self,w,form):srels_by_cat=form.srelations_by_category(('generic','metadata'),'add')ifnotsrels_by_cat:returnu''req=form.req_=req._label=u'%s :'%_('This %s'%form.edited_entity.e_schema).capitalize()eid=form.edited_entity.eidw(u'<fieldset class="subentity">')w(u'<legend class="iformTitle">%s</legend>'%label)w(u'<table id="relatedEntities">')forrschema,target,relatedinform.relations_table():# already linked entitiesifrelated:w(u'<tr><th class="labelCol">%s</th>'%rschema.display_name(req,target))w(u'<td>')w(u'<ul>')forviewparamsinrelated:w(u'<li class="invisible">%s<div id="span%s" class="%s">%s</div></li>'%(viewparams[1],viewparams[0],viewparams[2],viewparams[3]))ifnotform.force_displayandform.maxrelitems<len(related):link=(u'<span class="invisible">''[<a href="javascript: window.location.href+=\'&__force_display=1\'">%s</a>]''</span>'%form.req._('view all'))w(u'<li class="invisible">%s</li>'%link)w(u'</ul>')w(u'</td>')w(u'</tr>')pendings=list(form.restore_pending_inserts())ifnotpendings:w(u'<tr><th> </th><td> </td></tr>')else:forrowinpendings:# soon to be linked to entitiesw(u'<tr id="tr%s">'%row[1])w(u'<th>%s</th>'%row[3])w(u'<td>')w(u'<a class="handle" title="%s" href="%s">[x]</a>'%(_('cancel this insert'),row[2]))w(u'<a id="a%s" class="editionPending" href="%s">%s</a>'%(row[1],row[4],html_escape(row[5])))w(u'</td>')w(u'</tr>')w(u'<tr id="relationSelectorRow_%s" class="separator">'%eid)w(u'<th class="labelCol">')w(u'<span>%s</span>'%_('add relation'))w(u'<select id="relationSelector_%s" tabindex="%s" onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'%(eid,req.next_tabindex(),html_escape(dumps(eid))))w(u'<option value="">%s</option>'%_('select a relation'))fori18nrtype,rschema,targetinsrels_by_cat:# more entities to link tow(u'<option value="%s_%s">%s</option>'%(rschema,target,i18nrtype))w(u'</select>')w(u'</th>')w(u'<td id="unrelatedDivs_%s"></td>'%eid)w(u'</tr>')w(u'</table>')w(u'</fieldset>')definline_entities_form(self,w,form):"""create a form to edit entity's inlined relations"""entity=form.edited_entity__=form.req.__forrschema,targettypes,roleinform.inlined_relations():# show inline forms only if there's one possible target type# for rschemaiflen(targettypes)!=1:self.warning('entity related by the %s relation should have ''inlined form but there is multiple target types, ''dunno what to do',rschema)continuetargettype=targettypes[0].typeifform.should_inline_relation_form(rschema,targettype,role):w(u'<div id="inline%sslot">'%rschema)existant=entity.has_eid()andentity.related(rschema)ifexistant:# display inline-edition view for all existing related entitiesw(self.view('inline-edition',existant,rtype=rschema,role=role,ptype=entity.e_schema,peid=entity.eid,**kwargs))ifrole=='subject':card=rschema.rproperty(entity.e_schema,targettype,'cardinality')[0]else:card=rschema.rproperty(targettype,entity.e_schema,'cardinality')[1]# there is no related entity and we need at least one: we need to# display one explicit inline-creation viewifform.should_display_inline_creation_form(rschema,existant,card):w(self.view('inline-creation',None,etype=targettype,peid=entity.eid,ptype=entity.e_schema,rtype=rschema,role=role,**kwargs))# we can create more than one related entity, we thus display a link# to add new related entitiesifform.should_display_add_new_relation_link(rschema,existant,card):divid="addNew%s%s%s:%s"%(targettype,rschema,role,entity.eid)w(u'<div class="inlinedform" id="%s" cubicweb:limit="true">'%divid)js="addInlineCreationForm('%s', '%s', '%s', '%s', '%s')"%(entity.eid,entity.e_schema,targettype,rschema,role)ifcardin'1?':js="toggleVisibility('%s'); %s"%(divid,js)w(u'<a class="addEntity" id="add%s:%slink" href="javascript: %s" >+ %s.</a>'%(rschema,entity.eid,js,__('add a %s'%targettype)))w(u'</div>')w(u'<div class="trame_grise"> </div>')w(u'</div>')classEntityInlinedFormRenderer(EntityFormRenderer):"""specific renderer for entity inlined edition form (inline-[creation|edition]) """defrender(self,form,values):form.add_media()data=[]w=data.appendtry:w(u'<div id="div-%(divid)s" onclick="%(divonclick)s">'%values)exceptKeyError:w(u'<div id="div-%(divid)s">'%values)else:w(u'<div id="notice-%s" class="notice">%s</div>'%(values['divid'],form.req._('click on the box to cancel the deletion')))w(u'<div class="iformBody">')values['removemsg']=form.req.__('remove this %s'%form.edited_entity.e_schema)w(u'<div class="iformTitle"><span>%(title)s</span> ''#<span class="icounter">1</span> ''[<a href="javascript: %(removejs)s;noop();">%(removemsg)s</a>]</div>'%values)self.render_fields(w,form,values)w(u'</div>')return'\n'.join(data)defrender_fields(self,w,form,values):form.form_build_context(values)w(u'<fieldset id="fs-%(divid)s">'%values)fields=self._render_hidden_fields(w,form)w(u'</fieldset>')w(u'<fieldset class="subentity">')iffields:self._render_fields(fields,w,form,values)self.render_child_forms(w,form,values)self.inline_entities_form(w,form)w(u'</fieldset>')