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/content_editor/extensions')
-rw-r--r--app/assets/javascripts/content_editor/extensions/code_block_highlight.js43
-rw-r--r--app/assets/javascripts/content_editor/extensions/diagram.js56
-rw-r--r--app/assets/javascripts/content_editor/extensions/image.js4
-rw-r--r--app/assets/javascripts/content_editor/extensions/playable.js11
4 files changed, 107 insertions, 7 deletions
diff --git a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js
index 204ac07d401..61f379fc0a2 100644
--- a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js
+++ b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js
@@ -1,10 +1,21 @@
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
-import { lowlight } from 'lowlight/lib/all';
+import { textblockTypeInputRule } from '@tiptap/core';
+import codeBlockLanguageLoader from '../services/code_block_language_loader';
const extractLanguage = (element) => element.getAttribute('lang');
+export const backtickInputRegex = /^```([a-z]+)?[\s\n]$/;
+export const tildeInputRegex = /^~~~([a-z]+)?[\s\n]$/;
export default CodeBlockLowlight.extend({
isolating: true,
+ exitOnArrowDown: false,
+
+ addOptions() {
+ return {
+ ...this.parent?.(),
+ languageLoader: codeBlockLanguageLoader,
+ };
+ },
addAttributes() {
return {
@@ -18,16 +29,40 @@ export default CodeBlockLowlight.extend({
},
};
},
+ addInputRules() {
+ const { languageLoader } = this.options;
+ const getAttributes = (match) => languageLoader?.loadLanguageFromInputRule(match) || {};
+
+ return [
+ textblockTypeInputRule({
+ find: backtickInputRegex,
+ type: this.type,
+ getAttributes,
+ }),
+ textblockTypeInputRule({
+ find: tildeInputRegex,
+ type: this.type,
+ getAttributes,
+ }),
+ ];
+ },
+ parseHTML() {
+ return [
+ ...(this.parent?.() || []),
+ {
+ tag: 'div.markdown-code-block',
+ skip: true,
+ },
+ ];
+ },
renderHTML({ HTMLAttributes }) {
return [
'pre',
{
...HTMLAttributes,
- class: `content-editor-code-block ${HTMLAttributes.class}`,
+ class: `content-editor-code-block ${gon.user_color_scheme} ${HTMLAttributes.class}`,
},
['code', {}, 0],
];
},
-}).configure({
- lowlight,
});
diff --git a/app/assets/javascripts/content_editor/extensions/diagram.js b/app/assets/javascripts/content_editor/extensions/diagram.js
new file mode 100644
index 00000000000..d192b815092
--- /dev/null
+++ b/app/assets/javascripts/content_editor/extensions/diagram.js
@@ -0,0 +1,56 @@
+import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
+import CodeBlockHighlight from './code_block_highlight';
+
+export default CodeBlockHighlight.extend({
+ name: 'diagram',
+
+ isolating: true,
+
+ addAttributes() {
+ return {
+ language: {
+ default: null,
+ parseHTML: (element) => {
+ return element.dataset.diagram;
+ },
+ },
+ };
+ },
+
+ parseHTML() {
+ return [
+ {
+ priority: PARSE_HTML_PRIORITY_HIGHEST,
+ tag: '[data-diagram]',
+ getContent(element, schema) {
+ const source = atob(element.dataset.diagramSrc.replace('data:text/plain;base64,', ''));
+ const node = schema.node('paragraph', {}, [schema.text(source)]);
+ return node.content;
+ },
+ },
+ ];
+ },
+
+ renderHTML({ HTMLAttributes: { language, ...HTMLAttributes } }) {
+ return [
+ 'div',
+ [
+ 'pre',
+ {
+ language,
+ class: `content-editor-code-block code highlight`,
+ ...HTMLAttributes,
+ },
+ ['code', {}, 0],
+ ],
+ ];
+ },
+
+ addCommands() {
+ return {};
+ },
+
+ addInputRules() {
+ return [];
+ },
+});
diff --git a/app/assets/javascripts/content_editor/extensions/image.js b/app/assets/javascripts/content_editor/extensions/image.js
index 519f7f168ce..311db8151cb 100644
--- a/app/assets/javascripts/content_editor/extensions/image.js
+++ b/app/assets/javascripts/content_editor/extensions/image.js
@@ -1,6 +1,6 @@
import { Image } from '@tiptap/extension-image';
import { VueNodeViewRenderer } from '@tiptap/vue-2';
-import ImageWrapper from '../components/wrappers/image.vue';
+import MediaWrapper from '../components/wrappers/media.vue';
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
const resolveImageEl = (element) =>
@@ -78,6 +78,6 @@ export default Image.extend({
];
},
addNodeView() {
- return VueNodeViewRenderer(ImageWrapper);
+ return VueNodeViewRenderer(MediaWrapper);
},
});
diff --git a/app/assets/javascripts/content_editor/extensions/playable.js b/app/assets/javascripts/content_editor/extensions/playable.js
index 0062bc563db..2c5269377c5 100644
--- a/app/assets/javascripts/content_editor/extensions/playable.js
+++ b/app/assets/javascripts/content_editor/extensions/playable.js
@@ -1,6 +1,8 @@
/* eslint-disable @gitlab/require-i18n-strings */
import { Node } from '@tiptap/core';
+import { VueNodeViewRenderer } from '@tiptap/vue-2';
+import MediaWrapper from '../components/wrappers/media.vue';
const queryPlayableElement = (element, mediaType) => element.querySelector(mediaType);
@@ -11,6 +13,9 @@ export default Node.create({
addAttributes() {
return {
+ uploading: {
+ default: false,
+ },
src: {
default: null,
parseHTML: (element) => {
@@ -60,7 +65,11 @@ export default Node.create({
...this.extraElementAttrs,
},
],
- ['a', { href: node.attrs.src }, node.attrs.alt],
+ ['a', { href: node.attrs.src }, node.attrs.title || node.attrs.alt || ''],
];
},
+
+ addNodeView() {
+ return VueNodeViewRenderer(MediaWrapper);
+ },
});