Файл: templates/frontend/dark-orange/js/jquery.easy-autocomplete.js
Строк: 1518
<?php
/*
 * 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);
?>