summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/view_form.js
diff options
context:
space:
mode:
authorSimon Lejeune <sle@openerp.com>2014-12-16 18:14:15 +0100
committerSimon Lejeune <sle@openerp.com>2014-12-19 17:49:13 +0100
commitb2e32a8f7e7d0b4278c22fbc3d0832a3e8b1469f (patch)
treed395ca7473d9adc5ce4fc7b6717c2f6b0d35537f /addons/web/static/src/js/view_form.js
parent01409c1d7b0050942ba5e53ff4f3bb927fd3eb51 (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/view_form.js')
-rw-r--r--addons/web/static/src/js/view_form.js120
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.