Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/editor/editor_lite.js')
-rw-r--r--app/assets/javascripts/editor/editor_lite.js221
1 files changed, 163 insertions, 58 deletions
diff --git a/app/assets/javascripts/editor/editor_lite.js b/app/assets/javascripts/editor/editor_lite.js
index 1808f968b8c..79beb3a4857 100644
--- a/app/assets/javascripts/editor/editor_lite.js
+++ b/app/assets/javascripts/editor/editor_lite.js
@@ -1,12 +1,17 @@
import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor';
-import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
-import languages from '~/ide/lib/languages';
+import { uuids } from '~/diffs/utils/uuids';
import { defaultEditorOptions } from '~/ide/lib/editor_options';
+import languages from '~/ide/lib/languages';
+import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
import { registerLanguages } from '~/ide/utils';
import { joinPaths } from '~/lib/utils/url_utility';
+import {
+ EDITOR_LITE_INSTANCE_ERROR_NO_EL,
+ URI_PREFIX,
+ EDITOR_READY_EVENT,
+ EDITOR_TYPE_DIFF,
+} from './constants';
import { clearDomElement } from './utils';
-import { EDITOR_LITE_INSTANCE_ERROR_NO_EL, URI_PREFIX } from './constants';
-import { uuids } from '~/diffs/utils/uuids';
export default class EditorLite {
constructor(options = {}) {
@@ -29,15 +34,12 @@ export default class EditorLite {
monacoEditor.setTheme(theme ? themeName : DEFAULT_THEME);
}
- static updateModelLanguage(path, instance) {
- if (!instance) return;
- const model = instance.getModel();
+ static getModelLanguage(path) {
const ext = `.${path.split('.').pop()}`;
const language = monacoLanguages
.getLanguages()
.find((lang) => lang.extensions.indexOf(ext) !== -1);
- const id = language ? language.id : 'plaintext';
- monacoEditor.setModelLanguage(model, id);
+ return language ? language.id : 'plaintext';
}
static pushToImportsArray(arr, toImport) {
@@ -73,50 +75,19 @@ export default class EditorLite {
});
}
- /**
- * Creates a monaco instance with the given options.
- *
- * @param {Object} options Options used to initialize monaco.
- * @param {Element} options.el The element which will be used to create the monacoEditor.
- * @param {string} options.blobPath The path used as the URI of the model. Monaco uses the extension of this path to determine the language.
- * @param {string} options.blobContent The content to initialize the monacoEditor.
- * @param {string} options.blobGlobalId This is used to help globally identify monaco instances that are created with the same blobPath.
- */
- createInstance({
- el = undefined,
- blobPath = '',
- blobContent = '',
- blobGlobalId = uuids()[0],
- extensions = [],
- ...instanceOptions
- } = {}) {
+ static prepareInstance(el) {
if (!el) {
throw new Error(EDITOR_LITE_INSTANCE_ERROR_NO_EL);
}
clearDomElement(el);
- const uriFilePath = joinPaths(URI_PREFIX, blobGlobalId, blobPath);
-
- const model = monacoEditor.createModel(blobContent, undefined, Uri.file(uriFilePath));
-
monacoEditor.onDidCreateEditor(() => {
delete el.dataset.editorLoading;
});
+ }
- const instance = monacoEditor.create(el, {
- ...this.options,
- ...instanceOptions,
- });
- instance.setModel(model);
- instance.onDidDispose(() => {
- const index = this.instances.findIndex((inst) => inst === instance);
- this.instances.splice(index, 1);
- model.dispose();
- });
- instance.updateModelLanguage = (path) => EditorLite.updateModelLanguage(path, instance);
- instance.use = (args) => this.use(args, instance);
-
+ static manageDefaultExtensions(instance, el, extensions) {
EditorLite.loadExtensions(extensions, instance)
.then((modules) => {
if (modules) {
@@ -126,33 +97,167 @@ export default class EditorLite {
}
})
.then(() => {
- el.dispatchEvent(new Event('editor-ready'));
+ el.dispatchEvent(new Event(EDITOR_READY_EVENT));
})
.catch((e) => {
throw e;
});
+ }
+
+ static createEditorModel({
+ blobPath,
+ blobContent,
+ blobOriginalContent,
+ blobGlobalId,
+ instance,
+ isDiff,
+ } = {}) {
+ if (!instance) {
+ return null;
+ }
+ const uriFilePath = joinPaths(URI_PREFIX, blobGlobalId, blobPath);
+ const uri = Uri.file(uriFilePath);
+ const existingModel = monacoEditor.getModel(uri);
+ const model = existingModel || monacoEditor.createModel(blobContent, undefined, uri);
+ if (!isDiff) {
+ instance.setModel(model);
+ return model;
+ }
+ const diffModel = {
+ original: monacoEditor.createModel(
+ blobOriginalContent,
+ EditorLite.getModelLanguage(model.uri.path),
+ ),
+ modified: model,
+ };
+ instance.setModel(diffModel);
+ return diffModel;
+ }
+
+ static convertMonacoToELInstance = (inst) => {
+ const editorLiteInstanceAPI = {
+ updateModelLanguage: (path) => {
+ return EditorLite.instanceUpdateLanguage(inst, path);
+ },
+ use: (exts = []) => {
+ return EditorLite.instanceApplyExtension(inst, exts);
+ },
+ };
+ const handler = {
+ get(target, prop, receiver) {
+ if (Reflect.has(editorLiteInstanceAPI, prop)) {
+ return editorLiteInstanceAPI[prop];
+ }
+ return Reflect.get(target, prop, receiver);
+ },
+ };
+ return new Proxy(inst, handler);
+ };
+
+ static instanceUpdateLanguage(inst, path) {
+ const lang = EditorLite.getModelLanguage(path);
+ const model = inst.getModel();
+ return monacoEditor.setModelLanguage(model, lang);
+ }
+
+ static instanceApplyExtension(inst, exts = []) {
+ const extensions = [].concat(exts);
+ extensions.forEach((extension) => {
+ EditorLite.mixIntoInstance(extension, inst);
+ });
+ return inst;
+ }
+
+ static instanceRemoveFromRegistry(editor, instance) {
+ const index = editor.instances.findIndex((inst) => inst === instance);
+ editor.instances.splice(index, 1);
+ }
+
+ static instanceDisposeModels(editor, instance, model) {
+ const instanceModel = instance.getModel() || model;
+ if (!instanceModel) {
+ return;
+ }
+ if (instance.getEditorType() === EDITOR_TYPE_DIFF) {
+ const { original, modified } = instanceModel;
+ if (original) {
+ original.dispose();
+ }
+ if (modified) {
+ modified.dispose();
+ }
+ } else {
+ instanceModel.dispose();
+ }
+ }
+
+ /**
+ * Creates a monaco instance with the given options.
+ *
+ * @param {Object} options Options used to initialize monaco.
+ * @param {Element} options.el The element which will be used to create the monacoEditor.
+ * @param {string} options.blobPath The path used as the URI of the model. Monaco uses the extension of this path to determine the language.
+ * @param {string} options.blobContent The content to initialize the monacoEditor.
+ * @param {string} options.blobGlobalId This is used to help globally identify monaco instances that are created with the same blobPath.
+ */
+ createInstance({
+ el = undefined,
+ blobPath = '',
+ blobContent = '',
+ blobOriginalContent = '',
+ blobGlobalId = uuids()[0],
+ extensions = [],
+ isDiff = false,
+ ...instanceOptions
+ } = {}) {
+ EditorLite.prepareInstance(el);
+
+ const createEditorFn = isDiff ? 'createDiffEditor' : 'create';
+ const instance = EditorLite.convertMonacoToELInstance(
+ monacoEditor[createEditorFn].call(this, el, {
+ ...this.options,
+ ...instanceOptions,
+ }),
+ );
+
+ let model;
+ if (instanceOptions.model !== null) {
+ model = EditorLite.createEditorModel({
+ blobGlobalId,
+ blobOriginalContent,
+ blobPath,
+ blobContent,
+ instance,
+ isDiff,
+ });
+ }
+
+ instance.onDidDispose(() => {
+ EditorLite.instanceRemoveFromRegistry(this, instance);
+ EditorLite.instanceDisposeModels(this, instance, model);
+ });
+
+ EditorLite.manageDefaultExtensions(instance, el, extensions);
this.instances.push(instance);
return instance;
}
+ createDiffInstance(args) {
+ return this.createInstance({
+ ...args,
+ isDiff: true,
+ });
+ }
+
dispose() {
this.instances.forEach((instance) => instance.dispose());
}
- use(exts = [], instance = null) {
- const extensions = Array.isArray(exts) ? exts : [exts];
- const initExtensions = (inst) => {
- extensions.forEach((extension) => {
- EditorLite.mixIntoInstance(extension, inst);
- });
- };
- if (instance) {
- initExtensions(instance);
- } else {
- this.instances.forEach((inst) => {
- initExtensions(inst);
- });
- }
+ use(exts) {
+ this.instances.forEach((inst) => {
+ inst.use(exts);
+ });
+ return this;
}
}