backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 02 Aug 2010 15:37:45 +0200
changeset 6055 bb7bd9cafacf
parent 6047 ee6deb534f57 (current diff)
parent 6054 1ab6978b72b8 (diff)
child 6066 953578709324
backport stable
--- a/.hgtags	Fri Jul 30 13:18:36 2010 +0200
+++ b/.hgtags	Mon Aug 02 15:37:45 2010 +0200
@@ -145,3 +145,5 @@
 8a23821dc1383e14a7e92a931b91bc6eed4d0af7 cubicweb-debian-version-3.9.2-1
 900772fd9caaf068eb2fdd4544b03efec91901e6 cubicweb-version-3.9.3
 ab1f9686ff3e0843b570b98f89fb5ccc8d7dec8c cubicweb-debian-version-3.9.3-1
+6cebb361dcb27ded654426b4c82f6401c862e034 cubicweb-version-3.9.4
+8d32d82134dc1d8eb0ce230191f34fd49084a168 cubicweb-debian-version-3.9.4-1
--- a/__pkginfo__.py	Fri Jul 30 13:18:36 2010 +0200
+++ b/__pkginfo__.py	Mon Aug 02 15:37:45 2010 +0200
@@ -22,7 +22,7 @@
 
 modname = distname = "cubicweb"
 
-numversion = (3, 9, 3)
+numversion = (3, 9, 4)
 version = '.'.join(str(num) for num in numversion)
 
 description = "a repository of entities / relations for knowledge management"
--- a/debian/changelog	Fri Jul 30 13:18:36 2010 +0200
+++ b/debian/changelog	Mon Aug 02 15:37:45 2010 +0200
@@ -1,3 +1,9 @@
+cubicweb (3.9.4-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Mon, 02 Aug 2010 14:25:38 +0200
+
 cubicweb (3.9.3-1) unstable; urgency=low
 
   * new upstream release
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/coding_standards_css.rst	Mon Aug 02 15:37:45 2010 +0200
@@ -0,0 +1,33 @@
+CSS Coding Standards
+--------------------
+
+(Draft, to be continued)
+
+:Naming: camelCase
+
+Indentation rules
+~~~~~~~~~~~~~~~~~
+- 2 espaces avant les propriétés
+
+- pas d'espace avant les ":", un espace après
+
+- 1 seul espace entre les différentes valeurs pour une même propriété
+
+
+Documentation
+~~~~~~~~~~~~~
+Please keep rules semantically linked grouped together, with a comment about
+what they are for.
+
+Recommendation
+~~~~~~~~~~~~~~
+- Try to use existing classes rather than introduce new ones
+
+- Keep things as simple as possible while in the framework
+
+- Think about later customization by application
+
+- Avoid introducing a new CSS file for a few lines of CSS, at least while the
+  framework doesn't include packing functionalities
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/coding_standards_js.rst	Mon Aug 02 15:37:45 2010 +0200
@@ -0,0 +1,37 @@
+Javascript Coding Standards
+---------------------------
+
+(Draft, to be continued)
+
+:Naming: camelCase, except for CONSTANTS
+
+Indentation rules
+~~~~~~~~~~~~~~~~~
+- espace avant accolade ouvrante
+
+- retour à la ligne après accolade ouvrante (éventuellement pas
+  de retour à la ligne s'il y a tout sur la même ligne, mais ce n'est
+  pas le cas ici.
+
+- no tabs
+
+
+Documentation
+~~~~~~~~~~~~~
+XXX explain comment format for documentation generation
+
+
+Coding
+~~~~~~
+- Don't forget 'var' before variable definition, and semi-colon (';') after **each** statement.
+- Check the firebug console for deprecation warnings
+
+
+API usage
+~~~~~~~~~
+- unless intended, use jQuery('container') rather than jqNode('container')
+
+
+See also
+~~~~~~~~
+http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
\ No newline at end of file
--- a/i18n/en.po	Fri Jul 30 13:18:36 2010 +0200
+++ b/i18n/en.po	Mon Aug 02 15:37:45 2010 +0200
@@ -534,7 +534,7 @@
 msgid "OR"
 msgstr ""
 
-msgid "Parent classes:"
+msgid "Parent class:"
 msgstr ""
 
 msgid "Password"
@@ -1486,6 +1486,9 @@
 msgid "context where this component should be displayed"
 msgstr ""
 
+msgid "context where this facet should be displayed, leave empty for both"
+msgstr ""
+
 msgid "control subject entity's relations order"
 msgstr ""
 
@@ -1966,12 +1969,18 @@
 msgid "display order of the component"
 msgstr ""
 
+msgid "display order of the facet"
+msgstr ""
+
 msgid "display the box or not"
 msgstr ""
 
 msgid "display the component or not"
 msgstr ""
 
+msgid "display the facet or not"
+msgstr ""
+
 msgid ""
 "distinct label to distinguate between other permission entity of the same "
 "name"
@@ -2017,6 +2026,9 @@
 msgid "embed"
 msgstr ""
 
+msgid "embedded html"
+msgstr ""
+
 msgid "embedding this url is forbidden"
 msgstr ""
 
--- a/i18n/es.po	Fri Jul 30 13:18:36 2010 +0200
+++ b/i18n/es.po	Mon Aug 02 15:37:45 2010 +0200
@@ -542,7 +542,7 @@
 msgid "OR"
 msgstr "O"
 
-msgid "Parent classes:"
+msgid "Parent class:"
 msgstr ""
 
 msgid "Password"
@@ -1519,6 +1519,9 @@
 msgid "context where this component should be displayed"
 msgstr "Contexto en el cual el componente debe aparecer en el sistema"
 
+msgid "context where this facet should be displayed, leave empty for both"
+msgstr ""
+
 msgid "control subject entity's relations order"
 msgstr "Controla el orden de relaciones de la entidad sujeto"
 
@@ -2009,12 +2012,18 @@
 msgid "display order of the component"
 msgstr "Orden de aparición del componente"
 
+msgid "display order of the facet"
+msgstr ""
+
 msgid "display the box or not"
 msgstr "Mostrar la caja o no"
 
 msgid "display the component or not"
 msgstr "Mostrar el componente o no"
 
+msgid "display the facet or not"
+msgstr ""
+
 msgid ""
 "distinct label to distinguate between other permission entity of the same "
 "name"
@@ -2062,6 +2071,9 @@
 msgid "embed"
 msgstr "Incrustrado"
 
+msgid "embedded html"
+msgstr ""
+
 msgid "embedding this url is forbidden"
 msgstr "La inclusión de este url esta prohibida"
 
--- a/i18n/fr.po	Fri Jul 30 13:18:36 2010 +0200
+++ b/i18n/fr.po	Mon Aug 02 15:37:45 2010 +0200
@@ -553,8 +553,8 @@
 msgid "OR"
 msgstr "OU"
 
-msgid "Parent classes:"
-msgstr "Classes parentes :"
+msgid "Parent class:"
+msgstr "Classe parente"
 
 msgid "Password"
 msgstr "Mot de passe"
@@ -1540,6 +1540,9 @@
 msgid "context where this component should be displayed"
 msgstr "contexte où ce composant doit être affiché"
 
+msgid "context where this facet should be displayed, leave empty for both"
+msgstr ""
+
 msgid "control subject entity's relations order"
 msgstr "contrôle l'ordre des relations de l'entité sujet"
 
@@ -2044,12 +2047,18 @@
 msgid "display order of the component"
 msgstr "ordre d'affichage du composant"
 
+msgid "display order of the facet"
+msgstr "ordre d'affichage de la facette"
+
 msgid "display the box or not"
 msgstr "afficher la boîte ou non"
 
 msgid "display the component or not"
 msgstr "afficher le composant ou non"
 
+msgid "display the facet or not"
+msgstr "afficher la facette ou non"
+
 msgid ""
 "distinct label to distinguate between other permission entity of the same "
 "name"
@@ -2097,6 +2106,9 @@
 msgid "embed"
 msgstr "embarqué"
 
+msgid "embedded html"
+msgstr "HTML contenu"
+
 msgid "embedding this url is forbidden"
 msgstr "l'inclusion de cette url est interdite"
 
--- a/server/sources/rql2sql.py	Fri Jul 30 13:18:36 2010 +0200
+++ b/server/sources/rql2sql.py	Mon Aug 02 15:37:45 2010 +0200
@@ -101,15 +101,12 @@
     subquery. This function check this and rewrite the rql syntax tree if
     necessary (in place). Return a boolean telling if the tree has been modified
     """
-    torewrite = set()
     modified = False
     for varname in tuple(unstable):
         var = select.defined_vars[varname]
         if not var.stinfo.get('optrelations'):
             continue
-        modified = True
         unstable.remove(varname)
-        torewrite.add(var)
         newselect = Select()
         newselect.need_distinct = False
         myunion = Union()
@@ -139,10 +136,17 @@
                 var.stinfo['rhsrelations'].add(newrel)
                 if rel.optional in ('right', 'both'):
                     var.add_optional_relation(newrel)
+        if not select.where and not modified:
+            # oops, generated the same thing as the original select....
+            # restore original query, else we'll indefinitly loop
+            for var, rel in towrap_rels:
+                select.add_restriction(rel)
+            continue
+        modified = True
         # extract subquery solutions
         mysolutions = [sol.copy() for sol in solutions]
         cleanup_solutions(newselect, mysolutions)
-        newselect.set_possible_types(solutions)
+        newselect.set_possible_types(mysolutions)
         # full sub-query
         aliases = [VariableRef(select.get_variable(avar.name, i))
                    for i, avar in enumerate(newselect.selection)]
--- a/server/test/unittest_querier.py	Fri Jul 30 13:18:36 2010 +0200
+++ b/server/test/unittest_querier.py	Mon Aug 02 15:37:45 2010 +0200
@@ -836,7 +836,7 @@
         rset = self.execute('Any X, NOW - CD WHERE X is Personne, X creation_date CD')
         self.failUnlessEqual(rset.description[0][1], 'Interval')
 
-    def test_select_subquery_aggregat(self):
+    def test_select_subquery_aggregat_1(self):
         # percent users by groups
         self.execute('SET X in_group G WHERE G name "users"')
         rset = self.execute('Any GN, COUNT(X)*100/T GROUPBY GN ORDERBY 2,1'
@@ -845,6 +845,17 @@
         self.assertEquals(rset.rows, [[u'guests', 50], [u'managers', 50], [u'users', 100]])
         self.assertEquals(rset.description, [('String', 'Int'), ('String', 'Int'), ('String', 'Int')])
 
+    def test_select_subquery_aggregat_2(self):
+        expected = self.execute('Any X, 0, COUNT(T) GROUPBY X '
+                                'WHERE X is Workflow, T transition_of X').rows
+        rset = self.execute('''
+Any P1,B,E WHERE P1 identity P2 WITH
+  P1,B BEING (Any P,COUNT(T) GROUPBY P WHERE P is Workflow, T is Transition,
+              T? transition_of P, T type "auto"),
+  P2,E BEING (Any P,COUNT(T) GROUPBY P WHERE P is Workflow, T is Transition,
+              T? transition_of P, T type "normal")''')
+        self.assertEquals(sorted(rset.rows), sorted(expected))
+
     def test_select_subquery_const(self):
         rset = self.execute('Any X WITH X BEING ((Any NULL) UNION (Any "toto"))')
         self.assertEquals(rset.rows, [[None], ['toto']])
--- a/tags.py	Fri Jul 30 13:18:36 2010 +0200
+++ b/tags.py	Mon Aug 02 15:37:45 2010 +0200
@@ -48,6 +48,7 @@
 tr = tag('tr')
 th = tag('th')
 td = tag('td')
+iframe = tag('iframe')
 
 def select(name, id=None, multiple=False, options=[], **attrs):
     if multiple:
--- a/web/test/unittest_viewselector.py	Fri Jul 30 13:18:36 2010 +0200
+++ b/web/test/unittest_viewselector.py	Mon Aug 02 15:37:45 2010 +0200
@@ -418,17 +418,27 @@
 
     def test_score_entity_selector(self):
         image = self.request().create_entity('File', data_name=u'bim.png', data=Binary('bim'))
-        # image primary view priority
+        # image/ehtml primary view priority
         req = self.request()
         rset = req.execute('File X WHERE X data_name "bim.png"')
         self.assertIsInstance(self.vreg['views'].select('image', req, rset=rset),
                               idownloadable.ImageView)
-        fileobj = self.request().create_entity('File', data_name=u'bim.txt', data=Binary('bim'))
-        # image primary view priority
+        self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'ehtml', req, rset=rset)
+
+        fileobj = self.request().create_entity('File', data_name=u'bim.html', data=Binary('<html>bam</html'))
+        # image/ehtml primary view priority
+        req = self.request()
+        rset = req.execute('File X WHERE X data_name "bim.html"')
+        self.assertIsInstance(self.vreg['views'].select('ehtml', req, rset=rset),
+                              idownloadable.EHTMLView)
+        self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'image', req, rset=rset)
+
+        fileobj = self.request().create_entity('File', data_name=u'bim.txt', data=Binary('boum'))
+        # image/ehtml primary view priority
         req = self.request()
         rset = req.execute('File X WHERE X data_name "bim.txt"')
         self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'image', req, rset=rset)
-
+        self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'ehtml', req, rset=rset)
 
 
     def _test_view(self, vid, rql, args):
--- a/web/views/idownloadable.py	Fri Jul 30 13:18:36 2010 +0200
+++ b/web/views/idownloadable.py	Mon Aug 02 15:37:45 2010 +0200
@@ -121,6 +121,10 @@
             self.wview('image', entity.cw_rset, row=entity.cw_row, col=entity.cw_col,
                        link=True, klass='contentimage')
             super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
+        elif contenttype.endswith('html'):
+            self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
+            self.wview('ehtml', entity.cw_rset, row=entity.cw_row, col=entity.cw_col,
+                       height='600px', width='100%')
         else:
             super(IDownloadablePrimaryView, self).render_entity_attributes(entity)
             self.wview('downloadlink', entity.cw_rset, title=self._cw._('download'), row=entity.cw_row)
@@ -156,11 +160,10 @@
                (url, name, durl, self._cw._('download')))
 
 
-class ImageView(EntityView):
-    __regid__ = 'image'
-    __select__ = has_mimetype('image/')
+class AbstractEmbeddedView(EntityView):
+    __abstract__ = True
 
-    title = _('image')
+    _embedding_tag = None
 
     def call(self, **kwargs):
         rset = self.cw_rset
@@ -172,13 +175,29 @@
     def cell_call(self, row, col, link=False, **kwargs):
         entity = self.cw_rset.get_entity(row, col)
         adapter = entity.cw_adapt_to('IDownloadable')
-        imgtag = tags.img(src=adapter.download_url(),
-                          alt=(self._cw._('download %s') % adapter.download_file_name()),
-                          **kwargs)
+        tag = self._embedding_tag(src=adapter.download_url(),
+                                  alt=(self._cw._('download %s') % adapter.download_file_name()),
+                                  **kwargs)
         if link:
-            self.w(u'<a href="%s">%s</a>' % (entity.absolute_url(vid='download'),
-                                             imgtag))
+            self.w(u'<a href="%s">%s</a>' % (adapter.download_url(), tag))
         else:
-            self.w(imgtag)
+            self.w(tag)
 
 
+class ImageView(AbstractEmbeddedView):
+    __regid__ = 'image'
+    __select__ = has_mimetype('image/')
+
+    title = _('image')
+    _embedding_tag = tags.img
+
+
+class EHTMLView(AbstractEmbeddedView):
+    __regid__ = 'ehtml'
+    __select__ = has_mimetype('text/html')
+
+    title = _('embedded html')
+    _embedding_tag = tags.iframe
+
+
+