PageSourceSearch

http://alga.kz/pay/media/js/ui/jquery.ui.autocomplete.js

js alga.kz collected 2026-10-05 00:10:53 UTC 17,102 bytes, 624 lines download raw bytes

1/*
2 * jQuery UI Autocomplete 1.8.18
3 *
4 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
7 *
8 * http://docs.jquery.com/UI/Autocomplete
9 *
10 * Depends:
11 *	jquery.ui.core.js
12 *	jquery.ui.widget.js
13 *	jquery.ui.position.js
14 */
15(function( $, undefined ) {
16
17// used to prevent race conditions with remote data sources
18var requestIndex = 0;
19
20$.widget( "ui.autocomplete", {
21	options: {
22		appendTo: "body",
23		autoFocus: false,
24		delay: 300,
25		minLength: 1,
26		position: {
27			my: "left top",
28			at: "left bottom",
29			collision: "none"
30		},
31		source: null
32	},
33
34	pending: 0,
35
36	_create: function() {
37		var self = this,
38			doc = this.element[ 0 ].ownerDocument,
39			suppressKeyPress;
40
41		this.element
42			.addClass( "ui-autocomplete-input" )
43			.attr( "autocomplete", "off" )
44			// TODO verify these actually work as intended
45			.attr({
46				role: "textbox",
47				"aria-autocomplete": "list",
48				"aria-haspopup": "true"
49			})
50			.bind( "keydown.autocomplete", function( event ) {
51				if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) {
52					return;
53				}
54
55				suppressKeyPress = false;
56				var keyCode = $.ui.keyCode;
57				switch( event.keyCode ) {
58				case keyCode.PAGE_UP:
59					self._move( "previousPage", event );
60					break;
61				case keyCode.PAGE_DOWN:
62					self._move( "nextPage", event );
63					break;
64				case keyCode.UP:
65					self._move( "previous", event );
66					// prevent moving cursor to beginning of text field in some browsers
67					event.preventDefault();
68					break;
69				case keyCode.DOWN:
70					self._move( "next", event );
71					// prevent moving cursor to end of text field in some browsers
72					event.preventDefault();
73					break;
74				case keyCode.ENTER:
75				case keyCode.NUMPAD_ENTER:
76					// when menu is open and has focus
77					if ( self.menu.active ) {
78						// #6055 - Opera still allows the keypress to occur
79						// which causes forms to submit
80						suppressKeyPress = true;
81						event.preventDefault();
82					}
83					//passthrough - ENTER and TAB both select the current element
84				case keyCode.TAB:
85					if ( !self.menu.active ) {
86						return;
87					}
88					self.menu.select( event );
89					break;
90				case keyCode.ESCAPE:
91					self.element.val( self.term );
92					self.close( event );
93					break;
94				default:
95					// keypress is triggered before the input value is changed
96					clearTimeout( self.searching );
97					self.searching = setTimeout(function() {
98						// only search if the value has changed
99						if ( self.term != self.element.val() ) {
100							self.selectedItem = null;
101							self.search( null, event );
102						}
103					}, self.options.delay );
104					break;
105				}
106			})
107			.bind( "keypress.autocomplete", function( event ) {
108				if ( suppressKeyPress ) {
109					suppressKeyPress = false;
110					event.preventDefault();
111				}
112			})
113			.bind( "focus.autocomplete", function() {
114				if ( self.options.disabled ) {
115					return;
116				}
117
118				self.selectedItem = null;
119				self.previous = self.element.val();
120			})
121			.bind( "blur.autocomplete", function( event ) {
122				if ( self.options.disabled ) {
123					return;
124				}
125
126				clearTimeout( self.searching );
127				// clicks on the menu (or a button to trigger a search) will cause a blur event
128				self.closing = setTimeout(function() {
129					self.close( event );
130					self._change( event );
131				}, 150 );
132			});
133		this._initSource();
134		this.response = function() {
135			return self._response.apply( self, arguments );
136		};
137		this.menu = $( "<ul></ul>" )
138			.addClass( "ui-autocomplete" )
139			.appendTo( $( this.options.appendTo || "body", doc )[0] )
140			// prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
141			.mousedown(function( event ) {
142				// clicking on the scrollbar causes focus to shift to the body
143				// but we can't detect a mouseup or a click immediately afterward
144				// so we have to track the next mousedown and close the menu if
145				// the user clicks somewhere outside of the autocomplete
146				var menuElement = self.menu.element[ 0 ];
147				if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
148					setTimeout(function() {
149						$( document ).one( 'mousedown', function( event ) {
150							if ( event.target !== self.element[ 0 ] &&
151								event.target !== menuElement &&
152								!$.ui.contains( menuElement, event.target ) ) {
153								self.close();
154							}
155						});
156					}, 1 );
157				}
158
159				// use another timeout to make sure the blur-event-handler on the input was already triggered
160				setTimeout(function() {
161					clearTimeout( self.closing );
162				}, 13);
163			})
164			.menu({
165				focus: function( event, ui ) {
166					var item = ui.item.data( "item.autocomplete" );
167					if ( false !== self._trigger( "focus", event, { item: item } ) ) {
168						// use value to match what will end up in the input, if it was a key event
169						if ( /^key/.test(event.originalEvent.type) ) {
170							self.element.val( item.value );
171						}
172					}
173				},
174				selected: function( event, ui ) {
175					var item = ui.item.data( "item.autocomplete" ),
176						previous = self.previous;
177
178					// only trigger when focus was lost (click on menu)
179					if ( self.element[0] !== doc.activeElement ) {
180						self.element.focus();
181						self.previous = previous;
182						// #6109 - IE triggers two focus events and the second
183						// is asynchronous, so we need to reset the previous
184						// term synchronously and asynchronously :-(
185						setTimeout(function() {
186							self.previous = previous;
187							self.selectedItem = item;
188						}, 1);
189					}
190
191					if ( false !== self._trigger( "select", event, { item: item } ) ) {
192						self.element.val( item.value );
193					}
194					// reset the term after the select event
195					// this allows custom select handling to work properly
196					self.term = self.element.val();
197
198					self.close( event );
199					self.selectedItem = item;
200				},
201				blur: function( event, ui ) {
202					// don't set the value of the text field if it's already correct
203					// this prevents moving the cursor unnecessarily
204					if ( self.menu.element.is(":visible") &&
205						( self.element.val() !== self.term ) ) {
206						self.element.val( self.term );
207					}
208				}
209			})
210			.zIndex( this.element.zIndex() + 1 )
211			// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
212			.css({ top: 0, left: 0 })
213			.hide()
214			.data( "menu" );
215		if ( $.fn.bgiframe ) {
216			 this.menu.element.bgiframe();
217		}
218		// turning off autocomplete prevents the browser from remembering the
219		// value when navigating through history, so we re-enable autocomplete
220		// if the page is unloaded before the widget is destroyed. #7790
221		self.beforeunloadHandler = function() {
222			self.element.removeAttr( "autocomplete" );
223		};
224		$( window ).bind( "beforeunload", self.beforeunloadHandler );
225	},
226
227	destroy: function() {
228		this.element
229			.removeClass( "ui-autocomplete-input" )
230			.removeAttr( "autocomplete" )
231			.removeAttr( "role" )
232			.removeAttr( "aria-autocomplete" )
233			.removeAttr( "aria-haspopup" );
234		this.menu.element.remove();
235		$( window ).unbind( "beforeunload", this.beforeunloadHandler );
236		$.Widget.prototype.destroy.call( this );
237	},
238
239	_setOption: function( key, value ) {
240		$.Widget.prototype._setOption.apply( this, arguments );
241		if ( key === "source" ) {
242			this._initSource();
243		}
244		if ( key === "appendTo" ) {
245			this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
246		}
247		if ( key === "disabled" && value && this.xhr ) {
248			this.xhr.abort();
249		}
250	},
251
252	_initSource: function() {
253		var self = this,
254			array,
255			url;
256		if ( $.isArray(this.options.source) ) {
257			array = this.options.source;
258			this.source = function( request, response ) {
259				response( $.ui.autocomplete.filter(array, request.term) );
260			};
261		} else if ( typeof this.options.source === "string" ) {
262			url = this.options.source;
263			this.source = function( request, response ) {
264				if ( self.xhr ) {
265					self.xhr.abort();
266				}
267				self.xhr = $.ajax({
268					url: url,
269					data: request,
270					dataType: "json",
271					context: {
272						autocompleteRequest: ++requestIndex
273					},
274					success: function( data, status ) {
275						if ( this.autocompleteRequest === requestIndex ) {
276							response( data );
277						}
278					},
279					error: function() {
280						if ( this.autocompleteRequest === requestIndex ) {
281							response( [] );
282						}
283					}
284				});
285			};
286		} else {
287			this.source = this.options.source;
288		}
289	},
290
291	search: function( value, event ) {
292		value = value != null ? value : this.element.val();
293
294		// always save the actual value, not the one passed as an argument
295		this.term = this.element.val();
296
297		if ( value.length < this.options.minLength ) {
298			return this.close( event );
299		}
300
301		clearTimeout( this.closing );
302		if ( this._trigger( "search", event ) === false ) {
303			return;
304		}
305
306		return this._search( value );
307	},
308
309	_search: function( value ) {
310		this.pending++;
311		this.element.addClass( "ui-autocomplete-loading" );
312
313		this.source( { term: value }, this.response );
314	},
315
316	_response: function( content ) {
317		if ( !this.options.disabled && content && content.length ) {
318			content = this._normalize( content );
319			this._suggest( content );
320			this._trigger( "open" );
321		} else {
322			this.close();
323		}
324		this.pending--;
325		if ( !this.pending ) {
326			this.element.removeClass( "ui-autocomplete-loading" );
327		}
328	},
329
330	close: function( event ) {
331		clearTimeout( this.closing );
332		if ( this.menu.element.is(":visible") ) {
333			this.menu.element.hide();
334			this.menu.deactivate();
335			this._trigger( "close", event );
336		}
337	},
338	
339	_change: function( event ) {
340		if ( this.previous !== this.element.val() ) {
341			this._trigger( "change", event, { item: this.selectedItem } );
342		}
343	},
344
345	_normalize: function( items ) {
346		// assume all items have the right format when the first item is complete
347		if ( items.length && items[0].label && items[0].value ) {
348			return items;
349		}
350		return $.map( items, function(item) {
351			if ( typeof item === "string" ) {
352				return {
353					label: item,
354					value: item
355				};
356			}
357			return $.extend({
358				label: item.label || item.value,
359				value: item.value || item.label
360			}, item );
361		});
362	},
363
364	_suggest: function( items ) {
365		var ul = this.menu.element
366			.empty()
367			.zIndex( this.element.zIndex() + 1 );
368		this._renderMenu( ul, items );
369		// TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
370		this.menu.deactivate();
371		this.menu.refresh();
372
373		// size and position menu
374		ul.show();
375		this._resizeMenu();
376		ul.position( $.extend({
377			of: this.element
378		}, this.options.position ));
379
380		if ( this.options.autoFocus ) {
381			this.menu.next( new $.Event("mouseover") );
382		}
383	},
384
385	_resizeMenu: function() {
386		var ul = this.menu.element;
387		ul.outerWidth( Math.max(
388			// Firefox wraps long text (possibly a rounding bug)
389			// so we add 1px to avoid the wrapping (#7513)
390			ul.width( "" ).outerWidth() + 1,
391			this.element.outerWidth()
392		) );
393	},
394
395	_renderMenu: function( ul, items ) {
396		var self = this;
397		$.each( items, function( index, item ) {
398			self._renderItem( ul, item );
399		});
400	},
401
402	_renderItem: function( ul, item) {
403		return $( "<li></li>" )
404			.data( "item.autocomplete", item )
405			.append( $( "<a></a>" ).text( item.label ) )
406			.appendTo( ul );
407	},
408
409	_move: function( direction, event ) {
410		if ( !this.menu.element.is(":visible") ) {
411			this.search( null, event );
412			return;
413		}
414		if ( this.menu.first() && /^previous/.test(direction) ||
415				this.menu.last() && /^next/.test(direction) ) {
416			this.element.val( this.term );
417			this.menu.deactivate();
418			return;
419		}
420		this.menu[ direction ]( event );
421	},
422
423	widget: function() {
424		return this.menu.element;
425	}
426});
427
428$.extend( $.ui.autocomplete, {
429	escapeRegex: function( value ) {
430		return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
431	},
432	filter: function(array, term) {
433		var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
434		return $.grep( array, function(value) {
435			return matcher.test( value.label || value.value || value );
436		});
437	}
438});
439
440}( jQuery ));
441
442/*
443 * jQuery UI Menu (not officially released)
444 * 
445 * This widget isn't yet finished and the API is subject to change. We plan to finish
446 * it for the next release. You're welcome to give it a try anyway and give us feedback,
447 * as long as you're okay with migrating your code later on. We can help with that, too.
448 *
449 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
450 * Dual licensed under the MIT or GPL Version 2 licenses.
451 * http://jquery.org/license
452 *
453 * http://docs.jquery.com/UI/Menu
454 *
455 * Depends:
456 *	jquery.ui.core.js
457 *  jquery.ui.widget.js
458 */
459(function($) {
460
461$.widget("ui.menu", {
462	_create: function() {
463		var self = this;
464		this.element
465			.addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
466			.attr({
467				role: "listbox",
468				"aria-activedescendant": "ui-active-menuitem"
469			})
470			.click(function( event ) {
471				if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
472					return;
473				}
474				// temporary
475				event.preventDefault();
476				self.select( event );
477			});
478		this.refresh();
479	},
480	
481	refresh: function() {
482		var self = this;
483
484		// don't refresh list items that are already adapted
485		var items = this.element.children("li:not(.ui-menu-item):has(a)")
486			.addClass("ui-menu-item")
487			.attr("role", "menuitem");
488		
489		items.children("a")
490			.addClass("ui-corner-all")
491			.attr("tabindex", -1)
492			// mouseenter doesn't work with event delegation
493			.mouseenter(function( event ) {
494				self.activate( event, $(this).parent() );
495			})
496			.mouseleave(function() {
497				self.deactivate();
498			});
499	},
500
501	activate: function( event, item ) {
502		this.deactivate();
503		if (this.hasScroll()) {
504			var offset = item.offset().top - this.element.offset().top,
505				scroll = this.element.scrollTop(),
506				elementHeight = this.element.height();
507			if (offset < 0) {
508				this.element.scrollTop( scroll + offset);
509			} else if (offset >= elementHeight) {
510				this.element.scrollTop( scroll + offset - elementHeight + item.height());
511			}
512		}
513		this.active = item.eq(0)
514			.children("a")
515				.addClass("ui-state-hover")
516				.attr("id", "ui-active-menuitem")
517			.end();
518		this._trigger("focus", event, { item: item });
519	},
520
521	deactivate: function() {
522		if (!this.active) { return; }
523
524		this.active.children("a")
525			.removeClass("ui-state-hover")
526			.removeAttr("id");
527		this._trigger("blur");
528		this.active = null;
529	},
530
531	next: function(event) {
532		this.move("next", ".ui-menu-item:first", event);
533	},
534
535	previous: function(event) {
536		this.move("prev", ".ui-menu-item:last", event);
537	},
538
539	first: function() {
540		return this.active && !this.active.prevAll(".ui-menu-item").length;
541	},
542
543	last: function() {
544		return this.active && !this.active.nextAll(".ui-menu-item").length;
545	},
546
547	move: function(direction, edge, event) {
548		if (!this.active) {
549			this.activate(event, this.element.children(edge));
550			return;
551		}
552		var next = this.active[direction + "All"](".ui-menu-item").eq(0);
553		if (next.length) {
554			this.activate(event, next);
555		} else {
556			this.activate(event, this.element.children(edge));
557		}
558	},
559
560	// TODO merge with previousPage
561	nextPage: function(event) {
562		if (this.hasScroll()) {
563			// TODO merge with no-scroll-else
564			if (!this.active || this.last()) {
565				this.activate(event, this.element.children(".ui-menu-item:first"));
566				return;
567			}
568			var base = this.active.offset().top,
569				height = this.element.height(),
570				result = this.element.children(".ui-menu-item").filter(function() {
571					var close = $(this).offset().top - base - height + $(this).height();
572					// TODO improve approximation
573					return close < 10 && close > -10;
574				});
575
576			// TODO try to catch this earlier when scrollTop indicates the last page anyway
577			if (!result.length) {
578				result = this.element.children(".ui-menu-item:last");
579			}
580			this.activate(event, result);
581		} else {
582			this.activate(event, this.element.children(".ui-menu-item")
583				.filter(!this.active || this.last() ? ":first" : ":last"));
584		}
585	},
586
587	// TODO merge with nextPage
588	previousPage: function(event) {
589		if (this.hasScroll()) {
590			// TODO merge with no-scroll-else
591			if (!this.active || this.first()) {
592				this.activate(event, this.element.children(".ui-menu-item:last"));
593				return;
594			}
595
596			var base = this.active.offset().top,
597				height = this.element.height();
598				result = this.element.children(".ui-menu-item").filter(function() {
599					var close = $(this).offset().top - base + height - $(this).height();
600					// TODO improve approximation
601					return close < 10 && close > -10;
602				});
603
604			// TODO try to catch this earlier when scrollTop indicates the last page anyway
605			if (!result.length) {
606				result = this.element.children(".ui-menu-item:first");
607			}
608			this.activate(event, result);
609		} else {
610			this.activate(event, this.element.children(".ui-menu-item")
611				.filter(!this.active || this.first() ? ":last" : ":first"));
612		}
613	},
614
615	hasScroll: function() {
616		return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight");
617	},
618
619	select: function( event ) {
620		this._trigger("selected", event, { item: this.active });
621	}
622});
623
624}(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.