diff options
Diffstat (limited to 'pages/options')
-rw-r--r-- | pages/options/options.html | 376 | ||||
-rw-r--r-- | pages/options/options.js | 225 |
2 files changed, 443 insertions, 158 deletions
diff --git a/pages/options/options.html b/pages/options/options.html index 317f8145..ca6429f1 100644 --- a/pages/options/options.html +++ b/pages/options/options.html @@ -12,124 +12,136 @@ <body> <div class="tab"> - <button class="tablinks" id="general-tab">General</button> - <button class="tablinks" id="advanced-tab">Advanced</button> - <button class="tablinks" id="whitelist-tab">Whitelist</button> + <button class="tablinks" id="general-tab" data-localize="__MSG_generalTab__">General</button> + <button class="tablinks" id="advanced-tab" data-localize="__MSG_advancedTab__">Advanced</button> + <button class="tablinks" id="exceptions-tab" data-localize="__MSG_exceptionsTab__">Exceptions</button> </div> <div id="general" class="tabcontent"> - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Toggle Nitter redirects"> - <h1>Nitter Redirects</h1> - <input aria-hidden="true" id="disable-nitter" type="checkbox" checked> - <label for="disable-nitter" class="checkbox-label"> - </label> - </div> + <section class="settings-block"> + <table class="option" aria-label="Toggle Nitter redirects"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_disableNitter__">Nitter Redirects</h1> + </td> + <td> + <input aria-hidden="true" id="disable-nitter" type="checkbox" checked> + <label for="disable-nitter" class="checkbox-label"></label> + </td> + </tr> + </tbody> + </table> </section> - - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Toggle Invidious redirects"> - <h1>Invidious Redirects</h1> - <input aria-hidden="true" id="disable-invidious" type="checkbox" checked> - <label for="disable-invidious" class="checkbox-label"> - </label> - </div> + <section class="settings-block"> + <table class="option" aria-label="Toggle Invidious redirects"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_disableInvidious__">Invidious Redirects</h1> + </td> + <td> + <input aria-hidden="true" id="disable-invidious" type="checkbox" checked> + <label for="disable-invidious" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> </section> - - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Toggle Bibliogram redirects"> - <h1>Bibliogram Redirects</h1> - <input aria-hidden="true" id="disable-bibliogram" type="checkbox" checked> - <label for="disable-bibliogram" class="checkbox-label"> - </label> + <section class="settings-block"> + <table class="option" aria-label="Toggle Bibliogram redirects"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_disableBibliogram__">Bibliogram Redirects</h1> + </td> + <td> + <input aria-hidden="true" id="disable-bibliogram" type="checkbox" checked> + <label for="disable-bibliogram" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> + </section> + <section class="settings-block"> + <table class="option" aria-label="Toggle OpenStreetMap redirects"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_disableOsm__">OpenStreetMap Redirects</h1> + </td> + <td> + <input aria-hidden="true" id="disable-osm" type="checkbox" checked> + <label for="disable-osm" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> + </section> + <section class="settings-block"> + <h1 data-localize="__MSG_nitterInstance__">Nitter Instance</h1> + <div class="autocomplete"> + <input id="nitter-instance" type="url" name="nitter-instance" placeholder="https://nitter.net"> </div> </section> - - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Toggle OpenStreetMap redirects"> - <h1>OpenStreetMap Redirects</h1> - <input aria-hidden="true" id="disable-osm" type="checkbox" checked> - <label for="disable-osm" class="checkbox-label"> - </label> + <section class="settings-block"> + <h1 data-localize="__MSG_invidiousInstance__">Invidious Instance</h1> + <div class="autocomplete"> + <input id="invidious-instance" type="url" placeholder="https://invidio.us"> </div> </section> - - <section class="options settings_block"> - <h1>Nitter Instance</h1> - <input id="nitter-instance" list="nitter-instance-list" type="url" placeholder="https://nitter.net"> - <datalist id="nitter-instance-list"> - <option value="https://nitter.net"> - <option value="https://nitter.snopyta.org"> - <option value="https://nitter.42l.fr"> - <option value="https://nitter.nixnet.services"> - <option value="https://nitter.13ad.de"> - <option value="https://nitter.pussthecat.org"> - <option value="https://nitter.mastodont.cat"> - <option value="https://nitter.dark.fail"> - <option value="https://nitter.tedomum.net"> - <option value="https://t.maisputain.ovh"> - <option value="http://3nzoldnxplag42gqjs23xvghtzf6t6yzssrtytnntc6ppc7xxuoneoad.onion"> - <option value="http://nitter.l4qlywnpwqsluw65ts7md3khrivpirse744un3x7mlskqauz5pyuzgqd.onion"> - </datalist> - <h1>Invidious Instance</h1> - <input id="invidious-instance" list="invidious-instances-list" type="url" placeholder="https://invidio.us"> - <datalist id="invidious-instances-list"> - <option value="https://invidio.us"> - <option value="https://invidious.snopyta.org"> - <option value="https://invidious.fdn.fr"> - <option value="https://invidious.13ad.de"> - <option value="https://watch.nettohikari.com"> - <option value="https://yewtu.be"> - <option value="https://yt.maisputain.ovh"> - <option value="https://invidious.toot.koeln"> - <option value="https://invidious.ggc-project.de"> - <option value="http://kgg2m7yk5aybusll.onion"> - <option value="http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion"> - <option value="http://fz253lmuao3strwbfbmx46yu7acac2jz27iwtorgmbqlkurlclmancad.onion"> - <option value="http://qklhadlycap4cnod.onion"> - <option value="http://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion"> - <option value="http://mfqczy4mysscub2s.onion"> - </datalist> - <h1>Bibliogram Instance</h1> - <input id="bibliogram-instance" list="bibliogram-instance-list" type="url" placeholder="https://bibliogram.art"> - <datalist id="bibliogram-instance-list"> - <option value="https://bibliogram.art"> - <option value="https://bibliogram.snopyta.org"> - <option value="https://bibliogram.pussthecat.org"> - <option value="https://bibliogram.nixnet.services"> - <option value="https://bibliogram.hamster.dance"> - <option value="https://insta.maisputain.ovh"> - <option value="https://bibliogram.ggc-project.de"> - </datalist> - <h1>OpenStreetMap Instance</h1> - <input id="osm-instance" list="osm-instance-list" type="url" placeholder="https://openstreetmap.org"> - <datalist id="osm-instance-list"> - <option value="https://openstreetmap.org"> - </datalist> + <section class="settings-block"> + <h1 data-localize="__MSG_bibliogramInstance__">Bibliogram Instance</h1> + <div class="autocomplete"> + <input id="bibliogram-instance" type="url" placeholder="https://bibliogram.art"> + </div> </section> + <sections class="settings-block"> + <h1 data-localize="__MSG_osmInstance__">OpenStreetMap Instance</h1> + <div class="autocomplete"> + <input id="osm-instance" type="url" placeholder="https://openstreetmap.org"> + </div> + </sections> </div> <div id="advanced" class="tabcontent"> - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Always proxy videos through Invidious"> - <h1>Always proxy videos through Invidious</h1> - <input aria-hidden="true" id="always-proxy" type="checkbox" checked> - <label for="always-proxy" class="checkbox-label"> - </label> - </div> + <section class="settings-block"> + <table class="option" aria-label="Always proxy videos through Invidious"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_alwaysProxy__">Always proxy videos through Invidious</h1> + </td> + <td> + <input aria-hidden="true" id="always-proxy" type="checkbox" checked> + <label for="always-proxy" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> </section> - - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Only redirect embedded video to Invidious"> - <h1>Only redirect embedded video to Invidious</h1> - <input aria-hidden="true" id="only-embed" type="checkbox" checked> - <label for="only-embed" class="checkbox-label"> - </label> - </div> + <section class="settings-block"> + <table class="option" aria-label="Only redirect embedded video to Invidious"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_onlyEmbeddedVideo__">Only redirect embedded video to Invidious</h1> + </td> + <td> + <input aria-hidden="true" id="only-embed" type="checkbox" checked> + <label for="only-embed" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> </section> - - <section class="options settings_block"> - <h1>Invidious Video Quality</h1> + <section class="settings-block"> + <h1 data-localize="__MSG_videoQuality__">Invidious Video Quality</h1> <select id="video-quality"> <option value="">Default</option> <option value="hd720">720p</option> @@ -137,48 +149,138 @@ <option value="dash">DASH (Dynamic Adaptive Streaming over HTTP)</option> </select> </section> - - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Invidious dark mode aways on"> - <h1>Invidious dark mode always on</h1> - <input aria-hidden="true" id="invidious-dark-mode" type="checkbox" checked> - <label for="invidious-dark-mode" class="checkbox-label"> - </label> - </div> + <section class="settings-block"> + <table class="option" aria-label="Invidious dark mode aways on"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_invidiousDarkMode__">Invidious dark mode always on</h1> + </td> + <td> + <input aria-hidden="true" id="invidious-dark-mode" type="checkbox" checked> + <label for="invidious-dark-mode" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> </section> - - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Persist Invidious preferences"> - <h1>Persist Invidious preferences (as cookie)</h1> - <input aria-hidden="true" id="persist-invidious-prefs" type="checkbox" checked> - <label for="persist-invidious-prefs" class="checkbox-label"> - </label> - </div> + <section class="settings-block"> + <h1 data-localize="__MSG_invidiousVolume__">Invidious Volume</h1> + <input id="invidious-volume" name="invidious-volume" type="range" min="0" max="100" step="1"> </section> - - <section class="options settings_block"> - <div class="onoffswitch switch" aria-label="Proactively remove Twitter service worker"> - <h1>Proactively remove Twitter service worker</h1> - <input aria-hidden="true" id="remove-twitter-sw" type="checkbox" checked> - <label for="remove-twitter-sw" class="checkbox-label"> - </label> - </div> + <section class="settings-block"> + <h1 data-localize="__MSG_invidiousPlayerStyle__">Invidious Player Style</h1> + <select id="invidious-player-style"> + <option value="invidious">Invidious</option> + <option value="youtube">YouTube</option> + </select> + </section> + <section class="settings-block"> + <h1 data-localize="__MSG_invidiousSubtitles__">Invidious Subtitles - language codes (comma-separated)</h1> + <input id="invidious-subtitles" name="invidious-subtitles" type="text"> + </section> + <section class="settings-block"> + <table class="option" aria-label="Invidious automatically play video on load"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_invidiousAutoplay__">Invidious automatically play video on load</h1> + </td> + <td> + <input aria-hidden="true" id="invidious-autoplay" type="checkbox" checked> + <label for="invidious-autoplay" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> + </section> + <section class="settings-block"> + <table class="option" aria-label="Persist Invidious preferences"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_persistInvidiousPrefs__">Persist Invidious preferences (as cookie)</h1> + </td> + <td> + <input aria-hidden="true" id="persist-invidious-prefs" type="checkbox" checked> + <label for="persist-invidious-prefs" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> + </section> + <section class="settings-block"> + <table class="option" aria-label="Proactively remove Twitter service worker"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_removeTwitterSW__">Proactively remove Twitter service worker</h1> + </td> + <td> + <input aria-hidden="true" id="remove-twitter-sw" type="checkbox" checked> + <label for="remove-twitter-sw" class="checkbox-label"> + </label> + </td> + </tr> + </tbody> + </table> </section> </div> - <div id="whitelist" class="tabcontent"> - <section class="options settings_block"> - <h1>Whitelisted Sites</h1> - <div class="whitelist"> - <input id="new-whitelist-item" type="text" placeholder="URL (RegExp accepted)"> - <button id="add-to-whitelist">Add to Whitelist</button> - </div> + <div id="exceptions" class="tabcontent"> + <section class="settings-block" data-localize="__MSG_exceptionsDescription__"> + <p> + Enter a URL or Regular Expression to be excluded from redirects. + </p> + <p> + All requests for or initiating from a URL that matches your exception + will be excluded from redirects. + </p> + <p> + <b>Note -</b> Supports JavaScript regular expressions, excluding + the enclosing forward slashes. + </p> + </section> + <section class="settings-block"> + <table class="exceptions option"> + <tbody> + <tr> + <td> + <h1 data-localize="__MSG_addException__">Add Exception</h1> + </td> + </tr> + <tr> + <td> + <input id="new-exceptions-item" type="text" placeholder="URL or RegExp"> + </td> + <td> + <input type="radio" id="url" name="type" value="URL" checked> + <label class="radio" for="url">URL</label> + <input type="radio" id="regExp" name="type" value="RegExp"> + <label class="radio" for="regExp">RegExp</label> + </td> + <td> + <button id="add-to-exceptions"> + <svg xmlns='http://www.w3.org/2000/svg' width='512' height='512' viewBox='0 0 512 512'> + <line x1='256' y1='112' x2='256' y2='400' + style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px' /> + <line x1='400' y1='256' x2='112' y2='256' + style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px' /> + </svg> + </button> + </td> + </tr> + </tbody> + </table> </section> - <ul id="whitelist-items"></ul> + <ul id="exceptions-items"></ul> </div> <script src="./options.js"></script> - + <script src="../../assets/javascript/localise.js"></script> </body> -</html> +</html> \ No newline at end of file diff --git a/pages/options/options.js b/pages/options/options.js index 5e25a495..19f9bba7 100644 --- a/pages/options/options.js +++ b/pages/options/options.js @@ -1,5 +1,55 @@ 'use strict'; +const nitterInstances = [ + 'https://nitter.net', + 'https://nitter.snopyta.org', + 'https://nitter.42l.fr', + 'https://nitter.nixnet.services', + 'https://nitter.13ad.de', + 'https://nitter.pussthecat.org', + 'https://nitter.mastodont.cat', + 'https://nitter.dark.fail', + 'https://nitter.tedomum.net', + 'https://t.maisputain.ovh', + 'http://3nzoldnxplag42gqjs23xvghtzf6t6yzssrtytnntc6ppc7xxuoneoad.onion', + 'http://nitter.l4qlywnpwqsluw65ts7md3khrivpirse744un3x7mlskqauz5pyuzgqd.onion' +]; +const invidiousInstances = [ + 'https://invidio.us', + 'https://invidious.snopyta.org', + 'https://invidious.fdn.fr', + 'https://invidious.13ad.de', + 'https://watch.nettohikari.com', + 'https://yewtu.be', + 'https://yt.maisputain.ovh', + 'https://invidious.toot.koeln', + 'https://invidious.ggc-project.de', + 'http://kgg2m7yk5aybusll.onion', + 'http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion', + 'http://fz253lmuao3strwbfbmx46yu7acac2jz27iwtorgmbqlkurlclmancad.onion', + 'http://qklhadlycap4cnod.onion', + 'http://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion', + 'http://mfqczy4mysscub2s.onion' +]; +const bibliogramInstances = [ + 'https://bibliogram.art', + 'https://bibliogram.snopyta.org', + 'https://bibliogram.pussthecat.org', + 'https://bibliogram.nixnet.services', + 'https://bibliogram.hamster.dance', + 'https://insta.maisputain.ovh', + 'https://bibliogram.ggc-project.de' +]; +const osmInstances = [ + 'https://openstreetmap.org' +]; +const autocompletes = [ + { id: 'nitter-instance', instances: nitterInstances }, + { id: 'invidious-instance', instances: invidiousInstances }, + { id: 'bibliogram-instance', instances: bibliogramInstances }, + { id: 'osm-instance', instances: osmInstances } +]; + let nitterInstance = document.getElementById('nitter-instance'); let invidiousInstance = document.getElementById('invidious-instance'); let bibliogramInstance = document.getElementById('bibliogram-instance'); @@ -14,24 +64,35 @@ let videoQuality = document.getElementById('video-quality'); let removeTwitterSW = document.getElementById('remove-twitter-sw'); let invidiousDarkMode = document.getElementById('invidious-dark-mode'); let persistInvidiousPrefs = document.getElementById('persist-invidious-prefs'); -let whitelist; +let invidiousVolume = document.getElementById('invidious-volume'); +let invidiousPlayerStyle = document.getElementById('invidious-player-style'); +let invidiousSubtitles = document.getElementById('invidious-subtitles'); +let invidiousAutoplay = document.getElementById('invidious-autoplay'); +let exceptions; window.browser = window.browser || window.chrome; -function prependWhitelistItem(item, index) { +function prependExceptionsItem(item, index) { const li = document.createElement('li'); li.appendChild(document.createTextNode(item.toString())); const button = document.createElement('button'); - button.appendChild(document.createTextNode('X')); + li.appendChild(button); + document.getElementById('exceptions-items').prepend(li); + const svg = + `<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 512 512'> + <line x1='368' y1='368' x2='144' y2='144' + style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px' /> + <line x1='368' y1='144' x2='144' y2='368' + style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px' /> + </svg>`; + button.innerHTML = svg; button.addEventListener('click', () => { - li.remove(); - whitelist.splice(index, 1); + exceptions.splice(index, 1); browser.storage.sync.set({ - whitelist: whitelist + exceptions: exceptions }); + li.remove(); }); - li.appendChild(button); - document.getElementById('whitelist-items').prepend(li); } browser.storage.sync.get( @@ -48,9 +109,13 @@ browser.storage.sync.get( 'onlyEmbeddedVideo', 'videoQuality', 'removeTwitterSW', - 'whitelist', 'invidiousDarkMode', - 'persistInvidiousPrefs' + 'persistInvidiousPrefs', + 'invidiousVolume', + 'invidiousPlayerStyle', + 'invidiousSubtitles', + 'invidiousAutoplay', + 'exceptions' ], result => { nitterInstance.value = result.nitterInstance || ''; @@ -67,8 +132,12 @@ browser.storage.sync.get( removeTwitterSW.checked = !result.removeTwitterSW; invidiousDarkMode.checked = result.invidiousDarkMode; persistInvidiousPrefs.checked = result.persistInvidiousPrefs; - whitelist = result.whitelist || []; - whitelist.forEach(prependWhitelistItem); + exceptions = result.exceptions || []; + exceptions.forEach(prependExceptionsItem); + invidiousVolume.value = result.invidiousVolume; + invidiousPlayerStyle.value = result.invidiousPlayerStyle; + invidiousSubtitles.value = result.invidiousSubtitles || ''; + invidiousAutoplay.checked = !result.invidiousAutoplay; } ); @@ -92,22 +161,27 @@ document.getElementById('general-tab').addEventListener( document.getElementById('advanced-tab').addEventListener( 'click', openTab.bind(null, 'advanced') ); -document.getElementById('whitelist-tab').addEventListener( - 'click', openTab.bind(null, 'whitelist') +document.getElementById('exceptions-tab').addEventListener( + 'click', openTab.bind(null, 'exceptions') ); document.getElementById('general-tab').click(); -function addToWhitelist() { - const input = document.getElementById('new-whitelist-item'); +function addToExceptions() { + const input = document.getElementById('new-exceptions-item'); + const type = document.querySelector('input[name="type"]:checked').value; if (input.value) { try { + let value = input.value; new RegExp(input.value); - const index = whitelist.push(input.value); - prependWhitelistItem(input.value, index); + if (type === 'URL') { + value = value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + exceptions.push(value); browser.storage.sync.set({ - whitelist: whitelist + exceptions: exceptions }); + prependExceptionsItem(value, exceptions.indexOf(value)); input.value = ''; } catch (error) { input.setCustomValidity('Invalid RegExp'); @@ -117,8 +191,8 @@ function addToWhitelist() { } } -document.getElementById('add-to-whitelist').addEventListener( - 'click', addToWhitelist +document.getElementById('add-to-exceptions').addEventListener( + 'click', addToExceptions ); function debounce(func, wait, immediate) { @@ -231,3 +305,112 @@ invidiousDarkMode.addEventListener('change', event => { persistInvidiousPrefs.addEventListener('change', event => { browser.storage.sync.set({ persistInvidiousPrefs: event.target.checked }); }); + +let invidiousVolumeChange = debounce(() => { + if (invidiousInstance.checkValidity()) { + browser.storage.sync.set({ + invidiousVolume: invidiousVolume.value + }); + } +}, 500); +invidiousVolume.addEventListener('input', invidiousVolumeChange); + +invidiousPlayerStyle.addEventListener('change', event => { + browser.storage.sync.set({ + invidiousPlayerStyle: event.target.options[invidiousPlayerStyle.selectedIndex].value + }); +}); + +let invidiousSubtitlesChange = debounce(() => { + if (invidiousInstance.checkValidity()) { + browser.storage.sync.set({ + invidiousSubtitles: invidiousSubtitles.value + }); + } +}, 500); +invidiousSubtitles.addEventListener('input', invidiousSubtitlesChange); + +invidiousAutoplay.addEventListener('change', event => { + browser.storage.sync.set({ invidiousAutoplay: !event.target.checked }); +}); + + +function autocomplete(input, list) { + let currentFocus; + input.addEventListener("focus", (e) => { + showOptions(e); + }); + input.addEventListener("input", (e) => { + const val = e.target.value; + if (!val) { return false; } + currentFocus = -1; + showOptions(e); + }); + input.addEventListener("keydown", function (e) { + let x = document.getElementById(this.id + "autocomplete-list"); + if (x) x = x.getElementsByTagName("div"); + if (e.keyCode == 40) { + currentFocus++; + addActive(x); + } else if (e.keyCode == 38) { + currentFocus--; + addActive(x); + } else if (e.keyCode == 13) { + e.preventDefault(); + if (currentFocus > -1) { + if (x) x[currentFocus].click(); + } + } + }); + function showOptions(e) { + let a, b, i, val = e.target.value; + closeAllLists(); + a = document.createElement("div"); + a.setAttribute("id", e.target.id + "autocomplete-list"); + a.setAttribute("class", "autocomplete-items"); + e.target.parentNode.appendChild(a); + for (i = 0; i < list.length; i++) { + if (list[i].toLowerCase().indexOf(val.toLowerCase()) > -1) { + b = document.createElement("div"); + b.innerHTML = "<strong>" + list[i].substr(0, val.length) + "</strong>"; + b.innerHTML += list[i].substr(val.length); + b.innerHTML += "<input type='hidden' value='" + list[i] + "'>"; + b.addEventListener("click", function (e) { + input.value = e.target.getElementsByTagName("input")[0].value; + input.dispatchEvent(new Event('input')); + closeAllLists(); + }); + a.appendChild(b); + } + } + } + function addActive(x) { + if (!x) return false; + removeActive(x); + if (currentFocus >= x.length) currentFocus = 0; + if (currentFocus < 0) currentFocus = (x.length - 1); + x[currentFocus].classList.add("autocomplete-active"); + } + function removeActive(x) { + for (let i = 0; i < x.length; i++) { + x[i].classList.remove("autocomplete-active"); + } + } + function closeAllLists(elmnt) { + let x = document.getElementsByClassName("autocomplete-items"); + for (let i = 0; i < x.length; i++) { + if (elmnt != x[i] && elmnt != input) { + x[i].parentNode.removeChild(x[i]); + } + } + } + document.addEventListener("click", (e) => { + if (!autocompletes.find(element => element.id === e.target.id)) { + closeAllLists(e.target); + } + }); +} + +autocompletes.forEach((value) => { + autocomplete(document.getElementById(value.id), value.instances); +}) |