1
0
mirror of synced 2025-02-04 06:09:23 +03:00

simplify optgroup querying and rendering code. provide a more powerful populateResults() function fixes #58. fixes #105. fixes #84

This commit is contained in:
Igor Vaynberg 2012-06-14 00:21:22 -07:00
parent 9fc18a9ca8
commit 55fd00169e

View File

@ -20,7 +20,7 @@
return; return;
} }
var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, uid = 1;; var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid;
KEY = { KEY = {
TAB: 9, TAB: 9,
@ -67,6 +67,8 @@
} }
}; };
nextUid=(function() { var counter=1; return function() { return counter++; }}());
function indexOf(value, array) { function indexOf(value, array) {
var i = 0, l = array.length, v; var i = 0, l = array.length, v;
@ -474,38 +476,58 @@
} }
opts = $.extend({}, { opts = $.extend({}, {
formatList: function(results) { populateResults: function(container, results) {
var proc = function(results, depth) { var uidToData={}, populate, markup=[], uid, data, result, children;
depth = depth || 0;
var parts = [];
$.each(results, function() { populate=function(results, depth) {
var result = this;
parts.push('<li class="select2-result select2-result-uid-' + result.uid + ' select2-result-depth-' + depth);
if (result.unselectable) {
parts.push(' select2-result-unselectable');
}
if (result.children && result.children.length) {
parts.push(' select2-result-with-children');
}
parts.push('" data-select2-uid="' + result.uid + '">');
parts.push('<div class="select2-result-label">' + result.text + '</div>'); var i, l, uid, result, selectable, compound;
for (i = 0, l = results.length; i < l; i = i + 1) {
if (result.children && result.children.length) { result=results[i];
parts.push('<ul class="select2-result-sub">'); selectable=("id" in result); // TODO switch to id() function
parts.push(proc(result.children, depth + 1)) compound=("children" in result) && result.children.length > 0;
parts.push('</ul>');
markup.push("<li class='select2-result-depth-"+depth);
if (!selectable) { markup.push(" select2-result-unselectable"); } else { markup.push(" select2-result");}
if (compound) { markup.push(" select2-result-with-children"); }
markup.push("'");
if (selectable) {
uid=nextUid();
markup.push(" id='select2-result-"+uid+"'");
uidToData[uid]=result;
} }
parts.push('</li>'); markup.push("><div class='select2-result-label'>"+opts.formatResult(result)+"</div>");
});
if (compound) {
markup.push("<ul class='select2-result-sub'>");
populate(result.children, depth + 1);
markup.push("</ul>");
}
return parts.join(''); markup.push("</li>");
}
}; };
return proc(results, 0); populate(results, 0);
children=container.children();
if (children.length==0) {
container.html(markup.join(""));
} else {
$(children[children.length-1]).append(markup.join(""));
}
for (uid in uidToData) {
$("#select2-result-"+uid).data("select2-data", uidToData[uid]);
}
},
formatResult: function(result) {
return result.text;
}, },
formatSelection: function (data) { formatSelection: function (data) {
if (data.fullText) { if (data.fullText) {
@ -531,79 +553,26 @@
if (select) { if (select) {
opts.query = this.bind(function (query) { opts.query = this.bind(function (query) {
var data = {results: [], map: {}, more: false}, var data = { results: [], more: false },
term = query.term, term = query.term,
idx = 0, process;
placeholder = this.getPlaceholder();
element.find("> *").each(function() { process=function(element, collection) {
var el = $(this); var group;
if (element.is("option")) {
if (el.is('optgroup')) { if (query.matcher(term, element.text())) {
var item = { collection.push({id:element.attr("value"), text:element.text()});
id: 'select2-group-' + (uid++), }
uid: uid++, } else if (element.is("optgroup")) {
text: el.attr('label'), group={text:element.attr("label"), children:[]};
unselectable: true, element.children().each(function() { process($(this), group.children); });
children: [] if (group.children.length>0) {
}; collection.push(group);
data.map[item.uid] = item;
el.find('> option').each(function() {
var sub = {
id: $(this).attr('value'),
uid: uid++,
text: $(this).text(),
unselectable: false,
fullText: el.attr('label') + ' > ' + $(this).text(),
children: []
};
data.map[sub.uid] = sub;
item.children.push(sub);
});
data.results.push(item);
} else {
var item = {
id: $(this).attr('value'),
uid: uid++,
text: $(this).text(),
unselectable: false,
children: []
};
data.map[item.uid] = item;
data.results.push(item);
}
});
if (term !== "") {
var filterDeep = function(items, depth) {
var filtered = [];
for (var itemIdx = 0; itemIdx < items.length; itemIdx++) {
var newItem = $.extend(true, [], items[itemIdx]);
if (newItem.children) {
newItem.children = filterDeep(newItem.children);
}
var isMatch = false;
if (newItem.children && newItem.children.length) {
isMatch = true;
} else if (!newItem.unselectable && query.matcher(term, newItem.text)) {
isMatch = true;
}
if (isMatch) {
filtered.push(newItem);
}
} }
return filtered;
} }
};
data.results = filterDeep(data.results); element.children().each(function() { process($(this), data.results); });
}
query.callback(data); query.callback(data);
}); });
@ -796,10 +765,10 @@
more = results.find("li.select2-more-results"), more = results.find("li.select2-more-results"),
below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
offset = -1, // index of first element without data offset = -1, // index of first element without data
page = this.resultsPage + 1; page = this.resultsPage + 1,
self=this;
if (more.length === 0) return; if (more.length === 0) return;
below = more.offset().top - results.offset().top - results.height(); below = more.offset().top - results.offset().top - results.height();
if (below <= 0) { if (below <= 0) {
@ -807,26 +776,21 @@
this.opts.query({ this.opts.query({
term: this.search.val(), term: this.search.val(),
page: page, page: page,
context: self.context, context: this.context,
matcher: self.opts.matcher, matcher: this.opts.matcher,
callback: this.bind(function (data) { callback: this.bind(function (data) {
var self = this; console.log("load more callback", data);
var htmlResult = self.opts.formatList(data.results);
more.before(htmlResult); self.opts.populateResults(results, data.results);
results.find(".select2-result").each(function () {
var e = $(this); if (data.more===true) {
if (e.data("select2-data") !== undefined) { more.detach();
offset = i; results.children().filter(":last").append(more);
} else {
e.data("select2-data", data.map[e.data('select2-uid')]);
}
});
if (data.more) {
more.removeClass("select2-active"); more.removeClass("select2-active");
} else { } else {
more.remove(); more.remove();
} }
this.resultsPage = page; self.resultsPage = page;
})}); })});
} }
}, },
@ -844,12 +808,16 @@
search.addClass("select2-active"); search.addClass("select2-active");
function render(html) { function postRender() {
results.html(html);
results.scrollTop(0); results.scrollTop(0);
search.removeClass("select2-active"); search.removeClass("select2-active");
} }
function render(html) {
results.html(html);
postRender();
}
if (search.val().length < opts.minimumInputLength) { if (search.val().length < opts.minimumInputLength) {
render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>"); render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>");
return; return;
@ -862,8 +830,7 @@
context: null, context: null,
matcher: opts.matcher, matcher: opts.matcher,
callback: this.bind(function (data) { callback: this.bind(function (data) {
var parts = [], // html parts var def; // default choice
def; // default choice
// create a default choice and prepend it to the list // create a default choice and prepend it to the list
if (this.opts.createSearchChoice && search.val() !== "") { if (this.opts.createSearchChoice && search.val() !== "") {
@ -883,17 +850,14 @@
return; return;
} }
var htmlResult = self.opts.formatList(data.results); results.empty();
self.opts.populateResults(results, data.results);
postRender();
if (data.more === true) { if (data.more === true) {
htmlResult += "<li class='select2-more-results'>Loading more results...</li>"; results.children().filter(":last").append("<li class='select2-more-results'>Loading more results...</li>");
} }
render(htmlResult);
results.find(".select2-result").each(function () {
var d = data.map[$(this).data('select2-uid')];
$(this).data("select2-data", d);
});
this.postprocessResults(data, initial); this.postprocessResults(data, initial);
})}); })});
}, },