PageSourceSearch

https://careers.ccs.spokane.edu/assets/sites/easy-autocomplete-66f05834.js

js spokane.edu collected 2026-09-24 09:43:57 UTC 34,437 bytes, 1,623 lines download raw bytes

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.