@nrk/core-input
Advanced tools
Comparing version 1.1.0 to 1.1.1
import {name, version} from './package.json' | ||
import {IS_IOS, addEvent, escapeHTML, dispatchEvent, queryAll} from '../utils' | ||
import {IS_IOS, addEvent, escapeHTML, dispatchEvent, requestAnimFrame, queryAll} from '../utils' | ||
@@ -102,4 +102,6 @@ const UUID = `data-${name}-${version}`.replace(/\W+/g, '-') // Strip invalid attribute characters | ||
function setupExpand (input, open = input.getAttribute('aria-expanded') === 'true') { | ||
input.nextElementSibling[open ? 'removeAttribute' : 'setAttribute']('hidden', '') | ||
input.setAttribute('aria-expanded', open) | ||
requestAnimFrame(() => { // Fixes VoiceOver Safari focus jumping to parentElement | ||
input.nextElementSibling[open ? 'removeAttribute' : 'setAttribute']('hidden', '') | ||
input.setAttribute('aria-expanded', open) | ||
}) | ||
} | ||
@@ -126,4 +128,5 @@ | ||
req.open('GET', url.replace('{{value}}', window.encodeURIComponent(input.value)), true) | ||
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest') // https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With | ||
req.send() | ||
}, AJAX_DEBOUNCE) | ||
} |
@@ -1,2 +0,236 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.coreInput=t()}(this,function(){"use strict";var e="undefined"!=typeof window,o=(e&&/(android)/i.test(navigator.userAgent),e&&/iPad|iPhone|iPod/.test(String(navigator.platform))),i=function(e){void 0===e&&(e=!1);try{window.addEventListener("test",null,{get passive(){e=!0}})}catch(e){}return e}();function t(e,t,n,r){(void 0===r&&(r=!1),"undefined"==typeof window||window[e=e+"-"+t])||(i||"object"!=typeof r||(r=Boolean(r.capture)),("resize"===t||"load"===t?window:document).addEventListener(window[e]=t,n,r))}var n={"&":"&","<":"<",">":">",'"':""","/":"/","'":"'"};function r(e){return String(e||"").replace(/[&<>"'/]/g,function(e){return n[e]})}var a="prevent_recursive_dispatch_maximum_callstack";function u(e,t,n){void 0===n&&(n={});var r,i=""+a+t;if(e[i])return!0;e[i]=!0,"function"==typeof window.CustomEvent?r=new window.CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n}):(r=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,n);var o=e.dispatchEvent(r);return e[i]=null,o}function c(e,t){if(void 0===t&&(t=document),e){if(e.nodeType)return[e];if("string"==typeof e)return[].slice.call(t.querySelectorAll(e));if(e.length)return[].slice.call(e)}return[]}var d="data-@nrk/core-input-1.0.4".replace(/\W+/g,"-"),l=13,f=27,s=33,p=34,v=35,m=36,b=38,g=40,y='[tabindex="-1"]',w=500;function x(e,t){var r="object"==typeof t?t:{content:t},i="string"==typeof r.content;return c(e).map(function(e){var t=e.nextElementSibling,n=void 0===r.ajax?e.getAttribute(d):r.ajax;return e.setAttribute(d,n||""),e.setAttribute(o?"data-role":"role","combobox"),e.setAttribute("aria-autocomplete","list"),e.setAttribute("autocomplete","off"),i&&(t.innerHTML=r.content),c("a,button",t).forEach(C),A(e,r.open),e})}function h(a){a.ctrlKey||a.altKey||a.metaKey||a.defaultPrevented||c("["+d+"]").forEach(function(e){var t,n,r=e.nextElementSibling,i=e===a.target||r.contains(a.target),o="click"===a.type&&i&&c(y,r).filter(function(e){return e.contains(a.target)})[0];o?(t=e,n={relatedTarget:r,currentTarget:o,value:o.value||o.textContent.trim()},u(t,"input.select",n)&&(t.value=n.value,t.focus(),A(t,!1))):A(e,i)})}function E(e,t){var n=e.nextElementSibling,r=c(y+":not([hidden])",n),i=r.indexOf(document.activeElement),o=!1;t.keyCode===g?o=r[i+1]||r[0]:t.keyCode===b?o=r[i-1]||r.pop():n.contains(t.target)&&(t.keyCode===v||t.keyCode===p?o=r.pop():t.keyCode===m||t.keyCode===s?o=r[0]:t.keyCode!==l&&e.focus()),n.hasAttribute("hidden")||t.keyCode!==f||t.preventDefault(),A(e,t.keyCode!==f),!1!==o&&t.preventDefault(),o&&o.focus()}function A(e,t){void 0===t&&(t="true"===e.getAttribute("aria-expanded")),e.nextElementSibling[t?"removeAttribute":"setAttribute"]("hidden",""),e.setAttribute("aria-expanded",t)}function C(e,t,n){e.setAttribute("aria-label",e.textContent.trim()+", "+(t+1)+" av "+n.length),e.setAttribute("tabindex","-1")}function k(e){var t=e.getAttribute(d),n=k.req=k.req||new window.XMLHttpRequest;if(!t)return!1;clearTimeout(k.timer),n.abort(),n.onload=function(){try{n.responseJSON=JSON.parse(n.responseText)}catch(e){n.responseJSON=!1}u(e,"input.ajax",n)},k.timer=setTimeout(function(){e.value&&(n.open("GET",t.replace("{{value}}",window.encodeURIComponent(e.value)),!0),n.send())},w)}return x.escapeHTML=r,x.highlight=function(e,t){var n=t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&");return r(e).replace(new RegExp(n||".^","gi"),"<mark>$&</mark>")},t(d,"click",h),t(d,"focus",h,!0),t(d,"input",function(e){var r,t,n=e.target;n.hasAttribute(d)&&(t={relatedTarget:(r=n).nextElementSibling},u(r,"input.filter",t)&&!k(r)&&c(y,r.nextElementSibling).reduce(function(e,t){var n=-1!==t.textContent.toLowerCase().indexOf(r.value.toLowerCase());return t[n?"removeAttribute":"setAttribute"]("hidden",""),n?e.concat(t):e},[]).forEach(C))}),t(d,"keydown",function(e){if(!(e.ctrlKey||e.altKey||e.metaKey)){if(e.target.hasAttribute(d))return E(e.target,e);for(var t=e.target,n=void 0;t;t=t.parentElement)if((n=t.previousElementSibling)&&n.hasAttribute(d))return E(n,e)}}),x}); | ||
/*! @nrk/core-input v1.1.0 - Copyright (c) 2017-2018 NRK */ | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.coreInput = factory()); | ||
}(this, (function () { 'use strict'; | ||
var name = "@nrk/core-input"; | ||
var version = "1.1.0"; | ||
var IS_BROWSER = typeof window !== 'undefined'; | ||
var IS_ANDROID = IS_BROWSER && /(android)/i.test(navigator.userAgent); // Bad, but needed | ||
var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(String(navigator.platform)); | ||
var HAS_EVENT_OPTIONS = (function (has) { | ||
if ( has === void 0 ) has = false; | ||
try { window.addEventListener('test', null, {get passive () { has = true; }}); } catch (e) {} | ||
return has | ||
})(); | ||
/** | ||
* addEvent | ||
* @param {String} uuid An unique ID of the event to bind - ensurnes single instance | ||
* @param {String} type The type of event to bind | ||
* @param {Function} handler The function to call on event | ||
* @param {Boolean|Object} options useCapture or options object for addEventListener. Defaults to false | ||
*/ | ||
function addEvent (uuid, type, handler, options) { | ||
if ( options === void 0 ) options = false; | ||
if (typeof window === 'undefined' || window[uuid = uuid + "-" + type]) { return } // Ensure single instance | ||
if (!HAS_EVENT_OPTIONS && typeof options === 'object') { options = Boolean(options.capture); } // Fix unsupported options | ||
var node = (type === 'resize' || type === 'load') ? window : document; | ||
node.addEventListener(window[uuid] = type, handler, options); | ||
} | ||
/** | ||
* escapeHTML | ||
* @param {String} str A string with potential html tokens | ||
* @return {String} Escaped HTML string according to OWASP recommendation | ||
*/ | ||
var ESCAPE_MAP = {'&': '&', '<': '<', '>': '>', '"': '"', '/': '/', '\'': '''}; | ||
function escapeHTML (str) { | ||
return String(str || '').replace(/[&<>"'/]/g, function (char) { return ESCAPE_MAP[char]; }) | ||
} | ||
/** | ||
* dispatchEvent - with infinite loop prevention | ||
* @param {Element} elem The target object | ||
* @param {String} name The source object(s) | ||
* @param {Object} detail Detail object (bubbles and cancelable is set to true) | ||
* @return {Boolean} Whether the event was canceled | ||
*/ | ||
var IGNORE = 'prevent_recursive_dispatch_maximum_callstack'; | ||
function dispatchEvent (element, name, detail) { | ||
if ( detail === void 0 ) detail = {}; | ||
var ignore = "" + IGNORE + name; | ||
var event; | ||
if (element[ignore]) { return true } // We are already processing this event, so skip sending a new one | ||
else { element[ignore] = true; } // Add name to dispatching ignore | ||
if (typeof window.CustomEvent === 'function') { | ||
event = new window.CustomEvent(name, {bubbles: true, cancelable: true, detail: detail}); | ||
} else { | ||
event = document.createEvent('CustomEvent'); | ||
event.initCustomEvent(name, true, true, detail); | ||
} | ||
// IE reports incorrect event.defaultPrevented | ||
// but correct return value on element.dispatchEvent | ||
var result = element.dispatchEvent(event); | ||
element[ignore] = null; // Remove name from dispatching ignore | ||
return result // Follow W3C standard for return value | ||
} | ||
/** | ||
* requestAnimFrame (super simple polyfill) | ||
*/ | ||
function requestAnimFrame (fn) { | ||
(window.requestAnimationFrame || window.setTimeout)(fn); | ||
} | ||
/** | ||
* queryAll | ||
* @param {String|NodeList|Array|Element} elements A CSS selector string, nodeList, element array, or single element | ||
* @return {Element[]} Array of elements | ||
*/ | ||
function queryAll (elements, context) { | ||
if ( context === void 0 ) context = document; | ||
if (elements) { | ||
if (elements.nodeType) { return [elements] } | ||
if (typeof elements === 'string') { return [].slice.call(context.querySelectorAll(elements)) } | ||
if (elements.length) { return [].slice.call(elements) } | ||
} | ||
return [] | ||
} | ||
var UUID = ("data-" + name + "-" + version).replace(/\W+/g, '-'); // Strip invalid attribute characters | ||
var KEYS = {ENTER: 13, ESC: 27, PAGEUP: 33, PAGEDOWN: 34, END: 35, HOME: 36, UP: 38, DOWN: 40}; | ||
var ITEM = '[tabindex="-1"]'; | ||
var AJAX_DEBOUNCE = 500; | ||
function input (elements, content) { | ||
var options = typeof content === 'object' ? content : {content: content}; | ||
var repaint = typeof options.content === 'string'; | ||
return queryAll(elements).map(function (input) { | ||
var list = input.nextElementSibling; | ||
var ajax = typeof options.ajax === 'undefined' ? input.getAttribute(UUID) : options.ajax; | ||
input.setAttribute(UUID, ajax || ''); | ||
input.setAttribute(IS_IOS ? 'data-role' : 'role', 'combobox'); // iOS does not inform user area is editable if combobox | ||
input.setAttribute('aria-autocomplete', 'list'); | ||
input.setAttribute('autocomplete', 'off'); | ||
if (repaint) { list.innerHTML = options.content; } | ||
queryAll('a,button', list).forEach(setupItem); | ||
setupExpand(input, options.open); | ||
return input | ||
}) | ||
} | ||
// Expose helper functions | ||
input.escapeHTML = escapeHTML; | ||
input.highlight = function (haystack, needle) { | ||
var escapedRegExp = needle.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); // From lodash | ||
return escapeHTML(haystack).replace(new RegExp(escapedRegExp || '.^', 'gi'), '<mark>$&</mark>') | ||
}; | ||
addEvent(UUID, 'click', onClickOrFocus); | ||
addEvent(UUID, 'focus', onClickOrFocus, true); // Use focus with capturing instead of focusin for old Firefox | ||
function onClickOrFocus (event) { | ||
if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented) { return } | ||
queryAll(("[" + UUID + "]")).forEach(function (input) { | ||
var list = input.nextElementSibling; | ||
var open = input === event.target || list.contains(event.target); | ||
var item = event.type === 'click' && open && queryAll(ITEM, list).filter(function (item) { return item.contains(event.target); })[0]; | ||
if (item) { onSelect(input, {relatedTarget: list, currentTarget: item, value: item.value || item.textContent.trim()}); } | ||
else { setupExpand(input, open); } | ||
}); | ||
} | ||
addEvent(UUID, 'input', function (ref) { | ||
var input = ref.target; | ||
if (input.hasAttribute(UUID)) { onFilter(input, {relatedTarget: input.nextElementSibling}); } | ||
}); | ||
addEvent(UUID, 'keydown', function (event) { | ||
if (event.ctrlKey || event.altKey || event.metaKey) { return } | ||
if (event.target.hasAttribute(UUID)) { return onKey(event.target, event) } // Quick check | ||
for (var el = event.target, prev = (void 0); el; el = el.parentElement) { // Check if inside list | ||
if ((prev = el.previousElementSibling) && prev.hasAttribute(UUID)) { return onKey(prev, event) } | ||
} | ||
}); | ||
function onKey (input, event) { | ||
var list = input.nextElementSibling; | ||
var focus = queryAll((ITEM + ":not([hidden])"), list); | ||
var index = focus.indexOf(document.activeElement); | ||
var item = false; | ||
if (event.keyCode === KEYS.DOWN) { item = focus[index + 1] || focus[0]; } | ||
else if (event.keyCode === KEYS.UP) { item = focus[index - 1] || focus.pop(); } | ||
else if (list.contains(event.target)) { // Aditional shortcuts if focus is inside list | ||
if (event.keyCode === KEYS.END || event.keyCode === KEYS.PAGEDOWN) { item = focus.pop(); } | ||
else if (event.keyCode === KEYS.HOME || event.keyCode === KEYS.PAGEUP) { item = focus[0]; } | ||
else if (event.keyCode !== KEYS.ENTER) { input.focus(); } | ||
} | ||
if (!list.hasAttribute('hidden') && event.keyCode === KEYS.ESC) { event.preventDefault(); } | ||
setupExpand(input, event.keyCode !== KEYS.ESC); | ||
if (item !== false) { event.preventDefault(); } // event.preventDefault even if empty list | ||
if (item) { item.focus(); } | ||
} | ||
function onSelect (input, detail) { | ||
if (dispatchEvent(input, 'input.select', detail)) { | ||
input.value = detail.value; | ||
input.focus(); | ||
setupExpand(input, false); | ||
} | ||
} | ||
function onFilter (input, detail) { | ||
if (dispatchEvent(input, 'input.filter', detail) && !ajax(input)) { | ||
queryAll(ITEM, input.nextElementSibling).reduce(function (acc, item) { | ||
var show = item.textContent.toLowerCase().indexOf(input.value.toLowerCase()) !== -1; | ||
item[show ? 'removeAttribute' : 'setAttribute']('hidden', ''); | ||
return show ? acc.concat(item) : acc | ||
}, []).forEach(setupItem); | ||
} | ||
} | ||
function setupExpand (input, open) { | ||
if ( open === void 0 ) open = input.getAttribute('aria-expanded') === 'true'; | ||
requestAnimFrame(function () { // Fixes VoiceOver Safari focus jumping to parentElement | ||
input.nextElementSibling[open ? 'removeAttribute' : 'setAttribute']('hidden', ''); | ||
input.setAttribute('aria-expanded', open); | ||
}); | ||
} | ||
function setupItem (item, index, items) { | ||
item.setAttribute('aria-label', ((item.textContent.trim()) + ", " + (index + 1) + " av " + (items.length))); | ||
item.setAttribute('tabindex', '-1'); | ||
} | ||
function ajax (input) { | ||
var url = input.getAttribute(UUID); | ||
var req = ajax.req = ajax.req || new window.XMLHttpRequest(); | ||
if (!url) { return false } | ||
clearTimeout(ajax.timer); // Clear previous search | ||
req.abort(); // Abort previous request | ||
req.onload = function () { | ||
try { req.responseJSON = JSON.parse(req.responseText); } catch (err) { req.responseJSON = false; } | ||
dispatchEvent(input, 'input.ajax', req); | ||
}; | ||
ajax.timer = setTimeout(function () { // Debounce next request 500 milliseconds | ||
if (!input.value) { return } // Abort if input is empty | ||
req.open('GET', url.replace('{{value}}', window.encodeURIComponent(input.value)), true); | ||
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With | ||
req.send(); | ||
}, AJAX_DEBOUNCE); | ||
} | ||
return input; | ||
}))); | ||
//# sourceMappingURL=core-input.min.js.map |
305
jsx/index.js
@@ -1,2 +0,303 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):e.CoreInput=t(e.React)}(this,function(a){"use strict";a=a&&a.hasOwnProperty("default")?a.default:a;var e="undefined"!=typeof window,o=(e&&/(android)/i.test(navigator.userAgent),e&&/iPad|iPhone|iPod/.test(String(navigator.platform))),r=function(e){void 0===e&&(e=!1);try{window.addEventListener("test",null,{get passive(){e=!0}})}catch(e){}return e}();function t(e,t,n,i){(void 0===i&&(i=!1),"undefined"==typeof window||window[e=e+"-"+t])||(r||"object"!=typeof i||(i=Boolean(i.capture)),("resize"===t||"load"===t?window:document).addEventListener(window[e]=t,n,i))}var n={"&":"&","<":"<",">":">",'"':""","/":"/","'":"'"};function i(e){return String(e||"").replace(/[&<>"'/]/g,function(e){return n[e]})}var u="prevent_recursive_dispatch_maximum_callstack";function l(e,t,n){void 0===n&&(n={});var i,r=""+u+t;if(e[r])return!0;e[r]=!0,"function"==typeof window.CustomEvent?i=new window.CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n}):(i=document.createEvent("CustomEvent")).initCustomEvent(t,!0,!0,n);var o=e.dispatchEvent(i);return e[r]=null,o}function c(e,t){if(void 0===t&&(t=document),e){if(e.nodeType)return[e];if("string"==typeof e)return[].slice.call(t.querySelectorAll(e));if(e.length)return[].slice.call(e)}return[]}var s="data-@nrk/core-input-1.0.4".replace(/\W+/g,"-"),p=13,d=27,f=33,h=34,v=35,m=36,g=38,b=40,y='[tabindex="-1"]',x=500;function E(e,t){var i="object"==typeof t?t:{content:t},r="string"==typeof i.content;return c(e).map(function(e){var t=e.nextElementSibling,n=void 0===i.ajax?e.getAttribute(s):i.ajax;return e.setAttribute(s,n||""),e.setAttribute(o?"data-role":"role","combobox"),e.setAttribute("aria-autocomplete","list"),e.setAttribute("autocomplete","off"),r&&(t.innerHTML=i.content),c("a,button",t).forEach(S),C(e,i.open),e})}function w(a){a.ctrlKey||a.altKey||a.metaKey||a.defaultPrevented||c("["+s+"]").forEach(function(e){var t,n,i=e.nextElementSibling,r=e===a.target||i.contains(a.target),o="click"===a.type&&r&&c(y,i).filter(function(e){return e.contains(a.target)})[0];o?(t=e,n={relatedTarget:i,currentTarget:o,value:o.value||o.textContent.trim()},l(t,"input.select",n)&&(t.value=n.value,t.focus(),C(t,!1))):C(e,r)})}function A(e,t){var n=e.nextElementSibling,i=c(y+":not([hidden])",n),r=i.indexOf(document.activeElement),o=!1;t.keyCode===b?o=i[r+1]||i[0]:t.keyCode===g?o=i[r-1]||i.pop():n.contains(t.target)&&(t.keyCode===v||t.keyCode===h?o=i.pop():t.keyCode===m||t.keyCode===f?o=i[0]:t.keyCode!==p&&e.focus()),n.hasAttribute("hidden")||t.keyCode!==d||t.preventDefault(),C(e,t.keyCode!==d),!1!==o&&t.preventDefault(),o&&o.focus()}function C(e,t){void 0===t&&(t="true"===e.getAttribute("aria-expanded")),e.nextElementSibling[t?"removeAttribute":"setAttribute"]("hidden",""),e.setAttribute("aria-expanded",t)}function S(e,t,n){e.setAttribute("aria-label",e.textContent.trim()+", "+(t+1)+" av "+n.length),e.setAttribute("tabindex","-1")}function j(e){var t=e.getAttribute(s),n=j.req=j.req||new window.XMLHttpRequest;if(!t)return!1;clearTimeout(j.timer),n.abort(),n.onload=function(){try{n.responseJSON=JSON.parse(n.responseText)}catch(e){n.responseJSON=!1}l(e,"input.ajax",n)},j.timer=setTimeout(function(){e.value&&(n.open("GET",t.replace("{{value}}",window.encodeURIComponent(e.value)),!0),n.send())},x)}E.escapeHTML=i,E.highlight=function(e,t){var n=t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&");return i(e).replace(new RegExp(n||".^","gi"),"<mark>$&</mark>")},t(s,"click",w),t(s,"focus",w,!0),t(s,"input",function(e){var i,t,n=e.target;n.hasAttribute(s)&&(t={relatedTarget:(i=n).nextElementSibling},l(i,"input.filter",t)&&!j(i)&&c(y,i.nextElementSibling).reduce(function(e,t){var n=-1!==t.textContent.toLowerCase().indexOf(i.value.toLowerCase());return t[n?"removeAttribute":"setAttribute"]("hidden",""),n?e.concat(t):e},[]).forEach(S))}),t(s,"keydown",function(e){if(!(e.ctrlKey||e.altKey||e.metaKey)){if(e.target.hasAttribute(s))return A(e.target,e);for(var t=e.target,n=void 0;t;t=t.parentElement)if((n=t.previousElementSibling)&&n.hasAttribute(s))return A(n,e)}});var k=function(t){function o(e){t.call(this,e),this.onFilter=this.onFilter.bind(this),this.onSelect=this.onSelect.bind(this),this.onAjax=this.onAjax.bind(this)}t&&(o.__proto__=t),(o.prototype=Object.create(t&&t.prototype)).constructor=o;var e={defaultProps:{configurable:!0}};return e.defaultProps.get=function(){return{open:null,ajax:null,onAjax:null,onFilter:null,onSelect:null}},o.prototype.componentDidMount=function(){this.el.addEventListener("input.filter",this.onFilter),this.el.addEventListener("input.select",this.onSelect),this.el.addEventListener("input.ajax",this.onAjax),E(this.el.firstElementChild,this.props)},o.prototype.componentDidUpdate=function(){E(this.el.firstElementChild)},o.prototype.componentWillUnmount=function(){this.el.removeEventListener("input.filter",this.onFilter),this.el.removeEventListener("input.select",this.onSelect),this.el.removeEventListener("input.ajax",this.onAjax)},o.prototype.onFilter=function(e){this.props.onFilter&&this.props.onFilter(e)},o.prototype.onSelect=function(e){this.props.onSelect&&this.props.onSelect(e)},o.prototype.onAjax=function(e){this.props.onAjax&&this.props.onAjax(e)},o.prototype.render=function(){var n,i,e,r=this;return a.createElement("div",(n=this.props,i=o.defaultProps,void 0===(e={ref:function(e){return r.el=e}})&&(e={}),Object.keys(n).reduce(function(e,t){return i.hasOwnProperty(t)||(e[t]=n[t]),e},e)),a.Children.map(this.props.children,function(e,t){return 0===t?a.cloneElement(e,{"aria-expanded":String(Boolean(r.props.open))}):1===t?a.cloneElement(e,{hidden:!r.props.open}):e}))},Object.defineProperties(o,e),o}(a.Component);return k.Highlight=function(e){var t=e.text,n=e.query;return void 0===n&&(n=""),a.createElement("span",{dangerouslySetInnerHTML:{__html:E.highlight(t,n)}})},k}); | ||
//# sourceMappingURL=index.js.map | ||
'use strict'; | ||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
var React = _interopDefault(require('react')); | ||
var name = "@nrk/core-input"; | ||
var version = "1.1.0"; | ||
var IS_BROWSER = typeof window !== 'undefined'; | ||
var IS_ANDROID = IS_BROWSER && /(android)/i.test(navigator.userAgent); // Bad, but needed | ||
var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(String(navigator.platform)); | ||
var HAS_EVENT_OPTIONS = (function (has) { | ||
if ( has === void 0 ) has = false; | ||
try { window.addEventListener('test', null, {get passive () { has = true; }}); } catch (e) {} | ||
return has | ||
})(); | ||
/** | ||
* addEvent | ||
* @param {String} uuid An unique ID of the event to bind - ensurnes single instance | ||
* @param {String} type The type of event to bind | ||
* @param {Function} handler The function to call on event | ||
* @param {Boolean|Object} options useCapture or options object for addEventListener. Defaults to false | ||
*/ | ||
function addEvent (uuid, type, handler, options) { | ||
if ( options === void 0 ) options = false; | ||
if (typeof window === 'undefined' || window[uuid = uuid + "-" + type]) { return } // Ensure single instance | ||
if (!HAS_EVENT_OPTIONS && typeof options === 'object') { options = Boolean(options.capture); } // Fix unsupported options | ||
var node = (type === 'resize' || type === 'load') ? window : document; | ||
node.addEventListener(window[uuid] = type, handler, options); | ||
} | ||
/** | ||
* escapeHTML | ||
* @param {String} str A string with potential html tokens | ||
* @return {String} Escaped HTML string according to OWASP recommendation | ||
*/ | ||
var ESCAPE_MAP = {'&': '&', '<': '<', '>': '>', '"': '"', '/': '/', '\'': '''}; | ||
function escapeHTML (str) { | ||
return String(str || '').replace(/[&<>"'/]/g, function (char) { return ESCAPE_MAP[char]; }) | ||
} | ||
/** | ||
* exclude | ||
* @param {Object} target The target object | ||
* @param {Object} exclude The source to exclude keys from | ||
* @return {Object} The target object without keys found in source | ||
*/ | ||
function exclude (target, exclude, include) { | ||
if ( include === void 0 ) include = {}; | ||
return Object.keys(target).reduce(function (acc, key) { | ||
if (!exclude.hasOwnProperty(key)) { acc[key] = target[key]; } | ||
return acc | ||
}, include) | ||
} | ||
/** | ||
* dispatchEvent - with infinite loop prevention | ||
* @param {Element} elem The target object | ||
* @param {String} name The source object(s) | ||
* @param {Object} detail Detail object (bubbles and cancelable is set to true) | ||
* @return {Boolean} Whether the event was canceled | ||
*/ | ||
var IGNORE = 'prevent_recursive_dispatch_maximum_callstack'; | ||
function dispatchEvent (element, name, detail) { | ||
if ( detail === void 0 ) detail = {}; | ||
var ignore = "" + IGNORE + name; | ||
var event; | ||
if (element[ignore]) { return true } // We are already processing this event, so skip sending a new one | ||
else { element[ignore] = true; } // Add name to dispatching ignore | ||
if (typeof window.CustomEvent === 'function') { | ||
event = new window.CustomEvent(name, {bubbles: true, cancelable: true, detail: detail}); | ||
} else { | ||
event = document.createEvent('CustomEvent'); | ||
event.initCustomEvent(name, true, true, detail); | ||
} | ||
// IE reports incorrect event.defaultPrevented | ||
// but correct return value on element.dispatchEvent | ||
var result = element.dispatchEvent(event); | ||
element[ignore] = null; // Remove name from dispatching ignore | ||
return result // Follow W3C standard for return value | ||
} | ||
/** | ||
* requestAnimFrame (super simple polyfill) | ||
*/ | ||
function requestAnimFrame (fn) { | ||
(window.requestAnimationFrame || window.setTimeout)(fn); | ||
} | ||
/** | ||
* queryAll | ||
* @param {String|NodeList|Array|Element} elements A CSS selector string, nodeList, element array, or single element | ||
* @return {Element[]} Array of elements | ||
*/ | ||
function queryAll (elements, context) { | ||
if ( context === void 0 ) context = document; | ||
if (elements) { | ||
if (elements.nodeType) { return [elements] } | ||
if (typeof elements === 'string') { return [].slice.call(context.querySelectorAll(elements)) } | ||
if (elements.length) { return [].slice.call(elements) } | ||
} | ||
return [] | ||
} | ||
var UUID = ("data-" + name + "-" + version).replace(/\W+/g, '-'); // Strip invalid attribute characters | ||
var KEYS = {ENTER: 13, ESC: 27, PAGEUP: 33, PAGEDOWN: 34, END: 35, HOME: 36, UP: 38, DOWN: 40}; | ||
var ITEM = '[tabindex="-1"]'; | ||
var AJAX_DEBOUNCE = 500; | ||
function input (elements, content) { | ||
var options = typeof content === 'object' ? content : {content: content}; | ||
var repaint = typeof options.content === 'string'; | ||
return queryAll(elements).map(function (input) { | ||
var list = input.nextElementSibling; | ||
var ajax = typeof options.ajax === 'undefined' ? input.getAttribute(UUID) : options.ajax; | ||
input.setAttribute(UUID, ajax || ''); | ||
input.setAttribute(IS_IOS ? 'data-role' : 'role', 'combobox'); // iOS does not inform user area is editable if combobox | ||
input.setAttribute('aria-autocomplete', 'list'); | ||
input.setAttribute('autocomplete', 'off'); | ||
if (repaint) { list.innerHTML = options.content; } | ||
queryAll('a,button', list).forEach(setupItem); | ||
setupExpand(input, options.open); | ||
return input | ||
}) | ||
} | ||
// Expose helper functions | ||
input.escapeHTML = escapeHTML; | ||
input.highlight = function (haystack, needle) { | ||
var escapedRegExp = needle.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); // From lodash | ||
return escapeHTML(haystack).replace(new RegExp(escapedRegExp || '.^', 'gi'), '<mark>$&</mark>') | ||
}; | ||
addEvent(UUID, 'click', onClickOrFocus); | ||
addEvent(UUID, 'focus', onClickOrFocus, true); // Use focus with capturing instead of focusin for old Firefox | ||
function onClickOrFocus (event) { | ||
if (event.ctrlKey || event.altKey || event.metaKey || event.defaultPrevented) { return } | ||
queryAll(("[" + UUID + "]")).forEach(function (input) { | ||
var list = input.nextElementSibling; | ||
var open = input === event.target || list.contains(event.target); | ||
var item = event.type === 'click' && open && queryAll(ITEM, list).filter(function (item) { return item.contains(event.target); })[0]; | ||
if (item) { onSelect(input, {relatedTarget: list, currentTarget: item, value: item.value || item.textContent.trim()}); } | ||
else { setupExpand(input, open); } | ||
}); | ||
} | ||
addEvent(UUID, 'input', function (ref) { | ||
var input = ref.target; | ||
if (input.hasAttribute(UUID)) { onFilter(input, {relatedTarget: input.nextElementSibling}); } | ||
}); | ||
addEvent(UUID, 'keydown', function (event) { | ||
if (event.ctrlKey || event.altKey || event.metaKey) { return } | ||
if (event.target.hasAttribute(UUID)) { return onKey(event.target, event) } // Quick check | ||
for (var el = event.target, prev = (void 0); el; el = el.parentElement) { // Check if inside list | ||
if ((prev = el.previousElementSibling) && prev.hasAttribute(UUID)) { return onKey(prev, event) } | ||
} | ||
}); | ||
function onKey (input, event) { | ||
var list = input.nextElementSibling; | ||
var focus = queryAll((ITEM + ":not([hidden])"), list); | ||
var index = focus.indexOf(document.activeElement); | ||
var item = false; | ||
if (event.keyCode === KEYS.DOWN) { item = focus[index + 1] || focus[0]; } | ||
else if (event.keyCode === KEYS.UP) { item = focus[index - 1] || focus.pop(); } | ||
else if (list.contains(event.target)) { // Aditional shortcuts if focus is inside list | ||
if (event.keyCode === KEYS.END || event.keyCode === KEYS.PAGEDOWN) { item = focus.pop(); } | ||
else if (event.keyCode === KEYS.HOME || event.keyCode === KEYS.PAGEUP) { item = focus[0]; } | ||
else if (event.keyCode !== KEYS.ENTER) { input.focus(); } | ||
} | ||
if (!list.hasAttribute('hidden') && event.keyCode === KEYS.ESC) { event.preventDefault(); } | ||
setupExpand(input, event.keyCode !== KEYS.ESC); | ||
if (item !== false) { event.preventDefault(); } // event.preventDefault even if empty list | ||
if (item) { item.focus(); } | ||
} | ||
function onSelect (input, detail) { | ||
if (dispatchEvent(input, 'input.select', detail)) { | ||
input.value = detail.value; | ||
input.focus(); | ||
setupExpand(input, false); | ||
} | ||
} | ||
function onFilter (input, detail) { | ||
if (dispatchEvent(input, 'input.filter', detail) && !ajax(input)) { | ||
queryAll(ITEM, input.nextElementSibling).reduce(function (acc, item) { | ||
var show = item.textContent.toLowerCase().indexOf(input.value.toLowerCase()) !== -1; | ||
item[show ? 'removeAttribute' : 'setAttribute']('hidden', ''); | ||
return show ? acc.concat(item) : acc | ||
}, []).forEach(setupItem); | ||
} | ||
} | ||
function setupExpand (input, open) { | ||
if ( open === void 0 ) open = input.getAttribute('aria-expanded') === 'true'; | ||
requestAnimFrame(function () { // Fixes VoiceOver Safari focus jumping to parentElement | ||
input.nextElementSibling[open ? 'removeAttribute' : 'setAttribute']('hidden', ''); | ||
input.setAttribute('aria-expanded', open); | ||
}); | ||
} | ||
function setupItem (item, index, items) { | ||
item.setAttribute('aria-label', ((item.textContent.trim()) + ", " + (index + 1) + " av " + (items.length))); | ||
item.setAttribute('tabindex', '-1'); | ||
} | ||
function ajax (input) { | ||
var url = input.getAttribute(UUID); | ||
var req = ajax.req = ajax.req || new window.XMLHttpRequest(); | ||
if (!url) { return false } | ||
clearTimeout(ajax.timer); // Clear previous search | ||
req.abort(); // Abort previous request | ||
req.onload = function () { | ||
try { req.responseJSON = JSON.parse(req.responseText); } catch (err) { req.responseJSON = false; } | ||
dispatchEvent(input, 'input.ajax', req); | ||
}; | ||
ajax.timer = setTimeout(function () { // Debounce next request 500 milliseconds | ||
if (!input.value) { return } // Abort if input is empty | ||
req.open('GET', url.replace('{{value}}', window.encodeURIComponent(input.value)), true); | ||
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Requested-With | ||
req.send(); | ||
}, AJAX_DEBOUNCE); | ||
} | ||
var Input = (function (superclass) { | ||
function Input (props) { | ||
superclass.call(this, props); | ||
this.onFilter = this.onFilter.bind(this); | ||
this.onSelect = this.onSelect.bind(this); | ||
this.onAjax = this.onAjax.bind(this); | ||
} | ||
if ( superclass ) Input.__proto__ = superclass; | ||
Input.prototype = Object.create( superclass && superclass.prototype ); | ||
Input.prototype.constructor = Input; | ||
var staticAccessors = { defaultProps: { configurable: true } }; | ||
staticAccessors.defaultProps.get = function () { return {open: null, ajax: null, onAjax: null, onFilter: null, onSelect: null} }; | ||
Input.prototype.componentDidMount = function componentDidMount () { // Mount client side only to avoid rerender | ||
this.el.addEventListener('input.filter', this.onFilter); | ||
this.el.addEventListener('input.select', this.onSelect); | ||
this.el.addEventListener('input.ajax', this.onAjax); | ||
input(this.el.firstElementChild, this.props); | ||
}; | ||
Input.prototype.componentDidUpdate = function componentDidUpdate () { input(this.el.firstElementChild); }; // Must mount also on update in case content changes | ||
Input.prototype.componentWillUnmount = function componentWillUnmount () { | ||
this.el.removeEventListener('input.filter', this.onFilter); | ||
this.el.removeEventListener('input.select', this.onSelect); | ||
this.el.removeEventListener('input.ajax', this.onAjax); | ||
}; | ||
Input.prototype.onFilter = function onFilter (event) { this.props.onFilter && this.props.onFilter(event); }; | ||
Input.prototype.onSelect = function onSelect (event) { this.props.onSelect && this.props.onSelect(event); }; | ||
Input.prototype.onAjax = function onAjax (event) { this.props.onAjax && this.props.onAjax(event); }; | ||
Input.prototype.render = function render () { | ||
var this$1 = this; | ||
return React.createElement('div', exclude(this.props, Input.defaultProps, {ref: function (el) { return (this$1.el = el); }}), | ||
React.Children.map(this.props.children, function (child, adjacent) { | ||
if (adjacent === 0) { return React.cloneElement(child, {'aria-expanded': String(Boolean(this$1.props.open))}) } | ||
if (adjacent === 1) { return React.cloneElement(child, {'hidden': !this$1.props.open}) } | ||
return child | ||
}) | ||
) | ||
}; | ||
Object.defineProperties( Input, staticAccessors ); | ||
return Input; | ||
}(React.Component)); | ||
Input.Highlight = function (ref) { | ||
var text = ref.text; | ||
var query = ref.query; if ( query === void 0 ) query = ''; | ||
return React.createElement('span', {dangerouslySetInnerHTML: { | ||
__html: input.highlight(text, query) // We know coreInput escapes, so this is safe | ||
}}); | ||
}; | ||
module.exports = Input; |
@@ -5,10 +5,6 @@ { | ||
"author": "NRK <opensource@nrk.no> (https://www.nrk.no/)", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"license": "MIT", | ||
"main": "core-input.min.js", | ||
"main": "core-input.cjs.js", | ||
"jsx": "jsx/index.js", | ||
"optionalDependencies": { | ||
"react": "*", | ||
"react-dom": "*" | ||
}, | ||
"repository": { | ||
@@ -15,0 +11,0 @@ "type": "git", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
109315
0
10
1051
0
1
377
1