diff options
| author | Thibault Delavallée <tde@openerp.com> | 2014-04-08 10:37:33 +0200 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2014-04-08 10:37:33 +0200 |
| commit | a74eb749ae38784f370a9eeb073c3bbf09b35bbd (patch) | |
| tree | 3c83c289f1cb493d887ee8b647616465885fb3c9 /addons/web/static | |
| parent | 423f81bf5cf4dd9e949fcabbd2babe4fe3187676 (diff) | |
| parent | f1d3f2a0c42f1de5970b5f897c4e5b279d1ee23b (diff) | |
[MERGE] Sync with trunk
bzr revid: tde@openerp.com-20140401100513-e4iglorrxnj0ne8j
bzr revid: tde@openerp.com-20140403122017-zl668mpi0w5gwps0
bzr revid: tde@openerp.com-20140408083733-8plf5daah4c8yxxx
Diffstat (limited to 'addons/web/static')
| -rw-r--r-- | addons/web/static/src/css/base.css | 51 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.sass | 44 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 16 | ||||
| -rw-r--r-- | addons/web/static/src/js/core.js | 7 | ||||
| -rw-r--r-- | addons/web/static/src/js/data.js | 14 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 3 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 94 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list.js | 3 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 12 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 16 | ||||
| -rw-r--r-- | addons/web/static/test/list-editable.js | 23 | ||||
| -rw-r--r-- | addons/web/static/test/list.js | 8 | ||||
| -rw-r--r-- | addons/web/static/test/search.js | 38 |
13 files changed, 260 insertions, 69 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 3996579e02a..5469c5376b0 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,4 @@ -@charset "utf-8"; +@charset "UTF-8"; @font-face { font-family: "mnmliconsRegular"; src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot"); @@ -368,6 +368,7 @@ .openerp .oe_left { float: left; margin-right: 8px; + width: 305px; } .openerp .oe_right { float: right; @@ -456,11 +457,46 @@ background: #ed6f6a; } .openerp .oe_button_box { - width: 270px; - text-align: right; + width: 400px; + text-align: left; +} +.openerp .oe_button_box .oe_stat_button:hover { + background: #7c7bad; + color: white; +} +.openerp .oe_button_box .oe_stat_button:hover .fa { + color: white; } -.openerp .oe_button_box button { - margin: 4px; +.openerp .oe_button_box .oe_stat_button { + font-weight: normal; + display: inline-table; + width: 33% !important; + height: 42px; + margin: 0px -1px -1px 0px; + padding: 0; + color: #666666; + border: 1px solid #dddddd; + border-radius: 0; + box-shadow: none; + background: white; +} +.openerp .oe_button_box .oe_stat_button > div { + display: table-cell; + vertical-align: middle; + text-align: left; + padding: 0; + line-height: 120%; +} +.openerp .oe_button_box .oe_stat_button .stat_button_icon { + color: #7c7bad; + font-size: 24px; + padding: 0px 3px; + width: 37px; + text-align: center; +} +.openerp .oe_button_box .oe_stat_button svg { + width: 38px; + height: 38px; } .openerp .oe_avatar > img { max-height: 90px; @@ -1248,12 +1284,14 @@ width: 100%; } .openerp .oe_view_manager .oe_view_manager_body { - display: table-row; height: inherit; } .openerp .oe_view_manager .oe_view_manager_view_kanban:not(:empty) { height: inherit; } +.openerp .oe_view_manager[data-view-type=kanban] .oe_view_manager_body { + display: table-row; +} .openerp .oe_view_manager table.oe_view_manager_header { border-collapse: separate; width: 100%; @@ -2362,6 +2400,7 @@ } .openerp .oe_hidden_input_file { position: relative; + overflow-x: hidden; } .openerp .oe_hidden_input_file input.oe_form_binary_file { z-index: 0; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index b08427e0832..65f22a89481 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -385,6 +385,7 @@ $sheet-padding: 16px .oe_left float: left margin-right: 8px + width: 305px .oe_right float: right margin-left: 8px @@ -429,10 +430,40 @@ $sheet-padding: 16px &:hover background: #ED6F6A .oe_button_box - width: 270px - text-align: right - button - margin: 4px + width: 400px + text-align: left + .oe_stat_button:hover + background: #7c7bad + color: white + .fa + color: white + .oe_stat_button + font-weight: normal + display: inline-table + width: 33% !important + height: 42px + margin: 0px -1px -1px 0px + padding: 0 + color: #666 + border: 1px solid #dddddd + border-radius: 0 + box-shadow: none + background: white + > div + display: table-cell + vertical-align: middle + text-align: left + padding: 0 + line-height: 120% + .stat_button_icon + color: #7C7BAD + font-size: 24px + padding: 0px 3px + width: 37px + text-align: center + svg + width: 38px + height: 38px .oe_avatar > img max-height: 90px @@ -1037,10 +1068,12 @@ $sheet-padding: 16px height: inherit width: 100% .oe_view_manager_body - display: table-row height: inherit .oe_view_manager_view_kanban:not(:empty) height: inherit + &[data-view-type=kanban] + .oe_view_manager_body + display: table-row table.oe_view_manager_header border-collapse: separate @@ -1920,6 +1953,7 @@ $sheet-padding: 16px // Position: relative is used for the hidden input[type=file] // Do not remove it anymore ! position: relative + overflow-x: hidden input.oe_form_binary_file z-index: 0 line-height: 0 diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 8e5df84e2c3..de56927799e 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -105,9 +105,6 @@ instance.web.Dialog = instance.web.Widget.extend({ autoOpen: false, position: [false, 40], buttons: null, - beforeClose: function () { - self.trigger("closing"); - }, resizeStop: function() { self.trigger("resized"); }, @@ -208,8 +205,9 @@ instance.web.Dialog = instance.web.Widget.extend({ /** Closes the popup, if destroy_on_close was passed to the constructor, it is also destroyed. */ - close: function() { + close: function(reason) { if (this.dialog_inited && this.$el.is(":data(dialog)")) { + this.trigger("closing", reason); this.$el.dialog('close'); } }, @@ -225,14 +223,14 @@ instance.web.Dialog = instance.web.Widget.extend({ /** Destroys the popup, also closes it. */ - destroy: function () { + destroy: function (reason) { this.$buttons.remove(); _.each(this.getChildren(), function(el) { el.destroy(); }); if (! this.__tmp_dialog_closing) { this.__tmp_dialog_destroying = true; - this.close(); + this.close(reason); this.__tmp_dialog_destroying = undefined; } if (this.dialog_inited && !this.isDestroyed() && this.$el.is(":data(dialog)")) { @@ -256,7 +254,7 @@ instance.web.CrashManager = instance.web.Class.extend({ new (handler)(this, error).display(); return; } - if (error.data.name === "openerp.http.SessionExpiredException") { + if (error.data.name === "openerp.http.SessionExpiredException" || error.data.name === "werkzeug.exceptions.Forbidden") { this.show_warning({type: "Session Expired", data: { message: _t("Your OpenERP session expired. Please refresh the current web page.") }}); return; } @@ -1264,9 +1262,9 @@ instance.web.WebClient = instance.web.Client.extend({ }; self.action_manager.do_action(result); var form = self.action_manager.dialog_widget.views.form.controller; - form.on("on_button_cancel", self.action_manager.dialog, self.action_manager.dialog.close); + form.on("on_button_cancel", self.action_manager, self.action_manager.dialog_stop); form.on('record_saved', self, function() { - self.action_manager.dialog.close(); + self.action_manager.dialog_stop(); self.update_logo(); }); }); diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index b92ca1d3ba5..90c84ba9cda 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -271,7 +271,12 @@ instance.web.Session.include( /** @lends instance.web.Session# */{ for(var i=0; i<cookies.length; ++i) { var cookie = cookies[i].replace(/^\s*/, ''); if(cookie.indexOf(nameEQ) === 0) { - return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length))); + try { + return JSON.parse(decodeURIComponent(cookie.substring(nameEQ.length))); + } catch(err) { + // wrong cookie, delete it + this.set_cookie(name, '', -1); + } } } return null; diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 517afa7f5c2..73f244bc6a3 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -457,9 +457,17 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin, return $.Deferred().resolve([]); options = options || {}; - return this._model.call('read', - [ids, fields || false], - {context: this.get_context(options.context)}) + var method = 'read'; + var ids_arg = ids; + var context = this.get_context(options.context); + if (options.check_access_rule === true){ + method = 'search_read'; + ids_arg = [['id', 'in', ids]]; + context = new instance.web.CompoundContext(context, {active_test: false}); + } + return this._model.call(method, + [ids_arg, fields || false], + {context: context}) .then(function (records) { if (records.length <= 1) { return records; } var indexes = {}; diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 7c04ad40149..04bb1a61d99 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1560,9 +1560,6 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({ this.model = new instance.web.Model(this.attrs.relation); }, complete: function (needle) { - if (this.attrs.operator || this.attrs.filter_domain) { - return this._super(needle); - } var self = this; // FIXME: "concurrent" searches (multiple requests, mis-ordered responses) var context = instance.web.pyeval.eval( diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index aefee14fcb5..27d5a524ad8 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -967,9 +967,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM context: { 'bin_size': true, 'future_display_name': true - } + }, + check_access_rule: true }).then(function(r) { self.trigger('load_record', r); + }).fail(function (){ + self.do_action('history_back'); }); } }); @@ -1277,6 +1280,9 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt var defs = []; _.each(this.to_replace, function(el) { defs.push(el[0].replace(el[1])); + if (el[1].children().length) { + el[0].$el.append(el[1].children()); + } }); this.to_replace = []; return $.when.apply($, defs); @@ -1304,7 +1310,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt var tagname = $tag[0].nodeName.toLowerCase(); if (this.tags_registry.contains(tagname)) { this.tags_to_init.push($tag); - return $tag; + return (tagname === 'button') ? this.process_button($tag) : $tag; } var fn = self['process_' + tagname]; if (fn) { @@ -1321,6 +1327,13 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt return $tag; } }, + process_button: function ($button) { + var self = this; + $button.children().each(function() { + self.process($(this)); + }); + return $button; + }, process_widget: function($widget) { this.widgets_to_init.push($widget); return $widget; @@ -1906,6 +1919,8 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ template: 'WidgetButton', init: function(field_manager, node) { node.attrs.type = node.attrs['data-button-type']; + this.is_stat_button = /\boe_stat_button\b/.test(node.attrs['class']); + this.icon = node.attrs.icon && "<span class=\"fa " + node.attrs.icon + " fa-fw\"></span>"; this._super(field_manager, node); this.force_disabled = false; this.string = (this.node.attrs.string || '').replace(/_/g, ''); @@ -1976,11 +1991,12 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ var self = this; var context = this.build_context(); - return this.view.do_execute_action( _.extend({}, this.node.attrs, {context: context}), - this.view.dataset, this.view.datarecord.id, function () { - self.view.recursive_reload(); + this.view.dataset, this.view.datarecord.id, function (reason) { + if (!_.isObject(reason)) { + self.view.recursive_reload(); + } }); }, check_disable: function() { @@ -2253,7 +2269,7 @@ instance.web.form.ReinitializeFieldMixin = _.extend({}, instance.web.form.Reini /** Some hack to make placeholders work in ie9. */ -if ($.browser.msie && $.browser.version === "9.0") { +if (!('placeholder' in document.createElement('input'))) { document.addEventListener("DOMNodeInserted",function(event){ var nodename = event.target.nodeName.toLowerCase(); if ( nodename === "input" || nodename == "textarea" ) { @@ -2805,6 +2821,50 @@ instance.web.form.FieldProgressBar = instance.web.form.AbstractField.extend({ } }); +/** + The PercentPie field expect a float from 0 to 100. +*/ +instance.web.form.FieldPercentPie = instance.web.form.AbstractField.extend({ + template: 'FieldPercentPie', + + render_value: function() { + var value = this.get('value'), + formatted_value = Math.round(value || 0) + '%', + svg = this.$('svg')[0]; + + svg.innerHTML = ""; + nv.addGraph(function() { + var size=43; + var chart = nv.models.pieChart() + .width(size) + .height(size) + .margin({top: 0, right: 0, bottom: 0, left: 0}) + .donut(true) + .showLegend(false) + .showLabels(false) + .tooltips(false) + .color(['#7C7BAD','#DDD']) + .donutRatio(0.62); + + d3.select(svg) + .datum([{'x': 'value', 'y': value}, {'x': 'complement', 'y': 100 - value}]) + .transition() + .call(chart) + .attr({width:size, height:size}); + + d3.select(svg) + .append("text") + .attr({x: size/2, y: size/2 + 3, 'text-anchor': 'middle'}) + .style({"font-size": "10px", "font-weight": "bold"}) + .text(formatted_value); + + return chart; + }); + + } +}); + + instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { template: 'FieldSelection', @@ -5852,6 +5912,26 @@ instance.web.form.X2ManyCounter = instance.web.form.AbstractField.extend(instanc }); /** + This widget is intended to be used on stat button numeric fields. It will display + the value many2many and one2many. It is a read-only field that will + display a simple string "<value of field> <label of the field>" +*/ +instance.web.form.StatInfo = instance.web.form.AbstractField.extend({ + init: function() { + this._super.apply(this, arguments); + this.set("value", 0); + }, + render_value: function() { + var options = { + value: this.get("value") || 0, + text: this.string, + }; + this.$el.html(QWeb.render("StatInfo", options)); + }, + +}); + +/** * Registry of form fields, called by :js:`instance.web.FormView`. * * All referenced classes must implement FieldInterface. Those represent the classes whose instances @@ -5878,6 +5958,7 @@ instance.web.form.widgets = new instance.web.Registry({ 'reference' : 'instance.web.form.FieldReference', 'boolean' : 'instance.web.form.FieldBoolean', 'float' : 'instance.web.form.FieldFloat', + 'percentpie': 'instance.web.form.FieldPercentPie', 'integer': 'instance.web.form.FieldFloat', 'float_time': 'instance.web.form.FieldFloat', 'progressbar': 'instance.web.form.FieldProgressBar', @@ -5888,6 +5969,7 @@ instance.web.form.widgets = new instance.web.Registry({ 'monetary': 'instance.web.form.FieldMonetary', 'many2many_checkboxes': 'instance.web.form.FieldMany2ManyCheckBoxes', 'x2many_counter': 'instance.web.form.X2ManyCounter', + 'statinfo': 'instance.web.form.StatInfo', }); /** diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index d9a44fb991d..16d0310ab4d 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -537,7 +537,8 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi [record.get('id')], _.pluck(_(this.columns).filter(function (r) { return r.tag === 'field'; - }), 'name') + }), 'name'), + {check_access_rule: true} ).done(function (records) { var values = records[0]; if (!values) { diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index e24de77ea4f..f3a67a150a1 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -25,9 +25,9 @@ instance.web.ActionManager = instance.web.Widget.extend({ this._super.apply(this, arguments); this.$el.on('click', 'a.oe_breadcrumb_item', this.on_breadcrumb_clicked); }, - dialog_stop: function () { + dialog_stop: function (reason) { if (this.dialog) { - this.dialog.destroy(); + this.dialog.destroy(reason); } this.dialog = null; }, @@ -408,7 +408,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ if (this.dialog_widget && !this.dialog_widget.isDestroyed()) { this.dialog_widget.destroy(); } - this.dialog_stop(); + this.dialog_stop(executor.action); this.dialog = new instance.web.Dialog(this, { dialogClass: executor.klass, }); @@ -426,7 +426,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog.open(); return initialized; } else { - this.dialog_stop(); + this.dialog_stop(executor.action); this.inner_action = executor.action; this.inner_widget = widget; executor.post_process(widget); @@ -639,7 +639,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ this.$el .find('.oe_view_manager_switch a').filter('[data-view-type="' + view_type + '"]') .parent().addClass('active'); - + this.$el.attr("data-view-type", view_type); return $.when(view_promise).done(function () { _.each(_.keys(self.views), function(view_name) { var controller = self.views[view_name].controller; @@ -1415,7 +1415,7 @@ instance.web.View = instance.web.Widget.extend({ // Wrong group_by values will simply fail and forbid rendering of the destination view var ncontext = new instance.web.CompoundContext( _.object(_.reject(_.pairs(dataset.get_context().eval()), function(pair) { - return pair[0].match('^(?:(?:default_|search_default_).+|group_by|group_by_no_leaf|active_id|active_ids)$') !== null; + return pair[0].match('^(?:(?:default_|search_default_).+|.+_view_ref|group_by|group_by_no_leaf|active_id|active_ids)$') !== null; })) ); ncontext.add(action_data.context || {}); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index ded573f2af3..1aa9dec8880 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1207,6 +1207,11 @@ <span></span> </span> </t> +<t t-name="FieldPercentPie"> + <span class="oe_form_field oe_form_field_percent_pie" t-att-style="widget.node.attrs.style"> + <svg></svg> + </span> +</t> <t t-name="FieldStatus"> <ul t-att-class="'oe_form_field_status ' + (widget.options.clickable ? 'oe_form_status_clickable' : 'oe_form_status')" t-att-style="widget.node.attrs.style"/> </t> @@ -1271,7 +1276,6 @@ <td> <t t-call="HiddenInputFile"> <t t-set="fileupload_id" t-value="widget.fileupload_id"/> - <t t-set="fileupload_style" t-translation="off">width: 83px;</t> <button class="oe_button oe_field_button" type="button"> <img t-att-src='_s + "/web/static/src/img/icons/STOCK_DIRECTORY.png"'/> <span>Select</span> @@ -1370,13 +1374,15 @@ </div> </t> <t t-name="WidgetButton"> - <button type="button" class="oe_button oe_form_button" + <button type="button" t-att-class="widget.is_stat_button ? 'oe_stat_button btn btn-default' : '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" t-att-accesskey="widget.node.attrs.accesskey"> - <img t-if="widget.node.attrs.icon" t-att-src="_s + widget.node.attrs.icon" width="16" height="16"/> - <span t-if="widget.string"><t t-esc="widget.string"/></span> + <img t-if="!widget.is_stat_button and widget.node.attrs.icon " t-att-src="_s + widget.node.attrs.icon" width="16" height="16"/> + <div t-if="widget.is_stat_button" class="stat_button_icon"><t t-if="widget.icon" t-raw="widget.icon"/></div> + <span t-if="widget.string and !widget.is_stat_button"><t t-esc="widget.string"/></span> + <div t-if="widget.string and widget.is_stat_button"><t t-esc="widget.string"/></div> </button> </t> <t t-name="WidgetButton.tooltip" t-extend="WidgetLabel.tooltip"> @@ -1949,4 +1955,6 @@ <t t-name="X2ManyCounter"> <a href="javascript:void(0)"><t t-esc="text"/></a> </t> +<t t-name="StatInfo"> + <strong><t t-esc="value"/></strong><br/><t t-esc="text"/></t> </templates> diff --git a/addons/web/static/test/list-editable.js b/addons/web/static/test/list-editable.js index 20a14cb24d5..e73249549b8 100644 --- a/addons/web/static/test/list-editable.js +++ b/addons/web/static/test/list-editable.js @@ -81,7 +81,7 @@ openerp.testing.section('editor', { test('toggle-edition-save', { asserts: 4, setup: function (instance, $s, mock) { - mock('test.model:read', function () { + mock('test.model:search_read', function () { return [{id: 42, a: false, b: false, c: false}]; }); } @@ -183,6 +183,15 @@ openerp.testing.section('list.edition', { } return []; }); + mock('demo:search_read', function (args) { + // args[0][0] = ["id", "=", 42] + // args[0][0] = 42 + var id = args[0][0][2]; + if (id in records) { + return [records[id]]; + } + return []; + }); mock('demo:fields_view_get', function () { return { type: 'tree', @@ -316,11 +325,13 @@ openerp.testing.section('list.edition.onwrite', { mock('demo:read', function (args, kwargs) { if (_.isEmpty(args[0])) { return []; - } else if (_.isEqual(args[0], [1])) { - return [ - {id: 1, a: 'some value'} - ]; - } else if (_.isEqual(args[0], [42])) { + } + throw new Error(JSON.stringify(_.toArray(arguments))); + }); + mock('demo:search_read', function (args, kwargs) { + if (_.isEqual(args[0], [['id', 'in', [1]]])) { + return [{id: 1, a: 'some value'}]; + } else if (_.isEqual(args[0], [['id', 'in', [42]]])) { return [ {id: 42, a: 'foo'} ]; } throw new Error(JSON.stringify(_.toArray(arguments))); diff --git a/addons/web/static/test/list.js b/addons/web/static/test/list.js index bb4c4c38640..2ea8790a694 100644 --- a/addons/web/static/test/list.js +++ b/addons/web/static/test/list.js @@ -18,8 +18,12 @@ openerp.testing.section('list.buttons', { return [ {id: 1, a: 'foo'}, {id: 2, a: 'bar'}, {id: 3, a: 'baz'} ]; - } else if (_.isEqual(args[0], [2])) { - // button action virtually removed record + } + throw new Error(JSON.stringify(_.toArray(arguments))); + }); + mock('demo:search_read', function (args, kwargs) { + console.log(args); + if (_.isEqual(args[0], [['id', 'in', [2]]])) { return []; } throw new Error(JSON.stringify(_.toArray(arguments))); diff --git a/addons/web/static/test/search.js b/addons/web/static/test/search.js index 9874795e1c9..96bbb660103 100644 --- a/addons/web/static/test/search.js +++ b/addons/web/static/test/search.js @@ -620,29 +620,33 @@ openerp.testing.section('search.completions', { {relation: 'dummy.model'}, view); return f.complete("bob"); }); - test("M2O custom operator", {asserts: 6}, function (instance) { - var view = { inputs: [], }; + test("M2O custom operator", {asserts: 10}, function (instance, $s, mock) { + mock('dummy.model:name_search', function (args, kwargs) { + deepEqual(args, [], "should have no positional arguments"); + // the operator is meant for the final search term generation, not the autocompletion + equal(kwargs.operator, undefined, "operator should not be used for autocompletion") + strictEqual(kwargs.name, 'bob'); + return [[42, "Match"]]; + }); + var view = {inputs: [], dataset: {get_context: function () {}}}; var f = new instance.web.search.ManyToOneField( - {attrs: {string: 'Dummy', operator:'ilike'}}, + {attrs: {string: 'Dummy', operator: 'ilike'}}, {relation: 'dummy.model'}, view); return f.complete('bob') - .done(function (completions) { - equal(completions.length, 1, "should provide a single completion"); - var c = completions[0]; - equal(c.label, "Search <em>Dummy</em> for: <strong>bob</strong>", - "should propose fuzzy searching of the value"); - ok(c.facet, "should have a facet"); + .done(function (c) { + equal(c.length, 2, "should return result + title"); + var title = c[0]; + equal(title.label, f.attrs.string, "title should match field name"); + ok(!title.facet, "title should not have a facet"); - var facet = new instance.web.search.Facet(c.facet); - equal(facet.get('category'), f.attrs.string, - "completion facet should bear the field's name"); - strictEqual(facet.get('field'), f, - "completion facet should yield the field"); - deepEqual(facet.values.toJSON(), [{label: 'bob', value: 'bob'}], - "facet should have a single value using the completion item"); + var f1 = new instance.web.search.Facet(c[1].facet); + equal(c[1].label, "Match"); + equal(f1.get('category'), f.attrs.string); + equal(f1.get('field'), f); + deepEqual(f1.values.toJSON(), [{label: 'Match', value: 42}]); }); -}); + }); test('Integer: invalid', {asserts: 1}, function (instance) { var view = {inputs: []}; var f = new instance.web.search.IntegerField( |
