mirror of https://github.com/halo-dev/halo
pref: optimize the rich text editor link paste logic (#5680)
#### What type of PR is this? /kind improvement /area editor /area ui /milestone 2.15.x #### What this PR does / why we need it: 优化默认富文本编辑器中自动创建链接的逻辑。 - 移除了粘贴文本时,如果文本为链接则会自动转为链接的问题。 - 移除输入链接文本之后回车,会自动转化为链接的问题。 - 新增当选中的文本内容为链接时,点击链接按钮,将会自动转化选中的文本为链接。 #### How to test it? 在富文本编辑器中,测试如下场景: 1. 在浏览器地址栏复制一个链接,粘贴后不会再转为链接,而是一个普通文本。 2. 输入一段链接文本,按回车后是否不会再被转为链接。 3. 选中一段可以被解析为链接的地址,选中此地址,点击链接按钮,此地址是否会被默认转为链接。 #### Which issue(s) this PR fixes: Fixes #5653 #### Does this PR introduce a user-facing change? ```release-note 优化默认富文本编辑器中文本自动转为链接的相关逻辑 ```pull/5698/head
parent
37f530b619
commit
505f38a145
|
@ -82,12 +82,14 @@
|
|||
"floating-vue": "2.0.0-beta.24",
|
||||
"github-markdown-css": "^5.2.0",
|
||||
"highlight.js": "11.8.0",
|
||||
"linkifyjs": "^4.1.3",
|
||||
"lowlight": "^3.0.0",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"tippy.js": "^6.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.117",
|
||||
"@types/linkifyjs": "^2.1.7",
|
||||
"release-it": "^16.1.5",
|
||||
"vite-plugin-dts": "^3.7.3"
|
||||
},
|
||||
|
|
|
@ -3,7 +3,9 @@ import { computed, type Component } from "vue";
|
|||
import { VTooltip, Dropdown as VDropdown } from "floating-vue";
|
||||
import MdiLinkVariant from "~icons/mdi/link-variant";
|
||||
import { i18n } from "@/locales";
|
||||
import type { Editor } from "@/tiptap/vue-3";
|
||||
import { type Editor } from "@/tiptap/vue-3";
|
||||
import { test } from "linkifyjs";
|
||||
import { TextSelection } from "@tiptap/pm/state";
|
||||
|
||||
const props = defineProps<{
|
||||
editor: Editor;
|
||||
|
@ -39,10 +41,44 @@ const target = computed({
|
|||
});
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Convert the currently selected text when clicking the link
|
||||
*/
|
||||
const handleLinkBubbleButton = () => {
|
||||
if (props.isActive({ editor: props.editor })) {
|
||||
return;
|
||||
}
|
||||
const { state } = props.editor;
|
||||
const { selection } = state;
|
||||
const { empty } = selection;
|
||||
|
||||
if (selection instanceof TextSelection) {
|
||||
if (empty) {
|
||||
return false;
|
||||
}
|
||||
const { content } = selection.content();
|
||||
if (!content || content.childCount !== 1) {
|
||||
return false;
|
||||
}
|
||||
const text = content.firstChild?.textContent;
|
||||
if (text && test(text, "url")) {
|
||||
props.editor.commands.setLink({
|
||||
href: text,
|
||||
target: "_self",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VDropdown class="inline-flex" :triggers="['click']" :distance="10">
|
||||
<VDropdown
|
||||
class="inline-flex"
|
||||
:triggers="['click']"
|
||||
:distance="10"
|
||||
@click="handleLinkBubbleButton"
|
||||
>
|
||||
<button
|
||||
v-tooltip="
|
||||
isActive({ editor })
|
||||
|
|
|
@ -15,6 +15,11 @@ const Link = TiptapLink.extend<ExtensionOptions & LinkOptions>({
|
|||
};
|
||||
},
|
||||
|
||||
addPasteRules() {
|
||||
// Remove the function of pasted text parsing as a link
|
||||
return [];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
const href = HTMLAttributes.href;
|
||||
// False positive; we're explicitly checking for javascript: links to ignore them
|
||||
|
|
|
@ -568,6 +568,9 @@ importers:
|
|||
highlight.js:
|
||||
specifier: 11.8.0
|
||||
version: 11.8.0
|
||||
linkifyjs:
|
||||
specifier: ^4.1.3
|
||||
version: 4.1.3
|
||||
lowlight:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
|
@ -584,6 +587,9 @@ importers:
|
|||
'@iconify/json':
|
||||
specifier: ^2.2.117
|
||||
version: 2.2.147
|
||||
'@types/linkifyjs':
|
||||
specifier: ^2.1.7
|
||||
version: 2.1.7
|
||||
release-it:
|
||||
specifier: ^16.1.5
|
||||
version: 16.2.1(typescript@5.3.3)
|
||||
|
@ -5621,7 +5627,7 @@ packages:
|
|||
ts-dedent: 2.2.0
|
||||
type-fest: 2.19.0
|
||||
vue: 3.4.19(typescript@5.3.3)
|
||||
vue-component-type-helpers: 2.0.7
|
||||
vue-component-type-helpers: 2.0.11
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
@ -5919,7 +5925,7 @@ packages:
|
|||
dependencies:
|
||||
'@tiptap/core': 2.2.3(@tiptap/pm@2.2.3)
|
||||
'@tiptap/pm': 2.2.3
|
||||
linkifyjs: 4.1.1
|
||||
linkifyjs: 4.1.3
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-list-item@2.2.3(@tiptap/core@2.2.3):
|
||||
|
@ -6321,6 +6327,12 @@ packages:
|
|||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||
dev: true
|
||||
|
||||
/@types/linkifyjs@2.1.7:
|
||||
resolution: {integrity: sha512-+SIYXs1lajyD7t/2+V9GLfdFlc/6Nr2tr65kjA2F5oOzBlPH+NiPqySJDHzREoGcL91Au9Qef8M5JdZiRXsaJw==}
|
||||
dependencies:
|
||||
'@types/react': 18.2.41
|
||||
dev: true
|
||||
|
||||
/@types/lodash-es@4.17.12:
|
||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
||||
dependencies:
|
||||
|
@ -8577,6 +8589,7 @@ packages:
|
|||
|
||||
/commander@2.20.3:
|
||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
/commander@4.1.1:
|
||||
|
@ -12623,8 +12636,8 @@ packages:
|
|||
uc.micro: 2.0.0
|
||||
dev: false
|
||||
|
||||
/linkifyjs@4.1.1:
|
||||
resolution: {integrity: sha512-zFN/CTVmbcVef+WaDXT63dNzzkfRBKT1j464NJQkV7iSgJU0sLBus9W0HBwnXK13/hf168pbrx/V/bjEHOXNHA==}
|
||||
/linkifyjs@4.1.3:
|
||||
resolution: {integrity: sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==}
|
||||
dev: false
|
||||
|
||||
/lint-staged@13.2.2:
|
||||
|
@ -17591,8 +17604,8 @@ packages:
|
|||
resolution: {integrity: sha512-0vOfAtI67UjeO1G6UiX5Kd76CqaQ67wrRZiOe7UAb9Jm6GzlUr/fC7CV90XfwapJRjpCMaZFhv1V0ajWRmE9Dg==}
|
||||
dev: true
|
||||
|
||||
/vue-component-type-helpers@2.0.7:
|
||||
resolution: {integrity: sha512-7e12Evdll7JcTIocojgnCgwocX4WzIYStGClBQ+QuWPinZo/vQolv2EMq4a3lg16TKfwWafLimG77bxb56UauA==}
|
||||
/vue-component-type-helpers@2.0.11:
|
||||
resolution: {integrity: sha512-8aluKz5oVC8PvVQAYgyIefOlqzKVmAOTCx2imbrFBVLbF7mnJvyMsE2A7rqX/4f4uT6ee9o8u3GcoRpUWc0xsw==}
|
||||
dev: true
|
||||
|
||||
/vue-demi@0.13.11(vue@3.4.19):
|
||||
|
|
|
@ -243,7 +243,7 @@ onMounted(() => {
|
|||
}),
|
||||
ExtensionTaskList,
|
||||
ExtensionLink.configure({
|
||||
autolink: true,
|
||||
autolink: false,
|
||||
openOnClick: false,
|
||||
}),
|
||||
ExtensionTextAlign.configure({
|
||||
|
|
Loading…
Reference in New Issue