superclick.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Superclick v1.0.0 - jQuery menu widget
  3. * Copyright (c) 2013 Joel Birch
  4. *
  5. * Dual licensed under the MIT and GPL licenses:
  6. * http://www.opensource.org/licenses/mit-license.php
  7. * http://www.gnu.org/licenses/gpl.html
  8. */
  9. ;(function($) {
  10. var methods = (function(){
  11. // private properties and methods go here
  12. var c = {
  13. bcClass: 'sf-breadcrumb',
  14. menuClass: 'sf-js-enabled',
  15. anchorClass: 'sf-with-ul',
  16. menuArrowClass: 'sf-arrows'
  17. },
  18. outerClick = (function() {
  19. $(window).load(function() {
  20. $('body').children().on('click.superclick', function() {
  21. var $allMenus = $('.sf-js-enabled');
  22. $allMenus.superclick('reset');
  23. });
  24. });
  25. })(),
  26. toggleMenuClasses = function($menu, o) {
  27. var classes = c.menuClass;
  28. if (o.cssArrows) {
  29. classes += ' ' + c.menuArrowClass;
  30. }
  31. $menu.toggleClass(classes);
  32. },
  33. setPathToCurrent = function($menu, o) {
  34. return $menu.find('li.' + o.pathClass).slice(0, o.pathLevels)
  35. .addClass(o.activeClass + ' ' + c.bcClass)
  36. .filter(function() {
  37. return ($(this).children('.sidebar-submenu').hide().show().length);
  38. }).removeClass(o.pathClass);
  39. },
  40. toggleAnchorClass = function($li) {
  41. $li.children('a').toggleClass(c.anchorClass);
  42. },
  43. toggleTouchAction = function($menu) {
  44. var touchAction = $menu.css('ms-touch-action');
  45. touchAction = (touchAction === 'pan-y') ? 'auto' : 'pan-y';
  46. $menu.css('ms-touch-action', touchAction);
  47. },
  48. clickHandler = function(e) {
  49. var $this = $(this),
  50. $ul = $this.siblings('.sidebar-submenu'),
  51. func;
  52. if ($ul.length) {
  53. func = ($ul.is(':hidden')) ? over : out;
  54. $.proxy(func, $this.parent('li'))();
  55. return false;
  56. }
  57. },
  58. over = function() {
  59. var $this = $(this),
  60. o = getOptions($this);
  61. $this.siblings().superclick('hide').end().superclick('show');
  62. },
  63. out = function() {
  64. var $this = $(this),
  65. o = getOptions($this);
  66. $.proxy(close, $this, o)();
  67. },
  68. close = function(o) {
  69. o.retainPath = ( $.inArray(this[0], o.$path) > -1);
  70. this.superclick('hide');
  71. if (!this.parents('.' + o.activeClass).length) {
  72. o.onIdle.call(getMenu(this));
  73. if (o.$path.length) {
  74. $.proxy(over, o.$path)();
  75. }
  76. }
  77. },
  78. getMenu = function($el) {
  79. return $el.closest('.' + c.menuClass);
  80. },
  81. getOptions = function($el) {
  82. return getMenu($el).data('sf-options');
  83. };
  84. return {
  85. // public methods
  86. hide: function(instant) {
  87. if (this.length) {
  88. var $this = this,
  89. o = getOptions($this);
  90. if (!o) {
  91. return this;
  92. }
  93. var not = (o.retainPath === true) ? o.$path : '',
  94. $ul = $this.find('li.' + o.activeClass).add(this).not(not).removeClass(o.activeClass).children('.sidebar-submenu'),
  95. speed = o.speedOut;
  96. if (instant) {
  97. $ul.show();
  98. speed = 0;
  99. }
  100. o.retainPath = false;
  101. o.onBeforeHide.call($ul);
  102. $ul.stop(true, true).animate(o.animationOut, speed, function() {
  103. var $this = $(this);
  104. o.onHide.call($this);
  105. });
  106. }
  107. return this;
  108. },
  109. show: function() {
  110. var o = getOptions(this);
  111. if (!o) {
  112. return this;
  113. }
  114. var $this = this.addClass(o.activeClass),
  115. $ul = $this.children('.sidebar-submenu');
  116. o.onBeforeShow.call($ul);
  117. $ul.stop(true, true).animate(o.animation, o.speed, function() {
  118. o.onShow.call($ul);
  119. });
  120. return this;
  121. },
  122. destroy: function() {
  123. return this.each(function(){
  124. var $this = $(this),
  125. o = $this.data('sf-options'),
  126. $liHasUl = $this.find('li:has(ul)');
  127. if (!o) {
  128. return false;
  129. }
  130. toggleMenuClasses($this, o);
  131. toggleAnchorClass($liHasUl);
  132. toggleTouchAction($this);
  133. // remove event handlers
  134. $this.off('.superclick');
  135. // clear animation's inline display style
  136. $liHasUl.children('.sidebar-submenu').attr('style', function(i, style){
  137. return style.replace(/display[^;]+;?/g, '');
  138. });
  139. // reset 'current' path classes
  140. o.$path.removeClass(o.activeClass + ' ' + c.bcClass).addClass(o.pathClass);
  141. $this.find('.' + o.activeClass).removeClass(o.activeClass);
  142. o.onDestroy.call($this);
  143. $this.removeData('sf-options');
  144. });
  145. },
  146. reset: function() {
  147. return this.each(function(){
  148. var $menu = $(this),
  149. o = getOptions($menu),
  150. $openLis = $( $menu.find('.' + o.activeClass).toArray().reverse() );
  151. $openLis.children('a').trigger('click');
  152. });
  153. },
  154. init: function(op){
  155. return this.each(function() {
  156. var $this = $(this);
  157. if ($this.data('sf-options')) {
  158. return false;
  159. }
  160. var o = $.extend({}, $.fn.superclick.defaults, op),
  161. $liHasUl = $this.find('li:has(ul)');
  162. o.$path = setPathToCurrent($this, o);
  163. $this.data('sf-options', o);
  164. toggleMenuClasses($this, o);
  165. toggleAnchorClass($liHasUl);
  166. toggleTouchAction($this);
  167. $this.on('click.superclick', 'a', clickHandler);
  168. $liHasUl.not('.' + c.bcClass).superclick('hide',true);
  169. o.onInit.call(this);
  170. });
  171. }
  172. };
  173. })();
  174. $.fn.superclick = function(method, args) {
  175. if (methods[method]) {
  176. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  177. }
  178. else if (typeof method === 'object' || ! method) {
  179. return methods.init.apply(this, arguments);
  180. }
  181. else {
  182. return $.error('Method ' + method + ' does not exist on jQuery.fn.superclick');
  183. }
  184. };
  185. $.fn.superclick.defaults = {
  186. activeClass: 'sfHover', // keep 'hover' in classname for compatibility reasons
  187. pathClass: 'overrideThisToUse',
  188. pathLevels: 1,
  189. animation: {opacity:'show'},
  190. animationOut: {opacity:'hide'},
  191. speed: 'normal',
  192. speedOut: 'fast',
  193. cssArrows: true,
  194. onInit: $.noop,
  195. onBeforeShow: $.noop,
  196. onShow: $.noop,
  197. onBeforeHide: $.noop,
  198. onHide: $.noop,
  199. onIdle: $.noop,
  200. onDestroy: $.noop
  201. };
  202. })(jQuery);