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/ide/components/repo_editor.vue')
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue89
1 files changed, 67 insertions, 22 deletions
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index c72a8b2b0d0..a7646083428 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -14,6 +14,9 @@ import Editor from '../lib/editor';
import FileTemplatesBar from './file_templates/bar.vue';
import { __ } from '~/locale';
import { extractMarkdownImagesFromEntries } from '../stores/utils';
+import { getPathParent, readFileAsDataURL } from '../utils';
+import { getRulesWithTraversal } from '../lib/editorconfig/parser';
+import mapRulesToMonaco from '../lib/editorconfig/rules_mapper';
export default {
components: {
@@ -31,6 +34,7 @@ export default {
return {
content: '',
images: {},
+ rules: {},
};
},
computed: {
@@ -50,7 +54,6 @@ export default {
'getStagedFile',
'isEditModeActive',
'isCommitModeActive',
- 'isReviewModeActive',
'currentBranch',
]),
...mapGetters('fileTemplates', ['showFileTemplatesBar']),
@@ -82,10 +85,6 @@ export default {
active: this.isPreviewViewMode,
};
},
- fileType() {
- const info = viewerInformationForPath(this.file.path);
- return (info && info.id) || '';
- },
showEditor() {
return !this.shouldHideEditor && this.isEditorViewMode;
},
@@ -98,6 +97,12 @@ export default {
currentBranchCommit() {
return this.currentBranch?.commit.id;
},
+ previewMode() {
+ return viewerInformationForPath(this.file.path);
+ },
+ fileType() {
+ return this.previewMode?.id || '';
+ },
},
watch: {
file(newVal, oldVal) {
@@ -165,6 +170,12 @@ export default {
this.editor = Editor.create(this.editorOptions);
}
this.initEditor();
+
+ // listen in capture phase to be able to override Monaco's behaviour.
+ window.addEventListener('paste', this.onPaste, true);
+ },
+ destroyed() {
+ window.removeEventListener('paste', this.onPaste, true);
},
methods: {
...mapActions([
@@ -174,10 +185,10 @@ export default {
'setFileLanguage',
'setEditorPosition',
'setFileViewMode',
- 'setFileEOL',
'updateViewer',
'removePendingTab',
'triggerFilesChange',
+ 'addTempImage',
]),
initEditor() {
if (this.shouldHideEditor && (this.file.content || this.file.raw)) {
@@ -186,7 +197,7 @@ export default {
this.editor.clearEditor();
- this.fetchFileData()
+ Promise.all([this.fetchFileData(), this.fetchEditorconfigRules()])
.then(() => {
this.createEditorInstance();
})
@@ -223,7 +234,7 @@ export default {
if (this.viewer === viewerTypes.edit) {
this.editor.createInstance(this.$refs.editor);
} else {
- this.editor.createDiffInstance(this.$refs.editor, !this.isReviewModeActive);
+ this.editor.createDiffInstance(this.$refs.editor);
}
this.setupEditor();
@@ -245,15 +256,15 @@ export default {
this.editor.attachModel(this.model);
}
+ this.model.updateOptions(this.rules);
+
this.model.onChange(model => {
const { file } = model;
+ if (!file.active) return;
- if (file.active) {
- this.changeFileContent({
- path: file.path,
- content: model.getModel().getValue(),
- });
- }
+ const monacoModel = model.getModel();
+ const content = monacoModel.getValue();
+ this.changeFileContent({ path: file.path, content });
});
// Handle Cursor Position
@@ -274,16 +285,51 @@ export default {
fileLanguage: this.model.language,
});
- // Get File eol
- this.setFileEOL({
- eol: this.model.eol,
- });
+ this.$emit('editorSetup');
},
refreshEditorDimensions() {
if (this.showEditor) {
this.editor.updateDimensions();
}
},
+ fetchEditorconfigRules() {
+ return getRulesWithTraversal(this.file.path, path => {
+ const entry = this.entries[path];
+ if (!entry) return Promise.resolve(null);
+
+ const content = entry.content || entry.raw;
+ if (content) return Promise.resolve(content);
+
+ return this.getFileData({ path: entry.path, makeFileActive: false }).then(() =>
+ this.getRawFileData({ path: entry.path }),
+ );
+ }).then(rules => {
+ this.rules = mapRulesToMonaco(rules);
+ });
+ },
+ onPaste(event) {
+ const editor = this.editor.instance;
+ const reImage = /^image\/(png|jpg|jpeg|gif)$/;
+ const file = event.clipboardData.files[0];
+
+ if (editor.hasTextFocus() && this.fileType === 'markdown' && reImage.test(file?.type)) {
+ // don't let the event be passed on to Monaco.
+ event.preventDefault();
+ event.stopImmediatePropagation();
+
+ return readFileAsDataURL(file).then(content => {
+ const parentPath = getPathParent(this.file.path);
+ const path = `${parentPath ? `${parentPath}/` : ''}${file.name}`;
+
+ return this.addTempImage({ name: path, rawPath: content }).then(({ name: fileName }) => {
+ this.editor.replaceSelectedText(`![${fileName}](./${fileName})`);
+ });
+ });
+ }
+
+ // do nothing if no image is found in the clipboard
+ return Promise.resolve();
+ },
},
viewerTypes,
FILE_VIEW_MODE_EDITOR,
@@ -301,16 +347,15 @@ export default {
role="button"
@click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_EDITOR })"
>
- <template v-if="viewer === $options.viewerTypes.edit">{{ __('Edit') }}</template>
- <template v-else>{{ __('Review') }}</template>
+ {{ __('Edit') }}
</a>
</li>
- <li v-if="file.previewMode" :class="previewTabCSS">
+ <li v-if="previewMode" :class="previewTabCSS">
<a
href="javascript:void(0);"
role="button"
@click.prevent="setFileViewMode({ file, viewMode: $options.FILE_VIEW_MODE_PREVIEW })"
- >{{ file.previewMode.previewTitle }}</a
+ >{{ previewMode.previewTitle }}</a
>
</li>
</ul>