rails-active-ui 0.2.2 → 0.3.1

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