1
+ /*
2
+ * Lazy Load - for lazy loading images without jQuery
3
+ */
4
+
5
+ var lazyLoad = ( function ( window , document , undefined ) {
6
+
7
+ var _elements ,
8
+ _settings ,
9
+ _processedElements = [ ] ,
10
+ _defaultSettings = {
11
+ threshold : 0 ,
12
+ failure_limit : 0 ,
13
+ event : "scroll" ,
14
+ effect : "show" ,
15
+ container : window ,
16
+ src_data_attribute : "original" ,
17
+ //skip_invisible: true, // TODO: Restore this
18
+ show_while_loading : false ,
19
+ process_callback : null ,
20
+ load_callback : null ,
21
+ set_callback : null ,
22
+ placeholder : "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
23
+ } ,
24
+ _supportsAddEventListener = ! ! window . addEventListener ;
25
+
26
+ function _getOffset ( element ) {
27
+ var theBox = element . getBoundingClientRect ( ) ,
28
+ documentElement = element . ownerDocument . documentElement ;
29
+ return {
30
+ top : theBox . top + window . pageYOffset - documentElement . clientTop ,
31
+ left : theBox . left + window . pageXOffset - documentElement . clientLeft
32
+ } ;
33
+ }
34
+
35
+ function _getDocumentWidth ( ) {
36
+ return window . innerWidth || ( document . documentElement . clientWidth || document . body . clientWidth ) ; //Math.max(visibleWidth, document.body.scrollWidth);
37
+ }
38
+
39
+ function _getDocumentHeight ( ) {
40
+ return window . innerHeight || ( document . documentElement . clientHeight || document . body . clientHeight ) ; //Math.max(visibleHeight, document.body.scrollHeight);
41
+ }
42
+
43
+ function _isBelowViewport ( element ) {
44
+ var fold ,
45
+ container = _settings . container ;
46
+
47
+ if ( container === undefined || container === window ) {
48
+ fold = _getDocumentHeight ( ) + window . pageYOffset ;
49
+ } else {
50
+ fold = _getOffset ( container ) . top + container . offsetHeight ;
51
+ }
52
+
53
+ return fold <= _getOffset ( element ) . top - _settings . threshold ;
54
+ }
55
+
56
+ function _isAtRightOfViewport ( element ) {
57
+ var fold ,
58
+ container = _settings . container ;
59
+
60
+ if ( container === undefined || container === window ) {
61
+ fold = _getDocumentWidth ( ) + window . pageXOffset ;
62
+ } else {
63
+ fold = _getOffset ( container ) . left + _getDocumentWidth ( ) ;
64
+ }
65
+
66
+ return fold <= _getOffset ( element ) . left - _settings . threshold ;
67
+ }
68
+
69
+ function _isAboveViewport ( element ) {
70
+ var fold ,
71
+ container = _settings . container ;
72
+
73
+ if ( container === undefined || container === window ) {
74
+ fold = window . pageYOffset ;
75
+ } else {
76
+ fold = _getOffset ( container ) . top ;
77
+ }
78
+
79
+ return fold >= _getOffset ( element ) . top + _settings . threshold + element . offsetHeight ;
80
+ }
81
+
82
+ function _isAtLeftOfViewport ( element ) {
83
+ var fold ,
84
+ container = _settings . container ;
85
+
86
+ if ( container === undefined || container === window ) {
87
+ fold = window . pageXOffset ;
88
+ } else {
89
+ fold = _getOffset ( container ) . left ;
90
+ }
91
+
92
+ return fold >= _getOffset ( element ) . left + _settings . threshold + element . offsetWidth ;
93
+ }
94
+
95
+ function _merge_options ( obj1 , obj2 ) {
96
+ var obj3 = { } , propertyName ;
97
+ for ( propertyName in obj1 ) {
98
+ if ( obj1 . hasOwnProperty ( propertyName ) ) {
99
+ obj3 [ propertyName ] = obj1 [ propertyName ] ;
100
+ }
101
+ }
102
+ for ( propertyName in obj2 ) {
103
+ if ( obj2 . hasOwnProperty ( propertyName ) ) {
104
+ obj3 [ propertyName ] = obj2 [ propertyName ] ;
105
+ }
106
+ }
107
+ return obj3 ;
108
+ }
109
+
110
+ function _getOriginalSrc ( element ) {
111
+ var dataAttributeContent ;
112
+ dataAttributeContent = element . getAttribute ( 'data-' + _settings . src_data_attribute ) ;
113
+ return dataAttributeContent || _settings . placeholder ;
114
+ }
115
+
116
+ function _setImageAndDisplay ( element ) {
117
+ /* Setting `src` in the original `img` */
118
+ var original = _getOriginalSrc ( element ) ;
119
+ if ( element . nodeName . toLowerCase ( ) === "img" ) {
120
+ element . setAttribute ( "src" , original ) ;
121
+ } else {
122
+ element . style . backgroundImage = "url('" + original + "')" ;
123
+ }
124
+ _callCallback ( element , "set_callback" ) ;
125
+ }
126
+
127
+ function _callCallback ( element , callbackName ) {
128
+ if ( _settings [ callbackName ] ) {
129
+ _settings [ callbackName ] . call ( element , _elements . length , _settings ) ;
130
+ }
131
+ }
132
+
133
+ function _showOnLoad ( element ) {
134
+
135
+ var fakeImg ;
136
+
137
+ /* If no src attribute given use data:uri. */
138
+ if ( ! element . getAttribute ( "src" ) ) {
139
+ element . setAttribute ( "src" , _settings . placeholder ) ;
140
+ }
141
+ /* Creating a new `img` in a DOM fragment. */
142
+ fakeImg = document . createElement ( 'img' ) ;
143
+ /* Listening to the load event */
144
+ if ( _supportsAddEventListener ) {
145
+ fakeImg . addEventListener ( "load" , function ( ) {
146
+ _callCallback ( element , "load_callback" ) ;
147
+ _setImageAndDisplay ( element ) ;
148
+ fakeImg . removeEventListener ( "load" ) ;
149
+ } ) ;
150
+ }
151
+ else {
152
+ // TODO: fallback for IE<9
153
+ }
154
+ /* Setting the source in the fake image */
155
+ fakeImg . setAttribute ( "src" , _getOriginalSrc ( element ) ) ;
156
+ }
157
+
158
+ function _showOnAppear ( element ) {
159
+ if ( _supportsAddEventListener ) {
160
+ element . addEventListener ( "load" , function ( ) {
161
+ _callCallback ( element , "load_callback" ) ;
162
+ element . removeEventListener ( "load" ) ;
163
+ } ) ;
164
+ }
165
+ else {
166
+ // TODO: fallback for IE<9
167
+ }
168
+ _setImageAndDisplay ( element ) ;
169
+ }
170
+
171
+ function _processImage ( element ) {
172
+ //if (-1 === _processedElements.indexOf(element)) { // TODO: This check is necessary? (evaluate not only the scroll event case)
173
+ _callCallback ( element , "process_callback" ) ;
174
+ /* Forking behaviour depending on show_while_loading (true value is ideal for progressive jpeg). */
175
+ if ( _settings . show_while_loading ) {
176
+ _showOnAppear ( element ) ;
177
+ } else {
178
+ _showOnLoad ( element ) ;
179
+ }
180
+ /* Marking the element as processed so is not processed next time. */
181
+ _processedElements . push ( element ) ;
182
+ //}
183
+ }
184
+
185
+ function _purgeElementsArray ( ) {
186
+ _processedElements . forEach ( function ( element ) {
187
+ var indexOfProcessedElement = _elements . indexOf ( element ) ;
188
+ if ( indexOfProcessedElement === - 1 ) return ;
189
+ _elements . splice ( indexOfProcessedElement , 1 ) ;
190
+ } ) ;
191
+ _processedElements = [ ] ;
192
+ }
193
+
194
+ return {
195
+ initialize : function ( elements , options ) {
196
+ _elements = Array . prototype . slice . call ( elements , 0 ) ;
197
+ _settings = _merge_options ( _defaultSettings , options ) ;
198
+
199
+ if ( _supportsAddEventListener ) {
200
+ /* If event is scroll, add scroll event listener in the container (not in every single image) */
201
+ if ( 0 === _settings . event . indexOf ( "scroll" ) ) {
202
+ _settings . container . addEventListener ( _settings . event , function ( ) {
203
+ return lazyLoad . update ( ) ;
204
+ } ) ;
205
+ }
206
+ /* If event is not, add event listener every single image */
207
+ else {
208
+ _elements . forEach ( function ( element ) {
209
+ element . addEventListener ( _settings . event , function ( ) {
210
+ _processImage ( element ) ;
211
+ } ) ;
212
+ } ) ;
213
+ }
214
+ }
215
+ else {
216
+ // TODO: fallback for IE<9
217
+ }
218
+
219
+ lazyLoad . update ( ) ;
220
+ } ,
221
+ update : function ( ) {
222
+ var countBeforeFail = 0 ;
223
+ _elements . forEach ( function ( element ) {
224
+
225
+ // TODO: Find a way to replicate "isVisible"
226
+ /*if (_settings.skip_invisible && !$this.is(":visible")) {
227
+ return;
228
+ }*/
229
+
230
+ if ( _isAboveViewport ( element ) ||
231
+ _isAtLeftOfViewport ( element ) ) {
232
+ /* Nothing. */
233
+ } else if ( ! _isBelowViewport ( element ) && ! _isAtRightOfViewport ( element ) ) {
234
+ _processImage ( element ) ;
235
+ /* If we found an image we'll load, reset the counter */
236
+ countBeforeFail = 0 ;
237
+ } else {
238
+ if ( ++ countBeforeFail > _settings . failure_limit ) {
239
+ // This should break the forEach, does it?
240
+ return false ;
241
+ }
242
+ }
243
+ } ) ;
244
+
245
+ _purgeElementsArray ( ) ;
246
+ }
247
+ } ;
248
+
249
+ } ( window , document ) ) ;
0 commit comments