vendor: 34,437 bytes, lines 1-1623
1/* 2 * easy-autocomplete 3 * $ctj plugin for autocompletion 4 * 5 * @author Åukasz PaweÅczak (http://github.com/pawelczak) 6 * @version 1.3.5 7 * Copyright License: 8 */ 9 10/* 11 * EasyAutocomplete - Configuration 12 */ 13var EasyAutocomplete = (function(scope){ 14 15 scope.Configuration = function Configuration(options) { 16 var defaults = { 17 data: "list-required", 18 url: "list-required", 19 dataType: "json", 20 21 listLocation: function(data) { 22 return data; 23 }, 24 25 xmlElementName: "", 26 27 getValue: function(element) { 28 return element; 29 }, 30 31 autocompleteOff: true, 32 33 placeholder: false, 34 35 ajaxCallback: function() {}, 36 37 matchResponseProperty: false, 38 39 list: { 40 sort: { 41 enabled: false, 42 method: function(a, b) { 43 a = defaults.getValue(a); 44 b = defaults.getValue(b); 45 if (a < b) { 46 return -1; 47 } 48 if (a > b) { 49 return 1; 50 } 51 return 0; 52 } 53 }, 54 55 maxNumberOfElements: 6, 56 57 hideOnEmptyPhrase: true, 58 59 match: { 60 enabled: false, 61 caseSensitive: false, 62 method: function(element, phrase) { 63 64 if (element.search(phrase) > -1) { 65 return true; 66 } else { 67 return false; 68 } 69 } 70 }, 71 72 showAnimation: { 73 type: "normal", //normal|slide|fade 74 time: 400, 75 callback: function() {} 76 }, 77 78 hideAnimation: { 79 type: "normal", 80 time: 400, 81 callback: function() {} 82 }, 83 84 /* Events */ 85 onClickEvent: function() {}, 86 onSelectItemEvent: function() {}, 87 onLoadEvent: function() {}, 88 onChooseEvent: function() {}, 89 onKeyEnterEvent: function() {}, 90 onMouseOverEvent: function() {}, 91 onMouseOutEvent: function() {}, 92 onShowListEvent: function() {}, 93 onHideListEvent: function() {} 94 }, 95 96 highlightPhrase: true, 97 98 theme: "", 99 100 cssClasses: "", 101 102 minCharNumber: 0, 103 104 requestDelay: 0, 105 106 adjustWidth: true, 107 108 ajaxSettings: {}, 109 110 preparePostData: function(data, inputPhrase) {return data;}, 111 112 loggerEnabled: true, 113 114 template: "", 115 116 categoriesAssigned: false, 117 118 categories: [{ 119 maxNumberOfElements: 4 120 }] 121 122 }; 123 124 var externalObjects = ["ajaxSettings", "template"]; 125 126 this.get = function(propertyName) { 127 return defaults[propertyName]; 128 }; 129 130 this.equals = function(name, value) { 131 if (isAssigned(name)) { 132 if (defaults[name] === value) { 133 return true; 134 } 135 } 136 137 return false; 138 }; 139 140 this.checkDataUrlProperties = function() { 141 if (defaults.url === "list-required" && defaults.data === "list-required") { 142 return false; 143 } 144 return true; 145 }; 146 this.checkRequiredProperties = function() { 147 for (var propertyName in defaults) { 148 if (defaults[propertyName] === "required") { 149 logger.error("Option " + propertyName + " must be defined"); 150 return false; 151 } 152 } 153 return true; 154 }; 155 156 this.printPropertiesThatDoesntExist = function(consol, optionsToCheck) { 157 printPropertiesThatDoesntExist(consol, optionsToCheck); 158 }; 159 160 161 prepareDefaults(); 162 163 mergeOptions(); 164 165 if (defaults.loggerEnabled === true) { 166 printPropertiesThatDoesntExist(console, options); 167 } 168 169 addAjaxSettings(); 170 171 processAfterMerge(); 172 function prepareDefaults() { 173 174 if (options.dataType === "xml") { 175 176 if (!options.getValue) { 177 178 options.getValue = function(element) { 179 return $ctj(element).text(); 180 }; 181 } 182 183 184 if (!options.list) { 185 186 options.list = {}; 187 } 188 189 if (!options.list.sort) { 190 options.list.sort = {}; 191 } 192 193 194 options.list.sort.method = function(a, b) { 195 a = options.getValue(a); 196 b = options.getValue(b); 197 if (a < b) { 198 return -1; 199 } 200 if (a > b) { 201 return 1; 202 } 203 return 0; 204 }; 205 206 if (!options.list.match) { 207 options.list.match = {}; 208 } 209 210 options.list.match.method = function(element, phrase) { 211 212 if (element.search(phrase) > -1) { 213 return true; 214 } else { 215 return false; 216 } 217 }; 218 219 } 220 if (options.categories !== undefined && options.categories instanceof Array) { 221 222 var categories = []; 223 224 for (var i = 0, length = options.categories.length; i < length; i += 1) { 225 226 var category = options.categories[i]; 227 228 for (var property in defaults.categories[0]) { 229 230 if (category[property] === undefined) { 231 category[property] = defaults.categories[0][property]; 232 } 233 } 234 235 categories.push(category); 236 } 237 238 options.categories = categories; 239 } 240 } 241 242 function mergeOptions() { 243 244 defaults = mergeObjects(defaults, options); 245 246 function mergeObjects(source, target) { 247 var mergedObject = source || {}; 248 249 for (var propertyName in source) { 250 if (target[propertyName] !== undefined && target[propertyName] !== null) { 251 252 if (typeof target[propertyName] !== "object" || 253 target[propertyName] instanceof Array) { 254 mergedObject[propertyName] = target[propertyName]; 255 } else { 256 mergeObjects(source[propertyName], target[propertyName]); 257 } 258 } 259 } 260 261 /* If data is an object */ 262 if (target.data !== undefined && target.data !== null && typeof target.data === "object") { 263 mergedObject.data = target.data; 264 } 265 266 return mergedObject; 267 } 268 } 269 270 271 function processAfterMerge() { 272 273 if (defaults.url !== "list-required" && typeof defaults.url !== "function") { 274 var defaultUrl = defaults.url; 275 defaults.url = function() { 276 return defaultUrl; 277 }; 278 } 279 280 if (defaults.ajaxSettings.url !== undefined && typeof defaults.ajaxSettings.url !== "function") { 281 var defaultUrl = defaults.ajaxSettings.url; 282 defaults.ajaxSettings.url = function() { 283 return defaultUrl; 284 }; 285 } 286 287 if (typeof defaults.listLocation === "string") { 288 var defaultlistLocation = defaults.listLocation; 289 290 if (defaults.dataType.toUpperCase() === "XML") { 291 defaults.listLocation = function(data) { 292 return $ctj(data).find(defaultlistLocation); 293 }; 294 } else { 295 defaults.listLocation = function(data) { 296 return data[defaultlistLocation]; 297 }; 298 } 299 } 300 301 if (typeof defaults.getValue === "string") { 302 var defaultsGetValue = defaults.getValue; 303 defaults.getValue = function(element) { 304 return element[defaultsGetValue]; 305 }; 306 } 307 308 if (options.categories !== undefined) { 309 defaults.categoriesAssigned = true; 310 } 311 312 } 313 314 function addAjaxSettings() { 315 316 if (options.ajaxSettings !== undefined && typeof options.ajaxSettings === "object") { 317 defaults.ajaxSettings = options.ajaxSettings; 318 } else { 319 defaults.ajaxSettings = {}; 320 } 321 322 } 323 324 function isAssigned(name) { 325 if (defaults[name] !== undefined && defaults[name] !== null) { 326 return true; 327 } else { 328 return false; 329 } 330 } 331 function printPropertiesThatDoesntExist(consol, optionsToCheck) { 332 333 checkPropertiesIfExist(defaults, optionsToCheck); 334 335 function checkPropertiesIfExist(source, target) { 336 for(var property in target) { 337 if (source[property] === undefined) { 338 consol.log("Property '" + property + "' does not exist in EasyAutocomplete options API."); 339 } 340 341 if (typeof source[property] === "object" && $ctj.inArray(property, externalObjects) === -1) { 342 checkPropertiesIfExist(source[property], target[property]); 343 } 344 } 345 } 346 } 347 }; 348 349 return scope; 350 351})(EasyAutocomplete || {}); 352 353 354/* 355 * EasyAutocomplete - Logger 356 */ 357var EasyAutocomplete = (function(scope){ 358 359 scope.Logger = function Logger() { 360 361 this.error = function(message) { 362 console.log("ERROR: " + message); 363 }; 364 365 this.warning = function(message) { 366 console.log("WARNING: " + message); 367 }; 368 }; 369 370 return scope; 371 372})(EasyAutocomplete || {}); 373 374 375/* 376 * EasyAutocomplete - Constans 377 */ 378var EasyAutocomplete = (function(scope){ 379 380 scope.Constans = function Constans() { 381 var constants = { 382 CONTAINER_CLASS: "easy-autocomplete-container", 383 CONTAINER_ID: "eac-container-", 384 385 WRAPPER_CSS_CLASS: "easy-autocomplete" 386 }; 387 388 this.getValue = function(propertyName) { 389 return constants[propertyName]; 390 }; 391 392 }; 393 394 return scope; 395 396})(EasyAutocomplete || {}); 397 398/* 399 * EasyAutocomplete - ListBuilderService 400 * 401 * @author Åukasz PaweÅczak 402 * 403 */ 404var EasyAutocomplete = (function(scope) { 405 406 scope.ListBuilderService = function ListBuilderService(configuration, proccessResponseData) { 407 408 409 this.init = function(data) { 410 var listBuilder = [], 411 builder = {}; 412 413 builder.data = configuration.get("listLocation")(data); 414 builder.getValue = configuration.get("getValue"); 415 builder.maxListSize = configuration.get("list").maxNumberOfElements; 416 417 418 listBuilder.push(builder); 419 420 return listBuilder; 421 }; 422 423 this.updateCategories = function(listBuilder, data) { 424 425 if (configuration.get("categoriesAssigned")) { 426 427 listBuilder = []; 428 429 for(var i = 0; i < configuration.get("categories").length; i += 1) { 430 431 var builder = convertToListBuilder(configuration.get("categories")[i], data); 432 433 listBuilder.push(builder); 434 } 435 436 } 437 438 return listBuilder; 439 }; 440 441 this.convertXml = function(listBuilder) { 442 if(configuration.get("dataType").toUpperCase() === "XML") { 443 444 for(var i = 0; i < listBuilder.length; i += 1) { 445 listBuilder[i].data = convertXmlToList(listBuilder[i]); 446 } 447 } 448 449 return listBuilder; 450 }; 451 452 this.processData = function(listBuilder, inputPhrase) { 453 454 for(var i = 0, length = listBuilder.length; i < length; i+=1) { 455 listBuilder[i].data = proccessResponseData(configuration, listBuilder[i], inputPhrase); 456 } 457 458 return listBuilder; 459 }; 460 461 this.checkIfDataExists = function(listBuilders) { 462 463 for(var i = 0, length = listBuilders.length; i < length; i += 1) { 464 465 if (listBuilders[i].data !== undefined && listBuilders[i].data instanceof Array) { 466 if (listBuilders[i].data.length > 0) { 467 return true; 468 } 469 } 470 } 471 472 return false; 473 }; 474 475 476 function convertToListBuilder(category, data) { 477 478 var builder = {}; 479 480 if(configuration.get("dataType").toUpperCase() === "XML") { 481 482 builder = convertXmlToListBuilder(); 483 } else { 484 485 builder = convertDataToListBuilder(); 486 } 487 488 489 if (category.header !== undefined) { 490 builder.header = category.header; 491 } 492 493 if (category.maxNumberOfElements !== undefined) { 494 builder.maxNumberOfElements = category.maxNumberOfElements; 495 } 496 497 if (configuration.get("list").maxNumberOfElements !== undefined) { 498 499 builder.maxListSize = configuration.get("list").maxNumberOfElements; 500 } 501 502 if (category.getValue !== undefined) { 503 504 if (typeof category.getValue === "string") { 505 var defaultsGetValue = category.getValue; 506 builder.getValue = function(element) { 507 return element[defaultsGetValue]; 508 }; 509 } else if (typeof category.getValue === "function") { 510 builder.getValue = category.getValue; 511 } 512 513 } else { 514 builder.getValue = configuration.get("getValue"); 515 } 516 517 518 return builder; 519 520 521 function convertXmlToListBuilder() { 522 523 var builder = {}, 524 listLocation; 525 526 if (category.xmlElementName !== undefined) { 527 builder.xmlElementName = category.xmlElementName; 528 } 529 530 if (category.listLocation !== undefined) { 531 532 listLocation = category.listLocation; 533 } else if (configuration.get("listLocation") !== undefined) { 534 535 listLocation = configuration.get("listLocation"); 536 } 537 538 if (listLocation !== undefined) { 539 if (typeof listLocation === "string") { 540 builder.data = $ctj(data).find(listLocation); 541 } else if (typeof listLocation === "function") { 542 543 builder.data = listLocation(data); 544 } 545 } else { 546 547 builder.data = data; 548 } 549 550 return builder; 551 } 552 553 554 function convertDataToListBuilder() { 555 556 var builder = {}; 557 558 if (category.listLocation !== undefined) { 559 560 if (typeof category.listLocation === "string") { 561 builder.data = data[category.listLocation]; 562 } else if (typeof category.listLocation === "function") { 563 builder.data = category.listLocation(data); 564 } 565 } else { 566 builder.data = data; 567 } 568 569 return builder; 570 } 571 } 572 573 function convertXmlToList(builder) { 574 var simpleList = []; 575 576 if (builder.xmlElementName === undefined) { 577 builder.xmlElementName = configuration.get("xmlElementName"); 578 } 579 580 581 $ctj(builder.data).find(builder.xmlElementName).each(function() { 582 simpleList.push(this); 583 }); 584 585 return simpleList; 586 } 587 588 }; 589 590 return scope; 591 592})(EasyAutocomplete || {}); 593 594 595/* 596 * EasyAutocomplete - Data proccess module 597 * 598 * Process list to display: 599 * - sort 600 * - decrease number to specific number 601 * - show only matching list 602 * 603 */ 604var EasyAutocomplete = (function(scope) { 605 606 scope.proccess = function proccessData(config, listBuilder, phrase) { 607 608 scope.proccess.match = match; 609 610 var list = listBuilder.data, 611 inputPhrase = phrase;//TODO REFACTOR 612 613 list = findMatch(list, inputPhrase); 614 list = reduceElementsInList(list); 615 list = sort(list); 616 617 return list; 618 619 620 function findMatch(list, phrase) { 621 var preparedList = [], 622 value = ""; 623 624 if (config.get("list").match.enabled) { 625 626 for(var i = 0, length = list.length; i < length; i += 1) { 627 628 value = config.get("getValue")(list[i]); 629 630 if (match(value, phrase)) { 631 preparedList.push(list[i]); 632 } 633 634 } 635 636 } else { 637 preparedList = list; 638 } 639 640 return preparedList; 641 } 642 643 function match(value, phrase) { 644 645 if (!config.get("list").match.caseSensitive) { 646 647 if (typeof value === "string") { 648 value = value.toLowerCase(); 649 } 650 651 phrase = phrase.toLowerCase(); 652 } 653 if (config.get("list").match.method(value, phrase)) { 654 return true; 655 } else { 656 return false; 657 } 658 } 659 660 function reduceElementsInList(list) { 661 if (listBuilder.maxNumberOfElements !== undefined && list.length > listBuilder.maxNumberOfElements) { 662 list = list.slice(0, listBuilder.maxNumberOfElements); 663 } 664 665 return list; 666 } 667 668 function sort(list) { 669 if (config.get("list").sort.enabled) { 670 list.sort(config.get("list").sort.method); 671 } 672 673 return list; 674 } 675 676 }; 677 678 679 return scope; 680 681 682})(EasyAutocomplete || {}); 683 684 685/* 686 * EasyAutocomplete - Template 687 * 688 * 689 * 690 */ 691var EasyAutocomplete = (function(scope){ 692 693 scope.Template = function Template(options) { 694 695 696 var genericTemplates = { 697 basic: { 698 type: "basic", 699 method: function(element) { return element; }, 700 cssClass: "" 701 }, 702 description: { 703 type: "description", 704 fields: { 705 description: "description" 706 }, 707 method: function(element) { return element + " - description"; }, 708 cssClass: "eac-description" 709 }, 710 iconLeft: { 711 type: "iconLeft", 712 fields: { 713 icon: "" 714 }, 715 method: function(element) { 716 return element; 717 }, 718 cssClass: "eac-icon-left" 719 }, 720 iconRight: { 721 type: "iconRight", 722 fields: { 723 iconSrc: "" 724 }, 725 method: function(element) { 726 return element; 727 }, 728 cssClass: "eac-icon-right" 729 }, 730 links: { 731 type: "links", 732 fields: { 733 link: "" 734 }, 735 method: function(element) { 736 return element; 737 }, 738 cssClass: "" 739 }, 740 custom: { 741 type: "custom", 742 method: function() {}, 743 cssClass: "" 744 } 745 }, 746 747 748 749 /* 750 * Converts method with {{text}} to function 751 */ 752 convertTemplateToMethod = function(template) { 753 754 755 var _fields = template.fields, 756 buildMethod; 757 758 if (template.type === "description") { 759 760 buildMethod = genericTemplates.description.method; 761 762 if (typeof _fields.description === "string") { 763 buildMethod = function(elementValue, element) { 764 return elementValue + " - <span>" + element[_fields.description] + "</span>"; 765 }; 766 } else if (typeof _fields.description === "function") { 767 buildMethod = function(elementValue, element) { 768 return elementValue + " - <span>" + _fields.description(element) + "</span>"; 769 }; 770 } 771 772 return buildMethod; 773 } 774 775 if (template.type === "iconRight") { 776 777 if (typeof _fields.iconSrc === "string") { 778 buildMethod = function(elementValue, element) { 779 return elementValue + "<img class='eac-icon' src='" + element[_fields.iconSrc] + "' />" ; 780 }; 781 } else if (typeof _fields.iconSrc === "function") { 782 buildMethod = function(elementValue, element) { 783 return elementValue + "<img class='eac-icon' src='" + _fields.iconSrc(element) + "' />" ; 784 }; 785 } 786 787 return buildMethod; 788 } 789 790 791 if (template.type === "iconLeft") { 792 793 if (typeof _fields.iconSrc === "string") { 794 buildMethod = function(elementValue, element) { 795 return "<img class='eac-icon' src='" + element[_fields.iconSrc] + "' />" + elementValue; 796 }; 797 } else if (typeof _fields.iconSrc === "function") { 798 buildMethod = function(elementValue, element) { 799 return "<img class='eac-icon' src='" + _fields.iconSrc(element) + "' />" + elementValue; 800 }; 801 } 802 803 return buildMethod; 804 } 805 806 if(template.type === "links") { 807 808 if (typeof _fields.link === "string") { 809 buildMethod = function(elementValue, element) { 810 return "<a href='" + element[_fields.link] + "' >" + elementValue + "</a>"; 811 }; 812 } else if (typeof _fields.link === "function") { 813 buildMethod = function(elementValue, element) { 814 return "<a href='" + _fields.link(element) + "' >" + elementValue + "</a>"; 815 }; 816 } 817 818 return buildMethod; 819 } 820 821 822 if (template.type === "custom") { 823 824 return template.method; 825 } 826 827 return genericTemplates.basic.method; 828 829 }, 830 831 832 prepareBuildMethod = function(options) { 833 if (!options || !options.type) { 834 835 return genericTemplates.basic.method; 836 } 837 838 if (options.type && genericTemplates[options.type]) { 839 840 return convertTemplateToMethod(options); 841 } else { 842 843 return genericTemplates.basic.method; 844 } 845 846 }, 847 848 templateClass = function(options) { 849 var emptyStringFunction = function() {return "";}; 850 851 if (!options || !options.type) { 852 853 return emptyStringFunction; 854 } 855 856 if (options.type && genericTemplates[options.type]) { 857 return (function () { 858 var _cssClass = genericTemplates[options.type].cssClass; 859 return function() { return _cssClass;}; 860 })(); 861 } else { 862 return emptyStringFunction; 863 } 864 }; 865 866 867 this.getTemplateClass = templateClass(options); 868 869 this.build = prepareBuildMethod(options); 870 871 872 }; 873 874 return scope; 875 876})(EasyAutocomplete || {}); 877 878 879/* 880 * EasyAutocomplete - $ctj plugin for autocompletion 881 * 882 */ 883var EasyAutocomplete = (function(scope) { 884 885 886 scope.main = function Core($input, options) { 887 888 var module = { 889 name: "EasyAutocomplete", 890 shortcut: "eac" 891 }; 892 893 var consts = new scope.Constans(), 894 config = new scope.Configuration(options), 895 logger = new scope.Logger(), 896 template = new scope.Template(options.template), 897 listBuilderService = new scope.ListBuilderService(config, scope.proccess), 898 checkParam = config.equals, 899 900 $field = $input, 901 $container = "", 902 elementsList = [], 903 selectedElement = -1, 904 requestDelayTimeoutId; 905 906 scope.consts = consts; 907 908 this.getConstants = function() { 909 return consts; 910 }; 911 912 this.getConfiguration = function() { 913 return config; 914 }; 915 916 this.getContainer = function() { 917 return $container; 918 }; 919 920 this.getSelectedItemIndex = function() { 921 return selectedElement; 922 }; 923 924 this.getItems = function () { 925 return elementsList; 926 }; 927 928 this.getItemData = function(index) { 929 930 if (elementsList.length < index || elementsList[index] === undefined) { 931 return -1; 932 } else { 933 return elementsList[index]; 934 } 935 }; 936 937 this.getSelectedItemData = function() { 938 return this.getItemData(selectedElement); 939 }; 940 941 this.build = function() { 942 prepareField(); 943 }; 944 945 this.init = function() { 946 init(); 947 }; 948 function init() { 949 950 if ($field.length === 0) { 951 logger.error("Input field doesn't exist."); 952 return; 953 } 954 955 if (!config.checkDataUrlProperties()) { 956 logger.error("One of options variables 'data' or 'url' must be defined."); 957 return; 958 } 959 960 if (!config.checkRequiredProperties()) { 961 logger.error("Will not work without mentioned properties."); 962 return; 963 } 964 965 966 prepareField(); 967 bindEvents(); 968 969 } 970 function prepareField() { 971 972 973 if ($field.parent().hasClass(consts.getValue("WRAPPER_CSS_CLASS"))) { 974 removeContainer(); 975 removeWrapper(); 976 } 977 978 createWrapper(); 979 createContainer(); 980 981 $container = $ctj("#" + getContainerId()); 982 if (config.get("placeholder")) { 983 $field.attr("placeholder", config.get("placeholder")); 984 } 985 986 987 function createWrapper() { 988 var $wrapper = $ctj("<div>"), 989 classes = consts.getValue("WRAPPER_CSS_CLASS"); 990 991 992 if (config.get("theme") && config.get("theme") !== "") { 993 classes += " eac-" + config.get("theme"); 994 } 995 996 if (config.get("cssClasses") && config.get("cssClasses") !== "") { 997 classes += " " + config.get("cssClasses"); 998 } 999 1000 if (template.getTemplateClass() !== "") { 1001 classes += " " + template.getTemplateClass(); 1002 } 1003 1004 1005 $wrapper 1006 .addClass(classes); 1007 $field.wrap($wrapper); 1008 1009 1010 if (config.get("adjustWidth") === true) { 1011 adjustWrapperWidth(); 1012 } 1013 1014 1015 } 1016 1017 function adjustWrapperWidth() { 1018 var fieldWidth = $field.outerWidth(); 1019 1020 $field.parent().css("width", fieldWidth); 1021 } 1022 1023 function removeWrapper() { 1024 $field.unwrap(); 1025 } 1026 1027 function createContainer() { 1028 var $elements_container = $ctj("<div>").addClass(consts.getValue("CONTAINER_CLASS")); 1029 1030 $elements_container 1031 .attr("id", getContainerId()) 1032 .prepend($ctj("<ul>")); 1033 1034 1035 (function() { 1036 1037 $elements_container 1038 /* List show animation */ 1039 .on("show.eac", function() { 1040 1041 switch(config.get("list").showAnimation.type) { 1042 1043 case "slide": 1044 var animationTime = config.get("list").showAnimation.time, 1045 callback = config.get("list").showAnimation.callback; 1046 1047 $elements_container.find("ul").slideDown(animationTime, callback); 1048 break; 1049 1050 case "fade": 1051 var animationTime = config.get("list").showAnimation.time, 1052 callback = config.get("list").showAnimation.callback; 1053 1054 $elements_container.find("ul").fadeIn(animationTime), callback; 1055 break; 1056 1057 default: 1058 $elements_container.find("ul").show(); 1059 break; 1060 } 1061 1062 config.get("list").onShowListEvent(); 1063 1064 }) 1065 /* List hide animation */ 1066 .on("hide.eac", function() { 1067 1068 switch(config.get("list").hideAnimation.type) { 1069 1070 case "slide": 1071 var animationTime = config.get("list").hideAnimation.time, 1072 callback = config.get("list").hideAnimation.callback; 1073 1074 $elements_container.find("ul").slideUp(animationTime, callback); 1075 break; 1076 1077 case "fade": 1078 var animationTime = config.get("list").hideAnimation.time, 1079 callback = config.get("list").hideAnimation.callback; 1080 1081 $elements_container.find("ul").fadeOut(animationTime, callback); 1082 break; 1083 1084 default: 1085 $elements_container.find("ul").hide(); 1086 break; 1087 } 1088 1089 config.get("list").onHideListEvent(); 1090 1091 }) 1092 .on("selectElement.eac", function() { 1093 $elements_container.find("ul li").removeClass("selected"); 1094 $elements_container.find("ul li").eq(selectedElement).addClass("selected"); 1095 1096 config.get("list").onSelectItemEvent(); 1097 }) 1098 .on("loadElements.eac", function(event, listBuilders, phrase) { 1099 1100 1101 var $item = "", 1102 $listContainer = $elements_container.find("ul"); 1103 1104 $listContainer 1105 .empty() 1106 .detach(); 1107 1108 elementsList = []; 1109 var counter = 0; 1110 for(var builderIndex = 0, listBuildersLength = listBuilders.length; builderIndex < listBuildersLength; builderIndex += 1) { 1111 1112 var listData = listBuilders[builderIndex].data; 1113 1114 if (listData.length === 0) { 1115 continue; 1116 } 1117 1118 if (listBuilders[builderIndex].header !== undefined && listBuilders[builderIndex].header.length > 0) { 1119 $listContainer.append("<div class='eac-category' >" + listBuilders[builderIndex].header + "</div>"); 1120 } 1121 1122 for(var i = 0, listDataLength = listData.length; i < listDataLength && counter < listBuilders[builderIndex].maxListSize; i += 1) { 1123 $item = $ctj("<li><div class='eac-item'></div></li>"); 1124 1125 1126 (function() { 1127 var j = i, 1128 itemCounter = counter, 1129 elementsValue = listBuilders[builderIndex].getValue(listData[j]); 1130 1131 $item.find(" > div") 1132 .on("click", function() { 1133 1134 $field.val(elementsValue).trigger("change"); 1135 1136 selectedElement = itemCounter; 1137 selectElement(itemCounter); 1138 1139 config.get("list").onClickEvent(); 1140 config.get("list").onChooseEvent(); 1141 }) 1142 .mouseover(function() { 1143 1144 selectedElement = itemCounter; 1145 selectElement(itemCounter); 1146 1147 config.get("list").onMouseOverEvent(); 1148 }) 1149 .mouseout(function() { 1150 config.get("list").onMouseOutEvent(); 1151 }) 1152 .html(template.build(highlight(elementsValue, phrase), listData[j])); 1153 })(); 1154 1155 $listContainer.append($item); 1156 elementsList.push(listData[i]); 1157 counter += 1; 1158 } 1159 } 1160 1161 $elements_container.append($listContainer); 1162 1163 config.get("list").onLoadEvent(); 1164 }); 1165 1166 })(); 1167 1168 $field.after($elements_container); 1169 } 1170 1171 function removeContainer() { 1172 $field.next("." + consts.getValue("CONTAINER_CLASS")).remove(); 1173 } 1174 1175 function highlight(string, phrase) { 1176 1177 if(config.get("highlightPhrase") && phrase !== "") { 1178 return highlightPhrase(string, phrase); 1179 } else { 1180 return string; 1181 } 1182 1183 } 1184 1185 function escapeRegExp(str) { 1186 return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 1187 } 1188 1189 function highlightPhrase(string, phrase) { 1190 var escapedPhrase = escapeRegExp(phrase); 1191 return (string + "").replace(new RegExp("(" + escapedPhrase + ")", "gi") , "<b>$1</b>"); 1192 } 1193 1194 1195 1196 } 1197 function getContainerId() { 1198 1199 var elementId = $field.attr("id"); 1200 1201 elementId = consts.getValue("CONTAINER_ID") + elementId; 1202 1203 return elementId; 1204 } 1205 function bindEvents() { 1206 1207 bindAllEvents(); 1208 1209 1210 function bindAllEvents() { 1211 if (checkParam("autocompleteOff", true)) { 1212 removeAutocomplete(); 1213 } 1214 1215 bindFocusOut(); 1216 bindKeyup(); 1217 bindKeydown(); 1218 bindKeypress(); 1219 bindFocus(); 1220 bindBlur(); 1221 } 1222 1223 function bindFocusOut() { 1224 $field.focusout(function () { 1225 1226 var fieldValue = $field.val(), 1227 phrase; 1228 1229 if (!config.get("list").match.caseSensitive) { 1230 fieldValue = fieldValue.toLowerCase(); 1231 } 1232 1233 for (var i = 0, length = elementsList.length; i < length; i += 1) { 1234 1235 phrase = config.get("getValue")(elementsList[i]); 1236 if (!config.get("list").match.caseSensitive) { 1237 phrase = phrase.toLowerCase(); 1238 } 1239 1240 if (phrase === fieldValue) { 1241 selectedElement = i; 1242 selectElement(selectedElement); 1243 return; 1244 } 1245 } 1246 }); 1247 } 1248 1249 function bindKeyup() { 1250 $field 1251 .off("keyup") 1252 .keyup(function(event) { 1253 1254 switch(event.keyCode) { 1255 1256 case 27: 1257 1258 hideContainer(); 1259 loseFieldFocus(); 1260 break; 1261 1262 case 38: 1263 1264 event.preventDefault(); 1265 1266 if(elementsList.length > 0 && selectedElement > 0) { 1267 1268 selectedElement -= 1; 1269 1270 $field.val(config.get("getValue")(elementsList[selectedElement])); 1271 1272 selectElement(selectedElement); 1273 1274 } 1275 break; 1276 1277 case 40: 1278 1279 event.preventDefault(); 1280 1281 if(elementsList.length > 0 && selectedElement < elementsList.length - 1) { 1282 1283 selectedElement += 1; 1284 1285 $field.val(config.get("getValue")(elementsList[selectedElement])); 1286 1287 selectElement(selectedElement); 1288 1289 } 1290 1291 break; 1292 1293 default: 1294 1295 if (event.keyCode > 40 || event.keyCode === 8) { 1296 1297 var inputPhrase = $field.val(); 1298 1299 if (!(config.get("list").hideOnEmptyPhrase === true && event.keyCode === 8 && inputPhrase === "")) { 1300 1301 if (config.get("requestDelay") > 0) { 1302 if (requestDelayTimeoutId !== undefined) { 1303 clearTimeout(requestDelayTimeoutId); 1304 } 1305 1306 requestDelayTimeoutId = setTimeout(function () { loadData(inputPhrase);}, config.get("requestDelay")); 1307 } else { 1308 loadData(inputPhrase); 1309 } 1310 1311 } else { 1312 hideContainer(); 1313 } 1314 1315 } 1316 1317 1318 break; 1319 } 1320 1321 1322 function loadData(inputPhrase) { 1323 1324 1325 if (inputPhrase.length < config.get("minCharNumber")) { 1326 return; 1327 } 1328 1329 1330 if (config.get("data") !== "list-required") { 1331 1332 var data = config.get("data"); 1333 1334 var listBuilders = listBuilderService.init(data); 1335 1336 listBuilders = listBuilderService.updateCategories(listBuilders, data); 1337 1338 listBuilders = listBuilderService.processData(listBuilders, inputPhrase); 1339 1340 loadElements(listBuilders, inputPhrase); 1341 1342 if ($field.parent().find("li").length > 0) { 1343 showContainer(); 1344 } else { 1345 hideContainer(); 1346 } 1347 1348 } 1349 1350 var settings = createAjaxSettings(); 1351 1352 if (settings.url === undefined || settings.url === "") { 1353 settings.url = config.get("url"); 1354 } 1355 1356 if (settings.dataType === undefined || settings.dataType === "") { 1357 settings.dataType = config.get("dataType"); 1358 } 1359 1360 1361 if (settings.url !== undefined && settings.url !== "list-required") { 1362 1363 settings.url = settings.url(inputPhrase); 1364 1365 settings.data = config.get("preparePostData")(settings.data, inputPhrase); 1366 1367 $ctj.ajax(settings) 1368 .done(function(data) { 1369 1370 var listBuilders = listBuilderService.init(data); 1371 1372 listBuilders = listBuilderService.updateCategories(listBuilders, data); 1373 1374 listBuilders = listBuilderService.convertXml(listBuilders); 1375 if (checkInputPhraseMatchResponse(inputPhrase, data)) { 1376 1377 listBuilders = listBuilderService.processData(listBuilders, inputPhrase); 1378 1379 loadElements(listBuilders, inputPhrase); 1380 1381 } 1382 1383 if (listBuilderService.checkIfDataExists(listBuilders) && $field.parent().find("li").length > 0) { 1384 showContainer(); 1385 } else { 1386 hideContainer(); 1387 } 1388 1389 config.get("ajaxCallback")(); 1390 1391 }) 1392 .fail(function() { 1393 logger.warning("Fail to load response data"); 1394 }) 1395 .always(function() { 1396 1397 }); 1398 } 1399 1400 1401 1402 function createAjaxSettings() { 1403 1404 var settings = {}, 1405 ajaxSettings = config.get("ajaxSettings") || {}; 1406 1407 for (var set in ajaxSettings) { 1408 settings[set] = ajaxSettings[set]; 1409 } 1410 1411 return settings; 1412 } 1413 1414 function checkInputPhraseMatchResponse(inputPhrase, data) { 1415 1416 if (config.get("matchResponseProperty") !== false) { 1417 if (typeof config.get("matchResponseProperty") === "string") { 1418 return (data[config.get("matchResponseProperty")] === inputPhrase); 1419 } 1420 1421 if (typeof config.get("matchResponseProperty") === "function") { 1422 return (config.get("matchResponseProperty")(data) === inputPhrase); 1423 } 1424 1425 return true; 1426 } else { 1427 return true; 1428 } 1429 1430 } 1431 1432 } 1433 1434 1435 }); 1436 } 1437 1438 function bindKeydown() { 1439 $field 1440 .on("keydown", function(evt) { 1441 evt = evt || window.event; 1442 var keyCode = evt.keyCode; 1443 if (keyCode === 38) { 1444 suppressKeypress = true; 1445 return false; 1446 } 1447 }) 1448 .keydown(function(event) { 1449 1450 if (event.keyCode === 13 && selectedElement > -1) { 1451 1452 $field.val(config.get("getValue")(elementsList[selectedElement])); 1453 1454 config.get("list").onKeyEnterEvent(); 1455 config.get("list").onChooseEvent(); 1456 1457 selectedElement = -1; 1458 hideContainer(); 1459 1460 event.preventDefault(); 1461 } 1462 }); 1463 } 1464 1465 function bindKeypress() { 1466 $field 1467 .off("keypress"); 1468 } 1469 1470 function bindFocus() { 1471 $field.focus(function() { 1472 1473 if ($field.val() !== "" && elementsList.length > 0) { 1474 1475 selectedElement = -1; 1476 showContainer(); 1477 } 1478 1479 }); 1480 } 1481 1482 function bindBlur() { 1483 $field.blur(function() { 1484 setTimeout(function() { 1485 1486 selectedElement = -1; 1487 hideContainer(); 1488 }, 250); 1489 }); 1490 } 1491 1492 function removeAutocomplete() { 1493 $field.attr("autocomplete","off"); 1494 } 1495 1496 } 1497 1498 function showContainer() { 1499 $container.trigger("show.eac"); 1500 } 1501 1502 function hideContainer() { 1503 $container.trigger("hide.eac"); 1504 } 1505 1506 function selectElement(index) { 1507 1508 $container.trigger("selectElement.eac", index); 1509 } 1510 1511 function loadElements(list, phrase) { 1512 $container.trigger("loadElements.eac", [list, phrase]); 1513 } 1514 1515 function loseFieldFocus() { 1516 $field.trigger("blur"); 1517 } 1518 1519 1520 }; 1521 scope.eacHandles = []; 1522 1523 scope.getHandle = function(id) { 1524 return scope.eacHandles[id]; 1525 }; 1526 1527 scope.inputHasId = function(input) { 1528 1529 if($ctj(input).attr("id") !== undefined && $ctj(input).attr("id").length > 0) { 1530 return true; 1531 } else { 1532 return false; 1533 } 1534 1535 }; 1536 1537 scope.assignRandomId = function(input) { 1538 1539 var fieldId = ""; 1540 1541 do { 1542 fieldId = "eac-" + Math.floor(Math.random() * 10000); 1543 } while ($ctj("#" + fieldId).length !== 0); 1544 1545 elementId = scope.consts.getValue("CONTAINER_ID") + fieldId; 1546 1547 $ctj(input).attr("id", fieldId); 1548 1549 }; 1550 1551 scope.setHandle = function(handle, id) { 1552 scope.eacHandles[id] = handle; 1553 }; 1554 1555 1556 return scope; 1557 1558})(EasyAutocomplete || {}); 1559 1560(function($) { 1561 1562 $.fn.easyAutocomplete = function(options) { 1563 1564 return this.each(function() { 1565 var $this = $(this), 1566 eacHandle = new EasyAutocomplete.main($this, options); 1567 1568 if (!EasyAutocomplete.inputHasId($this)) { 1569 EasyAutocomplete.assignRandomId($this); 1570 } 1571 1572 eacHandle.init(); 1573 1574 EasyAutocomplete.setHandle(eacHandle, $this.attr("id")); 1575 1576 }); 1577 }; 1578 1579 $.fn.getSelectedItemIndex = function() { 1580 1581 var inputId = $(this).attr("id"); 1582 1583 if (inputId !== undefined) { 1584 return EasyAutocomplete.getHandle(inputId).getSelectedItemIndex(); 1585 } 1586 1587 return -1; 1588 }; 1589 1590 $.fn.getItems = function () { 1591 1592 var inputId = $(this).attr("id"); 1593 1594 if (inputId !== undefined) { 1595 return EasyAutocomplete.getHandle(inputId).getItems(); 1596 } 1597 1598 return -1; 1599 }; 1600 1601 $.fn.getItemData = function(index) { 1602 1603 var inputId = $(this).attr("id"); 1604 1605 if (inputId !== undefined && index > -1) { 1606 return EasyAutocomplete.getHandle(inputId).getItemData(index); 1607 } 1608 1609 return -1; 1610 }; 1611 1612 $.fn.getSelectedItemData = function() { 1613 1614 var inputId = $(this).attr("id"); 1615 1616 if (inputId !== undefined) { 1617 return EasyAutocomplete.getHandle(inputId).getSelectedItemData(); 1618 } 1619 1620 return -1; 1621 }; 1622 1623})($ctj);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.