PageSourceSearch

https://www.libriincantina.it/wp-includes/js/jquery/ui/menu.js?ver=1.14.2

js libriincantina.it collected 2026-10-02 07:12:38 UTC 18,907 bytes, 712 lines download raw bytes

vendor: 18,907 bytes, lines 1-712
1/*!
2 * jQuery UI Menu 1.14.2
3 * https://jqueryui.com
4 *
5 * Copyright OpenJS Foundation and other contributors
6 * Released under the MIT license.
7 * https://jquery.org/license
8 */
9
10//>>label: Menu
11//>>group: Widgets
12//>>description: Creates nestable menus.
13//>>docs: https://api.jqueryui.com/menu/
14//>>demos: https://jqueryui.com/menu/
15//>>css.structure: ../../themes/base/core.css
16//>>css.structure: ../../themes/base/menu.css
17//>>css.theme: ../../themes/base/theme.css
18
19( function( factory ) {
20	"use strict";
21
22	if ( typeof define === "function" && define.amd ) {
23
24		// AMD. Register as an anonymous module.
25		define( [
26			"jquery",
27			"../keycode",
28			"../position",
29			"../unique-id",
30			"../version",
31			"../widget"
32		], factory );
33	} else {
34
35		// Browser globals
36		factory( jQuery );
37	}
38} )( function( $ ) {
39"use strict";
40
41return $.widget( "ui.menu", {
42	version: "1.14.2",
43	defaultElement: "<ul>",
44	delay: 300,
45	options: {
46		icons: {
47			submenu: "ui-icon-caret-1-e"
48		},
49		items: "> *",
50		menus: "ul",
51		position: {
52			my: "left top",
53			at: "right top"
54		},
55		role: "menu",
56
57		// Callbacks
58		blur: null,
59		focus: null,
60		select: null
61	},
62
63	_create: function() {
64		this.activeMenu = this.element;
65
66		// Flag used to prevent firing of the click handler
67		// as the event bubbles up through nested menus
68		this.mouseHandled = false;
69		this.lastMousePosition = { x: null, y: null };
70		this.element
71			.uniqueId()
72			.attr( {
73				role: this.options.role,
74				tabIndex: 0
75			} );
76
77		this._addClass( "ui-menu", "ui-widget ui-widget-content" );
78		this._on( {
79
80			// Prevent focus from sticking to links inside menu after clicking
81			// them (focus should always stay on UL during navigation).
82			"mousedown .ui-menu-item": function( event ) {
83				event.preventDefault();
84
85				this._activateItem( event );
86			},
87			"click .ui-menu-item": function( event ) {
88				var target = $( event.target );
89				var active = $( this.document[ 0 ].activeElement );
90				if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
91					this.select( event );
92
93					// Only set the mouseHandled flag if the event will bubble, see #9469.
94					if ( !event.isPropagationStopped() ) {
95						this.mouseHandled = true;
96					}
97
98					// Open submenu on click
99					if ( target.has( ".ui-menu" ).length ) {
100						this.expand( event );
101					} else if ( !this.element.is( ":focus" ) &&
102							active.closest( ".ui-menu" ).length ) {
103
104						// Redirect focus to the menu
105						this.element.trigger( "focus", [ true ] );
106
107						// If the active item is on the top level, let it stay active.
108						// Otherwise, blur the active item since it is no longer visible.
109						if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
110							clearTimeout( this.timer );
111						}
112					}
113				}
114			},
115			"mouseenter .ui-menu-item": "_activateItem",
116			"mousemove .ui-menu-item": "_activateItem",
117			mouseleave: "collapseAll",
118			"mouseleave .ui-menu": "collapseAll",
119			focus: function( event, keepActiveItem ) {
120
121				// If there's already an active item, keep it active
122				// If not, activate the first item
123				var item = this.active || this._menuItems().first();
124
125				if ( !keepActiveItem ) {
126					this.focus( event, item );
127				}
128			},
129			blur: function( event ) {
130				this._delay( function() {
131					var notContained = !$.contains(
132						this.element[ 0 ],
133						this.document[ 0 ].activeElement
134					);
135					if ( notContained ) {
136						this.collapseAll( event );
137					}
138				} );
139			},
140			keydown: "_keydown"
141		} );
142
143		this.refresh();
144
145		// Clicks outside of a menu collapse any open menus
146		this._on( this.document, {
147			click: function( event ) {
148				if ( this._closeOnDocumentClick( event ) ) {
149					this.collapseAll( event, true );
150				}
151
152				// Reset the mouseHandled flag
153				this.mouseHandled = false;
154			}
155		} );
156	},
157
158	_activateItem: function( event ) {
159
160		// Ignore mouse events while typeahead is active, see #10458.
161		// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
162		// is over an item in the menu
163		if ( this.previousFilter ) {
164			return;
165		}
166
167		// If the mouse didn't actually move, but the page was scrolled, ignore the event (#9356)
168		if ( event.clientX === this.lastMousePosition.x &&
169				event.clientY === this.lastMousePosition.y ) {
170			return;
171		}
172
173		this.lastMousePosition = {
174			x: event.clientX,
175			y: event.clientY
176		};
177
178		var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
179			target = $( event.currentTarget );
180
181		// Ignore bubbled events on parent items, see #11641
182		if ( actualTarget[ 0 ] !== target[ 0 ] ) {
183			return;
184		}
185
186		// If the item is already active, there's nothing to do
187		if ( target.is( ".ui-state-active" ) ) {
188			return;
189		}
190
191		// Remove ui-state-active class from siblings of the newly focused menu item
192		// to avoid a jump caused by adjacent elements both having a class with a border
193		this._removeClass( target.siblings().children( ".ui-state-active" ),
194			null, "ui-state-active" );
195		this.focus( event, target );
196	},
197
198	_destroy: function() {
199		var items = this.element.find( ".ui-menu-item" )
200				.removeAttr( "role aria-disabled" ),
201			submenus = items.children( ".ui-menu-item-wrapper" )
202				.removeUniqueId()
203				.removeAttr( "tabIndex role aria-haspopup" );
204
205		// Destroy (sub)menus
206		this.element
207			.removeAttr( "aria-activedescendant" )
208			.find( ".ui-menu" ).addBack()
209				.removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
210					"tabIndex" )
211				.removeUniqueId()
212				.show();
213
214		submenus.children().each( function() {
215			var elem = $( this );
216			if ( elem.data( "ui-menu-submenu-caret" ) ) {
217				elem.remove();
218			}
219		} );
220	},
221
222	_keydown: function( event ) {
223		var match, prev, character, skip,
224			preventDefault = true;
225
226		switch ( event.keyCode ) {
227		case $.ui.keyCode.PAGE_UP:
228			this.previousPage( event );
229			break;
230		case $.ui.keyCode.PAGE_DOWN:
231			this.nextPage( event );
232			break;
233		case $.ui.keyCode.HOME:
234			this._move( "first", "first", event );
235			break;
236		case $.ui.keyCode.END:
237			this._move( "last", "last", event );
238			break;
239		case $.ui.keyCode.UP:
240			this.previous( event );
241			break;
242		case $.ui.keyCode.DOWN:
243			this.next( event );
244			break;
245		case $.ui.keyCode.LEFT:
246			this.collapse( event );
247			break;
248		case $.ui.keyCode.RIGHT:
249			if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
250				this.expand( event );
251			}
252			break;
253		case $.ui.keyCode.ENTER:
254		case $.ui.keyCode.SPACE:
255			this._activate( event );
256			break;
257		case $.ui.keyCode.ESCAPE:
258			this.collapse( event );
259			break;
260		default:
261			preventDefault = false;
262			prev = this.previousFilter || "";
263			skip = false;
264
265			// Support number pad values
266			character = event.keyCode >= 96 && event.keyCode <= 105 ?
267				( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
268
269			clearTimeout( this.filterTimer );
270
271			if ( character === prev ) {
272				skip = true;
273			} else {
274				character = prev + character;
275			}
276
277			match = this._filterMenuItems( character );
278			match = skip && match.index( this.active.next() ) !== -1 ?
279				this.active.nextAll( ".ui-menu-item" ) :
280				match;
281
282			// If no matches on the current filter, reset to the last character pressed
283			// to move down the menu to the first item that starts with that character
284			if ( !match.length ) {
285				character = String.fromCharCode( event.keyCode );
286				match = this._filterMenuItems( character );
287			}
288
289			if ( match.length ) {
290				this.focus( event, match );
291				this.previousFilter = character;
292				this.filterTimer = this._delay( function() {
293					delete this.previousFilter;
294				}, 1000 );
295			} else {
296				delete this.previousFilter;
297			}
298		}
299
300		if ( preventDefault ) {
301			event.preventDefault();
302		}
303	},
304
305	_activate: function( event ) {
306		if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
307			if ( this.active.children( "[aria-haspopup='true']" ).length ) {
308				this.expand( event );
309			} else {
310				this.select( event );
311			}
312		}
313	},
314
315	refresh: function() {
316		var menus, items, newSubmenus, newItems, newWrappers,
317			that = this,
318			icon = this.options.icons.submenu,
319			submenus = this.element.find( this.options.menus );
320
321		this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
322
323		// Initialize nested menus
324		newSubmenus = submenus.filter( ":not(.ui-menu)" )
325			.hide()
326			.attr( {
327				role: this.options.role,
328				"aria-hidden": "true",
329				"aria-expanded": "false"
330			} )
331			.each( function() {
332				var menu = $( this ),
333					item = menu.prev(),
334					submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
335
336				that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
337				item
338					.attr( "aria-haspopup", "true" )
339					.prepend( submenuCaret );
340				menu.attr( "aria-labelledby", item.attr( "id" ) );
341			} );
342
343		this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
344
345		menus = submenus.add( this.element );
346		items = menus.find( this.options.items );
347
348		// Initialize menu-items containing spaces and/or dashes only as dividers
349		items.not( ".ui-menu-item" ).each( function() {
350			var item = $( this );
351			if ( that._isDivider( item ) ) {
352				that._addClass( item, "ui-menu-divider", "ui-widget-content" );
353			}
354		} );
355
356		// Don't refresh list items that are already adapted
357		newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
358		newWrappers = newItems.children()
359			.not( ".ui-menu" )
360				.uniqueId()
361				.attr( {
362					tabIndex: -1,
363					role: this._itemRole()
364				} );
365		this._addClass( newItems, "ui-menu-item" )
366			._addClass( newWrappers, "ui-menu-item-wrapper" );
367
368		// Add aria-disabled attribute to any disabled menu item
369		items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
370
371		// If the active item has been removed, blur the menu
372		if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
373			this.blur();
374		}
375	},
376
377	_itemRole: function() {
378		return {
379			menu: "menuitem",
380			listbox: "option"
381		}[ this.options.role ];
382	},
383
384	_setOption: function( key, value ) {
385		if ( key === "icons" ) {
386			var icons = this.element.find( ".ui-menu-icon" );
387			this._removeClass( icons, null, this.options.icons.submenu )
388				._addClass( icons, null, value.submenu );
389		}
390		this._super( key, value );
391	},
392
393	_setOptionDisabled: function( value ) {
394		this._super( value );
395
396		this.element.attr( "aria-disabled", String( value ) );
397		this._toggleClass( null, "ui-state-disabled", !!value );
398	},
399
400	focus: function( event, item ) {
401		var nested, focused, activeParent;
402		this.blur( event, event && event.type === "focus" );
403
404		this._scrollIntoView( item );
405
406		this.active = item.first();
407
408		focused = this.active.children( ".ui-menu-item-wrapper" );
409		this._addClass( focused, null, "ui-state-active" );
410
411		// Only update aria-activedescendant if there's a role
412		// otherwise we assume focus is managed elsewhere
413		if ( this.options.role ) {
414			this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
415		}
416
417		// Highlight active parent menu item, if any
418		activeParent = this.active
419			.parent()
420				.closest( ".ui-menu-item" )
421					.children( ".ui-menu-item-wrapper" );
422		this._addClass( activeParent, null, "ui-state-active" );
423
424		if ( event && event.type === "keydown" ) {
425			this._close();
426		} else {
427			this.timer = this._delay( function() {
428				this._close();
429			}, this.delay );
430		}
431
432		nested = item.children( ".ui-menu" );
433		if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
434			this._startOpening( nested );
435		}
436		this.activeMenu = item.parent();
437
438		this._trigger( "focus", event, { item: item } );
439	},
440
441	_scrollIntoView: function( item ) {
442		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
443		if ( this._hasScroll() ) {
444			borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
445			paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
446			offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
447			scroll = this.activeMenu.scrollTop();
448			elementHeight = this.activeMenu.height();
449			itemHeight = item.outerHeight();
450
451			if ( offset < 0 ) {
452				this.activeMenu.scrollTop( scroll + offset );
453			} else if ( offset + itemHeight > elementHeight ) {
454				this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
455			}
456		}
457	},
458
459	blur: function( event, fromFocus ) {
460		if ( !fromFocus ) {
461			clearTimeout( this.timer );
462		}
463
464		if ( !this.active ) {
465			return;
466		}
467
468		this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
469			null, "ui-state-active" );
470
471		this._trigger( "blur", event, { item: this.active } );
472		this.active = null;
473	},
474
475	_startOpening: function( submenu ) {
476		clearTimeout( this.timer );
477
478		// Don't open if already open fixes a Firefox bug that caused a .5 pixel
479		// shift in the submenu position when mousing over the caret icon
480		if ( submenu.attr( "aria-hidden" ) !== "true" ) {
481			return;
482		}
483
484		this.timer = this._delay( function() {
485			this._close();
486			this._open( submenu );
487		}, this.delay );
488	},
489
490	_open: function( submenu ) {
491		var position = $.extend( {
492			of: this.active
493		}, this.options.position );
494
495		clearTimeout( this.timer );
496		this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
497			.hide()
498			.attr( "aria-hidden", "true" );
499
500		submenu
501			.show()
502			.removeAttr( "aria-hidden" )
503			.attr( "aria-expanded", "true" )
504			.position( position );
505	},
506
507	collapseAll: function( event, all ) {
508		clearTimeout( this.timer );
509		this.timer = this._delay( function() {
510
511			// If we were passed an event, look for the submenu that contains the event
512			var currentMenu = all ? this.element :
513				$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
514
515			// If we found no valid submenu ancestor, use the main menu to close all
516			// sub menus anyway
517			if ( !currentMenu.length ) {
518				currentMenu = this.element;
519			}
520
521			this._close( currentMenu );
522
523			this.blur( event );
524
525			// Work around active item staying active after menu is blurred
526			this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
527
528			this.activeMenu = currentMenu;
529		}, all ? 0 : this.delay );
530	},
531
532	// With no arguments, closes the currently active menu - if nothing is active
533	// it closes all menus.  If passed an argument, it will search for menus BELOW
534	_close: function( startMenu ) {
535		if ( !startMenu ) {
536			startMenu = this.active ? this.active.parent() : this.element;
537		}
538
539		startMenu.find( ".ui-menu" )
540			.hide()
541			.attr( "aria-hidden", "true" )
542			.attr( "aria-expanded", "false" );
543	},
544
545	_closeOnDocumentClick: function( event ) {
546		return !$( event.target ).closest( ".ui-menu" ).length;
547	},
548
549	_isDivider: function( item ) {
550
551		// Match hyphen, em dash, en dash
552		return !/[^\-\u2014\u2013\s]/.test( item.text() );
553	},
554
555	collapse: function( event ) {
556		var newItem = this.active &&
557			this.active.parent().closest( ".ui-menu-item", this.element );
558		if ( newItem && newItem.length ) {
559			this._close();
560			this.focus( event, newItem );
561		}
562	},
563
564	expand: function( event ) {
565		var newItem = this.active && this._menuItems( this.active.children( ".ui-menu" ) ).first();
566
567		if ( newItem && newItem.length ) {
568			this._open( newItem.parent() );
569
570			// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
571			this._delay( function() {
572				this.focus( event, newItem );
573			} );
574		}
575	},
576
577	next: function( event ) {
578		this._move( "next", "first", event );
579	},
580
581	previous: function( event ) {
582		this._move( "prev", "last", event );
583	},
584
585	isFirstItem: function() {
586		return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
587	},
588
589	isLastItem: function() {
590		return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
591	},
592
593	_menuItems: function( menu ) {
594		return ( menu || this.element )
595			.find( this.options.items )
596			.filter( ".ui-menu-item" );
597	},
598
599	_move: function( direction, filter, event ) {
600		var next;
601		if ( this.active ) {
602			if ( direction === "first" || direction === "last" ) {
603				next = this.active
604					[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
605					.last();
606			} else {
607				next = this.active
608					[ direction + "All" ]( ".ui-menu-item" )
609					.first();
610			}
611		}
612		if ( !next || !next.length || !this.active ) {
613			next = this._menuItems( this.activeMenu )[ filter ]();
614		}
615
616		this.focus( event, next );
617	},
618
619	nextPage: function( event ) {
620		var item, base, height;
621
622		if ( !this.active ) {
623			this.next( event );
624			return;
625		}
626		if ( this.isLastItem() ) {
627			return;
628		}
629		if ( this._hasScroll() ) {
630			base = this.active.offset().top;
631			height = this.element.innerHeight();
632
633			// jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
634			if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
635				height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
636			}
637
638			this.active.nextAll( ".ui-menu-item" ).each( function() {
639				item = $( this );
640				return item.offset().top - base - height < 0;
641			} );
642
643			this.focus( event, item );
644		} else {
645			this.focus( event, this._menuItems( this.activeMenu )
646				[ !this.active ? "first" : "last" ]() );
647		}
648	},
649
650	previousPage: function( event ) {
651		var item, base, height;
652		if ( !this.active ) {
653			this.next( event );
654			return;
655		}
656		if ( this.isFirstItem() ) {
657			return;
658		}
659		if ( this._hasScroll() ) {
660			base = this.active.offset().top;
661			height = this.element.innerHeight();
662
663			// jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
664			if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
665				height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
666			}
667
668			this.active.prevAll( ".ui-menu-item" ).each( function() {
669				item = $( this );
670				return item.offset().top - base + height > 0;
671			} );
672
673			this.focus( event, item );
674		} else {
675			this.focus( event, this._menuItems( this.activeMenu ).first() );
676		}
677	},
678
679	_hasScroll: function() {
680		return this.element.outerHeight() < this.element.prop( "scrollHeight" );
681	},
682
683	select: function( event ) {
684
685		// TODO: It should never be possible to not have an active item at this
686		// point, but the tests don't trigger mouseenter before click.
687		this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
688		var ui = { item: this.active };
689		if ( !this.active.has( ".ui-menu" ).length ) {
690			this.collapseAll( event, true );
691		}
692		this._trigger( "select", event, ui );
693	},
694
695	_filterMenuItems: function( character ) {
696		var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
697			regex = new RegExp( "^" + escapedCharacter, "i" );
698
699		return this.activeMenu
700			.find( this.options.items )
701
702				// Only match on items, not dividers or other content (#10571)
703				.filter( ".ui-menu-item" )
704					.filter( function() {
705						return regex.test(
706							String.prototype.trim.call(
707								$( this ).children( ".ui-menu-item-wrapper" ).text() ) );
708					} );
709	}
710} );
711
712} );

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.