--- 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" /> ' % (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)