foundation.magellan.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. ;(function ($, window, document, undefined) {
  2. 'use strict';
  3. Foundation.libs['magellan-expedition'] = {
  4. name : 'magellan-expedition',
  5. version : '5.2.2',
  6. settings : {
  7. active_class: 'active',
  8. threshold: 0, // pixels from the top of the expedition for it to become fixes
  9. destination_threshold: 20, // pixels from the top of destination for it to be considered active
  10. throttle_delay: 30 // calculation throttling to increase framerate
  11. },
  12. init : function (scope, method, options) {
  13. Foundation.inherit(this, 'throttle');
  14. this.bindings(method, options);
  15. },
  16. events : function () {
  17. var self = this,
  18. S = self.S,
  19. settings = self.settings;
  20. // initialize expedition offset
  21. self.set_expedition_position();
  22. S(self.scope)
  23. .off('.magellan')
  24. .on('click.fndtn.magellan', '[' + self.add_namespace('data-magellan-arrival') + '] a[href^="#"]', function (e) {
  25. e.preventDefault();
  26. var expedition = $(this).closest('[' + self.attr_name() + ']'),
  27. settings = expedition.data('magellan-expedition-init');
  28. var hash = this.hash.split('#').join(''),
  29. target = $("a[name='"+hash+"']");
  30. if (target.length === 0) target = $('#'+hash);
  31. // Account for expedition height if fixed position
  32. var scroll_top = target.offset().top;
  33. scroll_top = scroll_top - expedition.outerHeight();
  34. $('html, body').stop().animate({
  35. 'scrollTop': scroll_top
  36. }, 700, 'swing', function () {
  37. if(history.pushState) {
  38. history.pushState(null, null, '#'+hash);
  39. }
  40. else {
  41. location.hash = '#'+hash;
  42. }
  43. });
  44. })
  45. .on('scroll.fndtn.magellan', self.throttle(this.check_for_arrivals.bind(this), settings.throttle_delay))
  46. $(window).on('resize.fndtn.magellan', self.throttle(this.set_expedition_position.bind(this), settings.throttle_delay));
  47. },
  48. check_for_arrivals : function() {
  49. var self = this;
  50. self.update_arrivals();
  51. self.update_expedition_positions();
  52. },
  53. set_expedition_position : function() {
  54. var self = this;
  55. $('[' + this.attr_name() + '=fixed]', self.scope).each(function(idx, el) {
  56. var expedition = $(this),
  57. styles = expedition.attr('styles'), // save styles
  58. top_offset;
  59. expedition.attr('style', '');
  60. top_offset = expedition.offset().top;
  61. expedition.data(self.data_attr('magellan-top-offset'), top_offset);
  62. expedition.attr('style', styles);
  63. });
  64. },
  65. update_expedition_positions : function() {
  66. var self = this,
  67. window_top_offset = $(window).scrollTop();
  68. $('[' + this.attr_name() + '=fixed]', self.scope).each(function() {
  69. var expedition = $(this),
  70. top_offset = expedition.data('magellan-top-offset');
  71. if (window_top_offset >= top_offset) {
  72. // Placeholder allows height calculations to be consistent even when
  73. // appearing to switch between fixed/non-fixed placement
  74. var placeholder = expedition.prev('[' + self.add_namespace('data-magellan-expedition-clone') + ']');
  75. if (placeholder.length === 0) {
  76. placeholder = expedition.clone();
  77. placeholder.removeAttr(self.attr_name());
  78. placeholder.attr(self.add_namespace('data-magellan-expedition-clone'),'');
  79. expedition.before(placeholder);
  80. }
  81. expedition.css({position:'fixed', top: 0});
  82. } else {
  83. expedition.prev('[' + self.add_namespace('data-magellan-expedition-clone') + ']').remove();
  84. expedition.attr('style','');
  85. }
  86. });
  87. },
  88. update_arrivals : function() {
  89. var self = this,
  90. window_top_offset = $(window).scrollTop();
  91. $('[' + this.attr_name() + ']', self.scope).each(function() {
  92. var expedition = $(this),
  93. settings = settings = expedition.data(self.attr_name(true) + '-init'),
  94. offsets = self.offsets(expedition, window_top_offset),
  95. arrivals = expedition.find('[' + self.add_namespace('data-magellan-arrival') + ']'),
  96. active_item = false;
  97. offsets.each(function(idx, item) {
  98. if (item.viewport_offset >= item.top_offset) {
  99. var arrivals = expedition.find('[' + self.add_namespace('data-magellan-arrival') + ']');
  100. arrivals.not(item.arrival).removeClass(settings.active_class);
  101. item.arrival.addClass(settings.active_class);
  102. active_item = true;
  103. return true;
  104. }
  105. });
  106. if (!active_item) arrivals.removeClass(settings.active_class);
  107. });
  108. },
  109. offsets : function(expedition, window_offset) {
  110. var self = this,
  111. settings = expedition.data(self.attr_name(true) + '-init'),
  112. viewport_offset = window_offset;
  113. return expedition.find('[' + self.add_namespace('data-magellan-arrival') + ']').map(function(idx, el) {
  114. var name = $(this).data(self.data_attr('magellan-arrival')),
  115. dest = $('[' + self.add_namespace('data-magellan-destination') + '=' + name + ']');
  116. if (dest.length > 0) {
  117. var top_offset = dest.offset().top - settings.destination_threshold - expedition.outerHeight();
  118. return {
  119. destination : dest,
  120. arrival : $(this),
  121. top_offset : top_offset,
  122. viewport_offset : viewport_offset
  123. }
  124. }
  125. }).sort(function(a, b) {
  126. if (a.top_offset < b.top_offset) return -1;
  127. if (a.top_offset > b.top_offset) return 1;
  128. return 0;
  129. });
  130. },
  131. data_attr: function (str) {
  132. if (this.namespace.length > 0) {
  133. return this.namespace + '-' + str;
  134. }
  135. return str;
  136. },
  137. off : function () {
  138. this.S(this.scope).off('.magellan');
  139. this.S(window).off('.magellan');
  140. },
  141. reflow : function () {
  142. var self = this;
  143. // remove placeholder expeditions used for height calculation purposes
  144. $('[' + self.add_namespace('data-magellan-expedition-clone') + ']', self.scope).remove();
  145. }
  146. };
  147. }(jQuery, this, this.document));