rails-active-ui 0.1.0

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 (167) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +6 -0
  3. data/app/assets/stylesheets.css +73555 -0
  4. data/app/components/accordion_component.rb +34 -0
  5. data/app/components/ad_component.rb +28 -0
  6. data/app/components/api_component.rb +24 -0
  7. data/app/components/breadcrumb_component.rb +26 -0
  8. data/app/components/button_component.rb +49 -0
  9. data/app/components/calendar_component.rb +34 -0
  10. data/app/components/card_component.rb +56 -0
  11. data/app/components/checkbox_component.rb +41 -0
  12. data/app/components/column_component.rb +62 -0
  13. data/app/components/comment_component.rb +45 -0
  14. data/app/components/concerns/alignable.rb +21 -0
  15. data/app/components/concerns/attachable.rb +16 -0
  16. data/app/components/concerns/orientable.rb +21 -0
  17. data/app/components/concerns/positionable.rb +21 -0
  18. data/app/components/concerns/sizeable.rb +18 -0
  19. data/app/components/container_component.rb +23 -0
  20. data/app/components/dimmer_component.rb +30 -0
  21. data/app/components/divider_component.rb +30 -0
  22. data/app/components/dropdown_component.rb +63 -0
  23. data/app/components/embed_component.rb +32 -0
  24. data/app/components/emoji_component.rb +15 -0
  25. data/app/components/feed_component.rb +22 -0
  26. data/app/components/flag_component.rb +15 -0
  27. data/app/components/flyout_component.rb +41 -0
  28. data/app/components/form_component.rb +39 -0
  29. data/app/components/grid_component.rb +85 -0
  30. data/app/components/h_stack_component.rb +67 -0
  31. data/app/components/header_component.rb +60 -0
  32. data/app/components/icon_component.rb +41 -0
  33. data/app/components/image_component.rb +46 -0
  34. data/app/components/input_component.rb +52 -0
  35. data/app/components/item_component.rb +39 -0
  36. data/app/components/item_group_component.rb +30 -0
  37. data/app/components/label_component.rb +49 -0
  38. data/app/components/link_component.rb +23 -0
  39. data/app/components/list_component.rb +39 -0
  40. data/app/components/loader_component.rb +33 -0
  41. data/app/components/menu_component.rb +64 -0
  42. data/app/components/menu_item_component.rb +52 -0
  43. data/app/components/message_component.rb +54 -0
  44. data/app/components/modal_component.rb +50 -0
  45. data/app/components/nag_component.rb +25 -0
  46. data/app/components/overlay_component.rb +16 -0
  47. data/app/components/placeholder_component.rb +39 -0
  48. data/app/components/popup_component.rb +31 -0
  49. data/app/components/progress_component.rb +48 -0
  50. data/app/components/pusher_component.rb +18 -0
  51. data/app/components/rail_component.rb +31 -0
  52. data/app/components/rating_component.rb +41 -0
  53. data/app/components/reset_component.rb +12 -0
  54. data/app/components/reveal_component.rb +39 -0
  55. data/app/components/row_component.rb +39 -0
  56. data/app/components/search_component.rb +44 -0
  57. data/app/components/segment_component.rb +57 -0
  58. data/app/components/segment_group_component.rb +36 -0
  59. data/app/components/shape_component.rb +25 -0
  60. data/app/components/sidebar_component.rb +33 -0
  61. data/app/components/site_component.rb +12 -0
  62. data/app/components/slider_component.rb +46 -0
  63. data/app/components/state_component.rb +25 -0
  64. data/app/components/statistic_component.rb +43 -0
  65. data/app/components/step_component.rb +56 -0
  66. data/app/components/step_group_component.rb +38 -0
  67. data/app/components/sticky_component.rb +22 -0
  68. data/app/components/sub_header_component.rb +15 -0
  69. data/app/components/sub_menu_component.rb +24 -0
  70. data/app/components/tab_component.rb +24 -0
  71. data/app/components/table_cell_component.rb +60 -0
  72. data/app/components/table_component.rb +160 -0
  73. data/app/components/table_row_component.rb +43 -0
  74. data/app/components/text_component.rb +73 -0
  75. data/app/components/toast_component.rb +36 -0
  76. data/app/components/transition_component.rb +32 -0
  77. data/app/components/v_stack_component.rb +31 -0
  78. data/app/components/visibility_component.rb +22 -0
  79. data/app/helpers/component_helper.rb +109 -0
  80. data/app/helpers/fui_helper.rb +53 -0
  81. data/app/javascript/accordion.js +547 -0
  82. data/app/javascript/accordion.min.js +11 -0
  83. data/app/javascript/api.js +1112 -0
  84. data/app/javascript/api.min.js +11 -0
  85. data/app/javascript/calendar.js +1960 -0
  86. data/app/javascript/calendar.min.js +11 -0
  87. data/app/javascript/checkbox.js +819 -0
  88. data/app/javascript/checkbox.min.js +11 -0
  89. data/app/javascript/dimmer.js +686 -0
  90. data/app/javascript/dimmer.min.js +11 -0
  91. data/app/javascript/dropdown.js +4019 -0
  92. data/app/javascript/dropdown.min.js +11 -0
  93. data/app/javascript/embed.js +646 -0
  94. data/app/javascript/embed.min.js +11 -0
  95. data/app/javascript/flyout.js +1405 -0
  96. data/app/javascript/flyout.min.js +11 -0
  97. data/app/javascript/form.js +2070 -0
  98. data/app/javascript/form.min.js +11 -0
  99. data/app/javascript/jquery.js +10716 -0
  100. data/app/javascript/jquery.min.js +2 -0
  101. data/app/javascript/modal.js +1507 -0
  102. data/app/javascript/modal.min.js +11 -0
  103. data/app/javascript/nag.js +522 -0
  104. data/app/javascript/nag.min.js +11 -0
  105. data/app/javascript/popup.js +1457 -0
  106. data/app/javascript/popup.min.js +11 -0
  107. data/app/javascript/progress.js +922 -0
  108. data/app/javascript/progress.min.js +11 -0
  109. data/app/javascript/rating.js +496 -0
  110. data/app/javascript/rating.min.js +11 -0
  111. data/app/javascript/search.js +1519 -0
  112. data/app/javascript/search.min.js +11 -0
  113. data/app/javascript/shape.js +721 -0
  114. data/app/javascript/shape.min.js +11 -0
  115. data/app/javascript/sidebar.js +952 -0
  116. data/app/javascript/sidebar.min.js +11 -0
  117. data/app/javascript/site.js +415 -0
  118. data/app/javascript/site.min.js +11 -0
  119. data/app/javascript/slider.js +1449 -0
  120. data/app/javascript/slider.min.js +11 -0
  121. data/app/javascript/state.js +653 -0
  122. data/app/javascript/state.min.js +11 -0
  123. data/app/javascript/sticky.js +852 -0
  124. data/app/javascript/sticky.min.js +11 -0
  125. data/app/javascript/tab.js +867 -0
  126. data/app/javascript/tab.min.js +11 -0
  127. data/app/javascript/toast.js +916 -0
  128. data/app/javascript/toast.min.js +11 -0
  129. data/app/javascript/transition.js +955 -0
  130. data/app/javascript/transition.min.js +11 -0
  131. data/app/javascript/ui/controllers/fui_accordion_controller.js +45 -0
  132. data/app/javascript/ui/controllers/fui_api_controller.js +80 -0
  133. data/app/javascript/ui/controllers/fui_calendar_controller.js +66 -0
  134. data/app/javascript/ui/controllers/fui_checkbox_controller.js +48 -0
  135. data/app/javascript/ui/controllers/fui_dimmer_controller.js +45 -0
  136. data/app/javascript/ui/controllers/fui_dropdown_controller.js +68 -0
  137. data/app/javascript/ui/controllers/fui_embed_controller.js +49 -0
  138. data/app/javascript/ui/controllers/fui_flyout_controller.js +49 -0
  139. data/app/javascript/ui/controllers/fui_form_controller.js +62 -0
  140. data/app/javascript/ui/controllers/fui_modal_controller.js +61 -0
  141. data/app/javascript/ui/controllers/fui_nag_controller.js +52 -0
  142. data/app/javascript/ui/controllers/fui_popup_controller.js +58 -0
  143. data/app/javascript/ui/controllers/fui_progress_controller.js +60 -0
  144. data/app/javascript/ui/controllers/fui_rating_controller.js +49 -0
  145. data/app/javascript/ui/controllers/fui_search_controller.js +76 -0
  146. data/app/javascript/ui/controllers/fui_shape_controller.js +45 -0
  147. data/app/javascript/ui/controllers/fui_sidebar_controller.js +48 -0
  148. data/app/javascript/ui/controllers/fui_site_controller.js +29 -0
  149. data/app/javascript/ui/controllers/fui_slider_controller.js +53 -0
  150. data/app/javascript/ui/controllers/fui_state_controller.js +63 -0
  151. data/app/javascript/ui/controllers/fui_sticky_controller.js +50 -0
  152. data/app/javascript/ui/controllers/fui_tab_controller.js +57 -0
  153. data/app/javascript/ui/controllers/fui_toast_controller.js +60 -0
  154. data/app/javascript/ui/controllers/fui_transition_controller.js +60 -0
  155. data/app/javascript/ui/controllers/fui_visibility_controller.js +55 -0
  156. data/app/javascript/ui/index.js +114 -0
  157. data/app/javascript/visibility.js +1196 -0
  158. data/app/javascript/visibility.min.js +11 -0
  159. data/app/lib/component.rb +63 -0
  160. data/config/importmap.rb +27 -0
  161. data/config/initializers/ruby_template_handler.rb +31 -0
  162. data/config/routes.rb +2 -0
  163. data/lib/tasks/ui_tasks.rake +4 -0
  164. data/lib/ui/engine.rb +27 -0
  165. data/lib/ui/version.rb +3 -0
  166. data/lib/ui.rb +6 -0
  167. metadata +220 -0
@@ -0,0 +1,852 @@
1
+ /*!
2
+ * # Fomantic-UI 2.9.4 - Sticky
3
+ * https://github.com/fomantic/Fomantic-UI/
4
+ *
5
+ *
6
+ * Released under the MIT license
7
+ * https://opensource.org/licenses/MIT
8
+ *
9
+ */
10
+
11
+ (function ($, window, document) {
12
+ 'use strict';
13
+
14
+ function isFunction(obj) {
15
+ return typeof obj === 'function' && typeof obj.nodeType !== 'number';
16
+ }
17
+
18
+ window = window !== undefined && window.Math === Math
19
+ ? window
20
+ : globalThis;
21
+
22
+ $.fn.sticky = function (...args) {
23
+ const $allModules = $(this);
24
+ const $document = $(document);
25
+
26
+ let time = Date.now();
27
+ let performance = [];
28
+
29
+ const parameters = args[0];
30
+ const methodInvoked = typeof parameters === 'string';
31
+ const queryArguments = args.slice(1);
32
+ const contextCheck = function (context, win) {
33
+ let $context;
34
+ if ([window, document].includes(context)) {
35
+ $context = $(context);
36
+ } else {
37
+ $context = $(win.document).find(context);
38
+ if ($context.length === 0) {
39
+ $context = win.frameElement ? contextCheck(context, win.parent) : window;
40
+ }
41
+ }
42
+
43
+ return $context;
44
+ };
45
+ let returnedValue;
46
+
47
+ $allModules.each(function () {
48
+ const settings = $.isPlainObject(parameters)
49
+ ? $.extend(true, {}, $.fn.sticky.settings, parameters)
50
+ : $.extend({}, $.fn.sticky.settings);
51
+
52
+ const className = settings.className;
53
+ const namespace = settings.namespace;
54
+ const error = settings.error;
55
+
56
+ const eventNamespace = '.' + namespace;
57
+ const moduleNamespace = 'module-' + namespace;
58
+
59
+ const $module = $(this);
60
+ const $window = $(window);
61
+ const $scroll = contextCheck(settings.scrollContext, window);
62
+ let $container;
63
+ let $context;
64
+
65
+ let instance = $module.data(moduleNamespace);
66
+
67
+ const element = this;
68
+
69
+ let documentObserver;
70
+ let observer;
71
+
72
+ const module = {
73
+
74
+ initialize: function () {
75
+ module.determineContainer();
76
+ module.determineContext();
77
+ module.verbose('Initializing sticky', settings, $container);
78
+
79
+ module.save.positions();
80
+ module.checkErrors();
81
+ module.bind.events();
82
+
83
+ if (settings.observeChanges) {
84
+ module.observeChanges();
85
+ }
86
+ module.instantiate();
87
+ },
88
+
89
+ instantiate: function () {
90
+ module.verbose('Storing instance of module', module);
91
+ instance = module;
92
+ $module
93
+ .data(moduleNamespace, module);
94
+ },
95
+
96
+ destroy: function () {
97
+ module.verbose('Destroying previous instance');
98
+ module.reset();
99
+ if (documentObserver) {
100
+ documentObserver.disconnect();
101
+ }
102
+ if (observer) {
103
+ observer.disconnect();
104
+ }
105
+ $window
106
+ .off('load' + eventNamespace, module.event.load)
107
+ .off('resize' + eventNamespace, module.event.resize);
108
+ $scroll
109
+ .off('scrollchange' + eventNamespace, module.event.scrollchange);
110
+ $module.removeData(moduleNamespace);
111
+ },
112
+
113
+ observeChanges: function () {
114
+ documentObserver = new MutationObserver(module.event.documentChanged);
115
+ observer = new MutationObserver(module.event.changed);
116
+ documentObserver.observe(document, {
117
+ childList: true,
118
+ subtree: true,
119
+ });
120
+ observer.observe(element, {
121
+ childList: true,
122
+ subtree: true,
123
+ });
124
+ observer.observe($context[0], {
125
+ childList: true,
126
+ subtree: true,
127
+ });
128
+ module.debug('Setting up mutation observer', observer);
129
+ },
130
+
131
+ determineContainer: function () {
132
+ $container = settings.container ? contextCheck(settings.container, window) : $module.offsetParent();
133
+ },
134
+
135
+ determineContext: function () {
136
+ $context = settings.context ? contextCheck(settings.context, window) : $container;
137
+ if ($context.length === 0) {
138
+ module.error(error.invalidContext, settings.context, $module);
139
+ }
140
+ },
141
+
142
+ checkErrors: function () {
143
+ if (module.is.hidden()) {
144
+ module.error(error.visible, $module);
145
+ }
146
+ if (module.cache.element.height > module.cache.context.height) {
147
+ module.reset();
148
+ module.error(error.elementSize, $module);
149
+ }
150
+ },
151
+
152
+ bind: {
153
+ events: function () {
154
+ $window
155
+ .on('load' + eventNamespace, module.event.load)
156
+ .on('resize' + eventNamespace, module.event.resize);
157
+ // pub/sub pattern
158
+ $scroll
159
+ .off('scroll' + eventNamespace)
160
+ .on('scroll' + eventNamespace, module.event.scroll)
161
+ .on('scrollchange' + eventNamespace, module.event.scrollchange);
162
+ },
163
+ },
164
+
165
+ event: {
166
+ changed: function (mutations) {
167
+ clearTimeout(module.timer);
168
+ module.timer = setTimeout(function () {
169
+ module.verbose('DOM tree modified, updating sticky menu', mutations);
170
+ module.refresh();
171
+ }, 100);
172
+ },
173
+ documentChanged: function (mutations) {
174
+ for (const mutation of mutations) {
175
+ for (const node of mutation.removedNodes) {
176
+ if (node === element || $(node).find(element).length > 0) {
177
+ module.debug('Element removed from DOM, tearing down events');
178
+ module.destroy();
179
+ }
180
+ }
181
+ }
182
+ },
183
+ load: function () {
184
+ module.verbose('Page contents finished loading');
185
+ requestAnimationFrame(module.refresh);
186
+ },
187
+ resize: function () {
188
+ module.verbose('Window resized');
189
+ requestAnimationFrame(module.refresh);
190
+ },
191
+ scroll: function () {
192
+ requestAnimationFrame(function () {
193
+ $scroll.triggerHandler('scrollchange' + eventNamespace, $scroll.scrollTop());
194
+ });
195
+ },
196
+ scrollchange: function (event, scrollPosition) {
197
+ module.stick(scrollPosition);
198
+ settings.onScroll.call(element);
199
+ },
200
+ },
201
+
202
+ refresh: function (hardRefresh) {
203
+ module.reset();
204
+ if (!settings.context) {
205
+ module.determineContext();
206
+ }
207
+ if (hardRefresh) {
208
+ module.determineContainer();
209
+ }
210
+ module.save.positions();
211
+ module.stick();
212
+ settings.onReposition.call(element);
213
+ },
214
+
215
+ supports: {
216
+ sticky: function () {
217
+ const $element = $('<div/>');
218
+ $element.addClass(className.supported);
219
+
220
+ return $element.css('position').match('sticky');
221
+ },
222
+ },
223
+
224
+ save: {
225
+ lastScroll: function (scroll) {
226
+ module.lastScroll = scroll;
227
+ },
228
+ elementScroll: function (scroll) {
229
+ module.elementScroll = scroll;
230
+ },
231
+ positions: function () {
232
+ const scrollContext = {
233
+ height: $scroll.height(),
234
+ };
235
+ const element = {
236
+ margin: {
237
+ top: Number.parseInt($module.css('margin-top'), 10),
238
+ bottom: Number.parseInt($module.css('margin-bottom'), 10),
239
+ },
240
+ offset: $module.offset(),
241
+ width: $module.outerWidth(),
242
+ height: $module.outerHeight(),
243
+ };
244
+ const context = {
245
+ offset: $context.offset(),
246
+ height: $context.outerHeight(),
247
+ };
248
+ if (!module.is.standardScroll()) {
249
+ module.debug('Non-standard scroll. Removing scroll offset from element offset');
250
+
251
+ scrollContext.top = $scroll.scrollTop();
252
+ scrollContext.left = $scroll.scrollLeft();
253
+
254
+ element.offset.top += scrollContext.top;
255
+ context.offset.top += scrollContext.top;
256
+ element.offset.left += scrollContext.left;
257
+ context.offset.left += scrollContext.left;
258
+ }
259
+ module.cache = {
260
+ fits: (element.height + settings.offset) <= scrollContext.height,
261
+ sameHeight: element.height === context.height,
262
+ scrollContext: {
263
+ height: scrollContext.height,
264
+ },
265
+ element: {
266
+ margin: element.margin,
267
+ top: element.offset.top - element.margin.top,
268
+ left: element.offset.left,
269
+ width: element.width,
270
+ height: element.height,
271
+ bottom: element.offset.top + element.height,
272
+ },
273
+ context: {
274
+ top: context.offset.top,
275
+ height: context.height,
276
+ bottom: context.offset.top + context.height,
277
+ },
278
+ };
279
+ module.set.containerSize();
280
+
281
+ module.stick();
282
+ module.debug('Caching element positions', module.cache);
283
+ },
284
+ },
285
+
286
+ get: {
287
+ direction: function (scroll = $scroll.scrollTop()) {
288
+ let direction = 'down';
289
+ if (module.lastScroll && module.lastScroll > scroll) {
290
+ direction = 'up';
291
+ }
292
+
293
+ return direction;
294
+ },
295
+ scrollChange: function (scroll = $scroll.scrollTop()) {
296
+ return module.lastScroll
297
+ ? scroll - module.lastScroll
298
+ : 0;
299
+ },
300
+ currentElementScroll: function () {
301
+ if (module.elementScroll) {
302
+ return module.elementScroll;
303
+ }
304
+
305
+ return module.is.top()
306
+ ? Math.abs(Number.parseInt($module.css('top'), 10)) || 0
307
+ : Math.abs(Number.parseInt($module.css('bottom'), 10)) || 0;
308
+ },
309
+
310
+ elementScroll: function (scroll = $scroll.scrollTop()) {
311
+ const element = module.cache.element;
312
+ const scrollContext = module.cache.scrollContext;
313
+ const delta = module.get.scrollChange(scroll);
314
+ const maxScroll = element.height - scrollContext.height + settings.offset;
315
+ let elementScroll = module.get.currentElementScroll();
316
+ const possibleScroll = elementScroll + delta;
317
+ if (module.cache.fits || possibleScroll < 0) {
318
+ elementScroll = 0;
319
+ } else if (possibleScroll > maxScroll) {
320
+ elementScroll = maxScroll;
321
+ } else {
322
+ elementScroll = possibleScroll;
323
+ }
324
+
325
+ return elementScroll;
326
+ },
327
+ },
328
+
329
+ remove: {
330
+ lastScroll: function () {
331
+ delete module.lastScroll;
332
+ },
333
+ elementScroll: function () {
334
+ delete module.elementScroll;
335
+ },
336
+ minimumSize: function () {
337
+ $container
338
+ .css('min-height', '');
339
+ },
340
+ offset: function () {
341
+ $module.css('margin-top', '');
342
+ },
343
+ },
344
+
345
+ set: {
346
+ offset: function () {
347
+ module.verbose('Setting offset on element', settings.offset);
348
+ $module
349
+ .css('margin-top', settings.offset);
350
+ },
351
+ containerSize: function () {
352
+ const tagName = $container[0].tagName;
353
+ if (tagName === 'HTML' || tagName === 'body') {
354
+ module.determineContainer();
355
+ } else {
356
+ const tallestHeight = Math.max(module.cache.context.height, module.cache.element.height);
357
+ if (tallestHeight - $container.outerHeight() > settings.jitter) {
358
+ module.debug('Context is taller than container. Specifying exact height for container', module.cache.context.height);
359
+ $container.css({
360
+ height: tallestHeight,
361
+ });
362
+ } else {
363
+ $container.css({
364
+ height: '',
365
+ });
366
+ }
367
+ if (Math.abs($container.outerHeight() - module.cache.context.height) > settings.jitter) {
368
+ module.debug('Context has padding, specifying exact height for container', module.cache.context.height);
369
+ $container.css({
370
+ height: module.cache.context.height,
371
+ });
372
+ }
373
+ }
374
+ },
375
+ minimumSize: function () {
376
+ const element = module.cache.element;
377
+ $container
378
+ .css('min-height', element.height);
379
+ },
380
+ scroll: function (scroll) {
381
+ module.debug('Setting scroll on element', scroll);
382
+ if (module.elementScroll === scroll) {
383
+ return;
384
+ }
385
+ if (module.is.top()) {
386
+ $module
387
+ .css('bottom', '')
388
+ .css('top', -scroll + 'px');
389
+ }
390
+ if (module.is.bottom()) {
391
+ $module
392
+ .css('top', '')
393
+ .css('bottom', scroll + 'px');
394
+ }
395
+ },
396
+ size: function () {
397
+ if (module.cache.element.height !== 0 && module.cache.element.width !== 0) {
398
+ element.style.setProperty('width', module.cache.element.width + 'px', 'important');
399
+ element.style.setProperty('height', module.cache.element.height + 'px', 'important');
400
+ }
401
+ },
402
+ },
403
+
404
+ is: {
405
+ standardScroll: function () {
406
+ return $scroll[0] === window;
407
+ },
408
+ top: function () {
409
+ return $module.hasClass(className.top);
410
+ },
411
+ bottom: function () {
412
+ return $module.hasClass(className.bottom);
413
+ },
414
+ initialPosition: function () {
415
+ return !module.is.fixed() && !module.is.bound();
416
+ },
417
+ hidden: function () {
418
+ return !$module.is(':visible');
419
+ },
420
+ bound: function () {
421
+ return $module.hasClass(className.bound);
422
+ },
423
+ fixed: function () {
424
+ return $module.hasClass(className.fixed);
425
+ },
426
+ },
427
+
428
+ stick: function (scrollPosition = $scroll.scrollTop()) {
429
+ const cache = module.cache;
430
+ const fits = cache.fits;
431
+ const sameHeight = cache.sameHeight;
432
+ const element = cache.element;
433
+ const scrollContext = cache.scrollContext;
434
+ const context = cache.context;
435
+ const offset = module.is.bottom() && settings.pushing
436
+ ? settings.bottomOffset
437
+ : settings.offset;
438
+ const scroll = {
439
+ top: scrollPosition + offset,
440
+ bottom: scrollPosition + offset + scrollContext.height,
441
+ };
442
+ const elementScroll = fits
443
+ ? 0
444
+ : module.get.elementScroll(scroll.top);
445
+
446
+ // shorthand
447
+ const doesntFit = !fits;
448
+ const elementVisible = element.height !== 0;
449
+ if (elementVisible && !sameHeight) {
450
+ if (module.is.initialPosition()) {
451
+ if (scroll.top >= context.bottom) {
452
+ module.debug('Initial element position is bottom of container');
453
+ module.bindBottom();
454
+ } else if (scroll.top > element.top) {
455
+ if ((element.height + scroll.top - elementScroll) >= context.bottom && element.height < context.height) {
456
+ module.debug('Initial element position is bottom of container');
457
+ module.bindBottom();
458
+ } else {
459
+ module.debug('Initial element position is fixed');
460
+ module.fixTop();
461
+ }
462
+ }
463
+ } else if (module.is.fixed()) {
464
+ if (module.is.top()) {
465
+ if (scroll.top <= element.top) {
466
+ module.debug('Fixed element reached top of container');
467
+ module.setInitialPosition();
468
+ } else if ((element.height + scroll.top - elementScroll) >= context.bottom) {
469
+ module.debug('Fixed element reached bottom of container');
470
+ module.bindBottom();
471
+ } else if (doesntFit) { // scroll element if larger than screen
472
+ module.set.scroll(elementScroll);
473
+ module.save.lastScroll(scroll.top);
474
+ module.save.elementScroll(elementScroll);
475
+ }
476
+ } else if (module.is.bottom()) {
477
+ if ((scroll.bottom - element.height) <= element.top) { // top edge
478
+ module.debug('Bottom fixed rail has reached top of container');
479
+ module.setInitialPosition();
480
+ } else if (scroll.bottom >= context.bottom) { // bottom edge
481
+ module.debug('Bottom fixed rail has reached bottom of container');
482
+ module.bindBottom();
483
+ } else if (doesntFit) { // scroll element if larger than screen
484
+ module.set.scroll(elementScroll);
485
+ module.save.lastScroll(scroll.top);
486
+ module.save.elementScroll(elementScroll);
487
+ }
488
+ }
489
+ } else if (module.is.bottom()) {
490
+ if (scroll.top <= element.top) {
491
+ module.debug('Jumped from bottom fixed to top fixed, most likely used home/end button');
492
+ module.setInitialPosition();
493
+ } else if (settings.pushing) {
494
+ if (module.is.bound() && scroll.bottom <= context.bottom) {
495
+ module.debug('Fixing bottom attached element to bottom of browser.');
496
+ module.fixBottom();
497
+ }
498
+ } else if (module.is.bound() && (scroll.top <= context.bottom - element.height)) {
499
+ module.debug('Fixing bottom attached element to top of browser.');
500
+ module.fixTop();
501
+ }
502
+ }
503
+ }
504
+ },
505
+
506
+ bindTop: function () {
507
+ module.debug('Binding element to top of parent container');
508
+ module.remove.offset();
509
+ if (settings.setSize) {
510
+ module.set.size();
511
+ }
512
+ $module
513
+ .css({
514
+ left: '',
515
+ top: '',
516
+ marginBottom: '',
517
+ })
518
+ .removeClass(className.fixed)
519
+ .removeClass(className.bottom)
520
+ .addClass(className.bound)
521
+ .addClass(className.top);
522
+ settings.onTop.call(element);
523
+ settings.onUnstick.call(element);
524
+ },
525
+ bindBottom: function () {
526
+ module.debug('Binding element to bottom of parent container');
527
+ module.remove.offset();
528
+ if (settings.setSize) {
529
+ module.set.size();
530
+ }
531
+ $module
532
+ .css({
533
+ left: '',
534
+ top: '',
535
+ })
536
+ .removeClass(className.fixed)
537
+ .removeClass(className.top)
538
+ .addClass(className.bound)
539
+ .addClass(className.bottom);
540
+ settings.onBottom.call(element);
541
+ settings.onUnstick.call(element);
542
+ },
543
+
544
+ setInitialPosition: function () {
545
+ module.debug('Returning to initial position');
546
+ module.unfix();
547
+ module.unbind();
548
+ },
549
+
550
+ fixTop: function () {
551
+ module.debug('Fixing element to top of page');
552
+ if (settings.setSize) {
553
+ module.set.size();
554
+ }
555
+ module.set.minimumSize();
556
+ module.set.offset();
557
+ $module
558
+ .css({
559
+ left: module.cache.element.left,
560
+ bottom: '',
561
+ marginBottom: '',
562
+ })
563
+ .removeClass(className.bound)
564
+ .removeClass(className.bottom)
565
+ .addClass(className.fixed)
566
+ .addClass(className.top);
567
+ settings.onStick.call(element);
568
+ },
569
+
570
+ fixBottom: function () {
571
+ module.debug('Sticking element to bottom of page');
572
+ if (settings.setSize) {
573
+ module.set.size();
574
+ }
575
+ module.set.minimumSize();
576
+ module.set.offset();
577
+ $module
578
+ .css({
579
+ left: module.cache.element.left,
580
+ bottom: '',
581
+ marginBottom: '',
582
+ })
583
+ .removeClass(className.bound)
584
+ .removeClass(className.top)
585
+ .addClass(className.fixed)
586
+ .addClass(className.bottom);
587
+ settings.onStick.call(element);
588
+ },
589
+
590
+ unbind: function () {
591
+ if (module.is.bound()) {
592
+ module.debug('Removing container bound position on element');
593
+ module.remove.offset();
594
+ $module
595
+ .removeClass(className.bound)
596
+ .removeClass(className.top)
597
+ .removeClass(className.bottom);
598
+ }
599
+ },
600
+
601
+ unfix: function () {
602
+ if (module.is.fixed()) {
603
+ module.debug('Removing fixed position on element');
604
+ module.remove.minimumSize();
605
+ module.remove.offset();
606
+ $module
607
+ .removeClass(className.fixed)
608
+ .removeClass(className.top)
609
+ .removeClass(className.bottom);
610
+ settings.onUnstick.call(element);
611
+ }
612
+ },
613
+
614
+ reset: function () {
615
+ module.debug('Resetting elements position');
616
+ module.unbind();
617
+ module.unfix();
618
+ module.resetCSS();
619
+ module.remove.offset();
620
+ module.remove.lastScroll();
621
+ },
622
+
623
+ resetCSS: function () {
624
+ $module
625
+ .css({
626
+ width: '',
627
+ height: '',
628
+ });
629
+ $container
630
+ .css({
631
+ height: '',
632
+ });
633
+ },
634
+
635
+ setting: function (name, value) {
636
+ if ($.isPlainObject(name)) {
637
+ $.extend(true, settings, name);
638
+ } else if (value !== undefined) {
639
+ settings[name] = value;
640
+ } else {
641
+ return settings[name];
642
+ }
643
+ },
644
+ internal: function (name, value) {
645
+ if ($.isPlainObject(name)) {
646
+ $.extend(true, module, name);
647
+ } else if (value !== undefined) {
648
+ module[name] = value;
649
+ } else {
650
+ return module[name];
651
+ }
652
+ },
653
+ debug: function (...args) {
654
+ if (!settings.silent && settings.debug) {
655
+ if (settings.performance) {
656
+ module.performance.log(args);
657
+ } else {
658
+ module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
659
+ module.debug.apply(console, args);
660
+ }
661
+ }
662
+ },
663
+ verbose: function (...args) {
664
+ if (!settings.silent && settings.verbose && settings.debug) {
665
+ if (settings.performance) {
666
+ module.performance.log(args);
667
+ } else {
668
+ module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
669
+ module.verbose.apply(console, args);
670
+ }
671
+ }
672
+ },
673
+ error: function (...args) {
674
+ if (!settings.silent) {
675
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
676
+ module.error.apply(console, args);
677
+ }
678
+ },
679
+ performance: {
680
+ log: function (message) {
681
+ let currentTime;
682
+ let executionTime;
683
+ let previousTime;
684
+ if (settings.performance) {
685
+ currentTime = Date.now();
686
+ previousTime = time || currentTime;
687
+ executionTime = currentTime - previousTime;
688
+ time = currentTime;
689
+ performance.push({
690
+ Name: message[0],
691
+ Arguments: message.slice(1),
692
+ Element: element,
693
+ 'Execution Time': executionTime,
694
+ });
695
+ }
696
+ clearTimeout(module.performance.timer);
697
+ module.performance.timer = setTimeout(function () {
698
+ module.performance.display();
699
+ }, 0);
700
+ },
701
+ display: function () {
702
+ let title = settings.name + ':';
703
+ let totalTime = 0;
704
+ time = false;
705
+ clearTimeout(module.performance.timer);
706
+ $.each(performance, function (index, data) {
707
+ totalTime += data['Execution Time'];
708
+ });
709
+ title += ' ' + totalTime + 'ms';
710
+ if (performance.length > 0) {
711
+ console.groupCollapsed(title);
712
+ console.table(performance);
713
+ console.groupEnd();
714
+ }
715
+ performance = [];
716
+ },
717
+ },
718
+ invoke: function (query, passedArguments = queryArguments, context = element) {
719
+ let object = instance;
720
+ let maxDepth;
721
+ let found;
722
+ let response;
723
+ if (typeof query === 'string' && object !== undefined) {
724
+ query = query.split(/[ .]/);
725
+ maxDepth = query.length - 1;
726
+ $.each(query, function (depth, value) {
727
+ const camelCaseValue = depth !== maxDepth
728
+ ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
729
+ : query;
730
+ if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
731
+ object = object[camelCaseValue];
732
+ } else if (object[camelCaseValue] !== undefined) {
733
+ found = object[camelCaseValue];
734
+
735
+ return false;
736
+ } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
737
+ object = object[value];
738
+ } else if (object[value] !== undefined) {
739
+ found = object[value];
740
+
741
+ return false;
742
+ } else {
743
+ module.error(error.method, query);
744
+
745
+ return false;
746
+ }
747
+ });
748
+ }
749
+ if (isFunction(found)) {
750
+ response = found.apply(context, passedArguments);
751
+ } else if (found !== undefined) {
752
+ response = found;
753
+ }
754
+ if (Array.isArray(returnedValue)) {
755
+ returnedValue.push(response);
756
+ } else if (returnedValue !== undefined) {
757
+ returnedValue = [returnedValue, response];
758
+ } else if (response !== undefined) {
759
+ returnedValue = response;
760
+ }
761
+
762
+ return found;
763
+ },
764
+ };
765
+
766
+ if (methodInvoked) {
767
+ if (instance === undefined) {
768
+ module.initialize();
769
+ }
770
+ module.invoke(parameters);
771
+ } else {
772
+ if (instance !== undefined) {
773
+ instance.invoke('destroy');
774
+ }
775
+ module.initialize();
776
+ }
777
+ });
778
+
779
+ return returnedValue !== undefined
780
+ ? returnedValue
781
+ : this;
782
+ };
783
+
784
+ $.fn.sticky.settings = {
785
+
786
+ name: 'Sticky',
787
+ namespace: 'sticky',
788
+
789
+ silent: false,
790
+ debug: false,
791
+ verbose: true,
792
+ performance: true,
793
+
794
+ // whether to stick in the opposite direction on scroll up
795
+ pushing: false,
796
+
797
+ context: false,
798
+ container: false,
799
+
800
+ // Context to watch scroll events
801
+ scrollContext: window,
802
+
803
+ // Offset to adjust scroll
804
+ offset: 0,
805
+
806
+ // Offset to adjust scroll when attached to bottom of screen
807
+ bottomOffset: 0,
808
+
809
+ // will only set container height if the difference between context and container is larger than this number
810
+ jitter: 5,
811
+
812
+ // set width of the sticky element when it is fixed to page (used to make sure 100% width is maintained if no fixed size set)
813
+ setSize: true,
814
+
815
+ // Whether to automatically observe changes with Mutation Observers
816
+ observeChanges: false,
817
+
818
+ // Called when position is recalculated
819
+ onReposition: function () {},
820
+
821
+ // Called on each scroll
822
+ onScroll: function () {},
823
+
824
+ // Called when the element is stuck to viewport
825
+ onStick: function () {},
826
+
827
+ // Called when the element is unstuck from viewport
828
+ onUnstick: function () {},
829
+
830
+ // Called when element reaches top of context
831
+ onTop: function () {},
832
+
833
+ // Called when element reaches bottom of context
834
+ onBottom: function () {},
835
+
836
+ error: {
837
+ visible: 'Element is hidden, you must call refresh after element becomes visible. Use silent setting to suppress this warning in production.',
838
+ method: 'The method you called is not defined.',
839
+ invalidContext: 'Context specified does not exist',
840
+ elementSize: 'Sticky element is larger than its container, cannot create sticky.',
841
+ },
842
+
843
+ className: {
844
+ bound: 'bound',
845
+ fixed: 'fixed',
846
+ supported: 'native',
847
+ top: 'top',
848
+ bottom: 'bottom',
849
+ },
850
+
851
+ };
852
+ })(jQuery, window, document);