/* * easy-autocomplete * jQuery plugin for autocompletion * * @author Łukasz Pawełczak (http://github.com/pawelczak) * @version 1.3.5 * Copyright License: */ /* * EasyAutocomplete - Configuration */ var EasyAutocomplete = (function(scope){ scope.Configuration = function Configuration(options) { var defaults = { data: "list-required", url: "list-required", dataType: "json", listLocation: function(data) { return data; }, xmlElementName: "", getValue: function(element) { return element; }, autocompleteOff: true, placeholder: false, ajaxCallback: function() {}, matchResponseProperty: false, list: { sort: { enabled: false, method: function(a, b) { a = defaults.getValue(a); b = defaults.getValue(b); if (a < b) { return -1; } if (a > b) { return 1; } return 0; } }, maxNumberOfElements: 6, hideOnEmptyPhrase: true, match: { enabled: false, caseSensitive: false, method: function(element, phrase) { if (element.search(phrase) > -1) { return true; } else { return false; } } }, showAnimation: { type: "normal", //normal|slide|fade time: 400, callback: function() {} }, hideAnimation: { type: "normal", time: 400, callback: function() {} }, /* Events */ onClickEvent: function() {}, onSelectItemEvent: function() {}, onLoadEvent: function() {}, onChooseEvent: function() {}, onKeyEnterEvent: function() {}, onMouseOverEvent: function() {}, onMouseOutEvent: function() {}, onShowListEvent: function() {}, onHideListEvent: function() {} }, highlightPhrase: false, theme: "", cssClasses: "", minCharNumber: 0, requestDelay: 0, adjustWidth: true, ajaxSettings: {}, preparePostData: function(data, inputPhrase) {return data;}, loggerEnabled: true, template: "", categoriesAssigned: false, categories: [{ maxNumberOfElements: 4 }] }; var externalObjects = ["ajaxSettings", "template"]; this.get = function(propertyName) { return defaults[propertyName]; }; this.equals = function(name, value) { if (isAssigned(name)) { if (defaults[name] === value) { return true; } } return false; }; this.checkDataUrlProperties = function() { if (defaults.url === "list-required" && defaults.data === "list-required") { return false; } return true; }; this.checkRequiredProperties = function() { for (var propertyName in defaults) { if (defaults[propertyName] === "required") { logger.error("Option " + propertyName + " must be defined"); return false; } } return true; }; this.printPropertiesThatDoesntExist = function(consol, optionsToCheck) { printPropertiesThatDoesntExist(consol, optionsToCheck); }; prepareDefaults(); mergeOptions(); if (defaults.loggerEnabled === true) { printPropertiesThatDoesntExist(console, options); } addAjaxSettings(); processAfterMerge(); function prepareDefaults() { if (options.dataType === "xml") { if (!options.getValue) { options.getValue = function(element) { return $(element).text(); }; } if (!options.list) { options.list = {}; } if (!options.list.sort) { options.list.sort = {}; } options.list.sort.method = function(a, b) { a = options.getValue(a); b = options.getValue(b); if (a < b) { return -1; } if (a > b) { return 1; } return 0; }; if (!options.list.match) { options.list.match = {}; } options.list.match.method = function(element, phrase) { if (element.search(phrase) > -1) { return true; } else { return false; } }; } if (options.categories !== undefined && options.categories instanceof Array) { var categories = []; for (var i = 0, length = options.categories.length; i < length; i += 1) { var category = options.categories[i]; for (var property in defaults.categories[0]) { if (category[property] === undefined) { category[property] = defaults.categories[0][property]; } } categories.push(category); } options.categories = categories; } } function mergeOptions() { defaults = mergeObjects(defaults, options); function mergeObjects(source, target) { var mergedObject = source || {}; for (var propertyName in source) { if (target[propertyName] !== undefined && target[propertyName] !== null) { if (typeof target[propertyName] !== "object" || target[propertyName] instanceof Array) { mergedObject[propertyName] = target[propertyName]; } else { mergeObjects(source[propertyName], target[propertyName]); } } } /* If data is an object */ if (target.data !== undefined && target.data !== null && typeof target.data === "object") { mergedObject.data = target.data; } return mergedObject; } } function processAfterMerge() { if (defaults.url !== "list-required" && typeof defaults.url !== "function") { var defaultUrl = defaults.url; defaults.url = function() { return defaultUrl; }; } if (defaults.ajaxSettings.url !== undefined && typeof defaults.ajaxSettings.url !== "function") { var defaultUrl = defaults.ajaxSettings.url; defaults.ajaxSettings.url = function() { return defaultUrl; }; } if (typeof defaults.listLocation === "string") { var defaultlistLocation = defaults.listLocation; if (defaults.dataType.toUpperCase() === "XML") { defaults.listLocation = function(data) { return $(data).find(defaultlistLocation); }; } else { defaults.listLocation = function(data) { return data[defaultlistLocation]; }; } } if (typeof defaults.getValue === "string") { var defaultsGetValue = defaults.getValue; defaults.getValue = function(element) { return element[defaultsGetValue]; }; } if (options.categories !== undefined) { defaults.categoriesAssigned = true; } } function addAjaxSettings() { if (options.ajaxSettings !== undefined && typeof options.ajaxSettings === "object") { defaults.ajaxSettings = options.ajaxSettings; } else { defaults.ajaxSettings = {}; } } function isAssigned(name) { if (defaults[name] !== undefined && defaults[name] !== null) { return true; } else { return false; } } function printPropertiesThatDoesntExist(consol, optionsToCheck) { checkPropertiesIfExist(defaults, optionsToCheck); function checkPropertiesIfExist(source, target) { for(var property in target) { if (source[property] === undefined) { consol.log("Property '" + property + "' does not exist in EasyAutocomplete options API."); } if (typeof source[property] === "object" && $.inArray(property, externalObjects) === -1) { checkPropertiesIfExist(source[property], target[property]); } } } } }; return scope; })(EasyAutocomplete || {}); /* * EasyAutocomplete - Logger */ var EasyAutocomplete = (function(scope){ scope.Logger = function Logger() { this.error = function(message) { console.log("ERROR: " + message); }; this.warning = function(message) { console.log("WARNING: " + message); }; }; return scope; })(EasyAutocomplete || {}); /* * EasyAutocomplete - Constans */ var EasyAutocomplete = (function(scope){ scope.Constans = function Constans() { var constants = { CONTAINER_CLASS: "easy-autocomplete-container", CONTAINER_ID: "eac-container-", WRAPPER_CSS_CLASS: "easy-autocomplete" }; this.getValue = function(propertyName) { return constants[propertyName]; }; }; return scope; })(EasyAutocomplete || {}); /* * EasyAutocomplete - ListBuilderService * * @author Łukasz Pawełczak * */ var EasyAutocomplete = (function(scope) { scope.ListBuilderService = function ListBuilderService(configuration, proccessResponseData) { this.init = function(data) { var listBuilder = [], builder = {}; builder.data = configuration.get("listLocation")(data); builder.getValue = configuration.get("getValue"); builder.maxListSize = configuration.get("list").maxNumberOfElements; listBuilder.push(builder); return listBuilder; }; this.updateCategories = function(listBuilder, data) { if (configuration.get("categoriesAssigned")) { listBuilder = []; for(var i = 0; i < configuration.get("categories").length; i += 1) { var builder = convertToListBuilder(configuration.get("categories")[i], data); listBuilder.push(builder); } } return listBuilder; }; this.convertXml = function(listBuilder) { if(configuration.get("dataType").toUpperCase() === "XML") { for(var i = 0; i < listBuilder.length; i += 1) { listBuilder[i].data = convertXmlToList(listBuilder[i]); } } return listBuilder; }; this.processData = function(listBuilder, inputPhrase) { for(var i = 0, length = listBuilder.length; i < length; i+=1) { listBuilder[i].data = proccessResponseData(configuration, listBuilder[i], inputPhrase); } return listBuilder; }; this.checkIfDataExists = function(listBuilders) { for(var i = 0, length = listBuilders.length; i < length; i += 1) { if (listBuilders[i].data !== undefined && listBuilders[i].data instanceof Array) { if (listBuilders[i].data.length > 0) { return true; } } } return false; }; function convertToListBuilder(category, data) { var builder = {}; if(configuration.get("dataType").toUpperCase() === "XML") { builder = convertXmlToListBuilder(); } else { builder = convertDataToListBuilder(); } if (category.header !== undefined) { builder.header = category.header; } if (category.maxNumberOfElements !== undefined) { builder.maxNumberOfElements = category.maxNumberOfElements; } if (configuration.get("list").maxNumberOfElements !== undefined) { builder.maxListSize = configuration.get("list").maxNumberOfElements; } if (category.getValue !== undefined) { if (typeof category.getValue === "string") { var defaultsGetValue = category.getValue; builder.getValue = function(element) { return element[defaultsGetValue]; }; } else if (typeof category.getValue === "function") { builder.getValue = category.getValue; } } else { builder.getValue = configuration.get("getValue"); } return builder; function convertXmlToListBuilder() { var builder = {}, listLocation; if (category.xmlElementName !== undefined) { builder.xmlElementName = category.xmlElementName; } if (category.listLocation !== undefined) { listLocation = category.listLocation; } else if (configuration.get("listLocation") !== undefined) { listLocation = configuration.get("listLocation"); } if (listLocation !== undefined) { if (typeof listLocation === "string") { builder.data = $(data).find(listLocation); } else if (typeof listLocation === "function") { builder.data = listLocation(data); } } else { builder.data = data; } return builder; } function convertDataToListBuilder() { var builder = {}; if (category.listLocation !== undefined) { if (typeof category.listLocation === "string") { builder.data = data[category.listLocation]; } else if (typeof category.listLocation === "function") { builder.data = category.listLocation(data); } } else { builder.data = data; } return builder; } } function convertXmlToList(builder) { var simpleList = []; if (builder.xmlElementName === undefined) { builder.xmlElementName = configuration.get("xmlElementName"); } $(builder.data).find(builder.xmlElementName).each(function() { simpleList.push(this); }); return simpleList; } }; return scope; })(EasyAutocomplete || {}); /* * EasyAutocomplete - Data proccess module * * Process list to display: * - sort * - decrease number to specific number * - show only matching list * */ var EasyAutocomplete = (function(scope) { scope.proccess = function proccessData(config, listBuilder, phrase) { scope.proccess.match = match; var list = listBuilder.data, inputPhrase = phrase;//TODO REFACTOR list = findMatch(list, inputPhrase); list = reduceElementsInList(list); list = sort(list); return list; function findMatch(list, phrase) { var preparedList = [], value = ""; if (config.get("list").match.enabled) { for(var i = 0, length = list.length; i < length; i += 1) { value = config.get("getValue")(list[i]); if (match(value, phrase)) { preparedList.push(list[i]); } } } else { preparedList = list; } return preparedList; } function match(value, phrase) { if (!config.get("list").match.caseSensitive) { if (typeof value === "string") { value = value.toLowerCase(); } phrase = phrase.toLowerCase(); } if (config.get("list").match.method(value, phrase)) { return true; } else { return false; } } function reduceElementsInList(list) { if (listBuilder.maxNumberOfElements !== undefined && list.length > listBuilder.maxNumberOfElements) { list = list.slice(0, listBuilder.maxNumberOfElements); } return list; } function sort(list) { if (config.get("list").sort.enabled) { list.sort(config.get("list").sort.method); } return list; } }; return scope; })(EasyAutocomplete || {}); /* * EasyAutocomplete - Template * * * */ var EasyAutocomplete = (function(scope){ scope.Template = function Template(options) { var genericTemplates = { basic: { type: "basic", method: function(element) { return element; }, cssClass: "" }, description: { type: "description", fields: { description: "description" }, method: function(element) { return element + " - description"; }, cssClass: "eac-description" }, iconLeft: { type: "iconLeft", fields: { icon: "" }, method: function(element) { return element; }, cssClass: "eac-icon-left" }, iconRight: { type: "iconRight", fields: { iconSrc: "" }, method: function(element) { return element; }, cssClass: "eac-icon-right" }, links: { type: "links", fields: { link: "" }, method: function(element) { return element; }, cssClass: "" }, custom: { type: "custom", method: function() {}, cssClass: "" } }, /* * Converts method with {{text}} to function */ convertTemplateToMethod = function(template) { var _fields = template.fields, buildMethod; if (template.type === "description") { buildMethod = genericTemplates.description.method; if (typeof _fields.description === "string") { buildMethod = function(elementValue, element) { return elementValue + " - " + element[_fields.description] + ""; }; } else if (typeof _fields.description === "function") { buildMethod = function(elementValue, element) { return elementValue + " - " + _fields.description(element) + ""; }; } return buildMethod; } if (template.type === "iconRight") { if (typeof _fields.iconSrc === "string") { buildMethod = function(elementValue, element) { return elementValue + "" ; }; } else if (typeof _fields.iconSrc === "function") { buildMethod = function(elementValue, element) { return elementValue + "" ; }; } return buildMethod; } if (template.type === "iconLeft") { if (typeof _fields.iconSrc === "string") { buildMethod = function(elementValue, element) { return "" + elementValue; }; } else if (typeof _fields.iconSrc === "function") { buildMethod = function(elementValue, element) { return "" + elementValue; }; } return buildMethod; } if(template.type === "links") { if (typeof _fields.link === "string") { buildMethod = function(elementValue, element) { return "" + elementValue + ""; }; } else if (typeof _fields.link === "function") { buildMethod = function(elementValue, element) { return "" + elementValue + ""; }; } return buildMethod; } if (template.type === "custom") { return template.method; } return genericTemplates.basic.method; }, prepareBuildMethod = function(options) { if (!options || !options.type) { return genericTemplates.basic.method; } if (options.type && genericTemplates[options.type]) { return convertTemplateToMethod(options); } else { return genericTemplates.basic.method; } }, templateClass = function(options) { var emptyStringFunction = function() {return "";}; if (!options || !options.type) { return emptyStringFunction; } if (options.type && genericTemplates[options.type]) { return (function () { var _cssClass = genericTemplates[options.type].cssClass; return function() { return _cssClass;}; })(); } else { return emptyStringFunction; } }; this.getTemplateClass = templateClass(options); this.build = prepareBuildMethod(options); }; return scope; })(EasyAutocomplete || {}); /* * EasyAutocomplete - jQuery plugin for autocompletion * */ var EasyAutocomplete = (function(scope) { scope.main = function Core($input, options) { var module = { name: "EasyAutocomplete", shortcut: "eac" }; var consts = new scope.Constans(), config = new scope.Configuration(options), logger = new scope.Logger(), template = new scope.Template(options.template), listBuilderService = new scope.ListBuilderService(config, scope.proccess), checkParam = config.equals, $field = $input, $container = "", elementsList = [], selectedElement = -1, requestDelayTimeoutId; scope.consts = consts; this.getConstants = function() { return consts; }; this.getConfiguration = function() { return config; }; this.getContainer = function() { return $container; }; this.getSelectedItemIndex = function() { return selectedElement; }; this.getItems = function () { return elementsList; }; this.getItemData = function(index) { if (elementsList.length < index || elementsList[index] === undefined) { return -1; } else { return elementsList[index]; } }; this.getSelectedItemData = function() { return this.getItemData(selectedElement); }; this.build = function() { prepareField(); }; this.init = function() { init(); }; function init() { if ($field.length === 0) { logger.error("Input field doesn't exist."); return; } if (!config.checkDataUrlProperties()) { logger.error("One of options variables 'data' or 'url' must be defined."); return; } if (!config.checkRequiredProperties()) { logger.error("Will not work without mentioned properties."); return; } prepareField(); bindEvents(); } function prepareField() { if ($field.parent().hasClass(consts.getValue("WRAPPER_CSS_CLASS"))) { removeContainer(); removeWrapper(); } createWrapper(); createContainer(); $container = $("#" + getContainerId()); if (config.get("placeholder")) { $field.attr("placeholder", config.get("placeholder")); } function createWrapper() { var $wrapper = $("
"), classes = consts.getValue("WRAPPER_CSS_CLASS"); if (config.get("theme") && config.get("theme") !== "") { classes += " eac-" + config.get("theme"); } if (config.get("cssClasses") && config.get("cssClasses") !== "") { classes += " " + config.get("cssClasses"); } if (template.getTemplateClass() !== "") { classes += " " + template.getTemplateClass(); } $wrapper .addClass(classes); $field.wrap($wrapper); if (config.get("adjustWidth") === true) { adjustWrapperWidth(); } } function adjustWrapperWidth() { var fieldWidth = $field.outerWidth(); $field.parent().css("width", fieldWidth); } function removeWrapper() { $field.unwrap(); } function createContainer() { var $elements_container = $("
").addClass(consts.getValue("CONTAINER_CLASS")); if (getContainerId() == 'eac-container-main_search2') { $elements_container .attr("id", getContainerId()) .prepend($("