diff options
| author | Turkesh Patel (Open ERP) <tpa@tinyerp.com> | 2012-07-13 16:18:23 +0530 |
|---|---|---|
| committer | Turkesh Patel (Open ERP) <tpa@tinyerp.com> | 2012-07-13 16:18:23 +0530 |
| commit | 6c4117faab165cbfe96f71c7632b683828dcdfbc (patch) | |
| tree | 91cae8ec8fb16d258d1bc05b29fd8960f6c3f93c /addons/web/static/src | |
| parent | 0d4bd736e1bd8c8acb78f63e190111b1c72b05af (diff) | |
| parent | b65c05a58195c70156a658a7cad26ee08857db80 (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.css | 118 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.sass | 98 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 12 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_editor.js | 10 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_tree.js | 103 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 270 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 73 |
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 & New</button> - <button type="button" class="oe_button oe_abstractformpopup-form-save">Save & Close</button> + <button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save & New</button> + <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save & Close</button> </t> <button type="button" class="oe_button oe_abstractformpopup-form-close">Cancel</button> </t> |
