Files
DocumentServer-v-9.2.0/web-apps/apps/common/main/lib/controller/ScreenReaderFocus.js
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

427 lines
17 KiB
JavaScript

/*
* (c) Copyright Ascensio System SIA 2010-2024
*
* 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-6 Ernesta Birznieka-Upish
* 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
*
*/
/**
* ScreenReaderFocus.js
*
* Created on 22.11.2023
*
*/
if (Common === undefined)
var Common = {};
if (Common.UI === undefined) {
Common.UI = {};
}
Common.UI.ScreenReaderFocusManager = new(function() {
var _needShow = false,
_focusVisible = false,
_focusMode = false,
_currentLevel = 0,
_lastLevel = 0,
_currentSection = document,
_lastSection = document,
_currentControls = [],
_currentItemIndex,
_isLockedKeyEvents = false,
_unlockKeyEvents = false,
_isDocReady = false,
_isEditDiagram = false,
_isSidePanelMode = false,
_api,
_app,
_appPrefix;
var _setCurrentSection = function (btn, section) {
_lastSection = _currentSection;
if (section) {
_currentSection = section;
return;
}
if (btn === 'esc') {
if (_currentLevel === 0) {
_currentSection = document;
}
return;
}
if (_isEditDiagram) {
_currentSection = [$(window.parent.document).find('.advanced-settings-dlg:visible')[0], window.document];
} else if ($('#file-menu-panel').is(':visible')) {
_currentSection = $('#file-menu-panel');
} else {
_currentSection = _currentLevel === 0 ? document : ((btn && btn.closest('.hint-section')) || document);
}
};
var _lockedKeyEvents = function (isLocked) {
if (_api && (isLocked || !Common.Utils.ModalWindow.isVisible())) {
_isLockedKeyEvents = isLocked;
_api.asc_enableKeyEvents(!isLocked);
}
};
var _showFocus = function () {
if (_currentControls.length === 0 || (($('#file-menu-panel').is(':visible') || _isEditDiagram) && _currentLevel === 1)) {
_getControls();
// console.log(_currentControls);
}
if (!_focusVisible) {
if ($('#file-menu-panel').is(':visible')) {
_setFocusInActiveFileMenuItem();
} else {
_setFocusInActiveTab();
}
} else if (_currentLevel !== _lastLevel && (_currentLevel === 0 || _currentLevel === 1 && $('#file-menu-panel').is(':visible'))) {
var id = $(_lastSection).prop('id');
if (id === 'toolbar') {
_setFocusInActiveTab();
} else if (id === 'left-menu' || id === 'right-menu') {
_setFocusInActiveCategory(id);
} else if (id === 'file-menu-panel') {
_setFocusInActiveFileMenuItem();
}
} else if (_currentLevel === 1 && _currentLevel !== _lastLevel && ($(_currentSection).prop('id') === 'left-menu' || $(_currentSection).prop('id') === 'right-menu')) {
_setFocusInSideMenu($(_currentSection).prop('id') === 'left-menu');
}
var currItem = _currentControls[_currentItemIndex];
// console.log(_currentControls[_currentItemIndex]);
if (currItem) {
if ($(currItem).parent().hasClass('ribtab') && !$(currItem).parent().hasClass('active') && $(currItem).data('tab') !== 'file') {
$(currItem).trigger(jQuery.Event('click', {which: 1}));
}
$(_currentControls[_currentItemIndex]).focus();
}
if (_currentControls.length > 0) {
!_isLockedKeyEvents && _lockedKeyEvents(true);
_focusVisible = true;
} else {
_focusVisible = false;
}
};
var _hideFocus = function () {
_focusVisible = false;
_focusMode = false;
_isSidePanelMode = false;
};
var _nextItem = function () {
_lastLevel = _currentLevel;
_currentItemIndex++;
if (_currentItemIndex > _currentControls.length - 1) {
_currentItemIndex = 0;
}
};
var _prevItem = function () {
_lastLevel = _currentLevel;
_currentItemIndex--;
if (_currentItemIndex < 0) {
_currentItemIndex = _currentControls.length - 1;
}
};
var _nextLevel = function(level) {
_lastLevel = _currentLevel;
_currentItemIndex = 0;
_currentControls.length = 0;
if (level !== undefined) {
_currentLevel = level;
} else {
_currentLevel++;
}
};
var _prevLevel = function() {
_lastLevel = _currentLevel;
_currentControls.length = 0;
_currentLevel--;
};
var _resetToDefault = function() {
_currentLevel = ($('#file-menu-panel').is(':visible') || _isEditDiagram) ? 1 : 0;
_setCurrentSection();
_currentControls.length = 0;
};
var _setFocusInActiveTab = function () {
var activeTab;
for (var i=0; i<_currentControls.length; i++) {
var parent = $(_currentControls[i]).parent();
if (parent && parent.hasClass('ribtab') && parent.hasClass('active')) {
activeTab = _currentControls[i];
break;
}
}
if (activeTab) {
_currentItemIndex = i;
}
};
var _setFocusInActiveCategory = function (id) {
var activeCategory;
for (var i=0; i<_currentControls.length; i++) {
var item = $(_currentControls[i]);
if ($(item.closest('.hint-section')).prop('id') === id && item.hasClass('btn-category') && item.hasClass('active')) {
activeCategory = _currentControls[i];
break;
}
}
if (activeCategory) {
_currentItemIndex = i;
}
};
var _setFocusInActiveFileMenuItem = function () {
var activeItem;
for (var i=0; i<_currentControls.length; i++) {
if ($(_currentControls[i]).parent().hasClass('active')) {
activeItem = _currentControls[i];
break;
}
}
if (activeItem) {
_currentItemIndex = i;
}
};
var _setFocusInSideMenu = function (isLeftMenu) {
var index = 0,
view, btn;
if (isLeftMenu) {
view = _app.getController('LeftMenu').getView('LeftMenu');
btn = view.getFocusElement();
}
if (btn) {
for (var i=0; i<_currentControls.length; i++) {
if ($(_currentControls[i]).is($(btn))) {
index = i;
break;
}
}
}
_currentItemIndex = index;
};
var _isItemDisabled = function (item) {
return (item.hasClass('disabled') || item.parent().hasClass('disabled') || item.attr('disabled'));
};
var _getControls = function() {
_currentControls = [];
var arr = [];
if (_.isArray(_currentSection)) {
_currentSection.forEach(function (section) {
arr = arr.concat($(section).find('[data-hint=' + (_currentLevel) + ']').toArray());
});
} else {
arr = $(_currentSection).find('[data-hint=' + (_currentLevel) + ']').toArray();
}
_currentControls = arr.filter(function (item) {
return ($(item).is(':visible') && !_isItemDisabled($(item)));
});
_currentControls.forEach(function (item) {
if ($(item).attr("tabindex") === undefined) $(item).attr("tabindex", 0);
});
};
var _exitFocusMode = function () {
_hideFocus();
_resetToDefault();
_isLockedKeyEvents && _lockedKeyEvents(false);
};
var _init = function(api) {
if (Common.Utils.isIE || Common.UI.isMac && Common.Utils.isGecko) // turn off hints on IE and FireFox (shortcut F6 selects link in address bar)
return;
_api = api;
_app = window.DE || window.PE || window.SSE || window.PDFE || window.VE;
_isDocReady = true;
var filter = Common.localStorage.getKeysFilter();
_appPrefix = (filter && filter.length) ? filter.split(',')[0] : '';
if ( !Common.Utils.ScreeenReaderHelper ) {
require(['common/main/lib/util/ScreenReaderHelper'], function () {
Common.Utils.ScreeenReaderHelper.setEnabled(true);
});
}
$('#editor_sdk').on('click', function () {
_exitFocusMode();
});
$(document).on('mousedown', function () {
_exitFocusMode();
});
$(document).on('keyup', function(e) {
if ((e.keyCode == Common.UI.Keys.ALT || e.keyCode === 91) && _needShow && !(window.SSE && window.SSE.getController('Statusbar').getIsDragDrop())) {
e.preventDefault();
if (!_focusVisible) {
$('input:focus').blur(); // to change value in inputField
_currentLevel = ($('#file-menu-panel').is(':visible') || _isEditDiagram) ? 1 : 0;
_setCurrentSection();
_showFocus();
} else {
_exitFocusMode();
}
} else if (_unlockKeyEvents) {
_lockedKeyEvents(false);
_unlockKeyEvents = false;
} else if (_focusVisible) {
e.preventDefault();
}
_needShow = false;
});
$(document).on('keydown.after.bs.dropdown', function(e) {
if (_focusVisible) {
var tag = $(_currentControls[_currentItemIndex]).prop('tagName'),
isInputFocused = tag === 'INPUT' || tag === 'TEXTAREA',
isDirectionEvent = e.keyCode == Common.UI.Keys.TAB || e.keyCode == Common.UI.Keys.LEFT || e.keyCode == Common.UI.Keys.RIGHT ||
e.keyCode == Common.UI.Keys.UP || e.keyCode == Common.UI.Keys.DOWN,
isControlEvent = e.keyCode == Common.UI.Keys.ESC || e.keyCode == Common.UI.Keys.RETURN || e.keyCode == Common.UI.Keys.SPACE;
if($(_currentControls[_currentItemIndex]).data('move-focus-only-tab') && e.keyCode !== Common.UI.Keys.TAB && !isControlEvent) return;
if (!(isDirectionEvent || isControlEvent) || (e.keyCode == Common.UI.Keys.SPACE && isInputFocused)) return;
if (isDirectionEvent) e.preventDefault(); // allow to write in inputs
Common.UI.Menu.Manager.hideAll();
var turnOffHints = false,
btn = _currentControls[_currentItemIndex] && $(_currentControls[_currentItemIndex]);
var isFileMenu = $('#file-menu-panel').is(':visible'),
isBtnCategory = btn && btn.hasClass('btn-category'),
left = e.keyCode == Common.UI.Keys.LEFT,
right = e.keyCode == Common.UI.Keys.RIGHT,
up = e.keyCode == Common.UI.Keys.UP,
down = e.keyCode == Common.UI.Keys.DOWN,
tab = e.keyCode == Common.UI.Keys.TAB,
shiftTab = e.shiftKey && e.keyCode == Common.UI.Keys.TAB,
isPrevItem,
isNextItem,
isPrevLevel,
isNextLevel;
if (isFileMenu) {
isPrevItem = left || up;
isNextItem = _currentLevel === 2 ? (right || down || tab && !shiftTab) : (right || down);
isPrevLevel = shiftTab;
isNextLevel = tab && !shiftTab;
} else if (isBtnCategory) {
isPrevItem = up || shiftTab;
isNextItem = down || tab;
isPrevLevel = false;
isNextLevel = right || left;
} else if (_isSidePanelMode) {
isPrevItem = shiftTab;
isNextItem = tab;
isPrevLevel = false;
isNextLevel = false;
} else {
isPrevItem = left || shiftTab;
isNextItem = right || tab && !shiftTab;
isPrevLevel = up;
isNextLevel = down;
}
if (e.keyCode == Common.UI.Keys.ESC) {
_exitFocusMode();
return;
} else if (e.keyCode == Common.UI.Keys.RETURN || e.keyCode == Common.UI.Keys.SPACE) {
if (btn) {
if (btn.attr('for')) { // to trigger event in checkbox
(e.keyCode == Common.UI.Keys.RETURN) ? $('#' + btn.attr('for')).trigger(jQuery.Event('click', {which: 1})) : e.preventDefault(); // prevent type space in document
} else {
if (btn.data('tab') === 'file' || isFileMenu && _currentLevel === 1 || isBtnCategory)
btn.trigger(jQuery.Event('click', {which: 1}));
else
setTimeout(function() {btn.trigger(jQuery.Event('click', {which: 1}));}, 1); // click on toolbar buttons
}
if (btn.data('toggle') !== 'dropdown') btn.blur();
}
if (btn && btn.data('tab') === 'file' || isFileMenu && _currentLevel === 1 || isBtnCategory && btn.hasClass('active')) {
(isBtnCategory && btn.hasClass('active')) && (_isSidePanelMode = true);
_nextLevel();
_setCurrentSection(btn);
} else {
_hideFocus();
_resetToDefault();
Common.UI.HintManager.isHintVisible() && Common.UI.HintManager.clearHints(false, true);
if (btn && btn.data('toggle') !== 'dropdown') _unlockKeyEvents = true;
_isLockedKeyEvents = false;
return;
}
} else if (isPrevItem) {
turnOffHints = true;
_prevItem();
} else if (isNextItem) {
turnOffHints = true;
_nextItem();
} else if (isNextLevel) {
var attr = '[data-hint="' + (_currentLevel + 1) + '"]';
if ($(_currentSection).find(attr).length === 0 || btn && $(btn.closest('.hint-section')).find(attr).filter(':visible').length === 0) return;
turnOffHints = true;
_nextLevel();
_setCurrentSection(btn);
if (isBtnCategory) _isSidePanelMode = true;
} else if (isPrevLevel) {
if (_currentLevel === 0) return;
turnOffHints = true;
_prevLevel();
_setCurrentSection(btn);
}
if (!_focusMode && turnOffHints) {
_focusMode = true;
Common.UI.HintManager.isHintVisible() && Common.UI.HintManager.clearHints(false, true);
}
_showFocus();
}
});
$(document).on('keydown', function(e) {
_needShow = Common.Utils.InternalSettings.get(_appPrefix + "settings-show-alt-hints") && e.keyCode == Common.UI.Keys.ALT && !e.shiftKey &&
!Common.Utils.ModalWindow.isVisible() && _isDocReady && !(window.PE && $('#pe-preview').is(':visible'));
// Add outline style for focus elements for test
if (Common.localStorage.getBool('screen-reader-focus-mode', false)) {
!$(document.body).hasClass('focus-mode') && $(document.body).addClass('focus-mode');
} else {
$(document.body).hasClass('focus-mode') && $(document.body).removeClass('focus-mode');
}
});
};
var _isFocusMode = function () {
return !!_focusMode;
}
return {
init: _init,
isFocusMode: _isFocusMode,
exitFocusMode: _exitFocusMode
}
})();