asset-preloader
Advanced tools
Comparing version 0.1.3 to 0.1.4
@@ -7,102 +7,64 @@ 'use strict'; | ||
function _unsupportedIterableToArray(o, minLen) { | ||
if (!o) return; | ||
if (typeof o === "string") return _arrayLikeToArray(o, minLen); | ||
var n = Object.prototype.toString.call(o).slice(8, -1); | ||
if (n === "Object" && o.constructor) n = o.constructor.name; | ||
if (n === "Map" || n === "Set") return Array.from(o); | ||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); | ||
} | ||
function _extends() { | ||
_extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
function _arrayLikeToArray(arr, len) { | ||
if (len == null || len > arr.length) len = arr.length; | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; | ||
return target; | ||
}; | ||
return arr2; | ||
return _extends.apply(this, arguments); | ||
} | ||
function _createForOfIteratorHelperLoose(o, allowArrayLike) { | ||
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; | ||
if (it) return (it = it.call(o)).next.bind(it); | ||
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { | ||
if (it) o = it; | ||
var i = 0; | ||
return function () { | ||
if (i >= o.length) return { | ||
done: true | ||
}; | ||
return { | ||
done: false, | ||
value: o[i++] | ||
}; | ||
}; | ||
} | ||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); | ||
} | ||
var getItemByUrl = function getItemByUrl(context) { | ||
var getItemByUrl = function getItemByUrl(items) { | ||
return function (url) { | ||
for (var _iterator = _createForOfIteratorHelperLoose(context.state), _step; !(_step = _iterator()).done;) { | ||
var item = _step.value; | ||
if (item.url == url) return item; | ||
} | ||
return null; | ||
return items.find(function (item) { | ||
return item.url === url; | ||
}); | ||
}; | ||
}; | ||
var cancel = function cancel(context) { | ||
return function () { | ||
for (var _iterator2 = _createForOfIteratorHelperLoose(context.state), _step2; !(_step2 = _iterator2()).done;) { | ||
var item = _step2.value; | ||
if (item.completion < 1) { | ||
item.xhr.abort(); | ||
item.status = 0; | ||
} | ||
} | ||
var getTotalProgress = function getTotalProgress(items) { | ||
var maxProgress = items.length; | ||
var sumProgress = items.reduce(function (acc, itemState) { | ||
return itemState.progress ? acc + itemState.progress : acc; | ||
}, 0); | ||
var totalProgress = sumProgress / maxProgress; | ||
return totalProgress; | ||
}; | ||
context.onCancel(context.state); | ||
return context.state; | ||
var preloadAsset = function preloadAsset(_ref) { | ||
var url = _ref.url, | ||
onProgress = _ref.onProgress, | ||
onComplete = _ref.onComplete, | ||
onError = _ref.onError, | ||
_ref$responseType = _ref.responseType, | ||
responseType = _ref$responseType === void 0 ? 'blob' : _ref$responseType; | ||
var asset = { | ||
url: url | ||
}; | ||
}; | ||
var updateProgress = function updateProgress(context) { | ||
return function (item) { | ||
var sumCompletion = 0; | ||
var maxCompletion = context.state.length; | ||
for (var _iterator3 = _createForOfIteratorHelperLoose(context.state), _step3; !(_step3 = _iterator3()).done;) { | ||
var itemState = _step3.value; | ||
if (itemState.completion) { | ||
sumCompletion += itemState.completion; | ||
} | ||
} | ||
var totalCompletion = sumCompletion / maxCompletion; | ||
if (!isNaN(totalCompletion)) { | ||
context.onProgress({ | ||
progress: totalCompletion, | ||
item: item | ||
}); | ||
} | ||
}; | ||
}; | ||
var preloadItem = function preloadItem(context) { | ||
return function (url, done) { | ||
var request = function request() { | ||
var xhr = new XMLHttpRequest(); | ||
xhr.open('GET', url, true); | ||
xhr.responseType = 'blob'; | ||
var item = getItemByUrl(context)(url); | ||
item.xhr = xhr; | ||
xhr.open('GET', asset.url, true); | ||
xhr.responseType = responseType; | ||
asset.xhr = xhr; | ||
xhr.onprogress = function (event) { | ||
if (event.lengthComputable) { | ||
item.completion = event.loaded / event.total; | ||
item.downloaded = event.loaded; | ||
item.total = event.total; | ||
updateProgress(context)(item); | ||
asset.progress = event.loaded / event.total; | ||
asset.downloaded = event.loaded; | ||
asset.total = event.total; | ||
onProgress({ | ||
progress: asset.progress, | ||
event: event, | ||
asset: asset | ||
}); | ||
} | ||
@@ -117,10 +79,10 @@ }; | ||
var responseURL = event.target.responseURL; | ||
item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1); | ||
item.type = type; | ||
item.status = xhr.status; | ||
asset.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1); | ||
asset.type = type; | ||
asset.status = xhr.status; | ||
if (xhr.status == 404) { | ||
item.blobUrl = item.size = null; | ||
item.error = true; | ||
context.onError(item); | ||
asset.blobUrl = asset.size = null; | ||
asset.error = true; | ||
onError(asset); | ||
} else { | ||
@@ -132,8 +94,8 @@ // TODO: fix | ||
}); | ||
item.blobUrl = URL.createObjectURL(blob); | ||
item.size = blob.size; | ||
item.error = false; | ||
asset.blobUrl = URL.createObjectURL(blob); | ||
asset.size = blob.size; | ||
asset.error = false; | ||
} | ||
done(item); | ||
onComplete(asset); | ||
}; | ||
@@ -143,64 +105,100 @@ | ||
}; | ||
request(); | ||
return asset; | ||
}; | ||
var fetch = function fetch(context) { | ||
return function (urls) { | ||
return new Promise(function (resolve) { | ||
context.loaded = urls.length; | ||
for (var _iterator4 = _createForOfIteratorHelperLoose(urls), _step4; !(_step4 = _iterator4()).done;) { | ||
var itemUrl = _step4.value; | ||
// the item isn't a full StateItem yet but for the sake of simplicity we just cast | ||
context.state.push({ | ||
url: itemUrl | ||
}); | ||
preloadItem(context)(itemUrl, function (loadedItem) { | ||
context.onFetched(loadedItem); | ||
context.loaded--; | ||
if (context.loaded == 0) { | ||
context.onComplete(context.state); | ||
resolve(context.state); | ||
} | ||
}); | ||
} | ||
}); | ||
var createEvents = function createEvents() { | ||
return { | ||
onProgress: lightcast.createPubSub(), | ||
onComplete: lightcast.createPubSub(), | ||
onFetched: lightcast.createPubSub(), | ||
onError: lightcast.createPubSub(), | ||
onCancel: lightcast.createPubSub() | ||
}; | ||
}; | ||
var createPreloader = function createPreloader() { | ||
var onProgress = lightcast.createPubSub(); | ||
var onComplete = lightcast.createPubSub(); | ||
var onFetched = lightcast.createPubSub(); | ||
var onError = lightcast.createPubSub(); | ||
var onCancel = lightcast.createPubSub(); | ||
var context = { | ||
state: [], | ||
loaded: 0, | ||
onProgress: onProgress.dispatch, | ||
onComplete: onComplete.dispatch, | ||
onFetched: onFetched.dispatch, | ||
onError: onError.dispatch, | ||
onCancel: onCancel.dispatch | ||
var events = createEvents(); | ||
var assets = []; | ||
var assetsToLoad = 0; | ||
var pending = []; | ||
var start = function start() { | ||
pending.forEach(function (pendingAsset) { | ||
assets.push(pendingAsset()); | ||
}); | ||
pending.length = 0; | ||
}; | ||
var cancel = function cancel() { | ||
assets.forEach(function (item) { | ||
if (item.progress < 1) { | ||
item.xhr.abort(); | ||
item.status = 0; | ||
} | ||
}); | ||
events.onCancel.dispatch(assets); | ||
}; | ||
var dispose = function dispose() { | ||
cancel(context)(); | ||
onProgress.dispose(); | ||
onComplete.dispose(); | ||
onFetched.dispose(); | ||
onError.dispose(); | ||
onCancel.dispose(); | ||
cancel(); | ||
Object.values(events).forEach(function (_ref) { | ||
var dispose = _ref.dispose; | ||
return dispose(); | ||
}); | ||
}; | ||
var load = function load(url, _temp) { | ||
var _ref2 = _temp === void 0 ? {} : _temp, | ||
responseType = _ref2.responseType, | ||
_ref2$onProgress = _ref2.onProgress, | ||
_onProgress = _ref2$onProgress === void 0 ? function () {} : _ref2$onProgress; | ||
return new Promise(function (resolve, reject) { | ||
assetsToLoad++; | ||
var loadAsset = function loadAsset() { | ||
return preloadAsset({ | ||
url: url, | ||
responseType: responseType, | ||
onProgress: function onProgress(payload) { | ||
events.onProgress.dispatch(_extends({}, payload, { | ||
progress: getTotalProgress(assets) | ||
})); | ||
_onProgress(payload); | ||
}, | ||
onError: function onError(item) { | ||
reject(); | ||
events.onError.dispatch(item); | ||
}, | ||
onComplete: function onComplete(asset) { | ||
events.onFetched.dispatch(asset); | ||
resolve(asset); | ||
assetsToLoad--; | ||
if (assetsToLoad === 0) { | ||
events.onComplete.dispatch(assets); | ||
dispose(); | ||
} | ||
} | ||
}); | ||
}; | ||
pending.push(loadAsset); | ||
}); | ||
}; | ||
return { | ||
fetch: fetch(context), | ||
updateProgress: updateProgress(context), | ||
preloadItem: preloadItem(context), | ||
getItemByUrl: getItemByUrl(context), | ||
cancel: cancel(context), | ||
onProgress: onProgress.subscribe, | ||
onComplete: onComplete.subscribe, | ||
onFetched: onFetched.subscribe, | ||
onError: onError.subscribe, | ||
onCancel: onCancel.subscribe, | ||
dispose: dispose | ||
load: load, | ||
start: start, | ||
cancel: cancel, | ||
dispose: dispose, | ||
getItemByUrl: getItemByUrl(assets), | ||
onCancel: events.onCancel.subscribe, | ||
onProgress: events.onProgress.subscribe, | ||
onComplete: events.onComplete.subscribe, | ||
onFetched: events.onFetched.subscribe, | ||
onError: events.onError.subscribe | ||
}; | ||
@@ -207,0 +205,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("lightcast");function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,o=new Array(t);r<t;r++)o[r]=e[r];return o}function r(e,r){var o="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(o)return(o=o.call(e)).next.bind(o);if(Array.isArray(e)||(o=function(e,r){if(e){if("string"==typeof e)return t(e,void 0);var o=Object.prototype.toString.call(e).slice(8,-1);return"Object"===o&&e.constructor&&(o=e.constructor.name),"Map"===o||"Set"===o?Array.from(e):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?t(e,void 0):void 0}}(e))||r&&e&&"number"==typeof e.length){o&&(e=o);var n=0;return function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o=function(e){return function(t){for(var o,n=r(e.state);!(o=n()).done;){var a=o.value;if(a.url==t)return a}return null}},n=function(e){return function(){for(var t,o=r(e.state);!(t=o()).done;){var n=t.value;n.completion<1&&(n.xhr.abort(),n.status=0)}return e.onCancel(e.state),e.state}},a=function(e){return function(t){for(var o,n=0,a=e.state.length,s=r(e.state);!(o=s()).done;){var u=o.value;u.completion&&(n+=u.completion)}var i=n/a;isNaN(i)||e.onProgress({progress:i,item:t})}},s=function(e){return function(t,r){var n=new XMLHttpRequest;n.open("GET",t,!0),n.responseType="blob";var s=o(e)(t);s.xhr=n,n.onprogress=function(t){t.lengthComputable&&(s.completion=t.loaded/t.total,s.downloaded=t.loaded,s.total=t.total,a(e)(s))},n.onload=function(t){var o=t.target.response.type,a=t.target.responseURL;if(s.fileName=a.substring(a.lastIndexOf("/")+1),s.type=o,s.status=n.status,404==n.status)s.blobUrl=s.size=null,s.error=!0,e.onError(s);else{var u=new Blob([t.target.response],{type:o});s.blobUrl=URL.createObjectURL(u),s.size=u.size,s.error=!1}r(s)},n.send()}},u=function(e){return function(t){return new Promise((function(o){e.loaded=t.length;for(var n,a=r(t);!(n=a()).done;){var u=n.value;e.state.push({url:u}),s(e)(u,(function(t){e.onFetched(t),e.loaded--,0==e.loaded&&(e.onComplete(e.state),o(e.state))}))}}))}};exports.createPreloader=function(){var t=e.createPubSub(),r=e.createPubSub(),i=e.createPubSub(),l=e.createPubSub(),c=e.createPubSub(),d={state:[],loaded:0,onProgress:t.dispatch,onComplete:r.dispatch,onFetched:i.dispatch,onError:l.dispatch,onCancel:c.dispatch};return{fetch:u(d),updateProgress:a(d),preloadItem:s(d),getItemByUrl:o(d),cancel:n(d),onProgress:t.subscribe,onComplete:r.subscribe,onFetched:i.subscribe,onError:l.subscribe,onCancel:c.subscribe,dispose:function(){n(d)(),t.dispose(),r.dispose(),i.dispose(),l.dispose(),c.dispose()}}}; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("lightcast");function r(){return(r=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var o=arguments[r];for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&&(e[n]=o[n])}return e}).apply(this,arguments)}exports.createPreloader=function(){var o,n={onProgress:e.createPubSub(),onComplete:e.createPubSub(),onFetched:e.createPubSub(),onError:e.createPubSub(),onCancel:e.createPubSub()},t=[],s=0,u=[],c=function(){t.forEach((function(e){e.progress<1&&(e.xhr.abort(),e.status=0)})),n.onCancel.dispatch(t)},a=function(){c(),Object.values(n).forEach((function(e){return(0,e.dispose)()}))};return{load:function(e,o){var c=void 0===o?{}:o,i=c.responseType,l=c.onProgress,p=void 0===l?function(){}:l;return new Promise((function(o,c){s++,u.push((function(){return function(e){var r,o=e.onProgress,n=e.onComplete,t=e.onError,s=e.responseType,u=void 0===s?"blob":s,c={url:e.url};return(r=new XMLHttpRequest).open("GET",c.url,!0),r.responseType=u,c.xhr=r,r.onprogress=function(e){e.lengthComputable&&(c.progress=e.loaded/e.total,c.downloaded=e.loaded,c.total=e.total,o({progress:c.progress,event:e,asset:c}))},r.onload=function(e){var o=e.target.response.type,s=e.target.responseURL;if(c.fileName=s.substring(s.lastIndexOf("/")+1),c.type=o,c.status=r.status,404==r.status)c.blobUrl=c.size=null,c.error=!0,t(c);else{var u=new Blob([e.target.response],{type:o});c.blobUrl=URL.createObjectURL(u),c.size=u.size,c.error=!1}n(c)},r.send(),c}({url:e,responseType:i,onProgress:function(e){var o,s;n.onProgress.dispatch(r({},e,{progress:(o=t,s=o.length,o.reduce((function(e,r){return r.progress?e+r.progress:e}),0)/s)})),p(e)},onError:function(e){c(),n.onError.dispatch(e)},onComplete:function(e){n.onFetched.dispatch(e),o(e),0==--s&&(n.onComplete.dispatch(t),a())}})}))}))},start:function(){u.forEach((function(e){t.push(e())})),u.length=0},cancel:c,dispose:a,getItemByUrl:(o=t,function(e){return o.find((function(r){return r.url===e}))}),onCancel:n.onCancel.subscribe,onProgress:n.onProgress.subscribe,onComplete:n.onComplete.subscribe,onFetched:n.onFetched.subscribe,onError:n.onError.subscribe}}; | ||
//# sourceMappingURL=asset-preloader.cjs.production.min.js.map |
import { createPubSub } from 'lightcast'; | ||
function _unsupportedIterableToArray(o, minLen) { | ||
if (!o) return; | ||
if (typeof o === "string") return _arrayLikeToArray(o, minLen); | ||
var n = Object.prototype.toString.call(o).slice(8, -1); | ||
if (n === "Object" && o.constructor) n = o.constructor.name; | ||
if (n === "Map" || n === "Set") return Array.from(o); | ||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); | ||
} | ||
function _extends() { | ||
_extends = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
function _arrayLikeToArray(arr, len) { | ||
if (len == null || len > arr.length) len = arr.length; | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; | ||
return target; | ||
}; | ||
return arr2; | ||
return _extends.apply(this, arguments); | ||
} | ||
function _createForOfIteratorHelperLoose(o, allowArrayLike) { | ||
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; | ||
if (it) return (it = it.call(o)).next.bind(it); | ||
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { | ||
if (it) o = it; | ||
var i = 0; | ||
return function () { | ||
if (i >= o.length) return { | ||
done: true | ||
}; | ||
return { | ||
done: false, | ||
value: o[i++] | ||
}; | ||
}; | ||
} | ||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); | ||
} | ||
var getItemByUrl = function getItemByUrl(context) { | ||
var getItemByUrl = function getItemByUrl(items) { | ||
return function (url) { | ||
for (var _iterator = _createForOfIteratorHelperLoose(context.state), _step; !(_step = _iterator()).done;) { | ||
var item = _step.value; | ||
if (item.url == url) return item; | ||
} | ||
return null; | ||
return items.find(function (item) { | ||
return item.url === url; | ||
}); | ||
}; | ||
}; | ||
var cancel = function cancel(context) { | ||
return function () { | ||
for (var _iterator2 = _createForOfIteratorHelperLoose(context.state), _step2; !(_step2 = _iterator2()).done;) { | ||
var item = _step2.value; | ||
if (item.completion < 1) { | ||
item.xhr.abort(); | ||
item.status = 0; | ||
} | ||
} | ||
var getTotalProgress = function getTotalProgress(items) { | ||
var maxProgress = items.length; | ||
var sumProgress = items.reduce(function (acc, itemState) { | ||
return itemState.progress ? acc + itemState.progress : acc; | ||
}, 0); | ||
var totalProgress = sumProgress / maxProgress; | ||
return totalProgress; | ||
}; | ||
context.onCancel(context.state); | ||
return context.state; | ||
var preloadAsset = function preloadAsset(_ref) { | ||
var url = _ref.url, | ||
onProgress = _ref.onProgress, | ||
onComplete = _ref.onComplete, | ||
onError = _ref.onError, | ||
_ref$responseType = _ref.responseType, | ||
responseType = _ref$responseType === void 0 ? 'blob' : _ref$responseType; | ||
var asset = { | ||
url: url | ||
}; | ||
}; | ||
var updateProgress = function updateProgress(context) { | ||
return function (item) { | ||
var sumCompletion = 0; | ||
var maxCompletion = context.state.length; | ||
for (var _iterator3 = _createForOfIteratorHelperLoose(context.state), _step3; !(_step3 = _iterator3()).done;) { | ||
var itemState = _step3.value; | ||
if (itemState.completion) { | ||
sumCompletion += itemState.completion; | ||
} | ||
} | ||
var totalCompletion = sumCompletion / maxCompletion; | ||
if (!isNaN(totalCompletion)) { | ||
context.onProgress({ | ||
progress: totalCompletion, | ||
item: item | ||
}); | ||
} | ||
}; | ||
}; | ||
var preloadItem = function preloadItem(context) { | ||
return function (url, done) { | ||
var request = function request() { | ||
var xhr = new XMLHttpRequest(); | ||
xhr.open('GET', url, true); | ||
xhr.responseType = 'blob'; | ||
var item = getItemByUrl(context)(url); | ||
item.xhr = xhr; | ||
xhr.open('GET', asset.url, true); | ||
xhr.responseType = responseType; | ||
asset.xhr = xhr; | ||
xhr.onprogress = function (event) { | ||
if (event.lengthComputable) { | ||
item.completion = event.loaded / event.total; | ||
item.downloaded = event.loaded; | ||
item.total = event.total; | ||
updateProgress(context)(item); | ||
asset.progress = event.loaded / event.total; | ||
asset.downloaded = event.loaded; | ||
asset.total = event.total; | ||
onProgress({ | ||
progress: asset.progress, | ||
event: event, | ||
asset: asset | ||
}); | ||
} | ||
@@ -112,10 +74,10 @@ }; | ||
var responseURL = event.target.responseURL; | ||
item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1); | ||
item.type = type; | ||
item.status = xhr.status; | ||
asset.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1); | ||
asset.type = type; | ||
asset.status = xhr.status; | ||
if (xhr.status == 404) { | ||
item.blobUrl = item.size = null; | ||
item.error = true; | ||
context.onError(item); | ||
asset.blobUrl = asset.size = null; | ||
asset.error = true; | ||
onError(asset); | ||
} else { | ||
@@ -127,8 +89,8 @@ // TODO: fix | ||
}); | ||
item.blobUrl = URL.createObjectURL(blob); | ||
item.size = blob.size; | ||
item.error = false; | ||
asset.blobUrl = URL.createObjectURL(blob); | ||
asset.size = blob.size; | ||
asset.error = false; | ||
} | ||
done(item); | ||
onComplete(asset); | ||
}; | ||
@@ -138,64 +100,100 @@ | ||
}; | ||
request(); | ||
return asset; | ||
}; | ||
var fetch = function fetch(context) { | ||
return function (urls) { | ||
return new Promise(function (resolve) { | ||
context.loaded = urls.length; | ||
for (var _iterator4 = _createForOfIteratorHelperLoose(urls), _step4; !(_step4 = _iterator4()).done;) { | ||
var itemUrl = _step4.value; | ||
// the item isn't a full StateItem yet but for the sake of simplicity we just cast | ||
context.state.push({ | ||
url: itemUrl | ||
}); | ||
preloadItem(context)(itemUrl, function (loadedItem) { | ||
context.onFetched(loadedItem); | ||
context.loaded--; | ||
if (context.loaded == 0) { | ||
context.onComplete(context.state); | ||
resolve(context.state); | ||
} | ||
}); | ||
} | ||
}); | ||
var createEvents = function createEvents() { | ||
return { | ||
onProgress: createPubSub(), | ||
onComplete: createPubSub(), | ||
onFetched: createPubSub(), | ||
onError: createPubSub(), | ||
onCancel: createPubSub() | ||
}; | ||
}; | ||
var createPreloader = function createPreloader() { | ||
var onProgress = createPubSub(); | ||
var onComplete = createPubSub(); | ||
var onFetched = createPubSub(); | ||
var onError = createPubSub(); | ||
var onCancel = createPubSub(); | ||
var context = { | ||
state: [], | ||
loaded: 0, | ||
onProgress: onProgress.dispatch, | ||
onComplete: onComplete.dispatch, | ||
onFetched: onFetched.dispatch, | ||
onError: onError.dispatch, | ||
onCancel: onCancel.dispatch | ||
var events = createEvents(); | ||
var assets = []; | ||
var assetsToLoad = 0; | ||
var pending = []; | ||
var start = function start() { | ||
pending.forEach(function (pendingAsset) { | ||
assets.push(pendingAsset()); | ||
}); | ||
pending.length = 0; | ||
}; | ||
var cancel = function cancel() { | ||
assets.forEach(function (item) { | ||
if (item.progress < 1) { | ||
item.xhr.abort(); | ||
item.status = 0; | ||
} | ||
}); | ||
events.onCancel.dispatch(assets); | ||
}; | ||
var dispose = function dispose() { | ||
cancel(context)(); | ||
onProgress.dispose(); | ||
onComplete.dispose(); | ||
onFetched.dispose(); | ||
onError.dispose(); | ||
onCancel.dispose(); | ||
cancel(); | ||
Object.values(events).forEach(function (_ref) { | ||
var dispose = _ref.dispose; | ||
return dispose(); | ||
}); | ||
}; | ||
var load = function load(url, _temp) { | ||
var _ref2 = _temp === void 0 ? {} : _temp, | ||
responseType = _ref2.responseType, | ||
_ref2$onProgress = _ref2.onProgress, | ||
_onProgress = _ref2$onProgress === void 0 ? function () {} : _ref2$onProgress; | ||
return new Promise(function (resolve, reject) { | ||
assetsToLoad++; | ||
var loadAsset = function loadAsset() { | ||
return preloadAsset({ | ||
url: url, | ||
responseType: responseType, | ||
onProgress: function onProgress(payload) { | ||
events.onProgress.dispatch(_extends({}, payload, { | ||
progress: getTotalProgress(assets) | ||
})); | ||
_onProgress(payload); | ||
}, | ||
onError: function onError(item) { | ||
reject(); | ||
events.onError.dispatch(item); | ||
}, | ||
onComplete: function onComplete(asset) { | ||
events.onFetched.dispatch(asset); | ||
resolve(asset); | ||
assetsToLoad--; | ||
if (assetsToLoad === 0) { | ||
events.onComplete.dispatch(assets); | ||
dispose(); | ||
} | ||
} | ||
}); | ||
}; | ||
pending.push(loadAsset); | ||
}); | ||
}; | ||
return { | ||
fetch: fetch(context), | ||
updateProgress: updateProgress(context), | ||
preloadItem: preloadItem(context), | ||
getItemByUrl: getItemByUrl(context), | ||
cancel: cancel(context), | ||
onProgress: onProgress.subscribe, | ||
onComplete: onComplete.subscribe, | ||
onFetched: onFetched.subscribe, | ||
onError: onError.subscribe, | ||
onCancel: onCancel.subscribe, | ||
dispose: dispose | ||
load: load, | ||
start: start, | ||
cancel: cancel, | ||
dispose: dispose, | ||
getItemByUrl: getItemByUrl(assets), | ||
onCancel: events.onCancel.subscribe, | ||
onProgress: events.onProgress.subscribe, | ||
onComplete: events.onComplete.subscribe, | ||
onFetched: events.onFetched.subscribe, | ||
onError: events.onError.subscribe | ||
}; | ||
@@ -202,0 +200,0 @@ }; |
@@ -1,1 +0,2 @@ | ||
export { createPreloader, Asset, ProgressPayload } from './lib/preloader'; | ||
export { createPreloader } from './lib/preloader'; | ||
export { Asset, ProgressPayload } from './lib/preloadAsset'; |
@@ -1,46 +0,20 @@ | ||
export declare const getItemByUrl: (context: PreloaderContext) => (url: string) => Asset | null; | ||
export declare const cancel: (context: PreloaderContext) => () => Assets; | ||
export declare const updateProgress: (context: PreloaderContext) => (item: Asset) => void; | ||
export declare const preloadItem: (context: PreloaderContext) => (url: string, done: (item: Asset) => void) => void; | ||
export declare const fetch: (context: PreloaderContext) => (urls: Array<string>) => Promise<Assets>; | ||
export declare type Asset = { | ||
xhr: XMLHttpRequest; | ||
blobUrl: string | null; | ||
completion: number; | ||
downloaded: number; | ||
error: boolean; | ||
fileName: string; | ||
size: number | null; | ||
status: number; | ||
total: number; | ||
type: string; | ||
url: string; | ||
}; | ||
declare type Assets = Array<Asset>; | ||
export declare type ProgressPayload = { | ||
item: Asset; | ||
progress: number; | ||
}; | ||
declare type PreloaderContext = { | ||
state: Assets; | ||
loaded: number; | ||
import { Asset, ProgressPayload } from './preloadAsset'; | ||
declare type LoadOptions = { | ||
onProgress: (payload: ProgressPayload) => void; | ||
onComplete: (payload: Assets) => void; | ||
onFetched: (payload: Asset) => void; | ||
onError: (payload: any) => void; | ||
onCancel: (payload: Assets) => void; | ||
responseType: XMLHttpRequestResponseType; | ||
}; | ||
export declare const createPreloader: () => { | ||
fetch: (urls: Array<string>) => Promise<Assets>; | ||
updateProgress: (item: Asset) => void; | ||
preloadItem: (url: string, done: (item: Asset) => void) => void; | ||
getItemByUrl: (url: string) => Asset | null; | ||
cancel: () => Assets; | ||
load: (url: string, { responseType, onProgress }?: Partial<LoadOptions>) => Promise<Asset>; | ||
start: () => void; | ||
cancel: () => void; | ||
dispose: () => void; | ||
getItemByUrl: (url: string) => { | ||
url: string; | ||
} | undefined; | ||
onCancel: (callback: (payload: Asset[]) => void) => () => void; | ||
onProgress: (callback: (payload: ProgressPayload) => void) => () => void; | ||
onComplete: (callback: (payload: Assets) => void) => () => void; | ||
onComplete: (callback: (payload: Asset[]) => void) => () => void; | ||
onFetched: (callback: (payload: Asset) => void) => () => void; | ||
onError: (callback: (payload: string) => void) => () => void; | ||
onCancel: (callback: (payload: Assets) => void) => () => void; | ||
dispose: () => void; | ||
onError: (callback: (payload: Asset) => void) => () => void; | ||
}; | ||
export {}; |
{ | ||
"name": "asset-preloader", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"author": "skulptur", | ||
@@ -68,4 +68,4 @@ "license": "MIT", | ||
"dependencies": { | ||
"lightcast": "^0.1.2" | ||
"lightcast": "^0.1.3" | ||
} | ||
} |
## `asset-preloader` | ||
A tiny Typescript asset preloader for the browser via XHR2. It can preload assets of different file types and composite progress together and supports multiple event subscriptions. | ||
A tiny asset preloader for the browser via XHR2. It can preload assets of different file types and composite progress together, with support for multiple event subscriptions. | ||
@@ -22,12 +22,12 @@ ## Get started | ||
preloader | ||
.fetch([ | ||
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4', | ||
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', | ||
]) | ||
.then((assets) => { | ||
// use the promise or the onComplete event | ||
console.log('resolved', assets) | ||
}) | ||
const urls = [ | ||
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4', | ||
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', | ||
] | ||
urls.forEach((url) => preloader.load(url)) | ||
preloader.start() | ||
// event subscriptions | ||
preloader.onComplete((assets) => { | ||
@@ -34,0 +34,0 @@ console.log('completed', assets) |
@@ -1,1 +0,2 @@ | ||
export { createPreloader, Asset, ProgressPayload } from './lib/preloader' | ||
export { createPreloader } from './lib/preloader' | ||
export { Asset, ProgressPayload } from './lib/preloadAsset' |
@@ -1,182 +0,93 @@ | ||
// code adapted from and improved upon https://github.com/andreupifarre/preload-it | ||
import { createPubSub } from 'lightcast' | ||
import { getItemByUrl } from './getItemByUrl' | ||
import { getTotalProgress } from './getTotalProgress' | ||
import { preloadAsset, Asset, ProgressPayload } from './preloadAsset' | ||
import { createEvents } from './events' | ||
export const getItemByUrl = (context: PreloaderContext) => (url: string) => { | ||
for (var item of context.state) { | ||
if (item.url == url) return item | ||
} | ||
return null | ||
type LoadOptions = { | ||
onProgress: (payload: ProgressPayload) => void | ||
responseType: XMLHttpRequestResponseType | ||
} | ||
export const cancel = (context: PreloaderContext) => () => { | ||
for (var item of context.state) { | ||
if (item.completion < 1) { | ||
item.xhr.abort() | ||
item.status = 0 | ||
} | ||
} | ||
export const createPreloader = () => { | ||
const events = createEvents() | ||
context.onCancel(context.state) | ||
let assets: Array<Asset> = [] | ||
let assetsToLoad: number = 0 | ||
let hasStarted = false | ||
let pending: Array<() => Asset> = [] | ||
return context.state | ||
} | ||
export const updateProgress = (context: PreloaderContext) => (item: Asset) => { | ||
let sumCompletion = 0 | ||
let maxCompletion = context.state.length | ||
for (const itemState of context.state) { | ||
if (itemState.completion) { | ||
sumCompletion += itemState.completion | ||
} | ||
const start = () => { | ||
pending.forEach((pendingAsset) => { | ||
assets.push(pendingAsset()) | ||
}) | ||
pending.length = 0 | ||
} | ||
const totalCompletion = sumCompletion / maxCompletion | ||
if (!isNaN(totalCompletion)) { | ||
context.onProgress({ | ||
progress: totalCompletion, | ||
item: item, | ||
const cancel = () => { | ||
assets.forEach((item) => { | ||
if (item.progress < 1) { | ||
item.xhr.abort() | ||
item.status = 0 | ||
} | ||
}) | ||
} | ||
} | ||
export const preloadItem = (context: PreloaderContext) => ( | ||
url: string, | ||
done: (item: Asset) => void | ||
) => { | ||
const xhr = new XMLHttpRequest() | ||
xhr.open('GET', url, true) | ||
xhr.responseType = 'blob' | ||
const item = getItemByUrl(context)(url) as Asset | ||
item.xhr = xhr | ||
xhr.onprogress = (event) => { | ||
if (event.lengthComputable) { | ||
item.completion = event.loaded / event.total | ||
item.downloaded = event.loaded | ||
item.total = event.total | ||
updateProgress(context)(item) | ||
} | ||
events.onCancel.dispatch(assets) | ||
} | ||
xhr.onload = (event) => { | ||
// TODO: fix | ||
// @ts-expect-error | ||
const type = event.target.response.type | ||
// @ts-expect-error | ||
const responseURL = event.target.responseURL | ||
item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1) | ||
item.type = type | ||
item.status = xhr.status | ||
if (xhr.status == 404) { | ||
item.blobUrl = item.size = null | ||
item.error = true | ||
context.onError(item) | ||
} else { | ||
// TODO: fix | ||
// @ts-expect-error | ||
const blob = new Blob([event.target.response], { type }) | ||
item.blobUrl = URL.createObjectURL(blob) | ||
item.size = blob.size | ||
item.error = false | ||
} | ||
done(item) | ||
const dispose = () => { | ||
cancel() | ||
Object.values(events).forEach(({ dispose }) => dispose()) | ||
} | ||
xhr.send() | ||
} | ||
export const fetch = (context: PreloaderContext) => (urls: Array<string>) => { | ||
return new Promise<Assets>((resolve) => { | ||
context.loaded = urls.length | ||
for (let itemUrl of urls) { | ||
// the item isn't a full StateItem yet but for the sake of simplicity we just cast | ||
context.state.push({ url: itemUrl } as Asset) | ||
preloadItem(context)(itemUrl, (loadedItem) => { | ||
context.onFetched(loadedItem) | ||
context.loaded-- | ||
if (context.loaded == 0) { | ||
context.onComplete(context.state) | ||
resolve(context.state) | ||
} | ||
}) | ||
} | ||
}) | ||
} | ||
const load = ( | ||
url: string, | ||
{ responseType, onProgress = () => {} }: Partial<LoadOptions> = {} | ||
) => { | ||
return new Promise<Asset>((resolve, reject) => { | ||
assetsToLoad++ | ||
export type Asset = { | ||
xhr: XMLHttpRequest | ||
blobUrl: string | null | ||
completion: number | ||
downloaded: number | ||
error: boolean | ||
fileName: string | ||
size: number | null | ||
status: number | ||
total: number | ||
type: string | ||
url: string | ||
} | ||
const loadAsset = () => | ||
preloadAsset({ | ||
url, | ||
responseType, | ||
onProgress: (payload) => { | ||
events.onProgress.dispatch({ | ||
...payload, | ||
progress: getTotalProgress(assets), | ||
}) | ||
type Assets = Array<Asset> | ||
onProgress(payload) | ||
}, | ||
onError: (item) => { | ||
reject() | ||
events.onError.dispatch(item) | ||
}, | ||
onComplete: (asset) => { | ||
events.onFetched.dispatch(asset) | ||
resolve(asset) | ||
export type ProgressPayload = { | ||
item: Asset | ||
progress: number | ||
} | ||
assetsToLoad-- | ||
if (assetsToLoad === 0) { | ||
events.onComplete.dispatch(assets) | ||
dispose() | ||
} | ||
}, | ||
}) | ||
type PreloaderContext = { | ||
state: Assets | ||
loaded: number | ||
onProgress: (payload: ProgressPayload) => void | ||
onComplete: (payload: Assets) => void | ||
onFetched: (payload: Asset) => void | ||
onError: (payload: any) => void | ||
onCancel: (payload: Assets) => void | ||
} | ||
export const createPreloader = () => { | ||
const onProgress = createPubSub<ProgressPayload>() | ||
const onComplete = createPubSub<Assets>() | ||
const onFetched = createPubSub<Asset>() | ||
const onError = createPubSub<string>() | ||
const onCancel = createPubSub<Assets>() | ||
const context: PreloaderContext = { | ||
state: [], | ||
loaded: 0, | ||
onProgress: onProgress.dispatch, | ||
onComplete: onComplete.dispatch, | ||
onFetched: onFetched.dispatch, | ||
onError: onError.dispatch, | ||
onCancel: onCancel.dispatch, | ||
hasStarted ? assets.push(loadAsset()) : pending.push(loadAsset) | ||
}) | ||
} | ||
const dispose = () => { | ||
cancel(context)() | ||
onProgress.dispose() | ||
onComplete.dispose() | ||
onFetched.dispose() | ||
onError.dispose() | ||
onCancel.dispose() | ||
} | ||
return { | ||
fetch: fetch(context), | ||
updateProgress: updateProgress(context), | ||
preloadItem: preloadItem(context), | ||
getItemByUrl: getItemByUrl(context), | ||
cancel: cancel(context), | ||
onProgress: onProgress.subscribe, | ||
onComplete: onComplete.subscribe, | ||
onFetched: onFetched.subscribe, | ||
onError: onError.subscribe, | ||
onCancel: onCancel.subscribe, | ||
load, | ||
start, | ||
cancel, | ||
dispose, | ||
getItemByUrl: getItemByUrl(assets), | ||
onCancel: events.onCancel.subscribe, | ||
onProgress: events.onProgress.subscribe, | ||
onComplete: events.onComplete.subscribe, | ||
onFetched: events.onFetched.subscribe, | ||
onError: events.onError.subscribe, | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
55021
22
618
1
Updatedlightcast@^0.1.3