PageSourceSearch

https://login.ureserv.com/theme/ui/jquery.ui.autocomplete.js

js ureserv.com collected 2026-10-06 04:59:08 UTC 15,299 bytes, 544 lines download raw bytes

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