PageRenderTime 38ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/shiftnav-responsive-mobile-menu/assets/js/shiftnav.js

https://gitlab.com/pankajmohale/chef2go
JavaScript | 814 lines | 511 code | 201 blank | 102 comment | 128 complexity | 85b392fc5cafa121177af85be1c87557 MD5 | raw file
  1. /*
  2. * ShiftNav.js
  3. *
  4. * http://shiftnav.io
  5. *
  6. * Copyright Chris Mavricos, SevenSpark http://sevenspark.com
  7. */
  8. ;(function($,sr){
  9. // debouncing function from John Hann
  10. // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
  11. var debounce = function (func, threshold, execAsap) {
  12. var timeout;
  13. return function debounced () {
  14. var obj = this, args = arguments;
  15. function delayed () {
  16. if (!execAsap)
  17. func.apply(obj, args);
  18. timeout = null;
  19. };
  20. if (timeout)
  21. clearTimeout(timeout);
  22. else if (execAsap)
  23. func.apply(obj, args);
  24. timeout = setTimeout(delayed, threshold || 100);
  25. };
  26. }
  27. jQuery.fn[sr] = function(fn){ return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
  28. })(jQuery,'shiftsmartresize');
  29. var shift_supports = (function() {
  30. var div = document.createElement('div'),
  31. vendors = 'Khtml Ms O Moz Webkit'.split(' ');
  32. return function(prop) {
  33. var len = vendors.length;
  34. if ( prop in div.style ) return true;
  35. prop = prop.replace(/^[a-z]/, function(val) {
  36. return val.toUpperCase();
  37. });
  38. while(len--) {
  39. if ( vendors[len] + prop in div.style ) {
  40. return true;
  41. }
  42. }
  43. return false;
  44. };
  45. })();
  46. ;(function ( $, window, document, undefined ) {
  47. var pluginName = "shiftnav",
  48. defaults = {
  49. mouseEvents: true,
  50. retractors: true,
  51. touchOffClose: true,
  52. clicktest: false,
  53. windowstest: false,
  54. debug: false,
  55. open_current: false,
  56. collapse_accordions: false,
  57. scroll_offset:100,
  58. disable_transforms: false
  59. };
  60. function Plugin ( element, options ) {
  61. this.element = element;
  62. this.$shiftnav = $( this.element );
  63. this.$menu = this.$shiftnav.find( 'ul.shiftnav-menu' );
  64. this.settings = $.extend( {}, defaults, options );
  65. this._defaults = defaults;
  66. this._name = pluginName;
  67. this.touchenabled = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
  68. if( window.navigator.pointerEnabled ){
  69. this.touchStart = 'pointerdown';
  70. this.touchEnd = 'pointerup';
  71. this.touchMove = 'pointermove';
  72. }
  73. else if( window.navigator.msPointerEnabled ){
  74. this.touchStart = 'MSPointerDown';
  75. this.touchEnd = 'MSPointerUp';
  76. this.touchMove = 'MSPointerMove';
  77. }
  78. else{
  79. this.touchStart = 'touchstart';
  80. this.touchEnd = 'touchend';
  81. this.touchMove = 'touchmove';
  82. }
  83. this.toggleevent = this.touchEnd == 'touchend' ? this.touchEnd + ' click' : this.touchEnd; //add click except for IE
  84. //this.toggleevent = 'click';
  85. this.transitionend = 'transitionend.shiftnav webkitTransitionEnd.shiftnav msTransitionEnd.shiftnav oTransitionEnd.shiftnav';
  86. //TESTING
  87. if( this.settings.clicktest ) this.touchEnd = 'click';
  88. this.init();
  89. }
  90. Plugin.prototype = {
  91. init: function () {
  92. this.$shiftnav.removeClass( 'shiftnav-nojs' ); //We're off and running
  93. //this.$toggles = $( '.shiftnav-toggle[data-shiftnav-target="'+this.$shiftnav.attr('id')+'"]' );
  94. this.$toggles = $( '.shiftnav-toggle[data-shiftnav-target="'+this.$shiftnav.data('shiftnav-id')+'"]' );
  95. //Initialize user interaction events
  96. this.initializeShiftNav();
  97. this.initializeTargets();
  98. this.initializeSubmenuToggleMouseEvents();
  99. this.initializeRetractors();
  100. this.initializeResponsiveToggle();
  101. //this.initializeTouchoffClose(); //attached on open instead
  102. },
  103. /* Initalizers */
  104. initializeShiftNav: function(){
  105. var $body = $('body'),
  106. plugin = this;
  107. //Only enable the site once
  108. if( !$body.hasClass( 'shiftnav-enabled' ) ){
  109. $body.addClass( 'shiftnav-enabled' );
  110. if( shiftnav_data.lock_body == 'on' ) $body.addClass( 'shiftnav-lock' );
  111. if( shiftnav_data.lock_body_x == 'on' ) $body.addClass( 'shiftnav-lock-x' );
  112. if( shiftnav_data.shift_body != 'off' ){
  113. if( shiftnav_data.shift_body_wrapper != '' ){
  114. $( shiftnav_data.shift_body_wrapper ).addClass( 'shiftnav-wrap' );
  115. }
  116. else{
  117. $body.wrapInner( '<div class="shiftnav-wrap"></div>' ); //unique
  118. $( 'video[autoplay]' ).each( function(){
  119. $(this).get(0).play();
  120. });
  121. }
  122. }
  123. else $body.addClass( 'shiftnav-disable-shift-body' );
  124. //Move elements outside of shifter
  125. $( '#shiftnav-toggle-main, #wpadminbar, .shiftnav-fixed-left, .shiftnav-fixed-right' ).appendTo( 'body' );
  126. var $wrap = $( '.shiftnav-wrap' );
  127. //Pad top when either using the Full Bar & Auto Gap, or if override is enabled
  128. var $main_toggle = $( '#shiftnav-toggle-main' );
  129. if( ( !$main_toggle.hasClass( 'shiftnav-toggle-style-burger_only') && $main_toggle.hasClass( 'shiftnav-togglebar-gap-auto' ) ) ||
  130. $main_toggle.hasClass( 'shiftnav-togglebar-gap-on' ) ){
  131. var toggleHeight = $main_toggle.outerHeight();
  132. $wrap.css( 'padding-top' , toggleHeight );
  133. $main_toggle.addClass( 'shiftnav-togglebar-gap-on' );
  134. if( shiftnav_data.shift_body == 'off' ){
  135. //$body.css( 'padding-top' , toggleHeight );
  136. // var css = document.createElement("style");
  137. // css.type = "text/css";
  138. var style = '@media screen and (max-width:'+(shiftnav_data.breakpoint-1)+'px){ body.shiftnav-disable-shift-body{ padding-top:'+ toggleHeight + 'px; } }';
  139. var sheet = null;
  140. //Get the existing style element in the site head, or create one if it does not exist
  141. var style_el = document.getElementById( 'shiftnav-dynamic-css' );
  142. if( style_el ){
  143. sheet = style_el.sheet;
  144. }
  145. else{
  146. style_el = document.createElement("style");
  147. style_el.appendChild(document.createTextNode(""));
  148. document.head.appendChild(style_el);
  149. sheet = style_el.sheet;
  150. }
  151. //Add the rule to the style element
  152. if( sheet && "insertRule" in sheet ){
  153. sheet.insertRule( style , 0 );
  154. }
  155. // else{
  156. // $body.css( 'padding-top' , toggleHeight ); //would need to pair with an extra class and padding-top:0 in PHP generated CSS
  157. // }
  158. }
  159. }
  160. else if( $( 'body' ).hasClass( 'admin-bar' ) ) $( 'html' ).addClass( 'shiftnav-nogap' );
  161. //Setup non-transform
  162. //Some browsers provide false positives for feature detection, so we have to do browser detection as well, sadly
  163. var fpos = false; //falsePositive -
  164. var ua = navigator.userAgent.toLowerCase();
  165. //Many mobile Android browsers are dumb
  166. if( /android/.test( ua ) ){
  167. fpos = true; //we're going to whitelist mobile Android browsers, so assume false positive on Android
  168. //always ignore old androids
  169. if( /android [1-3]/.test( ua ) ) fpos = true;
  170. //Chrome on 4+ is good
  171. else if( /chrome/.test( ua ) ) fpos = false;
  172. //Firefox on 4+ is good
  173. else if( /firefox/.test( ua ) ) fpos = false;
  174. //always allow Chrome
  175. //else if( /chrome/.test( ua ) ) fpos = false;
  176. //Android 4.4+ is okay
  177. //else if( /android 4.[4-9]/.test( ua ) ) fpos = false;
  178. //else fpos = true;
  179. }
  180. if( !shift_supports( 'transform' ) || fpos || plugin.settings.disable_transforms ){
  181. $body.addClass( 'shiftnav-no-transforms' );
  182. }
  183. //Handle searchbar toggle
  184. $( '.shiftnav-searchbar-toggle' ).on( this.toggleevent , function( e ){
  185. e.stopPropagation();
  186. e.preventDefault();
  187. var $drop = $( this ).next( '.shiftnav-searchbar-drop' );
  188. //Close
  189. if( $drop.hasClass( 'shiftnav-searchbar-drop-open' ) ){
  190. $drop.removeClass( 'shiftnav-searchbar-drop-open' );
  191. $( 'body' ).off( 'click.shiftnav-searchbar-drop' );
  192. }
  193. //Open
  194. else{
  195. $drop.addClass( 'shiftnav-searchbar-drop-open' );
  196. $drop.find( '.shiftnav-search-input' ).focus();
  197. //Close on click-off - can't do this immediately because IE is so damn dumb
  198. if( plugin.settings.touchOffClose ){
  199. setTimeout( function(){
  200. $( 'body' ).on( 'click.shiftnav-searchbar-drop' , function( e ){
  201. $( '.shiftnav-searchbar-drop' ).removeClass( 'shiftnav-searchbar-drop-open' );
  202. $( 'body' ).off( 'click.shiftnav-searchbar-drop' );
  203. });
  204. }, 100);
  205. }
  206. }
  207. });
  208. $( '.shiftnav-searchbar-drop' ).on( this.toggleevent , function( e ){
  209. e.stopPropagation();
  210. });
  211. //When the dropdown loses focus, close it it touch off close is enabled
  212. if( this.settings.touchOffClose ){
  213. $( '.shiftnav-searchbar-drop .shiftnav-search-input').on( 'blur' , function( e ){
  214. if( $( this ).val() == '' && !toggle_clicked ){
  215. $( this ).parents( '.shiftnav-searchbar-drop' ).removeClass( 'shiftnav-searchbar-drop-open' );
  216. }
  217. });
  218. }
  219. var toggle_clicked;
  220. $( '.shiftnav-searchbar-toggle' ).on( 'mousedown' , function( e ){
  221. toggle_clicked = true;
  222. });
  223. $( '.shiftnav-searchbar-toggle' ).on( 'mouseup' , function( e ){
  224. toggle_clicked = false;
  225. });
  226. //Setup shift panel height
  227. $( '.shiftnav' ).css( 'max-height' , window.innerHeight );
  228. $( window ).shiftsmartresize( function(){
  229. $( '.shiftnav' ).css( 'max-height' , window.innerHeight );
  230. });
  231. }
  232. this.$shiftnav.appendTo( 'body' );
  233. if( this.$shiftnav.hasClass( 'shiftnav-right-edge' ) ){
  234. this.edge = 'right';
  235. }
  236. else this.edge = 'left';
  237. this.openclass = 'shiftnav-open shiftnav-open-' + this.edge;
  238. this.$shiftnav.find( '.shiftnav-panel-close' ).on( 'click' , function(){
  239. plugin.closeShiftNav();
  240. });
  241. //Set retractor heights
  242. this.$shiftnav.find( '.shiftnav-submenu-activation' ).each( function(){
  243. //var length = $( this ).outerHeight();
  244. var length = $( this ).siblings( '.shiftnav-target' ).outerHeight();
  245. $( this ).css( { 'height' : length , 'width' : length } );
  246. //$( this ).css( 'height' , $( this ).parent( '.menu-item' ).height() );
  247. });
  248. //Current open
  249. if( plugin.settings.open_current ){
  250. $( '.shiftnav .shiftnav-sub-accordion.current-menu-item, .shiftnav .shiftnav-sub-accordion.current-menu-ancestor' ).addClass( 'shiftnav-active' );
  251. }
  252. },
  253. initializeTargets: function(){
  254. var plugin = this;
  255. this.$shiftnav.find( '.shiftnav-scrollto' )
  256. .removeClass( 'current-menu-item' )
  257. .removeClass( 'current-menu-ancestor');
  258. this.$shiftnav.on( 'click' , '.shiftnav-target' , function( e ){
  259. var scrolltarget = $(this).data( 'shiftnav-scrolltarget' );
  260. if( scrolltarget ){
  261. var $target = $( scrolltarget ).first();
  262. if( $target.length > 0 ){
  263. //Make current
  264. var $li = $(this).parent('.menu-item');
  265. $li.siblings().removeClass( 'current-menu-item' ).removeClass( 'current-menu-ancestor' );
  266. $li.addClass( 'current-menu-item' );
  267. var top = $target.offset().top;
  268. top = top - plugin.settings.scroll_offset;
  269. $( 'html,body' ).animate({
  270. scrollTop: top
  271. }, 1000 , 'swing' ,
  272. function(){
  273. plugin.closeShiftNav(); //close the menu after a successful scroll
  274. });
  275. return false; //don't follow any links if this scroll target is present
  276. }
  277. //if target isn't present here, redirect with hash
  278. else{
  279. var href = $(this).attr( 'href' );
  280. if( href && href.indexOf( '#' ) == -1 ){ //check that hash does not already exist
  281. if( scrolltarget.indexOf( '#' ) == -1 ){ //if this is a class, add a hash tag
  282. scrolltarget = '#'+scrolltarget;
  283. }
  284. window.location = href + scrolltarget; //append hash/scroll target to URL and redirect
  285. e.preventDefault();
  286. }
  287. //No href, no worries
  288. }
  289. }
  290. else if( $( this ).is( 'span' ) ){
  291. var $li = $( this ).parent( '.menu-item' );
  292. if( $li.hasClass( 'shiftnav-active' ) ){
  293. plugin.closeSubmenu( $li , 'disabledLink' , plugin );
  294. }
  295. else{
  296. plugin.openSubmenu( $li , 'disabledLink' , plugin );
  297. }
  298. }
  299. });
  300. },
  301. initializeSubmenuToggleMouseEvents: function(){
  302. //Don't initialize if mouse events are disabled
  303. if( !this.settings.mouseEvents ) return;
  304. if( this.settings.clicktest ) return;
  305. if( this.settings.windowstest ) return;
  306. if( this.settings.debug ) console.log( 'initializeSubmenuToggleMouseEvents' );
  307. var plugin = this;
  308. this.$shiftnav.on( 'mouseup.shift-submenu-toggle' , '.shiftnav-submenu-activation' , function(e){ plugin.handleMouseActivation( e , this , plugin ); } );
  309. //$shiftnav.on( 'mouseout.shift-submenu-toggle' , '.menu-item' , this.handleMouseout ); //now only added on mouseover
  310. },
  311. disableSubmenuToggleMouseEvents: function(){
  312. if( this.settings.debug ) console.log( 'disableSubmenuToggleMouseEvents' );
  313. $shiftnav.off( 'mouseover.shift-submenu-toggle' );
  314. $shiftnav.off( 'mouseout.shift-submenu-toggle' );
  315. },
  316. initializeRetractors: function() {
  317. if( !this.settings.retractors ) return; //Don't initialize if retractors are disabled
  318. var plugin = this;
  319. //set up the retractors
  320. this.$shiftnav.on( 'mouseup.shiftnav' , '.shiftnav-retract' , function(e){ plugin.handleSubmenuRetractorEnd( e , this, plugin); } );
  321. },
  322. initializeResponsiveToggle: function(){
  323. var plugin = this;
  324. this.$toggles.on( 'click' , 'a', function(e){ //this.toggleevent,
  325. //allow link to be clicked but don't propagate so toggle won't activate
  326. e.stopPropagation();
  327. });
  328. //Toggle on click
  329. this.$toggles.on( 'click' , function(e){
  330. plugin.toggle( $(this) , plugin , e );
  331. });
  332. },
  333. toggle: function( $toggle , plugin , e ){
  334. e.preventDefault();
  335. e.stopPropagation();
  336. //Ignore click events when toggle is disabled to avoid both touch and click events firing
  337. if( e.originalEvent.type == 'click' && $(this).data( 'disableToggle' ) ){
  338. return;
  339. }
  340. if( plugin.$shiftnav.hasClass( 'shiftnav-open-target' ) ){
  341. //console.log( 'close shift nav' );
  342. plugin.closeShiftNav();
  343. }
  344. else{
  345. //console.log('open shift nav');
  346. var toggle_id = $toggle.attr( 'id' );
  347. var tag = toggle_id == 'shiftnav-toggle-main' ? '[Main Toggle Bar]' : '"'+$(this).text()+'"';
  348. //When clicking on main toggle, and the menu is open,
  349. //but it's not the main panel, close whichever panel is actually open instead
  350. if( ( ( toggle_id == 'shiftnav-toggle-main-button' ) ||
  351. ( toggle_id == 'shiftnav-toggle-main' ) ) &&
  352. $( 'body' ).hasClass( 'shiftnav-open' ) ){
  353. //Close all shiftnavs
  354. $( '.shiftnav.shiftnav-open-target' ).shiftnav( 'closeShiftNav' );
  355. }
  356. else{
  357. plugin.openShiftNav( 'toggle: ' + tag );
  358. }
  359. }
  360. //Temporarily disable toggle for click event when touch is fired
  361. if( e.originalEvent.type != 'click' ){
  362. $( this ).data( 'disableToggle' , true );
  363. setTimeout( function(){
  364. $( this ).data( 'disableToggle' , false );
  365. }, 1000 );
  366. }
  367. return false;
  368. },
  369. openShiftNav: function( tag ){
  370. tag = tag || '?';
  371. var plugin = this;
  372. if( this.settings.debug ) console.log( 'openShiftNav ' + tag );
  373. $( 'body' )
  374. .removeClass( 'shiftnav-open-right shiftnav-open-left' )
  375. .addClass( this.openclass )
  376. .addClass( 'shiftnav-transitioning' );
  377. //console.log( 'close ' + $( '.shiftnav-open-target' ).attr( 'id' ) );
  378. $( '.shiftnav-open-target' ).removeClass( 'shiftnav-open-target' );
  379. this.$shiftnav
  380. .addClass( 'shiftnav-open-target' )
  381. .on( plugin.transitionend, function(){
  382. //if( plugin.settings.debug ) console.log( 'finished submenu close transition' );
  383. $( 'body' ).removeClass( 'shiftnav-transitioning' );
  384. $( this ).off( plugin.transitionend );
  385. });
  386. this.disableTouchoffClose();
  387. this.initializeTouchoffClose();
  388. },
  389. closeShiftNav: function(){
  390. var plugin = this;
  391. $( 'body' )
  392. .removeClass( this.openclass )
  393. .addClass( 'shiftnav-transitioning' );
  394. this.$shiftnav
  395. .removeClass( 'shiftnav-open-target' )
  396. .on( plugin.transitionend, function(){
  397. //if( plugin.settings.debug ) console.log( 'finished submenu close transition' );
  398. $( 'body' ).removeClass( 'shiftnav-transitioning' );
  399. $( this ).off( plugin.transitionend );
  400. });
  401. this.disableTouchoffClose();
  402. },
  403. initializeTouchoffClose: function(){
  404. if( !this.settings.touchOffClose ) return; //Don't initialize if touch off close is disabled
  405. var plugin = this;
  406. $( document ).on( 'click.shiftnav ' + this.touchEnd + '.shiftnav' , function( e ){ plugin.handleTouchoffClose( e , this , plugin ); } );
  407. },
  408. disableTouchoffClose: function(){
  409. $( document ).off( '.shiftnav' );
  410. },
  411. handleMouseActivation: function( e , activator , plugin ){
  412. if( plugin.settings.debug ) console.log( 'handleMouseover, add mouseout', e );
  413. var $li = $( activator ).parent();
  414. if( $li.hasClass( 'shiftnav-active' ) ){
  415. plugin.closeSubmenu( $li , 'mouseActivate' , plugin );
  416. }
  417. else{
  418. plugin.openSubmenu( $li , 'mouseActivate' , plugin );
  419. }
  420. //Only attach mouseout after mouseover, this way menus opened by touch won't be closed by mouseout
  421. //$li.on( 'mouseout.shift-submenu-toggle' , function( e ){ plugin.handleMouseout( e , this , plugin ); } );
  422. },
  423. handleSubmenuRetractorEnd: function( e , li , plugin ){
  424. e.preventDefault();
  425. e.stopPropagation();
  426. var $li = $(li).parent( 'ul' ).parent( 'li' );
  427. plugin.closeSubmenu( $li , 'handleSubmenuRetractor' , plugin );
  428. if( plugin.settings.debug ) console.log( 'handleSubmenuRetractorEnd ' + $li.find('> a').text());
  429. },
  430. handleTouchoffClose: function( e , _this , plugin ){
  431. //Don't fire during transtion
  432. if( $( 'body' ).is( '.shiftnav-transitioning' ) ) return;
  433. if( $(e.target).parents().add( $(e.target) ).filter( '.shiftnav, .shiftnav-toggle, .shiftnav-ignore' ).length === 0 ){
  434. if( plugin.settings.debug ) console.log( 'touchoff close ', e );
  435. e.preventDefault();
  436. e.stopPropagation();
  437. plugin.closeShiftNav();
  438. plugin.disableTouchoffClose();
  439. }
  440. },
  441. /* Controllers */
  442. scrollPanel: function( y ){
  443. if( shiftnav_data.scroll_panel == 'off' ) return 0;
  444. if( typeof y == 'undefined' ){
  445. return this.$shiftnav.find( '.shiftnav-inner' ).scrollTop();
  446. }
  447. else{
  448. this.$shiftnav.find( '.shiftnav-inner' ).scrollTop( y );
  449. }
  450. },
  451. openSubmenu: function( $li , tag , plugin ){
  452. if( !$li.hasClass( 'shiftnav-active' ) ){
  453. //plugin.setMinimumHeight( 'open' , $li );
  454. if( $li.hasClass( 'shiftnav-sub-shift' ) ){
  455. $li.siblings( '.shiftnav-active' ).removeClass( 'shiftnav-active' );
  456. //switch to position absolute, then delay activation below due to Firefox browser bug
  457. $li.toggleClass( 'shiftnav-caulk' );
  458. plugin.$shiftnav.addClass( 'shiftnav-sub-shift-active' );
  459. }
  460. else{
  461. if( plugin.settings.collapse_accordions ){
  462. $li.siblings( '.shiftnav-active' ).removeClass( 'shiftnav-active' );
  463. }
  464. }
  465. //Active flags
  466. $li.parents( 'ul' ).removeClass( 'shiftnav-sub-active-current' );
  467. $li.find( '> ul' )
  468. .addClass( 'shiftnav-sub-active' )
  469. .addClass( 'shiftnav-sub-active-current' );
  470. //A dumb timeout hack to fix this FireFox browser bug https://bugzilla.mozilla.org/show_bug.cgi?id=625289
  471. setTimeout( function(){
  472. $li.addClass( 'shiftnav-active' );
  473. $li.trigger( 'shiftnav-open-submenu' ); //API
  474. $li.removeClass( 'shiftnav-caulk' );
  475. //Wait until item has moved before calculating position
  476. setTimeout( function(){
  477. //scroll to top of the menu, make note of initial position
  478. var y = plugin.scrollPanel();
  479. $li.data( 'scroll-back' , y );
  480. var scrollPanelTo = $li.offset().top + y;
  481. plugin.scrollPanel( scrollPanelTo );
  482. //plugin.scrollPanel( 0 );
  483. }, 100 );
  484. }, 1 );
  485. }
  486. },
  487. closeSubmenu: function( $li , tag , plugin ){
  488. //var plugin = this;
  489. if( this.settings.debug ) console.log( 'closeSubmenu ' + $li.find( '>a' ).text() + ' [' + tag + ']' );
  490. //If this menu is currently active and has a submenu, close it
  491. if( $li.hasClass( 'menu-item-has-children' ) && $li.hasClass( 'shiftnav-active' ) ){
  492. $li.addClass( 'shiftnav-in-transition' ); //transition class keeps visual flag until transition completes
  493. $li.each( function(){
  494. var _$li = $(this);
  495. var _$ul = _$li.find( '> ul' );
  496. //Remove the transition flag once the transition is completed
  497. _$ul.on( plugin.transitionend + '_closesubmenu', function(){
  498. if( plugin.settings.debug ) console.log( 'finished submenu close transition' );
  499. _$li.removeClass( 'shiftnav-in-transition' );
  500. _$ul.off( plugin.transitionend + '_closesubmenu' );
  501. });
  502. //Close all children
  503. plugin.closeSubmenu( _$li.find( '.shiftnav-active' ) , tag+'_recursive' , plugin );
  504. });
  505. }
  506. //Actually remove the active class, which causes the submenu to close
  507. $li.removeClass( 'shiftnav-active' );
  508. //Shift Sub Specific
  509. if( $li.hasClass( 'shiftnav-sub-shift' ) ){
  510. if( $li.parents( '.shiftnav-sub-shift' ).length == 0 ) plugin.$shiftnav.removeClass( 'shiftnav-sub-shift-active' );
  511. //return to original position
  512. var y = $li.data( 'scroll-back' );
  513. if( y !== 'undefined' ) plugin.scrollPanel( y );
  514. //console.log( 'y = ' + y );
  515. }
  516. //Active flags
  517. $li.find( '> ul' )
  518. .removeClass( 'shiftnav-sub-active' )
  519. .removeClass( 'shiftnav-sub-active-current' );
  520. $li.closest( 'ul' ).addClass( 'shiftnav-sub-active-current' );
  521. $li.trigger( 'shiftnav-close-submenu' ); //API
  522. },
  523. closeAllSubmenus: function(){
  524. $( this.element ).find( 'li.menu-item-has-children' ).removeClass( 'shiftnav-active' );
  525. },
  526. };
  527. $.fn[ pluginName ] = function ( options ) {
  528. var args = arguments;
  529. if ( options === undefined || typeof options === 'object' ) {
  530. return this.each(function() {
  531. if ( !$.data( this, "plugin_" + pluginName ) ) {
  532. $.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
  533. }
  534. });
  535. }
  536. else if ( typeof options === 'string' && options[0] !== '_' && options !== 'init') {
  537. // Cache the method call to make it possible to return a value
  538. var returns;
  539. this.each(function () {
  540. var instance = $.data(this, 'plugin_' + pluginName);
  541. // Tests that there's already a plugin-instance and checks that the requested public method exists
  542. if ( instance instanceof Plugin && typeof instance[options] === 'function') {
  543. // Call the method of our plugin instance, and pass it the supplied arguments.
  544. returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
  545. }
  546. // Allow instances to be destroyed via the 'destroy' method
  547. if (options === 'destroy') {
  548. $.data(this, 'plugin_' + pluginName, null);
  549. }
  550. });
  551. // If the earlier cached method gives a value back return the value, otherwise return this to preserve chainability.
  552. return returns !== undefined ? returns : this;
  553. }
  554. };
  555. })( jQuery, window, document );
  556. (function($){
  557. var shiftnav_is_initialized = false;
  558. jQuery(function($) {
  559. initialize_shiftnav( 'document.ready' );
  560. });
  561. //Backup
  562. $( window ).on( 'load' , function(){
  563. initialize_shiftnav( 'window.load' );
  564. });
  565. function initialize_shiftnav( init_point ){
  566. if( shiftnav_is_initialized ) return;
  567. shiftnav_is_initialized = true;
  568. if( ( typeof console != "undefined" ) && init_point == 'window.load' ) console.log( 'ShiftNav initialized via ' + init_point );
  569. //Remove Loading Message
  570. $( '.shiftnav-loading' ).remove();
  571. //Run ShiftNav
  572. jQuery( '.shiftnav' ).shiftnav({
  573. open_current : shiftnav_data.open_current == 'on' ? true : false,
  574. collapse_accordions : shiftnav_data.collapse_accordions == 'on' ? true : false,
  575. breakpoint : parseInt( shiftnav_data.breakpoint ),
  576. touchOffClose: shiftnav_data.touch_off_close == 'on' ? true : false,
  577. scroll_offset: shiftnav_data.scroll_offset,
  578. disable_transforms: shiftnav_data.disable_transforms == 'on' ? true : false
  579. //debug: true
  580. //mouseEvents: false
  581. //clicktest: true
  582. });
  583. //Scroll to non-ID "hashes"
  584. if( window.location.hash.substring(1,2) == '.' ){
  585. var $scrollTarget = $( window.location.hash.substring(1) );
  586. if( $scrollTarget.length ){
  587. var top = $scrollTarget.offset().top - shiftnav_data.scroll_offset;
  588. if( $scrollTarget.length ) window.scrollTo( 0 , top );
  589. }
  590. }
  591. if( window.location.hash ){
  592. //Highlight item
  593. var hash = window.location.hash;
  594. if( hash.substring(1,2) == '.' ) hash = hash.substring(1);
  595. //Sanitize any hash string, just in case. These ar all the valid URL fragment characters, anything else gets stripped
  596. hash = hash.replace( /[^#a-z0-9!$&'()*+,;=]/gi , '' ); //hash = hash.replace(/\W/g,
  597. //var $li = $( '.shiftnav .shiftnav-target[data-shiftnav-scrolltarget="'+hash+'"]' ).parent();
  598. //Do it this way to avoid passing user-editable content into the $() function - find() is safer
  599. var $li = $( '.shiftnav' ).find( '.shiftnav-target[data-shiftnav-scrolltarget="'+hash+'"]' ).parent();
  600. if( $li.length ){
  601. //console.log( $li );
  602. $li.siblings().removeClass( 'current-menu-item' ).removeClass( 'current-menu-ancestor' );
  603. $li.addClass( 'current-menu-item' );
  604. }
  605. }
  606. $( '.shiftnav' ).trigger( 'shiftnav-loaded' );
  607. }
  608. function escapeHtml(str) {
  609. var div = document.createElement('div');
  610. div.appendChild(document.createTextNode(str));
  611. return div.innerHTML;
  612. }
  613. })(jQuery);