summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorTurkesh Patel (Open ERP) <tpa@tinyerp.com>2012-07-13 16:18:23 +0530
committerTurkesh Patel (Open ERP) <tpa@tinyerp.com>2012-07-13 16:18:23 +0530
commit6c4117faab165cbfe96f71c7632b683828dcdfbc (patch)
tree91cae8ec8fb16d258d1bc05b29fd8960f6c3f93c /addons/web/static/src
parent0d4bd736e1bd8c8acb78f63e190111b1c72b05af (diff)
parentb65c05a58195c70156a658a7cad26ee08857db80 (diff)
[MRG] merge with lp:~openerp-dev/openerp-web/trunk-merge-translation
bzr revid: tpa@tinyerp.com-20120713104823-jbjotql32ernal0w
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/css/base.css118
-rw-r--r--addons/web/static/src/css/base.sass98
-rw-r--r--addons/web/static/src/js/chrome.js12
-rw-r--r--addons/web/static/src/js/view_editor.js10
-rw-r--r--addons/web/static/src/js/view_form.js4
-rw-r--r--addons/web/static/src/js/view_tree.js103
-rw-r--r--addons/web/static/src/js/views.js270
-rw-r--r--addons/web/static/src/xml/base.xml73
8 files changed, 470 insertions, 218 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 36d26d10741..939672e7293 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -34,7 +34,7 @@
background: white;
/* http://www.quirksmode.org/dom/inputfile.html
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
- */ */
+ */
}
.openerp a {
text-decoration: none;
@@ -188,13 +188,7 @@
}
.openerp.ui-dialog {
display: none;
- position: fixed;
padding: 6px;
- top: 50%;
- left: 50%;
- z-index: 1050;
- width: 560px;
- margin: -150px 0 0 -280px;
background-color: rgba(60, 60, 60, 0.7);
border: 1px solid;
border-color: #888888 #555555 #444444;
@@ -386,13 +380,16 @@
visibility: hidden;
}
.openerp .oe_button_box {
- width: 200px;
- text-align: center;
+ width: 38%;
+ text-align: right;
+}
+.openerp .oe_button_box button {
+ margin: 4px;
}
.openerp .oe_avatar {
margin: 0 16px 0 0;
}
-.openerp .oe_avatar img {
+.openerp .oe_avatar > img {
height: 50px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
@@ -536,7 +533,7 @@
cursor: pointer;
}
.openerp .oe_dropdown_toggle {
- color: #888888;
+ color: #404040;
font-weight: normal;
}
.openerp .oe_dropdown_hover:hover .oe_dropdown_menu, .openerp .oe_dropdown_menu.oe_opened {
@@ -545,7 +542,8 @@
.openerp .oe_dropdown_menu {
display: none;
position: absolute;
- top: 32px;
+ top: 26px;
+ left: 0;
z-index: 1;
border: 1px solid #afafb6;
background: white;
@@ -1857,7 +1855,7 @@
.openerp .oe_form td.oe_form_group_cell_label label {
line-height: 18px;
display: block;
- min-width: 120px;
+ min-width: 110px;
}
.openerp .oe_form td.oe_form_group_cell + .oe_form_group_cell {
padding-left: 6px;
@@ -1929,9 +1927,10 @@
}
.openerp .oe_form .oe_form_field_char input,
.openerp .oe_form .oe_form_field_url input,
+.openerp .oe_form .oe_form_field_email input,
.openerp .oe_form .oe_form_field_text textarea,
.openerp .oe_form .oe_form_field_selection select {
- width: inherit;
+ width: 100%;
}
.openerp .oe_form .oe_form_field_text.oe_inline, .openerp .oe_form .oe_form_field_text.oe_inline > textarea {
width: 500px;
@@ -2001,15 +2000,6 @@
-webkit-border-radius: 0px;
border-radius: 0px;
}
-.openerp .oe_form .oe_form_field_many2one input, .openerp .oe_form .oe_form_field_binary input, .openerp .oe_form .oe_form_field_binary input, .openerp .oe_form .oe_form_field_url input {
- border-right: none;
- -webkit-border-top-right-radius: 0px;
- -webkit-border-bottom-right-radius: 0px;
- -moz-border-radius-topright: 0px;
- -moz-border-radius-bottomright: 0px;
- border-top-right-radius: 0px;
- border-bottom-right-radius: 0px;
-}
.openerp .oe_form .oe_form_field_url button img {
vertical-align: top;
}
@@ -2073,10 +2063,19 @@
right: 5px;
top: 3px;
}
-.openerp .oe_form .oe_form_field_with_button input {
- width: 100%;
+.openerp .oe_form .oe_form_field_with_button.oe_no_button > .oe_button {
+ display: none;
+}
+.openerp .oe_form .oe_form_field_with_button:not(.oe_no_button) input {
+ border-right: none;
+ -webkit-border-top-right-radius: 0px;
+ -webkit-border-bottom-right-radius: 0px;
+ -moz-border-radius-topright: 0px;
+ -moz-border-radius-bottomright: 0px;
+ border-top-right-radius: 0px;
+ border-bottom-right-radius: 0px;
}
-.openerp .oe_form .oe_form_field_with_button > .oe_button {
+.openerp .oe_form .oe_form_field_with_button:not(.oe_no_button) > .oe_button {
float: right;
-moz-border-radius: 0;
-webkit-border-radius: 0;
@@ -2084,6 +2083,9 @@
border-bottom-left-radius: 0px;
height: 22px;
}
+.openerp .oe_form .oe_form_field_with_button input {
+ width: 100%;
+}
.openerp .oe_form .oe_form_field_with_button > div {
position: relative;
overflow: hidden;
@@ -2117,6 +2119,7 @@
}
.openerp .oe_form .oe_form_field_image .oe_form_field_image_controls {
position: absolute;
+ white-space: nowrap;
top: 1px;
padding: 3px 0 0 0;
margin: 0 1px;
@@ -2138,8 +2141,8 @@
}
.openerp .oe_form_field_many2one span.oe_m2o_drop_down_button {
position: absolute;
- top: 3px;
- right: 2px;
+ top: 1px;
+ right: 0px;
}
.openerp .oe_form .oe_form_field_one2many > .oe_view_manager .oe_list_pager_single_page {
display: none;
@@ -2345,6 +2348,59 @@
color: #333333;
}
+.openerp .tree_header {
+ background-color: #f0f0f0;
+ border-bottom: 1px solid #cacaca;
+ color: #4c4c4c;
+ padding: 5px;
+ height: 25px;
+}
+.openerp .tree_header button {
+ float: right;
+ height: 27px;
+ margin-right: 5px;
+}
+.openerp .oe-treeview-table {
+ width: 100%;
+ background-color: white;
+ border-spacing: 0;
+}
+.openerp .oe-treeview-table th {
+ padding: 10px;
+ color: #4c4c4c;
+ font-weight: bold;
+ background-color: #f0f0f0;
+ border-bottom: 2px solid #cacaca;
+}
+.openerp .oe-treeview-table .treeview-tr, .openerp .oe-treeview-table .treeview-td {
+ cursor: pointer;
+ border-right: 1px dotted #afafb6;
+ vertical-align: top;
+ text-align: left;
+ border-bottom: 1px solid #cfcccc;
+}
+.openerp .oe-treeview-table tr:hover {
+ background-color: #e0e0f8;
+}
+.openerp .oe-treeview-table .oe-number {
+ text-align: right !important;
+}
+.openerp .oe-treeview-table span {
+ font-size: 90%;
+ font-weight: normal;
+ white-space: nowrap;
+ display: block;
+}
+.openerp .oe-treeview-table .treeview-tr.oe-treeview-first {
+ background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat;
+}
+.openerp .oe-treeview-table .oe_open .treeview-tr.oe-treeview-first {
+ background-image: url(/web/static/src/img/collapse.gif);
+}
+.openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span {
+ margin-left: 16px;
+}
+
.kitten-mode-activated {
background-image: url(http://placekitten.com/g/1365/769);
background-size: cover;
@@ -2353,3 +2409,9 @@
.kitten-mode-activated > * {
opacity: 0.7;
}
+
+div.ui-widget-overlay {
+ background: black;
+ filter: alpha(opacity=30);
+ opacity: 0.3;
+}
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 2ba3b79c411..162b530ff30 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -205,13 +205,7 @@ $sheet-max-width: 860px
// Modal box
&.ui-dialog
display: none
- position: fixed
padding: 6px
- top: 50%
- left: 50%
- z-index: 1050
- width: 560px
- margin: -150px 0 0 -280px
//overflow: hidden
background-color: rgba(60,60,60,0.7)
border: 1px solid
@@ -330,11 +324,13 @@ $sheet-max-width: 860px
clear: both
visibility: hidden
.oe_button_box
- width: 200px
- text-align: center
+ width: 38%
+ text-align: right
+ button
+ margin: 4px
.oe_avatar
margin: 0 16px 0 0
- img
+ > img
height: 50px
@include radius(3px)
@include box-shadow(0 1px 3px rgba(0, 0, 0, 0.3))
@@ -432,14 +428,15 @@ $sheet-max-width: 860px
position: relative
cursor: pointer
.oe_dropdown_toggle
- color: #888
+ color: #404040
font-weight: normal
.oe_dropdown_hover:hover .oe_dropdown_menu, .oe_dropdown_menu.oe_opened
display: block
.oe_dropdown_menu
display: none
position: absolute
- top: 32px
+ top: 26px
+ left: 0
z-index: 1
border: 1px solid #afafb6
background: white
@@ -1449,7 +1446,7 @@ $sheet-max-width: 860px
label
line-height: 18px
display: block
- min-width: 120px
+ min-width: 110px
td.oe_form_group_cell + .oe_form_group_cell
padding-left: 6px
.oe_form_group
@@ -1512,9 +1509,10 @@ $sheet-max-width: 860px
width: 100%
.oe_form_field_char input,
.oe_form_field_url input,
+ .oe_form_field_email input,
.oe_form_field_text textarea,
.oe_form_field_selection select
- width: inherit
+ width: 100%
.oe_form_field_text.oe_inline, .oe_form_field_text.oe_inline > textarea
width: 500px
.oe_form_field_float input
@@ -1560,14 +1558,6 @@ $sheet-max-width: 860px
padding-left: 8px
@include box-shadow(none)
@include radius(0px)
- .oe_form_field_many2one input, .oe_form_field_binary input, .oe_form_field_binary input, .oe_form_field_url input
- border-right: none
- -webkit-border-top-right-radius: 0px
- -webkit-border-bottom-right-radius: 0px
- -moz-border-radius-topright: 0px
- -moz-border-radius-bottomright: 0px
- border-top-right-radius: 0px
- border-bottom-right-radius: 0px
.oe_form_field_url button img
vertical-align: top
.oe_form_field_date,
@@ -1618,14 +1608,25 @@ $sheet-max-width: 860px
filter: alpha(opacity=50)
right: 5px
top: 3px
- .oe_form_field_with_button
+ .oe_form_field_with_button.oe_no_button > .oe_button
+ display: none
+ .oe_form_field_with_button:not(.oe_no_button)
input
- width: 100%
+ border-right: none
+ -webkit-border-top-right-radius: 0px
+ -webkit-border-bottom-right-radius: 0px
+ -moz-border-radius-topright: 0px
+ -moz-border-radius-bottomright: 0px
+ border-top-right-radius: 0px
+ border-bottom-right-radius: 0px
> .oe_button
float: right
@include radius(0)
border-bottom-left-radius: 0px
height: 22px
+ .oe_form_field_with_button
+ input
+ width: 100%
> div
position: relative
overflow: hidden
@@ -1662,6 +1663,7 @@ $sheet-max-width: 860px
vertical-align: top
.oe_form_field_image_controls
position: absolute
+ white-space: nowrap
top: 1px
padding: 3px 0 0 0
margin: 0 1px
@@ -1680,8 +1682,8 @@ $sheet-max-width: 860px
position: relative
span.oe_m2o_drop_down_button
position: absolute
- top: 3px
- right: 2px
+ top: 1px
+ right: 0px
// }}}
// FormView.one2many {{{
.oe_form .oe_form_field_one2many > .oe_view_manager
@@ -1846,6 +1848,49 @@ $sheet-max-width: 860px
float: right
color: #333
// }}}
+//Tree view
+.openerp
+ .tree_header
+ background-color: #f0f0f0
+ border-bottom: 1px solid #cacaca
+ color: #4c4c4c
+ padding: 5px
+ height: 25px
+ button
+ float: right
+ height: 27px
+ margin-right: 5px
+ .oe-treeview-table
+ width: 100%
+ background-color: white
+ border-spacing: 0
+ th
+ padding: 10px
+ color: #4c4c4c
+ font-weight: bold
+ background-color: #f0f0f0
+ border-bottom: 2px solid #cacaca
+ .treeview-tr, .treeview-td
+ cursor: pointer
+ border-right: 1px dotted #afafb6
+ vertical-align: top
+ text-align: left
+ border-bottom: 1px solid #cfcccc
+ tr:hover
+ background-color: #e0e0f8
+ .oe-number
+ text-align: right !important
+ span
+ font-size: 90%
+ font-weight: normal
+ white-space: nowrap
+ display: block
+ .treeview-tr.oe-treeview-first
+ background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat
+ .oe_open .treeview-tr.oe-treeview-first
+ background-image: url(/web/static/src/img/collapse.gif)
+ .treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span
+ margin-left: 16px
// Kitten Mode {{{
.kitten-mode-activated
background-image: url(http://placekitten.com/g/1365/769)
@@ -1855,5 +1900,8 @@ $sheet-max-width: 860px
opacity: 0.70
// }}}
+div.ui-widget-overlay
+ background: black
+ @include opacity(0.3)
// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css"
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index b87ebe56856..c32d4feafe1 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -63,7 +63,7 @@ instance.web.Dialog = instance.web.Widget.extend({
this.dialog_options = {
modal: true,
destroy_on_close: true,
- width: $(window).width() * (($(window).width() > 1024) ? 0.5 : 0.75),
+ width: 750,
min_width: 0,
max_width: '95%',
height: 'auto',
@@ -822,8 +822,8 @@ instance.web.UserMenu = instance.web.Widget.extend({
{text: _t("Change password"), click: function(){ self.change_password(); }},
{text: _t("Cancel"), click: function(){ $(this).dialog('destroy'); }},
{text: _t("Save"), click: function(){
- var inner_viewmanager = action_manager.inner_viewmanager;
- inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save()
+ var inner_widget = action_manager.inner_widget;
+ inner_widget.views[inner_widget.active_view].controller.do_save()
.then(function() {
self.dialog.destroy();
// needs to refresh interface in case language changed
@@ -894,11 +894,12 @@ instance.web.WebClient = instance.web.Widget.extend({
});
this.$element.on('click', '.oe_dropdown_toggle', function(ev) {
ev.preventDefault();
- var $menu = $(this).find('.oe_dropdown_menu');
+ var $toggle = $(this);
+ var $menu = $toggle.find('.oe_dropdown_menu');
var state = $menu.is('.oe_opened');
setTimeout(function() {
// Do not alter propagation
- $menu.toggleClass('oe_opened', !state);
+ $toggle.add($menu).toggleClass('oe_opened', !state);
if (!state) {
// Move $menu if outside window's edge
var doc_width = $(document).width();
@@ -1036,6 +1037,7 @@ instance.web.WebClient = instance.web.Widget.extend({
if (options.needaction) {
action.context.search_default_needaction_pending = true;
}
+ self.action_manager.clear_breadcrumbs();
self.action_manager.do_action(action);
});
},
diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js
index 8733a191b21..6df78679ecb 100644
--- a/addons/web/static/src/js/view_editor.js
+++ b/addons/web/static/src/js/view_editor.js
@@ -53,7 +53,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({
this.main_view_id = this.parent.fields_view.view_id;
this.action_manager = new instance.web.ActionManager(this);
$.when(this.action_manager.do_action(action)).then(function() {
- var viewmanager = self.action_manager.inner_viewmanager,
+ var viewmanager = self.action_manager.inner_widget,
controller = viewmanager.views[viewmanager.active_view].controller;
self.action_manager.appendTo(self.view_edit_dialog.$element);
self.action_manager.renderElement(self.view_edit_dialog);
@@ -88,7 +88,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({
} else {
$.when(self.do_save_view(view_values)).then(function() {
self.create_view_dialog.close();
- var controller = self.action_manager.inner_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller;
+ var controller = self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller;
controller.reload_content();
});
}
@@ -167,7 +167,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({
do_delete_view: function() {
var self = this;
if (confirm(_t("Do you really want to remove this view?"))) {
- var controller = this.action_manager.inner_viewmanager.views[this.action_manager.inner_viewmanager.active_view].controller;
+ var controller = this.action_manager.inner_widget.views[this.action_manager.inner_widget.active_view].controller;
this.dataset.unlink([this.main_view_id]).then(function() {
controller.reload_content();
self.main_view_id = self.parent.fields_view.view_id;
@@ -397,7 +397,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({
action_manager.do_action(action);
}},
{text: _t("Close"), click: function(){
- self.action_manager.inner_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller.reload_content();
+ self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller.reload_content();
self.edit_xml_dialog.close();
}}
]
@@ -998,7 +998,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({
};
var action_manager = new instance.web.ActionManager(self);
$.when(action_manager.do_action(action)).then(function() {
- var controller = action_manager.dialog_viewmanager.views['form'].controller;
+ var controller = action_manager.dialog_widget.views['form'].controller;
controller.on_button_cancel.add_last(function(){
action_manager.destroy()
});
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 4d00db6ccea..a90654b2cf5 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -287,10 +287,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
on_record_loaded: function(record) {
var self = this, set_values = [];
if (!record) {
+ this.set({ 'title' : undefined });
this.do_warn("Form", "The record could not be found in the database.", true);
return $.Deferred().reject();
}
this.datarecord = record;
+ this.set({ 'title' : record.id ? record.name : "New record" });
if (this.qweb) {
this.kill_current_form();
@@ -2609,7 +2611,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
});
// some behavior for input
- this.$input.keyup(function() {
+ this.$input.keydown(function() {
if (self.current_display !== self.$input.val()) {
self.current_display = self.$input.val();
if (self.$input.val() === "") {
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
index e8bd7351f1f..2181b2aa157 100644
--- a/addons/web/static/src/js/view_tree.js
+++ b/addons/web/static/src/js/view_tree.js
@@ -63,6 +63,12 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
}
return fields;
},
+ store_record:function(records){
+ var self = this;
+ _(records).each(function (record) {
+ self.records[record.id] = record;
+ });
+ },
on_loaded: function (fields_view) {
var self = this;
var has_toolbar = !!fields_view.arch.attrs.toolbar;
@@ -87,17 +93,19 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
this.$element.addClass(this.fields_view.arch.attrs['class']);
this.dataset.read_slice(this.fields_list()).then(function(records) {
+ self.store_record(records);
if (!has_toolbar) {
// WARNING: will do a second read on the same ids, but only on
// first load so not very important
- self.getdata(null, _(records).pluck('id'));
+ self.render_data({'null':records})
+ self.getdata(_.pluck(records,"id"));
return;
}
var $select = self.$element.find('select')
.change(function () {
var $option = $(this).find(':selected');
- self.getdata($option.val(), $option.data('children'));
+ self.getdata($option.val());
});
_(records).each(function (record) {
self.records[record.id] = record;
@@ -112,7 +120,12 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
$select.change();
}
});
-
+ this.$element.find("#tree_view_expand").click(function(){
+ self.expand_all();
+ });
+ this.$element.find("#tree_view_collapse").click(function(){
+ self.collpase_all();
+ });
// TODO store open nodes in url ?...
this.do_push_state({});
@@ -128,6 +141,22 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
return [color, py.parse(py.tokenize(expr)), expr];
}).value();
},
+ expand_all: function(){
+ var self = this;
+ var tr = this.$element.find(".oe-treeview-table tbody tr[id^='treerow_']");
+ _.each(tr,function(rec){
+ self.showcontent($(rec).attr('data-id'),true);
+ });
+ },
+ collpase_all: function(){
+ var self = this;
+ var root_tr = this.$element.find(".oe-treeview-table tbody tr[data-level='"+1+"']");
+ _.each(root_tr,function(rec){
+ if($(rec).hasClass('oe_open')){
+ self.showcontent($(rec).attr('data-id'),false);
+ }
+ });
+ },
/**
* Returns the color for the provided record in the current view (from the
* ``@colors`` attribute)
@@ -164,50 +193,44 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
});
this.$element.delegate('.treeview-tr', 'click', function () {
- var is_loaded = 0,
- $this = $(this),
+ var $this = $(this),
record_id = $this.data('id'),
- record = self.records[record_id],
- children_ids = record[self.children_field];
-
- _(children_ids).each(function(childid) {
- if (self.$element.find('#treerow_' + childid).length) {
- if (self.$element.find('#treerow_' + childid).is(':hidden')) {
- is_loaded = -1;
- } else {
- is_loaded++;
- }
- }
- });
- if (is_loaded === 0) {
- if (!$this.parent().hasClass('oe_open')) {
- self.getdata(record_id, children_ids);
- }
- } else {
- self.showcontent(record_id, is_loaded < 0);
- }
+ bool = $this.parent().hasClass('oe_open');
+ self.showcontent(record_id, !bool);
});
},
// get child data of selected value
- getdata: function (id, children_ids) {
+ getdata: function (id) {
var self = this;
-
- self.dataset.read_ids(children_ids, this.fields_list()).then(function(records) {
- _(records).each(function (record) {
- self.records[record.id] = record;
- });
-
- var $curr_node = self.$element.find('#treerow_' + id);
+ var parent_child ={};
+ id = _.isArray(id)?id:parseInt(id);
+ var ir_model_data = new instance.web.Model(this.model,self.dataset.get_context() || {},[['id','child_of',id]]).query();
+ ir_model_data._execute().then(function(records){
+ self.store_record(records);
+ _.each(records,function(rec){
+ if(rec[self.children_field].length === 0)return;
+ parent_child[rec.id] = [];
+ _.each(rec[self.children_field],function(key){
+ parent_child[rec.id].push(self.records[key]);
+ });
+ })
+ self.render_data(parent_child);
+ });
+ },
+ render_data: function(groupby){
+ var self = this;
+ _.each(_.keys(groupby),function(key){
+ var $curr_node = self.$element.find('#treerow_' + key);
+ var record = groupby[key];
var children_rows = QWeb.render('TreeView.rows', {
- 'records': records,
+ 'records': record,
'children_field': self.children_field,
'fields_view': self.fields_view.arch.children,
'fields': self.fields,
- 'level': $curr_node.data('level') || 0,
+ 'level': ($curr_node.data('level') || 0) + 1,
'render': instance.web.format_value,
'color_for': self.color_for
});
-
if ($curr_node.length) {
$curr_node.addClass('oe_open');
$curr_node.after(children_rows);
@@ -215,8 +238,10 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
self.$element.find('tbody').html(children_rows);
}
});
+ self.collpase_all();
},
+
// Get details in listview
activate: function(id) {
var self = this;
@@ -259,13 +284,5 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
}, this);
},
- do_show: function () {
- this.$element.show();
- },
-
- do_hide: function () {
- this.$element.hide();
- this.hidden = true;
- }
});
};
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 98df8a0af0d..423bf3f9d46 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -10,28 +10,111 @@ instance.web.ActionManager = instance.web.Widget.extend({
init: function(parent) {
this._super(parent);
this.inner_action = null;
- this.inner_viewmanager = null;
+ this.inner_widget = null;
this.dialog = null;
- this.dialog_viewmanager = null;
- this.client_widget = null;
+ this.dialog_widget = null;
+ this.breadcrumbs = [];
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.on('click', '.oe_breadcrumb_item', this.on_breadcrumb_clicked);
},
dialog_stop: function () {
if (this.dialog) {
- this.dialog_viewmanager.destroy();
- this.dialog_viewmanager = null;
+ this.dialog_widget.destroy();
+ this.dialog_widget = null;
this.dialog.destroy();
this.dialog = null;
}
},
- content_stop: function () {
- if (this.inner_viewmanager) {
- this.inner_viewmanager.destroy();
- this.inner_viewmanager = null;
+ /**
+ * Add a new item to the breadcrumb
+ *
+ * If the title of an item is an array, the multiple title mode is in use.
+ * (eg: a widget with multiple views might need to display a title for each view)
+ * In multiple title mode, the show() callback can check the index it receives
+ * in order to detect which of its titles has been clicked on by the user.
+ *
+ * @param {Object} item breadcrumb item
+ * @param {Object} item.widget widget containing the view(s) to be added to the breadcrumb added
+ * @param {Function} [item.show] triggered whenever the widget should be shown back
+ * @param {Function} [item.hide] triggered whenever the widget should be shown hidden
+ * @param {Function} [item.destroy] triggered whenever the widget should be destroyed
+ * @param {String|Array} [item.title] title(s) of the view(s) to be displayed in the breadcrumb
+ * @param {Function} [item.get_title] should return the title(s) of the view(s) to be displayed in the breadcrumb
+ */
+ push_breadcrumb: function(item) {
+ var last = this.breadcrumbs.slice(-1)[0];
+ if (last) {
+ last.hide();
+ }
+ var item = _.extend({
+ show: function(index) {
+ this.widget.$element.show();
+ },
+ hide: function() {
+ this.widget.$element.hide();
+ },
+ destroy: function() {
+ this.widget.destroy();
+ },
+ get_title: function() {
+ return this.title || this.widget.get('title');
+ }
+ }, item);
+ item.id = _.uniqueId('breadcrumb_');
+ this.breadcrumbs.push(item);
+ },
+ on_breadcrumb_clicked: function(ev) {
+ var $e = $(ev.target);
+ var id = $e.data('id');
+ var item;
+ for (var i = this.breadcrumbs.length - 1; i >= 0; i--) {
+ var it = this.breadcrumbs[i];
+ if (it.id == id) {
+ item = it;
+ break;
+ }
+ this.remove_breadcrumb(i);
+ }
+ var index = $e.parent().find('.oe_breadcrumb_item[data-id=' + $e.data('id') + ']').index($e);
+ item.show(index, $e);
+ this.inner_widget = item.widget;
+ },
+ clear_breadcrumbs: function() {
+ while (this.breadcrumbs.length) {
+ this.remove_breadcrumb(0);
+ }
+ },
+ remove_breadcrumb: function(index) {
+ var item = this.breadcrumbs.splice(index, 1)[0];
+ if (item) {
+ var dups = _.filter(this.breadcrumbs, function(it) {
+ return item.widget === it.widget;
+ });
+ if (!dups.length) {
+ item.destroy();
+ }
}
- if (this.client_widget) {
- this.client_widget.destroy();
- this.client_widget = null;
+ },
+ get_title: function() {
+ var titles = [];
+ for (var i = 0; i < this.breadcrumbs.length; i += 1) {
+ var item = this.breadcrumbs[i];
+ var tit = item.get_title();
+ if (!_.isArray(tit)) {
+ tit = [tit];
+ }
+ for (var j = 0; j < tit.length; j += 1) {
+ var label = _.escape(tit[j]);
+ if (i === this.breadcrumbs.length - 1 && j === tit.length - 1) {
+ titles.push(label);
+ } else {
+ titles.push(_.str.sprintf('<a href="#" class="oe_breadcrumb_item" data-id="%s">%s</a>', item.id, label));
+ }
+ }
}
+ return titles.join(' / ');
},
do_push_state: function(state) {
if (this.getParent() && this.getParent().do_push_state) {
@@ -49,7 +132,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
var self = this,
action_loaded;
if (state.action_id) {
- var run_action = (!this.inner_viewmanager) || this.inner_viewmanager.action.id !== state.action_id;
+ var run_action = (!this.inner_widget || !this.inner_widget.action) || this.inner_widget.action.id !== state.action_id;
if (run_action) {
this.null_action();
action_loaded = this.do_action(state.action_id);
@@ -89,8 +172,8 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
$.when(action_loaded || null).then(function() {
- if (self.inner_viewmanager) {
- self.inner_viewmanager.do_load_state(state, warm);
+ if (self.inner_widget && self.inner_widget.do_load_state) {
+ self.inner_widget.do_load_state(state, warm);
}
});
},
@@ -124,7 +207,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
},
null_action: function() {
this.dialog_stop();
- this.content_stop();
+ this.clear_breadcrumbs();
},
ir_actions_act_window: function (action, on_close) {
var self = this;
@@ -141,25 +224,23 @@ instance.web.ActionManager = instance.web.Widget.extend({
if(on_close)
this.dialog.on_close.add(on_close);
} else {
- this.dialog_viewmanager.destroy();
+ this.dialog_widget.destroy();
}
this.dialog.dialog_title = action.name;
- this.dialog_viewmanager = new instance.web.ViewManagerAction(this.dialog, action);
- this.dialog_viewmanager.appendTo(this.dialog.$element);
- this.dialog_viewmanager.$element.addClass("oe_view_manager_" + action.target);
+ this.dialog_widget = new instance.web.ViewManagerAction(this, action);
+ this.dialog_widget.appendTo(this.dialog.$element);
this.dialog.open();
} else {
this.dialog_stop();
- this.content_stop();
if(action.menu_id) {
return this.getParent().do_action(action, function () {
instance.webclient.menu.open_menu(action.menu_id);
});
}
this.inner_action = action;
- this.inner_viewmanager = new instance.web.ViewManagerAction(this, action);
- this.inner_viewmanager.appendTo(this.$element);
- this.inner_viewmanager.$element.addClass("oe_view_manager_" + action.target);
+ var inner_widget = this.inner_widget = new instance.web.ViewManagerAction(this, action);
+ inner_widget.add_breadcrumb();
+ this.inner_widget.appendTo(this.$element);
}
},
ir_actions_act_window_close: function (action, on_closed) {
@@ -178,10 +259,14 @@ instance.web.ActionManager = instance.web.Widget.extend({
});
},
ir_actions_client: function (action) {
- this.content_stop();
this.dialog_stop();
var ClientWidget = instance.web.client_actions.get_object(action.tag);
- (this.client_widget = new ClientWidget(this, action.params)).appendTo(this.$element);
+ this.inner_widget = new ClientWidget(this, action.params);
+ this.push_breadcrumb({
+ widget: this.inner_widget,
+ title: action.name
+ });
+ this.inner_widget.appendTo(this.$element);
},
ir_actions_report_xml: function(action, on_closed) {
var self = this;
@@ -290,35 +375,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
this.active_view = view_type;
if (!view.controller) {
- // Lazy loading of views
- var controllerclass = this.registry.get_object(view_type);
- var options = _.clone(view.options);
- if (view_type === "form" && this.action) {
- switch (this.action.target) {
- case 'new':
- case 'inline':
- options.initial_mode = 'edit';
- break;
- }
- }
- var controller = new controllerclass(this, this.dataset, view.view_id, options);
- if (view.embedded_view) {
- controller.set_embedded_view(view.embedded_view);
- }
- controller.do_switch_view.add_last(_.bind(this.switch_view, this));
- controller.do_prev_view.add_last(this.on_prev_view);
- var container = this.$element.find(".oe_view_manager_view_" + view_type);
- view_promise = controller.appendTo(container);
- this.views[view_type].controller = controller;
- this.views[view_type].deferred.resolve(view_type);
- $.when(view_promise).then(function() {
- self.on_controller_inited(view_type, controller);
- if (self.searchview
- && self.flags.auto_search
- && view.controller.searchable !== false) {
- self.searchview.ready.then(self.searchview.do_search);
- }
- });
+ view_promise = this.do_create_view(view_type);
} else if (this.searchview
&& self.flags.auto_search
&& view.controller.searchable !== false) {
@@ -349,12 +406,81 @@ instance.web.ViewManager = instance.web.Widget.extend({
}
}
});
-
- self.$element.find('.oe_view_title_text:first').text(
- self.display_title());
});
return view_promise;
},
+ do_create_view: function(view_type) {
+ // Lazy loading of views
+ var self = this;
+ var view = this.views[view_type];
+ var controllerclass = this.registry.get_object(view_type);
+ var options = _.clone(view.options);
+ if (view_type === "form" && this.action) {
+ switch (this.action.target) {
+ case 'new':
+ case 'inline':
+ options.initial_mode = 'edit';
+ break;
+ }
+ }
+ var controller = new controllerclass(this, this.dataset, view.view_id, options);
+
+ controller.on("change:title", this, function() {
+ if (self.active_view === view_type) {
+ self.set_title(controller.get('title'));
+ }
+ });
+
+ if (view.embedded_view) {
+ controller.set_embedded_view(view.embedded_view);
+ }
+ controller.do_switch_view.add_last(_.bind(this.switch_view, this));
+
+ controller.do_prev_view.add_last(this.on_prev_view);
+ var container = this.$element.find(".oe_view_manager_view_" + view_type);
+ var view_promise = controller.appendTo(container);
+ this.views[view_type].controller = controller;
+ this.views[view_type].deferred.resolve(view_type);
+ return $.when(view_promise).then(function() {
+ self.on_controller_inited(view_type, controller);
+ if (self.searchview
+ && self.flags.auto_search
+ && view.controller.searchable !== false) {
+ self.searchview.ready.then(self.searchview.do_search);
+ }
+ });
+ },
+ set_title: function(title) {
+ this.$element.find('.oe_view_title_text:first').text(title);
+ },
+ add_breadcrumb: function() {
+ var self = this;
+ var views = [this.active_view || this.views_src[0].view_type];
+ this.on_mode_switch.add(function(mode) {
+ var last = views.slice(-1)[0];
+ if (mode !== last) {
+ if (mode !== 'form') {
+ views.length = 0;
+ }
+ views.push(mode);
+ }
+ });
+ this.getParent().push_breadcrumb({
+ widget: this,
+ show: function(index, $e) {
+ var view_to_select = views[index];
+ self.$element.show();
+ if (self.active_view !== view_to_select) {
+ self.on_mode_switch(view_to_select);
+ }
+ },
+ get_title: function() {
+ return _.map(views, function(v) {
+ return self.views[v].controller.get('title');
+ });
+ }
+ });
+ },
/**
* Method used internally when a view asks to switch view. This method is meant
* to be extended by child classes to change the default behavior, which simply
@@ -447,14 +573,6 @@ instance.web.ViewManager = instance.web.Widget.extend({
*/
on_action_executed: function () {
},
- display_title: function () {
- var view = this.views[this.active_view];
- if (view) {
- // ick
- return view.controller.fields_view.arch.attrs.string;
- }
- return '';
- }
});
instance.web.ViewManagerAction = instance.web.ViewManager.extend({
@@ -499,7 +617,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
if (this.session.hidden_menutips) {
return;
}
- this.session.hidden_menutips = {}
+ this.session.hidden_menutips = {};
},
/**
* Initializes the ViewManagerAction: sets up the searchview (if the
@@ -527,6 +645,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
var manager_ready = $.when(searchview_loaded, main_view_loaded);
this.$element.find('.oe_debug_view').change(this.on_debug_changed);
+ this.$element.addClass("oe_view_manager_" + (this.action.target || 'current'));
if (this.action.help && !this.flags.low_profile) {
var Users = new instance.web.DataSet(self, 'res.users'),
@@ -675,12 +794,18 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
view: controller,
view_manager: self
}));
- if (!self.action.name && fvg) {
- self.$element.find('.oe_view_title_text').text(fvg.arch.attrs.string || fvg.name);
- }
-
+ self.set_title();
});
},
+ do_create_view: function(view_type) {
+ var r = this._super.apply(this, arguments);
+ var view = this.views[view_type].controller;
+ view.set({ 'title': this.action.name });
+ return r;
+ },
+ set_title: function(title) {
+ this.$element.find('.oe_breadcrumb_title:first').html(this.getParent().get_title());
+ },
do_push_state: function(state) {
if (this.getParent() && this.getParent().do_push_state) {
state["view_type"] = this.active_view;
@@ -702,9 +827,6 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
self.views[self.active_view].controller.do_load_state(state, warm);
});
},
- display_title: function () {
- return this.action.name;
- }
});
instance.web.Sidebar = instance.web.Widget.extend({
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 29a7a61aa30..eb3f367ae8c 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -399,16 +399,17 @@
<t t-name="ViewManager">
<div class="oe_view_manager">
<table class="oe_view_manager_header">
- <col width="33%"/>
- <col width="33%"/>
- <col width="34%"/>
+ <col width="25%"/>
+ <col width="25%"/>
+ <col width="25%"/>
+ <col width="25%"/>
<tr class="oe_header_row oe_header_row_top">
<td colspan="2">
<h2 class="oe_view_title" t-if="widget.flags.display_title !== false">
- <span class="oe_view_title_text"><t t-esc="widget.display_title()"/></span>
+ <span class="oe_view_title_text oe_breadcrumb_title"/>
</h2>
</td>
- <td>
+ <td colspan="2">
<div class="oe_view_manager_view_search" t-opentag="true"/>
</td>
</tr>
@@ -416,7 +417,7 @@
<td>
<div class="oe_view_manager_buttons"/>
</td>
- <td>
+ <td colspan="2">
<div class="oe_view_manager_sidebar"/>
</td>
<td>
@@ -535,14 +536,16 @@
</t>
<t t-name="TreeView">
- <select t-if="toolbar" style="width: 30%">
- </select>
- <table class="oe_tree_table">
+ <div class = "tree_header">
+ <select t-if="toolbar" ></select>
+ <button id = "tree_view_collapse">Collapse All</button>
+ <button id = "tree_view_expand">Expand All</button>
+ </div>
+ <table class="oe-treeview-table">
<thead>
<tr>
<th t-foreach="fields_view" t-as="field"
- t-if="!field.attrs.modifiers.tree_invisible"
- class="treeview-header">
+ t-if="!field.attrs.modifiers.tree_invisible">
<t t-esc="fields[field.attrs.name].string" />
</th>
</tr>
@@ -554,11 +557,11 @@
<tr t-name="TreeView.rows"
t-foreach="records" t-as="record"
t-att-id="'treerow_' + record.id"
- t-att-data-id="record.id" t-att-data-level="level + 1">
+ t-att-data-id="record.id" t-att-data-level="level">
<t t-set="children" t-value="record[children_field]"/>
<t t-set="class" t-value="children and children.length ? 'treeview-tr' : 'treeview-td'"/>
- <t t-set="rank" t-value="'oe_tree_first'"/>
- <t t-set="style" t-value="'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;'"/>
+ <t t-set="rank" t-value="'oe-treeview-first'"/>
+ <t t-set="style" t-value="'background-position: ' + 19*(level-1) + 'px; padding-left: ' + 19*(level-1) + 'px;'"/>
<td t-foreach="fields_view" t-as="field"
t-if="!field.attrs.modifiers.tree_invisible"
@@ -863,7 +866,7 @@
</ul>
</t>
<t t-name="FieldChar">
- <span t-att-class="'oe_form_field '+widget.widget_class">
+ <span t-att-class="'oe_form_field '+widget.widget_class" t-att-style="widget.node.attrs.style">
<t t-if="!widget.get('effective_readonly')">
<input t-att-type="widget.password ? 'password' : 'text'"
t-att-id="widget.id_for_label"
@@ -875,7 +878,7 @@
</span>
</t>
<t t-name="FieldEmail">
- <span class="oe_form_field oe_form_field_email oe_form_field_with_button">
+ <span class="oe_form_field oe_form_field_email" t-att-style="widget.node.attrs.style">
<a t-if="widget.get('effective_readonly')" href="#" class="oe_form_uri" target="_blank"/>
<t t-if="!widget.get('effective_readonly')">
<div>
@@ -893,14 +896,9 @@
<t t-jquery="span:first">
this.removeClass('oe_form_field_email').addClass('oe_form_field_url');
</t>
- <t t-jquery="button.oe_button" t-operation="replace">
- <button class="oe_button" tabindex="-1" type="button" title="Open this resource">
- <img t-att-src='_s + "/web/static/src/img/icons/gtk-ok.png"'/>
- </button>
- </t>
</t>
<t t-name="FieldText">
- <div class="oe_form_field oe_form_field_text">
+ <div class="oe_form_field oe_form_field_text" t-att-style="widget.node.attrs.style">
<textarea rows="6"
t-att-name="widget.name"
class="field_text"
@@ -925,13 +923,13 @@
</span>
</t>
<t t-name="FieldDate">
- <span class="oe_form_field oe_datepicker_root oe_form_field_date"/>
+ <span class="oe_form_field oe_datepicker_root oe_form_field_date" t-att-style="widget.node.attrs.style"/>
</t>
<t t-name="FieldDatetime">
- <span class="oe_form_field oe_datepicker_root oe_form_field_datetime"/>
+ <span class="oe_form_field oe_datepicker_root oe_form_field_datetime" t-att-style="widget.node.attrs.style"/>
</t>
<t t-name="FieldSelection">
- <span class="oe_form_field oe_form_field_selection">
+ <span class="oe_form_field oe_form_field_selection" t-att-style="widget.node.attrs.style">
<select t-if="!widget.get('effective_readonly')"
t-att-name="widget.name"
t-att-tabindex="widget.node.attrs.tabindex"
@@ -944,7 +942,7 @@
</span>
</t>
<t t-name="FieldMany2One">
- <span class="oe_form_field oe_form_field_many2one oe_form_field_with_button">
+ <span class="oe_form_field oe_form_field_many2one oe_form_field_with_button" t-att-style="widget.node.attrs.style">
<a t-if="widget.get('effective_readonly')" href="#" class="oe_form_uri"/>
<t t-if="!widget.get('effective_readonly')">
<button class="oe_button oe_m2o_cm_button" title="Open Resource">
@@ -965,7 +963,7 @@
</span>
</t>
<t t-name="FieldMany2ManyTags">
- <div class="oe_form_field oe_form_field_many2manytags">
+ <div class="oe_form_field oe_form_field_many2manytags" t-att-style="widget.node.attrs.style">
<t t-if="! widget.get('effective_readonly')">
<textarea rows="1" style="width: 100%"
t-att-placeholder="widget.node.attrs.placeholder"></textarea>
@@ -982,7 +980,7 @@
</t>
</t>
<t t-name="FieldReference">
- <table class="oe_form_field oe_form_field_reference" border="0" cellpadding="0" cellspacing="0">
+ <table class="oe_form_field oe_form_field_reference" border="0" cellpadding="0" cellspacing="0" t-att-style="widget.node.attrs.style">
<tr>
<td t-attf-class="oe_form_frame_cell oe_form_selection">
<span t-attf-class="oe_form_view_reference_selection"/>
@@ -994,7 +992,7 @@
</table>
</t>
<t t-name="FieldBoolean">
- <span class="oe_form_field oe_form_field_boolean">
+ <span class="oe_form_field oe_form_field_boolean" t-att-style="widget.node.attrs.style">
<input type="checkbox"
t-att-id="widget.id_for_label"
t-att-name="widget.name"
@@ -1004,12 +1002,12 @@
</span>
</t>
<t t-name="FieldProgressBar">
- <span class="oe_form_field oe_form_field_progressbar" t-opentag="true">
+ <span class="oe_form_field oe_form_field_progressbar" t-att-style="widget.node.attrs.style">
<span></span>
</span>
</t>
<t t-name="FieldStatus">
- <ul class="oe_form_steps"/>
+ <ul class="oe_form_steps" t-att-style="widget.node.attrs.style"/>
</t>
<t t-name="FieldStatus.content">
<t t-set="size" t-value="widget.to_show.length"/>
@@ -1021,7 +1019,7 @@
</t>
</t>
<t t-name="FieldBinaryImage">
- <span class="oe_form_field oe_form_field_image">
+ <span class="oe_form_field oe_form_field_image" t-att-style="widget.node.attrs.style">
<div class="oe_form_field_image_controls oe_edit_only">
<t t-call="HiddenInputFile">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
@@ -1049,7 +1047,7 @@
</t>
<t t-name="FieldBinaryFile">
<t t-if="!widget.get('effective_readonly')">
- <table class="oe_form_field oe_form_field_binary" cellpadding="0" cellspacing="0" border="0">
+ <table class="oe_form_field oe_form_field_binary" cellpadding="0" cellspacing="0" border="0" t-att-style="widget.node.attrs.style">
<tr>
<td>
<input type="text" size="1" readonly="readonly"
@@ -1097,7 +1095,7 @@
</table>
</t>
<t t-if="widget.get('effective_readonly')">
- <span>
+ <span t-att-style="widget.node.attrs.style">
<a href="javascript:void(0)" class="oe_form_uri"/>
</span>
</t>
@@ -1116,6 +1114,7 @@
</t>
<t t-name="WidgetButton">
<button type="button" class="oe_button oe_form_button"
+ t-att-style="widget.node.attrs.style"
t-att-tabindex="widget.node.attrs.tabindex"
t-att-autofocus="widget.node.attrs.autofocus">
<img t-if="widget.node.attrs.icon" t-att-src="_s + '/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/>
@@ -1471,11 +1470,11 @@
</t>
<t t-name="AbstractFormPopup.buttons">
<t t-if="! multi_select">
- <button type="button" class="oe_button oe_abstractformpopup-form-save">Save</button>
+ <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save</button>
</t>
<t t-if="multi_select">
- <button type="button" class="oe_button oe_abstractformpopup-form-save-new">Save &amp; New</button>
- <button type="button" class="oe_button oe_abstractformpopup-form-save">Save &amp; Close</button>
+ <button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save &amp; New</button>
+ <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save &amp; Close</button>
</t>
<button type="button" class="oe_button oe_abstractformpopup-form-close">Cancel</button>
</t>