merge stable
authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
Tue, 23 Jun 2009 08:44:42 +0200
branchstable
changeset 2134 9a649393e2ef
parent 2131 00e6d1cb18ea (diff)
parent 2133 c3beb65d884d (current diff)
child 2135 55fc8b488907
merge
--- a/common/migration.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/common/migration.py	Tue Jun 23 08:44:42 2009 +0200
@@ -17,6 +17,8 @@
 from logilab.common.decorators import cached
 from logilab.common.configuration import REQUIRED, read_old_config
 
+from cubicweb import ConfigurationError
+
 
 def migration_files(config, toupgrade):
     """return an orderer list of path of scripts to execute to upgrade
@@ -328,18 +330,18 @@
             self.config.add_cubes(newcubes)
         return newcubes
 
-    def cmd_remove_cube(self, cube):
+    def cmd_remove_cube(self, cube, removedeps=False):
+        if removedeps:
+            toremove = self.config.expand_cubes([cube])
+        else:
+            toremove = (cube,)
         origcubes = self.config._cubes
-        basecubes = list(origcubes)
-        for pkg in self.config.expand_cubes([cube]):
-            try:
-                basecubes.remove(pkg)
-            except ValueError:
-                continue
+        basecubes = [c for c in origcubes if not c in toremove]
         self.config._cubes = tuple(self.config.expand_cubes(basecubes))
         removed = [p for p in origcubes if not p in self.config._cubes]
-        assert cube in removed, \
-               "can't remove cube %s, used as a dependancy" % cube
+        if not cube in removed:
+            raise ConfigurationError("can't remove cube %s, "
+                                     "used as a dependency" % cube)
         return removed
 
     def rewrite_configuration(self):
--- a/common/mixins.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/common/mixins.py	Tue Jun 23 08:44:42 2009 +0200
@@ -191,11 +191,18 @@
             return rset.get_entity(0, 0)
         return None
 
-    def change_state(self, stateeid, trcomment=None, trcommentformat=None):
+    def change_state(self, state, trcomment=None, trcommentformat=None):
         """change the entity's state according to a state defined in given
         parameters
         """
-        assert not isinstance(stateeid, basestring), 'change_state wants a state eid'
+        if isinstance(state, basestring):
+            state = self.wf_state(state)
+            assert state is not None, 'not a %s state: %s' % (self.id, state)
+        if hasattr(state, 'eid'):
+            stateeid = state.eid
+        else:
+            stateeid = state
+        stateeid = typed_eid(stateeid)
         if trcomment:
             self.req.set_shared_data('trcomment', trcomment)
         if trcommentformat:
--- a/devtools/fill.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/devtools/fill.py	Tue Jun 23 08:44:42 2009 +0200
@@ -10,7 +10,7 @@
 
 from random import randint, choice
 from copy import deepcopy
-from datetime import datetime, date, timedelta
+from datetime import datetime, date, time#timedelta
 from decimal import Decimal
 
 from yams.constraints import (SizeConstraint, StaticVocabularyConstraint,
@@ -163,7 +163,7 @@
 
     def generate_time(self, attrname, index):
         """generates a random time (format is ' HH:MM')"""
-        return timedelta(0, 11, index%60) #'11:%02d' % (index % 60)
+        return time(11, index%60) #'11:%02d' % (index % 60)
 
     def generate_datetime(self, attrname, index):
         """generates a random date (format is 'yyyy-mm-dd HH:MM')"""
--- a/entity.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/entity.py	Tue Jun 23 08:44:42 2009 +0200
@@ -398,7 +398,7 @@
         path = etype.lower()
         if mainattr != 'eid':
             value = getattr(self, mainattr)
-            if value is None:
+            if value is None or unicode(value) == u'':
                 mainattr = 'eid'
                 path += '/eid'
             elif needcheck:
--- a/server/migractions.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/server/migractions.py	Tue Jun 23 08:44:42 2009 +0200
@@ -523,8 +523,9 @@
             self.exec_event_script('postcreate', self.config.cube_dir(pack))
             self.commit()
 
-    def cmd_remove_cube(self, cube):
-        removedcubes = super(ServerMigrationHelper, self).cmd_remove_cube(cube)
+    def cmd_remove_cube(self, cube, removedeps=False):
+        removedcubes = super(ServerMigrationHelper, self).cmd_remove_cube(
+            cube, removedeps)
         if not removedcubes:
             return
         fsschema = self.fs_schema
--- a/server/msplanner.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/server/msplanner.py	Tue Jun 23 08:44:42 2009 +0200
@@ -361,7 +361,7 @@
                         self._set_source_for_term(source, const)
                         # if system source is used, add every rewritten constant
                         # to its supported terms even when associated entity
-                        # doesn't actually comes from it so we get a changes
+                        # doesn't actually come from it so we get a changes
                         # that allequals will return True as expected when
                         # computing needsplit
                         # check const is used in a relation restriction
@@ -555,7 +555,12 @@
             self.needsplit = False
         elif not self.needsplit:
             if not allequals(self._sourcesterms.itervalues()):
-                self.needsplit = True
+                for terms in self._sourcesterms.itervalues():
+                    if any(x for x in terms if not isinstance(x, Constant)):
+                        self.needsplit = True
+                        return
+                self._sourcesterms = {self.system_source: {}}
+                self.needsplit = False
             else:
                 sample = self._sourcesterms.itervalues().next()
                 if len(sample) > 1:
--- a/server/schemaserial.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/server/schemaserial.py	Tue Jun 23 08:44:42 2009 +0200
@@ -109,7 +109,7 @@
                                                        ETYPE_NAME_MAP[etype])
                 print sql
                 sqlcu.execute(sql)
-        # other table renaming done once schema has been readen
+        # other table renaming done once schema has been read
     # print 'reading schema from the database...'
     index = {}
     permsdict = deserialize_ertype_permissions(session)
--- a/server/test/unittest_migractions.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/server/test/unittest_migractions.py	Tue Jun 23 08:44:42 2009 +0200
@@ -7,6 +7,7 @@
 from logilab.common.testlib import TestCase, unittest_main
 from cubicweb.devtools.apptest import RepositoryBasedTC, get_versions
 
+from cubicweb import ConfigurationError
 from cubicweb.schema import CubicWebSchemaLoader
 from cubicweb.server.sqlutils import SQL_PREFIX
 from cubicweb.server.repository import Repository
@@ -365,7 +366,7 @@
         finally:
             self.mh.cmd_set_size_constraint('CWEType', 'description', None)
 
-    def test_add_remove_cube(self):
+    def test_add_remove_cube_and_deps(self):
         cubes = set(self.config.cubes())
         schema = self.repo.schema
         self.assertEquals(sorted(schema['see_also']._rproperties.keys()),
@@ -374,11 +375,10 @@
                                   ('Note', 'Note'), ('Note', 'Bookmark')]))
         try:
             try:
-                self.mh.cmd_remove_cube('email')
+                self.mh.cmd_remove_cube('email', removedeps=True)
                 # file was there because it's an email dependancy, should have been removed
-                cubes.remove('email')
-                cubes.remove('file')
-                self.assertEquals(set(self.config.cubes()), cubes)
+                self.failIf('email' in self.config.cubes())
+                self.failIf('file' in self.config.cubes())
                 for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', 'Image',
                                'sender', 'in_thread', 'reply_to', 'data_format'):
                     self.failIf(ertype in schema, ertype)
@@ -392,17 +392,14 @@
                 self.assertEquals(sorted(schema['see_also'].objects()), ['Bookmark', 'Folder', 'Note'])
                 self.assertEquals(self.execute('Any X WHERE X pkey "system.version.email"').rowcount, 0)
                 self.assertEquals(self.execute('Any X WHERE X pkey "system.version.file"').rowcount, 0)
-                self.failIf('email' in self.config.cubes())
-                self.failIf('file' in self.config.cubes())
             except :
                 import traceback
                 traceback.print_exc()
                 raise
         finally:
             self.mh.cmd_add_cube('email')
-            cubes.add('email')
-            cubes.add('file')
-            self.assertEquals(set(self.config.cubes()), cubes)
+            self.failUnless('email' in self.config.cubes())
+            self.failUnless('file' in self.config.cubes())
             for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', 'Image',
                            'sender', 'in_thread', 'reply_to', 'data_format'):
                 self.failUnless(ertype in schema, ertype)
@@ -420,8 +417,6 @@
                               email_version)
             self.assertEquals(self.execute('Any V WHERE X value V, X pkey "system.version.file"')[0][0],
                               file_version)
-            self.failUnless('email' in self.config.cubes())
-            self.failUnless('file' in self.config.cubes())
             # trick: overwrite self.maxeid to avoid deletion of just reintroduced
             #        types (and their associated tables!)
             self.maxeid = self.execute('Any MAX(X)')[0][0]
@@ -429,6 +424,38 @@
             # next test may fail complaining of missing tables
             self.commit()
 
+
+    def test_add_remove_cube_no_deps(self):
+        cubes = set(self.config.cubes())
+        schema = self.repo.schema
+        try:
+            try:
+                self.mh.cmd_remove_cube('email')
+                cubes.remove('email')
+                self.failIf('email' in self.config.cubes())
+                self.failUnless('file' in self.config.cubes())
+                for ertype in ('Email', 'EmailThread', 'EmailPart',
+                               'sender', 'in_thread', 'reply_to'):
+                    self.failIf(ertype in schema, ertype)
+            except :
+                import traceback
+                traceback.print_exc()
+                raise
+        finally:
+            self.mh.cmd_add_cube('email')
+            self.failUnless('email' in self.config.cubes())
+            # trick: overwrite self.maxeid to avoid deletion of just reintroduced
+            #        types (and their associated tables!)
+            self.maxeid = self.execute('Any MAX(X)')[0][0]
+            # why this commit is necessary is unclear to me (though without it
+            # next test may fail complaining of missing tables
+            self.commit()
+
+    def test_remove_dep_cube(self):
+        ex = self.assertRaises(ConfigurationError, self.mh.cmd_remove_cube, 'file')
+        self.assertEquals(str(ex), "can't remove cube file, used as a dependency")
+
+
     def test_set_state(self):
         user = self.session.user
         self.mh.set_state(user.eid, 'deactivated')
--- a/server/test/unittest_msplanner.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/server/test/unittest_msplanner.py	Tue Jun 23 08:44:42 2009 +0200
@@ -2118,6 +2118,15 @@
                      None, None, [self.vcs], {}, [])
                     ])
 
+    def test_nonregr_fully_simplified_extsource(self):
+        self.repo._type_source_cache[999998] = ('Note', 'vcs', 999998)
+        self.repo._type_source_cache[999999] = ('Note', 'vcs', 999999)
+        self.repo._type_source_cache[1000000] = ('Note', 'system', 1000000)
+        self._test('DISTINCT Any T,FALSE,L,M WHERE L eid 1000000, M eid 999999, T eid 999998',
+                   [('OneFetchStep', [('DISTINCT Any 999998,FALSE,1000000,999999', [{}])],
+                     None, None, [self.system], {}, [])
+                    ])
+
 
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
--- a/test/unittest_entity.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/test/unittest_entity.py	Tue Jun 23 08:44:42 2009 +0200
@@ -390,6 +390,11 @@
         metainf['extid']  = 1234
         self.assertEquals(note.absolute_url(), 'http://cubicweb2.com/note/1234')
 
+    def test_absolute_url_empty_field(self):
+        card = self.add_entity('Card', wikiid=u'', title=u'test')
+        self.assertEquals(card.absolute_url(),
+                          'http://testing.fr/cubicweb/card/eid/%s' % card.eid)
+
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()
--- a/web/data/cubicweb.css	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/data/cubicweb.css	Tue Jun 23 08:44:42 2009 +0200
@@ -1,6 +1,6 @@
 /*
  *  :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
  */
 /***************************************/
@@ -12,7 +12,7 @@
   padding :0px;
 }
 
-html, body {  
+html, body {
   background: #e2e2e2;
 }
 
@@ -277,8 +277,8 @@
   position: relative;
   min-height: 800px;
 }
- 
-table#mainLayout{ 
+
+table#mainLayout{
  margin:0px 3px;
 }
 
@@ -321,7 +321,7 @@
 
 /* boxes */
 div.navboxes {
- margin-top: 8px; 
+ margin-top: 8px;
 }
 
 div.boxFrame {
@@ -459,9 +459,9 @@
   max-width: 50em;
 }
 
-ul.sideBox li{ 
+ul.sideBox li{
  list-style: none;
- background: none; 
+ background: none;
  padding: 0px 0px 1px 1px;
  }
 
@@ -576,7 +576,7 @@
 
 div.primaryRight{
   float:right;
-  
+
  }
 
 div.metadata {
@@ -603,7 +603,7 @@
  padding-bottom:0.4px
 }
 
-div.row span.label{ 
+div.row span.label{
  padding-right:1em
 }
 
@@ -772,20 +772,20 @@
 /* addcombobox                         */
 /***************************************/
 
-input#newopt{ 
- width:120px ; 
+input#newopt{
+ width:120px ;
  display:block;
  float:left;
  }
 
-div#newvalue{ 
+div#newvalue{
  margin-top:2px;
  }
 
 #add_newopt{
  background: #fffff8 url("go.png") 50% 50% no-repeat;
  width: 20px;
- line-height: 20px; 
+ line-height: 20px;
  display:block;
  float:left;
 }
@@ -794,7 +794,7 @@
 /* buttons                             */
 /***************************************/
 
-input.button{  
+input.button{
   margin: 1em 1em 0px 0px;
   border: 1px solid #edecd2;
   border-color:#edecd2 #cfceb7 #cfceb7  #edecd2;
@@ -838,7 +838,7 @@
   font-weight: bold;
 }
 
-input.validateButton {  
+input.validateButton {
   margin: 1em 1em 0px 0px;
   border: 1px solid #edecd2;
   border-color:#edecd2 #cfceb7 #cfceb7  #edecd2;
--- a/web/data/cubicweb.facets.css	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/data/cubicweb.facets.css	Tue Jun 23 08:44:42 2009 +0200
@@ -1,7 +1,7 @@
 #filterbox fieldset{
  margin: 0px;
  padding: 0px;
-} 
+}
 
 div.facet {
  margin-bottom: 8px;
@@ -14,11 +14,11 @@
  font-size: 80%;
  color: #000;
  margin-bottom: 2px;
- cursor: pointer; 
+ cursor: pointer;
  font: bold 100% Georgia;
 }
 
-div.facetTitle a { 
+div.facetTitle a {
  padding-left: 10px;
  background: transparent url("puce.png") 0% 50% no-repeat;
  }
@@ -26,12 +26,12 @@
 div.facetBody {
 }
 
-.opened{  
- color: #000 !important; 
+.opened{
+ color: #000 !important;
 }
 
 div.overflowed{
-  height: 12em; 
+  height: 12em;
   overflow-y: auto;
 }
 
@@ -50,12 +50,12 @@
 }
 
 div.facetValue img{
- float: left; 
+ float: left;
  background: #fff;
 }
 
 div.facetValue a {
- margin-left: 20px; 
+ margin-left: 20px;
  display: block;
  margin-top: -6px; /* FIXME why do we need this ? */
 }
@@ -78,11 +78,11 @@
 }
 
 
-div.facetCheckBox{ 
+div.facetCheckBox{
  line-height:0.8em;
  }
 
-.facet input{ 
+.facet input{
  margin-top:3px;
  border:1px solid #ccc;
  font-size:11px;
--- a/web/data/cubicweb.htmlhelpers.js	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/data/cubicweb.htmlhelpers.js	Tue Jun 23 08:44:42 2009 +0200
@@ -247,6 +247,11 @@
     }
 }
 
+function limitTextAreaSize(textarea, size) {
+    var $area = jQuery(textarea);
+    $area.val($area.val().slice(0, size));
+}
+
 //============= page loading events ==========================================//
 function roundedCornersOnLoad() {
     jQuery('div.sideBox').corner('bottom 6px');
--- a/web/data/cubicweb.login.css	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/data/cubicweb.login.css	Tue Jun 23 08:44:42 2009 +0200
@@ -1,7 +1,7 @@
 /* styles for the login popup and login form
  *
  *  :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
  */
 
@@ -12,7 +12,7 @@
   width: 26em;
   padding: 0px 1px 1px;
   font-weight: bold;
-  background: #E4EAD8; 
+  background: #E4EAD8;
 }
 
 div#popupLoginBox div#loginContent {
@@ -20,7 +20,7 @@
   padding: 5px 3px 4px;
 }
 
-div#loginBox { 
+div#loginBox {
   position : absolute;
   top: 15%;
   left : 50%;
@@ -32,12 +32,12 @@
   text-align: center;
 }
 
-div#loginBox h1 { 
+div#loginBox h1 {
   color: #FF7700;
   font-size: 140%;
 }
 
-div#loginTitle { 
+div#loginTitle {
   color: #fff;
   font-weight: bold;
   font-size: 140%;
@@ -46,32 +46,32 @@
   background: #ff7700 url("banner.png") left top repeat-x;
 }
 
-div#loginBox div#loginContent form { 
+div#loginBox div#loginContent form {
   padding-top: 1em;
-  width: 90%; 
-  margin: auto;  
+  width: 90%;
+  margin: auto;
 }
 
-#popupLoginBox table td { 
-  padding: 0px 3px; 
+#popupLoginBox table td {
+  padding: 0px 3px;
   white-space: nowrap;
 }
 
-#loginContent table { 
+#loginContent table {
   padding: 0px 0.5em;
   margin: auto;
 }
 
-#loginBox table td { 
-  padding: 0px 3px 0.6em; 
+#loginBox table td {
+  padding: 0px 3px 0.6em;
   white-space: nowrap;
 }
 
-#loginBox .loginButton { 
+#loginBox .loginButton {
   margin-top: 0.6em;
  }
 
-#loginContent input.data { 
+#loginContent input.data {
   width:12em;
 }
 
@@ -79,5 +79,5 @@
   border: 1px solid #edecd2;
   border-color:#edecd2 #cfceb7 #cfceb7  #edecd2;
   margin: 2px 0px 0px;
-  background: #f0eff0 url("gradient-grey-up.png") left top repeat-x; 
+  background: #f0eff0 url("gradient-grey-up.png") left top repeat-x;
 }
--- a/web/facet.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/facet.py	Tue Jun 23 08:44:42 2009 +0200
@@ -744,7 +744,7 @@
                % (cssclass, html_escape(unicode(self.value))))
         self.w(u'<div class="facetCheckBoxWidget">')
         self.w(u'<img src="%s" alt="%s" cubicweb:unselimg="true" />&nbsp;' % (imgsrc, imgalt))
-        self.w(u'<label class="facetTitle" cubicweb:facetName="%s"><a href="javascript: {}">%s</a></label>' % (facetid,title))
+        self.w(u'<label class="facetTitle" cubicweb:facetName="%s"><a href="javascript: {}">%s</a></label>' % (facetid, title))
         self.w(u'</div>\n')
         self.w(u'</div>\n')
         self.w(u'</div>\n')
--- a/web/formwidgets.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/formwidgets.py	Tue Jun 23 08:44:42 2009 +0200
@@ -148,7 +148,7 @@
     """<textarea>"""
     def render(self, form, field):
         name, values, attrs = self._render_attrs(form, field)
-        attrs.setdefault('onkeypress', 'autogrow(this)')
+        attrs.setdefault('onkeyup', 'autogrow(this)')
         attrs.setdefault('cols', 80)
         attrs.setdefault('rows', 20)
         if not values:
--- a/web/test/unittest_form.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/test/unittest_form.py	Tue Jun 23 08:44:42 2009 +0200
@@ -145,12 +145,12 @@
 <option value="text/html">text/html</option>
 <option value="text/plain">text/plain</option>
 <option selected="selected" value="text/rest">text/rest</option>
-</select><textarea cols="60" id="description:%(eid)s" name="description:%(eid)s" onkeypress="autogrow(this)" rows="5" tabindex="1"/>''')
+</select><textarea cols="60" id="description:%(eid)s" name="description:%(eid)s" onkeyup="autogrow(this)" rows="5" tabindex="1"/>''')
 
 
     def test_richtextfield_2(self):
         self.req.use_fckeditor = lambda: True
-        self._test_richtextfield('<input name="description_format:%(eid)s" style="display: block" type="hidden" value="text/rest"/><textarea cols="80" cubicweb:type="wysiwyg" id="description:%(eid)s" name="description:%(eid)s" onkeypress="autogrow(this)" rows="20" tabindex="0"/>')
+        self._test_richtextfield('<input name="description_format:%(eid)s" style="display: block" type="hidden" value="text/rest"/><textarea cols="80" cubicweb:type="wysiwyg" id="description:%(eid)s" name="description:%(eid)s" onkeyup="autogrow(this)" rows="20" tabindex="0"/>')
 
 
     def test_filefield(self):
@@ -195,7 +195,7 @@
 <input name="data:%(eid)s__detach" type="checkbox"/>
 detach attached file
 <p><b>You can either submit a new file using the browse button above, or choose to remove already uploaded file by checking the "detach attached file" check-box, or edit file content online with the widget below.</b></p>
-<textarea cols="80" name="data:%(eid)s" onkeypress="autogrow(this)" rows="20" tabindex="3">new widgets system</textarea>''' % {'eid': file.eid})
+<textarea cols="80" name="data:%(eid)s" onkeyup="autogrow(this)" rows="20" tabindex="3">new widgets system</textarea>''' % {'eid': file.eid})
 
 
     def test_passwordfield(self):
--- a/web/views/actions.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/views/actions.py	Tue Jun 23 08:44:42 2009 +0200
@@ -6,6 +6,7 @@
 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
 """
 __docformat__ = "restructuredtext en"
+_ = unicode
 
 from cubicweb.vregistry import objectify_selector
 from cubicweb.selectors import (EntitySelector,
@@ -18,8 +19,6 @@
 from cubicweb.web.views import linksearch_select_url, vid_from_rset
 from cubicweb.web.views.autoform import AutomaticEntityForm
 
-_ = unicode
-
 
 class has_editable_relation(EntitySelector):
     """accept if some relations for an entity found in the result set is
--- a/web/views/basecomponents.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/views/basecomponents.py	Tue Jun 23 08:44:42 2009 +0200
@@ -29,7 +29,8 @@
     """build the rql input form, usually displayed in the header"""
     id = 'rqlinput'
     property_defs = VISIBLE_PROP_DEF
-
+    visible = False
+    
     def call(self, view=None):
         if hasattr(view, 'filter_box_context_info'):
             rset = view.filter_box_context_info()[0]
@@ -148,8 +149,10 @@
     site_wide = True
 
     def call(self):
-        self.w(u'<span id="appliName"><a href="%s">%s</a></span>' % (
-            self.req.base_url(), self.req.property_value('ui.site-title')))
+        title = self.req.property_value('ui.site-title')
+        if title:
+            self.w(u'<span id="appliName"><a href="%s">%s</a></span>' % (
+                self.req.base_url(), title))
 
 
 class SeeAlsoVComponent(component.RelatedObjectsVComponent):
--- a/web/views/basetemplates.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/views/basetemplates.py	Tue Jun 23 08:44:42 2009 +0200
@@ -431,7 +431,7 @@
         self.w(u'<div id="%s" class="%s">' % (id, klass))
         if title:
             self.w(u'<div id="loginTitle">%s</div>'
-                   % self.req.property_value('ui.site-title'))
+                   % (self.req.property_value('ui.site-title') or u'&nbsp;'))
         self.w(u'<div id="loginContent">\n')
 
         if message:
--- a/web/views/tableview.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/views/tableview.py	Tue Jun 23 08:44:42 2009 +0200
@@ -140,6 +140,7 @@
                 actions += self.form_filter(divid, displaycols, displayfilter,
                                             displayactions)
         elif displayfilter:
+            req.add_css('cubicweb.facets.css')
             actions += self.show_hide_actions(divid, True)
         self.w(u'<div id="%s"' % divid)
         if displayactions:
--- a/web/widgets.py	Mon Jun 22 11:15:17 2009 +0200
+++ b/web/widgets.py	Tue Jun 23 08:44:42 2009 +0200
@@ -418,7 +418,7 @@
                 hidden = u'<input type="hidden" name="edits-%s" value="%s"/>\n'\
                          '<input type="hidden" name="%s" value="text/html"/>\n' % (
                     frname, format, frname)
-            return u'%s<textarea cubicweb:type="wysiwyg" onkeypress="autogrow(this)" name="%s" %s>%s</textarea>' % (
+            return u'%s<textarea cubicweb:type="wysiwyg" onkeyup="autogrow(this)" name="%s" %s>%s</textarea>' % (
                 hidden, self.rname, self.format_attrs(), dvalue)
         if with_format and entity.e_schema.has_metadata(self.name, 'format'):
             fmtwdg = entity.get_widget(self.name + '_format')
@@ -426,7 +426,7 @@
             self.attrs['tabindex'] = entity.req.next_tabindex()
         else:
             fmtwdgstr = ''
-        return u'%s<br/><textarea onkeypress="autogrow(this)" name="%s" %s>%s</textarea>' % (
+        return u'%s<br/><textarea onkeyup="autogrow(this)" name="%s" %s>%s</textarea>' % (
             fmtwdgstr, self.rname, self.format_attrs(), dvalue)