summaryrefslogtreecommitdiff
path: root/scripts/autocomplete.js
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/autocomplete.js')
-rw-r--r--scripts/autocomplete.js233
1 files changed, 233 insertions, 0 deletions
diff --git a/scripts/autocomplete.js b/scripts/autocomplete.js
new file mode 100644
index 00000000..24396ea5
--- /dev/null
+++ b/scripts/autocomplete.js
@@ -0,0 +1,233 @@
+/*
+ * autocompleteTrigger (based on jQuery-UI Autocomplete)
+ * https://github.com/experteer/autocompleteTrigger
+ *
+ * Copyright 2013, Experteer GmbH, Munich
+ *
+ * @version: 1.4
+ * @author <a href="mailto:daniel.mattes@experteer.com">Daniel Mattes</a>
+ *
+ * @requires jQuery 1.6> and jQuery-Ui (including Autocomplete) 1.8>
+ * @requires https://github.com/accursoft/caret
+ *
+ * @description
+ * autocompleteTrigger allows you to specify a trigger (e. g. @ like twitter or facebook) and bind it to a textarea or input text field.
+ * If a user writes the trigger-sign into the textbox, the autocomplete dialog will displayed and the text after the trigger-sign
+ * will be used as search-query for the autocomplete options. If one of the suggested items will be selected, the value and trigger
+ * will be added to the textfield.
+ *
+ * Thanks to https://github.com/kof/fieldSelection (getCursorPosition) and
+ * http://stackoverflow.com/questions/4564378/jquery-autocomplete-plugin-that-triggers-after-token
+ *
+ * Dual licensed under MIT or GPLv2 licenses
+ * http://en.wikipedia.org/wiki/MIT_License
+ * http://en.wikipedia.org/wiki/GNU_General_Public_License
+ *
+ * @example
+ * $('input').autocompleteTrigger({
+ * triggerStart : '@',
+ * triggerEnd: '',
+ * source: [
+ "Asp",
+ "BASIC",
+ "COBOL",
+ "ColdFusion",
+ "Erlang",
+ "Fortran",
+ "Groovy",
+ "Java",
+ "JavaScript",
+ "Lisp",
+ "Perl",
+ "PHP",
+ "Python",
+ "Ruby",
+ "Scala",
+ "Scheme"
+ ]
+ * });
+ */
+
+;
+(function ($, window, document, undefined) {
+ $.widget("ui.autocompleteTrigger", {
+
+ //Options to be used as defaults
+ options: {
+ triggerStart: "%{",
+ triggerEnd: "}"
+ },
+
+
+ _create: function () {
+ this.triggered = false;
+
+ this.element.autocomplete($.extend({
+
+ search: function () {
+ /**
+ * @description only make a request and suggest items if acTrigger.triggered is true
+ */
+ var acTrigger = $(this).data("autocompleteTrigger") || $(this).data("uiAutocompleteTrigger");
+
+ return acTrigger.triggered;
+ },
+ select: function (event, ui) {
+ /**
+ * @description if a item is selected, insert the value between triggerStart and triggerEnd
+ */
+ var acTrigger = $(this).data("autocompleteTrigger") || $(this).data("uiAutocompleteTrigger");
+ var trigger = acTrigger.options.triggerStart;
+ var cursorPosition = acTrigger.getCursorPosition();
+
+ if ($(this).is('input,textarea')) {
+ var text = $(this).val();
+ var lastTriggerPosition = text.substring(0, cursorPosition).lastIndexOf(trigger);
+ var firstTextPart = text.substring(0, lastTriggerPosition + trigger.length) +
+ ui.item.value +
+ acTrigger.options.triggerEnd;
+ $(this).val(firstTextPart + text.substring(cursorPosition, text.length));
+ acTrigger.setCursorPosition(firstTextPart.length);
+ } else {
+
+ var text = $(this).text();
+ var html = $(this).html();
+
+ var searchTerm = text.substring(0, cursorPosition);
+
+ var i = 0;
+ var index = 0;
+ while (i < searchTerm.length) {
+ index = html.lastIndexOf(searchTerm.substring(i));
+ if (index != -1) {
+ break;
+ }
+ i++;
+ }
+// console.log({html: html, index: index, searchTerm: searchTerm.substring(i) })
+
+ var htmlCursorPosition = index + searchTerm.substring(i).length;
+ var htmlLastTriggerPosition = html.substring(0, htmlCursorPosition).lastIndexOf(trigger);
+ var htmlFirstTextPart = html.substring(0, htmlLastTriggerPosition + trigger.length) +
+ ui.item.value +
+ acTrigger.options.triggerEnd;
+// console.log({htmlCursorPosition: htmlCursorPosition, htmlLastTriggerPosition: htmlLastTriggerPosition, htmlFirstTextPart: htmlFirstTextPart })
+
+ // necessary to set cursor position
+ var lastTriggerPosition = text.substring(0, cursorPosition).lastIndexOf(trigger);
+ var firstTextPart = text.substring(0, lastTriggerPosition + trigger.length) +
+ ui.item.value +
+ acTrigger.options.triggerEnd;
+// console.log({lastTriggerPosition: lastTriggerPosition, firstTextPart: firstTextPart, length: firstTextPart.length})
+
+ $(this).html(htmlFirstTextPart + html.substring(htmlCursorPosition, html.length));
+ acTrigger.setCursorPosition(firstTextPart.length);
+ }
+
+ acTrigger.triggered = false;
+ return false;
+ },
+ focus: function () {
+ /**
+ * @description prevent to replace the hole text, if a item is hovered
+ */
+
+ return false;
+ },
+ minLength: 0
+ }, this.options))
+
+ .bind("keyup", function (event) {
+ /**
+ * @description Bind to keyup-events to detect text changes.
+ * If the trigger is found before the cursor, autocomplete will be called
+ */
+ var widget = $(this);
+ var acTrigger = $(this).data("autocompleteTrigger") || $(this).data("uiAutocompleteTrigger");
+ var delay = typeof acTrigger.options.delay === 'undefined' ? 0 : acTrigger.options.delay;
+
+ if (event.keyCode != $.ui.keyCode.UP && event.keyCode != $.ui.keyCode.DOWN) {
+
+ if ($(this).is('input,textarea')) {
+ var text = $(this).val();
+ } else {
+ var text = $(this).text();
+ }
+
+ acTrigger.textValue = text;
+ if (typeof acTrigger.locked === 'undefined') {
+ acTrigger.locked = false;
+ }
+
+ if (!acTrigger.locked) {
+ acTrigger.locked = true;
+ acTrigger.timeout = setTimeout(function () {
+ acTrigger.launchAutocomplete(acTrigger, widget);
+ }, delay);
+ }
+ }
+
+ });
+ },
+
+ /**
+ * @description Destroy an instantiated plugin and clean up modifications the widget has made to the DOM
+ */
+ destroy: function () {
+
+ // this.element.removeStuff();
+ // For UI 1.8, destroy must be invoked from the
+ // base widget
+ $.Widget.prototype.destroy.call(this);
+ // For UI 1.9, define _destroy instead and don't
+ // worry about
+ // calling the base widget
+ },
+
+ /**
+ * @description calculates the the current cursor position in the bound textfield, area,...
+ * @returns {int} the position of the cursor.
+ */
+ getCursorPosition: function () {
+ var elem = this.element[0];
+ return jQuery(elem).caret();
+ },
+
+ /**
+ * @description set the position of the cursor in a textfield, area,...
+ */
+ setCursorPosition: function (position) {
+ var elem = this.element[0];
+ return jQuery(elem).caret(position);
+ },
+
+ launchAutocomplete: function (acTrigger, widget) {
+ acTrigger.locked = false;
+ var text = acTrigger.textValue;
+ var textLength = text.length;
+ var cursorPosition = acTrigger.getCursorPosition();
+ var lastString;
+ var query;
+ var lastTriggerPosition;
+ var trigger = acTrigger.options.triggerStart;
+ var triggerEnd = acTrigger.options.triggerEnd;
+
+ lastTriggerPosition = text.substring(0, cursorPosition).lastIndexOf(trigger);
+ lastTriggerEndPosition = text.substring(0, cursorPosition).lastIndexOf(triggerEnd);
+
+// console.log('autocomplete: '+text+", lastTriggerPosition: "+lastTriggerPosition+", lastTriggerEndPosition: "+lastTriggerEndPosition + ", cursorPosition: "+cursorPosition);
+ if ((lastTriggerEndPosition < lastTriggerPosition || textLength >= trigger.length) && lastTriggerPosition != -1) {
+ query = text.substring(lastTriggerPosition + trigger.length, cursorPosition);
+// console.log('query '+query);
+ acTrigger.triggered = true;
+ widget.autocomplete("search", query);
+ } else {
+ acTrigger.triggered = false;
+ widget.autocomplete("close");
+ }
+
+ }
+
+
+ });
+})(jQuery, window, document); \ No newline at end of file