resource-loader
Advanced tools
Comparing version 1.1.2 to 1.1.3
@@ -48,3 +48,3 @@ # How to contribute | ||
so you can test, *however* please do not commit the new builds placed in `dist/` or your PR will be closed. By default | ||
the build process will output to an ignored folder (`build/`) you should be fine. | ||
the `dist/` folder is ignored so this shouldn't happen by accident. | ||
@@ -51,0 +51,0 @@ - **Only commit relevant changes.** Don't include changes that are not directly relevant to the fix you are making. |
{ | ||
"name": "resource-loader", | ||
"version": "1.1.2", | ||
"version": "1.1.3", | ||
"main": "./src/index.js", | ||
@@ -5,0 +5,0 @@ "description": "A generic asset loader, made with web games in mind.", |
@@ -1,4 +0,4 @@ | ||
# Asset Loader [![Build Status](https://travis-ci.org/englercj/asset-loader.svg?branch=master)](https://travis-ci.org/englercj/asset-loader) | ||
# Resource Loader [![Build Status](https://travis-ci.org/englercj/resource-loader.svg?branch=master)](https://travis-ci.org/englercj/resource-loader) | ||
A generic asset loader, made with web games in mind. | ||
A generic resource loader, made with web games in mind. | ||
@@ -11,23 +11,24 @@ ## Usage | ||
// chainable `add` to enqueue a resource | ||
loader.add(url, options); | ||
loader | ||
// chainable `add` to enqueue a resource | ||
.add(url, options) | ||
// chainable `before` to add a middleware that runs for each resource, *before* loading a resource. | ||
// this is useful to implement custom caching modules (using filesystem, indexeddb, memory, etc). | ||
loader.before(cachingMiddleware); | ||
// chainable `before` to add a middleware that runs for each resource, *before* loading a resource. | ||
// this is useful to implement custom caching modules (using filesystem, indexeddb, memory, etc). | ||
.before(cachingMiddleware); | ||
// chainable `after` to add a middleware that runs for each resource, *after* loading a resource. | ||
// this is useful to implement custom parsing modules (like spritesheet parsers, spine parser, etc). | ||
loader.after(parsingMiddleware); | ||
// chainable `after` to add a middleware that runs for each resource, *after* loading a resource. | ||
// this is useful to implement custom parsing modules (like spritesheet parsers, spine parser, etc). | ||
.after(parsingMiddleware); | ||
// `load` method loads the queue of resources, and calls the passed in callback called once all | ||
// resources have loaded. | ||
loader.load(function (resources) { | ||
// resources is an array of resource objects that have a couple properties: | ||
// - `url`: The URL that the resource was loaded from | ||
// - `error`: The error that happened when trying to load (if any) | ||
// - `data`: The raw data that was loaded | ||
// also may contain other properties based on the middleware that runs. | ||
}); | ||
// `load` method loads the queue of resources, and calls the passed in callback called once all | ||
// resources have loaded. | ||
.load(function (resources) { | ||
// resources is an array of resource objects that have a couple properties: | ||
// - `url`: The URL that the resource was loaded from | ||
// - `error`: The error that happened when trying to load (if any) | ||
// - `data`: The raw data that was loaded | ||
// also may contain other properties based on the middleware that runs. | ||
}); | ||
@@ -67,3 +68,1 @@ // throughout the process multiple events can happen. | ||
- IE 9 support | ||
- Video load support | ||
- Multi-source elements (audio/video) |
@@ -283,8 +283,2 @@ var async = require('async'), | ||
function _mapQueue(obj, res) { | ||
obj[res.name] = res; | ||
return obj; | ||
} | ||
/** | ||
@@ -313,3 +307,5 @@ * Called each time a resources is loaded. | ||
cb && cb(); | ||
if (cb) { | ||
cb(); | ||
} | ||
}); | ||
@@ -316,0 +312,0 @@ }; |
@@ -13,15 +13,20 @@ var Resource = require('../../Resource'); | ||
if (resource.data.type.indexOf('image') === 0) { | ||
var src = URL.createObjectURL(resource.data); | ||
resource.data = new Image(); | ||
resource.data.src = URL.createObjectURL(resource.data); | ||
resource.data.src = src; | ||
// cleanup the no longer used blob after the image loads | ||
resource.data.onload = function () { | ||
URL.revokeObjectURL(resource.data.src); | ||
URL.revokeObjectURL(src); | ||
resource.data.onload = null; | ||
next(); | ||
}; | ||
} | ||
} | ||
next(); | ||
else { | ||
next(); | ||
} | ||
}; | ||
}; |
@@ -1,2 +0,4 @@ | ||
var EventEmitter2 = require('eventemitter2').EventEmitter2; | ||
var EventEmitter2 = require('eventemitter2').EventEmitter2, | ||
// tests is CORS is supported in XHR, if not we need to use XDR | ||
useXdr = !!(window.XDomainRequest && !('withCredentials' in (new XMLHttpRequest()))); | ||
@@ -67,3 +69,3 @@ /** | ||
*/ | ||
this.xhrType = options.xhrType || Resource.XHR_RESPONSE_TYPE.DEFAULT; | ||
this.xhrType = options.xhrType; | ||
@@ -111,5 +113,6 @@ /** | ||
// xhr callbacks | ||
this._xhrOnError = null; | ||
this._xhrOnAbort = null; | ||
this._xhrOnLoad = null; | ||
this._boundXhrOnError = this._xhrOnError.bind(this); | ||
this._boundXhrOnAbort = this._xhrOnAbort.bind(this); | ||
this._boundXhrOnLoad = this._xhrOnLoad.bind(this); | ||
this._boundXdrOnTimeout = this._xdrOnTimeout.bind(this); | ||
@@ -150,2 +153,3 @@ /** | ||
Resource.prototype.complete = function () { | ||
// TODO: Clean this up in a wrapper or something...gross.... | ||
if (this.data && this.data.removeEventListener) { | ||
@@ -159,6 +163,14 @@ this.data.removeEventListener('error', this._boundOnError); | ||
if (this.xhr) { | ||
this.xhr.removeEventListener('error', this._xhrOnError); | ||
this.xhr.removeEventListener('abort', this._xhrOnAbort); | ||
this.xhr.removeEventListener('progress', this._boundOnProgress); | ||
this.xhr.removeEventListener('load', this._xhrOnLoad); | ||
if (this.xhr.removeEventListener) { | ||
this.xhr.removeEventListener('error', this._boundXhrOnError); | ||
this.xhr.removeEventListener('abort', this._boundXhrOnAbort); | ||
this.xhr.removeEventListener('progress', this._boundOnProgress); | ||
this.xhr.removeEventListener('load', this._boundXhrOnLoad); | ||
} | ||
else { | ||
this.xhr.onerror = null; | ||
this.xhr.ontimeout = null; | ||
this.xhr.onprogress = null; | ||
this.xhr.onload = null; | ||
} | ||
} | ||
@@ -198,3 +210,8 @@ | ||
default: | ||
this._loadXhr(); | ||
if (useXdr) { | ||
this._loadXdr(); | ||
} | ||
else { | ||
this._loadXhr(); | ||
} | ||
break; | ||
@@ -259,4 +276,3 @@ } | ||
var self = this, | ||
xhr = this.xhr = new XMLHttpRequest(); | ||
var xhr = this.xhr = new XMLHttpRequest(); | ||
@@ -266,37 +282,7 @@ // set the responseType | ||
// handle a load error | ||
xhr.addEventListener('error', this._xhrOnError = function () { | ||
self.error = new Error('XHR request failed. Status: ' + xhr.status + ', text: "' + xhr.statusText + '"'); | ||
self.complete(); | ||
}, false); | ||
// handle an aborted request | ||
xhr.addEventListener('abort', this._xhrOnAbort = function () { | ||
self.error = new Error('XHR request was aborted by the user.'); | ||
self.complete(); | ||
}, false); | ||
// handle progress events | ||
xhr.addEventListener('error', this._boundXhrOnError, false); | ||
xhr.addEventListener('abort', this._boundXhrOnAbort, false); | ||
xhr.addEventListener('progress', this._boundOnProgress, false); | ||
xhr.addEventListener('load', this._boundXhrOnLoad, false); | ||
// handle a successful load | ||
xhr.addEventListener('load', this._xhrOnLoad = function () { | ||
if (xhr.status === 200) { | ||
if (self.xhrType === Resource.XHR_RESPONSE_TYPE.TEXT) { | ||
self.data = xhr.responseText; | ||
} | ||
else if (self.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { | ||
self.data = xhr.responseXML || xhr.response; | ||
} | ||
else { | ||
self.data = xhr.response; | ||
} | ||
} | ||
else { | ||
self.error = new Error(xhr.responseText); | ||
} | ||
self.complete(); | ||
}, false); | ||
xhr.open('GET', this.url, true); | ||
@@ -307,2 +293,21 @@ xhr.send(); | ||
/** | ||
* Loads this resources using an XDomainRequest. This is here because we need to support IE9 (gross). | ||
* | ||
* @private | ||
*/ | ||
Resource.prototype._loadXdr = function () { | ||
var xdr = this.xhr = new XDomainRequest(); | ||
// XDomainRequest has a few quirks. Occasionally it will abort requests | ||
// A way to avoid this is to make sure ALL callbacks are set even if not used | ||
// More info here: http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9 | ||
xdr.timeout = 5000; | ||
xdr.onerror = this._boundXhrOnError; | ||
xdr.ontimeout = this._boundXdrOnTimeout; | ||
xdr.onprogress = this._boundOnProgress; | ||
xdr.onload = this._boundXhrOnLoad; | ||
}; | ||
/** | ||
* Creates a source used in loading via an element. | ||
@@ -340,6 +345,6 @@ * | ||
/** | ||
* Called if a load progress event fires. | ||
* Called if a load progress event fires for xhr/xdr. | ||
* | ||
* @fires progress | ||
* @param event {XMLHttpRequestProgressEvent} | ||
* @param event {XMLHttpRequestProgressEvent|Event} | ||
* @private | ||
@@ -354,2 +359,70 @@ */ | ||
/** | ||
* Called if an error event fires for xhr/xdr. | ||
* | ||
* @param event {XMLHttpRequestErrorEvent|Event} | ||
* @private | ||
*/ | ||
Resource.prototype._xhrOnError = function (event) { | ||
this.error = new Error( | ||
reqType(event.target) + ' Request failed. ' + | ||
'Status: ' + event.target.status + ', text: "' + event.target.statusText + '"' | ||
); | ||
this.complete(); | ||
}; | ||
/** | ||
* Called if an abort event fires for xhr. | ||
* | ||
* @param event {XMLHttpRequestAbortEvent} | ||
* @private | ||
*/ | ||
Resource.prototype._xhrOnAbort = function (event) { | ||
this.error = new Error(reqType(event.target) + ' Request was aborted by the user.'); | ||
this.complete(); | ||
}; | ||
/** | ||
* Called if a timeout event fires for xdr. | ||
* | ||
* @param event {Event} | ||
* @private | ||
*/ | ||
Resource.prototype._xdrOnTimeout = function (event) { | ||
this.error = new Error(reqType(event.target) + ' Request timed out.'); | ||
this.complete(); | ||
}; | ||
/** | ||
* Called when data successfully loads from an xhr/xdr request. | ||
* | ||
* @param event {XMLHttpRequestLoadEvent|Event} | ||
* @private | ||
*/ | ||
Resource.prototype._xhrOnLoad = function (event) { | ||
var xhr = event.target; | ||
if (xhr.status === 200) { | ||
if (this.xhrType === Resource.XHR_RESPONSE_TYPE.TEXT) { | ||
this.data = xhr.responseText; | ||
} | ||
else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { | ||
this.data = xhr.responseXML || xhr.response; | ||
} | ||
else { | ||
this.data = xhr.response; | ||
} | ||
} | ||
else { | ||
this.error = new Error(xhr.responseText); | ||
} | ||
this.complete(); | ||
}; | ||
function reqType(xhr) { | ||
return xhr.toString().replace('object ', ''); | ||
} | ||
/** | ||
* Sets the `crossOrigin` property for this resource based on if the url | ||
@@ -382,2 +455,9 @@ * for this resource is cross-origin. If crossOrigin was manually set, this | ||
/** | ||
* Determines the responseType of an XHR request based on the extension of the | ||
* resource being loaded. | ||
* | ||
* @private | ||
* @return {Resource.XHR_RESPONSE_TYPE} The responseType to use. | ||
*/ | ||
Resource.prototype._determineXhrType = function () { | ||
@@ -420,2 +500,9 @@ var ext = this.url.substr(this.url.lastIndexOf('.') + 1); | ||
/** | ||
* Determines the mime type of an XHR request based on the responseType of | ||
* resource being loaded. | ||
* | ||
* @private | ||
* @return {string} The mime type to use. | ||
*/ | ||
Resource.prototype._getMimeFromXhrType = function (type) { | ||
@@ -422,0 +509,0 @@ switch(type) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
47581
1046
67