diff --git a/cypress/e2e/nodes/Links.spec.js b/cypress/e2e/nodes/Links.spec.js
index 13d6db365e6..b84fb82db94 100644
--- a/cypress/e2e/nodes/Links.spec.js
+++ b/cypress/e2e/nodes/Links.spec.js
@@ -47,7 +47,7 @@ describe('test link marks', function() {
cy.get('.link-view-bubble .widget-default', { timeout: 10000 })
.find('.widget-default--name')
.contains('Nextcloud')
- .click({ force: true })
+ .click()
})
it('shows a link preview in the bubble after browsing to link', () => {
@@ -64,6 +64,16 @@ describe('test link marks', function() {
.contains('Nextcloud')
})
+ it('open button opens a new tab', () => {
+ const link = 'https://nextcloud.com/'
+ cy.insertLine(link)
+ clickLink(link)
+
+ cy.get('.link-view-bubble button[title="Open link"]').click()
+
+ cy.get('@winOpen').should('have.been.calledOnce')
+ })
+
it('closes the link bubble when clicking elsewhere', () => {
const link = 'https://nextcloud.com/'
cy.insertLine(link)
diff --git a/cypress/e2e/nodes/PreviewOptions.spec.js b/cypress/e2e/nodes/PreviewOptions.spec.js
index df0e22e86fd..48d5b53f3ce 100644
--- a/cypress/e2e/nodes/PreviewOptions.spec.js
+++ b/cypress/e2e/nodes/PreviewOptions.spec.js
@@ -23,6 +23,7 @@ describe('Preview Options', function() {
})
it('should render previewOptions correctly', function() {
+ cy.get('.action-button__text').contains('Open in new tab').should('be.visible')
cy.get('.action-button__text').contains('Remove link').should('be.visible')
cy.get('.action-radio__label').each(el => {
cy.wrap(el).invoke('text').should('match', /Text only|Show link preview/)
diff --git a/src/components/Editor.provider.js b/src/components/Editor.provider.js
index bcc4085f7f8..3d6233379ee 100644
--- a/src/components/Editor.provider.js
+++ b/src/components/Editor.provider.js
@@ -3,6 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+import { openLink } from '../helpers/links.js'
import { logger } from '../helpers/logger.js'
export const EDITOR = Symbol('tiptap:editor')
@@ -16,6 +17,7 @@ export const SYNC_SERVICE = Symbol('sync:service')
export const EDITOR_UPLOAD = Symbol('editor:upload')
export const HOOK_MENTION_SEARCH = Symbol('hook:mention-search')
export const HOOK_MENTION_INSERT = Symbol('hook:mention-insert')
+export const OPEN_LINK_HANDLER = Symbol('editor:open-link-handler')
export const useEditorMixin = {
inject: {
@@ -99,3 +101,13 @@ export const useMentionHook = {
},
},
}
+export const useOpenLinkHandler = {
+ inject: {
+ $openLinkHandler: {
+ from: OPEN_LINK_HANDLER,
+ default: {
+ openLink,
+ },
+ },
+ },
+}
diff --git a/src/components/Editor/PreviewOptions.vue b/src/components/Editor/PreviewOptions.vue
index 36857afc449..ac1a97c7265 100644
--- a/src/components/Editor/PreviewOptions.vue
+++ b/src/components/Editor/PreviewOptions.vue
@@ -27,11 +27,17 @@
{{ t('text', 'Show link preview') }}
+
+
+
+
+ {{ t('text', 'Open in new tab') }}
+
- {{ t('text','Remove link') }}
+ {{ t('text', 'Remove link') }}
@@ -45,6 +51,7 @@ import NcActionCaption from '@nextcloud/vue/components/NcActionCaption'
import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator'
import DotsVerticalIcon from 'vue-material-design-icons/DotsVertical.vue'
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
+import OpenIcon from 'vue-material-design-icons/OpenInNew.vue'
export default {
name: 'PreviewOptions',
@@ -57,6 +64,7 @@ export default {
NcActionRadio,
NcActionSeparator,
DeleteIcon,
+ OpenIcon,
},
props: {
@@ -64,6 +72,11 @@ export default {
type: String,
required: true,
},
+ href: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
@@ -83,6 +96,10 @@ export default {
deleteNode() {
this.$emit('delete')
},
+ openLink() {
+ if (!this.href) return
+ window.open(this.href, '_blank').focus()
+ },
},
}
diff --git a/src/components/Link/LinkBubbleView.vue b/src/components/Link/LinkBubbleView.vue
index 9d980280a34..6c355d9ece1 100644
--- a/src/components/Link/LinkBubbleView.vue
+++ b/src/components/Link/LinkBubbleView.vue
@@ -10,6 +10,15 @@
{{ title }}
+
+
+
+
+
+
{
editor.commands.hideLinkBubble()
diff --git a/src/tests/plugins/extractLinkParagraphs.spec.js b/src/tests/plugins/extractLinkParagraphs.spec.js
index a4fcd2419b0..3ba2b69c184 100644
--- a/src/tests/plugins/extractLinkParagraphs.spec.js
+++ b/src/tests/plugins/extractLinkParagraphs.spec.js
@@ -9,8 +9,9 @@ import Preview from '../../nodes/Preview.js'
import createCustomEditor from '../testHelpers/createCustomEditor.ts'
describe('extractLinkParagraphs', () => {
- const link = 'Link'
- const preview = 'Link'
+ const href = 'https://nextcloud.com'
+ const link = `Link`
+ const preview = `Link`
it('returns an empty array for an empty doc', () => {
const doc = prepareDoc('')
@@ -23,7 +24,7 @@ describe('extractLinkParagraphs', () => {
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
- { pos: 0, type: 'text-only', nodeSize: 6 },
+ { href, pos: 0, type: 'text-only', nodeSize: 6 },
])
})
@@ -31,7 +32,7 @@ describe('extractLinkParagraphs', () => {
const doc = prepareDoc(preview)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
- { pos: 0, type: 'link-preview', nodeSize: 6 },
+ { href, pos: 0, type: 'link-preview', nodeSize: 6 },
])
})
@@ -40,7 +41,7 @@ describe('extractLinkParagraphs', () => {
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
- { pos: 0, type: 'text-only', nodeSize: 7 },
+ { href, pos: 0, type: 'text-only', nodeSize: 7 },
])
})
@@ -50,8 +51,8 @@ describe('extractLinkParagraphs', () => {
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
- { pos: 0, type: 'text-only', nodeSize: 6 },
- { pos: 6, type: 'text-only', nodeSize: 6 },
+ { href, pos: 0, type: 'text-only', nodeSize: 6 },
+ { href, pos: 6, type: 'text-only', nodeSize: 6 },
])
})
@@ -60,8 +61,8 @@ describe('extractLinkParagraphs', () => {
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
- { pos: 0, type: 'text-only', nodeSize: 6 },
- { pos: 6, type: 'link-preview', nodeSize: 6 },
+ { href, pos: 0, type: 'text-only', nodeSize: 6 },
+ { href, pos: 6, type: 'link-preview', nodeSize: 6 },
])
})