Add focus manager component for using in modal windows.
[SSE] Use focus manager for windows with input fields, comboboxes, listview.
This commit is contained in:
parent
2c1a84f727
commit
a597d3376c
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
},
|
||||
|
|
130
apps/common/main/lib/component/FocusManager.js
Normal file
130
apps/common/main/lib/component/FocusManager.js
Normal file
|
@ -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 = $('<span aria-hidden="true" tabindex="' + this.tabindex + '"></span>');
|
||||
this.trapFirst.on('focus', function() {
|
||||
for (var i=0; i<me.fields.length; i++) {
|
||||
var field = me.fields[i];
|
||||
if (field.cmp.isVisible ? field.cmp.isVisible() : field.cmp.is(':visible')) {
|
||||
var el = (field.selector) ? (field.cmp.$el || $(field.cmp.el)).find(field.selector) : field.el;
|
||||
el.focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.parent.$window.prepend(this.trapFirst);
|
||||
|
||||
this.trapLast = $('<span aria-hidden="true" tabindex="' + (this.tabindex+1) + '"></span>');
|
||||
this.trapLast.on('focus', function() {
|
||||
for (var i=me.fields.length-1; i>=0; i--) {
|
||||
var field = me.fields[i];
|
||||
if (field.cmp.isVisible ? field.cmp.isVisible() : field.cmp.is(':visible')) {
|
||||
var el = (field.selector) ? (field.cmp.$el || $(field.cmp.el)).find(field.selector) : field.el;
|
||||
el.focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.parent.$window.append(this.trapLast);
|
||||
},
|
||||
|
||||
setTabIndex: function (tabindex) {
|
||||
this.tabindex = tabindex;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -137,7 +137,8 @@
|
|||
|
||||
define([
|
||||
'common/main/lib/component/BaseView',
|
||||
'common/main/lib/component/CheckBox'
|
||||
'common/main/lib/component/CheckBox',
|
||||
'common/main/lib/component/FocusManager'
|
||||
], function () {
|
||||
'use strict';
|
||||
|
||||
|
@ -612,6 +613,9 @@ define([
|
|||
!this.initConfig.id && (this.initConfig.id = 'window-' + this.cid);
|
||||
!this.initConfig.tpl && (this.initConfig.tpl = '');
|
||||
|
||||
if (options.focusManager)
|
||||
this.focusManager = Common.UI.FocusManager(1, this);
|
||||
|
||||
Common.UI.BaseView.prototype.initialize.call(this, this.initConfig);
|
||||
},
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@ define([
|
|||
type: 0, // 0 - category, 1 - series
|
||||
width : 350,
|
||||
cls : 'modal-dlg',
|
||||
buttons: ['ok', 'cancel']
|
||||
buttons: ['ok', 'cancel'],
|
||||
focusManager: true
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
|
@ -171,9 +172,10 @@ define([
|
|||
|
||||
$window.find('.dlg-btn').on('click', _.bind(this.onBtnClick, this));
|
||||
|
||||
_.defer(function(){
|
||||
me.inputRange1.cmpEl.find('input').focus();
|
||||
}, 10);
|
||||
this.focusManager.add([me.inputRange1, me.inputRange2, me.inputRange3], '.form-control');
|
||||
setTimeout(function(){
|
||||
me.inputRange1.cmpEl.find('input').focus();
|
||||
}, 10);
|
||||
},
|
||||
|
||||
onPrimary: function() {
|
||||
|
|
|
@ -49,7 +49,8 @@ define([
|
|||
SSE.Views.FormatSettingsDialog = Common.Views.AdvancedSettingsWindow.extend(_.extend({
|
||||
options: {
|
||||
contentWidth: 284,
|
||||
height: 340
|
||||
height: 340,
|
||||
focusManager: true
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
|
@ -171,7 +172,8 @@ define([
|
|||
cls: 'input-group-nr',
|
||||
menuStyle: 'min-width: 264px;',
|
||||
editable: false,
|
||||
data: this.numFormatData
|
||||
data: this.numFormatData,
|
||||
takeFocusOnClose: true
|
||||
});
|
||||
this.cmbFormat.setValue(this.FormatType);
|
||||
this.cmbFormat.on('selected', _.bind(this.onFormatSelect, this));
|
||||
|
@ -182,7 +184,8 @@ define([
|
|||
menuStyle: 'min-width: 264px;max-height:235px;',
|
||||
editable: false,
|
||||
data: [],
|
||||
scrollAlwaysVisible: true
|
||||
scrollAlwaysVisible: true,
|
||||
takeFocusOnClose: true
|
||||
});
|
||||
this.cmbNegative.on('selected', _.bind(this.onNegativeSelect, this));
|
||||
|
||||
|
@ -210,7 +213,8 @@ define([
|
|||
menuStyle: 'min-width: 264px;max-height:235px;',
|
||||
editable: false,
|
||||
data: [],
|
||||
scrollAlwaysVisible: true
|
||||
scrollAlwaysVisible: true,
|
||||
takeFocusOnClose: true
|
||||
});
|
||||
this.cmbSymbols.on('selected', _.bind(this.onSymbolsSelect, this));
|
||||
|
||||
|
@ -220,7 +224,8 @@ define([
|
|||
menuStyle: 'min-width: 264px;max-height:235px;',
|
||||
editable: false,
|
||||
data: [],
|
||||
scrollAlwaysVisible: true
|
||||
scrollAlwaysVisible: true,
|
||||
takeFocusOnClose: true
|
||||
});
|
||||
this.cmbType.on('selected', _.bind(this.onTypeSelect, this));
|
||||
|
||||
|
@ -230,7 +235,8 @@ define([
|
|||
menuStyle: 'min-width: 310px;max-height:235px;',
|
||||
editable: false,
|
||||
data: [],
|
||||
scrollAlwaysVisible: true
|
||||
scrollAlwaysVisible: true,
|
||||
takeFocusOnClose: true
|
||||
});
|
||||
this.cmbCode.on('selected', _.bind(this.onCodeSelect, this));
|
||||
|
||||
|
@ -243,11 +249,17 @@ define([
|
|||
|
||||
this.lblExample = this.$window.find('#format-settings-label-example');
|
||||
|
||||
this.focusManager.add([this.cmbFormat, this.spnDecimal, this.cmbSymbols, this.cmbNegative, this.cmbType, this.cmbCode], '.form-control');
|
||||
|
||||
this.afterRender();
|
||||
},
|
||||
|
||||
afterRender: function() {
|
||||
this._setDefaults(this.props);
|
||||
var cmp = this.cmbFormat;
|
||||
setTimeout(function(){
|
||||
(cmp.$el || $(cmp.el)).find('.form-control').focus();
|
||||
}, 10);
|
||||
},
|
||||
|
||||
show: function() {
|
||||
|
@ -489,7 +501,7 @@ define([
|
|||
this.lblExample.text(this.api.asc_getLocaleExample(this.Format));
|
||||
|
||||
this._decimalPanel.toggleClass('hidden', !hasDecimal);
|
||||
this._negativePanel.css('visibility', hasNegative ? '' : 'hidden');
|
||||
this._negativePanel.toggleClass('hidden', !hasNegative);
|
||||
this._separatorPanel.toggleClass('hidden', !hasSeparator);
|
||||
this._typePanel.toggleClass('hidden', !hasType);
|
||||
this._symbolsPanel.toggleClass('hidden', !hasSymbols);
|
||||
|
|
|
@ -63,7 +63,8 @@ define([
|
|||
contentTemplate : '',
|
||||
title : t.txtTitle,
|
||||
items : [],
|
||||
buttons: null
|
||||
buttons: null,
|
||||
focusManager: true
|
||||
}, options);
|
||||
|
||||
this.template = options.template || [
|
||||
|
@ -114,6 +115,7 @@ define([
|
|||
}
|
||||
me.filterFormulas();
|
||||
});
|
||||
this.focusManager.add(this.inputSearch._input);
|
||||
|
||||
this.btnOk = new Common.UI.Button({
|
||||
el: $('#formula-dlg-btn-ok')
|
||||
|
@ -149,9 +151,10 @@ define([
|
|||
|
||||
if (this.cmbListFunctions) {
|
||||
this.inputSearch.setValue('');
|
||||
_.delay(function (me) {
|
||||
var me = this;
|
||||
setTimeout(function () {
|
||||
me.inputSearch.$el.find('input').focus();
|
||||
}, 100, this);
|
||||
}, 100);
|
||||
}
|
||||
this._preventCloseCellEditor = false;
|
||||
},
|
||||
|
@ -242,10 +245,11 @@ define([
|
|||
menuStyle : 'min-width: 100%;',
|
||||
cls : 'input-group-nr',
|
||||
data : groupsListItems,
|
||||
editable : false
|
||||
editable : false,
|
||||
takeFocusOnClose: true
|
||||
});
|
||||
|
||||
this.cmbFuncGroup.on('selected', _.bind(this.onSelectGroup, this));
|
||||
this.focusManager.add(this.cmbFuncGroup, '.form-control');
|
||||
} else {
|
||||
this.cmbFuncGroup.setData(groupsListItems);
|
||||
}
|
||||
|
@ -266,6 +270,7 @@ define([
|
|||
this.cmbListFunctions = new Common.UI.ListView({
|
||||
el: $('#formula-dlg-combo-functions'),
|
||||
store: this.functions,
|
||||
tabindex: 1,
|
||||
itemTemplate: _.template('<div id="<%= id %>" class="list-item" style="pointer-events:none;"><%= value %></div>')
|
||||
});
|
||||
|
||||
|
@ -275,6 +280,8 @@ define([
|
|||
this.cmbListFunctions.onKeyDown = _.bind(this.onKeyDown, this.cmbListFunctions);
|
||||
this.cmbListFunctions.scrollToRecord = _.bind(this.onScrollToRecordCustom, this.cmbListFunctions);
|
||||
this.onUpdateFocus();
|
||||
|
||||
this.focusManager.add(this.cmbListFunctions, '.listview');
|
||||
}
|
||||
|
||||
if (this.functions) {
|
||||
|
|
|
@ -46,7 +46,8 @@ define([
|
|||
SSE.Views.FormulaWizard = Common.Views.AdvancedSettingsWindow.extend(_.extend({
|
||||
options: {
|
||||
contentWidth: 580,
|
||||
height: 397
|
||||
height: 397,
|
||||
focusManager: true
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
|
@ -281,6 +282,8 @@ define([
|
|||
else
|
||||
me.args[argcount].lblName.html(me.args[argcount].argName);
|
||||
me.args[argcount].lblValue.html('= '+ ( argres!==null && argres!==undefined ? argres : '<span style="opacity: 0.6; font-weight: bold;">' + me.args[argcount].argTypeName + '</span>'));
|
||||
|
||||
this.focusManager.add(txt._input);
|
||||
},
|
||||
|
||||
onInputChanging: function(input, newValue, oldValue, e) {
|
||||
|
|
|
@ -50,7 +50,8 @@ define([
|
|||
style: 'min-width: 216px;',
|
||||
cls: 'modal-dlg',
|
||||
id: 'window-page-margins',
|
||||
buttons: ['ok', 'cancel']
|
||||
buttons: ['ok', 'cancel'],
|
||||
focusManager: true
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
|
@ -146,6 +147,12 @@ define([
|
|||
$window.find('.dlg-btn').on('click', _.bind(this.onBtnClick, this));
|
||||
$window.find('input').on('keypress', _.bind(this.onKeyPress, this));
|
||||
|
||||
this.focusManager.add(this.spinners, '.form-control');
|
||||
var cmp = this.spnTop;
|
||||
setTimeout(function(){
|
||||
(cmp.$el || $(cmp.el)).find('.form-control').focus();
|
||||
}, 10);
|
||||
|
||||
this.updateMetricUnit();
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in a new issue