# HG changeset patch # User Julien Jehannet # Date 1235071270 -3600 # Node ID 17555e9b9854fd63636ee1d11f50cb813c8d8b2e # Parent e6ae125d590322c05821ed595b2c087b7d2579b6# Parent 224bb95cca0911fc367f92d9cd3ff72934cf1326 (merge) diff -r e6ae125d5903 -r 17555e9b9854 __pkginfo__.py diff -r e6ae125d5903 -r 17555e9b9854 common/migration.py --- a/common/migration.py Thu Feb 19 20:19:05 2009 +0100 +++ b/common/migration.py Thu Feb 19 20:21:10 2009 +0100 @@ -312,12 +312,18 @@ """a configuration option's type has changed""" self._option_changes.append(('typechanged', optname, oldtype, newvalue)) - def cmd_add_cube(self, cube): + def cmd_add_cubes(self, cubes): + """modify the list of used cubes in the in-memory config + returns newly inserted cubes, including dependencies + """ + if isinstance(cubes, basestring): + cubes = (cubes,) origcubes = self.config.cubes() - newcubes = [p for p in self.config.expand_cubes([cube]) + newcubes = [p for p in self.config.expand_cubes(cubes) if not p in origcubes] if newcubes: - assert cube in newcubes + for cube in cubes: + assert cube in newcubes self.config.add_cubes(newcubes) return newcubes diff -r e6ae125d5903 -r 17555e9b9854 common/selectors.py --- a/common/selectors.py Thu Feb 19 20:19:05 2009 +0100 +++ b/common/selectors.py Thu Feb 19 20:21:10 2009 +0100 @@ -161,13 +161,20 @@ def paginated_rset(cls, req, rset, *args, **kwargs): """accept result sets with more rows than the page size """ - if rset is None or len(rset) <= req.property_value('navigation.page-size'): + page_size = kwargs.get('page_size') + if page_size is None: + page_size = req.form.get('page_size') + if page_size is None: + page_size = req.property_value('navigation.page-size') + else: + page_size = int(page_size) + if rset is None or len(rset) <= page_size: return 0 return 1 largerset_selector = deprecated_function(paginated_rset) @lltrace -def sorted_rset(cls, req, rset, row=None, col=None): +def sorted_rset(cls, req, rset, row=None, col=None, **kwargs): """accept sorted result set""" rqlst = rset.syntax_tree() if len(rqlst.children) > 1 or not rqlst.children[0].orderby: diff -r e6ae125d5903 -r 17555e9b9854 common/test/unittest_entity.py --- a/common/test/unittest_entity.py Thu Feb 19 20:19:05 2009 +0100 +++ b/common/test/unittest_entity.py Thu Feb 19 20:21:10 2009 +0100 @@ -250,8 +250,7 @@ self.assertListEquals(rbc(e.relations_by_category('generic')), [('primary_email', 'subject'), ('evaluee', 'subject'), - ('for_user', 'object'), - ('bookmarked_by', 'object')]) + ('for_user', 'object')]) # owned_by is defined both as subject and object relations on EUser self.assertListEquals(rbc(e.relations_by_category('generated')), [('last_login_time', 'subject'), @@ -263,7 +262,8 @@ ('owned_by', 'subject'), ('created_by', 'object'), ('wf_info_for', 'object'), - ('owned_by', 'object')]) + ('owned_by', 'object'), + ('bookmarked_by', 'object')]) e = self.etype_instance('Personne') self.assertListEquals(rbc(e.relations_by_category('primary')), [('nom', 'subject'), ('eid', 'subject')]) diff -r e6ae125d5903 -r 17555e9b9854 devtools/repotest.py --- a/devtools/repotest.py Thu Feb 19 20:19:05 2009 +0100 +++ b/devtools/repotest.py Thu Feb 19 20:21:10 2009 +0100 @@ -3,7 +3,7 @@ This module contains functions to initialize a new repository. :organization: Logilab -:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" @@ -249,7 +249,8 @@ _orig_select_principal = rqlannotation._select_principal def _select_principal(scope, relations): - return _orig_select_principal(scope, sorted(relations, key=lambda x: x.r_type)) + return _orig_select_principal(scope, relations, + _sort=lambda rels: sorted(rels, key=lambda x: x.r_type)) try: from cubicweb.server.msplanner import PartPlanInformation diff -r e6ae125d5903 -r 17555e9b9854 doc/book/en/B0031-define-entities.en.txt --- a/doc/book/en/B0031-define-entities.en.txt Thu Feb 19 20:19:05 2009 +0100 +++ b/doc/book/en/B0031-define-entities.en.txt Thu Feb 19 20:21:10 2009 +0100 @@ -55,13 +55,21 @@ It is possible to manage attributes/relations in the simple or multiple editing form thanks to the following *rtags*: -* `primary`, indicates that an attribute or a relation has to be inserted - in the simple or multiple editing forms. In the case of a relation, - the related entity editing form will be included in the editing form. +* `primary`, indicates that an attribute or a relation has to be + inserted **in the simple or multiple editing forms**. In the case of + a relation, the related entity editing form will be included in the + editing form and represented as a combobox. Each item of the + combobox is a link to an existing entity. -* `secondary`, indicates that an attribute or a relation has to be inserted - in the simple editing form only. In the case of a relation, the related - entity editing form sill be included in the editing form. +* `secondary`, indicates that an attribute or a relation has to be + inserted **in the simple editing form only**. In the case of a + relation, the related entity editing form will be included in the + editing form and represented as a combobox. Each item of the combobox + is a link to an existing entity. + +* `inlineview`, includes the target entity's form in the editing form + of the current entity. It allows to create the target entity in the + same time as the current entity. * `generic`, indicates that a relation has to be inserted in the simple editing form, in the generic box of relation creation. diff -r e6ae125d5903 -r 17555e9b9854 doc/book/en/C012-create-instance.en.txt --- a/doc/book/en/C012-create-instance.en.txt Thu Feb 19 20:19:05 2009 +0100 +++ b/doc/book/en/C012-create-instance.en.txt Thu Feb 19 20:21:10 2009 +0100 @@ -24,11 +24,11 @@ A cube defines entities, their views, their schemas and workflows in an independant directory located in ``/path/to/forest/cubicweb/cubes/`` -for a Mercurila installation or in ``/usr/share/cubicweb/cubes`` for -a debian packages installation. +for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for +a debian package installation. When an instance is created, you list one or more cubes that your instance -will use. Use a cube means having the entities defined in your cube's schema +will use. Using a cube means having the entities defined in your cube's schema available in your instance as well as their views and workflows. .. note:: diff -r e6ae125d5903 -r 17555e9b9854 doc/book/en/Z010-beginners.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/Z010-beginners.en.txt Thu Feb 19 20:21:10 2009 +0100 @@ -0,0 +1,12 @@ +.. -*- coding: utf-8 -*- + +.. _QuickInstall: + +=========================================== +Quick Installation of a `CubicWeb` instance +=========================================== + +.. include:: C011-installation.en.txt +.. include:: Z012-create-instance.en.txt + + diff -r e6ae125d5903 -r 17555e9b9854 doc/book/en/Z012-create-instance.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/Z012-create-instance.en.txt Thu Feb 19 20:21:10 2009 +0100 @@ -0,0 +1,79 @@ +.. -*- coding: utf-8 -*- + +Creation of your first instance +=============================== + +What is an instance? +-------------------- + +A `CubicWeb` instance is a container that +refers to cubes and configuration parameters for your web application. +Each instance is stored as a directory in ``~/etc/cubicweb.d`` which enables +us to run your application. + +What is a cube? +--------------- + +Cubes represent data and basic building bricks of your web applications : +blogs, person, date, addressbook and a lot more. + +.. XXX They related to each other by a 'Schema' which is also the PostGres representation. + +Each cube defines entities, their views, their schemas and workflows +in an independant directory located in ``/path/to/forest/cubicweb/cubes/`` +for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for +a debian package installation. For example, the 'blog' cube defines the entities +blogs and blogentries. + +When an `CubicWeb` instance is created, you list the cubes that you want to use. +Using a cube means having the entities defined in your cube's schema +available in your instance as well as their views and workflows. + + +Creating a basic `CubicWeb` Instance +------------------------------------ + +We can create an instance to view our +application in a web browser. :: + + cubicweb-ctl create blog myblog + +.. XXX or :: + +.. XXX cubicweb-ctl create forge myforge + + +.. note:: + The commands used below are more detailled in the section dedicated to + :ref:`cubicweb-ctl`. + +A series of questions will be prompted to you, the default answer is usually +sufficient. You can allways modify the parameters later by editing +configuration files. When a user/psswd is requested to access the database +please use the login you create at the time you configured the database +(:ref:`ConfigurationPostgres`). + +It is important to distinguish here the user used to access the database and +the user used to login to the cubicweb application. When a `CubicWeb` application +starts, it uses the login/psswd for the database to get the schema and handle +low level transaction. But, when ``cubicweb-ctl create`` asks for +a manager login/psswd of `CubicWeb`, it refers to an application user +to administrate your web application. +The configuration files are stored in *~/etc/cubicweb.d/myblog/*. + +To launch the web application, you just type :: + + cubicweb-ctl start myblog + +You can see how it looks by +visiting the URL `http://localhost:8080`. +To login, please use the cubicweb administrator login/psswd you +defined when you created the instance. + +To shutdown the instance :: + + cubicweb-ctl stop myinstance + +.. XXX something like `cubicweb-ctl live-server intra` would be nice + + diff -r e6ae125d5903 -r 17555e9b9854 doc/book/en/index.txt --- a/doc/book/en/index.txt Thu Feb 19 20:19:05 2009 +0100 +++ b/doc/book/en/index.txt Thu Feb 19 20:21:10 2009 +0100 @@ -29,7 +29,9 @@ The hacker will join development at the forge_. -The impatient will move right away to :ref:`MiseEnPlaceEnv`. +The impatient will go strait away to :ref:`QuickInstall`. + +The impatient developper will move right away to :ref:`MiseEnPlaceEnv`. .. _Logilab: http://www.logilab.fr/ .. _forge: http://www.cubicweb.org/project/ diff -r e6ae125d5903 -r 17555e9b9854 doc/book/en/makefile --- a/doc/book/en/makefile Thu Feb 19 20:19:05 2009 +0100 +++ b/doc/book/en/makefile Thu Feb 19 20:21:10 2009 +0100 @@ -43,7 +43,7 @@ #apydoc: # epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py apidoc: - epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../ + epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../ # run sphinx ### html: diff -r e6ae125d5903 -r 17555e9b9854 doc/book/fr/makefile --- a/doc/book/fr/makefile Thu Feb 19 20:19:05 2009 +0100 +++ b/doc/book/fr/makefile Thu Feb 19 20:21:10 2009 +0100 @@ -43,7 +43,7 @@ #apydoc: # epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py apidoc: - epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../ + epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../ # run sphinx ### html: diff -r e6ae125d5903 -r 17555e9b9854 entities/authobjs.py --- a/entities/authobjs.py Thu Feb 19 20:19:05 2009 +0100 +++ b/entities/authobjs.py Thu Feb 19 20:21:10 2009 +0100 @@ -1,3 +1,10 @@ +"""entity classes user and group entities + +:organization: Logilab +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" from logilab.common.decorators import cached from cubicweb import Unauthorized @@ -26,6 +33,7 @@ 'in_group' : 'primary', ('owned_by', '*', 'object') : ('generated', 'link'), ('created_by','*','object') : ('generated', 'link'), + ('bookmarked_by', '*', 'object'): ('generated', 'create'), } # used by repository to check if the user can log in or not @@ -85,6 +93,13 @@ """ return self.matching_groups(group) == 1 + def is_anonymous(self): + """ checks if user is an anonymous user""" + #FIXME on the web-side anonymous user is detected according + # to config['anonymous-user'], we don't have this info on + # the server side. + return self.groups == frozenset(('guests', )) + def owns(self, eid): if hasattr(self.req, 'unsafe_execute'): # use unsafe_execute on the repository side, in case diff -r e6ae125d5903 -r 17555e9b9854 entities/lib.py --- a/entities/lib.py Thu Feb 19 20:19:05 2009 +0100 +++ b/entities/lib.py Thu Feb 19 20:21:10 2009 +0100 @@ -1,7 +1,7 @@ """entity classes for optional library entities :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" diff -r e6ae125d5903 -r 17555e9b9854 goa/test/data/bootstrap_cubes diff -r e6ae125d5903 -r 17555e9b9854 goa/test/data/bootstrap_packages diff -r e6ae125d5903 -r 17555e9b9854 goa/test/unittest_editcontroller.py --- a/goa/test/unittest_editcontroller.py Thu Feb 19 20:19:05 2009 +0100 +++ b/goa/test/unittest_editcontroller.py Thu Feb 19 20:21:10 2009 +0100 @@ -17,7 +17,7 @@ config.global_set_option('use-google-auth', False) config.global_set_option('schema-type', 'yams') config.global_set_option('included-cubes', ()) - config.global_set_option('included-yams-cubes', ('eblog',)) + config.global_set_option('included-yams-cubes', ('blog',)) MODEL_CLASSES = () from cubicweb.web.views import editcontroller diff -r e6ae125d5903 -r 17555e9b9854 i18n/en.po --- a/i18n/en.po Thu Feb 19 20:19:05 2009 +0100 +++ b/i18n/en.po Thu Feb 19 20:21:10 2009 +0100 @@ -376,6 +376,9 @@ msgid "Problem occured" msgstr "" +msgid "Project linked data" +msgstr "" + msgid "RQLExpression" msgstr "RQL expression" @@ -717,6 +720,9 @@ msgid "add" msgstr "" +msgid "add Bookmark bookmarked_by EUser object" +msgstr "bookmark" + msgid "add EEType add_permission RQLExpression subject" msgstr "rql expression for the add permission" @@ -1311,6 +1317,9 @@ msgid "created_by_object" msgstr "has created" +msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)" +msgstr "creating bookmark for %(linkto)s" + msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)" msgstr "creating constraint for attribute %(linkto)s" @@ -1668,12 +1677,18 @@ msgid "february" msgstr "" +msgid "file tree view" +msgstr "" + msgid "final" msgstr "" msgid "firstname" msgstr "" +msgid "foaf" +msgstr "" + msgid "follow" msgstr "" @@ -1997,6 +2012,9 @@ msgid "list" msgstr "" +msgid "loading" +msgstr "" + msgid "log in" msgstr "" @@ -2025,6 +2043,9 @@ msgid "manage bookmarks" msgstr "" +msgid "manage permissions" +msgstr "" + msgid "manage security" msgstr "" @@ -2137,6 +2158,9 @@ msgid "not authorized" msgstr "" +msgid "not selected" +msgstr "" + msgid "not specified" msgstr "" @@ -2173,6 +2197,15 @@ msgid "ordernum" msgstr "order" +msgid "owl (tbox+abox)" +msgstr "" + +msgid "owlabox" +msgstr "" + +msgid "owlaboxlight" +msgstr "" + msgid "owned_by" msgstr "owned by" @@ -2416,6 +2449,9 @@ msgid "select this entity" msgstr "" +msgid "selected" +msgstr "" + msgid "semantic description of this attribute" msgstr "" @@ -2541,6 +2577,9 @@ msgid "task progression" msgstr "" +msgid "tbox" +msgstr "" + msgid "text" msgstr "" @@ -2617,6 +2656,9 @@ msgid "transition_of_object" msgstr "use transitions" +msgid "tree view" +msgstr "" + msgid "tuesday" msgstr "" diff -r e6ae125d5903 -r 17555e9b9854 i18n/es.po --- a/i18n/es.po Thu Feb 19 20:19:05 2009 +0100 +++ b/i18n/es.po Thu Feb 19 20:21:10 2009 +0100 @@ -381,6 +381,9 @@ msgid "Problem occured" msgstr "Ha ocurrido un error" +msgid "Project linked data" +msgstr "" + msgid "RQLExpression" msgstr "Expresión RQL" @@ -738,6 +741,9 @@ msgid "add" msgstr "agregar" +msgid "add Bookmark bookmarked_by EUser object" +msgstr "" + msgid "add EEType add_permission RQLExpression subject" msgstr "Definir una expresión RQL de agregación" @@ -1359,6 +1365,9 @@ msgid "created_by_object" msgstr "ha creado" +msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)" +msgstr "" + msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)" msgstr "creación condicionada por el atributo %(linkto)s" @@ -1745,12 +1754,18 @@ msgid "february" msgstr "febrero" +msgid "file tree view" +msgstr "" + msgid "final" msgstr "final" msgid "firstname" msgstr "nombre" +msgid "foaf" +msgstr "" + msgid "follow" msgstr "seguir la liga" @@ -2090,6 +2105,9 @@ msgid "list" msgstr "liste" +msgid "loading" +msgstr "" + msgid "log in" msgstr "s'identifier" @@ -2118,6 +2136,9 @@ msgid "manage bookmarks" msgstr "gÈrer les signets" +msgid "manage permissions" +msgstr "" + msgid "manage security" msgstr "gestion de la sÈcuritÈ" @@ -2232,6 +2253,9 @@ msgid "not authorized" msgstr "non autorisÈ" +msgid "not selected" +msgstr "" + msgid "not specified" msgstr "non spÈcifiÈ" @@ -2268,6 +2292,15 @@ msgid "ordernum" msgstr "ordre" +msgid "owl (tbox+abox)" +msgstr "" + +msgid "owlabox" +msgstr "" + +msgid "owlaboxlight" +msgstr "" + msgid "owned_by" msgstr "appartient ‡" @@ -2521,6 +2554,9 @@ msgid "select this entity" msgstr "sÈlectionner cette entitÈ" +msgid "selected" +msgstr "" + msgid "semantic description of this attribute" msgstr "description sÈmantique de cet attribut" @@ -2649,6 +2685,9 @@ msgid "task progression" msgstr "avancement de la t‚che" +msgid "tbox" +msgstr "" + msgid "text" msgstr "text" @@ -2726,6 +2765,9 @@ msgid "transition_of_object" msgstr "a pour transition" +msgid "tree view" +msgstr "" + msgid "tuesday" msgstr "mardi" diff -r e6ae125d5903 -r 17555e9b9854 i18n/fr.po --- a/i18n/fr.po Thu Feb 19 20:19:05 2009 +0100 +++ b/i18n/fr.po Thu Feb 19 20:21:10 2009 +0100 @@ -381,6 +381,9 @@ msgid "Problem occured" msgstr "Une erreur est survenue" +msgid "Project linked data" +msgstr "" + msgid "RQLExpression" msgstr "Expression RQL" @@ -740,6 +743,9 @@ msgid "add" msgstr "ajouter" +msgid "add Bookmark bookmarked_by EUser object" +msgstr "signet" + msgid "add EEType add_permission RQLExpression subject" msgstr "définir une expression RQL d'ajout" @@ -1197,7 +1203,7 @@ msgstr "la barre de requête rql, dans l'en-tête de page" msgid "components_rss_feed_url" -msgstr "" +msgstr "syndication rss" msgid "components_rss_feed_url_description" msgstr "" @@ -1361,14 +1367,17 @@ msgid "created_by_object" msgstr "a créé" +msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)" +msgstr "création d'un signet pour %(linkto)s" + msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)" -msgstr "création contrainte pour l'attribut %(linkto)s" +msgstr "création d'une contrainte pour l'attribut %(linkto)s" msgid "creating EConstraint (ENFRDef %(linkto)s constrained_by EConstraint)" -msgstr "création contrainte pour la relation %(linkto)s" +msgstr "création d'une contrainte pour la relation %(linkto)s" msgid "creating EFRDef (EFRDef relation_type ERType %(linkto)s)" -msgstr "création attribut %(linkto)s" +msgstr "création d'un attribut %(linkto)s" msgid "creating ENFRDef (ENFRDef relation_type ERType %(linkto)s)" msgstr "création relation %(linkto)s" @@ -1744,12 +1753,18 @@ msgid "february" msgstr "février" +msgid "file tree view" +msgstr "arborescence (fichiers)" + msgid "final" msgstr "final" msgid "firstname" msgstr "prénom" +msgid "foaf" +msgstr "foaf" + msgid "follow" msgstr "suivre le lien" @@ -2091,6 +2106,9 @@ msgid "list" msgstr "liste" +msgid "loading" +msgstr "chargement" + msgid "log in" msgstr "s'identifier" @@ -2119,6 +2137,9 @@ msgid "manage bookmarks" msgstr "gérer les signets" +msgid "manage permissions" +msgstr "gestion des permissions" + msgid "manage security" msgstr "gestion de la sécurité" @@ -2233,6 +2254,9 @@ msgid "not authorized" msgstr "non autorisé" +msgid "not selected" +msgstr "non sélectionné" + msgid "not specified" msgstr "non spécifié" @@ -2269,6 +2293,15 @@ msgid "ordernum" msgstr "ordre" +msgid "owl (tbox+abox)" +msgstr "" + +msgid "owlabox" +msgstr "" + +msgid "owlaboxlight" +msgstr "" + msgid "owned_by" msgstr "appartient à" @@ -2522,6 +2555,9 @@ msgid "select this entity" msgstr "sélectionner cette entité" +msgid "selected" +msgstr "sélectionné" + msgid "semantic description of this attribute" msgstr "description sémantique de cet attribut" @@ -2650,6 +2686,9 @@ msgid "task progression" msgstr "avancement de la tâche" +msgid "tbox" +msgstr "" + msgid "text" msgstr "text" @@ -2727,6 +2766,9 @@ msgid "transition_of_object" msgstr "a pour transition" +msgid "tree view" +msgstr "arborescence" + msgid "tuesday" msgstr "mardi" diff -r e6ae125d5903 -r 17555e9b9854 interfaces.py --- a/interfaces.py Thu Feb 19 20:19:05 2009 +0100 +++ b/interfaces.py Thu Feb 19 20:21:10 2009 +0100 @@ -238,3 +238,7 @@ def rss_feed_url(self): """return an url which layout sub-entities item """ +class ISIOC(Interface): + """interface for entities with sioc views""" + + diff -r e6ae125d5903 -r 17555e9b9854 rset.py --- a/rset.py Thu Feb 19 20:19:05 2009 +0100 +++ b/rset.py Thu Feb 19 20:21:10 2009 +0100 @@ -1,7 +1,7 @@ """The `ResultSet` class which is returned as result of a rql query :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" @@ -60,11 +60,15 @@ def __repr__(self): if not self.rows: return '' % self.rql + rows = self.rows + if len(rows) > 10: + rows = rows[:10] + ['...'] if not self.description: - return '' % (self.rql, '\n'.join(str(r) for r in self.rows)) - return '' % (self.rql, - '\n'.join('%s (%s)' % (r, d) - for r, d in zip(self.rows, self.description))) + return '' % (self.rql, len(self.rows), + '\n'.join(str(r) for r in rows)) + return '' % (self.rql, len(self.rows), + '\n'.join('%s (%s)' % (r, d) + for r, d in zip(rows, self.description))) @cached def possible_actions(self): @@ -464,7 +468,8 @@ rqlst = self.syntax_tree() etype = self.description[row][col] if self.vreg.schema.eschema(etype).is_final(): - # final type, find a better (ambiguous) one + # final type, find a better one to locate the correct subquery + # (ambiguous if possible) for i in xrange(len(rqlst.children[0].selection)): if i == col: continue @@ -476,18 +481,17 @@ locate_query_col = i if len(self.column_types(i)) > 1: break - # UNION query, find the subquery from which this entity has been - # found + # UNION query, find the subquery from which this entity has been found select = rqlst.locate_subquery(locate_query_col, etype, self.args) try: myvar = select.selection[col].variable except AttributeError: - # no .selection attribute is available + # not a variable return None, None rel = myvar.main_relation() if rel is not None: index = rel.children[0].variable.selected_index() - if index is not None: + if index is not None and self.rows[row][index]: return self.get_entity(row, index), rel.r_type return None, None diff -r e6ae125d5903 -r 17555e9b9854 server/migractions.py --- a/server/migractions.py Thu Feb 19 20:19:05 2009 +0100 +++ b/server/migractions.py Thu Feb 19 20:21:10 2009 +0100 @@ -264,13 +264,15 @@ self.commit() def cmd_add_cube(self, cube, update_database=True): + self.cmd_add_cubes( (cube,), update_database) + + def cmd_add_cubes(self, cubes, update_database=True): """update_database is telling if the database schema should be updated or if only the relevant eproperty should be inserted (for the case where a cube has been extracted from an existing application, so the cube schema is already in there) """ - newcubes = super(ServerMigrationHelper, self).cmd_add_cube( - cube) + newcubes = super(ServerMigrationHelper, self).cmd_add_cubes(cubes) if not newcubes: return for pack in newcubes: @@ -279,22 +281,22 @@ if not update_database: self.commit() return - self.new_schema = self.config.load_schema() + with_new_cubes = 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 self.new_schema.relations(): + for rschema in with_new_cubes.relations(): if not rschema in self.repo.schema: self.cmd_add_relation_type(rschema.type) new.add(rschema.type) - for eschema in self.new_schema.entities(): + for eschema in with_new_cubes.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 self.new_schema.relations(): + for rschema in with_new_cubes.relations(): existingschema = self.repo.schema.rschema(rschema.type) for (fromtype, totype) in rschema.iter_rdefs(): if existingschema.has_rdef(fromtype, totype): diff -r e6ae125d5903 -r 17555e9b9854 server/repository.py --- a/server/repository.py Thu Feb 19 20:19:05 2009 +0100 +++ b/server/repository.py Thu Feb 19 20:21:10 2009 +0100 @@ -490,7 +490,7 @@ session = self.internal_session() try: if session.execute('EUser X WHERE X login %(login)s', {'login': login}): - return + return False # we have to create the user user = self.vreg.etype_class('EUser')(session, None) if isinstance(password, unicode): @@ -505,6 +505,7 @@ session.commit() finally: session.close() + return True def connect(self, login, password, cnxprops=None): """open a connection for a given user diff -r e6ae125d5903 -r 17555e9b9854 server/rqlannotation.py --- a/server/rqlannotation.py Thu Feb 19 20:19:05 2009 +0100 +++ b/server/rqlannotation.py Thu Feb 19 20:21:10 2009 +0100 @@ -146,16 +146,17 @@ class CantSelectPrincipal(Exception): pass -def _select_principal(sqlscope, relations): +def _select_principal(sqlscope, relations, _sort=lambda x:x): """given a list of rqlst relations, select one which will be used to represent an invariant variable (e.g. using on extremity of the relation instead of the variable's type table """ + # _sort argument is there for test diffscope_rels = {} has_same_scope_rel = False ored_rels = set() diffscope_rels = set() - for rel in relations: + for rel in _sort(relations): # note: only eid and has_text among all final relations may be there if rel.r_type in ('eid', 'identity'): has_same_scope_rel = rel.sqlscope is sqlscope @@ -175,18 +176,17 @@ if isinstance(common_parent(rel1, rel2), Or): ored_rels.discard(rel1) ored_rels.discard(rel2) - for rel in ored_rels: + for rel in _sort(ored_rels): if rel.sqlscope is sqlscope: return rel diffscope_rels.add(rel) # if DISTINCT query, can use variable from a different scope as principal # since introduced duplicates will be removed if sqlscope.stmt.distinct and diffscope_rels: - return iter(diffscope_rels).next() + return iter(_sort(diffscope_rels)).next() # XXX could use a relation for a different scope if it can't generate # duplicates, so we would have to check cardinality - raise CantSelectPrincipal() - + raise CantSelectPrincipal() def _select_main_var(relations): """given a list of rqlst relations, select one which will be used as main diff -r e6ae125d5903 -r 17555e9b9854 server/session.py --- a/server/session.py Thu Feb 19 20:19:05 2009 +0100 +++ b/server/session.py Thu Feb 19 20:21:10 2009 +0100 @@ -21,6 +21,18 @@ from cubicweb.common.utils import make_uid from cubicweb.server.rqlrewrite import RQLRewriter +_ETYPE_PYOBJ_MAP = { bool: 'Boolean', + int: 'Int', + long: 'Int', + float: 'Float', + Decimal: 'Decimal', + unicode: 'String', + NoneType: None, + Binary: 'Bytes', + DateTimeType: 'Datetime', + DateTimeDeltaType: 'Interval', + } + def etype_from_pyobj(value): """guess yams type from python value""" # note: @@ -28,17 +40,7 @@ # * use type(value) and not value.__class__ since mx instances have no # __class__ attribute # * XXX Date, Time - return {bool: 'Boolean', - int: 'Int', - long: 'Int', - float: 'Float', - Decimal: 'Decimal', - unicode: 'String', - NoneType: None, - Binary: 'Bytes', - DateTimeType: 'Datetime', - DateTimeDeltaType: 'Interval', - }[type(value)] + return _ETYPE_PYOBJ_MAP[type(value)] def is_final(rqlst, variable, args): # try to find if this is a final var or not @@ -58,35 +60,8 @@ description.append(term.get_type(solution, args)) return description -#XXX rql <= 0.18.3 bw compat from rql import stmts -if not hasattr(stmts.Union, 'get_variable_variables'): - def _union_get_variable_variables(self): - """return the set of variable names which take different type according to - the solution - """ - change = set() - values = {} - for select in self.children: - change.update(select.get_variable_variables(values)) - return change - stmts.Union.get_variable_variables = _union_get_variable_variables - - def _select_get_variable_variables(self, _values=None): - """return the set of variable names which take different type according to - the solution - """ - change = set() - if _values is None: - _values = {} - for solution in self.solutions: - for vname, etype in solution.iteritems(): - if not vname in _values: - _values[vname] = etype - elif _values[vname] != etype: - change.add(vname) - return change - stmts.Select.get_variable_variables = _select_get_variable_variables +assert hasattr(stmts.Union, 'get_variable_variables'), "You need RQL > 0.18.3" class Session(RequestSessionMixIn): """tie session id, user, connections pool and other session data all diff -r e6ae125d5903 -r 17555e9b9854 server/test/unittest_rql2sql.py --- a/server/test/unittest_rql2sql.py Thu Feb 19 20:19:05 2009 +0100 +++ b/server/test/unittest_rql2sql.py Thu Feb 19 20:21:10 2009 +0100 @@ -805,7 +805,7 @@ 'F name "read", F require_group E, U in_group E)), U eid 1', '''SELECT A.eid, rel_documented_by0.eid_to FROM Affaire AS A LEFT OUTER JOIN documented_by_relation AS rel_documented_by0 ON (rel_documented_by0.eid_from=A.eid) -WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.eid AND F.name=read AND rel_require_group2.eid_from=F.eid AND rel_in_group3.eid_from=1 AND rel_in_group3.eid_to=rel_require_group2.eid_to)))'''), +WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.eid AND F.name=read AND rel_require_group2.eid_from=F.eid AND rel_in_group3.eid_to=rel_require_group2.eid_to AND rel_in_group3.eid_from=1)))'''), ("Any X WHERE X eid 12, P? connait X", '''SELECT X.eid diff -r e6ae125d5903 -r 17555e9b9854 test/unittest_rset.py --- a/test/unittest_rset.py Thu Feb 19 20:19:05 2009 +0100 +++ b/test/unittest_rset.py Thu Feb 19 20:21:10 2009 +0100 @@ -300,7 +300,13 @@ attr = etype == 'Bookmark' and 'title' or 'name' self.assertEquals(entity[attr], n) - + def test_related_entity_optional(self): + e = self.add_entity('Bookmark', title=u'aaaa', path=u'path') + rset = self.execute('Any B,U,L WHERE B bookmarked_by U?, U login L') + entity, rtype = rset.related_entity(0, 2) + self.assertEquals(entity, None) + self.assertEquals(rtype, None) + def test_related_entity_union_subquery(self): e = self.add_entity('Bookmark', title=u'aaaa', path=u'path') rset = self.execute('Any X,N ORDERBY N WITH X,N BEING ' diff -r e6ae125d5903 -r 17555e9b9854 vregistry.py --- a/vregistry.py Thu Feb 19 20:19:05 2009 +0100 +++ b/vregistry.py Thu Feb 19 20:21:10 2009 +0100 @@ -20,7 +20,7 @@ :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" @@ -105,7 +105,10 @@ "can't be used together") if '__select__' not in classdict and '__selectors__' in classdict: selectors = classdict['__selectors__'] - classdict['__select__'] = classmethod(chainall(*selectors)) + if len(selectors) > 1: + classdict['__select__'] = classmethod(chainall(*selectors)) + else: + classdict['__select__'] = classmethod(selectors[0]) return super(autoselectors, mcs).__new__(mcs, name, bases, classdict) def __setattr__(self, attr, value): diff -r e6ae125d5903 -r 17555e9b9854 web/application.py --- a/web/application.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/application.py Thu Feb 19 20:21:10 2009 +0100 @@ -1,7 +1,7 @@ """CubicWeb web client application object :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" @@ -317,6 +317,7 @@ try: ctrlid, rset = self.url_resolver.process(req, path) controller = self.select_controller(ctrlid, req) + req.update_search_state() result = controller.publish(rset=rset) if req.cnx is not None: # req.cnx is None if anonymous aren't allowed and we are diff -r e6ae125d5903 -r 17555e9b9854 web/component.py --- a/web/component.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/component.py Thu Feb 19 20:21:10 2009 +0100 @@ -73,6 +73,19 @@ selected_page_link_templ = u'%s' previous_page_link_templ = next_page_link_templ = page_link_templ no_previous_page_link = no_next_page_link = u'' + + @classmethod + def selected(cls, req, rset, row=None, col=None, page_size=None, **kwargs): + """by default web app objects are usually instantiated on + selection according to a request, a result set, and optional + row and col + """ + instance = super(NavigationComponent, cls).selected(req, rset, row, col, **kwargs) + if page_size is not None: + instance.page_size = page_size + elif 'page_size' in req.form: + instance.page_size = int(req.form['page_size']) + return instance def __init__(self, req, rset): super(NavigationComponent, self).__init__(req, rset) diff -r e6ae125d5903 -r 17555e9b9854 web/data/cubicweb.preferences.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/data/cubicweb.preferences.js Thu Feb 19 20:21:10 2009 +0100 @@ -0,0 +1,10 @@ +/* toggle visibility of an element by its id + * & set current visibility status in a cookie + * XXX whenever used outside of preferences, don't forget to + * move me in a more appropriate place + */ +function toggle_and_remember_visibility(elemId, cookiename) { + jqNode(elemId).toggleClass('hidden'); + async_remote_exec('set_cookie', cookiename, + jQuery('#' + elemId).attr('class')); +} diff -r e6ae125d5903 -r 17555e9b9854 web/data/cubicweb.tabs.js --- a/web/data/cubicweb.tabs.js Thu Feb 19 20:19:05 2009 +0100 +++ b/web/data/cubicweb.tabs.js Thu Feb 19 20:21:10 2009 +0100 @@ -1,7 +1,6 @@ -function set_tab(tabname) { +function set_tab(tabname, cookiename) { // set appropriate cookie - // XXX see if we can no just do it with jQuery - async_remote_exec('remember_active_tab', tabname); + async_remote_exec('set_cookie', cookiename, tabname); // trigger show + tabname event trigger_load(tabname); } diff -r e6ae125d5903 -r 17555e9b9854 web/data/jquery.corner.js --- a/web/data/jquery.corner.js Thu Feb 19 20:19:05 2009 +0100 +++ b/web/data/jquery.corner.js Thu Feb 19 20:21:10 2009 +0100 @@ -1,1 +1,178 @@ -if(!document.createElement('canvas').getContext){(function(){var m=Math;var y=m.round;var z=m.sin;var A=m.cos;var Z=10;var B=Z/2;function getContext(){if(this.context_){return this.context_}return this.context_=new CanvasRenderingContext2D_(this)}var C=Array.prototype.slice;function bind(f,b,c){var a=C.call(arguments,2);return function(){return f.apply(b,a.concat(C.call(arguments)))}}var D={init:function(a){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var b=a||document;b.createElement('canvas');b.attachEvent('onreadystatechange',bind(this.init_,this,b))}},init_:function(a){if(!a.namespaces['g_vml_']){a.namespaces.add('g_vml_','urn:schemas-microsoft-com:vml')}if(!a.styleSheets['ex_canvas_']){var b=a.createStyleSheet();b.owningElement.id='ex_canvas_';b.cssText='canvas{display:inline-block;overflow:hidden;'+'text-align:left;width:300px;height:150px}'+'g_vml_\\:*{behavior:url(#default#VML)}'}},i:function(a){if(!a.getContext){a.getContext=getContext;a.attachEvent('onpropertychange',onPropertyChange);a.attachEvent('onresize',onResize);var b=a.attributes;if(b.width&&b.width.specified){a.style.width=b.width.nodeValue+'px'}else{a.width=a.clientWidth}if(b.height&&b.height.specified){a.style.height=b.height.nodeValue+'px'}else{a.height=a.clientHeight}}return a}};function onPropertyChange(e){var a=e.srcElement;switch(e.propertyName){case'width':a.style.width=a.attributes.width.nodeValue+'px';a.getContext().clearRect();break;case'height':a.style.height=a.attributes.height.nodeValue+'px';a.getContext().clearRect();break}}function onResize(e){var a=e.srcElement;if(a.firstChild){a.firstChild.style.width=a.clientWidth+'px';a.firstChild.style.height=a.clientHeight+'px'}}D.init();var E=[];for(var i=0;i<16;i++){for(var j=0;j<16;j++){E[i*16+j]=i.toString(16)+j.toString(16)}}function createMatrixIdentity(){return[[1,0,0],[0,1,0],[0,0,1]]}function processStyle(a){var b,alpha=1;a=String(a);if(a.substring(0,3)=='rgb'){var c=a.indexOf('(',3);var d=a.indexOf(')',c+1);var e=a.substring(c+1,d).split(',');b='#';for(var i=0;i<3;i++){b+=E[Number(e[i])]}if(e.length==4&&a.substr(3,1)=='a'){alpha=e[3]}}else{b=a}return[b,alpha]}function processLineCap(a){switch(a){case'butt':return'flat';case'round':return'round';case'square':default:return'square'}}function CanvasRenderingContext2D_(a){this.m_=createMatrixIdentity();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle='#000';this.fillStyle='#000';this.lineWidth=1;this.lineJoin='miter';this.lineCap='butt';this.miterLimit=Z*1;this.globalAlpha=1;this.canvas=a;var b=a.ownerDocument.createElement('div');b.style.width=a.clientWidth+'px';b.style.height=a.clientHeight+'px';b.style.overflow='hidden';b.style.position='absolute';a.appendChild(b);this.element_=b;this.arcScaleX_=1;this.arcScaleY_=1}var F=CanvasRenderingContext2D_.prototype;F.clearRect=function(){this.element_.innerHTML='';this.currentPath_=[]};F.beginPath=function(){this.currentPath_=[]};F.moveTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'moveTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.lineTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'lineTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.bezierCurveTo=function(a,b,c,d,e,f){var p=this.getCoords_(e,f);var g=this.getCoords_(a,b);var h=this.getCoords_(c,d);this.currentPath_.push({type:'bezierCurveTo',cp1x:g.x,cp1y:g.y,cp2x:h.x,cp2y:h.y,x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.fillRect=function(a,b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.fill();this.currentPath_=[]};F.createLinearGradient=function(a,b,c,d){return new CanvasGradient_('gradient')};F.createRadialGradient=function(a,b,c,d,e,f){var g=new CanvasGradient_('gradientradial');g.radius1_=c;g.radius2_=f;g.focus_.x=a;g.focus_.y=b;return g};F.stroke=function(d){var e=[];var f=false;var a=processStyle(d?this.fillStyle:this.strokeStyle);var g=a[0];var h=a[1]*this.globalAlpha;var W=10;var H=10;e.push('');if(typeof this.fillStyle=='object'){var m={x:'50%',y:'50%'};var n=l.x-k.x;var o=l.y-k.y;var q=n>o?n:o;m.x=y(this.fillStyle.focus_.x/n*100+50)+'%';m.y=y(this.fillStyle.focus_.y/o*100+50)+'%';var r=[];if(this.fillStyle.type_=='gradientradial'){var s=this.fillStyle.radius1_/q*100;var t=this.fillStyle.radius2_/q*100-s}else{var s=0;var t=100}var u={offset:null,color:null};var v={offset:null,color:null};this.fillStyle.colors_.sort(function(a,b){return a.offset-b.offset});for(var i=0;iu.offset||u.offset==null){u.offset=w.offset;u.color=w.color}if(w.offset')}else if(d){e.push('')}else{var x=Math.max(this.arcScaleX_,this.arcScaleY_)*this.lineWidth;e.push('')}e.push('');this.element_.insertAdjacentHTML('beforeEnd',e.join(''))};F.fill=function(){this.stroke(true)};F.closePath=function(){this.currentPath_.push({type:'close'})};F.getCoords_=function(a,b){return{x:Z*(a*this.m_[0][0]+b*this.m_[1][0]+this.m_[2][0])-B,y:Z*(a*this.m_[0][1]+b*this.m_[1][1]+this.m_[2][1])-B}};function CanvasPattern_(){}G_vmlCMjrc=D})()}if(jQuery.browser.msie){document.execCommand("BackgroundImageCache",false,true)}(function($){var N=$.browser.msie;var O=N&&!window.XMLHttpRequest;var P=$.browser.opera;var Q=typeof document.createElement('canvas').getContext=="function";var R=function(i){return parseInt(i,10)||0};var S=function(a,b,c){var x=a,y;if(x.currentStyle){y=x.currentStyle[b]}else if(window.getComputedStyle){if(typeof arguments[2]=="string")b=c;y=document.defaultView.getComputedStyle(x,null).getPropertyValue(b)}return y};var T=function(a,p){return S(a,'border'+p+'Color','border-'+p.toLowerCase()+'-color')};var U=function(a,p){if(a.currentStyle&&!P){w=a.currentStyle['border'+p+'Width'];if(w=='thin')w=2;if(w=='medium'&&!(a.currentStyle['border'+p+'Style']=='none'))w=4;if(w=='thick')w=6}else{p=p.toLowerCase();w=document.defaultView.getComputedStyle(a,null).getPropertyValue('border-'+p+'-width')}return R(w)};var V=function(a,i){return a.tagName.toLowerCase()==i};var W=function(e,a,b,c,d){if(e=='tl')return a;if(e=='tr')return b;if(e=='bl')return c;if(e=='br')return d};var X=function(a,b,c,d,e,f,g){var h,curve_to;if(d.indexOf('rgba')!=-1){var i=/^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/;var j=i.exec(d);if(j){var k=[R(j[1]),R(j[2]),R(j[3])];d='rgb('+k[0]+', '+k[1]+', '+k[2]+')'}}var l=a.getContext('2d');if(b==1||g=='notch'){if(e>0&&b>1){l.fillStyle=f;l.fillRect(0,0,b,b);l.fillStyle=d;h=W(c,[0-e,0-e],[e,0-e],[0-e,e],[e,e]);l.fillRect(h[0],h[1],b,b)}else{l.fillStyle=d;l.fillRect(0,0,b,b)}return a}else if(g=='bevel'){h=W(c,[0,0,0,b,b,0,0,0],[0,0,b,b,b,0,0,0],[0,0,b,b,0,b,0,0],[b,b,b,0,0,b,b,b]);l.fillStyle=d;l.beginPath();l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);l.lineTo(h[4],h[5]);l.lineTo(h[6],h[7]);l.fill();if(e>0&&e0&&e'+p.html()+'');p.css('zoom','1');if(O){p.children(".JrcTdContainer").get(0).style.setExpression("height","this.parentNode.offsetHeight")}}p.children(".JrcTdContainer").append(a)}else{p.append(a)}};if(N){var ba=document.createStyleSheet();ba.media='print';ba.cssText='.jrcIECanvasDiv { display:none !important; }'}var bb=function(D){if(this.length==0||!(Q||N)){return this}if(D=="destroy"){return this.each(function(){var p,elm=$(this);if(elm.is(".jrcRounded")){if(typeof elm.data("ie6tmr.jrc")=='number')window.clearInterval(elm.data("ie6tmr.jrc"));if(elm.is("table"))p=elm.children("tbody").children("tr:first").children("td:first");else if(elm.is("td"))p=elm.children(".JrcTdContainer");else p=elm;p.children(".jrCorner").remove();elm.unbind('mouseleave.jrc').unbind('mouseenter.jrc').removeClass('jrcRounded').removeData('ie6tmr.jrc');if(elm.is("td"))elm.html(elm.children(".JrcTdContainer").html())}})}var o=(D||"").toLowerCase();var E=R((o.match(/(\d+)px/)||[])[1])||"auto";var F=((o.match(/(#[0-9a-f]+)/)||[])[1])||"auto";var G=/round|bevel|notch/;var H=((o.match(G)||['round'])[0]);var I=/hover/.test(o);var J=/oversized/.test(o);var K=o.match("hiddenparent");if(N){var G=/ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/;var L=((o.match(G)||['ie6fixinit'])[0])}var M={tl:/top|left|tl/.test(o),tr:/top|right|tr/.test(o),bl:/bottom|left|bl/.test(o),br:/bottom|right|br/.test(o)};if(!M.tl&&!M.tr&&!M.bl&&!M.br)M={tl:1,tr:1,bl:1,br:1};this.each(function(){var d=$(this),rbg=null,bg,s,b,pr;var a=this;var e=S(this,'display');var f=S(this,'position');var g=S(this,'lineHeight','line-height');if(F=="auto"){s=d.siblings(".jrcRounded:eq(0)");if(s.length>0){b=s.data("rbg.jrc");if(typeof b=="string"){rbg=b}}}if(K||rbg===null){var h=this.parentNode,hidden_parents=new Array(),a=0;while((typeof h=='object')&&!V(h,'html')){if(K&&S(h,'display')=='none'){hidden_parents.push({originalvisibility:S(h,'visibility'),elm:h});h.style.display='block';h.style.visibility='hidden'}var j=S(h,'backgroundColor','background-color');if(rbg===null&&j!="transparent"&&j!="rgba(0, 0, 0, 0)"){rbg=j}h=h.parentNode}if(rbg===null)rbg="#ffffff"}if(F=="auto"){bg=rbg;d.data("rbg.jrc",rbg)}else{bg=F}if(e=='none'){var k=S(this,'visibility');this.style.display='block';this.style.visibility='hidden';var l=true}else{var m=false}var n=d.height();var p=d.width();if(I){var q=o.replace(/hover|ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/g,"");if(L!='ie6nofix')q="ie6fixinit "+q;d.bind("mouseenter.jrc",function(){d.addClass('jrcHover');d.corner(q)});d.bind("mouseleave.jrc",function(){d.removeClass('jrcHover');d.corner(q)})}if(O&&L!='ie6nofix'){this.style.zoom=1;if(L!='ie6fixexpr'){if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}$(window).load(function(){if(L=='ie6fixonload'){if(d.css('height')=='auto')d.height(d.css('height'));if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}else if(L=='ie6fixwidthint'||L=='ie6fixheightint'||L=='ie6fixbothint'){var c,ie6FixFunction;if(L=='ie6fixheightint'){ie6FixFunction=function(){d.height('auto');var a=d.height();if(a%2!=0)a=a+1;d.css({height:a})}}else if(L=='ie6fixwidthint'){ie6FixFunction=function(){d.width('auto');var a=d.width();if(a%2!=0)a=a+1;d.css({width:a});d.data('lastWidth.jrc',d.get(0).offsetWidth)}}else if(L=='ie6fixbothint'){ie6FixFunction=function(){d.width('auto');d.height('auto');var a=d.width();var b=d.height();if(b%2!=0)b=b+1;if(a%2!=0)a=a+1;d.css({width:a,height:b})}}c=window.setInterval(ie6FixFunction,100);d.data("ie6tmr.jrc",c)}})}var r=n10)E=r/4}if(E>r/2&&!J){E=r/2}E=Math.floor(E);var t=U(this,'Top');var u=U(this,'Right');var v=U(this,'Bottom');var w=U(this,'Left');if(f=='static'&&!V(this,'td')){this.style.position='relative'}else if(f=='fixed'&&N&&!(document.compatMode=='CSS1Compat'&&!O)){this.style.position='absolute'}if(t+u+v+w>0){this.style.overflow='visible'}if(l)d.css({display:'none',visibility:k});if(typeof hidden_parents!="undefined"){for(var i=0;i0);if(y){if(V(this,'table'))pr=d.children("tbody").children("tr:first").children("td:first");else if(V(this,'td'))pr=d.children(".JrcTdContainer");else pr=d}if(M.tl){bordersWidth=t= 0 ) { + if ($.browser.safari && v == 'rgba(0, 0, 0, 0)') + continue; + var rgb = v.match(/\d+/g); + return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]); + } + if ( v && v != 'transparent' ) + return v; + } + return '#ffffff'; + }; + function getW(i) { + switch(fx) { + case 'round': return Math.round(width*(1-Math.cos(Math.asin(i/width)))); + case 'cool': return Math.round(width*(1+Math.cos(Math.asin(i/width)))); + case 'sharp': return Math.round(width*(1-Math.cos(Math.acos(i/width)))); + case 'bite': return Math.round(width*(Math.cos(Math.asin((width-i-1)/width)))); + case 'slide': return Math.round(width*(Math.atan2(i,width/i))); + case 'jut': return Math.round(width*(Math.atan2(width,(width-i-1)))); + case 'curl': return Math.round(width*(Math.atan(i))); + case 'tear': return Math.round(width*(Math.cos(i))); + case 'wicked': return Math.round(width*(Math.tan(i))); + case 'long': return Math.round(width*(Math.sqrt(i))); + case 'sculpt': return Math.round(width*(Math.log((width-i-1),width))); + case 'dog': return (i&1) ? (i+1) : width; + case 'dog2': return (i&2) ? (i+1) : width; + case 'dog3': return (i&3) ? (i+1) : width; + case 'fray': return (i%2)*width; + case 'notch': return width; + case 'bevel': return i+1; + } + }; + o = (o||"").toLowerCase(); + var keep = /keep/.test(o); // keep borders? + var cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]); // corner color + var sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]); // strip color + var width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10; // corner width + var re = /round|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dog/; + var fx = ((o.match(re)||['round'])[0]); + var edges = { T:0, B:1 }; + var opts = { + TL: /top|tl/.test(o), TR: /top|tr/.test(o), + BL: /bottom|bl/.test(o), BR: /bottom|br/.test(o) + }; + if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR ) + opts = { TL:1, TR:1, BL:1, BR:1 }; + var strip = document.createElement('div'); + strip.style.overflow = 'hidden'; + strip.style.height = '1px'; + strip.style.backgroundColor = sc || 'transparent'; + strip.style.borderStyle = 'solid'; + return this.each(function(index){ + var pad = { + T: parseInt($.css(this,'paddingTop'))||0, R: parseInt($.css(this,'paddingRight'))||0, + B: parseInt($.css(this,'paddingBottom'))||0, L: parseInt($.css(this,'paddingLeft'))||0 + }; + + if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' in IE + if (!keep) this.style.border = 'none'; + strip.style.borderColor = cc || gpc(this.parentNode); + var cssHeight = $.curCSS(this, 'height'); + + for (var j in edges) { + var bot = edges[j]; + // only add stips if needed + if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) { + strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none'); + var d = document.createElement('div'); + $(d).addClass('jquery-corner'); + var ds = d.style; + + bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild); + + if (bot && cssHeight != 'auto') { + if ($.css(this,'position') == 'static') + this.style.position = 'relative'; + ds.position = 'absolute'; + ds.bottom = ds.left = ds.padding = ds.margin = '0'; + if ($.browser.msie) + ds.setExpression('width', 'this.parentNode.offsetWidth'); + else + ds.width = '100%'; + } + else if (!bot && $.browser.msie) { + if ($.css(this,'position') == 'static') + this.style.position = 'relative'; + ds.position = 'absolute'; + ds.top = ds.left = ds.right = ds.padding = ds.margin = '0'; + + // fix ie6 problem when blocked element has a border width + var bw = 0; + if (ie6 || !$.boxModel) + bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth'); + ie6 ? ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"') : ds.width = '100%'; + } + else { + ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' : + (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px'; + } + + for (var i=0; i < width; i++) { + var w = Math.max(0,getW(i)); + var e = strip.cloneNode(false); + e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px'; + bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild); + } + } + } + }); +}; + +$.fn.uncorner = function(o) { return $('.jquery-corner', this).remove(); }; + +})(jQuery); diff -r e6ae125d5903 -r 17555e9b9854 web/request.py --- a/web/request.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/request.py Thu Feb 19 20:21:10 2009 +0100 @@ -201,7 +201,7 @@ def update_search_state(self): """update the current search state""" searchstate = self.form.get('__mode') - if not searchstate: + if not searchstate and self.cnx is not None: searchstate = self.get_session_data('search_state', 'normal') self.set_search_state(searchstate) @@ -212,7 +212,8 @@ else: self.search_state = ('linksearch', searchstate.split(':')) assert len(self.search_state[-1]) == 4 - self.set_session_data('search_state', searchstate) + if self.cnx is not None: + self.set_session_data('search_state', searchstate) def update_breadcrumbs(self): """stores the last visisted page in session data""" diff -r e6ae125d5903 -r 17555e9b9854 web/test/test_views.py --- a/web/test/test_views.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/test/test_views.py Thu Feb 19 20:21:10 2009 +0100 @@ -39,9 +39,9 @@ self.view('table', rset, template=None, displayfilter=True, displaycols=[0,2]) rset = self.execute('Any P,F,S LIMIT 1 WHERE P is EUser, P firstname F, P surname S') rset.req.form['rtype'] = 'firstname' - self.view('editrelation', rset, template=None, htmlcheck=False) + self.view('editrelation', rset, template=None) rset.req.form['rtype'] = 'use_email' - self.view('editrelation', rset, template=None, htmlcheck=False) + self.view('editrelation', rset, template=None) def test_sortable_js_added(self): diff -r e6ae125d5903 -r 17555e9b9854 web/test/unittest_viewselector.py --- a/web/test/unittest_viewselector.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/test/unittest_viewselector.py Thu Feb 19 20:21:10 2009 +0100 @@ -19,6 +19,7 @@ treeview, idownloadable, wdoc, debug) from cubicweb.entities.lib import Card from cubicweb.interfaces import IMileStone +from cubicweb.web.views import owl USERACTIONS = [('myprefs', actions.UserPreferencesAction), ('myinfos', actions.UserInfoAction), @@ -74,7 +75,7 @@ ('index', startup.IndexView), ('info', management.ProcessInformationView), ('manage', startup.ManageView), - ('owl', startup.OWLView), + ('owl', owl.OWLView), ('schema', startup.SchemaView), ('systemepropertiesform', management.SystemEpropertiesForm)]) # no entity but etype @@ -97,6 +98,7 @@ ('filetree', treeview.FileTreeView), ('list', baseviews.ListView), ('oneline', baseviews.OneLineView), + ('owlabox', owl.OWLABOXView), ('primary', baseviews.PrimaryView), ('rsetxml', baseviews.XMLRsetView), ('rss', baseviews.RssView), @@ -117,6 +119,7 @@ ('filetree', treeview.FileTreeView), ('list', baseviews.ListView), ('oneline', baseviews.OneLineView), + ('owlabox', owl.OWLABOXView), ('primary', baseviews.PrimaryView), ('rsetxml', baseviews.XMLRsetView), ('rss', baseviews.RssView), @@ -137,6 +140,7 @@ ('filetree', treeview.FileTreeView), ('list', baseviews.ListView), ('oneline', baseviews.OneLineView), + ('owlabox', owl.OWLABOXView), ('primary', baseviews.PrimaryView), ('rsetxml', baseviews.XMLRsetView), ('rss', baseviews.RssView), @@ -163,8 +167,10 @@ ('ecsvexport', baseviews.CSVEntityView), ('editable-table', tableview.EditableTableView), ('filetree', treeview.FileTreeView), + ('foaf', euser.FoafView), ('list', baseviews.ListView), ('oneline', baseviews.OneLineView), + ('owlabox', owl.OWLABOXView), ('primary', euser.EUserPrimaryView), ('rsetxml', baseviews.XMLRsetView), ('rss', baseviews.RssView), diff -r e6ae125d5903 -r 17555e9b9854 web/views/basecontrollers.py --- a/web/views/basecontrollers.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/basecontrollers.py Thu Feb 19 20:21:10 2009 +0100 @@ -60,7 +60,6 @@ def publish(self, rset=None): """publish a request, returning an encoded string""" - self.req.update_search_state() template = self.req.property_value('ui.main-template') if template not in self.vreg.registry('templates') : template = self.template @@ -453,7 +452,14 @@ # link the new entity to the main entity rql = 'SET F %(rel)s T WHERE F eid %(eid_to)s, T eid %(eid_from)s' % {'rel' : rel, 'eid_to' : eid_to, 'eid_from' : eid_from} return eid_from - + + def js_set_cookie(self, cookiename, cookievalue): + # XXX we should consider jQuery.Cookie + cookiename, cookievalue = str(cookiename), str(cookievalue) + cookies = self.req.get_cookie() + cookies[cookiename] = cookievalue + self.req.set_cookie(cookies, cookiename) + class SendMailController(Controller): id = 'sendmail' require_groups = ('managers', 'users') diff -r e6ae125d5903 -r 17555e9b9854 web/views/baseforms.py --- a/web/views/baseforms.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/baseforms.py Thu Feb 19 20:21:10 2009 +0100 @@ -2,7 +2,7 @@ or a list of entities of the same type :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" @@ -33,6 +33,9 @@ title = _('delete') domid = 'deleteconf' onsubmit = None + # don't use navigation, all entities asked to be deleted should be displayed + # else we will only delete the displayed page + need_navigation = False def call(self): """ask for confirmation before real deletion""" @@ -392,17 +395,20 @@ if rschema != 'eid'] def relations_form(self, entity, kwargs): + srels_by_cat = entity.srelations_by_category(('generic', 'metadata'), 'add') + if not srels_by_cat: + return u'' req = self.req _ = self.req._ label = u'%s :' % _('This %s' % entity.e_schema).capitalize() eid = entity.eid html = [] - pendings = list(self.restore_pending_inserts(entity)) w = html.append w(u'
') w(u'%s' % label) w(u'') for row in self.relations_table(entity): + # already linked entities if row[2]: w(u'' % row[0].display_name(req, row[1])) w(u'') w(u'') + pendings = list(self.restore_pending_inserts(entity)) if not pendings: w(u'') else: for row in pendings: + # soon to be linked to entities w(u'' % row[1]) w(u'' % row[3]) w(u'\n') @@ -419,7 +425,7 @@ req._(ChangeLogView.title).lower())) self.w(u'%s | ' % (req.build_url('doc/about'), req._('about this site'))) - self.w(u'© 2001-2008 Logilab S.A.') + self.w(u'© 2001-2009 Logilab S.A.') self.w(u'') diff -r e6ae125d5903 -r 17555e9b9854 web/views/baseviews.py --- a/web/views/baseviews.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/baseviews.py Thu Feb 19 20:21:10 2009 +0100 @@ -57,14 +57,14 @@ """ id = 'final' - def cell_call(self, row, col, props=None, displaytime=False): + def cell_call(self, row, col, props=None, displaytime=False, format='text/html'): etype = self.rset.description[row][col] value = self.rset.rows[row][col] if etype == 'String': entity, rtype = self.rset.related_entity(row, col) if entity is not None: # yes ! - self.w(entity.printable_value(rtype, value)) + self.w(entity.printable_value(rtype, value, format=format)) return if etype in ('Time', 'Interval'): _ = self.req._ @@ -639,7 +639,7 @@ row=rowindex, col=colindex) else: val = self.view('final', rset, displaytime=True, - row=rowindex, col=colindex) + row=rowindex, col=colindex, format='text/plain') w(simple_sgml_tag(tag, val, **attrs)) w(u' \n') w(u'\n' % self.xml_root) @@ -747,7 +747,8 @@ content = self.view('textincontext', rset, row=rowindex, col=colindex) else: - content = self.view('final', rset, displaytime=True, + content = self.view('final', rset, + displaytime=True, format='text/plain', row=rowindex, col=colindex) csvrow.append(content) writer.writerow(csvrow) @@ -800,7 +801,7 @@ rset, vid, divid, paginate = self.filter_box_context_info() self.w(u'
' % divid) self.pagination(self.req, rset, w=self.w) - self.wview(vid, rset) + self.wview(vid, rset, 'noresult') self.w(u'
') @cached @@ -862,13 +863,8 @@ assert rtype is not None, "rtype is mandatory for 'edirelation' view" targettype = self.req.form.get('targettype', targettype) role = self.req.form.get('role', role) - mode = entity.rtags.get_mode(rtype, targettype, role) - if mode == 'create': - return category = entity.rtags.get_category(rtype, targettype, role) - if category in ('generated', 'metadata'): - return - elif category in ('primary', 'secondary'): + if category in ('primary', 'secondary') or self.schema.rschema(rtype).is_final(): if hasattr(entity, '%s_format' % rtype): formatwdg = entity.get_widget('%s_format' % rtype, role) self.w(formatwdg.edit_render(entity)) @@ -879,10 +875,8 @@ self.w(u'%s %s %s' % (wdg.render_error(entity), wdg.edit_render(entity), wdg.render_help(entity),)) - elif category == 'generic': + else: self._render_generic_relation(entity, rtype, role) - else: - self.error("oops, wrong category %s", category) def _render_generic_relation(self, entity, relname, role): text = self.req.__('add %s %s %s' % (entity.e_schema, relname, role)) diff -r e6ae125d5903 -r 17555e9b9854 web/views/boxes.py --- a/web/views/boxes.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/boxes.py Thu Feb 19 20:21:10 2009 +0100 @@ -10,14 +10,14 @@ * startup views box :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" from logilab.mtconverter import html_escape -from cubicweb.common.selectors import (any_rset, appobject_selectable) +from cubicweb.common.selectors import any_rset, appobject_selectable from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, BoxHtml, RawBoxItem from cubicweb.web.box import BoxTemplate, ExtResourcesBoxTemplate @@ -175,17 +175,16 @@ def call(self, **kwargs): box = BoxWidget(self.req._(self.title), self.id) - actions = [v for v in self.vreg.possible_views(self.req, self.rset) - if v.category != 'startupview'] - for category, actions in self.sort_actions(actions): + views = [v for v in self.vreg.possible_views(self.req, self.rset) + if v.category != 'startupview'] + for category, views in self.sort_actions(views): menu = BoxMenu(category) - for action in actions: - menu.append(self.box_action(action)) + for view in views: + menu.append(self.box_action(view)) box.append(menu) if not box.is_empty(): box.render(self.w) - class RSSIconBox(ExtResourcesBoxTemplate): """just display the RSS icon on uniform result set""" @@ -203,23 +202,6 @@ self.w(u'rss\n' % (html_escape(url), rss)) -## warning("schemabox ne marche plus pour le moment") -## class SchemaBox(BoxTemplate): -## """display a box containing link to list of entities by type""" -## id = 'schema_box' -## visible = False # disabled by default -## title = _('entity list') -## order = 60 - -## def call(self, **kwargs): -## box = BoxWidget(self.req._(title), self.id) -## for etype in self.config.etypes(self.req.user, 'read'): -## view = self.vreg.select_view('list', self.req, self.etype_rset(etype)) -## box.append(self.mk_action(display_name(self.req, etype, 'plural'), -## view.url(), etype=etype)) -## if not box.is_empty(): -## box.render(self.w) - class StartupViewsBox(BoxTemplate): """display a box containing links to all startup views""" id = 'startup_views_box' diff -r e6ae125d5903 -r 17555e9b9854 web/views/euser.py --- a/web/views/euser.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/euser.py Thu Feb 19 20:21:10 2009 +0100 @@ -14,12 +14,6 @@ from cubicweb.web.form import EntityForm from cubicweb.web.views.baseviews import PrimaryView, EntityView -try: - from hashlib import sha1 as sha - -except ImportError: - from sha import sha - class EUserPrimaryView(PrimaryView): accepts = ('EUser',) skip_attrs = ('firstname', 'surname') @@ -38,7 +32,6 @@ return rschema.type in ['interested_in', 'tags', 'todo_by', 'bookmarked_by', ] - class FoafView(EntityView): id = 'foaf' accepts = ('EUser',) @@ -47,10 +40,10 @@ content_type = 'text/xml' def call(self): - self.w(u'\n' % self.req.encoding) - self.w(u'\n') + self.w(''' + '''% self.req.encoding) for i in xrange(self.rset.rowcount): self.cell_call(i, 0) self.w(u'\n') @@ -72,10 +65,15 @@ % html_escape(entity.firstname)) emailaddr = entity.get_email() if emailaddr: - self.w(u'%s\n' % html_escape(unicode(emailaddr))) - self.w(u'\n') + self.w(u'%s\n' % html_escape(emailaddr)) + self.w(u'\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""" diff -r e6ae125d5903 -r 17555e9b9854 web/views/facets.py --- a/web/views/facets.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/facets.py Thu Feb 19 20:21:10 2009 +0100 @@ -1,7 +1,7 @@ """the facets box and some basic facets :organization: Logilab -:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" diff -r e6ae125d5903 -r 17555e9b9854 web/views/linkedData.py --- a/web/views/linkedData.py Thu Feb 19 20:19:05 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -from logilab.mtconverter import html_escape - -from cubicweb.common.view import EntityView - -from urlparse import urlparse - -class LinkedDataProjectView(EntityView): - id = 'project_linked_data' - title = _('Project linked data') - accepts = ('Project',) - templatable = False - content_type = 'text/xml' - - def call(self): - '''display all project attribut and project dependencies and external project (in doap format) if - it is related to''' - - self.w(u'\n' % self.req.encoding) - self.w(u'''\n''') - for i in xrange(self.rset.rowcount): - self.cell_call(row=i, col=0) - self.w(u'\n') - - def cell_call(self, row, col): - self.wview('project_linked_data_item', self.rset, row=row, col=col) - -class LinkedDataProjectItemView(EntityView): - id = 'project_linked_data_item' - accepts = ('Project',) - - def cell_call(self, row, col): - entity = self.complete_entity(row, col) - self.w(u'\n' % html_escape(entity.absolute_url())) - self.w(u' %s\n' % html_escape(unicode(entity.dc_title()))) - self.w(u' %s\n' % (entity.creation_date.strftime('%Y-%m-%d'))) - self.w(u' %s\n' % html_escape(unicode(entity.summary))) - self.w(u' %s\n' % html_escape(unicode(entity.description))) - self.w(u' %s\n' % html_escape(entity.url or entity.absolute_url())) - if entity.modification_date: - self.w(u'%s\n'% (entity.modification_date.strftime('%Y-%m-%d'))) - if entity.vcsurl: - self.w(u''' - - ''' % html_escape(entity.vcsurl)) - if entity.reporturl: - self.w(u'"%s"' % html_escape(entity.vcsurl)) - - if entity.downloadurl: - self.w(u' %s\n' % html_escape(entity.downloadurl)) - liste = urlparse(entity.absolute_url()) - internal_address = liste[1] - for externalproject in entity.uses: - self.w(u'\n') - if externalproject.e_schema == 'ExtProject': - if externalproject.absolute_url().find(internal_address) > 0: - self.w(u'') - self.w(u' %s'% externalproject.absolute_url()) - else: - self.w(u'%s'% externalproject.absolute_url()) - self.w(u'\n') - for externalproject in entity.recommends: - self.w(u'\n') - if externalproject.e_schema == 'ExtProject': - if externalproject.absolute_url().find(internal_address) > 0: - self.w(u'') - self.w(u'%s'% externalproject.absolute_url()) - else: - self.w(u'%s'% externalproject.absolute_url()) - self.w(u'%s'% externalproject.absolute_url()) - - self.w(u'\n') - - diff -r e6ae125d5903 -r 17555e9b9854 web/views/management.py --- a/web/views/management.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/management.py Thu Feb 19 20:21:10 2009 +0100 @@ -13,17 +13,16 @@ from cubicweb.common.utils import UStringIO from cubicweb.common.view import AnyRsetView, StartupView, EntityView -from cubicweb.common.uilib import (html_traceback, rest_traceback, html_escape, - toggle_link) +from cubicweb.common.uilib import html_traceback, rest_traceback from cubicweb.common.selectors import (yes, one_line_rset, - accept_rset, none_rset, - chainfirst, chainall) + accept_rset, none_rset, + chainfirst, chainall) from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, stdmsgs from cubicweb.web.widgets import StaticComboBoxWidget from cubicweb.web.form import FormMixIn _ = unicode - + def begin_form(w, entity, redirectvid, redirectpath=None, msg=None): w(u'
\n' % entity.req.build_url('edit')) w(u'
\n') @@ -42,10 +41,10 @@ """display security information for a given entity""" id = 'security' title = _('security') - + def cell_call(self, row, col): - self.req.add_js('cubicweb.edition.js') - self.req.add_css('cubicweb.acl.css') + self.req.add_js('cubicweb.edition.js') + self.req.add_css('cubicweb.acl.css') entity = self.entity(row, col) w = self.w _ = self.req._ @@ -90,7 +89,7 @@ w(u'
' % u'
'.join(expr.expression for expr in rqlexprs)) w(u'\n') w(u'
%s') @@ -415,10 +421,12 @@ w(u'') w(u'
  
%s') @@ -434,7 +442,8 @@ w(u'') w(u'') diff -r e6ae125d5903 -r 17555e9b9854 web/views/basetemplates.py --- a/web/views/basetemplates.py Thu Feb 19 20:19:05 2009 +0100 +++ b/web/views/basetemplates.py Thu Feb 19 20:21:10 2009 +0100 @@ -2,16 +2,18 @@ """default templates for CubicWeb web client :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" + from logilab.mtconverter import html_escape from cubicweb import NoSelectableObject, ObjectNotFound from cubicweb.common.view import Template, MainTemplate, NOINDEX, NOFOLLOW from cubicweb.common.utils import make_uid +from cubicweb.common.utils import UStringIO from cubicweb.web.views.baseviews import vid_from_rset @@ -163,7 +165,10 @@ self.req, self.rset) if etypefilter and etypefilter.propval('visible'): etypefilter.dispatch(w=self.w) - self.pagination(self.req, self.rset, self.w, not (view and view.need_navigation)) + self.nav_html = UStringIO() + self.pagination(self.req, self.rset, self.nav_html.write, + not (view and view.need_navigation)) + self.w(_(self.nav_html.getvalue())) self.w(u'
\n') def template_html_header(self, content_type, page_title, additional_headers=()): @@ -199,6 +204,7 @@ def template_footer(self, view=None): self.w(u'
\n') # close id=contentmain + self.w(_(self.nav_html.getvalue())) self.w(u'\n') # closes id=pageContent self.content_footer(view) self.w(u'
%s
') - + def owned_by_edit_form(self, entity): self.w('

%s

' % self.req._('ownership')) begin_form(self.w, entity, 'security', msg= _('ownerships have been changed')) @@ -169,7 +168,7 @@ wdg = newperm.get_widget('label') w(u'%s\n' % wdg.edit_render(newperm)) wdg = newperm.get_widget('require_group') - w(u'%s\n' % wdg.edit_render(newperm)) + w(u'%s\n' % wdg.edit_render(newperm)) w(u'%s\n' % self.button_ok()) w(u'') w(u'
\n') @@ -178,12 +177,12 @@ return (u'' % self.req._(stdmsgs.BUTTON_OK)) - + class ErrorView(AnyRsetView): """default view when no result has been found""" __selectors__ = (yes,) id = 'error' - + def page_title(self): """returns a title according to the result set - used for the title in the HTML header @@ -192,11 +191,11 @@ def call(self): req = self.req.reset_headers() - _ = req._ + _ = req._; w = self.w ex = req.data.get('ex')#_("unable to find exception information")) excinfo = req.data.get('excinfo') title = _('an error occured') - self.w(u'

%s

' % title) + w(u'

%s

' % title) if 'errmsg' in req.data: ex = req.data['errmsg'] exclass = None @@ -205,53 +204,53 @@ ex = exc_message(ex, req.encoding) if excinfo is not None and self.config['print-traceback']: if exclass is None: - self.w(u'
%s
' + w(u'
%s
' % html_escape(ex).replace("\n","
")) else: - self.w(u'
%s: %s
' + w(u'
%s: %s
' % (exclass, html_escape(ex).replace("\n","
"))) - self.w(u'
') - self.w(u'
%s
' % html_traceback(excinfo, ex, '')) + w(u'
') + w(u'
%s
' % html_traceback(excinfo, ex, '')) else: - self.w(u'
%s
' % (html_escape(ex).replace("\n","
"))) + w(u'
%s
' % (html_escape(ex).replace("\n","
"))) # if excinfo is not None, it's probably not a bug if excinfo is None: return vcconf = self.config.vc_config() - self.w(u"
") + w(u"
") eversion = vcconf.get('cubicweb', _('no version information')) # NOTE: tuple wrapping needed since eversion is itself a tuple - self.w(u"CubicWeb version: %s
\n" % (eversion,)) + w(u"CubicWeb version: %s
\n" % (eversion,)) for pkg in self.config.cubes(): pkgversion = vcconf.get(pkg, _('no version information')) - self.w(u"Package %s version: %s
\n" % (pkg, pkgversion)) - self.w(u"
") + w(u"Package %s version: %s
\n" % (pkg, pkgversion)) + w(u"
") # creates a bug submission link if SUBMIT_URL is set submiturl = self.config['submit-url'] if submiturl: binfo = text_error_description(ex, excinfo, req, eversion, [(pkg, vcconf.get(pkg, _('no version information'))) for pkg in self.config.cubes()]) - self.w(u'
\n' % html_escape(submiturl)) - self.w(u'
\n') - self.w(u'' % html_escape(binfo)) - self.w(u'') - self.w(u'') - self.w(u'' % _('Submit bug report')) - self.w(u'
\n') - self.w(u'
\n') + w(u'
\n' % html_escape(submiturl)) + w(u'
\n') + w(u'' % html_escape(binfo)) + w(u'') + w(u'') + w(u'' % _('Submit bug report')) + w(u'
\n') + w(u'
\n') submitmail = self.config['submit-mail'] if submitmail: binfo = text_error_description(ex, excinfo, req, eversion, [(pkg, vcconf.get(pkg, _('no version information'))) for pkg in self.config.cubes()]) - self.w(u'
\n' % req.build_url('reportbug')) - self.w(u'
\n') - self.w(u'' % html_escape(binfo)) - self.w(u'') - self.w(u'' % _('Submit bug report by mail')) - self.w(u'
\n') - self.w(u'
\n') + w(u'
\n' % req.build_url('reportbug')) + w(u'
\n') + w(u'' % html_escape(binfo)) + w(u'') + w(u'' % _('Submit bug report by mail')) + w(u'
\n') + w(u'
\n') def exc_message(ex, encoding): @@ -262,7 +261,7 @@ return unicode(str(ex), encoding, 'replace') except: return unicode(repr(ex), encoding, 'replace') - + def text_error_description(ex, excinfo, req, eversion, cubes): binfo = rest_traceback(excinfo, html_escape(ex)) binfo += u'\n\n:URL: %s\n' % req.url() @@ -284,23 +283,48 @@ _('components') _('contentnavigation') + +def make_togglable_link(nodeid, label, cookiename): + """builds a HTML link that switches the visibility & remembers it""" + action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \ + (nodeid, cookiename) + return u'%s' % (action, label) + +def css_class(someclass): + return someclass and 'class="%s"' % someclass or '' + class SystemEpropertiesForm(FormMixIn, StartupView): controller = 'edit' id = 'systemepropertiesform' title = _('site configuration') require_groups = ('managers',) category = 'startupview' - + def linkable(self): return True - + def url(self): """return the url associated with this view. We can omit rql here""" return self.build_url('view', vid=self.id) - + + def _cookie_name(self, somestr): + return str('%s_property_%s' % (self.config.appid, somestr)) + + def _group_status(self, group, default=u'hidden'): + cookies = self.req.get_cookie() + cookiename = self._cookie_name(group) + cookie = cookies.get(cookiename) + if cookie is None: + cookies[cookiename] = default + self.req.set_cookie(cookies, cookiename, maxage=None) + status = default + else: + status = cookie.value + return status + def call(self, **kwargs): """The default view representing the application's index""" - self.req.add_js('cubicweb.edition.js') + self.req.add_js(('cubicweb.edition.js', 'cubicweb.preferences.js')) self.req.add_css('cubicweb.preferences.css') vreg = self.vreg values = self.defined_keys @@ -322,7 +346,7 @@ for group, objects in groupedopts.items(): for oid, keys in objects.items(): groupedopts[group][oid] = self.form(keys, True) - + w = self.w req = self.req _ = req._ @@ -330,17 +354,21 @@ w(self.error_message()) for label, group, form in sorted((_(g), g, f) for g, f in mainopts.iteritems()): + status = css_class(self._group_status(group)) #'hidden' (collapsed), or '' (open) ? w(u'

%s

\n' % - (toggle_link('fieldset_' + group, label))) - w(u'