diff options
| author | Martin Trigaux <mat@odoo.com> | 2019-07-24 07:36:59 +0000 |
|---|---|---|
| committer | Martin Trigaux <mat@odoo.com> | 2019-07-24 10:32:23 +0000 |
| commit | a98427834e00380e2e63e08668f5c2b069e3c2ea (patch) | |
| tree | fbefd4a26124efbaf5e6b4bdbf58ec570014c896 /addons/web/static | |
| parent | 4e6ee3ac97041653ff15a77abd77084dc0c9f525 (diff) | |
| parent | 860ab5a1c28ba85d7a193d68cfbbb1063bbf0651 (diff) | |
[MERGE] Forward port of saas-12.2 to saas-12.3 up to 860ab5a1c28ba
closes odoo/odoo#35119
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
Diffstat (limited to 'addons/web/static')
10 files changed, 137 insertions, 19 deletions
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 28c7d96b5d8..ec5661aa0a7 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 @@ -295,6 +295,7 @@ ActionManager.include({ } var lazyViewDef; + var lazyControllerID; if (lazyView) { // if the main view is lazy-loaded, its (lazy-loaded) controller is inserted // into the controller stack (so that breadcrumbs can be correctly computed), @@ -304,6 +305,7 @@ ActionManager.include({ // this controller being lazy-loaded, this call is actually sync lazyViewDef = self._createViewController(action, lazyView.type, {}, {lazy: true}) .then(function (lazyLoadedController) { + lazyControllerID = lazyLoadedController.jsID; self.controllerStack.push(lazyLoadedController.jsID); }); } @@ -322,7 +324,13 @@ ActionManager.include({ action.controllerID = controller.jsID; return self._executeAction(action, options); }) - .guardedCatch(self._destroyWindowAction.bind(self, action)); + .guardedCatch(function () { + if (lazyControllerID) { + var index = self.controllerStack.indexOf(lazyControllerID); + self.controllerStack = self.controllerStack.slice(0, index); + } + self._destroyWindowAction(action); + }); }); }, /** diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 9db594b60db..23adb8568de 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -620,9 +620,12 @@ var FormController = BasicController.extend({ * @private * @param {OdooEvent} event */ - _onFormDialogDiscarded: function(e) { - e.stopPropagation(); - this.renderer.focusLastActivatedWidget(); + _onFormDialogDiscarded: function(ev) { + ev.stopPropagation(); + var isFocused = this.renderer.focusLastActivatedWidget(); + if (ev.data.callback) { + ev.data.callback(_.str.toBool(isFocused)); + } }, /** * Opens a one2many record (potentially new) in a dialog. This handler is diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 96125727feb..5c7ef00ca67 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -194,8 +194,11 @@ var FormRenderer = BasicRenderer.extend({ * field. */ focusLastActivatedWidget: function () { - this._activateNextFieldWidget(this.state, this.lastActivatedFieldIndex - 1, - { noAutomaticCreate: true }); + if (this.lastActivatedFieldIndex !== -1) { + return this._activateNextFieldWidget(this.state, this.lastActivatedFieldIndex - 1, + { noAutomaticCreate: true }); + } + return false; }, /** * returns the active tab pages for each notebook diff --git a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js index 0c484931aae..6a9caa99a39 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js +++ b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js @@ -150,7 +150,7 @@ var KanbanColumnProgressBar = Widget.extend({ }); // Adapt active state - $bar.toggleClass('active progress-bar-striped', key === self.activeFilter); + $bar.toggleClass('progress-bar-animated progress-bar-striped', key === self.activeFilter); // Adapt width $bar.removeClass('o_bar_has_records transition-off'); diff --git a/addons/web/static/src/js/views/view_dialogs.js b/addons/web/static/src/js/views/view_dialogs.js index 75be3a3d07e..08150b96c86 100644 --- a/addons/web/static/src/js/views/view_dialogs.js +++ b/addons/web/static/src/js/views/view_dialogs.js @@ -241,8 +241,13 @@ var FormViewDialog = ViewDialog.extend({ * @override */ _focusOnClose: function() { - this.trigger_up('form_dialog_discarded'); - return true; + var isFocusSet = false; + this.trigger_up('form_dialog_discarded', { + callback: function (isFocused) { + isFocusSet = isFocused; + }, + }); + return isFocusSet; }, /** @@ -424,8 +429,13 @@ var SelectCreateDialog = ViewDialog.extend({ * @override */ _focusOnClose: function() { - this.trigger_up('form_dialog_discarded'); - return true; + var isFocusSet = false; + this.trigger_up('form_dialog_discarded', { + callback: function (isFocused) { + isFocusSet = isFocused; + }, + }); + return isFocusSet; }, }); diff --git a/addons/web/static/src/xml/kanban.xml b/addons/web/static/src/xml/kanban.xml index 0908d052980..9077df2e0ad 100644 --- a/addons/web/static/src/xml/kanban.xml +++ b/addons/web/static/src/xml/kanban.xml @@ -110,7 +110,7 @@ <div class="o_kanban_counter_progress progress"> <t t-foreach="widget.colors" t-as="color"> <t t-set="count" t-value="widget.subgroupCounts and widget.subgroupCounts[color] or 0"/> - <div t-attf-class="progress-bar transition-off bg-#{color_value}-full#{count ? ' o_bar_has_records' : ''}#{widget.activeFilter ? ' active progress-bar-striped' : ''}" + <div t-attf-class="progress-bar transition-off bg-#{color_value}-full#{count ? ' o_bar_has_records' : ''}#{widget.activeFilter ? ' progress-bar-animated progress-bar-striped' : ''}" t-att-data-filter="color" t-attf-data-original-title="#{count} #{color}" aria-valuemin="0" aria-valuemax="100" t-att-aria-valuenow="count*100" role="progressbar" diff --git a/addons/web/static/src/xml/menu.xml b/addons/web/static/src/xml/menu.xml index 6a4749d1c25..086d676e02a 100644 --- a/addons/web/static/src/xml/menu.xml +++ b/addons/web/static/src/xml/menu.xml @@ -20,7 +20,7 @@ </a> <div class="dropdown-menu" role="menu"> <t t-foreach="widget.getApps()" t-as="app"> - <a role="menuitem" + <a role="menuitem" t-attf-href="#menu_id=#{app.menuID}" class="dropdown-item o_app" t-att-data-menu-id="app.menuID" t-att-data-menu-xmlid="app.xmlID" diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index db3908ffd9f..4d05d723ccf 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -880,6 +880,41 @@ QUnit.module('ActionManager', { actionManager.destroy(); }); + QUnit.test('lazy loaded multi record view with failing mono record one', async function (assert) { + assert.expect(4); + + var actionManager = await createActionManager({ + actions: this.actions, + archs: this.archs, + data: this.data, + mockRPC: function (route, args) { + if (args.method === 'read') { + return Promise.reject(); + } + return this._super.apply(this, arguments); + }, + }); + + await actionManager.loadState({ + action: 3, + id: 2, + view_type: 'form', + }).then(function () { + assert.ok(false, 'should not resolve the deferred'); + }).catch(function () { + assert.ok(true, 'should reject the deferred'); + }); + + assert.containsNone(actionManager, '.o_form_view'); + assert.containsNone(actionManager, '.o_list_view'); + + await actionManager.doAction(1); + + assert.containsOnce(actionManager, '.o_kanban_view'); + + actionManager.destroy(); + }); + QUnit.test('change the viewType of the current action', async function (assert) { assert.expect(13); diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 406370b0a2b..9c60f7f5ca1 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -311,8 +311,8 @@ QUnit.module('relational_fields', { await testUtils.form.clickEdit(form); await testUtils.dom.click(form.$('.o_external_button')); - var $originalModal = $('.modal-dialog'); - var $focusedModal = $(document.activeElement).closest('.modal-dialog'); + var $originalModal = $('.modal'); + var $focusedModal = $(document.activeElement).closest('.modal'); assert.equal($originalModal.length, 1, 'There should be one modal'); assert.equal($originalModal[0], $focusedModal[0], 'Modal is focused'); @@ -320,8 +320,8 @@ QUnit.module('relational_fields', { // Open many2one modal of field in many2one modal await testUtils.dom.click($originalModal.find('.o_external_button')); - var $modals = $('.modal-dialog'); - $focusedModal = $(document.activeElement).closest('.modal-dialog'); + var $modals = $('.modal'); + $focusedModal = $(document.activeElement).closest('.modal'); assert.equal($modals.length, 2, 'There should be two modals'); assert.equal($modals[1], $focusedModal[0], 'Last modal is focused'); @@ -329,8 +329,8 @@ QUnit.module('relational_fields', { // Close second modal await testUtils.dom.click($modals.last().find('button[class="close"]')); - var $modal = $('.modal-dialog'); - $focusedModal = $(document.activeElement).closest('.modal-dialog'); + var $modal = $('.modal'); + $focusedModal = $(document.activeElement).closest('.modal'); assert.equal($modal.length, 1, 'There should be one modal'); assert.equal($modal[0], $originalModal[0], 'First modal is still opened'); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index f1c12414fcf..2c5eaa3e627 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -4865,6 +4865,65 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.module('focus and scroll test', async function () { + QUnit.test('no focus set on form when closing many2one modal if lastActivatedFieldIndex is not set', async function (assert) { + assert.expect(8); + + var form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<field name="display_name"/>' + + '<field name="foo"/>' + + '<field name="bar"/>' + + '<field name="p"/>' + + '<field name="timmy"/>' + + '<field name="product_ids"/>' + + '<field name="trululu"/>' + + '</form>', + res_id: 2, + archs: { + 'partner,false,list': '<tree><field name="display_name"/></tree>', + 'partner_type,false,list': '<tree><field name="name"/></tree>', + 'partner,false,form': '<form><field name="trululu"/></form>', + 'product,false,list': '<tree><field name="name"/></tree>', + }, + mockRPC: function (route, args) { + if (args.method === 'get_formview_id') { + return Promise.resolve(false); + } + return this._super(route, args); + }, + }); + + // set max-height to have scroll forcefully so that we can test scroll position after modal close + $('.o_content').css({'overflow': 'auto', 'max-height': '300px'}); + // Open many2one modal, lastActivatedFieldIndex will not set as we directly click on external button + await testUtils.form.clickEdit(form); + assert.strictEqual($(".o_content").scrollTop(), 0, "scroll position should be 0"); + + form.$(".o_field_many2one[name='trululu'] .o_input").focus(); + assert.notStrictEqual($(".o_content").scrollTop(), 0, "scroll position should not be 0"); + + await testUtils.dom.click(form.$('.o_external_button')); + // Close modal + await testUtils.dom.click($('.modal').last().find('button[class="close"]')); + assert.notStrictEqual($(".o_content").scrollTop(), 0, + "scroll position should not be 0 after closing modal"); + assert.containsNone(document.body, '.modal', 'There should be no modal'); + assert.doesNotHaveClass($('body'), 'modal-open', 'Modal is not said opened'); + assert.strictEqual(form.renderer.lastActivatedFieldIndex, -1, + "lastActivatedFieldIndex is -1"); + assert.equal(document.activeElement, $('body')[0], + 'body is focused, should not set focus on form widget'); + assert.notStrictEqual(document.activeElement, form.$('.o_field_many2one[name="trululu"] .o_input'), + 'field widget should not be focused when lastActivatedFieldIndex is -1'); + + form.destroy(); + }); + }); + QUnit.test('in create mode, autofocus fields are focused', async function (assert) { assert.expect(1); |
