debian-mirror-gitlab/app/assets/javascripts/editor/editor_lite.js

139 lines
4.3 KiB
JavaScript
Raw Normal View History

2020-11-24 15:15:51 +05:30
import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor';
2020-04-08 14:13:33 +05:30
import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
2020-05-24 23:13:21 +05:30
import languages from '~/ide/lib/languages';
2020-03-13 15:44:24 +05:30
import { defaultEditorOptions } from '~/ide/lib/editor_options';
2020-05-24 23:13:21 +05:30
import { registerLanguages } from '~/ide/utils';
2020-10-24 23:57:45 +05:30
import { joinPaths } from '~/lib/utils/url_utility';
2020-03-13 15:44:24 +05:30
import { clearDomElement } from './utils';
2020-11-24 15:15:51 +05:30
import { EDITOR_LITE_INSTANCE_ERROR_NO_EL, URI_PREFIX } from './constants';
2021-01-29 00:20:46 +05:30
import { uuids } from '~/diffs/utils/uuids';
2020-03-13 15:44:24 +05:30
export default class Editor {
constructor(options = {}) {
2020-11-24 15:15:51 +05:30
this.instances = [];
2020-03-13 15:44:24 +05:30
this.options = {
2020-04-08 14:13:33 +05:30
extraEditorClassName: 'gl-editor-lite',
2020-03-13 15:44:24 +05:30
...defaultEditorOptions,
...options,
};
Editor.setupMonacoTheme();
2020-05-24 23:13:21 +05:30
registerLanguages(...languages);
2020-03-13 15:44:24 +05:30
}
static setupMonacoTheme() {
2020-04-08 14:13:33 +05:30
const themeName = window.gon?.user_color_scheme || DEFAULT_THEME;
const theme = themes.find(t => t.name === themeName);
if (theme) monacoEditor.defineTheme(themeName, theme.data);
monacoEditor.setTheme(theme ? themeName : DEFAULT_THEME);
2020-03-13 15:44:24 +05:30
}
2020-11-24 15:15:51 +05:30
static updateModelLanguage(path, instance) {
if (!instance) return;
const model = instance.getModel();
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);
}
2021-01-03 14:25:43 +05:30
static pushToImportsArray(arr, toImport) {
arr.push(import(toImport));
}
static loadExtensions(extensions) {
if (!extensions) {
return Promise.resolve();
}
const promises = [];
const extensionsArray = typeof extensions === 'string' ? extensions.split(',') : extensions;
extensionsArray.forEach(ext => {
const prefix = ext.includes('/') ? '' : 'editor/';
const trimmedExt = ext.replace(/^\//, '').trim();
Editor.pushToImportsArray(promises, `~/${prefix}${trimmedExt}`);
});
return Promise.all(promises);
}
2020-10-24 23:57:45 +05:30
/**
* 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.
*/
2020-11-24 15:15:51 +05:30
createInstance({
el = undefined,
blobPath = '',
blobContent = '',
2021-01-29 00:20:46 +05:30
blobGlobalId = uuids()[0],
2021-01-03 14:25:43 +05:30
extensions = [],
2020-11-24 15:15:51 +05:30
...instanceOptions
} = {}) {
if (!el) {
throw new Error(EDITOR_LITE_INSTANCE_ERROR_NO_EL);
2020-10-24 23:57:45 +05:30
}
2020-11-24 15:15:51 +05:30
clearDomElement(el);
2020-03-13 15:44:24 +05:30
2020-11-24 15:15:51 +05:30
const uriFilePath = joinPaths(URI_PREFIX, blobGlobalId, blobPath);
2020-03-13 15:44:24 +05:30
2020-11-24 15:15:51 +05:30
const model = monacoEditor.createModel(blobContent, undefined, Uri.file(uriFilePath));
2020-10-24 23:57:45 +05:30
2020-11-24 15:15:51 +05:30
monacoEditor.onDidCreateEditor(() => {
delete el.dataset.editorLoading;
});
2020-03-13 15:44:24 +05:30
2020-11-24 15:15:51 +05:30
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 => Editor.updateModelLanguage(path, instance);
2021-01-03 14:25:43 +05:30
instance.use = args => this.use(args, instance);
Editor.loadExtensions(extensions, instance)
.then(modules => {
if (modules) {
modules.forEach(module => {
instance.use(module.default);
});
}
})
.then(() => {
el.dispatchEvent(new Event('editor-ready'));
})
.catch(e => {
throw e;
});
2020-07-28 23:09:34 +05:30
2020-11-24 15:15:51 +05:30
this.instances.push(instance);
return instance;
2020-07-28 23:09:34 +05:30
}
2020-11-24 15:15:51 +05:30
dispose() {
this.instances.forEach(instance => instance.dispose());
2020-07-28 23:09:34 +05:30
}
2020-11-24 15:15:51 +05:30
use(exts = [], instance = null) {
2020-07-28 23:09:34 +05:30
const extensions = Array.isArray(exts) ? exts : [exts];
2020-11-24 15:15:51 +05:30
if (instance) {
Object.assign(instance, ...extensions);
} else {
this.instances.forEach(inst => Object.assign(inst, ...extensions));
}
2020-03-13 15:44:24 +05:30
}
}