1624 lines
35 KiB
JavaScript
Executable File
1624 lines
35 KiB
JavaScript
Executable File
/*
|
|
* 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: true,
|
|
|
|
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 + " - <span>" + element[_fields.description] + "</span>";
|
|
};
|
|
} else if (typeof _fields.description === "function") {
|
|
buildMethod = function(elementValue, element) {
|
|
return elementValue + " - <span>" + _fields.description(element) + "</span>";
|
|
};
|
|
}
|
|
|
|
return buildMethod;
|
|
}
|
|
|
|
if (template.type === "iconRight") {
|
|
|
|
if (typeof _fields.iconSrc === "string") {
|
|
buildMethod = function(elementValue, element) {
|
|
return elementValue + "<img class='eac-icon' src='" + element[_fields.iconSrc] + "' />" ;
|
|
};
|
|
} else if (typeof _fields.iconSrc === "function") {
|
|
buildMethod = function(elementValue, element) {
|
|
return elementValue + "<img class='eac-icon' src='" + _fields.iconSrc(element) + "' />" ;
|
|
};
|
|
}
|
|
|
|
return buildMethod;
|
|
}
|
|
|
|
|
|
if (template.type === "iconLeft") {
|
|
|
|
if (typeof _fields.iconSrc === "string") {
|
|
buildMethod = function(elementValue, element) {
|
|
return "<img class='eac-icon' src='" + element[_fields.iconSrc] + "' />" + elementValue;
|
|
};
|
|
} else if (typeof _fields.iconSrc === "function") {
|
|
buildMethod = function(elementValue, element) {
|
|
return "<img class='eac-icon' src='" + _fields.iconSrc(element) + "' />" + elementValue;
|
|
};
|
|
}
|
|
|
|
return buildMethod;
|
|
}
|
|
|
|
if(template.type === "links") {
|
|
|
|
if (typeof _fields.link === "string") {
|
|
buildMethod = function(elementValue, element) {
|
|
return "<a href='" + element[_fields.link] + "' >" + elementValue + "</a>";
|
|
};
|
|
} else if (typeof _fields.link === "function") {
|
|
buildMethod = function(elementValue, element) {
|
|
return "<a href='" + _fields.link(element) + "' >" + elementValue + "</a>";
|
|
};
|
|
}
|
|
|
|
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 = $("<div>"),
|
|
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 = $("<div>").addClass(consts.getValue("CONTAINER_CLASS"));
|
|
|
|
$elements_container
|
|
.attr("id", getContainerId())
|
|
.prepend($("<ul>"));
|
|
|
|
|
|
(function() {
|
|
|
|
$elements_container
|
|
/* List show animation */
|
|
.on("show.eac", function() {
|
|
|
|
switch(config.get("list").showAnimation.type) {
|
|
|
|
case "slide":
|
|
var animationTime = config.get("list").showAnimation.time,
|
|
callback = config.get("list").showAnimation.callback;
|
|
|
|
$elements_container.find("ul").slideDown(animationTime, callback);
|
|
break;
|
|
|
|
case "fade":
|
|
var animationTime = config.get("list").showAnimation.time,
|
|
callback = config.get("list").showAnimation.callback;
|
|
|
|
$elements_container.find("ul").fadeIn(animationTime), callback;
|
|
break;
|
|
|
|
default:
|
|
$elements_container.find("ul").show();
|
|
break;
|
|
}
|
|
|
|
config.get("list").onShowListEvent();
|
|
|
|
})
|
|
/* List hide animation */
|
|
.on("hide.eac", function() {
|
|
|
|
switch(config.get("list").hideAnimation.type) {
|
|
|
|
case "slide":
|
|
var animationTime = config.get("list").hideAnimation.time,
|
|
callback = config.get("list").hideAnimation.callback;
|
|
|
|
$elements_container.find("ul").slideUp(animationTime, callback);
|
|
break;
|
|
|
|
case "fade":
|
|
var animationTime = config.get("list").hideAnimation.time,
|
|
callback = config.get("list").hideAnimation.callback;
|
|
|
|
$elements_container.find("ul").fadeOut(animationTime, callback);
|
|
break;
|
|
|
|
default:
|
|
$elements_container.find("ul").hide();
|
|
break;
|
|
}
|
|
|
|
config.get("list").onHideListEvent();
|
|
|
|
})
|
|
.on("selectElement.eac", function() {
|
|
$elements_container.find("ul li").removeClass("selected");
|
|
$elements_container.find("ul li").eq(selectedElement).addClass("selected");
|
|
|
|
config.get("list").onSelectItemEvent();
|
|
})
|
|
.on("loadElements.eac", function(event, listBuilders, phrase) {
|
|
|
|
|
|
var $item = "",
|
|
$listContainer = $elements_container.find("ul");
|
|
|
|
$listContainer
|
|
.empty()
|
|
.detach();
|
|
|
|
elementsList = [];
|
|
var counter = 0;
|
|
for(var builderIndex = 0, listBuildersLength = listBuilders.length; builderIndex < listBuildersLength; builderIndex += 1) {
|
|
|
|
var listData = listBuilders[builderIndex].data;
|
|
|
|
if (listData.length === 0) {
|
|
continue;
|
|
}
|
|
|
|
if (listBuilders[builderIndex].header !== undefined && listBuilders[builderIndex].header.length > 0) {
|
|
$listContainer.append("<div class='eac-category' >" + listBuilders[builderIndex].header + "</div>");
|
|
}
|
|
|
|
for(var i = 0, listDataLength = listData.length; i < listDataLength && counter < listBuilders[builderIndex].maxListSize; i += 1) {
|
|
$item = $("<li><div class='eac-item'></div></li>");
|
|
|
|
|
|
(function() {
|
|
var j = i,
|
|
itemCounter = counter,
|
|
elementsValue = listBuilders[builderIndex].getValue(listData[j]);
|
|
|
|
$item.find(" > div")
|
|
.on("click", function() {
|
|
|
|
$field.val(elementsValue).trigger("change");
|
|
|
|
selectedElement = itemCounter;
|
|
selectElement(itemCounter);
|
|
|
|
config.get("list").onClickEvent();
|
|
config.get("list").onChooseEvent();
|
|
})
|
|
.mouseover(function() {
|
|
|
|
selectedElement = itemCounter;
|
|
selectElement(itemCounter);
|
|
|
|
config.get("list").onMouseOverEvent();
|
|
})
|
|
.mouseout(function() {
|
|
config.get("list").onMouseOutEvent();
|
|
})
|
|
.html(template.build(highlight(elementsValue, phrase), listData[j]));
|
|
})();
|
|
|
|
$listContainer.append($item);
|
|
elementsList.push(listData[i]);
|
|
counter += 1;
|
|
}
|
|
}
|
|
|
|
$elements_container.append($listContainer);
|
|
|
|
config.get("list").onLoadEvent();
|
|
});
|
|
|
|
})();
|
|
|
|
$field.after($elements_container);
|
|
}
|
|
|
|
function removeContainer() {
|
|
$field.next("." + consts.getValue("CONTAINER_CLASS")).remove();
|
|
}
|
|
|
|
function highlight(string, phrase) {
|
|
|
|
if(config.get("highlightPhrase") && phrase !== "") {
|
|
return highlightPhrase(string, phrase);
|
|
} else {
|
|
return string;
|
|
}
|
|
|
|
}
|
|
|
|
function escapeRegExp(str) {
|
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
|
}
|
|
|
|
function highlightPhrase(string, phrase) {
|
|
var escapedPhrase = escapeRegExp(phrase);
|
|
return (string + "").replace(new RegExp("(" + escapedPhrase + ")", "gi") , "<b>$1</b>");
|
|
}
|
|
|
|
|
|
|
|
}
|
|
function getContainerId() {
|
|
|
|
var elementId = $field.attr("id");
|
|
|
|
elementId = consts.getValue("CONTAINER_ID") + elementId;
|
|
|
|
return elementId;
|
|
}
|
|
function bindEvents() {
|
|
|
|
bindAllEvents();
|
|
|
|
|
|
function bindAllEvents() {
|
|
if (checkParam("autocompleteOff", true)) {
|
|
removeAutocomplete();
|
|
}
|
|
|
|
bindFocusOut();
|
|
bindKeyup();
|
|
bindKeydown();
|
|
bindKeypress();
|
|
bindFocus();
|
|
bindBlur();
|
|
}
|
|
|
|
function bindFocusOut() {
|
|
$field.focusout(function () {
|
|
|
|
var fieldValue = $field.val(),
|
|
phrase;
|
|
|
|
if (!config.get("list").match.caseSensitive) {
|
|
fieldValue = fieldValue.toLowerCase();
|
|
}
|
|
|
|
for (var i = 0, length = elementsList.length; i < length; i += 1) {
|
|
|
|
phrase = config.get("getValue")(elementsList[i]);
|
|
if (!config.get("list").match.caseSensitive) {
|
|
phrase = phrase.toLowerCase();
|
|
}
|
|
|
|
if (phrase === fieldValue) {
|
|
selectedElement = i;
|
|
selectElement(selectedElement);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function bindKeyup() {
|
|
$field
|
|
.off("keyup")
|
|
.keyup(function(event) {
|
|
|
|
switch(event.keyCode) {
|
|
|
|
case 27:
|
|
|
|
hideContainer();
|
|
loseFieldFocus();
|
|
break;
|
|
|
|
case 38:
|
|
|
|
event.preventDefault();
|
|
|
|
if(elementsList.length > 0 && selectedElement > 0) {
|
|
|
|
selectedElement -= 1;
|
|
|
|
$field.val(config.get("getValue")(elementsList[selectedElement]));
|
|
|
|
selectElement(selectedElement);
|
|
|
|
}
|
|
break;
|
|
|
|
case 40:
|
|
|
|
event.preventDefault();
|
|
|
|
if(elementsList.length > 0 && selectedElement < elementsList.length - 1) {
|
|
|
|
selectedElement += 1;
|
|
|
|
$field.val(config.get("getValue")(elementsList[selectedElement]));
|
|
|
|
selectElement(selectedElement);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (event.keyCode > 40 || event.keyCode === 8) {
|
|
|
|
var inputPhrase = $field.val();
|
|
|
|
if (!(config.get("list").hideOnEmptyPhrase === true && event.keyCode === 8 && inputPhrase === "")) {
|
|
|
|
if (config.get("requestDelay") > 0) {
|
|
if (requestDelayTimeoutId !== undefined) {
|
|
clearTimeout(requestDelayTimeoutId);
|
|
}
|
|
|
|
requestDelayTimeoutId = setTimeout(function () { loadData(inputPhrase);}, config.get("requestDelay"));
|
|
} else {
|
|
loadData(inputPhrase);
|
|
}
|
|
|
|
} else {
|
|
hideContainer();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
function loadData(inputPhrase) {
|
|
|
|
|
|
if (inputPhrase.length < config.get("minCharNumber")) {
|
|
return;
|
|
}
|
|
|
|
|
|
if (config.get("data") !== "list-required") {
|
|
|
|
var data = config.get("data");
|
|
|
|
var listBuilders = listBuilderService.init(data);
|
|
|
|
listBuilders = listBuilderService.updateCategories(listBuilders, data);
|
|
|
|
listBuilders = listBuilderService.processData(listBuilders, inputPhrase);
|
|
|
|
loadElements(listBuilders, inputPhrase);
|
|
|
|
if ($field.parent().find("li").length > 0) {
|
|
showContainer();
|
|
} else {
|
|
hideContainer();
|
|
}
|
|
|
|
}
|
|
|
|
var settings = createAjaxSettings();
|
|
|
|
if (settings.url === undefined || settings.url === "") {
|
|
settings.url = config.get("url");
|
|
}
|
|
|
|
if (settings.dataType === undefined || settings.dataType === "") {
|
|
settings.dataType = config.get("dataType");
|
|
}
|
|
|
|
|
|
if (settings.url !== undefined && settings.url !== "list-required") {
|
|
|
|
settings.url = settings.url(inputPhrase);
|
|
|
|
settings.data = config.get("preparePostData")(settings.data, inputPhrase);
|
|
|
|
$.ajax(settings)
|
|
.done(function(data) {
|
|
|
|
var listBuilders = listBuilderService.init(data);
|
|
|
|
listBuilders = listBuilderService.updateCategories(listBuilders, data);
|
|
|
|
listBuilders = listBuilderService.convertXml(listBuilders);
|
|
if (checkInputPhraseMatchResponse(inputPhrase, data)) {
|
|
|
|
listBuilders = listBuilderService.processData(listBuilders, inputPhrase);
|
|
|
|
loadElements(listBuilders, inputPhrase);
|
|
|
|
}
|
|
|
|
if (listBuilderService.checkIfDataExists(listBuilders) && $field.parent().find("li").length > 0) {
|
|
showContainer();
|
|
} else {
|
|
hideContainer();
|
|
}
|
|
|
|
config.get("ajaxCallback")();
|
|
|
|
})
|
|
.fail(function() {
|
|
logger.warning("Fail to load response data");
|
|
})
|
|
.always(function() {
|
|
|
|
});
|
|
}
|
|
|
|
|
|
|
|
function createAjaxSettings() {
|
|
|
|
var settings = {},
|
|
ajaxSettings = config.get("ajaxSettings") || {};
|
|
|
|
for (var set in ajaxSettings) {
|
|
settings[set] = ajaxSettings[set];
|
|
}
|
|
|
|
return settings;
|
|
}
|
|
|
|
function checkInputPhraseMatchResponse(inputPhrase, data) {
|
|
|
|
if (config.get("matchResponseProperty") !== false) {
|
|
if (typeof config.get("matchResponseProperty") === "string") {
|
|
return (data[config.get("matchResponseProperty")] === inputPhrase);
|
|
}
|
|
|
|
if (typeof config.get("matchResponseProperty") === "function") {
|
|
return (config.get("matchResponseProperty")(data) === inputPhrase);
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
});
|
|
}
|
|
|
|
function bindKeydown() {
|
|
$field
|
|
.on("keydown", function(evt) {
|
|
evt = evt || window.event;
|
|
var keyCode = evt.keyCode;
|
|
if (keyCode === 38) {
|
|
suppressKeypress = true;
|
|
return false;
|
|
}
|
|
})
|
|
.keydown(function(event) {
|
|
|
|
if (event.keyCode === 13 && selectedElement > -1) {
|
|
|
|
$field.val(config.get("getValue")(elementsList[selectedElement]));
|
|
|
|
config.get("list").onKeyEnterEvent();
|
|
config.get("list").onChooseEvent();
|
|
|
|
selectedElement = -1;
|
|
hideContainer();
|
|
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
}
|
|
|
|
function bindKeypress() {
|
|
$field
|
|
.off("keypress");
|
|
}
|
|
|
|
function bindFocus() {
|
|
$field.focus(function() {
|
|
|
|
if ($field.val() !== "" && elementsList.length > 0) {
|
|
|
|
selectedElement = -1;
|
|
showContainer();
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
function bindBlur() {
|
|
$field.blur(function() {
|
|
setTimeout(function() {
|
|
|
|
selectedElement = -1;
|
|
hideContainer();
|
|
}, 250);
|
|
});
|
|
}
|
|
|
|
function removeAutocomplete() {
|
|
$field.attr("autocomplete","off");
|
|
}
|
|
|
|
}
|
|
|
|
function showContainer() {
|
|
$container.trigger("show.eac");
|
|
}
|
|
|
|
function hideContainer() {
|
|
$container.trigger("hide.eac");
|
|
}
|
|
|
|
function selectElement(index) {
|
|
|
|
$container.trigger("selectElement.eac", index);
|
|
}
|
|
|
|
function loadElements(list, phrase) {
|
|
$container.trigger("loadElements.eac", [list, phrase]);
|
|
}
|
|
|
|
function loseFieldFocus() {
|
|
$field.trigger("blur");
|
|
}
|
|
|
|
|
|
};
|
|
scope.eacHandles = [];
|
|
|
|
scope.getHandle = function(id) {
|
|
return scope.eacHandles[id];
|
|
};
|
|
|
|
scope.inputHasId = function(input) {
|
|
|
|
if($(input).attr("id") !== undefined && $(input).attr("id").length > 0) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
scope.assignRandomId = function(input) {
|
|
|
|
var fieldId = "";
|
|
|
|
do {
|
|
fieldId = "eac-" + Math.floor(Math.random() * 10000);
|
|
} while ($("#" + fieldId).length !== 0);
|
|
|
|
elementId = scope.consts.getValue("CONTAINER_ID") + fieldId;
|
|
|
|
$(input).attr("id", fieldId);
|
|
|
|
};
|
|
|
|
scope.setHandle = function(handle, id) {
|
|
scope.eacHandles[id] = handle;
|
|
};
|
|
|
|
|
|
return scope;
|
|
|
|
})(EasyAutocomplete || {});
|
|
|
|
(function($) {
|
|
|
|
$.fn.easyAutocomplete = function(options) {
|
|
|
|
return this.each(function() {
|
|
var $this = $(this),
|
|
eacHandle = new EasyAutocomplete.main($this, options);
|
|
|
|
if (!EasyAutocomplete.inputHasId($this)) {
|
|
EasyAutocomplete.assignRandomId($this);
|
|
}
|
|
|
|
eacHandle.init();
|
|
|
|
EasyAutocomplete.setHandle(eacHandle, $this.attr("id"));
|
|
|
|
});
|
|
};
|
|
|
|
$.fn.getSelectedItemIndex = function() {
|
|
|
|
var inputId = $(this).attr("id");
|
|
|
|
if (inputId !== undefined) {
|
|
return EasyAutocomplete.getHandle(inputId).getSelectedItemIndex();
|
|
}
|
|
|
|
return -1;
|
|
};
|
|
|
|
$.fn.getItems = function () {
|
|
|
|
var inputId = $(this).attr("id");
|
|
|
|
if (inputId !== undefined) {
|
|
return EasyAutocomplete.getHandle(inputId).getItems();
|
|
}
|
|
|
|
return -1;
|
|
};
|
|
|
|
$.fn.getItemData = function(index) {
|
|
|
|
var inputId = $(this).attr("id");
|
|
|
|
if (inputId !== undefined && index > -1) {
|
|
return EasyAutocomplete.getHandle(inputId).getItemData(index);
|
|
}
|
|
|
|
return -1;
|
|
};
|
|
|
|
$.fn.getSelectedItemData = function() {
|
|
|
|
var inputId = $(this).attr("id");
|
|
|
|
if (inputId !== undefined) {
|
|
return EasyAutocomplete.getHandle(inputId).getSelectedItemData();
|
|
}
|
|
|
|
return -1;
|
|
};
|
|
|
|
})(jQuery);
|