administrate-materialize-theme 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +49 -0
  4. data/Rakefile +1 -0
  5. data/app/assets/javascripts/administrate-materialize-theme/anime.min.js +34 -0
  6. data/app/assets/javascripts/administrate-materialize-theme/autocomplete.js +450 -0
  7. data/app/assets/javascripts/administrate-materialize-theme/bin/materialize.js +12374 -0
  8. data/app/assets/javascripts/administrate-materialize-theme/bin/materialize.min.js +6 -0
  9. data/app/assets/javascripts/administrate-materialize-theme/buttons.js +354 -0
  10. data/app/assets/javascripts/administrate-materialize-theme/cards.js +40 -0
  11. data/app/assets/javascripts/administrate-materialize-theme/carousel.js +717 -0
  12. data/app/assets/javascripts/administrate-materialize-theme/cash.js +960 -0
  13. data/app/assets/javascripts/administrate-materialize-theme/characterCounter.js +136 -0
  14. data/app/assets/javascripts/administrate-materialize-theme/chips.js +481 -0
  15. data/app/assets/javascripts/administrate-materialize-theme/collapsible.js +275 -0
  16. data/app/assets/javascripts/administrate-materialize-theme/component.js +44 -0
  17. data/app/assets/javascripts/administrate-materialize-theme/datepicker.js +975 -0
  18. data/app/assets/javascripts/administrate-materialize-theme/dropdown.js +617 -0
  19. data/app/assets/javascripts/administrate-materialize-theme/forms.js +275 -0
  20. data/app/assets/javascripts/administrate-materialize-theme/global.js +427 -0
  21. data/app/assets/javascripts/administrate-materialize-theme/materialbox.js +453 -0
  22. data/app/assets/javascripts/administrate-materialize-theme/modal.js +382 -0
  23. data/app/assets/javascripts/administrate-materialize-theme/parallax.js +138 -0
  24. data/app/assets/javascripts/administrate-materialize-theme/pushpin.js +145 -0
  25. data/app/assets/javascripts/administrate-materialize-theme/range.js +263 -0
  26. data/app/assets/javascripts/administrate-materialize-theme/scrollspy.js +295 -0
  27. data/app/assets/javascripts/administrate-materialize-theme/select.js +432 -0
  28. data/app/assets/javascripts/administrate-materialize-theme/sidenav.js +580 -0
  29. data/app/assets/javascripts/administrate-materialize-theme/slider.js +359 -0
  30. data/app/assets/javascripts/administrate-materialize-theme/tabs.js +402 -0
  31. data/app/assets/javascripts/administrate-materialize-theme/tapTarget.js +314 -0
  32. data/app/assets/javascripts/administrate-materialize-theme/theme.js +6 -0
  33. data/app/assets/javascripts/administrate-materialize-theme/timepicker.js +647 -0
  34. data/app/assets/javascripts/administrate-materialize-theme/toasts.js +310 -0
  35. data/app/assets/javascripts/administrate-materialize-theme/tooltip.js +303 -0
  36. data/app/assets/javascripts/administrate-materialize-theme/waves.js +335 -0
  37. data/app/assets/stylesheets/administrate-materialize-theme/components/_badges.scss +55 -0
  38. data/app/assets/stylesheets/administrate-materialize-theme/components/_buttons.scss +322 -0
  39. data/app/assets/stylesheets/administrate-materialize-theme/components/_cards.scss +195 -0
  40. data/app/assets/stylesheets/administrate-materialize-theme/components/_carousel.scss +90 -0
  41. data/app/assets/stylesheets/administrate-materialize-theme/components/_chips.scss +90 -0
  42. data/app/assets/stylesheets/administrate-materialize-theme/components/_collapsible.scss +91 -0
  43. data/app/assets/stylesheets/administrate-materialize-theme/components/_color-classes.scss +32 -0
  44. data/app/assets/stylesheets/administrate-materialize-theme/components/_color-variables.scss +370 -0
  45. data/app/assets/stylesheets/administrate-materialize-theme/components/_datepicker.scss +191 -0
  46. data/app/assets/stylesheets/administrate-materialize-theme/components/_dropdown.scss +85 -0
  47. data/app/assets/stylesheets/administrate-materialize-theme/components/_global.scss +769 -0
  48. data/app/assets/stylesheets/administrate-materialize-theme/components/_grid.scss +156 -0
  49. data/app/assets/stylesheets/administrate-materialize-theme/components/_icons-material-design.scss +5 -0
  50. data/app/assets/stylesheets/administrate-materialize-theme/components/_materialbox.scss +43 -0
  51. data/app/assets/stylesheets/administrate-materialize-theme/components/_modal.scss +94 -0
  52. data/app/assets/stylesheets/administrate-materialize-theme/components/_navbar.scss +208 -0
  53. data/app/assets/stylesheets/administrate-materialize-theme/components/_normalize.scss +447 -0
  54. data/app/assets/stylesheets/administrate-materialize-theme/components/_preloader.scss +334 -0
  55. data/app/assets/stylesheets/administrate-materialize-theme/components/_pulse.scss +34 -0
  56. data/app/assets/stylesheets/administrate-materialize-theme/components/_sidenav.scss +216 -0
  57. data/app/assets/stylesheets/administrate-materialize-theme/components/_slider.scss +92 -0
  58. data/app/assets/stylesheets/administrate-materialize-theme/components/_table_of_contents.scss +33 -0
  59. data/app/assets/stylesheets/administrate-materialize-theme/components/_tabs.scss +99 -0
  60. data/app/assets/stylesheets/administrate-materialize-theme/components/_tapTarget.scss +103 -0
  61. data/app/assets/stylesheets/administrate-materialize-theme/components/_timepicker.scss +183 -0
  62. data/app/assets/stylesheets/administrate-materialize-theme/components/_toast.scss +58 -0
  63. data/app/assets/stylesheets/administrate-materialize-theme/components/_tooltip.scss +32 -0
  64. data/app/assets/stylesheets/administrate-materialize-theme/components/_transitions.scss +13 -0
  65. data/app/assets/stylesheets/administrate-materialize-theme/components/_typography.scss +60 -0
  66. data/app/assets/stylesheets/administrate-materialize-theme/components/_variables.scss +349 -0
  67. data/app/assets/stylesheets/administrate-materialize-theme/components/_waves.scss +114 -0
  68. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_checkboxes.scss +200 -0
  69. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_file-input.scss +44 -0
  70. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_forms.scss +22 -0
  71. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_input-fields.scss +354 -0
  72. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_radio-buttons.scss +115 -0
  73. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_range.scss +161 -0
  74. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_select.scss +180 -0
  75. data/app/assets/stylesheets/administrate-materialize-theme/components/forms/_switches.scss +89 -0
  76. data/app/assets/stylesheets/administrate-materialize-theme/materialize.scss +41 -0
  77. data/app/assets/stylesheets/administrate-materialize-theme/theme.scss +200 -0
  78. data/lib/administrate-materialize-theme.rb +6 -0
  79. data/lib/administrate-materialize-theme/engine.rb +7 -0
  80. data/lib/administrate-materialize-theme/version.rb +5 -0
  81. metadata +150 -0
@@ -0,0 +1,145 @@
1
+ (function($) {
2
+ 'use strict';
3
+
4
+ let _defaults = {
5
+ top: 0,
6
+ bottom: Infinity,
7
+ offset: 0,
8
+ onPositionChange: null
9
+ };
10
+
11
+ /**
12
+ * @class
13
+ *
14
+ */
15
+ class Pushpin extends Component {
16
+ /**
17
+ * Construct Pushpin instance
18
+ * @constructor
19
+ * @param {Element} el
20
+ * @param {Object} options
21
+ */
22
+ constructor(el, options) {
23
+ super(Pushpin, el, options);
24
+
25
+ this.el.M_Pushpin = this;
26
+
27
+ /**
28
+ * Options for the modal
29
+ * @member Pushpin#options
30
+ */
31
+ this.options = $.extend({}, Pushpin.defaults, options);
32
+
33
+ this.originalOffset = this.el.offsetTop;
34
+ Pushpin._pushpins.push(this);
35
+ this._setupEventHandlers();
36
+ this._updatePosition();
37
+ }
38
+
39
+ static get defaults() {
40
+ return _defaults;
41
+ }
42
+
43
+ static init(els, options) {
44
+ return super.init(this, els, options);
45
+ }
46
+
47
+ /**
48
+ * Get Instance
49
+ */
50
+ static getInstance(el) {
51
+ let domElem = !!el.jquery ? el[0] : el;
52
+ return domElem.M_Pushpin;
53
+ }
54
+
55
+ /**
56
+ * Teardown component
57
+ */
58
+ destroy() {
59
+ this.el.style.top = null;
60
+ this._removePinClasses();
61
+ this._removeEventHandlers();
62
+
63
+ // Remove pushpin Inst
64
+ let index = Pushpin._pushpins.indexOf(this);
65
+ Pushpin._pushpins.splice(index, 1);
66
+ }
67
+
68
+ static _updateElements() {
69
+ for (let elIndex in Pushpin._pushpins) {
70
+ let pInstance = Pushpin._pushpins[elIndex];
71
+ pInstance._updatePosition();
72
+ }
73
+ }
74
+
75
+ _setupEventHandlers() {
76
+ document.addEventListener('scroll', Pushpin._updateElements);
77
+ }
78
+
79
+ _removeEventHandlers() {
80
+ document.removeEventListener('scroll', Pushpin._updateElements);
81
+ }
82
+
83
+ _updatePosition() {
84
+ let scrolled = M.getDocumentScrollTop() + this.options.offset;
85
+
86
+ if (
87
+ this.options.top <= scrolled &&
88
+ this.options.bottom >= scrolled &&
89
+ !this.el.classList.contains('pinned')
90
+ ) {
91
+ this._removePinClasses();
92
+ this.el.style.top = `${this.options.offset}px`;
93
+ this.el.classList.add('pinned');
94
+
95
+ // onPositionChange callback
96
+ if (typeof this.options.onPositionChange === 'function') {
97
+ this.options.onPositionChange.call(this, 'pinned');
98
+ }
99
+ }
100
+
101
+ // Add pin-top (when scrolled position is above top)
102
+ if (scrolled < this.options.top && !this.el.classList.contains('pin-top')) {
103
+ this._removePinClasses();
104
+ this.el.style.top = 0;
105
+ this.el.classList.add('pin-top');
106
+
107
+ // onPositionChange callback
108
+ if (typeof this.options.onPositionChange === 'function') {
109
+ this.options.onPositionChange.call(this, 'pin-top');
110
+ }
111
+ }
112
+
113
+ // Add pin-bottom (when scrolled position is below bottom)
114
+ if (scrolled > this.options.bottom && !this.el.classList.contains('pin-bottom')) {
115
+ this._removePinClasses();
116
+ this.el.classList.add('pin-bottom');
117
+ this.el.style.top = `${this.options.bottom - this.originalOffset}px`;
118
+
119
+ // onPositionChange callback
120
+ if (typeof this.options.onPositionChange === 'function') {
121
+ this.options.onPositionChange.call(this, 'pin-bottom');
122
+ }
123
+ }
124
+ }
125
+
126
+ _removePinClasses() {
127
+ // IE 11 bug (can't remove multiple classes in one line)
128
+ this.el.classList.remove('pin-top');
129
+ this.el.classList.remove('pinned');
130
+ this.el.classList.remove('pin-bottom');
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @static
136
+ * @memberof Pushpin
137
+ */
138
+ Pushpin._pushpins = [];
139
+
140
+ M.Pushpin = Pushpin;
141
+
142
+ if (M.jQueryLoaded) {
143
+ M.initializeJqueryWrapper(Pushpin, 'pushpin', 'M_Pushpin');
144
+ }
145
+ })(cash);
@@ -0,0 +1,263 @@
1
+ (function($, anim) {
2
+ 'use strict';
3
+
4
+ let _defaults = {};
5
+
6
+ /**
7
+ * @class
8
+ *
9
+ */
10
+ class Range extends Component {
11
+ /**
12
+ * Construct Range instance
13
+ * @constructor
14
+ * @param {Element} el
15
+ * @param {Object} options
16
+ */
17
+ constructor(el, options) {
18
+ super(Range, el, options);
19
+
20
+ this.el.M_Range = this;
21
+
22
+ /**
23
+ * Options for the range
24
+ * @member Range#options
25
+ */
26
+ this.options = $.extend({}, Range.defaults, options);
27
+
28
+ this._mousedown = false;
29
+
30
+ // Setup
31
+ this._setupThumb();
32
+
33
+ this._setupEventHandlers();
34
+ }
35
+
36
+ static get defaults() {
37
+ return _defaults;
38
+ }
39
+
40
+ static init(els, options) {
41
+ return super.init(this, els, options);
42
+ }
43
+
44
+ /**
45
+ * Get Instance
46
+ */
47
+ static getInstance(el) {
48
+ let domElem = !!el.jquery ? el[0] : el;
49
+ return domElem.M_Range;
50
+ }
51
+
52
+ /**
53
+ * Teardown component
54
+ */
55
+ destroy() {
56
+ this._removeEventHandlers();
57
+ this._removeThumb();
58
+ this.el.M_Range = undefined;
59
+ }
60
+
61
+ /**
62
+ * Setup Event Handlers
63
+ */
64
+ _setupEventHandlers() {
65
+ this._handleRangeChangeBound = this._handleRangeChange.bind(this);
66
+ this._handleRangeMousedownTouchstartBound = this._handleRangeMousedownTouchstart.bind(this);
67
+ this._handleRangeInputMousemoveTouchmoveBound = this._handleRangeInputMousemoveTouchmove.bind(
68
+ this
69
+ );
70
+ this._handleRangeMouseupTouchendBound = this._handleRangeMouseupTouchend.bind(this);
71
+ this._handleRangeBlurMouseoutTouchleaveBound = this._handleRangeBlurMouseoutTouchleave.bind(
72
+ this
73
+ );
74
+
75
+ this.el.addEventListener('change', this._handleRangeChangeBound);
76
+
77
+ this.el.addEventListener('mousedown', this._handleRangeMousedownTouchstartBound);
78
+ this.el.addEventListener('touchstart', this._handleRangeMousedownTouchstartBound);
79
+
80
+ this.el.addEventListener('input', this._handleRangeInputMousemoveTouchmoveBound);
81
+ this.el.addEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound);
82
+ this.el.addEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound);
83
+
84
+ this.el.addEventListener('mouseup', this._handleRangeMouseupTouchendBound);
85
+ this.el.addEventListener('touchend', this._handleRangeMouseupTouchendBound);
86
+
87
+ this.el.addEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound);
88
+ this.el.addEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound);
89
+ this.el.addEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound);
90
+ }
91
+
92
+ /**
93
+ * Remove Event Handlers
94
+ */
95
+ _removeEventHandlers() {
96
+ this.el.removeEventListener('change', this._handleRangeChangeBound);
97
+
98
+ this.el.removeEventListener('mousedown', this._handleRangeMousedownTouchstartBound);
99
+ this.el.removeEventListener('touchstart', this._handleRangeMousedownTouchstartBound);
100
+
101
+ this.el.removeEventListener('input', this._handleRangeInputMousemoveTouchmoveBound);
102
+ this.el.removeEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound);
103
+ this.el.removeEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound);
104
+
105
+ this.el.removeEventListener('mouseup', this._handleRangeMouseupTouchendBound);
106
+ this.el.removeEventListener('touchend', this._handleRangeMouseupTouchendBound);
107
+
108
+ this.el.removeEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound);
109
+ this.el.removeEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound);
110
+ this.el.removeEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound);
111
+ }
112
+
113
+ /**
114
+ * Handle Range Change
115
+ * @param {Event} e
116
+ */
117
+ _handleRangeChange() {
118
+ $(this.value).html(this.$el.val());
119
+
120
+ if (!$(this.thumb).hasClass('active')) {
121
+ this._showRangeBubble();
122
+ }
123
+
124
+ let offsetLeft = this._calcRangeOffset();
125
+ $(this.thumb)
126
+ .addClass('active')
127
+ .css('left', offsetLeft + 'px');
128
+ }
129
+
130
+ /**
131
+ * Handle Range Mousedown and Touchstart
132
+ * @param {Event} e
133
+ */
134
+ _handleRangeMousedownTouchstart(e) {
135
+ // Set indicator value
136
+ $(this.value).html(this.$el.val());
137
+
138
+ this._mousedown = true;
139
+ this.$el.addClass('active');
140
+
141
+ if (!$(this.thumb).hasClass('active')) {
142
+ this._showRangeBubble();
143
+ }
144
+
145
+ if (e.type !== 'input') {
146
+ let offsetLeft = this._calcRangeOffset();
147
+ $(this.thumb)
148
+ .addClass('active')
149
+ .css('left', offsetLeft + 'px');
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Handle Range Input, Mousemove and Touchmove
155
+ */
156
+ _handleRangeInputMousemoveTouchmove() {
157
+ if (this._mousedown) {
158
+ if (!$(this.thumb).hasClass('active')) {
159
+ this._showRangeBubble();
160
+ }
161
+
162
+ let offsetLeft = this._calcRangeOffset();
163
+ $(this.thumb)
164
+ .addClass('active')
165
+ .css('left', offsetLeft + 'px');
166
+ $(this.value).html(this.$el.val());
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Handle Range Mouseup and Touchend
172
+ */
173
+ _handleRangeMouseupTouchend() {
174
+ this._mousedown = false;
175
+ this.$el.removeClass('active');
176
+ }
177
+
178
+ /**
179
+ * Handle Range Blur, Mouseout and Touchleave
180
+ */
181
+ _handleRangeBlurMouseoutTouchleave() {
182
+ if (!this._mousedown) {
183
+ let paddingLeft = parseInt(this.$el.css('padding-left'));
184
+ let marginLeft = 7 + paddingLeft + 'px';
185
+
186
+ if ($(this.thumb).hasClass('active')) {
187
+ anim.remove(this.thumb);
188
+ anim({
189
+ targets: this.thumb,
190
+ height: 0,
191
+ width: 0,
192
+ top: 10,
193
+ easing: 'easeOutQuad',
194
+ marginLeft: marginLeft,
195
+ duration: 100
196
+ });
197
+ }
198
+ $(this.thumb).removeClass('active');
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Setup dropdown
204
+ */
205
+ _setupThumb() {
206
+ this.thumb = document.createElement('span');
207
+ this.value = document.createElement('span');
208
+ $(this.thumb).addClass('thumb');
209
+ $(this.value).addClass('value');
210
+ $(this.thumb).append(this.value);
211
+ this.$el.after(this.thumb);
212
+ }
213
+
214
+ /**
215
+ * Remove dropdown
216
+ */
217
+ _removeThumb() {
218
+ $(this.thumb).remove();
219
+ }
220
+
221
+ /**
222
+ * morph thumb into bubble
223
+ */
224
+ _showRangeBubble() {
225
+ let paddingLeft = parseInt(
226
+ $(this.thumb)
227
+ .parent()
228
+ .css('padding-left')
229
+ );
230
+ let marginLeft = -7 + paddingLeft + 'px'; // TODO: fix magic number?
231
+ anim.remove(this.thumb);
232
+ anim({
233
+ targets: this.thumb,
234
+ height: 30,
235
+ width: 30,
236
+ top: -30,
237
+ marginLeft: marginLeft,
238
+ duration: 300,
239
+ easing: 'easeOutQuint'
240
+ });
241
+ }
242
+
243
+ /**
244
+ * Calculate the offset of the thumb
245
+ * @return {Number} offset in pixels
246
+ */
247
+ _calcRangeOffset() {
248
+ let width = this.$el.width() - 15;
249
+ let max = parseFloat(this.$el.attr('max')) || 100; // Range default max
250
+ let min = parseFloat(this.$el.attr('min')) || 0; // Range default min
251
+ let percent = (parseFloat(this.$el.val()) - min) / (max - min);
252
+ return percent * width;
253
+ }
254
+ }
255
+
256
+ M.Range = Range;
257
+
258
+ if (M.jQueryLoaded) {
259
+ M.initializeJqueryWrapper(Range, 'range', 'M_Range');
260
+ }
261
+
262
+ Range.init($('input[type=range]'));
263
+ })(cash, M.anime);
@@ -0,0 +1,295 @@
1
+ (function($, anim) {
2
+ 'use strict';
3
+
4
+ let _defaults = {
5
+ throttle: 100,
6
+ scrollOffset: 200, // offset - 200 allows elements near bottom of page to scroll
7
+ activeClass: 'active',
8
+ getActiveElement: function(id) {
9
+ return 'a[href="#' + id + '"]';
10
+ }
11
+ };
12
+
13
+ /**
14
+ * @class
15
+ *
16
+ */
17
+ class ScrollSpy extends Component {
18
+ /**
19
+ * Construct ScrollSpy instance
20
+ * @constructor
21
+ * @param {Element} el
22
+ * @param {Object} options
23
+ */
24
+ constructor(el, options) {
25
+ super(ScrollSpy, el, options);
26
+
27
+ this.el.M_ScrollSpy = this;
28
+
29
+ /**
30
+ * Options for the modal
31
+ * @member Modal#options
32
+ * @prop {Number} [throttle=100] - Throttle of scroll handler
33
+ * @prop {Number} [scrollOffset=200] - Offset for centering element when scrolled to
34
+ * @prop {String} [activeClass='active'] - Class applied to active elements
35
+ * @prop {Function} [getActiveElement] - Used to find active element
36
+ */
37
+ this.options = $.extend({}, ScrollSpy.defaults, options);
38
+
39
+ // setup
40
+ ScrollSpy._elements.push(this);
41
+ ScrollSpy._count++;
42
+ ScrollSpy._increment++;
43
+ this.tickId = -1;
44
+ this.id = ScrollSpy._increment;
45
+ this._setupEventHandlers();
46
+ this._handleWindowScroll();
47
+ }
48
+
49
+ static get defaults() {
50
+ return _defaults;
51
+ }
52
+
53
+ static init(els, options) {
54
+ return super.init(this, els, options);
55
+ }
56
+
57
+ /**
58
+ * Get Instance
59
+ */
60
+ static getInstance(el) {
61
+ let domElem = !!el.jquery ? el[0] : el;
62
+ return domElem.M_ScrollSpy;
63
+ }
64
+
65
+ /**
66
+ * Teardown component
67
+ */
68
+ destroy() {
69
+ ScrollSpy._elements.splice(ScrollSpy._elements.indexOf(this), 1);
70
+ ScrollSpy._elementsInView.splice(ScrollSpy._elementsInView.indexOf(this), 1);
71
+ ScrollSpy._visibleElements.splice(ScrollSpy._visibleElements.indexOf(this.$el), 1);
72
+ ScrollSpy._count--;
73
+ this._removeEventHandlers();
74
+ $(this.options.getActiveElement(this.$el.attr('id'))).removeClass(this.options.activeClass);
75
+ this.el.M_ScrollSpy = undefined;
76
+ }
77
+
78
+ /**
79
+ * Setup Event Handlers
80
+ */
81
+ _setupEventHandlers() {
82
+ let throttledResize = M.throttle(this._handleWindowScroll, 200);
83
+ this._handleThrottledResizeBound = throttledResize.bind(this);
84
+ this._handleWindowScrollBound = this._handleWindowScroll.bind(this);
85
+ if (ScrollSpy._count === 1) {
86
+ window.addEventListener('scroll', this._handleWindowScrollBound);
87
+ window.addEventListener('resize', this._handleThrottledResizeBound);
88
+ document.body.addEventListener('click', this._handleTriggerClick);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Remove Event Handlers
94
+ */
95
+ _removeEventHandlers() {
96
+ if (ScrollSpy._count === 0) {
97
+ window.removeEventListener('scroll', this._handleWindowScrollBound);
98
+ window.removeEventListener('resize', this._handleThrottledResizeBound);
99
+ document.body.removeEventListener('click', this._handleTriggerClick);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Handle Trigger Click
105
+ * @param {Event} e
106
+ */
107
+ _handleTriggerClick(e) {
108
+ let $trigger = $(e.target);
109
+ for (let i = ScrollSpy._elements.length - 1; i >= 0; i--) {
110
+ let scrollspy = ScrollSpy._elements[i];
111
+ if ($trigger.is('a[href="#' + scrollspy.$el.attr('id') + '"]')) {
112
+ e.preventDefault();
113
+ let offset = scrollspy.$el.offset().top + 1;
114
+
115
+ anim({
116
+ targets: [document.documentElement, document.body],
117
+ scrollTop: offset - scrollspy.options.scrollOffset,
118
+ duration: 400,
119
+ easing: 'easeOutCubic'
120
+ });
121
+ break;
122
+ }
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Handle Window Scroll
128
+ */
129
+ _handleWindowScroll() {
130
+ // unique tick id
131
+ ScrollSpy._ticks++;
132
+
133
+ // viewport rectangle
134
+ let top = M.getDocumentScrollTop(),
135
+ left = M.getDocumentScrollLeft(),
136
+ right = left + window.innerWidth,
137
+ bottom = top + window.innerHeight;
138
+
139
+ // determine which elements are in view
140
+ let intersections = ScrollSpy._findElements(top, right, bottom, left);
141
+ for (let i = 0; i < intersections.length; i++) {
142
+ let scrollspy = intersections[i];
143
+ let lastTick = scrollspy.tickId;
144
+ if (lastTick < 0) {
145
+ // entered into view
146
+ scrollspy._enter();
147
+ }
148
+
149
+ // update tick id
150
+ scrollspy.tickId = ScrollSpy._ticks;
151
+ }
152
+
153
+ for (let i = 0; i < ScrollSpy._elementsInView.length; i++) {
154
+ let scrollspy = ScrollSpy._elementsInView[i];
155
+ let lastTick = scrollspy.tickId;
156
+ if (lastTick >= 0 && lastTick !== ScrollSpy._ticks) {
157
+ // exited from view
158
+ scrollspy._exit();
159
+ scrollspy.tickId = -1;
160
+ }
161
+ }
162
+
163
+ // remember elements in view for next tick
164
+ ScrollSpy._elementsInView = intersections;
165
+ }
166
+
167
+ /**
168
+ * Find elements that are within the boundary
169
+ * @param {number} top
170
+ * @param {number} right
171
+ * @param {number} bottom
172
+ * @param {number} left
173
+ * @return {Array.<ScrollSpy>} A collection of elements
174
+ */
175
+ static _findElements(top, right, bottom, left) {
176
+ let hits = [];
177
+ for (let i = 0; i < ScrollSpy._elements.length; i++) {
178
+ let scrollspy = ScrollSpy._elements[i];
179
+ let currTop = top + scrollspy.options.scrollOffset || 200;
180
+
181
+ if (scrollspy.$el.height() > 0) {
182
+ let elTop = scrollspy.$el.offset().top,
183
+ elLeft = scrollspy.$el.offset().left,
184
+ elRight = elLeft + scrollspy.$el.width(),
185
+ elBottom = elTop + scrollspy.$el.height();
186
+
187
+ let isIntersect = !(
188
+ elLeft > right ||
189
+ elRight < left ||
190
+ elTop > bottom ||
191
+ elBottom < currTop
192
+ );
193
+
194
+ if (isIntersect) {
195
+ hits.push(scrollspy);
196
+ }
197
+ }
198
+ }
199
+ return hits;
200
+ }
201
+
202
+ _enter() {
203
+ ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter(function(value) {
204
+ return value.height() != 0;
205
+ });
206
+
207
+ if (ScrollSpy._visibleElements[0]) {
208
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).removeClass(
209
+ this.options.activeClass
210
+ );
211
+ if (
212
+ ScrollSpy._visibleElements[0][0].M_ScrollSpy &&
213
+ this.id < ScrollSpy._visibleElements[0][0].M_ScrollSpy.id
214
+ ) {
215
+ ScrollSpy._visibleElements.unshift(this.$el);
216
+ } else {
217
+ ScrollSpy._visibleElements.push(this.$el);
218
+ }
219
+ } else {
220
+ ScrollSpy._visibleElements.push(this.$el);
221
+ }
222
+
223
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).addClass(
224
+ this.options.activeClass
225
+ );
226
+ }
227
+
228
+ _exit() {
229
+ ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter(function(value) {
230
+ return value.height() != 0;
231
+ });
232
+
233
+ if (ScrollSpy._visibleElements[0]) {
234
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).removeClass(
235
+ this.options.activeClass
236
+ );
237
+
238
+ ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter((el) => {
239
+ return el.attr('id') != this.$el.attr('id');
240
+ });
241
+ if (ScrollSpy._visibleElements[0]) {
242
+ // Check if empty
243
+ $(this.options.getActiveElement(ScrollSpy._visibleElements[0].attr('id'))).addClass(
244
+ this.options.activeClass
245
+ );
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ /**
252
+ * @static
253
+ * @memberof ScrollSpy
254
+ * @type {Array.<ScrollSpy>}
255
+ */
256
+ ScrollSpy._elements = [];
257
+
258
+ /**
259
+ * @static
260
+ * @memberof ScrollSpy
261
+ * @type {Array.<ScrollSpy>}
262
+ */
263
+ ScrollSpy._elementsInView = [];
264
+
265
+ /**
266
+ * @static
267
+ * @memberof ScrollSpy
268
+ * @type {Array.<cash>}
269
+ */
270
+ ScrollSpy._visibleElements = [];
271
+
272
+ /**
273
+ * @static
274
+ * @memberof ScrollSpy
275
+ */
276
+ ScrollSpy._count = 0;
277
+
278
+ /**
279
+ * @static
280
+ * @memberof ScrollSpy
281
+ */
282
+ ScrollSpy._increment = 0;
283
+
284
+ /**
285
+ * @static
286
+ * @memberof ScrollSpy
287
+ */
288
+ ScrollSpy._ticks = 0;
289
+
290
+ M.ScrollSpy = ScrollSpy;
291
+
292
+ if (M.jQueryLoaded) {
293
+ M.initializeJqueryWrapper(ScrollSpy, 'scrollSpy', 'M_ScrollSpy');
294
+ }
295
+ })(cash, M.anime);