var esPhinx, Iterable; (function($) { "use strict"; $.prototype.extend({ autocomplete: function(elementsList, options, callback) { var completeOften, searchTextBox = this, nonCharacterKeysPattern = new RegExp($ .nonCharacterKeysPattern()), inline = false, elements2Recovery = [], afterAmountCharacters = options.afterAmountCharacters, complete2Recovery = function(object, times) { var i = 0; while (i++ < times) { elements2Recovery.push(object); } }, resolveArguments = function(options) { if (!Object.belongToClass(options, Object)) { options = {}; } if (typeof options.caseSensitive != "boolean") { options.caseSensitive = false; } if (typeof options.orderlySearch != "boolean") { options.orderlySearch = false; } if (typeof afterAmountCharacters != "number") { afterAmountCharacters = 1; } }, inlineSearch = function(element, options) { var eventListenerMethod, previousSearchText = searchTextBox.value(); if (typeof eventListenerMethod == "function") { searchTextBox.off("input", eventListenerMethod); } eventListenerMethod = function(e) { var resolvedList, foundElements, startingIndex, finalIndex, foundElement, previousElement = element, parent = element.clone(), searchTextLength = searchTextBox.value().length, searchTextDifference = previousSearchText.length - searchTextLength, searchTextAmount = (searchTextLength - afterAmountCharacters) + 1, replaceLast = function(object) { elements2Recovery.pop(); complete2Recovery(object); }; if (searchTextBox.value()) { startingIndex = searchTextBox.cursorPosition() - 2; if (startingIndex < 0) { startingIndex = 0; } finalIndex = startingIndex + searchTextDifference - 1; // when delete if (searchTextLength < previousSearchText.length && searchTextLength >= afterAmountCharacters) { if (startingIndex === 0) { elements2Recovery.deleteAt(startingIndex, finalIndex); } else { elements2Recovery.deleteAt(startingIndex, elements2Recovery.lastIndex()); } previousElement = elements2Recovery[ elements2Recovery.lastIndex()]; } resolvedList = resolveList(previousElement, options.order); foundElements = resolvedList.elements; if (foundElements.some() || elements2Recovery.length < searchTextAmount) { if (searchTextDifference < 0) { completeOften = Math .abs(searchTextDifference); } else { completeOften = searchTextAmount - elements2Recovery.length; } if (foundElements.some()) { foundElement = parent.append(foundElements); previousElement = foundElement; } complete2Recovery(previousElement, completeOften); } else { replaceLast(previousElement); } previousSearchText = searchTextBox.value(); callback.call($(this), foundElements, resolvedList .maps, e); } else { // reset elements2Recovery = []; previousSearchText = ""; previousElement = element; callback.call($(this), $(), e); } }; searchTextBox.on("input", eventListenerMethod); }, remoteSearch = function(options) { var word, prevText, nextText, element, URLParameters, resolvedList, clipboardData, request = function(e) { if (options.remote.URLParameters) { URLParameters = options.remote.URLParameters .call(searchTextBox); } $.Ajax.new(options.remote.url.call(searchTextBox)) .get({ URLParameters: URLParameters, progress: function(xhr) { if (options.remote.loading) { options.remote .loading(xhr, e); } }, complete: function() { $(e.target).off("keypress"); }, success: function(r) { element = $(r); if (element.some()) { completeOften = (searchTextBox .value().length - afterAmountCharacters) + 1; complete2Recovery(element, completeOften); } resolvedList = resolveList(element, options.order); callback.call(searchTextBox, resolvedList.elements, resolvedList.maps, e); if (element.length) { inlineSearch(element, options); } } }); }; searchTextBox.on("keyup", function(e) { word = searchTextBox.value(); if (word.length > afterAmountCharacters) { inline = true; } else if (word.length < afterAmountCharacters) { inline = false; } if (word.length == afterAmountCharacters && !nonCharacterKeysPattern.test(e.key) && !inline && options.remote) { $(e.target).on("keypress", function(e) { e.preventDefault(); }); request(e); } }); searchTextBox.on("paste", function(e) { word = searchTextBox.value(); prevText = word .slice(0, searchTextBox.cursorPosition()); nextText = word .slice(searchTextBox.selectionEnd(), word.length); clipboardData = e.clipboardData.getData("text"); if (word.length >= afterAmountCharacters) { inline = true; } else { inline = false; } word = prevText + clipboardData + nextText; if (word.length >= afterAmountCharacters && !inline && options.remote) { searchTextBox.value(word); request(e); e.preventDefault(); } }); }, mapIf = function(searchTextAsArray, textNodeAsArray) { var iterator, sliceIndex, regexp, textNodeHashSet = Object .asCountableLiteral(textNodeAsArray), mapped = {}, amount = 0, index = 0, previousIndex = -1, callback = function(slice) { slice = slice.trim(); index = Object.firstFromASlice(textNodeHashSet, slice, index, options .caseSensitive); if (index && ((options.orderlySearch && index > previousIndex) || !options.orderlySearch) && textNodeAsArray.countSlice(slice, options.caseSensitive) >= searchTextAsArray.amount(slice)) { previousIndex = index; if (options.caseSensitive) { regexp = new RegExp(slice); } else { regexp = new RegExp(slice, "i"); } sliceIndex = textNodeAsArray[index] .search(regexp); mapped[index] = textNodeAsArray[index] .slice(sliceIndex, sliceIndex + slice .length); Object.delete(index, textNodeHashSet); amount += 1; } else { this.finalize(); } }; if (textNodeHashSet.length >= searchTextAsArray.length) { iterator = Iterable.Proxy.new(searchTextAsArray); iterator.each(callback); if (amount == searchTextAsArray.length) { return mapped; } } return false; }, // resolveList = function(list, order = "desc") { resolveList = function(list, order) { if (order != "asc") {order = "desc";} var textNode, mapped, textNodeAsArray, sorted, found = {elements: $(), maps: []}, textBoxContentArr = searchTextBox.value().split(" ") .compact(), callback = function(element) { textNode = $(element).textContent().trim(); textNodeAsArray = textNode.split(" "); mapped = mapIf(textBoxContentArr, textNodeAsArray); if (mapped) { found.elements.push(element); found.maps.push(mapped); } }; if (list.elements().amount() == 1 && list.isA(window.Element)) { list = list.childElements().clone(true); } if (order == "desc") { sorted = list.orderTextNodeByDesc(); } else { sorted = list.orderTextNodeByAsc(); } sorted.each(callback); return found; }; resolveArguments(options); // init if (!Object.belongToClass(elementsList, Object)) { inlineSearch(elementsList, options); } else { options = elementsList; remoteSearch(options); } } }); })(esPhinx);