"""abstract component class and base components definition 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"_=unicodefromsimplejsonimportdumpsfromlogilab.common.deprecationimportclass_renamedfromlogilab.mtconverterimportxml_escapefromcubicwebimportrolefromcubicweb.utilsimportmerge_dictsfromcubicweb.viewimportComponentfromcubicweb.selectorsimport(paginated_rset,one_line_rset,primary_view,match_context_prop,partial_has_related_entities)classEntityVComponent(Component):"""abstract base class for additinal components displayed in content headers and footer according to: * the displayed entity's type * a context (currently 'header' or 'footer') it should be configured using .accepts, .etype, .rtype, .target and .context class attributes """__registry__='contentnavigation'__select__=one_line_rset()&primary_view()&match_context_prop()cw_property_defs={_('visible'):dict(type='Boolean',default=True,help=_('display the component or not')),_('order'):dict(type='Int',default=99,help=_('display order of the component')),_('context'):dict(type='String',default='navtop',vocabulary=(_('navtop'),_('navbottom'),_('navcontenttop'),_('navcontentbottom'),_('ctxtoolbar')),help=_('context where this component should be displayed')),}context='navcontentbottom'defcall(self,view=None):returnself.cell_call(0,0,view=view)defcell_call(self,row,col,view=None):raiseNotImplementedError()classNavigationComponent(Component):"""abstract base class for navigation components"""__regid__='navigation'__select__=paginated_rset()cw_property_defs={_('visible'):dict(type='Boolean',default=True,help=_('display the component or not')),}page_size_property='navigation.page-size'start_param='__start'stop_param='__stop'page_link_templ=u'<span class="slice"><a href="%s" title="%s">%s</a></span>'selected_page_link_templ=u'<span class="selectedSlice"><a href="%s" title="%s">%s</a></span>'previous_page_link_templ=next_page_link_templ=page_link_templno_previous_page_link=u'<<'no_next_page_link=u'>>'def__init__(self,req,rset,**kwargs):super(NavigationComponent,self).__init__(req,rset=rset,**kwargs)self.starting_from=0self.total=rset.rowcountdefget_page_size(self):try:returnself._page_sizeexceptAttributeError:page_size=self.cw_extra_kwargs.get('page_size')ifpage_sizeisNone:if'page_size'inself._cw.form:page_size=int(self._cw.form['page_size'])else:page_size=self._cw.property_value(self.page_size_property)self._page_size=page_sizereturnpage_sizedefset_page_size(self,page_size):self._page_size=page_sizepage_size=property(get_page_size,set_page_size)defpage_boundaries(self):try:stop=int(self._cw.form[self.stop_param])+1start=int(self._cw.form[self.start_param])exceptKeyError:start,stop=0,self.page_sizeifstart>=len(self.cw_rset):start,stop=0,self.page_sizeself.starting_from=startreturnstart,stopdefclean_params(self,params):ifself.start_paraminparams:delparams[self.start_param]ifself.stop_paraminparams:delparams[self.stop_param]defpage_url(self,path,params,start,stop):params=merge_dicts(params,{self.start_param:start,self.stop_param:stop,})ifpath=='json':rql=params.pop('rql',self.cw_rset.printable_rql())# latest 'true' used for 'swap' modeurl='javascript: replacePageChunk(%s, %s, %s, %s, true)'%(dumps(params.get('divid','paginated-content')),dumps(rql),dumps(params.pop('vid',None)),dumps(params))else:url=self._cw.build_url(path,**params)returnurldefpage_link(self,path,params,start,stop,content):url=xml_escape(self.page_url(path,params,start,stop))ifstart==self.starting_from:returnself.selected_page_link_templ%(url,content,content)returnself.page_link_templ%(url,content,content)defprevious_link(self,path,params,content='<<',title=_('previous_results')):start=self.starting_fromifnotstart:returnself.no_previous_page_linkstart=max(0,start-self.page_size)stop=start+self.page_size-1url=xml_escape(self.page_url(path,params,start,stop))returnself.previous_page_link_templ%(url,title,content)defnext_link(self,path,params,content='>>',title=_('next_results')):start=self.starting_from+self.page_sizeifstart>=self.total:returnself.no_next_page_linkstop=start+self.page_size-1url=xml_escape(self.page_url(path,params,start,stop))returnself.next_page_link_templ%(url,title,content)classRelatedObjectsVComponent(EntityVComponent):"""a section to display some related entities"""__select__=EntityVComponent.__select__&partial_has_related_entities()vid='list'defrql(self):"""override this method if you want to use a custom rql query"""returnNonedefcell_call(self,row,col,view=None):rql=self.rql()ifrqlisNone:entity=self.cw_rset.get_entity(row,col)rset=entity.related(self.rtype,role(self))else:eid=self.cw_rset[row][col]rset=self._cw.execute(self.rql(),{'x':eid},'x')ifnotrset.rowcount:returnself.w(u'<div class="%s">'%self.div_class())self.w(u'<h4>%s</h4>\n'%self._cw._(self.title).capitalize())self.wview(self.vid,rset)self.w(u'</div>')VComponent=class_renamed('VComponent',Component,'VComponent is deprecated, use Component')SingletonVComponent=class_renamed('SingletonVComponent',Component,'SingletonVComponent is deprecated, use ''Component and explicit registration control')