add lisp packages

This commit is contained in:
2020-12-05 21:29:49 +01:00
parent 85e20365ae
commit a6e2395755
7272 changed files with 1363243 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/node:10.6.0
working_directory: ~/repo
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: yarn install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}
# run tests!
- run: yarn test

View File

@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: amorey

View File

@@ -0,0 +1,6 @@
Authors ordered by first contribution.
Andres Morey <andresmarcel@gmail.com>
revyh https://github.com/revyh
Ryan Burke https://github.com/codeburke
Todd Williams https://github.com/toddw

View File

@@ -0,0 +1,116 @@
# LoadJS Changelog
## 4.2.0 - December 1, 2019
* Added support for .webp image extensions
## 4.0.1 - September 25, 2019
* Removed unnecessary console.log() statement
## 4.0.0 - September 25, 2019
* Added support for automatic image and css detection on urls with with query arguments and anchor tags
## 3.6.1 - April 11, 2019
* Upgraded devDependencies
* Fixed issue with source code documentation (https://github.com/muicss/loadjs/issues/88)
## 3.6.0 - March 14, 2019
* Bugfix for IE Edge CSS file cross-domain onerror detection
* Added support for Promises via `returnPromise` option
## 3.5.5 - December 8, 2018
* Bugfix for IE Edge CSS file cross-domain SecurityError
## 3.5.4 - March 28, 2018
* Added support for loading images
## 3.5.3 - March 21, 2018
* Updated documentation
## 3.5.2 - January 10, 2018
* Added support for success function as callback argument
## 3.5.1 - August 9, 2017
* Upgraded devDependencies and re-built payload
## 3.5.0 - March 28, 2017
* Added support for "css!" prefix to force treating file as stylesheet
* Added support for DOM insertion bypass if `before` callback returns `false`
## 3.4.0 - February 23, 2017
* Added isDefined() method to check if a bundle is already defined
## 3.3.1 - January 11, 2017
* Minor code cleanup
## 3.3.0 - January 9, 2017
* Added reset() method to reset dependency trackers
## 3.2.1 - December 18, 2016
* Minor code cleanup
## 3.2.0 - December 11, 2016
* Added `before` callback hook to modify script/link elements before adding
them to the DOM
## 3.1.0 - December 9, 2016
* Added numRetries option
## 3.0.0 - August 25, 2016
* Changed 'fail' callback name to 'error'
* Fixed bug in main attribute of bower.json
## 2.1.2 - August 22, 2016
* Upgraded devDependencies, rebuilt packaged, saved a byte
## 2.1.1 - July 25, 2016
* Fixed bug causing issues with external css files
## 2.1.0 - June 19, 2016
* Added support for loading CSS files
## 2.0.0 - June 15, 2016
* Changed API to accept object with success/fail functions
* Added support for async: false
## 1.0.4 - May 25, 2016
* Added support for ad blocked script failures
## 1.0.3 - May 18, 2016
* Shaved off 3 more bytes (minified + gzipped)
## 1.0.2 - May 18, 2016
* Added bower.json
* Removed onload script deletion
## 1.0.1 - March 22, 2016
* Small improvement to internal code to save a few bytes
## 1.0.0 - March 21, 2016
* Added UMD support

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Andres Morey
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.

View File

@@ -0,0 +1,383 @@
# LoadJS
<img src="https://www.muicss.com/static/images/loadjs.svg" width="250px">
LoadJS is a tiny async loader for modern browsers (899 bytes).
[![Dependency Status](https://david-dm.org/muicss/loadjs.svg)](https://david-dm.org/muicss/loadjs)
[![devDependency Status](https://david-dm.org/muicss/loadjs/dev-status.svg)](https://david-dm.org/muicss/loadjs?type=dev)
[![CDNJS](https://img.shields.io/cdnjs/v/loadjs.svg)](https://cdnjs.com/libraries/loadjs)
## Introduction
LoadJS is a tiny async loading library for modern browsers (IE9+). It has a simple yet powerful dependency management system that lets you fetch JavaScript, CSS and image files in parallel and execute code after the dependencies have been met. The recommended way to use LoadJS is to include the minified source code of [loadjs.js](https://raw.githubusercontent.com/muicss/loadjs/master/dist/loadjs.min.js) in your &lt;html&gt; (possibly in the &lt;head&gt; tag) and then use the `loadjs` global to manage JavaScript dependencies after pageload.
LoadJS is based on the excellent [$script](https://github.com/ded/script.js) library by [Dustin Diaz](https://github.com/ded). We kept the behavior of the library the same but we re-wrote the code from scratch to add support for success/error callbacks and to optimize the library for modern browsers. LoadJS is 899 bytes (minified + gzipped).
Here's an example of what you can do with LoadJS:
```javascript
// define a dependency bundle and execute code when it loads
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar');
loadjs.ready('foobar', function() {
/* foo.js & bar.js loaded */
});
```
You can also use more advanced syntax for more options:
```javascript
// define a dependency bundle with advanced options
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar', {
before: function(path, scriptEl) { /* execute code before fetch */ },
async: true, // load files synchronously or asynchronously (default: true)
numRetries: 3 // see caveats about using numRetries with async:false (default: 0),
returnPromise: false // return Promise object (default: false)
});
loadjs.ready('foobar', {
success: function() { /* foo.js & bar.js loaded */ },
error: function(depsNotFound) { /* foobar bundle load failed */ },
});
```
The latest version of LoadJS can be found in the `dist/` directory in this repository:
* [https://cdn.rawgit.com/muicss/loadjs/4.2.0/dist/loadjs.js](https://cdn.rawgit.com/muicss/loadjs/4.2.0/dist/loadjs.js) (for development)
* [https://cdn.rawgit.com/muicss/loadjs/4.2.0/dist/loadjs.min.js](https://cdn.rawgit.com/muicss/loadjs/4.2.0/dist/loadjs.min.js) (for production)
You can also use it as a CJS or AMD module:
```bash
$ npm install --save loadjs
```
```javascript
var loadjs = require('loadjs');
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar');
loadjs.ready('foobar', function() {
/* foo.js & bar.js loaded */
});
```
## Browser Support
* IE9+ (`async: false` support only works in IE10+)
* Opera 12+
* Safari 5+
* Chrome
* Firefox
* iOS 6+
* Android 4.4+
LoadJS also detects script load failures from AdBlock Plus and Ghostery in:
* Safari
* Chrome
Note: LoadJS treats empty CSS files as load failures in IE9-11 and uses `rel="preload"` to load CSS files in Edge (to get around lack of support for onerror events on `<link rel="stylesheet">` tags)
## Documentation
1. Load a single file
```javascript
loadjs('/path/to/foo.js', function() {
/* foo.js loaded */
});
```
1. Fetch files in parallel and load them asynchronously
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], function() {
/* foo.js and bar.js loaded */
});
```
1. Fetch JavaScript, CSS and image files
```javascript
loadjs(['/path/to/foo.css', '/path/to/bar.png', 'path/to/thunk.js'], function() {
/* foo.css, bar.png and thunk.js loaded */
});
```
1. Force treat file as CSS stylesheet
```javascript
loadjs(['css!/path/to/cssfile.custom'], function() {
/* cssfile.custom loaded as stylesheet */
});
```
1. Force treat file as image
```javascript
loadjs(['img!/path/to/image.custom'], function() {
/* image.custom loaded */
});
```
1. Add a bundle id
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar', function() {
/* foo.js & bar.js loaded */
});
```
1. Use .ready() to define bundles and callbacks separately
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar');
loadjs.ready('foobar', function() {
/* foo.js & bar.js loaded */
});
```
1. Use multiple bundles in .ready() dependency lists
```javascript
loadjs('/path/to/foo.js', 'foo');
loadjs(['/path/to/bar1.js', '/path/to/bar2.js'], 'bar');
loadjs.ready(['foo', 'bar'], function() {
/* foo.js & bar1.js & bar2.js loaded */
});
```
1. Chain .ready() together
```javascript
loadjs('/path/to/foo.js', 'foo');
loadjs('/path/to/bar.js', 'bar');
loadjs
.ready('foo', function() {
/* foo.js loaded */
})
.ready('bar', function() {
/* bar.js loaded */
});
```
1. Use Promises to register callbacks
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], {returnPromise: true})
.then(function() { /* foo.js & bar.js loaded */ })
.catch(function(pathsNotFound) { /* at least one didn't load */ });
```
1. Check if bundle has already been defined
```javascript
if (!loadjs.isDefined('foobar')) {
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar', function() {
/* foo.js & bar.js loaded */
});
}
```
1. Fetch files in parallel and load them in series
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], {
success: function() { /* foo.js and bar.js loaded in series */ },
async: false
});
```
1. Add an error callback
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar', {
success: function() { /* foo.js & bar.js loaded */ },
error: function(pathsNotFound) { /* at least one path didn't load */ }
});
```
1. Retry files before calling the error callback
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], 'foobar', {
success: function() { /* foo.js & bar.js loaded */ },
error: function(pathsNotFound) { /* at least one path didn't load */ },
numRetries: 3
});
// NOTE: Using `numRetries` with `async: false` can cause files to load out-of-sync on retries
```
1. Execute a callback before script tags are embedded
```javascript
loadjs(['/path/to/foo.js', '/path/to/bar.js'], {
success: function() {},
error: function(pathsNotFound) {},
before: function(path, scriptEl) {
/* called for each script node before being embedded */
if (path === '/path/to/foo.js') scriptEl.crossOrigin = true;
}
});
```
1. Bypass LoadJS default DOM insertion mechanism (DOM `<head>`)
```javascript
loadjs(['/path/to/foo.js'], {
success: function() {},
error: function(pathsNotFound) {},
before: function(path, scriptEl) {
document.body.appendChild(scriptEl);
/* return `false` to bypass default DOM insertion mechanism */
return false;
}
});
```
1. Use bundle ids in error callback
```javascript
loadjs('/path/to/foo.js', 'foo');
loadjs('/path/to/bar.js', 'bar');
loadjs(['/path/to/thunkor.js', '/path/to/thunky.js'], 'thunk');
// wait for multiple depdendencies
loadjs.ready(['foo', 'bar', 'thunk'], {
success: function() {
// foo.js & bar.js & thunkor.js & thunky.js loaded
},
error: function(depsNotFound) {
if (depsNotFound.indexOf('foo') > -1) {}; // foo failed
if (depsNotFound.indexOf('bar') > -1) {}; // bar failed
if (depsNotFound.indexOf('thunk') > -1) {}; // thunk failed
}
});
```
1. Use .done() for more control
```javascript
loadjs.ready(['dependency1', 'dependency2'], function() {
/* run code after dependencies have been met */
});
function fn1() {
loadjs.done('dependency1');
}
function fn2() {
loadjs.done('dependency2');
}
```
1. Reset dependency trackers
```javascript
loadjs.reset();
```
1. Implement a require-like dependency manager
```javascript
var bundles = {
'bundleA': ['/file1.js', '/file2.js'],
'bundleB': ['/file3.js', '/file4.js']
};
function require(bundleIds, callbackFn) {
bundleIds.forEach(function(bundleId) {
if (!loadjs.isDefined(bundleId)) loadjs(bundles[bundleId], bundleId);
});
loadjs.ready(bundleIds, callbackFn);
}
require(['bundleA'], function() { /* bundleA loaded */ });
require(['bundleB'], function() { /* bundleB loaded */ });
require(['bundleA', 'bundleB'], function() { /* bundleA and bundleB loaded */ });
```
## Directory structure
<pre>
loadjs/
├── dist
│   ├── loadjs.js
│   ├── loadjs.min.js
│   └── loadjs.umd.js
├── examples
├── gulpfile.js
├── LICENSE.txt
├── package.json
├── README.md
├── src
│   └── loadjs.js
├── test
└── umd-templates
</pre>
## Development Quickstart
1. Install dependencies
* [nodejs](http://nodejs.org/)
* [npm](https://www.npmjs.org/)
* http-server (via npm)
1. Clone repository
```bash
$ git clone git@github.com:muicss/loadjs.git
$ cd loadjs
```
1. Install node dependencies using npm
```bash
$ npm install
```
1. Build examples
```bash
$ npm run build-examples
```
To view the examples you can use any static file server. To use the `nodejs` http-server module:
```bash
$ npm install http-server
$ npm run http-server -- -p 3000
```
Then visit [http://localhost:3000/examples](http://localhost:3000/examples)
1. Build distribution files
```bash
$ npm run build-dist
```
The files will be located in the `dist` directory.
1. Run tests
To run the browser tests first build the `loadjs` library:
```bash
$ npm run build-tests
```
Then visit [http://localhost:3000/test](http://localhost:3000/test)
1. Build all files
```bash
$ npm run build-all
```

View File

@@ -0,0 +1,31 @@
# Release Instructions
1. Build packages
```bash
$ npm run build-all
```
1. Add release notes to CHANGELOG.md
1. Change version number in package.json
1. Change version number in bower.json
1. Update CDN urls in README.md
1. Commit changes and tag code
```bash
$ git add . --all
$ git commit -a -m "bumped version number"
$ git push origin master
$ git tag <version-number>
$ git push --tags
```
1. Push changes to NPM
```bash
$ npm publish
```

View File

@@ -0,0 +1,30 @@
{
"name": "loadjs",
"version": "4.2.0",
"license": "MIT",
"authors": [
"Andres Morey <andres@muicss.com>"
],
"homepage": "https://github.com/muicss/loadjs",
"description": "LoadJS is a tiny async loader for modern browsers.",
"main": [
"dist/loadjs.js"
],
"repository": {
"type": "git",
"url": "git://github.com/muicss/loadjs.git"
},
"keywords": [
"async loader",
"dependency manager"
],
"dependencies": {
},
"ignore": [
"examples",
"gulpfile.js",
"package.json",
"test",
"umd-templates"
]
}

View File

@@ -0,0 +1,308 @@
loadjs = (function () {
/**
* Global dependencies.
* @global {Object} document - DOM
*/
var devnull = function() {},
bundleIdCache = {},
bundleResultCache = {},
bundleCallbackQueue = {};
/**
* Subscribe to bundle load event.
* @param {string[]} bundleIds - Bundle ids
* @param {Function} callbackFn - The callback function
*/
function subscribe(bundleIds, callbackFn) {
// listify
bundleIds = bundleIds.push ? bundleIds : [bundleIds];
var depsNotFound = [],
i = bundleIds.length,
numWaiting = i,
fn,
bundleId,
r,
q;
// define callback function
fn = function (bundleId, pathsNotFound) {
if (pathsNotFound.length) depsNotFound.push(bundleId);
numWaiting--;
if (!numWaiting) callbackFn(depsNotFound);
};
// register callback
while (i--) {
bundleId = bundleIds[i];
// execute callback if in result cache
r = bundleResultCache[bundleId];
if (r) {
fn(bundleId, r);
continue;
}
// add to callback queue
q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];
q.push(fn);
}
}
/**
* Publish bundle load event.
* @param {string} bundleId - Bundle id
* @param {string[]} pathsNotFound - List of files not found
*/
function publish(bundleId, pathsNotFound) {
// exit if id isn't defined
if (!bundleId) return;
var q = bundleCallbackQueue[bundleId];
// cache result
bundleResultCache[bundleId] = pathsNotFound;
// exit if queue is empty
if (!q) return;
// empty callback queue
while (q.length) {
q[0](bundleId, pathsNotFound);
q.splice(0, 1);
}
}
/**
* Execute callbacks.
* @param {Object or Function} args - The callback args
* @param {string[]} depsNotFound - List of dependencies not found
*/
function executeCallbacks(args, depsNotFound) {
// accept function as argument
if (args.call) args = {success: args};
// success and error callbacks
if (depsNotFound.length) (args.error || devnull)(depsNotFound);
else (args.success || devnull)(args);
}
/**
* Load individual file.
* @param {string} path - The file path
* @param {Function} callbackFn - The callback function
*/
function loadFile(path, callbackFn, args, numTries) {
var doc = document,
async = args.async,
maxTries = (args.numRetries || 0) + 1,
beforeCallbackFn = args.before || devnull,
pathname = path.replace(/[\?|#].*$/, ''),
pathStripped = path.replace(/^(css|img)!/, ''),
isLegacyIECss,
e;
numTries = numTries || 0;
if (/(^css!|\.css$)/.test(pathname)) {
// css
e = doc.createElement('link');
e.rel = 'stylesheet';
e.href = pathStripped;
// tag IE9+
isLegacyIECss = 'hideFocus' in e;
// use preload in IE Edge (to detect load errors)
if (isLegacyIECss && e.relList) {
isLegacyIECss = 0;
e.rel = 'preload';
e.as = 'style';
}
} else if (/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(pathname)) {
// image
e = doc.createElement('img');
e.src = pathStripped;
} else {
// javascript
e = doc.createElement('script');
e.src = path;
e.async = async === undefined ? true : async;
}
e.onload = e.onerror = e.onbeforeload = function (ev) {
var result = ev.type[0];
// treat empty stylesheets as failures to get around lack of onerror
// support in IE9-11
if (isLegacyIECss) {
try {
if (!e.sheet.cssText.length) result = 'e';
} catch (x) {
// sheets objects created from load errors don't allow access to
// `cssText` (unless error is Code:18 SecurityError)
if (x.code != 18) result = 'e';
}
}
// handle retries in case of load failure
if (result == 'e') {
// increment counter
numTries += 1;
// exit function and try again
if (numTries < maxTries) {
return loadFile(path, callbackFn, args, numTries);
}
} else if (e.rel == 'preload' && e.as == 'style') {
// activate preloaded stylesheets
return e.rel = 'stylesheet'; // jshint ignore:line
}
// execute callback
callbackFn(path, result, ev.defaultPrevented);
};
// add to document (unless callback returns `false`)
if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);
}
/**
* Load multiple files.
* @param {string[]} paths - The file paths
* @param {Function} callbackFn - The callback function
*/
function loadFiles(paths, callbackFn, args) {
// listify paths
paths = paths.push ? paths : [paths];
var numWaiting = paths.length,
x = numWaiting,
pathsNotFound = [],
fn,
i;
// define callback function
fn = function(path, result, defaultPrevented) {
// handle error
if (result == 'e') pathsNotFound.push(path);
// handle beforeload event. If defaultPrevented then that means the load
// will be blocked (ex. Ghostery/ABP on Safari)
if (result == 'b') {
if (defaultPrevented) pathsNotFound.push(path);
else return;
}
numWaiting--;
if (!numWaiting) callbackFn(pathsNotFound);
};
// load scripts
for (i=0; i < x; i++) loadFile(paths[i], fn, args);
}
/**
* Initiate script load and register bundle.
* @param {(string|string[])} paths - The file paths
* @param {(string|Function|Object)} [arg1] - The (1) bundleId or (2) success
* callback or (3) object literal with success/error arguments, numRetries,
* etc.
* @param {(Function|Object)} [arg2] - The (1) success callback or (2) object
* literal with success/error arguments, numRetries, etc.
*/
function loadjs(paths, arg1, arg2) {
var bundleId,
args;
// bundleId (if string)
if (arg1 && arg1.trim) bundleId = arg1;
// args (default is {})
args = (bundleId ? arg2 : arg1) || {};
// throw error if bundle is already defined
if (bundleId) {
if (bundleId in bundleIdCache) {
throw "LoadJS";
} else {
bundleIdCache[bundleId] = true;
}
}
function loadFn(resolve, reject) {
loadFiles(paths, function (pathsNotFound) {
// execute callbacks
executeCallbacks(args, pathsNotFound);
// resolve Promise
if (resolve) {
executeCallbacks({success: resolve, error: reject}, pathsNotFound);
}
// publish bundle load event
publish(bundleId, pathsNotFound);
}, args);
}
if (args.returnPromise) return new Promise(loadFn);
else loadFn();
}
/**
* Execute callbacks when dependencies have been satisfied.
* @param {(string|string[])} deps - List of bundle ids
* @param {Object} args - success/error arguments
*/
loadjs.ready = function ready(deps, args) {
// subscribe to bundle load event
subscribe(deps, function (depsNotFound) {
// execute callbacks
executeCallbacks(args, depsNotFound);
});
return loadjs;
};
/**
* Manually satisfy bundle dependencies.
* @param {string} bundleId - The bundle id
*/
loadjs.done = function done(bundleId) {
publish(bundleId, []);
};
/**
* Reset loadjs dependencies statuses
*/
loadjs.reset = function reset() {
bundleIdCache = {};
bundleResultCache = {};
bundleCallbackQueue = {};
};
/**
* Determine if bundle has already been defined
* @param String} bundleId - The bundle id
*/
loadjs.isDefined = function isDefined(bundleId) {
return bundleId in bundleIdCache;
};
// export
return loadjs;
})();

View File

@@ -0,0 +1 @@
loadjs=function(){var h=function(){},c={},u={},f={};function o(e,n){if(e){var r=f[e];if(u[e]=n,r)for(;r.length;)r[0](e,n),r.splice(0,1)}}function l(e,n){e.call&&(e={success:e}),n.length?(e.error||h)(n):(e.success||h)(e)}function d(r,t,s,i){var c,o,e=document,n=s.async,u=(s.numRetries||0)+1,f=s.before||h,l=r.replace(/[\?|#].*$/,""),a=r.replace(/^(css|img)!/,"");i=i||0,/(^css!|\.css$)/.test(l)?((o=e.createElement("link")).rel="stylesheet",o.href=a,(c="hideFocus"in o)&&o.relList&&(c=0,o.rel="preload",o.as="style")):/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(l)?(o=e.createElement("img")).src=a:((o=e.createElement("script")).src=r,o.async=void 0===n||n),!(o.onload=o.onerror=o.onbeforeload=function(e){var n=e.type[0];if(c)try{o.sheet.cssText.length||(n="e")}catch(e){18!=e.code&&(n="e")}if("e"==n){if((i+=1)<u)return d(r,t,s,i)}else if("preload"==o.rel&&"style"==o.as)return o.rel="stylesheet";t(r,n,e.defaultPrevented)})!==f(r,o)&&e.head.appendChild(o)}function r(e,n,r){var t,s;if(n&&n.trim&&(t=n),s=(t?r:n)||{},t){if(t in c)throw"LoadJS";c[t]=!0}function i(n,r){!function(e,t,n){var r,s,i=(e=e.push?e:[e]).length,c=i,o=[];for(r=function(e,n,r){if("e"==n&&o.push(e),"b"==n){if(!r)return;o.push(e)}--i||t(o)},s=0;s<c;s++)d(e[s],r,n)}(e,function(e){l(s,e),n&&l({success:n,error:r},e),o(t,e)},s)}if(s.returnPromise)return new Promise(i);i()}return r.ready=function(e,n){return function(e,r){e=e.push?e:[e];var n,t,s,i=[],c=e.length,o=c;for(n=function(e,n){n.length&&i.push(e),--o||r(i)};c--;)t=e[c],(s=u[t])?n(t,s):(f[t]=f[t]||[]).push(n)}(e,function(e){l(n,e)}),r},r.done=function(e){o(e,[])},r.reset=function(){c={},u={},f={}},r.isDefined=function(e){return e in c},r}();

View File

@@ -0,0 +1,316 @@
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.loadjs = factory();
}
}(this, function() {
/**
* Global dependencies.
* @global {Object} document - DOM
*/
var devnull = function() {},
bundleIdCache = {},
bundleResultCache = {},
bundleCallbackQueue = {};
/**
* Subscribe to bundle load event.
* @param {string[]} bundleIds - Bundle ids
* @param {Function} callbackFn - The callback function
*/
function subscribe(bundleIds, callbackFn) {
// listify
bundleIds = bundleIds.push ? bundleIds : [bundleIds];
var depsNotFound = [],
i = bundleIds.length,
numWaiting = i,
fn,
bundleId,
r,
q;
// define callback function
fn = function (bundleId, pathsNotFound) {
if (pathsNotFound.length) depsNotFound.push(bundleId);
numWaiting--;
if (!numWaiting) callbackFn(depsNotFound);
};
// register callback
while (i--) {
bundleId = bundleIds[i];
// execute callback if in result cache
r = bundleResultCache[bundleId];
if (r) {
fn(bundleId, r);
continue;
}
// add to callback queue
q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];
q.push(fn);
}
}
/**
* Publish bundle load event.
* @param {string} bundleId - Bundle id
* @param {string[]} pathsNotFound - List of files not found
*/
function publish(bundleId, pathsNotFound) {
// exit if id isn't defined
if (!bundleId) return;
var q = bundleCallbackQueue[bundleId];
// cache result
bundleResultCache[bundleId] = pathsNotFound;
// exit if queue is empty
if (!q) return;
// empty callback queue
while (q.length) {
q[0](bundleId, pathsNotFound);
q.splice(0, 1);
}
}
/**
* Execute callbacks.
* @param {Object or Function} args - The callback args
* @param {string[]} depsNotFound - List of dependencies not found
*/
function executeCallbacks(args, depsNotFound) {
// accept function as argument
if (args.call) args = {success: args};
// success and error callbacks
if (depsNotFound.length) (args.error || devnull)(depsNotFound);
else (args.success || devnull)(args);
}
/**
* Load individual file.
* @param {string} path - The file path
* @param {Function} callbackFn - The callback function
*/
function loadFile(path, callbackFn, args, numTries) {
var doc = document,
async = args.async,
maxTries = (args.numRetries || 0) + 1,
beforeCallbackFn = args.before || devnull,
pathname = path.replace(/[\?|#].*$/, ''),
pathStripped = path.replace(/^(css|img)!/, ''),
isLegacyIECss,
e;
numTries = numTries || 0;
if (/(^css!|\.css$)/.test(pathname)) {
// css
e = doc.createElement('link');
e.rel = 'stylesheet';
e.href = pathStripped;
// tag IE9+
isLegacyIECss = 'hideFocus' in e;
// use preload in IE Edge (to detect load errors)
if (isLegacyIECss && e.relList) {
isLegacyIECss = 0;
e.rel = 'preload';
e.as = 'style';
}
} else if (/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(pathname)) {
// image
e = doc.createElement('img');
e.src = pathStripped;
} else {
// javascript
e = doc.createElement('script');
e.src = path;
e.async = async === undefined ? true : async;
}
e.onload = e.onerror = e.onbeforeload = function (ev) {
var result = ev.type[0];
// treat empty stylesheets as failures to get around lack of onerror
// support in IE9-11
if (isLegacyIECss) {
try {
if (!e.sheet.cssText.length) result = 'e';
} catch (x) {
// sheets objects created from load errors don't allow access to
// `cssText` (unless error is Code:18 SecurityError)
if (x.code != 18) result = 'e';
}
}
// handle retries in case of load failure
if (result == 'e') {
// increment counter
numTries += 1;
// exit function and try again
if (numTries < maxTries) {
return loadFile(path, callbackFn, args, numTries);
}
} else if (e.rel == 'preload' && e.as == 'style') {
// activate preloaded stylesheets
return e.rel = 'stylesheet'; // jshint ignore:line
}
// execute callback
callbackFn(path, result, ev.defaultPrevented);
};
// add to document (unless callback returns `false`)
if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);
}
/**
* Load multiple files.
* @param {string[]} paths - The file paths
* @param {Function} callbackFn - The callback function
*/
function loadFiles(paths, callbackFn, args) {
// listify paths
paths = paths.push ? paths : [paths];
var numWaiting = paths.length,
x = numWaiting,
pathsNotFound = [],
fn,
i;
// define callback function
fn = function(path, result, defaultPrevented) {
// handle error
if (result == 'e') pathsNotFound.push(path);
// handle beforeload event. If defaultPrevented then that means the load
// will be blocked (ex. Ghostery/ABP on Safari)
if (result == 'b') {
if (defaultPrevented) pathsNotFound.push(path);
else return;
}
numWaiting--;
if (!numWaiting) callbackFn(pathsNotFound);
};
// load scripts
for (i=0; i < x; i++) loadFile(paths[i], fn, args);
}
/**
* Initiate script load and register bundle.
* @param {(string|string[])} paths - The file paths
* @param {(string|Function|Object)} [arg1] - The (1) bundleId or (2) success
* callback or (3) object literal with success/error arguments, numRetries,
* etc.
* @param {(Function|Object)} [arg2] - The (1) success callback or (2) object
* literal with success/error arguments, numRetries, etc.
*/
function loadjs(paths, arg1, arg2) {
var bundleId,
args;
// bundleId (if string)
if (arg1 && arg1.trim) bundleId = arg1;
// args (default is {})
args = (bundleId ? arg2 : arg1) || {};
// throw error if bundle is already defined
if (bundleId) {
if (bundleId in bundleIdCache) {
throw "LoadJS";
} else {
bundleIdCache[bundleId] = true;
}
}
function loadFn(resolve, reject) {
loadFiles(paths, function (pathsNotFound) {
// execute callbacks
executeCallbacks(args, pathsNotFound);
// resolve Promise
if (resolve) {
executeCallbacks({success: resolve, error: reject}, pathsNotFound);
}
// publish bundle load event
publish(bundleId, pathsNotFound);
}, args);
}
if (args.returnPromise) return new Promise(loadFn);
else loadFn();
}
/**
* Execute callbacks when dependencies have been satisfied.
* @param {(string|string[])} deps - List of bundle ids
* @param {Object} args - success/error arguments
*/
loadjs.ready = function ready(deps, args) {
// subscribe to bundle load event
subscribe(deps, function (depsNotFound) {
// execute callbacks
executeCallbacks(args, depsNotFound);
});
return loadjs;
};
/**
* Manually satisfy bundle dependencies.
* @param {string} bundleId - The bundle id
*/
loadjs.done = function done(bundleId) {
publish(bundleId, []);
};
/**
* Reset loadjs dependencies statuses
*/
loadjs.reset = function reset() {
bundleIdCache = {};
bundleResultCache = {};
bundleCallbackQueue = {};
};
/**
* Determine if bundle has already been defined
* @param String} bundleId - The bundle id
*/
loadjs.isDefined = function isDefined(bundleId) {
return bundleId in bundleIdCache;
};
// export
return loadjs;
}));

View File

@@ -0,0 +1,18 @@
<!doctype html>
<html>
<head>
<script src="assets/log.js"></script>
<script src="assets/loadjs/loadjs.js"></script>
<script>
// load a file after window onload event fires
window.addEventListener('load', function(ev) {
loadjs('assets/file1.js', function() {
log('file1.js loaded');
});
});
</script>
</head>
<body>
<h1>Example: Load script after window onload event fires</h1>
</body>
</html>

View File

@@ -0,0 +1 @@
throw "Error";

View File

@@ -0,0 +1,3 @@
.test-div {
width: 100px;
}

View File

@@ -0,0 +1,3 @@
window.timesLoaded1 = window.timesLoaded1 || 0;
log('file1: loaded (' + timesLoaded1 + ')');
timesLoaded1 += 1;

View File

@@ -0,0 +1,3 @@
window.timesLoaded2 = window.timesLoaded2 || 0;
log('file2: loaded (' + timesLoaded2 + ')');
timesLoaded2 += 1;

View File

@@ -0,0 +1,3 @@
window.timesLoaded3 = window.timesLoaded3 || 0;
log('file3: loaded (' + timesLoaded3 + ')');
timesLoaded3 += 1;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
<title>iTunesArtwork@2x</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="Size-Guides" sketch:type="MSLayerGroup" transform="translate(0.000000, -124.000000)"></g>
<g id="iTunesArtwork@2x" sketch:type="MSArtboardGroup">
<path d="M357.009067,0 L666.990933,0 C769.792,0 821.179733,0 876.5184,17.4933333 C936.9344,39.4837333 984.516267,87.0656 1006.50667,147.4816 C1024,202.811733 1024,254.216533 1024,357.009067 L1024,666.990933 C1024,769.792 1024,821.179733 1006.50667,876.5184 C984.516267,936.9344 936.9344,984.516267 876.5184,1006.49813 C821.179733,1024 769.792,1024 666.990933,1024 L357.009067,1024 C254.208,1024 202.811733,1024 147.4816,1006.49813 C87.0656,984.516267 39.4837333,936.9344 17.4933333,876.5184 C0,821.179733 0,769.792 0,666.990933 L0,357.009067 C0,254.216533 0,202.811733 17.4933333,147.4816 C39.4837333,87.0656 87.0656,39.4837333 147.4816,17.4933333 C202.811733,0 254.208,0 357.009067,0 L357.009067,0" id="Icon-Shape" fill="#D7D7D7" sketch:type="MSShapeGroup"></path>
<path d="M692.497264,349.385524 C697.470239,354.906145 698.437452,360.978828 695.398902,367.603573 L471.813752,846.652148 C468.227556,853.550716 462.428696,857 454.417171,857 C453.313047,857 451.378621,856.721761 448.613894,856.165282 C443.923575,854.787335 440.403627,852.163936 438.05405,848.295085 C435.704474,844.426234 435.081748,840.28356 436.185872,835.867063 L517.749735,501.31743 L349.640201,543.132822 C348.536077,543.406645 346.87989,543.543556 344.671642,543.543556 C339.698667,543.543556 335.419081,542.024281 331.832886,538.985731 C326.85991,534.843057 325.066813,529.459348 326.453593,522.834603 L409.673642,181.24949 C410.777766,177.380639 412.986014,174.205178 416.298387,171.723107 C419.61076,169.241036 423.475194,168 427.891691,168 L563.698968,168 C568.945766,168 573.362263,169.72685 576.948458,173.180551 C580.534654,176.634251 582.327751,180.706261 582.327751,185.396581 C582.327751,187.604829 581.638778,190.091317 580.260831,192.856044 L509.455554,384.562921 L673.417998,343.979732 C675.626246,343.423253 677.282433,343.145014 678.386557,343.145014 C683.633355,343.145014 688.328091,345.216351 692.470765,349.359025 L692.497264,349.385524 Z" id="Shape" fill="#C62828" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,308 @@
loadjs = (function () {
/**
* Global dependencies.
* @global {Object} document - DOM
*/
var devnull = function() {},
bundleIdCache = {},
bundleResultCache = {},
bundleCallbackQueue = {};
/**
* Subscribe to bundle load event.
* @param {string[]} bundleIds - Bundle ids
* @param {Function} callbackFn - The callback function
*/
function subscribe(bundleIds, callbackFn) {
// listify
bundleIds = bundleIds.push ? bundleIds : [bundleIds];
var depsNotFound = [],
i = bundleIds.length,
numWaiting = i,
fn,
bundleId,
r,
q;
// define callback function
fn = function (bundleId, pathsNotFound) {
if (pathsNotFound.length) depsNotFound.push(bundleId);
numWaiting--;
if (!numWaiting) callbackFn(depsNotFound);
};
// register callback
while (i--) {
bundleId = bundleIds[i];
// execute callback if in result cache
r = bundleResultCache[bundleId];
if (r) {
fn(bundleId, r);
continue;
}
// add to callback queue
q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];
q.push(fn);
}
}
/**
* Publish bundle load event.
* @param {string} bundleId - Bundle id
* @param {string[]} pathsNotFound - List of files not found
*/
function publish(bundleId, pathsNotFound) {
// exit if id isn't defined
if (!bundleId) return;
var q = bundleCallbackQueue[bundleId];
// cache result
bundleResultCache[bundleId] = pathsNotFound;
// exit if queue is empty
if (!q) return;
// empty callback queue
while (q.length) {
q[0](bundleId, pathsNotFound);
q.splice(0, 1);
}
}
/**
* Execute callbacks.
* @param {Object or Function} args - The callback args
* @param {string[]} depsNotFound - List of dependencies not found
*/
function executeCallbacks(args, depsNotFound) {
// accept function as argument
if (args.call) args = {success: args};
// success and error callbacks
if (depsNotFound.length) (args.error || devnull)(depsNotFound);
else (args.success || devnull)(args);
}
/**
* Load individual file.
* @param {string} path - The file path
* @param {Function} callbackFn - The callback function
*/
function loadFile(path, callbackFn, args, numTries) {
var doc = document,
async = args.async,
maxTries = (args.numRetries || 0) + 1,
beforeCallbackFn = args.before || devnull,
pathname = path.replace(/[\?|#].*$/, ''),
pathStripped = path.replace(/^(css|img)!/, ''),
isLegacyIECss,
e;
numTries = numTries || 0;
if (/(^css!|\.css$)/.test(pathname)) {
// css
e = doc.createElement('link');
e.rel = 'stylesheet';
e.href = pathStripped;
// tag IE9+
isLegacyIECss = 'hideFocus' in e;
// use preload in IE Edge (to detect load errors)
if (isLegacyIECss && e.relList) {
isLegacyIECss = 0;
e.rel = 'preload';
e.as = 'style';
}
} else if (/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(pathname)) {
// image
e = doc.createElement('img');
e.src = pathStripped;
} else {
// javascript
e = doc.createElement('script');
e.src = path;
e.async = async === undefined ? true : async;
}
e.onload = e.onerror = e.onbeforeload = function (ev) {
var result = ev.type[0];
// treat empty stylesheets as failures to get around lack of onerror
// support in IE9-11
if (isLegacyIECss) {
try {
if (!e.sheet.cssText.length) result = 'e';
} catch (x) {
// sheets objects created from load errors don't allow access to
// `cssText` (unless error is Code:18 SecurityError)
if (x.code != 18) result = 'e';
}
}
// handle retries in case of load failure
if (result == 'e') {
// increment counter
numTries += 1;
// exit function and try again
if (numTries < maxTries) {
return loadFile(path, callbackFn, args, numTries);
}
} else if (e.rel == 'preload' && e.as == 'style') {
// activate preloaded stylesheets
return e.rel = 'stylesheet'; // jshint ignore:line
}
// execute callback
callbackFn(path, result, ev.defaultPrevented);
};
// add to document (unless callback returns `false`)
if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);
}
/**
* Load multiple files.
* @param {string[]} paths - The file paths
* @param {Function} callbackFn - The callback function
*/
function loadFiles(paths, callbackFn, args) {
// listify paths
paths = paths.push ? paths : [paths];
var numWaiting = paths.length,
x = numWaiting,
pathsNotFound = [],
fn,
i;
// define callback function
fn = function(path, result, defaultPrevented) {
// handle error
if (result == 'e') pathsNotFound.push(path);
// handle beforeload event. If defaultPrevented then that means the load
// will be blocked (ex. Ghostery/ABP on Safari)
if (result == 'b') {
if (defaultPrevented) pathsNotFound.push(path);
else return;
}
numWaiting--;
if (!numWaiting) callbackFn(pathsNotFound);
};
// load scripts
for (i=0; i < x; i++) loadFile(paths[i], fn, args);
}
/**
* Initiate script load and register bundle.
* @param {(string|string[])} paths - The file paths
* @param {(string|Function|Object)} [arg1] - The (1) bundleId or (2) success
* callback or (3) object literal with success/error arguments, numRetries,
* etc.
* @param {(Function|Object)} [arg2] - The (1) success callback or (2) object
* literal with success/error arguments, numRetries, etc.
*/
function loadjs(paths, arg1, arg2) {
var bundleId,
args;
// bundleId (if string)
if (arg1 && arg1.trim) bundleId = arg1;
// args (default is {})
args = (bundleId ? arg2 : arg1) || {};
// throw error if bundle is already defined
if (bundleId) {
if (bundleId in bundleIdCache) {
throw "LoadJS";
} else {
bundleIdCache[bundleId] = true;
}
}
function loadFn(resolve, reject) {
loadFiles(paths, function (pathsNotFound) {
// execute callbacks
executeCallbacks(args, pathsNotFound);
// resolve Promise
if (resolve) {
executeCallbacks({success: resolve, error: reject}, pathsNotFound);
}
// publish bundle load event
publish(bundleId, pathsNotFound);
}, args);
}
if (args.returnPromise) return new Promise(loadFn);
else loadFn();
}
/**
* Execute callbacks when dependencies have been satisfied.
* @param {(string|string[])} deps - List of bundle ids
* @param {Object} args - success/error arguments
*/
loadjs.ready = function ready(deps, args) {
// subscribe to bundle load event
subscribe(deps, function (depsNotFound) {
// execute callbacks
executeCallbacks(args, depsNotFound);
});
return loadjs;
};
/**
* Manually satisfy bundle dependencies.
* @param {string} bundleId - The bundle id
*/
loadjs.done = function done(bundleId) {
publish(bundleId, []);
};
/**
* Reset loadjs dependencies statuses
*/
loadjs.reset = function reset() {
bundleIdCache = {};
bundleResultCache = {};
bundleCallbackQueue = {};
};
/**
* Determine if bundle has already been defined
* @param String} bundleId - The bundle id
*/
loadjs.isDefined = function isDefined(bundleId) {
return bundleId in bundleIdCache;
};
// export
return loadjs;
})();

View File

@@ -0,0 +1 @@
loadjs=function(){var h=function(){},c={},u={},f={};function o(e,n){if(e){var r=f[e];if(u[e]=n,r)for(;r.length;)r[0](e,n),r.splice(0,1)}}function l(e,n){e.call&&(e={success:e}),n.length?(e.error||h)(n):(e.success||h)(e)}function d(r,t,s,i){var c,o,e=document,n=s.async,u=(s.numRetries||0)+1,f=s.before||h,l=r.replace(/[\?|#].*$/,""),a=r.replace(/^(css|img)!/,"");i=i||0,/(^css!|\.css$)/.test(l)?((o=e.createElement("link")).rel="stylesheet",o.href=a,(c="hideFocus"in o)&&o.relList&&(c=0,o.rel="preload",o.as="style")):/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(l)?(o=e.createElement("img")).src=a:((o=e.createElement("script")).src=r,o.async=void 0===n||n),!(o.onload=o.onerror=o.onbeforeload=function(e){var n=e.type[0];if(c)try{o.sheet.cssText.length||(n="e")}catch(e){18!=e.code&&(n="e")}if("e"==n){if((i+=1)<u)return d(r,t,s,i)}else if("preload"==o.rel&&"style"==o.as)return o.rel="stylesheet";t(r,n,e.defaultPrevented)})!==f(r,o)&&e.head.appendChild(o)}function r(e,n,r){var t,s;if(n&&n.trim&&(t=n),s=(t?r:n)||{},t){if(t in c)throw"LoadJS";c[t]=!0}function i(n,r){!function(e,t,n){var r,s,i=(e=e.push?e:[e]).length,c=i,o=[];for(r=function(e,n,r){if("e"==n&&o.push(e),"b"==n){if(!r)return;o.push(e)}--i||t(o)},s=0;s<c;s++)d(e[s],r,n)}(e,function(e){l(s,e),n&&l({success:n,error:r},e),o(t,e)},s)}if(s.returnPromise)return new Promise(i);i()}return r.ready=function(e,n){return function(e,r){e=e.push?e:[e];var n,t,s,i=[],c=e.length,o=c;for(n=function(e,n){n.length&&i.push(e),--o||r(i)};c--;)t=e[c],(s=u[t])?n(t,s):(f[t]=f[t]||[]).push(n)}(e,function(e){l(n,e)}),r},r.done=function(e){o(e,[])},r.reset=function(){c={},u={},f={}},r.isDefined=function(e){return e in c},r}();

View File

@@ -0,0 +1,20 @@
// define global logging function
function log(msg) {
var d = new Date(), ts;
ts = d.toLocaleTimeString().split(' ');
ts = ts[0] + '.' + d.getMilliseconds() + ' ' + ts[1];
console.log('[' + ts + '] ' + msg);
}
// log DOMContentLoaded event
document.addEventListener('DOMContentLoaded', function(ev) {
log('DOMContentLoaded fired');
});
// log window onload event
window.addEventListener('load', function(ev) {
log('window load event fired');
});

View File

@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<script src="assets/log.js"></script>
<script src="assets/file1.js"></script>
</head>
<body>
<h1>Example: Load script before DOMContentLoaded event fires</h1>
</body>
</html>

View File

@@ -0,0 +1,16 @@
<!doctype html>
<html>
<head>
<script src="assets/log.js"></script>
<script src="assets/loadjs/loadjs.js"></script>
<script>
loadjs('assets/file1.js', function() {
log('file1.js loaded');
});
</script>
</head>
<body>
<h1>Example: Trigger script load before window onload event fires</h1>
<p>Note: If the network fetch returns before the DOMContentLoaded event or the window onload event fires then the browser will delay event execution until the script has finished executing.</p>
</body>
</html>

View File

@@ -0,0 +1,45 @@
<!doctype html>
<html>
<head>
<script src="assets/log.js"></script>
<script src="assets/loadjs/loadjs.js"></script>
<script>
loadjs("//cdn.muicss.com/mui-0.9.41/css/mui.min.css", {
success: function() {
log('example1: mui.min.css triggered success (OK)');
},
error: function() {
log('example1: mui.min.css triggered error (FAIL)');
}
});
loadjs("//cdn.muicss.com/mui-0.9.41/css/mui-doesntexist.min.css", {
success: function() {
log('example2: mui-doesntexist.css triggered success (FAIL)');
},
error: function() {
log('example2: mui-doesntexist.css triggered error (OK)');
}
});
loadjs('assets/fontcss-doesntexist.css', {
success: function() {
log('example3: font-doesntexist.css triggered success (FAIL)');
},
error: function() {
log('example3: font-doesntexist.css triggered error (OK)');
}
});
</script>
</head>
<body>
<div class="mui-container">
<div class="mui-panel">
<h1>My Title</h1>
<button class="mui-btn mui-btn--primary mui-btn--raised">My Button</button>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,40 @@
<!doctype html>
<html>
<head>
<script>
function loadSheet(path) {
var e = document.createElement('link');
e.rel = 'stylesheet';
e.href = path;
e.onload = function(ev) {
console.log('---- ONLOAD ----');
console.log(path + ': ' + ev.type);
try {
console.log('sheet.cssText.length: ' + e.sheet.cssText.length);
} catch (err) {
console.log('error code: ' + err.code);
}
console.log(ev);
console.log('----------------');
};
e.onerror = function(ev) {console.log('onerror: ' + ev.type);};
document.head.appendChild(e);
}
loadSheet('//cdn.muicss.com/mui-0.9.41/css/mui.min.css');
loadSheet('//cdn.muicss.com/mui-0.9.41/css/mui-doesntexist.min.css');
loadSheet('assets/fontcss-doesntexist.css');
loadSheet('assets/file.css');
</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,43 @@
<!doctype html>
<html>
<head>
<script>
function loadSheet(path) {
var e = document.createElement('link');
//e.rel = 'stylesheet';
e.rel = 'preload';
e.as = 'style';
e.href = path;
e.onload = function(ev) {
//if (e.rel == 'preload') return e.rel = 'stylesheet';
console.log('[ONLOAD] ' + path + ': ' + ev.type);
};
e.onerror = function(ev) {
//if (e.rel == 'preload') return e.rel = 'stylesheet';
console.log('[ONERROR] ' + path + ': ' + ev.type);
};
document.head.appendChild(e);
}
//loadSheet('//cdn.muicss.com/mui-0.9.41/css/mui.min.css');
loadSheet('//cdn.muicss.com/mui-0.9.41/css/mui-doesntexist.min.css');
//loadSheet('assets/fontcss-doesntexist.css');
//loadSheet('assets/file.css');
</script>
</head>
<body>
<div class="mui-container">
<div class="mui-panel">
<h1>My Title</h1>
<button class="mui-btn mui-btn--primary mui-btn--raised">My Button</button>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,133 @@
<!doctype html>
<html>
<head>
<script>
var results = {
0: [],
1: [],
2: []
};
function standardDeviation(values) {
var avg = average(values);
var squareDiffs = values.map(function(value){
var diff = value - avg;
var sqrDiff = diff * diff;
return sqrDiff;
});
var avgSquareDiff = average(squareDiffs);
var stdDev = Math.sqrt(avgSquareDiff);
return stdDev;
}
function average(data){
var sum = data.reduce(function(sum, value){
return sum + value;
}, 0);
var avg = sum / data.length;
return avg;
}
function doLoad(path, callbackFn) {
var e = document.createElement('link'),
t0;
e.rel = 'stylesheet';
e.href = path + '?' + Math.random();
e.onload = function(ev) {
var t1 = performance.now();
results[0].push(t1 - t0);
setTimeout(function(){callbackFn(e)}, 0);
};
t0 = performance.now();
document.head.appendChild(e);
}
function doPreload(path, callbackFn) {
var e = document.createElement('link'),
t0;
e.rel = 'preload';
e.as = 'style';
e.href = path + '?' + Math.random();
e.onload = function(ev) {
var t1 = performance.now();
results[1].push(t1 - t0);
setTimeout(function(){callbackFn(e)}, 0);
};
t0 = performance.now();
document.head.appendChild(e);
}
function doPreloadWithExecution(path, callbackFn) {
var e = document.createElement('link'),
t0;
e.rel = 'preload';
e.as = 'style';
e.href = path + '?' + Math.random();
e.onload = function(ev) {
if (e.rel == 'preload') return e.rel = 'stylesheet';
var t1 = performance.now();
results[2].push(t1 - t0);
setTimeout(function(){callbackFn(e)}, 0);
};
t0 = performance.now();
document.head.appendChild(e);
}
function printResults(str, data) {
var sum = data.reduce(function(a, b) {return a + b;}, 0);
console.log('-----------');
console.log(str + '(' + data.length + '):');
console.log('Min: ' + Math.min(...data));
console.log('Max: ' + Math.max(...data));
console.log('Avg: ' + sum / data.length);
console.log('Std: ' + standardDeviation(data));
console.log('-----------');
}
function loadAll(n) {
console.log(n);
if (n == 100) {
setTimeout(function() {
printResults('Load', results[0]);
printResults('Preload', results[1]);
printResults('PreloadWithExecution', results[2]);
}, 2000);
return;
}
var path = '//cdn.muicss.com/mui-0.9.41/css/mui.min.css';
doLoad(path, function(e1) {
doPreload(path, function(e2) {
doPreloadWithExecution(path, function(e3) {
loadAll(n + 1);
});
});
});
}
loadAll(0);
</script>
</head>
<body>
<div class="mui-container">
<div class="mui-panel">
<h1>My Title</h1>
<button class="mui-btn mui-btn--primary mui-btn--raised">My Button</button>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,99 @@
<!doctype html>
<html>
<head>
<script src="assets/log.js"></script>
<script src="assets/loadjs/loadjs.js"></script>
<script>
// load a single file
loadjs('assets/file1.js', function() {
log('example1: file1.js loaded');
});
// load multiple files
loadjs(['assets/file1.js', 'assets/file2.js'], function() {
log('example2: file1.js & file2.js loaded');
});
// add a bundle id
loadjs(['assets/file1.js', 'assets/file2.js'], 'example3', function() {
log('example3: file1.js & file2.js loaded');
});
// add a failure callback
loadjs(['assets/file1.js', 'assets/file-doesntexist.js'],
'example4',
function() {
throw "Load should fail";
},
function(pathsNotFound) {
log('example4: ' + pathsNotFound + ' not found');
});
// execute a callback after bundle finishes loading
loadjs(['assets/file1.js', 'assets/file2.js'], 'example5');
loadjs.ready('example5', function() {
log('example5: file1.js & file2.js loaded');
});
// .ready() can be chained together
loadjs('assets/file1.js', 'example6a');
loadjs('assets/file2.js', 'example6b');
loadjs
.ready('example6a', function() {
log('example6a: file1.js loaded');
})
.ready('example6b', function() {
log('example6b: file2.js loaded');
});
// compose more complex dependency lists
loadjs('assets/file1.js', 'example7a');
loadjs(['assets/file2.js', 'assets/file3.js'], 'example7b');
loadjs(['assets/file3.js', 'assets/file-doesntexist.js'], 'example7c');
// wait for multiple depdendencies
loadjs.ready(['example7a', 'example7b'],
function() {
log('example7ab: file1.js & file2.js & file3.js loaded');
},
function(depsNotFound) {
throw "Load should succeed";
});
loadjs.ready(['example7a', 'example7b', 'example7c'],
function() {
throw "Load should fail";
},
function(depsNotFound) {
log('example7abc: ' + depsNotFound + ' failed');
});
// use .done() for more control
loadjs.ready('my-awesome-plugin', function() {
myAwesomePlugin();
log('example8: my-awesome-plugin was loaded');
});
loadjs('https://code.jquery.com/jquery-1.11.3.min.js', function() {
// plugin requires jquery
window.myAwesomePlugin = function() {
if (!window.jQuery) throw "jQuery is missing!";
};
// plugin is done loading
loadjs.done('my-awesome-plugin');
});
</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,31 @@
<!doctype html>
<html>
<head>
<script src="assets/log.js"></script>
<script src="assets/loadjs/loadjs.js"></script>
<script>
loadjs('assets/flash.svg', function() {
log('example1: flash.svg loaded');
});
loadjs('assets/flash.png', function() {
log('example2: flash.png loaded');
});
loadjs('assets/flash-doesntexist.svg', {
success: function() {
log('example3: flash-doesntexist.svg triggered success (FAIL)');
},
error: function() {
log('example3: flash-doesntexist.svg triggered error (OK)');
}
});
loadjs('img!assets/flash.svg?trick', function() {
log('example4: flash.svg loaded');
});
</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,95 @@
'use strict';
var del = require('del'),
gulp = require('gulp'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
rename = require('gulp-rename'),
umd = require('gulp-umd');
var umdNamespace = function() {
return 'loadjs';
};
// ============================================================================
// PUBLIC TASKS
// ============================================================================
gulp.task('build-examples', gulp.series(
clean('./examples/assets/loadjs'),
buildJs('./examples/assets/loadjs')
));
gulp.task('build-dist', gulp.series(
clean('./dist'),
gulp.parallel(
buildJs('./dist'),
buildUmdJs('./dist')
)
));
gulp.task('build-tests', gulp.series(
clean('./test/assets/loadjs'),
buildJs('./test/assets/loadjs')
));
gulp.task('build-all', gulp.parallel(
'build-examples',
'build-dist',
'build-tests'
));
// ============================================================================
// PRIVATE TASKS
// ============================================================================
function makeTask(displayName, fn) {
if (displayName) fn.displayName = displayName;
return fn;
}
function clean(dirname) {
return makeTask('clean: ' + dirname, function(done) {
return del(dirname, done);
});
}
function buildJs(dirname) {
return makeTask('build-js: ' + dirname, function() {
return gulp.src('src/loadjs.js')
.pipe(umd({
namespace: umdNamespace,
template: 'umd-templates/web.js'
}))
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(rename('loadjs.js'))
.pipe(gulp.dest(dirname))
.pipe(uglify())
.pipe(rename('loadjs.min.js'))
.pipe(gulp.dest(dirname));
});
}
function buildUmdJs(dirname) {
return makeTask('build-umd-js: ' + dirname, function() {
return gulp.src('src/loadjs.js')
.pipe(umd({
namespace: umdNamespace,
template: 'umd-templates/UMD.js'
}))
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(rename('loadjs.umd.js'))
.pipe(gulp.dest(dirname));
});
}

View File

@@ -0,0 +1,63 @@
{
"_from": "loadjs@^4.2.0",
"_id": "loadjs@4.2.0",
"_inBundle": false,
"_integrity": "sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==",
"_location": "/loadjs",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "loadjs@^4.2.0",
"name": "loadjs",
"escapedName": "loadjs",
"rawSpec": "^4.2.0",
"saveSpec": null,
"fetchSpec": "^4.2.0"
},
"_requiredBy": [
"/plyr"
],
"_resolved": "https://registry.npmjs.org/loadjs/-/loadjs-4.2.0.tgz",
"_shasum": "2a0336376397a6a43edf98c9ec3229ddd5abb6f6",
"_spec": "loadjs@^4.2.0",
"_where": "/home/andy/plyr/node_modules/plyr",
"bugs": {
"url": "https://github.com/muicss/loadjs/issues",
"email": "contact@muicss.com"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Tiny async loader for modern browsers",
"devDependencies": {
"del": "^5.1.0",
"gulp": "^4.0.2",
"gulp-jshint": "^2.1.0",
"gulp-rename": "^1.4.0",
"gulp-uglify": "^3.0.2",
"gulp-umd": "^2.0.0",
"jshint": "^2.10.2"
},
"homepage": "https://github.com/muicss/loadjs",
"keywords": [
"async",
"loader",
"dependency manager"
],
"license": "MIT",
"main": "dist/loadjs.umd.js",
"name": "loadjs",
"repository": {
"type": "git",
"url": "git+https://github.com/muicss/loadjs.git"
},
"scripts": {
"build-all": "gulp build-all",
"build-dist": "gulp build-dist",
"build-examples": "gulp build-examples",
"build-tests": "gulp build-tests",
"gulp": "gulp",
"http-server": "http-server"
},
"version": "4.2.0"
}

View File

@@ -0,0 +1,305 @@
/**
* Global dependencies.
* @global {Object} document - DOM
*/
var devnull = function() {},
bundleIdCache = {},
bundleResultCache = {},
bundleCallbackQueue = {};
/**
* Subscribe to bundle load event.
* @param {string[]} bundleIds - Bundle ids
* @param {Function} callbackFn - The callback function
*/
function subscribe(bundleIds, callbackFn) {
// listify
bundleIds = bundleIds.push ? bundleIds : [bundleIds];
var depsNotFound = [],
i = bundleIds.length,
numWaiting = i,
fn,
bundleId,
r,
q;
// define callback function
fn = function (bundleId, pathsNotFound) {
if (pathsNotFound.length) depsNotFound.push(bundleId);
numWaiting--;
if (!numWaiting) callbackFn(depsNotFound);
};
// register callback
while (i--) {
bundleId = bundleIds[i];
// execute callback if in result cache
r = bundleResultCache[bundleId];
if (r) {
fn(bundleId, r);
continue;
}
// add to callback queue
q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];
q.push(fn);
}
}
/**
* Publish bundle load event.
* @param {string} bundleId - Bundle id
* @param {string[]} pathsNotFound - List of files not found
*/
function publish(bundleId, pathsNotFound) {
// exit if id isn't defined
if (!bundleId) return;
var q = bundleCallbackQueue[bundleId];
// cache result
bundleResultCache[bundleId] = pathsNotFound;
// exit if queue is empty
if (!q) return;
// empty callback queue
while (q.length) {
q[0](bundleId, pathsNotFound);
q.splice(0, 1);
}
}
/**
* Execute callbacks.
* @param {Object or Function} args - The callback args
* @param {string[]} depsNotFound - List of dependencies not found
*/
function executeCallbacks(args, depsNotFound) {
// accept function as argument
if (args.call) args = {success: args};
// success and error callbacks
if (depsNotFound.length) (args.error || devnull)(depsNotFound);
else (args.success || devnull)(args);
}
/**
* Load individual file.
* @param {string} path - The file path
* @param {Function} callbackFn - The callback function
*/
function loadFile(path, callbackFn, args, numTries) {
var doc = document,
async = args.async,
maxTries = (args.numRetries || 0) + 1,
beforeCallbackFn = args.before || devnull,
pathname = path.replace(/[\?|#].*$/, ''),
pathStripped = path.replace(/^(css|img)!/, ''),
isLegacyIECss,
e;
numTries = numTries || 0;
if (/(^css!|\.css$)/.test(pathname)) {
// css
e = doc.createElement('link');
e.rel = 'stylesheet';
e.href = pathStripped;
// tag IE9+
isLegacyIECss = 'hideFocus' in e;
// use preload in IE Edge (to detect load errors)
if (isLegacyIECss && e.relList) {
isLegacyIECss = 0;
e.rel = 'preload';
e.as = 'style';
}
} else if (/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(pathname)) {
// image
e = doc.createElement('img');
e.src = pathStripped;
} else {
// javascript
e = doc.createElement('script');
e.src = path;
e.async = async === undefined ? true : async;
}
e.onload = e.onerror = e.onbeforeload = function (ev) {
var result = ev.type[0];
// treat empty stylesheets as failures to get around lack of onerror
// support in IE9-11
if (isLegacyIECss) {
try {
if (!e.sheet.cssText.length) result = 'e';
} catch (x) {
// sheets objects created from load errors don't allow access to
// `cssText` (unless error is Code:18 SecurityError)
if (x.code != 18) result = 'e';
}
}
// handle retries in case of load failure
if (result == 'e') {
// increment counter
numTries += 1;
// exit function and try again
if (numTries < maxTries) {
return loadFile(path, callbackFn, args, numTries);
}
} else if (e.rel == 'preload' && e.as == 'style') {
// activate preloaded stylesheets
return e.rel = 'stylesheet'; // jshint ignore:line
}
// execute callback
callbackFn(path, result, ev.defaultPrevented);
};
// add to document (unless callback returns `false`)
if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);
}
/**
* Load multiple files.
* @param {string[]} paths - The file paths
* @param {Function} callbackFn - The callback function
*/
function loadFiles(paths, callbackFn, args) {
// listify paths
paths = paths.push ? paths : [paths];
var numWaiting = paths.length,
x = numWaiting,
pathsNotFound = [],
fn,
i;
// define callback function
fn = function(path, result, defaultPrevented) {
// handle error
if (result == 'e') pathsNotFound.push(path);
// handle beforeload event. If defaultPrevented then that means the load
// will be blocked (ex. Ghostery/ABP on Safari)
if (result == 'b') {
if (defaultPrevented) pathsNotFound.push(path);
else return;
}
numWaiting--;
if (!numWaiting) callbackFn(pathsNotFound);
};
// load scripts
for (i=0; i < x; i++) loadFile(paths[i], fn, args);
}
/**
* Initiate script load and register bundle.
* @param {(string|string[])} paths - The file paths
* @param {(string|Function|Object)} [arg1] - The (1) bundleId or (2) success
* callback or (3) object literal with success/error arguments, numRetries,
* etc.
* @param {(Function|Object)} [arg2] - The (1) success callback or (2) object
* literal with success/error arguments, numRetries, etc.
*/
function loadjs(paths, arg1, arg2) {
var bundleId,
args;
// bundleId (if string)
if (arg1 && arg1.trim) bundleId = arg1;
// args (default is {})
args = (bundleId ? arg2 : arg1) || {};
// throw error if bundle is already defined
if (bundleId) {
if (bundleId in bundleIdCache) {
throw "LoadJS";
} else {
bundleIdCache[bundleId] = true;
}
}
function loadFn(resolve, reject) {
loadFiles(paths, function (pathsNotFound) {
// execute callbacks
executeCallbacks(args, pathsNotFound);
// resolve Promise
if (resolve) {
executeCallbacks({success: resolve, error: reject}, pathsNotFound);
}
// publish bundle load event
publish(bundleId, pathsNotFound);
}, args);
}
if (args.returnPromise) return new Promise(loadFn);
else loadFn();
}
/**
* Execute callbacks when dependencies have been satisfied.
* @param {(string|string[])} deps - List of bundle ids
* @param {Object} args - success/error arguments
*/
loadjs.ready = function ready(deps, args) {
// subscribe to bundle load event
subscribe(deps, function (depsNotFound) {
// execute callbacks
executeCallbacks(args, depsNotFound);
});
return loadjs;
};
/**
* Manually satisfy bundle dependencies.
* @param {string} bundleId - The bundle id
*/
loadjs.done = function done(bundleId) {
publish(bundleId, []);
};
/**
* Reset loadjs dependencies statuses
*/
loadjs.reset = function reset() {
bundleIdCache = {};
bundleResultCache = {};
bundleCallbackQueue = {};
};
/**
* Determine if bundle has already been defined
* @param String} bundleId - The bundle id
*/
loadjs.isDefined = function isDefined(bundleId) {
return bundleId in bundleIdCache;
};
// export
return loadjs;

View File

@@ -0,0 +1,5 @@
if (pathsLoaded['asyncfalse2.js'] === undefined) {
pathsLoaded['asyncfalse1.js'] = true;
} else {
pathsLoaded['asyncfalse1.js'] = false;
}

View File

@@ -0,0 +1,5 @@
if (pathsLoaded['asyncfalse1.js'] === undefined) {
pathsLoaded['asyncfalse2.js'] = true;
} else {
pathsLoaded['asyncfalse2.js'] = false;
}

View File

@@ -0,0 +1,3 @@
.test-div {
width: 300px;
}

View File

@@ -0,0 +1,3 @@
.test-div {
width: 100px;
}

View File

@@ -0,0 +1 @@
pathsLoaded['file1.js'] = true;

View File

@@ -0,0 +1,3 @@
.test-div {
width: 200px;
}

View File

@@ -0,0 +1 @@
pathsLoaded['file2.js'] = true;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
<title>iTunesArtwork@2x</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="Size-Guides" sketch:type="MSLayerGroup" transform="translate(0.000000, -124.000000)"></g>
<g id="iTunesArtwork@2x" sketch:type="MSArtboardGroup">
<path d="M357.009067,0 L666.990933,0 C769.792,0 821.179733,0 876.5184,17.4933333 C936.9344,39.4837333 984.516267,87.0656 1006.50667,147.4816 C1024,202.811733 1024,254.216533 1024,357.009067 L1024,666.990933 C1024,769.792 1024,821.179733 1006.50667,876.5184 C984.516267,936.9344 936.9344,984.516267 876.5184,1006.49813 C821.179733,1024 769.792,1024 666.990933,1024 L357.009067,1024 C254.208,1024 202.811733,1024 147.4816,1006.49813 C87.0656,984.516267 39.4837333,936.9344 17.4933333,876.5184 C0,821.179733 0,769.792 0,666.990933 L0,357.009067 C0,254.216533 0,202.811733 17.4933333,147.4816 C39.4837333,87.0656 87.0656,39.4837333 147.4816,17.4933333 C202.811733,0 254.208,0 357.009067,0 L357.009067,0" id="Icon-Shape" fill="#D7D7D7" sketch:type="MSShapeGroup"></path>
<path d="M692.497264,349.385524 C697.470239,354.906145 698.437452,360.978828 695.398902,367.603573 L471.813752,846.652148 C468.227556,853.550716 462.428696,857 454.417171,857 C453.313047,857 451.378621,856.721761 448.613894,856.165282 C443.923575,854.787335 440.403627,852.163936 438.05405,848.295085 C435.704474,844.426234 435.081748,840.28356 436.185872,835.867063 L517.749735,501.31743 L349.640201,543.132822 C348.536077,543.406645 346.87989,543.543556 344.671642,543.543556 C339.698667,543.543556 335.419081,542.024281 331.832886,538.985731 C326.85991,534.843057 325.066813,529.459348 326.453593,522.834603 L409.673642,181.24949 C410.777766,177.380639 412.986014,174.205178 416.298387,171.723107 C419.61076,169.241036 423.475194,168 427.891691,168 L563.698968,168 C568.945766,168 573.362263,169.72685 576.948458,173.180551 C580.534654,176.634251 582.327751,180.706261 582.327751,185.396581 C582.327751,187.604829 581.638778,190.091317 580.260831,192.856044 L509.455554,384.562921 L673.417998,343.979732 C675.626246,343.423253 677.282433,343.145014 678.386557,343.145014 C683.633355,343.145014 688.328091,345.216351 692.470765,349.359025 L692.497264,349.385524 Z" id="Shape" fill="#C62828" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 908 B

View File

@@ -0,0 +1,308 @@
loadjs = (function () {
/**
* Global dependencies.
* @global {Object} document - DOM
*/
var devnull = function() {},
bundleIdCache = {},
bundleResultCache = {},
bundleCallbackQueue = {};
/**
* Subscribe to bundle load event.
* @param {string[]} bundleIds - Bundle ids
* @param {Function} callbackFn - The callback function
*/
function subscribe(bundleIds, callbackFn) {
// listify
bundleIds = bundleIds.push ? bundleIds : [bundleIds];
var depsNotFound = [],
i = bundleIds.length,
numWaiting = i,
fn,
bundleId,
r,
q;
// define callback function
fn = function (bundleId, pathsNotFound) {
if (pathsNotFound.length) depsNotFound.push(bundleId);
numWaiting--;
if (!numWaiting) callbackFn(depsNotFound);
};
// register callback
while (i--) {
bundleId = bundleIds[i];
// execute callback if in result cache
r = bundleResultCache[bundleId];
if (r) {
fn(bundleId, r);
continue;
}
// add to callback queue
q = bundleCallbackQueue[bundleId] = bundleCallbackQueue[bundleId] || [];
q.push(fn);
}
}
/**
* Publish bundle load event.
* @param {string} bundleId - Bundle id
* @param {string[]} pathsNotFound - List of files not found
*/
function publish(bundleId, pathsNotFound) {
// exit if id isn't defined
if (!bundleId) return;
var q = bundleCallbackQueue[bundleId];
// cache result
bundleResultCache[bundleId] = pathsNotFound;
// exit if queue is empty
if (!q) return;
// empty callback queue
while (q.length) {
q[0](bundleId, pathsNotFound);
q.splice(0, 1);
}
}
/**
* Execute callbacks.
* @param {Object or Function} args - The callback args
* @param {string[]} depsNotFound - List of dependencies not found
*/
function executeCallbacks(args, depsNotFound) {
// accept function as argument
if (args.call) args = {success: args};
// success and error callbacks
if (depsNotFound.length) (args.error || devnull)(depsNotFound);
else (args.success || devnull)(args);
}
/**
* Load individual file.
* @param {string} path - The file path
* @param {Function} callbackFn - The callback function
*/
function loadFile(path, callbackFn, args, numTries) {
var doc = document,
async = args.async,
maxTries = (args.numRetries || 0) + 1,
beforeCallbackFn = args.before || devnull,
pathname = path.replace(/[\?|#].*$/, ''),
pathStripped = path.replace(/^(css|img)!/, ''),
isLegacyIECss,
e;
numTries = numTries || 0;
if (/(^css!|\.css$)/.test(pathname)) {
// css
e = doc.createElement('link');
e.rel = 'stylesheet';
e.href = pathStripped;
// tag IE9+
isLegacyIECss = 'hideFocus' in e;
// use preload in IE Edge (to detect load errors)
if (isLegacyIECss && e.relList) {
isLegacyIECss = 0;
e.rel = 'preload';
e.as = 'style';
}
} else if (/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(pathname)) {
// image
e = doc.createElement('img');
e.src = pathStripped;
} else {
// javascript
e = doc.createElement('script');
e.src = path;
e.async = async === undefined ? true : async;
}
e.onload = e.onerror = e.onbeforeload = function (ev) {
var result = ev.type[0];
// treat empty stylesheets as failures to get around lack of onerror
// support in IE9-11
if (isLegacyIECss) {
try {
if (!e.sheet.cssText.length) result = 'e';
} catch (x) {
// sheets objects created from load errors don't allow access to
// `cssText` (unless error is Code:18 SecurityError)
if (x.code != 18) result = 'e';
}
}
// handle retries in case of load failure
if (result == 'e') {
// increment counter
numTries += 1;
// exit function and try again
if (numTries < maxTries) {
return loadFile(path, callbackFn, args, numTries);
}
} else if (e.rel == 'preload' && e.as == 'style') {
// activate preloaded stylesheets
return e.rel = 'stylesheet'; // jshint ignore:line
}
// execute callback
callbackFn(path, result, ev.defaultPrevented);
};
// add to document (unless callback returns `false`)
if (beforeCallbackFn(path, e) !== false) doc.head.appendChild(e);
}
/**
* Load multiple files.
* @param {string[]} paths - The file paths
* @param {Function} callbackFn - The callback function
*/
function loadFiles(paths, callbackFn, args) {
// listify paths
paths = paths.push ? paths : [paths];
var numWaiting = paths.length,
x = numWaiting,
pathsNotFound = [],
fn,
i;
// define callback function
fn = function(path, result, defaultPrevented) {
// handle error
if (result == 'e') pathsNotFound.push(path);
// handle beforeload event. If defaultPrevented then that means the load
// will be blocked (ex. Ghostery/ABP on Safari)
if (result == 'b') {
if (defaultPrevented) pathsNotFound.push(path);
else return;
}
numWaiting--;
if (!numWaiting) callbackFn(pathsNotFound);
};
// load scripts
for (i=0; i < x; i++) loadFile(paths[i], fn, args);
}
/**
* Initiate script load and register bundle.
* @param {(string|string[])} paths - The file paths
* @param {(string|Function|Object)} [arg1] - The (1) bundleId or (2) success
* callback or (3) object literal with success/error arguments, numRetries,
* etc.
* @param {(Function|Object)} [arg2] - The (1) success callback or (2) object
* literal with success/error arguments, numRetries, etc.
*/
function loadjs(paths, arg1, arg2) {
var bundleId,
args;
// bundleId (if string)
if (arg1 && arg1.trim) bundleId = arg1;
// args (default is {})
args = (bundleId ? arg2 : arg1) || {};
// throw error if bundle is already defined
if (bundleId) {
if (bundleId in bundleIdCache) {
throw "LoadJS";
} else {
bundleIdCache[bundleId] = true;
}
}
function loadFn(resolve, reject) {
loadFiles(paths, function (pathsNotFound) {
// execute callbacks
executeCallbacks(args, pathsNotFound);
// resolve Promise
if (resolve) {
executeCallbacks({success: resolve, error: reject}, pathsNotFound);
}
// publish bundle load event
publish(bundleId, pathsNotFound);
}, args);
}
if (args.returnPromise) return new Promise(loadFn);
else loadFn();
}
/**
* Execute callbacks when dependencies have been satisfied.
* @param {(string|string[])} deps - List of bundle ids
* @param {Object} args - success/error arguments
*/
loadjs.ready = function ready(deps, args) {
// subscribe to bundle load event
subscribe(deps, function (depsNotFound) {
// execute callbacks
executeCallbacks(args, depsNotFound);
});
return loadjs;
};
/**
* Manually satisfy bundle dependencies.
* @param {string} bundleId - The bundle id
*/
loadjs.done = function done(bundleId) {
publish(bundleId, []);
};
/**
* Reset loadjs dependencies statuses
*/
loadjs.reset = function reset() {
bundleIdCache = {};
bundleResultCache = {};
bundleCallbackQueue = {};
};
/**
* Determine if bundle has already been defined
* @param String} bundleId - The bundle id
*/
loadjs.isDefined = function isDefined(bundleId) {
return bundleId in bundleIdCache;
};
// export
return loadjs;
})();

View File

@@ -0,0 +1 @@
loadjs=function(){var h=function(){},c={},u={},f={};function o(e,n){if(e){var r=f[e];if(u[e]=n,r)for(;r.length;)r[0](e,n),r.splice(0,1)}}function l(e,n){e.call&&(e={success:e}),n.length?(e.error||h)(n):(e.success||h)(e)}function d(r,t,s,i){var c,o,e=document,n=s.async,u=(s.numRetries||0)+1,f=s.before||h,l=r.replace(/[\?|#].*$/,""),a=r.replace(/^(css|img)!/,"");i=i||0,/(^css!|\.css$)/.test(l)?((o=e.createElement("link")).rel="stylesheet",o.href=a,(c="hideFocus"in o)&&o.relList&&(c=0,o.rel="preload",o.as="style")):/(^img!|\.(png|gif|jpg|svg|webp)$)/.test(l)?(o=e.createElement("img")).src=a:((o=e.createElement("script")).src=r,o.async=void 0===n||n),!(o.onload=o.onerror=o.onbeforeload=function(e){var n=e.type[0];if(c)try{o.sheet.cssText.length||(n="e")}catch(e){18!=e.code&&(n="e")}if("e"==n){if((i+=1)<u)return d(r,t,s,i)}else if("preload"==o.rel&&"style"==o.as)return o.rel="stylesheet";t(r,n,e.defaultPrevented)})!==f(r,o)&&e.head.appendChild(o)}function r(e,n,r){var t,s;if(n&&n.trim&&(t=n),s=(t?r:n)||{},t){if(t in c)throw"LoadJS";c[t]=!0}function i(n,r){!function(e,t,n){var r,s,i=(e=e.push?e:[e]).length,c=i,o=[];for(r=function(e,n,r){if("e"==n&&o.push(e),"b"==n){if(!r)return;o.push(e)}--i||t(o)},s=0;s<c;s++)d(e[s],r,n)}(e,function(e){l(s,e),n&&l({success:n,error:r},e),o(t,e)},s)}if(s.returnPromise)return new Promise(i);i()}return r.ready=function(e,n){return function(e,r){e=e.push?e:[e];var n,t,s,i=[],c=e.length,o=c;for(n=function(e,n){n.length&&i.push(e),--o||r(i)};c--;)t=e[c],(s=u[t])?n(t,s):(f[t]=f[t]||[]).push(n)}(e,function(e){l(n,e)}),r},r.done=function(e){o(e,[])},r.reset=function(){c={},u={},f={}},r.isDefined=function(e){return e in c},r}();

View File

@@ -0,0 +1,22 @@
<!doctype html>
<html>
<head>
<title>Mocha</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="vendor/mocha-4.1.0/mocha.css">
</head>
<body>
<div id="mocha"></div>
<script src="vendor/mocha-4.1.0/mocha.js"></script>
<script src="vendor/chai-4.1.2.js"></script>
<script src="assets/loadjs/loadjs.js"></script>
<script>mocha.setup('bdd')</script>
<script src="tests.js"></script>
<script>
//mocha.checkLeaks();
mocha.globals(['loadjs', 'pathsLoaded', 'script*']);
mocha.run();
</script>
</body>
</html>

View File

@@ -0,0 +1,817 @@
/**
* loadjs tests
* @module test/tests.js
*/
var pathsLoaded = null, // file register
testEl = null,
assert = chai.assert,
expect = chai.expect;
describe('LoadJS tests', function() {
beforeEach(function() {
// reset register
pathsLoaded = {};
// reset loadjs dependencies
loadjs.reset();
});
// ==========================================================================
// JavaScript file loading tests
// ==========================================================================
describe('JavaScript file loading tests', function() {
it('should call success callback on valid path', function(done) {
loadjs(['assets/file1.js'], {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
done();
}
});
});
it('should call error callback on invalid path', function(done) {
loadjs(['assets/file-doesntexist.js'], {
success: function() {
throw "Executed success callback";
},
error: function(pathsNotFound) {
assert.equal(pathsNotFound.length, 1);
assert.equal(pathsNotFound[0], 'assets/file-doesntexist.js');
done();
}
});
});
it('should call before callback before embedding into document', function(done) {
var scriptTags = [];
loadjs(['assets/file1.js', 'assets/file2.js'], {
before: function(path, el) {
scriptTags.push({
path: path,
el: el
});
// add cross origin script for file2
if (path === 'assets/file2.js') {
el.crossOrigin = 'anonymous';
}
},
success: function() {
assert.equal(scriptTags[0].path, 'assets/file1.js');
assert.equal(scriptTags[1].path, 'assets/file2.js');
assert.equal(scriptTags[0].el.crossOrigin, undefined);
assert.equal(scriptTags[1].el.crossOrigin, 'anonymous');
done();
}
});
});
it('should bypass insertion if before returns `false`', function(done) {
loadjs(['assets/file1.js'], {
before: function(path, el) {
// append to body (instead of head)
document.body.appendChild(el);
// return `false` to bypass default DOM insertion
return false;
},
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
// verify that file was added to body
var els = document.body.querySelectorAll('script'),
el;
for (var i=0; i < els.length; i++) {
el = els[i];
if (el.src.indexOf('assets/file1.js') !== -1) done();
}
}
});
});
it('should call success callback on two valid paths', function(done) {
loadjs(['assets/file1.js', 'assets/file2.js'], {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(pathsLoaded['file2.js'], true);
done();
}
});
});
it('should call error callback on one invalid path', function(done) {
loadjs(['assets/file1.js', 'assets/file-doesntexist.js'], {
success: function() {
throw "Executed success callback";
},
error: function(pathsNotFound) {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(pathsNotFound.length, 1);
assert.equal(pathsNotFound[0], 'assets/file-doesntexist.js');
done();
}
});
});
it('should support async false', function(done) {
this.timeout(5000);
var numCompleted = 0,
numTests = 20,
paths = ['assets/asyncfalse1.js', 'assets/asyncfalse2.js'];
// run tests sequentially
var testFn = function(paths) {
// add cache busters
var pathsUncached = paths.slice(0);
pathsUncached[0] += '?_=' + Math.random();
pathsUncached[1] += '?_=' + Math.random();
loadjs(pathsUncached, {
success: function() {
var f1 = paths[0].replace('assets/', '');
var f2 = paths[1].replace('assets/', '');
// check load order
assert.isTrue(pathsLoaded[f1]);
assert.isFalse(pathsLoaded[f2]);
// increment tests
numCompleted += 1;
if (numCompleted === numTests) {
// exit
done();
} else {
// reset register
pathsLoaded = {};
// run test again
paths.reverse();
testFn(paths);
}
},
async: false
});
};
// run tests
testFn(paths);
});
it('should support multiple tries', function(done) {
loadjs('assets/file-numretries.js', {
error: function() {
// check number of scripts in document
var selector = 'script[src="assets/file-numretries.js"]',
scripts = document.querySelectorAll(selector);
if (scripts.length === 2) done();
},
numRetries: 1
});
});
// Un-'x' this for testing ad blocked scripts.
// Ghostery: Disallow "Google Adservices"
// AdBlock Plus: Add "www.googletagservices.com/tag/js/gpt.js" as a
// custom filter under Options
//
xit('it should report ad blocked scripts as missing', function(done) {
var s1 = 'https://www.googletagservices.com/tag/js/gpt.js',
s2 = 'https://munchkin.marketo.net/munchkin-beta.js';
loadjs([s1, s2, 'assets/file1.js'], {
success: function() {
throw new Error('Executed success callback');
},
error: function(pathsNotFound) {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(pathsNotFound.length, 2);
assert.equal(pathsNotFound[0], s1);
assert.equal(pathsNotFound[1], s2);
done();
}
});
});
});
// ==========================================================================
// CSS file loading tests
// ==========================================================================
describe('CSS file loading tests', function() {
before(function() {
// add test div to body for css tests
testEl = document.createElement('div');
testEl.className = 'test-div mui-container';
testEl.style.display = 'inline-block';
document.body.appendChild(testEl);
});
afterEach(function() {
var els = document.getElementsByTagName('link'),
i = els.length,
el;
// iteratete through stylesheets
while (i--) {
el = els[i];
// remove test stylesheets
if (el.href.indexOf('mocha.css') === -1) {
el.parentNode.removeChild(el);
}
}
});
it('should load one file', function(done) {
loadjs(['assets/file1.css'], {
success: function() {
assert.equal(testEl.offsetWidth, 100);
done();
}
});
});
it('should load multiple files', function(done) {
loadjs(['assets/file1.css', 'assets/file2.css'], {
success: function() {
assert.equal(testEl.offsetWidth, 200);
done();
}
});
});
it('should call error callback on one invalid path', function(done) {
loadjs(['assets/file1.css', 'assets/file-doesntexist.css'], {
success: function() {
throw new Error('Executed success callback');
},
error: function(pathsNotFound) {
assert.equal(testEl.offsetWidth, 100);
assert.equal(pathsNotFound.length, 1);
assert.equal(pathsNotFound[0], 'assets/file-doesntexist.css');
done();
}
});
});
it('should support mix of css and js', function(done) {
loadjs(['assets/file1.css', 'assets/file1.js'], {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(testEl.offsetWidth, 100);
done();
}
});
});
it('should support forced "css!" files', function(done) {
loadjs(['css!assets/file1.css'], {
success: function() {
// loop through files
var els = document.getElementsByTagName('link'),
i = els.length,
el;
while (i--) {
if (els[i].href.indexOf('file1.css') !== -1) done();
}
}
});
});
it('supports urls with query arguments', function(done) {
loadjs(['assets/file1.css?x=x'], {
success: function() {
assert.equal(testEl.offsetWidth, 100);
done();
}
});
});
it('supports urls with anchor tags', function(done) {
loadjs(['assets/file1.css#anchortag'], {
success: function() {
assert.equal(testEl.offsetWidth, 100);
done();
}
});
});
it('supports urls with query arguments and anchor tags', function(done) {
loadjs(['assets/file1.css?x=x#anchortag'], {
success: function() {
assert.equal(testEl.offsetWidth, 100);
done();
}
});
});
it('should load external css files', function(done) {
this.timeout(0);
loadjs(['//cdn.muicss.com/mui-0.6.8/css/mui.min.css'], {
success: function() {
var styleObj = getComputedStyle(testEl);
assert.equal(styleObj.getPropertyValue('padding-left'), '15px');
done();
}
});
});
it('should call error on missing external file', function(done) {
this.timeout(0);
loadjs(['//cdn.muicss.com/mui-0.6.8/css/mui-doesnotexist.min.css'], {
success: function() {
throw new Error('Executed success callback');
},
error: function(pathsNotFound) {
var styleObj = getComputedStyle(testEl);
assert.equal(styleObj.getPropertyValue('padding-left'), '0px');
assert.equal(pathsNotFound.length, 1);
done();
}
});
});
// teardown
return after(function() {
// remove test div
testEl.parentNode.removeChild(testEl);
});
});
// ==========================================================================
// Image file loading tests
// ==========================================================================
describe('Image file loading tests', function() {
function assertLoaded(src) {
// loop through images
var imgs = document.getElementsByTagName('img');
Array.prototype.slice.call(imgs).forEach(function(img) {
// verify image was loaded
if (img.src === src) assert.equal(img.naturalWidth > 0, true);
});
}
function assertNotLoaded(src) {
// loop through images
var imgs = document.getElementsByTagName('img');
Array.prototype.slice.call(imgs).forEach(function(img) {
// fail if image was loaded
if (img.src === src) assert.equal(img.naturalWidth, 0);
});
}
it('should load one file', function(done) {
loadjs(['assets/flash.png'], {
success: function() {
assertLoaded('assets/flash.png');
done();
}
});
});
it('should load multiple files', function(done) {
loadjs(['assets/flash.png', 'assets/flash.jpg'], {
success: function() {
assertLoaded('assets/flash.png');
assertLoaded('assets/flash.jpg');
done();
}
});
});
it('detects png|gif|jpg|svg|webp extensions', function(done) {
let files = [
'assets/flash.png',
'assets/flash.gif',
'assets/flash.jpg',
'assets/flash.svg',
'assets/flash.webp'
];
loadjs(files, function() {
files.forEach(file => {assertLoaded(file);});
done();
});
});
it('supports urls with query arguments', function(done) {
var src = 'assets/flash.png?' + Math.random();
loadjs([src], {
success: function() {
assertLoaded(src);
done();
}
});
});
it('supports urls with anchor tags', function(done) {
var src = 'assets/flash.png#' + Math.random();
loadjs([src], {
success: function() {
assertLoaded(src);
done();
}
});
});
it('supports urls with query arguments and anchor tags', function(done) {
var src = 'assets/flash.png';
src += '?' + Math.random();
src += '#' + Math.random();
loadjs([src], {
success: function() {
assertLoaded(src);
done();
}
});
});
it('should support forced "img!" files', function(done) {
var src = 'assets/flash.png?' + Math.random();
loadjs(['img!' + src], {
success: function() {
assertLoaded(src);
done();
}
});
});
it('should call error callback on one invalid path', function(done) {
var src1 = 'assets/flash.png?' + Math.random(),
src2 = 'assets/flash-doesntexist.png?' + Math.random();
loadjs(['img!' + src1, 'img!' + src2], {
success: function() {
throw new Error('Executed success callback');
},
error: function(pathsNotFound) {
assert.equal(pathsNotFound.length, 1);
assertLoaded(src1);
assertNotLoaded(src2);
done();
}
});
});
it('should support mix of img and js', function(done) {
var src = 'assets/flash.png?' + Math.random();
loadjs(['img!' + src, 'assets/file1.js'], {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
assertLoaded(src);
done();
}
});
});
it('should load external img files', function(done) {
this.timeout(0);
var src = 'https://www.muicss.com/static/images/mui-logo.png?';
src += Math.random();
loadjs(['img!' + src], {
success: function() {
assertLoaded(src);
done();
}
});
});
it('should call error on missing external file', function(done) {
this.timeout(0);
var src = 'https://www.muicss.com/static/images/';
src += 'mui-logo-doesntexist.png?' + Math.random();
loadjs(['img!' + src], {
success: function() {
throw new Error('Executed success callback');
},
error: function(pathsNotFound) {
assertNotLoaded(src);
done();
}
});
});
});
// ==========================================================================
// API tests
// ==========================================================================
describe('API tests', function() {
it('should throw an error if bundle is already defined', function() {
// define bundle
loadjs(['assets/file1.js'], 'bundle');
// define bundle again
var fn = function() {
loadjs(['assets/file1.js'], 'bundle');
};
expect(fn).to.throw("LoadJS");
});
it('should create a bundle id and a callback inline', function(done) {
loadjs(['assets/file1.js', 'assets/file2.js'], 'bundle', {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(pathsLoaded['file2.js'], true);
done();
}
});
});
it('should chain loadjs object', function(done) {
function bothDone() {
if (pathsLoaded['file1.js'] && pathsLoaded['file2.js']) done();
}
// define bundles
loadjs('assets/file1.js', 'bundle1');
loadjs('assets/file2.js', 'bundle2');
loadjs
.ready('bundle1', {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
bothDone();
}})
.ready('bundle2', {
success: function() {
assert.equal(pathsLoaded['file2.js'], true);
bothDone();
}
});
});
it('should handle multiple dependencies', function(done) {
loadjs('assets/file1.js', 'bundle1');
loadjs('assets/file2.js', 'bundle2');
loadjs.ready(['bundle1', 'bundle2'], {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(pathsLoaded['file2.js'], true);
done();
}
});
});
it('should error on missing depdendencies', function(done) {
loadjs('assets/file1.js', 'bundle1');
loadjs('assets/file-doesntexist.js', 'bundle2');
loadjs.ready(['bundle1', 'bundle2'], {
success: function() {
throw "Executed success callback";
},
error: function(depsNotFound) {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(depsNotFound.length, 1);
assert.equal(depsNotFound[0], 'bundle2');
done();
}
});
});
it('should execute callbacks on .done()', function(done) {
// add handler
loadjs.ready('plugin', {
success: function() {
done();
}
});
// execute done
loadjs.done('plugin');
});
it('should execute callbacks created after .done()', function(done) {
// execute done
loadjs.done('plugin');
// add handler
loadjs.ready('plugin', {
success: function() {
done();
}
});
});
it('should define bundles', function(done) {
// define bundle
loadjs(['assets/file1.js', 'assets/file2.js'], 'bundle');
// use 1 second delay to let files load
setTimeout(function() {
loadjs.ready('bundle', {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(pathsLoaded['file2.js'], true);
done();
}
});
}, 1000);
});
it('should allow bundle callbacks before definitions', function(done) {
// define callback
loadjs.ready('bundle', {
success: function() {
assert.equal(pathsLoaded['file1.js'], true);
assert.equal(pathsLoaded['file2.js'], true);
done();
}
});
// use 1 second delay
setTimeout(function() {
loadjs(['assets/file1.js', 'assets/file2.js'], 'bundle');
}, 1000);
});
it('should reset dependencies statuses', function() {
loadjs(['assets/file1.js'], 'cleared');
loadjs.reset();
// define bundle again
var fn = function() {
loadjs(['assets/file1.js'], 'cleared');
};
expect(fn).not.to.throw("LoadJS");
});
it('should indicate if bundle has already been defined', function() {
loadjs(['assets/file1/js'], 'bundle1');
assert.equal(loadjs.isDefined('bundle1'), true);
assert.equal(loadjs.isDefined('bundleXX'), false);
});
it('should accept success callback functions to loadjs()', function(done) {
loadjs('assets/file1.js', function() {
done();
});
});
it('should accept success callback functions to .ready()', function(done) {
loadjs.done('plugin');
loadjs.ready('plugin', function() {
done();
});
});
it('should return Promise object if returnPromise is true', function() {
var prom = loadjs(['assets/file1.js'], {returnPromise: true});
// verify that response object is a Promise
assert.equal(prom instanceof Promise, true);
});
it('Promise object should support resolutions', function(done) {
var prom = loadjs(['assets/file1.js'], {returnPromise: true});
prom.then(function() {
assert.equal(pathsLoaded['file1.js'], true);
done();
});
});
it('Promise object should support rejections', function(done) {
var prom = loadjs(['assets/file-doesntexist.js'], {returnPromise: true});
prom.then(
function(){},
function(pathsNotFound) {
assert.equal(pathsNotFound.length, 1);
assert.equal(pathsNotFound[0], 'assets/file-doesntexist.js');
done();
}
);
});
it('Promise object should support catches', function(done) {
var prom = loadjs(['assets/file-doesntexist.js'], {returnPromise: true});
prom
.catch(function(pathsNotFound) {
assert.equal(pathsNotFound.length, 1);
assert.equal(pathsNotFound[0], 'assets/file-doesntexist.js');
done();
});
});
it('supports Promises and success callbacks', function(done) {
var numCompleted = 0;
function completedFn() {
numCompleted += 1;
if (numCompleted === 2) done();
};
var prom = loadjs('assets/file1.js', {
success: completedFn,
returnPromise: true
});
prom.then(completedFn);
});
it('supports Promises and bundle ready events', function(done) {
var numCompleted = 0;
function completedFn() {
numCompleted += 1;
if (numCompleted === 2) done();
};
loadjs('assets/file1.js', 'bundle1', {returnPromise: true})
.then(completedFn);
loadjs.ready('bundle1', completedFn);
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,326 @@
@charset "utf-8";
body {
margin:0;
}
#mocha {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 60px 50px;
}
#mocha ul,
#mocha li {
margin: 0;
padding: 0;
}
#mocha ul {
list-style: none;
}
#mocha h1,
#mocha h2 {
margin: 0;
}
#mocha h1 {
margin-top: 15px;
font-size: 1em;
font-weight: 200;
}
#mocha h1 a {
text-decoration: none;
color: inherit;
}
#mocha h1 a:hover {
text-decoration: underline;
}
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
}
#mocha .hidden {
display: none;
}
#mocha h2 {
font-size: 12px;
font-weight: normal;
cursor: pointer;
}
#mocha .suite {
margin-left: 15px;
}
#mocha .test {
margin-left: 15px;
overflow: hidden;
}
#mocha .test.pending:hover h2::after {
content: '(pending)';
font-family: arial, sans-serif;
}
#mocha .test.pass.medium .duration {
background: #c09853;
}
#mocha .test.pass.slow .duration {
background: #b94a48;
}
#mocha .test.pass::before {
content: '✓';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #00d6b2;
}
#mocha .test.pass .duration {
font-size: 9px;
margin-left: 5px;
padding: 2px 5px;
color: #fff;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
#mocha .test.pass.fast .duration {
display: none;
}
#mocha .test.pending {
color: #0b97c4;
}
#mocha .test.pending::before {
content: '◦';
color: #0b97c4;
}
#mocha .test.fail {
color: #c00;
}
#mocha .test.fail pre {
color: black;
}
#mocha .test.fail::before {
content: '✖';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #c00;
}
#mocha .test pre.error {
color: #c00;
max-height: 300px;
overflow: auto;
}
#mocha .test .html-error {
overflow: auto;
color: black;
line-height: 1.5;
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
max-height: 300px;
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test .html-error pre.error {
border: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: 0;
-moz-box-shadow: 0;
box-shadow: 0;
padding: 0;
margin: 0;
margin-top: 18px;
max-height: none;
}
/**
* (1): approximate for browsers not supporting calc
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
* ^^ seriously
*/
#mocha .test pre {
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test h2 {
position: relative;
}
#mocha .test a.replay {
position: absolute;
top: 3px;
right: 0;
text-decoration: none;
vertical-align: middle;
display: block;
width: 15px;
height: 15px;
line-height: 15px;
text-align: center;
background: #eee;
font-size: 15px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
-webkit-transition:opacity 200ms;
-moz-transition:opacity 200ms;
-o-transition:opacity 200ms;
transition: opacity 200ms;
opacity: 0.3;
color: #888;
}
#mocha .test:hover a.replay {
opacity: 1;
}
#mocha-report.pass .test.fail {
display: none;
}
#mocha-report.fail .test.pass {
display: none;
}
#mocha-report.pending .test.pass,
#mocha-report.pending .test.fail {
display: none;
}
#mocha-report.pending .test.pass.pending {
display: block;
}
#mocha-error {
color: #c00;
font-size: 1.5em;
font-weight: 100;
letter-spacing: 1px;
}
#mocha-stats {
position: fixed;
top: 15px;
right: 10px;
font-size: 12px;
margin: 0;
color: #888;
z-index: 1;
}
#mocha-stats .progress {
float: right;
padding-top: 0;
/**
* Set safe initial values, so mochas .progress does not inherit these
* properties from Bootstrap .progress (which causes .progress height to
* equal line height set in Bootstrap).
*/
height: auto;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
background-color: initial;
}
#mocha-stats em {
color: black;
}
#mocha-stats a {
text-decoration: none;
color: inherit;
}
#mocha-stats a:hover {
border-bottom: 1px solid #eee;
}
#mocha-stats li {
display: inline-block;
margin: 0 5px;
list-style: none;
padding-top: 11px;
}
#mocha-stats canvas {
width: 40px;
height: 40px;
}
#mocha code .comment { color: #ddd; }
#mocha code .init { color: #2f6fad; }
#mocha code .string { color: #5890ad; }
#mocha code .keyword { color: #8a6343; }
#mocha code .number { color: #2f6fad; }
@media screen and (max-device-width: 480px) {
#mocha {
margin: 60px 0px;
}
#mocha #stats {
position: absolute;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(<%= amd %>, factory);
} else if (typeof exports === 'object') {
module.exports = factory(<%= cjs %>);
} else {
root.<%= namespace %> = factory(<%= global %>);
}
}(this, function(<%= param %>) {
<%= contents %>
}));

View File

@@ -0,0 +1,3 @@
<%= namespace %> = (function (<%= param %>) {
<%= contents %>
})(<%= global %>);