I'm populating datalist elements for an autocomplete dropdown with keywords from data-* attributes of elements in a webpage, and when sorting them and removing duplicates I'd prefer to keep the keywords that begin with uppercase over the lowercase keywords.

My code for getting the unique keywords could probably use some optimization for efficiency as well, though running it in a web worker means that isn't a priority.

I tried a localeCompare trick with the caseFirst:upper option, but that didn't do it (or perhaps it could if the duplicate removing code was smarter)

TL;DR I want capitalized Foo/Bar/Baz to be in the autocomplete dropdown instead of foo/bar/baz

<!DOCTYPE HTML><html lang="en"><head><meta charset="utf-8"> <title>Populate Autocomplete</title> <script type="text/javascript"> function acEntries(dl,kwlist) { var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=\"text\/js-worker\"]"), function (oScript) { return oScript.textContent; }),{type: "text/javascript"}), worker = new Worker(window.URL.createObjectURL(blob)); Array.prototype.slice.call(document.querySelectorAll("dd[data-"+dl.toLowerCase()+"]")).forEach(function(g){ var ds = g.dataset.fooTopics; if(!ds)return; /* Ensure there is a data- attribute of CSV keywords to include in the kwlist array */ kwlist = kwlist.concat(ds.split(",")); }) worker.postMessage(kwlist); /* Asynchronously remove duplicate keywords and sort */ worker.onmessage = function (ev) { var d = document.getElementById(dl),t = d.firstChild.content,v = ev.data, observer = new MutationObserver(function(mo) { t.firstChild.setAttribute("value",v.shift()); if(v.length<1){observer.disconnect()} requestAnimationFrame(function(){d.appendChild(t.cloneNode(true))}); /* add the next keyword to datalist */ }), config = {childList:true}; t.firstChild.setAttribute("value",v.shift()); observer.observe(d,config); /* watch for keywords being added to datalist */ d.appendChild(t.cloneNode(true)); /* add the first keyword to the datalist */ worker.terminate(); } } </script></head><body onload="acEntries('Foo-topics',[])"> <dl><dt></dt> <dd data-foo-topics="Foo,bar,Baz">Foobar Baz</dd> <dd data-foo-topics="Floo,Bar,Blaz">Floobar Blaz</dd> <dd data-foo-topics="foo,Blah,baz">Fooblah Baz</dd> </dl> <input type="search" list="Foo-topics" placeholder="Foo-topics" autocomplete="off" aria-autocomplete="list"> <datalist id="Foo-topics"><template><option></template></datalist> <script type="text/js-worker"> self.addEventListener('message', msgRcvd); function msgRcvd(er) { var arr = er.data.sort(function(a, b) { return a.localeCompare(b, {sensitivity:'base',caseFirst:'upper'}); }), len = arr.length, nw = (len >= 1 ? [arr[0]] : []); for(var i = 1; i < len; i++) { if(nw[nw.length -1].toLowerCase() != arr[i].toLowerCase()) { nw.push(arr[i]); } } self.postMessage(nw); } </script></body></html>

Play with it at http://htmlpad.org/ArrayComplete/edit