diff options
| author | Thibault Delavallée <tde@openerp.com> | 2012-12-10 13:54:23 +0100 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2012-12-10 13:54:23 +0100 |
| commit | 1ca5e68b1f3ddb440b104c6c47ea35e8d26a1eed (patch) | |
| tree | 4070b56d1253290fa69f4fbc43ad4862c883080e /addons/web/static/src/js | |
| parent | a5ca416f055871fb2765567c2cf2f06445c1d2ca (diff) | |
| parent | 70f8f99b35c93a880cf15a1f21b7f88aef5a8d36 (diff) | |
[MERGE] Sync with trunk.
bzr revid: tde@openerp.com-20121130093732-i8y10ayjqiaq5t7p
bzr revid: tde@openerp.com-20121204142854-pauouyapnw7z8zwj
bzr revid: tde@openerp.com-20121205101544-k4ui6thr0ibzw0vx
bzr revid: tde@openerp.com-20121210125423-81wbh4af9sxdqjki
Diffstat (limited to 'addons/web/static/src/js')
| -rw-r--r-- | addons/web/static/src/js/boot.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 49 | ||||
| -rw-r--r-- | addons/web/static/src/js/corelib.js | 3 | ||||
| -rw-r--r-- | addons/web/static/src/js/coresetup.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/pyeval.js | 30 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/testing.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 48 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list.js | 19 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list_editable.js | 11 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_tree.js | 14 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 87 |
12 files changed, 153 insertions, 122 deletions
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index 5d50841d78d..4565d220dc8 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -22,7 +22,7 @@ * @param {Array|String} modules list of modules to initialize */ init: function(modules) { - if (modules === "fuck your shit, don't load anything you cunt") { + if (modules === null) { modules = []; } else { modules = _.union(['web'], modules || []); diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index c6d216d128c..55e14d6d783 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -830,7 +830,7 @@ instance.web.Menu = instance.web.Widget.extend({ this.renderElement(); this.limit_entries(); // Hide toplevel item if there is only one - var $toplevel = this.$("li") + var $toplevel = this.$("li"); if($toplevel.length == 1) { $toplevel.hide(); } @@ -1125,7 +1125,6 @@ instance.web.WebClient = instance.web.Client.extend({ start: function() { var self = this; return $.when(this._super()).then(function() { - self.$(".oe_logo").attr("href", $.param.fragment("" + window.location, "", 2).slice(0, -1)); if (jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) { $("body").addClass("kitten-mode-activated"); if ($.blockUI) { @@ -1186,26 +1185,32 @@ instance.web.WebClient = instance.web.Client.extend({ }, check_timezone: function() { var self = this; - var user_offset = instance.session.user_context.tz_offset; - var offset = -(new Date().getTimezoneOffset()); - // _.str.sprintf()'s zero front padding is buggy with signed decimals, so doing it manually - var browser_offset = (offset < 0) ? "-" : "+"; - browser_offset += _.str.sprintf("%02d", Math.abs(offset / 60)); - browser_offset += _.str.sprintf("%02d", Math.abs(offset % 60)); - if (browser_offset !== user_offset) { - var notification = this.do_warn(_t("Timezone"), QWeb.render('WebClient.timezone_notification', { - user_timezone: instance.session.user_context.tz || 'UTC', - user_offset: user_offset, - browser_offset: browser_offset, - }), true); - notification.element.find('.oe_webclient_timezone_notification').on('click', function() { - notification.close(); - }).find('a').on('click', function() { - notification.close(); - self.user_menu.on_menu_settings(); - return false; - }); - } + return new instance.web.Model('res.users').call('read', [[this.session.uid], ['tz_offset']]).then(function(result) { + var user_offset = result[0]['tz_offset']; + var offset = -(new Date().getTimezoneOffset()); + // _.str.sprintf()'s zero front padding is buggy with signed decimals, so doing it manually + var browser_offset = (offset < 0) ? "-" : "+"; + browser_offset += _.str.sprintf("%02d", Math.abs(offset / 60)); + browser_offset += _.str.sprintf("%02d", Math.abs(offset % 60)); + if (browser_offset !== user_offset) { + var $icon = $(QWeb.render('WebClient.timezone_systray')); + $icon.on('click', function() { + var notification = self.do_warn(_t("Timezone mismatch"), QWeb.render('WebClient.timezone_notification', { + user_timezone: instance.session.user_context.tz || 'UTC', + user_offset: user_offset, + browser_offset: browser_offset, + }), true); + notification.element.find('.oe_webclient_timezone_notification').on('click', function() { + notification.close(); + }).find('a').on('click', function() { + notification.close(); + self.user_menu.on_menu_settings(); + return false; + }); + }); + $icon.appendTo(self.$('.oe_systray')); + } + }); }, destroy_content: function() { _.each(_.clone(this.getChildren()), function(el) { diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js index 55984162a55..f7a84e608c6 100644 --- a/addons/web/static/src/js/corelib.js +++ b/addons/web/static/src/js/corelib.js @@ -969,6 +969,9 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, { if (_.isString(url)) { url = { url: url }; } + _.defaults(params, { + context: this.user_context || {} + }); // Construct a JSON-RPC2 request, method is currently unused if (this.debug) params.debug = 1; diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index fa1348a5f8c..74c30334e1e 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -622,7 +622,7 @@ var messages_by_seconds = function() { [120, _t("Don't leave yet,<br />it's still loading...")], [300, _t("You may not believe it,<br />but the application is actually loading...")], [420, _t("Take a minute to get a coffee,<br />because it's loading...")], - [3600, _t("Maybe you should consider reloading the application by pressing F5...")], + [3600, _t("Maybe you should consider reloading the application by pressing F5...")] ]; }; diff --git a/addons/web/static/src/js/pyeval.js b/addons/web/static/src/js/pyeval.js index 265449f9f64..2c1b5ec9d7d 100644 --- a/addons/web/static/src/js/pyeval.js +++ b/addons/web/static/src/js/pyeval.js @@ -24,7 +24,7 @@ openerp.web.pyeval = function (instance) { var mod = a%b; // in python, sign(a % b) === sign(b). Not in JS. If wrong side, add a // round of b - if (mod > 0 && b < 0 || mod < 0 && b > 0) { + if (mod > 0 && b < 0 || mod < 0 && b > 0) { mod += b; } return fn(Math.floor(a/b), mod); @@ -398,14 +398,9 @@ openerp.web.pyeval = function (instance) { now: py.classmethod.fromJSON(function () { var d = new Date(); return py.PY_call(datetime.datetime, - [d.getFullYear(), d.getMonth() + 1, d.getDate(), - d.getHours(), d.getMinutes(), d.getSeconds(), - d.getMilliseconds() * 1000]); - }), - today: py.classmethod.fromJSON(function () { - var d = new Date(); - return py.PY_call(datetime.datetime, - [d.getFullYear(), d.getMonth() + 1, d.getDate()]); + [d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(), + d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), + d.getUTCMilliseconds() * 1000]); }), combine: py.classmethod.fromJSON(function () { var args = py.PY_parseArgs(arguments, 'date time'); @@ -439,11 +434,6 @@ openerp.web.pyeval = function (instance) { throw new Error('ValueError: No known conversion for ' + m); })); }, - today: py.classmethod.fromJSON(function () { - var d = new Date(); - return py.PY_call( - datetime.date, [d.getFullYear(), d.getMonth() + 1, d.getDate()]); - }), __eq__: function (other) { return (this.year === other.year && this.month === other.month @@ -479,6 +469,17 @@ openerp.web.pyeval = function (instance) { return py.PY_call(datetime.date, [year, month, day]) } }); + /** + Returns the current local date, which means the date on the client (which can be different + compared to the date of the server). + + @return {datetime.date} + */ + var context_today = function() { + var d = new Date(); + return py.PY_call( + datetime.date, [d.getFullYear(), d.getMonth() + 1, d.getDate()]); + }; datetime.time = py.type('time', null, { __init__: function () { var zero = py.float.fromJSON(0); @@ -691,6 +692,7 @@ openerp.web.pyeval = function (instance) { return { uid: py.float.fromJSON(instance.session.uid), datetime: datetime, + context_today: context_today, time: time, relativedelta: relativedelta, current_date: py.PY_call( diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 3917f342391..eea8bba726d 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -341,12 +341,10 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea if (this.headless) { this.ready.resolve(); } else { - var load_view = this.rpc("/web/view/load", { - model: this.model, + var load_view = instance.web.fields_view_get({ + model: this.dataset._model, view_id: this.view_id, view_type: 'search', - context: instance.web.pyeval.eval( - 'context', this.dataset.get_context()) }); $.when(load_view).then(function (r) { diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js index 5aeeeb4de78..e7aad43ffc7 100644 --- a/addons/web/static/src/js/testing.js +++ b/addons/web/static/src/js/testing.js @@ -10,7 +10,7 @@ openerp.testing = {}; formats: ['coresetup', 'dates'], chrome: ['corelib', 'coresetup'], views: ['corelib', 'coresetup', 'data', 'chrome'], - search: ['data', 'coresetup', 'formats'], + search: ['views', 'formats'], list: ['views', 'data'], form: ['data', 'views', 'list', 'formats'], list_editable: ['list', 'form', 'data'], @@ -263,7 +263,7 @@ openerp.testing = {}; ++di; } - instance = openerp.init("fuck your shit, don't load anything you cunt"); + instance = openerp.init(null); _(d).chain() .reverse() .uniq() diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index ac76354b571..814995da5f7 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -1189,36 +1189,19 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt }); } }, - view_arch_to_dom_node: function(arch) { - // Historic mess for views arch - // - // server: - // -> got xml as string - // -> parse to xml and manipulate domains and contexts - // -> convert to json - // client: - // -> got view as json - // -> convert back to xml as string - // -> parse it as xml doc (manipulate button@type for IE) - // -> convert back to string - // -> parse it as dom element with jquery - // -> for each widget, convert node to json - // - // Wow !!! - var xml = instance.web.json_node_to_xml(arch); - - var doc = $.parseXML('<div class="oe_form">' + xml + '</div>'); + get_arch_fragment: function() { + var doc = $.parseXML(instance.web.json_node_to_xml(this.fvg.arch)).documentElement; + // IE won't allow custom button@type and will revert it to spec default : 'submit' $('button', doc).each(function() { $(this).attr('data-button-type', $(this).attr('type')).attr('type', 'button'); }); - xml = instance.web.xml_to_str(doc); - return $(xml); + return $('<div class="oe_form"/>').append(instance.web.xml_to_str(doc)); }, render_to: function($target) { var self = this; this.$target = $target; - this.$form = this.view_arch_to_dom_node(this.fvg.arch); + this.$form = this.get_arch_fragment(); this.process_version(); @@ -2680,13 +2663,10 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan init: function(field_manager, node) { var self = this; this._super(field_manager, node); - this.values = _.clone(this.field.selection); - _.each(this.values, function(v, i) { - if (v[0] === false && v[1] === '') { - self.values.splice(i, 1); - } - }); - this.values.unshift([false, '']); + this.values = _(this.field.selection).chain() + .reject(function (v) { return v[0] === false && v[1] === ''; }) + .unshift([false, '']) + .value(); }, initialize_content: function() { // Flag indicating whether we're in an event chain containing a change @@ -2930,6 +2910,15 @@ instance.web.form.M2ODialog = instance.web.Dialog.extend({ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, { template: "FieldMany2One", + events: { + 'keydown input': function (e) { + switch (e.which) { + case $.ui.keyCode.UP: + case $.ui.keyCode.DOWN: + e.stopPropagation(); + } + } + }, init: function(field_manager, node) { this._super(field_manager, node); instance.web.form.CompletionFieldMixin.init.call(this); @@ -5260,6 +5249,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ instance.web.form.FieldMonetary = instance.web.form.FieldFloat.extend({ template: "FieldMonetary", + widget_class: 'oe_form_field_float oe_form_field_monetary', init: function() { this._super.apply(this, arguments); this.set({"currency": false}); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 5008d1765a6..04ff8b48923 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -600,6 +600,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi this.dataset.index = _(this.dataset.ids).indexOf(ids[0]); if (this.sidebar) { + this.options.$sidebar.show(); this.sidebar.$el.show(); } @@ -922,6 +923,18 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. }, this); this.$current = $('<tbody>') + .delegate('input[readonly=readonly]', 'click', function (e) { + /* + Against all logic and sense, as of right now @readonly + apparently does nothing on checkbox and radio inputs, so + the trick of using @readonly to have, well, readonly + checkboxes (which still let clicks go through) does not + work out of the box. We *still* need to preventDefault() + on the event, otherwise the checkbox's state *will* toggle + on click + */ + e.preventDefault(); + }) .delegate('th.oe_list_record_selector', 'click', function (e) { e.stopPropagation(); var selection = self.get_selection(); @@ -939,12 +952,18 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. field = $target.closest('td').data('field'), $row = $target.closest('tr'), record_id = self.row_id($row); + + if ($target.attr('disabled')) { + return; + } + $target.attr('disabled', 'disabled'); // note: $.data converts data to number if it's composed only // of digits, nice when storing actual numbers, not nice when // storing strings composed only of digits. Force the action // name to be a string $(self).trigger('action', [field.toString(), record_id, function (id) { + $target.removeAttr('disabled'); return self.reload_record(self.records.get(id)); }]); }) diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index 83a7efa6cd0..efc442de2a9 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -105,8 +105,15 @@ openerp.web.list_editable = function (instance) { * Replace do_search to handle editability process */ do_search: function(domain, context, group_by) { - this._context_editable = !!context.set_editable; - this._super.apply(this, arguments); + var self=this, _super = self._super, args=arguments; + var ready = this.editor.is_editing() + ? this.cancel_edition(true) + : $.when(); + + return ready.then(function () { + self._context_editable = !!context.set_editable; + return _super.apply(self, args); + }); }, /** * Replace do_add_record to handle editability (and adding new record diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js index 4d08da385fd..acac93f1842 100644 --- a/addons/web/static/src/js/view_tree.js +++ b/addons/web/static/src/js/view_tree.js @@ -9,6 +9,7 @@ var QWeb = instance.web.qweb, instance.web.views.add('tree', 'instance.web.TreeView'); instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeView# */{ display_name: _lt('Tree'), + view_type: 'tree', /** * Indicates that this view is not searchable, and thus that no search * view should be displayed (if there is one active). @@ -36,18 +37,9 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie this.options = _.extend({}, this.defaults, options || {}); _.bindAll(this, 'color_for'); + this.on('view_loaded', this, this.load_tree); }, - start: function () { - return this.rpc("/web/treeview/load", { - model: this.model, - view_id: this.view_id, - view_type: "tree", - toolbar: this.view_manager ? !!this.view_manager.sidebar : false, - context: instance.web.pyeval.eval( - 'context', this.dataset.get_context()) - }).done(this.on_loaded); - }, /** * Returns the list of fields needed to correctly read objects. * @@ -64,7 +56,7 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie } return fields; }, - on_loaded: function (fields_view) { + load_tree: function (fields_view) { var self = this; var has_toolbar = !!fields_view.arch.attrs.toolbar; // field name in OpenERP is kinda stupid: this is the name of the field diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index d7dcd590218..c0c6ae1f31d 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -275,7 +275,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ } if (action.domain) { action.domain = instance.web.pyeval.eval( - 'domain', action.domain); + 'domain', action.domain, action.context || {}); } if (!action.type) { @@ -758,12 +758,6 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ dataset.index = 0; } this.dataset = dataset; - - // setup storage for session-wise menu hiding - if (this.session.hidden_menutips) { - return; - } - this.session.hidden_menutips = {}; }, /** * Initializes the ViewManagerAction: sets up the searchview (if the @@ -1204,13 +1198,11 @@ instance.web.View = instance.web.Widget.extend({ } else { if (! this.view_type) console.warn("view_type is not defined", this); - view_loaded = this.rpc("/web/view/load", { - "model": this.dataset.model, + view_loaded = instance.web.fields_view_get({ + "model": this.dataset._model, "view_id": this.view_id, "view_type": this.view_type, - toolbar: !!this.options.$sidebar, - context: instance.web.pyeval.eval( - 'context', this.dataset.get_context(context)) + "toolbar": !!this.options.$sidebar, }); } return view_loaded.then(function(r) { @@ -1385,12 +1377,53 @@ instance.web.View = instance.web.Widget.extend({ } }); -instance.web.xml_to_json = function(node) { +/** + * Performs a fields_view_get and apply postprocessing. + * return a {$.Deferred} resolved with the fvg + * + * @param {Object} [args] + * @param {String|Object} args.model instance.web.Model instance or string repr of the model + * @param {null|Object} args.context context if args.model is a string + * @param {null|Number} args.view_id id of the view to be loaded, default view if null + * @param {null|String} args.view_type type of view to be loaded if view_id is null + * @param {Boolean} [args.toolbar=false] get the toolbar definition + */ +instance.web.fields_view_get = function(args) { + function postprocess(fvg) { + var doc = $.parseXML(fvg.arch).documentElement; + fvg.arch = instance.web.xml_to_json(doc, (doc.nodeName.toLowerCase() !== 'kanban')); + if ('id' in fvg.fields) { + // Special case for id's + var id_field = fvg.fields['id']; + id_field.original_type = id_field.type; + id_field.type = 'id'; + } + _.each(fvg.fields, function(field) { + _.each(field.views || {}, function(view) { + postprocess(view); + }); + }); + return fvg; + } + args = _.defaults(args, { + toolbar: false, + }); + var model = args.model; + if (typeof model === 'string') { + model = new instance.web.Model(args.model, args.context); + } + return args.model.call('fields_view_get', [args.view_id, args.view_type, model.context(), args.toolbar]).then(function(fvg) { + return postprocess(fvg); + }); +}; + +instance.web.xml_to_json = function(node, strip_whitespace) { switch (node.nodeType) { + case 9: + return instance.web.xml_to_json(node.documentElement, strip_whitespace); case 3: case 4: - return node.data; - break; + return (strip_whitespace && node.data.trim() === '') ? undefined : node.data; case 1: var attrs = $(node).getAttributes(); _.each(['domain', 'filter_domain', 'context', 'default_get'], function(key) { @@ -1403,7 +1436,9 @@ instance.web.xml_to_json = function(node) { return { tag: node.tagName.toLowerCase(), attrs: attrs, - children: _.map(node.childNodes, instance.web.xml_to_json) + children: _.compact(_.map(node.childNodes, function(node) { + return instance.web.xml_to_json(node, strip_whitespace); + })), } } } @@ -1455,26 +1490,6 @@ instance.web.xml_to_str = function(node) { throw new Error(_t("Could not serialize XML")); } }; -instance.web.str_to_xml = function(s) { - if (window.DOMParser) { - var dp = new DOMParser(); - var r = dp.parseFromString(s, "text/xml"); - if (r.body && r.body.firstChild && r.body.firstChild.nodeName == 'parsererror') { - throw new Error(_t("Could not parse string to xml")); - } - return r; - } - var xDoc; - try { - xDoc = new ActiveXObject("MSXML2.DOMDocument"); - } catch (e) { - throw new Error(_.str.sprintf( _t("Could not find a DOM Parser: %s"), e.message)); - } - xDoc.async = false; - xDoc.preserveWhiteSpace = true; - xDoc.loadXML(s); - return xDoc; -} /** * Registry for all the main views |
