fomantic-ui 2.9.1-beta.17 → 2.9.1-beta.19

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 (252) hide show
  1. package/.eslintrc.js +109 -0
  2. package/.github/workflows/ci.yml +13 -3
  3. package/dist/components/accordion.css +1 -1
  4. package/dist/components/accordion.js +569 -598
  5. package/dist/components/accordion.min.css +1 -1
  6. package/dist/components/accordion.min.js +2 -2
  7. package/dist/components/ad.css +1 -1
  8. package/dist/components/ad.min.css +1 -1
  9. package/dist/components/api.js +1161 -1184
  10. package/dist/components/api.min.js +2 -2
  11. package/dist/components/breadcrumb.css +1 -1
  12. package/dist/components/breadcrumb.min.css +1 -1
  13. package/dist/components/button.css +1 -1
  14. package/dist/components/button.min.css +1 -1
  15. package/dist/components/calendar.css +1 -1
  16. package/dist/components/calendar.js +1895 -1818
  17. package/dist/components/calendar.min.css +1 -1
  18. package/dist/components/calendar.min.js +2 -2
  19. package/dist/components/card.css +1 -1
  20. package/dist/components/card.min.css +1 -1
  21. package/dist/components/checkbox.css +1 -1
  22. package/dist/components/checkbox.js +842 -841
  23. package/dist/components/checkbox.min.css +1 -1
  24. package/dist/components/checkbox.min.js +2 -2
  25. package/dist/components/comment.css +1 -1
  26. package/dist/components/comment.min.css +1 -1
  27. package/dist/components/container.css +3 -1
  28. package/dist/components/container.min.css +2 -2
  29. package/dist/components/dimmer.css +1 -1
  30. package/dist/components/dimmer.js +708 -737
  31. package/dist/components/dimmer.min.css +1 -1
  32. package/dist/components/dimmer.min.js +2 -2
  33. package/dist/components/divider.css +1 -1
  34. package/dist/components/divider.min.css +1 -1
  35. package/dist/components/dropdown.css +11 -8
  36. package/dist/components/dropdown.js +4161 -4238
  37. package/dist/components/dropdown.min.css +2 -2
  38. package/dist/components/dropdown.min.js +2 -2
  39. package/dist/components/embed.css +1 -1
  40. package/dist/components/embed.js +651 -675
  41. package/dist/components/embed.min.css +1 -1
  42. package/dist/components/embed.min.js +2 -2
  43. package/dist/components/feed.css +1 -1
  44. package/dist/components/feed.min.css +1 -1
  45. package/dist/components/flag.css +1 -1
  46. package/dist/components/flag.min.css +1 -1
  47. package/dist/components/flyout.css +6 -3
  48. package/dist/components/flyout.js +1464 -1467
  49. package/dist/components/flyout.min.css +2 -2
  50. package/dist/components/flyout.min.js +2 -2
  51. package/dist/components/form.css +1 -1
  52. package/dist/components/form.js +1979 -2004
  53. package/dist/components/form.min.css +1 -1
  54. package/dist/components/form.min.js +2 -2
  55. package/dist/components/grid.css +1 -1
  56. package/dist/components/grid.min.css +1 -1
  57. package/dist/components/header.css +1 -1
  58. package/dist/components/header.min.css +1 -1
  59. package/dist/components/icon.css +1 -1
  60. package/dist/components/icon.min.css +1 -1
  61. package/dist/components/image.css +1 -1
  62. package/dist/components/image.min.css +1 -1
  63. package/dist/components/input.css +1 -1
  64. package/dist/components/input.min.css +1 -1
  65. package/dist/components/item.css +1 -1
  66. package/dist/components/item.min.css +1 -1
  67. package/dist/components/label.css +1 -1
  68. package/dist/components/label.min.css +1 -1
  69. package/dist/components/list.css +1 -1
  70. package/dist/components/list.min.css +1 -1
  71. package/dist/components/loader.css +1 -1
  72. package/dist/components/loader.min.css +1 -1
  73. package/dist/components/message.css +1 -1
  74. package/dist/components/message.min.css +1 -1
  75. package/dist/components/modal.css +7 -1
  76. package/dist/components/modal.js +1491 -1487
  77. package/dist/components/modal.min.css +2 -2
  78. package/dist/components/modal.min.js +2 -2
  79. package/dist/components/nag.css +1 -1
  80. package/dist/components/nag.js +518 -529
  81. package/dist/components/nag.min.css +1 -1
  82. package/dist/components/nag.min.js +2 -2
  83. package/dist/components/placeholder.css +1 -1
  84. package/dist/components/placeholder.min.css +1 -1
  85. package/dist/components/popup.css +1 -1
  86. package/dist/components/popup.js +1437 -1456
  87. package/dist/components/popup.min.css +1 -1
  88. package/dist/components/popup.min.js +2 -2
  89. package/dist/components/progress.css +1 -1
  90. package/dist/components/progress.js +969 -997
  91. package/dist/components/progress.min.css +1 -1
  92. package/dist/components/progress.min.js +2 -2
  93. package/dist/components/rail.css +1 -1
  94. package/dist/components/rail.min.css +1 -1
  95. package/dist/components/rating.css +1 -1
  96. package/dist/components/rating.js +505 -523
  97. package/dist/components/rating.min.css +1 -1
  98. package/dist/components/rating.min.js +2 -2
  99. package/dist/components/reset.css +1 -1
  100. package/dist/components/reset.min.css +1 -1
  101. package/dist/components/reveal.css +1 -1
  102. package/dist/components/reveal.min.css +1 -1
  103. package/dist/components/search.css +3 -1
  104. package/dist/components/search.js +1498 -1534
  105. package/dist/components/search.min.css +2 -2
  106. package/dist/components/search.min.js +2 -2
  107. package/dist/components/segment.css +3 -1
  108. package/dist/components/segment.min.css +2 -2
  109. package/dist/components/shape.css +1 -1
  110. package/dist/components/shape.js +792 -809
  111. package/dist/components/shape.min.css +1 -1
  112. package/dist/components/shape.min.js +2 -2
  113. package/dist/components/sidebar.css +3 -1
  114. package/dist/components/sidebar.js +1071 -1098
  115. package/dist/components/sidebar.min.css +2 -2
  116. package/dist/components/sidebar.min.js +2 -2
  117. package/dist/components/site.css +1 -1
  118. package/dist/components/site.js +462 -471
  119. package/dist/components/site.min.css +1 -1
  120. package/dist/components/site.min.js +2 -2
  121. package/dist/components/slider.js +1287 -1311
  122. package/dist/components/slider.min.js +2 -2
  123. package/dist/components/state.js +639 -657
  124. package/dist/components/state.min.js +2 -2
  125. package/dist/components/statistic.css +1 -1
  126. package/dist/components/statistic.min.css +1 -1
  127. package/dist/components/step.css +1 -1
  128. package/dist/components/step.min.css +1 -1
  129. package/dist/components/sticky.css +1 -1
  130. package/dist/components/sticky.js +857 -903
  131. package/dist/components/sticky.min.css +1 -1
  132. package/dist/components/sticky.min.js +2 -2
  133. package/dist/components/tab.css +1 -1
  134. package/dist/components/tab.js +922 -963
  135. package/dist/components/tab.min.css +1 -1
  136. package/dist/components/tab.min.js +2 -2
  137. package/dist/components/table.css +5 -1
  138. package/dist/components/table.min.css +2 -2
  139. package/dist/components/text.css +1 -1
  140. package/dist/components/text.min.css +1 -1
  141. package/dist/components/toast.css +1 -1
  142. package/dist/components/toast.js +886 -890
  143. package/dist/components/toast.min.css +1 -1
  144. package/dist/components/toast.min.js +2 -2
  145. package/dist/components/transition.css +1 -1
  146. package/dist/components/transition.js +1041 -1077
  147. package/dist/components/transition.min.css +1 -1
  148. package/dist/components/transition.min.js +2 -2
  149. package/dist/components/visibility.js +1220 -1244
  150. package/dist/components/visibility.min.js +2 -2
  151. package/dist/semantic.css +84 -60
  152. package/dist/semantic.js +28949 -29435
  153. package/dist/semantic.min.css +2 -2
  154. package/dist/semantic.min.js +2 -2
  155. package/examples/assets/show-examples.js +13 -13
  156. package/gulpfile.js +9 -10
  157. package/package.json +5 -2
  158. package/scripts/nightly-version.js +81 -75
  159. package/src/definitions/behaviors/api.js +1162 -1185
  160. package/src/definitions/behaviors/form.js +1978 -2003
  161. package/src/definitions/behaviors/state.js +645 -663
  162. package/src/definitions/behaviors/visibility.js +1219 -1243
  163. package/src/definitions/collections/table.less +2 -0
  164. package/src/definitions/elements/container.less +1 -0
  165. package/src/definitions/elements/segment.less +1 -0
  166. package/src/definitions/globals/site.js +461 -470
  167. package/src/definitions/modules/accordion.js +568 -597
  168. package/src/definitions/modules/calendar.js +1894 -1817
  169. package/src/definitions/modules/checkbox.js +841 -840
  170. package/src/definitions/modules/dimmer.js +707 -736
  171. package/src/definitions/modules/dropdown.js +4160 -4237
  172. package/src/definitions/modules/dropdown.less +5 -8
  173. package/src/definitions/modules/embed.js +650 -674
  174. package/src/definitions/modules/flyout.js +1463 -1466
  175. package/src/definitions/modules/flyout.less +15 -12
  176. package/src/definitions/modules/modal.js +1490 -1486
  177. package/src/definitions/modules/modal.less +3 -0
  178. package/src/definitions/modules/nag.js +517 -528
  179. package/src/definitions/modules/popup.js +1436 -1455
  180. package/src/definitions/modules/progress.js +968 -996
  181. package/src/definitions/modules/rating.js +504 -522
  182. package/src/definitions/modules/search.js +1497 -1533
  183. package/src/definitions/modules/search.less +1 -0
  184. package/src/definitions/modules/shape.js +791 -808
  185. package/src/definitions/modules/sidebar.js +1070 -1097
  186. package/src/definitions/modules/sidebar.less +1 -0
  187. package/src/definitions/modules/slider.js +1286 -1310
  188. package/src/definitions/modules/sticky.js +873 -919
  189. package/src/definitions/modules/tab.js +921 -962
  190. package/src/definitions/modules/toast.js +885 -889
  191. package/src/definitions/modules/transition.js +1040 -1076
  192. package/src/themes/default/elements/container.variables +0 -7
  193. package/src/themes/default/elements/segment.variables +0 -7
  194. package/src/themes/default/globals/site.variables +7 -0
  195. package/src/themes/default/globals/variation.variables +1 -0
  196. package/tasks/admin/components/create.js +274 -276
  197. package/tasks/admin/components/init.js +123 -130
  198. package/tasks/admin/components/update.js +149 -157
  199. package/tasks/admin/distributions/create.js +184 -187
  200. package/tasks/admin/distributions/init.js +123 -130
  201. package/tasks/admin/distributions/update.js +145 -152
  202. package/tasks/admin/publish.js +5 -7
  203. package/tasks/admin/register.js +36 -38
  204. package/tasks/admin/release.js +8 -10
  205. package/tasks/build/assets.js +42 -39
  206. package/tasks/build/css.js +225 -216
  207. package/tasks/build/javascript.js +118 -113
  208. package/tasks/build.js +10 -10
  209. package/tasks/check-install.js +14 -16
  210. package/tasks/clean.js +5 -5
  211. package/tasks/collections/admin.js +34 -36
  212. package/tasks/collections/build.js +18 -20
  213. package/tasks/collections/docs.js +9 -11
  214. package/tasks/collections/install.js +9 -11
  215. package/tasks/collections/rtl.js +9 -11
  216. package/tasks/collections/various.js +8 -10
  217. package/tasks/config/admin/github.js +17 -17
  218. package/tasks/config/admin/oauth.example.js +4 -4
  219. package/tasks/config/admin/release.js +98 -98
  220. package/tasks/config/admin/templates/component-package.js +9 -10
  221. package/tasks/config/admin/templates/css-package.js +18 -20
  222. package/tasks/config/admin/templates/less-package.js +11 -13
  223. package/tasks/config/defaults.js +116 -116
  224. package/tasks/config/docs.js +23 -23
  225. package/tasks/config/npm/gulpfile.js +8 -9
  226. package/tasks/config/project/config.js +127 -134
  227. package/tasks/config/project/install.js +715 -713
  228. package/tasks/config/project/release.js +32 -38
  229. package/tasks/config/tasks.js +163 -164
  230. package/tasks/config/user.js +23 -29
  231. package/tasks/docs/build.js +97 -95
  232. package/tasks/docs/metadata.js +90 -96
  233. package/tasks/docs/serve.js +80 -81
  234. package/tasks/install.js +370 -378
  235. package/tasks/rtl/build.js +2 -2
  236. package/tasks/rtl/watch.js +2 -2
  237. package/tasks/version.js +4 -4
  238. package/tasks/watch.js +28 -30
  239. package/test/meteor/assets.js +10 -13
  240. package/test/meteor/fonts.js +12 -13
  241. package/test/modules/accordion.spec.js +6 -8
  242. package/test/modules/checkbox.spec.js +5 -7
  243. package/test/modules/dropdown.spec.js +5 -7
  244. package/test/modules/modal.spec.js +6 -8
  245. package/test/modules/module.spec.js +158 -178
  246. package/test/modules/popup.spec.js +5 -7
  247. package/test/modules/search.spec.js +5 -7
  248. package/test/modules/shape.spec.js +5 -7
  249. package/test/modules/sidebar.spec.js +5 -7
  250. package/test/modules/tab.spec.js +6 -8
  251. package/test/modules/transition.spec.js +5 -7
  252. package/test/modules/video.spec.js +5 -7
@@ -8,1306 +8,1282 @@
8
8
  *
9
9
  */
10
10
 
11
- ;(function ($, window, document, undefined) {
11
+ (function ($, window, document, undefined) {
12
+ 'use strict';
12
13
 
13
- 'use strict';
14
+ function isFunction(obj) {
15
+ return typeof obj === 'function' && typeof obj.nodeType !== 'number';
16
+ }
14
17
 
15
- function isFunction(obj) {
16
- return typeof obj === "function" && typeof obj.nodeType !== "number";
17
- }
18
+ window = (typeof window != 'undefined' && window.Math == Math)
19
+ ? window
20
+ : globalThis;
18
21
 
19
- window = (typeof window != 'undefined' && window.Math == Math)
20
- ? window
21
- : (typeof self != 'undefined' && self.Math == Math)
22
- ? self
23
- : Function('return this')()
24
- ;
22
+ $.fn.visibility = function (parameters) {
23
+ var
24
+ $allModules = $(this),
25
+ moduleSelector = $allModules.selector || '',
25
26
 
26
- $.fn.visibility = function(parameters) {
27
- var
28
- $allModules = $(this),
29
- moduleSelector = $allModules.selector || '',
27
+ time = new Date().getTime(),
28
+ performance = [],
30
29
 
31
- time = new Date().getTime(),
32
- performance = [],
30
+ query = arguments[0],
31
+ methodInvoked = (typeof query == 'string'),
32
+ queryArguments = [].slice.call(arguments, 1),
33
+ returnedValue,
33
34
 
34
- query = arguments[0],
35
- methodInvoked = (typeof query == 'string'),
36
- queryArguments = [].slice.call(arguments, 1),
37
- returnedValue,
35
+ moduleCount = $allModules.length,
36
+ loadedCount = 0
37
+ ;
38
38
 
39
- moduleCount = $allModules.length,
40
- loadedCount = 0
41
- ;
42
-
43
- $allModules
44
- .each(function() {
45
- var
46
- settings = ( $.isPlainObject(parameters) )
47
- ? $.extend(true, {}, $.fn.visibility.settings, parameters)
48
- : $.extend({}, $.fn.visibility.settings),
49
-
50
- className = settings.className,
51
- namespace = settings.namespace,
52
- error = settings.error,
53
- metadata = settings.metadata,
54
-
55
- eventNamespace = '.' + namespace,
56
- moduleNamespace = 'module-' + namespace,
57
-
58
- $window = $(window),
59
-
60
- $module = $(this),
61
- $context = [window,document].indexOf(settings.context) < 0 ? $(document).find(settings.context) : $(settings.context),
62
-
63
- $placeholder,
64
-
65
- instance = $module.data(moduleNamespace),
66
-
67
- requestAnimationFrame = window.requestAnimationFrame
68
- || window.mozRequestAnimationFrame
69
- || window.webkitRequestAnimationFrame
70
- || window.msRequestAnimationFrame
71
- || function(callback) { setTimeout(callback, 0); },
72
-
73
- element = this,
74
- disabled = false,
75
-
76
- contextObserver,
77
- observer,
78
- module
79
- ;
80
-
81
- module = {
39
+ $allModules.each(function () {
40
+ var
41
+ settings = ($.isPlainObject(parameters))
42
+ ? $.extend(true, {}, $.fn.visibility.settings, parameters)
43
+ : $.extend({}, $.fn.visibility.settings),
82
44
 
83
- initialize: function() {
84
- module.debug('Initializing', settings);
45
+ className = settings.className,
46
+ namespace = settings.namespace,
47
+ error = settings.error,
48
+ metadata = settings.metadata,
85
49
 
86
- module.setup.cache();
50
+ eventNamespace = '.' + namespace,
51
+ moduleNamespace = 'module-' + namespace,
87
52
 
88
- if( module.should.trackChanges() ) {
53
+ $window = $(window),
89
54
 
90
- if(settings.type == 'image') {
91
- module.setup.image();
92
- }
93
- if(settings.type == 'fixed') {
94
- module.setup.fixed();
95
- }
55
+ $module = $(this),
56
+ $context = [window, document].indexOf(settings.context) < 0 ? $(document).find(settings.context) : $(settings.context),
96
57
 
97
- if(settings.observeChanges) {
98
- module.observeChanges();
99
- }
100
- module.bind.events();
101
- }
102
-
103
- module.save.position();
104
- if( !module.is.visible() ) {
105
- module.error(error.visible, $module);
106
- }
107
-
108
- if(settings.initialCheck) {
109
- module.checkVisibility();
110
- }
111
- module.instantiate();
112
- },
58
+ $placeholder,
113
59
 
114
- instantiate: function() {
115
- module.debug('Storing instance', module);
116
- $module
117
- .data(moduleNamespace, module)
118
- ;
119
- instance = module;
120
- },
60
+ instance = $module.data(moduleNamespace),
121
61
 
122
- destroy: function() {
123
- module.verbose('Destroying previous module');
124
- if(observer) {
125
- observer.disconnect();
126
- }
127
- if(contextObserver) {
128
- contextObserver.disconnect();
129
- }
130
- $window
131
- .off('load' + eventNamespace, module.event.load)
132
- .off('resize' + eventNamespace, module.event.resize)
133
- ;
134
- $context
135
- .off('scroll' + eventNamespace, module.event.scroll)
136
- .off('scrollchange' + eventNamespace, module.event.scrollchange)
137
- ;
138
- if(settings.type == 'fixed') {
139
- module.resetFixed();
140
- module.remove.placeholder();
141
- }
142
- $module
143
- .off(eventNamespace)
144
- .removeData(moduleNamespace)
145
- ;
146
- },
62
+ requestAnimationFrame = window.requestAnimationFrame
63
+ || window.mozRequestAnimationFrame
64
+ || window.webkitRequestAnimationFrame
65
+ || window.msRequestAnimationFrame
66
+ || function (callback) {
67
+ setTimeout(callback, 0);
68
+ },
147
69
 
148
- observeChanges: function() {
149
- if('MutationObserver' in window) {
150
- contextObserver = new MutationObserver(module.event.contextChanged);
151
- observer = new MutationObserver(module.event.changed);
152
- contextObserver.observe(document, {
153
- childList : true,
154
- subtree : true
155
- });
156
- observer.observe(element, {
157
- childList : true,
158
- subtree : true
159
- });
160
- module.debug('Setting up mutation observer', observer);
161
- }
162
- },
70
+ element = this,
71
+ disabled = false,
163
72
 
164
- bind: {
165
- events: function() {
166
- module.verbose('Binding visibility events to scroll and resize');
167
- if(settings.refreshOnLoad) {
168
- $window
169
- .on('load' + eventNamespace, module.event.load)
170
- ;
171
- }
172
- $window
173
- .on('resize' + eventNamespace, module.event.resize)
73
+ contextObserver,
74
+ observer,
75
+ module
174
76
  ;
175
- // pub/sub pattern
176
- $context
177
- .off('scroll' + eventNamespace)
178
- .on('scroll' + eventNamespace, module.event.scroll)
179
- .on('scrollchange' + eventNamespace, module.event.scrollchange)
180
- ;
181
- }
182
- },
183
77
 
184
- event: {
185
- changed: function(mutations) {
186
- module.verbose('DOM tree modified, updating visibility calculations');
187
- module.timer = setTimeout(function() {
188
- module.verbose('DOM tree modified, updating sticky menu');
189
- module.refresh();
190
- }, 100);
191
- },
192
- contextChanged: function(mutations) {
193
- [].forEach.call(mutations, function(mutation) {
194
- if(mutation.removedNodes) {
195
- [].forEach.call(mutation.removedNodes, function(node) {
196
- if(node == element || $(node).find(element).length > 0) {
197
- module.debug('Element removed from DOM, tearing down events');
198
- module.destroy();
199
- }
200
- });
201
- }
202
- });
203
- },
204
- resize: function() {
205
- module.debug('Window resized');
206
- if(settings.refreshOnResize) {
207
- requestAnimationFrame(module.refresh);
208
- }
209
- },
210
- load: function() {
211
- module.debug('Page finished loading');
212
- requestAnimationFrame(module.refresh);
213
- },
214
- // publishes scrollchange event on one scroll
215
- scroll: function() {
216
- if(settings.throttle) {
217
- clearTimeout(module.timer);
218
- module.timer = setTimeout(function() {
219
- $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]);
220
- }, settings.throttle);
221
- }
222
- else {
223
- requestAnimationFrame(function() {
224
- $context.triggerHandler('scrollchange' + eventNamespace, [ $context.scrollTop() ]);
225
- });
226
- }
227
- },
228
- // subscribes to scrollchange
229
- scrollchange: function(event, scrollPosition) {
230
- module.checkVisibility(scrollPosition);
231
- },
232
- },
78
+ module = {
233
79
 
234
- precache: function(images, callback) {
235
- if (!(images instanceof Array)) {
236
- images = [images];
237
- }
238
- var
239
- imagesLength = images.length,
240
- loadedCounter = 0,
241
- cache = [],
242
- cacheImage = document.createElement('img'),
243
- handleLoad = function() {
244
- loadedCounter++;
245
- if (loadedCounter >= images.length) {
246
- if (isFunction(callback)) {
247
- callback();
248
- }
249
- }
250
- }
251
- ;
252
- while (imagesLength--) {
253
- cacheImage = document.createElement('img');
254
- cacheImage.onload = handleLoad;
255
- cacheImage.onerror = handleLoad;
256
- cacheImage.src = images[imagesLength];
257
- cache.push(cacheImage);
258
- }
259
- },
80
+ initialize: function () {
81
+ module.debug('Initializing', settings);
260
82
 
261
- enableCallbacks: function() {
262
- module.debug('Allowing callbacks to occur');
263
- disabled = false;
264
- },
83
+ module.setup.cache();
265
84
 
266
- disableCallbacks: function() {
267
- module.debug('Disabling all callbacks temporarily');
268
- disabled = true;
269
- },
85
+ if (module.should.trackChanges()) {
86
+ if (settings.type == 'image') {
87
+ module.setup.image();
88
+ }
89
+ if (settings.type == 'fixed') {
90
+ module.setup.fixed();
91
+ }
270
92
 
271
- should: {
272
- trackChanges: function() {
273
- if(methodInvoked) {
274
- module.debug('One time query, no need to bind events');
275
- return false;
276
- }
277
- module.debug('Callbacks being attached');
278
- return true;
279
- }
280
- },
93
+ if (settings.observeChanges) {
94
+ module.observeChanges();
95
+ }
96
+ module.bind.events();
97
+ }
281
98
 
282
- setup: {
283
- cache: function() {
284
- module.cache = {
285
- occurred : {},
286
- screen : {},
287
- element : {},
288
- };
289
- },
290
- image: function() {
291
- var
292
- src = $module.data(metadata.src)
293
- ;
294
- if(src) {
295
- module.verbose('Lazy loading image', src);
296
- settings.once = true;
297
- settings.observeChanges = false;
298
-
299
- // show when top visible
300
- settings.onOnScreen = function() {
301
- module.debug('Image on screen', element);
302
- module.precache(src, function() {
303
- module.set.image(src, function() {
304
- loadedCount++;
305
- if(loadedCount == moduleCount) {
306
- settings.onAllLoaded.call(this);
99
+ module.save.position();
100
+ if (!module.is.visible()) {
101
+ module.error(error.visible, $module);
307
102
  }
308
- settings.onLoad.call(this);
309
- });
310
- });
311
- };
312
- }
313
- },
314
- fixed: function() {
315
- module.debug('Setting up fixed');
316
- settings.once = false;
317
- settings.observeChanges = false;
318
- settings.initialCheck = true;
319
- settings.refreshOnLoad = true;
320
- if(!parameters.transition) {
321
- settings.transition = false;
322
- }
323
- module.create.placeholder();
324
- module.debug('Added placeholder', $placeholder);
325
- settings.onTopPassed = function() {
326
- module.debug('Element passed, adding fixed position', $module);
327
- module.show.placeholder();
328
- module.set.fixed();
329
- if(settings.transition) {
330
- if($.fn.transition !== undefined) {
331
- $module.transition(settings.transition, settings.duration);
332
- }
333
- }
334
- };
335
- settings.onTopPassedReverse = function() {
336
- module.debug('Element returned to position, removing fixed', $module);
337
- module.hide.placeholder();
338
- module.remove.fixed();
339
- };
340
- }
341
- },
342
103
 
343
- create: {
344
- placeholder: function() {
345
- module.verbose('Creating fixed position placeholder');
346
- $placeholder = $module
347
- .clone(false)
348
- .css('display', 'none')
349
- .addClass(className.placeholder)
350
- .insertAfter($module)
351
- ;
352
- }
353
- },
104
+ if (settings.initialCheck) {
105
+ module.checkVisibility();
106
+ }
107
+ module.instantiate();
108
+ },
109
+
110
+ instantiate: function () {
111
+ module.debug('Storing instance', module);
112
+ $module
113
+ .data(moduleNamespace, module)
114
+ ;
115
+ instance = module;
116
+ },
117
+
118
+ destroy: function () {
119
+ module.verbose('Destroying previous module');
120
+ if (observer) {
121
+ observer.disconnect();
122
+ }
123
+ if (contextObserver) {
124
+ contextObserver.disconnect();
125
+ }
126
+ $window
127
+ .off('load' + eventNamespace, module.event.load)
128
+ .off('resize' + eventNamespace, module.event.resize)
129
+ ;
130
+ $context
131
+ .off('scroll' + eventNamespace, module.event.scroll)
132
+ .off('scrollchange' + eventNamespace, module.event.scrollchange)
133
+ ;
134
+ if (settings.type == 'fixed') {
135
+ module.resetFixed();
136
+ module.remove.placeholder();
137
+ }
138
+ $module
139
+ .off(eventNamespace)
140
+ .removeData(moduleNamespace)
141
+ ;
142
+ },
143
+
144
+ observeChanges: function () {
145
+ if ('MutationObserver' in window) {
146
+ contextObserver = new MutationObserver(module.event.contextChanged);
147
+ observer = new MutationObserver(module.event.changed);
148
+ contextObserver.observe(document, {
149
+ childList: true,
150
+ subtree: true,
151
+ });
152
+ observer.observe(element, {
153
+ childList: true,
154
+ subtree: true,
155
+ });
156
+ module.debug('Setting up mutation observer', observer);
157
+ }
158
+ },
159
+
160
+ bind: {
161
+ events: function () {
162
+ module.verbose('Binding visibility events to scroll and resize');
163
+ if (settings.refreshOnLoad) {
164
+ $window
165
+ .on('load' + eventNamespace, module.event.load)
166
+ ;
167
+ }
168
+ $window
169
+ .on('resize' + eventNamespace, module.event.resize)
170
+ ;
171
+ // pub/sub pattern
172
+ $context
173
+ .off('scroll' + eventNamespace)
174
+ .on('scroll' + eventNamespace, module.event.scroll)
175
+ .on('scrollchange' + eventNamespace, module.event.scrollchange)
176
+ ;
177
+ },
178
+ },
179
+
180
+ event: {
181
+ changed: function (mutations) {
182
+ module.verbose('DOM tree modified, updating visibility calculations');
183
+ module.timer = setTimeout(function () {
184
+ module.verbose('DOM tree modified, updating sticky menu');
185
+ module.refresh();
186
+ }, 100);
187
+ },
188
+ contextChanged: function (mutations) {
189
+ [].forEach.call(mutations, function (mutation) {
190
+ if (mutation.removedNodes) {
191
+ [].forEach.call(mutation.removedNodes, function (node) {
192
+ if (node == element || $(node).find(element).length > 0) {
193
+ module.debug('Element removed from DOM, tearing down events');
194
+ module.destroy();
195
+ }
196
+ });
197
+ }
198
+ });
199
+ },
200
+ resize: function () {
201
+ module.debug('Window resized');
202
+ if (settings.refreshOnResize) {
203
+ requestAnimationFrame(module.refresh);
204
+ }
205
+ },
206
+ load: function () {
207
+ module.debug('Page finished loading');
208
+ requestAnimationFrame(module.refresh);
209
+ },
210
+ // publishes scrollchange event on one scroll
211
+ scroll: function () {
212
+ if (settings.throttle) {
213
+ clearTimeout(module.timer);
214
+ module.timer = setTimeout(function () {
215
+ $context.triggerHandler('scrollchange' + eventNamespace, [$context.scrollTop()]);
216
+ }, settings.throttle);
217
+ } else {
218
+ requestAnimationFrame(function () {
219
+ $context.triggerHandler('scrollchange' + eventNamespace, [$context.scrollTop()]);
220
+ });
221
+ }
222
+ },
223
+ // subscribes to scrollchange
224
+ scrollchange: function (event, scrollPosition) {
225
+ module.checkVisibility(scrollPosition);
226
+ },
227
+ },
228
+
229
+ precache: function (images, callback) {
230
+ if (!(images instanceof Array)) {
231
+ images = [images];
232
+ }
233
+ var
234
+ imagesLength = images.length,
235
+ loadedCounter = 0,
236
+ cache = [],
237
+ cacheImage = document.createElement('img'),
238
+ handleLoad = function () {
239
+ loadedCounter++;
240
+ if (loadedCounter >= images.length) {
241
+ if (isFunction(callback)) {
242
+ callback();
243
+ }
244
+ }
245
+ }
246
+ ;
247
+ while (imagesLength--) {
248
+ cacheImage = document.createElement('img');
249
+ cacheImage.onload = handleLoad;
250
+ cacheImage.onerror = handleLoad;
251
+ cacheImage.src = images[imagesLength];
252
+ cache.push(cacheImage);
253
+ }
254
+ },
255
+
256
+ enableCallbacks: function () {
257
+ module.debug('Allowing callbacks to occur');
258
+ disabled = false;
259
+ },
260
+
261
+ disableCallbacks: function () {
262
+ module.debug('Disabling all callbacks temporarily');
263
+ disabled = true;
264
+ },
265
+
266
+ should: {
267
+ trackChanges: function () {
268
+ if (methodInvoked) {
269
+ module.debug('One time query, no need to bind events');
270
+
271
+ return false;
272
+ }
273
+ module.debug('Callbacks being attached');
274
+
275
+ return true;
276
+ },
277
+ },
278
+
279
+ setup: {
280
+ cache: function () {
281
+ module.cache = {
282
+ occurred: {},
283
+ screen: {},
284
+ element: {},
285
+ };
286
+ },
287
+ image: function () {
288
+ var
289
+ src = $module.data(metadata.src)
290
+ ;
291
+ if (src) {
292
+ module.verbose('Lazy loading image', src);
293
+ settings.once = true;
294
+ settings.observeChanges = false;
295
+
296
+ // show when top visible
297
+ settings.onOnScreen = function () {
298
+ module.debug('Image on screen', element);
299
+ module.precache(src, function () {
300
+ module.set.image(src, function () {
301
+ loadedCount++;
302
+ if (loadedCount == moduleCount) {
303
+ settings.onAllLoaded.call(this);
304
+ }
305
+ settings.onLoad.call(this);
306
+ });
307
+ });
308
+ };
309
+ }
310
+ },
311
+ fixed: function () {
312
+ module.debug('Setting up fixed');
313
+ settings.once = false;
314
+ settings.observeChanges = false;
315
+ settings.initialCheck = true;
316
+ settings.refreshOnLoad = true;
317
+ if (!parameters.transition) {
318
+ settings.transition = false;
319
+ }
320
+ module.create.placeholder();
321
+ module.debug('Added placeholder', $placeholder);
322
+ settings.onTopPassed = function () {
323
+ module.debug('Element passed, adding fixed position', $module);
324
+ module.show.placeholder();
325
+ module.set.fixed();
326
+ if (settings.transition) {
327
+ if ($.fn.transition !== undefined) {
328
+ $module.transition(settings.transition, settings.duration);
329
+ }
330
+ }
331
+ };
332
+ settings.onTopPassedReverse = function () {
333
+ module.debug('Element returned to position, removing fixed', $module);
334
+ module.hide.placeholder();
335
+ module.remove.fixed();
336
+ };
337
+ },
338
+ },
339
+
340
+ create: {
341
+ placeholder: function () {
342
+ module.verbose('Creating fixed position placeholder');
343
+ $placeholder = $module
344
+ .clone(false)
345
+ .css('display', 'none')
346
+ .addClass(className.placeholder)
347
+ .insertAfter($module)
348
+ ;
349
+ },
350
+ },
351
+
352
+ show: {
353
+ placeholder: function () {
354
+ module.verbose('Showing placeholder');
355
+ $placeholder
356
+ .css('display', 'block')
357
+ .css('visibility', 'hidden')
358
+ ;
359
+ },
360
+ },
361
+ hide: {
362
+ placeholder: function () {
363
+ module.verbose('Hiding placeholder');
364
+ $placeholder
365
+ .css('display', 'none')
366
+ .css('visibility', '')
367
+ ;
368
+ },
369
+ },
370
+
371
+ set: {
372
+ fixed: function () {
373
+ module.verbose('Setting element to fixed position');
374
+ $module
375
+ .addClass(className.fixed)
376
+ .css({
377
+ position: 'fixed',
378
+ top: settings.offset + 'px',
379
+ left: 'auto',
380
+ zIndex: settings.zIndex,
381
+ })
382
+ ;
383
+ settings.onFixed.call(element);
384
+ },
385
+ image: function (src, callback) {
386
+ $module
387
+ .attr('src', src)
388
+ ;
389
+ if (settings.transition) {
390
+ if ($.fn.transition !== undefined) {
391
+ if ($module.hasClass(className.visible)) {
392
+ module.debug('Transition already occurred on this image, skipping animation');
393
+
394
+ return;
395
+ }
396
+ $module.transition(settings.transition, settings.duration, callback);
397
+ } else {
398
+ $module.fadeIn(settings.duration, callback);
399
+ }
400
+ } else {
401
+ $module.show();
402
+ }
403
+ },
404
+ },
405
+
406
+ is: {
407
+ onScreen: function () {
408
+ var
409
+ calculations = module.get.elementCalculations()
410
+ ;
411
+
412
+ return calculations.onScreen;
413
+ },
414
+ offScreen: function () {
415
+ var
416
+ calculations = module.get.elementCalculations()
417
+ ;
418
+
419
+ return calculations.offScreen;
420
+ },
421
+ visible: function () {
422
+ if (module.cache && module.cache.element) {
423
+ return !(module.cache.element.width === 0 && module.cache.element.offset.top === 0);
424
+ }
425
+
426
+ return false;
427
+ },
428
+ verticallyScrollableContext: function () {
429
+ var
430
+ overflowY = ($context[0] !== window)
431
+ ? $context.css('overflow-y')
432
+ : false
433
+ ;
434
+
435
+ return (overflowY == 'auto' || overflowY == 'scroll');
436
+ },
437
+ horizontallyScrollableContext: function () {
438
+ var
439
+ overflowX = ($context[0] !== window)
440
+ ? $context.css('overflow-x')
441
+ : false
442
+ ;
443
+
444
+ return (overflowX == 'auto' || overflowX == 'scroll');
445
+ },
446
+ },
447
+
448
+ refresh: function () {
449
+ module.debug('Refreshing constants (width/height)');
450
+ if (settings.type == 'fixed') {
451
+ module.resetFixed();
452
+ }
453
+ module.reset();
454
+ module.save.position();
455
+ if (settings.checkOnRefresh) {
456
+ module.checkVisibility();
457
+ }
458
+ settings.onRefresh.call(element);
459
+ },
460
+
461
+ resetFixed: function () {
462
+ module.remove.fixed();
463
+ module.remove.occurred();
464
+ },
465
+
466
+ reset: function () {
467
+ module.verbose('Resetting all cached values');
468
+ if ($.isPlainObject(module.cache)) {
469
+ module.cache.screen = {};
470
+ module.cache.element = {};
471
+ }
472
+ },
473
+
474
+ checkVisibility: function (scroll) {
475
+ module.verbose('Checking visibility of element', module.cache.element);
476
+
477
+ if (!disabled && module.is.visible()) {
478
+ // save scroll position
479
+ module.save.scroll(scroll);
480
+
481
+ // update calculations derived from scroll
482
+ module.save.calculations();
483
+
484
+ // percentage
485
+ module.passed();
486
+
487
+ // reverse (must be first)
488
+ module.passingReverse();
489
+ module.topVisibleReverse();
490
+ module.bottomVisibleReverse();
491
+ module.topPassedReverse();
492
+ module.bottomPassedReverse();
493
+
494
+ // one time
495
+ module.onScreen();
496
+ module.offScreen();
497
+ module.passing();
498
+ module.topVisible();
499
+ module.bottomVisible();
500
+ module.topPassed();
501
+ module.bottomPassed();
502
+
503
+ // on update callback
504
+ if (settings.onUpdate) {
505
+ settings.onUpdate.call(element, module.get.elementCalculations());
506
+ }
507
+ }
508
+ },
509
+
510
+ passed: function (amount, newCallback) {
511
+ var
512
+ calculations = module.get.elementCalculations()
513
+ ;
514
+ // assign callback
515
+ if (amount && newCallback) {
516
+ settings.onPassed[amount] = newCallback;
517
+ } else if (amount !== undefined) {
518
+ return (module.get.pixelsPassed(amount) > calculations.pixelsPassed);
519
+ } else if (calculations.passing) {
520
+ $.each(settings.onPassed, function (amount, callback) {
521
+ if (calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) {
522
+ module.execute(callback, amount);
523
+ } else if (!settings.once) {
524
+ module.remove.occurred(callback);
525
+ }
526
+ });
527
+ }
528
+ },
529
+
530
+ onScreen: function (newCallback) {
531
+ var
532
+ calculations = module.get.elementCalculations(),
533
+ callback = newCallback || settings.onOnScreen,
534
+ callbackName = 'onScreen'
535
+ ;
536
+ if (newCallback) {
537
+ module.debug('Adding callback for onScreen', newCallback);
538
+ settings.onOnScreen = newCallback;
539
+ }
540
+ if (calculations.onScreen) {
541
+ module.execute(callback, callbackName);
542
+ } else if (!settings.once) {
543
+ module.remove.occurred(callbackName);
544
+ }
545
+ if (newCallback !== undefined) {
546
+ return calculations.onOnScreen;
547
+ }
548
+ },
549
+
550
+ offScreen: function (newCallback) {
551
+ var
552
+ calculations = module.get.elementCalculations(),
553
+ callback = newCallback || settings.onOffScreen,
554
+ callbackName = 'offScreen'
555
+ ;
556
+ if (newCallback) {
557
+ module.debug('Adding callback for offScreen', newCallback);
558
+ settings.onOffScreen = newCallback;
559
+ }
560
+ if (calculations.offScreen) {
561
+ module.execute(callback, callbackName);
562
+ } else if (!settings.once) {
563
+ module.remove.occurred(callbackName);
564
+ }
565
+ if (newCallback !== undefined) {
566
+ return calculations.onOffScreen;
567
+ }
568
+ },
569
+
570
+ passing: function (newCallback) {
571
+ var
572
+ calculations = module.get.elementCalculations(),
573
+ callback = newCallback || settings.onPassing,
574
+ callbackName = 'passing'
575
+ ;
576
+ if (newCallback) {
577
+ module.debug('Adding callback for passing', newCallback);
578
+ settings.onPassing = newCallback;
579
+ }
580
+ if (calculations.passing) {
581
+ module.execute(callback, callbackName);
582
+ } else if (!settings.once) {
583
+ module.remove.occurred(callbackName);
584
+ }
585
+ if (newCallback !== undefined) {
586
+ return calculations.passing;
587
+ }
588
+ },
589
+
590
+ topVisible: function (newCallback) {
591
+ var
592
+ calculations = module.get.elementCalculations(),
593
+ callback = newCallback || settings.onTopVisible,
594
+ callbackName = 'topVisible'
595
+ ;
596
+ if (newCallback) {
597
+ module.debug('Adding callback for top visible', newCallback);
598
+ settings.onTopVisible = newCallback;
599
+ }
600
+ if (calculations.topVisible) {
601
+ module.execute(callback, callbackName);
602
+ } else if (!settings.once) {
603
+ module.remove.occurred(callbackName);
604
+ }
605
+ if (newCallback === undefined) {
606
+ return calculations.topVisible;
607
+ }
608
+ },
609
+
610
+ bottomVisible: function (newCallback) {
611
+ var
612
+ calculations = module.get.elementCalculations(),
613
+ callback = newCallback || settings.onBottomVisible,
614
+ callbackName = 'bottomVisible'
615
+ ;
616
+ if (newCallback) {
617
+ module.debug('Adding callback for bottom visible', newCallback);
618
+ settings.onBottomVisible = newCallback;
619
+ }
620
+ if (calculations.bottomVisible) {
621
+ module.execute(callback, callbackName);
622
+ } else if (!settings.once) {
623
+ module.remove.occurred(callbackName);
624
+ }
625
+ if (newCallback === undefined) {
626
+ return calculations.bottomVisible;
627
+ }
628
+ },
629
+
630
+ topPassed: function (newCallback) {
631
+ var
632
+ calculations = module.get.elementCalculations(),
633
+ callback = newCallback || settings.onTopPassed,
634
+ callbackName = 'topPassed'
635
+ ;
636
+ if (newCallback) {
637
+ module.debug('Adding callback for top passed', newCallback);
638
+ settings.onTopPassed = newCallback;
639
+ }
640
+ if (calculations.topPassed) {
641
+ module.execute(callback, callbackName);
642
+ } else if (!settings.once) {
643
+ module.remove.occurred(callbackName);
644
+ }
645
+ if (newCallback === undefined) {
646
+ return calculations.topPassed;
647
+ }
648
+ },
649
+
650
+ bottomPassed: function (newCallback) {
651
+ var
652
+ calculations = module.get.elementCalculations(),
653
+ callback = newCallback || settings.onBottomPassed,
654
+ callbackName = 'bottomPassed'
655
+ ;
656
+ if (newCallback) {
657
+ module.debug('Adding callback for bottom passed', newCallback);
658
+ settings.onBottomPassed = newCallback;
659
+ }
660
+ if (calculations.bottomPassed) {
661
+ module.execute(callback, callbackName);
662
+ } else if (!settings.once) {
663
+ module.remove.occurred(callbackName);
664
+ }
665
+ if (newCallback === undefined) {
666
+ return calculations.bottomPassed;
667
+ }
668
+ },
669
+
670
+ passingReverse: function (newCallback) {
671
+ var
672
+ calculations = module.get.elementCalculations(),
673
+ callback = newCallback || settings.onPassingReverse,
674
+ callbackName = 'passingReverse'
675
+ ;
676
+ if (newCallback) {
677
+ module.debug('Adding callback for passing reverse', newCallback);
678
+ settings.onPassingReverse = newCallback;
679
+ }
680
+ if (!calculations.passing) {
681
+ if (module.get.occurred('passing')) {
682
+ module.execute(callback, callbackName);
683
+ }
684
+ } else if (!settings.once) {
685
+ module.remove.occurred(callbackName);
686
+ }
687
+ if (newCallback !== undefined) {
688
+ return !calculations.passing;
689
+ }
690
+ },
691
+
692
+ topVisibleReverse: function (newCallback) {
693
+ var
694
+ calculations = module.get.elementCalculations(),
695
+ callback = newCallback || settings.onTopVisibleReverse,
696
+ callbackName = 'topVisibleReverse'
697
+ ;
698
+ if (newCallback) {
699
+ module.debug('Adding callback for top visible reverse', newCallback);
700
+ settings.onTopVisibleReverse = newCallback;
701
+ }
702
+ if (!calculations.topVisible) {
703
+ if (module.get.occurred('topVisible')) {
704
+ module.execute(callback, callbackName);
705
+ }
706
+ } else if (!settings.once) {
707
+ module.remove.occurred(callbackName);
708
+ }
709
+ if (newCallback === undefined) {
710
+ return !calculations.topVisible;
711
+ }
712
+ },
713
+
714
+ bottomVisibleReverse: function (newCallback) {
715
+ var
716
+ calculations = module.get.elementCalculations(),
717
+ callback = newCallback || settings.onBottomVisibleReverse,
718
+ callbackName = 'bottomVisibleReverse'
719
+ ;
720
+ if (newCallback) {
721
+ module.debug('Adding callback for bottom visible reverse', newCallback);
722
+ settings.onBottomVisibleReverse = newCallback;
723
+ }
724
+ if (!calculations.bottomVisible) {
725
+ if (module.get.occurred('bottomVisible')) {
726
+ module.execute(callback, callbackName);
727
+ }
728
+ } else if (!settings.once) {
729
+ module.remove.occurred(callbackName);
730
+ }
731
+ if (newCallback === undefined) {
732
+ return !calculations.bottomVisible;
733
+ }
734
+ },
735
+
736
+ topPassedReverse: function (newCallback) {
737
+ var
738
+ calculations = module.get.elementCalculations(),
739
+ callback = newCallback || settings.onTopPassedReverse,
740
+ callbackName = 'topPassedReverse'
741
+ ;
742
+ if (newCallback) {
743
+ module.debug('Adding callback for top passed reverse', newCallback);
744
+ settings.onTopPassedReverse = newCallback;
745
+ }
746
+ if (!calculations.topPassed) {
747
+ if (module.get.occurred('topPassed')) {
748
+ module.execute(callback, callbackName);
749
+ }
750
+ } else if (!settings.once) {
751
+ module.remove.occurred(callbackName);
752
+ }
753
+ if (newCallback === undefined) {
754
+ return !calculations.onTopPassed;
755
+ }
756
+ },
757
+
758
+ bottomPassedReverse: function (newCallback) {
759
+ var
760
+ calculations = module.get.elementCalculations(),
761
+ callback = newCallback || settings.onBottomPassedReverse,
762
+ callbackName = 'bottomPassedReverse'
763
+ ;
764
+ if (newCallback) {
765
+ module.debug('Adding callback for bottom passed reverse', newCallback);
766
+ settings.onBottomPassedReverse = newCallback;
767
+ }
768
+ if (!calculations.bottomPassed) {
769
+ if (module.get.occurred('bottomPassed')) {
770
+ module.execute(callback, callbackName);
771
+ }
772
+ } else if (!settings.once) {
773
+ module.remove.occurred(callbackName);
774
+ }
775
+ if (newCallback === undefined) {
776
+ return !calculations.bottomPassed;
777
+ }
778
+ },
779
+
780
+ execute: function (callback, callbackName) {
781
+ var
782
+ calculations = module.get.elementCalculations(),
783
+ screen = module.get.screenCalculations()
784
+ ;
785
+ callback = callback || false;
786
+ if (callback) {
787
+ if (settings.continuous) {
788
+ module.debug('Callback being called continuously', callbackName, calculations);
789
+ callback.call(element, calculations, screen);
790
+ } else if (!module.get.occurred(callbackName)) {
791
+ module.debug('Conditions met', callbackName, calculations);
792
+ callback.call(element, calculations, screen);
793
+ }
794
+ }
795
+ module.save.occurred(callbackName);
796
+ },
797
+
798
+ remove: {
799
+ fixed: function () {
800
+ module.debug('Removing fixed position');
801
+ $module
802
+ .removeClass(className.fixed)
803
+ .css({
804
+ position: '',
805
+ top: '',
806
+ left: '',
807
+ zIndex: '',
808
+ })
809
+ ;
810
+ settings.onUnfixed.call(element);
811
+ },
812
+ placeholder: function () {
813
+ module.debug('Removing placeholder content');
814
+ if ($placeholder) {
815
+ $placeholder.remove();
816
+ }
817
+ },
818
+ occurred: function (callback) {
819
+ if (callback) {
820
+ var
821
+ occurred = module.cache.occurred
822
+ ;
823
+ if (occurred[callback] !== undefined && occurred[callback] === true) {
824
+ module.debug('Callback can now be called again', callback);
825
+ module.cache.occurred[callback] = false;
826
+ }
827
+ } else {
828
+ module.cache.occurred = {};
829
+ }
830
+ },
831
+ },
832
+
833
+ save: {
834
+ calculations: function () {
835
+ module.verbose('Saving all calculations necessary to determine positioning');
836
+ module.save.direction();
837
+ module.save.screenCalculations();
838
+ module.save.elementCalculations();
839
+ },
840
+ occurred: function (callback) {
841
+ if (callback) {
842
+ if (module.cache.occurred[callback] === undefined || (module.cache.occurred[callback] !== true)) {
843
+ module.verbose('Saving callback occurred', callback);
844
+ module.cache.occurred[callback] = true;
845
+ }
846
+ }
847
+ },
848
+ scroll: function (scrollPosition) {
849
+ scrollPosition = scrollPosition + settings.offset || $context.scrollTop() + settings.offset;
850
+ module.cache.scroll = scrollPosition;
851
+ },
852
+ direction: function () {
853
+ var
854
+ scroll = module.get.scroll(),
855
+ lastScroll = module.get.lastScroll(),
856
+ direction
857
+ ;
858
+ if (scroll > lastScroll && lastScroll) {
859
+ direction = 'down';
860
+ } else if (scroll < lastScroll && lastScroll) {
861
+ direction = 'up';
862
+ } else {
863
+ direction = 'static';
864
+ }
865
+ module.cache.direction = direction;
866
+
867
+ return module.cache.direction;
868
+ },
869
+ elementPosition: function () {
870
+ var
871
+ element = module.cache.element,
872
+ screen = module.get.screenSize()
873
+ ;
874
+ module.verbose('Saving element position');
875
+ // (quicker than $.extend)
876
+ element.fits = (element.height < screen.height);
877
+ element.offset = $module.offset();
878
+ element.width = $module.outerWidth();
879
+ element.height = $module.outerHeight();
880
+ // compensate for scroll in context
881
+ if (module.is.verticallyScrollableContext()) {
882
+ element.offset.top += $context.scrollTop() - $context.offset().top;
883
+ }
884
+ if (module.is.horizontallyScrollableContext()) {
885
+ element.offset.left += $context.scrollLeft() - $context.offset().left;
886
+ }
887
+ // store
888
+ module.cache.element = element;
889
+
890
+ return element;
891
+ },
892
+ elementCalculations: function () {
893
+ var
894
+ screen = module.get.screenCalculations(),
895
+ element = module.get.elementPosition()
896
+ ;
897
+ // offset
898
+ if (settings.includeMargin) {
899
+ element.margin = {};
900
+ element.margin.top = parseInt($module.css('margin-top'), 10);
901
+ element.margin.bottom = parseInt($module.css('margin-bottom'), 10);
902
+ element.top = element.offset.top - element.margin.top;
903
+ element.bottom = element.offset.top + element.height + element.margin.bottom;
904
+ } else {
905
+ element.top = element.offset.top;
906
+ element.bottom = element.offset.top + element.height;
907
+ }
908
+
909
+ // visibility
910
+ element.topPassed = (screen.top >= element.top);
911
+ element.bottomPassed = (screen.top >= element.bottom);
912
+ element.topVisible = (screen.bottom >= element.top) && !element.topPassed;
913
+ element.bottomVisible = (screen.bottom >= element.bottom) && !element.bottomPassed;
914
+ element.pixelsPassed = 0;
915
+ element.percentagePassed = 0;
916
+
917
+ // meta calculations
918
+ element.onScreen = ((element.topVisible || element.passing) && !element.bottomPassed);
919
+ element.passing = (element.topPassed && !element.bottomPassed);
920
+ element.offScreen = (!element.onScreen);
921
+
922
+ // passing calculations
923
+ if (element.passing) {
924
+ element.pixelsPassed = (screen.top - element.top);
925
+ element.percentagePassed = (screen.top - element.top) / element.height;
926
+ }
927
+ module.cache.element = element;
928
+ module.verbose('Updated element calculations', element);
929
+
930
+ return element;
931
+ },
932
+ screenCalculations: function () {
933
+ var
934
+ scroll = module.get.scroll()
935
+ ;
936
+ module.save.direction();
937
+ module.cache.screen.top = scroll;
938
+ module.cache.screen.bottom = scroll + module.cache.screen.height;
939
+
940
+ return module.cache.screen;
941
+ },
942
+ screenSize: function () {
943
+ module.verbose('Saving window position');
944
+ module.cache.screen = {
945
+ height: $context.height(),
946
+ };
947
+ },
948
+ position: function () {
949
+ module.save.screenSize();
950
+ module.save.elementPosition();
951
+ },
952
+ },
953
+
954
+ get: {
955
+ pixelsPassed: function (amount) {
956
+ var
957
+ element = module.get.elementCalculations()
958
+ ;
959
+ if (amount.search('%') > -1) {
960
+ return (element.height * (parseInt(amount, 10) / 100));
961
+ }
962
+
963
+ return parseInt(amount, 10);
964
+ },
965
+ occurred: function (callback) {
966
+ return (module.cache.occurred !== undefined)
967
+ ? module.cache.occurred[callback] || false
968
+ : false;
969
+ },
970
+ direction: function () {
971
+ if (module.cache.direction === undefined) {
972
+ module.save.direction();
973
+ }
974
+
975
+ return module.cache.direction;
976
+ },
977
+ elementPosition: function () {
978
+ if (module.cache.element === undefined) {
979
+ module.save.elementPosition();
980
+ }
981
+
982
+ return module.cache.element;
983
+ },
984
+ elementCalculations: function () {
985
+ if (module.cache.element === undefined) {
986
+ module.save.elementCalculations();
987
+ }
988
+
989
+ return module.cache.element;
990
+ },
991
+ screenCalculations: function () {
992
+ if (module.cache.screen === undefined) {
993
+ module.save.screenCalculations();
994
+ }
995
+
996
+ return module.cache.screen;
997
+ },
998
+ screenSize: function () {
999
+ if (module.cache.screen === undefined) {
1000
+ module.save.screenSize();
1001
+ }
1002
+
1003
+ return module.cache.screen;
1004
+ },
1005
+ scroll: function () {
1006
+ if (module.cache.scroll === undefined) {
1007
+ module.save.scroll();
1008
+ }
1009
+
1010
+ return module.cache.scroll;
1011
+ },
1012
+ lastScroll: function () {
1013
+ if (module.cache.screen === undefined) {
1014
+ module.debug('First scroll event, no last scroll could be found');
1015
+
1016
+ return false;
1017
+ }
1018
+
1019
+ return module.cache.screen.top;
1020
+ },
1021
+ },
1022
+
1023
+ setting: function (name, value) {
1024
+ if ($.isPlainObject(name)) {
1025
+ $.extend(true, settings, name);
1026
+ } else if (value !== undefined) {
1027
+ settings[name] = value;
1028
+ } else {
1029
+ return settings[name];
1030
+ }
1031
+ },
1032
+ internal: function (name, value) {
1033
+ if ($.isPlainObject(name)) {
1034
+ $.extend(true, module, name);
1035
+ } else if (value !== undefined) {
1036
+ module[name] = value;
1037
+ } else {
1038
+ return module[name];
1039
+ }
1040
+ },
1041
+ debug: function () {
1042
+ if (!settings.silent && settings.debug) {
1043
+ if (settings.performance) {
1044
+ module.performance.log(arguments);
1045
+ } else {
1046
+ module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1047
+ module.debug.apply(console, arguments);
1048
+ }
1049
+ }
1050
+ },
1051
+ verbose: function () {
1052
+ if (!settings.silent && settings.verbose && settings.debug) {
1053
+ if (settings.performance) {
1054
+ module.performance.log(arguments);
1055
+ } else {
1056
+ module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1057
+ module.verbose.apply(console, arguments);
1058
+ }
1059
+ }
1060
+ },
1061
+ error: function () {
1062
+ if (!settings.silent) {
1063
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1064
+ module.error.apply(console, arguments);
1065
+ }
1066
+ },
1067
+ performance: {
1068
+ log: function (message) {
1069
+ var
1070
+ currentTime,
1071
+ executionTime,
1072
+ previousTime
1073
+ ;
1074
+ if (settings.performance) {
1075
+ currentTime = new Date().getTime();
1076
+ previousTime = time || currentTime;
1077
+ executionTime = currentTime - previousTime;
1078
+ time = currentTime;
1079
+ performance.push({
1080
+ Name: message[0],
1081
+ Arguments: [].slice.call(message, 1) || '',
1082
+ Element: element,
1083
+ 'Execution Time': executionTime,
1084
+ });
1085
+ }
1086
+ clearTimeout(module.performance.timer);
1087
+ module.performance.timer = setTimeout(module.performance.display, 500);
1088
+ },
1089
+ display: function () {
1090
+ var
1091
+ title = settings.name + ':',
1092
+ totalTime = 0
1093
+ ;
1094
+ time = false;
1095
+ clearTimeout(module.performance.timer);
1096
+ $.each(performance, function (index, data) {
1097
+ totalTime += data['Execution Time'];
1098
+ });
1099
+ title += ' ' + totalTime + 'ms';
1100
+ if (moduleSelector) {
1101
+ title += ' \'' + moduleSelector + '\'';
1102
+ }
1103
+ if ((console.group !== undefined || console.table !== undefined) && performance.length > 0) {
1104
+ console.groupCollapsed(title);
1105
+ if (console.table) {
1106
+ console.table(performance);
1107
+ } else {
1108
+ $.each(performance, function (index, data) {
1109
+ console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
1110
+ });
1111
+ }
1112
+ console.groupEnd();
1113
+ }
1114
+ performance = [];
1115
+ },
1116
+ },
1117
+ invoke: function (query, passedArguments, context) {
1118
+ var
1119
+ object = instance,
1120
+ maxDepth,
1121
+ found,
1122
+ response
1123
+ ;
1124
+ passedArguments = passedArguments || queryArguments;
1125
+ context = context || element;
1126
+ if (typeof query == 'string' && object !== undefined) {
1127
+ query = query.split(/[\. ]/);
1128
+ maxDepth = query.length - 1;
1129
+ $.each(query, function (depth, value) {
1130
+ var camelCaseValue = (depth != maxDepth)
1131
+ ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1132
+ : query
1133
+ ;
1134
+ if ($.isPlainObject(object[camelCaseValue]) && (depth != maxDepth)) {
1135
+ object = object[camelCaseValue];
1136
+ } else if (object[camelCaseValue] !== undefined) {
1137
+ found = object[camelCaseValue];
1138
+
1139
+ return false;
1140
+ } else if ($.isPlainObject(object[value]) && (depth != maxDepth)) {
1141
+ object = object[value];
1142
+ } else if (object[value] !== undefined) {
1143
+ found = object[value];
1144
+
1145
+ return false;
1146
+ } else {
1147
+ module.error(error.method, query);
1148
+
1149
+ return false;
1150
+ }
1151
+ });
1152
+ }
1153
+ if (isFunction(found)) {
1154
+ response = found.apply(context, passedArguments);
1155
+ } else if (found !== undefined) {
1156
+ response = found;
1157
+ }
1158
+ if (Array.isArray(returnedValue)) {
1159
+ returnedValue.push(response);
1160
+ } else if (returnedValue !== undefined) {
1161
+ returnedValue = [returnedValue, response];
1162
+ } else if (response !== undefined) {
1163
+ returnedValue = response;
1164
+ }
354
1165
 
355
- show: {
356
- placeholder: function() {
357
- module.verbose('Showing placeholder');
358
- $placeholder
359
- .css('display', 'block')
360
- .css('visibility', 'hidden')
361
- ;
362
- }
363
- },
364
- hide: {
365
- placeholder: function() {
366
- module.verbose('Hiding placeholder');
367
- $placeholder
368
- .css('display', 'none')
369
- .css('visibility', '')
370
- ;
371
- }
372
- },
1166
+ return found;
1167
+ },
1168
+ };
373
1169
 
374
- set: {
375
- fixed: function() {
376
- module.verbose('Setting element to fixed position');
377
- $module
378
- .addClass(className.fixed)
379
- .css({
380
- position : 'fixed',
381
- top : settings.offset + 'px',
382
- left : 'auto',
383
- zIndex : settings.zIndex
384
- })
385
- ;
386
- settings.onFixed.call(element);
387
- },
388
- image: function(src, callback) {
389
- $module
390
- .attr('src', src)
391
- ;
392
- if(settings.transition) {
393
- if( $.fn.transition !== undefined) {
394
- if($module.hasClass(className.visible)) {
395
- module.debug('Transition already occurred on this image, skipping animation');
396
- return;
1170
+ if (methodInvoked) {
1171
+ if (instance === undefined) {
1172
+ module.initialize();
397
1173
  }
398
- $module.transition(settings.transition, settings.duration, callback);
399
- }
400
- else {
401
- $module.fadeIn(settings.duration, callback);
402
- }
403
- }
404
- else {
405
- $module.show();
406
- }
407
- }
408
- },
409
-
410
- is: {
411
- onScreen: function() {
412
- var
413
- calculations = module.get.elementCalculations()
414
- ;
415
- return calculations.onScreen;
416
- },
417
- offScreen: function() {
418
- var
419
- calculations = module.get.elementCalculations()
420
- ;
421
- return calculations.offScreen;
422
- },
423
- visible: function() {
424
- if(module.cache && module.cache.element) {
425
- return !(module.cache.element.width === 0 && module.cache.element.offset.top === 0);
1174
+ instance.save.scroll();
1175
+ instance.save.calculations();
1176
+ module.invoke(query);
1177
+ } else {
1178
+ if (instance !== undefined) {
1179
+ instance.invoke('destroy');
1180
+ }
1181
+ module.initialize();
426
1182
  }
427
- return false;
428
- },
429
- verticallyScrollableContext: function() {
430
- var
431
- overflowY = ($context[0] !== window)
432
- ? $context.css('overflow-y')
433
- : false
434
- ;
435
- return (overflowY == 'auto' || overflowY == 'scroll');
436
- },
437
- horizontallyScrollableContext: function() {
438
- var
439
- overflowX = ($context[0] !== window)
440
- ? $context.css('overflow-x')
441
- : false
442
- ;
443
- return (overflowX == 'auto' || overflowX == 'scroll');
444
- }
445
- },
446
-
447
- refresh: function() {
448
- module.debug('Refreshing constants (width/height)');
449
- if(settings.type == 'fixed') {
450
- module.resetFixed();
451
- }
452
- module.reset();
453
- module.save.position();
454
- if(settings.checkOnRefresh) {
455
- module.checkVisibility();
456
- }
457
- settings.onRefresh.call(element);
458
- },
459
-
460
- resetFixed: function () {
461
- module.remove.fixed();
462
- module.remove.occurred();
463
- },
464
-
465
- reset: function() {
466
- module.verbose('Resetting all cached values');
467
- if( $.isPlainObject(module.cache) ) {
468
- module.cache.screen = {};
469
- module.cache.element = {};
470
- }
471
- },
472
-
473
- checkVisibility: function(scroll) {
474
- module.verbose('Checking visibility of element', module.cache.element);
1183
+ });
475
1184
 
476
- if( !disabled && module.is.visible() ) {
1185
+ return (returnedValue !== undefined)
1186
+ ? returnedValue
1187
+ : this;
1188
+ };
477
1189
 
478
- // save scroll position
479
- module.save.scroll(scroll);
1190
+ $.fn.visibility.settings = {
480
1191
 
481
- // update calculations derived from scroll
482
- module.save.calculations();
1192
+ name: 'Visibility',
1193
+ namespace: 'visibility',
483
1194
 
484
- // percentage
485
- module.passed();
1195
+ debug: false,
1196
+ verbose: false,
1197
+ performance: true,
486
1198
 
487
- // reverse (must be first)
488
- module.passingReverse();
489
- module.topVisibleReverse();
490
- module.bottomVisibleReverse();
491
- module.topPassedReverse();
492
- module.bottomPassedReverse();
1199
+ // whether to use mutation observers to follow changes
1200
+ observeChanges: true,
493
1201
 
494
- // one time
495
- module.onScreen();
496
- module.offScreen();
497
- module.passing();
498
- module.topVisible();
499
- module.bottomVisible();
500
- module.topPassed();
501
- module.bottomPassed();
1202
+ // check position immediately on init
1203
+ initialCheck: true,
502
1204
 
503
- // on update callback
504
- if(settings.onUpdate) {
505
- settings.onUpdate.call(element, module.get.elementCalculations());
506
- }
507
- }
508
- },
1205
+ // whether to refresh calculations after all page images load
1206
+ refreshOnLoad: true,
509
1207
 
510
- passed: function(amount, newCallback) {
511
- var
512
- calculations = module.get.elementCalculations()
513
- ;
514
- // assign callback
515
- if(amount && newCallback) {
516
- settings.onPassed[amount] = newCallback;
517
- }
518
- else if(amount !== undefined) {
519
- return (module.get.pixelsPassed(amount) > calculations.pixelsPassed);
520
- }
521
- else if(calculations.passing) {
522
- $.each(settings.onPassed, function(amount, callback) {
523
- if(calculations.bottomVisible || calculations.pixelsPassed > module.get.pixelsPassed(amount)) {
524
- module.execute(callback, amount);
525
- }
526
- else if(!settings.once) {
527
- module.remove.occurred(callback);
528
- }
529
- });
530
- }
531
- },
1208
+ // whether to refresh calculations after page resize event
1209
+ refreshOnResize: true,
532
1210
 
533
- onScreen: function(newCallback) {
534
- var
535
- calculations = module.get.elementCalculations(),
536
- callback = newCallback || settings.onOnScreen,
537
- callbackName = 'onScreen'
538
- ;
539
- if(newCallback) {
540
- module.debug('Adding callback for onScreen', newCallback);
541
- settings.onOnScreen = newCallback;
542
- }
543
- if(calculations.onScreen) {
544
- module.execute(callback, callbackName);
545
- }
546
- else if(!settings.once) {
547
- module.remove.occurred(callbackName);
548
- }
549
- if(newCallback !== undefined) {
550
- return calculations.onOnScreen;
551
- }
552
- },
1211
+ // should call callbacks on refresh event (resize, etc)
1212
+ checkOnRefresh: true,
553
1213
 
554
- offScreen: function(newCallback) {
555
- var
556
- calculations = module.get.elementCalculations(),
557
- callback = newCallback || settings.onOffScreen,
558
- callbackName = 'offScreen'
559
- ;
560
- if(newCallback) {
561
- module.debug('Adding callback for offScreen', newCallback);
562
- settings.onOffScreen = newCallback;
563
- }
564
- if(calculations.offScreen) {
565
- module.execute(callback, callbackName);
566
- }
567
- else if(!settings.once) {
568
- module.remove.occurred(callbackName);
569
- }
570
- if(newCallback !== undefined) {
571
- return calculations.onOffScreen;
572
- }
573
- },
1214
+ // callback should only occur one time
1215
+ once: true,
574
1216
 
575
- passing: function(newCallback) {
576
- var
577
- calculations = module.get.elementCalculations(),
578
- callback = newCallback || settings.onPassing,
579
- callbackName = 'passing'
580
- ;
581
- if(newCallback) {
582
- module.debug('Adding callback for passing', newCallback);
583
- settings.onPassing = newCallback;
584
- }
585
- if(calculations.passing) {
586
- module.execute(callback, callbackName);
587
- }
588
- else if(!settings.once) {
589
- module.remove.occurred(callbackName);
590
- }
591
- if(newCallback !== undefined) {
592
- return calculations.passing;
593
- }
594
- },
1217
+ // callback should fire continuously when evaluates to true
1218
+ continuous: false,
595
1219
 
1220
+ // offset to use with scroll top
1221
+ offset: 0,
596
1222
 
597
- topVisible: function(newCallback) {
598
- var
599
- calculations = module.get.elementCalculations(),
600
- callback = newCallback || settings.onTopVisible,
601
- callbackName = 'topVisible'
602
- ;
603
- if(newCallback) {
604
- module.debug('Adding callback for top visible', newCallback);
605
- settings.onTopVisible = newCallback;
606
- }
607
- if(calculations.topVisible) {
608
- module.execute(callback, callbackName);
609
- }
610
- else if(!settings.once) {
611
- module.remove.occurred(callbackName);
612
- }
613
- if(newCallback === undefined) {
614
- return calculations.topVisible;
615
- }
616
- },
1223
+ // whether to include margin in elements position
1224
+ includeMargin: false,
617
1225
 
618
- bottomVisible: function(newCallback) {
619
- var
620
- calculations = module.get.elementCalculations(),
621
- callback = newCallback || settings.onBottomVisible,
622
- callbackName = 'bottomVisible'
623
- ;
624
- if(newCallback) {
625
- module.debug('Adding callback for bottom visible', newCallback);
626
- settings.onBottomVisible = newCallback;
627
- }
628
- if(calculations.bottomVisible) {
629
- module.execute(callback, callbackName);
630
- }
631
- else if(!settings.once) {
632
- module.remove.occurred(callbackName);
633
- }
634
- if(newCallback === undefined) {
635
- return calculations.bottomVisible;
636
- }
637
- },
638
-
639
- topPassed: function(newCallback) {
640
- var
641
- calculations = module.get.elementCalculations(),
642
- callback = newCallback || settings.onTopPassed,
643
- callbackName = 'topPassed'
644
- ;
645
- if(newCallback) {
646
- module.debug('Adding callback for top passed', newCallback);
647
- settings.onTopPassed = newCallback;
648
- }
649
- if(calculations.topPassed) {
650
- module.execute(callback, callbackName);
651
- }
652
- else if(!settings.once) {
653
- module.remove.occurred(callbackName);
654
- }
655
- if(newCallback === undefined) {
656
- return calculations.topPassed;
657
- }
658
- },
1226
+ // scroll context for visibility checks
1227
+ context: window,
659
1228
 
660
- bottomPassed: function(newCallback) {
661
- var
662
- calculations = module.get.elementCalculations(),
663
- callback = newCallback || settings.onBottomPassed,
664
- callbackName = 'bottomPassed'
665
- ;
666
- if(newCallback) {
667
- module.debug('Adding callback for bottom passed', newCallback);
668
- settings.onBottomPassed = newCallback;
669
- }
670
- if(calculations.bottomPassed) {
671
- module.execute(callback, callbackName);
672
- }
673
- else if(!settings.once) {
674
- module.remove.occurred(callbackName);
675
- }
676
- if(newCallback === undefined) {
677
- return calculations.bottomPassed;
678
- }
679
- },
1229
+ // visibility check delay in ms (defaults to animationFrame)
1230
+ throttle: false,
680
1231
 
681
- passingReverse: function(newCallback) {
682
- var
683
- calculations = module.get.elementCalculations(),
684
- callback = newCallback || settings.onPassingReverse,
685
- callbackName = 'passingReverse'
686
- ;
687
- if(newCallback) {
688
- module.debug('Adding callback for passing reverse', newCallback);
689
- settings.onPassingReverse = newCallback;
690
- }
691
- if(!calculations.passing) {
692
- if(module.get.occurred('passing')) {
693
- module.execute(callback, callbackName);
694
- }
695
- }
696
- else if(!settings.once) {
697
- module.remove.occurred(callbackName);
698
- }
699
- if(newCallback !== undefined) {
700
- return !calculations.passing;
701
- }
702
- },
1232
+ // special visibility type (image, fixed)
1233
+ type: false,
703
1234
 
1235
+ // z-index to use with visibility 'fixed'
1236
+ zIndex: '10',
704
1237
 
705
- topVisibleReverse: function(newCallback) {
706
- var
707
- calculations = module.get.elementCalculations(),
708
- callback = newCallback || settings.onTopVisibleReverse,
709
- callbackName = 'topVisibleReverse'
710
- ;
711
- if(newCallback) {
712
- module.debug('Adding callback for top visible reverse', newCallback);
713
- settings.onTopVisibleReverse = newCallback;
714
- }
715
- if(!calculations.topVisible) {
716
- if(module.get.occurred('topVisible')) {
717
- module.execute(callback, callbackName);
718
- }
719
- }
720
- else if(!settings.once) {
721
- module.remove.occurred(callbackName);
722
- }
723
- if(newCallback === undefined) {
724
- return !calculations.topVisible;
725
- }
726
- },
1238
+ // image only animation settings
1239
+ transition: 'fade in',
1240
+ duration: 1000,
727
1241
 
728
- bottomVisibleReverse: function(newCallback) {
729
- var
730
- calculations = module.get.elementCalculations(),
731
- callback = newCallback || settings.onBottomVisibleReverse,
732
- callbackName = 'bottomVisibleReverse'
733
- ;
734
- if(newCallback) {
735
- module.debug('Adding callback for bottom visible reverse', newCallback);
736
- settings.onBottomVisibleReverse = newCallback;
737
- }
738
- if(!calculations.bottomVisible) {
739
- if(module.get.occurred('bottomVisible')) {
740
- module.execute(callback, callbackName);
741
- }
742
- }
743
- else if(!settings.once) {
744
- module.remove.occurred(callbackName);
745
- }
746
- if(newCallback === undefined) {
747
- return !calculations.bottomVisible;
748
- }
749
- },
1242
+ // array of callbacks for percentage
1243
+ onPassed: {},
750
1244
 
751
- topPassedReverse: function(newCallback) {
752
- var
753
- calculations = module.get.elementCalculations(),
754
- callback = newCallback || settings.onTopPassedReverse,
755
- callbackName = 'topPassedReverse'
756
- ;
757
- if(newCallback) {
758
- module.debug('Adding callback for top passed reverse', newCallback);
759
- settings.onTopPassedReverse = newCallback;
760
- }
761
- if(!calculations.topPassed) {
762
- if(module.get.occurred('topPassed')) {
763
- module.execute(callback, callbackName);
764
- }
765
- }
766
- else if(!settings.once) {
767
- module.remove.occurred(callbackName);
768
- }
769
- if(newCallback === undefined) {
770
- return !calculations.onTopPassed;
771
- }
772
- },
1245
+ // standard callbacks
1246
+ onOnScreen: false,
1247
+ onOffScreen: false,
1248
+ onPassing: false,
1249
+ onTopVisible: false,
1250
+ onBottomVisible: false,
1251
+ onTopPassed: false,
1252
+ onBottomPassed: false,
773
1253
 
774
- bottomPassedReverse: function(newCallback) {
775
- var
776
- calculations = module.get.elementCalculations(),
777
- callback = newCallback || settings.onBottomPassedReverse,
778
- callbackName = 'bottomPassedReverse'
779
- ;
780
- if(newCallback) {
781
- module.debug('Adding callback for bottom passed reverse', newCallback);
782
- settings.onBottomPassedReverse = newCallback;
783
- }
784
- if(!calculations.bottomPassed) {
785
- if(module.get.occurred('bottomPassed')) {
786
- module.execute(callback, callbackName);
787
- }
788
- }
789
- else if(!settings.once) {
790
- module.remove.occurred(callbackName);
791
- }
792
- if(newCallback === undefined) {
793
- return !calculations.bottomPassed;
794
- }
795
- },
1254
+ // reverse callbacks
1255
+ onPassingReverse: false,
1256
+ onTopVisibleReverse: false,
1257
+ onBottomVisibleReverse: false,
1258
+ onTopPassedReverse: false,
1259
+ onBottomPassedReverse: false,
796
1260
 
797
- execute: function(callback, callbackName) {
798
- var
799
- calculations = module.get.elementCalculations(),
800
- screen = module.get.screenCalculations()
801
- ;
802
- callback = callback || false;
803
- if(callback) {
804
- if(settings.continuous) {
805
- module.debug('Callback being called continuously', callbackName, calculations);
806
- callback.call(element, calculations, screen);
807
- }
808
- else if(!module.get.occurred(callbackName)) {
809
- module.debug('Conditions met', callbackName, calculations);
810
- callback.call(element, calculations, screen);
811
- }
812
- }
813
- module.save.occurred(callbackName);
814
- },
1261
+ // special callbacks for image
1262
+ onLoad: function () {},
1263
+ onAllLoaded: function () {},
815
1264
 
816
- remove: {
817
- fixed: function() {
818
- module.debug('Removing fixed position');
819
- $module
820
- .removeClass(className.fixed)
821
- .css({
822
- position : '',
823
- top : '',
824
- left : '',
825
- zIndex : ''
826
- })
827
- ;
828
- settings.onUnfixed.call(element);
829
- },
830
- placeholder: function() {
831
- module.debug('Removing placeholder content');
832
- if($placeholder) {
833
- $placeholder.remove();
834
- }
835
- },
836
- occurred: function(callback) {
837
- if(callback) {
838
- var
839
- occurred = module.cache.occurred
840
- ;
841
- if(occurred[callback] !== undefined && occurred[callback] === true) {
842
- module.debug('Callback can now be called again', callback);
843
- module.cache.occurred[callback] = false;
844
- }
845
- }
846
- else {
847
- module.cache.occurred = {};
848
- }
849
- }
850
- },
1265
+ // special callbacks for fixed position
1266
+ onFixed: function () {},
1267
+ onUnfixed: function () {},
851
1268
 
852
- save: {
853
- calculations: function() {
854
- module.verbose('Saving all calculations necessary to determine positioning');
855
- module.save.direction();
856
- module.save.screenCalculations();
857
- module.save.elementCalculations();
858
- },
859
- occurred: function(callback) {
860
- if(callback) {
861
- if(module.cache.occurred[callback] === undefined || (module.cache.occurred[callback] !== true)) {
862
- module.verbose('Saving callback occurred', callback);
863
- module.cache.occurred[callback] = true;
864
- }
865
- }
866
- },
867
- scroll: function(scrollPosition) {
868
- scrollPosition = scrollPosition + settings.offset || $context.scrollTop() + settings.offset;
869
- module.cache.scroll = scrollPosition;
870
- },
871
- direction: function() {
872
- var
873
- scroll = module.get.scroll(),
874
- lastScroll = module.get.lastScroll(),
875
- direction
876
- ;
877
- if(scroll > lastScroll && lastScroll) {
878
- direction = 'down';
879
- }
880
- else if(scroll < lastScroll && lastScroll) {
881
- direction = 'up';
882
- }
883
- else {
884
- direction = 'static';
885
- }
886
- module.cache.direction = direction;
887
- return module.cache.direction;
888
- },
889
- elementPosition: function() {
890
- var
891
- element = module.cache.element,
892
- screen = module.get.screenSize()
893
- ;
894
- module.verbose('Saving element position');
895
- // (quicker than $.extend)
896
- element.fits = (element.height < screen.height);
897
- element.offset = $module.offset();
898
- element.width = $module.outerWidth();
899
- element.height = $module.outerHeight();
900
- // compensate for scroll in context
901
- if(module.is.verticallyScrollableContext()) {
902
- element.offset.top += $context.scrollTop() - $context.offset().top;
903
- }
904
- if(module.is.horizontallyScrollableContext()) {
905
- element.offset.left += $context.scrollLeft() - $context.offset().left;
906
- }
907
- // store
908
- module.cache.element = element;
909
- return element;
910
- },
911
- elementCalculations: function() {
912
- var
913
- screen = module.get.screenCalculations(),
914
- element = module.get.elementPosition()
915
- ;
916
- // offset
917
- if(settings.includeMargin) {
918
- element.margin = {};
919
- element.margin.top = parseInt($module.css('margin-top'), 10);
920
- element.margin.bottom = parseInt($module.css('margin-bottom'), 10);
921
- element.top = element.offset.top - element.margin.top;
922
- element.bottom = element.offset.top + element.height + element.margin.bottom;
923
- }
924
- else {
925
- element.top = element.offset.top;
926
- element.bottom = element.offset.top + element.height;
927
- }
1269
+ // utility callbacks
1270
+ onUpdate: false, // disabled by default for performance
1271
+ onRefresh: function () {},
928
1272
 
929
- // visibility
930
- element.topPassed = (screen.top >= element.top);
931
- element.bottomPassed = (screen.top >= element.bottom);
932
- element.topVisible = (screen.bottom >= element.top) && !element.topPassed;
933
- element.bottomVisible = (screen.bottom >= element.bottom) && !element.bottomPassed;
934
- element.pixelsPassed = 0;
935
- element.percentagePassed = 0;
936
-
937
- // meta calculations
938
- element.onScreen = ((element.topVisible || element.passing) && !element.bottomPassed);
939
- element.passing = (element.topPassed && !element.bottomPassed);
940
- element.offScreen = (!element.onScreen);
941
-
942
- // passing calculations
943
- if(element.passing) {
944
- element.pixelsPassed = (screen.top - element.top);
945
- element.percentagePassed = (screen.top - element.top) / element.height;
946
- }
947
- module.cache.element = element;
948
- module.verbose('Updated element calculations', element);
949
- return element;
950
- },
951
- screenCalculations: function() {
952
- var
953
- scroll = module.get.scroll()
954
- ;
955
- module.save.direction();
956
- module.cache.screen.top = scroll;
957
- module.cache.screen.bottom = scroll + module.cache.screen.height;
958
- return module.cache.screen;
959
- },
960
- screenSize: function() {
961
- module.verbose('Saving window position');
962
- module.cache.screen = {
963
- height: $context.height()
964
- };
965
- },
966
- position: function() {
967
- module.save.screenSize();
968
- module.save.elementPosition();
969
- }
1273
+ metadata: {
1274
+ src: 'src',
970
1275
  },
971
1276
 
972
- get: {
973
- pixelsPassed: function(amount) {
974
- var
975
- element = module.get.elementCalculations()
976
- ;
977
- if(amount.search('%') > -1) {
978
- return ( element.height * (parseInt(amount, 10) / 100) );
979
- }
980
- return parseInt(amount, 10);
981
- },
982
- occurred: function(callback) {
983
- return (module.cache.occurred !== undefined)
984
- ? module.cache.occurred[callback] || false
985
- : false
986
- ;
987
- },
988
- direction: function() {
989
- if(module.cache.direction === undefined) {
990
- module.save.direction();
991
- }
992
- return module.cache.direction;
993
- },
994
- elementPosition: function() {
995
- if(module.cache.element === undefined) {
996
- module.save.elementPosition();
997
- }
998
- return module.cache.element;
999
- },
1000
- elementCalculations: function() {
1001
- if(module.cache.element === undefined) {
1002
- module.save.elementCalculations();
1003
- }
1004
- return module.cache.element;
1005
- },
1006
- screenCalculations: function() {
1007
- if(module.cache.screen === undefined) {
1008
- module.save.screenCalculations();
1009
- }
1010
- return module.cache.screen;
1011
- },
1012
- screenSize: function() {
1013
- if(module.cache.screen === undefined) {
1014
- module.save.screenSize();
1015
- }
1016
- return module.cache.screen;
1017
- },
1018
- scroll: function() {
1019
- if(module.cache.scroll === undefined) {
1020
- module.save.scroll();
1021
- }
1022
- return module.cache.scroll;
1023
- },
1024
- lastScroll: function() {
1025
- if(module.cache.screen === undefined) {
1026
- module.debug('First scroll event, no last scroll could be found');
1027
- return false;
1028
- }
1029
- return module.cache.screen.top;
1030
- }
1277
+ className: {
1278
+ fixed: 'fixed',
1279
+ placeholder: 'constraint',
1280
+ visible: 'visible',
1031
1281
  },
1032
1282
 
1033
- setting: function(name, value) {
1034
- if( $.isPlainObject(name) ) {
1035
- $.extend(true, settings, name);
1036
- }
1037
- else if(value !== undefined) {
1038
- settings[name] = value;
1039
- }
1040
- else {
1041
- return settings[name];
1042
- }
1043
- },
1044
- internal: function(name, value) {
1045
- if( $.isPlainObject(name) ) {
1046
- $.extend(true, module, name);
1047
- }
1048
- else if(value !== undefined) {
1049
- module[name] = value;
1050
- }
1051
- else {
1052
- return module[name];
1053
- }
1054
- },
1055
- debug: function() {
1056
- if(!settings.silent && settings.debug) {
1057
- if(settings.performance) {
1058
- module.performance.log(arguments);
1059
- }
1060
- else {
1061
- module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1062
- module.debug.apply(console, arguments);
1063
- }
1064
- }
1065
- },
1066
- verbose: function() {
1067
- if(!settings.silent && settings.verbose && settings.debug) {
1068
- if(settings.performance) {
1069
- module.performance.log(arguments);
1070
- }
1071
- else {
1072
- module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1073
- module.verbose.apply(console, arguments);
1074
- }
1075
- }
1283
+ error: {
1284
+ method: 'The method you called is not defined.',
1285
+ visible: 'Element is hidden, you must call refresh after element becomes visible',
1076
1286
  },
1077
- error: function() {
1078
- if(!settings.silent) {
1079
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1080
- module.error.apply(console, arguments);
1081
- }
1082
- },
1083
- performance: {
1084
- log: function(message) {
1085
- var
1086
- currentTime,
1087
- executionTime,
1088
- previousTime
1089
- ;
1090
- if(settings.performance) {
1091
- currentTime = new Date().getTime();
1092
- previousTime = time || currentTime;
1093
- executionTime = currentTime - previousTime;
1094
- time = currentTime;
1095
- performance.push({
1096
- 'Name' : message[0],
1097
- 'Arguments' : [].slice.call(message, 1) || '',
1098
- 'Element' : element,
1099
- 'Execution Time' : executionTime
1100
- });
1101
- }
1102
- clearTimeout(module.performance.timer);
1103
- module.performance.timer = setTimeout(module.performance.display, 500);
1104
- },
1105
- display: function() {
1106
- var
1107
- title = settings.name + ':',
1108
- totalTime = 0
1109
- ;
1110
- time = false;
1111
- clearTimeout(module.performance.timer);
1112
- $.each(performance, function(index, data) {
1113
- totalTime += data['Execution Time'];
1114
- });
1115
- title += ' ' + totalTime + 'ms';
1116
- if(moduleSelector) {
1117
- title += ' \'' + moduleSelector + '\'';
1118
- }
1119
- if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
1120
- console.groupCollapsed(title);
1121
- if(console.table) {
1122
- console.table(performance);
1123
- }
1124
- else {
1125
- $.each(performance, function(index, data) {
1126
- console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
1127
- });
1128
- }
1129
- console.groupEnd();
1130
- }
1131
- performance = [];
1132
- }
1133
- },
1134
- invoke: function(query, passedArguments, context) {
1135
- var
1136
- object = instance,
1137
- maxDepth,
1138
- found,
1139
- response
1140
- ;
1141
- passedArguments = passedArguments || queryArguments;
1142
- context = context || element;
1143
- if(typeof query == 'string' && object !== undefined) {
1144
- query = query.split(/[\. ]/);
1145
- maxDepth = query.length - 1;
1146
- $.each(query, function(depth, value) {
1147
- var camelCaseValue = (depth != maxDepth)
1148
- ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1149
- : query
1150
- ;
1151
- if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
1152
- object = object[camelCaseValue];
1153
- }
1154
- else if( object[camelCaseValue] !== undefined ) {
1155
- found = object[camelCaseValue];
1156
- return false;
1157
- }
1158
- else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
1159
- object = object[value];
1160
- }
1161
- else if( object[value] !== undefined ) {
1162
- found = object[value];
1163
- return false;
1164
- }
1165
- else {
1166
- module.error(error.method, query);
1167
- return false;
1168
- }
1169
- });
1170
- }
1171
- if ( isFunction( found ) ) {
1172
- response = found.apply(context, passedArguments);
1173
- }
1174
- else if(found !== undefined) {
1175
- response = found;
1176
- }
1177
- if(Array.isArray(returnedValue)) {
1178
- returnedValue.push(response);
1179
- }
1180
- else if(returnedValue !== undefined) {
1181
- returnedValue = [returnedValue, response];
1182
- }
1183
- else if(response !== undefined) {
1184
- returnedValue = response;
1185
- }
1186
- return found;
1187
- }
1188
- };
1189
-
1190
- if(methodInvoked) {
1191
- if(instance === undefined) {
1192
- module.initialize();
1193
- }
1194
- instance.save.scroll();
1195
- instance.save.calculations();
1196
- module.invoke(query);
1197
- }
1198
- else {
1199
- if(instance !== undefined) {
1200
- instance.invoke('destroy');
1201
- }
1202
- module.initialize();
1203
- }
1204
- })
1205
- ;
1206
-
1207
- return (returnedValue !== undefined)
1208
- ? returnedValue
1209
- : this
1210
- ;
1211
- };
1212
-
1213
- $.fn.visibility.settings = {
1214
-
1215
- name : 'Visibility',
1216
- namespace : 'visibility',
1217
-
1218
- debug : false,
1219
- verbose : false,
1220
- performance : true,
1221
-
1222
- // whether to use mutation observers to follow changes
1223
- observeChanges : true,
1224
-
1225
- // check position immediately on init
1226
- initialCheck : true,
1227
-
1228
- // whether to refresh calculations after all page images load
1229
- refreshOnLoad : true,
1230
-
1231
- // whether to refresh calculations after page resize event
1232
- refreshOnResize : true,
1233
-
1234
- // should call callbacks on refresh event (resize, etc)
1235
- checkOnRefresh : true,
1236
-
1237
- // callback should only occur one time
1238
- once : true,
1239
-
1240
- // callback should fire continuously when evaluates to true
1241
- continuous : false,
1242
-
1243
- // offset to use with scroll top
1244
- offset : 0,
1245
-
1246
- // whether to include margin in elements position
1247
- includeMargin : false,
1248
-
1249
- // scroll context for visibility checks
1250
- context : window,
1251
-
1252
- // visibility check delay in ms (defaults to animationFrame)
1253
- throttle : false,
1254
-
1255
- // special visibility type (image, fixed)
1256
- type : false,
1257
-
1258
- // z-index to use with visibility 'fixed'
1259
- zIndex : '10',
1260
-
1261
- // image only animation settings
1262
- transition : 'fade in',
1263
- duration : 1000,
1264
-
1265
- // array of callbacks for percentage
1266
- onPassed : {},
1267
-
1268
- // standard callbacks
1269
- onOnScreen : false,
1270
- onOffScreen : false,
1271
- onPassing : false,
1272
- onTopVisible : false,
1273
- onBottomVisible : false,
1274
- onTopPassed : false,
1275
- onBottomPassed : false,
1276
-
1277
- // reverse callbacks
1278
- onPassingReverse : false,
1279
- onTopVisibleReverse : false,
1280
- onBottomVisibleReverse : false,
1281
- onTopPassedReverse : false,
1282
- onBottomPassedReverse : false,
1283
-
1284
- // special callbacks for image
1285
- onLoad : function() {},
1286
- onAllLoaded : function() {},
1287
-
1288
- // special callbacks for fixed position
1289
- onFixed : function() {},
1290
- onUnfixed : function() {},
1291
-
1292
- // utility callbacks
1293
- onUpdate : false, // disabled by default for performance
1294
- onRefresh : function(){},
1295
-
1296
- metadata : {
1297
- src: 'src'
1298
- },
1299
-
1300
- className: {
1301
- fixed : 'fixed',
1302
- placeholder : 'constraint',
1303
- visible : 'visible'
1304
- },
1305
-
1306
- error : {
1307
- method : 'The method you called is not defined.',
1308
- visible : 'Element is hidden, you must call refresh after element becomes visible'
1309
- }
1310
-
1311
- };
1312
1287
 
1313
- })( jQuery, window, document );
1288
+ };
1289
+ })(jQuery, window, document);