Merge lp:~openerp-dev/openobject-client-web/6.0-opw-584287-xal into lp:openobject-client-web

Proposed by Samus CTO (OpenERP)
Status: Work in progress
Proposed branch: lp:~openerp-dev/openobject-client-web/6.0-opw-584287-xal
Merge into: lp:openobject-client-web
Diff against target: 392 lines (+133/-60)
11 files modified
addons/openerp/static/javascript/form.js (+45/-3)
addons/openerp/static/javascript/o2m.js (+4/-0)
addons/openerp/static/jscal/calendar.js (+3/-1)
addons/openerp/static/jscal/lang/calendar-fr.js (+40/-40)
addons/openerp/validators.py (+8/-8)
addons/openerp/widgets/form/_form.py (+5/-1)
addons/openerp/widgets/form/templates/datetime.mako (+1/-1)
addons/openerp/widgets/form/templates/hidden.mako (+1/-1)
addons/openerp/widgets/listgrid.py (+4/-1)
addons/openerp/widgets/templates/listgrid/hidden.mako (+1/-1)
openobject/i18n/format.py (+21/-3)
To merge this branch: bzr merge lp:~openerp-dev/openobject-client-web/6.0-opw-584287-xal
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+157889@code.launchpad.net
To post a comment you must log in.

Unmerged revisions

4907. By Xavier ALT

[FIX] when coping parent parent on One2Many popup initialization - keep input 'format' attribute

4906. By Xavier ALT

[FIX] add format attribute for hidden date/datetime field otherwise convertion will not happen at all

4905. By Xavier ALT

[FIX] get_datetime_format: fix call to _to_posix_format() - courtesy of Jean-Francois BOUR

4904. By jftempo

[FIX] babel format_dateime should be called with precise locale

4903. By Xavier ALT

[FIX] web: fix UnicodeEncodeError when calling format_datetime() with value as 'datetime' object

4902. By Xavier ALT

[FIX] fix jscal Date.parseDate implementation to correctly split date with accentuated chars

4901. By Xavier ALT

[FIX] web: Calendar picker 'fr' localisation should use lowercase value - not capitalized one

4900. By Xavier ALT

[FIX] web: better support of month name/week day name in date (posix %a, %b, %A, %B)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'addons/openerp/static/javascript/form.js'
--- addons/openerp/static/javascript/form.js 2012-10-15 13:19:24 +0000
+++ addons/openerp/static/javascript/form.js 2013-04-09 14:55:26 +0000
@@ -26,6 +26,26 @@
26 return openobject.http.getURL(act, params);26 return openobject.http.getURL(act, params);
27}27}
2828
29function datetime_get_server_value(elem, format) {
30 var $elem = jQuery(elem);
31 var field_date_format = $elem.attr('format') || '';
32 if (!field_date_format.match(/(%a|%b|%A|%B)/)) {
33 return elem.value;
34 }
35 // convert it back to str and compare to original value to determine
36 // if this a value set by jscal Calendar - or server/user input. In
37 // last case - keep the original value intact - in all other case
38 // we change the input value to match the server-format because depending
39 // on the language we might not be able to parse month or day of week names
40 var field_date = Date.parseDate(elem.value, field_date_format);
41 var field_date_str = field_date.print(field_date_format);
42 if (field_date_str == elem.value) {
43 var server_date_format = $elem.attr('kind') == 'date' ? '%Y-%m-%d' : '%Y-%m-%d %H:%M:%S';
44 return field_date.print(server_date_format);
45 }
46 return elem.value;
47}
48
29function openRecord(id, src, target, readonly){49function openRecord(id, src, target, readonly){
3050
31 var kind = getNodeAttribute(src + '_set', 'kind');51 var kind = getNodeAttribute(src + '_set', 'kind');
@@ -232,6 +252,16 @@
232 return;252 return;
233 }253 }
234254
255 $form.find('input[kind^="date"]').each(function(i, f) {
256 if (!this.value ||
257 !(this.getAttribute('kind') == 'date'
258 || this.getAttribute('kind') == 'datetime')) {
259 return; // skip input having no
260 }
261 // make sure date/datetime value is parseable by server
262 this.value = datetime_get_server_value(this);
263 });
264
235 // Cant use $form.attr due to http://dev.jquery.com/ticket/3113 as there is a form with a field called265 // Cant use $form.attr due to http://dev.jquery.com/ticket/3113 as there is a form with a field called
236 // action when creating an activity266 // action when creating an activity
237 $form[0].setAttribute('action', action);267 $form[0].setAttribute('action', action);
@@ -384,10 +414,16 @@
384 return;414 return;
385 }415 }
386416
417 // sure value is server-parseable in case of translated date/datetime fields
418 var this_value = this.value;
419 if ($this.attr('kind') == 'date' || $this.attr('kind') == 'datetime') {
420 this_value = datetime_get_server_value(this);
421 }
422
387 if (extended && name.indexOf('/__id') == -1) {423 if (extended && name.indexOf('/__id') == -1) {
388 var attrs = {};424 var attrs = {};
389425
390 value = (is_editable ? this.value : $this.attr('value')) || "";426 value = (is_editable ? this_value : $this.attr('value')) || "";
391 var kind = $this.attr('kind') || "char";427 var kind = $this.attr('kind') || "char";
392428
393 //take care of _terp_id429 //take care of _terp_id
@@ -440,7 +476,7 @@
440476
441 }477 }
442 else {478 else {
443 frm[name] = this.value;479 frm[name] = this_value;
444 }480 }
445 });481 });
446482
@@ -532,11 +568,17 @@
532 return;568 return;
533 }569 }
534570
571 var caller_value = $caller.val();
572 if ($caller.attr('kind') == 'date' || $caller.attr('datetime')) {
573 // make sure date/dateime value is parseable by server
574 caller_value = datetime_get_server_value($caller[0]);
575 }
576
535 openobject.http.postJSON(post_url, jQuery.extend({}, form_data, {577 openobject.http.postJSON(post_url, jQuery.extend({}, form_data, {
536 _terp_callback: callback,578 _terp_callback: callback,
537 _terp_change_default: change_default,579 _terp_change_default: change_default,
538 _terp_caller: $caller.attr('id').slice(id_slice_offset),580 _terp_caller: $caller.attr('id').slice(id_slice_offset),
539 _terp_value: $caller.val(),581 _terp_value: caller_value,
540 _terp_model: select('_terp_model').val(),582 _terp_model: select('_terp_model').val(),
541 _terp_context: select('_terp_context').val(),583 _terp_context: select('_terp_context').val(),
542 id: select('_terp_id').val()584 id: select('_terp_id').val()
543585
=== modified file 'addons/openerp/static/javascript/o2m.js'
--- addons/openerp/static/javascript/o2m.js 2012-08-24 10:26:51 +0000
+++ addons/openerp/static/javascript/o2m.js 2013-04-09 14:55:26 +0000
@@ -333,6 +333,10 @@
333 if(!attr) { return; }333 if(!attr) { return; }
334 attrs[attribute] = attr;334 attrs[attribute] = attr;
335 });335 });
336 // copy special 'format' attribute for date/datetime fields
337 if ($this.attr('kind') == 'date' || $this.attr('kind') == 'datetime') {
338 attrs[format] = $this.attr('format');
339 }
336 $form.append($('<input>', $.extend(attrs, {340 $form.append($('<input>', $.extend(attrs, {
337 type: 'hidden',341 type: 'hidden',
338 disabled: 'disabled',342 disabled: 'disabled',
339343
=== modified file 'addons/openerp/static/jscal/calendar.js'
--- addons/openerp/static/jscal/calendar.js 2011-01-07 16:14:12 +0000
+++ addons/openerp/static/jscal/calendar.js 2013-04-09 14:55:26 +0000
@@ -1587,7 +1587,9 @@
1587 var y = 0;1587 var y = 0;
1588 var m = -1;1588 var m = -1;
1589 var d = 0;1589 var d = 0;
1590 var a = str.split(/\W+/);1590 // FIXME: improve this to handle all language from 'data' folder
1591 // currently only work for french
1592 var a = str.split(/[^A-Za-z0-9_éû]+/);
1591 var b = fmt.match(/%./g);1593 var b = fmt.match(/%./g);
1592 var i = 0, j = 0;1594 var i = 0, j = 0;
1593 var hr = 0;1595 var hr = 0;
15941596
=== modified file 'addons/openerp/static/jscal/lang/calendar-fr.js'
--- addons/openerp/static/jscal/lang/calendar-fr.js 2009-04-13 14:25:09 +0000
+++ addons/openerp/static/jscal/lang/calendar-fr.js 2013-04-09 14:55:26 +0000
@@ -8,25 +8,25 @@
88
9// full day names9// full day names
10Calendar._DN = new Array10Calendar._DN = new Array
11("Dimanche",11("dimanche",
12 "Lundi",12 "lundi",
13 "Mardi",13 "mardi",
14 "Mercredi",14 "mercredi",
15 "Jeudi",15 "jeudi",
16 "Vendredi",16 "vendredi",
17 "Samedi",17 "samedi",
18 "Dimanche");18 "dimanche");
1919
20// short day names20// short day names
21Calendar._SDN = new Array21Calendar._SDN = new Array
22("Dim.",22("dim.",
23 "Lun.",23 "lun.",
24 "Mar.",24 "mar.",
25 "Mer.",25 "mer.",
26 "Jeu.",26 "jeu.",
27 "Ven.",27 "ven.",
28 "Sam.",28 "sam.",
29 "Dim.");29 "dim.");
3030
31// First day of the week. "0" means display Sunday first, "1" means display31// First day of the week. "0" means display Sunday first, "1" means display
32// Monday first, etc.32// Monday first, etc.
@@ -34,33 +34,33 @@
3434
35// full month names35// full month names
36Calendar._MN = new Array36Calendar._MN = new Array
37("Janvier",37("janvier",
38 "Février",38 "février",
39 "Mars",39 "mars",
40 "Avril",40 "avril",
41 "Mai",41 "mai",
42 "Juin",42 "juin",
43 "Juillet",43 "juillet",
44 "Août",44 "août",
45 "Septembre",45 "septembre",
46 "Octobre",46 "octobre",
47 "Novembre",47 "novembre",
48 "Décembre");48 "décembre");
4949
50// short month names50// short month names
51Calendar._SMN = new Array51Calendar._SMN = new Array
52("Janv.",52("janv.",
53 "Févr.",53 "févr.",
54 "Mars",54 "mars",
55 "Avril",55 "avril",
56 "Mai",56 "mai",
57 "Juin",57 "juin",
58 "Juil.",58 "juil.",
59 "Août",59 "août",
60 "Sept.",60 "sept.",
61 "Oct.",61 "oct.",
62 "Nov.",62 "nov.",
63 "Déc.");63 "déc.");
6464
65// tooltips65// tooltips
66Calendar._TT = {};66Calendar._TT = {};
6767
=== modified file 'addons/openerp/validators.py'
--- addons/openerp/validators.py 2012-07-30 08:07:39 +0000
+++ addons/openerp/validators.py 2013-04-09 14:55:26 +0000
@@ -116,14 +116,14 @@
116 self.kind = kind116 self.kind = kind
117117
118 def _to_python(self, value, state):118 def _to_python(self, value, state):
119 # do validation119 try:
120 try:120 if value:
121 res = time.strptime(value, self.format)121 value = value.strip()
122 except ValueError:122 # do validation and convert value
123 raise formencode.api.Invalid(_('Invalid datetime format'), value, state)123 res = format.parse_datetime(value, kind=self.kind)
124 # return str instead of real datetime object124 if value and not res:
125 try:125 raise ValueError() # validation failed
126 return format.parse_datetime(value, kind=self.kind)126 return res
127 except ValueError:127 except ValueError:
128 raise formencode.api.Invalid(_('Invalid datetime format'), value, state)128 raise formencode.api.Invalid(_('Invalid datetime format'), value, state)
129129
130130
=== modified file 'addons/openerp/widgets/form/_form.py'
--- addons/openerp/widgets/form/_form.py 2012-02-29 07:24:24 +0000
+++ addons/openerp/widgets/form/_form.py 2013-04-09 14:55:26 +0000
@@ -597,7 +597,7 @@
597class Hidden(TinyInputWidget):597class Hidden(TinyInputWidget):
598 template = "/openerp/widgets/form/templates/hidden.mako"598 template = "/openerp/widgets/form/templates/hidden.mako"
599599
600 params = ['relation', 'field_id']600 params = ['relation', 'field_id', 'date_format']
601 member_widgets = ['widget']601 member_widgets = ['widget']
602602
603 def __init__(self, **attrs):603 def __init__(self, **attrs):
@@ -607,6 +607,10 @@
607 self.validator = self.widget.validator607 self.validator = self.widget.validator
608 self.relation = attrs.get('relation') or None608 self.relation = attrs.get('relation') or None
609 self.editable = self.readonly609 self.editable = self.readonly
610 self.date_format = None
611 if kind in ('date', 'datetime'):
612 self.date_format = format.get_datetime_format(kind)
613
610 if 'field_id' not in attrs:614 if 'field_id' not in attrs:
611 self.field_id = self.name615 self.field_id = self.name
612616
613617
=== modified file 'addons/openerp/widgets/form/templates/datetime.mako'
--- addons/openerp/widgets/form/templates/datetime.mako 2011-11-23 08:40:36 +0000
+++ addons/openerp/widgets/form/templates/datetime.mako 2013-04-09 14:55:26 +0000
@@ -1,6 +1,6 @@
1% if editable:1% if editable:
2 <input type="text" id="${name}" name="${name}" autocomplete="OFF" size="3"2 <input type="text" id="${name}" name="${name}" autocomplete="OFF" size="3"
3 class="${css_class}" ${py.attrs(attrs, kind=kind, value=value)}/>3 class="${css_class}" ${py.attrs(attrs, kind=kind, value=value, format=format)}/>
4 % if error:4 % if error:
5 <span class="fielderror">${error}</span>5 <span class="fielderror">${error}</span>
6 % endif6 % endif
77
=== modified file 'addons/openerp/widgets/form/templates/hidden.mako'
--- addons/openerp/widgets/form/templates/hidden.mako 2010-12-13 06:03:56 +0000
+++ addons/openerp/widgets/form/templates/hidden.mako 2013-04-09 14:55:26 +0000
@@ -1,2 +1,2 @@
1<input type="hidden" name="${name}" class="${css_class}" value="${value}"1<input type="hidden" name="${name}" class="${css_class}" value="${value}"
2 ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value)}/>2 ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value, format=date_format)}/>
33
=== modified file 'addons/openerp/widgets/listgrid.py'
--- addons/openerp/widgets/listgrid.py 2012-11-15 12:41:38 +0000
+++ addons/openerp/widgets/listgrid.py 2013-04-09 14:55:26 +0000
@@ -707,7 +707,7 @@
707class Hidden(TinyInputWidget):707class Hidden(TinyInputWidget):
708 template = "openerp/widgets/templates/listgrid/hidden.mako"708 template = "openerp/widgets/templates/listgrid/hidden.mako"
709709
710 params = ['relation', 'field_id']710 params = ['relation', 'field_id', 'date_format']
711 member_widgets = ['widget']711 member_widgets = ['widget']
712712
713 def __init__(self, **attrs):713 def __init__(self, **attrs):
@@ -718,6 +718,9 @@
718 self.relation = attrs.get('relation') or None718 self.relation = attrs.get('relation') or None
719 self.editable = self.readonly719 self.editable = self.readonly
720 self.color = None720 self.color = None
721 self.date_format = None
722 if kind in ('date', 'datetime'):
723 self.date_format = format.get_datetime_format(kind)
721 if 'field_id' not in attrs:724 if 'field_id' not in attrs:
722 self.field_id = self.name725 self.field_id = self.name
723726
724727
=== modified file 'addons/openerp/widgets/templates/listgrid/hidden.mako'
--- addons/openerp/widgets/templates/listgrid/hidden.mako 2010-12-31 09:49:30 +0000
+++ addons/openerp/widgets/templates/listgrid/hidden.mako 2013-04-09 14:55:26 +0000
@@ -1,2 +1,2 @@
1<input type="hidden" name="${name}" class="${css_class}" value="${value}" disabled="True"1<input type="hidden" name="${name}" class="${css_class}" value="${value}" disabled="True"
2 ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value)}/>2 ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value, format=date_format)}/>
33
=== modified file 'openobject/i18n/format.py'
--- openobject/i18n/format.py 2011-12-02 10:38:29 +0000
+++ openobject/i18n/format.py 2013-04-09 14:55:26 +0000
@@ -44,6 +44,15 @@
4444
45__pat = re.compile("%\(([dMy]+)\)s")45__pat = re.compile("%\(([dMy]+)\)s")
46__sub = {'d': '%d', 'M': '%m', 'y': '%Y'}46__sub = {'d': '%d', 'M': '%m', 'y': '%Y'}
47
48__mdname_format_regexp = re.compile('(%a|%b|%A|%B)')
49__mdname_format_ldml_map = {
50 '%a': 'ddd',
51 '%A': 'dddd',
52 '%b': 'MMM',
53 '%B': 'MMMM',
54}
55
47def _to_posix_format(format):56def _to_posix_format(format):
48 """Convert LDML format string to posix format string.57 """Convert LDML format string to posix format string.
49 """58 """
@@ -52,6 +61,14 @@
52def format_date_custom(dt, fmt="y-M-d"):61def format_date_custom(dt, fmt="y-M-d"):
53 return dates.format_date(dt, format=fmt, locale=get_locale())62 return dates.format_date(dt, format=fmt, locale=get_locale())
5463
64def format_date_localized(dt, local_format):
65 mdname_formats = set(__mdname_format_regexp.findall(local_format))
66 for format in mdname_formats:
67 format_local_value = dates.format_datetime(dt,
68 __mdname_format_ldml_map[format], locale=get_locale())
69 local_format = local_format.replace(format, format_local_value)
70 return unicode(dt.strftime(local_format.encode('utf-8')), 'utf-8')
71
55def get_datetime_format(kind="datetime"):72def get_datetime_format(kind="datetime"):
56 """Get local datetime format.73 """Get local datetime format.
5774
@@ -72,7 +89,7 @@
72 # TODO: correctly convert from LDML to POSIX datetime formatting89 # TODO: correctly convert from LDML to POSIX datetime formatting
73 # current converter is trivial and lame and probably very easy to break90 # current converter is trivial and lame and probably very easy to break
74 date_format = _to_posix_format(dates.get_date_format(91 date_format = _to_posix_format(dates.get_date_format(
75 format='short', locale=get_locale())).format92 format='short', locale=get_locale()).format)
76 if kind == 'time':93 if kind == 'time':
77 # Should use dates.get_time_format(locale=get_locale())94 # Should use dates.get_time_format(locale=get_locale())
78 return '%H:%M:%S'95 return '%H:%M:%S'
@@ -129,7 +146,7 @@
129 value = ustr(value)146 value = ustr(value)
130 try:147 try:
131 value = DT.datetime.strptime(value[:10], server_format)148 value = DT.datetime.strptime(value[:10], server_format)
132 return value.strftime(local_format)149 return format_date_localized(value, local_format)
133 except:150 except:
134 return ''151 return ''
135152
@@ -157,7 +174,8 @@
157 if as_timetuple:174 if as_timetuple:
158 return value175 return value
159176
160 return time.strftime(local_format, value)177 value_dt = DT.datetime(*value[:6])
178 return format_date_localized(value_dt, local_format)
161179
162def parse_datetime(value, kind="datetime", as_timetuple=False):180def parse_datetime(value, kind="datetime", as_timetuple=False):
163 """Convert date value to the server datetime considering timezone info.181 """Convert date value to the server datetime considering timezone info.