From f4dfe66ea8a215ec4dca60abcf33d07208cf57d3 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Mon, 2 Nov 2020 08:12:22 +0800 Subject: [PATCH] MDL-70075 core: Listen for the `focus` and `blur` events again The `blur` event does not bubble, but the `focusout` events are not available in all supported versions of Firefox. Rather than switching event, this patch using event capture to effectively achieve the same result and bubble the event up through the DOM to the delegated listener. There should be no functional change with this patch, except to support Firefox fully. --- lib/amd/build/custom_interaction_events.min.js | 2 +- lib/amd/build/custom_interaction_events.min.js.map | 2 +- lib/amd/src/custom_interaction_events.js | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) rewrite lib/amd/build/custom_interaction_events.min.js.map (95%) diff --git a/lib/amd/build/custom_interaction_events.min.js b/lib/amd/build/custom_interaction_events.min.js index fdf405e8e8c..2e6312a9df8 100644 --- a/lib/amd/build/custom_interaction_events.min.js +++ b/lib/amd/build/custom_interaction_events.min.js @@ -1,2 +1,2 @@ -define ("core/custom_interaction_events",["jquery","core/key_codes"],function(a,b){var c={activate:"cie:activate",keyboardActivate:"cie:keyboardactivate",escape:"cie:escape",down:"cie:down",up:"cie:up",home:"cie:home",end:"cie:end",next:"cie:next",previous:"cie:previous",asterix:"cie:asterix",scrollLock:"cie:scrollLock",scrollTop:"cie:scrollTop",scrollBottom:"cie:scrollBottom",ctrlPageUp:"cie:ctrlPageUp",ctrlPageDown:"cie:ctrlPageDown",enter:"cie:enter",accessibleChange:"cie:accessibleChange"},d={},e=function(a,b){b=b||[];if(b.length&&-1!==b.indexOf(a)){return!0}return!1},f=function(a){return a.shiftKey||a.metaKey||a.altKey||a.ctrlKey},g=function(b,c){var e="";if(!c.hasOwnProperty("originalEvent")){e=""+b+c.type+c.timeStamp;if(!d.hasOwnProperty(e)){d[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}return}e="triggeredCustom_"+b;if(!c.originalEvent.hasOwnProperty(e)){c.originalEvent[e]=!0;a(c.target).trigger(b,[{originalEvent:c}])}},h=function(a,b,c){a.off("keydown."+b).on("keydown."+b,function(a){if(!f(a)){if(a.keyCode==c){g(b,a)}}})},i=function(a){a.off("click.cie.activate").on("click.cie.activate",function(a){g(c.activate,a)});a.off("keydown.cie.activate").on("keydown.cie.activate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.activate,a)}}})},j=function(a){a.off("keydown.cie.keyboardactivate").on("keydown.cie.keyboardactivate",function(a){if(!f(a)){if(a.keyCode==b.enter||a.keyCode==b.space){g(c.keyboardActivate,a)}}})},k=function(a){h(a,c.escape,b.escape)},l=function(a){h(a,c.down,b.arrowDown)},m=function(a){h(a,c.up,b.arrowUp)},n=function(a){h(a,c.home,b.home)},o=function(a){h(a,c.end,b.end)},p=function(d){var e="rtl"==a("html").attr("dir")?b.arrowLeft:b.arrowRight;h(d,c.next,e)},q=function(d){var e="rtl"==a("html").attr("dir")?b.arrowRight:b.arrowLeft;h(d,c.previous,e)},r=function(a){h(a,c.asterix,b.asterix)},s=function(a){a.off("scroll.cie.scrollTop").on("scroll.cie.scrollTop",function(b){var d=a.scrollTop();if(0===d){g(c.scrollTop,b)}})},t=function(a){a.off("scroll.cie.scrollBottom").on("scroll.cie.scrollBottom",function(b){var d=a.scrollTop(),e=a.innerHeight(),f=a[0].scrollHeight;if(d+e>=f){g(c.scrollBottom,b)}})},u=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),h="DOMMouseScroll"==b.type?-40*b.originalEvent.detail:b.originalEvent.wheelDelta,i=0e-f-d){a.scrollTop(e);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}else if(i&&h>d){a.scrollTop(0);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}return!0})},v=function(a){a.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(a){if(a.ctrlKey){if(a.keyCode==b.pageUp){g(c.ctrlPageUp,a)}}})},w=function(a){a.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(a){if(a.ctrlKey){if(a.keyCode==b.pageDown){g(c.ctrlPageDown,a)}}})},x=function(a){h(a,c.enter,b.enter)},y=function(d){var e=-1!==navigator.userAgent.indexOf("Macintosh"),f="ontouchstart"in window||"msMaxTouchPoints"in navigator&&0=f){g(c.scrollBottom,b)}})},u=function(a){a.off("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock").on("DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock",function(b){var d=a.scrollTop(),e=a[0].scrollHeight,f=a.height(),h="DOMMouseScroll"==b.type?-40*b.originalEvent.detail:b.originalEvent.wheelDelta,i=0e-f-d){a.scrollTop(e);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}else if(i&&h>d){a.scrollTop(0);b.stopPropagation();b.preventDefault();b.returnValue=!1;g(c.scrollLock,b);return!1}return!0})},v=function(a){a.off("keydown.cie.ctrlpageup").on("keydown.cie.ctrlpageup",function(a){if(a.ctrlKey){if(a.keyCode==b.pageUp){g(c.ctrlPageUp,a)}}})},w=function(a){a.off("keydown.cie.ctrlpagedown").on("keydown.cie.ctrlpagedown",function(a){if(a.ctrlKey){if(a.keyCode==b.pageDown){g(c.ctrlPageDown,a)}}})},x=function(a){h(a,c.enter,b.enter)},y=function(d){var e=-1!==navigator.userAgent.indexOf("Macintosh"),f="ontouchstart"in window||"msMaxTouchPoints"in navigator&&0.\n\n/**\n * This module provides a wrapper to encapsulate a lot of the common combinations of\n * user interaction we use in Moodle.\n *\n * @module core/custom_interaction_events\n * @class custom_interaction_events\n * @package core\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.2\n */\ndefine(['jquery', 'core/key_codes'], function($, keyCodes) {\n // The list of events provided by this module. Namespaced to avoid clashes.\n var events = {\n activate: 'cie:activate',\n keyboardActivate: 'cie:keyboardactivate',\n escape: 'cie:escape',\n down: 'cie:down',\n up: 'cie:up',\n home: 'cie:home',\n end: 'cie:end',\n next: 'cie:next',\n previous: 'cie:previous',\n asterix: 'cie:asterix',\n scrollLock: 'cie:scrollLock',\n scrollTop: 'cie:scrollTop',\n scrollBottom: 'cie:scrollBottom',\n ctrlPageUp: 'cie:ctrlPageUp',\n ctrlPageDown: 'cie:ctrlPageDown',\n enter: 'cie:enter',\n accessibleChange: 'cie:accessibleChange',\n };\n // Static cache of jQuery events that have been handled. This should\n // only be populated by JavaScript generated events (which will keep it\n // fairly small).\n var triggeredEvents = {};\n\n /**\n * Check if the caller has asked for the given event type to be\n * registered.\n *\n * @method shouldAddEvent\n * @private\n * @param {string} eventType name of the event (see events above)\n * @param {array} include the list of events to be added\n * @return {bool} true if the event should be added, false otherwise.\n */\n var shouldAddEvent = function(eventType, include) {\n include = include || [];\n\n if (include.length && include.indexOf(eventType) !== -1) {\n return true;\n }\n\n return false;\n };\n\n /**\n * Check if any of the modifier keys have been pressed on the event.\n *\n * @method isModifierPressed\n * @private\n * @param {event} e jQuery event\n * @return {bool} true if shift, meta (command on Mac), alt or ctrl are pressed\n */\n var isModifierPressed = function(e) {\n return (e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);\n };\n\n /**\n * Trigger the custom event for the given jQuery event.\n *\n * This function will only fire the custom event if one hasn't already been\n * fired for the jQuery event.\n *\n * This is to prevent multiple custom event handlers triggering multiple\n * custom events for a single jQuery event as it bubbles up the stack.\n *\n * @param {string} eventName The name of the custom event\n * @param {event} e The jQuery event\n * @return {void}\n */\n var triggerEvent = function(eventName, e) {\n var eventTypeKey = \"\";\n\n if (!e.hasOwnProperty('originalEvent')) {\n // This is a jQuery event generated from JavaScript not a browser event so\n // we need to build the cache key for the event.\n eventTypeKey = \"\" + eventName + e.type + e.timeStamp;\n\n if (!triggeredEvents.hasOwnProperty(eventTypeKey)) {\n // If we haven't seen this jQuery event before then fire a custom\n // event for it and remember the event for later.\n triggeredEvents[eventTypeKey] = true;\n $(e.target).trigger(eventName, [{originalEvent: e}]);\n }\n return;\n }\n\n eventTypeKey = \"triggeredCustom_\" + eventName;\n if (!e.originalEvent.hasOwnProperty(eventTypeKey)) {\n // If this is a jQuery event generated by the browser then set a\n // property on the original event to track that we've seen it before.\n // The property is set on the original event because it's the only part\n // of the jQuery event that is maintained through multiple event handlers.\n e.originalEvent[eventTypeKey] = true;\n $(e.target).trigger(eventName, [{originalEvent: e}]);\n return;\n }\n };\n\n /**\n * Register a keyboard event that ignores modifier keys.\n *\n * @method addKeyboardEvent\n * @private\n * @param {object} element A jQuery object of the element to bind events to\n * @param {string} event The custom interaction event name\n * @param {int} keyCode The key code.\n */\n var addKeyboardEvent = function(element, event, keyCode) {\n element.off('keydown.' + event).on('keydown.' + event, function(e) {\n if (!isModifierPressed(e)) {\n if (e.keyCode == keyCode) {\n triggerEvent(event, e);\n }\n }\n });\n };\n\n /**\n * Trigger the activate event on the given element if it is clicked or the enter\n * or space key are pressed without a modifier key.\n *\n * @method addActivateListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addActivateListener = function(element) {\n element.off('click.cie.activate').on('click.cie.activate', function(e) {\n triggerEvent(events.activate, e);\n });\n element.off('keydown.cie.activate').on('keydown.cie.activate', function(e) {\n if (!isModifierPressed(e)) {\n if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n triggerEvent(events.activate, e);\n }\n }\n });\n };\n\n /**\n * Trigger the keyboard activate event on the given element if the enter\n * or space key are pressed without a modifier key.\n *\n * @method addKeyboardActivateListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addKeyboardActivateListener = function(element) {\n element.off('keydown.cie.keyboardactivate').on('keydown.cie.keyboardactivate', function(e) {\n if (!isModifierPressed(e)) {\n if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n triggerEvent(events.keyboardActivate, e);\n }\n }\n });\n };\n\n /**\n * Trigger the escape event on the given element if the escape key is pressed\n * without a modifier key.\n *\n * @method addEscapeListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addEscapeListener = function(element) {\n addKeyboardEvent(element, events.escape, keyCodes.escape);\n };\n\n /**\n * Trigger the down event on the given element if the down arrow key is pressed\n * without a modifier key.\n *\n * @method addDownListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addDownListener = function(element) {\n addKeyboardEvent(element, events.down, keyCodes.arrowDown);\n };\n\n /**\n * Trigger the up event on the given element if the up arrow key is pressed\n * without a modifier key.\n *\n * @method addUpListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addUpListener = function(element) {\n addKeyboardEvent(element, events.up, keyCodes.arrowUp);\n };\n\n /**\n * Trigger the home event on the given element if the home key is pressed\n * without a modifier key.\n *\n * @method addHomeListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addHomeListener = function(element) {\n addKeyboardEvent(element, events.home, keyCodes.home);\n };\n\n /**\n * Trigger the end event on the given element if the end key is pressed\n * without a modifier key.\n *\n * @method addEndListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addEndListener = function(element) {\n addKeyboardEvent(element, events.end, keyCodes.end);\n };\n\n /**\n * Trigger the next event on the given element if the right arrow key is pressed\n * without a modifier key in LTR mode or left arrow key in RTL mode.\n *\n * @method addNextListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addNextListener = function(element) {\n // Left and right are flipped in RTL mode.\n var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowLeft : keyCodes.arrowRight;\n\n addKeyboardEvent(element, events.next, keyCode);\n };\n\n /**\n * Trigger the previous event on the given element if the left arrow key is pressed\n * without a modifier key in LTR mode or right arrow key in RTL mode.\n *\n * @method addPreviousListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addPreviousListener = function(element) {\n // Left and right are flipped in RTL mode.\n var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowRight : keyCodes.arrowLeft;\n\n addKeyboardEvent(element, events.previous, keyCode);\n };\n\n /**\n * Trigger the asterix event on the given element if the asterix key is pressed\n * without a modifier key.\n *\n * @method addAsterixListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addAsterixListener = function(element) {\n addKeyboardEvent(element, events.asterix, keyCodes.asterix);\n };\n\n\n /**\n * Trigger the scrollTop event on the given element if the user scrolls to\n * the top of the given element.\n *\n * @method addScrollTopListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addScrollTopListener = function(element) {\n element.off('scroll.cie.scrollTop').on('scroll.cie.scrollTop', function(e) {\n var scrollTop = element.scrollTop();\n if (scrollTop === 0) {\n triggerEvent(events.scrollTop, e);\n }\n });\n };\n\n /**\n * Trigger the scrollBottom event on the given element if the user scrolls to\n * the bottom of the given element.\n *\n * @method addScrollBottomListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addScrollBottomListener = function(element) {\n element.off('scroll.cie.scrollBottom').on('scroll.cie.scrollBottom', function(e) {\n var scrollTop = element.scrollTop();\n var innerHeight = element.innerHeight();\n var scrollHeight = element[0].scrollHeight;\n\n if (scrollTop + innerHeight >= scrollHeight) {\n triggerEvent(events.scrollBottom, e);\n }\n });\n };\n\n /**\n * Trigger the scrollLock event on the given element if the user scrolls to\n * the bottom or top of the given element.\n *\n * @method addScrollLockListener\n * @private\n * @param {jQuery} element jQuery object to add event listeners to\n */\n var addScrollLockListener = function(element) {\n // Lock mousewheel scrolling within the element to stop the annoying window scroll.\n element.off('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock')\n .on('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock', function(e) {\n var scrollTop = element.scrollTop();\n var scrollHeight = element[0].scrollHeight;\n var height = element.height();\n var delta = (e.type == 'DOMMouseScroll' ?\n e.originalEvent.detail * -40 :\n e.originalEvent.wheelDelta);\n var up = delta > 0;\n\n if (!up && -delta > scrollHeight - height - scrollTop) {\n // Scrolling down past the bottom.\n element.scrollTop(scrollHeight);\n e.stopPropagation();\n e.preventDefault();\n e.returnValue = false;\n // Fire the scroll lock event.\n triggerEvent(events.scrollLock, e);\n\n return false;\n } else if (up && delta > scrollTop) {\n // Scrolling up past the top.\n element.scrollTop(0);\n e.stopPropagation();\n e.preventDefault();\n e.returnValue = false;\n // Fire the scroll lock event.\n triggerEvent(events.scrollLock, e);\n\n return false;\n }\n\n return true;\n });\n };\n\n /**\n * Trigger the ctrlPageUp event on the given element if the user presses the\n * control and page up key.\n *\n * @method addCtrlPageUpListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addCtrlPageUpListener = function(element) {\n element.off('keydown.cie.ctrlpageup').on('keydown.cie.ctrlpageup', function(e) {\n if (e.ctrlKey) {\n if (e.keyCode == keyCodes.pageUp) {\n triggerEvent(events.ctrlPageUp, e);\n }\n }\n });\n };\n\n /**\n * Trigger the ctrlPageDown event on the given element if the user presses the\n * control and page down key.\n *\n * @method addCtrlPageDownListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addCtrlPageDownListener = function(element) {\n element.off('keydown.cie.ctrlpagedown').on('keydown.cie.ctrlpagedown', function(e) {\n if (e.ctrlKey) {\n if (e.keyCode == keyCodes.pageDown) {\n triggerEvent(events.ctrlPageDown, e);\n }\n }\n });\n };\n\n /**\n * Trigger the enter event on the given element if the enter key is pressed\n * without a modifier key.\n *\n * @method addEnterListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addEnterListener = function(element) {\n addKeyboardEvent(element, events.enter, keyCodes.enter);\n };\n\n /**\n * Trigger the AccessibleChange event on the given element if the value of the element is changed.\n *\n * @method addAccessibleChangeListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addAccessibleChangeListener = function(element) {\n var onMac = navigator.userAgent.indexOf('Macintosh') !== -1;\n var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0));\n if (onMac || touchEnabled) {\n element.on('change', function(e) {\n triggerEvent(events.accessibleChange, e);\n });\n } else {\n element.on('focusin', function(e) {\n $(e.target).data('initValue', e.target.value);\n });\n element.on('focusout', function(e) {\n var initValue = $(e.target).data('initValue');\n $(e.target).removeData('initValue');\n if (e.target.value !== initValue) {\n triggerEvent(events.accessibleChange, e);\n }\n });\n element.on('keydown', function(e) {\n if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) {\n triggerEvent(events.accessibleChange, e);\n } else if (e.which === keyCodes.escape) {\n e.target.value = $(e.target).data('initValue');\n }\n });\n element.on('click', function(e) {\n var initValue = $(e.target).data('initValue');\n // Some browsers trigger onclick before onblur, therefore it is possible that initValue is undefined.\n if (typeof initValue !== 'undefined' && initValue != e.target.value) {\n triggerEvent(events.accessibleChange, e);\n }\n });\n }\n };\n\n /**\n * Get the list of events and their handlers.\n *\n * @method getHandlers\n * @private\n * @return {object} object key of event names and value of handler functions\n */\n var getHandlers = function() {\n var handlers = {};\n\n handlers[events.activate] = addActivateListener;\n handlers[events.keyboardActivate] = addKeyboardActivateListener;\n handlers[events.escape] = addEscapeListener;\n handlers[events.down] = addDownListener;\n handlers[events.up] = addUpListener;\n handlers[events.home] = addHomeListener;\n handlers[events.end] = addEndListener;\n handlers[events.next] = addNextListener;\n handlers[events.previous] = addPreviousListener;\n handlers[events.asterix] = addAsterixListener;\n handlers[events.scrollLock] = addScrollLockListener;\n handlers[events.scrollTop] = addScrollTopListener;\n handlers[events.scrollBottom] = addScrollBottomListener;\n handlers[events.ctrlPageUp] = addCtrlPageUpListener;\n handlers[events.ctrlPageDown] = addCtrlPageDownListener;\n handlers[events.enter] = addEnterListener;\n handlers[events.accessibleChange] = addAccessibleChangeListener;\n\n return handlers;\n };\n\n /**\n * Add all of the listeners on the given element for the requested events.\n *\n * @method define\n * @public\n * @param {object} element the DOM element to register event listeners on\n * @param {array} include the array of events to be triggered\n */\n var define = function(element, include) {\n element = $(element);\n include = include || [];\n\n if (!element.length || !include.length) {\n return;\n }\n\n $.each(getHandlers(), function(eventType, handler) {\n if (shouldAddEvent(eventType, include)) {\n handler(element);\n }\n });\n };\n\n return /** @module core/custom_interaction_events */ {\n define: define,\n events: events,\n };\n});\n"],"file":"custom_interaction_events.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/custom_interaction_events.js"],"names":["define","$","keyCodes","events","activate","keyboardActivate","escape","down","up","home","end","next","previous","asterix","scrollLock","scrollTop","scrollBottom","ctrlPageUp","ctrlPageDown","enter","accessibleChange","triggeredEvents","shouldAddEvent","eventType","include","length","indexOf","isModifierPressed","e","shiftKey","metaKey","altKey","ctrlKey","triggerEvent","eventName","eventTypeKey","hasOwnProperty","type","timeStamp","target","trigger","originalEvent","addKeyboardEvent","element","event","keyCode","off","on","addActivateListener","space","addKeyboardActivateListener","addEscapeListener","addDownListener","arrowDown","addUpListener","arrowUp","addHomeListener","addEndListener","addNextListener","attr","arrowLeft","arrowRight","addPreviousListener","addAsterixListener","addScrollTopListener","addScrollBottomListener","innerHeight","scrollHeight","addScrollLockListener","height","delta","detail","wheelDelta","stopPropagation","preventDefault","returnValue","addCtrlPageUpListener","pageUp","addCtrlPageDownListener","pageDown","addEnterListener","addAccessibleChangeListener","onMac","navigator","userAgent","touchEnabled","window","msMaxTouchPoints","nativeElement","get","addEventListener","data","value","initValue","removeData","which","getHandlers","handlers","each","handler"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * This module provides a wrapper to encapsulate a lot of the common combinations of\n * user interaction we use in Moodle.\n *\n * @module core/custom_interaction_events\n * @class custom_interaction_events\n * @package core\n * @copyright 2016 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.2\n */\ndefine(['jquery', 'core/key_codes'], function($, keyCodes) {\n // The list of events provided by this module. Namespaced to avoid clashes.\n var events = {\n activate: 'cie:activate',\n keyboardActivate: 'cie:keyboardactivate',\n escape: 'cie:escape',\n down: 'cie:down',\n up: 'cie:up',\n home: 'cie:home',\n end: 'cie:end',\n next: 'cie:next',\n previous: 'cie:previous',\n asterix: 'cie:asterix',\n scrollLock: 'cie:scrollLock',\n scrollTop: 'cie:scrollTop',\n scrollBottom: 'cie:scrollBottom',\n ctrlPageUp: 'cie:ctrlPageUp',\n ctrlPageDown: 'cie:ctrlPageDown',\n enter: 'cie:enter',\n accessibleChange: 'cie:accessibleChange',\n };\n // Static cache of jQuery events that have been handled. This should\n // only be populated by JavaScript generated events (which will keep it\n // fairly small).\n var triggeredEvents = {};\n\n /**\n * Check if the caller has asked for the given event type to be\n * registered.\n *\n * @method shouldAddEvent\n * @private\n * @param {string} eventType name of the event (see events above)\n * @param {array} include the list of events to be added\n * @return {bool} true if the event should be added, false otherwise.\n */\n var shouldAddEvent = function(eventType, include) {\n include = include || [];\n\n if (include.length && include.indexOf(eventType) !== -1) {\n return true;\n }\n\n return false;\n };\n\n /**\n * Check if any of the modifier keys have been pressed on the event.\n *\n * @method isModifierPressed\n * @private\n * @param {event} e jQuery event\n * @return {bool} true if shift, meta (command on Mac), alt or ctrl are pressed\n */\n var isModifierPressed = function(e) {\n return (e.shiftKey || e.metaKey || e.altKey || e.ctrlKey);\n };\n\n /**\n * Trigger the custom event for the given jQuery event.\n *\n * This function will only fire the custom event if one hasn't already been\n * fired for the jQuery event.\n *\n * This is to prevent multiple custom event handlers triggering multiple\n * custom events for a single jQuery event as it bubbles up the stack.\n *\n * @param {string} eventName The name of the custom event\n * @param {event} e The jQuery event\n * @return {void}\n */\n var triggerEvent = function(eventName, e) {\n var eventTypeKey = \"\";\n\n if (!e.hasOwnProperty('originalEvent')) {\n // This is a jQuery event generated from JavaScript not a browser event so\n // we need to build the cache key for the event.\n eventTypeKey = \"\" + eventName + e.type + e.timeStamp;\n\n if (!triggeredEvents.hasOwnProperty(eventTypeKey)) {\n // If we haven't seen this jQuery event before then fire a custom\n // event for it and remember the event for later.\n triggeredEvents[eventTypeKey] = true;\n $(e.target).trigger(eventName, [{originalEvent: e}]);\n }\n return;\n }\n\n eventTypeKey = \"triggeredCustom_\" + eventName;\n if (!e.originalEvent.hasOwnProperty(eventTypeKey)) {\n // If this is a jQuery event generated by the browser then set a\n // property on the original event to track that we've seen it before.\n // The property is set on the original event because it's the only part\n // of the jQuery event that is maintained through multiple event handlers.\n e.originalEvent[eventTypeKey] = true;\n $(e.target).trigger(eventName, [{originalEvent: e}]);\n return;\n }\n };\n\n /**\n * Register a keyboard event that ignores modifier keys.\n *\n * @method addKeyboardEvent\n * @private\n * @param {object} element A jQuery object of the element to bind events to\n * @param {string} event The custom interaction event name\n * @param {int} keyCode The key code.\n */\n var addKeyboardEvent = function(element, event, keyCode) {\n element.off('keydown.' + event).on('keydown.' + event, function(e) {\n if (!isModifierPressed(e)) {\n if (e.keyCode == keyCode) {\n triggerEvent(event, e);\n }\n }\n });\n };\n\n /**\n * Trigger the activate event on the given element if it is clicked or the enter\n * or space key are pressed without a modifier key.\n *\n * @method addActivateListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addActivateListener = function(element) {\n element.off('click.cie.activate').on('click.cie.activate', function(e) {\n triggerEvent(events.activate, e);\n });\n element.off('keydown.cie.activate').on('keydown.cie.activate', function(e) {\n if (!isModifierPressed(e)) {\n if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n triggerEvent(events.activate, e);\n }\n }\n });\n };\n\n /**\n * Trigger the keyboard activate event on the given element if the enter\n * or space key are pressed without a modifier key.\n *\n * @method addKeyboardActivateListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addKeyboardActivateListener = function(element) {\n element.off('keydown.cie.keyboardactivate').on('keydown.cie.keyboardactivate', function(e) {\n if (!isModifierPressed(e)) {\n if (e.keyCode == keyCodes.enter || e.keyCode == keyCodes.space) {\n triggerEvent(events.keyboardActivate, e);\n }\n }\n });\n };\n\n /**\n * Trigger the escape event on the given element if the escape key is pressed\n * without a modifier key.\n *\n * @method addEscapeListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addEscapeListener = function(element) {\n addKeyboardEvent(element, events.escape, keyCodes.escape);\n };\n\n /**\n * Trigger the down event on the given element if the down arrow key is pressed\n * without a modifier key.\n *\n * @method addDownListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addDownListener = function(element) {\n addKeyboardEvent(element, events.down, keyCodes.arrowDown);\n };\n\n /**\n * Trigger the up event on the given element if the up arrow key is pressed\n * without a modifier key.\n *\n * @method addUpListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addUpListener = function(element) {\n addKeyboardEvent(element, events.up, keyCodes.arrowUp);\n };\n\n /**\n * Trigger the home event on the given element if the home key is pressed\n * without a modifier key.\n *\n * @method addHomeListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addHomeListener = function(element) {\n addKeyboardEvent(element, events.home, keyCodes.home);\n };\n\n /**\n * Trigger the end event on the given element if the end key is pressed\n * without a modifier key.\n *\n * @method addEndListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addEndListener = function(element) {\n addKeyboardEvent(element, events.end, keyCodes.end);\n };\n\n /**\n * Trigger the next event on the given element if the right arrow key is pressed\n * without a modifier key in LTR mode or left arrow key in RTL mode.\n *\n * @method addNextListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addNextListener = function(element) {\n // Left and right are flipped in RTL mode.\n var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowLeft : keyCodes.arrowRight;\n\n addKeyboardEvent(element, events.next, keyCode);\n };\n\n /**\n * Trigger the previous event on the given element if the left arrow key is pressed\n * without a modifier key in LTR mode or right arrow key in RTL mode.\n *\n * @method addPreviousListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addPreviousListener = function(element) {\n // Left and right are flipped in RTL mode.\n var keyCode = $('html').attr('dir') == \"rtl\" ? keyCodes.arrowRight : keyCodes.arrowLeft;\n\n addKeyboardEvent(element, events.previous, keyCode);\n };\n\n /**\n * Trigger the asterix event on the given element if the asterix key is pressed\n * without a modifier key.\n *\n * @method addAsterixListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addAsterixListener = function(element) {\n addKeyboardEvent(element, events.asterix, keyCodes.asterix);\n };\n\n\n /**\n * Trigger the scrollTop event on the given element if the user scrolls to\n * the top of the given element.\n *\n * @method addScrollTopListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addScrollTopListener = function(element) {\n element.off('scroll.cie.scrollTop').on('scroll.cie.scrollTop', function(e) {\n var scrollTop = element.scrollTop();\n if (scrollTop === 0) {\n triggerEvent(events.scrollTop, e);\n }\n });\n };\n\n /**\n * Trigger the scrollBottom event on the given element if the user scrolls to\n * the bottom of the given element.\n *\n * @method addScrollBottomListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addScrollBottomListener = function(element) {\n element.off('scroll.cie.scrollBottom').on('scroll.cie.scrollBottom', function(e) {\n var scrollTop = element.scrollTop();\n var innerHeight = element.innerHeight();\n var scrollHeight = element[0].scrollHeight;\n\n if (scrollTop + innerHeight >= scrollHeight) {\n triggerEvent(events.scrollBottom, e);\n }\n });\n };\n\n /**\n * Trigger the scrollLock event on the given element if the user scrolls to\n * the bottom or top of the given element.\n *\n * @method addScrollLockListener\n * @private\n * @param {jQuery} element jQuery object to add event listeners to\n */\n var addScrollLockListener = function(element) {\n // Lock mousewheel scrolling within the element to stop the annoying window scroll.\n element.off('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock')\n .on('DOMMouseScroll.cie.DOMMouseScrollLock mousewheel.cie.mousewheelLock', function(e) {\n var scrollTop = element.scrollTop();\n var scrollHeight = element[0].scrollHeight;\n var height = element.height();\n var delta = (e.type == 'DOMMouseScroll' ?\n e.originalEvent.detail * -40 :\n e.originalEvent.wheelDelta);\n var up = delta > 0;\n\n if (!up && -delta > scrollHeight - height - scrollTop) {\n // Scrolling down past the bottom.\n element.scrollTop(scrollHeight);\n e.stopPropagation();\n e.preventDefault();\n e.returnValue = false;\n // Fire the scroll lock event.\n triggerEvent(events.scrollLock, e);\n\n return false;\n } else if (up && delta > scrollTop) {\n // Scrolling up past the top.\n element.scrollTop(0);\n e.stopPropagation();\n e.preventDefault();\n e.returnValue = false;\n // Fire the scroll lock event.\n triggerEvent(events.scrollLock, e);\n\n return false;\n }\n\n return true;\n });\n };\n\n /**\n * Trigger the ctrlPageUp event on the given element if the user presses the\n * control and page up key.\n *\n * @method addCtrlPageUpListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addCtrlPageUpListener = function(element) {\n element.off('keydown.cie.ctrlpageup').on('keydown.cie.ctrlpageup', function(e) {\n if (e.ctrlKey) {\n if (e.keyCode == keyCodes.pageUp) {\n triggerEvent(events.ctrlPageUp, e);\n }\n }\n });\n };\n\n /**\n * Trigger the ctrlPageDown event on the given element if the user presses the\n * control and page down key.\n *\n * @method addCtrlPageDownListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addCtrlPageDownListener = function(element) {\n element.off('keydown.cie.ctrlpagedown').on('keydown.cie.ctrlpagedown', function(e) {\n if (e.ctrlKey) {\n if (e.keyCode == keyCodes.pageDown) {\n triggerEvent(events.ctrlPageDown, e);\n }\n }\n });\n };\n\n /**\n * Trigger the enter event on the given element if the enter key is pressed\n * without a modifier key.\n *\n * @method addEnterListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addEnterListener = function(element) {\n addKeyboardEvent(element, events.enter, keyCodes.enter);\n };\n\n /**\n * Trigger the AccessibleChange event on the given element if the value of the element is changed.\n *\n * @method addAccessibleChangeListener\n * @private\n * @param {object} element jQuery object to add event listeners to\n */\n var addAccessibleChangeListener = function(element) {\n var onMac = navigator.userAgent.indexOf('Macintosh') !== -1;\n var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0));\n if (onMac || touchEnabled) {\n element.on('change', function(e) {\n triggerEvent(events.accessibleChange, e);\n });\n } else {\n var nativeElement = element.get()[0];\n // The `focus` and `blur` events do not support bubbling. Use Event Capture instead.\n nativeElement.addEventListener('focus', function(e) {\n $(e.target).data('initValue', e.target.value);\n }, true);\n nativeElement.addEventListener('blur', function(e) {\n var initValue = $(e.target).data('initValue');\n $(e.target).removeData('initValue');\n if (e.target.value !== initValue) {\n triggerEvent(events.accessibleChange, e);\n }\n }, true);\n element.on('keydown', function(e) {\n if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) {\n triggerEvent(events.accessibleChange, e);\n } else if (e.which === keyCodes.escape) {\n e.target.value = $(e.target).data('initValue');\n }\n });\n element.on('click', function(e) {\n var initValue = $(e.target).data('initValue');\n // Some browsers trigger onclick before onblur, therefore it is possible that initValue is undefined.\n if (typeof initValue !== 'undefined' && initValue != e.target.value) {\n triggerEvent(events.accessibleChange, e);\n }\n });\n }\n };\n\n /**\n * Get the list of events and their handlers.\n *\n * @method getHandlers\n * @private\n * @return {object} object key of event names and value of handler functions\n */\n var getHandlers = function() {\n var handlers = {};\n\n handlers[events.activate] = addActivateListener;\n handlers[events.keyboardActivate] = addKeyboardActivateListener;\n handlers[events.escape] = addEscapeListener;\n handlers[events.down] = addDownListener;\n handlers[events.up] = addUpListener;\n handlers[events.home] = addHomeListener;\n handlers[events.end] = addEndListener;\n handlers[events.next] = addNextListener;\n handlers[events.previous] = addPreviousListener;\n handlers[events.asterix] = addAsterixListener;\n handlers[events.scrollLock] = addScrollLockListener;\n handlers[events.scrollTop] = addScrollTopListener;\n handlers[events.scrollBottom] = addScrollBottomListener;\n handlers[events.ctrlPageUp] = addCtrlPageUpListener;\n handlers[events.ctrlPageDown] = addCtrlPageDownListener;\n handlers[events.enter] = addEnterListener;\n handlers[events.accessibleChange] = addAccessibleChangeListener;\n\n return handlers;\n };\n\n /**\n * Add all of the listeners on the given element for the requested events.\n *\n * @method define\n * @public\n * @param {object} element the DOM element to register event listeners on\n * @param {array} include the array of events to be triggered\n */\n var define = function(element, include) {\n element = $(element);\n include = include || [];\n\n if (!element.length || !include.length) {\n return;\n }\n\n $.each(getHandlers(), function(eventType, handler) {\n if (shouldAddEvent(eventType, include)) {\n handler(element);\n }\n });\n };\n\n return /** @module core/custom_interaction_events */ {\n define: define,\n events: events,\n };\n});\n"],"file":"custom_interaction_events.min.js"} \ No newline at end of file diff --git a/lib/amd/src/custom_interaction_events.js b/lib/amd/src/custom_interaction_events.js index 84f09d2d5fd..c429e926341 100644 --- a/lib/amd/src/custom_interaction_events.js +++ b/lib/amd/src/custom_interaction_events.js @@ -431,16 +431,18 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) { triggerEvent(events.accessibleChange, e); }); } else { - element.on('focusin', function(e) { + var nativeElement = element.get()[0]; + // The `focus` and `blur` events do not support bubbling. Use Event Capture instead. + nativeElement.addEventListener('focus', function(e) { $(e.target).data('initValue', e.target.value); - }); - element.on('focusout', function(e) { + }, true); + nativeElement.addEventListener('blur', function(e) { var initValue = $(e.target).data('initValue'); $(e.target).removeData('initValue'); if (e.target.value !== initValue) { triggerEvent(events.accessibleChange, e); } - }); + }, true); element.on('keydown', function(e) { if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) { triggerEvent(events.accessibleChange, e); -- 2.11.4.GIT