backport stable branch, take care a lot of conflicts occured, this may be the revision you're looking for...
--- a/.hgtags Mon Mar 02 20:44:14 2009 +0100
+++ b/.hgtags Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/__pkginfo__.py Mon Mar 02 21:03:54 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/mixins.py Mon Mar 02 20:44:14 2009 +0100
+++ b/common/mixins.py Mon Mar 02 21:03:54 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)
@@ -368,22 +368,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']
@@ -402,6 +398,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 Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/common/uilib.py Mon Mar 02 21:03:54 2009 +0100
@@ -179,7 +179,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/debian/changelog Mon Mar 02 20:44:14 2009 +0100
+++ b/debian/changelog Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/debian/control Mon Mar 02 21:03:54 2009 +0100
@@ -59,7 +59,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.
@@ -74,7 +74,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 Mon Mar 02 20:44:14 2009 +0100
+++ b/devtools/__init__.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/devtools/apptest.py Mon Mar 02 21:03:54 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/entity.py Mon Mar 02 20:44:14 2009 +0100
+++ b/entity.py Mon Mar 02 21:03:54 2009 +0100
@@ -45,6 +45,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/goa/dbmyams.py Mon Mar 02 20:44:14 2009 +0100
+++ b/goa/dbmyams.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/i18n/en.po Mon Mar 02 21:03:54 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"
@@ -2203,15 +2228,12 @@
msgid "ordernum"
msgstr "order"
-msgid "owl (tbox+abox)"
+msgid "owl"
msgstr ""
msgid "owlabox"
msgstr ""
-msgid "owlaboxlight"
-msgstr ""
-
msgid "owned_by"
msgstr "owned by"
@@ -2583,9 +2605,6 @@
msgid "task progression"
msgstr ""
-msgid "tbox"
-msgstr ""
-
msgid "text"
msgstr ""
--- a/i18n/es.po Mon Mar 02 20:44:14 2009 +0100
+++ b/i18n/es.po Mon Mar 02 21:03:54 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"
@@ -2295,15 +2320,12 @@
msgid "ordernum"
msgstr "ordre"
-msgid "owl (tbox+abox)"
+msgid "owl"
msgstr ""
msgid "owlabox"
msgstr ""
-msgid "owlaboxlight"
-msgstr ""
-
msgid "owned_by"
msgstr "appartient ‡"
@@ -2688,9 +2710,6 @@
msgid "task progression"
msgstr "avancement de la t‚che"
-msgid "tbox"
-msgstr ""
-
msgid "text"
msgstr "text"
--- a/i18n/fr.po Mon Mar 02 20:44:14 2009 +0100
+++ b/i18n/fr.po Mon Mar 02 21:03:54 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"
@@ -2299,15 +2324,12 @@
msgid "ordernum"
msgstr "ordre"
-msgid "owl (tbox+abox)"
+msgid "owl"
msgstr ""
msgid "owlabox"
msgstr ""
-msgid "owlaboxlight"
-msgstr ""
-
msgid "owned_by"
msgstr "appartient à"
@@ -2692,9 +2714,6 @@
msgid "task progression"
msgstr "avancement de la tâche"
-msgid "tbox"
-msgstr ""
-
msgid "text"
msgstr "text"
--- a/server/migractions.py Mon Mar 02 20:44:14 2009 +0100
+++ b/server/migractions.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/server/rqlannotation.py Mon Mar 02 21:03:54 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/sources/ldapuser.py Mon Mar 02 20:44:14 2009 +0100
+++ b/server/sources/ldapuser.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/server/sources/native.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/server/test/data/schema/relations.rel Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/server/test/unittest_ldapuser.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/server/test/unittest_migractions.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/server/test/unittest_rqlannotation.py Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/test/unittest_schema.py Mon Mar 02 21:03:54 2009 +0100
@@ -226,6 +226,7 @@
def setUp(self):
self.loader = CubicWebSchemaLoader()
self.loader.defined = {}
+ self.loader.loaded_files = []
self.loader._instantiate_handlers()
def _test(self, schemafile, msg):
--- a/view.py Mon Mar 02 20:44:14 2009 +0100
+++ b/view.py Mon Mar 02 21:03:54 2009 +0100
@@ -304,7 +304,22 @@
def create_url(self, etype, **kwargs):
""" return the url of the entity creation form for a given entity type"""
return self.req.build_url('add/%s'%etype, **kwargs)
+<<<<<<< /home/syt/src/fcubicweb/cubicweb/view.py
+=======
+
+
+# concrete views base classes #################################################
+
+class EntityView(View):
+ """base class for views applying on an entity (i.e. uniform result set)
+ """
+ __registerer__ = accepts_registerer
+ __selectors__ = (accept,)
+ accepts = ('Any',)
+ category = 'entityview'
+
+>>>>>>> /tmp/view.py~other.mliJlS
def field(self, label, value, row=True, show_label=True, w=None, tr=True):
""" read-only field """
if w is None:
--- a/web/data/cubicweb.ajax.js Mon Mar 02 20:44:14 2009 +0100
+++ b/web/data/cubicweb.ajax.js Mon Mar 02 21:03:54 2009 +0100
@@ -35,6 +35,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.edition.js Mon Mar 02 20:44:14 2009 +0100
+++ b/web/data/cubicweb.edition.js Mon Mar 02 21:03:54 2009 +0100
@@ -402,9 +402,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 Mon Mar 02 20:44:14 2009 +0100
+++ b/web/data/cubicweb.formfilter.js Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/web/data/cubicweb.widgets.js Mon Mar 02 21:03:54 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 Mon Mar 02 20:44:14 2009 +0100
+++ b/web/facet.py Mon Mar 02 21:03:54 2009 +0100
@@ -506,10 +506,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():
@@ -522,6 +519,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 Mon Mar 02 20:44:14 2009 +0100
+++ b/web/test/unittest_views_baseforms.py Mon Mar 02 21:03:54 2009 +0100
@@ -19,7 +19,7 @@
return DateTime(0000, 1, 1)
widgets.today = widgets.now = _today
-def teardown_module(options, result):
+def teardown_module(options, results):
widgets.today = orig_today
widgets.now = orig_now
--- a/web/views/baseforms.py Mon Mar 02 20:44:14 2009 +0100
+++ b/web/views/baseforms.py Mon Mar 02 21:03:54 2009 +0100
@@ -46,6 +46,7 @@
"""ask for confirmation before real deletion"""
req, w = self.req, self.w
_ = req._
+ req.add_css('cubicweb.form.css')
req.add_js('cubicweb.edition.js')
w(u'<script type="text/javascript">updateMessage(\'%s\');</script>\n'
% _('this action is not reversible!'))
@@ -98,6 +99,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._
form = ChangeStateForm(self.req, entity=entity,
redirect_path=self.redirectpath(entity))
@@ -479,7 +481,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 Mon Mar 02 20:44:14 2009 +0100
+++ b/web/views/baseviews.py Mon Mar 02 21:03:54 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
@@ -50,6 +52,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]
@@ -61,23 +78,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))
@@ -223,27 +243,43 @@
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:
+ self.w(u'<table width="100%">')
+ for label, rset in sideboxes:
+ self.w(u'<tr><td>')
self.w(u'<div class="sideRelated">')
self.wview('sidebox', rset, title=label)
self.w(u'</div>')
+ self.w(u'</td></tr>')
+ self.w(u'</table>')
elif siderelations:
+ self.w(u'<table width="100%">')
+ self.w(u'<tr><td>')
self.w(u'<div class="sideRelated">')
for relatedinfos in siderelations:
# if not relatedinfos[0].meta:
# 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)
+ self.w(u'</td></tr>')
+ self.w(u'</table>')
+ boxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ row=self.row, view=self,
+ context='incontext'))
+ if boxes:
+ self.w(u'<table width="100%">')
+ for box in boxes:
+ self.w(u'<tr><td>')
+ 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)
+ self.w(u'</td></tr>')
+ self.w(u'</table>')
def is_side_related(self, rschema, eschema):
return rschema.meta and \
--- a/web/views/euser.py Mon Mar 02 20:44:14 2009 +0100
+++ b/web/views/euser.py Mon Mar 02 21:03:54 2009 +0100
@@ -87,14 +87,6 @@
self.w(u'</foaf:Person>\n')
-class FoafUsableView(FoafView):
- id = 'foaf_usable'
- # XXX killme
- title = None
- def call(self):
- self.cell_call(0, 0)
-
-
class EditGroups(FormMixIn, EntityView):
"""displays a simple euser / egroups editable table"""
--- a/web/views/idownloadable.py Mon Mar 02 20:44:14 2009 +0100
+++ b/web/views/idownloadable.py Mon Mar 02 21:03:54 2009 +0100
@@ -17,6 +17,12 @@
_ = unicode
+def is_image(entity):
+ mt = entity.download_content_type()
+ if not (mt and mt.startswith('image/')):
+ return 0
+ return 1
+
def download_box(w, entity, title=None, label=None):
req = entity.req
w(u'<div class="sideRelated">')
@@ -32,11 +38,14 @@
w(u'</div>')
w(u'</div>\n</div>\n')
-
+
class DownloadBox(EntityBoxTemplate):
id = 'download_box'
- __select__ = (one_line_rset() & implements(IDownloadable) & match_context_prop())
+ # no download box for images
+ # XXX primary_view selector ?
+ __select__ = (one_line_rset() & implements(IDownloadable) & match_context_prop() & ~ score_entity(is_image)
order = 10
+
def cell_call(self, row, col, title=None, label=None, **kwargs):
entity = self.entity(row, col)
download_box(self.w, entity, title, label)
@@ -87,7 +96,8 @@
class IDownloadablePrimaryView(baseviews.PrimaryView):
__select__ = implements(IDownloadable)
- #skip_attrs = ('eid', 'data',) # XXX
+ # 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>'
@@ -96,12 +106,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'))
@@ -130,12 +140,6 @@
(url, name, durl, self.req._('download')))
-def is_image(entity):
- mt = entity.download_content_type()
- if not (mt and mt.startswith('image/')):
- return 0
- return 1
-
class ImageView(baseviews.EntityView):
id = 'image'
__select__ = implements(IDownloadable) & score_entity(is_image)
--- a/web/views/tabs.py Mon Mar 02 20:44:14 2009 +0100
+++ b/web/views/tabs.py Mon Mar 02 21:03:54 2009 +0100
@@ -32,22 +32,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'] = uilib.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:
@@ -71,12 +64,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
@@ -102,7 +95,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>')
@@ -116,16 +109,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})
--- a/web/views/treeview.py Mon Mar 02 20:44:14 2009 +0100
+++ b/web/views/treeview.py Mon Mar 02 21:03:54 2009 +0100
@@ -18,26 +18,29 @@
return str('treestate-%s' % treeid)
+from cubicweb.web.views.baseviews import OneLineView
+
class TreeView(EntityView):
id = 'treeview'
itemvid = 'treeitemview'
css_classes = 'treeview widget'
title = _('tree view')
- def call(self, subvid=None, treeid=None, initial_load=True):
+ def call(self, subvid=None):
if subvid is None and 'subvid' in self.req.form:
subvid = self.req.form.pop('subvid') # consume it
if subvid is None:
subvid = 'oneline'
- if treeid is None and 'treeid' in self.req.form:
- treeid = self.req.form.pop('treeid')
- assert treeid is not None
- if initial_load:
- self.req.add_css('jquery.treeview.css')
- self.req.add_js(('cubicweb.ajax.js', 'jquery.treeview.js'))
- self.req.html_headers.add_onload(u"""
-jQuery("#tree-%s").treeview({toggle: toggleTree, prerendered: true});""" % treeid)
- self.w(u'<ul id="tree-%s" class="%s">' % (treeid, self.css_classes))
+ self.req.add_css('jquery.treeview.css')
+ self.req.add_js(('cubicweb.ajax.js', 'jquery.treeview.js', 'cubicweb.widgets.js'))
+ # XXX noautoload is a quick hack to avoid treeview to be rebuilt
+ # after a json query and avoid double toggling bugs.
+ # Need to find a way to do that cleanly.
+ if 'noautoload' in self.req.form:
+ self.w(u'<ul class="%s" cubicweb:wdgtype="TreeView">' % self.css_classes)
+ else:
+ self.w(u'<ul class="%s" cubicweb:loadtype="auto" cubicweb:wdgtype="TreeView">'
+ % self.css_classes)
for rowidx in xrange(len(self.rset)):
self.wview(self.itemvid, self.rset, row=rowidx, col=0,
vid=subvid, parentvid=self.id, treeid=treeid)
@@ -54,6 +57,8 @@
def call(self, subvid=None, treeid=None, initial_load=True):
super(FileTreeView, self).call(treeid=treeid, subvid='filetree-oneline', initial_load=initial_load)
+
+
class FileItemInnerView(EntityView):
"""inner view used by the TreeItemView instead of oneline view
@@ -65,18 +70,17 @@
def cell_call(self, row, col):
entity = self.entity(row, col)
if ITree.is_implemented_by(entity.__class__) and not entity.is_leaf():
- self.w(u'<div class="folder">%s</div>\n' % entity.view('oneline'))
+ self.w(u'<div class="folder">%s</div>' % entity.view('oneline'))
else:
# XXX define specific CSS classes according to mime types
- self.w(u'<div class="file">%s</div>\n' % entity.view('oneline'))
+ self.w(u'<div class="file">%s</div>' % entity.view('oneline'))
class DefaultTreeViewItemView(EntityView):
"""default treeitem view for entities which don't implement ITree"""
id = 'treeitemview'
-
- def cell_call(self, row, col, vid='oneline', parentvid='treeview', treeid=None):
- assert treeid is not None
+
+ def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
entity = self.entity(row, col)
itemview = self.view(vid, self.rset, row=row, col=col)
if row == len(self.rset) - 1:
@@ -92,81 +96,32 @@
"""
id = 'treeitemview'
__select_ = implements(ITree)
-
- def open_state(self, eeid, treeid):
- cookies = self.req.get_cookie()
- treestate = cookies.get(treecookiename(treeid))
- if treestate:
- return str(eeid) in treestate.value.split(';')
- return False
-
- def cell_call(self, row, col, treeid, vid='oneline', parentvid='treeview'):
- w = self.w
+
+ def cell_call(self, row, col, vid='oneline', parentvid='treeview'):
entity = self.entity(row, col)
- liclasses = []
+ cssclasses = []
is_leaf = False
- is_last = row == len(self.rset) - 1
- is_open = self.open_state(entity.eid, treeid)
+ if row == len(self.rset) - 1:
+ is_leaf = True
if not hasattr(entity, 'is_leaf') or entity.is_leaf():
- if is_last:
- liclasses.append('last')
- w(u'<li class="%s">' % u' '.join(liclasses))
+ if is_leaf : cssclasses.append('last')
+ self.w(u'<li class="%s">' % u' '.join(cssclasses))
else:
rql = entity.children_rql() % {'x': entity.eid}
url = html_escape(self.build_url('json', rql=rql, vid=parentvid,
pageid=self.req.pageid,
- treeid=treeid,
- subvid=vid))
- divclasses = ['hitarea']
- if is_open:
- liclasses.append('collapsable')
- divclasses.append('collapsable-hitarea')
- else:
- liclasses.append('expandable')
- divclasses.append('closed-hitarea expandable-hitarea')
- if is_last:
- if is_open:
- liclasses.append('lastCollapsable')
- divclasses.append('lastCollapsable-hitarea')
- else:
- liclasses.append('lastExpandable')
- divclasses.append('lastExpandable-hitarea')
- if is_open:
- w(u'<li class="%s">' % u' '.join(liclasses))
- else:
- w(u'<li cubicweb:loadurl="%s" class="%s">' % (url, u' '.join(liclasses)))
- if is_leaf:
- divtail = ''
- else:
- divtail = ''' onclick="async_remote_exec('node_clicked', '%s', '%s')"''' % \
- (treeid, entity.eid)
- w(u'<div class="%s"%s></div>' % (u' '.join(divclasses), divtail))
-
+ subvid=vid,
+ noautoload=True))
+ cssclasses.append('expandable')
+ divclasses = ['hitarea expandable-hitarea']
+ if is_leaf :
+ cssclasses.append('lastExpandable')
+ divclasses.append('lastExpandable-hitarea')
+ self.w(u'<li cubicweb:loadurl="%s" class="%s">' % (url, u' '.join(cssclasses)))
+ self.w(u'<div class="%s"> </div>' % u' '.join(divclasses))
# add empty <ul> because jquery's treeview plugin checks for
# sublists presence
- if not is_open:
- w(u'<ul class="placeholder"><li>place holder</li></ul>')
- # the local node info
+ self.w(u'<ul class="placeholder"><li>place holder</li></ul>')
self.wview(vid, self.rset, row=row, col=col)
- if is_open: # recurse if needed
- self.wview(parentvid, self.req.execute(rql), treeid=treeid, initial_load=False)
- w(u'</li>')
-
+ self.w(u'</li>')
-@monkeypatch(JSonController)
-def js_node_clicked(self, treeid, nodeeid):
- """add/remove eid in treestate cookie"""
- cookies = self.req.get_cookie()
- statename = treecookiename(treeid)
- treestate = cookies.get(statename)
- if treestate is None:
- cookies[statename] = nodeeid
- self.req.set_cookie(cookies, statename)
- else:
- marked = set(filter(None, treestate.value.split(';')))
- if nodeeid in marked:
- marked.remove(nodeeid)
- else:
- marked.add(nodeeid)
- cookies[statename] = ';'.join(marked)
- self.req.set_cookie(cookies, statename)