Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

datalist-polyfill

Package Overview
Dependencies
Maintainers
1
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

datalist-polyfill - npm Package Compare versions

Comparing version 1.13.2 to 1.14.0

4

bower.json
{
"name": "datalist-polyfill",
"description": "An extremely lightweight and library-dependency-free vanilla JavaScript datalist polyfill.",
"version": "1.13.2",
"version": "1.14.0",
"homepage": "https://github.com/mfranzke/datalist-polyfill",

@@ -21,3 +21,3 @@ "authors": [{

"type": "MIT",
"url": "http://www.opensource.org/licenses/mit-license.php"
"url": "https://opensource.org/licenses/mit-license.php"
}],

@@ -24,0 +24,0 @@ "ignore": [

# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.14.0] - 2018-06-12
### Added
- #GH-16 correction as an enhancement to the current functionality
- Added MutationObserver to even also capture changes to the option elements as a correction to enhance the current functionality (#GH-16).
### Changed
- Changed some URLs from HTTP to the new kid on the block: HTTPS. Nice ! ;-)
- Additionally did some necessary updates to the documentation.
## [1.13.2] - 2018-06-11

@@ -12,0 +18,0 @@ ### Changed

/*
* datalist-polyfill.js - https://github.com/mfranzke/datalist-polyfill
* @license Copyright(c) 2017 by Maximilian Franzke
* Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, Michael, @hryamzik, @ottoville, @IceCreamYou, @wlekin and @eddr - many thanks for that !
* Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, @mischah, @hryamzik, @ottoville, @IceCreamYou, @wlekin, @eddr and @beebee1987 - many thanks for that !
*/

@@ -83,2 +83,35 @@ /*

// for observing any changes to the option elements within the datalist elements, define MutationObserver initially
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
// define a new observer
if (typeof(MutationObserver) !== 'undefined') {
var obs = new MutationObserver(function(mutations) {
var datalistNeedsAnUpdate = false;
// look through all mutations that just occured
for(var i=0; i<mutations.length; ++i) {
// look through all added nodes of this mutation
for(var j=0; j<mutations[i].addedNodes.length; ++j) {
if (mutations[i].target.tagName.toLowerCase() === 'datalist') {
datalistNeedsAnUpdate = mutations[i].target;
}
}
}
if (datalistNeedsAnUpdate) {
var input = document.querySelector('[list="' + datalistNeedsAnUpdate.id + '"]');
if (input.value !== '') {
var dataList = datalistNeedsAnUpdate;
prepOptions(dataList, input);
toggleVisibility(dataList.getElementsByClassName(classNamePolyfillingSelect)[0]);
}
}
});
}
// function regarding the inputs interactions

@@ -99,3 +132,3 @@ var inputInputList = function(event) {

var dataListSelect = dataList.getElementsByClassName(classNamePolyfillingSelect)[0];
var dataListSelect = dataList.getElementsByClassName(classNamePolyfillingSelect)[0] || setUpPolyfillingSelect(eventTarget, dataList);

@@ -112,63 +145,10 @@ // still check for an existing instance

var dataListOptions = dataList.querySelectorAll('option:not([disabled]):not(.message)'),
inputValue = eventTarget.value,
newSelectValues = document.createDocumentFragment(),
disabledValues = document.createDocumentFragment(),
visible = false,
multipleEmails = (eventTarget.type === 'email' && eventTarget.multiple),
var inputValue = eventTarget.value,
keyOpen = (event.keyCode === keyUP || event.keyCode === keyDOWN);
// in case of type=email and multiple attribute, we would need to split the inputs value into pieces
if (multipleEmails) {
var multipleEntries = inputValue.split(','),
relevantIndex = multipleEntries.length - 1;
inputValue = multipleEntries[relevantIndex].trim();
}
// if the input contains a value, than ...
if (inputValue !== '' || keyOpen) {
// ... create an array out of the options list
var nodeArray = Array.prototype.slice.call(dataListOptions);
prepOptions(dataList, eventTarget);
// ... sort all entries and
nodeArray.sort(function(a, b) {
return a.value.localeCompare(b.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) {
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;
} else if (!opt.text) {
// manipulating the option inner text, that would get displayed
opt.innerText = label || optionValue;
}
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);
}
});
// input the options fragment into the datalists select
dataListSelect.appendChild(newSelectValues);
var dataListSelectOptionsLength = dataListSelect.options.length,

@@ -178,5 +158,2 @@ firstEntry = 0,

dataListSelect.size = (dataListSelectOptionsLength > 10) ? 10 : dataListSelectOptionsLength;
dataListSelect.multiple = (!touched && dataListSelectOptionsLength < 2);
if (touched) {

@@ -198,10 +175,6 @@ // preselect best fitting index

// input the unused options as siblings next to the select - and differentiate in between the regular, and the IE9 fix syntax upfront
var dataListAppend = dataList.getElementsByClassName('ie9_fix')[0] || dataList;
dataListAppend.appendChild(disabledValues);
}
// toggle the visibility of the datalist select according to previous checks
toggleVisibility(dataListSelect, visible);
toggleVisibility(dataListSelect);

@@ -218,97 +191,104 @@ // on arrow up or down keys, focus the select

// focus or blur events
var changesInputList = function(event) {
// function for preparing and sorting the options/suggestions
var prepOptions = function(dataList, input) {
var eventTarget = event.target,
eventTargetTagName = eventTarget.tagName.toLowerCase(),
inputType = eventTarget.type,
inputStyles = window.getComputedStyle(eventTarget);
if (typeof(obs) !== 'undefined') {
obs.disconnect();
}
// check for whether the events target was an input datalist and whether it's of one of the supported input types defined above
if (eventTargetTagName && eventTargetTagName === 'input' && eventTarget.getAttribute('list') && supportedTypes.indexOf(inputType) > -1) {
var dataListSelect = dataList.getElementsByClassName(classNamePolyfillingSelect)[0] || setUpPolyfillingSelect(input, dataList),
dataListOptions = dataList.querySelectorAll('option:not([disabled]):not(.message)'),
inputValue = input.value,
newSelectValues = document.createDocumentFragment(),
disabledValues = document.createDocumentFragment(),
multipleEmails = (input.type === 'email' && input.multiple);
var eventType = event.type,
list = eventTarget.getAttribute('list'),
dataList = document.getElementById(list);
// in case of type=email and multiple attribute, we would need to split the inputs value into pieces
if (multipleEmails) {
var multipleEntries = inputValue.split(','),
relevantIndex = multipleEntries.length - 1;
// still check for an existing instance
if (dataList !== null) {
inputValue = multipleEntries[relevantIndex].trim();
}
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' && eventTarget.value !== '') || (event.relatedTarget && event.relatedTarget === dataListSelect)) && dataListSelect && dataListSelect.options && dataListSelect.options.length),
message = dataList.title;
// ... create an array out of the options list
var nodeArray = Array.prototype.slice.call(dataListOptions);
// creating the select if there's no instance so far (e.g. because of that it hasn't been handled or it has been dynamically inserted)
if (dataListSelect === undefined) {
var rects = eventTarget.getClientRects(),
// measurements
inputStyleMarginRight = parseFloat(inputStyles.getPropertyValue('margin-right')),
inputStyleMarginLeft = parseFloat(inputStyles.getPropertyValue('margin-left'));
// ... sort all entries and
nodeArray.sort(function(a, b) {
return a.value.localeCompare(b.value);
})
.forEach(function(opt) {
var optionValue = opt.value;
dataListSelect = document.createElement('select');
// ... 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) {
// setting a class for easier selecting that select afterwards
dataListSelect.setAttribute('class', classNamePolyfillingSelect);
var label = opt.getAttribute('label'),
text = opt.text,
textOptionPart = text.substr(0, optionValue.length + textValueSeperator.length),
optionPart = optionValue + textValueSeperator;
// set general styling related definitions
dataListSelect.style.position = 'absolute';
// the innertext should be value / text in case they are different
if (text && !label && text !== optionValue && textOptionPart !== optionPart) {
opt.innerText = optionValue + textValueSeperator + text;
// initially hiding the datalist select
toggleVisibility(dataListSelect, false);
} else if (!opt.text) {
// manipulating the option inner text, that would get displayed
opt.innerText = label || optionValue;
}
// WAI ARIA attributes
dataListSelect.setAttribute('aria-live', 'polite');
dataListSelect.setAttribute('role', 'listbox');
if (!touched) {
dataListSelect.setAttribute('aria-multiselectable', 'false');
}
newSelectValues.appendChild(opt);
} 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);
}
});
// the select should get positioned underneath the input field ...
if (inputStyles.getPropertyValue('display') === 'block') {
dataListSelect.style.marginTop = '-' + inputStyles.getPropertyValue('margin-bottom');
} else {
if (inputStyles.getPropertyValue('direction') === 'rtl') {
dataListSelect.style.marginRight = '-' + (rects[0].width + inputStyleMarginLeft) + 'px';
} else {
dataListSelect.style.marginLeft = '-' + (rects[0].width + inputStyleMarginRight) + 'px';
}
// input the options fragment into the datalists select
dataListSelect.appendChild(newSelectValues);
dataListSelect.style.marginTop = parseInt((rects[0].height + (eventTarget.offsetTop - dataList.offsetTop)), 10) + 'px';
}
var dataListSelectOptionsLength = dataListSelect.options.length;
// set the polyfilling selects border-radius equally as the one by the polyfilled input
dataListSelect.style.borderRadius = inputStyles.getPropertyValue('border-radius');
dataListSelect.style.minWidth = rects[0].width + 'px';
dataListSelect.size = (dataListSelectOptionsLength > 10) ? 10 : dataListSelectOptionsLength;
dataListSelect.multiple = (!touched && dataListSelectOptionsLength < 2);
if (touched) {
var messageElement = document.createElement('option');
// input the unused options as siblings next to the select - and differentiate in between the regular, and the IE9 fix syntax upfront
var dataListAppend = dataList.getElementsByClassName('ie9_fix')[0] || dataList;
// ... and it's first entry should contain the localized message to select an entry
messageElement.innerText = message;
// ... and disable this option, as it shouldn't get selected by the user
messageElement.disabled = true;
// ... and assign a dividable class to it
messageElement.setAttribute('class', 'message');
// ... and finally insert it into the select
dataListSelect.appendChild(messageElement);
}
dataListAppend.appendChild(disabledValues);
// add select to datalist element ...
dataList.appendChild(dataListSelect);
if (typeof(obs) !== 'undefined') {
obs.observe(dataList, {
childList: true
});
}
// ... and our upfollowing function to the change event
};
if (touched) {
dataListSelect.addEventListener('change', changeDataListSelect);
} else {
dataListSelect.addEventListener('click', changeDataListSelect);
}
dataListSelect.addEventListener('blur', changeDataListSelect);
dataListSelect.addEventListener('keyup', changeDataListSelect);
}
// focus or blur events
var changesInputList = function(event) {
var eventTarget = event.target,
eventTargetTagName = eventTarget.tagName.toLowerCase();
// check for whether the events target was an input datalist and whether it's of one of the supported input types defined above
if (eventTargetTagName && eventTargetTagName === 'input' && eventTarget.getAttribute('list')) {
var eventType = event.type,
list = eventTarget.getAttribute('list'),
dataList = document.getElementById(list);
// still check for an existing instance
if (dataList !== null) {
// creating the select if there's no instance so far (e.g. because of that it hasn't been handled or it has been dynamically inserted)
var dataListSelect = dataList.getElementsByClassName(classNamePolyfillingSelect)[0] || setUpPolyfillingSelect(eventTarget, dataList),
// 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 - and check for general existance of any option as suggestions
visible = (((eventType === 'focus' && eventTarget.value !== '') || (event.relatedTarget && event.relatedTarget === dataListSelect)) && dataListSelect && dataListSelect.options && dataListSelect.options.length);
// 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
// we'd like to prevent autocomplete on the input datalist field
eventTarget.setAttribute('autocomplete', 'off');

@@ -346,2 +326,83 @@

// define function for setting up the polyfilling select
var setUpPolyfillingSelect = function(input, dataList) {
var inputType = input.type;
if (supportedTypes.indexOf(inputType) > -1) {
// still check for an existing instance
if (dataList !== null) {
var message = dataList.title,
rects = input.getClientRects(),
// measurements
inputStyles = window.getComputedStyle(input),
inputStyleMarginRight = parseFloat(inputStyles.getPropertyValue('margin-right')),
inputStyleMarginLeft = parseFloat(inputStyles.getPropertyValue('margin-left')),
dataListSelect = document.createElement('select');
// setting a class for easier selecting that select afterwards
dataListSelect.setAttribute('class', classNamePolyfillingSelect);
// set general styling related definitions
dataListSelect.style.position = 'absolute';
// initially hiding the datalist select
toggleVisibility(dataListSelect, false);
// WAI ARIA attributes
dataListSelect.setAttribute('aria-live', 'polite');
dataListSelect.setAttribute('role', 'listbox');
if (!touched) {
dataListSelect.setAttribute('aria-multiselectable', 'false');
}
// the select should get positioned underneath the input field ...
if (inputStyles.getPropertyValue('display') === 'block') {
dataListSelect.style.marginTop = '-' + inputStyles.getPropertyValue('margin-bottom');
} else {
if (inputStyles.getPropertyValue('direction') === 'rtl') {
dataListSelect.style.marginRight = '-' + (rects[0].width + inputStyleMarginLeft) + 'px';
} else {
dataListSelect.style.marginLeft = '-' + (rects[0].width + inputStyleMarginRight) + 'px';
}
dataListSelect.style.marginTop = parseInt((rects[0].height + (input.offsetTop - dataList.offsetTop)), 10) + 'px';
}
// set the polyfilling selects border-radius equally as the one by the polyfilled input
dataListSelect.style.borderRadius = inputStyles.getPropertyValue('border-radius');
dataListSelect.style.minWidth = rects[0].width + 'px';
if (touched) {
var messageElement = document.createElement('option');
// ... and it's first entry should contain the localized message to select an entry
messageElement.innerText = message;
// ... and disable this option, as it shouldn't get selected by the user
messageElement.disabled = true;
// ... and assign a dividable class to it
messageElement.setAttribute('class', 'message');
// ... and finally insert it into the select
dataListSelect.appendChild(messageElement);
}
// add select to datalist element ...
dataList.appendChild(dataListSelect);
// ... and our upfollowing function to the change event
if (touched) {
dataListSelect.addEventListener('change', changeDataListSelect);
} else {
dataListSelect.addEventListener('click', changeDataListSelect);
}
dataListSelect.addEventListener('blur', changeDataListSelect);
dataListSelect.addEventListener('keyup', changeDataListSelect);
return dataListSelect;
}
}
};
// function regarding changes to the datalist polyfilling created select

@@ -395,3 +456,3 @@ var changeDataListSelect = function(event) {

// finally focusing the input, as other browser do it as well
// finally focusing the input, as other browser do this as well
inputList.focus();

@@ -411,2 +472,6 @@

var toggleVisibility = function(dataListSelect, visible) {
if (visible === undefined) {
visible = (dataListSelect && dataListSelect.options && dataListSelect.options.length);
}
if (visible) {

@@ -413,0 +478,0 @@ dataListSelect.removeAttribute('hidden');

/*
* datalist-polyfill.js - https://github.com/mfranzke/datalist-polyfill
* @license Copyright(c) 2017 by Maximilian Franzke
* Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, Michael, @hryamzik, @ottoville, @IceCreamYou, @wlekin and @eddr - many thanks for that !
* Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, @mischah, @hryamzik, @ottoville, @IceCreamYou, @wlekin, @eddr and @beebee1987 - many thanks for that !
*/
!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,o=40,r=" / ",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 o=i.getAttribute("list"),r=document.getElementById(o);if(null!==r){var a=r.getElementsByClassName("polyfilling")[0];if(void 0!==a){if(27===t.keyCode)return void c(a,!1);var l=r.querySelectorAll("option:not([disabled]):not(.message)"),s=i.value,u=document.createDocumentFragment(),d=document.createDocumentFragment(),p=!1,f="email"===i.type&&i.multiple,m=38===t.keyCode||40===t.keyCode;if(f){var y=s.split(","),g=y.length-1;s=y[g].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"),n=e.text,o=n.substr(0,t.length+" / ".length),r=t+" / ";n&&!i&&n!==t&&o!==r?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}(r.getElementsByClassName("ie9_fix")[0]||r).appendChild(d)}c(a,p),m&&a.focus()}}}},d=function(t){var i=t.target,n=i.tagName.toLowerCase(),o=i.type,r=window.getComputedStyle(i);if(n&&"input"===n&&i.getAttribute("list")&&a.indexOf(o)>-1){var l=t.type,s=i.getAttribute("list"),f=document.getElementById(s);if(null!==f){var m=f.getElementsByClassName("polyfilling")[0],y=("focus"===l&&""!==i.value||t.relatedTarget&&t.relatedTarget===m)&&m&&m.options&&m.options.length,g=f.title;if(void 0===m){var v=i.getClientRects(),b=parseFloat(r.getPropertyValue("margin-right")),h=parseFloat(r.getPropertyValue("margin-left"));if(m=document.createElement("select"),m.setAttribute("class","polyfilling"),m.style.position="absolute",c(m,!1),m.setAttribute("aria-live","polite"),m.setAttribute("role","listbox"),e||m.setAttribute("aria-multiselectable","false"),"block"===r.getPropertyValue("display")?m.style.marginTop="-"+r.getPropertyValue("margin-bottom"):("rtl"===r.getPropertyValue("direction")?m.style.marginRight="-"+(v[0].width+h)+"px":m.style.marginLeft="-"+(v[0].width+b)+"px",m.style.marginTop=parseInt(v[0].height+(i.offsetTop-f.offsetTop),10)+"px"),m.style.borderRadius=r.getPropertyValue("border-radius"),m.style.minWidth=v[0].width+"px",e){var E=document.createElement("option");E.innerText=g,E.disabled=!0,E.setAttribute("class","message"),m.appendChild(E)}f.appendChild(m),e?m.addEventListener("change",p):m.addEventListener("click",p),m.addEventListener("blur",p),m.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(m,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,o=n.parentNode,r=o.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=o.id,u=document.querySelector('input[list="'+s+'"]'),d=n.value;if(null!==u&&void 0!==d&&d.length>0&&d!==r){var p=u.value,f,m="email"===u.type&&u.multiple,y;m&&(f=p.lastIndexOf(","))>-1?u.value=p.slice(0,f)+","+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),u.focus(),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)}();
!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,o=40,r=" / ",a=["text","email","number","search","tel","url"],l="polyfilled",s="polyfilling";window.addEventListener("touchstart",function t(){e=!0,window.removeEventListener("touchstart",t)});var u=window.MutationObserver||window.WebKitMutationObserver;if(void 0!==u)var d=new u(function(e){for(var t=!1,i=0;i<e.length;++i)for(var n=0;n<e[i].addedNodes.length;++n)"datalist"===e[i].target.tagName.toLowerCase()&&(t=e[i].target);if(t){var o=document.querySelector('[list="'+t.id+'"]');if(""!==o.value){var r=t;c(r,o),g(r.getElementsByClassName("polyfilling")[0])}}});var p=function(t){var i=t.target,n=i.tagName.toLowerCase();if(n&&"input"===n&&i.getAttribute("list")){var o=i.getAttribute("list"),r=document.getElementById(o);if(null!==r){var a=r.getElementsByClassName("polyfilling")[0]||m(i,r);if(void 0!==a){if(27===t.keyCode)return void g(a,!1);var l=i.value,s=38===t.keyCode||40===t.keyCode;if(""!==l||s){c(r,i);var u=a.options.length,d=0,p=u-1;if(e)a.selectedIndex=0;else if(-1===a.selectedIndex)switch(t.keyCode){case 38:a.selectedIndex=p;break;case 40:a.selectedIndex=0;break}}g(a),s&&a.focus()}}}},c=function(t,i){void 0!==d&&d.disconnect();var n=t.getElementsByClassName("polyfilling")[0]||m(i,t),o=t.querySelectorAll("option:not([disabled]):not(.message)"),r=i.value,a=document.createDocumentFragment(),l=document.createDocumentFragment();if("email"===i.type&&i.multiple){var s=r.split(","),u=s.length-1;r=s[u].trim()}Array.prototype.slice.call(o).sort(function(e,t){return e.value.localeCompare(t.value)}).forEach(function(e){var t=e.value;if(""!==t&&-1!==t.toLowerCase().indexOf(r.toLowerCase())&&!1===e.disabled){var i=e.getAttribute("label"),n=e.text,o=n.substr(0,t.length+" / ".length),s=t+" / ";n&&!i&&n!==t&&o!==s?e.innerText=t+" / "+n:e.text||(e.innerText=i||t),a.appendChild(e)}else l.appendChild(e)}),n.appendChild(a);var p=n.options.length;n.size=p>10?10:p,n.multiple=!e&&p<2,(t.getElementsByClassName("ie9_fix")[0]||t).appendChild(l),void 0!==d&&d.observe(t,{childList:!0})},f=function(e){var t=e.target,i=t.tagName.toLowerCase();if(i&&"input"===i&&t.getAttribute("list")){var n=e.type,o=t.getAttribute("list"),r=document.getElementById(o);if(null!==r){var a=r.getElementsByClassName("polyfilling")[0]||m(t,r),l=("focus"===n&&""!==t.value||e.relatedTarget&&e.relatedTarget===a)&&a&&a.options&&a.options.length;if(!new RegExp(" polyfilled ").test(" "+t.className+" ")){switch(t.setAttribute("autocomplete","off"),t.setAttribute("role","textbox"),t.setAttribute("aria-haspopup","true"),t.setAttribute("aria-autocomplete","list"),t.setAttribute("aria-owns",o),n){case"focus":t.addEventListener("keyup",p),t.addEventListener("focusout",f,!0);break;case"blur":t.removeEventListener("keyup",p),t.removeEventListener("focusout",f,!0);break}t.className+=" polyfilled"}g(a,l)}}},m=function(t,i){var n=t.type;if(a.indexOf(n)>-1&&null!==i){var o=i.title,r=t.getClientRects(),l=window.getComputedStyle(t),s=parseFloat(l.getPropertyValue("margin-right")),u=parseFloat(l.getPropertyValue("margin-left")),d=document.createElement("select");if(d.setAttribute("class","polyfilling"),d.style.position="absolute",g(d,!1),d.setAttribute("aria-live","polite"),d.setAttribute("role","listbox"),e||d.setAttribute("aria-multiselectable","false"),"block"===l.getPropertyValue("display")?d.style.marginTop="-"+l.getPropertyValue("margin-bottom"):("rtl"===l.getPropertyValue("direction")?d.style.marginRight="-"+(r[0].width+u)+"px":d.style.marginLeft="-"+(r[0].width+s)+"px",d.style.marginTop=parseInt(r[0].height+(t.offsetTop-i.offsetTop),10)+"px"),d.style.borderRadius=l.getPropertyValue("border-radius"),d.style.minWidth=r[0].width+"px",e){var p=document.createElement("option");p.innerText=o,p.disabled=!0,p.setAttribute("class","message"),d.appendChild(p)}return i.appendChild(d),e?d.addEventListener("change",v):d.addEventListener("click",v),d.addEventListener("blur",v),d.addEventListener("keyup",v),d}},v=function(e){var t=e.target,i=t.tagName.toLowerCase();if(i&&("select"===i||"option"===i)){var n="select"===i?t:t.parentNode,o=n.parentNode,r=o.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=o.id,u=document.querySelector('input[list="'+s+'"]'),d=n.value;if(null!==u&&void 0!==d&&d.length>0&&d!==r){var p=u.value,c,f="email"===u.type&&u.multiple,m;f&&(c=p.lastIndexOf(","))>-1?u.value=p.slice(0,c)+","+d:u.value=d,"function"==typeof Event?m=new Event("input",{bubbles:!0}):(m=document.createEvent("Event"),m.initEvent("input",!0,!1)),u.dispatchEvent(m),u.focus(),l=!1}}g(n,l)}},g=function(e,t){void 0===t&&(t=e&&e.options&&e.options.length),t?e.removeAttribute("hidden"):e.setAttributeNode(document.createAttribute("hidden")),e.setAttribute("aria-hidden",(!t).toString())};document.addEventListener("focus",f,!0)}();
{
"name": "datalist-polyfill",
"version": "1.13.2",
"version": "1.14.0",
"description": "A lightweight and dependency-free vanilla JavaScript datalist polyfill.",

@@ -5,0 +5,0 @@ "main": "datalist-polyfill.js",

@@ -10,7 +10,8 @@ # datalist-polyfill

Tested in Safari, which it's mainly meant for, as nearly all of the other browsers support it quite well: <http://caniuse.com/#feat=datalist>
Released under the MIT License: <http://www.opensource.org/licenses/mit-license.php>
* Mainly built for Safari, as nearly all of the other browsers support it quite well: <https://caniuse.com/#feat=datalist>
* Released under the MIT License: <https://opensource.org/licenses/mit-license.php>
* Made in Germany. And supported by so many great people from all over this planet - see "Credits" accordingly.
## Features
* Lightweight: 5.24 kB of JavaScript, around 2.35 kB gzipped
* Lightweight: 5.94 kB of minified JavaScript, around 2.59 kB gzipped
* Fully flexible to change the datalist entries / `<option>`s

@@ -35,3 +36,3 @@ * Supporting:

* dependency-free
* Supporting DOM changes by event delegation
* Supporting DOM changes by event delegation and MutationObserver
* code accessibility / readability

@@ -55,3 +56,3 @@

### dynamic HTML (or DHTML, if you like to be a little bit nostalgic)
In case that you'd like to dynamically add or modify / create your HTML code, you're good to go with this polyfill, as it's based on event delegation that makes your UI work easily - no refresh nor reinit function to call after DOM manipulation or something similar.
In case that you'd like to dynamically add or modify / create your HTML code, you're good to go with this polyfill, as it's based on event delegation and additionally using MutationObserver (IE11+) that makes your UI work easily - no refresh nor reinit function to call after DOM manipulation or something similar.

@@ -106,3 +107,3 @@ ### Changes to the available `option` elements

## Credits
Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, @mischah, @hryamzik, @ottoville, @IceCreamYou, @wlekin and @eddr. Thank you very much for that, highly appreciated !
Supported by Christian, Johannes, @mitchhentges, @mertenhanisch, @ailintom, @Kravimir, @mischah, @hryamzik, @ottoville, @IceCreamYou, @wlekin, @eddr and @beebee1987. Thank you very much for that, highly appreciated !

@@ -121,2 +122,4 @@ ## Tested with

* iPhone 6 Plus / 10.3, Mobile Safari 10.0
* Windows
* Windows 7 SP1, Internet Explorer 9.0.8112.16421

@@ -123,0 +126,0 @@ ## Outro

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc