Commit a3f33674 authored by Paul Slaughter's avatar Paul Slaughter

Add global id param in editor_lite

*Why?*
This helps create unique monaco models that share
the same file paths.

*Also:*
Fix scrolling issue with snippets by passing
"alwaysConsumeMouseWheel: false"
parent 160570ab
import Editor from '~/editor/editor_lite';
export function initEditorLite({ el, blobPath, blobContent }) {
export function initEditorLite({ el, ...args }) {
if (!el) {
throw new Error(`"el" parameter is required to initialize Editor`);
}
const editor = new Editor();
editor.createInstance({
el,
blobPath,
blobContent,
...args,
});
return editor;
......
......@@ -3,6 +3,7 @@ import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
import languages from '~/ide/lib/languages';
import { defaultEditorOptions } from '~/ide/lib/editor_options';
import { registerLanguages } from '~/ide/utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { clearDomElement } from './utils';
export default class Editor {
......@@ -30,7 +31,16 @@ export default class Editor {
monacoEditor.setTheme(theme ? themeName : DEFAULT_THEME);
}
createInstance({ el = undefined, blobPath = '', blobContent = '' } = {}) {
/**
* 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 = '' } = {}) {
if (!el) return;
this.editorEl = el;
this.blobContent = blobContent;
......@@ -38,11 +48,9 @@ export default class Editor {
clearDomElement(this.editorEl);
this.model = monacoEditor.createModel(
this.blobContent,
undefined,
new Uri('gitlab', false, this.blobPath),
);
const uriFilePath = joinPaths('gitlab', blobGlobalId, blobPath);
this.model = monacoEditor.createModel(this.blobContent, undefined, Uri.file(uriFilePath));
monacoEditor.onDidCreateEditor(this.renderEditor.bind(this));
......@@ -51,6 +59,11 @@ export default class Editor {
}
dispose() {
if (this.model) {
this.model.dispose();
this.model = null;
}
return this.instance && this.instance.dispose();
}
......@@ -58,6 +71,10 @@ export default class Editor {
delete this.editorEl.dataset.editorLoading;
}
onChangeContent(fn) {
return this.model.onDidChangeContent(fn);
}
updateModelLanguage(path) {
if (path === this.blobPath) return;
this.blobPath = path;
......
import Editor from '~/editor/editor_lite';
import * as utils from '~/blob/utils';
const mockCreateMonacoInstance = jest.fn();
jest.mock('~/editor/editor_lite', () => {
return jest.fn().mockImplementation(() => {
return { createInstance: mockCreateMonacoInstance };
});
});
jest.mock('~/editor/editor_lite');
describe('Blob utilities', () => {
beforeEach(() => {
Editor.mockClear();
});
describe('initEditorLite', () => {
let editorEl;
const blobPath = 'foo.txt';
const blobContent = 'Foo bar';
const blobGlobalId = 'snippet_777';
beforeEach(() => {
setFixtures('<div id="editor"></div>');
editorEl = document.getElementById('editor');
editorEl = document.createElement('div');
});
describe('Monaco editor', () => {
......@@ -29,25 +20,21 @@ describe('Blob utilities', () => {
expect(Editor).toHaveBeenCalled();
});
it('creates the instance with the passed parameters', () => {
utils.initEditorLite({ el: editorEl });
expect(mockCreateMonacoInstance.mock.calls[0]).toEqual([
{
it.each([[{}], [{ blobPath, blobContent, blobGlobalId }]])(
'creates the instance with the passed parameters %s',
extraParams => {
const params = {
el: editorEl,
blobPath: undefined,
blobContent: undefined,
},
]);
utils.initEditorLite({ el: editorEl, blobPath, blobContent });
expect(mockCreateMonacoInstance.mock.calls[1]).toEqual([
{
el: editorEl,
blobPath,
blobContent,
},
]);
});
...extraParams,
};
expect(Editor.prototype.createInstance).not.toHaveBeenCalled();
utils.initEditorLite(params);
expect(Editor.prototype.createInstance).toHaveBeenCalledWith(params);
},
);
});
});
});
......@@ -2,13 +2,15 @@ import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monac
import Editor from '~/editor/editor_lite';
import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
const URI_PREFIX = 'gitlab';
describe('Base editor', () => {
let editorEl;
let editor;
const blobContent = 'Foo Bar';
const blobPath = 'test.md';
const uri = new Uri('gitlab', false, blobPath);
const fakeModel = { foo: 'bar' };
const blobGlobalId = 'snippet_777';
const fakeModel = { foo: 'bar', dispose: jest.fn() };
beforeEach(() => {
setFixtures('<div id="editor" data-editor-loading></div>');
......@@ -21,6 +23,8 @@ describe('Base editor', () => {
editorEl.remove();
});
const createUri = (...paths) => Uri.file([URI_PREFIX, ...paths].join('/'));
it('initializes Editor with basic properties', () => {
expect(editor).toBeDefined();
expect(editor.editorEl).toBe(null);
......@@ -65,7 +69,7 @@ describe('Base editor', () => {
it('creates model to be supplied to Monaco editor', () => {
editor.createInstance({ el: editorEl, blobPath, blobContent });
expect(modelSpy).toHaveBeenCalledWith(blobContent, undefined, uri);
expect(modelSpy).toHaveBeenCalledWith(blobContent, undefined, createUri(blobPath));
expect(setModel).toHaveBeenCalledWith(fakeModel);
});
......@@ -75,6 +79,16 @@ describe('Base editor', () => {
expect(editor.editorEl).not.toBe(null);
expect(instanceSpy).toHaveBeenCalledWith(editorEl, expect.anything());
});
it('with blobGlobalId, creates model with id in uri', () => {
editor.createInstance({ el: editorEl, blobPath, blobContent, blobGlobalId });
expect(modelSpy).toHaveBeenCalledWith(
blobContent,
undefined,
createUri(blobGlobalId, blobPath),
);
});
});
describe('implementation', () => {
......@@ -82,10 +96,6 @@ describe('Base editor', () => {
editor.createInstance({ el: editorEl, blobPath, blobContent });
});
afterEach(() => {
editor.model.dispose();
});
it('correctly proxies value from the model', () => {
expect(editor.getValue()).toEqual(blobContent);
});
......@@ -132,10 +142,6 @@ describe('Base editor', () => {
editor.createInstance({ el: editorEl, blobPath, blobContent });
});
afterEach(() => {
editor.model.dispose();
});
it('is extensible with the extensions', () => {
expect(editor.foo).toBeUndefined();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment