# HG changeset patch # User Sylvain Thénault # Date 1331890155 -3600 # Node ID 8be58694f4166128575ad37a0afb36f7c201af0b # Parent 4da49700b06a4dbce6cabfdbcb20a87f2e983953# Parent 2279e02e62be26872fcb04ce62d93a3de6531738 backport stable diff -r 4da49700b06a -r 8be58694f416 .hgtags --- a/.hgtags Thu Mar 15 14:26:12 2012 +0100 +++ b/.hgtags Fri Mar 16 10:29:15 2012 +0100 @@ -245,3 +245,8 @@ 4d0f5d18e8a07ab218efe90d758af723ea4a1b2b cubicweb-debian-version-3.14.3-1 508645a542870cb0def9c43056e5084ff8def5ca cubicweb-version-3.14.4 bc40991b7f13642d457f5ca80ac1486c29e25a6e cubicweb-debian-version-3.14.4-1 +4c8cb2e9d0ee13af1d584e2920d1ae76f47380e9 cubicweb-debian-version-3.14.4-2 +f559ab9602e7eeb4996ac0f83d544a6e0374e204 cubicweb-version-3.14.5 +55fc796ed5d5f31245ae60bd148c9e42657a1af6 cubicweb-debian-version-3.14.5-1 +db021578232b885dc5e55dfca045332ce01e7f35 cubicweb-version-3.14.6 +75364c0994907764715bd5011f6a59d934dbeb7d cubicweb-debian-version-3.14.6-1 diff -r 4da49700b06a -r 8be58694f416 __pkginfo__.py diff -r 4da49700b06a -r 8be58694f416 debian/changelog --- a/debian/changelog Thu Mar 15 14:26:12 2012 +0100 +++ b/debian/changelog Fri Mar 16 10:29:15 2012 +0100 @@ -1,3 +1,21 @@ +cubicweb (3.14.6-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Tue, 13 Mar 2012 14:21:04 +0100 + +cubicweb (3.14.5-1) unstable; urgency=low + + * New upstream release + + -- David Douard Thu, 01 Mar 2012 15:29:29 +0100 + +cubicweb (3.14.4-2) unstable; urgency=low + + * add missing build-deps to generate the documentation + + -- David Douard Wed, 29 Feb 2012 17:00:52 +0100 + cubicweb (3.14.4-1) unstable; urgency=low * New upstream release diff -r 4da49700b06a -r 8be58694f416 debian/control --- a/debian/control Thu Mar 15 14:26:12 2012 +0100 +++ b/debian/control Fri Mar 16 10:29:15 2012 +0100 @@ -7,7 +7,7 @@ Adrien Di Mascio , Aurélien Campéas , Nicolas Chauvat -Build-Depends: debhelper (>= 7), python (>= 2.5), python-central (>= 0.5), python-sphinx +Build-Depends: debhelper (>= 7), python (>= 2.5), python-central (>= 0.5), python-sphinx, python-logilab-common, python-unittest2 # for the documentation: # python-sphinx, python-logilab-common, python-unittest2, logilab-doctools, logilab-xml Standards-Version: 3.9.1 diff -r 4da49700b06a -r 8be58694f416 debian/watch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/watch Fri Mar 16 10:29:15 2012 +0100 @@ -0,0 +1,2 @@ +version=3 +http://download.logilab.org/pub/cubicweb cubicweb-(.*)\.tar\.gz diff -r 4da49700b06a -r 8be58694f416 entity.py --- a/entity.py Thu Mar 15 14:26:12 2012 +0100 +++ b/entity.py Fri Mar 16 10:29:15 2012 +0100 @@ -635,11 +635,12 @@ mainattr, needcheck = self.cw_rest_attr_info() etype = str(self.e_schema) path = etype.lower() + fallback = False if mainattr != 'eid': value = getattr(self, mainattr) if not can_use_rest_path(value): mainattr = 'eid' - path += '/eid' + path = None elif needcheck: # make sure url is not ambiguous try: @@ -650,12 +651,16 @@ nbresults = self.__unique = self._cw.execute(rql, {'value' : value})[0][0] if nbresults != 1: # ambiguity? mainattr = 'eid' - path += '/eid' + path = None if mainattr == 'eid': if use_ext_eid: value = self.cw_metainformation()['extid'] else: value = self.eid + if path is None: + # fallback url: / url is used as cw entities uri, + # prefer it to //eid/ + return unicode(value) return '%s/%s' % (path, self._cw.url_quote(value)) def cw_attr_metadata(self, attr, metadata): diff -r 4da49700b06a -r 8be58694f416 misc/migration/3.12.0_Any.py --- a/misc/migration/3.12.0_Any.py Thu Mar 15 14:26:12 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -if schema['TZDatetime'].eid is None: - add_entity_type('TZDatetime') -if schema['TZTime'].eid is None: - add_entity_type('TZTime') diff -r 4da49700b06a -r 8be58694f416 misc/migration/3.14.4_Any.py --- a/misc/migration/3.14.4_Any.py Thu Mar 15 14:26:12 2012 +0100 +++ b/misc/migration/3.14.4_Any.py Fri Mar 16 10:29:15 2012 +0100 @@ -4,6 +4,7 @@ rdefdef = schema['CWSource'].rdef('name') attrtype = y2sql.type_from_constraints(dbhelper, rdefdef.object, rdefdef.constraints).split()[0] -sql(dbhelper.sql_change_col_type('entities', 'asource', attrtype, False)) -sql(dbhelper.sql_change_col_type('entities', 'source', attrtype, False)) -sql(dbhelper.sql_change_col_type('deleted_entities', 'source', attrtype, False)) +cursor = session.cnxset['system'] +dbhelper.change_col_type(cursor, 'entities', 'asource', attrtype, False) +dbhelper.change_col_type(cursor, 'entities', 'source', attrtype, False) +dbhelper.change_col_type(cursor, 'deleted_entities', 'source', attrtype, False) diff -r 4da49700b06a -r 8be58694f416 misc/migration/bootstrapmigration_repository.py --- a/misc/migration/bootstrapmigration_repository.py Thu Mar 15 14:26:12 2012 +0100 +++ b/misc/migration/bootstrapmigration_repository.py Fri Mar 16 10:29:15 2012 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -40,6 +40,13 @@ sql('UPDATE entities SET asource=cw_name ' 'FROM cw_CWSource, cw_source_relation ' 'WHERE entities.eid=cw_source_relation.eid_from AND cw_source_relation.eid_to=cw_CWSource.cw_eid') + commit() + +if schema['TZDatetime'].eid is None: + add_entity_type('TZDatetime', auto=False) +if schema['TZTime'].eid is None: + add_entity_type('TZTime', auto=False) + if applcubicwebversion <= (3, 14, 0) and cubicwebversion >= (3, 14, 0): if 'require_permission' in schema and not 'localperms'in repo.config.cubes(): diff -r 4da49700b06a -r 8be58694f416 rqlrewrite.py --- a/rqlrewrite.py Thu Mar 15 14:26:12 2012 +0100 +++ b/rqlrewrite.py Fri Mar 16 10:29:15 2012 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -228,39 +228,44 @@ if not r in sti['rhsrelations']) else: vi['rhs_rels'] = vi['lhs_rels'] = {} - parent = None + previous = None inserted = False for rqlexpr in rqlexprs: self.current_expr = rqlexpr if varexistsmap is None: try: - new = self.insert_snippet(varmap, rqlexpr.snippet_rqlst, parent) + new = self.insert_snippet(varmap, rqlexpr.snippet_rqlst, previous) except Unsupported: continue inserted = True if new is not None and self._insert_scope is None: self.exists_snippet[rqlexpr] = new - parent = parent or new + previous = previous or new else: # called to reintroduce snippet due to ambiguity creation, # so skip snippets which are not introducing this ambiguity exists = varexistsmap[varmap] - if self.exists_snippet[rqlexpr] is exists: + if self.exists_snippet.get(rqlexpr) is exists: self.insert_snippet(varmap, rqlexpr.snippet_rqlst, exists) if varexistsmap is None and not inserted: # no rql expression found matching rql solutions. User has no access right raise Unauthorized() # XXX may also be because of bad constraints in schema definition - def insert_snippet(self, varmap, snippetrqlst, parent=None): + def insert_snippet(self, varmap, snippetrqlst, previous=None): new = snippetrqlst.where.accept(self) existing = self.existingvars self.existingvars = None try: - return self._insert_snippet(varmap, parent, new) + return self._insert_snippet(varmap, previous, new) finally: self.existingvars = existing - def _insert_snippet(self, varmap, parent, new): + def _insert_snippet(self, varmap, previous, new): + """insert `new` snippet into the syntax tree, which have been rewritten + using `varmap`. In cases where an action is protected by several rql + expresssion, `previous` will be the first rql expression which has been + inserted, and so should be ORed with the following expressions. + """ if new is not None: if self._insert_scope is None: insert_scope = None @@ -274,28 +279,28 @@ insert_scope = self._insert_scope if self._insert_scope is None and any(vi.get('stinfo', {}).get('optrelations') for vi in self.varinfos): - assert parent is None - self._insert_scope = self.snippet_subquery(varmap, new) + assert previous is None + self._insert_scope, new = self.snippet_subquery(varmap, new) self.insert_pending() #self._insert_scope = None - return + return new if not isinstance(new, (n.Exists, n.Not)): new = n.Exists(new) - if parent is None: + if previous is None: insert_scope.add_restriction(new) else: - grandpa = parent.parent - or_ = n.Or(parent, new) - grandpa.replace(parent, or_) + grandpa = previous.parent + or_ = n.Or(previous, new) + grandpa.replace(previous, or_) if not self.removing_ambiguity: try: self.compute_solutions() except Unsupported: # some solutions have been lost, can't apply this rql expr - if parent is None: + if previous is None: self.current_statement().remove_node(new, undefine=True) else: - grandpa.replace(or_, parent) + grandpa.replace(or_, previous) self._cleanup_inserted(new) raise else: @@ -419,7 +424,7 @@ # some solutions have been lost, can't apply this rql expr self.select.remove_subquery(self.select.with_[-1]) raise - return subselect + return subselect, snippetrqlst def remove_ambiguities(self, snippets, newsolutions): # the snippet has introduced some ambiguities, we have to resolve them @@ -476,11 +481,17 @@ def _cleanup_inserted(self, node): # cleanup inserted variable references + removed = set() for vref in node.iget_nodes(n.VariableRef): vref.unregister_reference() if not vref.variable.stinfo['references']: # no more references, undefine the variable del self.select.defined_vars[vref.name] + removed.add(vref.name) + for key, newvar in self.rewritten.items(): # I mean items we alter it + if newvar in removed: + del self.rewritten[key] + def _may_be_shared_with(self, sniprel, target): """if the snippet relation can be skipped to use a relation from the diff -r 4da49700b06a -r 8be58694f416 server/migractions.py --- a/server/migractions.py Thu Mar 15 14:26:12 2012 +0100 +++ b/server/migractions.py Fri Mar 16 10:29:15 2012 +0100 @@ -1039,17 +1039,15 @@ gmap = self.group_mapping() cmap = self.cstrtype_mapping() done = set() - for rdef in rschema.rdefs.itervalues(): - if not (reposchema.has_entity(rdef.subject) - and reposchema.has_entity(rdef.object)): + for subj, obj in rschema.rdefs: + if not (reposchema.has_entity(subj) + and reposchema.has_entity(obj)): continue # symmetric relations appears twice - if (rdef.subject, rdef.object) in done: + if (subj, obj) in done: continue - done.add( (rdef.subject, rdef.object) ) - self._set_rdef_eid(rdef) - ss.execschemarql(execute, rdef, - ss.rdef2rql(rdef, cmap, gmap)) + done.add( (subj, obj) ) + self.cmd_add_relation_definition(subj, rtype, obj) if rtype in META_RTYPES: # if the relation is in META_RTYPES, ensure we're adding it for # all entity types *in the persistent schema*, not only those in @@ -1099,9 +1097,8 @@ print 'warning: relation %s %s %s is already known, skip addition' % ( subjtype, rtype, objtype) return - execute = self._cw.execute rdef = self._get_rdef(rschema, subjtype, objtype) - ss.execschemarql(execute, rdef, + ss.execschemarql(self._cw.execute, rdef, ss.rdef2rql(rdef, self.cstrtype_mapping(), self.group_mapping())) if commit: @@ -1115,7 +1112,7 @@ schemaobj = getattr(rdef, attr) if getattr(schemaobj, 'eid', None) is None: schemaobj.eid = self.repo.schema[schemaobj].eid - assert schemaobj.eid is not None + assert schemaobj.eid is not None, schemaobj return rdef def cmd_drop_relation_definition(self, subjtype, rtype, objtype, commit=True): diff -r 4da49700b06a -r 8be58694f416 server/sources/storages.py --- a/server/sources/storages.py Thu Mar 15 14:26:12 2012 +0100 +++ b/server/sources/storages.py Fri Mar 16 10:29:15 2012 +0100 @@ -194,16 +194,16 @@ # Mark the new file as added during the transaction. # The file will be removed on rollback AddFileOp.get_instance(entity._cw).add_data(fpath) - if oldpath != fpath: - # register the new location for the file. + # reinstall poped value if fpath is None: entity.cw_edited.edited_attribute(attr, None) else: + # register the new location for the file. entity.cw_edited.edited_attribute(attr, Binary(fpath)) + if oldpath is not None and oldpath != fpath: # Mark the old file as useless so the file will be removed at # commit. - if oldpath is not None: - DeleteFileOp.get_instance(entity._cw).add_data(oldpath) + DeleteFileOp.get_instance(entity._cw).add_data(oldpath) return binary def entity_deleted(self, entity, attr): diff -r 4da49700b06a -r 8be58694f416 server/test/unittest_multisources.py --- a/server/test/unittest_multisources.py Thu Mar 15 14:26:12 2012 +0100 +++ b/server/test/unittest_multisources.py Fri Mar 16 10:29:15 2012 +0100 @@ -337,7 +337,7 @@ ceid = cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0] self.cnx2.commit() lc = self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0, 0) - self.assertEqual(lc.absolute_url(), 'http://extern.org/card/eid/%s' % ceid) + self.assertEqual(lc.absolute_url(), 'http://extern.org/%s' % ceid) cu.execute('DELETE Card X WHERE X eid %(x)s', {'x':ceid}) self.cnx2.commit() @@ -346,7 +346,7 @@ ceid = cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0] self.cnx3.commit() lc = self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0, 0) - self.assertEqual(lc.absolute_url(), 'http://testing.fr/cubicweb/card/eid/%s' % lc.eid) + self.assertEqual(lc.absolute_url(), 'http://testing.fr/cubicweb/%s' % lc.eid) cu.execute('DELETE Card X WHERE X eid %(x)s', {'x':ceid}) self.cnx3.commit() diff -r 4da49700b06a -r 8be58694f416 test/unittest_entity.py --- a/test/unittest_entity.py Thu Mar 15 14:26:12 2012 +0100 +++ b/test/unittest_entity.py Fri Mar 16 10:29:15 2012 +0100 @@ -673,18 +673,18 @@ # ambiguity test person2 = req.create_entity('Personne', prenom=u'remi', nom=u'doe') person.cw_clear_all_caches() - self.assertEqual(person.rest_path(), 'personne/eid/%s' % person.eid) - self.assertEqual(person2.rest_path(), 'personne/eid/%s' % person2.eid) + self.assertEqual(person.rest_path(), unicode(person.eid)) + self.assertEqual(person2.rest_path(), unicode(person2.eid)) # unique attr with None value (wikiid in this case) card1 = req.create_entity('Card', title=u'hop') - self.assertEqual(card1.rest_path(), 'card/eid/%s' % card1.eid) + self.assertEqual(card1.rest_path(), unicode(card1.eid)) # don't use rest if we have /, ? or & in the path (breaks mod_proxy) card2 = req.create_entity('Card', title=u'pod', wikiid=u'zo/bi') - self.assertEqual(card2.rest_path(), 'card/eid/%d' % card2.eid) + self.assertEqual(card2.rest_path(), unicode(card2.eid)) card3 = req.create_entity('Card', title=u'pod', wikiid=u'zo&bi') - self.assertEqual(card3.rest_path(), 'card/eid/%d' % card3.eid) + self.assertEqual(card3.rest_path(), unicode(card3.eid)) card4 = req.create_entity('Card', title=u'pod', wikiid=u'zo?bi') - self.assertEqual(card4.rest_path(), 'card/eid/%d' % card4.eid) + self.assertEqual(card4.rest_path(), unicode(card4.eid)) def test_set_attributes(self): @@ -723,7 +723,7 @@ req = self.request() card = req.create_entity('Card', wikiid=u'', title=u'test') self.assertEqual(card.absolute_url(), - 'http://testing.fr/cubicweb/card/eid/%s' % card.eid) + 'http://testing.fr/cubicweb/%s' % card.eid) def test_create_entity(self): req = self.request() diff -r 4da49700b06a -r 8be58694f416 test/unittest_rqlrewrite.py --- a/test/unittest_rqlrewrite.py Thu Mar 15 14:26:12 2012 +0100 +++ b/test/unittest_rqlrewrite.py Fri Mar 16 10:29:15 2012 +0100 @@ -183,9 +183,9 @@ self.assertEqual(rqlst.as_string(), "Any A,C,T WHERE A documented_by C?, A is Affaire " "WITH C,T BEING (Any C,T WHERE C title T, " - "EXISTS(C in_state B, D in_group F, G require_state B, G name 'read', G require_group F), " - "D eid %(A)s, C is Card, " - "EXISTS(C in_state E, E name 'public'))") + "(EXISTS(C in_state B, D in_group F, G require_state B, G name 'read', G require_group F)) " + "OR (EXISTS(C in_state E, E name 'public')), " + "D eid %(A)s, C is Card)") def test_optional_var_4(self): constraint1 = 'A created_by U, X documented_by A' @@ -199,8 +199,8 @@ u'Any X,LA,Y WHERE LA? documented_by X, LA concerne Y, B eid %(C)s, ' 'EXISTS(X created_by B), EXISTS(Y created_by B), ' 'X is Card, Y is IN(Division, Note, Societe) ' - 'WITH LA BEING (Any LA WHERE EXISTS(A created_by B, LA documented_by A), ' - 'B eid %(D)s, LA is Affaire, EXISTS(E created_by B, LA concerne E))') + 'WITH LA BEING (Any LA WHERE (EXISTS(A created_by B, LA documented_by A)) OR (EXISTS(E created_by B, LA concerne E)), ' + 'B eid %(D)s, LA is Affaire)') def test_optional_var_inlined(self): c1 = ('X require_permission P') @@ -431,6 +431,33 @@ self.assertEqual(rqlst.as_string(), u'Any A WHERE NOT EXISTS(A documented_by C, EXISTS(C owned_by B, B login "hop", B is CWUser), C is Card), A is Affaire') + def test_rqlexpr_multiexpr_outerjoin(self): + c1 = RRQLExpression('X owned_by Z, Z login "hop"', 'X') + c2 = RRQLExpression('X owned_by Z, Z login "hip"', 'X') + c3 = RRQLExpression('X owned_by Z, Z login "momo"', 'X') + rqlst = rqlhelper.parse('Any A WHERE A documented_by C?', annotate=False) + rewrite(rqlst, {('C', 'X'): (c1, c2, c3)}, {}, 'X') + self.assertEqual(rqlst.as_string(), + u'Any A WHERE A documented_by C?, A is Affaire ' + 'WITH C BEING (Any C WHERE ((EXISTS(C owned_by B, B login "hop")) ' + 'OR (EXISTS(C owned_by D, D login "momo"))) ' + 'OR (EXISTS(C owned_by A, A login "hip")), C is Card)') + + def test_multiple_erql_one_bad(self): + #: reproduce bug #2236985 + #: (rqlrewrite fails to remove rewritten entry for unsupported constraint and then crash) + #: + #: This check a very rare code path triggered by the four condition below + + # 1. c_ok introduce an ambiguity + c_ok = ERQLExpression('X concerne R') + # 2. c_bad is just plain wrong and won't be kept + # 3. but it declare a new variable + # 4. this variable require a rewrite + c_bad = ERQLExpression('X documented_by R, A in_state R') + + rqlst = parse('Any A, R WHERE A ref R, S is Affaire') + rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {}) if __name__ == '__main__': unittest_main() diff -r 4da49700b06a -r 8be58694f416 uilib.py --- a/uilib.py Thu Mar 15 14:26:12 2012 +0100 +++ b/uilib.py Fri Mar 16 10:29:15 2012 +0100 @@ -108,7 +108,7 @@ elif value.days > 2 or value.days < -2: return req._('%d days') % int(value.days) else: - minus = 1 if value.days > 0 else -1 + minus = 1 if value.days >= 0 else -1 if value.seconds > 3600: return req._('%d hours') % (int(value.seconds // 3600) * minus) elif value.seconds >= 120: diff -r 4da49700b06a -r 8be58694f416 web/data/cubicweb.old.css --- a/web/data/cubicweb.old.css Thu Mar 15 14:26:12 2012 +0100 +++ b/web/data/cubicweb.old.css Fri Mar 16 10:29:15 2012 +0100 @@ -161,6 +161,9 @@ color: #000; background-color: #f2f2f2; border: 1px solid #ccc; + margin: 10px 0; + padding-bottom: 12px; + padding-left: 5px; } code { diff -r 4da49700b06a -r 8be58694f416 web/data/fullcalendar.locale.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/data/fullcalendar.locale.js Fri Mar 16 10:29:15 2012 +0100 @@ -0,0 +1,38 @@ +/* + translations for fullCalendar plugin + */ + +$.fullCalendar.regional = function(lng, options){ + var defaults = {'fr' : { + monthNames: + ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'], + monthNamesShort: ['janv.','févr.','mars','avr.','mai','juin','juil.','août','sept.','oct.','nov.','déc.'], + dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], + dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'], + titleFormat: { + month: 'MMMM yyyy', // ex : Janvier 2010 + week: "d[ MMMM][ yyyy]{ - d MMMM yyyy}", // ex : 10 — 16 Janvier 2010, + day: 'dddd d MMMM yyyy' // ex : Jeudi 14 Janvier 2010 + }, + columnFormat: {'month': 'dddd', + 'agendaWeek': 'dddd dd/M/yyyy', + 'agendaDay': 'dddd dd/M/yyyy'}, + axisFormat: 'H:mm', + timeFormat: { + '': 'H:mm', + agenda: 'H:mm{ - H:mm}'}, + allDayText: 'journée', + axisFormat: 'H:mm', + buttonText: { + today: "aujourd'hui", + month: 'mois', + week: 'semaine', + day: 'jour' + } + }}; + if(lng in defaults){ + return $.extend({}, defaults[lng], options); + } + else {return options;}; + }; +; \ No newline at end of file diff -r 4da49700b06a -r 8be58694f416 web/test/unittest_views_basetemplates.py --- a/web/test/unittest_views_basetemplates.py Thu Mar 15 14:26:12 2012 +0100 +++ b/web/test/unittest_views_basetemplates.py Fri Mar 16 10:29:15 2012 +0100 @@ -35,6 +35,13 @@ self.set_option('allow-email-login', 'no') self.assertEqual(self._login_labels(), ['login', 'password']) + +class MainNoTopTemplateTC(CubicWebTC): + + def test_valid_xhtml(self): + self.view('index', template='main-no-top') + + if __name__ == '__main__': from logilab.common.testlib import unittest_main unittest_main() diff -r 4da49700b06a -r 8be58694f416 web/views/basetemplates.py --- a/web/views/basetemplates.py Thu Mar 15 14:26:12 2012 +0100 +++ b/web/views/basetemplates.py Fri Mar 16 10:29:15 2012 +0100 @@ -256,10 +256,10 @@ whead(u'\n'.join(additional_headers) + u'\n') self.wview('htmlheader', rset=self.cw_rset) w = self.w - w(u'%s\n' % xml_escape(page_title)) + whead(u'%s\n' % xml_escape(page_title)) w(u'\n') w(u'
') - w(u'\n') + w(u'
\n') w(u'') - w(u'
') - w(u'
\n') - vtitle = self._cw.form.get('vtitle') - if vtitle: - w(u'
%s
' % xml_escape(vtitle)) + w(u'
') def topleft_header(self): logo = self._cw.vreg['components'].select_or_none('logo', self._cw, diff -r 4da49700b06a -r 8be58694f416 web/views/calendar.py --- a/web/views/calendar.py Thu Mar 15 14:26:12 2012 +0100 +++ b/web/views/calendar.py Fri Mar 16 10:29:15 2012 +0100 @@ -178,42 +178,31 @@ fullcalendar_options = { 'firstDay': 1, + 'firstHour': 8, + 'defaultView': 'month', + 'editable': True, 'header': {'left': 'prev,next today', 'center': 'title', 'right': 'month,agendaWeek,agendaDay', }, - 'editable': True, - 'defaultView': 'month', - 'timeFormat': {'month': '', - '': 'H:mm'}, - 'firstHour': 8, - 'axisFormat': 'H:mm', - 'columnFormat': {'month': 'dddd', - 'agendaWeek': 'dddd yyyy/M/dd', - 'agendaDay': 'dddd yyyy/M/dd'} } - def call(self): self._cw.demote_to_html() self._cw.add_css(('fullcalendar.css', 'cubicweb.calendar.css')) - self._cw.add_js(('jquery.ui.js', 'fullcalendar.min.js', 'jquery.qtip.min.js')) + self._cw.add_js(('jquery.ui.js', 'fullcalendar.min.js', 'jquery.qtip.min.js', 'fullcalendar.locale.js')) self.calendar_id = 'cal' + make_uid('uid') self.add_onload() # write calendar div to load jquery fullcalendar object self.w(u'
' % self.calendar_id) - def add_onload(self): fullcalendar_options = self.fullcalendar_options.copy() fullcalendar_options['events'] = self.get_events() - fullcalendar_options['buttonText'] = {'today': self._cw._('today'), - 'month': self._cw._('month'), - 'week': self._cw._('week'), - 'day': self._cw._('day')} + # i18n # js callback to add a tooltip and to put html in event's title js = """ - var options = %s; + var options = $.fullCalendar.regional('%s', %s); options.eventRender = function(event, $element) { // add a tooltip for each event var div = '
'+ event.description+ '
'; @@ -223,8 +212,7 @@ }; $("#%s").fullCalendar(options); """ #" - self._cw.add_onload(js % (json_dumps(fullcalendar_options), self.calendar_id)) - + self._cw.add_onload(js % (self._cw.lang, json_dumps(fullcalendar_options), self.calendar_id)) def get_events(self): events = []