diff --git a/static/third/lazyload/HISTORY b/static/third/lazyload/HISTORY new file mode 100644 index 0000000000..8955c4a701 --- /dev/null +++ b/static/third/lazyload/HISTORY @@ -0,0 +1,68 @@ +LazyLoad Changelog +================================================================================ + +Version 2.0.3 (2011-07-05) + * Fixed a bug caused by an unwanted Closure Compiler optimization that broke + CSS load completion detection in Gecko when using the minified version of + LazyLoad. [Allex Wang] + * Fixed a race condition in which a URL could be removed from the "pending" + queue if it finished loading before other URLs in the same batch had been + added to the queue, resulting in the queue's length changing unexpectedly + during iteration. [Klaas Neirinck] + +Version 2.0.2 (2011-04-17) + * Added support for reliable detection of CSS load completion in Gecko + browsers based on a technique described by Zach Leatherman at + . + * Fixed a bug that prevented CSS load completion from being detected in WebKit + when there were no other stylesheets on the page. [Klaas Neirinck] + * Fixed a bug that could prevent CSS callbacks from being called in IE. + +Version 2.0.1 (2011-03-05) + * Added support for async=false. This ensures that parallel script loading + still works in Firefox 4 while preserving execution order. For more info, + see . + * Stylesheet load completion is now detected reliably in WebKit by polling + document.styleSheets for changes. Thanks to Jonathan Cook for suggesting + this solution. + * Dynamically created script and link nodes are now given a "lazyload" class + so they can be identified later. + * The charset for dynamically created script and link nodes is set to "utf-8". + +Version 2.0.0 (2009-08-06) + * Added support for CSS. Caveat: Gecko and WebKit don't support the onload + event for link nodes, so the CSS callback will fire almost immediately in + those browsers. + * When an array of URLs is specified, the resources will be loaded in parallel + in browsers that support it. Currently, all browsers support loading CSS in + parallel, but only Gecko and Opera support parallel scripts while preserving + execution order. + * The load() method has been replaced by css() and js() methods for loading + CSS and JS, respectively. + * The loadOnce() method has been removed, since it wasn't terribly useful. + * Improved reliability in all supported browsers. + +Version 1.0.4 (2008-07-24) + * Improved reliability with all supported browsers. + * Reduced the minified size to 1751 bytes (a whopping 67 bytes smaller than + version 1.0.3). + * Fixed a bug that caused the load completion callback to fire immediately in + Safari 3.x. + * Fixed a bug that caused the load completion callback to fail to fire in + Internet Explorer if the script was loaded from the cache. + +Version 1.0.3 (2007-06-18) + * Added "force" parameter to the loadOnce() method to force execution of the + callback even when all specified scripts have already been loaded. + +Version 1.0.2 (2007-06-02) + * Improved browser detection. + * Switched to NaturalDocs for source documentation. + +Version 1.0.1 (2007-05-30) + * Fixed potential race condition when load() is called multiple times in + succession. + * Refactored to reduce complexity. + +Version 1.0.0 (2007-05-29) + * First release. diff --git a/static/third/lazyload/LICENSE b/static/third/lazyload/LICENSE new file mode 100644 index 0000000000..cf4690b1cb --- /dev/null +++ b/static/third/lazyload/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011 Ryan Grove +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/static/third/lazyload/README.md b/static/third/lazyload/README.md new file mode 100644 index 0000000000..bc98a61c7c --- /dev/null +++ b/static/third/lazyload/README.md @@ -0,0 +1,97 @@ +LazyLoad +======== + +LazyLoad is a tiny (only 966 bytes minified and gzipped), dependency-free +JavaScript utility that makes it super easy to load external JavaScript and CSS +files on demand. + +Whenever possible, LazyLoad will automatically load resources in parallel while +ensuring execution order when you specify an array of URLs to load. In browsers +that don't preserve the execution order of asynchronously-loaded scripts, +LazyLoad will safely load the scripts sequentially. + +Use LazyLoad when you need a small, fast, safe dynamic JS or CSS loader, but +don't need the overhead of dependency management or other extra functionality +that larger script loaders provide. + +Downloads +--------- + + * [lazyload.js](https://github.com/rgrove/lazyload/raw/master/lazyload.js) (full source) + +Usage +----- + +Using LazyLoad is simple. Just call the appropriate method -- `css()` to load +CSS, `js()` to load JavaScript -- and pass in a URL or array of URLs to load. +You can also provide a callback function if you'd like to be notified when the +resources have finished loading, as well as an argument to pass to the callback +and a context in which to execute the callback. + +```js +// Load a single JavaScript file and execute a callback when it finishes. +LazyLoad.js('http://example.com/foo.js', function () { + alert('foo.js has been loaded'); +}); + +// Load multiple JS files and execute a callback when they've all finished. +LazyLoad.js(['foo.js', 'bar.js', 'baz.js'], function () { + alert('all files have been loaded'); +}); + +// Load a CSS file and pass an argument to the callback function. +LazyLoad.css('foo.css', function (arg) { + alert(arg); +}, 'foo.css has been loaded'); + +// Load a CSS file and execute the callback in a different scope. +LazyLoad.css('foo.css', function () { + alert(this.foo); // displays 'bar' +}, null, {foo: 'bar'}); +``` + +Supported Browsers +------------------ + + * Firefox 2+ + * Google Chrome + * Internet Explorer 6+ + * Opera 9+ + * Safari 3+ + * Mobile Safari + * Android + +Other browsers may work, but haven't been tested. It's a safe bet that anything +based on a recent version of Gecko or WebKit will probably work. + +Caveats +------- + +All browsers support parallel loading of CSS. However, only Firefox and Opera +currently support parallel script loading while preserving execution order. To +ensure that scripts are always executed in the correct order, LazyLoad will load +all scripts sequentially in browsers other than Firefox and Opera. Hopefully +other browsers will improve their parallel script loading behavior soon. + +License +------- + +Copyright (c) 2011 Ryan Grove (ryan@wonko.com). +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/static/third/lazyload/lazyload.js b/static/third/lazyload/lazyload.js new file mode 100644 index 0000000000..3985f30973 --- /dev/null +++ b/static/third/lazyload/lazyload.js @@ -0,0 +1,390 @@ +/*jslint browser: true, eqeqeq: true, bitwise: true, newcap: true, immed: true, regexp: false */ + +/** +LazyLoad makes it easy and painless to lazily load one or more external +JavaScript or CSS files on demand either during or after the rendering of a web +page. + +Supported browsers include Firefox 2+, IE6+, Safari 3+ (including Mobile +Safari), Google Chrome, and Opera 9+. Other browsers may or may not work and +are not officially supported. + +Visit https://github.com/rgrove/lazyload/ for more info. + +Copyright (c) 2011 Ryan Grove +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the 'Software'), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@module lazyload +@class LazyLoad +@static +*/ + +LazyLoad = (function (doc) { + // -- Private Variables ------------------------------------------------------ + + // User agent and feature test information. + var env, + + // Reference to the element (populated lazily). + head, + + // Requests currently in progress, if any. + pending = {}, + + // Number of times we've polled to check whether a pending stylesheet has + // finished loading. If this gets too high, we're probably stalled. + pollCount = 0, + + // Queued requests. + queue = {css: [], js: []}, + + // Reference to the browser's list of stylesheets. + styleSheets = doc.styleSheets; + + // -- Private Methods -------------------------------------------------------- + + /** + Creates and returns an HTML element with the specified name and attributes. + + @method createNode + @param {String} name element name + @param {Object} attrs name/value mapping of element attributes + @return {HTMLElement} + @private + */ + function createNode(name, attrs) { + var node = doc.createElement(name), attr; + + for (attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + node.setAttribute(attr, attrs[attr]); + } + } + + return node; + } + + /** + Called when the current pending resource of the specified type has finished + loading. Executes the associated callback (if any) and loads the next + resource in the queue. + + @method finish + @param {String} type resource type ('css' or 'js') + @private + */ + function finish(type) { + var p = pending[type], + callback, + urls; + + if (p) { + callback = p.callback; + urls = p.urls; + + urls.shift(); + pollCount = 0; + + // If this is the last of the pending URLs, execute the callback and + // start the next request in the queue (if any). + if (!urls.length) { + callback && callback.call(p.context, p.obj); + pending[type] = null; + queue[type].length && load(type); + } + } + } + + /** + Populates the env variable with user agent and feature test + information. + + @method getEnv + @private + */ + function getEnv() { + var ua = navigator.userAgent; + + env = { + // True if this browser supports disabling async mode on dynamically + // created script nodes. See + // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order + async: doc.createElement('script').async === true + }; + + (env.webkit = /AppleWebKit\//.test(ua)) + || (env.ie = /MSIE|Trident/.test(ua)) + || (env.opera = /Opera/.test(ua)) + || (env.gecko = /Gecko\//.test(ua)) + || (env.unknown = true); + } + + /** + Loads the specified resources, or the next resource of the specified type + in the queue if no resources are specified. If a resource of the specified + type is already being loaded, the new request will be queued until the + first request has been finished. + + When an array of resource URLs is specified, those URLs will be loaded in + parallel if it is possible to do so while preserving execution order. All + browsers support parallel loading of CSS, but only Firefox and Opera + support parallel loading of scripts. In other browsers, scripts will be + queued and loaded one at a time to ensure correct execution order. + + @method load + @param {String} type resource type ('css' or 'js') + @param {String|Array} urls (optional) URL or array of URLs to load + @param {Function} callback (optional) callback function to execute when the + resource is loaded + @param {Object} obj (optional) object to pass to the callback function + @param {Object} context (optional) if provided, the callback function will + be executed in this object's context + @private + */ + function load(type, urls, callback, obj, context) { + var _finish = function () { finish(type); }, + isCSS = type === 'css', + nodes = [], + i, len, node, p, pendingUrls, url; + + env || getEnv(); + + if (urls) { + // If urls is a string, wrap it in an array. Otherwise assume it's an + // array and create a copy of it so modifications won't be made to the + // original. + urls = typeof urls === 'string' ? [urls] : urls.concat(); + + // Create a request object for each URL. If multiple URLs are specified, + // the callback will only be executed after all URLs have been loaded. + // + // Sadly, Firefox and Opera are the only browsers capable of loading + // scripts in parallel while preserving execution order. In all other + // browsers, scripts must be loaded sequentially. + // + // All browsers respect CSS specificity based on the order of the link + // elements in the DOM, regardless of the order in which the stylesheets + // are actually downloaded. + if (isCSS || env.async || env.gecko || env.opera) { + // Load in parallel. + queue[type].push({ + urls : urls, + callback: callback, + obj : obj, + context : context + }); + } else { + // Load sequentially. + for (i = 0, len = urls.length; i < len; ++i) { + queue[type].push({ + urls : [urls[i]], + callback: i === len - 1 ? callback : null, // callback is only added to the last URL + obj : obj, + context : context + }); + } + } + } + + // If a previous load request of this type is currently in progress, we'll + // wait our turn. Otherwise, grab the next item in the queue. + if (pending[type] || !(p = pending[type] = queue[type].shift())) { + return; + } + + head || (head = doc.head || doc.getElementsByTagName('head')[0]); + pendingUrls = p.urls; + + for (i = 0, len = pendingUrls.length; i < len; ++i) { + url = pendingUrls[i]; + + if (isCSS) { + node = env.gecko ? createNode('style') : createNode('link', { + href: url, + rel : 'stylesheet' + }); + } else { + node = createNode('script', {src: url}); + node.async = false; + } + + node.className = 'lazyload'; + node.setAttribute('charset', 'utf-8'); + + if (env.ie && !isCSS && 'onreadystatechange' in node && !('draggable' in node)) { + node.onreadystatechange = function () { + if (/loaded|complete/.test(node.readyState)) { + node.onreadystatechange = null; + _finish(); + } + }; + } else if (isCSS && (env.gecko || env.webkit)) { + // Gecko and WebKit don't support the onload event on link nodes. + if (env.webkit) { + // In WebKit, we can poll for changes to document.styleSheets to + // figure out when stylesheets have loaded. + p.urls[i] = node.href; // resolve relative URLs (or polling won't work) + pollWebKit(); + } else { + // In Gecko, we can import the requested URL into a