Skip to content

Commit

Permalink
feat(editor): Refactor link click handlers
Browse files Browse the repository at this point in the history
New link click behaviour:
* Link left clicks without Ctrl/Meta open link bubble (Fixes: #3691)
* Link left clicks with Ctrl/Meta open link in new tab
* Link middle clicks open link in new tab
* Link middle clicks on Linux don't paste content (Fixes: #2198)
* No more custom open link handler in editor

Implementation details:
* Moved link click handler plugins back into Link mark class.
* Added 'data-md-href' attribute to a-elements in DOM, to be used in
  onClick handlers.

Signed-off-by: Jonas <[email protected]>
  • Loading branch information
mejo- committed Jan 30, 2024
1 parent d83a01f commit 58ac817
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 92 deletions.
23 changes: 0 additions & 23 deletions src/components/RichTextReader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ export default {
return [
RichText.configure({
editing: false,
link: {
onClick: (event, attrs) => {
this.$emit('click-link', event, attrs)
return true
},
},
}),
]
},
Expand All @@ -58,23 +52,6 @@ export default {
required: true,
},
},
mounted() {
this.$el.addEventListener('click', this.preventOpeningLinks, true)
},
unmounted() {
this.$el.removeEventListener('click', this.preventOpeningLinks, true)
},
methods: {
preventOpeningLinks(event) {
// We use custom onClick handler only for left clicks
if (event.target.closest('a') && event.button === 0 && !event.ctrlKey) {
event.preventDefault()
}
},
},
}
</script>

Expand Down
4 changes: 2 additions & 2 deletions src/extensions/LinkBubblePluginView.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class LinkBubblePluginView {
// Required for read-only mode on Firefox. For some reason, editor selection doesn't get
// updated when clicking a link in read-only mode on Firefox.
clickHandler = (event) => {
// Only regard left clicks without Ctrl
if (event.button !== 0 || event.ctrlKey) {
// Only regard left clicks without Ctrl/Meta
if (event.button !== 0 || event.ctrlKey || event.metaKey) {
return false
}

Expand Down
4 changes: 2 additions & 2 deletions src/helpers/links.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const parseHref = function(dom) {
return ref
}

const openLink = function(event, _attrs) {
const openLink = function(event, target = '_self') {
const linkElement = event.target.closest('a')
const htmlHref = linkElement.href
const query = OC.parseQueryString(htmlHref)
Expand Down Expand Up @@ -128,7 +128,7 @@ const openLink = function(event, _attrs) {
return
}
}
window.open(htmlHref)
window.open(htmlHref, target)
return true
}

Expand Down
55 changes: 42 additions & 13 deletions src/marks/Link.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@
*/

import TipTapLink from '@tiptap/extension-link'
import { domHref, parseHref, openLink } from './../helpers/links.js'
import { clickHandler, clickPreventer } from '../plugins/link.js'
import { Plugin, PluginKey } from '@tiptap/pm/state'
import { domHref, parseHref } from './../helpers/links.js'

const Link = TipTapLink.extend({

addOptions() {
return {
...this.parent?.(),
onClick: openLink,
relativePath: null,
}
},
Expand Down Expand Up @@ -63,6 +62,7 @@ const Link = TipTapLink.extend({
return ['a', {
...mark.attrs,
href: domHref(mark, this.options.relativePath),
'data-md-href': mark.attrs.href,
rel: 'noopener noreferrer nofollow',
}, 0]
},
Expand All @@ -74,19 +74,48 @@ const Link = TipTapLink.extend({
return !key.startsWith('handleClickLink')
})

if (!this.options.openOnClick) {
return plugins
}

// add custom click handle plugin
// Custom click handler plugins
return [
...plugins,
clickHandler({
editor: this.editor,
type: this.type,
onClick: this.options.onClick,
new Plugin({
key: new PluginKey('textHandleClickLink'),
props: {
handleDOMEvents: {
// Open link in new tab on middle click
pointerup: (view, event) => {
if (event.target.closest('a') && event.button === 1 && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
event.preventDefault()

const linkElement = event.target.closest('a')
window.open(linkElement.href, '_blank')
}
},
// Prevent paste into links
// On Linux, middle click pastes, which breaks "open in new tab" on middle click
// Pasting into links will break the link anyway, so just disable it altogether.
paste: (view, event) => {
if (event.target.closest('a')) {
event.stopPropagation()
event.preventDefault()
event.stopImmediatePropagation()
}
},
// Prevent open link on left click (required for read-only mode)
// Open link in new tab on Ctrl/Cmd + left click
click: (view, event) => {
if (event.target.closest('a')) {
if (event.button === 0) {
event.preventDefault()
if (event.ctrlKey || event.metaKey) {
const linkElement = event.target.closest('a')
window.open(linkElement.href, '_blank')
}
}
}
},
},
},
}),
clickPreventer(),
]
},
})
Expand Down
52 changes: 0 additions & 52 deletions src/plugins/link.js

This file was deleted.

0 comments on commit 58ac817

Please sign in to comment.