2011-06-14 12:13:47 +02:00
|
|
|
/**
|
2021-06-12 17:03:22 +02:00
|
|
|
* EGroupware egw_action framework - Shortcut/Keyboard input manager
|
2011-06-14 12:13:47 +02:00
|
|
|
*
|
2021-06-12 17:03:22 +02:00
|
|
|
* @link https://www.egroupware.org
|
2011-06-14 12:13:47 +02:00
|
|
|
* @author Andreas Stöckel <as@stylite.de>
|
|
|
|
* @copyright 2011 by Andreas Stöckel
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @package egw_action
|
|
|
|
*/
|
|
|
|
|
2011-08-03 16:04:30 +02:00
|
|
|
/*egw:uses
|
2016-06-06 17:38:20 +02:00
|
|
|
vendor.bower-asset.jquery.dist.jquery;
|
2011-08-03 16:04:30 +02:00
|
|
|
egw_action;
|
2011-06-14 12:13:47 +02:00
|
|
|
*/
|
|
|
|
|
2021-06-14 13:45:57 +02:00
|
|
|
import {egw_getAppObjectManager, egw_globalObjectManager} from "./egw_action.js";
|
2021-06-11 09:06:25 +02:00
|
|
|
import {_egw_active_menu} from "./egw_menu.js";
|
2021-06-14 14:57:42 +02:00
|
|
|
import {
|
|
|
|
EGW_AO_FLAG_DEFAULT_FOCUS,
|
|
|
|
EGW_AO_EXEC_SELECTED,
|
|
|
|
EGW_VALID_KEYS,
|
|
|
|
EGW_KEY_MENU,
|
|
|
|
EGW_KEY_F1, EGW_KEY_F12
|
|
|
|
} from "./egw_action_constants.js";
|
2011-06-14 12:13:47 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The tranlation function converts the given native key code into one of the
|
|
|
|
* egw key constants as listed above. This key codes were chosen to match the
|
|
|
|
* key codes of IE and FF.
|
|
|
|
*/
|
2021-07-06 14:53:56 +02:00
|
|
|
export var egw_keycode_translation_function = function(_nativeKeyCode) {
|
2011-06-14 12:13:47 +02:00
|
|
|
// Map the numpad to the 0..9 keys
|
|
|
|
if (_nativeKeyCode >= 96 && _nativeKeyCode <= 105)
|
|
|
|
{
|
|
|
|
_nativeKeyCode -= 48
|
|
|
|
}
|
|
|
|
|
|
|
|
return _nativeKeyCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the given keycode is in the list of valid key codes. If not,
|
|
|
|
* returns -1.
|
|
|
|
*/
|
2021-07-06 15:50:49 +02:00
|
|
|
export function egw_keycode_makeValid(_keyCode) {
|
2011-06-14 12:13:47 +02:00
|
|
|
var idx = EGW_VALID_KEYS.indexOf(_keyCode);
|
|
|
|
if (idx >= 0) {
|
|
|
|
return _keyCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-06-15 22:54:58 +02:00
|
|
|
function _egw_nodeIsInInput(_node)
|
|
|
|
{
|
|
|
|
if ((_node != null) && (_node != document))
|
|
|
|
{
|
|
|
|
var tagName = _node.tagName.toLowerCase();
|
2014-03-03 20:00:25 +01:00
|
|
|
if (tagName == "input" || tagName == "select" || tagName == 'textarea' || tagName == 'button')
|
2011-06-15 22:54:58 +02:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return _egw_nodeIsInInput(_node.parentNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-14 12:13:47 +02:00
|
|
|
/**
|
2016-06-06 17:38:20 +02:00
|
|
|
* Register the onkeypress handler on the document
|
2011-06-14 12:13:47 +02:00
|
|
|
*/
|
2021-06-11 09:06:25 +02:00
|
|
|
jQuery(function() {
|
2011-06-14 12:13:47 +02:00
|
|
|
|
|
|
|
// Fetch the key down event and translate it into browser-independent and
|
|
|
|
// easy to use key codes and shift states
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(document).keydown( function(e) {
|
2011-06-14 12:13:47 +02:00
|
|
|
|
|
|
|
// Translate the given key code and make it valid
|
|
|
|
var keyCode = e.which;
|
|
|
|
keyCode = egw_keycode_translation_function(keyCode);
|
|
|
|
keyCode = egw_keycode_makeValid(keyCode);
|
|
|
|
|
|
|
|
// Only go on if this is a valid key code - call the key handler
|
|
|
|
if (keyCode != -1)
|
|
|
|
{
|
2021-05-13 18:01:38 +02:00
|
|
|
// Check whether the event came from the sidebox - if yes, ignore
|
|
|
|
if(jQuery(e.target).parents("#egw_fw_sidemenu").length > 0) return;
|
|
|
|
|
2021-05-13 23:09:53 +02:00
|
|
|
// If a context menu is open, give the keyboard to it
|
2021-06-11 09:06:25 +02:00
|
|
|
if (typeof _egw_active_menu !== undefined && _egw_active_menu &&
|
|
|
|
_egw_active_menu.keyHandler(keyCode, e.shiftKey, e.ctrlKey || e.metaKey, e.altKey))
|
2021-05-13 23:09:53 +02:00
|
|
|
{
|
|
|
|
e.preventDefault();
|
|
|
|
return;
|
|
|
|
}
|
2011-06-15 22:54:58 +02:00
|
|
|
// Check whether the event came from an input field - if yes, only
|
|
|
|
// allow function keys (like F1) to be captured by our code
|
|
|
|
var inInput = _egw_nodeIsInInput(e.target);
|
|
|
|
if (!inInput || (keyCode >= EGW_KEY_F1 && keyCode <= EGW_KEY_F12))
|
2011-06-14 12:13:47 +02:00
|
|
|
{
|
2011-06-15 22:54:58 +02:00
|
|
|
if (egw_keyHandler(keyCode, e.shiftKey, e.ctrlKey || e.metaKey, e.altKey))
|
|
|
|
{
|
|
|
|
// If the key handler successfully passed the key event to some
|
|
|
|
// sub component, prevent the default action
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
2011-06-14 12:13:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2013-04-09 18:13:10 +02:00
|
|
|
/**
|
|
|
|
* Required to catch the context menu
|
|
|
|
*/
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(window).on("contextmenu",document, function(event) {
|
2014-01-11 16:20:11 +01:00
|
|
|
// Check for actual key press
|
|
|
|
if(!(event.originalEvent.x == 1 && event.originalEvent.y == 1)) return true;
|
2013-04-10 11:03:08 +02:00
|
|
|
if(!event.ctrlKey && egw_keyHandler(EGW_KEY_MENU, event.shiftKey, event.ctrlKey || event.metaKey, event.altKey))
|
2013-04-09 18:13:10 +02:00
|
|
|
{
|
|
|
|
// If the key handler successfully passed the key event to some
|
|
|
|
// sub component, prevent the default action
|
|
|
|
event.preventDefault();
|
2013-04-10 11:03:08 +02:00
|
|
|
return false;
|
2013-04-09 18:13:10 +02:00
|
|
|
}
|
2013-04-10 11:03:08 +02:00
|
|
|
return true;
|
2013-04-09 18:13:10 +02:00
|
|
|
});
|
|
|
|
|
2011-06-19 12:48:51 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates an unique key for the given shortcut
|
2011-06-14 12:13:47 +02:00
|
|
|
*/
|
2021-06-11 11:31:06 +02:00
|
|
|
export function egw_shortcutIdx(_keyCode, _shift, _ctrl, _alt)
|
2011-06-14 12:13:47 +02:00
|
|
|
{
|
2016-06-06 17:38:20 +02:00
|
|
|
return "_" + _keyCode + "_" +
|
2011-06-14 12:13:47 +02:00
|
|
|
(_shift ? "S" : "") +
|
|
|
|
(_ctrl ? "C" : "") +
|
|
|
|
(_alt ? "A" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
var egw_registeredShortcuts = {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers a global shortcut. If the shortcut already exists, it is overwritten.
|
|
|
|
* @param int _keyCode is one of the keycode constants
|
|
|
|
* @param bool _shift whether shift has to be set
|
|
|
|
* @param bool _ctrl whether ctrl has to be set
|
|
|
|
* @param bool _alt whether alt has to be set
|
|
|
|
* @param function _handler the function which will be called when the shortcut
|
|
|
|
* is evoked. An object containing the shortcut data will be passed as first
|
|
|
|
* parameter.
|
|
|
|
* @param object _context is the context in which the function will be executed
|
|
|
|
*/
|
2021-06-11 11:31:06 +02:00
|
|
|
export function egw_registerGlobalShortcut(_keyCode, _shift, _ctrl, _alt, _handler, _context)
|
2011-06-14 12:13:47 +02:00
|
|
|
{
|
|
|
|
// Generate the hash map index for the shortcut
|
|
|
|
var idx = egw_shortcutIdx(_keyCode, _shift, _ctrl, _alt);
|
|
|
|
|
|
|
|
// Register the shortcut
|
|
|
|
egw_registeredShortcuts[idx] = {
|
|
|
|
"handler": _handler,
|
|
|
|
"context": _context,
|
|
|
|
"shortcut": {
|
|
|
|
"keyCode": _keyCode,
|
|
|
|
"shift": _shift,
|
|
|
|
"ctrl": _ctrl,
|
|
|
|
"alt": _alt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregisters the given shortcut.
|
|
|
|
*/
|
2021-06-11 11:31:06 +02:00
|
|
|
export function egw_unregisterGlobalShortcut(_keyCode, _shift, _ctrl, _alt)
|
|
|
|
{
|
2011-06-14 12:13:47 +02:00
|
|
|
// Generate the hash map index for the shortcut
|
|
|
|
var idx = egw_shortcutIdx(_keyCode, _shift, _ctrl, _alt);
|
|
|
|
|
|
|
|
// Delete the entry from the hash map
|
|
|
|
delete egw_registeredShortcuts[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* the egw_keyHandler function handles various key presses. The boolean
|
|
|
|
* _shift, _ctrl, _alt values have been translated into platform independent
|
|
|
|
* values (for apple devices).
|
|
|
|
*/
|
2021-06-10 15:40:49 +02:00
|
|
|
export function egw_keyHandler(_keyCode, _shift, _ctrl, _alt) {
|
2011-06-14 12:13:47 +02:00
|
|
|
|
|
|
|
// Check whether there is a global shortcut waiting for the keypress event
|
|
|
|
var idx = egw_shortcutIdx(_keyCode, _shift, _ctrl, _alt);
|
|
|
|
if (typeof egw_registeredShortcuts[idx] != "undefined")
|
|
|
|
{
|
|
|
|
var shortcut = egw_registeredShortcuts[idx];
|
|
|
|
|
2015-10-27 17:45:37 +01:00
|
|
|
// Call the registered shortcut function and return its result, if it handled it
|
|
|
|
var result = shortcut.handler.call(shortcut.context, shortcut.shortcut);
|
|
|
|
if(result) return result;
|
2011-06-14 12:13:47 +02:00
|
|
|
}
|
2016-06-06 17:38:20 +02:00
|
|
|
|
2015-10-27 17:45:37 +01:00
|
|
|
// Pass the keypress to the currently focused action object
|
|
|
|
|
|
|
|
// Get the object manager and fetch the container of the currently
|
|
|
|
// focused object
|
2021-03-24 21:53:23 +01:00
|
|
|
var focusedObject = egw_globalObjectManager ? egw_globalObjectManager.getFocusedObject() : null;
|
2015-10-27 17:45:37 +01:00
|
|
|
var appMgr = egw_getAppObjectManager(false);
|
2020-05-20 18:31:32 +02:00
|
|
|
if (appMgr && !focusedObject)
|
2011-06-14 12:13:47 +02:00
|
|
|
{
|
2020-05-20 18:31:32 +02:00
|
|
|
focusedObject = appMgr.getFocusedObject();
|
2011-06-14 12:13:47 +02:00
|
|
|
|
2015-10-27 17:45:37 +01:00
|
|
|
if (!focusedObject)
|
2011-06-14 12:13:47 +02:00
|
|
|
{
|
2015-10-27 17:45:37 +01:00
|
|
|
// If the current application doesn't have a focused object,
|
|
|
|
// check whether the application object manager contains an object
|
|
|
|
// with the EGW_AO_FLAG_DEFAULT_FOCUS flag set.
|
|
|
|
var cntr = null;
|
|
|
|
for (var i = 0; i < appMgr.children.length; i++)
|
2011-06-15 22:54:58 +02:00
|
|
|
{
|
2015-10-27 17:45:37 +01:00
|
|
|
var child = appMgr.children[i];
|
|
|
|
if (egwBitIsSet(EGW_AO_FLAG_DEFAULT_FOCUS, child.flags))
|
2011-06-15 22:54:58 +02:00
|
|
|
{
|
2015-10-27 17:45:37 +01:00
|
|
|
cntr = child;
|
|
|
|
break;
|
2011-06-15 22:54:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-27 17:45:37 +01:00
|
|
|
// Get the first child of the found container and focus the first
|
|
|
|
// object
|
|
|
|
if (cntr && cntr.children.length > 0)
|
2011-06-14 12:13:47 +02:00
|
|
|
{
|
2015-10-27 17:45:37 +01:00
|
|
|
cntr.children[0].setFocused(true);
|
|
|
|
focusedObject = cntr.children[0];
|
|
|
|
}
|
|
|
|
}
|
2020-05-20 18:31:32 +02:00
|
|
|
}
|
|
|
|
if (focusedObject)
|
|
|
|
{
|
|
|
|
// Handle the default keys (arrow_up, down etc.)
|
|
|
|
var cntr = focusedObject.getContainerRoot();
|
|
|
|
var handled = false;
|
2011-06-16 15:43:46 +02:00
|
|
|
|
2020-05-20 18:31:32 +02:00
|
|
|
if (cntr)
|
2015-10-27 17:45:37 +01:00
|
|
|
{
|
2020-05-20 18:31:32 +02:00
|
|
|
handled = cntr.handleKeyPress(_keyCode, _shift, _ctrl, _alt);
|
|
|
|
}
|
2011-06-16 15:43:46 +02:00
|
|
|
|
2020-05-20 18:31:32 +02:00
|
|
|
// Execute the egw_popup key handler of the focused object
|
|
|
|
if (!handled)
|
|
|
|
{
|
|
|
|
return focusedObject.executeActionImplementation(
|
2015-10-27 17:45:37 +01:00
|
|
|
{
|
2020-05-20 18:31:32 +02:00
|
|
|
"keyEvent": {
|
|
|
|
"keyCode": _keyCode,
|
|
|
|
"shift": _shift,
|
|
|
|
"ctrl": _ctrl,
|
|
|
|
"alt": _alt
|
|
|
|
}
|
|
|
|
}, "popup", EGW_AO_EXEC_SELECTED);
|
2015-10-27 17:45:37 +01:00
|
|
|
}
|
2020-05-20 18:31:32 +02:00
|
|
|
|
|
|
|
return handled;
|
2011-06-14 12:13:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|