diff --git a/CHANGELOG.md b/CHANGELOG.md index 2892d44..27b5852 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ See also [the changelog of monaco-editor](https://github.com/Microsoft/monaco-ed - update to PrimeFaces 7.0 - update to monaco editor 0.16.2 -- No more uses of `eval`. +- no more uses of `eval`. - due to the above: the property `extender` of the `monacoEditor` component, if given, must now be a valid JavaScript expression evaluating to an extender object. Loading the extender from an URL is not supported anymore. The recommended way is to define a factory function in diff --git a/pom.xml b/pom.xml index e30449c..a65c18e 100644 --- a/pom.xml +++ b/pom.xml @@ -228,6 +228,8 @@ ECMASCRIPT_2018 ECMASCRIPT_2015 + (function(){%output%}).call(window); + true widget.js ${project.basedir}/src/main/ ${project.basedir}/target/generated-sources diff --git a/src/main/js/widget.js b/src/main/js/widget.js index 18b49d9..05081c7 100644 --- a/src/main/js/widget.js +++ b/src/main/js/widget.js @@ -1,415 +1,443 @@ -(function() { - function getScriptName(label) { - if (label === 'json') { - return 'json.worker.js'; +/// + +function getScriptName(label) { + if (label === 'json') { + return 'json.worker.js'; + } + if (label === 'css') { + return 'css.worker.js'; + } + if (label === 'html') { + return 'html.worker.js'; + } + if (label === 'typescript' || label === 'javascript') { + return 'ts.worker.js'; + } + return 'editor.worker.js'; +} + +function endsWith(string, suffix) { + var this_len = string.length; + return string.substring(this_len - suffix.length, this_len) === suffix; +} + +function getBaseUrl() { + var res = PrimeFaces.resources.getFacesResource("", "", "0"); + var idx = res.lastIndexOf(".xhtml"); + return idx >= 0 ? res.substring(0, idx) : res; +} + +/** + * @param {string} url URL from which to load the script. + * @return {Promise} The loaded JavaScript. + */ +async function getScript(url) { + return jQuery.ajax({ + type: "GET", + url: url, + dataType: "script", + cache: true, + async: true + }); +} + +/** + * Loads the extender for this monaco editor. It may be either + * + * - an empty string or undefined, in which case no extender is loaded + * - a JavaScript expression that evaluates to an extender object + * - a path to a resource (eg. `extender.js.xhtml?ln=mylib`) that evaluates to an extender object + * + * @param {Partial} options The extender string as specified on the component. + * @return {Partial} + */ +function loadExtender(options) { + const extenderString = options.extender; + + // No extender given + if (typeof extenderString === "undefined") { + return {}; + } + + // Extender was evaluated already + if (typeof extenderString === "object") { + return extenderString; + } + + // Try creating an extender from the factory + if (typeof extenderString === "function") { + try { + const extender = extenderString(); + if (typeof extender === "object") { + return extender; + } } - if (label === 'css') { - return 'css.worker.js'; + catch (e) { + console.warn("Extender must be an expression that evaluates to MonacoExtender", e); } - if (label === 'html') { - return 'html.worker.js'; + } + + // Could not create extender. + console.warn("Extender was specified, but could not be loaded: ", extenderString); + return {}; +} + +/** + * @param {Partial} options + * @return {Promise<{forceLibReload: boolean, uiLanguageUri: string}>} + */ +async function loadLanguage(options) { + // Load language file, if requested. + if (options.uiLanguage && MonacoEnvironment.Locale.language !== options.uiLanguage) { + // Determine URI for loading the locale. + const uri = options.uiLanguageUri ? + getBaseUrl() + "uiLanguageUri" : + PrimeFaces.resources.getFacesResource("/monacoEditor/locale/" + options.uiLanguage + ".js", "primefaces-blutorange", options.version); + // And load UI language + await getScript(uri); + return { + forceLibReload: true, + uiLanguageUri: uri, + }; + } + else { + return { + forceLibReload: MonacoEnvironment.Locale.language !== options.uiLanguage, + uiLanguageUri: "" + }; + } +} + +/** + * @param {Partial} options + * @param {boolean} forceLibReload If true, loads the monaco editor again, even if it is loaded already. This is necessary in case the language changes. + * @return {Promise} Whether the monaco library was (re)loaded. + */ +async function loadEditorLib(options, forceLibReload) { + if (!("monaco" in window) || forceLibReload) { + if (!options.uiLanguage) { + MonacoEnvironment.Locale = { + language: "", + data: {}, + }; } - if (label === 'typescript' || label === 'javascript') { - return 'ts.worker.js'; + const uriEditor = PrimeFaces.resources.getFacesResource("/monacoEditor/editor.js", "primefaces-blutorange", options.version); + await getScript(uriEditor); + return true; + } + else { + return false; + } +} + +/** + * Evaluate the `beforeCreate` callback of the extender. It is passed the current options and may + * + * - not return anything, in which case the passed options are used (which may have been modified inplace) + * - return an options object, in which case these options are used + * - return a promise, in which case the editor is initialized only once that promise resolves. The promise + * may resolve to a new options object to be used. + * + * @param {ExtMonacoEditor} widget + * @param {MonacoExtender} extender + * @param {boolean} wasLibLoaded + * @return {Promise} + */ +async function createEditorConstructionOptions(widget, extender, wasLibLoaded) { + const editorOptions = typeof widget.options.editorOptions === "object" ? + widget.options.editorOptions : + typeof widget.options.editorOptions === "string" ? + JSON.parse(widget.options.editorOptions) : + {}; + + const model = createModel(widget.options, widget.id, widget.getInput().val()); + const options = jQuery.extend({ + readOnly: widget.options.readonly || widget.options.disabled, + model: model, + }, editorOptions); + + if (typeof extender.beforeCreate === "function") { + const result = extender.beforeCreate(widget, options, wasLibLoaded); + if (typeof result === "object") { + return typeof result.then === "function" ? (await result) || result : result; } - return 'editor.worker.js'; } - function endsWith(string, suffix) { - var this_len = string.length; - return string.substring(this_len - suffix.length, this_len) === suffix; - } + return options; +} + +/** + * @param {Partial} options + * @param {string} id + * @param {string} value + * @returns {monaco.editor.ITextModel} + */ +function createModel(options, id, value = "") { + const language = options.language || "plaintext"; + + // Path, basename and extension + /** @type {string} */ + let dir; + /** @type {string} */ + let basename; + /** @type {string} */ + let extension; + + if (options.directory) { + dir = options.directory; + } + else { + dir = String(id).replace(/[^a-zA-Z0-9_-]/g, "/"); + } + if (basename) { + basename = options.basename; + } + else { + basename = "file"; + } + if (options.ext) { + extension = options.ext; + } + else { + const langInfo = monaco.languages.getLanguages().filter(lang => lang.id === language)[0]; + extension = langInfo && langInfo.extensions.length > 0 ? langInfo.extensions[0] : ""; + } - function getScript(url) { - return jQuery.ajax({ - type: "GET", - url: url, - dataType: "script", - cache: true, - async: true - }); + // Build path and uri + if (dir.length > 0 && dir[dir.length - 1] !== "/") { + dir = dir + "/"; + } + if (extension.length > 0 && extension[0] !== ".") { + extension = "." + extension; + } + if (endsWith(basename, extension)) { + extension = ""; } - PrimeFaces.widget.ExtMonacoEditor = PrimeFaces.widget.BaseWidget.extend({ - init(cfg) { - this._super(cfg); + const uri = monaco.Uri.from({ + scheme: "inmemory", + path: dir + basename + extension + }); - this.$input = this.jq.find(".ui-helper-hidden-accessible textarea"); - this.$editor = this.jq.children(".ui-monaco-editor-ed"); - this.uiLanguageUri = ""; + // Create model and set value + let model = monaco.editor.getModel(uri); + if (!model) { + model = monaco.editor.createModel(value, language, uri); + } + model.setValue(value); + return model; +} + + +/** + * Default options for the monaco editor widget configuration. + */ +const EditorDefaults = { + autoResize: false, + basename: "", + directory: "", + disabled: false, + editorOptions: {}, + extender: "", + extension: "", + language: "plaintext", + readonly: false, + uiLanguage: "", + uiLanguageUri: "", + version: "1.0", +}; + +// Make sure the monaco environment is set. +const MonacoEnvironment = window.MonacoEnvironment = window.MonacoEnvironment || {}; + +class ExtMonacoEditor extends PrimeFaces.widget.BaseWidget { + /** + * @param {...any[]} args Arguments as passed by PrimeFaces. + */ + constructor(...args) { + super(...args); + /* super calls #init + this._editor = undefined; + this._editorContainer = $(); + this._extenderInstance = undefined; + this._input = jQuery(); + this._resizeObserver = undefined; + this._resolvedUiLanguageUri = ""; + this.options = jQuery.extend({}, EditorDefaults); + */ + } - // Remove any existing editor. - this.destroy(); + init(cfg) { + super.init(cfg); - // Set defaults. - this.options = jQuery.extend({}, this._defaults, this.cfg); + // Set defaults. + this.options = jQuery.extend({}, EditorDefaults, this.cfg); - // English is the default. - if (this.options.uiLanguage === "en") { - this.options.uiLanguage = ""; - } + // Get elements + this._input = this.jq.find(".ui-helper-hidden-accessible textarea"); + this._editorContainer = this.jq.children(".ui-monaco-editor-ed"); - // Set monaco environment - window.MonacoEnvironment = window.MonacoEnvironment || {}; - if (!("getWorker" in MonacoEnvironment)) { - MonacoEnvironment.getWorker = this._createWorkerFactory(); - } - if (!("Locale" in MonacoEnvironment)) { - MonacoEnvironment.Locale = {language: "", data: {}}; - } + // Remove any existing editor. + this.destroy(); - this._loadExtender(true); - }, - - /** - * @return {monaco.editor} Instance of the monacor editor, or undefined if this widget is not yet initialized. - */ - getMonaco() { - return this._editor; - }, - - /** - * Loads the extender for this monaco editor. It may be either - * - * - an empty string or undefined, in which case no extender is loaded - * - a JavaScript expression that evaluates to an extender object - * - a path to a resource (eg. `extender.js.xhtml?ln=mylib`) that evaluates to an extender object - * @param wasLibLoaded - * @private - */ - _loadExtender() { - this._evaluatedExtender = {}; - - // No extender given - if (typeof this.options.extender === "undefined") { - this._loadLanguage(); - return; - } + // English is the default. + if (this.options.uiLanguage === "en") { + this.options.uiLanguage = ""; + } - // Extender was evaluated already - if (typeof this.options.extender === "object") { - this._evaluatedExtender = this.options.extender; - this._loadLanguage(); - return; - } - - // Try creating an extender from the factory - var extenderFound = false; - if (typeof this.options.extender === "function") { - try { - this._evaluatedExtender = this.options.extender(); - extenderFound = true; - } - catch (e) { - console.warn("Extender must be an expression that evaluates to MonacoExtender"); - } - } + // Set monaco environment + if (!("getWorker" in MonacoEnvironment)) { + MonacoEnvironment.getWorker = this._createWorkerFactory(); + } + if (!("Locale" in MonacoEnvironment)) { + MonacoEnvironment.Locale = { + data: {}, + language: "", + }; + } - if (extenderFound) { - this._loadLanguage(); - return; - } + // Begin loading the editor + this._setup().then(() => { + this._fireEvent("initialized"); + this.jq.data("initialized", true); + }).catch(error => { + console.error("Failed to initialize monaco editor", error); + }); + } - console.warn("Extender was specified, but could not be loaded"); - this._loadLanguage(); - }, - - _loadLanguage() { - // Load language file, if requested. - if (this.options.uiLanguage && MonacoEnvironment.Locale.language !== this.options.uiLanguage) { - // Determine URI for loading the locale. - if (this.options.uiLanguageUri) { - this.uiLanguageUri = this._getBaseUrl() + this.options.uiLanguageUri; - } - else { - this.uiLanguageUri = PrimeFaces.resources.getFacesResource("/monacoEditor/locale/" + this.options.uiLanguage + ".js", "primefaces-blutorange", this.options.version); - } - // Load UI language - getScript(this.uiLanguageUri).then(() => this._loadEditor(true)).catch(error => { - console.warn("Failed to load locale for " + this.options.uiLanguage, error); - this._loadEditor(MonacoEnvironment.Locale.language !== this.options.uiLanguage); - }); - } - else { - this._loadEditor(MonacoEnvironment.Locale.language !== this.options.uiLanguage); - } - }, - - /** - * - * @param forceLibReload If true, loads the monaco editor again, even if it is loaded already. This is necessary in case the language changes. - * @private - */ - _loadEditor(forceLibReload) { - if (window.monaco === undefined || forceLibReload) { - if (this.options.uiLanguage == "") { - MonacoEnvironment.Locale = {language: "", data: {}}; - } - var uriEditor = PrimeFaces.resources.getFacesResource("/monacoEditor/editor.js", "primefaces-blutorange", this.options.version); - getScript(uriEditor).then(() => this._beforeCreate(true)).catch(error => { - console.warn("Failed to load monaco editor resources, cannot initialize editor", error); - }); - } - else { - this._beforeCreate(false); - } - }, - - /** - * Evaluate the `beforeCreate` callback of the extender. It is passed the current options and may - * - * - not return anything, in which case the passed options are used (which may have been modified inplace) - * - return an options object, in which case these options are used - * - return a promise, in which case the editor is initialized only once that promise resolves. The promise - * may resolve to an new options object to be used. - * @param wasLibLoaded - * @private - */ - _beforeCreate (wasLibLoaded) { - this._getEditorContainer().empty(); - - const extender = this._evaluatedExtender; - - const editorOptions = typeof this.options.editorOptions === "object" ? - this.options.editorOptions : - typeof this.options.editorOptions === "string" ? - JSON.parse(this.options.editorOptions) : - {}; - - const model = this._createModel(editorOptions); - - const options = jQuery.extend({ - readOnly: this.options.readonly || this.options.disabled, - model: model, - - // TODO Remove this in version 0.17 - language: this.options.language || "plaintext", - value: this._getInput().val() || "" - }, editorOptions); - - if (typeof extender.beforeCreate === "function") { - const result = extender.beforeCreate(this, options, wasLibLoaded); - if (typeof result === "object") { - if (typeof result.then === "function") { - // Promise / thenable returned - const thened = result.then(newOptions => { - this._render(typeof newOptions === "object" ? newOptions : options, extender, wasLibLoaded); - }); - if (typeof thened.catch === "function") { - thened.catch(error => console.error("Extender promise failed to resolve", error)); - } - } - else { - this._render(result, extender, wasLibLoaded); - } - } - else { - this._render(options, extender, wasLibLoaded); - } - } - else { - this._render(options, extender, wasLibLoaded); - } - }, + /** + * @return {monaco.editor.IStandaloneCodeEditor} Instance of the monacor editor, or undefined if this widget is not yet initialized. + */ + getMonaco() { + return this._editor; + } - _render(options, extender, wasLibLoaded) { - // TODO Remove this in version 0.17 - if (typeof options.value !== undefined) { - delete options.value; - } - if (typeof options.language !== undefined) { - delete options.language; - } + destroy() { + const extender = this._extenderInstance; + const monaco = this.getMonaco(); + if (extender && typeof extender.beforeDestroy === "function") { + extender.beforeDestroy(this); + } + if (this._resizeObserver !== undefined) { + this._resizeObserver.disconnect(this.jq.get(0)); + } + if (monaco !== undefined) { + monaco.dispose(); + } + if (extender && typeof extender.afterDestroy === "function") { + extender.afterDestroy(this); + } + } - // Create a new editor instance. - this._editor = monaco.editor.create(this._getEditorContainer().get(0), options); + /** + * @returns {jQuery} The hidden textarea holding the value. + */ + getInput() { + return this._input; + } - // Evaluate the `afterCreate` callback of the extender. - if (typeof extender.afterCreate === "function") { - extender.afterCreate(this, wasLibLoaded); - } + /** + * @returns {jQuery} The element holding the editor. + */ + getEditorContainer() { + return this._editorContainer; + } - if (this.options.autoResize) { - if (typeof window.ResizeObserver === "function") { - this.resizeObserver = new ResizeObserver(this._onResize.bind(this)); - this.resizeObserver.observe(this.jq.get(0)); - } - else { - console.warn("Browser environment does not support autoresize. window.ResizeObserver is not defined."); - } + async _setup() { + const extender = loadExtender(this.options); + this._extenderInstance = extender; + const {forceLibReload, uiLanguageUri} = await loadLanguage(this.options); + this._resolvedUiLanguageUri = uiLanguageUri; + const wasLibLoaded = await loadEditorLib(this.options, forceLibReload); + this.getEditorContainer().empty(); + const editorConstructionOptions = await createEditorConstructionOptions(this, extender, wasLibLoaded); + this._render(editorConstructionOptions, extender, wasLibLoaded); + return; + } + + /** + * + * @param {monaco.editor.IEditorConstructionOptions} options + * @param {MonacoExtender} extender + * @param {boolean} wasLibLoaded + */ + _render(options, extender, wasLibLoaded) { + // Create a new editor instance. + this._editor = monaco.editor.create(this.getEditorContainer().get(0), options); + + // Evaluate the `afterCreate` callback of the extender. + if (typeof extender.afterCreate === "function") { + extender.afterCreate(this, wasLibLoaded); + } + + // Resize + if (this.options.autoResize) { + if (typeof ResizeObserver === "function") { + this._resizeObserver = new ResizeObserver(this._onResize.bind(this)); + this._resizeObserver.observe(this.jq.get(0)); + } + else { + console.warn("Browser environment does not support autoresize. window.ResizeObserver is not defined."); } + } - // Change event. - // Set the value of the editor on the hidden textarea. - this._editor.onDidChangeModelContent(changes => { - this._getInput().val(this.getMonaco().getModel().getValue()); - this._fireEvent('change', changes); - }); + // Change event. + // Set the value of the editor on the hidden textarea. + this._editor.onDidChangeModelContent(changes => { + this.getInput().val(this.getMonaco().getModel().getValue()); + this._fireEvent('change', changes); + }); - // Focus / blur - this._editor.onDidFocusEditorWidget(() => this._fireEvent('focus')); - this._editor.onDidBlurEditorWidget(() => this._fireEvent('blur')); + // Focus / blur + this._editor.onDidFocusEditorWidget(() => this._fireEvent('focus')); + this._editor.onDidBlurEditorWidget(() => this._fireEvent('blur')); - // Paste - this._editor.onDidPaste(range => this._fireEvent('paste', range)); + // Paste + this._editor.onDidPaste(range => this._fireEvent('paste', range)); - // Mouse / Key - this._editor.onMouseDown(mouseEvent => this._fireEvent('mousedown', mouseEvent)); - this._editor.onMouseMove(mouseEvent => this._fireEvent('mousemove', mouseEvent)); - this._editor.onMouseUp(mouseEvent => this._fireEvent('mouseup', mouseEvent)); - this._editor.onKeyDown(keyboardEvent => this._fireEvent('keydown', keyboardEvent)); - this._editor.onKeyUp(keyboardEvent => this._fireEvent('keyup', keyboardEvent)); - this._editor.onDidType(key => this._fireEvent('keypress', key)); + // Mouse / Key + this._editor.onMouseDown(mouseEvent => this._fireEvent('mousedown', mouseEvent)); + this._editor.onMouseMove(mouseEvent => this._fireEvent('mousemove', mouseEvent)); + this._editor.onMouseUp(mouseEvent => this._fireEvent('mouseup', mouseEvent)); + this._editor.onKeyDown(keyboardEvent => this._fireEvent('keydown', keyboardEvent)); + this._editor.onKeyUp(keyboardEvent => this._fireEvent('keyup', keyboardEvent)); + this._editor.onDidType(key => this._fireEvent('keypress', key)); + } - this._fireEvent("initialized"); - this.jq.data("initialized", true); - }, - - destroy() { - var extender = this._evaluatedExtender; - if (extender && typeof extender.beforeDestroy === "function") { - extender.beforeDestroy(this); - } - var monaco = this.getMonaco(); - if (this.resizeObserver !== undefined) { - this.resizeObserver.disconnect(this.jq.get(0)); - } - if (monaco !== undefined) { - monaco.dispose(); - } - if (extender && typeof extender.afterDestroy === "function") { - extender.afterDestroy(this); - } - }, - - _onResize() { - var monaco = this.getMonaco(); - if (monaco !== undefined) { - monaco.layout(); - } - }, - - _getBaseUrl() { - var res = PrimeFaces.resources.getFacesResource("", "", "0"); - var idx = res.lastIndexOf(".xhtml"); - return idx >= 0 ? res.substring(0, idx) : res; - }, - - _fireEvent (eventName, ...params) { - var onName = "on" + eventName; - this.jq.trigger("monacoEditor:" + eventName, params); - if (typeof this.options[onName] === "function") { - this.options[onName].apply(this, params || []); - } - this.callBehavior(eventName, { - params: params || {} - }); - }, - - /** - * @return {(moduleId: string, label: string) => Worker} The factory that creates the workers for JSON, CSS and other languages. - */ - _createWorkerFactory() { - return (moduleId, label) => { - const extender = this._evaluatedExtender; - if (typeof extender === "object" && typeof extender.createWorker === "function") { - return extender.createWorker(this, moduleId, label); - } - else { - const workerUrl = PrimeFaces.resources.getFacesResource("monacoEditor/" + getScriptName(label), "primefaces-blutorange", this.options.version); - const interceptWorkerUrl = PrimeFaces.resources.getFacesResource("monacoEditor/worker.js", "primefaces-blutorange", this.options.version); - return new Worker(interceptWorkerUrl + "&worker=" + encodeURIComponent(workerUrl) + "&locale=" + encodeURIComponent(this.uiLanguageUri || "")); - } - }; - }, - - _createModel(editorOptions) { - // Value and language - var value = this._getInput().val() || ""; - var language = this.options.language || "plaintext"; - - // Path, basename and extension - /** @type {string} */ - var dir; - /** @type {string} */ - var basename; - /** @type {string} */ - var extension; - if (this.options.directory) { - dir = this.options.directory; - } - else { - dir = String(this.id).replace(/[^a-zA-Z0-9_-]/g, "/"); - } - if (this.options.basename) { - basename = this.options.basename; - } - else { - basename = "file"; - } - if (this.options.extension) { - extension = this.options.extension; - } - else { - var langInfo = monaco.languages.getLanguages().filter(lang => lang.id === language)[0]; - extension = langInfo && langInfo.extensions.length > 0 ? langInfo.extensions[0] : ""; - } - - // Build path and uri - if (dir.length > 0 && dir[dir.length - 1] !== "/") { - dir = dir + "/"; - } - if (extension.length > 0 && extension[0] !== ".") { - extension = "." + extension; - } - if (endsWith(basename, extension)) { - extension = ""; - } - var uri = monaco.Uri.from({ - scheme: "inmemory", - path: dir + basename + extension - }); - - // Return model - var model = monaco.editor.getModel(uri); - if (model) { - model.setValue(value); - return model; + _onResize() { + const monaco = this.getMonaco(); + if (monaco !== undefined) { + monaco.layout(); + } + } + + _fireEvent(eventName, ...params) { + var onName = "on" + eventName; + this.jq.trigger("monacoEditor:" + eventName, params); + if (typeof this.options[onName] === "function") { + this.options[onName].apply(this, params || []); + } + this.callBehavior(eventName, { + params: params || {} + }); + } + + /** + * @return {(moduleId: string, label: string) => Worker} The factory that creates the workers for JSON, CSS and other languages. + */ + _createWorkerFactory() { + return (moduleId, label) => { + const extender = this._extenderInstance; + if (typeof extender === "object" && typeof extender.createWorker === "function") { + return extender.createWorker(this, moduleId, label); } else { - return monaco.editor.createModel(value, language, uri); + const workerUrl = PrimeFaces.resources.getFacesResource("monacoEditor/" + getScriptName(label), "primefaces-blutorange", this.options.version); + const interceptWorkerUrl = PrimeFaces.resources.getFacesResource("monacoEditor/worker.js", "primefaces-blutorange", this.options.version); + return new Worker(interceptWorkerUrl + "&worker=" + encodeURIComponent(workerUrl) + "&locale=" + encodeURIComponent(this._resolvedUiLanguageUri || "")); } - }, - - /** - * @returns {jQuery} The hidden textarea holding the value. - * @private - */ - _getInput() { - return this.$input; - }, - - /** - * @returns {jQuery} The element holding the editor. - * @private - */ - _getEditorContainer() { - return this.$editor; - }, - - _defaults: { - autoResize: false, - basename: "", - directory: "", - disabled: false, - editorOptions: {}, - extender: "", - extension: "", - language: "plaintext", - readonly: false, - uiLanguage: "", - uiLanguageUri: "", - version: "1.0" - }, - }); -})(); + }; + } +} + +PrimeFaces.widget.ExtMonacoEditor = ExtMonacoEditor; diff --git a/src/npm/generateLocales.js b/src/npm/generateLocales.js index f5c479d..553a9b2 100644 --- a/src/npm/generateLocales.js +++ b/src/npm/generateLocales.js @@ -33,53 +33,53 @@ const missingTranslations = { "singleSelection": ["vs/workbench/browser/parts/editor/editorStatus", "singleSelection"], "multiSelectionRange": ["vs/workbench/browser/parts/editor/editorStatus", "multiSelectionRange"], "multiSelection": ["vs/workbench/browser/parts/editor/editorStatus", "multiSelectionRange"], - "ShowAccessibilityHelpAction": ["vs/workbench/parts/codeEditor/electron-browser/accessibility", "ShowAccessibilityHelpAction"], + "ShowAccessibilityHelpAction": ["vs/workbench/contrib/codeEditor/browser/accessibility/accessibility", "ShowAccessibilityHelpAction"], }, "vs/editor/standalone/browser/inspectTokens/inspectTokens": { "inspectTokens": "Developer: Inspect Tokens" }, "vs/editor/standalone/browser/quickOpen/quickOutline": { "quickOutlineActionInput": "Type the name of an identifier you wish to navigate to", - "QuickOutlineAction.label": ["vs/workbench/parts/quickopen/browser/quickopen.contribution", "gotoSymbolDescription"], - "symbols": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "symbols"], - "method": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "method"], - "function": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "function"], - "_constructor": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "_constructor"], - "variable": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "variable"], - "class": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "class"], - "interface": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "interface"], - "namespace": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "namespace"], - "package": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "package"], - "modules": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "modules"], - "property": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "property"], - "enum": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "enum"], - "string": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "string"], - "rule": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "rule"], - "file": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "file"], - "array": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "array"], - "number": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "number"], - "boolean": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "boolean"], - "object": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "object"], - "key": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "key"], - "entryAriaLabel": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "entryAriaLabel"], - "modules": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "modules"], - "noSymbolsMatching": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "noSymbolsMatching"], - "noSymbolsFound": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "noSymbolsFound"], - "gotoSymbolHandlerAriaLabel": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "gotoSymbolHandlerAriaLabel"], - "cannotRunGotoSymbolInFile": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "cannotRunGotoSymbolInFile"], - "cannotRunGotoSymbol": ["vs/workbench/parts/quickopen/browser/gotoSymbolHandler", "cannotRunGotoSymbol"], + "QuickOutlineAction.label": ["vs/workbench/contrib/quickopen/browser/quickopen.contribution", "gotoSymbolDescription"], + "symbols": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "symbols"], + "method": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "method"], + "function": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "function"], + "_constructor": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "_constructor"], + "variable": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "variable"], + "class": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "class"], + "interface": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "interface"], + "namespace": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "namespace"], + "package": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "package"], + "modules": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "modules"], + "property": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "property"], + "enum": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "enum"], + "string": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "string"], + "rule": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "rule"], + "file": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "file"], + "array": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "array"], + "number": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "number"], + "boolean": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "boolean"], + "object": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "object"], + "key": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "key"], + "entryAriaLabel": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "entryAriaLabel"], + "modules": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "modules"], + "noSymbolsMatching": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "noSymbolsMatching"], + "noSymbolsFound": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "noSymbolsFound"], + "gotoSymbolHandlerAriaLabel": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "gotoSymbolHandlerAriaLabel"], + "cannotRunGotoSymbolInFile": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "cannotRunGotoSymbolInFile"], + "cannotRunGotoSymbol": ["vs/workbench/contrib/quickopen/browser/gotoSymbolHandler", "cannotRunGotoSymbol"], }, "vs/editor/standalone/browser/quickOpen/gotoLine": { - "gotoLineLabelEmptyWithLineLimit": ["vs/workbench/parts/quickopen/browser/gotoLineHandler", "gotoLineLabelEmptyWithLimit"], - "gotoLineAriaLabel": ["vs/workbench/parts/quickopen/browser/gotoLineHandler", "gotoLineLabel"], - "gotoLineLabelValidLine": ["vs/workbench/parts/quickopen/browser/gotoLineHandler", "gotoLineLabel"], - "gotoLineActionInput": ["vs/workbench/parts/quickopen/browser/gotoLineHandler", "gotoLineLabelEmpty"], - "GotoLineAction.label": ["vs/workbench/parts/quickopen/browser/gotoLineHandler", "gotoLine"], + "gotoLineLabelEmptyWithLineLimit": ["vs/workbench/contrib/quickopen/browser/gotoLineHandler", "gotoLineLabelEmptyWithLimit"], + "gotoLineAriaLabel": ["vs/workbench/contrib/quickopen/browser/gotoLineHandler", "gotoLineLabel"], + "gotoLineLabelValidLine": ["vs/workbench/contrib/quickopen/browser/gotoLineHandler", "gotoLineLabel"], + "gotoLineActionInput": ["vs/workbench/contrib/quickopen/browser/gotoLineHandler", "gotoLineLabelEmpty"], + "GotoLineAction.label": ["vs/workbench/contrib/quickopen/browser/gotoLineHandler", "gotoLine"], }, "vs/editor/standalone/browser/quickOpen/quickCommand": { "quickCommandActionInput": "Type the name of an action you want to execute", - "QuickCommandAction.label": ["vs/workbench/parts/quickopen/browser/quickopen.contribution", "miCommandPalette"], - "ariaLabelEntry": ["vs/workbench/parts/quickopen/browser/commandsHandler", "entryAriaLabel"], + "QuickCommandAction.label": ["vs/workbench/contrib/quickopen/browser/quickopen.contribution", "miCommandPalette"], + "ariaLabelEntry": ["vs/workbench/contrib/quickopen/browser/commandsHandler", "entryAriaLabel"], }, "vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast": { "toggleHighContrast": "Toggle High Contrast Theme" diff --git a/src/npm/primefaces-monaco.d.ts b/src/npm/primefaces-monaco.d.ts index f190f3f..4445eec 100644 --- a/src/npm/primefaces-monaco.d.ts +++ b/src/npm/primefaces-monaco.d.ts @@ -42,15 +42,19 @@ export interface MonacoExtender { * See [IEditorConstructionOptions](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.ieditorconstructionoptions.html) for all editor options. * @param editorWidget The current monaco editor widget. Note that calling `getMonaco()` on the editor widget right now returns `undefined`. * @param options The current options that would be used to create the editor. + * @param wasLibLoaded `true` if the monaco editor library was reloaded, `false` otherwise. In case it was reloaded, you + * may want to setup some language defaults again. * @return Nothing to use the options as passed; a new options object to be used for creating the editor; or a Promise * that may return the new options. */ - beforeCreate(editorWidget: PrimeFaces.Widget.ExtMonacoEditor, options: monaco.editor.IEditorConstructionOptions): monaco.languages.ProviderResult; + beforeCreate(editorWidget: PrimeFaces.Widget.ExtMonacoEditor, options: monaco.editor.IEditorConstructionOptions, wasLibLoaded: boolean): monaco.languages.ProviderResult; /** * Called after the editor was created. * @param editorWidget The current monaco editor widget. + * @param wasLibLoaded `true` if the monaco editor library was reloaded, `false` otherwise. In case it was reloaded, you + * may want to setup some language defaults again. */ - afterCreate(editorWidget: PrimeFaces.Widget.ExtMonacoEditor): void; + afterCreate(editorWidget: PrimeFaces.Widget.ExtMonacoEditor, wasLibLoaded: boolean): void; /** * Called before the editor is destroyed, eg. when updating a component via AJAX. * @param editorWidget The current monaco editor widget. @@ -206,6 +210,12 @@ declare namespace PrimeFaces { * Destroys this widget. Called by the PrimeFaces framework. */ destroy(): void; + /** + * If it exists, calls the behavior with the given name. + * @param name Name of the behavior. + * @param args Additional arguments for the behavior. + */ + callBehavior(name: string, ...args: unknown[]): void; } /** * The monaco editor widget. This is a thin wrapper around the actual monaco editor and @@ -223,6 +233,16 @@ declare namespace PrimeFaces { * JavaScript. See also the [monaco editor API docs](https://microsoft.github.io/monaco-editor/api/index.html). */ getMonaco(): monaco.editor.IStandaloneCodeEditor; + /** + * @returns {jQuery} The HTML container element holding the editor. It exists even + * if the editor was not created yet. + */ + getEditorContainer(); + /** + * @returns {jQuery} The hidden textarea holding the value (eg. what the value sent when + * the form is submitted). + */ + getInput(); } } } \ No newline at end of file