diff --git a/src/components/NcRichText/NcRichText.vue b/src/components/NcRichText/NcRichText.vue index c8e3920119..ec3aea99d8 100644 --- a/src/components/NcRichText/NcRichText.vue +++ b/src/components/NcRichText/NcRichText.vue @@ -320,6 +320,7 @@ import { RouterLink } from 'vue-router' import NcCheckboxRadioSwitch from '../NcCheckboxRadioSwitch/NcCheckboxRadioSwitch.vue' import NcReferenceList from './NcReferenceList.vue' import NcRichTextCopyButton from './NcRichTextCopyButton.vue' +import NcRichTextExternalLink from './NcRichTextExternalLink.vue' import { createElementId } from '../../utils/createElementId.ts' import { getRoute, parseUrl, remarkAutolink } from './autolink.ts' import { remarkPlaceholder } from './remarkPlaceholder.ts' @@ -532,11 +533,9 @@ export default { return entry } const { component, props } = entry - // do not override class of NcLink - const componentClass = component.name === 'NcLink' ? undefined : 'rich-text--component' return h(component, { ...props, - class: componentClass, + class: 'rich-text--component', }) }) } @@ -632,6 +631,7 @@ export default { if (String(type) === 'a') { const route = getRoute(this.$router, props.href) if (route) { + // Resolved link to this app; render RouterLink delete props.href delete props.target @@ -640,6 +640,18 @@ export default { to: route, }, { default: () => children }) } + + const isAbsoluteURL = /^https?:\/\//.test(props.href) + if (isAbsoluteURL) { + // External link; render normally, open in the new tab + props.href = props.href.trim() + return h(NcRichTextExternalLink, props, children) + } else { + // Unresolved relative link that does not belong to this app; render only children + delete props.href + delete props.target + return h('span', props, children) + } } return h(type, props, children) } @@ -684,13 +696,6 @@ export default { .rich-text--fallback, .rich-text-component { display: inline; } - - .rich-text--external-link { - text-decoration: underline; - &:after { - content: ' ↗'; - } - } } /* Markdown styles */ diff --git a/src/components/NcRichText/NcRichTextExternalLink.vue b/src/components/NcRichText/NcRichTextExternalLink.vue new file mode 100644 index 0000000000..ae48831b4a --- /dev/null +++ b/src/components/NcRichText/NcRichTextExternalLink.vue @@ -0,0 +1,41 @@ + + + + + + + + + +An internal component + diff --git a/src/components/NcRichText/autolink.ts b/src/components/NcRichText/autolink.ts index 0af3b0a6da..e253f8cbbe 100644 --- a/src/components/NcRichText/autolink.ts +++ b/src/components/NcRichText/autolink.ts @@ -9,28 +9,10 @@ import type { Router } from 'vue-router' import { getBaseUrl, getRootUrl } from '@nextcloud/router' import { u } from 'unist-builder' import { SKIP, visitParents } from 'unist-util-visit-parents' -import { defineComponent, h } from 'vue' +import NcRichTextExternalLink from './NcRichTextExternalLink.vue' import { logger } from '../../utils/logger.ts' import { URL_PATTERN_AUTOLINK } from './helpers.js' -const NcLink = defineComponent({ - name: 'NcLink', - props: { - href: { - type: String, - required: true, - }, - }, - render() { - return h('a', { - href: this.href, - rel: 'noopener noreferrer', - target: '_blank', - class: 'rich-text--external-link', - }, [this.href.trim()]) - }, -}) - /** * * @param root0 @@ -99,7 +81,7 @@ export function parseUrl(text: string) { textAfter = lastChar } list.push(textBefore) - list.push({ component: NcLink, props: { href } }) + list.push({ component: NcRichTextExternalLink, props: { href: href.trim(), decorateExternal: true } }) if (textAfter) { list.push(textAfter) }