summaryrefslogtreecommitdiff
path: root/src/view
diff options
context:
space:
mode:
authorAlon Levy <alon@pobox.com>2014-12-05 20:17:46 +0200
committerAlon Levy <alon@pobox.com>2014-12-05 20:39:53 +0200
commitc53dce9f564b3d8bcb712f3047d48a700ad2f82d (patch)
tree9af17877f2f6e45654b4e04e2372f5990f96a764 /src/view
parentf5569e0b4d0fa21999e1be6334cd25dd67f5d86b (diff)
replace jquery.autocomplete with our own autocompletion
Missing: - handling dropdown in the middle of the sentence correctly (almost there, extra space added) - clicking changes focus (transition event related?) and .focus() doesn't work - could not find how to fix it.
Diffstat (limited to 'src/view')
-rw-r--r--src/view/completer.js167
-rw-r--r--src/view/node_info.js4
2 files changed, 169 insertions, 2 deletions
diff --git a/src/view/completer.js b/src/view/completer.js
new file mode 100644
index 00000000..ce848eff
--- /dev/null
+++ b/src/view/completer.js
@@ -0,0 +1,167 @@
+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) {
+ var triggerStart = '#',
+ triggerEnd = '',
+ 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;
+
+ // 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;
+ });
+
+ function completions(text)
+ {
+ var ret = [],
+ noquotes = unquoted(text);
+
+ for (var name in options) {
+ if (name.toLowerCase().indexOf(noquotes) === 0) {
+ ret.push(name);
+ }
+ }
+ return ret;
+ }
+
+ function oninput(text, cursor) {
+ // #this is a #
+ // ^
+ //
+ // #this is a #t
+ // ^
+ //
+ // #this and #that then #he
+ // ^
+ console.log(text);
+ console.log(cursor);
+ var hash = text.slice(0, cursor).lastIndexOf('#');
+ // TODO check if current completion has been invalidated
+ _invalidateSelection();
+ dropdown_raw.innerHTML = ""; // remove all elements
+ if (hash == -1) {
+ return;
+ }
+ var space = text.slice(hash).indexOf(' ');
+ space = space == -1 ? text.length : space;
+ if (space < cursor) {
+ return;
+ }
+ // [hash] [cursor] [space/end]
+ completions(text.slice(hash + 1, space)).forEach(function(name) {
+ dropdown.append($('<div>' + name + '</div>'));
+ dropdown.children().each(function (index, elem) {
+ elem.onclick = function() { _applySuggestion(index); };
+ input_element.focus();
+ });
+ });
+ completion_start = hash + 1;
+ completion_end = space;
+ }
+
+ function _invalidateSelection() {
+ update_highlighting(-1);
+ }
+
+ function move_option(change, default_value) {
+ var next,
+ n = dropdown.children().length;
+
+ if (n == 0) {
+ return;
+ }
+ if (selected_index == -1) {
+ next = default_value;
+ } else {
+ next = (selected_index + change) % n;
+ }
+ update_highlighting(next);
+ }
+ function next_option() {
+ move_option(1, 0);
+ }
+ function prev_option() {
+ move_option(-1, dropdown.children().length);
+ }
+ function _get_option(index) {
+ return dropdown.children()[index].innerHTML;
+ }
+ function _choice(i) {
+ return dropdown.children().eq(i);
+ }
+ function update_highlighting(new_index) {
+ if (selected_index != -1) {
+ _choice(selected_index).removeClass('selected');
+ }
+ if (new_index != -1) {
+ _choice(new_index).addClass('selected');
+ }
+ selected_index = new_index;
+ }
+ function _applySuggestion(index) {
+ var cur = input_element.val(),
+ start = cur.slice(0, completion_start) + _get_option(index) + ' ';
+ input_element.val(start + cur.slice(completion_end));
+ setCaret(input_element, start.length);
+ oninput('', 0);
+ }
+ function handleEnter() {
+ if (selected_index == -1) {
+ return false;
+ }
+ _applySuggestion(selected_index);
+ return true;
+ }
+
+ return {
+ options: options_bus,
+ hide: function() {
+ console.log('hide');
+ dropdown.hide();
+ },
+ show: function() {
+ console.log('show');
+ dropdown.show();
+ },
+ oninput: oninput,
+ next_option: next_option,
+ prev_option: prev_option,
+ handleEnter: handleEnter,
+ };
+});
+
+return completer;
+
+});
diff --git a/src/view/node_info.js b/src/view/node_info.js
index f798b387..55d7ac72 100644
--- a/src/view/node_info.js
+++ b/src/view/node_info.js
@@ -1,5 +1,5 @@
-define(['jquery', 'view/helpers', 'view/internal'],
-function($, view_helpers, internal) {
+define(['jquery', 'datepicker', 'view/helpers', 'view/internal'],
+function($, _unused_datepicker, view_helpers, internal) {
function show(d) {
var editURL = '';