merge and add missing import in schema.py stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 23 Jun 2009 13:46:18 +0200
branchstable
changeset 2147 476a75ede2cc
parent 2143 d4c2fb633062 (diff)
parent 2146 6645e18e8c93 (current diff)
child 2148 2b2b9626a98f
child 2150 746c5e6acd38
merge and add missing import in schema.py
schema.py
web/test/unittest_form.py
--- a/.hgtags	Tue Jun 23 13:43:39 2009 +0200
+++ b/.hgtags	Tue Jun 23 13:46:18 2009 +0200
@@ -40,3 +40,4 @@
 4003d24974f15f17bd03b7efd6a5047cad4e4c41 cubicweb-debian-version-3_2_3-1
 2d7d3062ca03d4b4144100013dc4ab7f9d9cb25e cubicweb-version-3_3_0
 07214e923e75c8f0490e609e9bee0f4964b87114 cubicweb-debian-version-3_3_0-1
+a356da3e725bfcb59d8b48a89d04be05ea261fd3 3.3.1
--- a/__pkginfo__.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/__pkginfo__.py	Tue Jun 23 13:46:18 2009 +0200
@@ -7,7 +7,7 @@
 distname = "cubicweb"
 modname = "cubicweb"
 
-numversion = (3, 3, 0)
+numversion = (3, 3, 1)
 version = '.'.join(str(num) for num in numversion)
 
 license = 'LGPL v2'
--- a/common/migration.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/common/migration.py	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/common/mixins.py	Tue Jun 23 13:46:18 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/debian/changelog	Tue Jun 23 13:43:39 2009 +0200
+++ b/debian/changelog	Tue Jun 23 13:46:18 2009 +0200
@@ -1,3 +1,9 @@
+cubicweb (3.3.1-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Aurélien Campéas <aurelien.campeas@logilab.fr>  Mon, 22 Jun 2009 12:00:00 +0200
+
 cubicweb (3.3.0-1) unstable; urgency=low
 
   * new upstream release
--- a/devtools/fill.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/devtools/fill.py	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/entity.py	Tue Jun 23 13:46:18 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/interfaces.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/interfaces.py	Tue Jun 23 13:46:18 2009 +0200
@@ -197,6 +197,14 @@
     """interface for items that do have a begin date 'start' and an end date 'stop'
     """
 
+    @property
+    def start(self):
+        """return start date"""
+
+    @property
+    def stop(self):
+        """return stop state"""
+
 class ICalendarViews(Interface):
     """calendar views interface"""
     def matching_dates(self, begin, end):
--- a/schema.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/schema.py	Tue Jun 23 13:46:18 2009 +0200
@@ -6,8 +6,10 @@
 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
 """
 __docformat__ = "restructuredtext en"
+_ = unicode
 
 import re
+from os.path import join
 from logging import getLogger
 from warnings import warn
 
@@ -34,7 +36,7 @@
 
 BASEGROUPS = ('managers', 'users', 'guests', 'owners')
 
-LOGGER = getLogger('cubicweb.schemaloader')
+_LOGGER = getLogger('cubicweb.schemaloader')
 
 # schema entities created from serialized schema have an eid rproperty
 ybo.ETYPE_PROPERTIES += ('eid',)
@@ -636,8 +638,8 @@
             raise RQLSyntaxError(expression)
         for mainvar in mainvars.split(','):
             if len(self.rqlst.defined_vars[mainvar].references()) <= 2:
-                LOGGER.warn('You did not use the %s variable in your RQL expression %s',
-                            mainvar, self)
+                _LOGGER.warn('You did not use the %s variable in your RQL '
+                             'expression %s', mainvar, self)
 
     def __str__(self):
         return self.full_rql
@@ -904,9 +906,9 @@
 
     def _load_definition_files(self, cubes=None):
         # bootstraping, ignore cubes
-        for filepath in self.include_schema_files('bootstrap'):
-            self.info('loading %s', filepath)
-            self.handle_file(filepath)
+        filepath = join(self.lib_directory, 'bootstrap.py')
+        self.info('loading %s', filepath)
+        self.handle_file(filepath)
 
     def unhandled_file(self, filepath):
         """called when a file without handler associated has been found"""
@@ -930,10 +932,10 @@
         return super(CubicWebSchemaLoader, self).load(config, path=path, **kwargs)
 
     def _load_definition_files(self, cubes):
-        for filepath in (self.include_schema_files('bootstrap')
-                         + self.include_schema_files('base')
-                         + self.include_schema_files('workflow')
-                         + self.include_schema_files('Bookmark')):
+        for filepath in (join(self.lib_directory, 'bootstrap.py'),
+                         join(self.lib_directory, 'base.py'),
+                         join(self.lib_directory, 'workflow.py'),
+                         join(self.lib_directory, 'Bookmark.py')):
             self.info('loading %s', filepath)
             self.handle_file(filepath)
         for cube in cubes:
--- a/server/migractions.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/server/migractions.py	Tue Jun 23 13:46:18 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/schemaserial.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/server/schemaserial.py	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/server/test/unittest_migractions.py	Tue Jun 23 13:46:18 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/test/unittest_entity.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/test/unittest_entity.py	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/data/cubicweb.css	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/data/cubicweb.facets.css	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/data/cubicweb.htmlhelpers.js	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/data/cubicweb.login.css	Tue Jun 23 13:46:18 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/data/cubicweb.preferences.js	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/data/cubicweb.preferences.js	Tue Jun 23 13:46:18 2009 +0200
@@ -4,6 +4,8 @@
  *     move me in a more appropriate place
  */
 
+var prefsValues = {};
+
 function togglePrefVisibility(elemId) {
     clearPreviousMessages();
     jQuery('#' + elemId).toggleClass('hidden');
@@ -21,7 +23,6 @@
     _toggleFieldset(fieldsetid, 0, linklabel, linkhref);
 }
 
-
 function _toggleFieldset(fieldsetid, closeaction, linklabel, linkhref){
     jQuery('#'+fieldsetid).find('div.openlink').each(function(){
 	    var link = A({'href' : "javascript:noop();",
@@ -75,7 +76,6 @@
     jQuery('#err-value:' + formid).remove();
 }
 
-
 function checkValues(form, success){
     var unfreezeButtons = false;
     jQuery(form).find('select').each(function () {
@@ -100,8 +100,8 @@
 }
 
 function _checkValue(input, unfreezeButtons){
-     var currentValueInput = jQuery("input[name=current-" + input.attr('name') + "]");
-     if (currentValueInput.val() != input.val()){
+    var currentValue = prefsValues[input.attr('name')];
+     if (currentValue != input.val()){
 	 input.addClass('changed');
 	 unfreezeButtons = true;
      }else{
@@ -112,27 +112,22 @@
      return unfreezeButtons;
 }
 
-
 function setCurrentValues(form){
-    jQuery(form).find('input[name^=current-value]').each(function () {
-	    var currentValueInput = jQuery(this);
-	    var name = currentValueInput.attr('name').split('-')[1];
-	    jQuery(form).find("[name=" + name + "]").each(function (){
-		    var input = jQuery(this);
-		    if(input.attr('type') == 'radio'){
-			// NOTE: there seems to be a bug with jQuery(input).attr('checked')
-			//       in our case, we can't rely on its value, we use
-			//       the DOM API instead.
-			if(input[0].checked){
-			    currentValueInput.val(input.val());
-			}
-		    }else{
-			currentValueInput.val(input.val());
-		    }
-		});
-    });
+    jQuery(form).find('input[name^=value]').each(function () {
+	    var input = jQuery(this);
+	    if(input.attr('type') == 'radio'){
+		// NOTE: there seems to be a bug with jQuery(input).attr('checked')
+		//       in our case, we can't rely on its value, we use
+		//       the DOM API instead.
+		if(input[0].checked){
+		    prefsValues[input.attr('name')] = input.val();
+		}
+	    }else{
+		prefsValues[input.attr('name')] = input.val();
+	    }
+	});
 }
-
+     
 function initEvents(){
   jQuery('form').each(function() {
 	  var form = jQuery(this);
@@ -153,4 +148,3 @@
 $(document).ready(function() {
 	initEvents();
 });
-
--- a/web/facet.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/facet.py	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/formwidgets.py	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/test/unittest_form.py	Tue Jun 23 13:46:18 2009 +0200
@@ -147,12 +147,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):
@@ -197,7 +197,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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/views/actions.py	Tue Jun 23 13:46:18 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/autoform.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/views/autoform.py	Tue Jun 23 13:46:18 2009 +0200
@@ -292,7 +292,7 @@
 
         by default true if there is no related entity and we need at least one
         """
-        return not existant and card in '1+'
+        return not existant and card in '1+' or self.req.form.has_key('force_%s_display' % rschema)
 
     def should_display_add_new_relation_link(self, rschema, existant, card):
         """return true if we should add a link to add a new creation form
--- a/web/views/basecomponents.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/views/basecomponents.py	Tue Jun 23 13:46:18 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	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/views/basetemplates.py	Tue Jun 23 13:46:18 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/cwproperties.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/views/cwproperties.py	Tue Jun 23 13:46:18 2009 +0200
@@ -139,7 +139,6 @@
             w(u'<h2 class="propertiesform">%s</h2>\n' %
               (make_togglable_link('fieldset_' + group, label.capitalize())))
             w(u'<div id="fieldset_%s" %s>' % (group, status))
-
             # create selection
             sorted_objects =  sorted((self.req.__('%s_%s' % (group, o)), o, f)
                                            for o, f in objects.iteritems())
@@ -217,10 +216,9 @@
                                                 eidparam=True))
         subform.vreg = self.vreg
         subform.form_add_hidden('pkey', key, eidparam=True)
-        subform.form_add_hidden("current-value:%s" % entity.eid,)
         form.form_add_subform(subform)
         return subform
-
+    
 def is_user_prefs(cls, req, rset, row=None, col=0, **kwargs):
     return req.user.eid == rset[row or 0][col]
 
@@ -303,7 +301,7 @@
         choices = entity.vreg.user_property_keys()
         return [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
 
-
+    
 class PropertyValueField(StringField):
     """specific field for CWProperty.value  which will be different according to
     the selected key type and vocabulary information
@@ -355,7 +353,6 @@
                 self.choices = field.vocabulary(form)
         self.widget = wdg
 
-
 uicfg.autoform_field.tag_attribute(('CWProperty', 'pkey'), PropertyKeyField)
 uicfg.autoform_field.tag_attribute(('CWProperty', 'value'), PropertyValueField)
 
--- a/web/views/idownloadable.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/views/idownloadable.py	Tue Jun 23 13:46:18 2009 +0200
@@ -125,7 +125,7 @@
         """the secondary view is a link to download the file"""
         entity = self.entity(row, col)
         url = html_escape(entity.absolute_url())
-        name = html_escape(entity.download_file_name())
+        name = html_escape(title or entity.download_file_name())
         durl = html_escape(entity.download_url())
         self.w(u'<a href="%s">%s</a> [<a href="%s">%s</a>]' %
                (url, name, durl, self.req._('download')))
--- a/web/views/primary.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/views/primary.py	Tue Jun 23 13:46:18 2009 +0200
@@ -54,6 +54,7 @@
             self.w(u'<table width="100%"><tr><td style="width: 75%">')
         self.w(u'<div>')
         self.w(u'<div class="mainInfo">')
+        self.content_navigation_components('navcontenttop')
         try:
             self.render_entity_attributes(entity)
         except TypeError: # XXX bw compat
@@ -61,7 +62,6 @@
                  'deprecated (%s)' % self.__class__)
             self.render_entity_attributes(entity, [])
         self.w(u'</div>')
-        self.content_navigation_components('navcontenttop')
         if self.main_related_section:
             try:
                 self.render_entity_relations(entity)
--- a/web/widgets.py	Tue Jun 23 13:43:39 2009 +0200
+++ b/web/widgets.py	Tue Jun 23 13:46:18 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)