Commit 4c375307 authored by Sarah Groff Hennigh-Palermo's avatar Sarah Groff Hennigh-Palermo

Merge branch '241025-remove-proxy-methods' into 'master'

Resolve "Remove proxy methods from Editor Lite's core"

See merge request gitlab-org/gitlab!40662
parents 0b6f909f 3153d599
...@@ -46,7 +46,7 @@ export default { ...@@ -46,7 +46,7 @@ export default {
blobGlobalId: this.fileGlobalId, blobGlobalId: this.fileGlobalId,
}); });
this.editor.onChangeContent(debounce(this.onFileChange.bind(this), 250)); this.editor.onDidChangeModelContent(debounce(this.onFileChange.bind(this), 250));
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
if (!performance.getEntriesByName(SNIPPET_MARK_BLOBS_CONTENT).length) { if (!performance.getEntriesByName(SNIPPET_MARK_BLOBS_CONTENT).length) {
......
import $ from 'jquery'; import $ from 'jquery';
import Api from '~/api'; import Api from '~/api';
import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
import { deprecatedCreateFlash as Flash } from '../flash'; import { deprecatedCreateFlash as Flash } from '../flash';
import FileTemplateTypeSelector from './template_selectors/type_selector'; import FileTemplateTypeSelector from './template_selectors/type_selector';
import BlobCiYamlSelector from './template_selectors/ci_yaml_selector'; import BlobCiYamlSelector from './template_selectors/ci_yaml_selector';
import DockerfileSelector from './template_selectors/dockerfile_selector'; import DockerfileSelector from './template_selectors/dockerfile_selector';
import GitignoreSelector from './template_selectors/gitignore_selector'; import GitignoreSelector from './template_selectors/gitignore_selector';
import LicenseSelector from './template_selectors/license_selector'; import LicenseSelector from './template_selectors/license_selector';
import MetricsDashboardSelector from './template_selectors/metrics_dashboard_selector'; import MetricsDashboardSelector from './template_selectors/metrics_dashboard_selector';
import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
export default class FileTemplateMediator { export default class FileTemplateMediator {
constructor({ editor, currentAction, projectId }) { constructor({ editor, currentAction, projectId }) {
......
...@@ -6,12 +6,11 @@ export function initEditorLite({ el, ...args }) { ...@@ -6,12 +6,11 @@ export function initEditorLite({ el, ...args }) {
alwaysConsumeMouseWheel: false, alwaysConsumeMouseWheel: false,
}, },
}); });
editor.createInstance({
return editor.createInstance({
el, el,
...args, ...args,
}); });
return editor;
} }
export default () => ({}); export default () => ({});
...@@ -40,9 +40,10 @@ export default class EditBlob { ...@@ -40,9 +40,10 @@ export default class EditBlob {
const MarkdownExtensionPromise = this.options.isMarkdown const MarkdownExtensionPromise = this.options.isMarkdown
? import('~/editor/editor_markdown_ext') ? import('~/editor/editor_markdown_ext')
: Promise.resolve(false); : Promise.resolve(false);
const FileTemplateExtensionPromise = import('~/editor/editor_file_template_ext');
return Promise.all([EditorPromise, MarkdownExtensionPromise]) return Promise.all([EditorPromise, MarkdownExtensionPromise, FileTemplateExtensionPromise])
.then(([EditorModule, MarkdownExtension]) => { .then(([EditorModule, MarkdownExtension, FileTemplateExtension]) => {
const EditorLite = EditorModule.default; const EditorLite = EditorModule.default;
const editorEl = document.getElementById('editor'); const editorEl = document.getElementById('editor');
const fileNameEl = const fileNameEl =
...@@ -50,18 +51,16 @@ export default class EditBlob { ...@@ -50,18 +51,16 @@ export default class EditBlob {
const fileContentEl = document.getElementById('file-content'); const fileContentEl = document.getElementById('file-content');
const form = document.querySelector('.js-edit-blob-form'); const form = document.querySelector('.js-edit-blob-form');
this.editor = new EditorLite(); const rootEditor = new EditorLite();
if (MarkdownExtension) { this.editor = rootEditor.createInstance({
this.editor.use(MarkdownExtension.default);
}
this.editor.createInstance({
el: editorEl, el: editorEl,
blobPath: fileNameEl.value, blobPath: fileNameEl.value,
blobContent: editorEl.innerText, blobContent: editorEl.innerText,
}); });
rootEditor.use([MarkdownExtension.default, FileTemplateExtension.default], this.editor);
fileNameEl.addEventListener('change', () => { fileNameEl.addEventListener('change', () => {
this.editor.updateModelLanguage(fileNameEl.value); this.editor.updateModelLanguage(fileNameEl.value);
}); });
......
import { Position } from 'monaco-editor';
export default {
navigateFileStart() {
this.setPosition(new Position(1, 1));
},
};
import { editor as monacoEditor, languages as monacoLanguages, Position, Uri } from 'monaco-editor'; import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor';
import { DEFAULT_THEME, themes } from '~/ide/lib/themes'; import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
import languages from '~/ide/lib/languages'; import languages from '~/ide/lib/languages';
import { defaultEditorOptions } from '~/ide/lib/editor_options'; import { defaultEditorOptions } from '~/ide/lib/editor_options';
...@@ -73,6 +73,7 @@ export default class Editor { ...@@ -73,6 +73,7 @@ export default class Editor {
this.instances.splice(index, 1); this.instances.splice(index, 1);
model.dispose(); model.dispose();
}); });
instance.updateModelLanguage = path => this.updateModelLanguage(path);
// Reference to the model on the editor level will go away in // Reference to the model on the editor level will go away in
// https://gitlab.com/gitlab-org/gitlab/-/issues/241023 // https://gitlab.com/gitlab-org/gitlab/-/issues/241023
...@@ -92,10 +93,6 @@ export default class Editor { ...@@ -92,10 +93,6 @@ export default class Editor {
delete this.editorEl.dataset.editorLoading; delete this.editorEl.dataset.editorLoading;
} }
onChangeContent(fn) {
return this.model.onDidChangeContent(fn);
}
updateModelLanguage(path) { updateModelLanguage(path) {
if (path === this.blobPath) return; if (path === this.blobPath) return;
this.blobPath = path; this.blobPath = path;
...@@ -107,46 +104,6 @@ export default class Editor { ...@@ -107,46 +104,6 @@ export default class Editor {
monacoEditor.setModelLanguage(this.model, id); monacoEditor.setModelLanguage(this.model, id);
} }
/**
* @deprecated do not use .getValue() directly on the editor.
* This proxy-method will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/241025
* Rather use it on the exact instance
*/
getValue() {
return this.instances[0].getValue();
}
/**
* @deprecated do not use .setValue() directly on the editor.
* This proxy-method will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/241025
* Rather use it on the exact instance
*/
setValue(val) {
this.instances[0].setValue(val);
}
/**
* @deprecated do not use .focus() directly on the editor.
* This proxy-method will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/241025
* Rather use it on the exact instance
*/
focus() {
this.instances[0].focus();
}
/**
* @deprecated do not use .updateOptions() directly on the editor.
* This proxy-method will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/241025
* Rather use it on the exact instance
*/
updateOptions(options = {}) {
this.instances[0].updateOptions(options);
}
navigateFileStart() {
this.instances[0].setPosition(new Position(1, 1));
}
use(exts = [], instance = null) { use(exts = [], instance = null) {
const extensions = Array.isArray(exts) ? exts : [exts]; const extensions = Array.isArray(exts) ? exts : [exts];
if (instance) { if (instance) {
......
...@@ -2,12 +2,14 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -2,12 +2,14 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import BlobEditContent from '~/blob/components/blob_edit_content.vue'; import BlobEditContent from '~/blob/components/blob_edit_content.vue';
import * as utils from '~/blob/utils'; import * as utils from '~/blob/utils';
import Editor from '~/editor/editor_lite';
jest.mock('~/editor/editor_lite'); jest.mock('~/editor/editor_lite');
describe('Blob Header Editing', () => { describe('Blob Header Editing', () => {
let wrapper; let wrapper;
const onDidChangeModelContent = jest.fn();
const updateModelLanguage = jest.fn();
const getValue = jest.fn();
const value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; const value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
const fileName = 'lorem.txt'; const fileName = 'lorem.txt';
const fileGlobalId = 'snippet_777'; const fileGlobalId = 'snippet_777';
...@@ -24,7 +26,12 @@ describe('Blob Header Editing', () => { ...@@ -24,7 +26,12 @@ describe('Blob Header Editing', () => {
} }
beforeEach(() => { beforeEach(() => {
jest.spyOn(utils, 'initEditorLite'); jest.spyOn(utils, 'initEditorLite').mockImplementation(() => ({
onDidChangeModelContent,
updateModelLanguage,
getValue,
dispose: jest.fn(),
}));
createComponent(); createComponent();
}); });
...@@ -34,8 +41,8 @@ describe('Blob Header Editing', () => { ...@@ -34,8 +41,8 @@ describe('Blob Header Editing', () => {
}); });
const triggerChangeContent = val => { const triggerChangeContent = val => {
jest.spyOn(Editor.prototype, 'getValue').mockReturnValue(val); getValue.mockReturnValue(val);
const [cb] = Editor.prototype.onChangeContent.mock.calls[0]; const [cb] = onDidChangeModelContent.mock.calls[0];
cb(); cb();
...@@ -79,12 +86,12 @@ describe('Blob Header Editing', () => { ...@@ -79,12 +86,12 @@ describe('Blob Header Editing', () => {
}); });
return nextTick().then(() => { return nextTick().then(() => {
expect(Editor.prototype.updateModelLanguage).toHaveBeenCalledWith(newFileName); expect(updateModelLanguage).toHaveBeenCalledWith(newFileName);
}); });
}); });
it('registers callback with editor onChangeContent', () => { it('registers callback with editor onChangeContent', () => {
expect(Editor.prototype.onChangeContent).toHaveBeenCalledWith(expect.any(Function)); expect(onDidChangeModelContent).toHaveBeenCalledWith(expect.any(Function));
}); });
it('emits input event when the blob content is changed', () => { it('emits input event when the blob content is changed', () => {
......
import EditBlob from '~/blob_edit/edit_blob'; import EditBlob from '~/blob_edit/edit_blob';
import EditorLite from '~/editor/editor_lite'; import EditorLite from '~/editor/editor_lite';
import MarkdownExtension from '~/editor/editor_markdown_ext'; import MarkdownExtension from '~/editor/editor_markdown_ext';
import FileTemplateExtension from '~/editor/editor_file_template_ext';
jest.mock('~/editor/editor_lite'); jest.mock('~/editor/editor_lite');
jest.mock('~/editor/editor_markdown_ext'); jest.mock('~/editor/editor_markdown_ext');
describe('Blob Editing', () => { describe('Blob Editing', () => {
const mockInstance = 'foo';
beforeEach(() => { beforeEach(() => {
setFixtures( setFixtures(
`<div class="js-edit-blob-form"><div id="file_path"></div><div id="iditor"></div><input id="file-content"></div>`, `<div class="js-edit-blob-form"><div id="file_path"></div><div id="editor"></div><input id="file-content"></div>`,
); );
jest.spyOn(EditorLite.prototype, 'createInstance').mockReturnValue(mockInstance);
}); });
const initEditor = (isMarkdown = false) => { const initEditor = (isMarkdown = false) => {
...@@ -19,13 +22,29 @@ describe('Blob Editing', () => { ...@@ -19,13 +22,29 @@ describe('Blob Editing', () => {
}); });
}; };
it('does not load MarkdownExtension by default', async () => { it('loads FileTemplateExtension by default', async () => {
await initEditor(); await initEditor();
expect(EditorLite.prototype.use).not.toHaveBeenCalled(); expect(EditorLite.prototype.use).toHaveBeenCalledWith(
expect.arrayContaining([FileTemplateExtension]),
mockInstance,
);
}); });
it('loads MarkdownExtension only for the markdown files', async () => { describe('Markdown', () => {
await initEditor(true); it('does not load MarkdownExtension by default', async () => {
expect(EditorLite.prototype.use).toHaveBeenCalledWith(MarkdownExtension); await initEditor();
expect(EditorLite.prototype.use).not.toHaveBeenCalledWith(
expect.arrayContaining([MarkdownExtension]),
mockInstance,
);
});
it('loads MarkdownExtension only for the markdown files', async () => {
await initEditor(true);
expect(EditorLite.prototype.use).toHaveBeenCalledWith(
[MarkdownExtension, FileTemplateExtension],
mockInstance,
);
});
}); });
}); });
...@@ -78,18 +78,18 @@ describe('Markdown Extension for Editor Lite', () => { ...@@ -78,18 +78,18 @@ describe('Markdown Extension for Editor Lite', () => {
selectSecondString(); selectSecondString();
instance.replaceSelectedText(expectedStr); instance.replaceSelectedText(expectedStr);
expect(editor.getValue()).toBe(`${firstLine}\n${expectedStr}\n${thirdLine}`); expect(instance.getValue()).toBe(`${firstLine}\n${expectedStr}\n${thirdLine}`);
}); });
it('prepends the supplied text if no text is selected', () => { it('prepends the supplied text if no text is selected', () => {
instance.replaceSelectedText(expectedStr); instance.replaceSelectedText(expectedStr);
expect(editor.getValue()).toBe(`${expectedStr}${firstLine}\n${secondLine}\n${thirdLine}`); expect(instance.getValue()).toBe(`${expectedStr}${firstLine}\n${secondLine}\n${thirdLine}`);
}); });
it('replaces selection with empty string if no text is supplied', () => { it('replaces selection with empty string if no text is supplied', () => {
selectSecondString(); selectSecondString();
instance.replaceSelectedText(); instance.replaceSelectedText();
expect(editor.getValue()).toBe(`${firstLine}\n\n${thirdLine}`); expect(instance.getValue()).toBe(`${firstLine}\n\n${thirdLine}`);
}); });
it('puts cursor at the end of the new string and collapses selection by default', () => { it('puts cursor at the end of the new string and collapses selection by default', () => {
......
...@@ -15,11 +15,13 @@ describe('Snippet editor', () => { ...@@ -15,11 +15,13 @@ describe('Snippet editor', () => {
const updatedMockContent = 'New Foo Bar'; const updatedMockContent = 'New Foo Bar';
const mockEditor = { const mockEditor = {
createInstance: jest.fn(),
updateModelLanguage: jest.fn(), updateModelLanguage: jest.fn(),
getValue: jest.fn().mockReturnValueOnce(updatedMockContent), getValue: jest.fn().mockReturnValueOnce(updatedMockContent),
}; };
Editor.mockImplementation(() => mockEditor); const createInstance = jest.fn().mockImplementation(() => ({ ...mockEditor }));
Editor.mockImplementation(() => ({
createInstance,
}));
function setUpFixture(name, content) { function setUpFixture(name, content) {
setHTMLFixture(` setHTMLFixture(`
...@@ -56,7 +58,7 @@ describe('Snippet editor', () => { ...@@ -56,7 +58,7 @@ describe('Snippet editor', () => {
}); });
it('correctly initializes Editor', () => { it('correctly initializes Editor', () => {
expect(mockEditor.createInstance).toHaveBeenCalledWith({ expect(createInstance).toHaveBeenCalledWith({
el: editorEl, el: editorEl,
blobPath: mockName, blobPath: mockName,
blobContent: mockContent, blobContent: mockContent,
......
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