PageSourceSearch

https://www.absolon.cz/assets-bda2c34b546e34501eeea8f86e541433/js/selectmenu/jquery.ui.selectmenu.js

js absolon.cz collected 2026-10-02 22:36:09 UTC 27,150 bytes, 886 lines download raw bytes

1 /*
2 * jQuery UI selectmenu 1.3.0pre version
3 *
4 * Copyright (c) 2009-2010 filament group, http://filamentgroup.com
5 * Copyright (c) 2010-2012 Felix Nagel, http://www.felixnagel.com
6 * Dual licensed under the MIT (MIT-LICENSE.txt)
7 * and GPL (GPL-LICENSE.txt) licenses.
8 *
9 * http://docs.jquery.com/UI
10 * https://github.com/fnagel/jquery-ui/wiki/Selectmenu
11 */
12
13(function($) {
14
15$.widget("ui.selectmenu", {
16	options: {
17		appendTo: "body",
18		typeAhead: 1000,
19		style: 'dropdown',
20		positionOptions: {
21			my: "left top",
22			at: "left bottom",
23			offset: null
24		},
25		//width: "97.6%",
26		//menuWidth: "auto",
27		//handleWidth: 26,
28		maxHeight: "auto",   
29		icons: null,
30		format: null,
31		escapeHtml: false,
32		bgImage: function() {}
33	},
34
35	_create: function() {
36		var self = this, o = this.options;
37
38		// set a default id value, generate a new random one if not set by developer
39		var selectmenuId = (this.element.attr( 'id' ) || 'ui-selectmenu-' + Math.random().toString( 16 ).slice( 2, 10 )).replace(/(:|\.)/g,'')
40
41		// quick array of button and menu id's
42		this.ids = [ selectmenuId, selectmenuId + '-button', selectmenuId + '-menu' ];
43
44		// define safe mouseup for future toggling
45		this._safemouseup = true;
46		this.isOpen = false;
47
48		// create menu button wrapper
49		this.newelement = $( '<a />', {
50			'class': this.widgetBaseClass + ' ui-widget ui-state-default ui-corner-all',
51			'id' : this.ids[ 1 ],
52			'role': 'button',
53			'href': '#nogo',
54			'tabindex': this.element.attr( 'disabled' ) ? 1 : 0,
55			'aria-haspopup': true,
56			'aria-owns': this.ids[ 2 ]
57		});
58		this.newelementWrap = $( "<span />" )
59			.append( this.newelement )
60			.insertAfter( this.element );
61
62		// transfer tabindex
63		var tabindex = this.element.attr( 'tabindex' );
64		if ( tabindex ) {
65			this.newelement.attr( 'tabindex', tabindex );
66		}
67
68		// save reference to select in data for ease in calling methods
69		this.newelement.data( 'selectelement', this.element );
70
71		// menu icon
72		this.selectmenuIcon = $( '<span class="' + this.widgetBaseClass + '-icon ui-icon"></span>' )
73			.prependTo( this.newelement );
74
75		// append status span to button
76		this.newelement.prepend( '<span class="' + self.widgetBaseClass + '-status" />' );
77
78		// make associated form label trigger focus
79		this.element.bind({
80			'click.selectmenu':  function( event ) {
81				self.newelement.focus();
82				event.preventDefault();
83			}
84		});
85
86		// click toggle for menu visibility
87		this.newelement
88			.bind('mousedown.selectmenu', function(event) {
89				self._toggle(event, true);
90				// make sure a click won't open/close instantly
91				if (o.style == "popup") {
92					self._safemouseup = false;
93					setTimeout(function() { self._safemouseup = true; }, 300);
94				}
95				return false;
96			})
97			.bind('click.selectmenu', function() {
98				return false;
99			})
100			.bind("keydown.selectmenu", function(event) {
101				var ret = false;
102				switch (event.keyCode) {
103					case $.ui.keyCode.ENTER:
104						ret = true;
105						break;
106					case $.ui.keyCode.SPACE:
107						self._toggle(event);
108						break;
109					case $.ui.keyCode.UP:
110						if (event.altKey) {
111							self.open(event);
112						} else {
113							self._moveSelection(-1);
114						}
115						break;
116					case $.ui.keyCode.DOWN:
117						if (event.altKey) {
118							self.open(event);
119						} else {
120							self._moveSelection(1);
121						}
122						break;
123					case $.ui.keyCode.LEFT:
124						self._moveSelection(-1);
125						break;
126					case $.ui.keyCode.RIGHT:
127						self._moveSelection(1);
128						break;
129					case $.ui.keyCode.TAB:
130						ret = true;
131						break;
132					case $.ui.keyCode.PAGE_UP:
133					case $.ui.keyCode.HOME:
134						self.index(0);
135						break;
136					case $.ui.keyCode.PAGE_DOWN:
137					case $.ui.keyCode.END:
138						self.index(self._optionLis.length);
139						break;
140					default:
141						ret = true;
142				}
143				return ret;
144			})
145			.bind('keypress.selectmenu', function(event) {
146				if (event.which > 0) {
147					self._typeAhead(event.which, 'mouseup');
148				}
149				return true;
150			})
151			.bind('mouseover.selectmenu', function() {
152				if (!o.disabled) $(this).addClass('ui-state-hover');
153			})
154			.bind('mouseout.selectmenu', function() {
155				if (!o.disabled) $(this).removeClass('ui-state-hover');
156			})
157			.bind('focus.selectmenu', function() {
158				if (!o.disabled) $(this).addClass('ui-state-focus');
159			})
160			.bind('blur.selectmenu', function() {
161				if (!o.disabled) $(this).removeClass('ui-state-focus');
162			});
163
164		// document click closes menu
165		$(document).bind("mousedown.selectmenu-" + this.ids[0], function(event) {
166			if ( self.isOpen ) {
167				self.close( event );
168			}
169		});
170
171		// change event on original selectmenu
172		this.element
173			.bind("click.selectmenu", function() {
174				self._refreshValue();
175			})
176			// FIXME: newelement can be null under unclear circumstances in IE8
177			// TODO not sure if this is still a problem (fnagel 20.03.11)
178			.bind("focus.selectmenu", function() {
179				if (self.newelement) {
180					self.newelement[0].focus();
181				}
182			});
183
184		// set width when not set via options
185		if (!o.width) {
186			o.width = $('#VarietiesSelectMenu').width()-10;
187			//o.width = this.element.outerWidth();
188		}
189		// set menu button width
190		this.newelement.width(o.width);
191
192		// hide original selectmenu element
193		this.element.hide();
194
195		// create menu portion, append to body
196		this.list = $( '<ul />', {
197			'class': 'ui-widget ui-widget-content',
198			'aria-hidden': true,
199			'role': 'listbox',
200			'aria-labelledby': this.ids[1],
201			'id': this.ids[2]
202		});
203		this.listWrap = $( "<div />", {
204			'class': self.widgetBaseClass + '-menu'
205		}).append( this.list ).appendTo( o.appendTo );
206
207		// transfer menu click to menu button
208		this.list
209			.bind("keydown.selectmenu", function(event) {
210				var ret = false;
211				switch (event.keyCode) {
212					case $.ui.keyCode.UP:
213						if (event.altKey) {
214							self.close(event, true);
215						} else {
216							self._moveFocus(-1);
217						}
218						break;
219					case $.ui.keyCode.DOWN:
220						if (event.altKey) {
221							self.close(event, true);
222						} else {
223							self._moveFocus(1);
224						}
225						break;
226					case $.ui.keyCode.LEFT:
227						self._moveFocus(-1);
228						break;
229					case $.ui.keyCode.RIGHT:
230						self._moveFocus(1);
231						break;
232					case $.ui.keyCode.HOME:
233						self._moveFocus(':first');
234						break;
235					case $.ui.keyCode.PAGE_UP:
236						self._scrollPage('up');
237						break;
238					case $.ui.keyCode.PAGE_DOWN:
239						self._scrollPage('down');
240						break;
241					case $.ui.keyCode.END:
242						self._moveFocus(':last');
243						break;
244					case $.ui.keyCode.ENTER:
245					case $.ui.keyCode.SPACE:
246						self.close(event, true);
247						$(event.target).parents('li:eq(0)').trigger('mouseup');
248						break;
249					case $.ui.keyCode.TAB:
250						ret = true;
251						self.close(event, true);
252						$(event.target).parents('li:eq(0)').trigger('mouseup');
253						break;
254					case $.ui.keyCode.ESCAPE:
255						self.close(event, true);
256						break;
257					default:
258						ret = true;
259				}
260				return ret;
261			})
262			.bind('keypress.selectmenu', function(event) {
263				if (event.which > 0) {
264					self._typeAhead(event.which, 'focus');
265				}
266				return true;
267			})
268			// this allows for using the scrollbar in an overflowed list
269			.bind( 'mousedown.selectmenu mouseup.selectmenu', function() { return false; });
270
271		// needed when window is resized
272		$(window).bind( "resize.selectmenu-" + this.ids[0], $.proxy( self.close, this ) );
273	},
274
275	_init: function() {
276		var self = this, o = this.options;
277
278		// serialize selectmenu element options
279		var selectOptionData = [];
280		this.element.find('option').each(function() {
281			var opt = $(this);
282			selectOptionData.push({
283				value: opt.attr('value'),
284				text: self._formatText(opt.text()),
285				selected: opt.prop('selected'),
286				disabled: opt.prop('disabled'),
287				classes: opt.attr('class'),
288				typeahead: opt.attr('typeahead'),
289				parentOptGroup: opt.parent('optgroup'),
290				bgImage: o.bgImage.call(opt)
291			});
292		});
293
294		// active state class is only used in popup style
295		var activeClass = (self.options.style == "popup") ? " ui-state-active" : "";
296
297		// empty list so we can refresh the selectmenu via selectmenu()
298		this.list.html("");
299
300		// write li's
301		if (selectOptionData.length) {
302			for (var i = 0; i < selectOptionData.length; i++) {
303				var thisLiAttr = { role : 'presentation' };
304				if ( selectOptionData[ i ].disabled ) {
305					thisLiAttr[ 'class' ] = this.namespace + '-state-disabled';
306				}
307				var thisAAttr = {
308					html: selectOptionData[i].text || '&nbsp;',
309					href : '#nogo',
310					tabindex : -1,
311					role : 'option',
312					'aria-selected' : false,
313					focus: function() {					    
314					    // bubble the focus event
315						// TODO: this isnt a clean solution, see #241
316					    $(this).parent().focus();
317					}
318				};
319				if ( selectOptionData[ i ].disabled ) {
320					thisAAttr[ 'aria-disabled' ] = selectOptionData[ i ].disabled;
321				}
322				if ( selectOptionData[ i ].typeahead ) {
323					thisAAttr[ 'typeahead' ] = selectOptionData[ i ].typeahead;
324				}
325				var thisA = $('<a/>', thisAAttr);
326				var thisLi = $('<li/>', thisLiAttr)
327					.append(thisA)
328					.data('index', i)
329					.addClass(selectOptionData[i].classes)
330					.data('optionClasses', selectOptionData[i].classes || '')
331					.bind("mouseup.selectmenu", function(event) {
332						if (self._safemouseup && !self._disabled(event.currentTarget) && !self._disabled($( event.currentTarget ).parents( "ul>li." + self.widgetBaseClass + "-group " )) ) {
333							var changed = $(this).data('index') != self._selectedIndex();
334							self.index($(this).data('index'));
335							self.select(event);
336							if (changed) {
337								self.change(event);
338							}
339							self.close(event, true);
340						}
341						return false;
342					})
343					.bind("click.selectmenu", function() {
344						return false;
345					})
346					.bind('mouseover.selectmenu focus.selectmenu', function(e) {
347						// no hover if diabled
348						if (!$(e.currentTarget).hasClass(self.namespace + '-state-disabled') && !$(e.currentTarget).parent("ul").parent("li").hasClass(self.namespace + '-state-disabled')) {
349							self._selectedOptionLi().addClass(activeClass);
350							self._focusedOptionLi().removeClass(self.widgetBaseClass + '-item-focus ui-state-hover');
351							$(this).removeClass('ui-state-active').addClass(self.widgetBaseClass + '-item-focus ui-state-hover');
352						}
353					})
354					.bind('mouseout.selectmenu blur.selectmenu', function() {
355						if ($(this).is(self._selectedOptionLi().selector)) {
356							$(this).addClass(activeClass);
357						}
358						$(this).removeClass(self.widgetBaseClass + '-item-focus ui-state-hover');
359					});
360
361				// optgroup or not...
362				if ( selectOptionData[i].parentOptGroup.length ) {
363					var optGroupName = self.widgetBaseClass + '-group-' + this.element.find( 'optgroup' ).index( selectOptionData[i].parentOptGroup );
364					if (this.list.find( 'li.' + optGroupName ).length ) {
365						this.list.find( 'li.' + optGroupName + ':last ul' ).append( thisLi );
366					} else {
367						$(' <li role="presentation" class="' + self.widgetBaseClass + '-group ' + optGroupName + (selectOptionData[i].parentOptGroup.prop("disabled") ? ' ' + this.namespace + '-state-disabled" aria-disabled="true"' : '"' ) + '><span class="' + self.widgetBaseClass + '-group-label">' + selectOptionData[i].parentOptGroup.attr('label') + '</span><ul></ul></li> ')
368							.appendTo( this.list )
369							.find( 'ul' )
370							.append( thisLi );
371					}
372				} else {
373					thisLi.appendTo(this.list);
374				}
375
376				// append icon if option is specified
377				if (o.icons) {
378					for (var j in o.icons) {
379						if (thisLi.is(o.icons[j].find)) {
380							thisLi
381								.data('optionClasses', selectOptionData[i].classes + ' ' + self.widgetBaseClass + '-hasIcon')
382								.addClass(self.widgetBaseClass + '-hasIcon');
383							var iconClass = o.icons[j].icon || "";
384							thisLi
385								.find('a:eq(0)')
386								.prepend('<span class="' + self.widgetBaseClass + '-item-icon ui-icon ' + iconClass + '"></span>');
387							if (selectOptionData[i].bgImage) {
388								thisLi.find('span').css('background-image', selectOptionData[i].bgImage);
389							}
390						}
391					}
392				}
393			}
394		} else {
395			$('<li role="presentation"><a href="#nogo" tabindex="-1" role="option"></a></li>').appendTo(this.list);
396		}
397		// we need to set and unset the CSS classes for dropdown and popup style
398		var isDropDown = ( o.style == 'dropdown' );
399		this.newelement
400			.toggleClass( self.widgetBaseClass + '-dropdown', isDropDown )
401			.toggleClass( self.widgetBaseClass + '-popup', !isDropDown );
402		this.list
403			.toggleClass( self.widgetBaseClass + '-menu-dropdown ui-corner-bottom', isDropDown )
404			.toggleClass( self.widgetBaseClass + '-menu-popup ui-corner-all', !isDropDown )
405			// add corners to top and bottom menu items
406			.find( 'li:first' )
407			.toggleClass( 'ui-corner-top', !isDropDown )
408			.end().find( 'li:last' )
409			.addClass( 'ui-corner-bottom' );
410		this.selectmenuIcon
411			.toggleClass( 'ui-icon-triangle-1-s', isDropDown )
412			.toggleClass( 'ui-icon-triangle-2-n-s', !isDropDown );
413
414		// set menu width to either menuWidth option value, width option value, or select width
415		if ( o.style == 'dropdown' ) {
416			this.list.width( $('#VarietiesSelectMenu').width()-10/*o.menuWidth ? o.menuWidth : o.width*/ );
417		} else {
418			this.list.width( $('#VarietiesSelectMenu').width()-40 /*o.menuWidth ? o.menuWidth : o.width - o.handleWidth */);
419		}
420
421		// reset height to auto
422		this.list.css( 'height', 'auto' );
423		var listH = this.listWrap.height();
424		var winH = $( window ).height();
425		// calculate default max height
426		var maxH = o.maxHeight ? Math.min( o.maxHeight, winH ) : winH / 3;
427		if ( listH > maxH ) this.list.height( maxH );
428
429		// save reference to actionable li's (not group label li's)
430		this._optionLis = this.list.find( 'li:not(.' + self.widgetBaseClass + '-group)' );
431
432		// transfer disabled state
433		if ( this.element.attr( 'disabled' ) ) {
434			this.disable();
435		} else {
436			this.enable();
437		}
438
439		// update value
440		this._refreshValue();
441
442		// set selected item so movefocus has intial state
443		this._selectedOptionLi().addClass(this.widgetBaseClass + '-item-focus');
444
445		// needed when selectmenu is placed at the very bottom / top of the page
446		clearTimeout(this.refreshTimeout);
447		this.refreshTimeout = window.setTimeout(function () {
448			self._refreshPosition();
449		}, 200);
450	},
451
452	destroy: function() {
453		this.element.removeData( this.widgetName )
454			.removeClass( this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled' )
455			.removeAttr( 'aria-disabled' )
456			.unbind( ".selectmenu" );
457
458		$( window ).unbind( ".selectmenu-" + this.ids[0] );
459		$( document ).unbind( ".selectmenu-" + this.ids[0] );
460
461		this.newelementWrap.remove();
462		this.listWrap.remove();
463
464		// unbind click event and show original select
465		this.element
466			.unbind(".selectmenu")
467			.show();
468
469		// call widget destroy function
470		$.Widget.prototype.destroy.apply(this, arguments);
471	},
472
473	_typeAhead: function( code, eventType ) {
474		var self = this,
475			c = String.fromCharCode(code).toLowerCase(),
476			matchee = null,
477			nextIndex = null;
478
479		// Clear any previous timer if present
480		if ( self._typeAhead_timer ) {
481			window.clearTimeout( self._typeAhead_timer );
482			self._typeAhead_timer = undefined;
483		}
484
485		// Store the character typed
486		self._typeAhead_chars = (self._typeAhead_chars === undefined ? "" : self._typeAhead_chars).concat(c);
487
488		// Detect if we are in cyciling mode or direct selection mode
489		if ( self._typeAhead_chars.length < 2 ||
490		     (self._typeAhead_chars.substr(-2, 1) === c && self._typeAhead_cycling) ) {
491			self._typeAhead_cycling = true;
492
493			// Match only the first character and loop
494			matchee = c;
495		}
496		else {
497			// We won't be cycling anymore until the timer expires
498			self._typeAhead_cycling = false;
499
500			// Match all the characters typed
501			matchee = self._typeAhead_chars;
502		}
503
504		// We need to determine the currently active index, but it depends on
505		// the used context: if it's in the element, we want the actual
506		// selected index, if it's in the menu, just the focused one
507		// I copied this code from _moveSelection() and _moveFocus()
508		// respectively --thg2k
509		var selectedIndex = (eventType !== 'focus' ?
510			this._selectedOptionLi().data('index') :
511			this._focusedOptionLi().data('index')) || 0;
512
513		for (var i = 0; i < this._optionLis.length; i++) {
514			var thisText = this._optionLis.eq(i).text().substr(0, matchee.length).toLowerCase();
515
516			if ( thisText === matchee ) {
517				if ( self._typeAhead_cycling ) {
518					if ( nextIndex === null )
519						nextIndex = i;
520
521					if ( i > selectedIndex ) {
522						nextIndex = i;
523						break;
524					}
525				} else {
526					nextIndex = i;
527				}
528			}
529		}
530
531		if ( nextIndex !== null ) {
532			// Why using trigger() instead of a direct method to select the
533			// index? Because we don't what is the exact action to do, it
534			// depends if the user is typing on the element or on the popped
535			// up menu
536			this._optionLis.eq(nextIndex).find("a").trigger( eventType );
537		}
538
539		self._typeAhead_timer = window.setTimeout(function() {
540			self._typeAhead_timer = undefined;
541			self._typeAhead_chars = undefined;
542			self._typeAhead_cycling = undefined;
543		}, self.options.typeAhead);
544	},
545
546	// returns some usefull information, called by callbacks only
547	_uiHash: function() {
548		var index = this.index();
549		return {
550			index: index,
551			option: $("option", this.element).get(index),
552			value: this.element[0].value
553		};
554	},
555
556	open: function(event) {
557		var self = this, o = this.options;
558		if ( self.newelement.attr("aria-disabled") != 'true' ) {
559			self._closeOthers(event);
560			self.newelement.addClass('ui-state-active');
561
562			self.list.attr('aria-hidden', false);
563			self.listWrap.addClass( self.widgetBaseClass + '-open' );
564
565			var selected = this._selectedOptionLi();
566			if ( o.style == "dropdown" ) {
567				self.newelement.removeClass('ui-corner-all').addClass('ui-corner-top');
568			} else {
569				// center overflow and avoid flickering
570				this.list
571					.css("left", -5000)
572					.scrollTop( this.list.scrollTop() + selected.position().top - this.list.outerHeight()/2 + selected.outerHeight()/2 )
573					.css("left","auto");
574			}
575
576			self._refreshPosition();
577
578			var link = selected.find("a");
579			if (link.length) link[0].focus();
580
581			self.isOpen = true;
582			self._trigger("open", event, self._uiHash());
583		}
584	},
585
586	close: function(event, retainFocus) {
587		if ( this.newelement.is('.ui-state-active') ) {
588			this.newelement
589				.removeClass('ui-state-active');
590			this.listWrap.removeClass(this.widgetBaseClass + '-open');
591			this.list.attr('aria-hidden', true);
592			if ( this.options.style == "dropdown" ) {
593				this.newelement.removeClass('ui-corner-top').addClass('ui-corner-all');
594			}
595			if ( retainFocus ) {
596				this.newelement.focus();
597			}
598			this.isOpen = false;
599			this._trigger("close", event, this._uiHash());
600		}
601	},
602/*
603	jed: function() {
604		var element = document.getElementById("nextLine"); 
605		element.setAttribute("class", "ui-selectmenu-item-content");
606		element.setAttribute("className", "ui-selectmenu-item-content");// pro IE
607		this.element.removeClass("ui-selectmenu-item-content-detail").addClass("ui-selectmenu-item-content");
608	},
609*/
610
611	change: function(event) {
612		this.element.trigger("change");
613		this._trigger("change", event, this._uiHash());
614	},
615
616	select: function(event) {
617		if (this._disabled(event.currentTarget)) { return false; }
618		this._trigger("select", event, this._uiHash());
619	},
620
621	widget: function() {
622		return this.listWrap.add( this.newelementWrap );
623	},
624
625	_closeOthers: function(event) {
626		$('.' + this.widgetBaseClass + '.ui-state-active').not(this.newelement).each(function() {
627			$(this).data('selectelement').selectmenu('close', event);
628		});
629		$('.' + this.widgetBaseClass + '.ui-state-hover').trigger('mouseout');
630	},
631
632	_toggle: function(event, retainFocus) {
633		if ( this.isOpen ) {
634			this.close(event, retainFocus);
635		} else {
636			this.open(event);
637		}
638	},
639
640	_formatText: function(text) {
641		if (this.options.format) {
642			text = this.options.format(text);
643		} else if (this.options.escapeHtml) {
644			text = $('<div />').text(text).html();
645		}
646		return text;
647	},
648
649	_selectedIndex: function() {
650		return this.element[0].selectedIndex;
651	},
652
653	_selectedOptionLi: function() {
654		return this._optionLis.eq(this._selectedIndex());
655	},
656
657	_focusedOptionLi: function() {
658		return this.list.find('.' + this.widgetBaseClass + '-item-focus');
659	},
660
661	_moveSelection: function(amt, recIndex) {
662		// do nothing if disabled
663		if (!this.options.disabled) {
664			var currIndex = parseInt(this._selectedOptionLi().data('index') || 0, 10);
665			var newIndex = currIndex + amt;
666			// do not loop when using up key
667
668			if (newIndex < 0) {
669				newIndex = 0;
670			}
671			if (newIndex > this._optionLis.size() - 1) {
672				newIndex = this._optionLis.size() - 1;
673			}
674			// Occurs when a full loop has been made
675			if (newIndex === recIndex) { return false; }
676
677			if (this._optionLis.eq(newIndex).hasClass( this.namespace + '-state-disabled' )) {
678				// if option at newIndex is disabled, call _moveFocus, incrementing amt by one
679				(amt > 0) ? ++amt : --amt;
680				this._moveSelection(amt, newIndex);
681			} else {
682				this._optionLis.eq(newIndex).trigger('mouseover').trigger('mouseup');
683			}
684		}
685	},
686
687	_moveFocus: function(amt, recIndex) {
688		if (!isNaN(amt)) {
689			var currIndex = parseInt(this._focusedOptionLi().data('index') || 0, 10);
690			var newIndex = currIndex + amt;
691		} else {
692			var newIndex = parseInt(this._optionLis.filter(amt).data('index'), 10);
693		}
694
695		if (newIndex < 0) {
696			newIndex = 0;
697		}
698		if (newIndex > this._optionLis.size() - 1) {
699			newIndex = this._optionLis.size() - 1;
700		}
701
702		//Occurs when a full loop has been made
703		if (newIndex === recIndex) { return false; }
704
705		var activeID = this.widgetBaseClass + '-item-' + Math.round(Math.random() * 1000);
706
707		this._focusedOptionLi().find('a:eq(0)').attr('id', '');
708
709		if (this._optionLis.eq(newIndex).hasClass( this.namespace + '-state-disabled' )) {
710			// if option at newIndex is disabled, call _moveFocus, incrementing amt by one
711			(amt > 0) ? ++amt : --amt;
712			this._moveFocus(amt, newIndex);
713		} else {
714			this._optionLis.eq(newIndex).find('a:eq(0)').attr('id',activeID).focus();
715		}
716
717		this.list.attr('aria-activedescendant', activeID);
718	},
719
720	_scrollPage: function(direction) {
721		var numPerPage = Math.floor(this.list.outerHeight() / this._optionLis.first().outerHeight());
722		numPerPage = (direction == 'up' ? -numPerPage : numPerPage);
723		this._moveFocus(numPerPage);
724	},
725
726	_setOption: function(key, value) {
727		this.options[key] = value;
728		// set
729		if (key == 'disabled') {
730			if (value) this.close();
731			this.element
732				.add(this.newelement)
733				.add(this.list)[value ? 'addClass' : 'removeClass'](
734					this.widgetBaseClass + '-disabled' + ' ' +
735					this.namespace + '-state-disabled')
736				.attr("aria-disabled", value);
737		}
738	},
739
740	disable: function(index, type){
741			// if options is not provided, call the parents disable function
742			if ( typeof( index ) == 'undefined' ) {
743				this._setOption( 'disabled', true );
744			} else {
745				if ( type == "optgroup" ) {
746					this._disableOptgroup(index);
747				} else {
748					this._disableOption(index);
749				}
750			}
751	},
752
753	enable: function(index, type) {
754			// if options is not provided, call the parents enable function
755			if ( typeof( index ) == 'undefined' ) {
756				this._setOption('disabled', false);
757			} else {
758				if ( type == "optgroup" ) {
759					this._enableOptgroup(index);
760				} else {
761					this._enableOption(index);
762				}
763			}
764	},
765
766	_disabled: function(elem) {
767			return $(elem).hasClass( this.namespace + '-state-disabled' );
768	},
769
770
771	_disableOption: function(index) {
772			var optionElem = this._optionLis.eq(index);
773			if (optionElem) {
774				optionElem.addClass(this.namespace + '-state-disabled')
775					.find("a").attr("aria-disabled", true);
776				this.element.find("option").eq(index).prop("disabled", "disabled");
777			}
778	},
779
780	_enableOption: function(index) {
781			var optionElem = this._optionLis.eq(index);
782			if (optionElem) {
783				optionElem.removeClass( this.namespace + '-state-disabled' )
784					.find("a").attr("aria-disabled", false);
785				this.element.find("option").eq(index).prop("disabled",false);
786			}
787	},
788
789	_disableOptgroup: function(index) {
790			var optGroupElem = this.list.find( 'li.' + this.widgetBaseClass + '-group-' + index );
791			if (optGroupElem) {
792				optGroupElem.addClass(this.namespace + '-state-disabled')
793					.attr("aria-disabled", true);
794				this.element.find("optgroup").eq(index).prop("disabled", "disabled");
795			}
796	},
797
798	_enableOptgroup: function(index) {
799			var optGroupElem = this.list.find( 'li.' + this.widgetBaseClass + '-group-' + index );
800			if (optGroupElem) {
801				optGroupElem.removeClass(this.namespace + '-state-disabled')
802					.attr("aria-disabled", false);
803				this.element.find("optgroup").eq(index).removeAttr("disabled");
804			}
805	},
806
807	index: function(newValue) {
808		if (arguments.length) {
809			if (!this._disabled($(this._optionLis[newValue]))) {
810				this.element[0].selectedIndex = newValue;
811				this._refreshValue();
812			} else {
813				return false;
814			}
815		} else {
816			return this._selectedIndex();
817		}
818	},
819
820	value: function(newValue) {
821		if (arguments.length) {
822			this.element[0].value = newValue;
823			this._refreshValue();
824		} else {
825			return this.element[0].value;
826		}
827	},
828
829	_refreshValue: function() {
830		var activeClass = (this.options.style == "popup") ? " ui-state-active" : "";
831		var activeID = this.widgetBaseClass + '-item-' + Math.round(Math.random() * 1000);
832		// deselect previous
833		this.list
834			.find('.' + this.widgetBaseClass + '-item-selected')
835			.removeClass(this.widgetBaseClass + "-item-selected" + activeClass)
836			.find('a')
837			.attr('aria-selected', 'false')
838			.attr('id', '');
839		// select new
840		this._selectedOptionLi()
841			.addClass(this.widgetBaseClass + "-item-selected" + activeClass)
842			.find('a')
843			.attr('aria-selected', 'true')
844			.attr('id', activeID);
845
846		// toggle any class brought in from option
847		var currentOptionClasses = (this.newelement.data('optionClasses') ? this.newelement.data('optionClasses') : "");
848		var newOptionClasses = (this._selectedOptionLi().data('optionClasses') ? this._selectedOptionLi().data('optionClasses') : "");
849		this.newelement
850			.removeClass(currentOptionClasses)
851			.data('optionClasses', newOptionClasses)
852			.addClass( newOptionClasses )
853			.find('.' + this.widgetBaseClass + '-status')
854			.html(
855				this._selectedOptionLi()
856					.find('a:eq(0)')
857					.html()
858			);
859
860		this.list.attr('aria-activedescendant', activeID);
861	},
862
863	_refreshPosition: function() {
864		var o = this.options;
865
866		// if its a pop-up we need to calculate the position of the selected li
867		if ( o.style == "popup" && !o.positionOptions.offset ) {
868			var selected = this._selectedOptionLi();
869			var _offset = "0 " + ( this.list.offset().top  - selected.offset().top - ( this.newelement.outerHeight() + selected.outerHeight() ) / 2);
870		}
871		this.listWrap
872			.removeAttr('style')
873			.zIndex( this.element.zIndex() + 1000000 )
874			.css('position', 'absolute')
875			.position({
876				// set options for position plugin
877				of: o.positionOptions.of || this.newelement,
878				my: o.positionOptions.my,
879				at: o.positionOptions.at,
880				offset: o.positionOptions.offset || _offset,
881				collision: o.positionOptions.collision || o.style == "popup" ? 'fit' :'flip'
882			});
883	}
884});
885
886})(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.