diff options
| author | Antony Lesuisse <al@openerp.com> | 2012-08-01 14:48:04 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2012-08-01 14:48:04 +0200 |
| commit | fbb2f80cf1c6c593ac6de1e2636ae0dc9dd8a7f8 (patch) | |
| tree | 5b1672edaf3e7eebf269127ec301a9ac8f93c488 /addons/web/static/src/js | |
| parent | c72a63472bda74f7b2a31328e5c514ae24808375 (diff) | |
| parent | 574f3891a550cfda0b07b397f390c543cb897601 (diff) | |
[MERGE] backbonify-widgets, minor api changes that make Widget more similar to backbone Views
bzr revid: al@openerp.com-20120801124804-ov9l9ytabqx54gdo
Diffstat (limited to 'addons/web/static/src/js')
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 17 | ||||
| -rw-r--r-- | addons/web/static/src/js/corelib.js | 152 | ||||
| -rw-r--r-- | addons/web/static/src/js/coresetup.js | 7 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 9 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list_editable.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 5 |
7 files changed, 147 insertions, 51 deletions
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index a74fe190271..b3591f534f2 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -57,9 +57,7 @@ instance.web.Dialog = instance.web.Widget.extend({ init: function (parent, options, content) { var self = this; this._super(parent); - if (content) { - this.$element = content instanceof $ ? content : $(content); - } + this.setElement(content || this.make(this.tagName)); this.dialog_options = { modal: true, destroy_on_close: true, @@ -589,6 +587,12 @@ instance.web.Login = instance.web.Widget.extend({ self.$(".oe_login_pane").fadeIn("fast"); self.$element.addClass("oe_login_invalid"); }); + }, + show: function () { + this.$element.show(); + }, + hide: function () { + this.$element.hide(); } }); instance.web.client_actions.add("login", "instance.web.Login"); @@ -880,12 +884,11 @@ instance.web.Client = instance.web.Widget.extend({ }, start: function() { var self = this; - return instance.connection.session_bind(this.origin).then(function() { + return instance.connection.session_bind(this.origin).pipe(function() { var $e = $(QWeb.render(self._template, {})); - self.$element.replaceWith($e); - self.$element = $e; + self.replaceElement($e); self.bind_events(); - self.show_common(); + return self.show_common(); }); }, bind_events: function() { diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js index a092b670ef1..846ae3e4758 100644 --- a/addons/web/static/src/js/corelib.js +++ b/addons/web/static/src/js/corelib.js @@ -491,24 +491,20 @@ instance.web.CallbackEnabledMixin = _.extend({}, instance.web.PropertiesMixin, { * * The semantics of this precisely replace closing over the method call. * - * @param {String} method_name name of the method to invoke + * @param {String|Function} method function or name of the method to invoke * @returns {Function} proxied method */ - proxy: function (method_name) { + proxy: function (method) { var self = this; return function () { - return self[method_name].apply(self, arguments); + var fn = (typeof method === 'string') ? self[method] : method; + return fn.apply(self, arguments); } } }); instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, { /** - * Tag name when creating a default $element. - * @type string - */ - tagName: 'div', - /** * Constructs the widget and sets its parent if a parent is given. * * @constructs instance.web.Widget @@ -517,14 +513,9 @@ instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, { * @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. - * @param {String} element_id Deprecated. Sets the element_id. Only useful when you want - * to bind the current Widget to an already existing part of the DOM, which is not compatible - * with the DOM insertion methods provided by the current implementation of Widget. So - * for new components this argument should not be provided any more. */ init: function(parent) { instance.web.CallbackEnabledMixin.init.call(this); - this.$element = $(document.createElement(this.tagName)); this.setParent(parent); }, /** @@ -534,7 +525,7 @@ instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, { _.each(this.getChildren(), function(el) { el.destroy(); }); - if(this.$element != null) { + if(this.$element) { this.$element.remove(); } instance.web.PropertiesMixin.destroy.call(this); @@ -613,6 +604,7 @@ instance.web.WidgetMixin = _.extend({},instance.web.CallbackEnabledMixin, { * @returns {jQuery.Deferred} */ start: function() { + return $.when(); } }); @@ -673,6 +665,12 @@ instance.web.CallbackEnabled = instance.web.Class.extend(instance.web.CallbackEn * 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 * redefined in subclasses or the default render() method can not be used. @@ -689,13 +687,11 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, { * @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. - * @param {String} element_id Deprecated. Sets the element_id. Only useful when you want - * to bind the current Widget to an already existing part of the DOM, which is not compatible - * with the DOM insertion methods provided by the current implementation of Widget. So - * for new components this argument should not be provided any more. */ init: function(parent) { instance.web.WidgetMixin.init.call(this,parent); + // FIXME: this should not be + this.setElement(this._make_descriptive()); this.session = instance.connection; }, /** @@ -704,20 +700,120 @@ instance.web.Widget = instance.web.Class.extend(instance.web.WidgetMixin, { * key that references `this`. */ renderElement: function() { - var rendered = null; - if (this.template) - rendered = instance.web.qweb.render(this.template, {widget: this}); - if (_.str.trim(rendered)) { - var elem = $(rendered); - this.$element.replaceWith(elem); - this.$element = elem; + var $el; + if (this.template) { + $el = $(_.str.trim(instance.web.qweb.render( + this.template, {widget: this}))); + } else { + $el = this._make_descriptive(); + } + this.replaceElement($el); + }, + + /** + * Re-sets the widget's root element and replaces the old root element + * (if any) by the new one in the DOM. + * + * @param {HTMLElement | jQuery} $el + * @returns {*} this + */ + replaceElement: function ($el) { + var $oldel = this.$element; + this.setElement($el); + if ($oldel && !$oldel.is(this.$element)) { + $oldel.replaceWith(this.$element); } + return this; }, /** - * Shortcut for $element.find() like backbone + * Re-sets the widget's root element (el/$el/$element). + * + * Includes: + * * re-delegating events + * * re-binding sub-elements + * * if the widget already had a root element, replacing the pre-existing + * element in the DOM + * + * @param {HTMLElement | jQuery} element new root element for the widget + * @return {*} this + */ + setElement: function (element) { + // NB: completely useless, as WidgetMixin#init creates a $element + // always + if (this.$element) { + this.undelegateEvents(); + } + + this.$element = (element instanceof $) ? element : $(element); + this.el = this.$element[0]; + + this.delegateEvents(); + + return this; + }, + /** + * Utility function to build small DOM elements. + * + * @param {String} tagName name of the DOM element to create + * @param {Object} [attributes] map of DOM attributes to set on the element + * @param {String} [content] HTML content to set on the element + * @return {Element} + */ + make: function (tagName, attributes, content) { + var el = document.createElement(tagName); + if (!_.isEmpty(attributes)) { + $(el).attr(attributes); + } + if (content) { + $(el).html(content); + } + return el; + }, + /** + * Makes a potential root element from the declarative builder of the + * widget + * + * @return {jQuery} + * @private + */ + _make_descriptive: function () { + var attrs = _.extend({}, this.attributes || {}); + if (this.id) { attrs.id = this.id; } + if (this.className) { attrs['class'] = this.className; } + return $(this.make(this.tagName, attrs)); + }, + delegateEvents: function () { + var events = this.events; + if (_.isEmpty(events)) { return; } + + for(var key in events) { + if (!events.hasOwnProperty(key)) { continue; } + + var method = this.proxy(events[key]); + + var match = /^(\S+)(\s+(.*))?$/.exec(key); + var event = match[1]; + var selector = match[3]; + + event += '.widget_events'; + if (!selector) { + this.$element.on(event, method); + } else { + this.$element.on(event, selector, method); + } + } + }, + undelegateEvents: function () { + this.$element.off('.widget_events'); + }, + /** + * Shortcut for ``this.$element.find(selector)`` + * + * @param {String} selector CSS selector, rooted in $el + * @returns {jQuery} selector match */ - "$": function() { - return this.$element.find.apply(this.$element,arguments); + $: function(selector) { + return this.$element.find(selector); }, /** * Informs the action manager to do an action. This supposes that diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index 24441dc509f..12eeb1d79b4 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -19,15 +19,14 @@ instance.web.OldWidget = instance.web.Widget.extend({ this._super(parent); this.element_id = element_id; this.element_id = this.element_id || _.uniqueId('widget-'); + var tmp = document.getElementById(this.element_id); - this.$element = tmp ? $(tmp) : $(document.createElement(this.tagName)); + this.setElement(tmp || this._make_descriptive()); }, renderElement: function() { var rendered = this.render(); if (rendered) { - var elem = $(rendered); - this.$element.replaceWith(elem); - this.$element = elem; + this.replaceElement($(rendered)); } return this; }, diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index c3e7ad72dcb..f9cf10e76f4 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -861,13 +861,13 @@ instance.web.search.Invalid = instance.web.Class.extend( /** @lends instance.web ); } }); -instance.web.search.Widget = instance.web.OldWidget.extend( /** @lends instance.web.search.Widget# */{ +instance.web.search.Widget = instance.web.Widget.extend( /** @lends instance.web.search.Widget# */{ template: null, /** * Root class of all search widgets * * @constructs instance.web.search.Widget - * @extends instance.web.OldWidget + * @extends instance.web.Widget * * @param view the ancestor view of this widget */ diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 1f693acbc7f..99df34d6c6c 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -101,7 +101,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM w.off('focused blurred'); w.destroy(); }); - this.$element.off('.formBlur'); + if (this.$element) { + this.$element.off('.formBlur'); + } this._super(); }, on_loaded: function(data) { @@ -3076,7 +3078,6 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ this.views = views; this.viewmanager = new instance.web.form.One2ManyViewManager(this, this.dataset, views, {}); - this.viewmanager.$element.addClass("oe_view_manager_one2many"); this.viewmanager.o2m = self; var once = $.Deferred().then(function() { self.init_form_last_update.resolve(); @@ -4304,7 +4305,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan this.selection.view = this.view; this.selection.set({force_readonly: this.get('effective_readonly')}); this.selection.on("change:value", this, this.on_selection_changed); - this.selection.$element = $(".oe_form_view_reference_selection", this.$element); + this.selection.setElement(this.$(".oe_form_view_reference_selection")); this.selection.renderElement(); this.selection.start(); this.selection @@ -4317,7 +4318,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan this.m2o.view = this.view; this.m2o.set({force_readonly: this.get("effective_readonly")}); this.m2o.on("change:value", this, this.data_changed); - this.m2o.$element = $(".oe_form_view_reference_m2o", this.$element); + this.m2o.setElement(this.$(".oe_form_view_reference_m2o")); this.m2o.renderElement(); this.m2o.start(); this.m2o diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index ca889f68d8d..6c38495d0dc 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -96,9 +96,6 @@ openerp.web.list_editable = function (instance) { }, on_loaded: function (data, grouped) { var self = this; - if (this.editor) { - this.editor.destroy(); - } // tree/@editable takes priority on everything else if present. var result = this._super(data, grouped); if (this.editable()) { @@ -118,6 +115,7 @@ openerp.web.list_editable = function (instance) { self.start_edition(); } }); + this.editor.destroy(); // Editor is not restartable due to formview not being // restartable this.editor = this.make_editor(); diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index e47981a4284..2b79701ba4d 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -423,7 +423,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ .find('.oe_view_manager_switch a').filter('[data-view-type="' + view_type + '"]') .parent().addClass('active'); - $.when(view_promise).then(function () { + return $.when(view_promise).then(function () { _.each(_.keys(self.views), function(view_name) { var controller = self.views[view_name].controller; if (controller) { @@ -445,7 +445,6 @@ instance.web.ViewManager = instance.web.Widget.extend({ } }); }); - return view_promise; }, do_create_view: function(view_type) { // Lazy loading of views @@ -1175,7 +1174,7 @@ instance.web.View = instance.web.Widget.extend({ this.view_id = view_id; this.set_default_options(options); }, - start: function() { + start: function () { return this.load_view(); }, load_view: function() { |
