--- a/.hgtags Tue Mar 03 14:54:31 2009 +0100
+++ b/.hgtags Tue Mar 03 15:06:03 2009 +0100
@@ -16,3 +16,5 @@
fc222bc99929d395c1c2235c40d3bb6f247b4ba9 cubicweb-debian-version-3_0_4-1
7ad527099393ef56f27af313392022bb8ed73082 cubicweb-version-3_0_9
a8e9e53b245d53838a07aa8c76d1bed352692a9f cubicweb-debian-version-3_0_9-1
+a711c7c185d15a1bd22b7eaab46a26b98b74fbf3 cubicweb-version-3_1_0
+dd3efdf58d281286d6f52f7416db349b75b7789c cubicweb-debian-version-3_1_0-1
--- a/__pkginfo__.py Tue Mar 03 14:54:31 2009 +0100
+++ b/__pkginfo__.py Tue Mar 03 15:06:03 2009 +0100
@@ -6,7 +6,7 @@
distname = "cubicweb"
modname = "cubicweb"
-numversion = (3, 0, 10)
+numversion = (3, 1, 0)
version = '.'.join(str(num) for num in numversion)
license = 'GPL'
--- a/common/entity.py Tue Mar 03 14:54:31 2009 +0100
+++ b/common/entity.py Tue Mar 03 15:06:03 2009 +0100
@@ -41,6 +41,8 @@
'inlineview'))
def __init__(self, eclass, tagdefs):
+ # XXX if a rtag is redefined in a subclass,
+ # the rtag of the base class overwrite the rtag of the subclass
self.eclass = eclass
self._tagdefs = {}
for relation, tags in tagdefs.iteritems():
--- a/common/mixins.py Tue Mar 03 14:54:31 2009 +0100
+++ b/common/mixins.py Tue Mar 03 15:06:03 2009 +0100
@@ -175,14 +175,14 @@
return self.req._(self.state)
def wf_state(self, statename):
- rset = self.req.execute('Any S, SN WHERE S name %(n)s, S state_of E, E name %(e)s',
+ rset = self.req.execute('Any S, SN WHERE S name SN, S name %(n)s, S state_of E, E name %(e)s',
{'n': statename, 'e': str(self.e_schema)})
if rset:
return rset.get_entity(0, 0)
return None
def wf_transition(self, trname):
- rset = self.req.execute('Any T, TN WHERE T name %(n)s, T transition_of E, E name %(e)s',
+ rset = self.req.execute('Any T, TN WHERE T name TN, T name %(n)s, T transition_of E, E name %(e)s',
{'n': trname, 'e': str(self.e_schema)})
if rset:
return rset.get_entity(0, 0)
@@ -369,22 +369,18 @@
"""provide default implementations for IProgress interface methods"""
@property
- @cached
def cost(self):
return self.progress_info()['estimated']
@property
- @cached
def revised_cost(self):
return self.progress_info().get('estimatedcorrected', self.cost)
@property
- @cached
def done(self):
return self.progress_info()['done']
@property
- @cached
def todo(self):
return self.progress_info()['todo']
@@ -403,6 +399,6 @@
return 100. * self.done / self.revised_cost
except ZeroDivisionError:
# total cost is 0 : if everything was estimated, task is completed
- if self.progress_info().get('notestmiated'):
+ if self.progress_info().get('notestimated'):
return 0.
return 100
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common/test/unittest_mixins.py Tue Mar 03 15:06:03 2009 +0100
@@ -0,0 +1,25 @@
+from logilab.common.testlib import unittest_main
+from cubicweb.devtools.apptest import EnvBasedTC
+
+class WorkfloableMixInTC(EnvBasedTC):
+ def test_wf_state(self):
+ s = self.add_entity('State', name=u'activated')
+ self.execute('SET X state_of ET WHERE ET name "Bookmark", X eid %(x)s',
+ {'x': s.eid})
+ es = self.user().wf_state('activated')
+ self.assertEquals(es.state_of[0].name, 'EUser')
+
+ def test_wf_transition(self):
+ t = self.add_entity('Transition', name=u'deactivate')
+ self.execute('SET X transition_of ET WHERE ET name "Bookmark", X eid %(x)s',
+ {'x': t.eid})
+ et = self.user().wf_transition('deactivate')
+ self.assertEquals(et.transition_of[0].name, 'EUser')
+
+ def test_change_state(self):
+ user = self.user()
+ user.change_state(user.wf_state('deactivated').eid)
+ self.assertEquals(user.state, 'deactivated')
+
+if __name__ == '__main__':
+ unittest_main()
--- a/common/uilib.py Tue Mar 03 14:54:31 2009 +0100
+++ b/common/uilib.py Tue Mar 03 15:06:03 2009 +0100
@@ -190,7 +190,7 @@
if text is None:
return u''
words = text.split()
- text = ' '.join(words) # normalize spaces
+ text = u' '.join(words) # normalize spaces
minlength = len(' '.join(words[:nbwords]))
textlength = text.find('.', minlength) + 1
if textlength == 0: # no point found
--- a/common/view.py Tue Mar 03 14:54:31 2009 +0100
+++ b/common/view.py Tue Mar 03 15:06:03 2009 +0100
@@ -302,6 +302,7 @@
"""
__registerer__ = accepts_registerer
__selectors__ = (accept,)
+ accepts = ('Any',)
category = 'entityview'
def field(self, label, value, row=True, show_label=True, w=None, tr=True):
--- a/debian/changelog Tue Mar 03 14:54:31 2009 +0100
+++ b/debian/changelog Tue Mar 03 15:06:03 2009 +0100
@@ -1,3 +1,9 @@
+cubicweb (3.1.0-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr> Wed, 25 Feb 2009 18:41:47 +0100
+
cubicweb (3.0.10-1) unstable; urgency=low
* merge cubicweb-core package into cubicweb-common
--- a/debian/control Tue Mar 03 14:54:31 2009 +0100
+++ b/debian/control Tue Mar 03 15:06:03 2009 +0100
@@ -60,7 +60,7 @@
Package: cubicweb-web
Architecture: all
XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-simplejson (>= 1.3), python-docutils, python-vobject, python-elementtree
+Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), python-docutils, python-vobject, python-elementtree
Recommends: fckeditor
Description: web interface library for the CubicWeb framework
CubicWeb is a semantic web application framework.
@@ -75,7 +75,7 @@
Package: cubicweb-common
Architecture: all
XB-Python-Version: ${python:Versions}
-Depends: ${python:Depends}, python-logilab-mtconverter (>= 0.4.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml, python-logilab-common (>= 0.37.2), python-yams (>= 0.20.2), python-rql (>= 0.20.2)
+Depends: ${python:Depends}, python-logilab-mtconverter (>= 0.6.0), python-simpletal (>= 4.0), graphviz, gettext, python-lxml, python-logilab-common (>= 0.38.1), python-yams (>= 0.20.2), python-rql (>= 0.20.2), python-simplejson (>= 1.3)
Recommends: python-psyco
Conflicts: cubicweb-core
Replaces: cubicweb-core
--- a/devtools/__init__.py Tue Mar 03 14:54:31 2009 +0100
+++ b/devtools/__init__.py Tue Mar 03 15:06:03 2009 +0100
@@ -260,6 +260,8 @@
- http://www.sqlite.org/cvstrac/tktview?tn=1327,33
(some dates are returned as strings rather thant date objects)
"""
+ if hasattr(querier.__class__, '_devtools_sqlite_patched'):
+ return # already monkey patched
def wrap_execute(base_execute):
def new_execute(*args, **kwargs):
rset = base_execute(*args, **kwargs)
@@ -288,7 +290,7 @@
return rset
return new_execute
querier.__class__.execute = wrap_execute(querier.__class__.execute)
-
+ querier.__class__._devtools_sqlite_patched = True
def init_test_database(driver='sqlite', configdir='data', config=None,
vreg=None):
--- a/devtools/apptest.py Tue Mar 03 14:54:31 2009 +0100
+++ b/devtools/apptest.py Tue Mar 03 15:06:03 2009 +0100
@@ -407,6 +407,7 @@
self.__close(self.cnxid)
# other utilities #########################################################
+
def set_debug(self, debugmode):
from cubicweb.server import set_debug
set_debug(debugmode)
@@ -452,7 +453,7 @@
self.__commit = repo.commit
self.__rollback = repo.rollback
self.__close = repo.close
- self.cnxid = repo.connect(*self.default_user_password())
+ self.cnxid = self.cnx.sessionid
self.session = repo._sessions[self.cnxid]
# XXX copy schema since hooks may alter it and it may be not fully
# cleaned (missing some schema synchronization support)
--- a/goa/dbmyams.py Tue Mar 03 14:54:31 2009 +0100
+++ b/goa/dbmyams.py Tue Mar 03 15:06:03 2009 +0100
@@ -109,6 +109,7 @@
super(GaeSchemaLoader, self).__init__(*args, **kwargs)
self.defined = {}
self.created = []
+ self.loaded_files = []
self._instantiate_handlers()
def finalize(self, register_base_types=False):
--- a/i18n/en.po Tue Mar 03 14:54:31 2009 +0100
+++ b/i18n/en.po Tue Mar 03 15:06:03 2009 +0100
@@ -47,10 +47,26 @@
msgstr ""
#, python-format
+msgid "%d days"
+msgstr ""
+
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#, python-format
msgid "%d months"
msgstr ""
#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#, python-format
msgid "%d weeks"
msgstr ""
@@ -59,7 +75,31 @@
msgstr ""
#, python-format
-msgid "%s days"
+msgid "%d days"
+msgstr ""
+
+#, python-format
+msgid "%d hours"
+msgstr ""
+
+#, python-format
+msgid "%d minutes"
+msgstr ""
+
+#, python-format
+msgid "%d months"
+msgstr ""
+
+#, python-format
+msgid "%d seconds"
+msgstr ""
+
+#, python-format
+msgid "%d weeks"
+msgstr ""
+
+#, python-format
+msgid "%d years"
msgstr ""
#, python-format
@@ -67,14 +107,6 @@
msgstr ""
#, python-format
-msgid "%s hours"
-msgstr ""
-
-#, python-format
-msgid "%s minutes"
-msgstr ""
-
-#, python-format
msgid "%s not estimated"
msgstr ""
@@ -83,10 +115,6 @@
msgstr ""
#, python-format
-msgid "%s seconds"
-msgstr ""
-
-#, python-format
msgid "%s software version of the database"
msgstr ""
@@ -376,9 +404,6 @@
msgid "Problem occured"
msgstr ""
-msgid "Project linked data"
-msgstr ""
-
msgid "RQLExpression"
msgstr "RQL expression"
@@ -2197,15 +2222,12 @@
msgid "ordernum"
msgstr "order"
-msgid "owl (tbox+abox)"
+msgid "owl"
msgstr ""
msgid "owlabox"
msgstr ""
-msgid "owlaboxlight"
-msgstr ""
-
msgid "owned_by"
msgstr "owned by"
@@ -2577,9 +2599,6 @@
msgid "task progression"
msgstr ""
-msgid "tbox"
-msgstr ""
-
msgid "text"
msgstr ""
--- a/i18n/es.po Tue Mar 03 14:54:31 2009 +0100
+++ b/i18n/es.po Tue Mar 03 15:06:03 2009 +0100
@@ -52,34 +52,66 @@
msgstr "%(subject)s %(etype)s #%(eid)s (%(login)s)"
#, python-format
+msgid "%d days"
+msgstr "%d días"
+
+#, python-format
+msgid "%d hours"
+msgstr "%d horas"
+
+#, python-format
+msgid "%d minutes"
+msgstr "%d minutos"
+
+#, python-format
msgid "%d months"
msgstr "%d meses"
#, python-format
+msgid "%d seconds"
+msgstr "%d segundos"
+
+#, python-format
msgid "%d weeks"
msgstr "%d semanas"
#, python-format
-msgid "%d years"
-msgstr "%d años"
+msgid "%d years"
+msgstr "%d años"
+
+#, python-format
+msgid "%d days"
+msgstr "%d días"
+
+#, python-format
+msgid "%d hours"
+msgstr "%d horas"
#, python-format
-msgid "%s days"
-msgstr "%d días"
+msgid "%d minutes"
+msgstr "%d minutos"
+
+#, python-format
+msgid "%d months"
+msgstr "%d meses"
+
+#, python-format
+msgid "%d seconds"
+msgstr "%d segundos"
+
+#, python-format
+msgid "%d weeks"
+msgstr "%d semanas"
+
+#, python-format
+msgid "%d years"
+msgstr "%d años"
#, python-format
msgid "%s error report"
msgstr "%s reporte de errores"
#, python-format
-msgid "%s hours"
-msgstr "%s horas"
-
-#, python-format
-msgid "%s minutes"
-msgstr "%s minutos"
-
-#, python-format
msgid "%s not estimated"
msgstr "%s no estimado(s)"
@@ -88,10 +120,6 @@
msgstr "%s resultados de la demanda"
#, python-format
-msgid "%s seconds"
-msgstr "%s segundos"
-
-#, python-format
msgid "%s software version of the database"
msgstr "version sistema de la base para %s"
@@ -381,9 +409,6 @@
msgid "Problem occured"
msgstr "Ha ocurrido un error"
-msgid "Project linked data"
-msgstr ""
-
msgid "RQLExpression"
msgstr "Expresión RQL"
@@ -2292,15 +2317,12 @@
msgid "ordernum"
msgstr "ordre"
-msgid "owl (tbox+abox)"
+msgid "owl"
msgstr ""
msgid "owlabox"
msgstr ""
-msgid "owlaboxlight"
-msgstr ""
-
msgid "owned_by"
msgstr "appartient ‡"
@@ -2685,9 +2707,6 @@
msgid "task progression"
msgstr "avancement de la t‚che"
-msgid "tbox"
-msgstr ""
-
msgid "text"
msgstr "text"
--- a/i18n/fr.po Tue Mar 03 14:54:31 2009 +0100
+++ b/i18n/fr.po Tue Mar 03 15:06:03 2009 +0100
@@ -52,10 +52,26 @@
msgstr "%(subject)s %(etype)s #%(eid)s (%(login)s)"
#, python-format
+msgid "%d days"
+msgstr "%d jours"
+
+#, python-format
+msgid "%d hours"
+msgstr "%d heures"
+
+#, python-format
+msgid "%d minutes"
+msgstr "%d minutes"
+
+#, python-format
msgid "%d months"
msgstr "%d mois"
#, python-format
+msgid "%d seconds"
+msgstr "%d secondes"
+
+#, python-format
msgid "%d weeks"
msgstr "%d semaines"
@@ -64,22 +80,38 @@
msgstr "%d années"
#, python-format
-msgid "%s days"
-msgstr "%d jours"
+msgid "%d days"
+msgstr "%d jours"
+
+#, python-format
+msgid "%d hours"
+msgstr "%d heures"
+
+#, python-format
+msgid "%d minutes"
+msgstr "%d minutes"
+
+#, python-format
+msgid "%d months"
+msgstr "%d mois"
+
+#, python-format
+msgid "%d seconds"
+msgstr "%d secondes"
+
+#, python-format
+msgid "%d weeks"
+msgstr "%d semaines"
+
+#, python-format
+msgid "%d years"
+msgstr "%d années"
#, python-format
msgid "%s error report"
msgstr "%s rapport d'erreur"
#, python-format
-msgid "%s hours"
-msgstr "%s heures"
-
-#, python-format
-msgid "%s minutes"
-msgstr "%s minutes"
-
-#, python-format
msgid "%s not estimated"
msgstr "%s non estimé(s)"
@@ -88,10 +120,6 @@
msgstr "%s résultats pour la requête"
#, python-format
-msgid "%s seconds"
-msgstr "%s secondes"
-
-#, python-format
msgid "%s software version of the database"
msgstr "version logicielle de la base pour %s"
@@ -381,9 +409,6 @@
msgid "Problem occured"
msgstr "Une erreur est survenue"
-msgid "Project linked data"
-msgstr ""
-
msgid "RQLExpression"
msgstr "Expression RQL"
@@ -2293,15 +2318,12 @@
msgid "ordernum"
msgstr "ordre"
-msgid "owl (tbox+abox)"
+msgid "owl"
msgstr ""
msgid "owlabox"
msgstr ""
-msgid "owlaboxlight"
-msgstr ""
-
msgid "owned_by"
msgstr "appartient à"
@@ -2686,9 +2708,6 @@
msgid "task progression"
msgstr "avancement de la tâche"
-msgid "tbox"
-msgstr ""
-
msgid "text"
msgstr "text"
--- a/interfaces.py Tue Mar 03 14:54:31 2009 +0100
+++ b/interfaces.py Tue Mar 03 15:06:03 2009 +0100
@@ -238,7 +238,20 @@
def rss_feed_url(self):
"""return an url which layout sub-entities item
"""
-class ISIOC(Interface):
- """interface for entities with sioc views"""
+class ISiocItem(Interface):
+ """interface for entities (which are item
+ in sioc specification) with sioc views"""
-
+ def isioc_content(self):
+ """return content entity"""
+
+ def isioc_container(self):
+ """return container entity"""
+
+class ISiocContainer(Interface):
+ """interface for entities (which are container
+ in sioc specification) with sioc views"""
+
+ def isioc_type(self):
+ """return container type (forum, weblog, mailinglist)"""
+
--- a/server/migractions.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/migractions.py Tue Mar 03 15:06:03 2009 +0100
@@ -57,7 +57,7 @@
self.repo_connect()
if not schema:
schema = config.load_schema(expand_cubes=True)
- self.new_schema = schema
+ self.fs_schema = schema
self._synchronized = set()
@cached
@@ -217,7 +217,9 @@
'rql': self.rqlexec,
'rqliter': self.rqliter,
'schema': self.repo.schema,
- 'newschema': self.new_schema,
+ # XXX deprecate
+ 'newschema': self.fs_schema,
+ 'fsschema': self.fs_schema,
'cnx': self.cnx,
'session' : self.session,
'repo' : self.repo,
@@ -281,22 +283,22 @@
if not update_database:
self.commit()
return
- with_new_cubes = self.config.load_schema()
+ newcubes_schema = self.config.load_schema()
new = set()
# execute pre-create files
for pack in reversed(newcubes):
self.exec_event_script('precreate', self.config.cube_dir(pack))
# add new entity and relation types
- for rschema in with_new_cubes.relations():
+ for rschema in newcubes_schema.relations():
if not rschema in self.repo.schema:
self.cmd_add_relation_type(rschema.type)
new.add(rschema.type)
- for eschema in with_new_cubes.entities():
+ for eschema in newcubes_schema.entities():
if not eschema in self.repo.schema:
self.cmd_add_entity_type(eschema.type)
new.add(eschema.type)
# check if attributes has been added to existing entities
- for rschema in with_new_cubes.relations():
+ for rschema in newcubes_schema.relations():
existingschema = self.repo.schema.rschema(rschema.type)
for (fromtype, totype) in rschema.iter_rdefs():
if existingschema.has_rdef(fromtype, totype):
@@ -315,25 +317,25 @@
removedcubes = super(ServerMigrationHelper, self).cmd_remove_cube(cube)
if not removedcubes:
return
- oldschema = self.new_schema
- self.new_schema = newschema = self.config.load_schema()
+ fsschema = self.fs_schema
+ removedcubes_schema = self.config.load_schema()
reposchema = self.repo.schema
# execute pre-remove files
for pack in reversed(removedcubes):
self.exec_event_script('preremove', self.config.cube_dir(pack))
# remove cubes'entity and relation types
- for rschema in oldschema.relations():
- if not rschema in newschema and rschema in reposchema:
+ for rschema in fsschema.relations():
+ if not rschema in removedcubes_schema and rschema in reposchema:
self.cmd_drop_relation_type(rschema.type)
- for eschema in oldschema.entities():
- if not eschema in newschema and eschema in reposchema:
+ for eschema in fsschema.entities():
+ if not eschema in removedcubes_schema and eschema in reposchema:
self.cmd_drop_entity_type(eschema.type)
- for rschema in oldschema.relations():
- if rschema in newschema and rschema in reposchema:
+ for rschema in fsschema.relations():
+ if rschema in removedcubes_schema and rschema in reposchema:
# check if attributes/relations has been added to entities from
# other cubes
for fromtype, totype in rschema.iter_rdefs():
- if not newschema[rschema.type].has_rdef(fromtype, totype) and \
+ if not removedcubes_schema[rschema.type].has_rdef(fromtype, totype) and \
reposchema[rschema.type].has_rdef(fromtype, totype):
self.cmd_drop_relation_definition(
str(fromtype), rschema.type, str(totype))
@@ -349,7 +351,7 @@
def cmd_add_attribute(self, etype, attrname, attrtype=None, commit=True):
"""add a new attribute on the given entity type"""
if attrtype is None:
- rschema = self.new_schema.rschema(attrname)
+ rschema = self.fs_schema.rschema(attrname)
attrtype = rschema.objects(etype)[0]
self.cmd_add_relation_definition(etype, attrname, attrtype, commit=commit)
@@ -368,7 +370,7 @@
`oldname` is a string giving the name of the existing attribute
`newname` is a string giving the name of the renamed attribute
"""
- eschema = self.new_schema.eschema(etype)
+ eschema = self.fs_schema.eschema(etype)
attrtype = eschema.destination(newname)
# have to commit this first step anyway to get the definition
# actually in the schema
@@ -393,7 +395,7 @@
if eschema.is_final():
applschema.del_entity_type(etype)
else:
- eschema = self.new_schema.eschema(etype)
+ eschema = self.fs_schema.eschema(etype)
confirm = self.verbosity >= 2
# register the entity into EEType
self.rqlexecall(ss.eschema2rql(eschema), ask_confirm=confirm)
@@ -499,7 +501,7 @@
committing depends on the `commit` argument value).
"""
- rschema = self.new_schema.rschema(rtype)
+ rschema = self.fs_schema.rschema(rtype)
# register the relation into ERType and insert necessary relation
# definitions
self.rqlexecall(ss.rschema2rql(rschema, addrdef=False),
@@ -537,7 +539,7 @@
"""register a new relation definition, from its definition found in the
schema definition file
"""
- rschema = self.new_schema.rschema(rtype)
+ rschema = self.fs_schema.rschema(rtype)
if not rtype in self.repo.schema:
self.cmd_add_relation_type(rtype, addrdef=False, commit=True)
self.rqlexecall(ss.rdef2rql(rschema, subjtype, objtype),
@@ -564,7 +566,7 @@
"""permission synchronization for an entity or relation type"""
if ertype in ('eid', 'has_text', 'identity'):
return
- newrschema = self.new_schema[ertype]
+ newrschema = self.fs_schema[ertype]
teid = self.repo.schema[ertype].eid
if 'update' in newrschema.ACTIONS or newrschema.is_final():
# entity type
@@ -644,7 +646,7 @@
if rtype in self._synchronized:
return
self._synchronized.add(rtype)
- rschema = self.new_schema.rschema(rtype)
+ rschema = self.fs_schema.rschema(rtype)
self.rqlexecall(ss.updaterschema2rql(rschema),
ask_confirm=self.verbosity>=2)
reporschema = self.repo.schema.rschema(rtype)
@@ -674,7 +676,7 @@
self._synchronized.add(etype)
repoeschema = self.repo.schema.eschema(etype)
try:
- eschema = self.new_schema.eschema(etype)
+ eschema = self.fs_schema.eschema(etype)
except KeyError:
return
repospschema = repoeschema.specializes()
@@ -719,7 +721,7 @@
* constraints
"""
subjtype, objtype = str(subjtype), str(objtype)
- rschema = self.new_schema.rschema(rtype)
+ rschema = self.fs_schema.rschema(rtype)
reporschema = self.repo.schema.rschema(rschema)
if (subjtype, rschema, objtype) in self._synchronized:
return
@@ -903,6 +905,13 @@
if commit:
self.commit()
+ def cmd_set_state(self, eid, statename, commit=False):
+ self.session.set_pool() # ensure pool is set
+ entity = self.session.eid_rset(eid).get_entity(0, 0)
+ entity.change_state(entity.wf_state(statename).eid)
+ if commit:
+ self.commit()
+
# EProperty handling ######################################################
def cmd_property_value(self, pkey):
--- a/server/rqlannotation.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/rqlannotation.py Tue Mar 03 15:06:03 2009 +0100
@@ -260,7 +260,6 @@
has_text_query = True
return has_text_query
-
def is_ambiguous(self, var):
# ignore has_text relation
if len([rel for rel in var.stinfo['relations']
@@ -337,7 +336,7 @@
except KeyError:
# no relation to deambiguify
continue
-
+
def _debug_print(self):
print 'varsols', dict((x, sorted(str(v) for v in values))
for x, values in self.varsols.iteritems())
@@ -375,8 +374,9 @@
otheretypes = (other.uidtype,)
deambiguifier = None
if otheretypes is not None:
- # unless types for variable are already non-ambigous, check
- # if this relation has some type ambiguity
+ # to restrict, we must check that for all type in othertypes,
+ # possible types on the other end of the relation are matching
+ # variable's possible types
rschema = self.rschema(rel.r_type)
if onlhs:
rtypefunc = rschema.subjects
@@ -386,7 +386,8 @@
reltypes = frozenset(rtypefunc(otheretype))
if var.stinfo['possibletypes'] != reltypes:
break
- self.restrict(var, reltypes)
+ else:
+ self.restrict(var, var.stinfo['possibletypes'])
self.deambification_map[var] = deambiguifier
return True
return False
--- a/server/session.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/session.py Tue Mar 03 15:06:03 2009 +0100
@@ -1,7 +1,7 @@
"""Repository users' and internal' sessions.
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
--- a/server/sources/ldapuser.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/sources/ldapuser.py Tue Mar 03 15:06:03 2009 +0100
@@ -176,6 +176,10 @@
external repository
"""
self.info('synchronizing ldap source %s', self.uri)
+ try:
+ ldap_emailattr = self.user_rev_attrs['email']
+ except KeyError:
+ return # no email in ldap, we're done
session = self.repo.internal_session()
try:
cursor = session.system_sql("SELECT eid, extid FROM entities WHERE "
@@ -184,7 +188,7 @@
# if no result found, _search automatically delete entity information
res = self._search(session, extid, BASE)
if res:
- ldapemailaddr = res[0].get(self.user_rev_attrs['email'])
+ ldapemailaddr = res[0].get(ldap_emailattr)
if ldapemailaddr:
rset = session.execute('EmailAddress X,A WHERE '
'U use_email X, U eid %(u)s',
@@ -628,7 +632,10 @@
filter = '(%s%s)' % (self._ldap_attrs[relation.r_type],
rhs.accept(self))
except KeyError:
- assert relation.r_type == 'password' # 2.38 migration
+ # unsupported attribute
+ self.source.warning('%s source can\'t handle relation %s, no '
+ 'results will be returned from this source',
+ self.source.uri, relation)
raise UnknownEid # trick to return no result
return filter
--- a/server/sources/native.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/sources/native.py Tue Mar 03 15:06:03 2009 +0100
@@ -451,6 +451,7 @@
try:
res = session.system_sql(sql).fetchone()
except:
+ assert self.pool, 'session has no pool set'
raise UnknownEid(eid)
if res is None:
raise UnknownEid(eid)
--- a/server/test/data/schema/relations.rel Tue Mar 03 14:54:31 2009 +0100
+++ b/server/test/data/schema/relations.rel Tue Mar 03 15:06:03 2009 +0100
@@ -43,3 +43,6 @@
EPermission require_state State
Note migrated_from Note
+
+Note attachment File
+Note attachment Image
--- a/server/test/unittest_ldapuser.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/test/unittest_ldapuser.py Tue Mar 03 15:06:03 2009 +0100
@@ -33,8 +33,8 @@
repo, cnx = init_test_database('sqlite', config=config)
class LDAPUserSourceTC(RepositoryBasedTC):
- repo = repo
-
+ repo, cnx = repo, cnx
+
def patch_authenticate(self):
self._orig_authenticate = LDAPUserSource.authenticate
LDAPUserSource.authenticate = nopwd_authenticate
@@ -242,7 +242,10 @@
['users', 'cochon'],
['users', 'syt']])
-
+ def test_cd_restriction(self):
+ rset = self.execute('EUser X WHERE X creation_date > "2009-02-01"')
+ self.assertEquals(len(rset), 2) # admin/anon but no ldap user since it doesn't support creation_date
+
def test_union(self):
afeids = self.execute('State X')
ueids = self.execute('EUser X')
--- a/server/test/unittest_migractions.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/test/unittest_migractions.py Tue Mar 03 15:06:03 2009 +0100
@@ -40,6 +40,8 @@
self.mh = ServerMigrationHelper(self.repo.config, migrschema,
repo=self.repo, cnx=self.cnx,
interactive=False)
+ assert self.cnx is self.mh._cnx
+ assert self.session is self.mh.session, (self.session.id, self.mh.session.id)
def test_add_attribute_int(self):
self.failIf('whatever' in self.schema)
@@ -424,6 +426,16 @@
# why this commit is necessary is unclear to me (though without it
# next test may fail complaining of missing tables
self.commit()
+
+ def test_set_state(self):
+ user = self.session.user
+ self.set_debug(True)
+ self.mh.set_state(user.eid, 'deactivated')
+ user.clear_related_cache('in_state', 'subject')
+ try:
+ self.assertEquals(user.state, 'deactivated')
+ finally:
+ self.set_debug(False)
if __name__ == '__main__':
unittest_main()
--- a/server/test/unittest_rqlannotation.py Tue Mar 03 14:54:31 2009 +0100
+++ b/server/test/unittest_rqlannotation.py Tue Mar 03 15:06:03 2009 +0100
@@ -286,6 +286,12 @@
'(EXISTS(S owned_by 1)) OR (EXISTS(S documented_by N, N title "published"))')
self.assertEquals(rqlst.defined_vars['S']._q_invariant, True)
+ def test_nonregr_ambiguity(self):
+ rqlst = self._prepare('Note N WHERE N attachment F')
+ # N may be an image as well, not invariant
+ self.assertEquals(rqlst.defined_vars['N']._q_invariant, False)
+ self.assertEquals(rqlst.defined_vars['F']._q_invariant, True)
+
if __name__ == '__main__':
from logilab.common.testlib import unittest_main
unittest_main()
--- a/test/unittest_schema.py Tue Mar 03 14:54:31 2009 +0100
+++ b/test/unittest_schema.py Tue Mar 03 15:06:03 2009 +0100
@@ -227,6 +227,7 @@
def setUp(self):
self.loader = CubicWebSchemaLoader()
self.loader.defined = {}
+ self.loader.loaded_files = []
self.loader._instantiate_handlers()
def _test(self, schemafile, msg):
--- a/web/data/cubicweb.ajax.js Tue Mar 03 14:54:31 2009 +0100
+++ b/web/data/cubicweb.ajax.js Tue Mar 03 15:06:03 2009 +0100
@@ -24,6 +24,9 @@
if (typeof buildWidgets != 'undefined') {
buildWidgets(node);
}
+ if (typeof roundedCornersOnLoad != 'undefined') {
+ roundedCornersOnLoad();
+ }
}
// cubicweb loadxhtml plugin to make jquery handle xhtml response
--- a/web/data/cubicweb.css Tue Mar 03 14:54:31 2009 +0100
+++ b/web/data/cubicweb.css Tue Mar 03 15:06:03 2009 +0100
@@ -586,9 +586,13 @@
margin-bottom: 0px;
}
+div.primaryRight{
+ float:right;
+
+ }
+
div.sideRelated {
margin-right: 1em;
- float: right;
padding: 12px 0px 12px 12px;
min-width: 21em;
max-width: 50em;
--- a/web/data/cubicweb.edition.js Tue Mar 03 14:54:31 2009 +0100
+++ b/web/data/cubicweb.edition.js Tue Mar 03 15:06:03 2009 +0100
@@ -264,7 +264,8 @@
var d = async_rawremote_exec('inline_creation_form', peid, ptype, ttype, rtype, role);
d.addCallback(function (response) {
var linknode = getNode('add' + rtype + ':' + peid + 'link');
- var form = jQuery(getDomFromResponse(response));
+ var dom = getDomFromResponse(response);
+ var form = jQuery(dom);
form.css('display', 'none');
form.insertBefore(linknode.parentNode).slideDown('fast');
// setStyle(form, {display: 'none'});
@@ -273,6 +274,7 @@
// slideDown(form, {'duration':0.6});
reorderTabindex();
form.trigger('inlinedform-added');
+ postAjaxLoad(dom);
// MochiKit.Signal.signal(CubicWeb, 'inlinedform-added', form);
});
d.addErrback(function (xxx) {
@@ -402,9 +404,8 @@
/* disable form buttons while the validation is being done */
function freezeFormButtons(formid) {
- var formbuttons = jQuery(formid + ' input.validateButton');
jQuery('#progress').show();
- jQuery(formid + ' input.validateButton').attr('disabled', 'disabled');
+ jQuery('#' + formid + ' input.validateButton').attr('disabled', 'disabled');
return true;
}
--- a/web/data/cubicweb.formfilter.js Tue Mar 03 14:54:31 2009 +0100
+++ b/web/data/cubicweb.formfilter.js Tue Mar 03 15:06:03 2009 +0100
@@ -105,14 +105,18 @@
var SELECTED_IMG = baseuri()+"data/black-check.png";
var UNSELECTED_IMG = baseuri()+"data/no-check-no-border.png";
-function initFacetBoxEvents(root){
+function initFacetBoxEvents(root) {
+ // facetargs : (divid, vid, paginate, extraargs)
root = root || document;
jQuery(root).find('form').each(function () {
var form = jQuery(this);
- var facetargs = evalJSON(form.attr('cubicweb:facetargs'));
- if (facetargs !== undefined && facetargs.length) {
+ // NOTE: don't evaluate facetargs here but in callbacks since its value
+ // may changes and we must send its value when the callback is
+ // called, not when the page is initialized
+ var facetargs = form.attr('cubicweb:facetargs');
+ if (facetargs !== undefined) {
form.submit(function() {
- buildRQL.apply(null, facetargs); //(divid, vid, paginate, extraargs);
+ buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
return false;
});
form.find('div.facet').each(function() {
@@ -144,13 +148,13 @@
jQuery(this).addClass('facetValueSelected');
jQuery(this).find('img').attr('src', SELECTED_IMG);
}
- buildRQL.apply(null, facetargs); // (divid, vid, paginate, extraargs);
+ buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
facet.find('.facetBody').animate({scrollTop: 0}, '');
});
facet.find('select.facetOperator').change(function() {
var nbselected = facet.find('div.facetValueSelected').length;
if (nbselected >= 2) {
- buildRQL.apply(null, facetargs); // (divid, vid, paginate, extraargs);
+ buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
}
});
facet.find('div.facetTitle').click(function() {
@@ -169,8 +173,7 @@
root = root || document;
jQuery(root).find('form').each(function () {
var form = jQuery(this);
- var facetargs = form.attr('cubicweb:facetargs');
- if (facetargs) {
+ if (form.attr('cubicweb:facetargs')) {
form.find('div.facet').each(function() {
var facet = jQuery(this);
var lastSelected = null;
--- a/web/data/cubicweb.widgets.js Tue Mar 03 14:54:31 2009 +0100
+++ b/web/data/cubicweb.widgets.js Tue Mar 03 15:06:03 2009 +0100
@@ -181,6 +181,14 @@
}
}
+Widgets.TreeView = defclass("TreeView", null, {
+ __init__: function(wdgnode) {
+ jQuery(wdgnode).treeview({toggle: toggleTree,
+ prerendered: true
+ });
+ }
+});
+
/* widget based on SIMILE's timeline widget
* http://code.google.com/p/simile-widgets/
--- a/web/facet.py Tue Mar 03 14:54:31 2009 +0100
+++ b/web/facet.py Tue Mar 03 15:06:03 2009 +0100
@@ -507,10 +507,7 @@
def _render(self):
title = html_escape(self.facet.title)
facetid = html_escape(self.facet.id)
- if len(self.items) > 6:
- self.w(u'<div id="%s" class="facet overflowed">\n' % facetid)
- else:
- self.w(u'<div id="%s" class="facet">\n' % facetid)
+ self.w(u'<div id="%s" class="facet">\n' % facetid)
self.w(u'<div class="facetTitle" cubicweb:facetName="%s">%s</div>\n' %
(html_escape(facetid), title))
if self.facet.support_and():
@@ -523,6 +520,8 @@
cssclass = ''
if not self.facet.start_unfolded:
cssclass += ' hidden'
+ if len(self.items) > 6:
+ cssclass +=' overflowed'
self.w(u'<div class="facetBody%s">\n' % cssclass)
for item in self.items:
item.render(self.w)
--- a/web/test/unittest_views_baseforms.py Tue Mar 03 14:54:31 2009 +0100
+++ b/web/test/unittest_views_baseforms.py Tue Mar 03 15:06:03 2009 +0100
@@ -18,7 +18,7 @@
return DateTime(0000, 1, 1)
widgets.today = widgets.now = _today
-def teardown_module(options):
+def teardown_module(options, results):
widgets.today = orig_today
widgets.now = orig_now
--- a/web/views/baseforms.py Tue Mar 03 14:54:31 2009 +0100
+++ b/web/views/baseforms.py Tue Mar 03 15:06:03 2009 +0100
@@ -40,6 +40,7 @@
def call(self):
"""ask for confirmation before real deletion"""
_ = self.req._
+ self.req.add_css('cubicweb.form.css')
self.req.add_js('cubicweb.edition.js')
self.w(u'<script type="text/javascript">updateMessage(\'%s\');</script>\n' % _('this action is not reversible!'))
# XXX above message should have style of a warning
@@ -101,6 +102,7 @@
transition = self.req.eid_rset(self.req.form['treid']).get_entity(0, 0)
dest = transition.destination()
self.req.add_js('cubicweb.edition.js')
+ self.req.add_css('cubicweb.form.css')
_ = self.req._
self.w(self.error_message())
self.w(u'<h4>%s %s</h4>\n' % (_(transition.name), entity.view('oneline')))
@@ -519,7 +521,6 @@
def on_submit(self, entity):
return u'return freezeFormButtons(\'%s\')' % (self.domid)
-
def submited_message(self):
return self.req._('element edited')
--- a/web/views/baseviews.py Tue Mar 03 14:54:31 2009 +0100
+++ b/web/views/baseviews.py Tue Mar 03 15:06:03 2009 +0100
@@ -11,6 +11,8 @@
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
+#from __future__ import with_statement
+
__docformat__ = "restructuredtext en"
from warnings import warn
@@ -56,6 +58,21 @@
entities)
"""
id = 'final'
+ # record generated i18n catalog messages
+ _('%d years')
+ _('%d months')
+ _('%d weeks')
+ _('%d days')
+ _('%d hours')
+ _('%d minutes')
+ _('%d seconds')
+ _('%d years')
+ _('%d months')
+ _('%d weeks')
+ _('%d days')
+ _('%d hours')
+ _('%d minutes')
+ _('%d seconds')
def cell_call(self, row, col, props=None, displaytime=False, format='text/html'):
etype = self.rset.description[row][col]
@@ -67,23 +84,26 @@
self.w(entity.printable_value(rtype, value, format=format))
return
if etype in ('Time', 'Interval'):
- _ = self.req._
# value is DateTimeDelta but we have no idea about what is the
# reference date here, so we can only approximate years and months
+ if format == 'text/html':
+ space = ' '
+ else:
+ space = ' '
if value.days > 730: # 2 years
- self.w(_('%d years') % (value.days // 365))
+ self.w(self.req.__('%%d%syears' % space) % (value.days // 365))
elif value.days > 60: # 2 months
- self.w(_('%d months') % (value.days // 30))
+ self.w(self.req.__('%%d%smonths' % space) % (value.days // 30))
elif value.days > 14: # 2 weeks
- self.w(_('%d weeks') % (value.days // 7))
+ self.w(self.req.__('%%d%sweeks' % space) % (value.days // 7))
elif value.days > 2:
- self.w(_('%s days') % int(value.days))
+ self.w(self.req.__('%%d%sdays' % space) % int(value.days))
elif value.hours > 2:
- self.w(_('%s hours') % int(value.hours))
+ self.w(self.req.__('%%d%shours' % space) % int(value.hours))
elif value.minutes >= 2:
- self.w(_('%s minutes') % int(value.minutes))
+ self.w(self.req.__('%%d%sminutes' % space) % int(value.minutes))
else:
- self.w(_('%s seconds') % int(value.seconds))
+ self.w(self.req.__('%%d%sseconds' % space) % int(value.seconds))
return
self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime))
@@ -138,22 +158,19 @@
self.render_entity_metadata(entity)
# entity's attributes and relations, excluding meta data
# if the entity isn't meta itself
- self.w(u'<table border="0" width="100%">')
- self.w(u'<tr>')
- self.w(u'<td valign="top">')
+ self.w(u'<div>')
self.w(u'<div class="mainInfo">')
self.render_entity_attributes(entity, siderelations)
self.w(u'</div>')
self.content_navigation_components('navcontenttop')
if self.main_related_section:
self.render_entity_relations(entity, siderelations)
- self.w(u'</td>')
+ self.w(u'</div>')
# side boxes
- self.w(u'<td valign="top">')
+ self.w(u'<div class="primaryRight">')
self.render_side_related(entity, siderelations)
- self.w(u'</td>')
- self.w(u'</tr>')
- self.w(u'</table>')
+ self.w(u'</div>')
+ self.w(u'<div class="clear"></div>')
self.content_navigation_components('navcontentbottom')
def content_navigation_components(self, context):
@@ -243,8 +260,10 @@
non-meta in a first step, meta in a second step
"""
if hasattr(self, 'get_side_boxes_defs'):
- for label, rset in self.get_side_boxes_defs(entity):
- if rset:
+ sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity)
+ if rset]
+ if sideboxes:
+ for label, rset in sideboxes:
self.w(u'<div class="sideRelated">')
self.wview('sidebox', rset, title=label)
self.w(u'</div>')
@@ -255,15 +274,17 @@
# continue
self._render_related_entities(entity, *relatedinfos)
self.w(u'</div>')
- for box in self.vreg.possible_vobjects('boxes', self.req, self.rset,
- row=self.row, view=self,
- context='incontext'):
- try:
- box.dispatch(w=self.w, row=self.row)
- except NotImplementedError:
- # much probably a context insensitive box, which only implements
- # .call() and not cell_call()
- box.dispatch(w=self.w)
+ boxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ row=self.row, view=self,
+ context='incontext'))
+ if boxes:
+ for box in boxes:
+ try:
+ box.dispatch(w=self.w, row=self.row)
+ except NotImplementedError:
+ # much probably a context insensitive box, which only implements
+ # .call() and not cell_call()
+ box.dispatch(w=self.w)
def is_side_related(self, rschema, eschema):
return rschema.meta and \
@@ -989,7 +1010,8 @@
else:
role = 'object'
rset = self.rset.get_entity(row, col).related(self.rtype, role)
- self.w(u'<h1>%s</h1>' % self.req._(self.title).capitalize())
+ if self.title:
+ self.w(u'<h1>%s</h1>' % self.req._(self.title).capitalize())
self.w(u'<div class="mainInfo">')
self.wview(self.vid, rset, 'noresult')
self.w(u'</div>')
--- a/web/views/euser.py Tue Mar 03 14:54:31 2009 +0100
+++ b/web/views/euser.py Tue Mar 03 15:06:03 2009 +0100
@@ -40,7 +40,7 @@
content_type = 'text/xml'
def call(self):
- self.w('''<?xml version="1.0" encoding="%s"?>
+ self.w(u'''<?xml version="1.0" encoding="%s"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self.req.encoding)
@@ -67,13 +67,7 @@
if emailaddr:
self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
self.w(u'</foaf:Person>\n')
-
-class FoafUsableView(FoafView):
- id = 'foaf_usable'
-
- def call(self):
- self.cell_call(0, 0)
-
+
class EditGroups(EntityForm):
"""displays a simple euser / egroups editable table"""
--- a/web/views/idownloadable.py Tue Mar 03 14:54:31 2009 +0100
+++ b/web/views/idownloadable.py Tue Mar 03 15:06:03 2009 +0100
@@ -35,9 +35,19 @@
class DownloadBox(EntityBoxTemplate):
id = 'download_box'
- __selectors__ = (one_line_rset, implement_interface, match_context_prop)
+ # XXX primary_view selector ?
+ __selectors__ = (one_line_rset, implement_interface, match_context_prop, score_entity_selector)
accepts_interfaces = (IDownloadable,)
order = 10
+
+ @classmethod
+ def score_entity(cls, entity):
+ mt = entity.download_content_type()
+ # no download box for images
+ if mt and mt.startswith('image/'):
+ return 0
+ return 1
+
def cell_call(self, row, col, title=None, label=None, **kwargs):
entity = self.entity(row, col)
download_box(self.w, entity, title, label)
@@ -90,8 +100,9 @@
class IDownloadablePrimaryView(baseviews.PrimaryView):
__selectors__ = (implement_interface,)
- #skip_attrs = ('eid', 'data',) # XXX
accepts_interfaces = (IDownloadable,)
+ # XXX File/Image attributes but this is not specified in the IDownloadable interface
+ skip_attrs = baseviews.PrimaryView.skip_attrs + ('data', 'name')
def render_entity_title(self, entity):
self.w(u'<h1>%s %s</h1>'
@@ -100,12 +111,12 @@
def render_entity_attributes(self, entity, siderelations):
super(IDownloadablePrimaryView, self).render_entity_attributes(entity, siderelations)
- self.wview('downloadlink', entity.rset, title=self.req._('download'), row=entity.row)
self.w(u'<div class="content">')
contenttype = entity.download_content_type()
if contenttype.startswith('image/'):
self.wview('image', entity.rset, row=entity.row)
else:
+ self.wview('downloadlink', entity.rset, title=self.req._('download'), row=entity.row)
try:
if ENGINE.has_input(contenttype):
self.w(entity.printable_value('data'))
--- a/web/views/tabs.py Tue Mar 03 14:54:31 2009 +0100
+++ b/web/views/tabs.py Tue Mar 03 15:06:03 2009 +0100
@@ -33,22 +33,15 @@
});""" % {'event': 'load_%s' % vid, 'vid': vid,
'reloadable' : str(reloadable).lower()})
- def lazyview(self, vid, rql=None, eid=None, rset=None, static=False,
- reloadable=False, show_spinbox=True, w=None):
+ def lazyview(self, vid, eid=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
"""
- assert rql or eid or rset or static, \
- 'lazyview wants at least : rql, or an eid, or an rset -- or call it with static=True'
w = w or self.w
self.req.add_js('cubicweb.lazy.js')
urlparams = {'vid' : vid, 'mode' : 'html'}
- if rql:
- urlparams['rql'] = rql
- elif eid:
+ if eid:
urlparams['rql'] = rql_for_eid(eid)
- elif rset:
- urlparams['rql'] = rset.printable_rql()
w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
vid, html_escape(self.build_url('json', **urlparams))))
if show_spinbox:
@@ -72,12 +65,12 @@
return str('%s_active_tab' % self.config.appid)
def active_tab(self, tabs, default):
- cookies = self.req.get_cookie()
+ cookie = self.req.get_cookie()
cookiename = self.cookie_name
- activetab = cookies.get(cookiename)
+ activetab = cookie.get(cookiename)
if activetab is None:
- cookies[cookiename] = default
- self.req.set_cookie(cookies, cookiename)
+ cookie[cookiename] = default
+ self.req.set_cookie(cookie, cookiename)
tab = default
else:
tab = activetab.value
@@ -108,7 +101,7 @@
active_tab = self.active_tab(tabs, default)
# build the html structure
w = self.w
- w(u'<div id="entity-tabs-%s">' % entity.eid)
+ w(u'<div id="entity-tabs">')
w(u'<ul>')
for tab in tabs:
w(u'<li>')
@@ -122,16 +115,15 @@
w(u'</div>')
for tab in tabs:
w(u'<div id="as-%s">' % tab)
- self.lazyview(tab, eid=entity.eid)
+ self.lazyview(tab, entity.eid)
w(u'</div>')
# call the set_tab() JS function *after* each tab is generated
# because the callback binding needs to be done before
self.req.html_headers.add_onload(u"""
- jQuery('#entity-tabs-%(eeid)s > ul').tabs( { selected: %(tabindex)s });
+ jQuery('#entity-tabs > ul').tabs( { selected: %(tabindex)s });
set_tab('%(vid)s', '%(cookiename)s');
""" % {'tabindex' : tabs.index(active_tab),
'vid' : active_tab,
- 'eeid' : entity.eid,
'cookiename' : self.cookie_name})
@@ -151,10 +143,11 @@
vid = 'gallery'
__selectors__ = EntityRelationView.__selectors__ + (one_line_rset,)
+
This is the view we want to have in a tab, only if there is something to show.
Then, just define as below, and declare this being the tab content :
- class ProjectScreenshotTab(EntityRelatedTab, ProjectScreenshotsView):
+ class ProjectScreenshotTab(DataDependantTab, ProjectScreenshotsView):
id = 'screenshots_tab'
"""
__selectors__ = EntityView.__selectors__ + (has_related_entities,)