activeadmin_materialize_theme 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +26 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/config/activeadmin_materialize_theme_manifest.js +1 -0
  6. data/app/assets/javascripts/activeadmin_materialize_theme.js +65 -0
  7. data/app/assets/javascripts/materialize/anime.min.js +34 -0
  8. data/app/assets/javascripts/materialize/autocomplete.js +450 -0
  9. data/app/assets/javascripts/materialize/bin/materialize.js +12374 -0
  10. data/app/assets/javascripts/materialize/bin/materialize.min.js +6 -0
  11. data/app/assets/javascripts/materialize/buttons.js +354 -0
  12. data/app/assets/javascripts/materialize/cards.js +40 -0
  13. data/app/assets/javascripts/materialize/carousel.js +717 -0
  14. data/app/assets/javascripts/materialize/cash.js +960 -0
  15. data/app/assets/javascripts/materialize/characterCounter.js +136 -0
  16. data/app/assets/javascripts/materialize/chips.js +481 -0
  17. data/app/assets/javascripts/materialize/collapsible.js +275 -0
  18. data/app/assets/javascripts/materialize/component.js +44 -0
  19. data/app/assets/javascripts/materialize/datepicker.js +975 -0
  20. data/app/assets/javascripts/materialize/dropdown.js +617 -0
  21. data/app/assets/javascripts/materialize/forms.js +275 -0
  22. data/app/assets/javascripts/materialize/global.js +427 -0
  23. data/app/assets/javascripts/materialize/materialbox.js +453 -0
  24. data/app/assets/javascripts/materialize/modal.js +382 -0
  25. data/app/assets/javascripts/materialize/parallax.js +138 -0
  26. data/app/assets/javascripts/materialize/pushpin.js +145 -0
  27. data/app/assets/javascripts/materialize/range.js +263 -0
  28. data/app/assets/javascripts/materialize/scrollspy.js +295 -0
  29. data/app/assets/javascripts/materialize/select.js +432 -0
  30. data/app/assets/javascripts/materialize/sidenav.js +580 -0
  31. data/app/assets/javascripts/materialize/slider.js +359 -0
  32. data/app/assets/javascripts/materialize/tabs.js +402 -0
  33. data/app/assets/javascripts/materialize/tapTarget.js +314 -0
  34. data/app/assets/javascripts/materialize/timepicker.js +647 -0
  35. data/app/assets/javascripts/materialize/toasts.js +310 -0
  36. data/app/assets/javascripts/materialize/tooltip.js +303 -0
  37. data/app/assets/javascripts/materialize/waves.js +335 -0
  38. data/app/assets/stylesheets/activeadmin_materialize_theme/base.scss +107 -0
  39. data/app/assets/stylesheets/activeadmin_materialize_theme/components/footer.scss +18 -0
  40. data/app/assets/stylesheets/activeadmin_materialize_theme/components/form.scss +140 -0
  41. data/app/assets/stylesheets/activeadmin_materialize_theme/components/header.scss +61 -0
  42. data/app/assets/stylesheets/activeadmin_materialize_theme/components/layout_index.scss +83 -0
  43. data/app/assets/stylesheets/activeadmin_materialize_theme/components/layout_show.scss +56 -0
  44. data/app/assets/stylesheets/activeadmin_materialize_theme/components/sidebar.scss +37 -0
  45. data/app/assets/stylesheets/activeadmin_materialize_theme/components/title_bar.scss +43 -0
  46. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/LICENSE +21 -0
  47. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/README.md +91 -0
  48. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_badges.scss +55 -0
  49. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_buttons.scss +322 -0
  50. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_cards.scss +195 -0
  51. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_carousel.scss +90 -0
  52. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_chips.scss +90 -0
  53. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_collapsible.scss +91 -0
  54. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_color-classes.scss +32 -0
  55. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_color-variables.scss +370 -0
  56. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_datepicker.scss +191 -0
  57. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_dropdown.scss +85 -0
  58. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_global.scss +769 -0
  59. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_grid.scss +156 -0
  60. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_icons-material-design.scss +5 -0
  61. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_materialbox.scss +43 -0
  62. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_modal.scss +94 -0
  63. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_navbar.scss +208 -0
  64. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_normalize.scss +447 -0
  65. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_preloader.scss +334 -0
  66. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_pulse.scss +34 -0
  67. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_sidenav.scss +216 -0
  68. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_slider.scss +92 -0
  69. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_table_of_contents.scss +33 -0
  70. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_tabs.scss +99 -0
  71. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_tapTarget.scss +103 -0
  72. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_timepicker.scss +183 -0
  73. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_toast.scss +58 -0
  74. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_tooltip.scss +32 -0
  75. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_transitions.scss +13 -0
  76. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_typography.scss +60 -0
  77. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_variables.scss +349 -0
  78. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/_waves.scss +114 -0
  79. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_checkboxes.scss +200 -0
  80. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_file-input.scss +44 -0
  81. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_forms.scss +22 -0
  82. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_input-fields.scss +354 -0
  83. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_radio-buttons.scss +115 -0
  84. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_range.scss +161 -0
  85. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_select.scss +180 -0
  86. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/components/forms/_switches.scss +89 -0
  87. data/app/assets/stylesheets/activeadmin_materialize_theme/materialize/materialize.scss +41 -0
  88. data/app/assets/stylesheets/activeadmin_materialize_theme/normalize.css +349 -0
  89. data/app/assets/stylesheets/activeadmin_materialize_theme/theme.scss +13 -0
  90. data/app/assets/stylesheets/activeadmin_materialize_theme/variables.scss +14 -0
  91. data/lib/activeadmin_materialize_theme.rb +6 -0
  92. data/lib/activeadmin_materialize_theme/engine.rb +7 -0
  93. data/lib/activeadmin_materialize_theme/version.rb +5 -0
  94. metadata +149 -0
@@ -0,0 +1,275 @@
1
+ (function($) {
2
+ // Function to update labels of text fields
3
+ M.updateTextFields = function() {
4
+ let input_selector =
5
+ 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], input[type=date], input[type=time], textarea';
6
+ $(input_selector).each(function(element, index) {
7
+ let $this = $(this);
8
+ if (
9
+ element.value.length > 0 ||
10
+ $(element).is(':focus') ||
11
+ element.autofocus ||
12
+ $this.attr('placeholder') !== null
13
+ ) {
14
+ $this.siblings('label').addClass('active');
15
+ } else if (element.validity) {
16
+ $this.siblings('label').toggleClass('active', element.validity.badInput === true);
17
+ } else {
18
+ $this.siblings('label').removeClass('active');
19
+ }
20
+ });
21
+ };
22
+
23
+ M.validate_field = function(object) {
24
+ let hasLength = object.attr('data-length') !== null;
25
+ let lenAttr = parseInt(object.attr('data-length'));
26
+ let len = object[0].value.length;
27
+
28
+ if (len === 0 && object[0].validity.badInput === false && !object.is(':required')) {
29
+ if (object.hasClass('validate')) {
30
+ object.removeClass('valid');
31
+ object.removeClass('invalid');
32
+ }
33
+ } else {
34
+ if (object.hasClass('validate')) {
35
+ // Check for character counter attributes
36
+ if (
37
+ (object.is(':valid') && hasLength && len <= lenAttr) ||
38
+ (object.is(':valid') && !hasLength)
39
+ ) {
40
+ object.removeClass('invalid');
41
+ object.addClass('valid');
42
+ } else {
43
+ object.removeClass('valid');
44
+ object.addClass('invalid');
45
+ }
46
+ }
47
+ }
48
+ };
49
+
50
+ M.textareaAutoResize = function($textarea) {
51
+ // Wrap if native element
52
+ if ($textarea instanceof Element) {
53
+ $textarea = $($textarea);
54
+ }
55
+
56
+ if (!$textarea.length) {
57
+ console.error('No textarea element found');
58
+ return;
59
+ }
60
+
61
+ // Textarea Auto Resize
62
+ let hiddenDiv = $('.hiddendiv').first();
63
+ if (!hiddenDiv.length) {
64
+ hiddenDiv = $('<div class="hiddendiv common"></div>');
65
+ $('body').append(hiddenDiv);
66
+ }
67
+
68
+ // Set font properties of hiddenDiv
69
+ let fontFamily = $textarea.css('font-family');
70
+ let fontSize = $textarea.css('font-size');
71
+ let lineHeight = $textarea.css('line-height');
72
+
73
+ // Firefox can't handle padding shorthand.
74
+ let paddingTop = $textarea.css('padding-top');
75
+ let paddingRight = $textarea.css('padding-right');
76
+ let paddingBottom = $textarea.css('padding-bottom');
77
+ let paddingLeft = $textarea.css('padding-left');
78
+
79
+ if (fontSize) {
80
+ hiddenDiv.css('font-size', fontSize);
81
+ }
82
+ if (fontFamily) {
83
+ hiddenDiv.css('font-family', fontFamily);
84
+ }
85
+ if (lineHeight) {
86
+ hiddenDiv.css('line-height', lineHeight);
87
+ }
88
+ if (paddingTop) {
89
+ hiddenDiv.css('padding-top', paddingTop);
90
+ }
91
+ if (paddingRight) {
92
+ hiddenDiv.css('padding-right', paddingRight);
93
+ }
94
+ if (paddingBottom) {
95
+ hiddenDiv.css('padding-bottom', paddingBottom);
96
+ }
97
+ if (paddingLeft) {
98
+ hiddenDiv.css('padding-left', paddingLeft);
99
+ }
100
+
101
+ // Set original-height, if none
102
+ if (!$textarea.data('original-height')) {
103
+ $textarea.data('original-height', $textarea.height());
104
+ }
105
+
106
+ if ($textarea.attr('wrap') === 'off') {
107
+ hiddenDiv.css('overflow-wrap', 'normal').css('white-space', 'pre');
108
+ }
109
+
110
+ hiddenDiv.text($textarea[0].value + '\n');
111
+ let content = hiddenDiv.html().replace(/\n/g, '<br>');
112
+ hiddenDiv.html(content);
113
+
114
+ // When textarea is hidden, width goes crazy.
115
+ // Approximate with half of window size
116
+
117
+ if ($textarea[0].offsetWidth > 0 && $textarea[0].offsetHeight > 0) {
118
+ hiddenDiv.css('width', $textarea.width() + 'px');
119
+ } else {
120
+ hiddenDiv.css('width', window.innerWidth / 2 + 'px');
121
+ }
122
+
123
+ /**
124
+ * Resize if the new height is greater than the
125
+ * original height of the textarea
126
+ */
127
+ if ($textarea.data('original-height') <= hiddenDiv.innerHeight()) {
128
+ $textarea.css('height', hiddenDiv.innerHeight() + 'px');
129
+ } else if ($textarea[0].value.length < $textarea.data('previous-length')) {
130
+ /**
131
+ * In case the new height is less than original height, it
132
+ * means the textarea has less text than before
133
+ * So we set the height to the original one
134
+ */
135
+ $textarea.css('height', $textarea.data('original-height') + 'px');
136
+ }
137
+ $textarea.data('previous-length', $textarea[0].value.length);
138
+ };
139
+
140
+ $(document).ready(function() {
141
+ // Text based inputs
142
+ let input_selector =
143
+ 'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], input[type=date], input[type=time], textarea';
144
+
145
+ // Add active if form auto complete
146
+ $(document).on('change', input_selector, function() {
147
+ if (this.value.length !== 0 || $(this).attr('placeholder') !== null) {
148
+ $(this)
149
+ .siblings('label')
150
+ .addClass('active');
151
+ }
152
+ M.validate_field($(this));
153
+ });
154
+
155
+ // Add active if input element has been pre-populated on document ready
156
+ $(document).ready(function() {
157
+ M.updateTextFields();
158
+ });
159
+
160
+ // HTML DOM FORM RESET handling
161
+ $(document).on('reset', function(e) {
162
+ let formReset = $(e.target);
163
+ if (formReset.is('form')) {
164
+ formReset
165
+ .find(input_selector)
166
+ .removeClass('valid')
167
+ .removeClass('invalid');
168
+ formReset.find(input_selector).each(function(e) {
169
+ if (this.value.length) {
170
+ $(this)
171
+ .siblings('label')
172
+ .removeClass('active');
173
+ }
174
+ });
175
+
176
+ // Reset select (after native reset)
177
+ setTimeout(function() {
178
+ formReset.find('select').each(function() {
179
+ // check if initialized
180
+ if (this.M_FormSelect) {
181
+ $(this).trigger('change');
182
+ }
183
+ });
184
+ }, 0);
185
+ }
186
+ });
187
+
188
+ /**
189
+ * Add active when element has focus
190
+ * @param {Event} e
191
+ */
192
+ document.addEventListener(
193
+ 'focus',
194
+ function(e) {
195
+ if ($(e.target).is(input_selector)) {
196
+ $(e.target)
197
+ .siblings('label, .prefix')
198
+ .addClass('active');
199
+ }
200
+ },
201
+ true
202
+ );
203
+
204
+ /**
205
+ * Remove active when element is blurred
206
+ * @param {Event} e
207
+ */
208
+ document.addEventListener(
209
+ 'blur',
210
+ function(e) {
211
+ let $inputElement = $(e.target);
212
+ if ($inputElement.is(input_selector)) {
213
+ let selector = '.prefix';
214
+
215
+ if (
216
+ $inputElement[0].value.length === 0 &&
217
+ $inputElement[0].validity.badInput !== true &&
218
+ $inputElement.attr('placeholder') === null
219
+ ) {
220
+ selector += ', label';
221
+ }
222
+ $inputElement.siblings(selector).removeClass('active');
223
+ M.validate_field($inputElement);
224
+ }
225
+ },
226
+ true
227
+ );
228
+
229
+ // Radio and Checkbox focus class
230
+ let radio_checkbox = 'input[type=radio], input[type=checkbox]';
231
+ $(document).on('keyup', radio_checkbox, function(e) {
232
+ // TAB, check if tabbing to radio or checkbox.
233
+ if (e.which === M.keys.TAB) {
234
+ $(this).addClass('tabbed');
235
+ let $this = $(this);
236
+ $this.one('blur', function(e) {
237
+ $(this).removeClass('tabbed');
238
+ });
239
+ return;
240
+ }
241
+ });
242
+
243
+ let text_area_selector = '.materialize-textarea';
244
+ $(text_area_selector).each(function() {
245
+ let $textarea = $(this);
246
+ /**
247
+ * Resize textarea on document load after storing
248
+ * the original height and the original length
249
+ */
250
+ $textarea.data('original-height', $textarea.height());
251
+ $textarea.data('previous-length', this.value.length);
252
+ M.textareaAutoResize($textarea);
253
+ });
254
+
255
+ $(document).on('keyup', text_area_selector, function() {
256
+ M.textareaAutoResize($(this));
257
+ });
258
+ $(document).on('keydown', text_area_selector, function() {
259
+ M.textareaAutoResize($(this));
260
+ });
261
+
262
+ // File Input Path
263
+ $(document).on('change', '.file-field input[type="file"]', function() {
264
+ let file_field = $(this).closest('.file-field');
265
+ let path_input = file_field.find('input.file-path');
266
+ let files = $(this)[0].files;
267
+ let file_names = [];
268
+ for (let i = 0; i < files.length; i++) {
269
+ file_names.push(files[i].name);
270
+ }
271
+ path_input[0].value = file_names.join(', ');
272
+ path_input.trigger('change');
273
+ });
274
+ }); // End of $(document).ready
275
+ })(cash);
@@ -0,0 +1,427 @@
1
+ // Required for Meteor package, the use of window prevents export by Meteor
2
+ (function(window) {
3
+ if (window.Package) {
4
+ M = {};
5
+ } else {
6
+ window.M = {};
7
+ }
8
+
9
+ // Check for jQuery
10
+ M.jQueryLoaded = !!window.jQuery;
11
+ })(window);
12
+
13
+ // AMD
14
+ if (typeof define === 'function' && define.amd) {
15
+ define('M', [], function() {
16
+ return M;
17
+ });
18
+
19
+ // Common JS
20
+ } else if (typeof exports !== 'undefined' && !exports.nodeType) {
21
+ if (typeof module !== 'undefined' && !module.nodeType && module.exports) {
22
+ exports = module.exports = M;
23
+ }
24
+ exports.default = M;
25
+ }
26
+
27
+ M.version = '1.0.0';
28
+
29
+ M.keys = {
30
+ TAB: 9,
31
+ ENTER: 13,
32
+ ESC: 27,
33
+ ARROW_UP: 38,
34
+ ARROW_DOWN: 40
35
+ };
36
+
37
+ /**
38
+ * TabPress Keydown handler
39
+ */
40
+ M.tabPressed = false;
41
+ M.keyDown = false;
42
+ let docHandleKeydown = function(e) {
43
+ M.keyDown = true;
44
+ if (e.which === M.keys.TAB || e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) {
45
+ M.tabPressed = true;
46
+ }
47
+ };
48
+ let docHandleKeyup = function(e) {
49
+ M.keyDown = false;
50
+ if (e.which === M.keys.TAB || e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) {
51
+ M.tabPressed = false;
52
+ }
53
+ };
54
+ let docHandleFocus = function(e) {
55
+ if (M.keyDown) {
56
+ document.body.classList.add('keyboard-focused');
57
+ }
58
+ };
59
+ let docHandleBlur = function(e) {
60
+ document.body.classList.remove('keyboard-focused');
61
+ };
62
+ document.addEventListener('keydown', docHandleKeydown, true);
63
+ document.addEventListener('keyup', docHandleKeyup, true);
64
+ document.addEventListener('focus', docHandleFocus, true);
65
+ document.addEventListener('blur', docHandleBlur, true);
66
+
67
+ /**
68
+ * Initialize jQuery wrapper for plugin
69
+ * @param {Class} plugin javascript class
70
+ * @param {string} pluginName jQuery plugin name
71
+ * @param {string} classRef Class reference name
72
+ */
73
+ M.initializeJqueryWrapper = function(plugin, pluginName, classRef) {
74
+ jQuery.fn[pluginName] = function(methodOrOptions) {
75
+ // Call plugin method if valid method name is passed in
76
+ if (plugin.prototype[methodOrOptions]) {
77
+ let params = Array.prototype.slice.call(arguments, 1);
78
+
79
+ // Getter methods
80
+ if (methodOrOptions.slice(0, 3) === 'get') {
81
+ let instance = this.first()[0][classRef];
82
+ return instance[methodOrOptions].apply(instance, params);
83
+ }
84
+
85
+ // Void methods
86
+ return this.each(function() {
87
+ let instance = this[classRef];
88
+ instance[methodOrOptions].apply(instance, params);
89
+ });
90
+
91
+ // Initialize plugin if options or no argument is passed in
92
+ } else if (typeof methodOrOptions === 'object' || !methodOrOptions) {
93
+ plugin.init(this, arguments[0]);
94
+ return this;
95
+ }
96
+
97
+ // Return error if an unrecognized method name is passed in
98
+ jQuery.error(`Method ${methodOrOptions} does not exist on jQuery.${pluginName}`);
99
+ };
100
+ };
101
+
102
+ /**
103
+ * Automatically initialize components
104
+ * @param {Element} context DOM Element to search within for components
105
+ */
106
+ M.AutoInit = function(context) {
107
+ // Use document.body if no context is given
108
+ let root = !!context ? context : document.body;
109
+
110
+ let registry = {
111
+ Autocomplete: root.querySelectorAll('.autocomplete:not(.no-autoinit)'),
112
+ Carousel: root.querySelectorAll('.carousel:not(.no-autoinit)'),
113
+ Chips: root.querySelectorAll('.chips:not(.no-autoinit)'),
114
+ Collapsible: root.querySelectorAll('.collapsible:not(.no-autoinit)'),
115
+ Datepicker: root.querySelectorAll('.datepicker:not(.no-autoinit)'),
116
+ Dropdown: root.querySelectorAll('.dropdown-trigger:not(.no-autoinit)'),
117
+ Materialbox: root.querySelectorAll('.materialboxed:not(.no-autoinit)'),
118
+ Modal: root.querySelectorAll('.modal:not(.no-autoinit)'),
119
+ Parallax: root.querySelectorAll('.parallax:not(.no-autoinit)'),
120
+ Pushpin: root.querySelectorAll('.pushpin:not(.no-autoinit)'),
121
+ ScrollSpy: root.querySelectorAll('.scrollspy:not(.no-autoinit)'),
122
+ FormSelect: root.querySelectorAll('select:not(.no-autoinit)'),
123
+ Sidenav: root.querySelectorAll('.sidenav:not(.no-autoinit)'),
124
+ Tabs: root.querySelectorAll('.tabs:not(.no-autoinit)'),
125
+ TapTarget: root.querySelectorAll('.tap-target:not(.no-autoinit)'),
126
+ Timepicker: root.querySelectorAll('.timepicker:not(.no-autoinit)'),
127
+ Tooltip: root.querySelectorAll('.tooltipped:not(.no-autoinit)'),
128
+ FloatingActionButton: root.querySelectorAll('.fixed-action-btn:not(.no-autoinit)')
129
+ };
130
+
131
+ for (let pluginName in registry) {
132
+ let plugin = M[pluginName];
133
+ plugin.init(registry[pluginName]);
134
+ }
135
+ };
136
+
137
+ /**
138
+ * Generate approximated selector string for a jQuery object
139
+ * @param {jQuery} obj jQuery object to be parsed
140
+ * @returns {string}
141
+ */
142
+ M.objectSelectorString = function(obj) {
143
+ let tagStr = obj.prop('tagName') || '';
144
+ let idStr = obj.attr('id') || '';
145
+ let classStr = obj.attr('class') || '';
146
+ return (tagStr + idStr + classStr).replace(/\s/g, '');
147
+ };
148
+
149
+ // Unique Random ID
150
+ M.guid = (function() {
151
+ function s4() {
152
+ return Math.floor((1 + Math.random()) * 0x10000)
153
+ .toString(16)
154
+ .substring(1);
155
+ }
156
+ return function() {
157
+ return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
158
+ };
159
+ })();
160
+
161
+ /**
162
+ * Escapes hash from special characters
163
+ * @param {string} hash String returned from this.hash
164
+ * @returns {string}
165
+ */
166
+ M.escapeHash = function(hash) {
167
+ return hash.replace(/(:|\.|\[|\]|,|=|\/)/g, '\\$1');
168
+ };
169
+
170
+ M.elementOrParentIsFixed = function(element) {
171
+ let $element = $(element);
172
+ let $checkElements = $element.add($element.parents());
173
+ let isFixed = false;
174
+ $checkElements.each(function() {
175
+ if ($(this).css('position') === 'fixed') {
176
+ isFixed = true;
177
+ return false;
178
+ }
179
+ });
180
+ return isFixed;
181
+ };
182
+
183
+ /**
184
+ * @typedef {Object} Edges
185
+ * @property {Boolean} top If the top edge was exceeded
186
+ * @property {Boolean} right If the right edge was exceeded
187
+ * @property {Boolean} bottom If the bottom edge was exceeded
188
+ * @property {Boolean} left If the left edge was exceeded
189
+ */
190
+
191
+ /**
192
+ * @typedef {Object} Bounding
193
+ * @property {Number} left left offset coordinate
194
+ * @property {Number} top top offset coordinate
195
+ * @property {Number} width
196
+ * @property {Number} height
197
+ */
198
+
199
+ /**
200
+ * Escapes hash from special characters
201
+ * @param {Element} container Container element that acts as the boundary
202
+ * @param {Bounding} bounding element bounding that is being checked
203
+ * @param {Number} offset offset from edge that counts as exceeding
204
+ * @returns {Edges}
205
+ */
206
+ M.checkWithinContainer = function(container, bounding, offset) {
207
+ let edges = {
208
+ top: false,
209
+ right: false,
210
+ bottom: false,
211
+ left: false
212
+ };
213
+
214
+ let containerRect = container.getBoundingClientRect();
215
+ // If body element is smaller than viewport, use viewport height instead.
216
+ let containerBottom =
217
+ container === document.body
218
+ ? Math.max(containerRect.bottom, window.innerHeight)
219
+ : containerRect.bottom;
220
+
221
+ let scrollLeft = container.scrollLeft;
222
+ let scrollTop = container.scrollTop;
223
+
224
+ let scrolledX = bounding.left - scrollLeft;
225
+ let scrolledY = bounding.top - scrollTop;
226
+
227
+ // Check for container and viewport for each edge
228
+ if (scrolledX < containerRect.left + offset || scrolledX < offset) {
229
+ edges.left = true;
230
+ }
231
+
232
+ if (
233
+ scrolledX + bounding.width > containerRect.right - offset ||
234
+ scrolledX + bounding.width > window.innerWidth - offset
235
+ ) {
236
+ edges.right = true;
237
+ }
238
+
239
+ if (scrolledY < containerRect.top + offset || scrolledY < offset) {
240
+ edges.top = true;
241
+ }
242
+
243
+ if (
244
+ scrolledY + bounding.height > containerBottom - offset ||
245
+ scrolledY + bounding.height > window.innerHeight - offset
246
+ ) {
247
+ edges.bottom = true;
248
+ }
249
+
250
+ return edges;
251
+ };
252
+
253
+ M.checkPossibleAlignments = function(el, container, bounding, offset) {
254
+ let canAlign = {
255
+ top: true,
256
+ right: true,
257
+ bottom: true,
258
+ left: true,
259
+ spaceOnTop: null,
260
+ spaceOnRight: null,
261
+ spaceOnBottom: null,
262
+ spaceOnLeft: null
263
+ };
264
+
265
+ let containerAllowsOverflow = getComputedStyle(container).overflow === 'visible';
266
+ let containerRect = container.getBoundingClientRect();
267
+ let containerHeight = Math.min(containerRect.height, window.innerHeight);
268
+ let containerWidth = Math.min(containerRect.width, window.innerWidth);
269
+ let elOffsetRect = el.getBoundingClientRect();
270
+
271
+ let scrollLeft = container.scrollLeft;
272
+ let scrollTop = container.scrollTop;
273
+
274
+ let scrolledX = bounding.left - scrollLeft;
275
+ let scrolledYTopEdge = bounding.top - scrollTop;
276
+ let scrolledYBottomEdge = bounding.top + elOffsetRect.height - scrollTop;
277
+
278
+ // Check for container and viewport for left
279
+ canAlign.spaceOnRight = !containerAllowsOverflow
280
+ ? containerWidth - (scrolledX + bounding.width)
281
+ : window.innerWidth - (elOffsetRect.left + bounding.width);
282
+ if (canAlign.spaceOnRight < 0) {
283
+ canAlign.left = false;
284
+ }
285
+
286
+ // Check for container and viewport for Right
287
+ canAlign.spaceOnLeft = !containerAllowsOverflow
288
+ ? scrolledX - bounding.width + elOffsetRect.width
289
+ : elOffsetRect.right - bounding.width;
290
+ if (canAlign.spaceOnLeft < 0) {
291
+ canAlign.right = false;
292
+ }
293
+
294
+ // Check for container and viewport for Top
295
+ canAlign.spaceOnBottom = !containerAllowsOverflow
296
+ ? containerHeight - (scrolledYTopEdge + bounding.height + offset)
297
+ : window.innerHeight - (elOffsetRect.top + bounding.height + offset);
298
+ if (canAlign.spaceOnBottom < 0) {
299
+ canAlign.top = false;
300
+ }
301
+
302
+ // Check for container and viewport for Bottom
303
+ canAlign.spaceOnTop = !containerAllowsOverflow
304
+ ? scrolledYBottomEdge - (bounding.height - offset)
305
+ : elOffsetRect.bottom - (bounding.height + offset);
306
+ if (canAlign.spaceOnTop < 0) {
307
+ canAlign.bottom = false;
308
+ }
309
+
310
+ return canAlign;
311
+ };
312
+
313
+ M.getOverflowParent = function(element) {
314
+ if (element == null) {
315
+ return null;
316
+ }
317
+
318
+ if (element === document.body || getComputedStyle(element).overflow !== 'visible') {
319
+ return element;
320
+ }
321
+
322
+ return M.getOverflowParent(element.parentElement);
323
+ };
324
+
325
+ /**
326
+ * Gets id of component from a trigger
327
+ * @param {Element} trigger trigger
328
+ * @returns {string}
329
+ */
330
+ M.getIdFromTrigger = function(trigger) {
331
+ let id = trigger.getAttribute('data-target');
332
+ if (!id) {
333
+ id = trigger.getAttribute('href');
334
+ if (id) {
335
+ id = id.slice(1);
336
+ } else {
337
+ id = '';
338
+ }
339
+ }
340
+ return id;
341
+ };
342
+
343
+ /**
344
+ * Multi browser support for document scroll top
345
+ * @returns {Number}
346
+ */
347
+ M.getDocumentScrollTop = function() {
348
+ return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
349
+ };
350
+
351
+ /**
352
+ * Multi browser support for document scroll left
353
+ * @returns {Number}
354
+ */
355
+ M.getDocumentScrollLeft = function() {
356
+ return window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
357
+ };
358
+
359
+ /**
360
+ * @typedef {Object} Edges
361
+ * @property {Boolean} top If the top edge was exceeded
362
+ * @property {Boolean} right If the right edge was exceeded
363
+ * @property {Boolean} bottom If the bottom edge was exceeded
364
+ * @property {Boolean} left If the left edge was exceeded
365
+ */
366
+
367
+ /**
368
+ * @typedef {Object} Bounding
369
+ * @property {Number} left left offset coordinate
370
+ * @property {Number} top top offset coordinate
371
+ * @property {Number} width
372
+ * @property {Number} height
373
+ */
374
+
375
+ /**
376
+ * Get time in ms
377
+ * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
378
+ * @type {function}
379
+ * @return {number}
380
+ */
381
+ let getTime =
382
+ Date.now ||
383
+ function() {
384
+ return new Date().getTime();
385
+ };
386
+
387
+ /**
388
+ * Returns a function, that, when invoked, will only be triggered at most once
389
+ * during a given window of time. Normally, the throttled function will run
390
+ * as much as it can, without ever going more than once per `wait` duration;
391
+ * but if you'd like to disable the execution on the leading edge, pass
392
+ * `{leading: false}`. To disable execution on the trailing edge, ditto.
393
+ * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
394
+ * @param {function} func
395
+ * @param {number} wait
396
+ * @param {Object=} options
397
+ * @returns {Function}
398
+ */
399
+ M.throttle = function(func, wait, options) {
400
+ let context, args, result;
401
+ let timeout = null;
402
+ let previous = 0;
403
+ options || (options = {});
404
+ let later = function() {
405
+ previous = options.leading === false ? 0 : getTime();
406
+ timeout = null;
407
+ result = func.apply(context, args);
408
+ context = args = null;
409
+ };
410
+ return function() {
411
+ let now = getTime();
412
+ if (!previous && options.leading === false) previous = now;
413
+ let remaining = wait - (now - previous);
414
+ context = this;
415
+ args = arguments;
416
+ if (remaining <= 0) {
417
+ clearTimeout(timeout);
418
+ timeout = null;
419
+ previous = now;
420
+ result = func.apply(context, args);
421
+ context = args = null;
422
+ } else if (!timeout && options.trailing !== false) {
423
+ timeout = setTimeout(later, remaining);
424
+ }
425
+ return result;
426
+ };
427
+ };