PageSourceSearch

https://www.planetsenior.de/js/development-bundle/ui/jquery.ui.autocomplete.js

js planetsenior.de collected 2026-10-02 14:08:14 UTC 12,579 bytes, 482 lines download raw bytes

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