[doc] merge and a couple corrections stable
authorNicolas Chauvat <nicolas.chauvat@logilab.fr>
Thu, 25 Jun 2009 20:29:27 +0200
branchstable
changeset 2174 7f576dc9502e
parent 2173 7fae9300b9f9 (current diff)
parent 2155 1dd3dfc6fd76 (diff)
child 2175 16d3c37c5d28
[doc] merge and a couple corrections
doc/book/en/annexes/faq.rst
doc/book/en/index.rst
doc/book/en/intro/foundations/index.rst
doc/book/en/intro/tutorial/blog-less-ten-minutes.rst
server/schemaserial.py
web/test/unittest_form.py
--- a/.hgtags	Thu Jun 25 20:18:16 2009 +0200
+++ b/.hgtags	Thu Jun 25 20:29:27 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	Thu Jun 25 20:18:16 2009 +0200
+++ b/__pkginfo__.py	Thu Jun 25 20:29:27 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/debian/changelog	Thu Jun 25 20:18:16 2009 +0200
+++ b/debian/changelog	Thu Jun 25 20:29:27 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/doc/book/en/annexes/faq.rst	Thu Jun 25 20:18:16 2009 +0200
+++ b/doc/book/en/annexes/faq.rst	Thu Jun 25 20:29:27 2009 +0200
@@ -72,7 +72,7 @@
 
   It may remind you of SQL but it is higher level than SQL, more like
   SPARQL. Except that SPARQL did not exist when we started the project.
-  Having SPARQL has a query language has been in our backlog for years.
+  Having SPARQL as a query language has been in our backlog for years.
 
   That RQL language is what is going to make a difference with django-
   like frameworks for several reasons.
--- a/doc/book/en/index.rst	Thu Jun 25 20:18:16 2009 +0200
+++ b/doc/book/en/index.rst	Thu Jun 25 20:29:27 2009 +0200
@@ -29,7 +29,7 @@
 
 The hacker will join development at the forge_.
 
-The impatient developper will move right away to :ref:`SetUpEnv`.
+The impatient developer will move right away to :ref:`SetUpEnv`.
 
 .. _Logilab: http://www.logilab.fr/
 .. _forge: http://www.cubicweb.org/project/
--- a/doc/book/en/intro/foundations/index.rst	Thu Jun 25 20:18:16 2009 +0200
+++ b/doc/book/en/intro/foundations/index.rst	Thu Jun 25 20:29:27 2009 +0200
@@ -17,7 +17,7 @@
 database and to display the results with the best rendering according to
 the context.
 This interface flexibility gives back the user the control of the
-rendering parameters that are usually reserved for developpers.
+rendering parameters that are usually reserved for developers.
 
 
 We can list a couple of web applications developped with `CubicWeb`, an online
--- a/doc/book/en/intro/tutorial/blog-less-ten-minutes.rst	Thu Jun 25 20:18:16 2009 +0200
+++ b/doc/book/en/intro/tutorial/blog-less-ten-minutes.rst	Thu Jun 25 20:29:27 2009 +0200
@@ -17,10 +17,10 @@
 
     cubicweb-ctl start -D myblog
 
-This is it. Your blog is ready to you. Go to http://localhost:8080 and enjoy!
+This is it. Your blog is running. Go to http://localhost:8080 and enjoy!
 
-As a developper, you'll want to know more about how to develop new
-cubes and cutomize the look of your application and this is what we
-talk about now.
+As a developer, you'll want to know more about how to develop new
+cubes and cutomize the look of your application and this is what the next
+section is about.
 
 
--- a/interfaces.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/interfaces.py	Thu Jun 25 20:29:27 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	Thu Jun 25 20:18:16 2009 +0200
+++ b/schema.py	Thu Jun 25 20:29:27 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/schemaserial.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/server/schemaserial.py	Thu Jun 25 20:29:27 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/web/data/cubicweb.htmlhelpers.js	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/data/cubicweb.htmlhelpers.js	Thu Jun 25 20:29:27 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.preferences.js	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/data/cubicweb.preferences.js	Thu Jun 25 20:29:27 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,25 +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('[name^=value]').each(function () {
+	    var input = jQuery(this);
+	    var name = input.attr('name');
+	    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[name] = input.val();
+		}
+	    }else{
+		prefsValues[name] = input.val();
+	    }
+	    jQuery('[name=edits-'+ name + ']').val(prefsValues[name]);
+	});
 }
 
 function initEvents(){
@@ -153,4 +150,3 @@
 $(document).ready(function() {
 	initEvents();
 });
-
--- a/web/facet.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/facet.py	Thu Jun 25 20:29:27 2009 +0200
@@ -10,7 +10,7 @@
 
 from itertools import chain
 from copy import deepcopy
-from datetime import date
+from datetime import date, datetime, timedelta
 
 from logilab.mtconverter import html_escape
 
@@ -683,8 +683,15 @@
 
 
 class DateFacetRangeWidget(FacetRangeWidget):
+
     formatter = 'function (value) {return (new Date(parseFloat(value))).strftime(DATE_FMT);}'
+
+    def round_max_value(self, d):
+        'round to upper value to avoid filtering out the max value'
+        return datetime(d.year, d.month, d.day) + timedelta(days=1)
+
     def __init__(self, facet, minvalue, maxvalue):
+        maxvalue = self.round_max_value(maxvalue)
         super(DateFacetRangeWidget, self).__init__(facet,
                                                    datetime2ticks(minvalue),
                                                    datetime2ticks(maxvalue))
@@ -744,7 +751,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/formfields.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/formfields.py	Thu Jun 25 20:29:27 2009 +0200
@@ -406,6 +406,9 @@
             name=name, widget=HiddenInput, eidparam=True)
         self.visible_field = visible_field
 
+    def format_single_value(self, req, value):
+        return self.visible_field.format_single_value(req, value)
+
 
 class RelationField(Field):
     def __init__(self, **kwargs):
--- a/web/formwidgets.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/formwidgets.py	Thu Jun 25 20:29:27 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	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/test/unittest_form.py	Thu Jun 25 20:29:27 2009 +0200
@@ -6,6 +6,8 @@
 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
 """
 
+from xml.etree.ElementTree import fromstring
+
 from logilab.common.testlib import unittest_main, mock_object
 
 from cubicweb import Binary
@@ -13,7 +15,7 @@
 from cubicweb.web.formfields import (IntField, StringField, RichTextField,
                                      DateTimeField, DateTimePicker,
                                      FileField, EditableFileField)
-from cubicweb.web.formwidgets import PasswordInput
+from cubicweb.web.formwidgets import PasswordInput, Input
 from cubicweb.web.views.forms import EntityFieldsForm, FieldsForm
 from cubicweb.web.views.workflow import ChangeStateForm
 from cubicweb.web.views.formrenderers import FormRenderer
@@ -145,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):
@@ -195,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):
@@ -210,5 +212,13 @@
 <span class="emphasis">confirm password</span>''' % {'eid': self.entity.eid})
 
 
+    def test_datefield(self):
+        class DFForm(EntityFieldsForm):
+            creation_date = DateTimeField(widget=Input)
+        form = DFForm(self.req, entity=self.entity)
+        init, cur = (fromstring(self._render_entity_field(attr, form)).get('value')
+                     for attr in ('edits-creation_date', 'creation_date'))
+        self.assertEquals(init, cur)
+
 if __name__ == '__main__':
     unittest_main()
--- a/web/views/autoform.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/views/autoform.py	Thu Jun 25 20:29:27 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/cwproperties.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/views/cwproperties.py	Thu Jun 25 20:29:27 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/formrenderers.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/views/formrenderers.py	Thu Jun 25 20:29:27 2009 +0200
@@ -206,6 +206,8 @@
         w(u'</table>')
 
     def render_buttons(self, w, form):
+        if not form.form_buttons:
+            return
         w(u'<table class="%s">\n<tr>\n' % self.button_bar_class)
         for button in form.form_buttons:
             w(u'<td>%s</td>\n' % button.render(form))
--- a/web/views/idownloadable.py	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/views/idownloadable.py	Thu Jun 25 20:29:27 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	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/views/primary.py	Thu Jun 25 20:29:27 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	Thu Jun 25 20:18:16 2009 +0200
+++ b/web/widgets.py	Thu Jun 25 20:29:27 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)