UNPKG

@webspellchecker/wproofreader-ckeditor5

Version:

Multilingual spelling and grammar checking plugin for CKEditor 5

170 lines (145 loc) 3.38 kB
import SrcStorage from './src-storage.js'; /** * Loads script asynchronously. */ export class ScriptLoader { /** * Creates an instance of the {@code ScriptLoader}. * @public * * @param {String} src - url of the script */ constructor(src) { this._validateSrc(src); this._src = src; this._globalSrcStorage = new SrcStorage(); } /** * Loads script by the passed url. * @public */ load() { return new Promise((resolve, reject) => { if (!this._isScriptOnPage()) { this._createScript(resolve, reject); } else { this._processExistingScript(resolve, reject); } }); } /** * Checks if the src of the script exists otherwise throws an {@code Error}. * @private */ _validateSrc(src) { if (!src) { throw new Error('Path to the script is not specified.'); } } /** * Checks if the script exists on the page. * @private */ _isScriptOnPage() { return document.querySelector('script[src="' + this._src + '"]') ? true : false; } /** * Creates the script and add listeners for it. * @private */ _createScript(resolve, reject) { this._script = this._createElement(); this._globalSrcStorage.add(this._src); this._globalSrcStorage.addCallbacks(this._src, resolve, reject); this._subscribeOnScriptLoad(); this._subscribeOnScriptError(); this._appendScript(this._script); } /** * Creates a script html element. * @private */ _createElement() { const script = document.createElement('script'); script.type = 'text/javascript'; script.charset = 'UTF-8'; script.src = this._src; return script; } /** * Subscribes on a load event of the script. * @private */ _subscribeOnScriptLoad() { this._script.onload = () => { this._globalSrcStorage.eachOnLoad(this._src, (callback) => { callback(); }); this._destroy(); }; } /** * Subscribes on an error event of the script. * @private */ _subscribeOnScriptError() { this._script.onerror = () => { const error = new Error(`${this._src} failed to load.`); this._globalSrcStorage.eachOnError(this._src, (callback) => { callback(error); }); this._destroy(); }; } /** * Destroys the {@code SrciptLoader}. * @private */ _destroy() { this._removeListeners(); this._globalSrcStorage.delete(this._src); this._src = null; this._script = null; } /** * Removes script listeners. * @private */ _removeListeners() { this._script.onload = null; this._script.onerror = null; } /** * Appends the script to the {@code head} block of a html page. * @private */ _appendScript(script) { const head = document.getElementsByTagName('head')[0]; head.appendChild(script); } /** * Processes existing script. It is not known whether it is fully loaded. * @private */ _processExistingScript(resolve, reject) { if (this._globalSrcStorage.has(this._src)) { this._addCallbacks(resolve, reject); } else { this._processLoadedScript(resolve); } } /** * Adds callbacks to the storage. Called when the script is on the page, but is not loaded yet. * @private */ _addCallbacks(resolve, reject) { this._globalSrcStorage.addCallbacks(this._src, resolve, reject); } /** * Processes loaded script. Called when the script on the page is fully loaded and ready to use. * @private */ _processLoadedScript(resolve) { resolve(); } }