From 846710d1b7187858130ab0884fa7a61a7d93327c Mon Sep 17 00:00:00 2001 From: Kevin Chappell Date: Wed, 6 Nov 2024 16:41:43 -0800 Subject: [PATCH] fix: style loaded when sprite is missing resolves #359 --- src/lib/js/common/loaders.js | 53 ++++++++++++++++++++++++++---------- src/lib/js/config.js | 3 +- src/lib/js/editor.js | 12 +++----- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/lib/js/common/loaders.js b/src/lib/js/common/loaders.js index 971dc28c..fd0652d3 100644 --- a/src/lib/js/common/loaders.js +++ b/src/lib/js/common/loaders.js @@ -1,16 +1,7 @@ import dom from './dom.js' -import { - CSS_URL, - FALLBACK_CSS_URL, - FALLBACK_SVG_SPRITE_URL, - POLYFILLS, - SVG_SPRITE_URL, - formeoSpriteId, -} from '../constants.js' +import { FALLBACK_CSS_URL, FALLBACK_SVG_SPRITE_URL, POLYFILLS, SVG_SPRITE_URL, formeoSpriteId } from '../constants.js' import { noop } from './utils/index.mjs' -/* global fetch */ - const loaded = { js: new Set(), css: new Set(), @@ -31,7 +22,6 @@ export const ajax = (fileUrl, callback, onError = noop) => { const onLoadStylesheet = (elem, cb) => { elem.removeEventListener('load', onLoadStylesheet) - elem.rel = 'stylesheet' cb(elem.src) } @@ -79,9 +69,8 @@ export const insertStyle = srcs => { const styleLink = dom.create({ tag: 'link', attrs: { - rel: 'preload', + rel: 'stylesheet', href: src, - as: 'style', }, action: { load: () => onLoadStylesheet(styleLink, resolve), @@ -96,6 +85,12 @@ export const insertStyle = srcs => { return Promise.all(promises) } +/** + * Inserts multiple script elements into the document. + * + * @param {string|string[]} srcs - A single script source URL or an array of script source URLs. + * @returns {Promise} A promise that resolves when all scripts have been loaded. + */ export const insertScripts = srcs => { srcs = Array.isArray(srcs) ? srcs : [srcs] const promises = srcs.map(src => insertScript(src)) @@ -145,6 +140,11 @@ export const insertIcons = iconSvgStr => { * @returns {Promise} A promise that resolves when the icons are fetched and inserted. */ export const fetchIcons = async (iconSpriteUrl = SVG_SPRITE_URL) => { + const formeoSprite = document.getElementById(formeoSpriteId) + if (formeoSprite) { + return + } + const parseResp = async resp => insertIcons(await resp.text()) return ajax(iconSpriteUrl, parseResp, () => ajax(FALLBACK_SVG_SPRITE_URL, parseResp)) } @@ -161,6 +161,12 @@ export const LOADER_MAP = { css: insertStyles, } +/** + * Fetches and loads the specified dependencies. + * + * @param {Object} dependencies - An object where keys are dependency types and values are the source URLs. + * @returns {Promise} A promise that resolves to an array of results from loading each dependency. + */ export const fetchDependencies = dependencies => { const promises = Object.entries(dependencies).map(([type, src]) => { return LOADER_MAP[type](src) @@ -168,6 +174,15 @@ export const fetchDependencies = dependencies => { return Promise.all(promises) } +/** + * Checks if the CSS for the Formeo sprite is loaded. + * + * This function determines if the CSS for the Formeo sprite is loaded by checking + * the visibility property of the sprite's computed style. If the visibility is + * 'hidden', it is assumed that the CSS is loaded. + * + * @returns {boolean} True if formeo CSS is loaded, false otherwise. + */ export const isCssLoaded = () => { const formeoSprite = document.getElementById(formeoSpriteId) const computedStyle = window.getComputedStyle(formeoSprite) @@ -175,10 +190,18 @@ export const isCssLoaded = () => { return computedStyle.visibility === 'hidden' } -export const fetchFormeoStyle = async () => { +/** + * Fetches and inserts the Formeo style sheet from the given URL. + * If the necessary styles are not loaded, it attempts to insert the style sheet. + * If the styles are still not loaded, it uses a fallback URL to insert the style sheet. + * + * @param {string} cssUrl - The URL of the CSS file to be loaded. + * @returns {Promise} A promise that resolves when the style sheet is loaded. + */ +export const fetchFormeoStyle = async cssUrl => { // check if necessary styles were loaded if (!isCssLoaded()) { - await insertStyle(CSS_URL) + await insertStyle(cssUrl) // check again and use fallback if necessary styles were not loaded if (!isCssLoaded()) { return await insertStyle(FALLBACK_CSS_URL) diff --git a/src/lib/js/config.js b/src/lib/js/config.js index b7b0511a..cdb2af4b 100644 --- a/src/lib/js/config.js +++ b/src/lib/js/config.js @@ -1,6 +1,6 @@ import mi18n from '@draggable/i18n' import { isIE } from './common/helpers' -import { SVG_SPRITE_URL } from './constants' +import { CSS_URL, SVG_SPRITE_URL } from './constants' const enUS = import.meta.env.enUS mi18n.addLanguage('en-US', enUS) @@ -16,6 +16,7 @@ export const defaults = { editorContainer: null, // element or selector to attach editor to external: {}, // assign external data to be used in conditions autolinker svgSprite: SVG_SPRITE_URL, // change to null + style: CSS_URL, // change to null iconFont: null, // 'glyphicons' || 'font-awesome' || 'fontello' config: {}, // stages, rows, columns, fields events: {}, diff --git a/src/lib/js/editor.js b/src/lib/js/editor.js index bc93f037..a8bceb54 100644 --- a/src/lib/js/editor.js +++ b/src/lib/js/editor.js @@ -4,8 +4,8 @@ import Events from './common/events.js' import Actions from './common/actions.js' import Controls from './components/controls/index.js' import Components from './components/index.js' -import { loadPolyfills, insertStyle, fetchIcons, isCssLoaded, fetchFormeoStyle } from './common/loaders.js' -import { SESSION_LOCALE_KEY, CSS_URL } from './constants.js' +import { loadPolyfills, fetchIcons, fetchFormeoStyle } from './common/loaders.js' +import { SESSION_LOCALE_KEY } from './constants.js' import { merge } from './common/utils/index.mjs' import { defaults } from './config.js' import '../sass/formeo.scss' @@ -65,19 +65,15 @@ export class FormeoEditor { loadPolyfills(this.opts.polyfills) } - if (this.opts.style) { - promises.push(insertStyle(this.opts.style)) - } // Ajax load svgSprite and inject into markup. - promises.push(fetchIcons(this.opts.svgSprite)) + await fetchIcons(this.opts.svgSprite) + promises.push(fetchFormeoStyle(this.opts.style)) promises.push(i18n.init({ ...this.opts.i18n, locale: window.sessionStorage?.getItem(SESSION_LOCALE_KEY) })) const resolvedPromises = await Promise.all(promises) - fetchFormeoStyle() - if (this.opts.allowEdit) { this.init() }