[MERGE] core api improvements: remove callbackenabled, widgetmixin
bzr revid: al@openerp.com-20121110195411-01ffp20dmaikot71
This commit is contained in:
commit
cd4b9409f8
|
@ -189,7 +189,7 @@ instance.web.Dialog = instance.web.Widget.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.web.CrashManager = instance.web.CallbackEnabled.extend({
|
instance.web.CrashManager = instance.web.Class.extend({
|
||||||
rpc_error: function(error) {
|
rpc_error: function(error) {
|
||||||
if (error.data.fault_code) {
|
if (error.data.fault_code) {
|
||||||
var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
|
var split = ("" + error.data.fault_code).split('\n')[0].split(' -- ');
|
||||||
|
|
|
@ -243,15 +243,17 @@ instance.web.ParentedMixin = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backbone's events. Do not ever use it directly, use EventDispatcherMixin instead.
|
* Backbone's events. Do not ever use it directly, use EventDispatcherMixin instead.
|
||||||
|
*
|
||||||
|
* This class just handle the dispatching of events, it is not meant to be extended,
|
||||||
|
* nor used directly. All integration with parenting and automatic unregistration of
|
||||||
|
* events is done in EventDispatcherMixin.
|
||||||
|
*
|
||||||
|
* Copyright notice for the following Class:
|
||||||
*
|
*
|
||||||
* (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
* (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||||
* Backbone may be freely distributed under the MIT license.
|
* Backbone may be freely distributed under the MIT license.
|
||||||
* For all details and documentation:
|
* For all details and documentation:
|
||||||
* http://backbonejs.org
|
* http://backbonejs.org
|
||||||
*
|
|
||||||
* This class just handle the dispatching of events, it is not meant to be extended,
|
|
||||||
* nor used directly. All integration with parenting and automatic unregistration of
|
|
||||||
* events is done in EventDispatcherMixin.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
var Events = instance.web.Class.extend({
|
var Events = instance.web.Class.extend({
|
||||||
|
@ -334,7 +336,6 @@ var Events = instance.web.Class.extend({
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// end of Jeremy Ashkenas' code
|
|
||||||
|
|
||||||
instance.web.EventDispatcherMixin = _.extend({}, instance.web.ParentedMixin, {
|
instance.web.EventDispatcherMixin = _.extend({}, instance.web.ParentedMixin, {
|
||||||
__eventDispatcherMixin: true,
|
__eventDispatcherMixin: true,
|
||||||
|
@ -426,66 +427,94 @@ instance.web.PropertiesMixin = _.extend({}, instance.web.EventDispatcherMixin, {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.web.CallbackEnabledMixin = _.extend({}, instance.web.PropertiesMixin, {
|
// Classes
|
||||||
init: function() {
|
|
||||||
instance.web.PropertiesMixin.init.call(this);
|
|
||||||
var self = this;
|
|
||||||
// Transform on_/do_* methods into callbacks
|
|
||||||
var callback_maker = function(fn) {
|
|
||||||
return function() {
|
|
||||||
return fn.apply(self, arguments);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for (var name in this) {
|
|
||||||
if(typeof(this[name]) == "function") {
|
|
||||||
if((/^on_|^do_/).test(name)) {
|
|
||||||
this[name] = callback_maker(this[name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 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|Function} method function or name of the method to invoke
|
|
||||||
* @returns {Function} proxied method
|
|
||||||
*/
|
|
||||||
proxy: function (method) {
|
|
||||||
var self = this;
|
|
||||||
return function () {
|
|
||||||
var fn = (typeof method === 'string') ? self[method] : method;
|
|
||||||
return fn.apply(self, arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, {
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Guide to create implementations of the Widget class:
|
||||||
|
* ==============================================
|
||||||
|
*
|
||||||
|
* Here is a sample child class:
|
||||||
|
*
|
||||||
|
* MyWidget = instance.base.Widget.extend({
|
||||||
|
* // the name of the QWeb template to use for rendering
|
||||||
|
* template: "MyQWebTemplate",
|
||||||
|
*
|
||||||
|
* init: function(parent) {
|
||||||
|
* this._super(parent);
|
||||||
|
* // stuff that you want to init before the rendering
|
||||||
|
* },
|
||||||
|
* start: function() {
|
||||||
|
* // stuff you want to make after the rendering, `this.$el` holds a correct value
|
||||||
|
* this.$el.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.destroy();
|
||||||
|
*
|
||||||
|
* That will kill the widget in a clean way and erase its content from the dom.
|
||||||
|
*/
|
||||||
|
instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, {
|
||||||
|
// Backbone-ish API
|
||||||
|
tagName: 'div',
|
||||||
|
id: null,
|
||||||
|
className: null,
|
||||||
|
attributes: {},
|
||||||
|
events: {},
|
||||||
|
/**
|
||||||
|
* The name of the QWeb template that will be used for rendering. Must be
|
||||||
|
* redefined in subclasses or the default render() method can not be used.
|
||||||
|
*
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
template: null,
|
||||||
/**
|
/**
|
||||||
* Constructs the widget and sets its parent if a parent is given.
|
* Constructs the widget and sets its parent if a parent is given.
|
||||||
*
|
*
|
||||||
* @constructs instance.web.Widget
|
* @constructs instance.web.Widget
|
||||||
* @extends instance.web.CallbackEnabled
|
|
||||||
*
|
*
|
||||||
* @param {instance.web.Widget} parent Binds the current instance to the given Widget instance.
|
* @param {instance.web.Widget} parent Binds the current instance to the given Widget instance.
|
||||||
* When that widget is destroyed by calling destroy(), the current instance will be
|
* When that widget is destroyed by calling destroy(), the current instance will be
|
||||||
* destroyed too. Can be null.
|
* destroyed too. Can be null.
|
||||||
*/
|
*/
|
||||||
init: function(parent) {
|
init: function(parent) {
|
||||||
instance.web.CallbackEnabledMixin.init.call(this);
|
instance.web.PropertiesMixin.init.call(this);
|
||||||
this.setParent(parent);
|
this.setParent(parent);
|
||||||
|
// Bind on_/do_* methods to this
|
||||||
|
// We might remove this automatic binding in the future
|
||||||
|
for (var name in this) {
|
||||||
|
if(typeof(this[name]) == "function") {
|
||||||
|
if((/^on_|^do_/).test(name)) {
|
||||||
|
this[name] = this[name].bind(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: this should not be
|
||||||
|
this.setElement(this._make_descriptive());
|
||||||
|
this.session = instance.session;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Destroys the current widget, also destroys all its children before destroying itself.
|
* Destroys the current widget, also destroys all its children before destroying itself.
|
||||||
|
@ -574,94 +603,32 @@ instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, {
|
||||||
*/
|
*/
|
||||||
start: function() {
|
start: function() {
|
||||||
return $.when();
|
return $.when();
|
||||||
}
|
},
|
||||||
});
|
|
||||||
|
|
||||||
// Classes
|
|
||||||
|
|
||||||
instance.web.CallbackEnabled = instance.web.Class.extend(instance.web.CallbackEnabledMixin, {
|
|
||||||
init: function() {
|
|
||||||
instance.web.CallbackEnabledMixin.init.call(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Guide to create implementations of the Widget class:
|
|
||||||
* ==============================================
|
|
||||||
*
|
|
||||||
* Here is a sample child class:
|
|
||||||
*
|
|
||||||
* MyWidget = instance.base.Widget.extend({
|
|
||||||
* // the name of the QWeb template to use for rendering
|
|
||||||
* template: "MyQWebTemplate",
|
|
||||||
*
|
|
||||||
* init: function(parent) {
|
|
||||||
* this._super(parent);
|
|
||||||
* // stuff that you want to init before the rendering
|
|
||||||
* },
|
|
||||||
* start: function() {
|
|
||||||
* // stuff you want to make after the rendering, `this.$el` holds a correct value
|
|
||||||
* this.$el.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.destroy();
|
|
||||||
*
|
|
||||||
* That will kill the widget in a clean way and erase its content from the dom.
|
|
||||||
*/
|
|
||||||
instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
|
|
||||||
// Backbone-ish API
|
|
||||||
tagName: 'div',
|
|
||||||
id: null,
|
|
||||||
className: null,
|
|
||||||
attributes: {},
|
|
||||||
events: {},
|
|
||||||
/**
|
/**
|
||||||
* The name of the QWeb template that will be used for rendering. Must be
|
* Proxies a method of the object, in order to keep the right ``this`` on
|
||||||
* redefined in subclasses or the default render() method can not be used.
|
* method invocations.
|
||||||
*
|
*
|
||||||
* @type string
|
* 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|Function} method function or name of the method to invoke
|
||||||
|
* @returns {Function} proxied method
|
||||||
*/
|
*/
|
||||||
template: null,
|
proxy: function (method) {
|
||||||
/**
|
var self = this;
|
||||||
* Constructs the widget and sets its parent if a parent is given.
|
return function () {
|
||||||
*
|
var fn = (typeof method === 'string') ? self[method] : method;
|
||||||
* @constructs instance.web.Widget
|
return fn.apply(self, arguments);
|
||||||
* @extends instance.web.CallbackEnabled
|
}
|
||||||
*
|
|
||||||
* @param {instance.web.Widget} parent Binds the current instance to the given Widget instance.
|
|
||||||
* When that widget is destroyed by calling destroy(), the current instance will be
|
|
||||||
* destroyed too. Can be null.
|
|
||||||
*/
|
|
||||||
init: function(parent) {
|
|
||||||
instance.web.WidgetMixin.init.call(this,parent);
|
|
||||||
// FIXME: this should not be
|
|
||||||
this.setElement(this._make_descriptive());
|
|
||||||
this.session = instance.session;
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Renders the element. The default implementation renders the widget using QWeb,
|
* Renders the element. The default implementation renders the widget using QWeb,
|
||||||
|
@ -678,7 +645,6 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, {
|
||||||
}
|
}
|
||||||
this.replaceElement($el);
|
this.replaceElement($el);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-sets the widget's root element and replaces the old root element
|
* Re-sets the widget's root element and replaces the old root element
|
||||||
* (if any) by the new one in the DOM.
|
* (if any) by the new one in the DOM.
|
||||||
|
@ -941,7 +907,7 @@ instance.web.Registry = instance.web.Class.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
|
instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
|
||||||
triggers: {
|
triggers: {
|
||||||
'request': 'Request sent',
|
'request': 'Request sent',
|
||||||
'response': 'Response received',
|
'response': 'Response received',
|
||||||
|
@ -950,13 +916,12 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @constructs instance.web.JsonRPC
|
* @constructs instance.web.JsonRPC
|
||||||
* @extends instance.web.CallbackEnabled
|
|
||||||
*
|
*
|
||||||
* @param {String} [server] JSON-RPC endpoint hostname
|
* @param {String} [server] JSON-RPC endpoint hostname
|
||||||
* @param {String} [port] JSON-RPC endpoint port
|
* @param {String} [port] JSON-RPC endpoint port
|
||||||
*/
|
*/
|
||||||
init: function() {
|
init: function() {
|
||||||
this._super();
|
instance.web.PropertiesMixin.init.call(this);
|
||||||
this.server = null;
|
this.server = null;
|
||||||
this.debug = ($.deparam($.param.querystring()).debug != undefined);
|
this.debug = ($.deparam($.param.querystring()).debug != undefined);
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,7 +53,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
||||||
this.session_id = this.get_cookie('session_id');
|
this.session_id = this.get_cookie('session_id');
|
||||||
return this.session_reload().then(function(result) {
|
return this.session_reload().then(function(result) {
|
||||||
var modules = instance._modules.join(',');
|
var modules = instance._modules.join(',');
|
||||||
var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).then(self.do_load_qweb);
|
var deferred = self.rpc('/web/webclient/qweblist', {mods: modules}).then(self.load_qweb.bind(self));
|
||||||
if(self.session_is_valid()) {
|
if(self.session_is_valid()) {
|
||||||
return deferred.then(function() { return self.load_modules(); });
|
return deferred.then(function() { return self.load_modules(); });
|
||||||
}
|
}
|
||||||
|
@ -168,15 +168,15 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
||||||
if(to_load.length) {
|
if(to_load.length) {
|
||||||
loaded = $.when(
|
loaded = $.when(
|
||||||
loaded,
|
loaded,
|
||||||
self.rpc('/web/webclient/csslist', {mods: to_load}).done(self.do_load_css),
|
self.rpc('/web/webclient/csslist', {mods: to_load}).done(self.load_css.bind(self)),
|
||||||
self.rpc('/web/webclient/qweblist', {mods: to_load}).then(self.do_load_qweb),
|
self.rpc('/web/webclient/qweblist', {mods: to_load}).then(self.load_qweb.bind(self)),
|
||||||
self.rpc('/web/webclient/jslist', {mods: to_load}).done(function(files) {
|
self.rpc('/web/webclient/jslist', {mods: to_load}).done(function(files) {
|
||||||
file_list = file_list.concat(files);
|
file_list = file_list.concat(files);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return loaded.then(function () {
|
return loaded.then(function () {
|
||||||
return self.do_load_js(file_list);
|
return self.load_js(file_list);
|
||||||
}).done(function() {
|
}).done(function() {
|
||||||
self.on_modules_loaded();
|
self.on_modules_loaded();
|
||||||
self.trigger('module_loaded');
|
self.trigger('module_loaded');
|
||||||
|
@ -190,7 +190,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
do_load_css: function (files) {
|
load_css: function (files) {
|
||||||
var self = this;
|
var self = this;
|
||||||
_.each(files, function (file) {
|
_.each(files, function (file) {
|
||||||
$('head').append($('<link>', {
|
$('head').append($('<link>', {
|
||||||
|
@ -200,7 +200,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
do_load_js: function(files) {
|
load_js: function(files) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var d = $.Deferred();
|
var d = $.Deferred();
|
||||||
if(files.length != 0) {
|
if(files.length != 0) {
|
||||||
|
@ -212,7 +212,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
||||||
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
|
if ( (tag.readyState && tag.readyState != "loaded" && tag.readyState != "complete") || tag.onload_done )
|
||||||
return;
|
return;
|
||||||
tag.onload_done = true;
|
tag.onload_done = true;
|
||||||
self.do_load_js(files).done(function () {
|
self.load_js(files).done(function () {
|
||||||
d.resolve();
|
d.resolve();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -223,7 +223,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
},
|
},
|
||||||
do_load_qweb: function(files) {
|
load_qweb: function(files) {
|
||||||
var self = this;
|
var self = this;
|
||||||
_.each(files, function(file) {
|
_.each(files, function(file) {
|
||||||
self.qweb_mutex.exec(function() {
|
self.qweb_mutex.exec(function() {
|
||||||
|
|
|
@ -358,17 +358,15 @@ instance.web.Model = instance.web.Class.extend({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
instance.web.DataSet = instance.web.CallbackEnabled.extend({
|
instance.web.DataSet = instance.web.Class.extend({
|
||||||
/**
|
/**
|
||||||
* Collection of OpenERP records, used to share records and the current selection between views.
|
* Collection of OpenERP records, used to share records and the current selection between views.
|
||||||
*
|
*
|
||||||
* @constructs instance.web.DataSet
|
* @constructs instance.web.DataSet
|
||||||
* @extends instance.web.CallbackEnabled
|
|
||||||
*
|
*
|
||||||
* @param {String} model the OpenERP model this dataset will manage
|
* @param {String} model the OpenERP model this dataset will manage
|
||||||
*/
|
*/
|
||||||
init: function(parent, model, context) {
|
init: function(parent, model, context) {
|
||||||
this._super(parent);
|
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.context = context || {};
|
this.context = context || {};
|
||||||
this.index = null;
|
this.index = null;
|
||||||
|
|
|
@ -1557,9 +1557,8 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var DataGroup = instance.web.CallbackEnabled.extend({
|
var DataGroup = instance.web.Class.extend({
|
||||||
init: function(parent, model, domain, context, group_by, level) {
|
init: function(parent, model, domain, context, group_by, level) {
|
||||||
this._super(parent, null);
|
|
||||||
this.model = new instance.web.Model(model, context, domain);
|
this.model = new instance.web.Model(model, context, domain);
|
||||||
this.group_by = group_by;
|
this.group_by = group_by;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
Loading…
Reference in New Issue