[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
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.handle_common_properties($new_notebook, $notebook);
|
||||
// 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);
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user