/**
__ ___ ___ ____ ____ ___
/__\ / __)/ __)( ___)(_ _)/ __)
/(__)\ \__ \\__ \ )__) )( \__ \
(__)(__)(___/(___/(____) (__) (___/ for SPARC
By Mike & Nike
This file is part of Sparc by Mike & Nike.
Sparc is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License,
as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
Sparc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Get your copy of the GNU General Public License at .
* @category Core
* @subcategory Libraries
* @hideconstructor
*/
class Assets {
static defaults = {};
/**
* @type {object}
* @property {Array} images
* @property {Array} css
* @property {Array} html
* @property {Array} json
* @property {Array} fonts
* @property {Array} sfx
*/
static Store = { 'images':{}, 'css':{}, 'html':{}, 'json':{}, 'fonts':{}, 'sfx':{} };
/**
* @async
* @param {*} args
* @param {string} args.path
* @param {string} args.name
* @param {string} [args.id]
* @param {boolean} [args.refresh]
* @returns {Promise}
*/
static getImage(args){
if( (!args.hasOwnProperty('path')) || (args.path=='') ) var fpath = this.defaults.basePath+'images/'+args.name;
else var fpath = (args.path+'/'+args.name).replace(/\/+/g,'/').replace(/http(s)?:\//g, 'http$1://');
let aid = args.id || fpath;
if(this.Store.images.hasOwnProperty(aid) && (!args.refresh)) {
return(new Promise((resolve) => {
resolve(this.Store.images[aid]);
})
);
}
let node = document.createElement('img');
return(new Promise( (resolve, fail) => {
node.onload = (e) => {
this.Store.images[aid] = node;
resolve(node);
}
node.onerror= (e) => {
console.warn('Could not load IMAGE asset ',aid, fpath);
}
node.src = fpath+'?'+crypto.randomUUID();
// for img nodes, setting the src is sufficient to start loading, then trigger the onload
})
);
}
/**
*
* @async
* @param {*} args
* @param {string} args.path
* @param {string} args.name
* @param {string} [args.id]
* @param {boolean} [args.refresh]
* @returns {Promise}
*/
static loadJson(args){
if( (!args.hasOwnProperty('path')) || (args.path=='') ) var fpath = this.defaults.basePath+'json/'+args.name;
else var fpath = (args.path+args.name).replace(/\/+/g,'/').replace(/http(s)?:\//g, 'http$1://');
let aid = args.id || fpath;
if( (this.Store.json.hasOwnProperty(aid)) && (!args.refresh) ){
return(new Promise((resolve) => {
resolve(this.Store.json[aid]);
})
);
}
return( fetch(fpath+'?'+crypto.randomUUID())
.then(response => response.json())
.then(data => {
this.Store.json[aid] = data;
return(data);
})
.catch(error => {
console.warn('Could not load json asset:', aid, fpath, error);
})
);
}
/**
*
* @async
* @param {*} args
* @param {string} args.path
* @param {string} args.name
* @param {string} [args.id]
* @param {boolean} [args.refresh]
* @returns {Promise}
*/
static loadCss(args){
if( (!args.hasOwnProperty('path')) || (args.path=='') ) var fpath = this.defaults.basePath+'styles/'+args.name;
else var fpath = (args.path+args.name).replace(/\/+/g,'/').replace(/http(s)?:\//g, 'http$1://');
let aid = args.id || fpath;
let _notInIndex = (aid) => {
if( (!app.config.squeeze) || (!app.config.squeeze.packages) ) return(true)
for(let dragee of app.config.squeeze.packages) {
let ext = dragee.target.toLowerCase().substring(dragee.target.lastIndexOf('.'))
if((ext!='.css') || (!dragee.setIndexPage)) continue
for(let file of dragee.sources) {
if(file == aid) return(false)
}
}
return(true)
}
if( this.Store.css.hasOwnProperty(aid) && (!args.refresh) ) {
return(new Promise((resolve) => {
resolve(this.Store.css[aid]);
})
);
}
let node;
if( (this.Store.css.hasOwnProperty(aid)) && (args.refresh) ) node = this.Store.css[aid];
else {
node = document.createElement('link');
node.setAttribute('rel','stylesheet');
node.setAttribute('type','text/css');
}
return( new Promise( (resolve, fail) => {
node.onload = (e) => {
this.Store.css[aid] = node;
resolve(node);
}
node.onerror= (e) => {
console.warn('Could not load CSS asset ', aid, fpath);
fail(node);
}
node.setAttribute('href',fpath+'?'+crypto.randomUUID());
// for link nodes, setting the href is NOT sufficient to start loading
// , then trigger the onload. Must add it to the dom !
document.head.appendChild(node)
})
);
}
/**
* Loads an audio file.
* @async
* @param {*} args
* @param {string} args.path
* @param {string} args.name
* @param {string} [args.id]
* @param {boolean} [args.refresh]
* @returns {Promise}
*/
static loadSound(args){
if( (!args.hasOwnProperty('path')) || (args.path=='') ) var fpath = this.defaults.basePath+'sfx/'+args.name;
else var fpath = (args.path+args.name).replace(/\/+/g,'/').replace(/http(s)?:\//g, 'http$1://');
let aid = args.id || fpath;
if( (this.Store.sfx.hasOwnProperty(aid)) && (!args.refresh) ) {
return(new Promise((resolve) => {
resolve(this.Store.sfx[aid]);
})
);
}
return(new Promise((resolve, fail) => {
this.Store.sfx[aid] = new Audio();
this.Store.sfx[aid].setAttribute('aid', aid);
this.Store.sfx[aid].addEventListener('canplaythrough', (e) => resolve(e.target), { 'once':true });
this.Store.sfx[aid].addEventListener('error', (e) => fail(e.target), { 'once':true });
this.Store.sfx[aid].src = fpath+'?'+crypto.randomUUID();
return(this.Store.sfx[aid]);
})
);
}
/**
* Plays a loaded audio, loads it first if needed.
* @async
* @param {*} args
* @param {string} args.path
* @param {string} args.name
* @param {string} [args.id]
* @param {boolean} [args.refresh]
* @returns {Promise}
*/
static playSound(args){
// Nike: Promise when fulfilled when sfx loaded.
// If we want when sfx finished to play then
// stick a 'ended' event listener as resolver in a new promise
return(
this.loadSound(args).then( (snd) => { snd.play(); })
);
}
/**
*
* @async
* @param {*} args
* @param {string} args.path
* @param {string} args.name
* @param {string} [args.id]
* @param {boolean} [args.refresh]
* @returns {Promise}
* @todo check issue with undeclared aid
*/
static loadFont(args){
// something fishy here => aid not declared
let acronym = aid || args.name.substr(0,args.name.lastIndexOf('.'));
if( (!args.hasOwnProperty('path')) || (args.path=='') ) var fpath = this.defaults.basePath+'fonts/'+args.name;
else var fpath = (args.path+args.name).replace(/\/+/g,'/').replace(/http(s)?:\//g, 'http$1://');
let aid = args.id || fpath;
if( (this.Store.fonts.hasOwnProperty(aid)) && (!args.refresh) ) {
return(new Promise((resolve) => {
resolve([loaded_face, acronym]);
})
);
}
let ff = new FontFace(acronym,'url('+fpath+'?'+crypto.randomUUID()+')');
return(ff.load()
.then(loaded_face => {
document.fonts.add(loaded_face);
this.Store.fonts[aid] = loaded_face;
return([loaded_face, acronym]);
})
.catch(error => {
console.warn('Could not load FONT asset:' + fpath);
[null, acronym]
})
);
}
/**
* Loads an HTML file
* @async
* @param {*} args
* @param {string} args.path
* @param {string} args.name
* @param {string} [args.id]
* @param {boolean} [args.refresh]
* @returns {string}
*/
static loadHtml(args) {
if( (!args.hasOwnProperty('path')) || (args.path=='') ) var fpath = this.defaults.basePath+'html/'+args.name;
else var fpath = (args.path+args.name).replace(/\/+/g,'/').replace(/http(s)?:\//g, 'http$1://');
let aid = args.id || fpath;
if( (this.Store.html.hasOwnProperty(aid)) && (!args.refresh) ) {
let html = this.Store.html[aid];
return(new Promise((resolve) => {
resolve(html);
})
);
}
return(fetch(fpath + '?' + crypto.randomUUID())
.then(response => response.text())
.then(html => {
this.Store.html[aid] = html;
return html;
})
.catch(error => {
console.warn('Could not load HTML asset:', aid, fpath);
return(null);
})
);
}
}
app.LoadedClasses.Assets = Assets;