summaryrefslogtreecommitdiff
path: root/addons/web
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
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')
-rw-r--r--addons/web/static/src/css/base.css75
-rw-r--r--addons/web/static/src/css/base.sass56
-rw-r--r--addons/web/static/src/js/view_form.js120
-rw-r--r--addons/web/static/src/xml/base.xml13
4 files changed, 91 insertions, 173 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index fdc7db1e2f2..81d8628c504 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -532,7 +532,7 @@
background-image: -webkit-radial-gradient(circle, #eee 0%, #ccc 40%, #bbb 100%);
background-image: -moz-radial-gradient(#eee 0%, #ccc 40%, #bbb 100%);
background-image: -ms-radial-gradient(#eee 0%, #ccc 40%, #bbb 100%);
- background-image: radial-gradient(circle, #eee 0%, #ccc 40%, #bbb 100%);
+ background-image: radial-gradient(circle, #eeeeee 0%, #cccccc 40%, #bbbbbb 100%);
}
.openerp .oe_kanban_status_green {
background: green;
@@ -616,79 +616,6 @@
font-style: italic;
text-decoration: none;
}
-.openerp .oe_notebook {
- margin: 8px 0;
- padding: 0 16px;
- list-style: none;
- zoom: 1;
-}
-.openerp .oe_notebook.ui-corner-all {
- -moz-border-radius: 0;
- -webkit-border-radius: 0;
- border-radius: 0;
-}
-.openerp .oe_notebook:before, .openerp .oe_notebook:after {
- display: table;
- content: "";
- zoom: 1;
-}
-.openerp .oe_notebook:after {
- clear: both;
-}
-.openerp .oe_notebook > li {
- float: left;
-}
-.openerp .oe_notebook > li > a {
- display: block;
- color: #808080;
-}
-.openerp .oe_notebook > li.ui-tabs-active > a {
- color: #4c4c4c;
-}
-.openerp .oe_notebook {
- border-color: #ddd;
- border-style: solid;
- border-width: 0 0 1px;
-}
-.openerp .oe_notebook > li {
- position: relative;
-}
-.openerp .oe_notebook > li > a {
- padding: 0 12px;
- margin-right: 2px;
- line-height: 30px;
- border: 1px solid transparent;
- -moz-border-radius: 4px 4px 0 0;
- -webkit-border-radius: 4px 4px 0 0;
- border-radius: 4px 4px 0 0;
-}
-.openerp .oe_notebook > li > a:hover {
- text-decoration: none;
- background-color: #eee;
- border-color: #eee #eee #ddd;
-}
-.openerp .ui-tabs .oe_notebook.ui-tabs-nav li.ui-tabs-active {
- border-bottom: none;
- padding-bottom: 1px;
-}
-.openerp .oe_notebook > li.ui-state-active > a, .openerp .oe_notebook > li.ui-state-active > a:hover {
- background-color: #ffffff;
- border: 1px solid #ddd;
- border-bottom-color: transparent;
- cursor: default;
-}
-.openerp .oe_notebook_page {
- padding: 0;
-}
-.openerp .oe_notebook_page > label:not([for]) {
- font-weight: normal !important;
-}
-.openerp div.ui-tabs {
- padding: 3px 0px 3px 0px;
-}
-.openerp .ui-tabs-hide {
- display: none;
-}
.openerp .oe_dropdown, .openerp .oe_dropdown_hover, .openerp .oe_dropdown_toggle {
position: relative;
cursor: pointer;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 632bc36c086..fc41de6f5e7 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -555,62 +555,6 @@ $sheet-padding: 16px
text-decoration: none
margin-bottom: 1px
// }}}
- // Notebook {{{
- .oe_notebook
- margin: 8px 0
- padding: 0 16px
- list-style: none
- zoom: 1
- .oe_notebook.ui-corner-all
- @include radius(0)
- .oe_notebook:before, .oe_notebook:after
- display: table
- content: ""
- zoom: 1
- .oe_notebook:after
- clear: both
- .oe_notebook > li
- float: left
- .oe_notebook > li > a
- display: block
- color: #808080
- .oe_notebook > li.ui-tabs-active > a
- color: #4c4c4c
- .oe_notebook
- border-color: #ddd
- border-style: solid
- border-width: 0 0 1px
- .oe_notebook > li
- position: relative
- .oe_notebook > li > a
- padding: 0 12px
- margin-right: 2px
- line-height: 30px
- border: 1px solid transparent
- @include radius(4px 4px 0 0)
- .oe_notebook > li > a:hover
- text-decoration: none
- background-color: #eee
- border-color: #eee #eee #ddd
- .ui-tabs .oe_notebook.ui-tabs-nav li.ui-tabs-active
- border-bottom: none
- padding-bottom: 1px
- .oe_notebook > li.ui-state-active > a, .oe_notebook > li.ui-state-active > a:hover
- background-color: #ffffff
- border: 1px solid #ddd
- border-bottom-color: transparent
- cursor: default
- .oe_notebook_page
- padding: 0
- //Customize label weight according bootstrap3
- > label:not([for])
- font-weight: normal !important
- // End of customize
- div.ui-tabs
- padding: 3px 0px 3px 0px
- .ui-tabs-hide
- display: none
- // }}}
// Dropdown {{{
.oe_dropdown, .oe_dropdown_hover, .oe_dropdown_toggle
position: relative
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.
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index e5b8286bdb9..dffa0a47fc3 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -888,17 +888,18 @@
</t>
<t t-name="FormRenderingNotebook">
<div class="oe_clear">
- <ul t-attf-class="oe_notebook #{classnames}">
+ <ul t-attf-class="nav nav-tabs #{classnames}" role="tablist">
<li t-foreach="pages" t-as="page" t-att-modifiers="page.modifiers">
- <a t-attf-href="##{page.id}" t-att-accesskey="page.accesskey">
+ <a role="tab" t-attf-href="##{page.id}" t-att-accesskey="page.accesskey" data-toggle="tab">
<t t-esc="page.string"/>
</a>
</li>
</ul>
- </div>
-</t>
-<t t-name="FormRenderingNotebookPage">
- <div t-attf-class="oe_notebook_page #{classnames}" t-att-id="id">
+ <div class="tab-content">
+ <div role="tabpanel" t-foreach="pages" t-as="page" t-attf-class="tab-pane fade #{classnames}" t-att-id="id">
+ <t t-raw="page.contents"/>
+ </div>
+ </div>
</div>
</t>
<t t-name="FormRenderingSeparator">