define( ['jquery', 'Bacon'], function($, Bacon) { function unquoted(name) { var start = 0, end = name.length; if (name.length >= 1) { if (name.charAt(0) == '"') { start = 1; if (name.length > 1 && name.charAt(name.length - 1) == '"') { end = name.length - 1; } } return name.substring(start, end); } return name; } function setCaret(e, num) { e.selectionStart = e.selectionEnd = num; } var completer = (function (input_element, dropdown, base_config) { var config = get_config(base_config), dropdown_raw = dropdown[0], options_bus = new Bacon.Bus(), options = [], selected_index = -1, input_element_raw = input_element[0], completion_start = 0, completion_end = 0, minimum_length = 1; // turn off the browser's autocomplete input_element.attr('autocomplete', 'off'); //$('.ui-autocomplete').css('width', '10px'); options_bus.onValue(function update_options(new_options) { options = new_options; }); input_element.keyup(function(e) { var ret = undefined; switch (e.keyCode) { case 38: //UP prev_option(); ret = false; break; case 40: //DOWN next_option(); ret = false; break; case 27: // Escape hide(); ret = false; break; default: // This catches cursor move due to keyboard events. no event for cursor movement itself // below we catch cursor moves due to mouse click oninput(input_element_raw.value, input_element_raw.selectionStart); } return ret; }); input_element.keydown(function(e) { switch (e.keyCode) { case 38: case 40: return false; case 9: // Tab if (config.hideOnTab) { hide(); } break; } }); function get_config(base) { return { triggerStart: base && base.triggerStart || '#', triggerEnd: base && base.triggerEnd || ' ', hideOnTab: base && base.hasOwnProperty('hideOnTab') ? base.hideOnTab : true, }; } function completions(text) { var ret = []; for (var name in options) { if (name.toLowerCase().indexOf(text.toLowerCase()) === 0) { ret.push(name); } } return ret; } function show() { if (dropdown.children().length > 0) { dropdown.show(); } } function hide() { dropdown.hide(); } /*** * #this is a # * ^ * * #this is a #t * ^ * * #this and #that then #he * ^ */ function oninput(text, cursor) { var hash = text.slice(0, cursor).lastIndexOf(config.triggerStart); // TODO check if current completion has been invalidated _invalidateSelection(); hide(); dropdown_raw.innerHTML = ""; // remove all elements if (hash == -1 && config.triggerStart != ' ') { // space matches start of string too return; } var space = text.slice(hash + 1).indexOf(config.triggerEnd); space = space == -1 ? text.length : space; if (space < cursor) { return; } completion_start = hash + 1; completion_end = space; var string = unquoted(text.slice(completion_start, completion_end)); if (string.length < minimum_length) { return; } completions(string).forEach(function(name) { var suggestion = $('