Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion cypress/e2e/Links.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,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', () => {
Expand All @@ -58,6 +58,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)
Expand Down
3 changes: 3 additions & 0 deletions cypress/e2e/nodes/PreviewOptions.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ 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)
Expand Down
12 changes: 12 additions & 0 deletions src/components/Editor.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 FILE = Symbol('editor:file')
Expand All @@ -11,6 +12,7 @@ export const IS_MOBILE = Symbol('editor:is-mobile')
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 useIsMobileMixin = {
inject: {
Expand Down Expand Up @@ -66,3 +68,13 @@ export const useMentionHook = {
},
},
}
export const useOpenLinkHandler = {
inject: {
$openLinkHandler: {
from: OPEN_LINK_HANDLER,
default: {
openLink,
},
},
},
}
19 changes: 18 additions & 1 deletion src/components/Link/LinkBubbleView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
<div class="link-view-bubble__title">
{{ title }}
</div>
<!-- open link -->
<NcButton
:title="t('text', 'Open link')"
:aria-label="t('text', 'Open link')"
type="tertiary"
@click="openLink(href)">
<template #icon>
<OpenInNewIcon :size="20" />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked for a different icon briefly as this does not always open in new... but i found nothing satisfying.

</template>
</NcButton>
<!-- copy link -->
<NcButton
:title="copyLinkTooltip"
Expand Down Expand Up @@ -103,9 +113,11 @@ import CheckIcon from 'vue-material-design-icons/Check.vue'
import CloseIcon from 'vue-material-design-icons/Close.vue'
import ContentCopyIcon from 'vue-material-design-icons/ContentCopy.vue'
import LinkOffIcon from 'vue-material-design-icons/LinkOff.vue'
import OpenInNewIcon from 'vue-material-design-icons/OpenInNew.vue'
import PencilOutlineIcon from 'vue-material-design-icons/PencilOutline.vue'

import CopyToClipboardMixin from '../../mixins/CopyToClipboardMixin.js'
import { useOpenLinkHandler } from '../Editor.provider.ts'

const PROTOCOLS_WITH_PREVIEW = ['http:', 'https:']

Expand All @@ -121,10 +133,11 @@ export default {
NcReferenceList,
NcTextField,
LinkOffIcon,
OpenInNewIcon,
PencilOutlineIcon,
},

mixins: [CopyToClipboardMixin],
mixins: [CopyToClipboardMixin, useOpenLinkHandler],

props: {
editor: {
Expand Down Expand Up @@ -204,6 +217,10 @@ export default {
this.referenceTitle = null
},

openLink(href) {
this.$openLinkHandler.openLink(href)
},

async copyLink() {
await this.copyToClipboard(this.href)
},
Expand Down
6 changes: 1 addition & 5 deletions src/css/prosemirror.scss
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,6 @@ div.ProseMirror {
font-size: var(--default-font-size);
}

img {
cursor: default;
max-width: 100%;
}

hr {
padding: 2px 0;
border: none;
Expand Down Expand Up @@ -419,6 +414,7 @@ div.ProseMirror {
}

.tippy-content div {
box-sizing: border-box;
visibility: visible !important;
}

Expand Down
6 changes: 6 additions & 0 deletions src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {
EDITOR_UPLOAD,
HOOK_MENTION_INSERT,
HOOK_MENTION_SEARCH,
OPEN_LINK_HANDLER,
} from './components/Editor.provider.ts'
import { ACTION_ATTACHMENT_PROMPT } from './components/Editor/MediaHandler.provider.js'
import { openLink } from './helpers/links.js'
// eslint-disable-next-line import/no-unresolved, n/no-missing-import
import 'vite/modulepreload-polyfill'

Expand Down Expand Up @@ -192,6 +194,7 @@ window.OCA.Text.createEditor = async function ({
onFileInsert = undefined,
onMentionSearch = undefined,
onMentionInsert = undefined,
openLinkHandler = undefined,
onSearch = undefined,
}) {
const { default: MarkdownContentEditor } = await import(
Expand All @@ -217,6 +220,9 @@ window.OCA.Text.createEditor = async function ({
[EDITOR_UPLOAD]: !!sessionEditor,
[HOOK_MENTION_SEARCH]: sessionEditor ? true : onMentionSearch,
[HOOK_MENTION_INSERT]: sessionEditor ? true : onMentionInsert,
[OPEN_LINK_HANDLER]: {
openLink: openLinkHandler || openLink,
},
[ATTACHMENT_RESOLVER]: {
resolve(src, preferRaw) {
return [
Expand Down
1 change: 0 additions & 1 deletion src/extensions/LinkBubble.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const LinkBubble = Extension.create({
return [
linkBubble({
editor: this.editor,
parent: this.editor.contentComponent,
}),
]
},
Expand Down
24 changes: 23 additions & 1 deletion src/helpers/links.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,26 @@ const isLinkToSelfWithHash = function (href) {
return href?.startsWith('#') || href?.startsWith(locationNoHash + '#')
}

export { domHref, isLinkToSelfWithHash, parseHref }
/**
* Open links, to be used as custom click handler
*
* @param {string} href the link href
*/
const openLink = function (href) {
const linkUrl = new URL(href, window.location.href)
// Consider rerouting links to Collectives if already inside Collectives app
const collectivesUrlBase = '/apps/collectives'
if (
window.OCA.Collectives?.vueRouter
&& linkUrl.pathname.toString().startsWith(generateUrl(collectivesUrlBase))
) {
const collectivesUrl = linkUrl.href.substring(
linkUrl.href.indexOf(collectivesUrlBase) + collectivesUrlBase.length,
)
window.OCA.Collectives.vueRouter.push(collectivesUrl)
return
}
window.open(linkUrl, '_blank')
}

export { domHref, isLinkToSelfWithHash, openLink, parseHref }
10 changes: 8 additions & 2 deletions src/plugins/LinkBubblePluginView.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class LinkBubblePluginView {
}

this.#component ||= new VueRenderer(LinkBubbleView, {
parent: this.options.parent,
parent: this.options.editor.contentComponent,
propsData: {
editor: this.options.editor,
href: null,
Expand Down Expand Up @@ -98,7 +98,13 @@ class LinkBubblePluginView {
}

updateTooltip(view, { mark, nodeStart }) {
let referenceEl = view.nodeDOM(nodeStart)
let referenceEl
try {
referenceEl = view.nodeDOM(nodeStart)
} catch (e) {
// Prevent throwing error at rerouting in `openLink()`
return
}
if (Object.prototype.toString.call(referenceEl) === '[object Text]') {
referenceEl = referenceEl.parentElement
}
Expand Down
5 changes: 3 additions & 2 deletions src/plugins/previewOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,16 @@ function decorationForLinkParagraph(linkParagraph, editor) {
* @param {object} linkParagraph - linkParagraph to generate anchor for
* @param {number} linkParagraph.pos - Position of the node
* @param {string} linkParagraph.type - selected type
* @param {string} linkParagraph.href - href of the link
* @param {number} linkParagraph.nodeSize - size of the node
* @param {object} editor - tiptap editor
*
* @return {Element}
*/
function previewOptionForLinkParagraph({ type, pos, nodeSize }, editor) {
function previewOptionForLinkParagraph({ type, href, pos, nodeSize }, editor) {
const el = document.createElement('div')
const Component = Vue.extend(PreviewOptions)
const propsData = { type }
const propsData = { type, href }
const previewOption = new Component({ propsData }).$mount(el)
previewOption.$on('open', () => {
editor.commands.hideLinkBubble()
Expand Down
Loading