PageSourceSearch

https://pharmamex.com.mx/includes/javascript/lib/jquery.autocomplete.js

js pharmamex.com.mx collected 2026-10-04 02:39:55 UTC 16,453 bytes, 593 lines download raw bytes

1jQuery.autocomplete = function(input, options) {
2	// Create a link to self
3	var me = this;
4  var currentRequest = null;   
5	// Create jQuery object for input element
6	var $input = $(input).attr("autocomplete", "off");
7
8	// Apply inputClass if necessary
9	if (options.inputClass) $input.addClass(options.inputClass);
10
11	// Create results
12	var results = document.createElement("div");
13 
14	// Create jQuery object for results
15	var $results = $(results);
16	$results.hide().addClass(options.resultsClass).css("position", "absolute");
17	if( options.width > 0 ) $results.css("width", options.width);
18
19	// Add to body element
20	// input.after(results);
21	$("body").append(results);
22
23	input.autocompleter = me;
24
25	var timeout = null;
26	var prev = "";
27	var active = -1;
28	var cache = {};
29	var keyb = false;
30	var hasFocus = false;
31	var lastKeyPressCode = null;
32
33	// flush cache
34	function flushCache(){
35		cache = {};
36		cache.data = {};
37		cache.length = 0;
38	};
39
40	// flush cache
41	flushCache();
42
43	// if there is a data array supplied
44	if( options.data != null ){
45		var sFirstChar = "", stMatchSets = {}, row = [];
46
47		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
48		if( typeof options.url != "string" ) options.cacheLength = 1;
49
50		// loop through the array and create a lookup structure
51		for( var i=0; i < options.data.length; i++ ){
52			// if row is a string, make an array otherwise just reference the array
53			row = ((typeof options.data[i] == "string") ? [options.data[i]] : options.data[i]);
54
55			// if the length is zero, don't add to list
56			if( row[0].length > 0 ){
57				// get the first character
58				sFirstChar = row[0].substring(0, 1).toLowerCase();
59				// if no lookup array for this character exists, look it up now
60				if( !stMatchSets[sFirstChar] ) stMatchSets[sFirstChar] = [];
61				// if the match is a string
62				stMatchSets[sFirstChar].push(row);
63			}
64		}
65
66		// add the data items to the cache
67		for( var k in stMatchSets ){
68			// increase the cache size
69			options.cacheLength++;
70			// add to the cache
71			addToCache(k, stMatchSets[k]);
72		}
73	}
74
75	$input
76	.keydown(function(e) {
77		// track last key pressed
78		lastKeyPressCode = e.keyCode;
79		switch(e.keyCode) {
80			case 38: // up
81				e.preventDefault();
82				moveSelect(-1);
83				break;
84			case 40: // down
85				e.preventDefault();
86				moveSelect(1);
87				break;
88			case 9:  // tab
89			case 13: // return
90			
91				break;
92			default:
93				active = -1;
94				if (timeout) clearTimeout(timeout);
95                timeout = setTimeout(function () {
96                    onChange();
97                }, options.delay);
98				break;
99		}
100	})
101	.focus(function(){
102		// track whether the field has focus, we shouldn't process any results if the field no longer has focus
103		hasFocus = true;
104	})
105	.blur(function() {
106		// track whether the field has focus
107		hasFocus = false;
108		hideResults();
109	});
110
111	hideResultsNow();
112
113	function onChange() {
114		// ignore if the following keys are pressed: [del] [shift] [capslock]
115		if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ) return $results.hide();
116		var v = $input.val();
117		if (v == prev) return;
118		prev = v;
119		if (v.length >= options.minChars) {
120			$input.addClass(options.loadingClass);
121			requestData(v);
122		} else {
123			$input.removeClass(options.loadingClass);
124			$results.hide();
125		}
126	};
127
128 	function moveSelect(step) {
129
130		var lis = $("li", results);
131		if (!lis) return;
132
133		active += step;
134
135		if (active < 0) {
136			active = 0;
137		} else if (active >= lis.length) {
138			active = lis.length - 1;
139		}
140
141		lis.removeClass("ac_over");
142
143		$(lis[active]).addClass("ac_over");
144
145		// Weird behaviour in IE
146		// if (lis[active] && lis[active].scrollIntoView) {
147		// 	lis[active].scrollIntoView(false);
148		// }
149
150	};
151
152	function selectCurrent() {
153		var li = $("li.ac_over", results)[0];
154		if (!li) {
155			var $li = $("li", results);
156			if (options.selectOnly) {
157				if ($li.length == 1) li = $li[0];
158			} else if (options.selectFirst) {
159				li = $li[0];
160			}
161		}
162		if (li) {
163			selectItem(li);
164			return true;
165		} else {
166			return false;
167		}
168	};
169
170	function selectItem(li) {
171		if (!li) {
172			li = document.createElement("li");
173			li.extra = [];
174			li.selectValue = "";
175		}
176		var v = $.trim(li.selectValue ? li.selectValue : li.innerHTML);
177		input.lastSelected = v;
178		prev = v;
179		$results.html("");
180		$input.val(v);
181		hideResultsNow();
182		if (options.onItemSelect) setTimeout(function() { options.onItemSelect(li) }, 1);
183	};
184
185	// selects a portion of the input string
186	function createSelection(start, end){
187		// get a reference to the input element
188		var field = $input.get(0);
189		if( field.createTextRange ){
190			var selRange = field.createTextRange();
191			selRange.collapse(true);
192			selRange.moveStart("character", start);
193			selRange.moveEnd("character", end);
194			selRange.select();
195		} else if( field.setSelectionRange ){
196			field.setSelectionRange(start, end);
197		} else {
198			if( field.selectionStart ){
199				field.selectionStart = start;
200				field.selectionEnd = end;
201			}
202		}
203		field.focus();
204	};
205
206	// fills in the input box w/the first match (assumed to be the best match)
207	function autoFill(sValue){
208		// if the last user key pressed was backspace, don't autofill
209		if( lastKeyPressCode != 8 ){
210			// fill in the value (keep the case the user has typed)
211			$input.val($input.val() + sValue.substring(prev.length));
212			// select the portion of the value not typed by the user (so the next character will erase)
213			createSelection(prev.length, sValue.length);
214		}
215	};
216
217	function showResults() {
218		// get the position of the input field right now (in case the DOM is shifted)
219		var pos = findPos(input);
220		// either use the specified width, or autocalculate based on form element
221		var iWidth = (options.width > 0) ? options.width : $input.width();
222		// do reposition on scroll if body has fixed header
223
224		if ($('body').hasClass('fixed-header')) {
225            $results.css({
226                width: parseInt(iWidth) + "px",
227                top: (pos.y + input.offsetHeight + 5) + "px",
228                left: pos.x + 3 + "px"
229            }).show();
230			$results.css({
231				top: ($(window).scrollTop() + 48) + "px"
232			});
233            $(window).on("scroll", function() {
234				$results.css({
235					top: ($(window).scrollTop() + 48) + "px"
236				});
237            });
238		} else {
239			if (IS_MOBILE != '1') {
240				$results.css({
241					width: parseInt(iWidth) + "px",
242					top: (pos.y + input.offsetHeight - 1) + "px",
243					left: pos.x + 3 + "px"
244				}).show();
245			} else {
246				$results.css({
247					top: ($(window).scrollTop() + 48) + "px"
248				}).show();
249			}
250        }
251	};
252
253	function hideResults() {
254		if (timeout) clearTimeout(timeout);
255		timeout = setTimeout(hideResultsNow, 200);
256	};
257
258	function hideResultsNow() {
259		if (timeout) clearTimeout(timeout);
260		$input.removeClass(options.loadingClass);
261		if ($results.is(":visible")) {
262			$results.hide();
263		}
264		if (options.mustMatch) {
265			var v = $input.val();
266			if (v != input.lastSelected) {
267				selectItem(null);
268			}
269		}
270	};
271
272	function receiveData(q, data,error=false) {
273		if (data||error) {
274			$input.removeClass(options.loadingClass);
275			results.innerHTML = "";
276
277			if(error){
278				let newDiv = document.createElement('div');
279				newDiv.className = 'my-class';
280				newDiv.id = 'my-id';
281				newDiv.innerHTML = '<span style="height: 100%; font-size: 1.5em;">'+data+'</span>';
282				results.appendChild(newDiv);
283				showResults();
284				return ;
285			}
286			// if the field no longer has focus or if there are no matches, do not display the drop down
287
288			if( !hasFocus || data.length == 0 ) return hideResultsNow();
289
290	//		if ($.browser.msie) {
291	//			// we put a styled iframe behind the calendar so HTML SELECT elements don't show through
292	//			$results.append(document.createElement('iframe'));
293	//		}
294			results.appendChild(dataToDom(data));
295			// autofill in the complete box w/the first match as long as the user hasn't entered in more data
296			if( options.autoFill && ($input.val().toLowerCase() == q.toLowerCase()) ) autoFill(data[0][0]);
297				var searchid = IS_MOBILE != '1' ? 'searchpr' : 'searchpr1';
298				var newDiv = document.createElement('div');
299				newDiv.className = 'my-class';
300				newDiv.id = 'my-id';
301				newDiv.innerHTML = '<a class="btn btn-default gradient" id = "show_results" href="javascript:;" onClick="{ var inp = document.getElementById(\''+searchid+'\');    this.href=SEARCH_LANG+\'?keywords=\'+inp.value; }">'+SHOW_RESULTS+' (' + data.length + ') </a>';
302				results.appendChild(newDiv);
303			showResults();
304		} else {
305			hideResultsNow();
306		}
307	};
308
309	function parseData(data) {
310		if (!data) return null;
311		var parsed = [];
312		var rows = data.split(options.lineSeparator);
313		for (var i=0; i < rows.length; i++) {
314			var row = $.trim(rows[i]);
315			if (row) {
316				parsed[parsed.length] = row.split(options.cellSeparator);
317			}
318		}
319		return parsed;
320	};
321
322	function dataToDom(data) {
323		var ul = document.createElement("ul");
324		var num = data.length;
325
326		// limited results to a max number
327		if( (options.maxItemsToShow > 0) && (options.maxItemsToShow < num) ) num = options.maxItemsToShow;
328
329		for (var i=0; i < num; i++) {
330			var row = data[i];
331			if (!row) continue;
332			var li = document.createElement("li");
333			if (options.formatItem) {
334				li.innerHTML = options.formatItem(row, i, num);
335				li.selectValue = row[0];
336			} else {
337				li.innerHTML = row[0];
338				li.selectValue = row[0];
339			}
340			var extra = null;
341			if (row.length > 1) {
342				extra = [];
343				for (var j=1; j < row.length; j++) {
344					extra[extra.length] = row[j];
345				}
346			}
347			li.extra = extra;
348			ul.appendChild(li);
349			$(li).hover(
350				function() { $("li", ul).removeClass("ac_over"); $(this).addClass("ac_over"); active = $("li", ul).indexOf($(this).get(0)); },
351				function() { $(this).removeClass("ac_over"); }
352			).click(function(e) { e.preventDefault(); e.stopPropagation(); selectItem(this) });
353		}
354		return ul;
355	};
356
357	function requestData(q) {
358		if (!options.matchCase) q = q.toLowerCase();
359		var data = options.cacheLength ? loadFromCache(q) : null;
360		// recieve the cached data
361		if (data != null && data.length) {
362			receiveData(q, data);
363		// if an AJAX url has been supplied, try loading the data now
364		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
365      currentRequest = jQuery.ajax({
366          type: 'get',
367          url: makeUrl(q),
368          beforeSend : function() { if(currentRequest != null) currentRequest.abort()},
369          success: function(data) {
370				let json = JSON.parse(data);
371				data = json.body.join('');
372				let count = json.count;
373 				data = parseData(data);
374    				addToCache(q, data);
375    				receiveData(q, data);
376			  if(json.not_found)
377				  receiveData(q,json.not_found,true);
378			  setButtonText(SHOW_RESULTS,count);
379          }
380      });
381		// if there's been no data found, remove the loading class
382		} else {
383			$input.removeClass(options.loadingClass);
384		}
385	};
386
387	function setButtonText(SHOW_RESULTS,count){
388		$("#show_results").text(SHOW_RESULTS + " ("+count+")");
389	}
390	function makeUrl(q) {
391		var url = options.url + "?q=" + encodeURI(q);
392		for (var i in options.extraParams) {
393			url += "&" + i + "=" + encodeURI(options.extraParams[i]);
394		}
395		return url;
396	};
397
398	function loadFromCache(q) {
399		if (!q) return null;
400		//if (cache.data[q]) return cache.data[q];
401		if (options.matchSubset) {
402			// for (var i = q.length - 1; i >= options.minChars; i--) {
403			// 	var qs = q.substr(0, i);
404			// 	var c = cache.data[qs];
405			// 	if (c) {
406			// 		var csub = [];
407			// 		for (var j = 0; j < c.length; j++) {
408			// 			var x = c[j];
409			// 			var x0 = x[0];
410			// 			if (matchSubset(x0, q)) {
411			// 				csub[csub.length] = x;
412			// 			}
413			// 		}
414			// 		return csub;
415			// 	}
416			// }
417            var arySplitRequest = q.split(" ");
418			var availableTags = cache.data;
419            var csub = [];
420            if (Object.keys(availableTags).length) {
421                for (var prop in availableTags) {
422                    for (var i = 0; i < availableTags[prop].length; i++) {
423
424
425                        var intCount = 0;
426                        for (var j = 0; j < arySplitRequest.length; j++) {
427
428                            var regexp = new RegExp(arySplitRequest[j], 'i');
429
430                            var test = availableTags[prop][i][0].match(regexp);
431
432                            if (test) {
433
434                                intCount++;
435
436                            } else if (!test) {
437
438                                intCount = arySplitRequest.length + 1;
439
440                            }
441
442                            if (intCount == arySplitRequest.length) {
443
444                                csub.push(availableTags[prop][i]);
445
446                            }
447                        }
448
449                    }
450                    if (csub.length) break;
451                }
452                return csub;
453
454            }
455		}
456		return null;
457	};
458
459	function matchSubset(s, sub) {
460		if (!options.matchCase) s = s.toLowerCase();
461		var i = s.indexOf(sub);
462		if (i == -1) return false;
463		return i == 0 || options.matchContains;
464	};
465
466	this.flushCache = function() {
467		flushCache();
468	};
469
470	this.setExtraParams = function(p) {
471		options.extraParams = p;
472	};
473
474	this.findValue = function(){
475		var q = $input.val();
476
477		if (!options.matchCase) q = q.toLowerCase();
478		var data = options.cacheLength ? loadFromCache(q) : null;
479		if (data) {
480			findValueCallback(q, data);
481		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
482			$.get(makeUrl(q), function(data) {
483				data = parseData(data)
484				addToCache(q, data);
485				findValueCallback(q, data);
486			});
487		} else {
488			// no matches
489			findValueCallback(q, null);
490		}
491	}
492
493	function findValueCallback(q, data){
494		if (data) $input.removeClass(options.loadingClass);
495
496		var num = (data) ? data.length : 0;
497		var li = null;
498
499		for (var i=0; i < num; i++) {
500			var row = data[i];
501
502			if( row[0].toLowerCase() == q.toLowerCase() ){
503				li = document.createElement("li");
504				if (options.formatItem) {
505					li.innerHTML = options.formatItem(row, i, num);
506					li.selectValue = row[0];
507				} else {
508					li.innerHTML = row[0];
509					li.selectValue = row[0];
510				}
511				var extra = null;
512				if( row.length > 1 ){
513					extra = [];
514					for (var j=1; j < row.length; j++) {
515						extra[extra.length] = row[j];
516					}
517				}
518				li.extra = extra;
519			}
520		}
521
522		if( options.onFindValue ) setTimeout(function() { options.onFindValue(li) }, 1);
523	}
524
525	function addToCache(q, data) {
526		if (!data || !q || !options.cacheLength) return;
527		if (!cache.length || cache.length > options.cacheLength) {
528			flushCache();
529			cache.length++;
530		} else if (!cache[q]) {
531			cache.length++;
532		}
533		cache.data[q] = data;
534	};
535
536	function findPos(obj) {
537		var curleft = obj.offsetLeft || 0;
538		var curtop = obj.offsetTop || 0;
539		while (obj = obj.offsetParent) {
540			curleft += obj.offsetLeft
541			curtop += obj.offsetTop
542		}
543		return {x:curleft,y:curtop};
544	}
545}
546
547jQuery.fn.autocomplete = function(url, options, data) {
548	// Make sure options exists
549	options = options || {};
550	// Set url as option
551	options.url = url;
552	// set some bulk local data
553	options.data = ((typeof data == "object") && (data.constructor == Array)) ? data : null;
554
555	// Set default values for required options
556	options.inputClass = options.inputClass || "ac_input";
557	options.resultsClass = options.resultsClass || "ac_results";
558	options.lineSeparator = options.lineSeparator || "\n";
559	options.cellSeparator = options.cellSeparator || "|";
560	options.minChars = options.minChars || 1;
561	options.delay = options.delay || 400;
562	options.matchCase = options.matchCase || 0;
563	options.matchSubset = options.matchSubset || 1;
564	options.matchContains = options.matchContains || 0;
565	options.cacheLength = options.cacheLength || 1;
566	options.mustMatch = options.mustMatch || 0;
567	options.extraParams = options.extraParams || {};
568	options.loadingClass = options.loadingClass || "ac_loading";
569	options.selectFirst = options.selectFirst || false;
570	options.selectOnly = options.selectOnly || false;
571	options.maxItemsToShow = options.maxItemsToShow || -1;
572	options.autoFill = options.autoFill || false;
573	options.width = parseInt(options.width, 10) || 0;
574
575	this.each(function() {
576		var input = this;
577		new jQuery.autocomplete(input, options);
578	});
579
580	// Don't break the chain
581	return this;
582}
583
584jQuery.fn.autocompleteArray = function(data, options) {
585	return this.autocomplete(null, options, data);
586}
587
588jQuery.fn.indexOf = function(e){
589	for( var i=0; i<this.length; i++ ){
590		if( this[i] == e ) return i;
591	}
592	return -1;
593};

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.