Skip to content

Commit 133630c

Browse files
mejo-backportbot[bot]
authored andcommitted
fix(links): allow to pass custom link handler into editor and use it
The return of the link handler 👻 Required as we want to pass a link handler from Collectives to be used for the "Open link" button and when opening a link via Ctrl-click. Signed-off-by: Jonas <jonas@freesources.org>
1 parent 10dcf3f commit 133630c

7 files changed

Lines changed: 30 additions & 20 deletions

File tree

src/EditorFactory.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ const createRichEditor = ({
5252
relativePath,
5353
isEmbedded,
5454
mentionSearch,
55+
openLink,
5556
}),
5657
FocusTrap,
5758
...extensions,

src/components/Editor.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ import {
9696
FILE,
9797
HOOK_MENTION_SEARCH,
9898
IS_MOBILE,
99+
OPEN_LINK_HANDLER,
99100
} from './Editor.provider.ts'
100101
import ReadonlyBar from './Menu/ReadonlyBar.vue'
101102
@@ -121,6 +122,7 @@ import {
121122
serializePlainText,
122123
} from './../EditorFactory.js'
123124
import { createMarkdownSerializer } from './../extensions/Markdown.js'
125+
import { openLink as defaultOpenLink } from './../helpers/links.js'
124126
import markdownit from './../markdownit/index.js'
125127
import isMobile from './../mixins/isMobile.js'
126128
import AttachmentResolver from './../services/AttachmentResolver.js'
@@ -245,13 +247,17 @@ export default defineComponent({
245247
CollaborationCaret.configure({ provider: { awareness } }),
246248
]
247249
const mentionSearch = inject(HOOK_MENTION_SEARCH)
250+
const openLinkHandler = inject(OPEN_LINK_HANDLER, {
251+
openLink: defaultOpenLink,
252+
})
248253
const editor = isRichEditor
249254
? createRichEditor({
250255
connection,
251256
relativePath: props.relativePath,
252257
extensions,
253258
isEmbedded: props.isEmbedded,
254259
mentionSearch,
260+
openLink: openLinkHandler.openLink,
255261
})
256262
: createPlainEditor({ language, extensions })
257263
provideEditor(editor)

src/components/Editor/MarkdownContentEditor.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@ import Wrapper from './Wrapper.vue'
2525
/* eslint-disable import/no-named-as-default */
2626
import { getCurrentUser } from '@nextcloud/auth'
2727
import { UndoRedo } from '@tiptap/extensions'
28-
import { provide, watch } from 'vue'
28+
import { inject, provide, watch } from 'vue'
2929
import { provideEditor } from '../../composables/useEditor.ts'
3030
import { editorFlagsKey } from '../../composables/useEditorFlags.ts'
3131
import { provideEditorHeadings } from '../../composables/useEditorHeadings.ts'
3232
import { useEditorMethods } from '../../composables/useEditorMethods.ts'
3333
import { provideEditorWidth } from '../../composables/useEditorWidth.ts'
3434
import { FocusTrap, RichText } from '../../extensions/index.js'
3535
import { createMarkdownSerializer } from '../../extensions/Markdown.js'
36+
import { openLink as defaultOpenLink } from '../../helpers/links.js'
3637
import AttachmentResolver from '../../services/AttachmentResolver.js'
37-
import { ATTACHMENT_RESOLVER } from '../Editor.provider.ts'
38+
import { ATTACHMENT_RESOLVER, OPEN_LINK_HANDLER } from '../Editor.provider.ts'
3839
import ReadonlyBar from '../Menu/ReadonlyBar.vue'
3940
import ContentContainer from './ContentContainer.vue'
4041
@@ -82,9 +83,13 @@ export default {
8283
emits: ['update:content'],
8384
8485
setup(props) {
86+
const openLinkHandler = inject(OPEN_LINK_HANDLER, {
87+
openLink: defaultOpenLink,
88+
})
8589
const extensions = [
8690
RichText.configure({
8791
extensions: [UndoRedo],
92+
openLink: openLinkHandler.openLink,
8893
}),
8994
FocusTrap,
9095
]

src/components/Editor/PreviewOptions.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ import DotsVerticalIcon from 'vue-material-design-icons/DotsVertical.vue'
7373
import OpenIcon from 'vue-material-design-icons/OpenInNew.vue'
7474
import DeleteOutlineIcon from 'vue-material-design-icons/TrashCanOutline.vue'
7575
import CopyToClipboardMixin from '../../mixins/CopyToClipboardMixin.js'
76+
import { useOpenLinkHandler } from '../Editor.provider.ts'
7677
7778
export default {
7879
name: 'PreviewOptions',
@@ -91,7 +92,7 @@ export default {
9192
OpenIcon,
9293
},
9394
94-
mixins: [CopyToClipboardMixin],
95+
mixins: [CopyToClipboardMixin, useOpenLinkHandler],
9596
9697
props: {
9798
type: {
@@ -126,7 +127,7 @@ export default {
126127
},
127128
openLink() {
128129
if (!this.href) return
129-
window.open(this.href, '_blank').focus()
130+
this.$openLinkHandler.openLink(this.href)
130131
},
131132
async copyLink() {
132133
await this.copyToClipboard(this.href)

src/extensions/RichText.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export default Extension.create({
6161
relativePath: null,
6262
isEmbedded: false,
6363
mentionSearch: undefined,
64+
openLink: undefined,
6465
}
6566
},
6667

@@ -122,6 +123,7 @@ export default Extension.create({
122123
openOnClick: true,
123124
shouldAutoLink: (href) => /^https?:\/\//.test(href),
124125
relativePath: this.options.relativePath,
126+
openLink: this.options.openLink,
125127
}),
126128
LinkBubble,
127129
this.options.editing

src/helpers/links.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,7 @@ const isLinkToSelfWithHash = function (href) {
6464
*/
6565
const openLink = function (href) {
6666
const linkUrl = new URL(href, window.location.href)
67-
// Consider rerouting links to Collectives if already inside Collectives app
68-
const collectivesUrlBase = '/apps/collectives'
69-
if (
70-
window.OCA.Collectives?.vueRouter
71-
&& linkUrl.pathname.toString().startsWith(generateUrl(collectivesUrlBase))
72-
) {
73-
const collectivesUrl = linkUrl.href.substring(
74-
linkUrl.href.indexOf(collectivesUrlBase) + collectivesUrlBase.length,
75-
)
76-
window.OCA.Collectives.vueRouter.push(collectivesUrl)
77-
return
78-
}
79-
window.open(linkUrl, '_blank')
67+
window.open(linkUrl.href, '_blank')
8068
}
8169

8270
export { domHref, isLinkToSelfWithHash, openLink, parseHref }

src/plugins/links.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,14 @@ export const linkClickingKey = new PluginKey('textHandleClickLink')
137137
* - Open link in new tab on middle click rather than pasting.
138138
* - Only open link on ctrl/cmd + left click.
139139
* We use the link bubble otherwise.
140+
*
141+
* @param openLink - the openLink callback function
140142
*/
141-
export function linkClicking() {
143+
export function linkClicking(
144+
openLink: (href: string) => void = (href) => {
145+
window.open(href, '_blank')
146+
},
147+
) {
142148
return new Plugin({
143149
key: linkClickingKey,
144150
props: {
@@ -155,6 +161,7 @@ export function linkClicking() {
155161
) {
156162
event.preventDefault()
157163
event.stopImmediatePropagation()
164+
// Open link in new tab on middle click (ignore custom link handler on purpose)
158165
window.open(linkEl.href, '_blank')
159166
}
160167
},
@@ -187,8 +194,8 @@ export function linkClicking() {
187194
// Open anchor links directly
188195
location.href = linkEl.href
189196
} else if (event.ctrlKey || event.metaKey) {
190-
// Open link in new tab on Ctrl/Cmd + left click
191-
window.open(linkEl.href, '_blank')
197+
// Open link directly on Ctrl/Cmd + left click
198+
openLink(linkEl.href)
192199
}
193200
}
194201
},

0 commit comments

Comments
 (0)