datalist-polyfill
Advanced tools
Comparing version 1.13.0 to 1.13.1
{ | ||
"name": "datalist-polyfill", | ||
"description": "An extremely lightweight and library-dependency-free vanilla JavaScript datalist polyfill.", | ||
"version": "1.13.0", | ||
"version": "1.13.1", | ||
"homepage": "https://github.com/mfranzke/datalist-polyfill", | ||
@@ -6,0 +6,0 @@ "authors": [{ |
@@ -8,3 +8,10 @@ # Changelog | ||
## [Unreleased] | ||
### Added | ||
- #GH-16 correction as an enhancement to the current functionality | ||
## [1.13.1] - 2018-06-04 | ||
### Changed | ||
- Some code refactoring, nothing really serious | ||
By the way, it was polyfills 1st birthday one month ago. Yeah !!! | ||
## [1.13.0] - 2018-05-28 | ||
@@ -11,0 +18,0 @@ ### Added |
@@ -70,4 +70,8 @@ /* | ||
// and defining the different input types that are supported by this polyfill | ||
supportedTypes = ['text', 'email', 'number', 'search', 'tel', 'url']; | ||
supportedTypes = ['text', 'email', 'number', 'search', 'tel', 'url'], | ||
// classes for elements | ||
classNameInput = 'polyfilled', | ||
classNamePolyfillingSelect = 'polyfilling'; | ||
// differentiate for touch interactions, adapted by https://medium.com/@david.gilbertson/the-only-way-to-detect-touch-with-javascript-7791a3346685 | ||
@@ -95,3 +99,3 @@ window.addEventListener('touchstart', function onFirstTouch() { | ||
var dataListSelect = dataList.getElementsByClassName('polyfilling')[0]; | ||
var dataListSelect = dataList.getElementsByClassName(classNamePolyfillingSelect)[0]; | ||
@@ -101,6 +105,5 @@ // still check for an existing instance | ||
// on an ESC key press within the input, let's break here and hide the select | ||
// on an ESC key press within the input, let's break here and hide the datalist select | ||
if (event.keyCode === keyESC) { | ||
dataListSelect.setAttributeNode(document.createAttribute('hidden')); | ||
dataListSelect.setAttribute('aria-hidden', 'true'); | ||
toggleVisibility(dataListSelect, false); | ||
@@ -136,33 +139,33 @@ return; | ||
}) | ||
.forEach(function(opt) { | ||
var optionValue = opt.value; | ||
.forEach(function(opt) { | ||
var optionValue = opt.value; | ||
// ... put this option into the fragment that is meant to get inserted into the select | ||
// "Each option element that is a descendant of the datalist element, that is not disabled, and whose value is a string that isn't the empty string, represents a suggestion. Each suggestion has a value and a label." (W3C) | ||
if (optionValue !== '' && optionValue.toLowerCase() | ||
.indexOf(inputValue.toLowerCase()) !== -1 && opt.disabled === false) { | ||
// ... put this option into the fragment that is meant to get inserted into the select | ||
// "Each option element that is a descendant of the datalist element, that is not disabled, and whose value is a string that isn't the empty string, represents a suggestion. Each suggestion has a value and a label." (W3C) | ||
if (optionValue !== '' && optionValue.toLowerCase() | ||
.indexOf(inputValue.toLowerCase()) !== -1 && opt.disabled === false) { | ||
var label = opt.getAttribute('label'), | ||
text = opt.text, | ||
textOptionPart = text.substr(0, optionValue.length + textValueSeperator.length), | ||
optionPart = optionValue + textValueSeperator; | ||
var label = opt.getAttribute('label'), | ||
text = opt.text, | ||
textOptionPart = text.substr(0, optionValue.length + textValueSeperator.length), | ||
optionPart = optionValue + textValueSeperator; | ||
// the innertext should be value / text in case they are different | ||
if (text && !label && text !== optionValue && textOptionPart !== optionPart) { | ||
opt.innerText = optionValue + textValueSeperator + text; | ||
// the innertext should be value / text in case they are different | ||
if (text && !label && text !== optionValue && textOptionPart !== optionPart) { | ||
opt.innerText = optionValue + textValueSeperator + text; | ||
} else if (!opt.text) { | ||
// manipulating the option inner text, that would get displayed | ||
opt.innerText = label || optionValue; | ||
} | ||
} else if (!opt.text) { | ||
// manipulating the option inner text, that would get displayed | ||
opt.innerText = label || optionValue; | ||
} | ||
newSelectValues.appendChild(opt); | ||
newSelectValues.appendChild(opt); | ||
// ... and set the state of the select to get displayed in that case | ||
visible = true; | ||
} else { | ||
// ... or put this option that isn't relevant to the users into the fragment that is supposed to get inserted outside of the select | ||
disabledValues.appendChild(opt); | ||
} | ||
}); | ||
// ... and set the state of the select to get displayed in that case | ||
visible = true; | ||
} else { | ||
// ... or put this option that isn't relevant to the users into the fragment that is supposed to get inserted outside of the select | ||
disabledValues.appendChild(opt); | ||
} | ||
}); | ||
@@ -201,9 +204,4 @@ // input the options fragment into the datalists select | ||
// toggle the visibility of the select according to previous checks | ||
if (visible) { | ||
dataListSelect.removeAttribute('hidden'); | ||
} else { | ||
dataListSelect.setAttributeNode(document.createAttribute('hidden')); | ||
} | ||
dataListSelect.setAttribute('aria-hidden', (!visible).toString()); | ||
// toggle the visibility of the datalist select according to previous checks | ||
toggleVisibility(dataListSelect, visible); | ||
@@ -238,5 +236,5 @@ // on arrow up or down keys, focus the select | ||
var dataListSelect = dataList.getElementsByClassName('polyfilling')[0], | ||
var dataListSelect = dataList.getElementsByClassName(classNamePolyfillingSelect)[0], | ||
// either have the select set to the state to get displayed in case of that it would have been focused or because it's the target on the inputs blur | ||
visible = ((eventType === 'focus' && event.target.value !== '') || (event.relatedTarget && event.relatedTarget === dataListSelect)), | ||
visible = (((eventType === 'focus' && eventTarget.value !== '') || (event.relatedTarget && event.relatedTarget === dataListSelect)) && dataListSelect && dataListSelect.options && dataListSelect.options.length), | ||
message = dataList.title; | ||
@@ -254,10 +252,11 @@ | ||
// setting a class for easier selecting that select afterwards | ||
dataListSelect.setAttribute('class', 'polyfilling'); | ||
dataListSelect.setAttribute('class', classNamePolyfillingSelect); | ||
// set general styling related definitions | ||
dataListSelect.setAttributeNode(document.createAttribute('hidden')); | ||
dataListSelect.style.position = 'absolute'; | ||
// initially hiding the datalist select | ||
toggleVisibility(dataListSelect, false); | ||
// WAI ARIA attributes | ||
dataListSelect.setAttribute('aria-hidden', 'true'); | ||
dataListSelect.setAttribute('aria-live', 'polite'); | ||
@@ -311,4 +310,6 @@ dataListSelect.setAttribute('role', 'listbox'); | ||
dataListSelect.addEventListener('keyup', changeDataListSelect); | ||
} | ||
// test for whether this input has already been enhanced by the polyfill | ||
if (!new RegExp(' ' + classNameInput + ' ').test(' ' + eventTarget.className + ' ')) { | ||
// plus we'd like to prevent autocomplete on the input datalist field | ||
@@ -322,25 +323,23 @@ eventTarget.setAttribute('autocomplete', 'off'); | ||
eventTarget.setAttribute('aria-owns', list); | ||
} | ||
// toggle the visibility of the select according to previous checks | ||
if (visible) { | ||
dataListSelect.removeAttribute('hidden'); | ||
} else { | ||
dataListSelect.setAttributeNode(document.createAttribute('hidden')); | ||
} | ||
dataListSelect.setAttribute('aria-hidden', (!visible).toString()); | ||
// bind the keyup event on the related datalists input | ||
switch (eventType) { | ||
case 'focus': | ||
eventTarget.addEventListener('keyup', inputInputList); | ||
// bind the keyup event on the related datalists input | ||
switch (eventType) { | ||
case 'focus': | ||
eventTarget.addEventListener('keyup', inputInputList); | ||
eventTarget.addEventListener('focusout', changesInputList, true); | ||
break; | ||
case 'blur': | ||
eventTarget.removeEventListener('keyup', inputInputList); | ||
eventTarget.addEventListener('focusout', changesInputList, true); | ||
break; | ||
case 'blur': | ||
eventTarget.removeEventListener('keyup', inputInputList); | ||
eventTarget.removeEventListener('focusout', changesInputList, true); | ||
break; | ||
} | ||
eventTarget.removeEventListener('focusout', changesInputList, true); | ||
break; | ||
// add class for identifying that this input is even already being polyfilled | ||
eventTarget.className += ' ' + classNameInput; | ||
} | ||
// toggle the visibility of the datalist select according to previous checks | ||
toggleVisibility(dataListSelect, visible); | ||
} | ||
@@ -403,14 +402,19 @@ } | ||
// toggle the visibility of the select according to previous checks | ||
if (visible) { | ||
select.removeAttribute('hidden'); | ||
} else { | ||
select.setAttributeNode(document.createAttribute('hidden')); | ||
} | ||
select.setAttribute('aria-hidden', (!visible).toString()); | ||
// toggle the visibility of the datalist select according to previous checks | ||
toggleVisibility(select, visible); | ||
} | ||
}; | ||
// toggle the visibility of the datalist select | ||
var toggleVisibility = function(dataListSelect, visible) { | ||
if (visible) { | ||
dataListSelect.removeAttribute('hidden'); | ||
} else { | ||
dataListSelect.setAttributeNode(document.createAttribute('hidden')); | ||
} | ||
dataListSelect.setAttribute('aria-hidden', (!visible).toString()); | ||
}; | ||
// binding the focus event - matching the input[list]s happens in the function afterwards | ||
document.addEventListener('focus', changesInputList, true); | ||
})(); |
@@ -6,2 +6,2 @@ /* | ||
*/ | ||
!function(){"use strict";if("list"in document.createElement("input")&&!(!document.createElement("datalist")||!window.HTMLDataListElement))return!1;!function(e){e&&e.prototype&&void 0===e.prototype.list&&Object.defineProperty(e.prototype,"list",{get:function(){if("object"==typeof this&&this instanceof e){var t=this.getAttribute("list");return document.getElementById(t)}return null}})}(window.HTMLInputElement),function(e){e&&e.prototype&&void 0===e.prototype.options&&Object.defineProperty(e.prototype,"options",{get:function(){if("object"==typeof this&&this instanceof e)return this.getElementsByTagName("option")}})}(window.HTMLElement);var e=!1,t=13,i=27,r=38,n=40,a=" / ",o=["text","email","number","search","tel","url"];window.addEventListener("touchstart",function t(){e=!0,window.removeEventListener("touchstart",t)});var l=function(t){var i=t.target,r=i.tagName.toLowerCase();if(r&&"input"===r&&i.getAttribute("list")){var n=i.getAttribute("list"),a=document.getElementById(n);if(null!==a){var o=a.getElementsByClassName("polyfilling")[0];if(void 0!==o){if(27===t.keyCode)return o.setAttributeNode(document.createAttribute("hidden")),void o.setAttribute("aria-hidden","true");var l=a.querySelectorAll("option:not([disabled]):not(.message)"),s=i.value,d=document.createDocumentFragment(),u=document.createDocumentFragment(),c=!1,p="email"===i.type&&i.multiple,m=38===t.keyCode||40===t.keyCode;if(p){var b=s.split(","),f=b.length-1;s=b[f].trim()}if(""!==s||m){Array.prototype.slice.call(l).sort(function(e,t){return e.value.localeCompare(t.value)}).forEach(function(e){var t=e.value;if(""!==t&&-1!==t.toLowerCase().indexOf(s.toLowerCase())&&!1===e.disabled){var i=e.getAttribute("label"),r=e.text,n=r.substr(0,t.length+" / ".length),a=t+" / ";r&&!i&&r!==t&&n!==a?e.innerText=t+" / "+r:e.text||(e.innerText=i||t),d.appendChild(e),c=!0}else u.appendChild(e)}),o.appendChild(d);var g=o.options.length,v=0,y=g-1;if(o.size=g>10?10:g,o.multiple=!e&&g<2,e)o.selectedIndex=0;else if(-1===o.selectedIndex)switch(t.keyCode){case 38:o.selectedIndex=y;break;case 40:o.selectedIndex=0;break}(a.getElementsByClassName("ie9_fix")[0]||a).appendChild(u)}c?o.removeAttribute("hidden"):o.setAttributeNode(document.createAttribute("hidden")),o.setAttribute("aria-hidden",(!c).toString()),m&&o.focus()}}}},s=function(t){var i=t.target,r=i.tagName.toLowerCase(),n=i.type,a=window.getComputedStyle(i);if(r&&"input"===r&&i.getAttribute("list")&&o.indexOf(n)>-1){var u=t.type,c=i.getAttribute("list"),p=document.getElementById(c);if(null!==p){var m=p.getElementsByClassName("polyfilling")[0],b="focus"===u&&""!==t.target.value||t.relatedTarget&&t.relatedTarget===m,f=p.title;if(void 0===m){var g=i.getClientRects(),v=parseFloat(a.getPropertyValue("margin-right")),y=parseFloat(a.getPropertyValue("margin-left"));if(m=document.createElement("select"),m.setAttribute("class","polyfilling"),m.setAttributeNode(document.createAttribute("hidden")),m.style.position="absolute",m.setAttribute("aria-hidden","true"),m.setAttribute("aria-live","polite"),m.setAttribute("role","listbox"),e||m.setAttribute("aria-multiselectable","false"),"block"===a.getPropertyValue("display")?m.style.marginTop="-"+a.getPropertyValue("margin-bottom"):("rtl"===a.getPropertyValue("direction")?m.style.marginRight="-"+(g[0].width+y)+"px":m.style.marginLeft="-"+(g[0].width+v)+"px",m.style.marginTop=parseInt(g[0].height+(i.offsetTop-p.offsetTop),10)+"px"),m.style.borderRadius=a.getPropertyValue("border-radius"),m.style.minWidth=g[0].width+"px",e){var h=document.createElement("option");h.innerText=f,h.disabled=!0,h.setAttribute("class","message"),m.appendChild(h)}p.appendChild(m),e?m.addEventListener("change",d):m.addEventListener("click",d),m.addEventListener("blur",d),m.addEventListener("keyup",d),i.setAttribute("autocomplete","off"),i.setAttribute("role","textbox"),i.setAttribute("aria-haspopup","true"),i.setAttribute("aria-autocomplete","list"),i.setAttribute("aria-owns",c)}switch(b?m.removeAttribute("hidden"):m.setAttributeNode(document.createAttribute("hidden")),m.setAttribute("aria-hidden",(!b).toString()),u){case"focus":i.addEventListener("keyup",l),i.addEventListener("focusout",s,!0);break;case"blur":i.removeEventListener("keyup",l),i.removeEventListener("focusout",s,!0);break}}}},d=function(e){var t=e.target,i=t.tagName.toLowerCase();if(i&&("select"===i||"option"===i)){var r="select"===i?t:t.parentNode,n=r.parentNode,a=n.title,o=e.type,l="keyup"===o&&13!==e.keyCode&&27!==e.keyCode;if("change"===o||"click"===o||"keyup"===o&&13===e.keyCode){var s=n.id,d=document.querySelector('input[list="'+s+'"]'),u=r.value;if(null!==d&&void 0!==u&&u.length>0&&u!==a){var c=d.value,p,m="email"===d.type&&d.multiple,b;m&&(p=c.lastIndexOf(","))>-1?d.value=c.slice(0,p)+","+u:d.value=u,"function"==typeof Event?b=new Event("input",{bubbles:!0}):(b=document.createEvent("Event"),b.initEvent("input",!0,!1)),d.dispatchEvent(b),l=!1}}l?r.removeAttribute("hidden"):r.setAttributeNode(document.createAttribute("hidden")),r.setAttribute("aria-hidden",(!l).toString())}};document.addEventListener("focus",s,!0)}(); | ||
!function(){"use strict";if("list"in document.createElement("input")&&!(!document.createElement("datalist")||!window.HTMLDataListElement))return!1;!function(e){e&&e.prototype&&void 0===e.prototype.list&&Object.defineProperty(e.prototype,"list",{get:function(){if("object"==typeof this&&this instanceof e){var t=this.getAttribute("list");return document.getElementById(t)}return null}})}(window.HTMLInputElement),function(e){e&&e.prototype&&void 0===e.prototype.options&&Object.defineProperty(e.prototype,"options",{get:function(){if("object"==typeof this&&this instanceof e)return this.getElementsByTagName("option")}})}(window.HTMLElement);var e=!1,t=13,i=27,n=38,r=40,o=" / ",a=["text","email","number","search","tel","url"],l="polyfilled",s="polyfilling";window.addEventListener("touchstart",function t(){e=!0,window.removeEventListener("touchstart",t)});var u=function(t){var i=t.target,n=i.tagName.toLowerCase();if(n&&"input"===n&&i.getAttribute("list")){var r=i.getAttribute("list"),o=document.getElementById(r);if(null!==o){var a=o.getElementsByClassName("polyfilling")[0];if(void 0!==a){if(27===t.keyCode)return void c(a,!1);var l=o.querySelectorAll("option:not([disabled]):not(.message)"),s=i.value,u=document.createDocumentFragment(),d=document.createDocumentFragment(),p=!1,m="email"===i.type&&i.multiple,f=38===t.keyCode||40===t.keyCode;if(m){var y=s.split(","),g=y.length-1;s=y[g].trim()}if(""!==s||f){Array.prototype.slice.call(l).sort(function(e,t){return e.value.localeCompare(t.value)}).forEach(function(e){var t=e.value;if(""!==t&&-1!==t.toLowerCase().indexOf(s.toLowerCase())&&!1===e.disabled){var i=e.getAttribute("label"),n=e.text,r=n.substr(0,t.length+" / ".length),o=t+" / ";n&&!i&&n!==t&&r!==o?e.innerText=t+" / "+n:e.text||(e.innerText=i||t),u.appendChild(e),p=!0}else d.appendChild(e)}),a.appendChild(u);var v=a.options.length,b=0,h=v-1;if(a.size=v>10?10:v,a.multiple=!e&&v<2,e)a.selectedIndex=0;else if(-1===a.selectedIndex)switch(t.keyCode){case 38:a.selectedIndex=h;break;case 40:a.selectedIndex=0;break}(o.getElementsByClassName("ie9_fix")[0]||o).appendChild(d)}c(a,p),f&&a.focus()}}}},d=function(t){var i=t.target,n=i.tagName.toLowerCase(),r=i.type,o=window.getComputedStyle(i);if(n&&"input"===n&&i.getAttribute("list")&&a.indexOf(r)>-1){var l=t.type,s=i.getAttribute("list"),m=document.getElementById(s);if(null!==m){var f=m.getElementsByClassName("polyfilling")[0],y=("focus"===l&&""!==i.value||t.relatedTarget&&t.relatedTarget===f)&&f&&f.options&&f.options.length,g=m.title;if(void 0===f){var v=i.getClientRects(),b=parseFloat(o.getPropertyValue("margin-right")),h=parseFloat(o.getPropertyValue("margin-left"));if(f=document.createElement("select"),f.setAttribute("class","polyfilling"),f.style.position="absolute",c(f,!1),f.setAttribute("aria-live","polite"),f.setAttribute("role","listbox"),e||f.setAttribute("aria-multiselectable","false"),"block"===o.getPropertyValue("display")?f.style.marginTop="-"+o.getPropertyValue("margin-bottom"):("rtl"===o.getPropertyValue("direction")?f.style.marginRight="-"+(v[0].width+h)+"px":f.style.marginLeft="-"+(v[0].width+b)+"px",f.style.marginTop=parseInt(v[0].height+(i.offsetTop-m.offsetTop),10)+"px"),f.style.borderRadius=o.getPropertyValue("border-radius"),f.style.minWidth=v[0].width+"px",e){var E=document.createElement("option");E.innerText=g,E.disabled=!0,E.setAttribute("class","message"),f.appendChild(E)}m.appendChild(f),e?f.addEventListener("change",p):f.addEventListener("click",p),f.addEventListener("blur",p),f.addEventListener("keyup",p)}if(!new RegExp(" polyfilled ").test(" "+i.className+" ")){switch(i.setAttribute("autocomplete","off"),i.setAttribute("role","textbox"),i.setAttribute("aria-haspopup","true"),i.setAttribute("aria-autocomplete","list"),i.setAttribute("aria-owns",s),l){case"focus":i.addEventListener("keyup",u),i.addEventListener("focusout",d,!0);break;case"blur":i.removeEventListener("keyup",u),i.removeEventListener("focusout",d,!0);break}i.className+=" polyfilled"}c(f,y)}}},p=function(e){var t=e.target,i=t.tagName.toLowerCase();if(i&&("select"===i||"option"===i)){var n="select"===i?t:t.parentNode,r=n.parentNode,o=r.title,a=e.type,l="keyup"===a&&13!==e.keyCode&&27!==e.keyCode;if("change"===a||"click"===a||"keyup"===a&&13===e.keyCode){var s=r.id,u=document.querySelector('input[list="'+s+'"]'),d=n.value;if(null!==u&&void 0!==d&&d.length>0&&d!==o){var p=u.value,m,f="email"===u.type&&u.multiple,y;f&&(m=p.lastIndexOf(","))>-1?u.value=p.slice(0,m)+","+d:u.value=d,"function"==typeof Event?y=new Event("input",{bubbles:!0}):(y=document.createEvent("Event"),y.initEvent("input",!0,!1)),u.dispatchEvent(y),l=!1}}c(n,l)}},c=function(e,t){t?e.removeAttribute("hidden"):e.setAttributeNode(document.createAttribute("hidden")),e.setAttribute("aria-hidden",(!t).toString())};document.addEventListener("focus",d,!0)}(); |
{ | ||
"name": "datalist-polyfill", | ||
"version": "1.13.0", | ||
"version": "1.13.1", | ||
"description": "A lightweight and dependency-free vanilla JavaScript datalist polyfill.", | ||
@@ -5,0 +5,0 @@ "main": "datalist-polyfill.js", |
@@ -14,3 +14,3 @@ # datalist-polyfill | ||
## Features | ||
* Lightweight: 5.52 kB of JavaScript, around 2.35 kB gzipped | ||
* Lightweight: 5.24 kB of JavaScript, around 2.35 kB gzipped | ||
* Fully flexible to change the datalist entries / `<option>`s | ||
@@ -17,0 +17,0 @@ * Supporting: |
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
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
48710
359