"""base classes to handle tabbed views:organization: Logilab:copyright: 2008-2009 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"fromlogilab.mtconverterimportxml_escapefromcubicwebimportNoSelectableObject,rolefromcubicweb.selectorsimportpartial_has_related_entitiesfromcubicweb.viewimportEntityViewfromcubicweb.commonimporttags,uilibfromcubicweb.utilsimportmake_uidfromcubicweb.web.viewsimportprimaryclassLazyViewMixin(object):"""provides two convenience methods for the tab machinery can also be used to lazy-load arbitrary views """def_prepare_bindings(self,vid,reloadable):self.req.add_onload(u""" jQuery('#lazy-%(vid)s').bind('%(event)s', function(event) { load_now('#lazy-%(vid)s', '#%(vid)s-hole', %(reloadable)s); });"""%{'event':'load_%s'%vid,'vid':vid,'reloadable':str(reloadable).lower()})deflazyview(self,vid,rql=None,eid=None,rset=None,tabid=None,reloadable=False,show_spinbox=True,w=None):"""a lazy version of wview first version only support lazy viewing for an entity at a time """w=worself.wself.req.add_js('cubicweb.lazy.js')urlparams={'vid':vid,'fname':'view'}ifrql:urlparams['rql']=rqlelifeid:urlparams['rql']=uilib.rql_for_eid(eid)elifrset:urlparams['rql']=rset.printable_rql()w(u'<div id="lazy-%s" cubicweb:loadurl="%s">'%(tabidorvid,xml_escape(self.build_url('json',**urlparams))))ifshow_spinbox:w(u'<img src="data/loading.gif" id="%s-hole" alt="%s"/>'%(tabidorvid,self.req._('loading')))w(u'</div>')self._prepare_bindings(tabidorvid,reloadable)defforceview(self,vid):"""trigger an event that will force immediate loading of the view on dom readyness """self.req.add_js('cubicweb.lazy.js')self.req.add_onload("trigger_load('%s');"%vid)classTabsMixin(LazyViewMixin):"""a tab mixin """@propertydefcookie_name(self):returnstr('%s_active_tab'%self.config.appid)defactive_tab(self,default):if'tab'inself.req.form:returnself.req.form['tab']cookies=self.req.get_cookie()cookiename=self.cookie_nameactivetab=cookies.get(cookiename)ifactivetabisNone:cookies[cookiename]=defaultself.req.set_cookie(cookies,cookiename)returndefaultreturnactivetab.valuedefprune_tabs(self,tabs,default_tab):selected_tabs=[]may_be_active_tab=self.active_tab(default_tab)active_tab=default_tabviewsvreg=self.vreg['views']fortabintabs:try:tabid,tabkwargs=tabtabkwargs=tabkwargs.copy()exceptValueError:tabid,tabkwargs=tab,{}tabkwargs.setdefault('rset',self.rset)vid=tabkwargs.get('vid',tabid)try:viewsvreg.select(vid,self.req,**tabkwargs)selected_tabs.append((tabid,tabkwargs))exceptNoSelectableObject:continueiftabid==may_be_active_tab:active_tab=tabidreturnselected_tabs,active_tabdefrender_tabs(self,tabs,default,entity=None):# delegate to the default tab if there is more than one entity# in the result set (tabs are pretty useless there)ifentityandlen(self.rset)>1:entity.view(default,w=self.w)returnself.req.add_css('ui.tabs.css')self.req.add_js(('ui.core.js','ui.tabs.js','cubicweb.ajax.js','cubicweb.tabs.js','cubicweb.lazy.js'))# prune tabs : not all are to be showntabs,active_tab=self.prune_tabs(tabs,default)# build the html structurew=self.wuid=entityandentity.eidormake_uid('tab')w(u'<div id="entity-tabs-%s">'%uid)w(u'<ul>')active_tab_idx=Nonefori,(tabid,tabkwargs)inenumerate(tabs):w(u'<li>')w(u'<a href="#%s">'%tabid)w(u'<span onclick="set_tab(\'%s\', \'%s\')">'%(tabid,self.cookie_name))w(tabkwargs.pop('label',self.req._(tabid)))w(u'</span>')w(u'</a>')w(u'</li>')iftabid==active_tab:active_tab_idx=iw(u'</ul>')w(u'</div>')fortabid,tabkwargsintabs:w(u'<div id="%s">'%tabid)tabkwargs.setdefault('tabid',tabid)tabkwargs.setdefault('vid',tabid)tabkwargs.setdefault('rset',self.rset)self.lazyview(**tabkwargs)w(u'</div>')# call the set_tab() JS function *after* each tab is generated# because the callback binding needs to be done before# XXX make work history: trueself.req.add_onload(u""" jQuery('#entity-tabs-%(eeid)s > ul').tabs( { selected: %(tabindex)s }); set_tab('%(vid)s', '%(cookiename)s');"""%{'tabindex':active_tab_idx,'vid':active_tab,'eeid':(entityandentity.eidoruid),'cookiename':self.cookie_name})classEntityRelationView(EntityView):"""view displaying entity related stuff. Such a view _must_ provide the rtype, target and vid attributes : Example : class ProjectScreenshotsView(EntityRelationView): '''display project's screenshots''' id = title = _('projectscreenshots') __select__ = EntityRelationView.__select__ & implements('Project') rtype = 'screenshot' role = 'subject' vid = 'gallery' in this example, entities related to project entity by the 'screenshot' relation (where the project is subject of the relation) will be displayed using the 'gallery' view. """__select__=EntityView.__select__&partial_has_related_entities()vid='list'defcell_call(self,row,col):rset=self.entity(row,col).related(self.rtype,role(self))self.w(u'<div class="mainInfo">')ifself.title:self.w(tags.h1(self.req._(self.title)))self.wview(self.vid,rset,'noresult')self.w(u'</div>')classTabedPrimaryView(TabsMixin,primary.PrimaryView):__abstract__=True# don't registertabs=['main_tab']default_tab='main_tab'defcell_call(self,row,col):entity=self.complete_entity(row,col)self.render_entity_title(entity)self.render_entity_metadata(entity)self.render_tabs(self.tabs,self.default_tab,entity)classPrimaryTab(primary.PrimaryView):id='main_tab'title=Nonedefis_primary(self):returnTruedefrender_entity_title(self,entity):passdefrender_entity_metadata(self,entity):pass