diff options
| author | Jiten (OpenERP) <jra@tinyerp.com> | 2011-11-22 10:48:03 +0530 |
|---|---|---|
| committer | Jiten (OpenERP) <jra@tinyerp.com> | 2011-11-22 10:48:03 +0530 |
| commit | 990ece97a5dfd2b22be25d73193452c034424cdb (patch) | |
| tree | d0ebc692ed7d608d0cf4a79a5506e48e85ee4c9b /addons/web/static | |
| parent | aad7d22763beb1774218bd7f041a918a56237964 (diff) | |
| parent | 8ca42daf0a1b0ef3505a0505328a9d785ecb564c (diff) | |
[MERGE] Merge from openerp-web.
bzr revid: jra@tinyerp.com-20111122051803-1ttx64ilabhxo4p1
Diffstat (limited to 'addons/web/static')
| -rw-r--r-- | addons/web/static/lib/qweb/qweb2.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.css | 60 | ||||
| -rw-r--r-- | addons/web/static/src/js/core.js | 27 | ||||
| -rw-r--r-- | addons/web/static/src/js/data.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 131 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_tree.js | 17 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 16 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 18 |
9 files changed, 167 insertions, 112 deletions
diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js index 34457ade4fd..a6a6da5a6d7 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,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','), + RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,in,instanceof,new,function,return,this,typeof,eval,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 c061353d113..d8f31af1d35 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -809,33 +809,33 @@ label.error { also on the first and last children of the first and last row */ .openerp .oe-listview table.oe-listview-content { - -webkit-border-radius: 7px; - -moz-border-radius: 7px; - border-radius: 7px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } .openerp .oe-listview table.oe-listview-content thead tr:first-child th:first-child { - -webkit-border-top-left-radius: 7px; - -moz-border-radius-topleft: 7px; - border-top-left-radius: 7px; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; } .openerp .oe-listview table.oe-listview-content thead tr:first-child th:last-child { - -webkit-border-top-right-radius: 7px; - -moz-border-radius-topright: 7px; - border-top-right-radius: 7px; + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; } .openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:first-child, .openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:first-child, .openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child th:first-child { - -webkit-border-bottom-left-radius: 7px; - -moz-border-radius-bottomleft: 7px; - border-bottom-left-radius: 7px; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; } .openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:last-child, .openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:last-child, .openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child td:last-child { - -webkit-border-bottom-right-radius: 7px; - -moz-border-radius-bottomright: 7px; - border-bottom-right-radius: 7px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; } /* Notebook */ @@ -967,20 +967,25 @@ label.error { .openerp .oe_forms textarea { resize:vertical; } -.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .button { +.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .oe_button { height: 22px; } .openerp .oe_forms input.field_datetime { min-width: 11em; } -.openerp .oe_forms.oe_frame .oe_datepicker_root { - width: 100%; -} -.openerp .oe_forms .button { +.openerp .oe_forms .oe_button { color: #4c4c4c; white-space: nowrap; + min-width: 100%; + width: 100%; } -.openerp .oe_forms .button span { +@-moz-document url-prefix() { + /* Strange firefox behaviour on width: 100% + white-space: nowrap */ + .openerp .oe_forms .oe_button { + width: auto; + } +} +.openerp .oe_forms .oe_button span { position: relative; vertical-align: top; } @@ -989,13 +994,20 @@ label.error { cursor: pointer; right: 5px; top: 3px; + z-index: 2; +} +.openerp .oe_datepicker_container { + position: absolute; + top: 0; + right: 0; + display: none; } .openerp .oe_datepicker_root { position: relative; display: inline-block; } -.openerp .oe_datepicker_root input[type="text"] { - min-width: 160px; +.openerp .oe_forms.oe_frame .oe_datepicker_root { + width: 100%; } .openerp .oe_input_icon_disabled { position: absolute; @@ -1003,7 +1015,7 @@ label.error { opacity: 0.5; filter:alpha(opacity=50); right: 5px; - top: 5px; + top: 3px; } .openerp img.oe_field_translate { margin-left: -21px; diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index f77f9bf1041..a9731ef5b16 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -125,7 +125,11 @@ openerp.web.callback = function(obj, method) { callback.callback_chain.splice(i, 1); i -= 1; } - r = c.callback.apply(c.self, c.args.concat(args)); + var result = c.callback.apply(c.self, c.args.concat(args)); + if (c.callback === method) { + // return the result of the original method + r = result; + } // TODO special value to stop the chain // openerp.web.callback_stop } @@ -354,6 +358,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. this.debug = (window.location.search.indexOf('?debug') !== -1); this.session_id = false; this.uid = false; + this.username = false; this.user_context= {}; this.db = false; this.module_list = []; @@ -484,10 +489,13 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. var self = this; var params = { db: db, login: login, password: password }; return this.rpc("/web/session/login", params, function(result) { - self.session_id = result.session_id; - self.uid = result.uid; - self.user_context = result.context; - self.db = result.db; + _.extend(self, { + session_id: result.session_id, + uid: result.uid, + user_context: result.context, + db: result.db, + username: result.login + }); self.session_save(); self.on_session_valid(); return true; @@ -501,9 +509,12 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. var self = this; this.session_id = this.get_cookie('session_id'); return this.rpc("/web/session/get_session_info", {}).then(function(result) { - self.uid = result.uid; - self.user_context = result.context; - self.db = result.db; + _.extend(self, { + uid: result.uid, + user_context: result.context, + db: result.db, + username: result.login + }); if (self.uid) self.on_session_valid(); else diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index e783f374dce..69d8fd9ddfd 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -316,7 +316,7 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet def.reject(); } else { fields = fields || false; - return this.read_ids([this.ids[this.index]], fields).then(function(records) { + this.read_ids([this.ids[this.index]], fields).then(function(records) { def.resolve(records[0]); }, function() { def.reject.apply(def, arguments); diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index c82584e87f8..f95801975b5 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -41,7 +41,11 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search if (this.headless) { this.ready.resolve(); } else { - this.rpc("/web/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded); + this.rpc("/web/searchview/load", { + model: this.model, + view_id: this.view_id, + context: this.dataset.get_context() + }, this.on_loaded); } return this.ready.promise(); }, diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 6cc46246651..8b84404f87a 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -140,7 +140,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# // null index means we should start a new record promise = this.on_button_new(); } else { - promise = this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded); + promise = this.dataset.read_index(_.keys(this.fields_view.fields)).pipe(this.on_record_loaded); } this.$element.show(); if (this.sidebar) { @@ -155,6 +155,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# } }, on_record_loaded: function(record) { + var self = this, + deferred_stack = $.Deferred.queue(); if (!record) { throw("Form: No record received"); } @@ -172,33 +174,41 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# this.$form_header.find('.oe_form_on_readonly').toggle(this.readonly); this.$form_header.find('.oe_form_on_editable').toggle(!this.readonly); this.datarecord = record; - for (var f in this.fields) { - var field = this.fields[f]; - field.dirty = false; - field.set_value(this.datarecord[f] || false); - field.validate(); - } - if (!record.id) { - // New record: Second pass in order to trigger the onchanges - this.show_invalid = false; - for (var f in record) { - var field = this.fields[f]; - if (field) { - field.dirty = true; - this.do_onchange(field); + + _(this.fields).each(function (field, f) { + field.reset(); + var result = field.set_value(self.datarecord[f] || false); + if (result && _.isFunction(result.promise)) { + deferred_stack.push(result); + } + $.when(result).then(function() { + field.validate(); + }); + }); + deferred_stack.push('force resolution if no fields'); + return deferred_stack.then(function() { + if (!record.id) { + // New record: Second pass in order to trigger the onchanges + self.show_invalid = false; + for (var f in record) { + var field = self.fields[f]; + if (field) { + field.dirty = true; + self.do_onchange(field); + } } } - } - this.on_form_changed(); - this.initial_mutating_lock.resolve(); - this.show_invalid = true; - this.do_update_pager(record.id == null); - if (this.sidebar) { - this.sidebar.attachments.do_update(); - } - if (this.default_focus_field && !this.embedded_view) { - this.default_focus_field.focus(); - } + self.on_form_changed(); + self.initial_mutating_lock.resolve(); + self.show_invalid = true; + self.do_update_pager(record.id == null); + if (self.sidebar) { + self.sidebar.attachments.do_update(); + } + if (self.default_focus_field && !self.embedded_view) { + self.default_focus_field.focus(); + } + }); }, on_form_changed: function() { for (var w in this.widgets) { @@ -354,12 +364,13 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# var keys = _.keys(self.fields_view.fields); $.when(self.do_set_editable()).then(function() { if (keys.length) { - self.dataset.default_get(keys).then(self.on_record_loaded).then(function() { + self.dataset.default_get(keys).pipe(self.on_record_loaded).then(function() { def.resolve(); }); } else { - self.on_record_loaded({}); - def.resolve(); + self.on_record_loaded({}).then(function() { + def.resolve(); + }); } }); } @@ -427,7 +438,10 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# if (!first_invalid_field) { first_invalid_field = f; } - } else if (f.is_dirty()) { + } else if (f.name !== 'id' && !f.readonly && (!self.datarecord.id || f.is_dirty())) { + // Special case 'id' field, do not save this field + // on 'create' : save all non readonly fields + // on 'edit' : save non readonly modified fields values[f.name] = f.get_value(); } } @@ -476,8 +490,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# // should not happen in the server, but may happen for internal purpose return $.Deferred().reject(); } else { - this.reload(); - return $.when(r).then(success); + return $.when(this.reload()).pipe(function () { + return $.when(r).then(success); }, null); } }, /** @@ -524,7 +538,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# if (self.dataset.index == null || self.dataset.index < 0) { return $.when(self.on_button_new()); } else { - return self.dataset.read_index(_.keys(self.fields_view.fields), self.on_record_loaded); + return self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_record_loaded); } }; this.reload_lock = this.reload_lock.pipe(act, act); @@ -1180,8 +1194,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f this.nolabel = (this.field.nolabel || node.attrs.nolabel) === '1'; this.readonly = this.modifiers['readonly'] === true; this.required = this.modifiers['required'] === true; - this.invalid = false; - this.dirty = false; + this.invalid = this.dirty = false; this.classname = 'oe_form_field_' + this.type; }, @@ -1251,6 +1264,9 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f this.invalid = false; }, focus: function() { + }, + reset: function() { + this.dirty = false; } }); @@ -1340,7 +1356,6 @@ openerp.web.form.FieldFloat = openerp.web.form.FieldChar.extend({ if (value === false || value === undefined) { // As in GTK client, floats default to 0 value = 0; - this.dirty = true; } this._super.apply(this, [value]); } @@ -1350,54 +1365,58 @@ openerp.web.DateTimeWidget = openerp.web.Widget.extend({ template: "web.datetimepicker", jqueryui_object: 'datetimepicker', type_of_date: "datetime", + init: function(parent) { + this._super(parent); + this.name = parent.name; + }, start: function() { var self = this; - this.$element.find('input').change(this.on_change); + this.$input = this.$element.find('input.oe_datepicker_master'); + this.$input_picker = this.$element.find('input.oe_datepicker_container'); + this.$input.change(this.on_change); this.picker({ onSelect: this.on_picker_select, changeMonth: true, changeYear: true, showWeek: true, - showButtonPanel: false + showButtonPanel: true }); this.$element.find('img.oe_datepicker_trigger').click(function() { if (!self.readonly) { self.picker('setDate', self.value ? openerp.web.auto_str_to_date(self.value) : new Date()); - self.$element.find('.oe_datepicker').toggle(); + self.$input_picker.show(); + self.picker('show'); + self.$input_picker.hide(); } }); - this.$element.find('.ui-datepicker-inline').removeClass('ui-widget-content ui-corner-all'); - this.$element.find('button.oe_datepicker_close').click(function() { - self.$element.find('.oe_datepicker').hide(); - }); this.set_readonly(false); this.value = false; }, picker: function() { - return $.fn[this.jqueryui_object].apply(this.$element.find('.oe_datepicker_container'), arguments); + return $.fn[this.jqueryui_object].apply(this.$input_picker, arguments); }, on_picker_select: function(text, instance) { var date = this.picker('getDate'); - this.$element.find('input').val(date ? this.format_client(date) : '').change(); + this.$input.val(date ? this.format_client(date) : '').change(); }, set_value: function(value) { this.value = value; - this.$element.find('input').val(value ? this.format_client(value) : ''); + this.$input.val(value ? this.format_client(value) : ''); }, get_value: function() { return this.value; }, set_value_from_ui: function() { - var value = this.$element.find('input').val() || false; + var value = this.$input.val() || false; this.value = this.parse_client(value); }, set_readonly: function(readonly) { this.readonly = readonly; - this.$element.find('input').attr('disabled', this.readonly); + this.$input.attr('disabled', this.readonly); this.$element.find('img.oe_datepicker_trigger').toggleClass('oe_input_icon_disabled', readonly); }, is_valid: function(required) { - var value = this.$element.find('input').val(); + var value = this.$input.val(); if (value === "") { return !required; } else { @@ -1410,7 +1429,7 @@ openerp.web.DateTimeWidget = openerp.web.Widget.extend({ } }, focus: function() { - this.$element.find('input').focus(); + this.$input.focus(); }, parse_client: function(v) { return openerp.web.parse_value(v, {"widget": this.type_of_date}); @@ -1427,11 +1446,7 @@ openerp.web.DateTimeWidget = openerp.web.Widget.extend({ openerp.web.DateWidget = openerp.web.DateTimeWidget.extend({ jqueryui_object: 'datepicker', - type_of_date: "date", - on_picker_select: function(text, instance) { - this._super(text, instance); - this.$element.find('.oe_datepicker').hide(); - } + type_of_date: "date" }); openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({ @@ -2109,7 +2124,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ }, reload_current_view: function() { var self = this; - self.is_loaded = self.is_loaded.pipe(function() { + return self.is_loaded = self.is_loaded.pipe(function() { var view = self.viewmanager.views[self.viewmanager.active_view].controller; if(self.viewmanager.active_view === "list") { return view.reload_content(); @@ -2182,8 +2197,8 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ if (this.dataset.index === null && this.dataset.ids.length > 0) { this.dataset.index = 0; } - self.reload_current_view(); - this.is_setted.resolve(); + self.is_setted.resolve(); + return self.reload_current_view(); }, get_value: function() { var self = this; diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js index 5143adb3838..34d47b92813 100644 --- a/addons/web/static/src/js/view_tree.js +++ b/addons/web/static/src/js/view_tree.js @@ -42,7 +42,8 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView# model: this.model, view_id: this.view_id, view_type: "tree", - toolbar: this.view_manager ? !!this.view_manager.sidebar : false + toolbar: this.view_manager ? !!this.view_manager.sidebar : false, + context: this.dataset.get_context() }, this.on_loaded); }, /** @@ -214,17 +215,23 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView# // Get details in listview activate: function(id) { var self = this; + var local_context = { + active_model: self.dataset.model, + active_id: id, + active_ids: [id]}; this.rpc('/web/treeview/action', { id: id, model: this.dataset.model, context: new openerp.web.CompoundContext( - this.dataset.get_context(), { - active_model: this.dataset.model, - active_id: id, - active_ids: [id]}) + this.dataset.get_context(), local_context) }, function (actions) { if (!actions.length) { return; } var action = actions[0][2]; + var c = new openerp.web.CompoundContext(local_context); + if (action.context) { + c.add(action.context); + } + action.context = c; self.do_action(action); }); }, diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index d348b2d7240..90060f47fc1 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -143,7 +143,7 @@ session.web.ActionManager = session.web.Widget.extend({ var ClientWidget = session.web.client_actions.get_object(action.tag); (this.client_widget = new ClientWidget(this, action.params)).appendTo(this); }, - ir_actions_report_xml: function(action) { + ir_actions_report_xml: function(action, on_closed) { var self = this; $.blockUI(); self.rpc("/web/session/eval_domain_and_context", { @@ -155,8 +155,14 @@ session.web.ActionManager = session.web.Widget.extend({ self.session.get_file({ url: '/web/report', data: {action: JSON.stringify(action)}, - complete: $.unblockUI - }); + complete: $.unblockUI, + success: function(){ + if (!self.dialog && on_closed) { + on_closed(); + } + self.dialog_stop(); + } + }) }); }, ir_actions_act_url: function (action) { @@ -210,7 +216,7 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View sidebar_id : self.element_id + '_sidebar_' + view.view_type, action : self.action, action_views_ids : views_ids - }, self.flags, view.options || {}) + }, self.flags, self.flags[view.view_type] || {}, view.options || {}) }); views_ids[view.view_type] = view.view_id; }); @@ -882,7 +888,7 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{ } }; var context = new session.web.CompoundContext(dataset.get_context(), action_data.context || {}); - + var handler = function (r) { var action = r.result; if (action && action.constructor == Object) { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 92a3e5ffc43..fb7ccdf7d8e 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -714,7 +714,7 @@ </t> <t t-name="Widget"> Unhandled widget - <t t-raw="console.log('Unhandled widget', widget)"/> + <t t-js="dict">console.warn('Unhandled widget', dict.widget);</t> </t> <t t-name="WidgetFrame"> <table border="0" width="100%" cellpadding="0" cellspacing="0" class="oe_frame oe_forms"> @@ -907,13 +907,13 @@ </t> <t t-name="web.datetimepicker"> <div class="oe_datepicker_root"> - <input type="text" size="1" style="width: 100%"/> + <input type="text" size="1" style="width: 100%" + t-att-name="widget.name" + t-attf-class="oe_datepicker_master field_#{widget.type_of_date}" + /> <img class="oe_input_icon oe_datepicker_trigger" src="/web/static/src/img/ui/field_calendar.png" title="Select date" width="16" height="16" border="0"/> - <div class="oe_datepicker ui-widget-content ui-corner-all" style="display: none; position: absolute; z-index: 1;"> - <div class="oe_datepicker_container"/> - <button type="button" class="oe_datepicker_close ui-state-default ui-priority-primary ui-corner-all" style="float: right;">Done</button> - </div> + <input type="text" size="1" class="oe_datepicker_container" disabled="disabled"/> </div> </t> <t t-name="FieldSelection"> @@ -1081,7 +1081,7 @@ </table> </t> <t t-name="WidgetButton"> - <button type="button" style="width: 100%" class="button"> + <button type="button" class="oe_button"> <img t-if="widget.node.attrs.icon" t-att-src="'/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/> <span t-if="widget.string"><t t-esc="widget.string"/></span> </button> @@ -1163,8 +1163,8 @@ t-att-title="attrs.help" t-att-class="classes.join(' ')" t-att-autofocus="attrs.default_focus === '1' ? 'autofocus' : undefined"> - <img t-if="attrs.icon" t-att-src="'/web/static/src/img/icons/' + attrs.icon + '.png'" width="16" height="16"/> - <br t-if="attrs.icon and attrs.string"/> + <img t-att-src="'/web/static/src/img/icons/' + (attrs.icon || 'gtk-home') + '.png'" width="16" height="16"/> + <br t-if="attrs.string"/> <t t-esc="attrs.string"/> </button> <span t-name="SearchView.filters" class="filter_label_group" |
