From 9fbc08788f3f46ab31fc05b5d268df0099c4e0e6 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Thu, 14 Sep 2023 17:52:22 +0200 Subject: [PATCH 01/13] chore(deps) replace legacy dependency with 'rehype-external-links' Signed-off-by: Maksim Sukharev --- package-lock.json | 242 ++++++++++++++++++++++++++++++++++++---------- package.json | 2 +- 2 files changed, 190 insertions(+), 54 deletions(-) diff --git a/package-lock.json b/package-lock.json index a88156dca9..66753fe08f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,9 +34,9 @@ "linkify-string": "^4.0.0", "md5": "^2.3.0", "node-polyfill-webpack-plugin": "^2.0.1", + "rehype-external-links": "^3.0.0", "rehype-react": "^7.1.2", "remark-breaks": "^3.0.2", - "remark-external-links": "^9.0.1", "remark-parse": "^10.0.1", "remark-rehype": "^10.1.0", "splitpanes": "^2.4.1", @@ -4403,6 +4403,11 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/@vue/compiler-core": { "version": "3.2.47", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", @@ -12413,6 +12418,26 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element/node_modules/@types/hast": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.0.tgz", + "integrity": "sha512-SoytUJRuf68HXYqcXicQIhCrLQjqeYU2anikr4G3p3Iz+OZO5QDQpDj++gv+RenHsnUBwNZ2dumBArF8VLSk2Q==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/hast-util-whitespace": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", @@ -20455,6 +20480,86 @@ "jsesc": "bin/jsesc" } }, + "node_modules/rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-external-links/node_modules/@types/hast": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.0.tgz", + "integrity": "sha512-SoytUJRuf68HXYqcXicQIhCrLQjqeYU2anikr4G3p3Iz+OZO5QDQpDj++gv+RenHsnUBwNZ2dumBArF8VLSk2Q==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/rehype-external-links/node_modules/@types/unist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", + "integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w==" + }, + "node_modules/rehype-external-links/node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rehype-external-links/node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-external-links/node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-external-links/node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-react": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/rehype-react/-/rehype-react-7.2.0.tgz", @@ -20503,36 +20608,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-external-links": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-9.0.1.tgz", - "integrity": "sha512-EYw+p8Zqy5oT5+W8iSKzInfRLY+zeKWHCf0ut+Q5SwnaSIDGXd2zzvp4SWqyAuVbinNmZ0zjMrDKaExWZnTYqQ==", - "dependencies": { - "@types/hast": "^2.3.2", - "@types/mdast": "^3.0.0", - "extend": "^3.0.0", - "is-absolute-url": "^4.0.0", - "mdast-util-definitions": "^5.0.0", - "space-separated-tokens": "^2.0.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-external-links/node_modules/is-absolute-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", - "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/remark-parse": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", @@ -30804,6 +30879,11 @@ } } }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "@vue/compiler-core": { "version": "3.2.47", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", @@ -36986,6 +37066,24 @@ "web-namespaces": "^2.0.0" } }, + "hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "requires": { + "@types/hast": "^3.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.0.tgz", + "integrity": "sha512-SoytUJRuf68HXYqcXicQIhCrLQjqeYU2anikr4G3p3Iz+OZO5QDQpDj++gv+RenHsnUBwNZ2dumBArF8VLSk2Q==", + "requires": { + "@types/unist": "*" + } + } + } + }, "hast-util-whitespace": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", @@ -43023,6 +43121,66 @@ } } }, + "rehype-external-links": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rehype-external-links/-/rehype-external-links-3.0.0.tgz", + "integrity": "sha512-yp+e5N9V3C6bwBeAC4n796kc86M4gJCdlVhiMTxIrJG5UHDMh+PJANf9heqORJbt1nrCbDwIlAZKjANIaVBbvw==", + "requires": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-is-element": "^3.0.0", + "is-absolute-url": "^4.0.0", + "space-separated-tokens": "^2.0.0", + "unist-util-visit": "^5.0.0" + }, + "dependencies": { + "@types/hast": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.0.tgz", + "integrity": "sha512-SoytUJRuf68HXYqcXicQIhCrLQjqeYU2anikr4G3p3Iz+OZO5QDQpDj++gv+RenHsnUBwNZ2dumBArF8VLSk2Q==", + "requires": { + "@types/unist": "*" + } + }, + "@types/unist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", + "integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w==" + }, + "is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==" + }, + "unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "requires": { + "@types/unist": "^3.0.0" + } + }, + "unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + } + }, + "unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "requires": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + } + } + } + }, "rehype-react": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/rehype-react/-/rehype-react-7.2.0.tgz", @@ -43159,28 +43317,6 @@ "unist-util-visit": "^4.0.0" } }, - "remark-external-links": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-9.0.1.tgz", - "integrity": "sha512-EYw+p8Zqy5oT5+W8iSKzInfRLY+zeKWHCf0ut+Q5SwnaSIDGXd2zzvp4SWqyAuVbinNmZ0zjMrDKaExWZnTYqQ==", - "requires": { - "@types/hast": "^2.3.2", - "@types/mdast": "^3.0.0", - "extend": "^3.0.0", - "is-absolute-url": "^4.0.0", - "mdast-util-definitions": "^5.0.0", - "space-separated-tokens": "^2.0.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0" - }, - "dependencies": { - "is-absolute-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", - "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==" - } - } - }, "remark-parse": { "version": "10.0.2", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", diff --git a/package.json b/package.json index ab997ae24e..a43ffbb552 100644 --- a/package.json +++ b/package.json @@ -65,9 +65,9 @@ "linkify-string": "^4.0.0", "md5": "^2.3.0", "node-polyfill-webpack-plugin": "^2.0.1", + "rehype-external-links": "^3.0.0", "rehype-react": "^7.1.2", "remark-breaks": "^3.0.2", - "remark-external-links": "^9.0.1", "remark-parse": "^10.0.1", "remark-rehype": "^10.1.0", "splitpanes": "^2.4.1", From 9be8794246beffda3fe75b99a9fcb0427b54ed75 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Wed, 6 Sep 2023 12:54:14 +0200 Subject: [PATCH 02/13] chore(RichText) replace legacy dependency with 'rehype-external-links' Signed-off-by: Maksim Sukharev --- src/components/NcRichText/NcRichText.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/NcRichText/NcRichText.vue b/src/components/NcRichText/NcRichText.vue index 90a9344f14..2939f514cc 100644 --- a/src/components/NcRichText/NcRichText.vue +++ b/src/components/NcRichText/NcRichText.vue @@ -76,7 +76,7 @@ import markdown from 'remark-parse' import breaks from 'remark-breaks' import remark2rehype from 'remark-rehype' import rehype2react from 'rehype-react' -import remarkExternalLinks from 'remark-external-links' +import rehypeExternalLinks from 'rehype-external-links' export default { name: 'NcRichText', @@ -176,10 +176,6 @@ export default { autolink: this.autolink, useMarkdown: this.useMarkdown, }) - .use(remarkExternalLinks, { - target: '_blank', - rel: ['noopener noreferrer'], - }) .use(breaks) .use(remark2rehype, { handlers: { @@ -190,6 +186,10 @@ export default { }) // .use(rehypeAddClasses, this.markdownCssClasses) .use(remarkPlaceholder) + .use(rehypeExternalLinks, { + target: '_blank', + rel: ['noopener noreferrer'], + }) .use(rehype2react, { createElement: (tag, attrs, children) => { if (!tag.startsWith('#')) { From a580e3af1654dd707f916d2e5365b4e703dcdfd6 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Thu, 31 Aug 2023 11:37:27 +0200 Subject: [PATCH 03/13] fix(NcAvatar) force white-space wrapping if show initials Signed-off-by: Maksim Sukharev --- src/components/NcAvatar/NcAvatar.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/NcAvatar/NcAvatar.vue b/src/components/NcAvatar/NcAvatar.vue index 69a844131b..83600cc531 100644 --- a/src/components/NcAvatar/NcAvatar.vue +++ b/src/components/NcAvatar/NcAvatar.vue @@ -700,6 +700,7 @@ export default { &--unknown { position: relative; background-color: var(--color-main-background); + white-space: normal; } &:not(&--unknown) { From ef77bd06c8541f14dab05a5ba13fc751c026a7be Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Wed, 6 Sep 2023 12:34:05 +0200 Subject: [PATCH 04/13] fix(placeholder) - don't wrap each element in span Signed-off-by: Maksim Sukharev --- src/components/NcRichText/placeholder.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/NcRichText/placeholder.js b/src/components/NcRichText/placeholder.js index f2ee5b4f91..accc69048c 100644 --- a/src/components/NcRichText/placeholder.js +++ b/src/components/NcRichText/placeholder.js @@ -26,10 +26,7 @@ export const remarkPlaceholder = function() { }) }) - node = u('element', { tagName: 'span' }, [ - ...placeholders, - ]) - parent.children[index] = node + parent.children.splice(index, 1, ...placeholders) } } } From 9d810ea31640d72cec4956e75953ccd685f3b47d Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Fri, 8 Sep 2023 10:24:09 +0200 Subject: [PATCH 05/13] fix(NcRichText) revert forced newlines, add base styling for markdown Signed-off-by: Maksim Sukharev --- cypress/component/richtext.cy.ts | 2 +- src/components/NcRichText/NcRichText.vue | 20 ++++--------- src/components/NcRichText/richtext.scss | 38 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/cypress/component/richtext.cy.ts b/cypress/component/richtext.cy.ts index 519068d7b9..b420d098e9 100644 --- a/cypress/component/richtext.cy.ts +++ b/cypress/component/richtext.cy.ts @@ -401,7 +401,7 @@ describe('NcRichText', () => { }, }) - cy.get('blockquote').should('have.text', '\nline 1\n\nline 3\n') + cy.get('blockquote').should('have.text', '\nline 1\nline 3\n') }) it('blockquote (with nested blockquote)', () => { diff --git a/src/components/NcRichText/NcRichText.vue b/src/components/NcRichText/NcRichText.vue index 2939f514cc..6e93dad7f9 100644 --- a/src/components/NcRichText/NcRichText.vue +++ b/src/components/NcRichText/NcRichText.vue @@ -217,18 +217,10 @@ export default { }, prefix: false, }) - .processSync(this.useMarkdown - // In order to correctly show newlines in Markdown, - // each newline contains a non-breaking space - ? this.text.slice() - .replace(/\n>\n/g, '\n>\u00A0\n') - .replace(/\n{2,}/g, (match) => { - return '\n' + '\n\u00A0\n'.repeat(match.length - 1) - }) - : this.text) + .processSync(this.text) .result - return h('div', { class: 'rich-text--wrapper' }, [ + return h('div', { class: 'rich-text--wrapper rich-text--wrapper-markdown' }, [ renderedMarkdown, this.referenceLimit > 0 ? h('div', { class: 'rich-text--reference-widget' }, [ @@ -239,11 +231,9 @@ export default { }, }, render(h) { - if (!this.useMarkdown) { - return this.renderPlaintext(h) - } - - return this.renderMarkdown(h) + return this.useMarkdown + ? this.renderMarkdown(h) + : this.renderPlaintext(h) }, } diff --git a/src/components/NcRichText/richtext.scss b/src/components/NcRichText/richtext.scss index 2d85ff4095..97c8994791 100644 --- a/src/components/NcRichText/richtext.scss +++ b/src/components/NcRichText/richtext.scss @@ -132,3 +132,41 @@ } } } + +.rich-text--wrapper-markdown { + div > *:first-child, + blockquote > *:first-child{ + margin-top: 0 !important; + } + div > *:last-child , + blockquote > *:last-child { + margin-bottom: 0 !important; + } + + h1, h2, h3, h4, h5, h6, p, ul, ol, blockquote, pre { + margin-top: 0; + margin-bottom: 1em; + } + + h1, h2, h3, h4, h5, h6 { + font-weight: bold; + } + + h1 { + font-size: 30px; + } + + ul, ol { + padding-left: 15px; + } + + ul { + list-style-type: disc; + } + + blockquote { + padding-left: 13px; + border-left: 2px solid var(--color-border-dark); + color: var(--color-text-lighter); + } +} From c3691dc37d77c86b132a2031bb2ec70dfc3b5093 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Fri, 8 Sep 2023 10:25:40 +0200 Subject: [PATCH 06/13] fix(NcRichText) escape XML-like content before markdown parsing Signed-off-by: Maksim Sukharev --- cypress/component/richtext.cy.ts | 43 +++++++++++++++++++++--- src/components/NcRichText/NcRichText.vue | 13 ++++++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/cypress/component/richtext.cy.ts b/cypress/component/richtext.cy.ts index b420d098e9..28ae7e6f77 100644 --- a/cypress/component/richtext.cy.ts +++ b/cypress/component/richtext.cy.ts @@ -6,6 +6,19 @@ import NcRichText from '../../src/components/NcRichText/NcRichText.vue' describe('NcRichText', () => { describe('renders with markdown', () => { + describe('normal text', () => { + it('XML-like text (escaped and unescaped)', () => { + mount(NcRichText, { + propsData: { + text: 'text</span>', + useMarkdown: true, + }, + }) + + cy.get('p').should('have.text', 'text') + }) + }) + describe('headings', () => { it('heading (with hash (#) syntax divided with space from text)', () => { const testCases = [ @@ -274,6 +287,17 @@ describe('NcRichText', () => { cy.get('code').should('have.text', 'inline code') }) + + it('inline code (with ignored bold, italic, XML-like syntax))', () => { + mount(NcRichText, { + propsData: { + text: '`inline code **bold text** _italic text_ text</span>`', + useMarkdown: true, + }, + }) + + cy.get('code').should('have.text', 'inline code **bold text** _italic text_ text') + }) }) describe('multiline code', () => { @@ -333,20 +357,20 @@ describe('NcRichText', () => { cy.get('code').should('have.text', 'line 1\nline 2\nline 3\n') }) - it('multiline code (with ignored bold, italic, inline code syntax)', () => { + it('multiline code (with ignored bold, italic, inline code, XML-like syntax)', () => { mount(NcRichText, { propsData: { - text: '```\n**bold text**\n_italic text_\n`inline code`\n```', + text: '```\n**bold text**\n_italic text_\n`inline code`\ntext</span>\n```', useMarkdown: true, }, }) - cy.get('pre').should('have.text', '**bold text**\n_italic text_\n`inline code`\n') + cy.get('pre').should('have.text', '**bold text**\n_italic text_\n`inline code`\ntext\n') }) }) describe('blockquote', () => { - it('blockquote (with greater then (gt >) syntax)', () => { + it('blockquote (with greater then (>) syntax - normal)', () => { mount(NcRichText, { propsData: { text: '> blockquote', @@ -357,6 +381,17 @@ describe('NcRichText', () => { cy.get('blockquote').should('have.text', '\nblockquote\n') }) + it('blockquote (with greater then (>) syntax - escaped)', () => { + mount(NcRichText, { + propsData: { + text: '> blockquote', + useMarkdown: true, + }, + }) + + cy.get('blockquote').should('have.text', '\nblockquote\n') + }) + it('blockquote (with bold, italic text, inline code)', () => { mount(NcRichText, { propsData: { diff --git a/src/components/NcRichText/NcRichText.vue b/src/components/NcRichText/NcRichText.vue index 6e93dad7f9..9cb7a92f3a 100644 --- a/src/components/NcRichText/NcRichText.vue +++ b/src/components/NcRichText/NcRichText.vue @@ -192,6 +192,12 @@ export default { }) .use(rehype2react, { createElement: (tag, attrs, children) => { + // unescape special symbol "<" for simple text nodes + children = children?.map(child => typeof child === 'string' + ? child.replace(/</gmi, '<') + : child, + ) + if (!tag.startsWith('#')) { return h(tag, attrs, children) } @@ -217,7 +223,12 @@ export default { }, prefix: false, }) - .processSync(this.text) + .processSync(this.text + // escape special symbol "<" to not treat text as HTML + .replace(/" to parse blockquotes + .replace(/>/gmi, '>') + ) .result return h('div', { class: 'rich-text--wrapper rich-text--wrapper-markdown' }, [ From 22740276c27666c71e5c2dae6c30b977ce682296 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Thu, 7 Sep 2023 11:02:53 +0200 Subject: [PATCH 07/13] feat(docs) show mentions in NcRichText output example Signed-off-by: Maksim Sukharev --- .../NcRichContenteditable.vue | 63 ++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/src/components/NcRichContenteditable/NcRichContenteditable.vue b/src/components/NcRichContenteditable/NcRichContenteditable.vue index d14577edd8..54fdc20fea 100644 --- a/src/components/NcRichContenteditable/NcRichContenteditable.vue +++ b/src/components/NcRichContenteditable/NcRichContenteditable.vue @@ -27,6 +27,8 @@ This component displays contenteditable div with automated `@` [at] autocompleti ### Examples +Try mentioning user @Test01 or inserting emoji :smile + ```vue +``` -