Skip to content

Commit 55fd001

Browse files
committed
simplify optgroup querying and rendering code. provide a more powerful populateResults() function fixes select2#58. fixes select2#105. fixes select2#84
1 parent 9fc18a9 commit 55fd001

1 file changed

Lines changed: 85 additions & 121 deletions

File tree

select2.js

Lines changed: 85 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
return;
2121
}
2222

23-
var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, uid = 1;;
23+
var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid;
2424

2525
KEY = {
2626
TAB: 9,
@@ -67,6 +67,8 @@
6767
}
6868
};
6969

70+
nextUid=(function() { var counter=1; return function() { return counter++; }}());
71+
7072
function indexOf(value, array) {
7173
var i = 0, l = array.length, v;
7274

@@ -474,38 +476,58 @@
474476
}
475477

476478
opts = $.extend({}, {
477-
formatList: function(results) {
478-
var proc = function(results, depth) {
479-
depth = depth || 0;
480-
var parts = [];
481-
482-
$.each(results, function() {
483-
var result = this;
484-
parts.push('<li class="select2-result select2-result-uid-' + result.uid + ' select2-result-depth-' + depth);
485-
if (result.unselectable) {
486-
parts.push(' select2-result-unselectable');
487-
}
488-
if (result.children && result.children.length) {
489-
parts.push(' select2-result-with-children');
490-
}
491-
parts.push('" data-select2-uid="' + result.uid + '">');
479+
populateResults: function(container, results) {
480+
var uidToData={}, populate, markup=[], uid, data, result, children;
481+
482+
populate=function(results, depth) {
483+
484+
var i, l, uid, result, selectable, compound;
485+
for (i = 0, l = results.length; i < l; i = i + 1) {
492486

493-
parts.push('<div class="select2-result-label">' + result.text + '</div>');
487+
result=results[i];
488+
selectable=("id" in result); // TODO switch to id() function
489+
compound=("children" in result) && result.children.length > 0;
494490

495-
if (result.children && result.children.length) {
496-
parts.push('<ul class="select2-result-sub">');
497-
parts.push(proc(result.children, depth + 1))
498-
parts.push('</ul>');
491+
markup.push("<li class='select2-result-depth-"+depth);
492+
if (!selectable) { markup.push(" select2-result-unselectable"); } else { markup.push(" select2-result");}
493+
if (compound) { markup.push(" select2-result-with-children"); }
494+
495+
markup.push("'");
496+
497+
if (selectable) {
498+
uid=nextUid();
499+
markup.push(" id='select2-result-"+uid+"'");
500+
uidToData[uid]=result;
499501
}
500502

501-
parts.push('</li>');
502-
});
503+
markup.push("><div class='select2-result-label'>"+opts.formatResult(result)+"</div>");
503504

505+
if (compound) {
506+
markup.push("<ul class='select2-result-sub'>");
507+
populate(result.children, depth + 1);
508+
markup.push("</ul>");
509+
}
504510

505-
return parts.join('');
511+
markup.push("</li>");
512+
}
506513
};
507514

508-
return proc(results, 0);
515+
populate(results, 0);
516+
517+
children=container.children();
518+
if (children.length==0) {
519+
container.html(markup.join(""));
520+
} else {
521+
$(children[children.length-1]).append(markup.join(""));
522+
}
523+
524+
for (uid in uidToData) {
525+
$("#select2-result-"+uid).data("select2-data", uidToData[uid]);
526+
}
527+
528+
},
529+
formatResult: function(result) {
530+
return result.text;
509531
},
510532
formatSelection: function (data) {
511533
if (data.fullText) {
@@ -531,79 +553,26 @@
531553

532554
if (select) {
533555
opts.query = this.bind(function (query) {
534-
var data = {results: [], map: {}, more: false},
556+
var data = { results: [], more: false },
535557
term = query.term,
536-
idx = 0,
537-
placeholder = this.getPlaceholder();
538-
539-
element.find("> *").each(function() {
540-
var el = $(this);
541-
542-
if (el.is('optgroup')) {
543-
var item = {
544-
id: 'select2-group-' + (uid++),
545-
uid: uid++,
546-
text: el.attr('label'),
547-
unselectable: true,
548-
children: []
549-
};
550-
data.map[item.uid] = item;
551-
552-
el.find('> option').each(function() {
553-
var sub = {
554-
id: $(this).attr('value'),
555-
uid: uid++,
556-
text: $(this).text(),
557-
unselectable: false,
558-
fullText: el.attr('label') + ' > ' + $(this).text(),
559-
children: []
560-
};
561-
562-
data.map[sub.uid] = sub;
563-
item.children.push(sub);
564-
});
565-
566-
data.results.push(item);
567-
} else {
568-
var item = {
569-
id: $(this).attr('value'),
570-
uid: uid++,
571-
text: $(this).text(),
572-
unselectable: false,
573-
children: []
574-
};
575-
576-
data.map[item.uid] = item;
577-
data.results.push(item);
578-
}
579-
});
558+
process;
580559

581-
if (term !== "") {
582-
var filterDeep = function(items, depth) {
583-
var filtered = [];
584-
for (var itemIdx = 0; itemIdx < items.length; itemIdx++) {
585-
var newItem = $.extend(true, [], items[itemIdx]);
586-
if (newItem.children) {
587-
newItem.children = filterDeep(newItem.children);
588-
}
589-
590-
var isMatch = false;
591-
if (newItem.children && newItem.children.length) {
592-
isMatch = true;
593-
} else if (!newItem.unselectable && query.matcher(term, newItem.text)) {
594-
isMatch = true;
595-
}
596-
597-
if (isMatch) {
598-
filtered.push(newItem);
599-
}
560+
process=function(element, collection) {
561+
var group;
562+
if (element.is("option")) {
563+
if (query.matcher(term, element.text())) {
564+
collection.push({id:element.attr("value"), text:element.text()});
565+
}
566+
} else if (element.is("optgroup")) {
567+
group={text:element.attr("label"), children:[]};
568+
element.children().each(function() { process($(this), group.children); });
569+
if (group.children.length>0) {
570+
collection.push(group);
600571
}
601-
602-
return filtered;
603572
}
573+
};
604574

605-
data.results = filterDeep(data.results);
606-
}
575+
element.children().each(function() { process($(this), data.results); });
607576

608577
query.callback(data);
609578
});
@@ -796,37 +765,32 @@
796765
more = results.find("li.select2-more-results"),
797766
below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
798767
offset = -1, // index of first element without data
799-
page = this.resultsPage + 1;
768+
page = this.resultsPage + 1,
769+
self=this;
800770

801771
if (more.length === 0) return;
802-
803772
below = more.offset().top - results.offset().top - results.height();
804773

805774
if (below <= 0) {
806775
more.addClass("select2-active");
807776
this.opts.query({
808777
term: this.search.val(),
809778
page: page,
810-
context: self.context,
811-
matcher: self.opts.matcher,
779+
context: this.context,
780+
matcher: this.opts.matcher,
812781
callback: this.bind(function (data) {
813-
var self = this;
814-
var htmlResult = self.opts.formatList(data.results);
815-
more.before(htmlResult);
816-
results.find(".select2-result").each(function () {
817-
var e = $(this);
818-
if (e.data("select2-data") !== undefined) {
819-
offset = i;
820-
} else {
821-
e.data("select2-data", data.map[e.data('select2-uid')]);
822-
}
823-
});
824-
if (data.more) {
782+
console.log("load more callback", data);
783+
784+
self.opts.populateResults(results, data.results);
785+
786+
if (data.more===true) {
787+
more.detach();
788+
results.children().filter(":last").append(more);
825789
more.removeClass("select2-active");
826790
} else {
827791
more.remove();
828792
}
829-
this.resultsPage = page;
793+
self.resultsPage = page;
830794
})});
831795
}
832796
},
@@ -844,12 +808,16 @@
844808

845809
search.addClass("select2-active");
846810

847-
function render(html) {
848-
results.html(html);
811+
function postRender() {
849812
results.scrollTop(0);
850813
search.removeClass("select2-active");
851814
}
852815

816+
function render(html) {
817+
results.html(html);
818+
postRender();
819+
}
820+
853821
if (search.val().length < opts.minimumInputLength) {
854822
render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>");
855823
return;
@@ -862,8 +830,7 @@
862830
context: null,
863831
matcher: opts.matcher,
864832
callback: this.bind(function (data) {
865-
var parts = [], // html parts
866-
def; // default choice
833+
var def; // default choice
867834

868835
// create a default choice and prepend it to the list
869836
if (this.opts.createSearchChoice && search.val() !== "") {
@@ -883,17 +850,14 @@
883850
return;
884851
}
885852

886-
var htmlResult = self.opts.formatList(data.results);
853+
results.empty();
854+
self.opts.populateResults(results, data.results);
855+
postRender();
887856

888857
if (data.more === true) {
889-
htmlResult += "<li class='select2-more-results'>Loading more results...</li>";
858+
results.children().filter(":last").append("<li class='select2-more-results'>Loading more results...</li>");
890859
}
891860

892-
render(htmlResult);
893-
results.find(".select2-result").each(function () {
894-
var d = data.map[$(this).data('select2-uid')];
895-
$(this).data("select2-data", d);
896-
});
897861
this.postprocessResults(data, initial);
898862
})});
899863
},

0 commit comments

Comments
 (0)