diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-12-12 11:38:25 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-12-12 11:38:25 +0100 |
| commit | f351dd8cab980a67ee17c431574d8ba9c37b8fdc (patch) | |
| tree | 2cb6e64d0a5083aade80206ea7fbfbcda69992b8 /addons/web/static | |
| parent | 1144235d06a2ad42060c05d4ece145ce46a660e1 (diff) | |
| parent | 047e2b28de4653f11e097e6232d7fb79d54ce3af (diff) | |
[MERGE] forward port branch 12.0 up to 047e2b28de4
Diffstat (limited to 'addons/web/static')
| -rw-r--r-- | addons/web/static/lib/py.js/lib/py.js | 12 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome/action_manager_act_window.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/graph/graph_renderer.js | 9 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/pivot/pivot_view.js | 8 | ||||
| -rw-r--r-- | addons/web/static/src/scss/layout_background.scss | 54 | ||||
| -rw-r--r-- | addons/web/static/src/scss/layout_boxed.scss | 67 | ||||
| -rw-r--r-- | addons/web/static/src/scss/layout_clean.scss | 32 | ||||
| -rw-r--r-- | addons/web/static/src/scss/report.scss | 15 | ||||
| -rw-r--r-- | addons/web/static/tests/chrome/action_manager_tests.js | 56 | ||||
| -rw-r--r-- | addons/web/static/tests/core/py_utils_tests.js | 7 | ||||
| -rw-r--r-- | addons/web/static/tests/views/graph_tests.js | 33 | ||||
| -rw-r--r-- | addons/web/static/tests/views/pivot_tests.js | 17 |
12 files changed, 241 insertions, 71 deletions
diff --git a/addons/web/static/lib/py.js/lib/py.js b/addons/web/static/lib/py.js/lib/py.js index 06d834321de..bd794323995 100644 --- a/addons/web/static/lib/py.js/lib/py.js +++ b/addons/web/static/lib/py.js/lib/py.js @@ -282,7 +282,10 @@ var py = {}; var name_pattern = new RegExp('^' + Name + '$'); var strip = new RegExp('^' + Whitespace); return function tokenize(s) { - var max=s.length, tokens = [], start, end = undefined; + s = s + .replace(/\\\"/g, '\\u0022') // for double quote + .replace(/\\\'/g, '\\u0027'); // for single quote + var max=s.length, tokens = [], start, end; // /g flag makes repeated exec() have memory var pseudoprog = new RegExp(PseudoToken, 'g'); @@ -302,7 +305,6 @@ var py = {}; end = pseudoprog.lastIndex; // strip leading space caught by Whitespace var token = s.slice(start, end).replace(strip, ''); - var initial = token[0]; if (number_pattern.test(token)) { tokens.push(create(symbols['(number)'], { @@ -310,9 +312,13 @@ var py = {}; })); } else if (string_pattern.test(token)) { var m = string_pattern.exec(token); + var value = (m[3] !== undefined ? m[3] : m[5]); + value + .replace(/\\u0022/g, '"') + .replace(/\\u0027/g, "'"); tokens.push(create(symbols['(string)'], { unicode: !!(m[2] || m[4]), - value: (m[3] !== undefined ? m[3] : m[5]) + value: value })); } else if (token in symbols) { var symbol; diff --git a/addons/web/static/src/js/chrome/action_manager_act_window.js b/addons/web/static/src/js/chrome/action_manager_act_window.js index 04b06377d3f..c1667e9b9e6 100644 --- a/addons/web/static/src/js/chrome/action_manager_act_window.js +++ b/addons/web/static/src/js/chrome/action_manager_act_window.js @@ -635,7 +635,7 @@ ActionManager.include({ _.object(_.reject(_.pairs(env.context), function (pair) { return pair[0].match('^(?:(?:default_|search_default_|show_).+|' + '.+_view_ref|group_by|group_by_no_leaf|active_id|' + - 'active_ids)$') !== null; + 'active_ids|orderedBy)$') !== null; })) ); ctx.add(actionData.context || {}); diff --git a/addons/web/static/src/js/views/graph/graph_renderer.js b/addons/web/static/src/js/views/graph/graph_renderer.js index fe4efab1b20..38c2f02351e 100644 --- a/addons/web/static/src/js/views/graph/graph_renderer.js +++ b/addons/web/static/src/js/views/graph/graph_renderer.js @@ -337,8 +337,8 @@ return AbstractRenderer.extend({ var self = this; // Remove Undefined of first GroupBy - var graphData = _.filter(this.state.data, function(elem){ - return elem.labels[0] !== undefined; + var graphData = _.filter(this.state.data, function (elem) { + return elem.labels[0] !== undefined && elem.labels[0] !== _t("Undefined"); }); // undefined label value becomes a string 'Undefined' translated @@ -391,10 +391,9 @@ return AbstractRenderer.extend({ var tick = 0; var serie, tickLabel; var identity = function (p) {return p;}; - - for (var i = 0; i < this.state.data.length; i++) { + for (var i = 0; i < graphData.length; i++) { if (graphData[i].labels[0] !== tickLabel) { - tickLabel = this.state.data[i].labels[0]; + tickLabel = graphData[i].labels[0]; ticksLabels.push(tickLabel); tick++; } diff --git a/addons/web/static/src/js/views/pivot/pivot_view.js b/addons/web/static/src/js/views/pivot/pivot_view.js index 38d8d80a9d7..5e05a2fe7e7 100644 --- a/addons/web/static/src/js/views/pivot/pivot_view.js +++ b/addons/web/static/src/js/views/pivot/pivot_view.js @@ -70,9 +70,6 @@ var PivotView = AbstractView.extend({ widgets[name] = field.attrs.widget; } - if (field.attrs.string) { - measures[name].string = field.attrs.string; - } if (field.attrs.invisible && py.eval(field.attrs.invisible)) { delete measures[name]; @@ -89,6 +86,11 @@ var PivotView = AbstractView.extend({ if (field.attrs.type === 'measure' && !(field.attrs.name in measures)) { measures[field.attrs.name] = self.fields[field.attrs.name]; } + + if (field.attrs.string) { + measures[name].string = field.attrs.string; + } + if (field.attrs.type === 'measure' || 'operator' in field.attrs) { activeMeasures.push(name); measures[name] = self.fields[name]; diff --git a/addons/web/static/src/scss/layout_background.scss b/addons/web/static/src/scss/layout_background.scss index ff2d0cef3b0..9c47ac72a27 100644 --- a/addons/web/static/src/scss/layout_background.scss +++ b/addons/web/static/src/scss/layout_background.scss @@ -34,34 +34,48 @@ background-position: bottom center; background-repeat: no-repeat; min-height: 620px; + + .table { + border-top: 1px solid gray('300'); + } + + .table td, .table th { + border-top: none; + } thead tr th, h2 { color: $o-brand-odoo; } tbody { color: gray('700'); - tr:nth-child(odd) { - background-color: rgba(220, 205, 216, 0.2); - } - tr td { - border-top: none; + tr { + &:nth-child(odd) { + background-color: rgba(220, 205, 216, 0.2); + } + &.o_line_section { + color: $o-brand-odoo; + background-color: rgba(73, 80, 87, 0.2) !important; + } } } /*Total table*/ - .row > .col-4 > table { - tr:nth-child(odd) { - background-color: transparent !important; - } - tr:first-child td { - /*we could get rid of this rule if .border-black td would be terminated in report.scss*/ - border-top: none !important; - } - tr:last-child td { - color: $o-brand-odoo; - } - } - #total { - table tr:last-child td { - border-bottom: 1px solid black; + /* row div rule compat 12.0 */ + .row > div > table, + div#total table { + tr { + &:nth-child(odd) { + background-color: transparent !important; + } + /* first-child & last-child rule compat 12.0 */ + &:first-child, + &:last-child, + &.o_subtotal, + &.o_total { + border-top: none !important; + td { + color: $o-brand-odoo; + border-top: 1px solid gray('400') !important; + } + } } } } diff --git a/addons/web/static/src/scss/layout_boxed.scss b/addons/web/static/src/scss/layout_boxed.scss index b0b2fb1f743..bf19b6fb7ae 100644 --- a/addons/web/static/src/scss/layout_boxed.scss +++ b/addons/web/static/src/scss/layout_boxed.scss @@ -23,52 +23,73 @@ } } .o_report_layout_boxed { - // This is not a general rule since the id is not used in all the reports, - // we should make a general structure for report body to use it everywhere - #informations { - border: 1px solid gray('700'); - padding-top: 10px; - margin: 0; - } > h2 { text-transform: uppercase; } table { border: 1px solid gray('700'); thead { + border-bottom: 2px solid gray('700'); tr th { - border-bottom: 3px solid gray('700') !important; text-transform: uppercase; + border: 1px solid gray('700'); } } tbody { color: gray('700'); tr { td { + // remove border-top from standard layout border-top: none; border-right: 1px solid gray('700'); } - td:last-child { + &.o_line_section td, + &.o_line_note td, + &.is-subtotal td { + border-top: 1px solid gray('700'); + border-bottom: 1px solid gray('700'); + } + &.o_line_section td { + background-color: gray('700'); + color: #fff; + } + &.is-subtotal, + td.o_price_total { background-color: gray('200'); } } } } + /* compat 12.0 */ + .page > table:not(.o_main_table) tr td:last-child { + background-color: gray('200'); + } + /* compat 12.0 */ + .row:not(#total) > div > table tr:not(:first-child):not(:last-child) td:last-child { + background-color: gray('200'); + } /*Total table*/ - .row > .col-4 > table { - td { - border-right: none; - } - tr:last-child td, tr:first-child td { - /*we could get rid of this rule if .border-black td would be terminated in report.scss*/ - border-top: none !important; - } - tr:first-child td { - background-color: transparent; - } - tr:last-child td { - background-color: gray('700'); - color: #fff; + /* row div rule compat 12.0 */ + .row > div > table, + div#total table { + tr { + &:first-child, + &.o_subtotal { + border-bottom: 1px solid gray('700'); + + td:first-child { + border-right: none; + } + } + &:last-child td, + &.o_total td { + background-color: gray('700'); + color: #fff; + + &:first-child { + border-right: none; + } + } } } } diff --git a/addons/web/static/src/scss/layout_clean.scss b/addons/web/static/src/scss/layout_clean.scss index 06b2e808dd4..910abc763a4 100644 --- a/addons/web/static/src/scss/layout_clean.scss +++ b/addons/web/static/src/scss/layout_clean.scss @@ -18,12 +18,10 @@ font-weight: bolder; } .pagenumber { - width: 35px; - height: 35px; border: 3px solid $o-brand-odoo; background-color: $o-brand-primary; color: white; - padding-top: 6px; + padding: 4px 8px; text-align: center; } } @@ -36,6 +34,10 @@ color: $o-brand-odoo; } table { + &.o_main_table { + margin-bottom: 0; + } + thead { color: $o-brand-odoo; tr th { @@ -66,18 +68,22 @@ } } /*Total table*/ - .row > .col-4 { - width: 43%; - position: relative; - top: -20px; - > table { - tr:last-child td { - border-top: 1px solid gray('200') !important; - } - tr:first-child td { - /*we could get rid of this rule if .border-black td would be terminated in report.scss*/ + /* compat 12.0 */ + .row:not(#total) > div:has(table) { + top: -16px; + } + /* row col rule compat 12.0 */ + .row > div > table, + div#total table { + tr { + &:first-child td, + &.o_subtotal { border-top: none !important; } + &:last-child td, + &.o_total { + border-top: 1px solid gray('200') !important; + } } } } diff --git a/addons/web/static/src/scss/report.scss b/addons/web/static/src/scss/report.scss index 37a7630225b..e901b5b9364 100644 --- a/addons/web/static/src/scss/report.scss +++ b/addons/web/static/src/scss/report.scss @@ -44,3 +44,18 @@ body { .o_underline { text-decoration: underline; } + +/*Total table*/ +div#total { + page-break-inside: avoid; + table { + tr { + &.o_subtotal, + &.o_total { + td { + border-top: 1px solid black !important; + } + } + } + } +} diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index 6c0b0d96703..7eea78ded29 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -2202,6 +2202,62 @@ QUnit.module('ActionManager', { actionManager.destroy(); }); + QUnit.test('orderedBy in context is not propagated when executing another action', function (assert) { + assert.expect(6); + + this.data.partner.fields.foo.sortable = true, + + this.archs['partner,false,form'] = '<header>' + + '<button name="8" string="Execute action" type="action"/>' + + '</header>'; + + var searchReadCount = 0; + var actionManager = createActionManager({ + actions: this.actions, + archs: this.archs, + data: this.data, + mockRPC: function (route, args) { + if (route === '/web/dataset/search_read') { + if (searchReadCount === 1) { + assert.strictEqual(args.model, 'partner'); + assert.notOk(args.sort); + } + if (searchReadCount === 2) { + assert.strictEqual(args.model, 'partner'); + assert.strictEqual(args.sort, "foo ASC"); + } + if (searchReadCount === 3) { + assert.strictEqual(args.model, 'pony'); + assert.notOk(args.sort); + } + searchReadCount += 1; + } + return this._super.apply(this, arguments); + }, + }); + actionManager.doAction(3); + + // Simulate the activation of a filter + var searchData = { + domains: [[["foo", "=", "yop"]]], + contexts: [{ + orderedBy: [], + }], + }; + actionManager.trigger_up('search', searchData); + + // Sort records + actionManager.$('.o_list_view th.o_column_sortable').click(); + + // get to the form view of the model, on the first record + actionManager.$('.o_data_cell:first').click(); + + // Change model by clicking on the button within the form + actionManager.$('.o_form_view button').click(); + + actionManager.destroy(); + }); + QUnit.test('breadcrumbs are updated when switching between views', function (assert) { assert.expect(10); diff --git a/addons/web/static/tests/core/py_utils_tests.js b/addons/web/static/tests/core/py_utils_tests.js index d59fd30f957..be5760fc6c7 100644 --- a/addons/web/static/tests/core/py_utils_tests.js +++ b/addons/web/static/tests/core/py_utils_tests.js @@ -1254,6 +1254,13 @@ QUnit.module('core', function () { assert.checkAST(expr); }); + QUnit.test("parse escaped quoted strings", function (assert) { + assert.expect(2); + + assert.checkAST(`'\"'`, "a string containing \""); + assert.checkAST(`'\'`, "a string containing \'"); + }); + QUnit.module('pyutils (_normalizeDomain)'); QUnit.assert.checkNormalization = function (domain, normalizedDomain) { diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js index 73f2179dc8f..d651afc030c 100644 --- a/addons/web/static/tests/views/graph_tests.js +++ b/addons/web/static/tests/views/graph_tests.js @@ -785,13 +785,40 @@ QUnit.module('Views', { '</graph>', }); - assert.strictEqual(graph.$("svg.nvd3-svg:contains('Undefined')").length, 0); - assert.strictEqual(graph.$("svg.nvd3-svg:contains('March')").length, 1); + assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0); + assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1); testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=bar]')); - assert.strictEqual(graph.$("svg.nvd3-svg:contains('Undefined')").length, 1); + assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 1); + assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1); + + graph.destroy(); + }); + + QUnit.test('Undefined should appear in bar, pie graph but not in line graph with multiple groupbys', function (assert) { + assert.expect(6); + + var graph = createView({ + View: GraphView, + model: "foo", + groupBy:['date', 'color_id'], + data: this.data, + arch: '<graph string="Partners" type="line">' + + '<field name="bar"/>' + + '</graph>', + }); + + assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0); assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1); + graph.$buttons.find('.o_graph_button[data-mode=bar]').click(); + assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 1); + assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1); + + // Undefined should not appear after switching back to line chart + graph.$buttons.find('.o_graph_button[data-mode=line]').click(); + assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0); + assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1); graph.destroy(); }); }); diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js index 46c28529bed..3e3ba9fd89a 100644 --- a/addons/web/static/tests/views/pivot_tests.js +++ b/addons/web/static/tests/views/pivot_tests.js @@ -149,6 +149,23 @@ QUnit.module('Views', { pivot.destroy(); }); + QUnit.test('pivot rendering with string attribute on non stored field', function (assert) { + assert.expect(1); + + this.data.partner.fields.fubar = {string: "Fubar", type: "integer", store:false}; + + var pivot = createView({ + View: PivotView, + model: "partner", + data: this.data, + arch: '<pivot string="Partners">' + + '<field name="fubar" string="fubar" type="measure"/>' + + '</pivot>', + }); + assert.ok(pivot.$el.hasClass('o_pivot'),'Non stored fields can have a string attribute'); + pivot.destroy(); + }); + QUnit.test('pivot rendering with invisible attribute on field', function (assert) { assert.expect(2); // when invisible, a field should neither be an active measure, |
