diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 234d765d5c7..14b8d4391c2 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1916,7 +1916,7 @@ class Reports(View): report = zlib.decompress(report) report_mimetype = self.TYPES_MAPPING.get( report_struct['format'], 'octet-stream') - file_name = None + file_name = action.get('name', 'report') if 'name' not in action: reports = req.session.model('ir.actions.report.xml') res_id = reports.search([('report_name', '=', action['report_name']),], diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js index c9b065ee69f..71a9628eff2 100644 --- a/addons/web/static/lib/qweb/qweb2.js +++ b/addons/web/static/lib/qweb/qweb2.js @@ -4,7 +4,7 @@ // TODO: t-set + t-value + children node == scoped variable ? var QWeb2 = { expressions_cache: {}, - RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,in,instanceof,new,function,return,this,typeof,eval,void,Math,RegExp,Array,Object,Date'.split(','), + RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,typeof,eval,void,Math,RegExp,Array,Object,Date'.split(','), ACTIONS_PRECEDENCE: 'foreach,if,call,set,esc,escf,raw,rawf,js,debug,log'.split(','), WORD_REPLACEMENT: { 'and': '&&', diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 16861a7853f..1ec0d534607 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -25,12 +25,16 @@ display: none !important; } } - .openerp.openerp_webclient_container { height: 100%; position: relative; } +.text-tag .text-button { + height: auto !important; + min-height: 16px; +} + .openerp { padding: 0; margin: 0; @@ -41,7 +45,7 @@ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5); /* http://www.quirksmode.org/dom/inputfile.html * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image - */ */ + */ } .openerp :-moz-placeholder { color: #afafb6 !important; @@ -53,6 +57,7 @@ } .openerp a { text-decoration: none; + cursor: pointer !important; } .openerp table { padding: 0; @@ -114,7 +119,7 @@ } .openerp a.button:link, .openerp a.button:visited, .openerp button, .openerp input[type='submit'], .openerp .ui-dialog-buttonpane .ui-dialog-buttonset .ui-button { display: inline-block; - border: 1px solid #ababab; + border: 1px solid rgba(0, 0, 0, 0.4); color: #4c4c4c; margin: 0; padding: 3px 12px; @@ -372,7 +377,6 @@ background: #dc5f59; } .openerp button.oe_highlight { - border: 1px solid #795151; background-color: #df3f3f; background-image: -webkit-gradient(linear, left top, left bottom, from(#df3f3f), to(#a21a1a)); background-image: -webkit-linear-gradient(top, #df3f3f, #a21a1a); @@ -542,6 +546,11 @@ font-style: italic; text-decoration: none; } +.openerp .oe_form header .oe_tags { + margin: 5px 0 0 5px; + width: 400px; + padding-bottom: 0; +} .openerp.oe_tooltip { font-size: 12px; } @@ -644,7 +653,7 @@ cursor: pointer; } .openerp .oe_dropdown_toggle { - color: #404040; + color: rgba(0, 0, 0, 0.5); font-weight: normal; } .openerp .oe_dropdown_hover:hover .oe_dropdown_menu, .openerp .oe_dropdown_menu.oe_opened { @@ -655,7 +664,7 @@ position: absolute; top: 26px; left: 0; - z-index: 1; + z-index: 3; margin: 0; padding: 0; border: 1px solid #afafb6; @@ -1081,6 +1090,48 @@ .openerp .oe_user_menu .oe_dropdown_menu { right: -1px; } +.openerp .oe_about { + background-color: white; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=); + -moz-border-radius: 0 0 2px 2px; + -webkit-border-radius: 0 0 2px 2px; + border-radius: 0 0 2px 2px; +} +.openerp .oe_about a { + color: #7c7bad; +} +.openerp .oe_about a:hover { + text-decoration: underline; +} +.openerp .oe_about a:focus { + outline: none; +} +.openerp .oe_about .oe_logo { + margin-left: -6px; +} +.openerp .oe_about .oe_bottom { + position: absolute; + top: 50%; + left: 0; + right: 0; + bottom: 0; + text-shadow: 0 1px 1px #999999; + background-color: #b41616; + background-image: -webkit-gradient(linear, left top, left bottom, from(#b41616), to(#600606)); + background-image: -webkit-linear-gradient(top, #b41616, #600606); + background-image: -moz-linear-gradient(top, #b41616, #600606); + background-image: -ms-linear-gradient(top, #b41616, #600606); + background-image: -o-linear-gradient(top, #b41616, #600606); + background-image: linear-gradient(to bottom, #b41616, #600606); + color: #eeeeee; + padding: 0 16px; + -moz-border-radius: 0 0 2px 2px; + -webkit-border-radius: 0 0 2px 2px; + border-radius: 0 0 2px 2px; +} +.openerp .oe_about .oe_bottom a { + color: #eeeeee; +} .openerp .oe_systray > div { float: left; padding: 0 4px 0 4px; @@ -1154,7 +1205,7 @@ color: white; padding: 2px 4px; margin: 1px 6px 0 0; - border: 1px solid lightGray; + border: 1px solid lightgrey; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -moz-border-radius: 4px; -webkit-border-radius: 4px; @@ -1179,7 +1230,7 @@ transform: scale(1.1); } .openerp .oe_secondary_submenu .oe_active { - border-top: 1px solid lightGray; + border-top: 1px solid lightgrey; border-bottom: 1px solid #dedede; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 -1px 3px rgba(40, 40, 40, 0.2); @@ -1521,6 +1572,7 @@ font-size: 1px; letter-spacing: -1px; color: transparent; + font-weight: normal; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; @@ -1914,10 +1966,10 @@ } .openerp .oe_form_nosheet > header { margin: -16px -16px 0 -16px; - padding: 8px; + padding: 0; } .openerp .oe_form_sheetbg { - padding: 8px 0; + padding: 16px 0; } .openerp .oe_form_sheet_width { min-width: 650px; @@ -1934,10 +1986,10 @@ border-bottom: 1px solid #dddddd; } .openerp .oe_application .oe_form_sheet { - border: 1px solid #afafb6; - -moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); - box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + border: 1px solid #c8c8d3; + -moz-box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); + -webkit-box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); } .openerp .oe_application .oe_form_sheet .ui-tabs { margin: 0 -16px; @@ -1957,6 +2009,9 @@ background-image: -o-linear-gradient(top, #fcfcfc, #dedede); background-image: linear-gradient(to bottom, #fcfcfc, #dedede); } +.openerp .oe_form header > span { + margin-left: 4px; +} .openerp .oe_form header ul { display: inline-block; float: right; @@ -2001,6 +2056,8 @@ .openerp .oe_form .oe_subtotal_footer .oe_subtotal_footer_separator { width: 108px; border-top: 1px solid #cacaca; + margin-top: 4px; + padding-top: 4px; font-weight: bold; font-size: 18px; } @@ -2043,7 +2100,7 @@ } .openerp .oe_form .oe_form_label_help[for] span, .openerp .oe_form .oe_form_label[for] span { font-size: 80%; - color: darkGreen; + color: darkgreen; vertical-align: top; position: relative; top: -4px; @@ -2202,6 +2259,14 @@ position: relative; overflow: hidden; } +.openerp .oe_form .oe_form_field_html { + position: relative; + width: 600px; + margin-left: 130px; + margin-top: 32px; + margin-bottom: 32px; + text-align: justify; +} .openerp .oe_form_editable .oe_form .oe_form_field_integer { width: 6em !important; } @@ -2214,6 +2279,9 @@ .openerp .oe_form_editable .oe_form .oe_form_field_datetime { width: 11.5em !important; } +.openerp .oe_hidden_input_file { + position: relative; +} .openerp .oe_hidden_input_file input.oe_form_binary_file { z-index: 0; line-height: 0; @@ -2283,7 +2351,7 @@ .openerp ul.oe_form_status li, .openerp ul.oe_form_status_clickable li { display: inline-block; list-style-type: none; - margin: 0 -20px 0 0; + margin: 0 -18px 0 0; padding: 0; background-color: #fcfcfc; background-image: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede)); @@ -2479,6 +2547,7 @@ } .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_float input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_view_integer input { text-align: right; + width: 100%; } .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime > span, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date > span { width: 100%; @@ -2638,20 +2707,24 @@ } .openerp .oe_list_content td.oe_list_field_handle { width: 1em; + padding: 0 !important; cursor: ns-resize; } .openerp .oe_list_content td.oe_list_field_handle .oe_list_handle { font-size: 1px; letter-spacing: -1px; color: transparent; + font-weight: normal; + margin-right: 7px; } .openerp .oe_list_content td.oe_list_field_handle .oe_list_handle:before { - font: 21px "mnmliconsRegular"; - content: "ö"; - color: #404040; + font: 18px "entypoRegular"; + content: "}"; + color: #e0e0e0; } .openerp .oe_list_cannot_edit .oe_list_header_handle, .openerp .oe_list_cannot_edit .oe_list_field_handle { display: none !important; + padding: 0 !important; } .openerp .oe_list_cannot_delete .oe_list_record_delete { display: none !important; @@ -2708,9 +2781,6 @@ .openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span { margin-left: 16px; } -.openerp .oe_trad_field.touched { - border: 1px solid green !important; -} .openerp .oe_layout_debugging .oe_form_group { outline: 2px dashed green; } diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index e3cb661d580..fc65f260db9 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -113,17 +113,29 @@ $sheet-max-width: 860px @keyframes #{$name} @content + // Transforms the (readable) text of an inline element into an mmlicons icon, // allows for actual readable text in-code (and in readers?) with iconic looks @mixin text-to-icon($icon-name, $color: #404040) font-size: 1px letter-spacing: -1px color: transparent + font-weight: normal &:before font: 21px "mnmliconsRegular" content: $icon-name color: $color +@mixin text-to-entypo-icon($icon-name, $color: #404040, $size: 21px) + font-size: 1px + letter-spacing: -1px + color: transparent + font-weight: normal + &:before + font: $size "entypoRegular" + content: $icon-name + color: $color + // }}} @media print @@ -134,6 +146,11 @@ $sheet-max-width: 860px height: 100% position: relative +// jQueryUI css bug fixing +.text-tag .text-button + height: auto !important + min-height: 16px + .openerp // Global style {{{ padding: 0 @@ -155,6 +172,7 @@ $sheet-max-width: 860px // Tag reset {{{ a text-decoration: none + cursor: pointer !important table padding: 0 border-collapse: collapse @@ -191,7 +209,7 @@ $sheet-max-width: 860px // Button style {{{ a.button:link, a.button:visited, button, input[type='submit'], .ui-dialog-buttonpane .ui-dialog-buttonset .ui-button display: inline-block - border: 1px solid #ababab + border: 1px solid rgba(0,0,0,0.4) color: #4c4c4c margin: 0 padding: 3px 12px @@ -362,7 +380,6 @@ $sheet-max-width: 860px color: white background: #DC5F59 button.oe_highlight - border: 1px solid #795151 @include vertical-gradient(#df3f3f, #a21a1a) @include box-shadow((0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset)) button.oe_highlight:hover @@ -459,6 +476,12 @@ $sheet-max-width: 860px text-decoration: none margin-bottom: 1px // }}} + .oe_form + header + .oe_tags + margin: 5px 0 0 5px + width: 400px + padding-bottom: 0 // Tooltips {{{ &.oe_tooltip font-size: 12px @@ -538,7 +561,7 @@ $sheet-max-width: 860px position: relative cursor: pointer .oe_dropdown_toggle - color: #404040 + color: rgba(0,0,0,0.5) font-weight: normal .oe_dropdown_hover:hover .oe_dropdown_menu, .oe_dropdown_menu.oe_opened display: block @@ -547,7 +570,7 @@ $sheet-max-width: 860px position: absolute top: 26px left: 0 - z-index: 1 + z-index: 3 margin: 0 padding: 0 border: 1px solid $tag-border @@ -866,6 +889,33 @@ $sheet-max-width: 860px .oe_dropdown_menu right: -1px // }}} + // About openerp {{{ + .oe_about + background-color: white + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=) + @include radius(0 0 2px 2px) + a + color: $link-color + &:hover + text-decoration: underline + &:focus + outline: none + .oe_logo + margin-left: -6px + .oe_bottom + position: absolute + top: 50% + left: 0 + right: 0 + bottom: 0 + text-shadow: 0 1px 1px #999999 + @include vertical-gradient(#b41616, #600606) + color: #eee + padding: 0 16px + @include radius(0 0 2px 2px) + a + color: #eee + // }}} // Systray {{{ .oe_systray > div float: left @@ -1509,9 +1559,9 @@ $sheet-max-width: 860px margin: 16px > header margin: -16px -16px 0 -16px - padding: 8px + padding: 0 .oe_form_sheetbg - padding: 8px 0 + padding: 16px 0 .oe_form_sheet_width min-width: 650px max-width: $sheet-max-width @@ -1526,8 +1576,8 @@ $sheet-max-width: 860px background: url(/web/static/src/img/form_sheetbg.png) border-bottom: 1px solid #ddd .oe_form_sheet - border: 1px solid $tag-border - @include box-shadow(0 0 10px rgba(0,0,0,0.3)) + border: 1px solid #c8c8d3 //$tag-border + @include box-shadow(0 4px 20px rgba(0,0,0,0.15)) .ui-tabs margin: 0 -16px .oe_notebook_page @@ -1540,6 +1590,8 @@ $sheet-max-width: 860px border-bottom: 1px solid #cacaca padding-left: 2px @include vertical-gradient(#fcfcfc, #dedede) + > span + margin-left: 4px ul display: inline-block float: right @@ -1574,6 +1626,8 @@ $sheet-max-width: 860px .oe_subtotal_footer_separator width: 108px border-top: 1px solid #cacaca + margin-top: 4px + padding-top: 4px font-weight: bold font-size: 18px label:after @@ -1735,6 +1789,14 @@ $sheet-max-width: 860px > div position: relative overflow: hidden + .oe_form_field_html + position: relative + width: 600px + margin-left: 130px + margin-top: 32px + margin-bottom: 32px + text-align: justify + .oe_form_editable .oe_form .oe_form_field_integer @@ -1751,6 +1813,9 @@ $sheet-max-width: 860px * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image */ .oe_hidden_input_file + // Position: relative is used for the hidden input[type=file] + // Do not remove it anymore ! + position: relative input.oe_form_binary_file z-index: 0 line-height: 0 @@ -1812,7 +1877,8 @@ $sheet-max-width: 860px li display: inline-block list-style-type: none - margin: 0 -20px 0 0 + // It is probably a bad idea to modify this margin + margin: 0 -18px 0 0 padding: 0 @include vertical-gradient(#fcfcfc, #dedede) &:first-child .label @@ -1946,6 +2012,7 @@ $sheet-max-width: 860px &.oe_form_field_float,&.oe_form_view_integer input text-align: right + width: 100% &.oe_form_field_datetime,&.oe_form_field_date > span width: 100% @@ -2068,13 +2135,16 @@ $sheet-max-width: 860px text-indent: -9001px td.oe_list_field_handle width: 1em + padding: 0 !important cursor: ns-resize .oe_list_handle - @include text-to-icon("ö") + @include text-to-entypo-icon("}",#E0E0E0,18px) + margin-right: 7px .oe_list_cannot_edit .oe_list_header_handle, .oe_list_field_handle display: none !important + padding: 0 !important .oe_list_cannot_delete .oe_list_record_delete display: none !important @@ -2123,10 +2193,6 @@ $sheet-max-width: 860px .treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span margin-left: 16px // }}} - // Translation {{{ - .oe_trad_field.touched - border: 1px solid green !important - // }}} // Debugging stuff {{{ .oe_layout_debugging .oe_form_group diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 3114aaf315f..e9185429993 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -79,6 +79,9 @@ instance.web.Dialog = instance.web.Widget.extend({ } } if (options) { + if (options.buttons) { + this.params_buttons = true; + } _.extend(this.dialog_options, options); } }, @@ -123,7 +126,13 @@ instance.web.Dialog = instance.web.Widget.extend({ if (! this.dialog_inited) this.init_dialog(); var o = this.get_options(options); + if (! this.params_buttons) { + this.$buttons.appendTo($("body")); + } instance.web.dialog(this.$el, o).dialog('open'); + if (! this.params_buttons) { + this.$buttons.appendTo(this.$el.dialog("widget")); + } if (o.height === 'auto' && o.max_height) { this.$el.css({ 'max-height': o.max_height, 'overflow-y': 'auto' }); } @@ -133,6 +142,10 @@ instance.web.Dialog = instance.web.Widget.extend({ this.renderElement(); var o = this.get_options(options); instance.web.dialog(this.$el, o); + if (! this.params_buttons) { + this.$buttons = $('
'); + this.$el.dialog("widget").append(this.$buttons); + } var res = this.start(); this.dialog_inited = true; return res; @@ -519,7 +532,9 @@ instance.web.Login = instance.web.Widget.extend({ }); var d; if (self.params.db) { - d = self.do_login(self.params.db, self.params.login, self.params.password); + if (self.params.login && self.params.password) { + d = self.do_login(self.params.db, self.params.login, self.params.password); + } } else { d = self.rpc("/web/database/get_list", {}).done(self.on_db_loaded).fail(self.on_db_failed); } @@ -564,7 +579,7 @@ instance.web.Login = instance.web.Widget.extend({ */ do_login: function (db, login, password) { var self = this; - this.$el.removeClass('oe_login_invalid'); + self.hide_error(); self.$(".oe_login_pane").fadeOut("slow"); return this.session.session_authenticate(db, login, password).pipe(function() { if (self.has_local_storage) { @@ -581,12 +596,19 @@ instance.web.Login = instance.web.Widget.extend({ } } self.trigger('login_successful'); - },function () { + }, function () { self.$(".oe_login_pane").fadeIn("fast", function() { - self.$el.addClass("oe_login_invalid"); + self.show_error("Invalid username or password"); }); }); }, + show_error: function(message) { + this.$el.addClass("oe_login_invalid"); + this.$(".oe_login_error_message").text(message); + }, + hide_error: function() { + this.$el.removeClass('oe_login_invalid'); + }, }); instance.web.client_actions.add("login", "instance.web.Login"); diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 7d328f012fe..f62b186f662 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -16,6 +16,14 @@ instance.web.form = {}; * Events: * - view_content_has_changed : when the values of the fields have changed. When * this event is triggered all fields should reprocess their modifiers. + * - field_changed: : when the value of a field change, an event is triggered + * named "field_changed:" with replaced by the name of the field. + * This event is not related to the on_change mechanism of OpenERP and is always called + * when the value of a field is setted or changed. This event is only triggered when the + * value of the field is syntactically valid, but it can be triggered when the value + * is sematically invalid (ie, when a required field is false). It is possible that an event + * about a precise field is never triggered even if that field exists in the view, in that + * case the value of the field is assumed to be false. */ instance.web.form.FieldManagerMixin = { /** @@ -26,6 +34,11 @@ instance.web.form.FieldManagerMixin = { * Returns true when the view is in create mode. */ is_create_mode: function() {}, + /** + * Returns the current value of a field present in the view. See the get_value() method + * method in FieldInterface for further information. + */ + get_field_value: function(field_name) {}, }; instance.web.views.add('form', 'instance.web.FormView'); @@ -159,10 +172,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.has_been_loaded.resolve(); // Add bounce effect on button 'Edit' when click on readonly page view. - this.$el.find(".oe_form_field,label").on('click', function (e) { + this.$el.find(".oe_form_group_row,.oe_form_field,label").on('click', function (e) { if(self.get("actual_mode") == "view") { var $button = self.options.$buttons.find(".oe_form_button_edit"); - $button.effect('bounce', {distance: 18, times: 5}, 150) + $button.effect('bounce', {distance: 18, times: 5}, 150); + e.stopPropagation(); + instance.web.bus.trigger('click', e); } }); @@ -269,9 +284,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM if (this.$buttons) { this.$buttons.show(); } - if (this.$pager) { - this.$pager.show(); - } this.$el.show().css({ opacity: '0', filter: 'alpha(opacity = 0)' @@ -332,7 +344,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM _(this.fields).each(function (field, f) { field._dirty_flag = false; + field._inhibit_on_change_flag = true; var result = field.set_value(self.datarecord[f] || false); + field._inhibit_on_change_flag = false; set_values.push(result); }); return $.when.apply(null, set_values).pipe(function() { @@ -407,7 +421,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.$pager.remove(); if (this.get("actual_mode") === "create") return; - this.$pager = $(QWeb.render("FormView.pager", {'widget':self})); + this.$pager = $(QWeb.render("FormView.pager", {'widget':self})).hide(); if (this.options.$pager) { this.$pager.appendTo(this.options.$pager); } else { @@ -420,10 +434,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.do_update_pager(); }, do_update_pager: function(hide_index) { - var index = hide_index ? '-' : this.dataset.index + 1; - this.$pager.find('button').prop('disabled', this.dataset.ids.length < 2).end() - .find('span.oe_pager_index').html(index).end() - .find('span.oe_pager_count').html(this.dataset.ids.length); + this.$pager.toggle(this.dataset.ids.length > 1); + if (hide_index) { + $(".oe_form_pager_state", this.$pager).html(""); + } else { + $(".oe_form_pager_state", this.$pager).html(_.str.sprintf(_t("%d / %d"), this.dataset.index + 1, this.dataset.ids.length)); + } }, parse_on_change: function (on_change, widget) { var self = this; @@ -579,7 +595,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM if (field) { var value_ = result.value[f]; if (field.get_value() != value_) { + field._inhibit_on_change_flag = true; field.set_value(value_); + field._inhibit_on_change_flag = false; field._dirty_flag = true; if (!_.contains(processed, field.name)) { this.do_onchange(field, processed); @@ -939,6 +957,15 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return self.dataset.parent_view.recursive_save(); }); }, + recursive_reload: function() { + var self = this; + var pre = $.when(); + if (self.dataset.parent_view) + pre = self.dataset.parent_view.recursive_reload(); + return pre.pipe(function() { + return self.reload(); + }); + }, is_dirty: function() { return _.any(this.fields, function (value_) { return value_._dirty_flag; @@ -1042,6 +1069,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.translatable_fields.push(field); } field.on('changed_value', this, function() { + if (field.is_syntax_valid()) { + this.trigger('field_changed:' + name); + } + if (field._inhibit_on_change_flag) { + return; + } field._dirty_flag = true; if (field.is_syntax_valid()) { this.do_onchange(field); @@ -1056,6 +1089,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM is_create_mode: function() { return this.get("actual_mode") === "create"; }, + get_field_value: function(field_name) { + return this.fields[field_name].get_value(); + }, }); /** @@ -1808,7 +1844,7 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ return this.view.do_execute_action( _.extend({}, this.node.attrs, {context: context}), this.view.dataset, this.view.datarecord.id, function () { - self.view.reload(); + self.view.recursive_reload(); }); }, check_disable: function() { @@ -1826,7 +1862,8 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ * - force_readonly: boolean, When it is true, the field should always appear * in read only mode, no matter what the value of the "readonly" property can be. * Events: - * - changed_value: triggered to inform the view to check on_changes + * - changed_value: triggered when the value of the field has changed. This can be due + * to a user interaction or a call to set_value(). * */ instance.web.form.FieldInterface = { @@ -1938,8 +1975,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w this.on("change:force_readonly", this, test_effective_readonly); test_effective_readonly.call(this); this.on("change:value", this, function() { - if (! this._inhibit_on_change) - this.trigger('changed_value'); + this.trigger('changed_value'); this._check_css_flags(); }); }, @@ -1974,9 +2010,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w this.$el.toggleClass('oe_form_required', this.get("required")); }, set_value: function(value_) { - this._inhibit_on_change = true; this.set({'value': value_}); - this._inhibit_on_change = false; }, get_value: function() { return this.get('value'); @@ -2613,6 +2647,7 @@ instance.web.form.CompletionFieldMixin = { var dataset = new instance.web.DataSet(this, this.field.relation, self.build_context()); var blacklist = this.get_search_blacklist(); + this.last_query = search_val; return this.orderer.add(dataset.name_search( search_val, new instance.web.CompoundDomain(self.build_domain(), [["id", "not in", blacklist]]), @@ -2720,6 +2755,32 @@ instance.web.form.CompletionFieldMixin = { }, }; +instance.web.form.M2ODialog = instance.web.Dialog.extend({ + template: "M2ODialog", + init: function(parent) { + this._super(parent, { + title: _.str.sprintf(_t("Add %s"), parent.string), + width: 312, + }); + }, + start: function() { + var self = this; + this.$buttons.html(QWeb.render("M2ODialog.buttons")); + this.$("input").val(this.getParent().last_query); + this.$buttons.find(".oe_form_m2o_qc_button").click(function(){ + self.getParent()._quick_create(self.$("input").val()); + self.destroy(); + }); + this.$buttons.find(".oe_form_m2o_sc_button").click(function(){ + self.getParent()._search_create_popup("form", undefined, self.getParent()._create_context(self.$("input").val())); + self.destroy(); + }); + this.$buttons.find(".oe_form_m2o_cancel_button").click(function(){ + self.destroy(); + }); + }, +}); + instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, { template: "FieldMany2One", init: function(field_manager, node) { @@ -2750,26 +2811,23 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.render_editable(); this.render_value(); }, + init_error_displayer: function() { + // nothing + }, + hide_error_displayer: function() { + // doesn't work + }, + show_error_displayer: function() { + new instance.web.form.M2ODialog(this).open(); + }, render_editable: function() { var self = this; this.$input = this.$el.find("input"); - self.$input.tipsy({ - title: function() { - return QWeb.render('Tipsy.alert', { - message: "No element was selected, you should create or select one from the dropdown list." - }); - }, - trigger:'manual', - fade: true, - gravity: 's', - html: true, - opacity: 1, - offset: 4, - }); + this.init_error_displayer(); self.$input.on('focus', function() { - self.$input.tipsy("hide"); + self.hide_error_displayer(); }); this.$drop_down = this.$el.find(".oe_m2o_drop_down_button"); @@ -2823,10 +2881,10 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc } } }); - self.tip_def = $.Deferred(); - self.untip_def = $.Deferred(); - var tip_delay = 200; - var tip_duration = 15000; + self.ed_def = $.Deferred(); + self.uned_def = $.Deferred(); + var ed_delay = 200; + var ed_duration = 15000; var anyoneLoosesFocus = function() { var used = false; if (self.floating) { @@ -2846,25 +2904,25 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc } self.floating = false; } - if (used && self.get("value") === false && ! self.no_tipsy) { - self.tip_def.reject(); - self.untip_def.reject(); - self.tip_def = $.Deferred(); - self.tip_def.then(function() { - self.$input.tipsy("show"); + if (used && self.get("value") === false && ! self.no_ed) { + self.ed_def.reject(); + self.uned_def.reject(); + self.ed_def = $.Deferred(); + self.ed_def.then(function() { + self.show_error_displayer(); }); setTimeout(function() { - self.tip_def.resolve(); - self.untip_def.reject(); - self.untip_def = $.Deferred(); - self.untip_def.then(function() { - self.$input.tipsy("hide"); + self.ed_def.resolve(); + self.uned_def.reject(); + self.uned_def = $.Deferred(); + self.uned_def.then(function() { + self.hide_error_displayer(); }); - setTimeout(function() {self.untip_def.resolve();}, tip_duration); - }, tip_delay); + setTimeout(function() {self.uned_def.resolve();}, ed_duration); + }, ed_delay); } else { - self.no_tipsy = false; - self.tip_def.reject(); + self.no_ed = false; + self.ed_def.reject(); } }; var ignore_blur = false; @@ -3004,13 +3062,13 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.$input.focus(); }, _quick_create: function() { - this.no_tipsy = true; - this.tip_def.reject(); + this.no_ed = true; + this.ed_def.reject(); return instance.web.form.CompletionFieldMixin._quick_create.apply(this, arguments); }, _search_create_popup: function() { - this.no_tipsy = true; - this.tip_def.reject(); + this.no_ed = true; + this.ed_def.reject(); return instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments); }, }); @@ -3287,6 +3345,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ this.dataset.index = 0; } self.is_setted.resolve(); + this.trigger_on_change(); return self.reload_current_view(); }, get_value: function() { @@ -3339,7 +3398,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ }, this)); }, is_syntax_valid: function() { - if (!this.viewmanager.views[this.viewmanager.active_view]) + if (! this.viewmanager || ! this.viewmanager.views[this.viewmanager.active_view]) return true; var view = this.viewmanager.views[this.viewmanager.active_view].controller; switch (this.viewmanager.active_view) { diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 8cdbcb5a9ff..8fcda146cd4 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -399,10 +399,14 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi */ setup_columns: function (fields, grouped) { var registry = instance.web.list.columns; + var reorder = this.options.reorderable; this.columns.splice(0, this.columns.length); this.columns.push.apply(this.columns, _(this.fields_view.arch.children).map(function (field) { var id = field.attrs.name; + if(field.attrs.widget == 'handle' && !reorder){ + field.attrs.reorderable = reorder || true; + } return registry.for_(id, fields[id], field); })); if (grouped) { @@ -411,9 +415,8 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi } this.visible_columns = _.filter(this.columns, function (column) { - return column.invisible !== '1'; + return column.invisible !== '1' && !column.reorderable; }); - this.aggregate_columns = _(this.visible_columns).invoke('to_aggregate'); }, /** @@ -830,6 +833,10 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi this.$el.prepend( $('
').html(this.options.action.help) ); + var create_nocontent = this.$buttons; + this.$el.find('.oe_view_nocontent').click(function() { + create_nocontent.effect('bounce', {distance: 18, times: 5}, 150); + }); } }); instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.ListView.List# */{ @@ -1045,7 +1052,11 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. var row = cells.join(''); this.$current .children('tr:not([data-id])').remove().end() - .append(new Array(count - this.records.length + 1).join(row)); + .append(new Array(count - this.records.length + 1).join(row)).click( + function() { + $('button.oe_list_add').effect('bounce', {distance: 18, times: 5}, 150); + } + ); }, /** * Gets the ids of all currently selected records, if any diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 02297e9db01..d170aacc89d 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -318,8 +318,8 @@ instance.web.ActionManager = instance.web.Widget.extend({ } return this.ir_actions_common(action, on_close, clear_breadcrumbs); }, - ir_actions_client: function (action, on_close) { - return this.ir_actions_common(action, on_close); + ir_actions_client: function (action, on_close, clear_breadcrumbs) { + return this.ir_actions_common(action, on_close, clear_breadcrumbs); }, ir_actions_act_window_close: function (action, on_closed) { if (!this.dialog && on_closed) { @@ -327,7 +327,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ } this.dialog_stop(); }, - ir_actions_server: function (action, on_closed) { + ir_actions_server: function (action, on_closed, clear_breadcrumbs) { var self = this; this.rpc('/web/action/run', { action_id: action.id, diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index d1d028aa3f5..58bc224918c 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -61,7 +61,7 @@