From a597d3376c56c506307a1b438e2f0c94b83bea87 Mon Sep 17 00:00:00 2001 From: Julia Radzhabova Date: Fri, 25 Sep 2020 14:44:15 +0300 Subject: [PATCH] Add focus manager component for using in modal windows. [SSE] Use focus manager for windows with input fields, comboboxes, listview. --- apps/common/main/lib/component/ComboBox.js | 7 +- apps/common/main/lib/component/DataView.js | 5 +- .../common/main/lib/component/FocusManager.js | 130 ++++++++++++++++++ apps/common/main/lib/component/Window.js | 6 +- .../main/app/view/ChartDataRangeDialog.js | 10 +- .../main/app/view/FormatSettingsDialog.js | 26 +++- .../main/app/view/FormulaDialog.js | 17 ++- .../main/app/view/FormulaWizard.js | 5 +- .../main/app/view/PageMarginsDialog.js | 9 +- 9 files changed, 193 insertions(+), 22 deletions(-) create mode 100644 apps/common/main/lib/component/FocusManager.js diff --git a/apps/common/main/lib/component/ComboBox.js b/apps/common/main/lib/component/ComboBox.js index 78a7b0a22..abb993cd1 100644 --- a/apps/common/main/lib/component/ComboBox.js +++ b/apps/common/main/lib/component/ComboBox.js @@ -86,7 +86,8 @@ define([ displayField: 'displayValue', valueField : 'value', search : false, - scrollAlwaysVisible: false + scrollAlwaysVisible: false, + takeFocusOnClose: false }, template: _.template([ @@ -340,6 +341,10 @@ define([ this.cmpEl.find('.dropdown-toggle').blur(); this.trigger('hide:after', this, e, isFromInputControl); Common.NotificationCenter.trigger('menu:hide', this, isFromInputControl); + if (this.options.takeFocusOnClose) { + var me = this; + setTimeout(function(){me._input.focus();}, 1); + } }, onAfterKeydownMenu: function(e) { diff --git a/apps/common/main/lib/component/DataView.js b/apps/common/main/lib/component/DataView.js index 723389239..855f52d0f 100644 --- a/apps/common/main/lib/component/DataView.js +++ b/apps/common/main/lib/component/DataView.js @@ -242,6 +242,7 @@ define([ me.listenStoreEvents= (me.options.listenStoreEvents!==undefined) ? me.options.listenStoreEvents : true; me.allowScrollbar = (me.options.allowScrollbar!==undefined) ? me.options.allowScrollbar : true; me.scrollAlwaysVisible = me.options.scrollAlwaysVisible || false; + me.tabindex = me.options.tabindex || 0; if (me.parentMenu) me.parentMenu.options.restoreHeight = (me.options.restoreHeight>0); me.rendered = false; @@ -678,7 +679,7 @@ define([ if (this.enableKeyEvents && this.handleSelect) { var el = $(this.el).find('.inner').addBack().filter('.inner'); el.addClass('canfocused'); - el.attr('tabindex', '0'); + el.attr('tabindex', this.tabindex.toString()); el.on((this.parentMenu && this.useBSKeydown) ? 'dataview:keydown' : 'keydown', _.bind(this.onKeyDown, this)); } }, @@ -1120,7 +1121,7 @@ define([ if (this.enableKeyEvents && this.handleSelect) { var el = $(this.el).find('.inner').addBack().filter('.inner'); el.addClass('canfocused'); - el.attr('tabindex', '0'); + el.attr('tabindex', this.tabindex.toString()); el.on((this.parentMenu && this.useBSKeydown) ? 'dataview:keydown' : 'keydown', _.bind(this.onKeyDown, this)); } }, diff --git a/apps/common/main/lib/component/FocusManager.js b/apps/common/main/lib/component/FocusManager.js new file mode 100644 index 000000000..877dd445b --- /dev/null +++ b/apps/common/main/lib/component/FocusManager.js @@ -0,0 +1,130 @@ +/* + * + * (c) Copyright Ascensio System SIA 2010-2020 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ +/** + * FocusManager.js + * + * Created by Julia Radzhabova on 24.09.2020 + * Copyright (c) 2020 Ascensio System SIA. All rights reserved. + * + */ + + +if (Common === undefined) + var Common = {}; + +if (Common.UI === undefined) { + Common.UI = {}; +} + +Common.UI.FocusManager = function (tabindex, parent) { + var register = function(fields, options, tabindex) { + var arr = [], + selector, + el; + if (typeof options==='string') { + selector = options; + } else { + el = options; + } + if (!fields.forEach) { + fields = [fields]; + if (el) + el = [el]; + } + + fields.forEach(function(cmp, index) { + var elem = selector ? (cmp.$el || $(cmp.el)).find(selector) : (el && el[index] ? el[index] : cmp); + elem && elem.attr && elem.attr('tabindex', tabindex.toString()); + arr.push({ + cmp: cmp, + el: elem, + selector: selector + }); + }); + return arr; + }; + + return { + tabindex: tabindex || 0, + parent: parent, + fields: [], + + add: function(fields, options) { // options may be selector or component.el + this.fields = this.fields.concat(register(fields, options, this.tabindex)); + !this.trapFirst && this.addTraps(); + }, + + insert: function(field, index, options) { + this.fields.splice(index, 0, register(field, options, this.tabindex)); + }, + + remove: function(index) { + this.fields.splice(index, 1); + }, + + addTraps: function() { + if (!this.parent || !this.parent.$window) return; + + var me = this; + this.trapFirst = $(''); + this.trapFirst.on('focus', function() { + for (var i=0; i