PageSourceSearch

https://www.patakuri.com/wp-content/themes/patakuri/js/jquery.slicknav.js

js patakuri.com collected 2026-10-03 01:40:41 UTC 11,164 bytes, 382 lines download raw bytes

1/*!
2	SlickNav Responsive Mobile Menu
3	(c) 2014 Josh Cope
4	licensed under MIT
5*/
6;(function ($, document, window) {
7	var
8	// default settings object.
9	defaults = {
10		label: 'MENU',
11		duplicate: true,
12		duration: 200,
13		easingOpen: 'swing',
14		easingClose: 'swing',
15		closedSymbol: '+',
16		openedSymbol: '-',
17		prependTo: 'nav',
18		parentTag: 'a',
19		closeOnClick: false,
20		allowParentLinks: false,
21		init: function(){},
22		open: function(){},
23		close: function(){}
24	},
25	mobileMenu = 'slicknav',
26	prefix = 'slicknav';
27	
28	function Plugin( element, options ) {
29		this.element = element;
30
31        // jQuery has an extend method which merges the contents of two or
32        // more objects, storing the result in the first object. The first object
33        // is generally empty as we don't want to alter the default options for
34        // future instances of the plugin
35        this.settings = $.extend( {}, defaults, options) ;
36        
37        this._defaults = defaults;
38        this._name = mobileMenu;
39        
40        this.init();
41	}
42	
43	Plugin.prototype.init = function () {
44        var $this = this;
45		var menu = $(this.element);
46		var settings = this.settings;
47		
48		// clone menu if needed
49		if (settings.duplicate) {
50			$this.mobileNav = menu.clone();
51			//remove ids from clone to prevent css issues
52			$this.mobileNav.removeAttr('id');
53			$this.mobileNav.find('*').each(function(i,e){
54				$(e).removeAttr('id');
55			});
56		}
57		else
58			$this.mobileNav = menu;
59		
60		// styling class for the button
61		var iconClass = prefix+'_icon';
62		
63		if (settings.label == '') {
64			iconClass += ' '+prefix+'_no-text';
65		}
66		
67		if (settings.parentTag == 'a') {
68			settings.parentTag = 'a href="#"';
69		}
70		
71		// create menu bar
72		$this.mobileNav.attr('class', prefix+'_nav');
73		var menuBar = $('<div class="'+prefix+'_menu"></div>');
74		$this.btn = $('<'+settings.parentTag+' aria-haspopup="true" tabindex="0" class="'+prefix+'_btn '+prefix+'_collapsed"><span class="'+prefix+'_menutxt">'+settings.label+'</span><span class="'+iconClass+'"><span class="'+prefix+'_icon-bar"></span><span class="'+prefix+'_icon-bar"></span><span class="'+prefix+'_icon-bar"></span></span></a>');
75		$(menuBar).append($this.btn);		
76		$(settings.prependTo).prepend(menuBar);
77		menuBar.append($this.mobileNav);
78		
79		// iterate over structure adding additional structure
80		var items = $this.mobileNav.find('li');
81		$(items).each(function () {
82			var item = $(this);
83			data = {};
84			data.children = item.children('ul').attr('role','menu');
85			item.data("menu", data);
86			
87			// if a list item has a nested menu
88			if (data.children.length > 0) {
89			
90				// select all text before the child menu
91				var a = item.contents();
92				var nodes = [];
93				$(a).each(function(){
94					if(!$(this).is("ul")) {
95						nodes.push(this);
96					}
97					else {
98						return false;
99					}
100				});
101				
102				// wrap item text with tag and add classes
103				var wrap = $(nodes).wrapAll('<'+settings.parentTag+' role="menuitem" aria-haspopup="true" tabindex="-1" class="'+prefix+'_item"/>').parent();
104				
105				item.addClass(prefix+'_collapsed');
106				item.addClass(prefix+'_parent');
107				
108				// create parent arrow
109				$(nodes).last().after('<span class="'+prefix+'_arrow">'+settings.closedSymbol+'</span>');
110				
111			
112			} else if ( item.children().length == 0) {
113				 item.addClass(prefix+'_txtnode');
114			}
115			
116			// accessibility for links
117			item.children('a').attr('role', 'menuitem').click(function(event){
118				//Emulate menu close if set
119                //Ensure that it's not a parent
120				if (settings.closeOnClick && !$(event.target).parent().closest('li').hasClass(prefix+'_parent'))
121					$($this.btn).click();
122			});
123            
124            //also close on click if parent links are set
125            if (settings.closeOnClick && settings.allowParentLinks) {
126                item.children('a').children('a').click(function(event){
127                    //Emulate menu close
128                        $($this.btn).click();
129                });
130            }
131		});
132		
133		// structure is in place, now hide appropriate items
134		$(items).each(function () {
135			var data = $(this).data("menu");
136			$this._visibilityToggle(data.children, false, null, true);
137		});
138		
139		// finally toggle entire menu
140		$this._visibilityToggle($this.mobileNav, false, 'init', true);
141		
142		// accessibility for menu button
143		$this.mobileNav.attr('role','menu');
144		
145		// outline prevention when using mouse
146		$(document).mousedown(function(){
147			$this._outlines(false);
148		});
149		
150		$(document).keyup(function(){
151			$this._outlines(true);
152		});
153		
154		// menu button click
155		$($this.btn).click(function (e) {
156			e.preventDefault();
157			$this._menuToggle();			
158		});
159		
160		// click on menu parent
161		$this.mobileNav.on('click', '.'+prefix+'_item', function(e){
162			e.preventDefault();
163			$this._itemClick($(this));
164		});
165		
166		// check for enter key on menu button and menu parents
167		$($this.btn).keydown(function (e) {
168			var ev = e || event;
169			if(ev.keyCode == 13) {
170				e.preventDefault();
171				$this._menuToggle();
172			}
173		});
174		
175		$this.mobileNav.on('keydown', '.'+prefix+'_item', function(e) {
176			var ev = e || event;
177			if(ev.keyCode == 13) {
178				e.preventDefault();
179				$this._itemClick($(e.target));
180			}
181		});
182		
183		// allow links clickable within parent tags if set
184		if (settings.allowParentLinks) {
185			$('.'+prefix+'_item a').click(function(e){
186					e.stopImmediatePropagation();
187			});
188		}
189    };
190	
191	//toggle menu
192	Plugin.prototype._menuToggle = function(el){
193		var $this = this;
194		var btn = $this.btn;
195		var mobileNav = $this.mobileNav;
196		
197		if (btn.hasClass(prefix+'_collapsed')) {
198			btn.removeClass(prefix+'_collapsed');
199			btn.addClass(prefix+'_open');
200		} else {
201			btn.removeClass(prefix+'_open');
202			btn.addClass(prefix+'_collapsed');
203		}
204		btn.addClass(prefix+'_animating');
205		$this._visibilityToggle(mobileNav, true, btn);
206	}
207	
208	// toggle clicked items
209	Plugin.prototype._itemClick = function(el) {
210		var $this = this;
211		var settings = $this.settings;
212		var data = el.data("menu");
213		if (!data) {
214			data = {};
215			data.arrow = el.children('.'+prefix+'_arrow');
216			data.ul = el.next('ul');
217			data.parent = el.parent();
218			el.data("menu", data);
219		}
220		if (data.parent.hasClass(prefix+'_collapsed')) {
221			data.arrow.html(settings.openedSymbol);
222			data.parent.removeClass(prefix+'_collapsed');
223			data.parent.addClass(prefix+'_open');
224			data.parent.addClass(prefix+'_animating');
225			$this._visibilityToggle(data.ul, true, el);
226		} else {
227			data.arrow.html(settings.closedSymbol);
228			data.parent.addClass(prefix+'_collapsed');
229			data.parent.removeClass(prefix+'_open');
230			data.parent.addClass(prefix+'_animating');
231			$this._visibilityToggle(data.ul, true, el);
232		}
233	}
234
235	// toggle actual visibility and accessibility tags
236	Plugin.prototype._visibilityToggle = function(el, animate, trigger, init) {
237		var $this = this;
238		var settings = $this.settings;
239		var items = $this._getActionItems(el);
240		var duration = 0;
241		if (animate)
242			duration = settings.duration;
243		
244		if (el.hasClass(prefix+'_hidden')) {
245			el.removeClass(prefix+'_hidden');
246			el.slideDown(duration, settings.easingOpen, function(){
247				
248				$(trigger).removeClass(prefix+'_animating');
249				$(trigger).parent().removeClass(prefix+'_animating');
250				
251				//Fire open callback
252				if (!init) {
253					settings.open(trigger);
254				}
255			});
256			el.attr('aria-hidden','false');
257			items.attr('tabindex', '0');
258			$this._setVisAttr(el, false);
259		} else {
260			el.addClass(prefix+'_hidden');
261			el.slideUp(duration, this.settings.easingClose, function() {
262				el.attr('aria-hidden','true');
263				items.attr('tabindex', '-1');
264				$this._setVisAttr(el, true);
265				el.hide(); //jQuery 1.7 bug fix
266				
267				$(trigger).removeClass(prefix+'_animating');
268				$(trigger).parent().removeClass(prefix+'_animating');
269				
270				//Fire init or close callback
271				if (!init)
272					settings.close(trigger);
273				else if (trigger == 'init')
274					settings.init();
275			});
276		}
277	}
278
279	// set attributes of element and children based on visibility
280	Plugin.prototype._setVisAttr = function(el, hidden) {
281		var $this = this;
282		
283		// select all parents that aren't hidden
284		var nonHidden = el.children('li').children('ul').not('.'+prefix+'_hidden');
285		
286		// iterate over all items setting appropriate tags
287		if (!hidden) {
288			nonHidden.each(function(){
289				var ul = $(this);
290				ul.attr('aria-hidden','false');
291				var items = $this._getActionItems(ul);
292				items.attr('tabindex', '0');
293				$this._setVisAttr(ul, hidden);
294			});
295		} else {
296			nonHidden.each(function(){
297				var ul = $(this);
298				ul.attr('aria-hidden','true');
299				var items = $this._getActionItems(ul);
300				items.attr('tabindex', '-1');
301				$this._setVisAttr(ul, hidden);
302			});
303		}
304	}
305
306	// get all 1st level items that are clickable
307	Plugin.prototype._getActionItems = function(el) {
308		var data = el.data("menu");
309		if (!data) {
310			data = {};
311			var items = el.children('li');
312			var anchors = items.children('a');
313			data.links = anchors.add(items.children('.'+prefix+'_item'));
314			el.data("menu", data);
315		}
316		return data.links;
317	}
318
319	Plugin.prototype._outlines = function(state) {
320		if (!state) {
321			$('.'+prefix+'_item, .'+prefix+'_btn').css('outline','none');
322		} else {
323			$('.'+prefix+'_item, .'+prefix+'_btn').css('outline','');
324		}
325	}
326	
327	Plugin.prototype.toggle = function(){
328		$this._menuToggle();
329	}
330	
331	Plugin.prototype.open = function(){
vendor: 1,809 bytes, lines 332-382
332		$this = this;
333		if ($this.btn.hasClass(prefix+'_collapsed')) {
334			$this._menuToggle();
335		}
336	}
337	
338	Plugin.prototype.close = function(){
339		$this = this;
340		if ($this.btn.hasClass(prefix+'_open')) {
341			$this._menuToggle();
342		}
343	}
344	
345	$.fn[mobileMenu] = function ( options ) {
346		var args = arguments;
347
348		// Is the first parameter an object (options), or was omitted, instantiate a new instance
349		if (options === undefined || typeof options === 'object') {
350			return this.each(function () {
351
352				// Only allow the plugin to be instantiated once due to methods
353				if (!$.data(this, 'plugin_' + mobileMenu)) {
354
355					// if it has no instance, create a new one, pass options to our plugin constructor,
356					// and store the plugin instance in the elements jQuery data object.
357					$.data(this, 'plugin_' + mobileMenu, new Plugin( this, options ));
358				}
359			});
360
361		// If is a string and doesn't start with an underscore or 'init' function, treat this as a call to a public method.
362		} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
363
364			// Cache the method call to make it possible to return a value
365			var returns;
366
367			this.each(function () {
368				var instance = $.data(this, 'plugin_' + mobileMenu);
369
370				// Tests that there's already a plugin-instance and checks that the requested public method exists
371				if (instance instanceof Plugin && typeof instance[options] === 'function') {
372
373					// Call the method of our plugin instance, and pass it the supplied arguments.
374					returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
375				}
376			});
377
378			// If the earlier cached method gives a value back return the value, otherwise return this to preserve chainability.
379			return returns !== undefined ? returns : this;
380		}
381	};
382}(jQuery, document, window));

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.