diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-07-13 14:32:05 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-07-13 14:32:05 +0200 |
| commit | f3929aa0f75c2d3ac039bfc5bd41194516ae5571 (patch) | |
| tree | 6ef909a475e4e99d1e9eb9c3d2e6c891fc7ad892 /addons/web | |
| parent | e8fc62ec74f94fd1bfea105a15082dfede4dc987 (diff) | |
| parent | 87dadc5bc83714cb0e748824f57e4cd35d02bbbf (diff) | |
[MERGE] forward port branch saas-11.2 up to 87dadc5bc83
Diffstat (limited to 'addons/web')
| -rw-r--r-- | addons/web/controllers/main.py | 2 | ||||
| -rw-r--r-- | addons/web/models/ir_http.py | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome/control_panel.js | 14 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/list/list_editable_renderer.js | 12 | ||||
| -rw-r--r-- | addons/web/static/tests/chrome/action_manager_tests.js | 56 | ||||
| -rw-r--r-- | addons/web/static/tests/views/form_tests.js | 36 | ||||
| -rw-r--r-- | addons/web/views/report_templates.xml | 3 |
7 files changed, 118 insertions, 9 deletions
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index f4cddcc1ee2..41d5d229772 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1496,6 +1496,8 @@ class ExcelExport(ExportFormat, http.Controller): if isinstance(cell_value, pycompat.string_types): cell_value = re.sub("\r", " ", pycompat.to_text(cell_value)) + # Excel supports a maximum of 32767 characters in each cell: + cell_value = cell_value[:32767] elif isinstance(cell_value, datetime.datetime): cell_style = datetime_style elif isinstance(cell_value, datetime.date): diff --git a/addons/web/models/ir_http.py b/addons/web/models/ir_http.py index bbe793812b9..46bc09a3022 100644 --- a/addons/web/models/ir_http.py +++ b/addons/web/models/ir_http.py @@ -26,7 +26,7 @@ class Http(models.AbstractModel): "session_id": request.session.sid, "uid": request.session.uid, "is_system": user._is_system(), - "is_superuser": user._is_superuser(), + "is_superuser": user._is_superuser() if request.session.uid else False, "user_context": request.session.get_context() if request.session.uid else {}, "db": request.session.db, "server_version": version_info.get('server_version'), @@ -37,7 +37,7 @@ class Http(models.AbstractModel): "company_id": user.company_id.id if request.session.uid else None, "partner_id": user.partner_id.id if request.session.uid and user.partner_id else None, "user_companies": {'current_company': (user.company_id.id, user.company_id.name), 'allowed_companies': [(comp.id, comp.name) for comp in user.company_ids]} if display_switch_company_menu else False, - "currencies": self.get_currencies(), + "currencies": self.get_currencies() if request.session.uid else {}, "web.base.url": self.env['ir.config_parameter'].sudo().get_param('web.base.url', default=''), } diff --git a/addons/web/static/src/js/chrome/control_panel.js b/addons/web/static/src/js/chrome/control_panel.js index 4104f37bd3e..0913b574a3d 100644 --- a/addons/web/static/src/js/chrome/control_panel.js +++ b/addons/web/static/src/js/chrome/control_panel.js @@ -148,15 +148,25 @@ var ControlPanel = Widget.extend({ } // Detach control_panel old content and attach new elements + var toDetach = this.nodes; + if (status.searchview && this.searchview === status.searchview) { + // If the searchview is the same as before, don't detach it s.t. + // we don't loose any floating content, nor the focus + toDetach = _.omit(toDetach, '$searchview'); + new_cp_content = _.omit(new_cp_content, '$searchview'); + } if (options.clear) { - this._detach_content(this.nodes); + this._detach_content(toDetach); // Show the searchview buttons area, which might have been hidden by // the searchview, as client actions may insert elements into it this.nodes.$searchview_buttons.show(); } else { - this._detach_content(_.pick(this.nodes, _.keys(new_cp_content))); + this._detach_content(_.pick(toDetach, _.keys(new_cp_content))); } this._attach_content(new_cp_content); + if (options.clear || status.searchview) { + this.searchview = status.searchview; + } // Update the searchview and switch buttons if (status.searchview || options.clear) { diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index a12b85abdd0..a0ce8d31af4 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -861,8 +861,16 @@ ListRenderer.include({ */ _onRemoveIconClick: function (event) { event.stopPropagation(); - var id = $(event.target).closest('tr').data('id'); - this.trigger_up('list_record_remove', {id: id}); + var $row = $(event.target).closest('tr'); + var id = $row.data('id'); + if ($row.hasClass('o_selected_row')) { + this.trigger_up('list_record_remove', {id: id}); + } else { + var self = this; + this.unselectRow().then(function () { + self.trigger_up('list_record_remove', {id: id}); + }); + } }, /** * If the list view editable, just let the event bubble. We don't want to diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index dee1b0dbb3f..95e5742e95f 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -3431,6 +3431,62 @@ QUnit.module('ActionManager', { actionManager.destroy(); }); + + QUnit.module('Search View Action'); + + QUnit.test('search view should keep focus during do_search', function (assert) { + assert.expect(5); + + /* One should be able to type something in the search view, press on enter to + * make the facet and trigger the search, then do this process + * over and over again seamlessly. + * Verifying the input's value is a lot trickier than verifying the search_read + * because of how native events are handled in tests + */ + + var searchDeferred = $.Deferred(); + + var actionManager = createActionManager({ + actions: this.actions, + archs: this.archs, + data: this.data, + mockRPC: function (route, args) { + if (route === '/web/dataset/search_read') { + assert.step('search_read ' + args.domain); + if ( _.isEqual(args.domain, [['foo', 'ilike', 'm']])) { + return searchDeferred.then(this._super.bind(this, route, args)); + } + } + return this._super.apply(this, arguments); + } + }); + + actionManager.doAction(3); + + var $searchInput = $('.o_searchview input'); + $searchInput.trigger($.Event('keypress', {key: 'm', which: 109, keyCode: 109})); + $searchInput.trigger($.Event('keydown', {key: 'Enter', which: 13, keyCode: 13})); + + assert.verifySteps(["search_read ", + "search_read foo,ilike,m"]); + + // Triggering the do_search above will kill the current searchview Input + $searchInput = $('.o_searchview input'); + $searchInput.trigger($.Event('keypress', {key: 'o', which: 111, keyCode: 111})); + + // We have something in the input of the search view. Making the search_read + // return at this point will trigger the redraw of the view. + // However we want to hold on to what we just typed + searchDeferred.resolve(); + + $searchInput.trigger($.Event('keydown', {key: 'Enter', which: 13, keyCode: 13})); + + assert.verifySteps(["search_read ", + "search_read foo,ilike,m", + "search_read |,foo,ilike,m,foo,ilike,o"]); + + actionManager.destroy(); + }); }); }); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index f53bac54e3a..a6176ab4328 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -3117,6 +3117,42 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('delete a line in a one2many while editing another line triggers a warning', function (assert) { + assert.expect(3); + + this.data.partner.records[0].p = [1, 2]; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form>' + + '<field name="p">' + + '<tree editable="bottom">' + + '<field name="display_name" required="True"/>' + + '</tree>' + + '</field>' + + '</form>', + res_id: 1, + }); + + form.$buttons.find('.o_form_button_edit').click(); + form.$('.o_data_cell').first().click(); // edit first row + form.$('input').val('').trigger('input'); + form.$('.fa-trash-o').eq(1).click(); // delete second row + + assert.strictEqual($('.modal').find('.modal-title').first().text(), "Warning", + "Clicking out of a dirty line while editing should trigger a warning modal."); + + $('.modal').find('.btn-primary').click(); // discard changes + + assert.strictEqual(form.$('.o_data_cell').first().text(), "first record", + "Value should have been reset to what it was before editing began."); + assert.strictEqual(form.$('.o_data_row').length, 1, + "The other line should have been deleted."); + form.destroy(); + }); + QUnit.test('properly apply onchange on many2many fields', function (assert) { assert.expect(14); diff --git a/addons/web/views/report_templates.xml b/addons/web/views/report_templates.xml index c26e1e2bf45..a675bfbd161 100644 --- a/addons/web/views/report_templates.xml +++ b/addons/web/views/report_templates.xml @@ -14,9 +14,6 @@ <link href="/portal/static/src/less/portal.less" rel="stylesheet" type="text/less"/> <link href="/website/static/src/less/website.less" rel="stylesheet" type="text/less"/> - <!-- TODO: Put in the right report ..? --> - <link href="https://fonts.googleapis.com/css?family=Work+Sans:thin,light,regular,medium,bold,semi-bold" rel="stylesheet"/> - <link href="/web/static/lib/fontawesome/css/font-awesome.css" rel="stylesheet" type="text/css"/> <link href="/web/static/src/less/report.less" rel="stylesheet" type="text/less"/> |
