diff options
| author | Xavier Morel <xmo@openerp.com> | 2011-08-16 16:25:15 +0200 |
|---|---|---|
| committer | Xavier Morel <xmo@openerp.com> | 2011-08-16 16:25:15 +0200 |
| commit | ffae7cb4b3e7350d19b273feb100ba73cd022214 (patch) | |
| tree | 15a06c6746e4d6f9d7042a269362ed72728eeceb /addons/base/static/src/js/core.js | |
| parent | d33c95fc4568516c22e12fdcce901d8250c9d218 (diff) | |
| parent | 36a1a0f1c3f6fe471453d52955f97110220599a3 (diff) | |
[MERGE] from trunk
bzr revid: xmo@openerp.com-20110816142515-ohq33zvua5uq8cd3
Diffstat (limited to 'addons/base/static/src/js/core.js')
| -rw-r--r-- | addons/base/static/src/js/core.js | 432 |
1 files changed, 368 insertions, 64 deletions
diff --git a/addons/base/static/src/js/core.js b/addons/base/static/src/js/core.js index 80dba3cd10c..96c6cb1372a 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) { @@ -305,16 +305,8 @@ openerp.base.Registry = openerp.base.Class.extend( /** @lends openerp.base.Regis } }); -/** - * Utility class that any class is allowed to extend to easy common manipulations. - * - * It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a - * logging facility. - */ -openerp.base.SessionAware = openerp.base.Class.extend({ - init: function(session) { - this.session = session; - +openerp.base.CallbackEnabled = openerp.base.Class.extend({ + init: function() { // Transform on_* method into openerp.base.callbacks for (var name in this) { if(typeof(this[name]) == "function") { @@ -325,6 +317,19 @@ openerp.base.SessionAware = openerp.base.Class.extend({ } } } + } +}); + +/** + * Utility class that any class is allowed to extend to easy common manipulations. + * + * It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a + * logging facility. + */ +openerp.base.SessionAware = openerp.base.CallbackEnabled.extend({ + init: function(session) { + this._super(); + this.session = session; }, /** * Performs a JSON-RPC call @@ -373,59 +378,6 @@ openerp.base.SessionAware = openerp.base.Class.extend({ } }); -/** - * Base class for all visual components. Provides a lot of functionalities helpful - * for the management of a part of the DOM. - * - * Widget handles: - * - Rendering with QWeb. - * - Life-cycle management and parenting (when a parent is destroyed, all its children are - * destroyed too). - * - Insertion in DOM. - * - * Widget also extends SessionAware for ease of use. - * - * Guide to create implementations of the Widget class: - * ============================================== - * - * Here is a sample child class: - * - * MyWidget = openerp.base.Widget.extend({ - * // the name of the QWeb template to use for rendering - * template: "MyQWebTemplate", - * // identifier prefix, it is useful to put an obvious one for debugging - * identifier_prefix: 'my-id-prefix-', - * - * init: function(parent) { - * this._super(parent); - * // stuff that you want to init before the rendering - * }, - * start: function() { - * this._super(); - * // stuff you want to make after the rendering, `this.$element` holds a correct value - * this.$element.find(".my_button").click(/* an example of event binding * /); - * - * // if you have some asynchronous operations, it's a good idea to return - * // a promise in start() - * var promise = this.rpc(...); - * return promise; - * } - * }); - * - * Now this class can simply be used with the following syntax: - * - * var my_widget = new MyWidget(this); - * my_widget.appendTo($(".some-div")); - * - * With these two lines, the MyWidget instance was inited, rendered, it was inserted into the - * DOM inside the ".some-div" div and its events were binded. - * - * And of course, when you don't need that widget anymore, just do: - * - * my_widget.stop(); - * - * That will kill the widget in a clean way and erase its content from the dom. - */ openerp.base.Widget = openerp.base.SessionAware.extend({ /** * The name of the QWeb template that will be used for rendering. Must be @@ -574,6 +526,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 +563,345 @@ openerp.base.OldWidget = openerp.base.Widget.extend({ } }); +openerp.base.TranslationDataBase = openerp.base.Class.extend({ + init: function() { + this.db = {}; + this.parameters = {"direction": 'ltr', + "date_format": '%m/%d/%Y', + "time_format": '%H:%M:%S', + "grouping": "[]", + "decimal_point": ".", + "thousands_sep": ","}; + }, + set_bundle: function(translation_bundle) { + var self = this; + this.db = {}; + var modules = _.keys(translation_bundle.modules).sort(); + if (_.include(modules, "base")) { + modules = ["base"].concat(_.without(modules, "base")); + } + _.each(modules, function(name) { + self.add_module_translation(translation_bundle.modules[name]); + }); + if (translation_bundle.lang_parameters) { + this.parameters = translation_bundle.lang_parameters; + } + }, + add_module_translation: function(mod) { + var self = this; + _.each(mod.messages, function(message) { + if (self.db[message.id] === undefined) { + self.db[message.id] = message.string; + } + }); + }, + build_translation_function: function() { + var self = this; + var fcnt = function(str) { + var tmp = self.get(str); + return tmp === undefined ? str : tmp; + } + fcnt.database = this; + return fcnt; + }, + get: function(key) { + if (this.db[key]) + return this.db[key]; + return undefined; + } +}); + +openerp.base._t = new openerp.base.TranslationDataBase().build_translation_function(); + +openerp.base.Session = openerp.base.CallbackEnabled.extend( /** @lends openerp.base.Session# */{ + /** + * @constructs + * @param element_id to use for exception reporting + * @param server + * @param port + */ + init: function(server, port) { + this._super(); + 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.user_context= {}; + this.uid = false; + this.session_id = false; + this.module_list = []; + this.module_loaded = {"base": true}; + this.context = {}; + this.shortcuts = []; + this.active_id = null; + }, + 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.user_context = result.context; + 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'); + this.user_context = this.get_cookie("user_context"); + // 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); + this.set_cookie('user_context', this.user_context); + }, + 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<cookies.length; ++i) { + var cookie = cookies[i].replace(/^\s*/, ''); + if(cookie.indexOf(nameEQ) === 0) { + return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length))); + } + } + return null; + }, + /** + * Create a new cookie with the provided name and value + * + * @private + * @param name the cookie's name + * @param value the cookie's value + * @param ttl the cookie's time to live, 1 year by default, set to -1 to delete + */ + set_cookie: function (name, value, ttl) { + ttl = ttl || 24*60*60*365; + document.cookie = [ + this.element_id + '|' + name + '=' + encodeURIComponent(JSON.stringify(value)), + 'max-age=' + ttl, + 'expires=' + new Date(new Date().getTime() + ttl*1000).toGMTString() + ].join(';'); + }, + /** + * Load additional web addons of that instance and init them + */ + load_modules: function() { + var self = this; + this.rpc('/base/session/modules', {}, function(result) { + self.module_list = result; + var lang = self.user_context.lang; + self.rpc('/base/webclient/translations',{ + mods: ["base"].concat(result), + lang: lang}) + .then(function(transs) { + openerp.base._t.database.set_bundle(transs); + var modules = self.module_list.join(','); + if(self.debug || true) { + self.rpc('/base/webclient/csslist', {"mods": modules}, self.do_load_css); + self.rpc('/base/webclient/jslist', {"mods": modules}, self.do_load_js); + } else { + self.do_load_css(["/base/webclient/css?mods="+modules]); + self.do_load_js(["/base/webclient/js?mods="+modules]); + } + openerp._modules_loaded = true; + }); + }); + }, + do_load_css: function (files) { + _.each(files, function (file) { + $('head').append($('<link>', { + 'href': file, + 'rel': 'stylesheet', + 'type': 'text/css' + })); + }); + }, + do_load_js: function(files) { + var self = this; + if(files.length != 0) { + var file = files.shift(); + var tag = document.createElement('script'); + tag.type = 'text/javascript'; + tag.src = file; + tag.onload = tag.onreadystatechange = function() { + if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done ) + return; + tag.onload_done = true; + self.do_load_js(files); + }; + document.head.appendChild(tag); + } else { + this.on_modules_loaded(); + } + }, + on_modules_loaded: function() { + for(var j=0; j<this.module_list.length; j++) { + var mod = this.module_list[j]; + if(this.module_loaded[mod]) + continue; + openerp[mod] = {}; + // init module mod + if(openerp._openerp[mod] != undefined) { + openerp._openerp[mod](openerp); + this.module_loaded[mod] = true; + } + } + } +}); + }; + // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: |
