diff options
| author | Simon Lejeune <sle@openerp.com> | 2014-12-16 18:14:15 +0100 |
|---|---|---|
| committer | Simon Lejeune <sle@openerp.com> | 2014-12-19 17:49:13 +0100 |
| commit | b2e32a8f7e7d0b4278c22fbc3d0832a3e8b1469f (patch) | |
| tree | d395ca7473d9adc5ce4fc7b6717c2f6b0d35537f /addons/web/static/src/js | |
| parent | 01409c1d7b0050942ba5e53ff4f3bb927fd3eb51 (diff) | |
[IMP] web: use bootstrap's notebook, rewrite process_notebook
Introduction of a specialized InvisibilityChanger for the notebook. It
allows to handle more elegantly the issues of the notebook during
page execution: modifiers hiding the active tab that must now
active its sibling.
Process_notebook only handle the processing of the page while
NotebookInvisibilityChanger only handle the behavior of the notebook
during the page execution.
- readable code (more readable, at least)
- correct handle of autofocus
- rendering of the whole notebook in one call to qweb's render
- one invisibility changer bound by header/content
- no custom css, only legacy bootstrap
Diffstat (limited to 'addons/web/static/src/js')
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 120 |
1 files changed, 83 insertions, 37 deletions
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index edff8582e09..7ebfd4de1a3 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -1514,50 +1514,54 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt }, process_notebook: function($notebook) { var self = this; + + // Extract useful info from the notebook xml declaration var pages = []; $notebook.find('> page').each(function() { var $page = $(this); var page_attrs = $page.getAttributes(); page_attrs.id = _.uniqueId('notebook_page_'); - var $new_page = self.render_element('FormRenderingNotebookPage', page_attrs); - $page.contents().appendTo($new_page); - $page.before($new_page).remove(); - var ic = self.handle_common_properties($new_page, $page).invisibility_changer; - page_attrs.__page = $new_page; - page_attrs.__ic = ic; + page_attrs.contents = $page.html(); + page_attrs.ref = $page; // reference to the current page node in the xml declaration pages.push(page_attrs); - - $new_page.children().each(function() { - self.process($(this)); - }); }); - var $new_notebook = this.render_element('FormRenderingNotebook', { pages : pages }); - $notebook.contents().appendTo($new_notebook); + + // Render the notebook and replace $notebook with it + var $new_notebook = self.render_element('FormRenderingNotebook', {'pages': pages}); $notebook.before($new_notebook).remove(); - self.process($($new_notebook.children()[0])); - //tabs and invisibility handling - $new_notebook.tabs(); - _.each(pages, function(page, i) { - if (! page.__ic) - return; - page.__ic.on("change:effective_invisible", null, function() { - if (!page.__ic.get('effective_invisible') && page.autofocus) { - $new_notebook.tabs('select', i); - return; - } - var current = $new_notebook.tabs("option", "selected"); - if (! pages[current].__ic || ! pages[current].__ic.get("effective_invisible")) - return; - var first_visible = _.find(_.range(pages.length), function(i2) { - return (! pages[i2].__ic) || (! pages[i2].__ic.get("effective_invisible")); - }); - if (first_visible !== undefined) { - $new_notebook.tabs('select', first_visible); - } - }); + + // Bind the invisibility changers and find the page to display + var pageid_to_display; + _.each(pages, function(page) { + $tab = $new_notebook.find('a[href=#' + page.id + ']').parent(); + $content = $new_notebook.find('#' + page.id); + + // Case: <page autofocus="autofocus">; + // We attach the autofocus attribute to the node because it can be useful during the + // page execution + self.attach_node_attr($tab, page.ref, 'autofocus'); + self.attach_node_attr($content, page.ref, 'autofocus'); + if (!pageid_to_display && page.autofocus) { + // If multiple autofocus, keep the first one + pageid_to_display = page.id; + } + + // Case: <page attrs="{'invisible': domain}">; + self.handle_common_properties($tab, page.ref, instance.web.form.NotebookInvisibilityChanger); + self.handle_common_properties($content, page.ref, instance.web.form.NotebookInvisibilityChanger); }); + if (!pageid_to_display) { + pageid_to_display = $new_notebook.find('div[role="tabpanel"]:not(.oe_form_invisible):first').attr('id'); + } + + // Display page. Note: we can't use bootstrap's show function because it is looking for + // document attached DOM, and the form view is only attached when everything is processed + $new_notebook.find('a[href=#' + pageid_to_display + ']').parent().addClass('active'); + $new_notebook.find('#' + pageid_to_display).addClass('active in'); // `in` class is required for bootstrap's fade + + self.process($new_notebook.children()); + self.handle_common_properties($new_notebook, $notebook); - this.handle_common_properties($new_notebook, $notebook); return $new_notebook; }, process_separator: function($separator) { @@ -1591,16 +1595,25 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt } return $new_label; }, - handle_common_properties: function($new_element, $node) { + handle_common_properties: function($new_element, $node, InvisibilityChanger) { var str_modifiers = $node.attr("modifiers") || "{}"; var modifiers = JSON.parse(str_modifiers); var ic = null; - if (modifiers.invisible !== undefined) - ic = new instance.web.form.InvisibilityChanger(this.view, this.view, modifiers.invisible, $new_element); + if (modifiers.invisible !== undefined) { + var InvisibilityChangerCls = InvisibilityChanger || instance.web.form.InvisibilityChanger; + ic = new InvisibilityChangerCls(this.view, this.view, modifiers.invisible, $new_element); + } $new_element.addClass($node.attr("class") || ""); $new_element.attr('style', $node.attr('style')); return {invisibility_changer: ic,}; }, + /** + * Attach a node attribute to an html element to be able to use it after + * the processing of the page. + */ + attach_node_attr: function($new_element, $node, attr) { + $new_element.data('autofocus', $node.attr(attr)); + } }); /** @@ -1772,6 +1785,39 @@ instance.web.form.InvisibilityChanger = instance.web.Class.extend(instance.web.P }, }); +// Specialization of InvisibilityChanger for the `notebook` form element to handle more +// elegantly its special cases (i.e. activate the closest visible sibling) +instance.web.form.NotebookInvisibilityChanger = instance.web.form.InvisibilityChanger.extend({ + _check_visibility: function() { + this._super(); + if (this.get("effective_invisible") === true) { + // Switch to invisible + // Remove this element as active and set a visible sibling active (if there is one) + if (this.$el.hasClass('active')) { + this.$el.removeClass('active in'); + var visible_siblings = this.$el.siblings(':not(.oe_form_invisible)'); + if (visible_siblings.length) { + $(visible_siblings[0]).addClass('active in'); + } + } + } else { + // Switch to visible + // If there is no visible active sibling, set this element as active, + // otherwise: + // if that sibling has autofocus, do nothing + // otherwise, remove that sibling as active and set this element as active + var visible_active_sibling = this.$el.siblings(':not(.oe_form_invisible).active'); + if (!(visible_active_sibling.length)) { + this.$el.addClass('active in'); + } else if (!$(visible_active_sibling[0]).data('autofocus')) { + this.$el.addClass('active in'); + $(visible_active_sibling[0]).removeClass('active in'); + } + } + }, +}); + + /** Base class for all fields, custom widgets and buttons to be displayed in the form view. |
