materialize-rails 0.97.5.custom1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +63 -0
  6. data/Rakefile +1 -0
  7. data/lib/materialize-rails.rb +25 -0
  8. data/lib/materialize-rails/engine.rb +14 -0
  9. data/lib/materialize-rails/version.rb +3 -0
  10. data/materialize-rails.gemspec +25 -0
  11. data/vendor/assets/fonts/materialize/material-design-icons/LICENSE.txt +428 -0
  12. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.eot +0 -0
  13. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.svg +769 -0
  14. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.ttf +0 -0
  15. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.woff +0 -0
  16. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.woff2 +0 -0
  17. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.eot +0 -0
  18. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.ttf +0 -0
  19. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.woff +0 -0
  20. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.woff2 +0 -0
  21. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.eot +0 -0
  22. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.ttf +0 -0
  23. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.woff +0 -0
  24. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.woff2 +0 -0
  25. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.eot +0 -0
  26. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.ttf +0 -0
  27. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.woff +0 -0
  28. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.woff2 +0 -0
  29. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.eot +0 -0
  30. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.ttf +0 -0
  31. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.woff +0 -0
  32. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.woff2 +0 -0
  33. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.eot +0 -0
  34. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.ttf +0 -0
  35. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.woff +0 -0
  36. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.woff2 +0 -0
  37. data/vendor/assets/javascripts/materialize.js +30 -0
  38. data/vendor/assets/javascripts/materialize/animation.js +9 -0
  39. data/vendor/assets/javascripts/materialize/buttons.js +91 -0
  40. data/vendor/assets/javascripts/materialize/cards.js +29 -0
  41. data/vendor/assets/javascripts/materialize/carousel.js +350 -0
  42. data/vendor/assets/javascripts/materialize/character_counter.js +59 -0
  43. data/vendor/assets/javascripts/materialize/chips.js +9 -0
  44. data/vendor/assets/javascripts/materialize/collapsible.js +137 -0
  45. data/vendor/assets/javascripts/materialize/date_picker/picker.date.js +1430 -0
  46. data/vendor/assets/javascripts/materialize/date_picker/picker.js +1123 -0
  47. data/vendor/assets/javascripts/materialize/dropdown.js +228 -0
  48. data/vendor/assets/javascripts/materialize/forms.js +581 -0
  49. data/vendor/assets/javascripts/materialize/global.js +45 -0
  50. data/vendor/assets/javascripts/materialize/hammer.min.js +1 -0
  51. data/vendor/assets/javascripts/materialize/initial.js +11 -0
  52. data/vendor/assets/javascripts/materialize/jquery.easing.1.3.js +205 -0
  53. data/vendor/assets/javascripts/materialize/jquery.hammer.js +33 -0
  54. data/vendor/assets/javascripts/materialize/leanModal.js +178 -0
  55. data/vendor/assets/javascripts/materialize/materialbox.js +269 -0
  56. data/vendor/assets/javascripts/materialize/parallax.js +58 -0
  57. data/vendor/assets/javascripts/materialize/pushpin.js +62 -0
  58. data/vendor/assets/javascripts/materialize/scrollFire.js +44 -0
  59. data/vendor/assets/javascripts/materialize/scrollspy.js +285 -0
  60. data/vendor/assets/javascripts/materialize/sideNav.js +315 -0
  61. data/vendor/assets/javascripts/materialize/slider.js +321 -0
  62. data/vendor/assets/javascripts/materialize/tabs.js +129 -0
  63. data/vendor/assets/javascripts/materialize/toasts.js +136 -0
  64. data/vendor/assets/javascripts/materialize/tooltip.js +203 -0
  65. data/vendor/assets/javascripts/materialize/transitions.js +154 -0
  66. data/vendor/assets/javascripts/materialize/velocity.min.js +5 -0
  67. data/vendor/assets/javascripts/materialize/waves.js +338 -0
  68. data/vendor/assets/stylesheets/components/_buttons.scss +181 -0
  69. data/vendor/assets/stylesheets/components/_cards.scss +134 -0
  70. data/vendor/assets/stylesheets/components/_carousel.scss +34 -0
  71. data/vendor/assets/stylesheets/components/_chips.scss +27 -0
  72. data/vendor/assets/stylesheets/components/_collapsible.scss +85 -0
  73. data/vendor/assets/stylesheets/components/_color.scss +412 -0
  74. data/vendor/assets/stylesheets/components/_dropdown.scss +57 -0
  75. data/vendor/assets/stylesheets/components/_form.scss +918 -0
  76. data/vendor/assets/stylesheets/components/_global.scss +766 -0
  77. data/vendor/assets/stylesheets/components/_grid.scss +146 -0
  78. data/vendor/assets/stylesheets/components/_icons-material-design.scss +3263 -0
  79. data/vendor/assets/stylesheets/components/_materialbox.scss +42 -0
  80. data/vendor/assets/stylesheets/components/_mixins.scss +5 -0
  81. data/vendor/assets/stylesheets/components/_modal.scss +90 -0
  82. data/vendor/assets/stylesheets/components/_navbar.scss +171 -0
  83. data/vendor/assets/stylesheets/components/_normalize.scss +427 -0
  84. data/vendor/assets/stylesheets/components/_prefixer.scss +384 -0
  85. data/vendor/assets/stylesheets/components/_preloader.scss +334 -0
  86. data/vendor/assets/stylesheets/components/_roboto.scss +49 -0
  87. data/vendor/assets/stylesheets/components/_sideNav.scss +112 -0
  88. data/vendor/assets/stylesheets/components/_slider.scss +92 -0
  89. data/vendor/assets/stylesheets/components/_table_of_contents.scss +33 -0
  90. data/vendor/assets/stylesheets/components/_tabs.scss +56 -0
  91. data/vendor/assets/stylesheets/components/_toast.scss +65 -0
  92. data/vendor/assets/stylesheets/components/_tooltip.scss +33 -0
  93. data/vendor/assets/stylesheets/components/_typography.scss +61 -0
  94. data/vendor/assets/stylesheets/components/_variables.scss +161 -0
  95. data/vendor/assets/stylesheets/components/_waves.scss +173 -0
  96. data/vendor/assets/stylesheets/components/date_picker/_default.date.scss +435 -0
  97. data/vendor/assets/stylesheets/components/date_picker/_default.scss +201 -0
  98. data/vendor/assets/stylesheets/components/date_picker/_default.time.scss +125 -0
  99. data/vendor/assets/stylesheets/materialize.scss +40 -0
  100. metadata +199 -0
@@ -0,0 +1,269 @@
1
+ (function ($) {
2
+
3
+ $.fn.materialbox = function () {
4
+
5
+ return this.each(function() {
6
+
7
+ if ($(this).hasClass('initialized')) {
8
+ return;
9
+ }
10
+
11
+ $(this).addClass('initialized');
12
+
13
+ var overlayActive = false;
14
+ var doneAnimating = true;
15
+ var inDuration = 275;
16
+ var outDuration = 200;
17
+ var origin = $(this);
18
+ var placeholder = $('<div></div>').addClass('material-placeholder');
19
+ var originalWidth = 0;
20
+ var originalHeight = 0;
21
+ var ancestorsChanged;
22
+ var ancestor;
23
+ origin.wrap(placeholder);
24
+
25
+
26
+ origin.on('click', function(){
27
+ var placeholder = origin.parent('.material-placeholder');
28
+ var windowWidth = window.innerWidth;
29
+ var windowHeight = window.innerHeight;
30
+ var originalWidth = origin.width();
31
+ var originalHeight = origin.height();
32
+
33
+
34
+ // If already modal, return to original
35
+ if (doneAnimating === false) {
36
+ returnToOriginal();
37
+ return false;
38
+ }
39
+ else if (overlayActive && doneAnimating===true) {
40
+ returnToOriginal();
41
+ return false;
42
+ }
43
+
44
+
45
+ // Set states
46
+ doneAnimating = false;
47
+ origin.addClass('active');
48
+ overlayActive = true;
49
+
50
+ // Set positioning for placeholder
51
+ placeholder.css({
52
+ width: placeholder[0].getBoundingClientRect().width,
53
+ height: placeholder[0].getBoundingClientRect().height,
54
+ position: 'relative',
55
+ top: 0,
56
+ left: 0
57
+ });
58
+
59
+ // Find ancestor with overflow: hidden; and remove it
60
+ ancestorsChanged = undefined;
61
+ ancestor = placeholder[0].parentNode;
62
+ var count = 0;
63
+ while (ancestor !== null && !$(ancestor).is(document)) {
64
+ var curr = $(ancestor);
65
+ if (curr.css('overflow') === 'hidden') {
66
+ curr.css('overflow', 'visible');
67
+ if (ancestorsChanged === undefined) {
68
+ ancestorsChanged = curr;
69
+ }
70
+ else {
71
+ ancestorsChanged = ancestorsChanged.add(curr);
72
+ }
73
+ }
74
+ ancestor = ancestor.parentNode;
75
+ }
76
+
77
+ // Set css on origin
78
+ origin.css({position: 'absolute', 'z-index': 1000})
79
+ .data('width', originalWidth)
80
+ .data('height', originalHeight);
81
+
82
+ // Add overlay
83
+ var overlay = $('<div id="materialbox-overlay"></div>')
84
+ .css({
85
+ opacity: 0
86
+ })
87
+ .click(function(){
88
+ if (doneAnimating === true)
89
+ returnToOriginal();
90
+ });
91
+ // Animate Overlay
92
+ $('body').append(overlay);
93
+ overlay.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'}
94
+ );
95
+
96
+
97
+ // Add and animate caption if it exists
98
+ if (origin.data('caption') !== "") {
99
+ var $photo_caption = $('<div class="materialbox-caption"></div>');
100
+ $photo_caption.text(origin.data('caption'));
101
+ $('body').append($photo_caption);
102
+ $photo_caption.css({ "display": "inline" });
103
+ $photo_caption.velocity({opacity: 1}, {duration: inDuration, queue: false, easing: 'easeOutQuad'});
104
+ }
105
+
106
+
107
+
108
+ // Resize Image
109
+ var ratio = 0;
110
+ var widthPercent = originalWidth / windowWidth;
111
+ var heightPercent = originalHeight / windowHeight;
112
+ var newWidth = 0;
113
+ var newHeight = 0;
114
+
115
+ if (widthPercent > heightPercent) {
116
+ ratio = originalHeight / originalWidth;
117
+ newWidth = windowWidth * 0.9;
118
+ newHeight = windowWidth * 0.9 * ratio;
119
+ }
120
+ else {
121
+ ratio = originalWidth / originalHeight;
122
+ newWidth = (windowHeight * 0.9) * ratio;
123
+ newHeight = windowHeight * 0.9;
124
+ }
125
+
126
+ // Animate image + set z-index
127
+ if(origin.hasClass('responsive-img')) {
128
+ origin.velocity({'max-width': newWidth, 'width': originalWidth}, {duration: 0, queue: false,
129
+ complete: function(){
130
+ origin.css({left: 0, top: 0})
131
+ .velocity(
132
+ {
133
+ height: newHeight,
134
+ width: newWidth,
135
+ left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2,
136
+ top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2
137
+ },
138
+ {
139
+ duration: inDuration,
140
+ queue: false,
141
+ easing: 'easeOutQuad',
142
+ complete: function(){doneAnimating = true;}
143
+ }
144
+ );
145
+ } // End Complete
146
+ }); // End Velocity
147
+ }
148
+ else {
149
+ origin.css('left', 0)
150
+ .css('top', 0)
151
+ .velocity(
152
+ {
153
+ height: newHeight,
154
+ width: newWidth,
155
+ left: $(document).scrollLeft() + windowWidth/2 - origin.parent('.material-placeholder').offset().left - newWidth/2,
156
+ top: $(document).scrollTop() + windowHeight/2 - origin.parent('.material-placeholder').offset().top - newHeight/ 2
157
+ },
158
+ {
159
+ duration: inDuration,
160
+ queue: false,
161
+ easing: 'easeOutQuad',
162
+ complete: function(){doneAnimating = true;}
163
+ }
164
+ ); // End Velocity
165
+ }
166
+
167
+ }); // End origin on click
168
+
169
+
170
+ // Return on scroll
171
+ $(window).scroll(function() {
172
+ if (overlayActive ) {
173
+ returnToOriginal();
174
+ }
175
+ });
176
+
177
+ // Return on ESC
178
+ $(document).keyup(function(e) {
179
+
180
+ if (e.keyCode === 27 && doneAnimating === true) { // ESC key
181
+ if (overlayActive) {
182
+ returnToOriginal();
183
+ }
184
+ }
185
+ });
186
+
187
+
188
+ // This function returns the modaled image to the original spot
189
+ function returnToOriginal() {
190
+
191
+ doneAnimating = false;
192
+
193
+ var placeholder = origin.parent('.material-placeholder');
194
+ var windowWidth = window.innerWidth;
195
+ var windowHeight = window.innerHeight;
196
+ var originalWidth = origin.data('width');
197
+ var originalHeight = origin.data('height');
198
+
199
+ origin.velocity("stop", true);
200
+ $('#materialbox-overlay').velocity("stop", true);
201
+ $('.materialbox-caption').velocity("stop", true);
202
+
203
+
204
+ $('#materialbox-overlay').velocity({opacity: 0}, {
205
+ duration: outDuration, // Delay prevents animation overlapping
206
+ queue: false, easing: 'easeOutQuad',
207
+ complete: function(){
208
+ // Remove Overlay
209
+ overlayActive = false;
210
+ $(this).remove();
211
+ }
212
+ });
213
+
214
+ // Resize Image
215
+ origin.velocity(
216
+ {
217
+ width: originalWidth,
218
+ height: originalHeight,
219
+ left: 0,
220
+ top: 0
221
+ },
222
+ {
223
+ duration: outDuration,
224
+ queue: false, easing: 'easeOutQuad'
225
+ }
226
+ );
227
+
228
+ // Remove Caption + reset css settings on image
229
+ $('.materialbox-caption').velocity({opacity: 0}, {
230
+ duration: outDuration, // Delay prevents animation overlapping
231
+ queue: false, easing: 'easeOutQuad',
232
+ complete: function(){
233
+ placeholder.css({
234
+ height: '',
235
+ width: '',
236
+ position: '',
237
+ top: '',
238
+ left: ''
239
+ });
240
+
241
+ origin.css({
242
+ height: '',
243
+ top: '',
244
+ left: '',
245
+ width: '',
246
+ 'max-width': '',
247
+ position: '',
248
+ 'z-index': ''
249
+ });
250
+
251
+ // Remove class
252
+ origin.removeClass('active');
253
+ doneAnimating = true;
254
+ $(this).remove();
255
+
256
+ // Remove overflow overrides on ancestors
257
+ ancestorsChanged.css('overflow', '');
258
+ }
259
+ });
260
+
261
+ }
262
+ });
263
+ };
264
+
265
+ $(document).ready(function(){
266
+ $('.materialboxed').materialbox();
267
+ });
268
+
269
+ }( jQuery ));
@@ -0,0 +1,58 @@
1
+ (function ($) {
2
+
3
+ $.fn.parallax = function () {
4
+ var window_width = $(window).width();
5
+ // Parallax Scripts
6
+ return this.each(function(i) {
7
+ var $this = $(this);
8
+ $this.addClass('parallax');
9
+
10
+ function updateParallax(initial) {
11
+ var container_height;
12
+ if (window_width < 601) {
13
+ container_height = ($this.height() > 0) ? $this.height() : $this.children("img").height();
14
+ }
15
+ else {
16
+ container_height = ($this.height() > 0) ? $this.height() : 500;
17
+ }
18
+ var $img = $this.children("img").first();
19
+ var img_height = $img.height();
20
+ var parallax_dist = img_height - container_height;
21
+ var bottom = $this.offset().top + container_height;
22
+ var top = $this.offset().top;
23
+ var scrollTop = $(window).scrollTop();
24
+ var windowHeight = window.innerHeight;
25
+ var windowBottom = scrollTop + windowHeight;
26
+ var percentScrolled = (windowBottom - top) / (container_height + windowHeight);
27
+ var parallax = Math.round((parallax_dist * percentScrolled));
28
+
29
+ if (initial) {
30
+ $img.css('display', 'block');
31
+ }
32
+ if ((bottom > scrollTop) && (top < (scrollTop + windowHeight))) {
33
+ $img.css('transform', "translate3D(-50%," + parallax + "px, 0)");
34
+ }
35
+
36
+ }
37
+
38
+ // Wait for image load
39
+ $this.children("img").one("load", function() {
40
+ updateParallax(true);
41
+ }).each(function() {
42
+ if(this.complete) $(this).load();
43
+ });
44
+
45
+ $(window).scroll(function() {
46
+ window_width = $(window).width();
47
+ updateParallax(false);
48
+ });
49
+
50
+ $(window).resize(function() {
51
+ window_width = $(window).width();
52
+ updateParallax(false);
53
+ });
54
+
55
+ });
56
+
57
+ };
58
+ }( jQuery ));
@@ -0,0 +1,62 @@
1
+ (function ($) {
2
+ $(document).ready(function() {
3
+
4
+ $.fn.pushpin = function (options) {
5
+
6
+ var defaults = {
7
+ top: 0,
8
+ bottom: Infinity,
9
+ offset: 0
10
+ }
11
+ options = $.extend(defaults, options);
12
+
13
+ $index = 0;
14
+ return this.each(function() {
15
+ var $uniqueId = Materialize.guid(),
16
+ $this = $(this),
17
+ $original_offset = $(this).offset().top;
18
+
19
+ function removePinClasses(object) {
20
+ object.removeClass('pin-top');
21
+ object.removeClass('pinned');
22
+ object.removeClass('pin-bottom');
23
+ }
24
+
25
+ function updateElements(objects, scrolled) {
26
+ objects.each(function () {
27
+ // Add position fixed (because its between top and bottom)
28
+ if (options.top <= scrolled && options.bottom >= scrolled && !$(this).hasClass('pinned')) {
29
+ removePinClasses($(this));
30
+ $(this).css('top', options.offset);
31
+ $(this).addClass('pinned');
32
+ }
33
+
34
+ // Add pin-top (when scrolled position is above top)
35
+ if (scrolled < options.top && !$(this).hasClass('pin-top')) {
36
+ removePinClasses($(this));
37
+ $(this).css('top', 0);
38
+ $(this).addClass('pin-top');
39
+ }
40
+
41
+ // Add pin-bottom (when scrolled position is below bottom)
42
+ if (scrolled > options.bottom && !$(this).hasClass('pin-bottom')) {
43
+ removePinClasses($(this));
44
+ $(this).addClass('pin-bottom');
45
+ $(this).css('top', options.bottom - $original_offset);
46
+ }
47
+ });
48
+ }
49
+
50
+ updateElements($this, $(window).scrollTop());
51
+ $(window).on('scroll.' + $uniqueId, function () {
52
+ var $scrolled = $(window).scrollTop() + options.offset;
53
+ updateElements($this, $scrolled);
54
+ });
55
+
56
+ });
57
+
58
+ };
59
+
60
+
61
+ });
62
+ }( jQuery ));
@@ -0,0 +1,44 @@
1
+ (function($) {
2
+
3
+ // Input: Array of JSON objects {selector, offset, callback}
4
+
5
+ Materialize.scrollFire = function(options) {
6
+
7
+ var didScroll = false;
8
+
9
+ window.addEventListener("scroll", function() {
10
+ didScroll = true;
11
+ });
12
+
13
+ // Rate limit to 100ms
14
+ setInterval(function() {
15
+ if(didScroll) {
16
+ didScroll = false;
17
+
18
+ var windowScroll = window.pageYOffset + window.innerHeight;
19
+
20
+ for (var i = 0 ; i < options.length; i++) {
21
+ // Get options from each line
22
+ var value = options[i];
23
+ var selector = value.selector,
24
+ offset = value.offset,
25
+ callback = value.callback;
26
+
27
+ var currentElement = document.querySelector(selector);
28
+ if ( currentElement !== null) {
29
+ var elementOffset = currentElement.getBoundingClientRect().top + window.pageYOffset;
30
+
31
+ if (windowScroll > (elementOffset + offset)) {
32
+ if (value.done !== true) {
33
+ var callbackFunc = new Function(callback);
34
+ callbackFunc();
35
+ value.done = true;
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }, 100);
42
+ };
43
+
44
+ })(jQuery);
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Extend jquery with a scrollspy plugin.
3
+ * This watches the window scroll and fires events when elements are scrolled into viewport.
4
+ *
5
+ * throttle() and getTime() taken from Underscore.js
6
+ * https://github.com/jashkenas/underscore
7
+ *
8
+ * @author Copyright 2013 John Smart
9
+ * @license https://raw.github.com/thesmart/jquery-scrollspy/master/LICENSE
10
+ * @see https://github.com/thesmart
11
+ * @version 0.1.2
12
+ */
13
+ (function($) {
14
+
15
+ var jWindow = $(window);
16
+ var elements = [];
17
+ var elementsInView = [];
18
+ var isSpying = false;
19
+ var ticks = 0;
20
+ var unique_id = 1;
21
+ var offset = {
22
+ top : 0,
23
+ right : 0,
24
+ bottom : 0,
25
+ left : 0,
26
+ }
27
+
28
+ /**
29
+ * Find elements that are within the boundary
30
+ * @param {number} top
31
+ * @param {number} right
32
+ * @param {number} bottom
33
+ * @param {number} left
34
+ * @return {jQuery} A collection of elements
35
+ */
36
+ function findElements(top, right, bottom, left) {
37
+ var hits = $();
38
+ $.each(elements, function(i, element) {
39
+ if (element.height() > 0) {
40
+ var elTop = element.offset().top,
41
+ elLeft = element.offset().left,
42
+ elRight = elLeft + element.width(),
43
+ elBottom = elTop + element.height();
44
+
45
+ var isIntersect = !(elLeft > right ||
46
+ elRight < left ||
47
+ elTop > bottom ||
48
+ elBottom < top);
49
+
50
+ if (isIntersect) {
51
+ hits.push(element);
52
+ }
53
+ }
54
+ });
55
+
56
+ return hits;
57
+ }
58
+
59
+
60
+ /**
61
+ * Called when the user scrolls the window
62
+ */
63
+ function onScroll() {
64
+ // unique tick id
65
+ ++ticks;
66
+
67
+ // viewport rectangle
68
+ var top = jWindow.scrollTop(),
69
+ left = jWindow.scrollLeft(),
70
+ right = left + jWindow.width(),
71
+ bottom = top + jWindow.height();
72
+
73
+ // determine which elements are in view
74
+ // + 60 accounts for fixed nav
75
+ var intersections = findElements(top+offset.top + 200, right+offset.right, bottom+offset.bottom, left+offset.left);
76
+ $.each(intersections, function(i, element) {
77
+
78
+ var lastTick = element.data('scrollSpy:ticks');
79
+ if (typeof lastTick != 'number') {
80
+ // entered into view
81
+ element.triggerHandler('scrollSpy:enter');
82
+ }
83
+
84
+ // update tick id
85
+ element.data('scrollSpy:ticks', ticks);
86
+ });
87
+
88
+ // determine which elements are no longer in view
89
+ $.each(elementsInView, function(i, element) {
90
+ var lastTick = element.data('scrollSpy:ticks');
91
+ if (typeof lastTick == 'number' && lastTick !== ticks) {
92
+ // exited from view
93
+ element.triggerHandler('scrollSpy:exit');
94
+ element.data('scrollSpy:ticks', null);
95
+ }
96
+ });
97
+
98
+ // remember elements in view for next tick
99
+ elementsInView = intersections;
100
+ }
101
+
102
+ /**
103
+ * Called when window is resized
104
+ */
105
+ function onWinSize() {
106
+ jWindow.trigger('scrollSpy:winSize');
107
+ }
108
+
109
+ /**
110
+ * Get time in ms
111
+ * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
112
+ * @type {function}
113
+ * @return {number}
114
+ */
115
+ var getTime = (Date.now || function () {
116
+ return new Date().getTime();
117
+ });
118
+
119
+ /**
120
+ * Returns a function, that, when invoked, will only be triggered at most once
121
+ * during a given window of time. Normally, the throttled function will run
122
+ * as much as it can, without ever going more than once per `wait` duration;
123
+ * but if you'd like to disable the execution on the leading edge, pass
124
+ * `{leading: false}`. To disable execution on the trailing edge, ditto.
125
+ * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
126
+ * @param {function} func
127
+ * @param {number} wait
128
+ * @param {Object=} options
129
+ * @returns {Function}
130
+ */
131
+ function throttle(func, wait, options) {
132
+ var context, args, result;
133
+ var timeout = null;
134
+ var previous = 0;
135
+ options || (options = {});
136
+ var later = function () {
137
+ previous = options.leading === false ? 0 : getTime();
138
+ timeout = null;
139
+ result = func.apply(context, args);
140
+ context = args = null;
141
+ };
142
+ return function () {
143
+ var now = getTime();
144
+ if (!previous && options.leading === false) previous = now;
145
+ var remaining = wait - (now - previous);
146
+ context = this;
147
+ args = arguments;
148
+ if (remaining <= 0) {
149
+ clearTimeout(timeout);
150
+ timeout = null;
151
+ previous = now;
152
+ result = func.apply(context, args);
153
+ context = args = null;
154
+ } else if (!timeout && options.trailing !== false) {
155
+ timeout = setTimeout(later, remaining);
156
+ }
157
+ return result;
158
+ };
159
+ };
160
+
161
+ /**
162
+ * Enables ScrollSpy using a selector
163
+ * @param {jQuery|string} selector The elements collection, or a selector
164
+ * @param {Object=} options Optional.
165
+ throttle : number -> scrollspy throttling. Default: 100 ms
166
+ offsetTop : number -> offset from top. Default: 0
167
+ offsetRight : number -> offset from right. Default: 0
168
+ offsetBottom : number -> offset from bottom. Default: 0
169
+ offsetLeft : number -> offset from left. Default: 0
170
+ * @returns {jQuery}
171
+ */
172
+ $.scrollSpy = function(selector, options) {
173
+ var visible = [];
174
+ selector = $(selector);
175
+ selector.each(function(i, element) {
176
+ elements.push($(element));
177
+ $(element).data("scrollSpy:id", i);
178
+ // Smooth scroll to section
179
+ $('a[href="#' + $(element).attr('id') + '"]').click(function(e) {
180
+ e.preventDefault();
181
+ var scrollOffset = options.offsetScroll || 0;
182
+ var offset = $(this.hash).offset().top + 1;
183
+
184
+ // offset - 200 allows elements near bottom of page to scroll
185
+
186
+ $('html, body').animate({ scrollTop: offset - scrollOffset - 200 }, {duration: 400, queue: false, easing: 'easeOutCubic'});
187
+
188
+ });
189
+ });
190
+ options = options || {
191
+ throttle: 100
192
+ };
193
+
194
+ offset.top = options.offsetTop || 0;
195
+ offset.right = options.offsetRight || 0;
196
+ offset.bottom = options.offsetBottom || 0;
197
+ offset.left = options.offsetLeft || 0;
198
+
199
+ var throttledScroll = throttle(onScroll, options.throttle || 100);
200
+ var readyScroll = function(){
201
+ $(document).ready(throttledScroll);
202
+ };
203
+
204
+ if (!isSpying) {
205
+ jWindow.on('scroll', readyScroll);
206
+ jWindow.on('resize', readyScroll);
207
+ isSpying = true;
208
+ }
209
+
210
+ // perform a scan once, after current execution context, and after dom is ready
211
+ setTimeout(readyScroll, 0);
212
+
213
+
214
+ selector.on('scrollSpy:enter', function() {
215
+ visible = $.grep(visible, function(value) {
216
+ return value.height() != 0;
217
+ });
218
+
219
+ var $this = $(this);
220
+
221
+ if (visible[0]) {
222
+ $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active');
223
+ if ($this.data('scrollSpy:id') < visible[0].data('scrollSpy:id')) {
224
+ visible.unshift($(this));
225
+ }
226
+ else {
227
+ visible.push($(this));
228
+ }
229
+ }
230
+ else {
231
+ visible.push($(this));
232
+ }
233
+
234
+
235
+ $('a[href="#' + visible[0].attr('id') + '"]').addClass('active');
236
+ });
237
+ selector.on('scrollSpy:exit', function() {
238
+ visible = $.grep(visible, function(value) {
239
+ return value.height() != 0;
240
+ });
241
+
242
+ if (visible[0]) {
243
+ $('a[href="#' + visible[0].attr('id') + '"]').removeClass('active');
244
+ var $this = $(this);
245
+ visible = $.grep(visible, function(value) {
246
+ return value.attr('id') != $this.attr('id');
247
+ });
248
+ if (visible[0]) { // Check if empty
249
+ $('a[href="#' + visible[0].attr('id') + '"]').addClass('active');
250
+ }
251
+ }
252
+ });
253
+
254
+ return selector;
255
+ };
256
+
257
+ /**
258
+ * Listen for window resize events
259
+ * @param {Object=} options Optional. Set { throttle: number } to change throttling. Default: 100 ms
260
+ * @returns {jQuery} $(window)
261
+ */
262
+ $.winSizeSpy = function(options) {
263
+ $.winSizeSpy = function() { return jWindow; }; // lock from multiple calls
264
+ options = options || {
265
+ throttle: 100
266
+ };
267
+ return jWindow.on('resize', throttle(onWinSize, options.throttle || 100));
268
+ };
269
+
270
+ /**
271
+ * Enables ScrollSpy on a collection of elements
272
+ * e.g. $('.scrollSpy').scrollSpy()
273
+ * @param {Object=} options Optional.
274
+ throttle : number -> scrollspy throttling. Default: 100 ms
275
+ offsetTop : number -> offset from top. Default: 0
276
+ offsetRight : number -> offset from right. Default: 0
277
+ offsetBottom : number -> offset from bottom. Default: 0
278
+ offsetLeft : number -> offset from left. Default: 0
279
+ * @returns {jQuery}
280
+ */
281
+ $.fn.scrollSpy = function(options) {
282
+ return $.scrollSpy($(this), options);
283
+ };
284
+
285
+ })(jQuery);