Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
- Base: wintercms/winter branch 1.2 (full framework) - Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS - Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication - Partials: hero (offline-first), features, modes (offline/nube toggle), screenshots, pricing (3 planes), comparison, FAQ, CTA - Plugin VivesPOS.Site with ContactForm - Dockerfile: PHP 8.2 Apache, port 80, healthcheck - Added winter/wn-pages, blog, sitemap, seo plugins - Active theme set to vivespos
197 lines
6.0 KiB
JavaScript
197 lines
6.0 KiB
JavaScript
import Singleton from '../abstracts/Singleton';
|
|
|
|
/**
|
|
* Asset Loader.
|
|
*
|
|
* Provides simple asset loading functionality for Snowboard, making it easy to pre-load images or
|
|
* include JavaScript or CSS assets on the fly.
|
|
*
|
|
* By default, this loader will listen to any assets that have been requested to load in an AJAX
|
|
* response, such as responses from a component.
|
|
*
|
|
* You can also load assets manually by calling the following:
|
|
*
|
|
* ```js
|
|
* Snowboard.addPlugin('assetLoader', AssetLoader);
|
|
* Snowboard.assetLoader().processAssets(assets);
|
|
* ```
|
|
*
|
|
* @copyright 2021 Winter.
|
|
* @author Ben Thomson <git@alfreido.com>
|
|
*/
|
|
export default class AssetLoader extends Singleton {
|
|
/**
|
|
* Event listeners.
|
|
*
|
|
* @returns {Object}
|
|
*/
|
|
listens() {
|
|
return {
|
|
ajaxLoadAssets: 'load',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Dependencies.
|
|
*
|
|
* @returns {Array}
|
|
*/
|
|
dependencies() {
|
|
return [
|
|
'url',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Process and load assets.
|
|
*
|
|
* The `assets` property of this method requires an object with any of the following keys and an
|
|
* array of paths:
|
|
*
|
|
* - `js`: An array of JavaScript URLs to load
|
|
* - `css`: An array of CSS stylesheet URLs to load
|
|
* - `img`: An array of image URLs to pre-load
|
|
*
|
|
* Both `js` and `css` files will be automatically injected, however `img` files will not.
|
|
*
|
|
* This method will return a Promise that resolves when all required assets are loaded. If an
|
|
* asset fails to load, this Promise will be rejected.
|
|
*
|
|
* ESLint *REALLY* doesn't like this code, but ignore it. It's the only way it works.
|
|
*
|
|
* @param {Object} assets
|
|
* @returns {Promise}
|
|
*/
|
|
async load(assets) {
|
|
if (assets.js && assets.js.length > 0) {
|
|
for (const script of assets.js) {
|
|
try {
|
|
await this.loadScript(script);
|
|
} catch (error) {
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (assets.css && assets.css.length > 0) {
|
|
for (const style of assets.css) {
|
|
try {
|
|
await this.loadStyle(style);
|
|
} catch (error) {
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (assets.img && assets.img.length > 0) {
|
|
for (const image of assets.img) {
|
|
try {
|
|
await this.loadImage(image);
|
|
} catch (error) {
|
|
return Promise.reject(error);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Promise.resolve();
|
|
}
|
|
|
|
/**
|
|
* Injects and loads a JavaScript URL into the DOM.
|
|
*
|
|
* The script will be appended before the closing `</body>` tag.
|
|
*
|
|
* @param {String} script
|
|
* @returns {Promise}
|
|
*/
|
|
loadScript(script) {
|
|
return new Promise((resolve, reject) => {
|
|
// Resolve script URL
|
|
script = this.snowboard.url().asset(script);
|
|
|
|
// Check that script is not already loaded
|
|
const loaded = document.querySelector(`script[src="${script}"]`);
|
|
if (loaded) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
// Create script
|
|
const domScript = document.createElement('script');
|
|
domScript.setAttribute('type', 'text/javascript');
|
|
domScript.setAttribute('src', script);
|
|
domScript.addEventListener('load', () => {
|
|
this.snowboard.globalEvent('assetLoader.loaded', 'script', script, domScript);
|
|
resolve();
|
|
});
|
|
domScript.addEventListener('error', () => {
|
|
this.snowboard.globalEvent('assetLoader.error', 'script', script, domScript);
|
|
reject(new Error(`Unable to load script file: "${script}"`));
|
|
});
|
|
document.body.append(domScript);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Injects and loads a CSS stylesheet into the DOM.
|
|
*
|
|
* The stylesheet will be appended before the closing `</head>` tag.
|
|
*
|
|
* @param {String} style
|
|
* @returns {Promise}
|
|
*/
|
|
loadStyle(style) {
|
|
return new Promise((resolve, reject) => {
|
|
// Resolve style URL
|
|
style = this.snowboard.url().asset(style);
|
|
|
|
// Check that stylesheet is not already loaded
|
|
const loaded = document.querySelector(`link[rel="stylesheet"][href="${style}"]`);
|
|
if (loaded) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
// Create stylesheet
|
|
const domCss = document.createElement('link');
|
|
domCss.setAttribute('rel', 'stylesheet');
|
|
domCss.setAttribute('href', style);
|
|
domCss.addEventListener('load', () => {
|
|
this.snowboard.globalEvent('assetLoader.loaded', 'style', style, domCss);
|
|
resolve();
|
|
});
|
|
domCss.addEventListener('error', () => {
|
|
this.snowboard.globalEvent('assetLoader.error', 'style', style, domCss);
|
|
reject(new Error(`Unable to load stylesheet file: "${style}"`));
|
|
});
|
|
document.head.append(domCss);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Pre-loads an image.
|
|
*
|
|
* The image will not be injected into the DOM.
|
|
*
|
|
* @param {String} image
|
|
* @returns {Promise}
|
|
*/
|
|
loadImage(image) {
|
|
return new Promise((resolve, reject) => {
|
|
// Resolve script URL
|
|
image = this.snowboard.url().asset(image);
|
|
|
|
const img = new Image();
|
|
img.addEventListener('load', () => {
|
|
this.snowboard.globalEvent('assetLoader.loaded', 'image', image, img);
|
|
resolve();
|
|
});
|
|
img.addEventListener('error', () => {
|
|
this.snowboard.globalEvent('assetLoader.error', 'image', image, img);
|
|
reject(new Error(`Unable to load image file: "${image}"`));
|
|
});
|
|
img.src = image;
|
|
});
|
|
}
|
|
}
|