PageSourceSearch

https://pro-line.com.tr/wp-content/plugins/responsive-menu/v4.0.0/assets/js/rmp-menu.js?ver=4.7.4

js pro-line.com.tr collected 2026-10-08 23:37:48 UTC 21,089 bytes, 680 lines download raw bytes

1/**
2 * This file contain the scrips for menu frontend.
3 * @author ExpressTech System
4 *
5 * @since 4.0.0
6 */
7
8jQuery( document ).ready( function( jQuery ) {
9
10	/**
11	 * RmpMenu Class
12	 * This RMP class is handling the frontend events and action on menu elements.
13	 * @since      4.0.0
14	 * @access     public
15	 *
16	 * @class      RmpMenu
17	 */
18	class RmpMenu {
19
20		/**
21		 * This is constructor function which is initialize the elements and options.
22		 * @access public
23		 * @since 4.0.0
24		 * @param {Array} options List of options.
25		 */
26		constructor( options ) {
27			RmpMenu.activeToggleClass        = 'is-active';
28			RmpMenu.openContainerClass       = 'rmp-menu-open';
29			RmpMenu.activeSubMenuArrowClass  = 'rmp-menu-subarrow-active';
30			RmpMenu.subMenuClass             = '.rmp-submenu';
31			RmpMenu.activeTopMenuClass  	 = 'rmp-topmenu-active';
32
33			this.options = options;
34			this.menuId  = this.options['menu_id'];
35			this.trigger = '#rmp_menu_trigger-' + this.menuId;
36
37			this.isOpen  = false;
38
39			this.container    =  '#rmp-container-' + this.menuId;
40			this.headerBar    =  '#rmp-header-bar-' + this.menuId;
41			this.menuWrap     =  'ul#rmp-menu-'+ this.menuId;
42			this.subMenuArrow = '.rmp-menu-subarrow';
43			this.wrapper      = '.rmp-container';
44			this.linkElement  = '.rmp-menu-item-link';
45			this.pageWrapper  = this.options['page_wrapper'];
46			this.use_desktop_menu = this.options['use_desktop_menu'];
47			this.originalHeight = '',
48			this.animationSpeed        =  this.options['animation_speed'] * 1000;
49			this.hamburgerBreakpoint   =  this.options['tablet_breakpoint'];
50			this.subMenuTransitionTime =  this.options['sub_menu_speed'] * 1000;
51
52			// The element focus returns to when the panel closes. `this.trigger` may become
53			// a list of selectors once a custom click trigger is configured.
54			this.primaryTrigger = '#rmp_menu_trigger-' + this.menuId;
55
56			// Honour the visitor's motion preference: animating a menu they asked to keep
57			// still is a WCAG 2.3.3 failure, so collapse every duration to zero instead.
58			if ( window.matchMedia && window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches ) {
59				this.animationSpeed        = 0;
60				this.subMenuTransitionTime = 0;
61			}
62
63			if ( this.options['button_click_trigger'].length > 0 ) {
64				this.trigger = this.trigger +' , '+ this.options['button_click_trigger'];
65			}
66
67			//Append hamburger icon inside an element
68			if ( this.options['button_position_type'] == 'inside-element' ) {
69				var destination = jQuery(this.trigger).attr('data-destination');
70				jQuery(this.trigger).appendTo(jQuery(destination).parent());
71			}
72
73			this.init();
74		}
75
76		/**
77		 * This function register the events and initiate the menu settings.
78		 */
79		init() {
80			const self = this;
81
82			/**
83			 * Register click event of trigger.
84			 * @fires click
85			 */
86			jQuery( this.trigger ).on( 'click', function( e ) {
87				e.stopPropagation();
88				self.triggerMenu();
89			} );
90
91			// Show/Hide sub menu item when the item toggle is activated. The toggle is a
92			// <button>, so Enter and Space reach this handler through a native click.
93			jQuery( self.menuWrap ).find( self.subMenuArrow ).on( 'click', function( e ) {
94				e.preventDefault();
95				e.stopPropagation();
96				self.triggerSubArrow( this );
97			});
98
99			if ( 'on' == self.options['menu_close_on_body_click'] ) {
100				jQuery( document ).on( 'click', 'body', function ( e ) {
101					if ( jQuery( window ).width() < self.hamburgerBreakpoint ) {
102						if ( self.isOpen ) {
103							if ( jQuery( e.target ).closest( self.container ).length || jQuery( e.target ).closest( self.target ).length ) {
104								return;
105							}
106						}
107						self.closeMenu();
108					}
109				});
110			}
111
112			/**
113			 * Close the menu when click on menu item link before load.
114			 */
115			if ( self.options['menu_close_on_link_click'] == 'on') {
116
117				jQuery(  this.menuWrap +' '+ self.linkElement ).on( 'click', function(e) {
118
119					if( jQuery(window).width() < self.hamburgerBreakpoint ) {
120						e.preventDefault();
121
122						// When close menu on parent clicks is on.
123						if ( self.options['menu_item_click_to_trigger_submenu'] == 'on' ) {
124							if( jQuery(this).is( '.rmp-menu-item-has-children > ' + self.linkElement ) ) {
125								return;
126							}
127						}
128
129						let _href = jQuery(this).attr('href');
130						let _target = ( typeof jQuery(this).attr('target') ) == 'undefined' ? '_self' : jQuery(this).attr('target');
131
132						if( self.isOpen ) {
133							if( jQuery(e.target).closest(self.subMenuArrow).length) {
134								return;
135							}
136							if( typeof _href != 'undefined' ) {
137								self.closeMenu();
138								setTimeout(function() {
139									window.open( _href, _target);
140								}, self.animationSpeed);
141							}
142						}
143					}
144				});
145			}
146
147			// Expand Sub items on Parent Item Click.
148			if ( 'on' == self.options['menu_item_click_to_trigger_submenu']  ) {
149				jQuery( this.menuWrap +' .rmp-menu-item-has-children > ' + self.linkElement ).on( 'click', function(e) {
150					if ( jQuery(window).width() < self.hamburgerBreakpoint ) {
151						e.preventDefault();
152						self.triggerSubArrow(
153							self.arrowForLink( this )
154						);
155					}
156				});
157			}
158
159			/*
160			 * Keyboard support for the off-canvas panel.
161			 *
162			 * The previous implementation swallowed every Tab press on the whole document
163			 * while a menu was open and drove focus with its own bookkeeping. That is a
164			 * keyboard trap (WCAG 2.1.2): once inside the menu there was no way back out to
165			 * the page, and Shift+Tab moved forwards like Tab. Tab order is now left to the
166			 * browser; we only close the loop at the two ends of the panel, and only when
167			 * focus is genuinely inside it.
168			 */
169			jQuery( document ).on( 'keydown.rmp-' + this.menuId, function ( event ) {
170				if ( ! self.isOpen || ! self.isOffCanvas() ) {
171					return;
172				}
173
174				if ( 'Escape' === event.key || 'Esc' === event.key || 27 === event.keyCode ) {
175					self.handleEscape( event );
176					return;
177				}
178
179				if ( 'Tab' === event.key || 9 === event.keyCode ) {
180					self.handleTab( event );
181				}
182			} );
183
184			// Keep the closed panel out of the tab order and the accessibility tree, and
185			// re-evaluate when the viewport crosses the hamburger breakpoint.
186			this.syncHiddenState();
187			jQuery( window ).on( 'resize.rmp-' + this.menuId, function () {
188				self.syncHiddenState();
189			} );
190
191			// Add rmp-topmenu-active class to current menu item on load
192			this.setActiveMenuItemOnLoad();
193
194		}
195		/**
196		 * True while the container behaves as an overlay panel, i.e. below the hamburger
197		 * breakpoint. Above it the container is display:none and needs no special handling.
198		 *
199		 * @return {boolean}
200		 */
201		isOffCanvas() {
202			// Ask the same question the stylesheet asks. `@media (max-width: N)` is
203			// inclusive and measures the viewport including the scrollbar, while
204			// jQuery's width() is exclusive of both - so at exactly the breakpoint, and
205			// across the scrollbar's width, the two disagreed and the panel was visible
206			// while its keyboard handling was switched off.
207			if ( window.matchMedia ) {
208				return window.matchMedia( '(max-width: ' + parseInt( this.hamburgerBreakpoint, 10 ) + 'px)' ).matches;
209			}
210
211			return jQuery( window ).width() <= this.hamburgerBreakpoint;
212		}
213
214		/**
215		 * The elements Tab cycles through while the panel is open: the trigger that opened
216		 * it, followed by everything focusable and visible inside the panel.
217		 *
218		 * @return {Array} Ordered list of DOM elements.
219		 */
220		focusCycle() {
221			const focusableSelector = 'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not
221([tabindex="-1"])';
222
223			return jQuery( this.primaryTrigger )
224				.add( jQuery( this.container ).find( focusableSelector ) )
225				.filter( ':visible' )
226				.toArray();
227		}
228
229		/**
230		 * Close the tab loop at the ends of the panel. Anything in between - and anything
231		 * outside the menu entirely - keeps the browser's own tab order.
232		 *
233		 * @param {Event} event Keydown event.
234		 */
235		handleTab( event ) {
236			const cycle = this.focusCycle();
237
238			// With a single focusable element it is both the first and the last, so both
239			// wrap branches would fire and Tab would never leave it. An empty panel has
240			// nothing to contain, so leave the tab order alone in both cases.
241			if ( cycle.length < 2 ) {
242				return;
243			}
244
245			const active    = document.activeElement;
246			const container = jQuery( this.container ).get( 0 );
247
248			// Focus sits on the panel itself right after opening; it is not tabbable, so
249			// wrap it manually rather than letting Shift+Tab escape behind the panel.
250			if ( event.shiftKey && active === container ) {
251				event.preventDefault();
252				cycle[ cycle.length - 1 ].focus();
253				return;
254			}
255
256			const index = cycle.indexOf( active );
257
258			if ( -1 === index ) {
259				return;
260			}
261
262			if ( ! event.shiftKey && index === cycle.length - 1 ) {
263				event.preventDefault();
264				cycle[0].focus();
265			} else if ( event.shiftKey && 0 === index ) {
266				event.preventDefault();
267				cycle[ cycle.length - 1 ].focus();
268			}
269		}
270
271		/**
272		 * Escape collapses the innermost open submenu the visitor is standing in, and
273		 * closes the whole panel when there is none.
274		 *
275		 * @param {Event} event Keydown event.
276		 */
277		handleEscape( event ) {
278			const openSubmenu = jQuery( document.activeElement ).closest( '.rmp-submenu.rmp-submenu-open' );
279
280			if ( openSubmenu.length ) {
281				const parentArrow = this.arrowForSubmenu( openSubmenu );
282
283				if ( parentArrow.length ) {
284					event.preventDefault();
285					this.triggerSubArrow( parentArrow );
286					parentArrow.trigger( 'focus' );
287					return;
288				}
289			}
290
291			event.preventDefault();
292			this.closeMenu();
293		}
294
295		/**
296		 * Hide the panel from assistive technology and from the tab order whenever it is
297		 * closed but still laid out - a slid-out panel is merely translated off screen, so
298		 * without this its links stay tabbable and a keyboard user tabs into nothing.
299		 */
300		syncHiddenState() {
301			const container = jQuery( this.container ).get( 0 );
302
303			if ( ! container ) {
304				return;
305			}
306
307			// Derive "open" from the DOM as well as our own flag, so a panel opened by
308			// third-party code that just adds the open class is not left inert.
309			const isOpen = this.isOpen || jQuery( this.container ).hasClass( RmpMenu.openContainerClass );
310
311			if ( isOpen || ! this.isOffCanvas() ) {
312				container.removeAttribute( 'aria-hidden' );
313				container.removeAttribute( 'inert' );
314				return;
315			}
316
317			container.setAttribute( 'aria-hidden', 'true' );
318			container.setAttribute( 'inert', '' );
319		}
320
321		/**
322		 * Move focus into the panel so the next Tab continues from the menu rather than
323		 * from wherever the visitor was on the page.
324		 */
325		focusPanel() {
326			const container = jQuery( this.container ).get( 0 );
327
328			if ( ! container ) {
329				return;
330			}
331
332			// The fade animation shows the container as it starts, so a task-queue turn is
333			// enough to make sure the element is focusable by the time we ask.
334			window.setTimeout( function () {
335				container.focus( { preventScroll: true } );
336			}, 0 );
337		}
338
339		/**
340		 * Return focus to the trigger, but only if it currently sits inside the panel we
341		 * are about to hide - closing by a click elsewhere must not steal focus.
342		 */
343		restoreFocus() {
344			const container = jQuery( this.container ).get( 0 );
345
346			if ( ! container || ! container.contains( document.activeElement ) ) {
347				return;
348			}
349
350			jQuery( this.primaryTrigger ).trigger( 'focus' );
351		}
352
353		// Add rmp-topmenu-active class to current menu item on load
354		setActiveMenuItemOnLoad() {
355			const currentURL = window.location.href;
356			const menuItems = jQuery(this.menuWrap).find('a');
357
358			menuItems.each(function() {
359				if (this.href === currentURL) {
360					jQuery(this).closest('.rmp-menu-item-has-children').addClass(RmpMenu.activeTopMenuClass);
361					return false; // Exit the loop once we've found and marked the current item
362				}
363			});
364		}
365		/**
366		 * Set push translate for toggle and page wrapper.
367		 */
368		setWrapperTranslate() {
369			let translate,translateContainer;
370			switch( this.options['menu_appear_from'] ) {
371				case 'left':
372					translate = 'translateX(' + this.menuWidth() + 'px)';
373					translateContainer = 'translateX(-' + this.menuWidth() + 'px)';
374					break;
375				case 'right':
376					translate = 'translateX(-' + this.menuWidth() + 'px)';
377					translateContainer = 'translateX(' + this.menuWidth() + 'px)';
378					break;
379				case 'top':
380					translate = 'translateY(' + this.wrapperHeight() + 'px)';
381					translateContainer = 'translateY(-' + this.menuHeight() + 'px)';
382					break;
383				case 'bottom':
384					translate = 'translateY(-' + this.menuHeight() + 'px)';
385					translateContainer = 'translateY(' + this.menuHeight() + 'px)';
386					break;
387			}
388
389			if ( this.options['animation_type'] == 'push' ) {
390				jQuery(this.pageWrapper).css( { 'transform':translate } );
391
392				//If push Wrapper has body element then handle menu position.
393				if	( 'body' == this.pageWrapper ) {
394					jQuery( this.container ).css( { 'transform' : translateContainer } );
395				}
396
397			}
398
399			if ( this.options['button_push_with_animation'] == 'on' ) {
400				jQuery( this.trigger ).css( { 'transform' : translate } );
401			}
402
403		}
404
405		/**
406		 * Clear push translate on button and page wrapper.
407		 */
408		clearWrapperTranslate() {
409
410			if ( this.options['animation_type'] == 'push' ) {
411				jQuery(this.pageWrapper).css( { 'transform' : '' } );
412			}
413
414			if ( this.options['button_push_with_animation'] == 'on' ) {
415				jQuery( this.trigger ).css( { 'transform' : '' } );
416			}
417		}
418
419		/**
420		 * Function to fadeIn the hamburger menu container.
421		 */
422		fadeMenuIn() {
423			jQuery(this.container).fadeIn(this.animationSpeed);
424		}
425
426		/**
427		 * Function to fadeOut the hamburger menu container.
428		 */
429		fadeMenuOut() {
430			jQuery(this.container)
431				.fadeOut(this.animationSpeed, function() {
432					jQuery(this).css('display', '');
433				});
434		}
435
436		/**
437		 * Function is use to open the hamburger menu.
438		 *
439		 * @since 4.0.0
440		 */
441		openMenu() {
442			jQuery(this.trigger).addClass(RmpMenu.activeToggleClass);
443			jQuery(this.container).addClass(RmpMenu.openContainerClass);
444
445			//this.pushMenuTrigger();
446
447			if ( this.options['animation_type'] == 'fade'){
448				this.fadeMenuIn();
449			} else {
450				this.setWrapperTranslate();
451			}
452
453			this.isOpen = true;
454
455			jQuery( this.trigger ).attr( 'aria-expanded', 'true' );
456			this.syncHiddenState();
457			this.focusPanel();
458		}
459
460		/**
461		 * Function is use to close the hamburger menu.
462		 *
463		 * @since 4.0.0
464		 */
465		closeMenu() {
466			// Hand focus back before hiding: leaving the focused element inside an
467			// aria-hidden/inert subtree is itself an accessibility failure.
468			this.restoreFocus();
469
470			jQuery(this.trigger).removeClass(RmpMenu.activeToggleClass);
471			jQuery(this.container).removeClass(RmpMenu.openContainerClass);
472
473			if ( this.options['animation_type'] == 'fade') {
474				this.fadeMenuOut();
475			} else {
476				this.clearWrapperTranslate();
477			}
478
479			this.isOpen = false;
480
481			jQuery( this.trigger ).attr( 'aria-expanded', 'false' );
482			this.syncHiddenState();
483		}
484
485		/**
486		 * Function is responsible for checking the menu is open or close.
487		 *
488		 * @since 4.0.0
489		 * @param {Event} e
490		 */
491		triggerMenu() {
492			this.isOpen ? this.closeMenu() : this.openMenu();
493		}
494
495		/**
496		 * Put one submenu toggle into a given state: glyph, active class and - the part
497		 * assistive technology actually reads - aria-expanded.
498		 *
499		 * @param {Object}  arrow    Toggle button (element or jQuery object).
500		 * @param {boolean} expanded Whether the submenu it controls is now open.
501		 */
502		setArrowState( arrow, expanded ) {
503			const $arrow = jQuery( arrow );
504
505			if ( ! $arrow.length ) {
506				return;
507			}
508
509			$arrow.html( expanded ? this.options['active_toggle_contents'] : this.options['inactive_toggle_contents'] );
510			$arrow.toggleClass( RmpMenu.activeSubMenuArrowClass, !! expanded );
511			$arrow.attr( 'aria-expanded', expanded ? 'true' : 'false' );
512		}
513
514		/*
515		 * Where the submenu toggle lives.
516		 *
517		 * Current markup puts the toggle BESIDE the item link. The 4.7.3 markup put it
518		 * INSIDE the link. Both have to be understood, not just the new one: a page
519		 * served from a full-page cache (Cloudflare APO, host caches, WP Super Cache)
520		 * keeps the old HTML until it is purged, while the browser loads this script -
521		 * the file on disk changed under the same URL. Looking only in the new place
522		 * left every submenu on such a page dead, and with "parent link opens submenu"
523		 * on, the parent link neither opened anything nor navigated.
524		 *
525		 * Every lookup between a toggle and its submenu goes through these three.
526		 */
527
528		/**
529		 * The submenu a toggle controls.
530		 *
531		 * @param {Object} arrow Toggle (element or jQuery object).
532		 * @return {Object} jQuery object, possibly empty.
533		 */
534		submenuFor( arrow ) {
535			const $arrow = jQuery( arrow );
536			let submenu  = $arrow.siblings( RmpMenu.subMenuClass );
537
538			if ( ! submenu.length ) {
539				submenu = $arrow.parent( this.linkElement ).siblings( RmpMenu.subMenuClass );
540			}
541
542			return submenu;
543		}
544
545		/**
546		 * The toggle belonging to an item link.
547		 *
548		 * @param {Object} link Item link (element or jQuery object).
549		 * @return {Object} jQuery object, possibly empty.
550		 */
551		arrowForLink( link ) {
552			const $link = jQuery( link );
553			let arrow   = $link.siblings( this.subMenuArrow );
554
555			if ( ! arrow.length ) {
556				arrow = $link.children( this.subMenuArrow );
557			}
558
559			return arrow.first();
560		}
561
562		/**
563		 * The toggle that controls a given submenu.
564		 *
565		 * @param {Object} submenu Submenu (element or jQuery object).
566		 * @return {Object} jQuery object, possibly empty.
567		 */
568		arrowForSubmenu( submenu ) {
569			const $submenu = jQuery( submenu );
570			let arrow      = $submenu.siblings( this.subMenuArrow );
571
572			if ( ! arrow.length ) {
573				arrow = $submenu.siblings( this.linkElement ).children( this.subMenuArrow );
574			}
575
576			return arrow.first();
577		}
578
579		triggerSubArrow( subArrow ) {
580			var self = this;
581
582			// The toggle is a sibling of the item link inside the <li>, so the submenu it
583			// controls is a sibling of the toggle itself.
584			var sub_menu = this.submenuFor( subArrow );
585
586			//Accordion animation.
587			if ( self.options['accordion_animation'] == 'on' ) {
588				// Get Top Most Parent and the siblings.
589				var top_siblings   = sub_menu.parents('.rmp-menu-item-has-children').last().siblings('.rmp-menu-item-has-children');
590				var first_siblings = sub_menu.parents('.rmp-menu-item-has-children').first().siblings('.rmp-menu-item-has-children');
591
592				// Close up just the top level parents to key the rest as it was.
593				top_siblings.children('.rmp-submenu').slideUp(self.subMenuTransitionTime, 'linear').removeClass('rmp-submenu-open');
594
595				// Set each parent arrow to inactive.
596				top_siblings.each(function() {
597					self.setArrowState( jQuery(this).find(self.subMenuArrow).first(), false );
598				});
599
600				// Now Repeat for the current item siblings.
601				first_siblings.children('.rmp-submenu').slideUp(self.subMenuTransitionTime, 'linear').removeClass('rmp-submenu-open');
602				first_siblings.each(function() {
603					self.setArrowState( jQuery(this).find(self.subMenuArrow).first(), false );
604				});
605			}
606
607			// Active sub menu as default behavior.
608			if( sub_menu.hasClass('rmp-submenu-open') ) {
609				sub_menu.slideUp(self.subMenuTransitionTime, 'linear',function() {
610					jQuery(this).css( 'display', '' );
611				} ).removeClass('rmp-submenu-open');
612				self.setArrowState( subArrow, false );
613			} else {
614				sub_menu.slideDown(self.subMenuTransitionTime, 'linear').addClass( 'rmp-submenu-open' );
615				self.setArrowState( subArrow, true );
616			}
617
618		}
619
620		/**
621		 * Function to add tranform style on trigger.
622		 *
623		 * @version 4.0.0
624		 *
625		 * @param {Event} e Event object.
626		 */
627		pushMenuTrigger( e ) {
628			if ( 'on' == this.options['button_push_with_animation'] ) {
629				jQuery( this.trigger ).css( { 'transform' : this.menuWidth() } );
630			}
631		}
632
633		/**
634		 * Returns the height of container.
635		 *
636		 * @version 4.0.0
637		 *
638		 * @return Number
639		 */
640		menuHeight() {
641			return jQuery( this.container ).height();
642		}
643
644		/**
645		 * Returns the width of the container.
646		 *
647		 * @version 4.0.0
648		 *
649		 * @return Number
650		 */
651		menuWidth() {
652			return jQuery( this.container ).width();
653		}
654
655		wrapperHeight() {
656			return jQuery( this.wrapper ).height();
657		}
658
659		backUpSlide( backButton ) {
660			let translateTo = parseInt( jQuery( this.menuWrap )[0].style.transform.replace( /^\D+/g, '' ) ) - 100;
661			jQuery( this.menuWrap ).css( { 'transform': 'translateX(-' + translateTo + '%)' } );
662			let previousSubmenuHeight = jQuery( backButton ).parent( 'ul' ).parent( 'li' ).parent( '.rmp-submenu' ).height();
663			if ( ! previousSubmenuHeight ) {
664				jQuery( this.menuWrap ).css( { 'height': this.originalHeight } );
665			} else {
666				jQuery( this.menuWrap + this.menuId ).css( { 'height': previousSubmenuHeight + 'px' } );
667			}
668		}
669	}
670
671	/**
672	 * Create multiple instance of menu and pass the options.
673	 *
674	 * @version 4.0.0
675	 */
676	for ( let index = 0; index < rmp_menu.menu.length; index++ ) {
677		let rmp = new RmpMenu( rmp_menu.menu[index] );
678	}
679
680} );

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.