diff --git a/awesomplete.js b/awesomplete.js
index fe4d0c38..5116dd54 100644
--- a/awesomplete.js
+++ b/awesomplete.js
@@ -217,19 +217,23 @@ _.prototype = {
if (value.length >= this.minChars && this._list.length > 0) {
this.index = -1;
- // Populate list with options that match
- this.ul.innerHTML = "";
-
- this._list
- .filter(function(item) {
- return me.filter(item, value);
- })
- .sort(this.sort)
- .every(function(text, i) {
- me.ul.appendChild(me.item(text, value));
-
- return i < me.maxItems - 1;
- });
+ // Populate list with options that match
+ this.ul.innerHTML = "";
+
+ var filteredAndSortedList =
+ this._list
+ .filter(function(item) {
+ return me.filter(item, value);
+ });
+
+ $.mergeSort(filteredAndSortedList ,this.sort);
+
+ filteredAndSortedList
+ .every(function(text, i) {
+ me.ul.appendChild(me.item(text, value));
+
+ return i < me.maxItems - 1;
+ });
if (this.ul.children.length === 0) {
this.close();
@@ -354,6 +358,50 @@ $.regExpEscape = function (s) {
return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
}
+$.mergeSort = function(array, compareFn) {
+
+ msort(array, 0, array.length);
+
+ function msort(array, begin, end) {
+ var size = end - begin;
+ if (size < 2) return;
+
+ var begin_right = begin + Math.floor(size / 2);
+
+ msort(array, begin, begin_right);
+ msort(array, begin_right, end);
+ merge(array, begin, begin_right, end);
+ }
+
+ function merge(array, begin, begin_right, end) {
+ for (; begin < begin_right; ++begin) {
+ if (compareFn(array[begin], array[begin_right]) > 0) {
+ var v = array[begin];
+ array[begin] = array[begin_right];
+ insert(array, begin_right, end, v);
+ }
+ }
+ }
+
+ function insert(array, begin, end, v) {
+ while (begin + 1 < end && compareFn(array[begin + 1], v) < 0) {
+ swap(array, begin, begin + 1);
+ ++begin;
+ }
+ array[begin] = v;
+ }
+
+ function swap(array, a, b) {
+ var tmp = array[a];
+ array[a] = array[b];
+ array[b] = tmp;
+ }
+
+}
+
+
+
+
// Initialization
function init() {
diff --git a/awesomplete.min.js b/awesomplete.min.js
index f5a6f19a..406eab92 100644
--- a/awesomplete.min.js
+++ b/awesomplete.min.js
@@ -1,10 +1,11 @@
// Awesomplete - Lea Verou - MIT license
-(function(){function m(a,b){for(var c in a){var g=a[c],e=this.input.getAttribute("data-"+c.toLowerCase());this[c]="number"===typeof g?parseInt(e):!1===g?null!==e:g instanceof Function?null:e;this[c]||0===this[c]||(this[c]=c in b?b[c]:g)}}function d(a,b){return"string"===typeof a?(b||document).querySelector(a):a||null}function h(a,b){return k.call((b||document).querySelectorAll(a))}function l(){h("input.awesomplete").forEach(function(a){new f(a)})}var f=function(a,b){var c=this;this.input=d(a);this.input.setAttribute("autocomplete",
-"off");this.input.setAttribute("aria-autocomplete","list");b=b||{};m.call(this,{minChars:2,maxItems:10,autoFirst:!1,filter:f.FILTER_CONTAINS,sort:f.SORT_BYLENGTH,item:function(a,b){return d.create("li",{innerHTML:a.replace(RegExp(d.regExpEscape(b.trim()),"gi"),"$&"),"aria-selected":"false"})},replace:function(a){this.input.value=a}},b);this.index=-1;this.container=d.create("div",{className:"awesomplete",around:a});this.ul=d.create("ul",{hidden:"",inside:this.container});this.status=d.create("span",
+(function(){function q(a,b){for(var c in a){var e=a[c],g=this.input.getAttribute("data-"+c.toLowerCase());this[c]="number"===typeof e?parseInt(g):!1===e?null!==g:e instanceof Function?null:g;this[c]||0===this[c]||(this[c]=c in b?b[c]:e)}}function d(a,b){return"string"===typeof a?(b||document).querySelector(a):a||null}function l(a,b){return n.call((b||document).querySelectorAll(a))}function m(){l("input.awesomplete").forEach(function(a){new f(a)})}var f=function(a,b){var c=this;this.input=d(a);this.input.setAttribute("autocomplete",
+"off");this.input.setAttribute("aria-autocomplete","list");b=b||{};q.call(this,{minChars:2,maxItems:10,autoFirst:!1,filter:f.FILTER_CONTAINS,sort:f.SORT_BYLENGTH,item:function(a,b){return d.create("li",{innerHTML:a.replace(RegExp(d.regExpEscape(b.trim()),"gi"),"$&"),"aria-selected":"false"})},replace:function(a){this.input.value=a}},b);this.index=-1;this.container=d.create("div",{className:"awesomplete",around:a});this.ul=d.create("ul",{hidden:"",inside:this.container});this.status=d.create("span",
{className:"visually-hidden",role:"status","aria-live":"assertive","aria-relevant":"additions",inside:this.container});d.bind(this.input,{input:this.evaluate.bind(this),blur:this.close.bind(this),keydown:function(a){var b=a.keyCode;if(c.opened)if(13===b&&c.selected)a.preventDefault(),c.select();else if(27===b)c.close();else if(38===b||40===b)a.preventDefault(),c[38===b?"previous":"next"]()}});d.bind(this.input.form,{submit:this.close.bind(this)});d.bind(this.ul,{mousedown:function(a){a=a.target;if(a!==
-this){for(;a&&!/li/i.test(a.nodeName);)a=a.parentNode;a&&c.select(a)}}});this.input.hasAttribute("list")?(this.list="#"+a.getAttribute("list"),a.removeAttribute("list")):this.list=this.input.getAttribute("data-list")||b.list||[];f.all.push(this)};f.prototype={set list(a){Array.isArray(a)?this._list=a:"string"===typeof a&&-1=this.minChars&&0=this.minChars&&0h))for(h=d+Math.floor(h/2),c(a,d,h),c(a,h,f);db(r[k+1],l);){var p=r,m=k+1,q=p[k];p[k]=p[m];p[m]=q;++k}r[k]=l}}c(a,0,a.length)};"undefined"!==typeof Document&&
+("loading"!==document.readyState?m():document.addEventListener("DOMContentLoaded",m));f.$=d;f.$$=l;"undefined"!==typeof self&&(self.Awesomplete=f);"object"===typeof exports&&(module.exports=f);return f})();
diff --git a/test/awesompleteShared.js b/test/awesompleteShared.js
index 64d53f43..b7b485b4 100644
--- a/test/awesompleteShared.js
+++ b/test/awesompleteShared.js
@@ -41,5 +41,12 @@ var shared = {
expect(li.getAttribute('aria-selected')).toBe('true');
expect(shared.awesompleter.status.textContent).toBe(li.textContent);
}
+ },
+ getListFromResults: function (awesompleter){
+ return [].slice.call(awesompleter.ul.children)
+ .map(function(value){
+ return value.textContent;
+ });
}
+
};
diff --git a/test/awesompleteSpec.js b/test/awesompleteSpec.js
index 601bf9d8..31998673 100644
--- a/test/awesompleteSpec.js
+++ b/test/awesompleteSpec.js
@@ -60,6 +60,7 @@ describe("awesomplete",function(){
shared.awesompleter = awesompleter;
})
+
it("should have a non-empty list", shared.expectListLengthToBe(12));
it("should have 3 min chars", shared.expectMinCharsToBe(3));
@@ -79,7 +80,21 @@ describe("awesomplete",function(){
it("should autocomplete when a suggestion is selected", shared.expectSelectingFirstSuggestionToWorkWith('test'));
it("should autocomplete the first suggestion when autoFirst is true", shared.expectAutoFirstToWorkWith('test'));
- })
+
+ // see http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.11
+ // Chrome's native Array.prototype.sort does not perform stable sorts with arrays above 10 items.
+ it("should perform a stable sort inside evaluation chain",function(){
+ var origList = ["New York","Staten Island","Jamaica","Schenectady","Flushing","White Plains","Great Neck","Yonkers","Utica","Elmira","Binghamton"];
+
+ awesompleter = new Awesomplete(dummyInput,{minChars:0, maxItems:20, sort: function(a,b){ return 0;}});
+ awesompleter.list = origList;
+ awesompleter.evaluate();
+
+ expect(shared.getListFromResults(awesompleter)).toEqual(origList);
+ });
+
+
+ });
});
describe("awesomplete helpers",function(){