Provide sufficient context to check 'delete' permission in AjaxEditRelationCtxComponent
Call rdef.check only when both fromeid and toeid are available. Though only
call it once (for the first encountered related entity).
Factorize a bit to keep handling of CSS/JS addition the same.
Closes #3670209.
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""html widgetsthose are in cubicweb since we need to know available widgets at schemaserialization time"""importrandomfrommathimportfloorfromlogilab.mtconverterimportxml_escapefromlogilab.common.deprecationimportclass_deprecatedfromcubicweb.utilsimportUStringIOfromcubicweb.uilibimporttoggle_action,htmlescapefromcubicweb.webimportjsonizefromcubicweb.web.componentimport_bwcompatible_render_item# XXX HTMLWidgets should have access to req (for datadir / static urls,# i18n strings, etc.)classHTMLWidget(object):def_initialize_stream(self,w=None):ifw:self.w=welse:self._stream=UStringIO()self.w=self._stream.writedef_render(self):raiseNotImplementedErrordefrender(self,w=None):self._initialize_stream(w)self._render()ifwisNone:returnself._stream.getvalue()defis_empty(self):returnFalseclassBoxWidget(HTMLWidget):# XXX Deprecateddef__init__(self,title,id,items=None,_class="boxFrame",islist=True,shadow=True,escape=True):self.title=titleself.id=idself.items=itemsor[]self._class=_classself.islist=islistself.shadow=shadowself.escape=escapedef__len__(self):returnlen(self.items)defis_empty(self):returnlen(self)==0defappend(self,item):self.items.append(item)defextend(self,items):self.items.extend(items)title_class='boxTitle'main_div_class='boxContent'listing_class='boxListing'defbox_begin_content(self):self.w(u'<div class="%s">\n'%self.main_div_class)ifself.islist:self.w(u'<ul class="%s">'%self.listing_class)defbox_end_content(self):ifself.islist:self.w(u'</ul>\n')self.w(u'</div>\n')ifself.shadow:self.w(u'<div class="shadow"> </div>')def_render(self):ifself.id:self.w(u'<div class="%s" id="%s">'%(self._class,self.id))else:self.w(u'<div class="%s">'%self._class)ifself.title:ifself.escape:title='<span>%s</span>'%xml_escape(self.title)else:title='<span>%s</span>'%self.titleself.w(u'<div class="%s">%s</div>'%(self.title_class,title))ifself.items:self.box_begin_content()foriteminself.items:_bwcompatible_render_item(self.w,item)self.box_end_content()self.w(u'</div>')classSideBoxWidget(BoxWidget):"""default CubicWeb's sidebox widget"""__metaclass__=class_deprecated__deprecation_warning__='[3.10] class %(cls)s is deprecated'title_class=u'sideBoxTitle'main_div_class=u'sideBoxBody'listing_class=''def__init__(self,title,id=None):super(SideBoxWidget,self).__init__(title,id=id,_class='sideBox',shadow=False)classMenuWidget(BoxWidget):main_div_class='menuContent'listing_class='menuListing'defbox_end_content(self):ifself.islist:self.w(u'</ul>\n')self.w(u'</div>\n')classRawBoxItem(HTMLWidget):# XXX deprecated"""a simpe box item displaying raw data"""def__init__(self,label,liclass=None):self.label=labelself.liclass=liclassdef_start_li(self):ifself.liclassisNone:returnu'<li>'else:returnu'<li class="%s">'%self.liclassdef_render(self):self.w(u'%s%s</li>'%(self._start_li(),self.label))classBoxMenu(RawBoxItem):"""a menu in a box"""link_class='boxMenu'def__init__(self,label,items=None,isitem=True,liclass=None,ident=None,link_class=None):super(BoxMenu,self).__init__(label,liclass)self.items=itemsor[]self.isitem=isitemself.ident=identoru'boxmenu_%s'%label.replace(' ','_').replace("'",'')iflink_class:self.link_class=link_classdefappend(self,item):self.items.append(item)def_begin_menu(self,ident):self.w(u'<ul id="%s" class="hidden">'%ident)def_end_menu(self):self.w(u'</ul>')def_render(self):ifself.isitem:self.w(self._start_li())ident=self.identself.w(u'<a href="%s" class="%s">%s</a>'%(toggle_action(ident),self.link_class,self.label))self._begin_menu(ident)foriteminself.items:_bwcompatible_render_item(self.w,item)self._end_menu()ifself.isitem:self.w(u'</li>')classPopupBoxMenu(BoxMenu):"""like BoxMenu but uses div and specific css class in order to behave like a popup menu """link_class='popupMenu'def_begin_menu(self,ident):self.w(u'<div class="popupWrapper"><div id="%s" class="hidden popup"><ul>'%ident)def_end_menu(self):self.w(u'</ul></div></div>')classBoxField(HTMLWidget):"""couples label / value meant to be displayed in a box"""__metaclass__=class_deprecated__deprecation_warning__='[3.10] class %(cls)s is deprecated'def__init__(self,label,value):self.label=labelself.value=valuedef_render(self):self.w(u'<li><div><span class="label">%s</span> 'u'<span class="value">%s</span></div></li>'%(self.label,self.value))classBoxSeparator(HTMLWidget):"""a menu separator"""__metaclass__=class_deprecated__deprecation_warning__='[3.10] class %(cls)s is deprecated'def_render(self):self.w(u'</ul><hr class="boxSeparator"/><ul>')classBoxLink(HTMLWidget):"""a link in a box"""__metaclass__=class_deprecated__deprecation_warning__='[3.10] class %(cls)s is deprecated'def__init__(self,href,label,_class='',title='',ident='',escape=False):self.href=hrefifescape:self.label=xml_escape(label)else:self.label=labelself._class=_classor''self.title=titleself.ident=identdef_render(self):link=u'<a href="%s" title="%s">%s</a>'%(xml_escape(self.href),xml_escape(self.title),self.label)ifself.ident:self.w(u'<li id="%s" class="%s">%s</li>\n'%(self.ident,self._class,link))else:self.w(u'<li class="%s">%s</li>\n'%(self._class,link))classBoxHtml(HTMLWidget):"""a form in a box"""__metaclass__=class_deprecated__deprecation_warning__='[3.10] class %(cls)s is deprecated'def__init__(self,rawhtml):self.rawhtml=rawhtmldef_render(self):self.w(self.rawhtml)classTableColumn(object):def__init__(self,name,rset_sortcol):""" :param name: the column's name :param rset_sortcol: the model's column used to sort this column view """self.name=nameself.cellrenderers=[]self.rset_sortcol=rset_sortcolself.cell_attrs={}defappend_renderer(self,cellvid,colindex):# XXX (adim) : why do we need colindex here ?self.cellrenderers.append((cellvid,colindex))defadd_attr(self,attr,value):self.cell_attrs[attr]=valueclassSimpleTableModel(object):""" uses a list of lists as a storage backend NB: the model expectes the cellvid passed to TableColumn.append_renderer to be a callable accepting a single argument and returning a unicode object """def__init__(self,rows):self._rows=rowsdefget_rows(self):returnself._rowsdefrender_cell(self,cellvid,rowindex,colindex,w):value=self._rows[rowindex][colindex]w(cellvid(value))@htmlescape@jsonizedefsortvalue(self,rowindex,colindex):value=self._rows[rowindex][colindex]ifvalueisNone:returnu''elifisinstance(value,int):returnu'%09d'%valueelse:returnunicode(value)classTableWidget(HTMLWidget):""" Display data in a Table with sortable column. When using remember to include the required css and js with: self._cw.add_js('jquery.tablesorter.js') self._cw.add_css(('cubicweb.tablesorter.css', 'cubicweb.tableview.css')) """highlight="onmouseover=\"$(this).addClass('highlighted');\" " \"onmouseout=\"$(this).removeClass('highlighted');\""def__init__(self,model):self.model=modelself.columns=[]defappend_column(self,column):""" :type column: TableColumn """self.columns.append(column)def_render(self):self.w(u'<table class="listing">')self.w(u'<thead>')self.w(u'<tr class="header">')forcolumninself.columns:attrs=('%s="%s"'%(name,value)forname,valueincolumn.cell_attrs.iteritems())self.w(u'<th %s>%s</th>'%(' '.join(attrs),column.nameoru''))self.w(u'</tr>')self.w(u'</thead><tbody>')forrowindexinxrange(len(self.model.get_rows())):klass=(rowindex%2==1)and'odd'or'even'self.w(u'<tr class="%s" %s>'%(klass,self.highlight))forcolumn,sortvalueinself.itercols(rowindex):attrs=dict(column.cell_attrs)attrs["cubicweb:sortvalue"]=sortvalueattrs=('%s="%s"'%(name,value)forname,valueinattrs.iteritems())self.w(u'<td %s>'%(' '.join(attrs)))forcellvid,colindexincolumn.cellrenderers:self.model.render_cell(cellvid,rowindex,colindex,w=self.w)self.w(u'</td>')self.w(u'</tr>')self.w(u'</tbody>')self.w(u'</table>')defitercols(self,rowindex):forcolumninself.columns:yieldcolumn,self.model.sortvalue(rowindex,column.rset_sortcol)