foundation.topbar.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. ;(function ($, window, document, undefined) {
  2. 'use strict';
  3. Foundation.libs.topbar = {
  4. name : 'topbar',
  5. version: '5.3.3',
  6. settings : {
  7. index : 0,
  8. sticky_class : 'sticky',
  9. custom_back_text: true,
  10. back_text: 'Back',
  11. mobile_show_parent_link: true,
  12. is_hover: true,
  13. scrolltop : true, // jump to top when sticky nav menu toggle is clicked
  14. sticky_on : 'all'
  15. },
  16. init : function (section, method, options) {
  17. Foundation.inherit(this, 'add_custom_rule register_media throttle');
  18. var self = this;
  19. self.register_media('topbar', 'foundation-mq-topbar');
  20. this.bindings(method, options);
  21. self.S('[' + this.attr_name() + ']', this.scope).each(function () {
  22. var topbar = $(this),
  23. settings = topbar.data(self.attr_name(true) + '-init'),
  24. section = self.S('section, .top-bar-section', this);
  25. topbar.data('index', 0);
  26. var topbarContainer = topbar.parent();
  27. if (topbarContainer.hasClass('fixed') || self.is_sticky(topbar, topbarContainer, settings) ) {
  28. self.settings.sticky_class = settings.sticky_class;
  29. self.settings.sticky_topbar = topbar;
  30. topbar.data('height', topbarContainer.outerHeight());
  31. topbar.data('stickyoffset', topbarContainer.offset().top);
  32. } else {
  33. topbar.data('height', topbar.outerHeight());
  34. }
  35. if (!settings.assembled) {
  36. self.assemble(topbar);
  37. }
  38. if (settings.is_hover) {
  39. self.S('.has-dropdown', topbar).addClass('not-click');
  40. } else {
  41. self.S('.has-dropdown', topbar).removeClass('not-click');
  42. }
  43. // Pad body when sticky (scrolled) or fixed.
  44. self.add_custom_rule('.f-topbar-fixed { padding-top: ' + topbar.data('height') + 'px }');
  45. if (topbarContainer.hasClass('fixed')) {
  46. self.S('body').addClass('f-topbar-fixed');
  47. }
  48. });
  49. },
  50. is_sticky: function (topbar, topbarContainer, settings) {
  51. var sticky = topbarContainer.hasClass(settings.sticky_class);
  52. if (sticky && settings.sticky_on === 'all') {
  53. return true;
  54. } else if (sticky && this.small() && settings.sticky_on === 'small') {
  55. return (matchMedia(Foundation.media_queries.small).matches && !matchMedia(Foundation.media_queries.medium).matches &&
  56. !matchMedia(Foundation.media_queries.large).matches);
  57. //return true;
  58. } else if (sticky && this.medium() && settings.sticky_on === 'medium') {
  59. return (matchMedia(Foundation.media_queries.small).matches && matchMedia(Foundation.media_queries.medium).matches &&
  60. !matchMedia(Foundation.media_queries.large).matches);
  61. //return true;
  62. } else if(sticky && this.large() && settings.sticky_on === 'large') {
  63. return (matchMedia(Foundation.media_queries.small).matches && matchMedia(Foundation.media_queries.medium).matches &&
  64. matchMedia(Foundation.media_queries.large).matches);
  65. //return true;
  66. }
  67. return false;
  68. },
  69. toggle: function (toggleEl) {
  70. var self = this,
  71. topbar;
  72. if (toggleEl) {
  73. topbar = self.S(toggleEl).closest('[' + this.attr_name() + ']');
  74. } else {
  75. topbar = self.S('[' + this.attr_name() + ']');
  76. }
  77. var settings = topbar.data(this.attr_name(true) + '-init');
  78. var section = self.S('section, .top-bar-section', topbar);
  79. if (self.breakpoint()) {
  80. if (!self.rtl) {
  81. section.css({left: '0%'});
  82. $('>.name', section).css({left: '100%'});
  83. } else {
  84. section.css({right: '0%'});
  85. $('>.name', section).css({right: '100%'});
  86. }
  87. self.S('li.moved', section).removeClass('moved');
  88. topbar.data('index', 0);
  89. topbar
  90. .toggleClass('expanded')
  91. .css('height', '');
  92. }
  93. if (settings.scrolltop) {
  94. if (!topbar.hasClass('expanded')) {
  95. if (topbar.hasClass('fixed')) {
  96. topbar.parent().addClass('fixed');
  97. topbar.removeClass('fixed');
  98. self.S('body').addClass('f-topbar-fixed');
  99. }
  100. } else if (topbar.parent().hasClass('fixed')) {
  101. if (settings.scrolltop) {
  102. topbar.parent().removeClass('fixed');
  103. topbar.addClass('fixed');
  104. self.S('body').removeClass('f-topbar-fixed');
  105. window.scrollTo(0,0);
  106. } else {
  107. topbar.parent().removeClass('expanded');
  108. }
  109. }
  110. } else {
  111. if (self.is_sticky(topbar, topbar.parent(), settings)) {
  112. topbar.parent().addClass('fixed');
  113. }
  114. if (topbar.parent().hasClass('fixed')) {
  115. if (!topbar.hasClass('expanded')) {
  116. topbar.removeClass('fixed');
  117. topbar.parent().removeClass('expanded');
  118. self.update_sticky_positioning();
  119. } else {
  120. topbar.addClass('fixed');
  121. topbar.parent().addClass('expanded');
  122. self.S('body').addClass('f-topbar-fixed');
  123. }
  124. }
  125. }
  126. },
  127. timer : null,
  128. events : function (bar) {
  129. var self = this,
  130. S = this.S;
  131. S(this.scope)
  132. .off('.topbar')
  133. .on('click.fndtn.topbar', '[' + this.attr_name() + '] .toggle-topbar', function (e) {
  134. e.preventDefault();
  135. self.toggle(this);
  136. })
  137. .on('click.fndtn.topbar','.top-bar .top-bar-section li a[href^="#"],[' + this.attr_name() + '] .top-bar-section li a[href^="#"]',function (e) {
  138. var li = $(this).closest('li');
  139. if(self.breakpoint() && !li.hasClass('back') && !li.hasClass('has-dropdown'))
  140. {
  141. self.toggle();
  142. }
  143. })
  144. .on('click.fndtn.topbar', '[' + this.attr_name() + '] li.has-dropdown', function (e) {
  145. var li = S(this),
  146. target = S(e.target),
  147. topbar = li.closest('[' + self.attr_name() + ']'),
  148. settings = topbar.data(self.attr_name(true) + '-init');
  149. if(target.data('revealId')) {
  150. self.toggle();
  151. return;
  152. }
  153. if (self.breakpoint()) return;
  154. if (settings.is_hover && !Modernizr.touch) return;
  155. e.stopImmediatePropagation();
  156. if (li.hasClass('hover')) {
  157. li
  158. .removeClass('hover')
  159. .find('li')
  160. .removeClass('hover');
  161. li.parents('li.hover')
  162. .removeClass('hover');
  163. } else {
  164. li.addClass('hover');
  165. $(li).siblings().removeClass('hover');
  166. if (target[0].nodeName === 'A' && target.parent().hasClass('has-dropdown')) {
  167. e.preventDefault();
  168. }
  169. }
  170. })
  171. .on('click.fndtn.topbar', '[' + this.attr_name() + '] .has-dropdown>a', function (e) {
  172. if (self.breakpoint()) {
  173. e.preventDefault();
  174. var $this = S(this),
  175. topbar = $this.closest('[' + self.attr_name() + ']'),
  176. section = topbar.find('section, .top-bar-section'),
  177. dropdownHeight = $this.next('.dropdown').outerHeight(),
  178. $selectedLi = $this.closest('li');
  179. topbar.data('index', topbar.data('index') + 1);
  180. $selectedLi.addClass('moved');
  181. if (!self.rtl) {
  182. section.css({left: -(100 * topbar.data('index')) + '%'});
  183. section.find('>.name').css({left: 100 * topbar.data('index') + '%'});
  184. } else {
  185. section.css({right: -(100 * topbar.data('index')) + '%'});
  186. section.find('>.name').css({right: 100 * topbar.data('index') + '%'});
  187. }
  188. topbar.css('height', $this.siblings('ul').outerHeight(true) + topbar.data('height'));
  189. }
  190. });
  191. S(window).off(".topbar").on("resize.fndtn.topbar", self.throttle(function() {
  192. self.resize.call(self);
  193. }, 50)).trigger("resize").trigger("resize.fndtn.topbar").load(function(){
  194. // Ensure that the offset is calculated after all of the pages resources have loaded
  195. S(this).trigger("resize.fndtn.topbar");
  196. });
  197. S('body').off('.topbar').on('click.fndtn.topbar', function (e) {
  198. var parent = S(e.target).closest('li').closest('li.hover');
  199. if (parent.length > 0) {
  200. return;
  201. }
  202. S('[' + self.attr_name() + '] li.hover').removeClass('hover');
  203. });
  204. // Go up a level on Click
  205. S(this.scope).on('click.fndtn.topbar', '[' + this.attr_name() + '] .has-dropdown .back', function (e) {
  206. e.preventDefault();
  207. var $this = S(this),
  208. topbar = $this.closest('[' + self.attr_name() + ']'),
  209. section = topbar.find('section, .top-bar-section'),
  210. settings = topbar.data(self.attr_name(true) + '-init'),
  211. $movedLi = $this.closest('li.moved'),
  212. $previousLevelUl = $movedLi.parent();
  213. topbar.data('index', topbar.data('index') - 1);
  214. if (!self.rtl) {
  215. section.css({left: -(100 * topbar.data('index')) + '%'});
  216. section.find('>.name').css({left: 100 * topbar.data('index') + '%'});
  217. } else {
  218. section.css({right: -(100 * topbar.data('index')) + '%'});
  219. section.find('>.name').css({right: 100 * topbar.data('index') + '%'});
  220. }
  221. if (topbar.data('index') === 0) {
  222. topbar.css('height', '');
  223. } else {
  224. topbar.css('height', $previousLevelUl.outerHeight(true) + topbar.data('height'));
  225. }
  226. setTimeout(function () {
  227. $movedLi.removeClass('moved');
  228. }, 300);
  229. });
  230. },
  231. resize : function () {
  232. var self = this;
  233. self.S('[' + this.attr_name() + ']').each(function () {
  234. var topbar = self.S(this),
  235. settings = topbar.data(self.attr_name(true) + '-init');
  236. var stickyContainer = topbar.parent('.' + self.settings.sticky_class);
  237. var stickyOffset;
  238. if (!self.breakpoint()) {
  239. var doToggle = topbar.hasClass('expanded');
  240. topbar
  241. .css('height', '')
  242. .removeClass('expanded')
  243. .find('li')
  244. .removeClass('hover');
  245. if(doToggle) {
  246. self.toggle(topbar);
  247. }
  248. }
  249. if(self.is_sticky(topbar, stickyContainer, settings)) {
  250. if(stickyContainer.hasClass('fixed')) {
  251. // Remove the fixed to allow for correct calculation of the offset.
  252. stickyContainer.removeClass('fixed');
  253. stickyOffset = stickyContainer.offset().top;
  254. if(self.S(document.body).hasClass('f-topbar-fixed')) {
  255. stickyOffset -= topbar.data('height');
  256. }
  257. topbar.data('stickyoffset', stickyOffset);
  258. stickyContainer.addClass('fixed');
  259. } else {
  260. stickyOffset = stickyContainer.offset().top;
  261. topbar.data('stickyoffset', stickyOffset);
  262. }
  263. }
  264. });
  265. },
  266. breakpoint : function () {
  267. return !matchMedia(Foundation.media_queries['topbar']).matches;
  268. },
  269. small : function () {
  270. return matchMedia(Foundation.media_queries['small']).matches;
  271. },
  272. medium : function () {
  273. return matchMedia(Foundation.media_queries['medium']).matches;
  274. },
  275. large : function () {
  276. return matchMedia(Foundation.media_queries['large']).matches;
  277. },
  278. assemble : function (topbar) {
  279. var self = this,
  280. settings = topbar.data(this.attr_name(true) + '-init'),
  281. section = self.S('section, .top-bar-section', topbar);
  282. // Pull element out of the DOM for manipulation
  283. section.detach();
  284. self.S('.has-dropdown>a', section).each(function () {
  285. var $link = self.S(this),
  286. $dropdown = $link.siblings('.dropdown'),
  287. url = $link.attr('href'),
  288. $titleLi;
  289. if (!$dropdown.find('.title.back').length) {
  290. if (settings.mobile_show_parent_link == true && url) {
  291. $titleLi = $('<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5></li><li class="parent-link show-for-small"><a class="parent-link js-generated" href="' + url + '">' + $link.html() +'</a></li>');
  292. } else {
  293. $titleLi = $('<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5>');
  294. }
  295. // Copy link to subnav
  296. if (settings.custom_back_text == true) {
  297. $('h5>a', $titleLi).html(settings.back_text);
  298. } else {
  299. $('h5>a', $titleLi).html('&laquo; ' + $link.html());
  300. }
  301. $dropdown.prepend($titleLi);
  302. }
  303. });
  304. // Put element back in the DOM
  305. section.appendTo(topbar);
  306. // check for sticky
  307. this.sticky();
  308. this.assembled(topbar);
  309. },
  310. assembled : function (topbar) {
  311. topbar.data(this.attr_name(true), $.extend({}, topbar.data(this.attr_name(true)), {assembled: true}));
  312. },
  313. height : function (ul) {
  314. var total = 0,
  315. self = this;
  316. $('> li', ul).each(function () {
  317. total += self.S(this).outerHeight(true);
  318. });
  319. return total;
  320. },
  321. sticky : function () {
  322. var self = this;
  323. this.S(window).on('scroll', function() {
  324. self.update_sticky_positioning();
  325. });
  326. },
  327. update_sticky_positioning: function() {
  328. var klass = '.' + this.settings.sticky_class,
  329. $window = this.S(window),
  330. self = this;
  331. if (self.settings.sticky_topbar && self.is_sticky(this.settings.sticky_topbar,this.settings.sticky_topbar.parent(), this.settings)) {
  332. var distance = this.settings.sticky_topbar.data('stickyoffset');
  333. if (!self.S(klass).hasClass('expanded')) {
  334. if ($window.scrollTop() > (distance)) {
  335. if (!self.S(klass).hasClass('fixed')) {
  336. self.S(klass).addClass('fixed');
  337. self.S('body').addClass('f-topbar-fixed');
  338. }
  339. } else if ($window.scrollTop() <= distance) {
  340. if (self.S(klass).hasClass('fixed')) {
  341. self.S(klass).removeClass('fixed');
  342. self.S('body').removeClass('f-topbar-fixed');
  343. }
  344. }
  345. }
  346. }
  347. },
  348. off : function () {
  349. this.S(this.scope).off('.fndtn.topbar');
  350. this.S(window).off('.fndtn.topbar');
  351. },
  352. reflow : function () {}
  353. };
  354. }(jQuery, window, window.document));