123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- /*******************************************
- * *
- * This util was created by Marius Olbertz *
- * Please thank Marius on GitHub /owlbertz *
- * or the web http://www.mariusolbertz.de/ *
- * *
- ******************************************/
- 'use strict';
- import $ from 'jquery';
- import { rtl as Rtl } from './foundation.core.utils';
- const keyCodes = {
- 9: 'TAB',
- 13: 'ENTER',
- 27: 'ESCAPE',
- 32: 'SPACE',
- 35: 'END',
- 36: 'HOME',
- 37: 'ARROW_LEFT',
- 38: 'ARROW_UP',
- 39: 'ARROW_RIGHT',
- 40: 'ARROW_DOWN'
- }
- var commands = {}
- // Functions pulled out to be referenceable from internals
- function findFocusable($element) {
- if(!$element) {return false; }
- return $element.find('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]').filter(function() {
- if (!$(this).is(':visible') || $(this).attr('tabindex') < 0) { return false; } //only have visible elements and those that have a tabindex greater or equal 0
- return true;
- });
- }
- function parseKey(event) {
- var key = keyCodes[event.which || event.keyCode] || String.fromCharCode(event.which).toUpperCase();
- // Remove un-printable characters, e.g. for `fromCharCode` calls for CTRL only events
- key = key.replace(/\W+/, '');
- if (event.shiftKey) key = `SHIFT_${key}`;
- if (event.ctrlKey) key = `CTRL_${key}`;
- if (event.altKey) key = `ALT_${key}`;
- // Remove trailing underscore, in case only modifiers were used (e.g. only `CTRL_ALT`)
- key = key.replace(/_$/, '');
- return key;
- }
- var Keyboard = {
- keys: getKeyCodes(keyCodes),
- /**
- * Parses the (keyboard) event and returns a String that represents its key
- * Can be used like Foundation.parseKey(event) === Foundation.keys.SPACE
- * @param {Event} event - the event generated by the event handler
- * @return String key - String that represents the key pressed
- */
- parseKey: parseKey,
- /**
- * Handles the given (keyboard) event
- * @param {Event} event - the event generated by the event handler
- * @param {String} component - Foundation component's name, e.g. Slider or Reveal
- * @param {Objects} functions - collection of functions that are to be executed
- */
- handleKey(event, component, functions) {
- var commandList = commands[component],
- keyCode = this.parseKey(event),
- cmds,
- command,
- fn;
- if (!commandList) return console.warn('Component not defined!');
- if (typeof commandList.ltr === 'undefined') { // this component does not differentiate between ltr and rtl
- cmds = commandList; // use plain list
- } else { // merge ltr and rtl: if document is rtl, rtl overwrites ltr and vice versa
- if (Rtl()) cmds = $.extend({}, commandList.ltr, commandList.rtl);
- else cmds = $.extend({}, commandList.rtl, commandList.ltr);
- }
- command = cmds[keyCode];
- fn = functions[command];
- if (fn && typeof fn === 'function') { // execute function if exists
- var returnValue = fn.apply();
- if (functions.handled || typeof functions.handled === 'function') { // execute function when event was handled
- functions.handled(returnValue);
- }
- } else {
- if (functions.unhandled || typeof functions.unhandled === 'function') { // execute function when event was not handled
- functions.unhandled();
- }
- }
- },
- /**
- * Finds all focusable elements within the given `$element`
- * @param {jQuery} $element - jQuery object to search within
- * @return {jQuery} $focusable - all focusable elements within `$element`
- */
- findFocusable: findFocusable,
- /**
- * Returns the component name name
- * @param {Object} component - Foundation component, e.g. Slider or Reveal
- * @return String componentName
- */
- register(componentName, cmds) {
- commands[componentName] = cmds;
- },
- // TODO9438: These references to Keyboard need to not require global. Will 'this' work in this context?
- //
- /**
- * Traps the focus in the given element.
- * @param {jQuery} $element jQuery object to trap the foucs into.
- */
- trapFocus($element) {
- var $focusable = findFocusable($element),
- $firstFocusable = $focusable.eq(0),
- $lastFocusable = $focusable.eq(-1);
- $element.on('keydown.zf.trapfocus', function(event) {
- if (event.target === $lastFocusable[0] && parseKey(event) === 'TAB') {
- event.preventDefault();
- $firstFocusable.focus();
- }
- else if (event.target === $firstFocusable[0] && parseKey(event) === 'SHIFT_TAB') {
- event.preventDefault();
- $lastFocusable.focus();
- }
- });
- },
- /**
- * Releases the trapped focus from the given element.
- * @param {jQuery} $element jQuery object to release the focus for.
- */
- releaseFocus($element) {
- $element.off('keydown.zf.trapfocus');
- }
- }
- /*
- * Constants for easier comparing.
- * Can be used like Foundation.parseKey(event) === Foundation.keys.SPACE
- */
- function getKeyCodes(kcs) {
- var k = {};
- for (var kc in kcs) k[kcs[kc]] = kcs[kc];
- return k;
- }
- export {Keyboard};
|