diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py
index d304825bd64..adf61f5facc 100644
--- a/addons/web/__openerp__.py
+++ b/addons/web/__openerp__.py
@@ -11,6 +11,7 @@
"static/lib/datejs/sugarpak.js",
"static/lib/datejs/extras.js",
"static/lib/jquery/jquery-1.6.2.js",
+ "static/lib/jquery.MD5/jquery.md5.js",
"static/lib/jquery.form/jquery.form.js",
"static/lib/jquery.validate/jquery.validate.js",
"static/lib/jquery.ba-bbq/jquery.ba-bbq.js",
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index 8120141b4f6..6cc46b476a9 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -1412,7 +1412,7 @@ class Import(View):
return fields
@openerpweb.httprequest
- def detect_data(self, req, csvfile, csvsep, csvdel, csvcode, jsonp):
+ def detect_data(self, req, csvfile, csvsep=',', csvdel='"', csvcode='utf-8', jsonp='callback'):
try:
data = list(csv.reader(
csvfile, quotechar=str(csvdel), delimiter=str(csvsep)))
diff --git a/addons/web/po/da.po b/addons/web/po/da.po
index cefd844d49a..c0931065d1e 100644
--- a/addons/web/po/da.po
+++ b/addons/web/po/da.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-12 04:44+0000\n"
-"X-Generator: Launchpad (build 14124)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/de.po b/addons/web/po/de.po
index 027f34f9866..0a26630321f 100644
--- a/addons/web/po/de.po
+++ b/addons/web/po/de.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-11 05:42+0000\n"
-"X-Generator: Launchpad (build 14123)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/es.po b/addons/web/po/es.po
index 508b4e62245..9bd7071871b 100644
--- a/addons/web/po/es.po
+++ b/addons/web/po/es.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-20 04:48+0000\n"
-"X-Generator: Launchpad (build 14165)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/es_EC.po b/addons/web/po/es_EC.po
index eb2283f6fe5..588408ba979 100644
--- a/addons/web/po/es_EC.po
+++ b/addons/web/po/es_EC.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-08 05:29+0000\n"
-"X-Generator: Launchpad (build 14110)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/et.po b/addons/web/po/et.po
index 75269bf5cda..6b6da84f3a5 100644
--- a/addons/web/po/et.po
+++ b/addons/web/po/et.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-11 05:42+0000\n"
-"X-Generator: Launchpad (build 14123)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/fr.po b/addons/web/po/fr.po
index a4287a31030..df35344c558 100644
--- a/addons/web/po/fr.po
+++ b/addons/web/po/fr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-24 05:18+0000\n"
-"X-Generator: Launchpad (build 14185)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/gl.po b/addons/web/po/gl.po
index b43664b9bee..34b2d50085f 100644
--- a/addons/web/po/gl.po
+++ b/addons/web/po/gl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-20 04:48+0000\n"
-"X-Generator: Launchpad (build 14165)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/it.po b/addons/web/po/it.po
index fc53244533b..647030fd4ea 100644
--- a/addons/web/po/it.po
+++ b/addons/web/po/it.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-09 05:22+0000\n"
-"X-Generator: Launchpad (build 14110)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/nl_BE.po b/addons/web/po/nl_BE.po
index 2a2dccb1712..3d649b59b9d 100644
--- a/addons/web/po/nl_BE.po
+++ b/addons/web/po/nl_BE.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-08 05:29+0000\n"
-"X-Generator: Launchpad (build 14110)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/po/sl.po b/addons/web/po/sl.po
index bc63e7ff313..54349249817 100644
--- a/addons/web/po/sl.po
+++ b/addons/web/po/sl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2011-10-20 04:48+0000\n"
-"X-Generator: Launchpad (build 14165)\n"
+"X-Launchpad-Export-Date: 2011-11-01 05:09+0000\n"
+"X-Generator: Launchpad (build 14197)\n"
#: addons/web/static/src/js/view_form.js:355
msgid ""
diff --git a/addons/web/static/lib/jquery.MD5/README.md b/addons/web/static/lib/jquery.MD5/README.md
new file mode 100644
index 00000000000..88778a7a3bf
--- /dev/null
+++ b/addons/web/static/lib/jquery.MD5/README.md
@@ -0,0 +1,32 @@
+# jQuery MD5 Plugin
+
+## Usage
+Create ([hex](http://en.wikipedia.org/wiki/Hexadecimal)-encoded) [MD5](http://en.wikipedia.org/wiki/MD5) hash of a given string value:
+
+ var md5 = $.md5('value');
+
+Create ([hex](http://en.wikipedia.org/wiki/Hexadecimal)-encoded) [HMAC](http://en.wikipedia.org/wiki/HMAC)-MD5 hash of a given string value and key:
+
+ var md5 = $.md5('value', 'key');
+
+Create raw [MD5](http://en.wikipedia.org/wiki/MD5) hash of a given string value:
+
+ var md5 = $.md5('value', null, true);
+
+Create raw [HMAC](http://en.wikipedia.org/wiki/HMAC)-MD5 hash of a given string value and key:
+
+ var md5 = $.md5('value', 'key', true);
+
+## Requirements
+None.
+
+If [jQuery](http://jquery.com/) is not available, the md5 function will be added to the global object:
+
+ var md5 = md5('value');
+
+## License
+Released under the [MIT license](http://creativecommons.org/licenses/MIT/).
+
+## Source Code & Download
+* Browse and checkout the [source code](https://github.com/blueimp/jQuery-MD5).
+* [Download](https://github.com/blueimp/jQuery-MD5/archives/master) the project to add the plugin to your website.
diff --git a/addons/web/static/lib/jquery.MD5/README.txt b/addons/web/static/lib/jquery.MD5/README.txt
new file mode 100644
index 00000000000..8a8cbf4db2a
--- /dev/null
+++ b/addons/web/static/lib/jquery.MD5/README.txt
@@ -0,0 +1,32 @@
+jQuery MD5 Plugin
+=================
+
+Usage
+-----
+Create (hex-encoded) MD5 hash of a given string value:
+ var md5 = $.md5('value');
+
+Create (hex-encoded) HMAC-MD5 hash of a given string value and key:
+ var md5 = $.md5('value', 'key');
+
+Create raw MD5 hash of a given string value:
+ var md5 = $.md5('value', null, true);
+
+Create raw HMAC-MD5 hash of a given string value and key:
+ var md5 = $.md5('value', 'key', true);
+
+Requirements
+------------
+None.
+
+If jQuery is not available, the md5 function will be added to the global object:
+ var md5 = md5('value');
+
+License
+-------
+Released under the MIT license:
+http://creativecommons.org/licenses/MIT/
+
+Source Code & Download
+----------------------
+https://github.com/blueimp/jQuery-MD5
diff --git a/addons/web/static/lib/jquery.MD5/jquery.md5.js b/addons/web/static/lib/jquery.MD5/jquery.md5.js
new file mode 100644
index 00000000000..bf9bbe97b55
--- /dev/null
+++ b/addons/web/static/lib/jquery.MD5/jquery.md5.js
@@ -0,0 +1,269 @@
+/*
+ * jQuery MD5 Plugin 1.2.1
+ * https://github.com/blueimp/jQuery-MD5
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://creativecommons.org/licenses/MIT/
+ *
+ * Based on
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*jslint bitwise: true */
+/*global unescape, jQuery */
+
+(function ($) {
+ 'use strict';
+
+ /*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+ function safe_add(x, y) {
+ var lsw = (x & 0xFFFF) + (y & 0xFFFF),
+ msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+ return (msw << 16) | (lsw & 0xFFFF);
+ }
+
+ /*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+ function bit_rol(num, cnt) {
+ return (num << cnt) | (num >>> (32 - cnt));
+ }
+
+ /*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+ function md5_cmn(q, a, b, x, s, t) {
+ return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
+ }
+ function md5_ff(a, b, c, d, x, s, t) {
+ return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+ }
+ function md5_gg(a, b, c, d, x, s, t) {
+ return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+ }
+ function md5_hh(a, b, c, d, x, s, t) {
+ return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+ }
+ function md5_ii(a, b, c, d, x, s, t) {
+ return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+ }
+
+ /*
+ * Calculate the MD5 of an array of little-endian words, and a bit length.
+ */
+ function binl_md5(x, len) {
+ /* append padding */
+ x[len >> 5] |= 0x80 << ((len) % 32);
+ x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+ var i, olda, oldb, oldc, oldd,
+ a = 1732584193,
+ b = -271733879,
+ c = -1732584194,
+ d = 271733878;
+
+ for (i = 0; i < x.length; i += 16) {
+ olda = a;
+ oldb = b;
+ oldc = c;
+ oldd = d;
+
+ a = md5_ff(a, b, c, d, x[i], 7, -680876936);
+ d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
+ c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
+ b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
+ a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
+ d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
+ c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
+ b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
+ a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
+ d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
+ c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
+ b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
+ a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
+ d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
+ c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
+ b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
+
+ a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
+ d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
+ c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
+ b = md5_gg(b, c, d, a, x[i], 20, -373897302);
+ a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
+ d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
+ c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
+ b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
+ a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
+ d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
+ c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
+ b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
+ a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
+ d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
+ c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
+ b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
+
+ a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
+ d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
+ c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
+ b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
+ a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
+ d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
+ c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
+ b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
+ a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
+ d = md5_hh(d, a, b, c, x[i], 11, -358537222);
+ c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
+ b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
+ a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
+ d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
+ c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
+ b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
+
+ a = md5_ii(a, b, c, d, x[i], 6, -198630844);
+ d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
+ c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
+ b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
+ a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
+ d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
+ c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
+ b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
+ a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
+ d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
+ c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
+ b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
+ a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
+ d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
+ c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
+ b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
+
+ a = safe_add(a, olda);
+ b = safe_add(b, oldb);
+ c = safe_add(c, oldc);
+ d = safe_add(d, oldd);
+ }
+ return [a, b, c, d];
+ }
+
+ /*
+ * Convert an array of little-endian words to a string
+ */
+ function binl2rstr(input) {
+ var i,
+ output = '';
+ for (i = 0; i < input.length * 32; i += 8) {
+ output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
+ }
+ return output;
+ }
+
+ /*
+ * Convert a raw string to an array of little-endian words
+ * Characters >255 have their high-byte silently ignored.
+ */
+ function rstr2binl(input) {
+ var i,
+ output = [];
+ output[(input.length >> 2) - 1] = undefined;
+ for (i = 0; i < output.length; i += 1) {
+ output[i] = 0;
+ }
+ for (i = 0; i < input.length * 8; i += 8) {
+ output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
+ }
+ return output;
+ }
+
+ /*
+ * Calculate the MD5 of a raw string
+ */
+ function rstr_md5(s) {
+ return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
+ }
+
+ /*
+ * Calculate the HMAC-MD5, of a key and some data (raw strings)
+ */
+ function rstr_hmac_md5(key, data) {
+ var i,
+ bkey = rstr2binl(key),
+ ipad = [],
+ opad = [],
+ hash;
+ ipad[15] = opad[15] = undefined;
+ if (bkey.length > 16) {
+ bkey = binl_md5(bkey, key.length * 8);
+ }
+ for (i = 0; i < 16; i += 1) {
+ ipad[i] = bkey[i] ^ 0x36363636;
+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
+ }
+ hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
+ return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
+ }
+
+ /*
+ * Convert a raw string to a hex string
+ */
+ function rstr2hex(input) {
+ var hex_tab = '0123456789abcdef',
+ output = '',
+ x,
+ i;
+ for (i = 0; i < input.length; i += 1) {
+ x = input.charCodeAt(i);
+ output += hex_tab.charAt((x >>> 4) & 0x0F) +
+ hex_tab.charAt(x & 0x0F);
+ }
+ return output;
+ }
+
+ /*
+ * Encode a string as utf-8
+ */
+ function str2rstr_utf8(input) {
+ return unescape(encodeURIComponent(input));
+ }
+
+ /*
+ * Take string arguments and return either raw or hex encoded strings
+ */
+ function raw_md5(s) {
+ return rstr_md5(str2rstr_utf8(s));
+ }
+ function hex_md5(s) {
+ return rstr2hex(raw_md5(s));
+ }
+ function raw_hmac_md5(k, d) {
+ return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d));
+ }
+ function hex_hmac_md5(k, d) {
+ return rstr2hex(raw_hmac_md5(k, d));
+ }
+
+ $.md5 = function (string, key, raw) {
+ if (!key) {
+ if (!raw) {
+ return hex_md5(string);
+ } else {
+ return raw_md5(string);
+ }
+ }
+ if (!raw) {
+ return hex_hmac_md5(key, string);
+ } else {
+ return raw_hmac_md5(key, string);
+ }
+ };
+
+}(typeof jQuery === 'function' ? jQuery : this));
\ No newline at end of file
diff --git a/addons/web/static/lib/jquery.MD5/tests/index.html b/addons/web/static/lib/jquery.MD5/tests/index.html
new file mode 100644
index 00000000000..27ba8d3607d
--- /dev/null
+++ b/addons/web/static/lib/jquery.MD5/tests/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+jQuery MD5 Plugin Tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/web/static/lib/jquery.MD5/tests/tests.js b/addons/web/static/lib/jquery.MD5/tests/tests.js
new file mode 100644
index 00000000000..ab70f2f991b
--- /dev/null
+++ b/addons/web/static/lib/jquery.MD5/tests/tests.js
@@ -0,0 +1,57 @@
+/*
+ * jQuery MD5 Plugin Tests 1.1
+ * https://github.com/blueimp/jQuery-MD5
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://creativecommons.org/licenses/MIT/
+ */
+
+/*global jQuery, module, test, strictEqual */
+
+(function ($) {
+ 'use strict';
+
+ module('Hex-encoded MD5');
+
+ test('Creating hex-encoded MD5 hash of an ASCII value', function () {
+ strictEqual($.md5('value'), '2063c1608d6e0baf80249c42e2be5804');
+ });
+
+ test('Creating hex-encoded MD5 hash of an UTF-8 value', function () {
+ strictEqual($.md5('日本'), '4dbed2e657457884e67137d3514119b3');
+ });
+
+ module('Hex-encoded HMAC-MD5');
+
+ test('Creating hex-encoded HMAC-MD5 hash of an ASCII value and key', function () {
+ strictEqual($.md5('value', 'key'), '01433efd5f16327ea4b31144572c67f6');
+ });
+
+ test('Creating hex-encoded HMAC-MD5 hash of an UTF-8 value and key', function () {
+ strictEqual($.md5('日本', '日本'), 'c78b8c7357926981cc04740bd3e9d015');
+ });
+
+ module('Raw MD5');
+
+ test('Creating raw MD5 hash of an ASCII value', function () {
+ strictEqual($.md5('value', null, true), ' c\xc1`\x8dn\x0b\xaf\x80$\x9cB\xe2\xbeX\x04');
+ });
+
+ test('Creating raw MD5 hash of an UTF-8 value', function () {
+ strictEqual($.md5('日本', null, true), 'M\xbe\xd2\xe6WEx\x84\xe6q7\xd3QA\x19\xb3');
+ });
+
+ module('Raw HMAC-MD5');
+
+ test('Creating raw HMAC-MD5 hash of an ASCII value and key', function () {
+ strictEqual($.md5('value', 'key', true), '\x01C>\xfd_\x162~\xa4\xb3\x11DW,g\xf6');
+ });
+
+ test('Creating raw HMAC-MD5 hash of an UTF-8 value and key', function () {
+ strictEqual($.md5('日本', '日本', true), '\xc7\x8b\x8csW\x92i\x81\xcc\x04t\x0b\xd3\xe9\xd0\x15');
+ });
+
+}(typeof jQuery === 'function' ? jQuery : this));
\ No newline at end of file
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 34ec885b2a9..3430dfe196a 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -846,7 +846,7 @@ label.error {
.openerp .oe_frame.oe_forms {
clear: both;
}
-.openerp table.oe_frame td {
+.openerp table.oe_frame {
color: #4c4c4c;
}
.openerp td.oe_form_frame_cell {
@@ -874,7 +874,6 @@ label.error {
}
.openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help {
- text-align: right;
margin: 3px 0 0 10px;
}
.openerp label.oe_label_help span {
@@ -885,6 +884,18 @@ label.error {
top: -4px;
padding: 0 2px;
}
+.openerp .oe_align_left {
+ text-align: left;
+}
+.openerp .oe_align_right {
+ text-align: right;
+}
+.openerp .oe_align_center {
+ text-align: center;
+}
+.openerp .oe_forms .oe_form_paragraph {
+ margin: 3px 0 0 0;
+}
/* Inputs */
.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms textarea {
@@ -1410,12 +1421,30 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
border-color: rgba(0,0,0,0);
border-left-color: #B5B9FF;
}
-.openerp .view_editor{
+.openerp .oe_view_editor {
+ border-collapse: collapse;
+ padding: 0;
+ align: left;
+ width: 100%;
+}
+.openerp .oe_view_editor_colum{
font-size: 90%;
font-weight: normal;
- height : 10%;
padding: 0;
border-bottom: 1px solid #CFCCCC;
}
-
-
+.openerp .oe_view_editor_row:hover{
+ background-color: #F3F3F3;
+}
+.openerp .oe_view_editor_tree_grid{
+ text-align: left;
+ white-space: nowrap;
+ border-collapse: collapse;
+ width: 100%;
+}
+.openerp .oe_view_editor_tree_grid a:hover {
+ color: blue;
+}
+.openerp .oe_view_editor_tree_grid a {
+ display: block;
+}
diff --git a/addons/web/static/src/css/data_import.css b/addons/web/static/src/css/data_import.css
index 1fb3b22aa45..e5d1c9a910c 100644
--- a/addons/web/static/src/css/data_import.css
+++ b/addons/web/static/src/css/data_import.css
@@ -11,6 +11,22 @@
.openerp .oe_import_grid-row .oe_import_grid-cell {
border-bottom: 1px solid #E3E3E3;
}
+
+.openerp .oe-import-no-result .oe-import-result {
+ display: none;
+}
+.openerp .oe-import fieldset {
+ cursor: pointer;
+}
+.openerp .oe-import fieldset legend:before {
+ content: '\25BC ';
+}
+.openerp .oe-import fieldset.oe-closed legend:before {
+ content: '\25B6 ';
+}
+.openerp .oe-import fieldset.oe-closed table {
+ display: none;
+}
.openerp .separator.horizontal {
font-weight: bold;
border-bottom-width: 1px;
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index bdb8e23c20b..22c2b0ba2ea 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -29,11 +29,11 @@ openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Not
warn: function(title, text) {
this.$element.notify('create', 'oe_notification_alert', {
title: title,
- text: text,
+ text: text
}, {
- expires: false,
+ expires: false
});
- },
+ }
});
@@ -195,10 +195,20 @@ openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading#
init: function(parent, element_id) {
this._super(parent, element_id);
this.count = 0;
+ this.blocked_ui = false;
this.session.on_rpc_request.add_first(this.on_rpc_event, 1);
this.session.on_rpc_response.add_last(this.on_rpc_event, -1);
},
on_rpc_event : function(increment) {
+ var self = this;
+ if (!this.count && increment === 1) {
+ // Block UI after 3s
+ this.long_running_timer = setTimeout(function () {
+ self.blocked_ui = true;
+ $.blockUI();
+ }, 3000);
+ }
+
this.count += increment;
if (this.count) {
//this.$element.html(QWeb.render("Loading", {}));
@@ -206,6 +216,12 @@ openerp.web.Loading = openerp.web.Widget.extend(/** @lends openerp.web.Loading#
this.$element.show();
this.widget_parent.$element.addClass('loading');
} else {
+ clearTimeout(this.long_running_timer);
+ // Don't unblock if blocked by somebody else
+ if (self.blocked_ui) {
+ this.blocked_ui = false;
+ $.unblockUI();
+ }
this.$element.fadeOut();
this.widget_parent.$element.removeClass('loading');
}
@@ -343,7 +359,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
self.$option_id.find("form[name=create_db_form]").validate({
submitHandler: function (form) {
var fields = $(form).serializeArray();
- $.blockUI({message:''});
+ $.blockUI();
self.rpc("/web/database/create", {'fields': fields}, function(result) {
if (result.error) {
$.unblockUI();
@@ -392,7 +408,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
.html(QWeb.render("BackupDB", self))
.find("form[name=backup_db_form]").validate({
submitHandler: function (form) {
- $.blockUI({message:''});
+ $.blockUI();
self.session.get_file({
form: form,
error: function (body) {
@@ -413,7 +429,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
self.$option_id.find("form[name=restore_db_form]").validate({
submitHandler: function (form) {
- $.blockUI({message:''});
+ $.blockUI();
$(form).ajaxSubmit({
url: '/web/database/restore',
type: 'POST',
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index 39a1ba7ef64..9563abea49a 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -1043,9 +1043,16 @@ openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.we
}
});
+if ($.blockUI) {
+ $.blockUI.defaults.baseZ = 1100;
+ $.blockUI.defaults.message = '';
+}
openerp.web._t = new openerp.web.TranslationDataBase().build_translation_function();
openerp.web.qweb = new QWeb2.Engine();
openerp.web.qweb.debug = (window.location.search.indexOf('?debug') !== -1);
+openerp.web.qweb.default_dict = {
+ '_' : _
+}
openerp.web.qweb.format_text_node = function(s) {
// Note that 'this' is the Qweb Node of the text
var translation = this.node.parentNode.attributes['t-translation'];
diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js
index 711e790dfaa..355c6c1b493 100644
--- a/addons/web/static/src/js/data_import.js
+++ b/addons/web/static/src/js/data_import.js
@@ -80,8 +80,8 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
this.toggle_import_button(false);
this.$element.find('#csvfile').change(this.on_autodetect_data);
this.$element.find('fieldset').change(this.on_autodetect_data);
- this.$element.find('fieldset legend').click(function() {
- $(this).next().toggle();
+ this.$element.delegate('fieldset legend', 'click', function() {
+ $(this).parent().toggleClass('oe-closed');
});
this.ready.push(new openerp.web.DataSet(this, this.model).call(
'fields_get', [], function (fields) {
@@ -194,9 +194,11 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
: with_headers ? results.records.slice(1)
: results.records
}));
+ this.$element.find('fieldset').addClass('oe-closed');
} else if (results['error']) {
result_node.append(QWeb.render('ImportView.error', {
'error': results['error']}));
+ this.$element.find('fieldset').removeClass('oe-closed');
} else if (results['success']) {
if (this.widget_parent.widget_parent.active_view == "list") {
this.widget_parent.reload_content();
@@ -204,6 +206,11 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
this.stop();
return;
}
+ this.$element.find('form').removeClass('oe-import-no-result');
+
+ this.$element.delegate('.oe-m2o-drop-down-button', 'click', function () {
+ $(this).prev('input').focus();
+ });
var self = this;
this.ready.then(function () {
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
index 3ab972f7a86..ca540844b7f 100644
--- a/addons/web/static/src/js/formats.js
+++ b/addons/web/static/src/js/formats.js
@@ -27,14 +27,8 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
return _.sprintf('%d', value);
case 'float':
var precision = descriptor.digits ? descriptor.digits[1] : 2;
- var int_part = Math.floor(value);
- var dec_part = _.sprintf(
- '%.' + precision + 'f',
- Math.abs(value) % 1).substring(2);
- return _.sprintf('%d%s%s',
- int_part,
- openerp.web._t.database.parameters.decimal_point,
- dec_part);
+ return _.sprintf('%.' + precision + 'f', value)
+ .replace('.', openerp.web._t.database.parameters.decimal_point);
case 'float_time':
return _.sprintf("%02d:%02d",
Math.floor(value),
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index c7aa1e3cfe3..b2402cf95fa 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -63,6 +63,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
rows.push(row);
var filters = [];
_.each(items, function (item) {
+ if (item.attrs.invisible === '1') { return; }
if (filters.length && item.tag !== 'filter') {
row.push(
new openerp.web.search.FilterGroup(
diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js
index 039ac0fac3e..d7f059005f7 100644
--- a/addons/web/static/src/js/view_editor.js
+++ b/addons/web/static/src/js/view_editor.js
@@ -83,37 +83,32 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
radio:true
},
};
- var action_manager = new openerp.web.ActionManager(this);
- this.view_edit_dialog = new openerp.web.Dialog(this,{
+ this.view_edit_dialog = new openerp.web.Dialog(this, {
modal: true,
title: 'ViewEditor',
width: 750,
height: 500,
buttons: {
- "Create": function(){
- //to do
+ "Create": function(){
+ //to do
+ },
+ "Edit": function(){
+ self.xml_id=0;
+ self.get_data();
+ },
+ "Close": function(){
+ self.view_edit_dialog.close();
+ }
},
- "Edit": function(){
- self.xml_id = 0 ;
- self.get_data();
- },
- "Close": function(){
- $(this).dialog('destroy');
- }
- },
});
- this.view_edit_dialog.start();
- this.view_edit_dialog.open();
+ this.view_edit_dialog.start().open();
+ var action_manager = new openerp.web.ActionManager(this);
action_manager.appendTo(this.view_edit_dialog);
action_manager.do_action(action);
},
check_attr: function(xml, tag, level) {
- var obj = new Object();
- obj.child_id = [];
- obj.id = this.xml_id++;
- obj.level = level+1;
+ var obj = {'child_id': [], 'id': this.xml_id++, 'level': level+1, 'att_list': [], 'name': ""};
var render_name = "<" + tag;
- obj.att_list = [];
obj.att_list.push(tag);
$(xml).each(function() {
_.each(this.attributes, function(attrs){
@@ -121,12 +116,12 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
if (attrs.nodeName == "string" || attrs.nodeName == "name" || attrs.nodeName == "index") {
render_name += ' ' + attrs.nodeName + '=' + '"' + attrs.nodeValue + '"' ;
}
- } else if (attrs.nodeName == "name") {
- render_name += ' ' + attrs.nodeName + '=' + '"' + attrs.nodeValue + '"';
- }
- if (attrs.nodeName != "position") {
- obj.att_list.push( [attrs.nodeName,attrs.nodeValue] );
+ } else {
+ if (attrs.nodeName == "name") {
+ render_name += ' ' + attrs.nodeName + '=' + '"' + attrs.nodeValue + '"';
+ }
}
+ obj.att_list.push( [attrs.nodeName,attrs.nodeValue] );
});
render_name+= ">";
});
@@ -139,7 +134,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
var p_list = parent_list.slice(1);
if (val.child_id.length != 0) {
_.each(val.child_id, function(val, key) {
- if (val.id==check_id) {
+ if (val.id == check_id) {
if (p_list.length!=0) {
self.save_object(val, p_list, child_obj_list);
} else {
@@ -167,7 +162,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
parent_list.push(parent_id);
self.save_object(main_object[0], parent_list.slice(1), child_obj_list);
}
- for (var i=0; i= prev_tr.attr('level') || prev_tr.length == 0) {
+ if(level >= parseInt(prev_tr.attr('level')) || prev_tr.length == 0) {
last_tr = prev_tr;
break;
}
@@ -375,7 +407,7 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
if (img) {
while (1) {
next_tr = side.next();
- if (next_tr.attr('level') <= level || next_tr.length == 0) {
+ if ( parseInt(next_tr.attr('level')) <= level || next_tr.length == 0) {
break;
} else {
list_shift.push(next_tr);
@@ -383,17 +415,19 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}
}
}
- if (last_tr.length != 0 && last_tr.attr('level') == level) {
+ if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == level &&
+ (self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") == -1) {
_.each(list_shift, function(rec) {
$(last_tr).before(rec);
});
+ self.save_move_arch(one_object, view_id, view_xml_id, id_tr, level, "up");
}
break;
case "side-down":
if (img) {
while (1) {
next_tr = cur_tr.next();
- if (next_tr.attr('level') <= level || next_tr.length == 0) {
+ if ( parseInt(next_tr.attr('level')) <= level || next_tr.length == 0) {
last_tr = next_tr;
break;
} else {
@@ -405,11 +439,15 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
else {
last_tr = cur_tr.next();
}
- if (last_tr.length != 0 && last_tr.attr('level') == level) {
+ if((self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") != -1){
+ return;
+ }
+ if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == level) {
var last_tr_id = (last_tr.attr('id')).split('-')[1];
img = last_tr.find("img[id='parentimg-" + last_tr_id + "']").attr('src');
if (img) {
- this.edit_xml_dialog.$element.find("img[id='parentimg-" + last_tr_id + "']").attr('src', '/web/static/src/img/expand.gif');
+ self.edit_xml_dialog.$element.find("img[id='parentimg-" + last_tr_id + "']").
+ attr('src', '/web/static/src/img/expand.gif');
while (1) {
var next_tr = last_tr.next();
if (next_tr.attr('level') <= level || next_tr.length == 0) break;
@@ -421,23 +459,93 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
_.each(list_shift, function(rec) {
$(last_tr).after(rec);
});
+ self.save_move_arch(one_object, view_id, view_xml_id, id_tr, level, "down");
}
break;
}
});
},
+ save_move_arch: function(one_object, view_id, view_xml_id, id_tr, level, move_direct){
+ var self = this;
+ var arch = _.detect(one_object['arch'],function(element){
+ return element.view_id == view_id;
+ });
+ var obj = self.get_view_object(view_xml_id, one_object['main_object'], []);
+ if(($(arch.arch).filter("data")).length != 0 && view_xml_id != 0){
+ var check_list = _.flatten(obj[0].child_id[0].att_list);
+ arch.arch = _.detect($(arch.arch).children(), function(xml_child){
+ var temp_obj = self.check_attr(xml_child, xml_child.tagName.toLowerCase());
+ var main_list = _.flatten(temp_obj.att_list);
+ check_list = _.uniq(check_list);
+ var insert = _.intersection(main_list,check_list);
+ if(insert.length == check_list.length ){return xml_child;}
+ });
+ }
+ return self.get_node(arch.arch, obj[0].child_id[0], parseInt(id_tr), [], parseInt(level),
+ parseInt(view_id), arch, move_direct);
+ },
get_view_object: function(view_xml_id, one_object,result){
- var self = this;
- if(result.length==0){
- var check = _.detect(one_object , function(obj){
- return view_xml_id==obj.id;
- });
- if(check){result.push(check);};
- _.each(one_object, function(obj){
- self.get_view_object(view_xml_id, obj.child_id, result);
- });
+ var self = this;
+ if(result.length==0){
+ var check = _.detect(one_object , function(obj){
+ return view_xml_id==obj.id;
+ });
+ if(check){result.push(check);};
+ _.each(one_object, function(obj){
+ self.get_view_object(view_xml_id, obj.child_id, result);
+ });
+ }
+ return result;
+ },
+ get_node: function(arch1, obj, id, child_list, level, view_id, arch, move_direct){
+ var self = this;
+ var children_list = $(arch1).children();
+ var list_obj_xml = _.zip(children_list,obj.child_id);
+ if (id) {
+ if (obj.id == id) {
+ var id;
+ var parent = $(arch1).parents();
+ var index = _.indexOf(child_list, obj)
+ var re_insert_obj = child_list.splice(index, 1);
+ if (move_direct == "down") {
+ var next = $(arch1).next();
+ $(next).after(arch1);
+ child_list.splice(index+1, 0, re_insert_obj[0]);
+ } else {
+ var prev = $(arch1).prev();
+ $(prev).before(arch1);
+ child_list.splice(index-1, 0, re_insert_obj[0]);
+ }
+ parent = parent[parent.length-1];
+ var convert_to_utf = self.xml2Str(parent);
+ if (convert_to_utf) {
+ convert_to_utf = convert_to_utf.replace('xmlns="http://www.w3.org/1999/xhtml"', "");
+ convert_to_utf = '' + convert_to_utf;
+ arch.arch = convert_to_utf;
+ dataset = new openerp.web.DataSet(this, 'ir.ui.view');
+ dataset.write(parseInt(view_id),{"arch":convert_to_utf}, function(r) {
+ });
+ }
+ }
+ if (obj.level <= level) {
+ _.each(list_obj_xml, function(child_node) {
+ self.get_node(child_node[0], child_node[1], id, obj.child_id, level, view_id, arch, move_direct);
+ });
+ }
+ }
+ },
+ xml2Str: function(xmlNode) {
+ try {
+ return (new XMLSerializer()).serializeToString(xmlNode);
}
- return result;
+ catch (e) {
+ try {
+ return xmlNode.xml;
+ }
+ catch (e) {
+ return false;
+ }
+ }
},
on_expand: function(expand_img){
var level = parseInt($(expand_img).closest("tr[id^='viewedit-']").attr('level'));
@@ -514,16 +622,16 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
.read_slice([],{})
.done(function(res_grp) {
_.each(res_grp,function(res){
- var key = res.id;
- group_names[key]=res.name;
- group_ids.push(res.id);
+ var key = res.id;
+ group_names[key]=res.name;
+ group_ids.push(res.id);
});
model_data
.read_slice([],{domain:[['res_id', 'in', group_ids],['model','=','res.groups']]})
.done(function(model_grp) {
_.each(model_grp,function(res_group){
- groups.push([res_group.name,group_names[res_group.res_id]]);
- });
+ groups.push([res_group.name,group_names[res_group.res_id]]);
+ });
self.groups = groups;
def.resolve();
});
@@ -544,7 +652,6 @@ openerp.web.ViewEditor.Field = openerp.web.Class.extend({
return QWeb.render(this.template, {widget: this});
}
});
-
openerp.web.ViewEditor.FieldBoolean = openerp.web.ViewEditor.Field.extend({
init: function(view, node) {
this._super(view, node);
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 85378659a20..d1d8cff5b9f 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -89,7 +89,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.fields_view = data;
var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch);
- this.rendered = QWeb.render(this.form_template, { 'frame': frame, 'view': this });
+ this.rendered = QWeb.render(this.form_template, { 'frame': frame, 'widget': this });
}
this.$element.html(this.rendered);
_.each(this.widgets, function(w) {
@@ -105,17 +105,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.$form_header.find('button.oe_form_button_cancel').click(this.do_cancel);
this.$form_header.find('button.oe_form_button_new').click(this.on_button_new);
this.$form_header.find('button.oe_form_button_duplicate').click(this.on_button_duplicate);
- this.$form_header.find('button.oe_form_button_toggle').click(function () {
- self.translatable_fields = [];
- self.widgets = {};
- self.fields = {};
- self.$form_header.find('button').unbind('click');
- self.registry = self.registry === openerp.web.form.widgets
- ? openerp.web.form.readonly
- : openerp.web.form.widgets;
- self.on_loaded(self.fields_view);
- self.reload();
- });
+ this.$form_header.find('button.oe_form_button_toggle').click(this.on_toggle_readonly);
if (this.options.sidebar && this.options.sidebar_id) {
this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id);
@@ -127,6 +117,18 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
this.has_been_loaded.resolve();
},
+ on_toggle_readonly: function() {
+ var self = this;
+ self.translatable_fields = [];
+ self.widgets = {};
+ self.fields = {};
+ self.$form_header.find('button').unbind('click');
+ self.registry = self.registry === openerp.web.form.widgets
+ ? openerp.web.form.readonly
+ : openerp.web.form.widgets;
+ self.on_loaded(self.fields_view);
+ self.reload();
+ },
do_show: function () {
var promise;
if (this.dataset.index === null) {
@@ -715,6 +717,16 @@ openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form.
this.invisible = this.modifiers['invisible'] === true;
this.classname = 'oe_form_' + this.type;
+ this.align = parseFloat(this.node.attrs.align);
+ if (isNaN(this.align) || this.align === 1) {
+ this.align = 'right';
+ } else if (this.align === 0) {
+ this.align = 'left';
+ } else {
+ this.align = 'center';
+ }
+
+
this.width = this.node.attrs.width;
},
start: function() {
@@ -1044,8 +1056,7 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({
this._super(view, node);
- // TODO fme: support for attrs.align
- if (this.node.tag == 'label' && (this.node.attrs.colspan || (this.string && this.string.length > 32))) {
+ if (this.node.tag == 'label' && (this.align === 'left' || this.node.attrs.colspan || (this.string && this.string.length > 32))) {
this.template = "WidgetParagraph";
this.colspan = parseInt(this.node.attrs.colspan || 1, 10);
} else {
@@ -1170,6 +1181,10 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
openerp.web.form.FieldChar = openerp.web.form.Field.extend({
template: 'FieldChar',
+ init: function (view, node) {
+ this._super(view, node);
+ this.password = this.node.attrs.password === 'True' || this.node.attrs.password === '1';
+ },
start: function() {
this._super.apply(this, arguments);
this.$element.find('input').change(this.on_ui_change);
@@ -1628,6 +1643,11 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
} else {
$("#" + self.cm_id + " .oe_m2o_menu_item_mandatory").addClass("oe-m2o-disabled-cm");
}
+ if (!self.readonly) {
+ $("#" + self.cm_id + " .oe_m2o_menu_item_noreadonly").removeClass("oe-m2o-disabled-cm");
+ } else {
+ $("#" + self.cm_id + " .oe_m2o_menu_item_noreadonly").addClass("oe-m2o-disabled-cm");
+ }
return true;
}, menuStyle: {width: "200px"}
});
@@ -1647,6 +1667,8 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
}
});
this.$drop_down.click(function() {
+ if (self.readonly)
+ return;
if (self.$input.autocomplete("widget").is(":visible")) {
self.$input.autocomplete("close");
} else {
@@ -1807,7 +1829,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
self.original_value = undefined;
self._change_int_ext_value(rval);
};
- if(typeof(value) === "number") {
+ if (value && !(value instanceof Array)) {
var dataset = new openerp.web.DataSetStatic(this, this.field.relation, self.build_context());
dataset.name_get([value], function(data) {
real_set_value(data[0]);
@@ -1853,6 +1875,10 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
},
focus: function () {
this.$input.focus();
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$input.attr('disabled', this.readonly);
}
});
@@ -1906,7 +1932,8 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
multi_selection: false,
init: function(view, node) {
this._super(view, node);
- this.is_started = $.Deferred();
+ this.is_loaded = $.Deferred();
+ this.initial_is_loaded = this.is_loaded;
this.is_setted = $.Deferred();
this.form_last_update = $.Deferred();
this.init_form_last_update = this.form_last_update;
@@ -1924,8 +1951,18 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
self.on_ui_change();
});
+ this.is_setted.then(function() {
+ self.load_views();
+ });
+ },
+ is_readonly: function() {
+ return this.readonly || this.force_readonly;
+ },
+ load_views: function() {
+ var self = this;
+
var modes = this.node.attrs.mode;
- modes = !!modes ? modes.split(",") : ["tree", "form"];
+ modes = !!modes ? modes.split(",") : ["tree"];
var views = [];
_.each(modes, function(mode) {
var view = {
@@ -1938,25 +1975,38 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
}
if(view.view_type === "list") {
view.options.selectable = self.multi_selection;
+ if (self.is_readonly()) {
+ view.options.addable = null;
+ view.options.deletable = null;
+ }
} else if (view.view_type === "form") {
view.options.not_interactible_on_create = true;
}
views.push(view);
});
this.views = views;
-
+
this.viewmanager = new openerp.web.ViewManager(this, this.dataset, views);
this.viewmanager.registry = openerp.web.views.clone({
list: 'openerp.web.form.One2ManyListView',
- form: 'openerp.web.form.One2ManyFormView'
+ form: 'openerp.web.FormView'
});
var once = $.Deferred().then(function() {
self.init_form_last_update.resolve();
});
+ var def = $.Deferred().then(function() {
+ self.initial_is_loaded.resolve();
+ });
this.viewmanager.on_controller_inited.add_last(function(view_type, controller) {
if (view_type == "list") {
controller.o2m = self;
+ if (self.is_readonly())
+ controller.set_editable(false);
} else if (view_type == "form") {
+ if (self.is_readonly()) {
+ controller.on_toggle_readonly();
+ $(controller.$element.find(".oe_form_buttons")[0]).children().remove();
+ }
controller.on_record_loaded.add_last(function() {
once.resolve();
});
@@ -1967,33 +2017,40 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
} else if (view_type == "graph") {
self.reload_current_view()
}
- self.is_started.resolve();
+ def.resolve();
});
- this.viewmanager.on_mode_switch.add_first(function() {
- self.save_form_view();
+ this.viewmanager.on_mode_switch.add_first(function(n_mode, b, c, d, e) {
+ $.when(self.save_form_view()).then(function() {
+ if(n_mode === "list")
+ setTimeout(function() {self.reload_current_view();}, 0);
+ });
});
this.is_setted.then(function() {
setTimeout(function () {
self.viewmanager.appendTo(self.$element);
}, 0);
});
+ return def;
},
reload_current_view: function() {
var self = this;
- var view = self.viewmanager.views[self.viewmanager.active_view].controller;
- if(self.viewmanager.active_view === "list") {
- view.reload_content();
- } else if (self.viewmanager.active_view === "form") {
- if (this.dataset.index === null && this.dataset.ids.length >= 1) {
- this.dataset.index = 0;
+ self.is_loaded = self.is_loaded.pipe(function() {
+ var view = self.viewmanager.views[self.viewmanager.active_view].controller;
+ if(self.viewmanager.active_view === "list") {
+ return view.reload_content();
+ } else if (self.viewmanager.active_view === "form") {
+ if (self.dataset.index === null && self.dataset.ids.length >= 1) {
+ self.dataset.index = 0;
+ }
+ var act = function() {
+ return view.do_show();
+ }
+ self.form_last_update = self.form_last_update.pipe(act, act);
+ return self.form_last_update;
+ } else if (self.viewmanager.active_view === "graph") {
+ return view.do_search(self.build_domain(), self.dataset.get_context(), []);
}
- var act = function() {
- return view.do_show();
- }
- this.form_last_update = this.form_last_update.pipe(act, act);;
- } else if (self.viewmanager.active_view === "graph") {
- view.do_search(this.build_domain(), this.dataset.get_context(), []);
- }
+ });
},
set_value: function(value) {
value = value || [];
@@ -2050,9 +2107,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
if (this.dataset.index === null && this.dataset.ids.length > 0) {
this.dataset.index = 0;
}
- $.when(this.is_started).then(function() {
- self.reload_current_view();
- });
+ self.reload_current_view();
this.is_setted.resolve();
},
get_value: function() {
@@ -2116,7 +2171,18 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
},
update_dom: function() {
this._super.apply(this, arguments);
- this.$element.toggleClass('disabled', this.readonly);
+ var self = this;
+ if (this.previous_readonly !== this.readonly) {
+ this.previous_readonly = this.readonly;
+ if (this.viewmanager) {
+ this.is_loaded = this.is_loaded.pipe(function() {
+ self.viewmanager.stop();
+ return $.when(self.load_views()).then(function() {
+ self.reload_current_view();
+ });
+ });
+ }
+ }
}
});
@@ -2127,9 +2193,6 @@ openerp.web.form.One2ManyDataSet = openerp.web.BufferedDataSet.extend({
}
});
-openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({
-});
-
openerp.web.form.One2ManyListView = openerp.web.ListView.extend({
do_add_record: function () {
if (this.options.editable) {
@@ -2168,7 +2231,8 @@ openerp.web.form.One2ManyListView = openerp.web.ListView.extend({
read_function: function() {
return self.o2m.dataset.read_ids.apply(self.o2m.dataset, arguments);
},
- form_view_options: {'not_interactible_on_create':true}
+ form_view_options: {'not_interactible_on_create':true},
+ readonly: self.o2m.is_readonly()
});
pop.on_write.add(function(id, data) {
self.o2m.dataset.write(id, data, {}, function(r) {
@@ -2184,7 +2248,9 @@ openerp.web.form.FieldMany2Many = openerp.web.form.Field.extend({
init: function(view, node) {
this._super(view, node);
this.list_id = _.uniqueId("many2many");
- this.is_started = $.Deferred();
+ this.is_loaded = $.Deferred();
+ this.initial_is_loaded = this.is_loaded;
+ this.is_setted = $.Deferred();
},
start: function() {
this._super.apply(this, arguments);
@@ -2196,18 +2262,10 @@ openerp.web.form.FieldMany2Many = openerp.web.form.Field.extend({
this.dataset.on_unlink.add_last(function(ids) {
self.on_ui_change();
});
-
- this.list_view = new openerp.web.form.Many2ManyListView(this, this.dataset, false, {
- 'addable': 'Add',
- 'selectable': self.multi_selection
- });
- this.list_view.m2m_field = this;
- this.list_view.on_loaded.add_last(function() {
- self.is_started.resolve();
+
+ this.is_setted.then(function() {
+ self.load_view();
});
- setTimeout(function () {
- self.list_view.appendTo($("#" + self.list_id));
- }, 0);
},
set_value: function(value) {
value = value || [];
@@ -2217,16 +2275,56 @@ openerp.web.form.FieldMany2Many = openerp.web.form.Field.extend({
this._super(value);
this.dataset.set_ids(value);
var self = this;
- $.when(this.is_started).then(function() {
- self.list_view.reload_content();
- });
+ self.reload_content();
+ this.is_setted.resolve();
},
get_value: function() {
return [commands.replace_with(this.dataset.ids)];
},
validate: function() {
this.invalid = false;
- // TODO niv
+ },
+ is_readonly: function() {
+ return this.readonly || this.force_readonly;
+ },
+ load_view: function() {
+ var self = this;
+ this.list_view = new openerp.web.form.Many2ManyListView(this, this.dataset, false, {
+ 'addable': self.is_readonly() ? null : 'Add',
+ 'deletable': self.is_readonly() ? false : true,
+ 'selectable': self.multi_selection
+ });
+ this.list_view.m2m_field = this;
+ var loaded = $.Deferred();
+ this.list_view.on_loaded.add_last(function() {
+ self.initial_is_loaded.resolve();
+ loaded.resolve();
+ });
+ setTimeout(function () {
+ self.list_view.appendTo($("#" + self.list_id));
+ }, 0);
+ return loaded;
+ },
+ reload_content: function() {
+ var self = this;
+ this.is_loaded = this.is_loaded.pipe(function() {
+ return self.list_view.reload_content();
+ });
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ var self = this;
+ if (this.previous_readonly !== this.readonly) {
+ this.previous_readonly = this.readonly;
+ if (this.list_view) {
+ this.is_loaded = this.is_loaded.pipe(function() {
+ self.list_view.stop();
+ return $.when(self.load_view()).then(function() {
+ self.reload_content();
+ });
+ });
+ }
+ }
}
});
@@ -2330,10 +2428,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
this.searchview.stop();
}
this.searchview = new openerp.web.SearchView(this,
- this.dataset, false, {
- "selectable": !this.options.disable_multiple_selection,
- "deletable": false
- });
+ this.dataset, false, {});
this.searchview.on_search.add(function(domains, contexts, groupbys) {
if (self.initial_ids) {
self.do_search(domains.concat([[["id", "in", self.initial_ids]], self.domain]),
@@ -2360,7 +2455,9 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
});
self.view_list = new openerp.web.form.SelectCreateListView(self,
self.dataset, false,
- _.extend({'deletable': false}, self.options.list_view_options || {}));
+ _.extend({'deletable': false,
+ 'selectable': !self.options.disable_multiple_selection
+ }, self.options.list_view_options || {}));
self.view_list.popup = self;
self.view_list.appendTo($("#" + self.element_id + "_view_list")).pipe(function() {
self.view_list.do_show();
@@ -2479,6 +2576,7 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp
* - read_function
* - parent_view
* - form_view_options
+ * - readonly
*/
show_element: function(model, row_id, context, options) {
this.model = model;
@@ -2518,7 +2616,13 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp
this.view_form.set_embedded_view(this.options.alternative_form_view);
}
this.view_form.appendTo(this.$element.find("#" + this.element_id + "_view_form"));
+ var once = $.Deferred().then(function() {
+ if (self.options.readonly) {
+ self.view_form.on_toggle_readonly();
+ }
+ });
this.view_form.on_loaded.add_last(function() {
+ once.resolve();
var $buttons = self.view_form.$element.find(".oe_form_buttons");
$buttons.html(QWeb.render("FormOpenPopup.form.buttons"));
var $nbutton = $buttons.find(".oe_formopenpopup-form-save");
@@ -2531,6 +2635,10 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp
$cbutton.click(function() {
self.stop();
});
+ if (self.options.readonly) {
+ $nbutton.hide();
+ $cbutton.text(_t("Close"));
+ }
self.view_form.do_show();
});
this.dataset.on_write.add(this.on_write);
@@ -2813,17 +2921,21 @@ openerp.web.form.FieldStatus = openerp.web.form.Field.extend({
}
});
-openerp.web.form.WidgetNotebookReadonly = openerp.web.form.WidgetNotebook.extend({
- template: 'WidgetNotebook.readonly'
-});
openerp.web.form.FieldReadonly = openerp.web.form.Field.extend({
});
openerp.web.form.FieldCharReadonly = openerp.web.form.FieldReadonly.extend({
template: 'FieldChar.readonly',
+ init: function(view, node) {
+ this._super(view, node);
+ this.password = this.node.attrs.password === 'True' || this.node.attrs.password === '1';
+ },
set_value: function (value) {
this._super.apply(this, arguments);
var show_value = openerp.web.format_value(value, this, '');
+ if (this.password) {
+ show_value = new Array(show_value.length + 1).join('*');
+ }
this.$element.find('div').text(show_value);
return show_value;
}
@@ -2851,7 +2963,7 @@ openerp.web.form.FieldUrlReadonly = openerp.web.form.FieldURIReadonly.extend({
});
openerp.web.form.FieldBooleanReadonly = openerp.web.form.FieldCharReadonly.extend({
set_value: function (value) {
- this._super(value ? '\u2714' : '\u2718');
+ this._super(value ? '\u2611' : '\u2610');
}
});
openerp.web.form.FieldSelectionReadonly = openerp.web.form.FieldReadonly.extend({
@@ -2886,9 +2998,17 @@ openerp.web.form.FieldMany2OneReadonly = openerp.web.form.FieldCharReadonly.exte
self.update_dom();
self.on_value_changed();
var real_set_value = function(rval) {
- self.$element.find('div').text(rval ? rval[1] : '');
+ self.value = rval;
+ var div = $(self.$element.find('div'));
+ div.html('');
+ var a = $(div.find("a"));
+ a.text(rval ? rval[1] : '');
+ a.click(function() {
+ var pop = new openerp.web.form.FormOpenPopup(self.view);
+ pop.show_element(self.field.relation, self.value[0],self.build_context(), {readonly:true});
+ });
};
- if(typeof(value) === "number") {
+ if (value && !(value instanceof Array)) {
var dataset = new openerp.web.DataSetStatic(
this, this.field.relation, self.build_context());
dataset.name_get([value], function(data) {
@@ -2933,8 +3053,14 @@ openerp.web.form.widgets = new openerp.web.Registry({
'binary': 'openerp.web.form.FieldBinaryFile',
'statusbar': 'openerp.web.form.FieldStatus'
});
+
+openerp.web.form.FieldMany2ManyReadonly = openerp.web.form.FieldMany2Many.extend({
+ force_readonly: true
+});
+openerp.web.form.FieldOne2ManyReadonly = openerp.web.form.FieldOne2Many.extend({
+ force_readonly: true
+});
openerp.web.form.readonly = openerp.web.form.widgets.clone({
- 'notebook': 'openerp.web.form.WidgetNotebookReadonly',
'char': 'openerp.web.form.FieldCharReadonly',
'email': 'openerp.web.form.FieldEmailReadonly',
'url': 'openerp.web.form.FieldUrlReadonly',
@@ -2944,6 +3070,9 @@ openerp.web.form.readonly = openerp.web.form.widgets.clone({
'datetime': 'openerp.web.form.FieldCharReadonly',
'selection' : 'openerp.web.form.FieldSelectionReadonly',
'many2one': 'openerp.web.form.FieldMany2OneReadonly',
+ 'many2many' : 'openerp.web.form.FieldMany2ManyReadonly',
+ 'one2many' : 'openerp.web.form.FieldOne2ManyReadonly',
+ 'one2many_list' : 'openerp.web.form.FieldOne2ManyReadonly',
'boolean': 'openerp.web.form.FieldBooleanReadonly',
'float': 'openerp.web.form.FieldCharReadonly',
'integer': 'openerp.web.form.FieldCharReadonly',
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index d09ec1d3035..e891a6c7db7 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -11,7 +11,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
// whether the column headers should be displayed
'header': true,
// display addition button, with that label
- 'addable': _t("New"),
+ 'addable': _t("Create"),
// whether the list view can be sorted, note that once a view has been
// sorted it can not be reordered anymore
'sortable': true,
@@ -201,8 +201,15 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
this.setup_columns(this.fields_view.fields, grouped);
this.$element.html(QWeb.render("ListView", this));
-
// Head hook
+ this.$element.find('.all-record-selector').click(function(){
+ self.$element.find('.oe-record-selector input').prop('checked',
+ self.$element.find('.all-record-selector').prop('checked') || false);
+ var selection = self.groups.get_selection();
+ $(self.groups).trigger(
+ 'selected', [selection.ids, selection.records]);
+ });
+
this.$element.find('.oe-list-add')
.click(this.do_add_record)
.attr('disabled', grouped && this.options.editable);
@@ -424,10 +431,13 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
},
/**
* re-renders the content of the list view
+ *
+ * @returns {$.Deferred} promise to content reloading
*/
reload_content: function () {
var self = this;
this.records.reset();
+ var reloaded = $.Deferred();
this.$element.find('.oe-listview-content').append(
this.groups.render(function () {
if (self.dataset.index == null) {
@@ -438,7 +448,9 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
}
}
self.compute_aggregates();
+ reloaded.resolve();
}));
+ return reloaded.promise();
},
/**
* Handler for the result of eval_domain_and_context, actually perform the
@@ -512,6 +524,17 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
return field.name === name;
});
if (!action) { return; }
+
+ var c = new openerp.web.CompoundContext();
+ c.set_eval_context(_.extend({
+ active_id: id,
+ active_ids: [id],
+ active_model: this.dataset.model
+ }, this.records.get(id).toContext()));
+ if (action.context) {
+ c.add(action.context);
+ }
+ action.context = c;
this.do_execute_action(action, this.dataset, id, callback);
},
/**
@@ -1201,6 +1224,10 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
var options = { offset: page * limit, limit: limit };
//TODO xmo: investigate why we need to put the setTimeout
setTimeout(function() {dataset.read_slice(fields, options , function (records) {
+ // FIXME: ignominious hacks, parents (aka form view) should not send two ListView#reload_content concurrently
+ if (self.records.length) {
+ self.records.reset(null, {silent: true});
+ }
if (!self.datagroup.openable) {
view.configure_pager(dataset);
} else {
@@ -1430,6 +1457,25 @@ var Record = openerp.web.Class.extend(/** @lends Record# */{
}
return {data: form_data};
+ },
+ /**
+ * Converts the current record to a format expected by context evaluations
+ * (identical to record.attributes, except m2o fields are their integer
+ * value rather than a pair)
+ */
+ toContext: function () {
+ var output = {}, attrs = this.attributes;
+ for(var k in attrs) {
+ var val = attrs[k];
+ if (typeof val !== 'object') {
+ output[k] = val;
+ } else if (val instanceof Array) {
+ output[k] = val[0];
+ } else {
+ throw new Error("Can't convert value " + val + " to context");
+ }
+ }
+ return output;
}
});
Record.include(Events);
@@ -1541,7 +1587,8 @@ var Collection = openerp.web.Class.extend(/** @lends Collection# */{
* @param {Array} [records]
* @returns this
*/
- reset: function (records) {
+ reset: function (records, options) {
+ options = options || {};
_(this._proxies).each(function (proxy) {
proxy.reset();
});
@@ -1552,7 +1599,9 @@ var Collection = openerp.web.Class.extend(/** @lends Collection# */{
if (records) {
this.add(records);
}
- this.trigger('reset', this);
+ if (!options.silent) {
+ this.trigger('reset', this);
+ }
return this;
},
/**
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index 4cc081a6266..dba0a1abba4 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -78,6 +78,17 @@ openerp.web.list_editable = function (openerp) {
// tree/@editable takes priority on everything else if present.
this.options.editable = data.arch.attrs.editable || this.options.editable;
return this._super(data, grouped);
+ },
+ /**
+ * Ensures the editable list is saved (saves any pending edition if
+ * needed, or tries to)
+ *
+ * Returns a deferred to the end of the saving.
+ *
+ * @returns {$.Deferred}
+ */
+ ensure_saved: function () {
+ return this.groups.ensure_saved();
}
});
@@ -86,6 +97,18 @@ openerp.web.list_editable = function (openerp) {
new_record: function () {
// TODO: handle multiple children
this.children[null].new_record();
+ },
+ /**
+ * Ensures descendant editable List instances are all saved if they have
+ * pending editions.
+ *
+ * @returns {$.Deferred}
+ */
+ ensure_saved: function () {
+ return $.when.apply(null,
+ _.invoke(
+ _.values(this.children),
+ 'ensure_saved'));
}
});
@@ -254,9 +277,11 @@ openerp.web.list_editable = function (openerp) {
* sibling if asked.
*
* @param {Boolean} [edit_next=false] should the next row become editable
+ * @returns {$.Deferred}
*/
save_row: function (edit_next) {
- var self = this;
+ //noinspection JSPotentiallyInvalidConstructorUsage
+ var self = this, done = $.Deferred();
this.edition_form.do_save(function (result) {
if (result.created && !self.edition_id) {
self.records.add({id: result.result},
@@ -267,28 +292,44 @@ openerp.web.list_editable = function (openerp) {
next_record = self.records.at(
self.records.indexOf(edited_record) + 1);
- self.handle_onwrite(self.edition_id);
- self.cancel_pending_edition().then(function () {
- $(self).trigger('saved', [self.dataset]);
- if (!edit_next) {
- return;
- }
- if (result.created) {
- self.new_record();
- return;
- }
- var next_record_id;
- if (next_record) {
- next_record_id = next_record.get('id');
- self.dataset.index = _(self.dataset.ids)
- .indexOf(next_record_id);
- } else {
- self.dataset.index = 0;
- next_record_id = self.records.at(0).get('id');
- }
- self.edit_record(next_record_id);
- });
- }, this.options.editable === 'top');
+ $.when(
+ self.handle_onwrite(self.edition_id),
+ self.cancel_pending_edition().then(function () {
+ $(self).trigger('saved', [self.dataset]);
+ if (!edit_next) {
+ return;
+ }
+ if (result.created) {
+ self.new_record();
+ return;
+ }
+ var next_record_id;
+ if (next_record) {
+ next_record_id = next_record.get('id');
+ self.dataset.index = _(self.dataset.ids)
+ .indexOf(next_record_id);
+ } else {
+ self.dataset.index = 0;
+ next_record_id = self.records.at(0).get('id');
+ }
+ self.edit_record(next_record_id);
+ })).then(function () {
+ done.resolve();
+ });
+ }, this.options.editable === 'top').fail(function () {
+ done.reject();
+ });
+ return done.promise();
+ },
+ /**
+ * If the current list is being edited, ensures it's saved
+ */
+ ensure_saved: function () {
+ if (this.edition) {
+ return this.save_row();
+ }
+ //noinspection JSPotentiallyInvalidConstructorUsage
+ return $.Deferred().resolve().promise();
},
/**
* Cancels the edition of the row for the current dataset index
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index a31bae4fce4..b6a37c82560 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -2,21 +2,21 @@
* OpenERP web library
*---------------------------------------------------------*/
-openerp.web.views = function(db) {
+openerp.web.views = function(session) {
-var _t = db.web._t;
+var _t = session.web._t;
/**
* Registry for all the client actions key: tag value: widget
*/
-db.web.client_actions = new db.web.Registry();
+session.web.client_actions = new session.web.Registry();
/**
* Registry for all the main views
*/
-db.web.views = new db.web.Registry();
+session.web.views = new session.web.Registry();
-db.web.ActionManager = db.web.Widget.extend({
+session.web.ActionManager = session.web.Widget.extend({
identifier_prefix: "actionmanager",
init: function(parent) {
this._super(parent);
@@ -93,20 +93,20 @@ db.web.ActionManager = db.web.Widget.extend({
ir_actions_act_window: function (action, on_close) {
if (action.target === 'new') {
if (this.dialog == null) {
- this.dialog = new db.web.Dialog(this, { title: action.name, width: '80%' });
+ this.dialog = new session.web.Dialog(this, { title: action.name, width: '80%' });
if(on_close)
this.dialog.on_close.add(on_close);
this.dialog.start();
} else {
this.dialog_viewmanager.stop();
}
- this.dialog_viewmanager = new db.web.ViewManagerAction(this, action);
+ this.dialog_viewmanager = new session.web.ViewManagerAction(this, action);
this.dialog_viewmanager.appendTo(this.dialog.$element);
this.dialog.open();
} else {
this.dialog_stop();
this.content_stop();
- this.inner_viewmanager = new db.web.ViewManagerAction(this, action);
+ this.inner_viewmanager = new session.web.ViewManagerAction(this, action);
this.inner_viewmanager.appendTo(this.$element);
this.url_update(action);
}
@@ -124,7 +124,7 @@ db.web.ActionManager = db.web.Widget.extend({
if (this.dialog && action.context) {
var model = action.context.active_model;
if (model === 'base.module.upgrade' || model === 'base.setup.installer' || model === 'base.module.upgrade') {
- db.webclient.do_reload();
+ session.webclient.do_reload();
}
}
this.dialog_stop();
@@ -140,7 +140,7 @@ db.web.ActionManager = db.web.Widget.extend({
},
ir_actions_client: function (action) {
this.content_stop();
- var ClientWidget = db.web.client_actions.get_object(action.tag);
+ var ClientWidget = session.web.client_actions.get_object(action.tag);
(this.client_widget = new ClientWidget(this, action.params)).appendTo(this);
},
ir_actions_report_xml: function(action) {
@@ -164,12 +164,12 @@ db.web.ActionManager = db.web.Widget.extend({
}
});
-db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
+session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.ViewManager# */{
identifier_prefix: "viewmanager",
template: "ViewManager",
/**
- * @constructs db.web.ViewManager
- * @extends db.web.Widget
+ * @constructs session.web.ViewManager
+ * @extends session.web.Widget
*
* @param parent
* @param dataset
@@ -185,10 +185,10 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
this.views_src = _.map(views, function(x) {return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;});
this.views = {};
this.flags = this.flags || {};
- this.registry = db.web.views;
+ this.registry = session.web.views;
},
render: function() {
- return db.web.qweb.render(this.template, {
+ return session.web.qweb.render(this.template, {
self: this,
prefix: this.element_id,
views: this.views_src});
@@ -271,6 +271,10 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
}
}
}
+ $.when(view_promise).then(function () {
+ self.$element.find('.oe_view_title:first').text(
+ self.display_title());
+ });
return view_promise;
},
/**
@@ -284,7 +288,7 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
if (this.searchview) {
this.searchview.stop();
}
- this.searchview = new db.web.SearchView(
+ this.searchview = new session.web.SearchView(
this, this.dataset,
view_id, search_defaults, this.flags.search_view === false);
@@ -331,16 +335,24 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
/**
* Called by children view after executing an action
*/
- on_action_executed: function () {}
+ on_action_executed: function () {},
+ display_title: function () {
+ var view = this.views[this.active_view];
+ if (view) {
+ // ick
+ return view.controller.fields_view.arch.attrs.string;
+ }
+ return '';
+ }
});
-db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.ViewManagerAction# */{
+session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepnerp.web.ViewManagerAction# */{
template:"ViewManagerAction",
/**
- * @constructs db.web.ViewManagerAction
- * @extends db.web.ViewManager
+ * @constructs session.web.ViewManagerAction
+ * @extends session.web.ViewManager
*
- * @param {db.web.ActionManager} parent parent object/widget
+ * @param {session.web.ActionManager} parent parent object/widget
* @param {Object} action descriptor for the action this viewmanager needs to manage its views.
*/
init: function(parent, action) {
@@ -350,7 +362,7 @@ db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.View
this._super(parent, null, action.views);
this.session = parent.session;
this.action = action;
- var dataset = new db.web.DataSetSearch(this, action.res_model, action.context, action.domain);
+ var dataset = new session.web.DataSetSearch(this, action.res_model, action.context, action.domain);
if (action.res_id) {
dataset.ids.push(action.res_id);
dataset.index = 0;
@@ -400,12 +412,12 @@ db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.View
this.$element.find('.oe_get_xml_view').click(function () {
// TODO: add search view?
- $('').text(db.web.json_node_to_xml(
+ $('').text(session.web.json_node_to_xml(
self.views[self.active_view].controller.fields_view.arch, true))
.dialog({ width: '95%'});
});
if (this.action.help && !this.flags.low_profile) {
- var Users = new db.web.DataSet(self, 'res.users'),
+ var Users = new session.web.DataSet(self, 'res.users'),
header = this.$element.find('.oe-view-manager-header');
header.delegate('blockquote button', 'click', function() {
var $this = $(this);
@@ -444,6 +456,16 @@ db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.View
if (!self.action.name && fvg) {
self.$element.find('.oe_view_title').text(fvg.arch.attrs.string || fvg.name);
}
+
+ var $title = self.$element.find('.oe_view_title'),
+ $search_prefix = $title.find('span');
+ if (controller.searchable !== false) {
+ if (!$search_prefix.length) {
+ $title.prepend('' + _t("Search:") + '');
+ }
+ } else {
+ $search_prefix.remove();
+ }
});
},
shortcut_check : function(view) {
@@ -451,7 +473,7 @@ db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.View
var grandparent = this.widget_parent && this.widget_parent.widget_parent;
// display shortcuts if on the first view for the action
var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle');
- if (!(grandparent instanceof db.web.WebClient) ||
+ if (!(grandparent instanceof session.web.WebClient) ||
!(view.view_type === this.views_src[0].view_type
&& view.view_id === this.views_src[0].view_id)) {
$shortcut_toggle.hide();
@@ -488,7 +510,7 @@ db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.View
* Intercept do_action resolution from children views
*/
on_action_executed: function () {
- return new db.web.DataSet(this, 'res.log')
+ return new session.web.DataSet(this, 'res.log')
.call('get', [], this.do_display_log);
},
/**
@@ -512,10 +534,13 @@ db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.View
return false;
});
});
+ },
+ display_title: function () {
+ return this.action.name;
}
});
-db.web.Sidebar = db.web.Widget.extend({
+session.web.Sidebar = session.web.Widget.extend({
init: function(parent, element_id) {
this._super(parent, element_id);
this.items = {};
@@ -524,7 +549,7 @@ db.web.Sidebar = db.web.Widget.extend({
start: function() {
this._super(this);
var self = this;
- this.$element.html(db.web.qweb.render('Sidebar'));
+ this.$element.html(session.web.qweb.render('Sidebar'));
this.$element.find(".toggle-sidebar").click(function(e) {
self.do_toggle();
});
@@ -544,7 +569,7 @@ db.web.Sidebar = db.web.Widget.extend({
{
label: _t("Manage Views"),
callback: this.call_default_on_sidebar,
- title: _t("Manage views of the current object"),
+ title: _t("Manage views of the current object")
}, {
label: _t("Edit Workflow"),
callback: this.call_default_on_sidebar,
@@ -553,18 +578,18 @@ db.web.Sidebar = db.web.Widget.extend({
}, {
label: _t("Customize Object"),
callback: this.call_default_on_sidebar,
- title: _t("Manage views of the current object"),
+ title: _t("Manage views of the current object")
}
]);
this.add_section(_t('Other Options'), 'other');
- this.add_items('other', [
+ this.add_items('other', [
{
label: _t("Import"),
- callback: this.call_default_on_sidebar,
+ callback: this.call_default_on_sidebar
}, {
label: _t("Export"),
- callback: this.call_default_on_sidebar,
+ callback: this.call_default_on_sidebar
}, {
label: _t("Translate"),
callback: this.call_default_on_sidebar,
@@ -594,17 +619,17 @@ db.web.Sidebar = db.web.Widget.extend({
}
});
},
-
+
add_section: function(name, code) {
if(!code) code = _.underscored(name);
var $section = this.sections[code];
if(!$section) {
section_id = _.uniqueId(this.element_id + '_section_' + code + '_');
- var $section = $(db.web.qweb.render("Sidebar.section", {
+ var $section = $(session.web.qweb.render("Sidebar.section", {
section_id: section_id,
name: name,
- classname: 'oe_sidebar_' + code,
+ classname: 'oe_sidebar_' + code
}));
$section.appendTo(this.$element.find('div.sidebar-actions'));
this.sections[code] = $section;
@@ -633,7 +658,7 @@ db.web.Sidebar = db.web.Widget.extend({
this.items[items[i].element_id] = items[i];
}
- var $items = $(db.web.qweb.render("Sidebar.section.items", {items: items}));
+ var $items = $(session.web.qweb.render("Sidebar.section.items", {items: items}));
$items.find('a.oe_sidebar_action_a').click(function() {
var item = self.items[$(this).attr('id')];
@@ -668,7 +693,7 @@ db.web.Sidebar = db.web.Widget.extend({
}
return false;
});
-
+
var $ul = $section.find('ul');
if(!$ul.length) {
$ul = $('
').appendTo($section);
@@ -687,7 +712,7 @@ db.web.Sidebar = db.web.Widget.extend({
}
});
-db.web.TranslateDialog = db.web.Dialog.extend({
+session.web.TranslateDialog = session.web.Dialog.extend({
dialog_title: _t("Translations"),
init: function(view) {
// TODO fme: should add the language to fields_view_get because between the fields view get
@@ -707,14 +732,14 @@ db.web.TranslateDialog = db.web.Dialog.extend({
this.translatable_fields_keys = _.map(this.view.translatable_fields || [], function(i) { return i.name });
this.languages = null;
this.languages_loaded = $.Deferred();
- (new db.web.DataSetSearch(this, 'res.lang', this.view.dataset.get_context(),
+ (new session.web.DataSetSearch(this, 'res.lang', this.view.dataset.get_context(),
[['translatable', '=', '1']])).read_slice(['code', 'name'], { sort: 'id' }, this.on_languages_loaded);
},
start: function() {
var self = this;
this._super();
$.when(this.languages_loaded).then(function() {
- self.$element.html(db.web.qweb.render('TranslateDialog', { widget: self }));
+ self.$element.html(session.web.qweb.render('TranslateDialog', { widget: self }));
self.$element.tabs();
if (!(self.view.translatable_fields && self.view.translatable_fields.length)) {
self.hide_tabs('fields');
@@ -819,7 +844,7 @@ db.web.TranslateDialog = db.web.Dialog.extend({
}
});
-db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
+session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
template: "EmptyComponent",
set_default_options: function(options) {
this.options = options || {};
@@ -833,7 +858,7 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
},
open_translate_dialog: function(field) {
if (!this.translate_dialog) {
- this.translate_dialog = new db.web.TranslateDialog(this).start();
+ this.translate_dialog = new session.web.TranslateDialog(this).start();
}
this.translate_dialog.open(field);
},
@@ -845,7 +870,7 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
* @param {String} [action_data.special=null] special action handlers (currently: only ``'cancel'``)
* @param {String} [action_data.type='workflow'] the action type, if present, one of ``'object'``, ``'action'`` or ``'workflow'``
* @param {Object} [action_data.context=null] additional action context, to add to the current context
- * @param {db.web.DataSet} dataset a dataset object used to communicate with the server
+ * @param {session.web.DataSet} dataset a dataset object used to communicate with the server
* @param {Object} [record_id] the identifier of the object on which the action is to be applied
* @param {Function} on_closed callback to execute when dialog is closed or when the action does not generate any result (no new action)
*/
@@ -857,12 +882,12 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
return self.widget_parent.on_action_executed.apply(null, arguments);
}
};
- var context = new db.web.CompoundContext(dataset.get_context(), action_data.context || {});
-
+ var context = new session.web.CompoundContext(dataset.get_context(), action_data.context || {});
+
var handler = function (r) {
var action = r.result;
if (action && action.constructor == Object) {
- var ncontext = new db.web.CompoundContext(context);
+ var ncontext = new session.web.CompoundContext(context);
if (record_id) {
ncontext.add({
active_id: record_id,
@@ -899,7 +924,7 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
/**
* Directly set a view to use instead of calling fields_view_get. This method must
* be called before start(). When an embedded view is set, underlying implementations
- * of db.web.View must use the provided view instead of any other one.
+ * of session.web.View must use the provided view instead of any other one.
*
* @param embedded_view A view.
*/
@@ -917,7 +942,7 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
},
on_sidebar_manage_views: function() {
if (this.fields_view && this.fields_view.arch) {
- var view_editor = new db.web.ViewEditor(this, this.$element, this.dataset, this.fields_view.arch);
+ var view_editor = new session.web.ViewEditor(this, this.$element, this.dataset, this.fields_view.arch);
view_editor.start();
} else {
this.do_warn("Manage Views", "Could not find current view declaration");
@@ -930,11 +955,11 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
console.log('Todo');
},
on_sidebar_import: function() {
- var import_view = new db.web.DataImport(this, this.dataset);
+ var import_view = new session.web.DataImport(this, this.dataset);
import_view.start();
},
on_sidebar_export: function() {
- var export_view = new db.web.DataExport(this, this.dataset);
+ var export_view = new session.web.DataExport(this, this.dataset);
export_view.start();
},
on_sidebar_translate: function() {
@@ -944,19 +969,19 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
}
});
-db.web.json_node_to_xml = function(node, single_quote, indent) {
+session.web.json_node_to_xml = function(node, human_readable, indent) {
// For debugging purpose, this function will convert a json node back to xml
// Maybe usefull for xml view editor
+ indent = indent || 0;
+ var sindent = (human_readable ? (new Array(indent + 1).join('\t')) : ''),
+ r = sindent + '<' + node.tag,
+ cr = human_readable ? '\n' : '';
if (typeof(node) === 'string') {
- return node;
- }
- else if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {
+ return sindent + node;
+ } else if (typeof(node.tag) !== 'string' || !node.children instanceof Array || !node.attrs instanceof Object) {
throw("Node a json node");
}
- indent = indent || 0;
- var sindent = new Array(indent + 1).join('\t'),
- r = sindent + '<' + node.tag;
for (var attr in node.attrs) {
var vattr = node.attrs[attr];
if (typeof(vattr) !== 'string') {
@@ -964,19 +989,19 @@ db.web.json_node_to_xml = function(node, single_quote, indent) {
vattr = JSON.stringify(vattr);
}
vattr = vattr.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
- if (single_quote) {
+ if (human_readable) {
vattr = vattr.replace(/"/g, "'");
}
r += ' ' + attr + '="' + vattr + '"';
}
if (node.children && node.children.length) {
- r += '>\n';
+ r += '>' + cr;
var childs = [];
for (var i = 0, ii = node.children.length; i < ii; i++) {
- childs.push(db.web.json_node_to_xml(node.children[i], single_quote, indent + 1));
+ childs.push(session.web.json_node_to_xml(node.children[i], human_readable, indent + 1));
}
- r += childs.join('\n');
- r += '\n' + sindent + '' + node.tag + '>';
+ r += childs.join(cr);
+ r += cr + sindent + '' + node.tag + '>';
return r;
} else {
return r + '/>';
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 41865e4f5a3..8cf925990cb 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -415,6 +415,9 @@
|