# HG changeset patch # User Nicolas Chauvat # Date 1245954567 -7200 # Node ID 7f576dc9502ec37a78dd2e0c1f4bf60512a12c32 # Parent 7fae9300b9f9a8427bab19b6a7a05b3263bf2583# Parent 1dd3dfc6fd763229f9f162c1298c396bdbe0697e [doc] merge and a couple corrections diff -r 7fae9300b9f9 -r 7f576dc9502e .hgtags --- 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 diff -r 7fae9300b9f9 -r 7f576dc9502e __pkginfo__.py --- 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' diff -r 7fae9300b9f9 -r 7f576dc9502e debian/changelog --- 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 Mon, 22 Jun 2009 12:00:00 +0200 + cubicweb (3.3.0-1) unstable; urgency=low * new upstream release diff -r 7fae9300b9f9 -r 7f576dc9502e doc/book/en/annexes/faq.rst --- 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. diff -r 7fae9300b9f9 -r 7f576dc9502e doc/book/en/index.rst --- 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/ diff -r 7fae9300b9f9 -r 7f576dc9502e doc/book/en/intro/foundations/index.rst --- 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 diff -r 7fae9300b9f9 -r 7f576dc9502e doc/book/en/intro/tutorial/blog-less-ten-minutes.rst --- 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. diff -r 7fae9300b9f9 -r 7f576dc9502e interfaces.py --- 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): diff -r 7fae9300b9f9 -r 7f576dc9502e schema.py --- 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: diff -r 7fae9300b9f9 -r 7f576dc9502e server/schemaserial.py --- 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) diff -r 7fae9300b9f9 -r 7f576dc9502e web/data/cubicweb.htmlhelpers.js --- 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'); diff -r 7fae9300b9f9 -r 7f576dc9502e web/data/cubicweb.preferences.js --- 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(); }); - diff -r 7fae9300b9f9 -r 7f576dc9502e web/facet.py --- 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'
') self.w(u'%s ' % (imgsrc, imgalt)) - self.w(u'' % (facetid,title)) + self.w(u'' % (facetid, title)) self.w(u'
\n') self.w(u'\n') self.w(u'\n') diff -r 7fae9300b9f9 -r 7f576dc9502e web/formfields.py --- 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): diff -r 7fae9300b9f9 -r 7f576dc9502e web/formwidgets.py --- 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 @@ """''' % {'eid': file.eid}) +''' % {'eid': file.eid}) def test_passwordfield(self): @@ -210,5 +212,13 @@ confirm password''' % {'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() diff -r 7fae9300b9f9 -r 7f576dc9502e web/views/autoform.py --- 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 diff -r 7fae9300b9f9 -r 7f576dc9502e web/views/cwproperties.py --- 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'

%s

\n' % (make_togglable_link('fieldset_' + group, label.capitalize()))) w(u'
' % (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) diff -r 7fae9300b9f9 -r 7f576dc9502e web/views/formrenderers.py --- 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'') def render_buttons(self, w, form): + if not form.form_buttons: + return w(u'\n\n' % self.button_bar_class) for button in form.form_buttons: w(u'\n' % button.render(form)) diff -r 7fae9300b9f9 -r 7f576dc9502e web/views/idownloadable.py --- 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'%s [%s]' % (url, name, durl, self.req._('download'))) diff -r 7fae9300b9f9 -r 7f576dc9502e web/views/primary.py --- 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'
%s
') self.w(u'
') self.w(u'
') + 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'
') - self.content_navigation_components('navcontenttop') if self.main_related_section: try: self.render_entity_relations(entity) diff -r 7fae9300b9f9 -r 7f576dc9502e web/widgets.py --- 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'\n'\ '\n' % ( frname, format, frname) - return u'%s' % ( + return u'%s' % ( 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
' % ( + return u'%s
' % ( fmtwdgstr, self.rname, self.format_attrs(), dvalue)