diff --git a/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue b/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue index 0ba2e6609f..8ca9ca6e42 100644 --- a/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue +++ b/app/src/interfaces/input-rich-text-html/input-rich-text-html.vue @@ -416,6 +416,13 @@ export default defineComponent({ editor.ui.registry.addToggleButton('customMedia', mediaButton); editor.ui.registry.addToggleButton('customLink', linkButton); editor.ui.registry.addButton('customCode', sourceCodeButton); + + editor.on('init', function () { + editor.shortcuts.remove('meta+k'); + editor.addShortcut('meta+k', 'Insert Link', () => { + editor.ui.registry.getAll().buttons.customlink.onAction(); + }); + }); } function setFocus(val: boolean) { diff --git a/app/src/interfaces/input-rich-text-html/useLink.ts b/app/src/interfaces/input-rich-text-html/useLink.ts index ba19d2e479..c383534333 100644 --- a/app/src/interfaces/input-rich-text-html/useLink.ts +++ b/app/src/interfaces/input-rich-text-html/useLink.ts @@ -32,25 +32,26 @@ export default function useLink(editor: Ref): UsableLink { newTab: true, }; const linkSelection = ref(defaultLinkSelection); + const linkNode = ref(null); + const currentSelectionNode = ref(null); const linkButton = { icon: 'link', tooltip: i18n.global.t('wysiwyg_options.link'), - onAction: (buttonApi: any) => { + onAction: () => { if (editor.value.plugins.fullscreen.isFullscreen()) { editor.value.execCommand('mceFullScreen'); } linkDrawerOpen.value = true; - if (buttonApi.isActive()) { - const node = editor.value.selection.getNode() as HTMLLinkElement; - editor.value.selection.select(node); + if (linkNode.value) { + editor.value.selection.select(currentSelectionNode.value); - const url = node.getAttribute('href'); - const title = node.getAttribute('title'); - const displayText = node.innerText; - const target = node.getAttribute('target'); + const url = linkNode.value.getAttribute('href'); + const title = linkNode.value.getAttribute('title'); + const displayText = linkNode.value.innerText; + const target = linkNode.value.getAttribute('target'); if (url === null || displayText === null) { return; @@ -69,7 +70,20 @@ export default function useLink(editor: Ref): UsableLink { }, onSetup: (buttonApi: any) => { const onLinkNodeSelect = (eventApi: any) => { - buttonApi.setActive(eventApi.element.tagName === 'A'); + let element = eventApi.element; + currentSelectionNode.value = eventApi.element; + linkNode.value = null; + + while (element && element.id !== 'tinymce') { + if (element.tagName === 'A') { + linkNode.value = element; + break; + } + + element = element.parentElement; + } + + buttonApi.setActive(!!linkNode.value); }; editor.value.on('NodeChange', onLinkNodeSelect); @@ -98,7 +112,21 @@ export default function useLink(editor: Ref): UsableLink { link.displayText || link.url }`; - editor.value.selection.setContent(linkHtml); + // New anchor tag or current selection node is an anchor tag + if (!linkNode.value || currentSelectionNode.value === linkNode.value) { + editor.value.selection.setContent(linkHtml); + } + // Parent node is an anchor tag + else if (currentSelectionNode.value) { + currentSelectionNode.value.innerHTML = link.displayText || link.url; + linkNode.value.setAttribute('data-mce-href', link.url); // Required for tinymce to update changes + linkNode.value.setAttribute('href', link.url); + linkNode.value.setAttribute('title', link.title || ''); + linkNode.value.setAttribute('target', link.newTab ? '_blank' : '_self'); + editor.value.selection.select(linkNode.value); + editor.value.selection.setNode(linkNode.value); + } + closeLinkDrawer(); } }