1/*jslint browser: true, eqeqeq: true, bitwise: true, newcap: true, immed: true, regexp: false */ 2 3/** 4LazyLoad makes it easy and painless to lazily load one or more external 5JavaScript or CSS files on demand either during or after the rendering of a web 6page. 7 8Supported browsers include Firefox 3.6+, IE9+, Safari 5.1.4+ (untested) (including Mobile 9Safari), Google Chrome 10+, and Opera 12+. Other browsers may or may not work and 10are not officially supported, including the browsers supported by the original LazyLoad: 11Firefox 2+, IE6+, Safari 3+, Google Chrome 0.8+, and Opera 9+ (not yet tested). 12 13Visit https://github.com/lewisje/lazyload/ for more info. 14 15Copyright (c) 2011 Ryan Grove <[email protected]> 16All rights reserved. 17Changes made by Cezary Daniel Nowak, 2014, and James Edward Lewis II, 2015. 18 19Permission is hereby granted, free of charge, to any person obtaining a copy of 20this software and associated documentation files (the 'Software'), to deal in 21the Software without restriction, including without limitation the rights to 22use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 23the Software, and to permit persons to whom the Software is furnished to do so, 24subject to the following conditions: 25 26The above copyright notice and this permission notice shall be included in all 27copies or substantial portions of the Software. 28 29THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 31FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 32COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 33IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35 36@module lazyload 37@class LazyLoad 38@static 39*/ 40 41var LazyLoad = (function (doc) { 42 'use strict'; 43 // -- Private Variables ------------------------------------------------------ 44 45 // Reference to the <head> element (populated lazily). 46 var head, 47 48 // Requests currently in progress, if any. 49 pending = {}, 50 51 // Number of times we've polled to check whether a pending stylesheet has 52 // finished loading. If this gets too high, we're probably stalled. 53 pollCount = 0, 54 55 // Cached requests. 56 cache = {}, 57 58 // Queued requests. 59 queue = {css: [], js: []}, 60 61 // Whether Function#bind exists. 62 canBind = typeof Function.prototype.bind === 'function', 63 64 // Reference to the browser's list of stylesheets. 65 styleSheets = doc.styleSheets, 66 finishCSS = canBind ? finish.bind(doc, 'css') : function finishCSS() {finish('css');}, 67 ua = navigator.userAgent, 68 // User agent and feature test information. 69 env = { 70 // True if this browser supports disabling async mode on dynamically 71 // created script nodes. See 72 // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order 73 async: createNode('script').async === true 74 }; 75 76 if (/AppleWebKit\//.test(ua)) env.webkit = true; 77 else if (/MSIE|Trident/.test(ua)) env.ie = true; 78 else if (/Opera/.test(ua)) env.opera = true; 79 else if (/Gecko\//.test(ua)) env.gecko = true; 80 else env.unknown = true; 81 // -- Private Methods -------------------------------------------------------- 82 83 /** 84 Creates and returns an HTML element with the specified name and attributes. 85 86 @method createNode 87 @param {String} name element name 88 @param {Object} attrs name/value mapping of element attributes 89 @return {HTMLElement} 90 @private 91 */ 92 function createNode(name, attrs) { 93 var attr, 94 node = doc.createElement(name); 95 96 if(attrs) { 97 for (attr in attrs) { 98 if (attrs.hasOwnProperty(attr)) { 99 node.setAttribute(attr, attrs[attr]); 100 } 101 } 102 } 103 104 return node; 105 } 106 107 /** 108 Called when the current pending resource of the specified type has finished 109 loading. Executes the associated callback (if any) and loads the next 110 resource in the queue. 111 112 @method finish 113 @param {String} type resource type ('css' or 'js') 114 @private 115 */ 116 function finish(type) { 117 var p = pending[type], callback, urls; 118 119 if (p) { 120 callback = p.callback; 121 urls = p.urls; 122 123 cache[urls.shift()] = true; 124 pollCount = 0; 125 126 // If this is the last of the pending URLs, execute the callback and 127 // start the next request in the queue (if any). 128 if (!urls.length) { 129 if (typeof callback === 'function') callback.call(p.context, p.obj); 130 pending[type] = 0; 131 if (queue[type].length) load(type); 132 } 133 } 134 } 135 136 /** 137 Loads the specified resources, or the next resource of the specified type 138 in the queue if no resources are specified. If a resource of the specified 139 type is already being loaded, the new request will be queued until the 140 first request has been finished. 141 142 When an array of resource URLs is specified, those URLs will be loaded in 143 parallel if it is possible to do so while preserving execution order. All 144 browsers support parallel loading of CSS, but only Firefox and Opera 145 support parallel loading of scripts. In other browsers, scripts will be 146 queued and loaded one at a time to ensure correct execution order. 147 148 @method load 149 @param {String} type resource type ('css' or 'js') 150 @param {String|Array} urls (optional) URL or array of URLs to load 151 @param {Function} callback (optional) callback function to execute when the 152 resource is loaded 153 @param {Object} obj (optional) object to pass to the callback function 154 @param {Object} context (optional) if provided, the callback function will 155 be executed in this object's context 156 @private 157 */ 158 function load(type, urls, callback, obj, context) { 159 var _finish = canBind ? finish.bind(doc, type) : function _finish() {finish(type);}, 160 isCSS = type === 'css', nodes = [], i, len, node, p, pendingUrls, url; 161 162 if (urls) { 163 // If urls is a string, wrap it in an array. Otherwise assume it's an 164 // array and create a copy of it so modifications won't be made to the 165 // original. 166 urls = typeof urls === 'string' ? [urls] : urls.slice(); 167 168 // Create a request object for each URL. If multiple URLs are specified, 169 // the callback will only be executed after all URLs have been loaded. 170 // 171 // Sadly, Firefox and Opera are the only browsers capable of loading 172 // scripts in parallel while preserving execution order. In all other 173 // browsers, scripts must be loaded sequentially. 174 // 175 // All browsers respect CSS specificity based on the order of the link 176 // elements in the DOM, regardless of the order in which the stylesheets 177 // are actually downloaded.
178 if (isCSS || env.async || env.gecko || env.opera) { 179 // Load in parallel. 180 queue[type].push({ 181 urls : urls, 182 callback: callback, 183 obj : obj, 184 context : context 185 }); 186 } else { 187 // Load sequentially. 188 for (i = 0, len = urls.length; i < len; ++i) { 189 queue[type].push({ 190 urls : [urls[i]], 191 callback: i === len - 1 ? callback : 0, // callback is only added to the last URL 192 obj : obj, 193 context : context 194 }); 195 } 196 } 197 } 198 199 // If a previous load request of this type is currently in progress, we'll 200 // wait our turn. Otherwise, grab the next item in the queue. 201 if (pending[type] || !(p = pending[type] = queue[type].shift())) return; 202 head = head || doc.head || doc.getElementsByTagName('head')[0]; 203 pendingUrls = p.urls.slice(); 204 205 var nodeReady = function nodeReady() { 206 if (/^(?:loaded|complete)$/i.test(node.readyState)) { 207 node.onreadystatechange = null; 208 _finish(); 209 } 210 }; 211 for (i = 0, len = pendingUrls.length; i < len; ++i) { 212 url = pendingUrls[i]; 213 if(cache[url] != null && !url.startsWith("var/theme/custom.css")) { 214 // _finish here can cause unexpected behavior when cache[url] === false but 215 // I won't figure out solution, since first issue on github :-) 216 _finish(); 217 continue; //prevent scripts/css from being loaded multiple times 218 } else { 219 cache[url] = false; 220 } 221 if (isCSS) { 222 node = env.gecko ? createNode('style') : createNode('link', { 223 href: url, 224 rel : 'stylesheet' 225 }); 226 } else { 227 node = createNode('script', {src: url}); 228 node.async = false; 229 } 230 231 node.className = 'lazyload'; 232 node.setAttribute('charset', 'utf-8'); 233 234 if (env.ie && !isCSS && 'onreadystatechange' in node && !('draggable' in node)) { 235 node.onreadystatechange = nodeReady; 236 } else if (isCSS && (env.gecko || env.webkit)) { 237 // Gecko and WebKit don't support the onload event on link nodes. 238 if (env.webkit) { 239 // In WebKit, we can poll for changes to document.styleSheets to 240 // figure out when stylesheets have loaded. 241 p.urls[i] = node.href; // resolve relative URLs (or polling won't work) 242 pollWebKit(); 243 } else { 244 // In Gecko, we can import the requested URL into a <style> node and 245 // poll for the existence of node.sheet.cssRules. Props to Zach 246 // Leatherman for calling my attention to this technique. 247 node.innerHTML = '@import "' + url + '";'; 248 pollGecko(node); 249 } 250 } else { 251 node.onload = node.onerror = _finish; 252 } 253 nodes.push(node); 254 } 255 for (i = 0, len = nodes.length; i < len; ++i) { 256 head.appendChild(nodes[i]); 257 } 258 } 259 260 /** 261 Begins polling to determine when the specified stylesheet has finished loading 262 in Gecko. Polling stops when all pending stylesheets have loaded or after 10 263 seconds (to prevent stalls). 264 265 Thanks to Zach Leatherman for calling my attention to the @import-based 266 cross-domain technique used here, and to Oleg Slobodskoi for an earlier 267 same-domain implementation. See Zach's blog for more details: 268 http://www.zachleat.com/web/2010/07/29/load-css-dynamically/ 269 270 @method pollGecko 271 @param {HTMLElement} node Style node to poll. 272 @private 273 */ 274 function pollGecko(node) { 275 var hasRules = 'sheet' in node && node.sheet && 'cssRules' in node.sheet; 276 277 if (!hasRules) { 278 // The stylesheet is still loading. 279 ++pollCount; 280 if (pollCount < 200) { 281 setTimeout(canBind ? pollGecko.bind(doc, node) : function pollBind() {pollGecko(node);}, 50); 282 } else { 283 // We've been polling for 10 seconds and nothing's happened. Stop 284 // polling and finish the pending requests to avoid blocking further 285 // requests. 286 if (hasRules) finishCSS(); 287 } 288 return; 289 } 290 // If we get here, the stylesheet has loaded. 291 finishCSS(); 292 } 293 294 /** 295 Begins polling to determine when pending stylesheets have finished loading 296 in WebKit. Polling stops when all pending stylesheets have loaded or after 10 297 seconds (to prevent stalls). 298 299 @method pollWebKit 300 @private 301 */ 302 function pollWebKit() { 303 var css = pending.css, i; 304 305 if (css) { 306 i = styleSheets.length; 307 // Look for a stylesheet matching the pending URL. 308 while (--i >= 0) { 309 if (styleSheets[i].href === css.urls[0]) { 310 finishCSS(); 311 break; 312 } 313 } 314 315 ++pollCount; 316 if (css) { 317 if (pollCount < 200) { 318 setTimeout(pollWebKit, 50); 319 } else { 320 // We've been polling for 10 seconds and nothing's happened, which may 321 // indicate that the stylesheet has been removed from the document 322 // before it had a chance to load. Stop polling and finish the pending 323 // request to prevent blocking further requests. 324 finishCSS(); 325 } 326 } 327 } 328 } 329 330 return { 331 /** 332 Requests the specified CSS URL or URLs and executes the specified 333 callback (if any) when they have finished loading. If an array of URLs is 334 specified, the stylesheets will be loaded in parallel and the callback 335 will be executed after all stylesheets have finished loading. 336 337 @method css 338 @param {String|Array} urls CSS URL or array of CSS URLs to load 339 @param {Function} callback (optional) callback function to execute when 340 the specified stylesheets are loaded 341 @static 342 */ 343 css: canBind ? load.bind(load, 'css') : function css(urls, callback, obj, context) { 344 load('css', urls, callback, obj, context); 345 }, 346 347 /** 348 Requests the specified JavaScript URL or URLs and executes the specified 349 callback (if any) when they have finished loading. If an array of URLs is 350 specified and the browser supports it, the scripts will be loaded in 351 parallel and the callback will be executed after all scripts have 352 finished loading. 353
354 Currently, only Firefox and Opera support parallel loading of scripts while 355 preserving execution order. In other browsers, scripts will be 356 queued and loaded one at a time to ensure correct execution order. 357 358 @method js 359 @param {String|Array} urls JS URL or array of JS URLs to load 360 @param {Function} callback (optional) callback function to execute when 361 the specified scripts are loaded 362 @static 363 */ 364 js: canBind ? load.bind(load, 'js') : function js(urls, callback, obj, context) { 365 load('js', urls, callback, obj, context); 366 } 367 }; 368})(this.document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.