diff --git a/addons/base/static/src/js/controller.js b/addons/base/static/src/js/controller.js index 1a13ab18607..a9bf99f8764 100644 --- a/addons/base/static/src/js/controller.js +++ b/addons/base/static/src/js/controller.js @@ -148,44 +148,118 @@ instance.base.generate_null_object_class = function(claz, add) { // -------------------------------------------------------- // OLD // -------------------------------------------------------- - /** - * OpenERP Controller - * TODO merge BaseWidget with Controller + * Class for OpenERP session aware classes to extend. Also provides callback mechanism and logging + * facility. */ -instance.base.Controller = instance.base.Class.extend( /** @lends instance.base.Controller# */{ +instance.base.SessionAware = instance.base.Class.extend({ + init: function(session) { + this.session = session; + + // Transform on_* method into openerp.base.callbacks + for (var name in this) { + if(typeof(this[name]) == "function") { + this[name].debug_name = name; + // bind ALL function to this not only on_and _do ? + if((/^on_|^do_/).test(name)) { + this[name] = instance.base.callback(this, this[name]); + } + } + } + }, + /** + * Performs a JSON-RPC call + * + * @param {String} url endpoint url + * @param {Object} data RPC parameters + * @param {Function} success RPC call success callback + * @param {Function} error RPC call error callback + * @returns {jQuery.Deferred} deferred object for the RPC call + */ + rpc: function(url, data, success, error) { + return this.session.rpc(url, data, success, error); + }, + log: function() { + var args = Array.prototype.slice.call(arguments); + var caller = arguments.callee.caller; + // TODO add support for line number using + // https://github.com/emwendelin/javascript-stacktrace/blob/master/stacktrace.js + // args.unshift("" + caller.debug_name); + this.on_log.apply(this,args); + }, + on_log: function() { + if(window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) { + var notify = false; + var body = false; + if(window.console) { + console.log(arguments); + } else { + body = true; + } + var a = Array.prototype.slice.call(arguments, 0); + for(var i = 0; i < a.length; i++) { + var v = a[i]==null ? "null" : a[i].toString(); + if(i==0) { + notify = v.match(/^not/); + body = v.match(/^bod/); + } + if(body) { + $('
').text(v).appendTo($('body'));
+                }
+                if(notify && this.notification) {
+                    this.notification.notify("Logging:",v);
+                }
+            }
+        }
+    }
+});
+
+instance.base.Controller = instance.base.SessionAware.extend({
+    /**
+     * 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,
+    /**
+     * The prefix used to generate an id automatically. Should be redefined in
+     * subclasses. If it is not defined, a generic identifier will be used.
+     * 
+     * @type string
+     */
+    identifier_prefix: 'generic-identifier',
     /**
      * @constructs
      * rpc operations, event binding and callback calling should be done in
      * start() instead of init so that events can be hooked in between.
      */
     init: function(parent, element_id) {
+        this._super((parent || {}).session);
+        //TODO niv: get away the possibility to specify an id
         this.element_id = element_id;
+        this.element_id = this.element_id || _.uniqueId(this.identifier_prefix);
+        
         this.$element = $('#' + element_id);
         if (element_id) {
             instance.screen[element_id] = this;
         }
         // save the parent children relationship
-        this.controller_parent = parent;
-        this.controller_children = [];
-        if(parent && parent.controller_children) {
-            parent.controller_children.push(this);
-        }
-        // backward compatibility
-        this.parent = this.controller_parent;
-        this.children = this.controller_children;
-
-        // Transform on_* method into openerp.base.callbacks
-        for (var name in this) {
-            if(typeof(this[name]) == "function") {
-                this[name].debug_name = name;
-                // bind ALL function to this not only on_and _do ?
-                if((/^on_|^do_/).test(name)) {
-                    this[name] = instance.base.callback(this, this[name]);
-                }
-            }
+        this.widget_parent = parent;
+        this.widget_children = [];
+        if(parent && parent.widget_children) {
+            parent.widget_children.push(this);
         }
     },
+    /**
+     * Render the widget. This.template must be defined.
+     * The content of the current object is passed as context to the template.
+     * 
+     * @param {object} additional Additional context arguments to pass to the template.
+     */
+    render: function (additional) {
+        return QWeb.render(this.template, _.extend({widget: this}, additional || {}));
+    },
     /**
      * Event binding, rpc and callback calling required to initialize the
      * object should happen here
@@ -196,354 +270,36 @@ instance.base.Controller = instance.base.Class.extend( /** @lends instance.base.
      * @returns {jQuery.Deferred}
      */
     start: function() {
-        // returns an already fulfilled promise. Maybe we could return nothing?
-        // $.when can take non-deferred and in that case it simply considers
-        // them all as fulfilled promises.
-        // But in thise case we *have* to ensure callers use $.when and don't
-        // try to call deferred methods on this return value.
+        var tmp = document.getElementById(this.element_id);
+        this.$element = tmp ? $(tmp) : null;
         return $.Deferred().done().promise();
     },
     stop: function() {
-        if (this.parent && this.parent.children) {
-            this.parent.children = _.without(this.parent.children, this);
-            this.parent.controller_children = this.parent.children;
+        _.each(_.clone(this.widget_children), function(el) {
+            el.stop();
+        });
+        if(this.$element != null) {
+            this.$element.remove();
         }
-        this.parent = null;
-        this.controller_parent = null;
-    },
-    log: function() {
-        var args = Array.prototype.slice.call(arguments);
-        var caller = arguments.callee.caller;
-        // TODO add support for line number using
-        // https://github.com/emwendelin/javascript-stacktrace/blob/master/stacktrace.js
-        // args.unshift("" + caller.debug_name);
-        this.on_log.apply(this,args);
-    },
-    on_log: function() {
-        if(window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) {
-            var notify = false;
-            var body = false;
-            if(window.console) {
-                console.log(arguments);
-            } else {
-                body = true;
-            }
-            var a = Array.prototype.slice.call(arguments, 0);
-            for(var i = 0; i < a.length; i++) {
-                var v = a[i]==null ? "null" : a[i].toString();
-                if(i==0) {
-                    notify = v.match(/^not/);
-                    body = v.match(/^bod/);
-                }
-                if(body) {
-                    $('
').text(v).appendTo($('body'));
-                }
-                if(notify && this.notification) {
-                    this.notification.notify("Logging:",v);
-                }
-            }
+        if (this.widget_parent && this.widget_parent.widget_children) {
+            this.widget_parent.widget_children = _.without(this.widget_parent.widget_children, this);
         }
-
-    }
-});
-
-/**
- * OpenERP session aware controller
- * a controller takes an already existing dom element and manage it
- */
-instance.base.Controller = instance.base.Controller.extend( /** @lends openerp.base.Controller# */{
-    init: function(parent, element_id) {
-        this._super(parent, element_id);
-        if(this.controller_parent && this.controller_parent.session) {
-            this.session = this.controller_parent.session;
-        }
-    },
-    /**
-     * Performs a JSON-RPC call
-     *
-     * @param {String} url endpoint url
-     * @param {Object} data RPC parameters
-     * @param {Function} success RPC call success callback
-     * @param {Function} error RPC call error callback
-     * @returns {jQuery.Deferred} deferred object for the RPC call
-     */
-    rpc: function(url, data, success, error) {
-        return this.session.rpc(url, data, success, error);
+        this.widget_parent = null;
     },
     do_action: function(action, on_finished) {
-        return this.parent.do_action(action, on_finished);
+        return this.widget_parent.do_action(action, on_finished);
     }
 });
 
-/**
- * OpenERP session aware widget
- * A widget is a controller that doesnt take an element_id
- * it render its own html render() that you should insert into the dom
- * and bind it at start()
+/*
+ * For retro compatibility only, the only difference with is that render takes
+ * directly this instead of 
  */
 instance.base.BaseWidget = instance.base.Controller.extend({
-    /**
-     * The name of the QWeb template that will be used for rendering. Must be
-     * redefined in subclasses or the render() method can not be used.
-     * 
-     * @type string
-     */
-    template: null,
-    /**
-     * The prefix used to generate an id automatically. Should be redefined in
-     * subclasses. If it is not defined, a default identifier will be used.
-     * 
-     * @type string
-     */
-    identifier_prefix: 'generic-identifier',
-    /**
-     * Base class for widgets. Handle rendering (based on a QWeb template),
-     * identifier generation, parenting and destruction of the widget.
-     * Also initialize the identifier.
-     *
-     * @constructs
-     * @params {openerp.base.search.BaseWidget} parent The parent widget.
-     */
-    init: function (parent) {
-        this._super(parent);
-        this.make_id(this.identifier_prefix);
-    },
-    /**
-     * Sets and returns a globally unique identifier for the widget.
-     *
-     * If a prefix is appended, the identifier will be appended to it.
-     *
-     * @params sections prefix sections, empty/falsy sections will be removed
-     */
-    make_id: function () {
-        this.element_id = _.uniqueId(_.toArray(arguments).join('_'));
-        return this.element_id;
-    },
-    /**
-     * Render the widget. This.template must be defined.
-     * The content of the current object is passed as context to the template.
-     * 
-     * @param {object} additional Additional context arguments to pass to the template.
-     */
     render: function (additional) {
-        return QWeb.render(this.template, _.extend({}, this, additional != null ? additional : {}));
-    },
-    /**
-     * "Starts" the widgets. Called at the end of the rendering, this allows
-     * to get a jQuery object referring to the DOM ($element attribute).
-     */
-    start: function () {
-        this._super();
-        var tmp = document.getElementById(this.element_id);
-        this.$element = tmp ? $(tmp) : null;
-    },
-    /**
-     * "Stops" the widgets. Called when the view destroys itself, this
-     * lets the widgets clean up after themselves.
-     */
-    stop: function () {
-        if(this.$element != null) {
-            this.$element.remove();
-        }
-        this._super();
+        return QWeb.render(this.template, _.extend(_.extend({}, this), additional || {}));
     }
 });
 
-// --------------------------------------------------------
-// N-style aka New-Style or Niv-Style
-// --------------------------------------------------------
-
-instance.base.NivController = instance.base.Class.extend({
-    init: function(parent) {
-        this.controller_parent = parent;
-        // Take the session of the parent if defined
-        if(this.controller_parent && this.controller_parent.session) {
-            this.session = this.controller_parent.session;
-        }
-        // Transform on_* method into openerp.base.callbacks
-        for (var name in this) {
-            if(typeof(this[name]) == "function") {
-                this[name].debug_name = name;
-                // bind ALL function to this not only on_and _do ?
-                if((/^on_|^do_/).test(name)) {
-                    this[name] = instance.base.callback(this, this[name]);
-                }
-            }
-        }
-    },
-    /**
-     * Event binding, rpc and callback calling required to initialize the
-     * object should happen here
-     *
-     * Returns a promise object letting callers (subclasses and direct callers)
-     * know when this component is done starting
-     *
-     * @returns {jQuery.Deferred}
-     */
-    start: function() {
-        // returns an already fulfilled promise. Maybe we could return nothing?
-        // $.when can take non-deferred and in that case it simply considers
-        // them all as fulfilled promises.
-        // But in thise case we *have* to ensure callers use $.when and don't
-        // try to call deferred methods on this return value.
-        return $.Deferred().done().promise();
-    },
-    stop: function() {
-    },
-    log: function() {
-        var args = Array.prototype.slice.call(arguments);
-        var caller = arguments.callee.caller;
-        // TODO add support for line number using
-        // https://github.com/emwendelin/javascript-stacktrace/blob/master/stacktrace.js
-        // args.unshift("" + caller.debug_name);
-        this.on_log.apply(this,args);
-    },
-    on_log: function() {
-        if(window.openerp.debug || (window.location.search.indexOf('?debug') !== -1)) {
-            var notify = false;
-            var body = false;
-            if(window.console) {
-                console.log(arguments);
-            } else {
-                body = true;
-            }
-            var a = Array.prototype.slice.call(arguments, 0);
-            for(var i = 0; i < a.length; i++) {
-                var v = a[i]==null ? "null" : a[i].toString();
-                if(i==0) {
-                    notify = v.match(/^not/);
-                    body = v.match(/^bod/);
-                }
-                if(body) {
-                    $('
').text(v).appendTo($('body'));
-                }
-                if(notify && this.notification) {
-                    this.notification.notify("Logging:",v);
-                }
-            }
-        }
-
-    },
-    /**
-     * Performs a JSON-RPC call
-     *
-     * @param {String} url endpoint url
-     * @param {Object} data RPC parameters
-     * @param {Function} success RPC call success callback
-     * @param {Function} error RPC call error callback
-     * @returns {jQuery.Deferred} deferred object for the RPC call
-     */
-    rpc: function(url, data, success, error) {
-        return this.session.rpc(url, data, success, error);
-    },
-    do_action: function(action, on_finished) {
-        return this.controller_parent.do_action(action, on_finished);
-    }
-});
-
-instance.base.NivWidget = instance.base.Controller.extend({
-    /**
-     * The name of the QWeb template that will be used for rendering. Must be
-     * redefined in subclasses or the render() method can not be used.
-     * 
-     * @type string
-     */
-    template: null,
-    /**
-     * The prefix used to generate an id automatically. Should be redefined in
-     * subclasses. If it is not defined, a default identifier will be used.
-     * 
-     * @type string
-     */
-    identifier_prefix: 'generic-identifier',
-    /**
-     * Base class for widgets. Handle rendering (based on a QWeb template),
-     * identifier generation, parenting and destruction of the widget.
-     * Also initialize the identifier.
-     *
-     * @constructs
-     * @params {openerp.base.search.BaseWidget} parent The parent widget.
-     */
-    init: function(parent, element_id) {
-        this._super(parent);
-        this.make_id(this.identifier_prefix);
-        // this.element_id = element_id;
-        // this.$element = $('#' + element_id);
-        // if (element_id) {
-        //     instance.screen[element_id] = this;
-        // }
-        // save the parent children relationship
-        this.controller_children = [];
-        if(parent && parent.controller_children) {
-            parent.controller_children.push(this);
-        }
-        // backward compatibility
-        this.parent = this.controller_parent;
-        this.children = this.controller_children;
-
-    },
-    /**
-     * Event binding, rpc and callback calling required to initialize the
-     * object should happen here
-     *
-     * Returns a promise object letting callers (subclasses and direct callers)
-     * know when this component is done starting
-     *
-     * @returns {jQuery.Deferred}
-     */
-    /**
-     * "Starts" the widgets. Called at the end of the rendering, this allows
-     * to get a jQuery object referring to the DOM ($element attribute).
-     */
-    start: function () {
-        this._super();
-        var tmp = document.getElementById(this.element_id);
-        this.$element = tmp ? $(tmp) : null;
-    },
-    stop: function() {
-        if(this.$element != null) {
-            this.$element.remove();
-        }
-        if (this.parent && this.parent.children) {
-            this.parent.children = _.without(this.parent.children, this);
-            this.parent.controller_children = this.parent.children;
-        }
-        this.parent = null;
-        this.controller_parent = null;
-    },
-    /**
-     * Sets and returns a globally unique identifier for the widget.
-     *
-     * If a prefix is appended, the identifier will be appended to it.
-     *
-     * @params sections prefix sections, empty/falsy sections will be removed
-     */
-    make_id: function () {
-        this.element_id = _.uniqueId(_.toArray(arguments).join('_'));
-        return this.element_id;
-    },
-    /**
-     * Render the widget. This.template must be defined.
-     * The content of the current object is passed as context to the template.
-     * 
-     * @param {object} additional Additional context arguments to pass to the template.
-     */
-    render: function (additional) {
-        return QWeb.render(this.template, _.extend({}, this, additional != null ? additional : {}));
-    },
-    widget_add: function(element, addfunc) {
-    },
-    widget_append: function(element) {
-    },
-    widget_prepend: function(element) {
-    },
-    widget_append2: function(element) {
-    },
-    widget_prepend2: function(element) {
-    },
-});
-
-
-};
-
+}
 // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/base/static/src/js/search.js b/addons/base/static/src/js/search.js
index 8a51abe1335..b74c845aa0d 100644
--- a/addons/base/static/src/js/search.js
+++ b/addons/base/static/src/js/search.js
@@ -891,7 +891,7 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
         if(this.$element.closest("table.oe-searchview-render-line").css("display") == "none") {
             return null;
         }
-        return _.reduce(this.children,
+        return _.reduce(this.widget_children,
             function(mem, x) { return mem.concat(x.get_domain());}, []);
     },
     on_activate: function() {
@@ -910,9 +910,9 @@ openerp.base.search.ExtendedSearch = openerp.base.BaseWidget.extend({
         }
     },
     check_last_element: function() {
-        _.each(this.children, function(x) {x.set_last_group(false);});
-        if (this.children.length >= 1) {
-            this.children[this.children.length - 1].set_last_group(true);
+        _.each(this.widget_children, function(x) {x.set_last_group(false);});
+        if (this.widget_children.length >= 1) {
+            this.widget_children[this.widget_children.length - 1].set_last_group(true);
         }
     }
 });
@@ -926,7 +926,7 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
     },
     add_prop: function() {
         var prop = new openerp.base.search.ExtendedSearchProposition(this, this.fields);
-        var render = prop.render({'index': this.children.length - 1});
+        var render = prop.render({'index': this.widget_children.length - 1});
         this.$element.find('.searchview_extended_propositions_list').append(render);
         prop.start();
     },
@@ -943,7 +943,7 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
         });
     },
     get_domain: function() {
-        var props = _(this.children).chain().map(function(x) {
+        var props = _(this.widget_children).chain().map(function(x) {
             return x.get_proposition();
         }).compact().value();
         var choice = this.$element.find(".searchview_extended_group_choice").val();
@@ -953,9 +953,9 @@ openerp.base.search.ExtendedSearchGroup = openerp.base.BaseWidget.extend({
             props);
     },
     stop: function() {
-        var parent = this.parent;
-        if (this.parent.children.length == 1)
-            this.parent.hide();
+        var parent = this.widget_parent;
+        if (this.widget_parent.widget_children.length == 1)
+            this.widget_parent.hide();
         this._super();
         parent.check_last_element();
     },
@@ -992,9 +992,12 @@ openerp.base.search.ExtendedSearchProposition = openerp.base.BaseWidget.extend({
         });
     },
     stop: function() {
-        if (this.parent.children.length == 1)
-            this.parent.stop();
+        var parent;
+        if (this.widget_parent.widget_children.length == 1)
+            parent = this.widget_parent;
         this._super();
+        if (parent)
+            parent.stop();
     },
     changed: function() {
         var nval = this.$element.find(".searchview_extended_prop_field").val();