summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-12-12 11:38:25 +0100
committerChristophe Simonis <chs@odoo.com>2018-12-12 11:38:25 +0100
commitf351dd8cab980a67ee17c431574d8ba9c37b8fdc (patch)
tree2cb6e64d0a5083aade80206ea7fbfbcda69992b8 /addons/web/static
parent1144235d06a2ad42060c05d4ece145ce46a660e1 (diff)
parent047e2b28de4653f11e097e6232d7fb79d54ce3af (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.js12
-rw-r--r--addons/web/static/src/js/chrome/action_manager_act_window.js2
-rw-r--r--addons/web/static/src/js/views/graph/graph_renderer.js9
-rw-r--r--addons/web/static/src/js/views/pivot/pivot_view.js8
-rw-r--r--addons/web/static/src/scss/layout_background.scss54
-rw-r--r--addons/web/static/src/scss/layout_boxed.scss67
-rw-r--r--addons/web/static/src/scss/layout_clean.scss32
-rw-r--r--addons/web/static/src/scss/report.scss15
-rw-r--r--addons/web/static/tests/chrome/action_manager_tests.js56
-rw-r--r--addons/web/static/tests/core/py_utils_tests.js7
-rw-r--r--addons/web/static/tests/views/graph_tests.js33
-rw-r--r--addons/web/static/tests/views/pivot_tests.js17
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,