"""Some views used to help to the edition process:organization: Logilab:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr"""__docformat__="restructuredtext en"fromsimplejsonimportdumpsfromlogilab.common.decoratorsimportcachedfromlogilab.mtconverterimporthtml_escapefromcubicwebimporttyped_eidfromcubicweb.viewimportEntityViewfromcubicweb.selectorsimport(one_line_rset,non_final_entity,match_search_state,match_form_params)fromcubicweb.common.uilibimportcutfromcubicweb.web.viewsimportlinksearch_select_urlfromcubicweb.web.formimportrelation_idfromcubicweb.web.views.baseviewsimportFinalView_=unicodeclassSearchForAssociationView(EntityView):"""view called by the edition view when the user asks to search for something to link to the edited eid """id='search-associate'__select__=(one_line_rset()&match_search_state('linksearch')&non_final_entity())title=_('search for association')defcell_call(self,row,col):rset,vid,divid,paginate=self.filter_box_context_info()self.w(u'<div id="%s">'%divid)self.pagination(self.req,rset,w=self.w)self.wview(vid,rset,'noresult')self.w(u'</div>')@cacheddeffilter_box_context_info(self):entity=self.entity(0,0)role,eid,rtype,etype=self.req.search_state[1]assertentity.eid==typed_eid(eid)# the default behaviour is to fetch all unrelated entities and display# them. Use fetch_order and not fetch_unrelated_order as sort method# since the latter is mainly there to select relevant items in the combo# box, it doesn't give interesting result in this contextrql=entity.unrelated_rql(rtype,etype,role,ordermethod='fetch_order',vocabconstraints=False)rset=self.req.execute(rql,{'x':entity.eid},'x')returnrset,'list',"search-associate-content",TrueclassOutOfContextSearch(EntityView):id='outofcontext-search'defcell_call(self,row,col):entity=self.entity(row,col)erset=entity.as_rset()ifself.req.match_search_state(erset):self.w(u'<a href="%s" title="%s">%s</a> <a href="%s" title="%s">[...]</a>'%(html_escape(linksearch_select_url(self.req,erset)),self.req._('select this entity'),html_escape(entity.view('textoutofcontext')),html_escape(entity.absolute_url(vid='primary')),self.req._('view detail for this entity')))else:entity.view('outofcontext',w=self.w)classUnrelatedDivs(EntityView):id='unrelateddivs'__select__=match_form_params('relation')@propertydeflimit(self):ifself.req.form.get('__force_display'):returnNonereturnself.req.property_value('navigation.related-limit')+1defcell_call(self,row,col):entity=self.entity(row,col)relname,target=self.req.form.get('relation').rsplit('_',1)rschema=self.schema.rschema(relname)hidden='hidden'inself.req.formis_cell='is_cell'inself.req.formself.w(self.build_unrelated_select_div(entity,rschema,target,is_cell=is_cell,hidden=hidden))defbuild_unrelated_select_div(self,entity,rschema,target,is_cell=False,hidden=True):options=[]divid='div%s_%s_%s'%(rschema.type,target,entity.eid)selectid='select%s_%s_%s'%(rschema.type,target,entity.eid)ifrschema.symetricortarget=='subject':targettypes=rschema.objects(entity.e_schema)etypes='/'.join(sorted(etype.display_name(self.req)foretypeintargettypes))else:targettypes=rschema.subjects(entity.e_schema)etypes='/'.join(sorted(etype.display_name(self.req)foretypeintargettypes))etypes=cut(etypes,self.req.property_value('navigation.short-line-size'))options.append('<option>%s%s</option>'%(self.req._('select a'),etypes))options+=self._get_select_options(entity,rschema,target)options+=self._get_search_options(entity,rschema,target,targettypes)if'Basket'inself.schema:# XXXoptions+=self._get_basket_options(entity,rschema,target,targettypes)relname,target=self.req.form.get('relation').rsplit('_',1)returnu"""\<div class="%s" id="%s"> <select id="%s" onchange="javascript: addPendingInsert(this.options[this.selectedIndex], %s, %s, '%s');">%s </select></div>"""%(hiddenand'hidden'or'',divid,selectid,html_escape(dumps(entity.eid)),is_celland'true'or'null',relname,'\n'.join(options))def_get_select_options(self,entity,rschema,target):"""add options to search among all entities of each possible type"""options=[]eid=entity.eidpending_inserts=self.req.get_pending_inserts(eid)rtype=rschema.typeforeview,reidinentity.vocabulary(rschema,target,self.limit):ifreidisNone:options.append('<option class="separator">-- %s --</option>'%html_escape(eview))else:optionid=relation_id(eid,rtype,target,reid)ifoptionidnotinpending_inserts:# prefix option's id with letters to make valid XHTML wiseoptions.append('<option id="id%s" value="%s">%s</option>'%(optionid,reid,html_escape(eview)))returnoptionsdef_get_search_options(self,entity,rschema,target,targettypes):"""add options to search among all entities of each possible type"""options=[]_=self.req._foreschemaintargettypes:mode='%s:%s:%s:%s'%(target,entity.eid,rschema.type,eschema)url=self.build_url(entity.rest_path(),vid='search-associate',__mode=mode)options.append((eschema.display_name(self.req),'<option value="%s">%s%s</option>'%(html_escape(url),_('Search for'),eschema.display_name(self.req))))return[oforl,oinsorted(options)]def_get_basket_options(self,entity,rschema,target,targettypes):options=[]rtype=rschema.type_=self.req._forbasketeid,basketnameinself._get_basket_links(self.req.user.eid,target,targettypes):optionid=relation_id(entity.eid,rtype,target,basketeid)options.append('<option id="%s" value="%s">%s%s</option>'%(optionid,basketeid,_('link to each item in'),html_escape(basketname)))returnoptionsdef_get_basket_links(self,ueid,target,targettypes):targettypes=set(targettypes)forbasketeid,basketname,elementsinself._get_basket_info(ueid):baskettypes=elements.column_types(0)# if every elements in the basket can be attached to the# edited entityifbaskettypes&targettypes:yieldbasketeid,basketnamedef_get_basket_info(self,ueid):basketref=[]basketrql='Any B,N WHERE B is Basket, B owned_by U, U eid %(x)s, B name N'basketresultset=self.req.execute(basketrql,{'x':ueid},'x')forresultinbasketresultset:basketitemsrql='Any X WHERE X in_basket B, B eid %(x)s'rset=self.req.execute(basketitemsrql,{'x':result[0]},'x')basketref.append((result[0],result[1],rset))returnbasketrefclassComboboxView(EntityView):"""the view used in combobox (unrelated entities) THIS IS A TEXT VIEW. DO NOT HTML_ESCAPE """id='combobox'title=Nonedefcell_call(self,row,col):"""the combo-box view for an entity: same as text out of context view by default """self.wview('textoutofcontext',self.rset,row=row,col=col)# class EditRelationView(EntityView):# """Note: This is work in progress# This view is part of the edition view refactoring.# It is still too big and cluttered with strange logic, but it's a start# The main idea is to be able to call an edition view for a specific# relation. For example :# self.wview('editrelation', person_rset, rtype='firstname')# self.wview('editrelation', person_rset, rtype='works_for')# """# id = 'editrelation'# __select__ = match_form_params('rtype')# # TODO: inlineview, multiple edit, (widget view ?)# def cell_call(self, row, col, rtype=None, role='subject', targettype=None,# showlabel=True):# self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.edition.js') )# entity = self.entity(row, col)# rtype = self.req.form.get('rtype', rtype)# showlabel = self.req.form.get('showlabel', showlabel)# assert rtype is not None, "rtype is mandatory for 'edirelation' view"# targettype = self.req.form.get('targettype', targettype)# role = self.req.form.get('role', role)# category = entity.rtags.get_category(rtype, targettype, role)# if category in ('primary', 'secondary') or self.schema.rschema(rtype).is_final():# if hasattr(entity, '%s_format' % rtype):# formatwdg = entity.get_widget('%s_format' % rtype, role)# self.w(formatwdg.edit_render(entity))# self.w(u'<br/>')# wdg = entity.get_widget(rtype, role)# if showlabel:# self.w(u'%s' % wdg.render_label(entity))# self.w(u'%s %s %s' %# (wdg.render_error(entity), wdg.edit_render(entity),# wdg.render_help(entity),))# else:# self._render_generic_relation(entity, rtype, role)# def _render_generic_relation(self, entity, relname, role):# text = self.req.__('add %s %s %s' % (entity.e_schema, relname, role))# # pending operations# operations = self.req.get_pending_operations(entity, relname, role)# if operations['insert'] or operations['delete'] or 'unfold' in self.req.form:# self.w(u'<h3>%s</h3>' % text)# self._render_generic_relation_form(operations, entity, relname, role)# else:# divid = "%s%sreledit" % (relname, role)# url = ajax_replace_url(divid, rql_for_eid(entity.eid), 'editrelation',# {'unfold' : 1, 'relname' : relname, 'role' : role})# self.w(u'<a href="%s">%s</a>' % (url, text))# self.w(u'<div id="%s"></div>' % divid)# def _build_opvalue(self, entity, relname, target, role):# if role == 'subject':# return '%s:%s:%s' % (entity.eid, relname, target)# else:# return '%s:%s:%s' % (target, relname, entity.eid)# def _render_generic_relation_form(self, operations, entity, relname, role):# rqlexec = self.req.execute# for optype, targets in operations.items():# for target in targets:# self._render_pending(optype, entity, relname, target, role)# opvalue = self._build_opvalue(entity, relname, target, role)# self.w(u'<a href="javascript: addPendingDelete(\'%s\', %s);">-</a> '# % (opvalue, entity.eid))# rset = rqlexec('Any X WHERE X eid %(x)s', {'x': target}, 'x')# self.wview('oneline', rset)# # now, unrelated ones# self._render_unrelated_selection(entity, relname, role)# def _render_pending(self, optype, entity, relname, target, role):# opvalue = self._build_opvalue(entity, relname, target, role)# self.w(u'<input type="hidden" name="__%s" value="%s" />'# % (optype, opvalue))# if optype == 'insert':# checktext = '-'# else:# checktext = '+'# rset = self.req.execute('Any X WHERE X eid %(x)s', {'x': target}, 'x')# self.w(u"""[<a href="javascript: cancelPending%s('%s:%s:%s')">%s</a>"""# % (optype.capitalize(), relname, target, role,# self.view('oneline', rset)))# def _render_unrelated_selection(self, entity, relname, role):# rschema = self.schema.rschema(relname)# if role == 'subject':# targettypes = rschema.objects(entity.e_schema)# else:# targettypes = rschema.subjects(entity.e_schema)# self.w(u'<select onselect="addPendingInsert(this.selected.value);">')# for targettype in targettypes:# unrelated = entity.unrelated(relname, targettype, role) # XXX limit# for rowindex, row in enumerate(unrelated):# teid = row[0]# opvalue = self._build_opvalue(entity, relname, teid, role)# self.w(u'<option name="__insert" value="%s>%s</option>'# % (opvalue, self.view('text', unrelated, row=rowindex)))# self.w(u'</select>')classEditableFinalView(FinalView):"""same as FinalView but enables inplace-edition when possible"""id='editable-final'defcell_call(self,row,col,props=None,displaytime=False):entity,rtype=self.rset.related_entity(row,col)ifentityisnotNone:self.w(entity.view('reledit',rtype=rtype))else:super(EditableFinalView,self).cell_call(row,col,props,displaytime)