/** * what-input - A global utility for tracking the current input method (mouse, keyboard or touch). * @version v5.2.10 * @link https://github.com/ten1seven/what-input * @license MIT */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define("whatInput", [], factory); else if(typeof exports === 'object') exports["whatInput"] = factory(); else root["whatInput"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { 'use strict'; module.exports = function () { /* * bail out if there is no document or window * (i.e. in a node/non-DOM environment) * * Return a stubbed API instead */ if (typeof document === 'undefined' || typeof window === 'undefined') { return { // always return "initial" because no interaction will ever be detected ask: function ask() { return 'initial'; }, // always return null element: function element() { return null; }, // no-op ignoreKeys: function ignoreKeys() {}, // no-op specificKeys: function specificKeys() {}, // no-op registerOnChange: function registerOnChange() {}, // no-op unRegisterOnChange: function unRegisterOnChange() {} }; } /* * variables */ // cache document.documentElement var docElem = document.documentElement; // currently focused dom element var currentElement = null; // last used input type var currentInput = 'initial'; // last used input intent var currentIntent = currentInput; // UNIX timestamp of current event var currentTimestamp = Date.now(); // check for a `data-whatpersist` attribute on either the `html` or `body` elements, defaults to `true` var shouldPersist = 'false'; // form input types var formInputs = ['button', 'input', 'select', 'textarea']; // empty array for holding callback functions var functionList = []; // list of modifier keys commonly used with the mouse and // can be safely ignored to prevent false keyboard detection var ignoreMap = [16, // shift 17, // control 18, // alt 91, // Windows key / left Apple cmd 93 // Windows menu / right Apple cmd ]; var specificMap = []; // mapping of events to input types var inputMap = { keydown: 'keyboard', keyup: 'keyboard', mousedown: 'mouse', mousemove: 'mouse', MSPointerDown: 'pointer', MSPointerMove: 'pointer', pointerdown: 'pointer', pointermove: 'pointer', touchstart: 'touch', touchend: 'touch' // boolean: true if the page is being scrolled };var isScrolling = false; // store current mouse position var mousePos = { x: null, y: null // map of IE 10 pointer events };var pointerMap = { 2: 'touch', 3: 'touch', // treat pen like touch 4: 'mouse' // check support for passive event listeners };var supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function get() { supportsPassive = true; } }); window.addEventListener('test', null, opts); } catch (e) {} // fail silently /* * set up */ var setUp = function setUp() { // add correct mouse wheel event mapping to `inputMap` inputMap[detectWheel()] = 'mouse'; addListeners(); }; /* * events */ var addListeners = function addListeners() { // `pointermove`, `MSPointerMove`, `mousemove` and mouse wheel event binding // can only demonstrate potential, but not actual, interaction // and are treated separately var options = supportsPassive ? { passive: true } : false; document.addEventListener('DOMContentLoaded', setPersist); // pointer events (mouse, pen, touch) if (window.PointerEvent) { window.addEventListener('pointerdown', setInput); window.addEventListener('pointermove', setIntent); } else if (window.MSPointerEvent) { window.addEventListener('MSPointerDown', setInput); window.addEventListener('MSPointerMove', setIntent); } else { // mouse events window.addEventListener('mousedown', setInput); window.addEventListener('mousemove', setIntent); // touch events if ('ontouchstart' in window) { window.addEventListener('touchstart', setInput, options); window.addEventListener('touchend', setInput); } } // mouse wheel window.addEventListener(detectWheel(), setIntent, options); // keyboard events window.addEventListener('keydown', setInput); window.addEventListener('keyup', setInput); // focus events window.addEventListener('focusin', setElement); window.addEventListener('focusout', clearElement); }; // checks if input persistence should happen and // get saved state from session storage if true (defaults to `false`) var setPersist = function setPersist() { shouldPersist = !(docElem.getAttribute('data-whatpersist') || document.body.getAttribute('data-whatpersist') === 'false'); if (shouldPersist) { // check for session variables and use if available try { if (window.sessionStorage.getItem('what-input')) { currentInput = window.sessionStorage.getItem('what-input'); } if (window.sessionStorage.getItem('what-intent')) { currentIntent = window.sessionStorage.getItem('what-intent'); } } catch (e) { // fail silently } } // always run these so at least `initial` state is set doUpdate('input'); doUpdate('intent'); }; // checks conditions before updating new input var setInput = function setInput(event) { var eventKey = event.which; var value = inputMap[event.type]; if (value === 'pointer') { value = pointerType(event); } var ignoreMatch = !specificMap.length && ignoreMap.indexOf(eventKey) === -1; var specificMatch = specificMap.length && specificMap.indexOf(eventKey) !== -1; var shouldUpdate = value === 'keyboard' && eventKey && (ignoreMatch || specificMatch) || value === 'mouse' || value === 'touch'; // prevent touch detection from being overridden by event execution order if (validateTouch(value)) { shouldUpdate = false; } if (shouldUpdate && currentInput !== value) { currentInput = value; persistInput('input', currentInput); doUpdate('input'); } if (shouldUpdate && currentIntent !== value) { // preserve intent for keyboard interaction with form fields var activeElem = document.activeElement; var notFormInput = activeElem && activeElem.nodeName && (formInputs.indexOf(activeElem.nodeName.toLowerCase()) === -1 || activeElem.nodeName.toLowerCase() === 'button' && !checkClosest(activeElem, 'form')); if (notFormInput) { currentIntent = value; persistInput('intent', currentIntent); doUpdate('intent'); } } }; // updates the doc and `inputTypes` array with new input var doUpdate = function doUpdate(which) { docElem.setAttribute('data-what' + which, which === 'input' ? currentInput : currentIntent); fireFunctions(which); }; // updates input intent for `mousemove` and `pointermove` var setIntent = function setIntent(event) { var value = inputMap[event.type]; if (value === 'pointer') { value = pointerType(event); } // test to see if `mousemove` happened relative to the screen to detect scrolling versus mousemove detectScrolling(event); // only execute if scrolling isn't happening if ((!isScrolling && !validateTouch(value) || isScrolling && event.type === 'wheel' || event.type === 'mousewheel' || event.type === 'DOMMouseScroll') && currentIntent !== value) { currentIntent = value; persistInput('intent', currentIntent); doUpdate('intent'); } }; var setElement = function setElement(event) { if (!event.target.nodeName) { // If nodeName is undefined, clear the element // This can happen if click inside an element. clearElement(); return; } currentElement = event.target.nodeName.toLowerCase(); docElem.setAttribute('data-whatelement', currentElement); if (event.target.classList && event.target.classList.length) { docElem.setAttribute('data-whatclasses', event.target.classList.toString().replace(' ', ',')); } }; var clearElement = function clearElement() { currentElement = null; docElem.removeAttribute('data-whatelement'); docElem.removeAttribute('data-whatclasses'); }; var persistInput = function persistInput(which, value) { if (shouldPersist) { try { window.sessionStorage.setItem('what-' + which, value); } catch (e) { // fail silently } } }; /* * utilities */ var pointerType = function pointerType(event) { if (typeof event.pointerType === 'number') { return pointerMap[event.pointerType]; } else { // treat pen like touch return event.pointerType === 'pen' ? 'touch' : event.pointerType; } }; // prevent touch detection from being overridden by event execution order var validateTouch = function validateTouch(value) { var timestamp = Date.now(); var touchIsValid = value === 'mouse' && currentInput === 'touch' && timestamp - currentTimestamp < 200; currentTimestamp = timestamp; return touchIsValid; }; // detect version of mouse wheel event to use // via https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event var detectWheel = function detectWheel() { var wheelType = null; // Modern browsers support "wheel" if ('onwheel' in document.createElement('div')) { wheelType = 'wheel'; } else { // Webkit and IE support at least "mousewheel" // or assume that remaining browsers are older Firefox wheelType = document.onmousewheel !== undefined ? 'mousewheel' : 'DOMMouseScroll'; } return wheelType; }; // runs callback functions var fireFunctions = function fireFunctions(type) { for (var i = 0, len = functionList.length; i < len; i++) { if (functionList[i].type === type) { functionList[i].fn.call(undefined, type === 'input' ? currentInput : currentIntent); } } }; // finds matching element in an object var objPos = function objPos(match) { for (var i = 0, len = functionList.length; i < len; i++) { if (functionList[i].fn === match) { return i; } } }; var detectScrolling = function detectScrolling(event) { if (mousePos.x !== event.screenX || mousePos.y !== event.screenY) { isScrolling = false; mousePos.x = event.screenX; mousePos.y = event.screenY; } else { isScrolling = true; } }; // manual version of `closest()` var checkClosest = function checkClosest(elem, tag) { var ElementPrototype = window.Element.prototype; if (!ElementPrototype.matches) { ElementPrototype.matches = ElementPrototype.msMatchesSelector || ElementPrototype.webkitMatchesSelector; } if (!ElementPrototype.closest) { do { if (elem.matches(tag)) { return elem; } elem = elem.parentElement || elem.parentNode; } while (elem !== null && elem.nodeType === 1); return null; } else { return elem.closest(tag); } }; /* * init */ // don't start script unless browser cuts the mustard // (also passes if polyfills are used) if ('addEventListener' in window && Array.prototype.indexOf) { setUp(); } /* * api */ return { // returns string: the current input type // opt: 'intent'|'input' // 'input' (default): returns the same value as the `data-whatinput` attribute // 'intent': includes `data-whatintent` value if it's different than `data-whatinput` ask: function ask(opt) { return opt === 'intent' ? currentIntent : currentInput; }, // returns string: the currently focused element or null element: function element() { return currentElement; }, // overwrites ignored keys with provided array ignoreKeys: function ignoreKeys(arr) { ignoreMap = arr; }, // overwrites specific char keys to update on specificKeys: function specificKeys(arr) { specificMap = arr; }, // attach functions to input and intent "events" // funct: function to fire on change // eventType: 'input'|'intent' registerOnChange: function registerOnChange(fn, eventType) { functionList.push({ fn: fn, type: eventType || 'input' }); }, unRegisterOnChange: function unRegisterOnChange(fn) { var position = objPos(fn); if (position || position === 0) { functionList.splice(position, 1); } }, clearStorage: function clearStorage() { window.sessionStorage.clear(); } }; }(); /***/ }) /******/ ]) }); ;