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
1=== modified file 'addons/openerp/static/javascript/form.js'
2--- addons/openerp/static/javascript/form.js 2012-10-15 13:19:24 +0000
3+++ addons/openerp/static/javascript/form.js 2013-04-09 14:55:26 +0000
4@@ -26,6 +26,26 @@
5 return openobject.http.getURL(act, params);
6 }
7
8+function datetime_get_server_value(elem, format) {
9+ var $elem = jQuery(elem);
10+ var field_date_format = $elem.attr('format') || '';
11+ if (!field_date_format.match(/(%a|%b|%A|%B)/)) {
12+ return elem.value;
13+ }
14+ // convert it back to str and compare to original value to determine
15+ // if this a value set by jscal Calendar - or server/user input. In
16+ // last case - keep the original value intact - in all other case
17+ // we change the input value to match the server-format because depending
18+ // on the language we might not be able to parse month or day of week names
19+ var field_date = Date.parseDate(elem.value, field_date_format);
20+ var field_date_str = field_date.print(field_date_format);
21+ if (field_date_str == elem.value) {
22+ var server_date_format = $elem.attr('kind') == 'date' ? '%Y-%m-%d' : '%Y-%m-%d %H:%M:%S';
23+ return field_date.print(server_date_format);
24+ }
25+ return elem.value;
26+}
27+
28 function openRecord(id, src, target, readonly){
29
30 var kind = getNodeAttribute(src + '_set', 'kind');
31@@ -232,6 +252,16 @@
32 return;
33 }
34
35+ $form.find('input[kind^="date"]').each(function(i, f) {
36+ if (!this.value ||
37+ !(this.getAttribute('kind') == 'date'
38+ || this.getAttribute('kind') == 'datetime')) {
39+ return; // skip input having no
40+ }
41+ // make sure date/datetime value is parseable by server
42+ this.value = datetime_get_server_value(this);
43+ });
44+
45 // Cant use $form.attr due to http://dev.jquery.com/ticket/3113 as there is a form with a field called
46 // action when creating an activity
47 $form[0].setAttribute('action', action);
48@@ -384,10 +414,16 @@
49 return;
50 }
51
52+ // sure value is server-parseable in case of translated date/datetime fields
53+ var this_value = this.value;
54+ if ($this.attr('kind') == 'date' || $this.attr('kind') == 'datetime') {
55+ this_value = datetime_get_server_value(this);
56+ }
57+
58 if (extended && name.indexOf('/__id') == -1) {
59 var attrs = {};
60
61- value = (is_editable ? this.value : $this.attr('value')) || "";
62+ value = (is_editable ? this_value : $this.attr('value')) || "";
63 var kind = $this.attr('kind') || "char";
64
65 //take care of _terp_id
66@@ -440,7 +476,7 @@
67
68 }
69 else {
70- frm[name] = this.value;
71+ frm[name] = this_value;
72 }
73 });
74
75@@ -532,11 +568,17 @@
76 return;
77 }
78
79+ var caller_value = $caller.val();
80+ if ($caller.attr('kind') == 'date' || $caller.attr('datetime')) {
81+ // make sure date/dateime value is parseable by server
82+ caller_value = datetime_get_server_value($caller[0]);
83+ }
84+
85 openobject.http.postJSON(post_url, jQuery.extend({}, form_data, {
86 _terp_callback: callback,
87 _terp_change_default: change_default,
88 _terp_caller: $caller.attr('id').slice(id_slice_offset),
89- _terp_value: $caller.val(),
90+ _terp_value: caller_value,
91 _terp_model: select('_terp_model').val(),
92 _terp_context: select('_terp_context').val(),
93 id: select('_terp_id').val()
94
95=== modified file 'addons/openerp/static/javascript/o2m.js'
96--- addons/openerp/static/javascript/o2m.js 2012-08-24 10:26:51 +0000
97+++ addons/openerp/static/javascript/o2m.js 2013-04-09 14:55:26 +0000
98@@ -333,6 +333,10 @@
99 if(!attr) { return; }
100 attrs[attribute] = attr;
101 });
102+ // copy special 'format' attribute for date/datetime fields
103+ if ($this.attr('kind') == 'date' || $this.attr('kind') == 'datetime') {
104+ attrs[format] = $this.attr('format');
105+ }
106 $form.append($('<input>', $.extend(attrs, {
107 type: 'hidden',
108 disabled: 'disabled',
109
110=== modified file 'addons/openerp/static/jscal/calendar.js'
111--- addons/openerp/static/jscal/calendar.js 2011-01-07 16:14:12 +0000
112+++ addons/openerp/static/jscal/calendar.js 2013-04-09 14:55:26 +0000
113@@ -1587,7 +1587,9 @@
114 var y = 0;
115 var m = -1;
116 var d = 0;
117- var a = str.split(/\W+/);
118+ // FIXME: improve this to handle all language from 'data' folder
119+ // currently only work for french
120+ var a = str.split(/[^A-Za-z0-9_éû]+/);
121 var b = fmt.match(/%./g);
122 var i = 0, j = 0;
123 var hr = 0;
124
125=== modified file 'addons/openerp/static/jscal/lang/calendar-fr.js'
126--- addons/openerp/static/jscal/lang/calendar-fr.js 2009-04-13 14:25:09 +0000
127+++ addons/openerp/static/jscal/lang/calendar-fr.js 2013-04-09 14:55:26 +0000
128@@ -8,25 +8,25 @@
129
130 // full day names
131 Calendar._DN = new Array
132-("Dimanche",
133- "Lundi",
134- "Mardi",
135- "Mercredi",
136- "Jeudi",
137- "Vendredi",
138- "Samedi",
139- "Dimanche");
140+("dimanche",
141+ "lundi",
142+ "mardi",
143+ "mercredi",
144+ "jeudi",
145+ "vendredi",
146+ "samedi",
147+ "dimanche");
148
149 // short day names
150 Calendar._SDN = new Array
151-("Dim.",
152- "Lun.",
153- "Mar.",
154- "Mer.",
155- "Jeu.",
156- "Ven.",
157- "Sam.",
158- "Dim.");
159+("dim.",
160+ "lun.",
161+ "mar.",
162+ "mer.",
163+ "jeu.",
164+ "ven.",
165+ "sam.",
166+ "dim.");
167
168 // First day of the week. "0" means display Sunday first, "1" means display
169 // Monday first, etc.
170@@ -34,33 +34,33 @@
171
172 // full month names
173 Calendar._MN = new Array
174-("Janvier",
175- "Février",
176- "Mars",
177- "Avril",
178- "Mai",
179- "Juin",
180- "Juillet",
181- "Août",
182- "Septembre",
183- "Octobre",
184- "Novembre",
185- "Décembre");
186+("janvier",
187+ "février",
188+ "mars",
189+ "avril",
190+ "mai",
191+ "juin",
192+ "juillet",
193+ "août",
194+ "septembre",
195+ "octobre",
196+ "novembre",
197+ "décembre");
198
199 // short month names
200 Calendar._SMN = new Array
201-("Janv.",
202- "Févr.",
203- "Mars",
204- "Avril",
205- "Mai",
206- "Juin",
207- "Juil.",
208- "Août",
209- "Sept.",
210- "Oct.",
211- "Nov.",
212- "Déc.");
213+("janv.",
214+ "févr.",
215+ "mars",
216+ "avril",
217+ "mai",
218+ "juin",
219+ "juil.",
220+ "août",
221+ "sept.",
222+ "oct.",
223+ "nov.",
224+ "déc.");
225
226 // tooltips
227 Calendar._TT = {};
228
229=== modified file 'addons/openerp/validators.py'
230--- addons/openerp/validators.py 2012-07-30 08:07:39 +0000
231+++ addons/openerp/validators.py 2013-04-09 14:55:26 +0000
232@@ -116,14 +116,14 @@
233 self.kind = kind
234
235 def _to_python(self, value, state):
236- # do validation
237- try:
238- res = time.strptime(value, self.format)
239- except ValueError:
240- raise formencode.api.Invalid(_('Invalid datetime format'), value, state)
241- # return str instead of real datetime object
242- try:
243- return format.parse_datetime(value, kind=self.kind)
244+ try:
245+ if value:
246+ value = value.strip()
247+ # do validation and convert value
248+ res = format.parse_datetime(value, kind=self.kind)
249+ if value and not res:
250+ raise ValueError() # validation failed
251+ return res
252 except ValueError:
253 raise formencode.api.Invalid(_('Invalid datetime format'), value, state)
254
255
256=== modified file 'addons/openerp/widgets/form/_form.py'
257--- addons/openerp/widgets/form/_form.py 2012-02-29 07:24:24 +0000
258+++ addons/openerp/widgets/form/_form.py 2013-04-09 14:55:26 +0000
259@@ -597,7 +597,7 @@
260 class Hidden(TinyInputWidget):
261 template = "/openerp/widgets/form/templates/hidden.mako"
262
263- params = ['relation', 'field_id']
264+ params = ['relation', 'field_id', 'date_format']
265 member_widgets = ['widget']
266
267 def __init__(self, **attrs):
268@@ -607,6 +607,10 @@
269 self.validator = self.widget.validator
270 self.relation = attrs.get('relation') or None
271 self.editable = self.readonly
272+ self.date_format = None
273+ if kind in ('date', 'datetime'):
274+ self.date_format = format.get_datetime_format(kind)
275+
276 if 'field_id' not in attrs:
277 self.field_id = self.name
278
279
280=== modified file 'addons/openerp/widgets/form/templates/datetime.mako'
281--- addons/openerp/widgets/form/templates/datetime.mako 2011-11-23 08:40:36 +0000
282+++ addons/openerp/widgets/form/templates/datetime.mako 2013-04-09 14:55:26 +0000
283@@ -1,6 +1,6 @@
284 % if editable:
285 <input type="text" id="${name}" name="${name}" autocomplete="OFF" size="3"
286- class="${css_class}" ${py.attrs(attrs, kind=kind, value=value)}/>
287+ class="${css_class}" ${py.attrs(attrs, kind=kind, value=value, format=format)}/>
288 % if error:
289 <span class="fielderror">${error}</span>
290 % endif
291
292=== modified file 'addons/openerp/widgets/form/templates/hidden.mako'
293--- addons/openerp/widgets/form/templates/hidden.mako 2010-12-13 06:03:56 +0000
294+++ addons/openerp/widgets/form/templates/hidden.mako 2013-04-09 14:55:26 +0000
295@@ -1,2 +1,2 @@
296 <input type="hidden" name="${name}" class="${css_class}" value="${value}"
297- ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value)}/>
298+ ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value, format=date_format)}/>
299
300=== modified file 'addons/openerp/widgets/listgrid.py'
301--- addons/openerp/widgets/listgrid.py 2012-11-15 12:41:38 +0000
302+++ addons/openerp/widgets/listgrid.py 2013-04-09 14:55:26 +0000
303@@ -707,7 +707,7 @@
304 class Hidden(TinyInputWidget):
305 template = "openerp/widgets/templates/listgrid/hidden.mako"
306
307- params = ['relation', 'field_id']
308+ params = ['relation', 'field_id', 'date_format']
309 member_widgets = ['widget']
310
311 def __init__(self, **attrs):
312@@ -718,6 +718,9 @@
313 self.relation = attrs.get('relation') or None
314 self.editable = self.readonly
315 self.color = None
316+ self.date_format = None
317+ if kind in ('date', 'datetime'):
318+ self.date_format = format.get_datetime_format(kind)
319 if 'field_id' not in attrs:
320 self.field_id = self.name
321
322
323=== modified file 'addons/openerp/widgets/templates/listgrid/hidden.mako'
324--- addons/openerp/widgets/templates/listgrid/hidden.mako 2010-12-31 09:49:30 +0000
325+++ addons/openerp/widgets/templates/listgrid/hidden.mako 2013-04-09 14:55:26 +0000
326@@ -1,2 +1,2 @@
327 <input type="hidden" name="${name}" class="${css_class}" value="${value}" disabled="True"
328- ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value)}/>
329+ ${py.attrs(attrs, id=field_id, kind=kind, relation=relation, value=value, format=date_format)}/>
330
331=== modified file 'openobject/i18n/format.py'
332--- openobject/i18n/format.py 2011-12-02 10:38:29 +0000
333+++ openobject/i18n/format.py 2013-04-09 14:55:26 +0000
334@@ -44,6 +44,15 @@
335
336 __pat = re.compile("%\(([dMy]+)\)s")
337 __sub = {'d': '%d', 'M': '%m', 'y': '%Y'}
338+
339+__mdname_format_regexp = re.compile('(%a|%b|%A|%B)')
340+__mdname_format_ldml_map = {
341+ '%a': 'ddd',
342+ '%A': 'dddd',
343+ '%b': 'MMM',
344+ '%B': 'MMMM',
345+}
346+
347 def _to_posix_format(format):
348 """Convert LDML format string to posix format string.
349 """
350@@ -52,6 +61,14 @@
351 def format_date_custom(dt, fmt="y-M-d"):
352 return dates.format_date(dt, format=fmt, locale=get_locale())
353
354+def format_date_localized(dt, local_format):
355+ mdname_formats = set(__mdname_format_regexp.findall(local_format))
356+ for format in mdname_formats:
357+ format_local_value = dates.format_datetime(dt,
358+ __mdname_format_ldml_map[format], locale=get_locale())
359+ local_format = local_format.replace(format, format_local_value)
360+ return unicode(dt.strftime(local_format.encode('utf-8')), 'utf-8')
361+
362 def get_datetime_format(kind="datetime"):
363 """Get local datetime format.
364
365@@ -72,7 +89,7 @@
366 # TODO: correctly convert from LDML to POSIX datetime formatting
367 # current converter is trivial and lame and probably very easy to break
368 date_format = _to_posix_format(dates.get_date_format(
369- format='short', locale=get_locale())).format
370+ format='short', locale=get_locale()).format)
371 if kind == 'time':
372 # Should use dates.get_time_format(locale=get_locale())
373 return '%H:%M:%S'
374@@ -129,7 +146,7 @@
375 value = ustr(value)
376 try:
377 value = DT.datetime.strptime(value[:10], server_format)
378- return value.strftime(local_format)
379+ return format_date_localized(value, local_format)
380 except:
381 return ''
382
383@@ -157,7 +174,8 @@
384 if as_timetuple:
385 return value
386
387- return time.strftime(local_format, value)
388+ value_dt = DT.datetime(*value[:6])
389+ return format_date_localized(value_dt, local_format)
390
391 def parse_datetime(value, kind="datetime", as_timetuple=False):
392 """Convert date value to the server datetime considering timezone info.