position: "last"
});
};
+ callback.remove = function(f) {
+ callback.callback_chain = _.difference(callback.callback_chain, _.filter(callback.callback_chain, function(el) {
+ return el.callback === f;
+ }));
+ return callback;
+ };
return callback.add({
callback: method,
}
}
}
+ },
+ /**
+ * Proxies a method of the object, in order to keep the right ``this`` on
+ * method invocations.
+ *
+ * This method is similar to ``Function.prototype.bind`` or ``_.bind``, and
+ * even more so to ``jQuery.proxy`` with a fundamental difference: its
+ * resolution of the method being called is lazy, meaning it will use the
+ * method as it is when the proxy is called, not when the proxy is created.
+ *
+ * Other methods will fix the bound method to what it is when creating the
+ * binding/proxy, which is fine in most javascript code but problematic in
+ * OpenERP Web where developers may want to replace existing callbacks with
+ * theirs.
+ *
+ * The semantics of this precisely replace closing over the method call.
+ *
+ * @param {String} method_name name of the method to invoke
+ * @returns {Function} proxied method
+ */
+ proxy: function (method_name) {
+ var self = this;
+ return function () {
+ return self[method_name].apply(self, arguments);
+ }
}
});
this.debug = ($.deparam($.param.querystring()).debug != undefined);
// TODO: session store in cookie should be optional
this.name = openerp._session_id;
+ this.qweb_mutex = new $.Mutex();
},
bind: function(origin) {
var window_origin = location.protocol+"//"+location.host;
this.username = false;
this.user_context= {};
this.db = false;
+ this.openerp_entreprise = false;
this.module_list = [];
this.module_loaded = {"web": true};
this.context = {};
this.shortcuts = [];
this.active_id = null;
- this.ready = $.Deferred();
return this.session_init();
},
/**
data: JSON.stringify(payload),
processData: false,
}, url);
+ if (this.synch)
+ ajax.async = false;
return $.ajax(ajax);
},
rpc_jsonp: function(url, payload) {
cache: false,
data: data
}, url);
+ if (this.synch)
+ ajax.async = false;
var payload_str = JSON.stringify(payload);
var payload_url = $.param({r:payload_str});
- if(playload_url.length < 2000) {
+ if(payload_url.length < 2000) {
// Direct jsonp request
ajax.data.r = payload_str;
return $.ajax(ajax);
var self = this;
// TODO: session store in cookie should be optional
this.session_id = this.get_cookie('session_id');
- return this.rpc("/web/session/get_session_info", {}).pipe(function(result) {
+ return this.session_reload().pipe(function(result) {
+ var modules = openerp._modules.join(',');
+ var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb);
+ if(self.session_is_valid()) {
+ return deferred.pipe(function() { return self.load_modules(); });
+ }
+ return deferred;
+ });
+ },
+ /**
+ * (re)loads the content of a session: db name, username, user id, session
+ * context and status of the support contract
+ *
+ * @returns {$.Deferred} deferred indicating the session is done reloading
+ */
+ session_reload: function () {
+ var self = this;
+ return this.rpc("/web/session/get_session_info", {}).then(function(result) {
// If immediately follows a login (triggered by trying to restore
// an invalid session or no session at all), refresh session data
// (should not change, but just in case...)
db: result.db,
username: result.login,
uid: result.uid,
- user_context: result.context
+ user_context: result.context,
+ openerp_entreprise: result.openerp_entreprise
});
- var deferred = self.do_load_qweb(['/web/webclient/qweb']);
- if(self.uid) {
- return deferred.then(self.load_modules());
- }
- return deferred;
});
},
session_is_valid: function() {
/**
* The session is validated either by login or by restoration of a previous session
*/
- session_authenticate: function(db, login, password) {
+ session_authenticate: function(db, login, password, _volatile) {
var self = this;
var base_location = document.location.protocol + '//' + document.location.host;
var params = { db: db, login: login, password: password, base_location: base_location };
db: result.db,
username: result.login,
uid: result.uid,
- user_context: result.context
+ user_context: result.context,
+ openerp_entreprise: result.openerp_entreprise
});
- // TODO: session store in cookie should be optional
- self.set_cookie('session_id', self.session_id);
+ if (!_volatile) {
+ self.set_cookie('session_id', self.session_id);
+ }
return self.load_modules();
});
},
session_logout: function() {
this.set_cookie('session_id', '');
- window.location.reload();
+ },
+ on_session_valid: function() {
},
/**
* Called when a rpc call fail due to an invalid session.
*/
load_modules: function() {
var self = this;
- if(openerp._modules_loaded) {
- return $.when();
- }
- this.rpc('/web/session/modules', {}, function(result) {
+ return this.rpc('/web/session/modules', {}).pipe(function(result) {
self.module_list = result;
var lang = self.user_context.lang;
var params = { mods: ["web"].concat(result), lang: lang};
- self.rpc('/web/webclient/translations',params).pipe(function(transs) {
- openerp.web._t.database.set_bundle(transs);
- var modules = self.module_list.join(',');
- var file_list = ["/web/static/lib/datejs/globalization/" +
- self.user_context.lang.replace("_", "-") + ".js"
- ];
- return $.when(
- self.rpc('/web/webclient/csslist', {mods: modules}, self.do_load_css),
- self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb),
- self.rpc('/web/webclient/jslist', {mods: modules}).pipe(function(files) {
+ var modules = self.module_list.join(',');
+ return $.when(
+ self.rpc('/web/webclient/csslist', {mods: modules}, self.do_load_css),
+ self.rpc('/web/webclient/qweblist', {mods: modules}).pipe(self.do_load_qweb),
+ self.rpc('/web/webclient/translations', params).pipe(function(trans) {
+ openerp.web._t.database.set_bundle(trans);
+ var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"];
+ return self.rpc('/web/webclient/jslist', {mods: modules}).pipe(function(files) {
return self.do_load_js(file_list.concat(files));
- })
- ).then(function() {
- self.ready.resolve();
- });
+ });
+ })
+ ).then(function() {
+ self.on_modules_loaded();
+ self.on_session_valid();
});
});
},
var head = document.head || document.getElementsByTagName('head')[0];
head.appendChild(tag);
} else {
- self.on_modules_loaded();
d.resolve();
}
return d;
},
do_load_qweb: function(files) {
var self = this;
- if (files.length != 0) {
- var file = files.shift();
- return self.rpc('/web/proxy/load', {path: file}).pipe(function(xml) {
- openerp.web.qweb.add_template(_.str.trim(xml));
- return self.do_load_qweb(files);
+ _.each(files, function(file) {
+ self.qweb_mutex.exec(function() {
+ return self.rpc('/web/proxy/load', {path: file}).pipe(function(xml) {
+ openerp.web.qweb.add_template(_.str.trim(xml));
+ });
});
- } else {
- return $.when();
- }
+ });
+ return self.qweb_mutex.def;
},
on_modules_loaded: function() {
for(var j=0; j<this.module_list.length; j++) {
}
};
timer = setTimeout(waitLoop, CHECK_INTERVAL);
- }
+ },
+ synchronized_mode: function(to_execute) {
+ var synch = this.synch;
+ this.synch = true;
+ try {
+ return to_execute();
+ } finally {
+ this.synch = synch;
+ }
+ },
});
/**
return tr === ts ? s : tr;
}
-/** Setup default connection */
-openerp.connection = new openerp.web.Connection();
-openerp.web.qweb.default_dict['__debug__'] = openerp.connection.debug;
-
/** Jquery extentions */
$.Mutex = (function() {
function Mutex() {
return Mutex;
})();
+/** Setup default connection */
+openerp.connection = new openerp.web.Connection();
+openerp.web.qweb.default_dict['__debug__'] = openerp.connection.debug;
+
+
$.async_when = function() {
var async = false;
var def = $.Deferred();
return def;
};
+// special tweak for the web client
+var old_async_when = $.async_when;
+$.async_when = function() {
+ if (openerp.connection.synch)
+ return $.when.apply(this, arguments);
+ else
+ return old_async_when.apply(this, arguments);
+};
+
};
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: