|
@@ -3,96 +3,82 @@
|
|
|
* This object really just helps readability since we can then have
|
|
|
* a traceable namespace.
|
|
|
*/
|
|
|
-var libtoaster = (function (){
|
|
|
-
|
|
|
- /* makeTypeahead parameters
|
|
|
- * elementSelector: JQuery elementSelector string
|
|
|
- * xhrUrl: the url to get the JSON from expects JSON in the form:
|
|
|
- * { "list": [ { "name": "test", "detail" : "a test thing" }, .... ] }
|
|
|
+var libtoaster = (function () {
|
|
|
+ // prevent conflicts with Bootstrap 2's typeahead (required during
|
|
|
+ // transition from v2 to v3)
|
|
|
+ var typeahead = jQuery.fn.typeahead.noConflict();
|
|
|
+ jQuery.fn._typeahead = typeahead;
|
|
|
+
|
|
|
+ /* Make a typeahead from an input element
|
|
|
+ *
|
|
|
+ * _makeTypeahead parameters
|
|
|
+ * jQElement: input element as selected by $('selector')
|
|
|
+ * xhrUrl: the url to get the JSON from; this URL should return JSON in the
|
|
|
+ * format:
|
|
|
+ * { "results": [ { "name": "test", "detail" : "a test thing" }, ... ] }
|
|
|
* xhrParams: the data/parameters to pass to the getJSON url e.g.
|
|
|
- * { 'type' : 'projects' } the text typed will be passed as 'search'.
|
|
|
- * selectedCB: function to call once an item has been selected one
|
|
|
- * arg of the item.
|
|
|
+ * { 'type' : 'projects' }; the text typed will be passed as 'search'.
|
|
|
+ * selectedCB: function to call once an item has been selected; has
|
|
|
+ * signature selectedCB(item), where item is an item in the format shown
|
|
|
+ * in the JSON list above, i.e.
|
|
|
+ * { "name": "name", "detail": "detail" }.
|
|
|
*/
|
|
|
- function _makeTypeahead (jQElement, xhrUrl, xhrParams, selectedCB) {
|
|
|
- if (!xhrUrl || xhrUrl.length === 0)
|
|
|
- throw("No url to typeahead supplied");
|
|
|
+ function _makeTypeahead(jQElement, xhrUrl, xhrParams, selectedCB) {
|
|
|
+ if (!xhrUrl || xhrUrl.length === 0) {
|
|
|
+ throw("No url supplied for typeahead");
|
|
|
+ }
|
|
|
|
|
|
var xhrReq;
|
|
|
|
|
|
- jQElement.typeahead({
|
|
|
- // each time the typeahead's choices change, a
|
|
|
- // "typeahead-choices-change" event is fired with an object
|
|
|
- // containing the available choices in a "choices" property
|
|
|
- source: function(query, process){
|
|
|
+ jQElement._typeahead(
|
|
|
+ {
|
|
|
+ highlight: true,
|
|
|
+ classNames: {
|
|
|
+ open: "dropdown-menu",
|
|
|
+ cursor: "active"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ source: function (query, syncResults, asyncResults) {
|
|
|
xhrParams.search = query;
|
|
|
|
|
|
- /* If we have a request in progress don't fire off another one*/
|
|
|
- if (xhrReq)
|
|
|
+ // if we have a request in progress, cancel it and start another
|
|
|
+ if (xhrReq) {
|
|
|
xhrReq.abort();
|
|
|
+ }
|
|
|
|
|
|
- xhrReq = $.getJSON(xhrUrl, this.options.xhrParams, function(data){
|
|
|
+ xhrReq = $.getJSON(xhrUrl, xhrParams, function (data) {
|
|
|
if (data.error !== "ok") {
|
|
|
- console.log("Error getting data from server "+data.error);
|
|
|
+ console.error("Error getting data from server: " + data.error);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
xhrReq = null;
|
|
|
|
|
|
- jQElement.trigger("typeahead-choices-change", {choices: data.results});
|
|
|
-
|
|
|
- return process(data.results);
|
|
|
+ asyncResults(data.results);
|
|
|
});
|
|
|
},
|
|
|
- updater: function(item) {
|
|
|
- var itemObj = this.$menu.find('.active').data('itemObject');
|
|
|
- selectedCB(itemObj);
|
|
|
- return item;
|
|
|
- },
|
|
|
- matcher: function(item) {
|
|
|
- if (!item.hasOwnProperty('name')) {
|
|
|
- console.log("Name property missing in data");
|
|
|
- return 0;
|
|
|
- }
|
|
|
|
|
|
- if (this.$element.val().length === 0)
|
|
|
- return 0;
|
|
|
-
|
|
|
- return 1;
|
|
|
- },
|
|
|
- highlighter: function (item) {
|
|
|
- /* Use jquery to escape the item name and detail */
|
|
|
- var current = $("<span></span>").text(item.name + ' '+item.detail);
|
|
|
- current = current.html();
|
|
|
-
|
|
|
- var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
|
|
|
- return current.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
|
|
|
- return '<strong>' + match + '</strong>'
|
|
|
- })
|
|
|
+ // how the selected item is shown in the input
|
|
|
+ display: function (item) {
|
|
|
+ return item.name;
|
|
|
},
|
|
|
- sorter: function (items) { return items; },
|
|
|
- xhrUrl: xhrUrl,
|
|
|
- xhrParams: xhrParams,
|
|
|
- xhrReq: xhrReq,
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- /* Copy of bootstrap's render func but sets selectedObject value */
|
|
|
- function customRenderFunc (items) {
|
|
|
- var that = this;
|
|
|
-
|
|
|
- items = $(items).map(function (i, item) {
|
|
|
- i = $(that.options.item).attr('data-value', item.name).data('itemObject', item);
|
|
|
- i.find('a').html(that.highlighter(item));
|
|
|
- return i[0];
|
|
|
- });
|
|
|
|
|
|
- items.first().addClass('active');
|
|
|
- this.$menu.html(items);
|
|
|
- return this;
|
|
|
- }
|
|
|
+ templates: {
|
|
|
+ // how the item is displayed in the dropdown
|
|
|
+ suggestion: function (item) {
|
|
|
+ var elt = document.createElement("div");
|
|
|
+ elt.innerHTML = item.name + " " + item.detail;
|
|
|
+ return elt;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
|
|
|
- jQElement.data('typeahead').render = customRenderFunc;
|
|
|
+ // when an item is selected using the typeahead, invoke the callback
|
|
|
+ jQElement.on("typeahead:select", function (event, item) {
|
|
|
+ selectedCB(item);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/* startABuild:
|