diff --git a/.bzrignore b/.bzrignore index 6e9359571f4..b83a43bf1d4 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,12 +1,11 @@ -RE:lib/(?!populate.sh).* .* *.egg-info *.orig -bin/ build/ -dist/ -include/ +RE:^bin/ +RE:^dist/ +RE:^include/ -share/ -man/ -lib/ +RE:^share/ +RE:^man/ +RE:^lib/ diff --git a/addons/base/static/src/js/boot.js b/addons/base/static/src/js/boot.js index 7ac8a6bb1e0..3d1d1e75e7c 100644 --- a/addons/base/static/src/js/boot.js +++ b/addons/base/static/src/js/boot.js @@ -1,6 +1,6 @@ -//--------------------------------------------------------- -// OpenERP Web Boostrap -//--------------------------------------------------------- +/*--------------------------------------------------------- + * OpenERP Web Boostrap Code + *---------------------------------------------------------*/ /** * @name openerp @@ -14,13 +14,8 @@ /** @lends openerp */ var openerp = this.openerp = { - /** - * Debug flag turns on logging - */ + // debug flag debug: true, - // element_ids registry linked to all controllers on the page - // TODO rename to elements, or keep gtk naming? - screen: {}, // Per session namespace // openerp. will map to // openerp.sessions.sessionname. using a closure @@ -40,8 +35,6 @@ // this unique id will be replaced by hostname_databasename by // openerp.base.Connection on the first connection _session_id: "session" + session_counter++, - screen: openerp.screen, - sessions: openerp.sessions, base: {}, web_mobile: {} }; @@ -51,12 +44,13 @@ } return new_instance; } + // TODO add initrpc to init core only for RPC }; })(); -//--------------------------------------------------------- -// OpenERP base module split -//--------------------------------------------------------- +/*--------------------------------------------------------- + * OpenERP Web base module split + *---------------------------------------------------------*/ openerp.base = function(instance) { openerp.base.core(instance); diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 822dc52b5c2..7e7f5ae6ab6 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -1,285 +1,9 @@ /*--------------------------------------------------------- - * OpenERP base library + * OpenERP Web chrome *---------------------------------------------------------*/ openerp.base.chrome = function(openerp) { -openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{ - /** - * @constructs - * @param element_id to use for exception reporting - * @param server - * @param port - */ - init: function(parent, element_id, server, port) { - this._super(parent, element_id); - this.server = (server == undefined) ? location.hostname : server; - this.port = (port == undefined) ? location.port : port; - this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp"; - this.debug = true; - this.db = ""; - this.login = ""; - this.password = ""; - this.uid = false; - this.session_id = false; - this.module_list = []; - this.module_loaded = {"base": true}; - this.context = {}; - }, - start: function() { - this.session_restore(); - }, - /** - * Executes an RPC call, registering the provided callbacks. - * - * Registers a default error callback if none is provided, and handles - * setting the correct session id and session context in the parameter - * objects - * - * @param {String} url RPC endpoint - * @param {Object} params call parameters - * @param {Function} success_callback function to execute on RPC call success - * @param {Function} error_callback function to execute on RPC call failure - * @returns {jQuery.Deferred} jquery-provided ajax deferred - */ - rpc: function(url, params, success_callback, error_callback) { - var self = this; - // Construct a JSON-RPC2 request, method is currently unused - params.session_id = this.session_id; - - // Call using the rpc_mode - var deferred = $.Deferred(); - this.rpc_ajax(url, { - jsonrpc: "2.0", - method: "call", - params: params, - id:null - }).then(function () {deferred.resolve.apply(deferred, arguments);}, - function(error) {deferred.reject(error, $.Event());}); - return deferred.fail(function() { - deferred.fail(function(error, event) { - if (!event.isDefaultPrevented()) { - self.on_rpc_error(error, event); - } - }); - }).then(success_callback, error_callback).promise(); - }, - /** - * Raw JSON-RPC call - * - * @returns {jQuery.Deferred} ajax-based deferred object - */ - rpc_ajax: function(url, payload) { - var self = this; - this.on_rpc_request(); - // url can be an $.ajax option object - if (_.isString(url)) { - url = { - url: url - } - } - var ajax = _.extend({ - type: "POST", - url: url, - dataType: 'json', - contentType: 'application/json', - data: JSON.stringify(payload), - processData: false - }, url); - var deferred = $.Deferred(); - $.ajax(ajax).done(function(response, textStatus, jqXHR) { - self.on_rpc_response(); - if (!response.error) { - deferred.resolve(response["result"], textStatus, jqXHR); - return; - } - if (response.error.data.type !== "session_invalid") { - deferred.reject(response.error); - return; - } - self.uid = false; - self.on_session_invalid(function() { - self.rpc(url, payload.params, - function() { - deferred.resolve.apply(deferred, arguments); - }, - function(error, event) { - event.preventDefault(); - deferred.reject.apply(deferred, arguments); - }); - }); - }).fail(function(jqXHR, textStatus, errorThrown) { - self.on_rpc_response(); - var error = { - code: -32098, - message: "XmlHttpRequestError " + errorThrown, - data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] } - }; - deferred.reject(error); - }); - return deferred.promise(); - }, - on_rpc_request: function() { - }, - on_rpc_response: function() { - }, - on_rpc_error: function(error) { - }, - /** - * The session is validated either by login or by restoration of a previous session - */ - on_session_valid: function() { - if(!openerp._modules_loaded) - this.load_modules(); - }, - on_session_invalid: function(contination) { - }, - session_is_valid: function() { - return this.uid; - }, - session_login: function(db, login, password, success_callback) { - var self = this; - this.db = db; - this.login = login; - this.password = password; - var params = { db: this.db, login: this.login, password: this.password }; - this.rpc("/base/session/login", params, function(result) { - self.session_id = result.session_id; - self.uid = result.uid; - self.session_save(); - self.on_session_valid(); - if (success_callback) - success_callback(); - }); - }, - session_logout: function() { - this.uid = false; - }, - /** - * Reloads uid and session_id from local storage, if they exist - */ - session_restore: function () { - this.uid = this.get_cookie('uid'); - this.session_id = this.get_cookie('session_id'); - this.db = this.get_cookie('db'); - this.login = this.get_cookie('login'); - // we should do an rpc to confirm that this session_id is valid and if it is retrieve the information about db and login - // then call on_session_valid - this.on_session_valid(); - }, - /** - * Saves the session id and uid locally - */ - session_save: function () { - this.set_cookie('uid', this.uid); - this.set_cookie('session_id', this.session_id); - this.set_cookie('db', this.db); - this.set_cookie('login', this.login); - }, - logout: function() { - delete this.uid; - delete this.session_id; - delete this.db; - delete this.login; - this.set_cookie('uid', ''); - this.set_cookie('session_id', ''); - this.set_cookie('db', ''); - this.set_cookie('login', ''); - this.on_session_invalid(function() {}); - }, - /** - * Fetches a cookie stored by an openerp session - * - * @private - * @param name the cookie's name - */ - get_cookie: function (name) { - var nameEQ = this.element_id + '|' + name + '='; - var cookies = document.cookie.split(';'); - for(var i=0; i').dialog(this.dialog_options); - if (auto_open !== false) { - this.open(); - } this._super(); + return this; }, open: function(dialog_options) { // TODO fme: bind window on resize @@ -952,6 +672,7 @@ openerp.base.Preferences = openerp.base.Widget.extend({ openerp.base.WebClient = openerp.base.Widget.extend({ init: function(element_id) { this._super(null, element_id); + openerp.webclient = this; QWeb.add_template("/base/static/src/xml/base.xml"); var params = {}; @@ -963,7 +684,7 @@ openerp.base.WebClient = openerp.base.Widget.extend({ this.session = new openerp.base.Session(this,"oe_errors"); this.loading = new openerp.base.Loading(this,"oe_loading"); this.crashmanager = new openerp.base.CrashManager(this); - this.crashmanager.start(false); + this.crashmanager.start(); // Do you autorize this ? will be replaced by notify() in controller openerp.base.Widget.prototype.notification = new openerp.base.Notification(this, "oe_notification"); @@ -988,6 +709,8 @@ openerp.base.WebClient = openerp.base.Widget.extend({ this.notification.notify("OpenERP Client", "The openerp client has been initialized."); }, on_logged: function() { + if(this.action_manager) + this.action_manager.stop(); this.action_manager = new openerp.base.ActionManager(this); this.action_manager.appendTo($("#oe_app")); diff --git a/addons/base/static/src/js/core.js b/addons/base/static/src/js/core.js index 80dba3cd10c..859c96645a1 100644 --- a/addons/base/static/src/js/core.js +++ b/addons/base/static/src/js/core.js @@ -1,5 +1,5 @@ /*--------------------------------------------------------- - * OpenERP controller framework + * OpenERP Web core *--------------------------------------------------------*/ openerp.base.core = function(openerp) { @@ -574,6 +574,18 @@ openerp.base.Widget = openerp.base.SessionAware.extend({ } return false; }, + do_notify: function() { + if (this.widget_parent) { + return this.widget_parent.do_notify.apply(this,arguments); + } + return false; + }, + do_warn: function() { + if (this.widget_parent) { + return this.widget_parent.do_warn.apply(this,arguments); + } + return false; + }, rpc: function(url, data, success, error) { var def = $.Deferred().then(success, error); var self = this; @@ -599,5 +611,282 @@ openerp.base.OldWidget = openerp.base.Widget.extend({ } }); +openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{ + /** + * @constructs + * @param element_id to use for exception reporting + * @param server + * @param port + */ + init: function(parent, element_id, server, port) { + this._super(parent, element_id); + this.server = (server == undefined) ? location.hostname : server; + this.port = (port == undefined) ? location.port : port; + this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp"; + this.debug = true; + this.db = ""; + this.login = ""; + this.password = ""; + this.uid = false; + this.session_id = false; + this.module_list = []; + this.module_loaded = {"base": true}; + this.context = {}; + }, + start: function() { + this.session_restore(); + }, + /** + * Executes an RPC call, registering the provided callbacks. + * + * Registers a default error callback if none is provided, and handles + * setting the correct session id and session context in the parameter + * objects + * + * @param {String} url RPC endpoint + * @param {Object} params call parameters + * @param {Function} success_callback function to execute on RPC call success + * @param {Function} error_callback function to execute on RPC call failure + * @returns {jQuery.Deferred} jquery-provided ajax deferred + */ + rpc: function(url, params, success_callback, error_callback) { + var self = this; + // Construct a JSON-RPC2 request, method is currently unused + params.session_id = this.session_id; + + // Call using the rpc_mode + var deferred = $.Deferred(); + this.rpc_ajax(url, { + jsonrpc: "2.0", + method: "call", + params: params, + id:null + }).then(function () {deferred.resolve.apply(deferred, arguments);}, + function(error) {deferred.reject(error, $.Event());}); + return deferred.fail(function() { + deferred.fail(function(error, event) { + if (!event.isDefaultPrevented()) { + self.on_rpc_error(error, event); + } + }); + }).then(success_callback, error_callback).promise(); + }, + /** + * Raw JSON-RPC call + * + * @returns {jQuery.Deferred} ajax-based deferred object + */ + rpc_ajax: function(url, payload) { + var self = this; + this.on_rpc_request(); + // url can be an $.ajax option object + if (_.isString(url)) { + url = { + url: url + } + } + var ajax = _.extend({ + type: "POST", + url: url, + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify(payload), + processData: false + }, url); + var deferred = $.Deferred(); + $.ajax(ajax).done(function(response, textStatus, jqXHR) { + self.on_rpc_response(); + if (!response.error) { + deferred.resolve(response["result"], textStatus, jqXHR); + return; + } + if (response.error.data.type !== "session_invalid") { + deferred.reject(response.error); + return; + } + self.uid = false; + self.on_session_invalid(function() { + self.rpc(url, payload.params, + function() { + deferred.resolve.apply(deferred, arguments); + }, + function(error, event) { + event.preventDefault(); + deferred.reject.apply(deferred, arguments); + }); + }); + }).fail(function(jqXHR, textStatus, errorThrown) { + self.on_rpc_response(); + var error = { + code: -32098, + message: "XmlHttpRequestError " + errorThrown, + data: {type: "xhr"+textStatus, debug: jqXHR.responseText, objects: [jqXHR, errorThrown] } + }; + deferred.reject(error); + }); + return deferred.promise(); + }, + on_rpc_request: function() { + }, + on_rpc_response: function() { + }, + on_rpc_error: function(error) { + }, + /** + * The session is validated either by login or by restoration of a previous session + */ + on_session_valid: function() { + if(!openerp._modules_loaded) + this.load_modules(); + }, + on_session_invalid: function(contination) { + }, + session_is_valid: function() { + return this.uid; + }, + session_login: function(db, login, password, success_callback) { + var self = this; + this.db = db; + this.login = login; + this.password = password; + var params = { db: this.db, login: this.login, password: this.password }; + this.rpc("/base/session/login", params, function(result) { + self.session_id = result.session_id; + self.uid = result.uid; + self.session_save(); + self.on_session_valid(); + if (success_callback) + success_callback(); + }); + }, + session_logout: function() { + this.uid = false; + }, + /** + * Reloads uid and session_id from local storage, if they exist + */ + session_restore: function () { + this.uid = this.get_cookie('uid'); + this.session_id = this.get_cookie('session_id'); + this.db = this.get_cookie('db'); + this.login = this.get_cookie('login'); + // we should do an rpc to confirm that this session_id is valid and if it is retrieve the information about db and login + // then call on_session_valid + this.on_session_valid(); + }, + /** + * Saves the session id and uid locally + */ + session_save: function () { + this.set_cookie('uid', this.uid); + this.set_cookie('session_id', this.session_id); + this.set_cookie('db', this.db); + this.set_cookie('login', this.login); + }, + logout: function() { + delete this.uid; + delete this.session_id; + delete this.db; + delete this.login; + this.set_cookie('uid', ''); + this.set_cookie('session_id', ''); + this.set_cookie('db', ''); + this.set_cookie('login', ''); + this.on_session_invalid(function() {}); + }, + /** + * Fetches a cookie stored by an openerp session + * + * @private + * @param name the cookie's name + */ + get_cookie: function (name) { + var nameEQ = this.element_id + '|' + name + '='; + var cookies = document.cookie.split(';'); + for(var i=0; i= limit) { - // TODO: check if this could work do only read if possible - // return read_ids(ids.slice(start,start+limit),fields,callback) - } - } + var offset = options.offset || 0; return this.rpc('/base/dataset/search_read', { model: this.model, - fields: fields, - domain: this.domain, - context: this.get_context(), + fields: options.fields || false, + domain: this.get_domain(options.domain), + context: this.get_context(options.context), sort: this.sort(), offset: offset, - limit: limit + limit: options.limit || false }, function (result) { self.ids = result.ids; self.offset = offset; @@ -453,6 +551,12 @@ openerp.base.DataSetSearch = openerp.base.DataSet.extend({ } }); }, + get_domain: function (other_domain) { + if (other_domain) { + return new openerp.base.CompoundDomain(this.domain, other_domain); + } + return this.domain; + }, /** * Reads or changes sort criteria on the dataset. * @@ -628,48 +732,51 @@ openerp.base.ReadOnlyDataSetSearch = openerp.base.DataSetSearch.extend({ on_unlink: function(ids) {} }); -openerp.base.CompoundContext = function() { - this.__ref = "compound_context"; - this.__contexts = []; - this.__eval_context = null; - var self = this; - _.each(arguments, function(x) { - self.add(x); - }); -}; -openerp.base.CompoundContext.prototype.add = function(context) { - this.__contexts.push(context); - return this; -}; -openerp.base.CompoundContext.prototype.set_eval_context = function(eval_context) { - this.__eval_context = eval_context; - return this; -}; -openerp.base.CompoundContext.prototype.get_eval_context = function() { - return this.__eval_context; -}; - -openerp.base.CompoundDomain = function() { - this.__ref = "compound_domain"; - this.__domains = []; - this.__eval_context = null; - var self = this; - _.each(arguments, function(x) { - self.add(x); - }); -}; -openerp.base.CompoundDomain.prototype.add = function(domain) { - this.__domains.push(domain); - return this; -}; -openerp.base.CompoundDomain.prototype.set_eval_context = function(eval_context) { - this.__eval_context = eval_context; - return this; -}; -openerp.base.CompoundDomain.prototype.get_eval_context = function() { - return this.__eval_context; -}; +openerp.base.CompoundContext = openerp.base.Class.extend({ + init: function () { + this.__ref = "compound_context"; + this.__contexts = []; + this.__eval_context = null; + var self = this; + _.each(arguments, function(x) { + self.add(x); + }); + }, + add: function (context) { + this.__contexts.push(context); + return this; + }, + set_eval_context: function (eval_context) { + this.__eval_context = eval_context; + return this; + }, + get_eval_context: function () { + return this.__eval_context; + } +}); +openerp.base.CompoundDomain = openerp.base.Class.extend({ + init: function () { + this.__ref = "compound_domain"; + this.__domains = []; + this.__eval_context = null; + var self = this; + _.each(arguments, function(x) { + self.add(x); + }); + }, + add: function(domain) { + this.__domains.push(domain); + return this; + }, + set_eval_context: function(eval_context) { + this.__eval_context = eval_context; + return this; + }, + get_eval_context: function() { + return this.__eval_context; + } +}); }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 6e0f986cb48..bbf7a4e5f31 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -451,12 +451,14 @@ openerp.base.form.SidebarAttachments = openerp.base.Widget.extend({ this.on_attachments_loaded([]); } else { (new openerp.base.DataSetSearch( - this, 'ir.attachment', this.view.dataset.get_context(), - [['res_model', '=', this.view.dataset.model], - ['res_id', '=', this.view.datarecord.id], - ['type', 'in', ['binary', 'url']]])).read_slice( - ['name', 'url', 'type'], false, false, - this.on_attachments_loaded); + this, 'ir.attachment', this.view.dataset.get_context(), + [ + ['res_model', '=', this.view.dataset.model], + ['res_id', '=', this.view.datarecord.id], + ['type', 'in', ['binary', 'url']] + ])).read_slice( + {fields: ['name', 'url', 'type']}, + this.on_attachments_loaded); } }, on_attachments_loaded: function(attachments) { @@ -510,36 +512,40 @@ openerp.base.form.compute_domain = function(expr, fields) { } } - var field = fields[ex[0]].get_value ? fields[ex[0]].get_value() : fields[ex[0]].value; + var field = fields[ex[0]]; + if (!field) { + throw new Error("Domain references unknown field : " + ex[0]); + } + var field_value = field.get_value ? fields[ex[0]].get_value() : fields[ex[0]].value; var op = ex[1]; var val = ex[2]; switch (op.toLowerCase()) { case '=': case '==': - stack.push(field == val); + stack.push(field_value == val); break; case '!=': case '<>': - stack.push(field != val); + stack.push(field_value != val); break; case '<': - stack.push(field < val); + stack.push(field_value < val); break; case '>': - stack.push(field > val); + stack.push(field_value > val); break; case '<=': - stack.push(field <= val); + stack.push(field_value <= val); break; case '>=': - stack.push(field >= val); + stack.push(field_value >= val); break; case 'in': - stack.push(_(val).contains(field)); + stack.push(_(val).contains(field_value)); break; case 'not in': - stack.push(!_(val).contains(field)); + stack.push(!_(val).contains(field_value)); break; default: this.log("Unsupported operator in modifiers :", op); @@ -767,8 +773,7 @@ openerp.base.form.WidgetButton = openerp.base.form.Widget.extend({ var self = this; this.view.execute_action( - this.node.attrs, this.view.dataset, this.session.action_manager, - this.view.datarecord.id, function () { + this.node.attrs, this.view.dataset, this.view.datarecord.id, function () { self.view.reload(); }); } @@ -803,7 +808,7 @@ openerp.base.form.WidgetLabel = openerp.base.form.Widget.extend({ var self = this; this.$element.find("label").dblclick(function() { var widget = self['for'] || self; - console.log(widget.element_id , widget); + self.log(widget.element_id , widget); }); } }); @@ -1885,7 +1890,7 @@ openerp.base.form.FieldMany2Many = openerp.base.form.Field.extend({ self.on_ui_change(); }); - this.list_view = new openerp.base.form.Many2ManyListView(new openerp.base.NullViewManager(this), this.list_id, this.dataset, false, { + this.list_view = new openerp.base.form.Many2ManyListView(this, this.list_id, this.dataset, false, { 'addable': 'Add', 'selectable': self.multi_selection }); @@ -2210,8 +2215,8 @@ openerp.base.form.FieldBinary = openerp.base.form.Field.extend({ delete(window[this.iframe]); if (size === false) { this.notification.warn("File Upload", "There was a problem while uploading your file"); - // TODO: use openerp web exception handler - console.log("Error while uploading file : ", name); + // TODO: use openerp web crashmanager + this.log("Error while uploading file : ", name); } else { this.on_file_uploaded_and_valid.apply(this, arguments); this.on_ui_change(); @@ -2320,10 +2325,8 @@ openerp.base.form.widgets = new openerp.base.Registry({ 'url' : 'openerp.base.form.FieldUrl', 'text' : 'openerp.base.form.FieldText', 'text_wiki' : 'openerp.base.form.FieldText', -// 'date' : 'openerp.base.form.FieldDate', -// 'datetime' : 'openerp.base.form.FieldDatetime', - 'date' : 'openerp.base.form.FieldChar', - 'datetime' : 'openerp.base.form.FieldChar', + 'date' : 'openerp.base.form.FieldDate', + 'datetime' : 'openerp.base.form.FieldDatetime', 'selection' : 'openerp.base.form.FieldSelection', 'many2one' : 'openerp.base.form.FieldMany2One', 'many2many' : 'openerp.base.form.FieldMany2Many', diff --git a/addons/base/static/src/js/formats.js b/addons/base/static/src/js/formats.js index 3157997e82d..fb1ada544a4 100644 --- a/addons/base/static/src/js/formats.js +++ b/addons/base/static/src/js/formats.js @@ -74,15 +74,16 @@ openerp.base.parse_time = function(str) { }; /* - * Just a simple function to add some '0' if an integer it too small. + * Left-pad provided arg 1 with zeroes until reaching size provided by second + * argument. + * + * @param {Number|String} str value to pad + * @param {Number} size size to reach on the final padded value + * @returns {String} padded string */ -var fts = function(str, size) { +var zpad = function(str, size) { str = "" + str; - var to_add = ""; - _.each(_.range(size - str.length), function() { - to_add = to_add + "0"; - }); - return to_add + str; + return new Array(size - str.length).join('0') + str; }; /** @@ -99,9 +100,9 @@ openerp.base.format_datetime = function(obj) { if (!obj) { return false; } - return fts(obj.getUTCFullYear(),4) + "-" + fts(obj.getUTCMonth() + 1,2) + "-" - + fts(obj.getUTCDate(),2) + " " + fts(obj.getUTCHours(),2) + ":" - + fts(obj.getUTCMinutes(),2) + ":" + fts(obj.getUTCSeconds(),2); + return zpad(obj.getUTCFullYear(),4) + "-" + zpad(obj.getUTCMonth() + 1,2) + "-" + + zpad(obj.getUTCDate(),2) + " " + zpad(obj.getUTCHours(),2) + ":" + + zpad(obj.getUTCMinutes(),2) + ":" + zpad(obj.getUTCSeconds(),2); }; /** @@ -115,8 +116,8 @@ openerp.base.format_date = function(obj) { if (!obj) { return false; } - return fts(obj.getFullYear(),4) + "-" + fts(obj.getMonth() + 1,2) + "-" - + fts(obj.getDate(),2); + return zpad(obj.getFullYear(),4) + "-" + zpad(obj.getMonth() + 1,2) + "-" + + zpad(obj.getDate(),2); }; /** @@ -130,8 +131,8 @@ openerp.base.format_time = function(obj) { if (!obj) { return false; } - return fts(obj.getHours(),2) + ":" + fts(obj.getMinutes(),2) + ":" - + fts(obj.getSeconds(),2); + return zpad(obj.getHours(),2) + ":" + zpad(obj.getMinutes(),2) + ":" + + zpad(obj.getSeconds(),2); }; /** diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 11440a003b5..e7abfdfaf0f 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -61,7 +61,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi /** * Retrieves the view's number of records per page (|| section) * - * options > defaults > indefinite + * options > defaults > parent.action.limit > indefinite * * @returns {Number|null} */ @@ -69,6 +69,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi if (this._limit === undefined) { this._limit = (this.options.limit || this.defaults.limit + || (this.widget_parent.action || {}).limit || null); } return this._limit; @@ -94,7 +95,7 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi self.do_delete(ids); }, 'action': function (e, action_name, id, callback) { - self.do_action(action_name, id, callback); + self.do_button_action(action_name, id, callback); }, 'row_link': function (e, id, dataset) { self.do_activate_record(dataset.index, id, dataset); @@ -399,11 +400,10 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * @param {Object} results results of evaluating domain and process for a search */ do_actual_search: function (results) { - this.dataset.context = results.context; - this.dataset.domain = results.domain; this.groups.datagroup = new openerp.base.DataGroup( this, this.model, - results.domain, results.context, + this.dataset.get_domain(results.domain), + this.dataset.get_context(results.context), results.group_by); this.groups.datagroup.sort = this.dataset._sort; @@ -454,17 +454,16 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi * @param {Object} id id of the record the action should be called on * @param {Function} callback should be called after the action is executed, if non-null */ - do_action: function (name, id, callback) { + do_button_action: function (name, id, callback) { var self = this, action = _.detect(this.columns, function (field) { return field.name === name; }); if (!action) { return; } - this.execute_action( - action, this.dataset, this.session.action_manager, id, function () { - $.when(callback.apply(this, arguments).then(function () { - self.compute_aggregates(); - })); + this.execute_action(action, this.dataset, id, function () { + $.when(callback.apply(this, arguments).then(function () { + self.compute_aggregates(); + })); }); }, /** @@ -476,11 +475,11 @@ openerp.base.ListView = openerp.base.View.extend( /** @lends openerp.base.ListVi */ do_activate_record: function (index, id, dataset) { var self = this; - _.extend(this.dataset, { - domain: dataset.domain, - context: dataset.get_context() - }).read_slice([], 0, false, function () { - self.select_record(index); + this.dataset.read_slice({ + context: dataset.get_context(), + domain: dataset.get_domain() + }, function () { + self.select_record(index); }); }, /** @@ -1034,10 +1033,11 @@ openerp.base.ListView.Groups = openerp.base.Class.extend( /** @lends openerp.bas d = new $.Deferred(), page = this.datagroup.openable ? this.page : view.page; - dataset.read_slice( - _.filter(_.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name'), _.identity), - page * limit, limit, - function (records) { + dataset.read_slice({ + fields: _.filter(_.pluck(_.select(this.columns, function(x) {return x.tag == "field";}), 'name'), _.identity), + offset: page * limit, + limit: limit + }, function (records) { if (!self.datagroup.openable) { view.configure_pager(dataset); } else { diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js index 0a1f2396123..661e0d650b8 100644 --- a/addons/base/static/src/js/search.js +++ b/addons/base/static/src/js/search.js @@ -3,7 +3,6 @@ openerp.base.search = function(openerp) { openerp.base.SearchView = openerp.base.Widget.extend({ init: function(parent, element_id, dataset, view_id, defaults) { this._super(parent, element_id); - this.view_manager = parent || new openerp.base.NullViewManager(); this.dataset = dataset; this.model = dataset.model; this.view_id = view_id; @@ -624,39 +623,6 @@ openerp.base.search.CharField = openerp.base.search.Field.extend( /** @lends ope return this.$element.val(); } }); -openerp.base.search.BooleanField = openerp.base.search.Field.extend({ - template: 'SearchView.field.selection', - init: function () { - this._super.apply(this, arguments); - this.attrs.selection = [ - ['true', 'Yes'], - ['false', 'No'] - ]; - }, - /** - * Search defaults likely to be boolean values (for a boolean field). - * - * In the HTML, we only get strings, and our strings here are - * 'true' and 'false', so ensure we get only - * those by truth-testing the default value. - * - * @param {Object} defaults default values for this search view - */ - render: function (defaults) { - var name = this.attrs.name; - if (name in defaults) { - defaults[name] = defaults[name] ? "true" : "false"; - } - return this._super(defaults); - }, - get_value: function () { - switch (this.$element.val()) { - case 'false': return false; - case 'true': return true; - default: return null; - } - } -}); openerp.base.search.NumberField = openerp.base.search.Field.extend(/** @lends openerp.base.search.NumberField# */{ get_value: function () { if (!this.$element.val()) { @@ -693,90 +659,73 @@ openerp.base.search.FloatField = openerp.base.search.NumberField.extend(/** @len return parseFloat(value); } }); -openerp.base.search.SelectionField = openerp.base.search.Field.extend({ +/** + * @class + * @extends openerp.base.search.Field + */ +openerp.base.search.SelectionField = openerp.base.search.Field.extend(/** @lends openerp.base.search.SelectionField# */{ template: 'SearchView.field.selection', get_value: function () { return this.$element.val(); } }); +openerp.base.search.BooleanField = openerp.base.search.SelectionField.extend(/** @lends openerp.base.search.BooleanField# */{ + /** + * @constructs + * @extends openerp.base.search.BooleanField + */ + init: function () { + this._super.apply(this, arguments); + this.attrs.selection = [ + ['true', 'Yes'], + ['false', 'No'] + ]; + }, + /** + * Search defaults likely to be boolean values (for a boolean field). + * + * In the HTML, we only want/get strings, and our strings here are ``true`` + * and ``false``, so ensure we use precisely those by truth-testing the + * default value (iif there is one in the view's defaults). + * + * @param {Object} defaults default values for this search view + * @returns {String} rendered boolean field + */ + render: function (defaults) { + var name = this.attrs.name; + if (name in defaults) { + defaults[name] = defaults[name] ? "true" : "false"; + } + return this._super(defaults); + }, + get_value: function () { + switch (this.$element.val()) { + case 'false': return false; + case 'true': return true; + default: return null; + } + } +}); openerp.base.search.DateField = openerp.base.search.Field.extend( /** @lends openerp.base.search.DateField# */{ - template: 'SearchView.fields.date', /** * enables date picker on the HTML widgets */ start: function () { this._super(); - this.$element.find('input').datepicker({ + this.$element.addClass('field_date').datepicker({ dateFormat: 'yy-mm-dd' }); }, stop: function () { - this.$element.find('input').datepicker('destroy'); + this.$element.datepicker('destroy'); }, - /** - * Returns an object with two optional keys ``from`` and ``to`` providing - * the values for resp. the from and to sections of the date widget. - * - * If a key is absent, then the corresponding field was not filled. - * - * @returns {Object} - */ - get_values: function () { - var values_array = this.$element.find('input').serializeArray(); - - if (!values_array || !values_array[0]) { - throw new openerp.base.search.Invalid( - this.attrs.name, null, "widget not ready"); - } - var from = values_array[0].value, - to = values_array[1].value; - - var field_values = {}; - if (from) { - field_values.from = from; - } - if (to) { - field_values.to = to; - } - return field_values; - }, - get_context: function () { - var values = this.get_values(); - if (!this.attrs.context || _.isEmpty(values)) { - return null; - } - return _.extend( - {}, this.attrs.context, - {own_values: {self: values}}); - }, - get_domain: function () { - var values = this.get_values(); - if (_.isEmpty(values)) { - return null; - } - var domain = this.attrs['filter_domain']; - if (!domain) { - domain = []; - if (values.from) { - domain.push([this.attrs.name, '>=', values.from]); - } - if (values.to) { - domain.push([this.attrs.name, '<=', values.to]); - } - return domain; - } - - return _.extend( - {}, domain, - {own_values: {self: values}}); + get_value: function () { + return this.$element.val(); } }); openerp.base.search.DateTimeField = openerp.base.search.DateField.extend({ // TODO: time? }); -openerp.base.search.OneToManyField = openerp.base.search.CharField.extend({ - // TODO: .relation, .context, .domain -}); openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({ // TODO: @widget // TODO: .selection, .context, .domain @@ -847,9 +796,6 @@ openerp.base.search.ManyToOneField = openerp.base.search.CharField.extend({ return this._super(); } }); -openerp.base.search.ManyToManyField = openerp.base.search.CharField.extend({ - // TODO: .related_columns (Array), .context, .domain -}); openerp.base.search.ExtendedSearch = openerp.base.OldWidget.extend({ template: 'SearchView.extended_search', diff --git a/addons/base/static/src/js/view_tree.js b/addons/base/static/src/js/view_tree.js index 05f58c077ff..da426080574 100644 --- a/addons/base/static/src/js/view_tree.js +++ b/addons/base/static/src/js/view_tree.js @@ -72,7 +72,7 @@ openerp.base.TreeView = openerp.base.View.extend({ 'toolbar': has_toolbar })); - this.dataset.read_slice(this.fields_list(), 0, false, function (records) { + this.dataset.read_slice({fields: this.fields_list()}, function (records) { if (!has_toolbar) { // WARNING: will do a second read on the same ids, but only on // first load so not very important @@ -177,7 +177,7 @@ openerp.base.TreeView = openerp.base.View.extend({ if (!actions.length) { return; } var action = actions[0][2]; action.flags.new_window = true; - self.session.action_manager.do_action(action); + self.do_action(action); }); }, diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 9c1379acd32..7cb7ec5d23f 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -9,27 +9,6 @@ openerp.base.views = function(openerp) { */ openerp.base.client_actions = new openerp.base.Registry(); -/** - * Registry for all the main views - */ -openerp.base.views = new openerp.base.Registry(); - -openerp.base.ActionDialog = openerp.base.Dialog.extend({ - identifier_prefix: 'action_dialog', - on_close: function() { - this._super(this, arguments); - if (this.close_callback) { - this.close_callback(); - } - }, - stop: function() { - this._super(this, arguments); - if (this.viewmanager) { - this.viewmanager.stop(); - } - } -}); - openerp.base.ActionManager = openerp.base.Widget.extend({ identifier_prefix: "actionmanager", init: function(parent) { @@ -68,25 +47,24 @@ openerp.base.ActionManager = openerp.base.Widget.extend({ pager : !popup }, action.flags || {}); if (!(type in this)) { - console.log("Action manager can't handle action of type " + action.type, action); + this.log("Action manager can't handle action of type " + action.type, action); return; } - this[type](action, on_closed); + this[type](action, on_close); }, - ir_actions_act_window: function (action, on_closed) { + ir_actions_act_window: function (action, on_close) { if (action.flags.popup) { if (this.dialog == null) { - this.dialog = new openerp.base.ActionDialog(this, { title: action.name, width: '80%' }); - this.dialog.close_callback = on_closed; - this.dialog.start(false); - this.dialog_viewmanager = new openerp.base.ViewManagerAction(this, action); - this.dialog_viewmanager.appendTo(this.dialog.$element); - this.dialog.open(); + this.dialog = new openerp.base.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 openerp.base.ViewManagerAction(this, action); - this.dialog_viewmanager.appendTo(this.dialog.$element); } + this.dialog_viewmanager = new openerp.base.ViewManagerAction(this, action); + this.dialog_viewmanager.appendTo(this.dialog.$element); + this.dialog.open(); } else { this.dialog_stop(); this.inner_stop(); @@ -101,7 +79,7 @@ openerp.base.ActionManager = openerp.base.Widget.extend({ */ }, ir_actions_act_window_close: function (action, on_closed) { - this.close_dialog(); + this.dialog_stop(); }, ir_actions_server: function (action, on_closed) { var self = this; @@ -253,9 +231,8 @@ openerp.base.ViewManager = openerp.base.Widget.extend({ this.searchview.hide(); } this.searchview.on_search.add(function(domains, contexts, groupbys) { - self.views[self.active_view].controller.do_search.call( - self, domains.concat(self.domains()), - contexts.concat(self.contexts()), groupbys); + var controller = self.views[self.active_view].controller; + controller.do_search.call(controller, domains, contexts, groupbys); }); return this.searchview.start(); }, @@ -269,49 +246,19 @@ openerp.base.ViewManager = openerp.base.Widget.extend({ on_remove: function() { }, on_edit: function() { - }, - /** - * Domains added on searches by the view manager, to override in subsequent - * view manager in order to add new pieces of domains to searches - * - * @returns an empty list - */ - domains: function () { - return []; - }, - /** - * Contexts added on searches by the view manager. - * - * @returns an empty list - */ - contexts: function () { - return []; } }); -openerp.base.NullViewManager = openerp.base.generate_null_object_class(openerp.base.ViewManager, { - init: function(parent) { - this._super(parent); - if(parent) - this.session = parent.session; - this.action = {flags: {}}; - } -}); - -// Move parts or everything to ActionManager openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ init: function(parent, action) { this.session = parent.session; var dataset; if (!action.res_id) { - dataset = new openerp.base.DataSetSearch(this, action.res_model, action.context || null, action.domain || null); + dataset = new openerp.base.DataSetSearch(this, action.res_model, action.context, action.domain); } else { - dataset = new openerp.base.DataSetStatic(this, action.res_model, {}, [action.res_id]); - if (action.context) { - // TODO fme: should normalize all DataSets constructors to (session, model, context, domain, ...) - dataset.context = action.context; - } + dataset = new openerp.base.DataSetStatic(this, action.res_model, action.context, [action.res_id]); } + this.action = action; this._super(parent, dataset, action.views); this.action = action; this.flags = this.action.flags || {}; @@ -344,28 +291,6 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ .then(this.searchview.do_search); } } - }, - /** - * adds action domain to the search domains - * - * @returns the action's domain - */ - domains: function () { - if (!this.action.domain) { - return []; - } - return [this.action.domain]; - }, - /** - * adds action context to the search contexts - * - * @returns the action's context - */ - contexts: function () { - if (!this.action.context) { - return []; - } - return [this.action.context]; } }); @@ -475,11 +400,10 @@ openerp.base.View = openerp.base.Widget.extend({ * @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 {openerp.base.DataSet} dataset a dataset object used to communicate with the server - * @param {openerp.base.ActionManager} action_manager object able to actually execute the action, if any is fetched * @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) */ - execute_action: function (action_data, dataset, action_manager, record_id, on_closed) { + execute_action: function (action_data, dataset, record_id, on_closed) { var self = this; var handler = function (r) { var action = r.result; @@ -497,8 +421,9 @@ openerp.base.View = openerp.base.Widget.extend({ }; var context = new openerp.base.CompoundContext(dataset.get_context(), action_data.context || {}); + if (action_data.special) { - // dunno + handler({result: {"type":"ir.actions.act_window_close"}}); } else if (action_data.type=="object") { return dataset.call_button(action_data.name, [[record_id], context], handler); } else if (action_data.type=="action") { @@ -563,16 +488,16 @@ openerp.base.View = openerp.base.Widget.extend({ } }, on_sidebar_edit_workflow: function() { - console.log('Todo'); + this.log('Todo'); }, on_sidebar_customize_object: function() { - console.log('Todo'); + this.log('Todo'); }, on_sidebar_import: function() { }, on_sidebar_export: function() { var export_view = new openerp.base.DataExport(this, this.dataset); - export_view.start(false); + export_view.start(); }, on_sidebar_translate: function() { }, @@ -580,6 +505,11 @@ openerp.base.View = openerp.base.Widget.extend({ } }); +/** + * Registry for all the main views + */ +openerp.base.views = new openerp.base.Registry(); + openerp.base.json_node_to_xml = function(node, single_quote, indent) { // For debugging purpose, this function will convert a json node back to xml // Maybe usefull for xml view editor diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 79fe7336ec8..4e581e8c175 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -78,7 +78,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -138,7 +138,7 @@ - + @@ -170,7 +170,7 @@ - + @@ -195,7 +195,7 @@ autofocus="autofocus"/> - + @@ -213,23 +213,23 @@
- CHANGE DATABASE PASSWORD + CHANGE MASTER PASSWORD
- + - + - + @@ -547,14 +547,9 @@
- - - - - - + - @@ -968,22 +963,6 @@ - - -
- - to - - -
-