提交 a01d39d8 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 583bde3f
......@@ -9,11 +9,7 @@ import { EDITOR_LITE_INSTANCE_ERROR_NO_EL, URI_PREFIX } from './constants';
export default class Editor {
constructor(options = {}) {
this.editorEl = null;
this.blobContent = '';
this.blobPath = '';
this.instances = [];
this.model = null;
this.options = {
extraEditorClassName: 'gl-editor-lite',
...defaultEditorOptions,
......@@ -32,6 +28,17 @@ export default class Editor {
monacoEditor.setTheme(theme ? themeName : DEFAULT_THEME);
}
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);
}
/**
* Creates a monaco instance with the given options.
*
......@@ -51,19 +58,18 @@ export default class Editor {
if (!el) {
throw new Error(EDITOR_LITE_INSTANCE_ERROR_NO_EL);
}
this.editorEl = el;
this.blobContent = blobContent;
this.blobPath = blobPath;
clearDomElement(this.editorEl);
clearDomElement(el);
const uriFilePath = joinPaths(URI_PREFIX, blobGlobalId, blobPath);
const model = monacoEditor.createModel(this.blobContent, undefined, Uri.file(uriFilePath));
const model = monacoEditor.createModel(blobContent, undefined, Uri.file(uriFilePath));
monacoEditor.onDidCreateEditor(this.renderEditor.bind(this));
monacoEditor.onDidCreateEditor(() => {
delete el.dataset.editorLoading;
});
const instance = monacoEditor.create(this.editorEl, {
const instance = monacoEditor.create(el, {
...this.options,
...instanceOptions,
});
......@@ -73,13 +79,7 @@ export default class Editor {
this.instances.splice(index, 1);
model.dispose();
});
instance.updateModelLanguage = path => this.updateModelLanguage(path);
// Reference to the model on the editor level will go away in
// https://gitlab.com/gitlab-org/gitlab/-/issues/241023
// After that, the references to the model will be routed through
// instance exclusively
this.model = model;
instance.updateModelLanguage = path => Editor.updateModelLanguage(path, instance);
this.instances.push(instance);
return instance;
......@@ -89,21 +89,6 @@ export default class Editor {
this.instances.forEach(instance => instance.dispose());
}
renderEditor() {
delete this.editorEl.dataset.editorLoading;
}
updateModelLanguage(path) {
if (path === this.blobPath) return;
this.blobPath = 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(this.model, id);
}
use(exts = [], instance = null) {
const extensions = Array.isArray(exts) ? exts : [exts];
if (instance) {
......
<script>
/* eslint-disable vue/no-v-html */
import $ from 'jquery';
import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import animateMixin from '../mixins/animate';
......@@ -8,6 +8,10 @@ import TaskList from '../../task_list';
import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default {
directives: {
SafeHtml,
},
mixins: [animateMixin, recaptchaModalImplementor],
props: {
......@@ -142,12 +146,12 @@ export default {
>
<div
ref="gfm-content"
v-safe-html="descriptionHtml"
:class="{
'issue-realtime-pre-pulse': preAnimation,
'issue-realtime-trigger-pulse': pulseAnimation,
}"
class="md"
v-html="descriptionHtml"
></div>
<textarea
v-if="descriptionText"
......
<script>
/* eslint-disable vue/no-v-html */
import { GlTooltipDirective, GlLink, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { polyfillSticky } from '~/lib/utils/sticky';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { __, sprintf } from '~/locale';
......@@ -8,9 +8,8 @@ import scrollDown from '../svg/scroll_down.svg';
export default {
components: {
GlIcon,
GlLink,
GlDeprecatedButton,
GlButton,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -87,18 +86,17 @@ export default {
<div class="controllers float-right">
<!-- links -->
<gl-link
<gl-button
v-if="rawPath"
v-gl-tooltip.body
:title="s__('Job|Show complete raw')"
:href="rawPath"
class="controllers-buttons"
data-testid="job-raw-link-controller"
>
<gl-icon name="doc-text" />
</gl-link>
icon="doc-text"
/>
<gl-link
<gl-button
v-if="erasePath"
v-gl-tooltip.body
:title="s__('Job|Erase job log')"
......@@ -107,30 +105,28 @@ export default {
class="controllers-buttons"
data-testid="job-log-erase-link"
data-method="post"
>
<gl-icon name="remove" />
</gl-link>
icon="remove"
/>
<!-- eo links -->
<!-- scroll buttons -->
<div v-gl-tooltip :title="s__('Job|Scroll to top')" class="controllers-buttons">
<gl-deprecated-button
<gl-button
:disabled="isScrollTopDisabled"
type="button"
class="btn-scroll btn-transparent btn-blank"
data-testid="job-controller-scroll-top"
icon="scroll_up"
@click="handleScrollToTop"
>
<gl-icon name="scroll_up" />
</gl-deprecated-button>
/>
</div>
<div v-gl-tooltip :title="s__('Job|Scroll to bottom')" class="controllers-buttons">
<gl-deprecated-button
<gl-button
:disabled="isScrollBottomDisabled"
class="js-scroll-bottom btn-scroll btn-transparent btn-blank"
:class="{ animate: isScrollingDown }"
data-testid="job-controller-scroll-bottom"
icon="scroll_down"
:class="{ animate: isScrollingDown }"
@click="handleScrollToBottom"
v-html="$options.scrollDown"
/>
......
......@@ -63,7 +63,7 @@
}
.top-bar {
@include build-trace-top-bar(35px);
@include build-trace-top-bar(50px);
&.has-archived-block {
top: $header-height + 28px;
......
......@@ -316,9 +316,9 @@ Learn more about [using `CI_JOB_TOKEN` to authenticate to the GitLab NPM registr
## Troubleshooting
### Error running yarn with NPM registry
### Error running Yarn with NPM registry
If you are using [yarn](https://classic.yarnpkg.com/en/) with the NPM registry, you may get
If you are using [Yarn](https://classic.yarnpkg.com/en/) with the NPM registry, you may get
an error message like:
```shell
......
......@@ -26,9 +26,7 @@ describe('Base editor', () => {
it('initializes Editor with basic properties', () => {
expect(editor).toBeDefined();
expect(editor.editorEl).toBe(null);
expect(editor.blobContent).toBe('');
expect(editor.blobPath).toBe('');
expect(editor.instances).toEqual([]);
});
it('removes `editor-loading` data attribute from the target DOM element', () => {
......@@ -59,10 +57,6 @@ describe('Base editor', () => {
editor.createInstance();
}).toThrow(EDITOR_LITE_INSTANCE_ERROR_NO_EL);
expect(editor.editorEl).toBe(null);
expect(editor.blobContent).toBe('');
expect(editor.blobPath).toBe('');
expect(modelSpy).not.toHaveBeenCalled();
expect(instanceSpy).not.toHaveBeenCalled();
expect(setModel).not.toHaveBeenCalled();
......@@ -93,14 +87,14 @@ describe('Base editor', () => {
});
it('initializes instance with passed properties', () => {
const instanceOptions = {
foo: 'bar',
};
editor.createInstance({
el: editorEl,
blobContent,
blobPath,
...instanceOptions,
});
expect(editor.editorEl).toBe(editorEl);
expect(editor.blobContent).toBe(blobContent);
expect(editor.blobPath).toBe(blobPath);
expect(instanceSpy).toHaveBeenCalledWith(editorEl, expect.objectContaining(instanceOptions));
});
it('disposes instance when the editor is disposed', () => {
......@@ -149,16 +143,26 @@ describe('Base editor', () => {
it('can initialize several instances of the same editor', () => {
editor.createInstance(inst1Args);
expect(editor.editorEl).toBe(editorEl1);
expect(editor.instances).toHaveLength(1);
editor.createInstance(inst2Args);
expect(editor.editorEl).toBe(editorEl2);
expect(instanceSpy).toHaveBeenCalledTimes(2);
expect(editor.instances).toHaveLength(2);
});
it('sets independent models on independent instances', () => {
inst1 = editor.createInstance(inst1Args);
inst2 = editor.createInstance(inst2Args);
const model1 = inst1.getModel();
const model2 = inst2.getModel();
expect(model1).toBeDefined();
expect(model2).toBeDefined();
expect(model1).not.toEqual(model2);
});
it('shares global editor options among all instances', () => {
editor = new Editor({
readOnly: true,
......@@ -218,20 +222,20 @@ describe('Base editor', () => {
const blobRenamedPath = 'test.js';
expect(editor.model.getLanguageIdentifier().language).toBe('markdown');
editor.updateModelLanguage(blobRenamedPath);
expect(instance.getModel().getLanguageIdentifier().language).toBe('markdown');
instance.updateModelLanguage(blobRenamedPath);
expect(editor.model.getLanguageIdentifier().language).toBe('javascript');
expect(instance.getModel().getLanguageIdentifier().language).toBe('javascript');
});
it('falls back to plaintext if there is no language associated with an extension', () => {
const blobRenamedPath = 'test.myext';
const spy = jest.spyOn(console, 'error').mockImplementation(() => {});
editor.updateModelLanguage(blobRenamedPath);
instance.updateModelLanguage(blobRenamedPath);
expect(spy).not.toHaveBeenCalled();
expect(editor.model.getLanguageIdentifier().language).toBe('plaintext');
expect(instance.getModel().getLanguageIdentifier().language).toBe('plaintext');
});
});
......@@ -298,7 +302,6 @@ describe('Base editor', () => {
};
editor.use(FunctionExt);
expect(instance.inst()).toEqual(editor.instances[0]);
expect(instance.mod()).toEqual(editor.model);
});
describe('multiple instances', () => {
......
......@@ -35,7 +35,7 @@ describe('Markdown Extension for Editor Lite', () => {
});
afterEach(() => {
editor.model.dispose();
instance.dispose();
editorEl.remove();
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册