diff options
author | nodiscc <nodiscc@gmail.com> | 2015-03-04 23:27:28 +0100 |
---|---|---|
committer | nodiscc <nodiscc@gmail.com> | 2015-03-04 23:27:28 +0100 |
commit | 0e5400e6178468cd0da0b266123545db2a80f707 (patch) | |
tree | f13db75997d25db1cee52da3bd985259863e165b /inc/blazy-1.3.1.js | |
parent | 7572cfbe9620b13569ee47337f7015bcad119332 (diff) | |
parent | 34047d23fb5e09b6bc2728f0f8827eaa038f02ea (diff) | |
download | Shaarli-0e5400e6178468cd0da0b266123545db2a80f707.tar.gz Shaarli-0e5400e6178468cd0da0b266123545db2a80f707.tar.zst Shaarli-0e5400e6178468cd0da0b266123545db2a80f707.zip |
Merge pull request #132 from ArthurHoaro/picwall
Lazy load images with the light lib bLazy.js instead of jQuery
Diffstat (limited to 'inc/blazy-1.3.1.js')
-rw-r--r-- | inc/blazy-1.3.1.js | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/inc/blazy-1.3.1.js b/inc/blazy-1.3.1.js new file mode 100644 index 00000000..cfc2dbde --- /dev/null +++ b/inc/blazy-1.3.1.js | |||
@@ -0,0 +1,232 @@ | |||
1 | /*! | ||
2 | hey, [be]Lazy.js - v1.3.1 - 2015.02.01 | ||
3 | A lazy loading and multi-serving image script | ||
4 | (c) Bjoern Klinggaard - @bklinggaard - http://dinbror.dk/blazy | ||
5 | */ | ||
6 | ;(function(root, blazy) { | ||
7 | if (typeof define === 'function' && define.amd) { | ||
8 | // AMD. Register bLazy as an anonymous module | ||
9 | define(blazy); | ||
10 | } else if (typeof exports === 'object') { | ||
11 | // Node. Does not work with strict CommonJS, but | ||
12 | // only CommonJS-like environments that support module.exports, | ||
13 | // like Node. | ||
14 | module.exports = blazy(); | ||
15 | } else { | ||
16 | // Browser globals. Register bLazy on window | ||
17 | root.Blazy = blazy(); | ||
18 | } | ||
19 | })(this, function () { | ||
20 | 'use strict'; | ||
21 | |||
22 | //vars | ||
23 | var source, options, viewport, images, count, isRetina, destroyed; | ||
24 | //throttle vars | ||
25 | var validateT, saveViewportOffsetT; | ||
26 | |||
27 | // constructor | ||
28 | function Blazy(settings) { | ||
29 | //IE7- fallback for missing querySelectorAll support | ||
30 | if (!document.querySelectorAll) { | ||
31 | var s=document.createStyleSheet(); | ||
32 | document.querySelectorAll = function(r, c, i, j, a) { | ||
33 | a=document.all, c=[], r = r.replace(/\[for\b/gi, '[htmlFor').split(','); | ||
34 | for (i=r.length; i--;) { | ||
35 | s.addRule(r[i], 'k:v'); | ||
36 | for (j=a.length; j--;) a[j].currentStyle.k && c.push(a[j]); | ||
37 | s.removeRule(0); | ||
38 | } | ||
39 | return c; | ||
40 | }; | ||
41 | } | ||
42 | //init vars | ||
43 | destroyed = true; | ||
44 | images = []; | ||
45 | viewport = {}; | ||
46 | //options | ||
47 | options = settings || {}; | ||
48 | options.error = options.error || false; | ||
49 | options.offset = options.offset || 100; | ||
50 | options.success = options.success || false; | ||
51 | options.selector = options.selector || '.b-lazy'; | ||
52 | options.separator = options.separator || '|'; | ||
53 | options.container = options.container ? document.querySelectorAll(options.container) : false; | ||
54 | options.errorClass = options.errorClass || 'b-error'; | ||
55 | options.breakpoints = options.breakpoints || false; | ||
56 | options.successClass = options.successClass || 'b-loaded'; | ||
57 | options.src = source = options.src || 'data-src'; | ||
58 | isRetina = window.devicePixelRatio > 1; | ||
59 | viewport.top = 0 - options.offset; | ||
60 | viewport.left = 0 - options.offset; | ||
61 | //throttle, ensures that we don't call the functions too often | ||
62 | validateT = throttle(validate, 25); | ||
63 | saveViewportOffsetT = throttle(saveViewportOffset, 50); | ||
64 | |||
65 | saveViewportOffset(); | ||
66 | |||
67 | //handle multi-served image src | ||
68 | each(options.breakpoints, function(object){ | ||
69 | if(object.width >= window.screen.width) { | ||
70 | source = object.src; | ||
71 | return false; | ||
72 | } | ||
73 | }); | ||
74 | |||
75 | // start lazy load | ||
76 | initialize(); | ||
77 | } | ||
78 | |||
79 | /* public functions | ||
80 | ************************************/ | ||
81 | Blazy.prototype.revalidate = function() { | ||
82 | initialize(); | ||
83 | }; | ||
84 | Blazy.prototype.load = function(element, force){ | ||
85 | if(!isElementLoaded(element)) loadImage(element, force); | ||
86 | }; | ||
87 | Blazy.prototype.destroy = function(){ | ||
88 | if(options.container){ | ||
89 | each(options.container, function(object){ | ||
90 | unbindEvent(object, 'scroll', validateT); | ||
91 | }); | ||
92 | } | ||
93 | unbindEvent(window, 'scroll', validateT); | ||
94 | unbindEvent(window, 'resize', validateT); | ||
95 | unbindEvent(window, 'resize', saveViewportOffsetT); | ||
96 | count = 0; | ||
97 | images.length = 0; | ||
98 | destroyed = true; | ||
99 | }; | ||
100 | |||
101 | /* private helper functions | ||
102 | ************************************/ | ||
103 | function initialize(){ | ||
104 | // First we create an array of images to lazy load | ||
105 | createImageArray(options.selector); | ||
106 | // Then we bind resize and scroll events if not already binded | ||
107 | if(destroyed) { | ||
108 | destroyed = false; | ||
109 | if(options.container) { | ||
110 | each(options.container, function(object){ | ||
111 | bindEvent(object, 'scroll', validateT); | ||
112 | }); | ||
113 | } | ||
114 | bindEvent(window, 'resize', saveViewportOffsetT); | ||
115 | bindEvent(window, 'resize', validateT); | ||
116 | bindEvent(window, 'scroll', validateT); | ||
117 | } | ||
118 | // And finally, we start to lazy load. Should bLazy ensure domready? | ||
119 | validate(); | ||
120 | } | ||
121 | |||
122 | function validate() { | ||
123 | for(var i = 0; i<count; i++){ | ||
124 | var image = images[i]; | ||
125 | if(elementInView(image) || isElementLoaded(image)) { | ||
126 | Blazy.prototype.load(image); | ||
127 | images.splice(i, 1); | ||
128 | count--; | ||
129 | i--; | ||
130 | } | ||
131 | } | ||
132 | if(count === 0) { | ||
133 | Blazy.prototype.destroy(); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | function loadImage(ele, force){ | ||
138 | // if element is visible | ||
139 | if(force || (ele.offsetWidth > 0 && ele.offsetHeight > 0)) { | ||
140 | var dataSrc = ele.getAttribute(source) || ele.getAttribute(options.src); // fallback to default data-src | ||
141 | if(dataSrc) { | ||
142 | var dataSrcSplitted = dataSrc.split(options.separator); | ||
143 | var src = dataSrcSplitted[isRetina && dataSrcSplitted.length > 1 ? 1 : 0]; | ||
144 | var img = new Image(); | ||
145 | // cleanup markup, remove data source attributes | ||
146 | each(options.breakpoints, function(object){ | ||
147 | ele.removeAttribute(object.src); | ||
148 | }); | ||
149 | ele.removeAttribute(options.src); | ||
150 | img.onerror = function() { | ||
151 | if(options.error) options.error(ele, "invalid"); | ||
152 | ele.className = ele.className + ' ' + options.errorClass; | ||
153 | }; | ||
154 | img.onload = function() { | ||
155 | // Is element an image or should we add the src as a background image? | ||
156 | ele.nodeName.toLowerCase() === 'img' ? ele.src = src : ele.style.backgroundImage = 'url("' + src + '")'; | ||
157 | ele.className = ele.className + ' ' + options.successClass; | ||
158 | if(options.success) options.success(ele); | ||
159 | }; | ||
160 | img.src = src; //preload image | ||
161 | } else { | ||
162 | if(options.error) options.error(ele, "missing"); | ||
163 | ele.className = ele.className + ' ' + options.errorClass; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | function elementInView(ele) { | ||
169 | var rect = ele.getBoundingClientRect(); | ||
170 | |||
171 | return ( | ||
172 | // Intersection | ||
173 | rect.right >= viewport.left | ||
174 | && rect.bottom >= viewport.top | ||
175 | && rect.left <= viewport.right | ||
176 | && rect.top <= viewport.bottom | ||
177 | ); | ||
178 | } | ||
179 | |||
180 | function isElementLoaded(ele) { | ||
181 | return (' ' + ele.className + ' ').indexOf(' ' + options.successClass + ' ') !== -1; | ||
182 | } | ||
183 | |||
184 | function createImageArray(selector) { | ||
185 | var nodelist = document.querySelectorAll(selector); | ||
186 | count = nodelist.length; | ||
187 | //converting nodelist to array | ||
188 | for(var i = count; i--; images.unshift(nodelist[i])){} | ||
189 | } | ||
190 | |||
191 | function saveViewportOffset(){ | ||
192 | viewport.bottom = (window.innerHeight || document.documentElement.clientHeight) + options.offset; | ||
193 | viewport.right = (window.innerWidth || document.documentElement.clientWidth) + options.offset; | ||
194 | } | ||
195 | |||
196 | function bindEvent(ele, type, fn) { | ||
197 | if (ele.attachEvent) { | ||
198 | ele.attachEvent && ele.attachEvent('on' + type, fn); | ||
199 | } else { | ||
200 | ele.addEventListener(type, fn, false); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | function unbindEvent(ele, type, fn) { | ||
205 | if (ele.detachEvent) { | ||
206 | ele.detachEvent && ele.detachEvent('on' + type, fn); | ||
207 | } else { | ||
208 | ele.removeEventListener(type, fn, false); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | function each(object, fn){ | ||
213 | if(object && fn) { | ||
214 | var l = object.length; | ||
215 | for(var i = 0; i<l && fn(object[i], i) !== false; i++){} | ||
216 | } | ||
217 | } | ||
218 | |||
219 | function throttle(fn, minDelay) { | ||
220 | var lastCall = 0; | ||
221 | return function() { | ||
222 | var now = +new Date(); | ||
223 | if (now - lastCall < minDelay) { | ||
224 | return; | ||
225 | } | ||
226 | lastCall = now; | ||
227 | fn.apply(images, arguments); | ||
228 | }; | ||
229 | } | ||
230 | |||
231 | return Blazy; | ||
232 | }); | ||