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