diff --git a/package.json b/package.json index f4a88b37..ed724729 100644 --- a/package.json +++ b/package.json @@ -93,9 +93,9 @@ ] }, "lint-staged": { - ".eslintignore": "npm run eslint-arg --", - ".eslintrc.js": "npm run eslint-arg --", - "src/**/*.{js,md,html}": "npm run eslint-arg --", + ".eslintignore": "npm run eslint", + ".eslintrc.js": "npm run eslint", + "src/**/*.{js,md,html}": "npm run eslint", "src/editor/extensions/*.png": "npm run imageoptim --", "src/editor/spinbtn/*.png": "npm run imageoptim --", "src/editor/jgraduate/images/*.{png,gif}": "npm run imageoptim --", diff --git a/src/editor/extensions/ext-mathjax.js b/src/editor/extensions/ext-mathjax.js index f64568de..3d77f7fd 100644 --- a/src/editor/extensions/ext-mathjax.js +++ b/src/editor/extensions/ext-mathjax.js @@ -7,8 +7,6 @@ * @copyright 2013 Jo Segaert * */ -// Todo: Wait for Mathjax 3.0 to get ES Module/avoid global -import {importScript} from '../../external/dynamic-import-polyfill/importModule.js'; export default { name: 'mathjax', @@ -204,7 +202,8 @@ export default { // We use `extIconsPath` here for now as it does not vary with // the modular type as does `extPath` try { - await importScript(svgEditor.curConfig.extIconsPath + mathjaxSrcSecure); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + await import(svgEditor.curConfig.extIconsPath + mathjaxSrcSecure); // When MathJax is loaded get the div where the math will be rendered. MathJax.Hub.queue.Push(function () { math = MathJax.Hub.getAllJax('#mathjax_creator')[0]; diff --git a/src/editor/index.js b/src/editor/index.js index 57e1c9dc..100951b8 100644 --- a/src/editor/index.js +++ b/src/editor/index.js @@ -76,7 +76,7 @@ svgEditor.setConfig({ // no_save_warning: false, // PATH CONFIGURATION // imgPath: 'images/', - // langPath: 'locale/', + // langPath: '/src/editor/locale/', // extPath: 'extensions/', // jGraduatePath: 'jgraduate/images/', /* diff --git a/src/editor/locale/locale.js b/src/editor/locale/locale.js index 6eaef5a8..a5f815c4 100644 --- a/src/editor/locale/locale.js +++ b/src/editor/locale/locale.js @@ -24,8 +24,6 @@ * @typedef {PlainObject} module:locale.LocaleSelectorValue */ -import {importSetGlobalDefault} from '../../external/dynamic-import-polyfill/importModule.js'; - const $ = jQuery; let langParam; @@ -388,11 +386,7 @@ export const putLocale = async function (givenParam, goodLangs, conf) { } const url = conf.langPath + 'lang.' + langParam + '.js'; - return readLang( - // Todo: Replace this with `return import(url);` when - // `import()` widely supported - await importSetGlobalDefault(url, { - global: 'svgEditorLang_' + langParam.replace(/-/g, '_') - }) - ); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + const module = await import(url); + return readLang(module.default); }; diff --git a/src/editor/svgedit.js b/src/editor/svgedit.js index fff1ddb7..7f019d0c 100644 --- a/src/editor/svgedit.js +++ b/src/editor/svgedit.js @@ -26,7 +26,6 @@ import {getTypeMap, convertUnit, isValidUnit} from '../common/units.js'; import { hasCustomHandler, getCustomHandler, injectExtendedContextMenuItemsIntoDom } from './contextmenu.js'; -import {importSetGlobalDefault} from '../external/dynamic-import-polyfill/importModule.js'; import deparam from '../external/deparam/deparam.esm.js'; import SvgCanvas from '../svgcanvas/svgcanvas.js'; @@ -237,13 +236,13 @@ const callbacks = [], no_save_warning: false, // PATH CONFIGURATION // The following path configuration items are disallowed in the URL (as should any future path configurations) - langPath: 'locale/', // Default will be changed if this is a non-modular load - extPath: 'extensions/', // Default will be changed if this is a non-modular load - canvgPath: 'canvg/', // Default will be changed if this is a non-modular load - jspdfPath: 'jspdf/', // Default will be changed if this is a non-modular load - imgPath: 'images/', - jGraduatePath: 'jgraduate/images/', - extIconsPath: 'extensions/', + langPath: '/src/editor/locale/', // Default will be changed if this is a non-modular load + extPath: '/src/editor/extensions/', // Default will be changed if this is a non-modular load + canvgPath: '/src/editor/canvg/', // Default will be changed if this is a non-modular load + jspdfPath: '/src/editor/jspdf/', // Default will be changed if this is a non-modular load + imgPath: '/src/editor/images/', + jGraduatePath: '/src/editor/jgraduate/images/', + extIconsPath: '/src/editor/extensions/', // DOCUMENT PROPERTIES // Change the following to a preference (already in the Document Properties dialog)? dimensions: [640, 480], @@ -351,11 +350,11 @@ function getImportLocale ({defaultLang, defaultName}) { * @param {string} language * @returns {Promise} Resolves to {@link module:locale.LocaleStrings} */ - function importLocale (language) { + async function importLocale (language) { const url = `${curConfig.extPath}ext-locale/${name}/${language}.js`; - return importSetGlobalDefault(url, { - global: `svgEditorExtensionLocale_${name}_${language.replace(/-/g, '_')}` - }); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + const locale = await import(url); + return locale.default; } try { return await importLocale(lang); @@ -836,14 +835,13 @@ editor.init = function () { try { await Promise.all( curConfig.extensions.map(async (extname) => { - const extName = extname.match(/^ext-(.+)\.js/); + const extensionName = extname.match(/^ext-(.+)\.js/); // const {extName} = extname.match(/^ext-(?.+)\.js/).groups; - if (!extName) { // Ensure URL cannot specify some other unintended file in the extPath + if (!extensionName) { // Ensure URL cannot specify some other unintended file in the extPath return undefined; } const url = curConfig.extPath + extname; - // Todo: Replace this with `return import(url);` when - // `import()` widely supported + /** * @tutorial ExtensionDocs * @typedef {PlainObject} module:SVGEditor.ExtensionObject @@ -854,11 +852,9 @@ editor.init = function () { /** * @type {module:SVGEditor.ExtensionObject} */ - const imported = await importSetGlobalDefault(url, { - global: 'svgEditorExtension_' + extName[1].replace(/-/g, '_') - // global: 'svgEditorExtension_' + extName.replace(/-/g, '_') - }); - const {name = extName[1], init} = imported; + // eslint-disable-next-line node/no-unsupported-features/es-syntax + const imported = await import(url); + const {name = extensionName[1], init} = imported.default; // const {name = extName, init} = imported; const importLocale = getImportLocale({defaultLang: langParam, defaultName: name}); return editor.addExtension(name, (init && init.bind(editor)), {$, importLocale}); diff --git a/src/external/dynamic-import-polyfill/importModule.js b/src/external/dynamic-import-polyfill/importModule.js deleted file mode 100644 index 758dee5c..00000000 --- a/src/external/dynamic-import-polyfill/importModule.js +++ /dev/null @@ -1,176 +0,0 @@ -/* eslint-disable jsdoc/require-file-overview */ -/** - * Adapted from {@link https://github.com/uupaa/dynamic-import-polyfill/blob/master/importModule.js}. - * @module importModule - * @license MIT - */ - -/** - * Converts a possible relative URL into an absolute one. - * @param {string} url - * @returns {string} - */ -function toAbsoluteURL (url) { - const a = document.createElement('a'); - a.setAttribute('href', url); // - return a.cloneNode(false).href; // -> "http://example.com/hoge.html" -} - -/** - * Add any of the whitelisted attributes to the script tag. - * @param {HTMLScriptElement} script - * @param {PlainObject} atts - * @returns {void} - */ -function addScriptAtts (script, atts) { - ['id', 'class', 'type'].forEach((prop) => { - if (prop in atts) { - script[prop] = atts[prop]; - } - }); -} - -// Additions by Brett -/** -* @typedef {PlainObject} module:importModule.ImportConfig -* @property {string} global The variable name to set on `window` (when not using the modular version) -* @property {boolean} [returnDefault=false] -*/ - -/** -* @function module:importModule.importSetGlobalDefault -* @param {string|GenericArray} url -* @param {module:importModule.ImportConfig} config -* @returns {Promise} The value to which it resolves depends on the export of the targeted module. -*/ -export function importSetGlobalDefault (url, config) { - return importSetGlobal(url, {...config, returnDefault: true}); -} -/** -* @function module:importModule.importSetGlobal -* @param {string|string[]} url -* @param {module:importModule.ImportConfig} config -* @returns {Promise} The promise resolves to either an `ArbitraryModule` or -* any other value depends on the export of the targeted module. -*/ -export async function importSetGlobal (url, {global: glob, returnDefault}) { - // Todo: Replace calls to this function with `import()` when supported - const modularVersion = !('svgEditor' in window) || - !window.svgEditor || - window.svgEditor.modules !== false; - if (modularVersion) { - return importModule(url, undefined, {returnDefault}); - } - await importScript(url); - return window[glob]; -} - -/** - * - * @author Brett Zamir (other items are from `dynamic-import-polyfill`) - * @param {string|string[]} url - * @param {PlainObject} [atts={}] - * @returns {Promise} Resolves to `undefined` or rejects with an `Error` upon a - * script loading error - */ -export function importScript (url, atts = {}) { - if (Array.isArray(url)) { - return Promise.all(url.map((u) => { - return importScript(u, atts); - })); - } - return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new - const script = document.createElement('script'); - /** - * - * @returns {void} - */ - function scriptOnError () { - reject(new Error(`Failed to import: ${url}`)); - destructor(); - } - /** - * - * @returns {void} - */ - function scriptOnLoad () { - resolve(); - destructor(); - } - const destructor = () => { - script.removeEventListener('error', scriptOnError); - script.removeEventListener('load', scriptOnLoad); - script.remove(); - script.src = ''; - }; - script.defer = 'defer'; - addScriptAtts(script, atts); - script.addEventListener('error', scriptOnError); - script.addEventListener('load', scriptOnLoad); - script.src = url; - - document.head.append(script); - }); -} - -/** -* -* @param {string|string[]} url -* @param {PlainObject} [atts={}] -* @param {PlainObject} opts -* @param {boolean} [opts.returnDefault=false} = {}] -* @returns {Promise} Resolves to value of loading module or rejects with -* `Error` upon a script loading error. -*/ -export function importModule (url, atts = {}, {returnDefault = false} = {}) { - if (Array.isArray(url)) { - return Promise.all(url.map((u) => { - return importModule(u, atts); - })); - } - return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new - const vector = '$importModule$' + Math.random().toString(32).slice(2); - const script = document.createElement('script'); - /** - * - * @returns {void} - */ - function scriptOnError () { - reject(new Error(`Failed to import: ${url}`)); - destructor(); - } - /** - * - * @returns {void} - */ - function scriptOnLoad () { - resolve(window[vector]); - destructor(); - } - const destructor = () => { - delete window[vector]; - script.removeEventListener('error', scriptOnError); - script.removeEventListener('load', scriptOnLoad); - script.remove(); - URL.revokeObjectURL(script.src); - script.src = ''; - }; - addScriptAtts(script, atts); - script.defer = 'defer'; - script.type = 'module'; - script.addEventListener('error', scriptOnError); - script.addEventListener('load', scriptOnLoad); - const absURL = toAbsoluteURL(url); - const loader = `import * as m from '${ - absURL.replace(/'/g, "\\'") - }'; window.${vector} = ${ - returnDefault ? 'm.default || ' : '' - }m;`; // export Module - const blob = new Blob([loader], {type: 'text/javascript'}); - script.src = URL.createObjectURL(blob); - - document.head.append(script); - }); -} - -export default importModule; diff --git a/src/svgcanvas/svgcanvas.js b/src/svgcanvas/svgcanvas.js index d5a60a83..af338ec6 100644 --- a/src/svgcanvas/svgcanvas.js +++ b/src/svgcanvas/svgcanvas.js @@ -33,7 +33,6 @@ import { } from './draw.js'; import {sanitizeSvg} from './sanitize.js'; import {getReverseNS, NS} from '../common/namespaces.js'; -import {importSetGlobal, importScript} from '../external/dynamic-import-polyfill/importModule.js'; import { text2xml, assignAttributes, cleanupElement, getElem, getUrlFromAttr, findDefs, getHref, setHref, getRefElem, getRotationAngle, getPathBBox, @@ -3990,9 +3989,8 @@ this.rasterExport = async function (imgType, quality, exportWindowName, opts = { const svg = this.svgCanvasToString(); if (!canvg) { - ({canvg} = await importSetGlobal(curConfig.canvgPath + 'canvg.js', { - global: 'canvg' - })); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + ({canvg} = await import(curConfig.canvgPath + 'canvg.js').default); } if (!$('#export_canvas').length) { $('', {id: 'export_canvas'}).hide().appendTo('body'); @@ -4076,24 +4074,12 @@ this.exportPDF = async function ( ) { if (!window.jsPDF) { // Todo: Switch to `import()` when widely supported and available (also allow customization of path) - await importScript([ - // We do not currently have these paths configurable as they are - // currently global-only, so not Rolled-up - 'jspdf/underscore-min.js', - // 'jspdf/jspdf.min.js', - '../../svgedit-myfix/editor/jspdf/jspdf-1.0.150.debug.js' - ]); - - const modularVersion = !('svgEditor' in window) || - !window.svgEditor || - window.svgEditor.modules !== false; - // Todo: Switch to `import()` when widely supported and available (also allow customization of path) - await importScript(curConfig.jspdfPath + 'jspdf.plugin.svgToPdf.js', { - type: modularVersion - ? 'module' - : 'text/javascript' - }); - // await importModule('jspdf/jspdf.plugin.svgToPdf.js'); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + await import('../editor/jspdf/underscore-min.js'); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + await import('../editor/jspdf/jspdf.min.js'); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + await import('../editor/jspdf/jspdf.plugin.svgToPdf.js'); } const res = getResolution();