vendor: 6,667 bytes, lines 1-187
1/*! 2 * SlickNav Responsive Mobile Menu v1.0.6 3 * (c) 2015 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: 'body', 18 appendTo: '', 19 parentTag: 'a', 20 closeOnClick: false, 21 allowParentLinks: false, 22 nestedParentLinks: true, 23 showChildren: false, 24 removeIds: false, 25 removeClasses: false, 26 removeStyles: false, 27 brand: '', 28 init: function () {}, 29 beforeOpen: function () {}, 30 beforeClose: function () {}, 31 afterOpen: function () {}, 32 afterClose: function () {} 33 }, 34 mobileMenu = 'slicknav', 35 prefix = 'slicknav'; 36 temp = null; 37 OldTemp = null; 38 OldTempClick = ''; 39 40 function Plugin(element, options) { 41 this.element = element; 42 43 // jQuery has an extend method which merges the contents of two or 44 // more objects, storing the result in the first object. The first object 45 // is generally empty as we don't want to alter the default options for 46 // future instances of the plugin 47 this.settings = $.extend({}, defaults, options); 48 49 this._defaults = defaults; 50 this._name = mobileMenu; 51 52 this.init(); 53 } 54 55 Plugin.prototype.init = function () { 56 var $this = this, 57 menu = $(this.element), 58 settings = this.settings, 59 iconClass, 60 menuBar; 61 62 // clone menu if needed 63 if (settings.duplicate) { 64 $this.mobileNav = menu.clone(); 65 //remove ids from clone to prevent css issues 66 $this.mobileNav.removeAttr('id'); 67 $this.mobileNav.find('*').each(function (i, e) { 68 $(e).removeAttr('id'); 69 }); 70 } else { 71 $this.mobileNav = menu; 72 73 // remove ids if set 74 $this.mobileNav.removeAttr('id'); 75 $this.mobileNav.find('*').each(function (i, e) { 76 $(e).removeAttr('id'); 77 }); 78 } 79 80 // remove classes if set 81 if (settings.removeClasses) { 82 $this.mobileNav.removeAttr('class'); 83 $this.mobileNav.find('*').each(function (i, e) { 84 $(e).removeAttr('class'); 85 }); 86 } 87 88 // remove styles if set 89 if (settings.removeStyles) { 90 $this.mobileNav.removeAttr('style'); 91 $this.mobileNav.find('*').each(function (i, e) { 92 $(e).removeAttr('style'); 93 }); 94 } 95 96 // styling class for the button 97 iconClass = prefix + '_icon'; 98 99 if (settings.label === '') { 100 iconClass += ' ' + prefix + '_no-text'; 101 } 102 103 if (settings.parentTag == 'a') { 104 settings.parentTag = 'a href="#"'; 105 } 106 107 // create menu bar 108 $this.mobileNav.attr('class', prefix + '_nav'); 109 menuBar = $('<div class="' + prefix + '_menu"></div>'); 110 if (settings.brand !== '') { 111 var brand = $('<div class="' + prefix + '_brand">'+settings.brand+'</div>'); 112 $(menuBar).append(brand); 113 } 114 $this.btn = $( 115 ['<' + settings.parentTag + ' aria-haspopup="true" tabindex="0" class="' + prefix + '_btn ' + prefix + '_collapsed">', 116 '<span class="' + prefix + '_menutxt">' + settings.label + '</span>', 117 '<span class="' + iconClass + '">', 118 '<span class="' + prefix + '_icon-bar"></span>', 119 '<span class="' + prefix + '_icon-bar"></span>', 120 '<span class="' + prefix + '_icon-bar"></span>', 121 '</span>', 122 '</' + settings.parentTag + '>' 123 ].join('') 124 ); 125 126 $(menuBar).append($this.btn); 127 if(settings.appendTo !== '') { 128 $(settings.appendTo).append(menuBar); 129 } else { 130 $(settings.prependTo).prepend(menuBar); 131 } 132 $("#menu-bar").append(menuBar); 133 134 $("#menu-mob").append($this.mobileNav); 135 136 // iterate over structure adding additional structure 137 var items = $this.mobileNav.find('li'); 138 $(items).each(function () { 139 var item = $(this), 140 data = {}; 141 data.children = item.children('ul').attr('role', 'menu').addClass('menu-submenu'); 142 item.data('menu', data); 143 144 // if a list item has a nested menu 145 if (data.children.length > 0) { 146 147 // select all text before the child menu 148 // check for anchors 149 150 var a = item.contents(), 151 containsAnchor = false, 152 nodes = []; 153 154 $(a).each(function () { 155 if (!$(this).is('ul')) { 156 nodes.push(this); 157 } else { 158 return false; 159 } 160 161 if($(this).is("a")) { 162 containsAnchor = true; 163 } 164 }); 165 166 var wrapElement = $( 167 '<' + settings.parentTag + ' role="menuitem" aria-haspopup="true" tabindex="-1" class="' + prefix + '_item"/>' 168 ); 169 170 // wrap item text with tag and add classes unless we are separating parent links 171 if ((!settings.allowParentLinks || settings.nestedParentLinks) || !containsAnchor) { 172 var $wrap = $(nodes).wrapAll(wrapElement).parent(); 173 $wrap.addClass(prefix+'_row'); 174 } else 175 $(nodes).wrapAll('<span class="'+prefix+'_parent-link '+prefix+'_row"/>').parent(); 176 177 if (!settings.showChildren) { 178 item.addClass(prefix+'_collapsed'); 179 } else { 180 item.addClass(prefix+'_open'); 181 } 182 183 item.addClass(prefix+'_parent'); 184 185 // create parent arrow. wrap with link if parent links and separating 186 var arrowElement = $('<span class="'+prefix+'_arrow">'+(settings.showChildren?settings.openedSymbol:settings.closedSymbol)+'</span>'); 187
188 if (settings.allowParentLinks && !settings.nestedParentLinks && containsAnchor) 189 arrowElement = arrowElement.wrap(wrapElement).parent(); 190 191 //append arrow 192 $(nodes).last().after(arrowElement); 193 194 195 } else if ( item.children().length === 0) { 196 item.addClass(prefix+'_txtnode'); 197 } 198 199 // accessibility for links 200 item.children('a').attr('role', 'menuitem').click(function(event){ 201 //Ensure that it's not a parent 202 if (settings.closeOnClick && !$(event.target).parent().closest('li').hasClass(prefix+'_parent')) { 203 //Emulate menu close if set 204 $($this.btn).click(); 205 } 206 }); 207 208 //also close on click if parent links are set 209 if (settings.closeOnClick && settings.allowParentLinks) { 210 item.children('a').children('a').click(function (event) { 211 //Emulate menu close 212 $($this.btn).click(); 213 }); 214 215 item.find('.'+prefix+'_parent-link a:not(.'+prefix+'_item)').click(function(event){ 216 //Emulate menu close 217 $($this.btn).click(); 218 }); 219 } 220 }); 221 222 // structure is in place, now hide appropriate items 223 $(items).each(function () { 224 var data = $(this).data('menu'); 225 if (!settings.showChildren){ 226 $this._visibilityToggle(data.children, null, false, null, true); 227 } 228 }); 229 230 // finally toggle entire menu 231 $this._visibilityToggle($this.mobileNav, null, false, 'init', true); 232 233 // accessibility for menu button 234 $this.mobileNav.attr('role','menu'); 235 236 // outline prevention when using mouse 237 $(document).mousedown(function(){ 238 $this._outlines(false); 239 }); 240 241 $(document).keyup(function(){ 242 $this._outlines(true); 243 }); 244 245 // menu button click 246 $($this.btn).click(function (e) { 247 e.preventDefault(); 248 $this._menuToggle(); 249 }); 250 251 // click on menu parent 252 $this.mobileNav.on('click', '.' + prefix + '_item', function (e) { 253 254 255 // Changes 256 // Close subcategories if another one is clicked 257 temp = e; 258 var tempclick = $(this); 259 console.log($(this)); 260 261 262 if(OldTemp != null) { 263 if(e.currentTarget != OldTemp.currentTarget){ 264 265 e.preventDefault(); 266 $this._itemClick(OldTempClick); 267 OldTemp = temp; 268 OldTempClick = tempclick; 269 270 } 271 else { 272 OldTemp = null; 273 OldTempClick = null; 274 } 275 } else { 276 OldTemp = temp; 277 OldTempClick = tempclick; 278 } 279 e.preventDefault(); 280 $this._itemClick($(this)); 281 282 }); 283 284 // check for enter key on menu button and menu parents 285 $($this.btn).keydown(function (e) { 286 var ev = e || event; 287 if(ev.keyCode == 13) { 288 e.preventDefault(); 289 $this._menuToggle(); 290 } 291 }); 292 293 $this.mobileNav.on('keydown', '.'+prefix+'_item', function(e) { 294 var ev = e || event; 295 if(ev.keyCode == 13) { 296 e.preventDefault(); 297 $this._itemClick($(e.target)); 298 } 299 }); 300 301 // allow links clickable within parent tags if set 302 if (settings.allowParentLinks && settings.nestedParentLinks) { 303 $('.'+prefix+'_item a').click(function(e){ 304 e.stopImmediatePropagation(); 305 }); 306 } 307 }; 308 309 //toggle menu 310 Plugin.prototype._menuToggle = function (el) { 311 var $this = this; 312 var btn = $this.btn; 313 var mobileNav = $this.mobileNav; 314 315 if (btn.hasClass(prefix+'_collapsed')) { 316 btn.removeClass(prefix+'_collapsed'); 317 btn.addClass(prefix+'_open'); 318 } else { 319 btn.removeClass(prefix+'_open'); 320 btn.addClass(prefix+'_collapsed'); 321 } 322 btn.addClass(prefix+'_animating'); 323 $this._visibilityToggle(mobileNav, btn.parent(), true, btn); 324 }; 325 326 // toggle clicked items 327 Plugin.prototype._itemClick = function (el) { 328 //console.log('itemclick'); 329 var $this = this; 330 var settings = $this.settings; 331 var data = el.data('menu'); 332 //console.log(data); 333 if (!data) { 334 data = {}; 335 data.arrow = el.children('.'+prefix+'_arrow'); 336 data.ul = el.next('ul'); 337 data.parent = el.parent(); 338 //Separated parent link structure 339 if (data.parent.hasClass(prefix+'_parent-link')) { 340 data.parent = el.parent().parent(); 341 data.ul = el.parent().next('ul'); 342 } 343 el.data('menu', data); 344 } 345 if (data.parent.hasClass(prefix+'_collapsed')) {
vendor: 6,693 bytes, lines 346-521
346 data.arrow.html(settings.openedSymbol); 347 data.parent.removeClass(prefix+'_collapsed'); 348 data.parent.addClass(prefix+'_open'); 349 data.parent.addClass(prefix+'_animating'); 350 $this._visibilityToggle(data.ul, data.parent, true, el); 351 } else { 352 data.arrow.html(settings.closedSymbol); 353 data.parent.addClass(prefix+'_collapsed'); 354 data.parent.removeClass(prefix+'_open'); 355 data.parent.addClass(prefix+'_animating'); 356 $this._visibilityToggle(data.ul, data.parent, true, el); 357 } 358 }; 359 360 // toggle actual visibility and accessibility tags 361 Plugin.prototype._visibilityToggle = function(el, parent, animate, trigger, init) { 362 var $this = this; 363 var settings = $this.settings; 364 var items = $this._getActionItems(el); 365 var duration = 0; 366 if (animate) { 367 duration = settings.duration; 368 } 369 370 if (el.hasClass(prefix+'_hidden')) { 371 el.removeClass(prefix+'_hidden'); 372 //Fire beforeOpen callback 373 if (!init) { 374 settings.beforeOpen(trigger); 375 } 376 el.slideDown(duration, settings.easingOpen, function(){ 377 378 $(trigger).removeClass(prefix+'_animating'); 379 $(parent).removeClass(prefix+'_animating'); 380 381 //Fire afterOpen callback 382 if (!init) { 383 settings.afterOpen(trigger); 384 } 385 }); 386 el.attr('aria-hidden','false'); 387 items.attr('tabindex', '0'); 388 $this._setVisAttr(el, false); 389 } else { 390 el.addClass(prefix+'_hidden'); 391 392 //Fire init or beforeClose callback 393 if (!init){ 394 settings.beforeClose(trigger); 395 } 396 397 el.slideUp(duration, this.settings.easingClose, function() { 398 el.attr('aria-hidden','true'); 399 items.attr('tabindex', '-1'); 400 $this._setVisAttr(el, true); 401 el.hide(); //jQuery 1.7 bug fix 402 403 $(trigger).removeClass(prefix+'_animating'); 404 $(parent).removeClass(prefix+'_animating'); 405 406 //Fire init or afterClose callback 407 if (!init){ 408 settings.afterClose(trigger); 409 } else if (trigger == 'init'){ 410 settings.init(); 411 } 412 }); 413 } 414 }; 415 416 // set attributes of element and children based on visibility 417 Plugin.prototype._setVisAttr = function(el, hidden) { 418 var $this = this; 419 //console.log('setvisattr'); 420 // select all parents that aren't hidden 421 var nonHidden = el.children('li').children('ul').not('.'+prefix+'_hidden'); 422 423 // iterate over all items setting appropriate tags 424 if (!hidden) { 425 nonHidden.each(function(){ 426 var ul = $(this); 427 ul.attr('aria-hidden','false'); 428 var items = $this._getActionItems(ul); 429 items.attr('tabindex', '0'); 430 $this._setVisAttr(ul, hidden); 431 }); 432 } else { 433 nonHidden.each(function(){ 434 var ul = $(this); 435 ul.attr('aria-hidden','true'); 436 var items = $this._getActionItems(ul); 437 items.attr('tabindex', '-1'); 438 $this._setVisAttr(ul, hidden); 439 }); 440 } 441 }; 442 443 // get all 1st level items that are clickable 444 Plugin.prototype._getActionItems = function(el) { 445 var data = el.data("menu"); 446 if (!data) { 447 data = {}; 448 var items = el.children('li'); 449 var anchors = items.find('a'); 450 data.links = anchors.add(items.find('.'+prefix+'_item')); 451 el.data('menu', data); 452 } 453 return data.links; 454 }; 455 456 Plugin.prototype._outlines = function(state) { 457 if (!state) { 458 $('.'+prefix+'_item, .'+prefix+'_btn').css('outline','none'); 459 } else { 460 $('.'+prefix+'_item, .'+prefix+'_btn').css('outline',''); 461 } 462 }; 463 464 Plugin.prototype.toggle = function(){ 465 var $this = this; 466 $this._menuToggle(); 467 }; 468 469 Plugin.prototype.open = function(){ 470 var $this = this; 471 if ($this.btn.hasClass(prefix+'_collapsed')) { 472 $this._menuToggle(); 473 console.log('prot-open'); 474 } 475 }; 476 477 Plugin.prototype.close = function(){ 478 var $this = this; 479 if ($this.btn.hasClass(prefix+'_open')) { 480 $this._menuToggle(); 481 } 482 }; 483 484 $.fn[mobileMenu] = function ( options ) { 485 var args = arguments; 486 487 // Is the first parameter an object (options), or was omitted, instantiate a new instance 488 if (options === undefined || typeof options === 'object') { 489 return this.each(function () { 490 491 // Only allow the plugin to be instantiated once due to methods 492 if (!$.data(this, 'plugin_' + mobileMenu)) { 493 494 // if it has no instance, create a new one, pass options to our plugin constructor, 495 // and store the plugin instance in the elements jQuery data object. 496 $.data(this, 'plugin_' + mobileMenu, new Plugin( this, options )); 497 } 498 }); 499 500 // If is a string and doesn't start with an underscore or 'init' function, treat this as a call to a public method. 501 } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') { 502 503 // Cache the method call to make it possible to return a value 504 var returns; 505 506 this.each(function () { 507 var instance = $.data(this, 'plugin_' + mobileMenu); 508 509 // Tests that there's already a plugin-instance and checks that the requested public method exists 510 if (instance instanceof Plugin && typeof instance[options] === 'function') { 511 512 // Call the method of our plugin instance, and pass it the supplied arguments. 513 returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) ); 514 } 515 }); 516 517 // If the earlier cached method gives a value back return the value, otherwise return this to preserve chainability. 518 return returns !== undefined ? returns : this; 519 } 520 }; 521}(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.