wwf
2025-05-20 938c3e5a587ce950a94964ea509b9e7f8834dfae
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {
  useCallback,
  useEffect,
} from 'react'
import { useTranslation } from 'react-i18next'
import {
  CLICK_COMMAND,
  COMMAND_PRIORITY_LOW,
} from 'lexical'
import {
  mergeRegister,
} from '@lexical/utils'
import {
  TOGGLE_LINK_COMMAND,
} from '@lexical/link'
import { escape } from 'lodash-es'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { useNoteEditorStore } from '../../store'
import { urlRegExp } from '../../utils'
import { useToastContext } from '@/app/components/base/toast'
 
export const useOpenLink = () => {
  const [editor] = useLexicalComposerContext()
  const noteEditorStore = useNoteEditorStore()
 
  useEffect(() => {
    return mergeRegister(
      editor.registerUpdateListener(() => {
        setTimeout(() => {
          const {
            selectedLinkUrl,
            selectedIsLink,
            setLinkAnchorElement,
            setLinkOperatorShow,
          } = noteEditorStore.getState()
 
          if (selectedIsLink) {
            setLinkAnchorElement(true)
 
            if (selectedLinkUrl)
              setLinkOperatorShow(true)
            else
              setLinkOperatorShow(false)
          }
          else {
            setLinkAnchorElement()
            setLinkOperatorShow(false)
          }
        })
      }),
      editor.registerCommand(
        CLICK_COMMAND,
        (payload) => {
          setTimeout(() => {
            const {
              selectedLinkUrl,
              selectedIsLink,
              setLinkAnchorElement,
              setLinkOperatorShow,
            } = noteEditorStore.getState()
 
            if (selectedIsLink) {
              if ((payload.metaKey || payload.ctrlKey) && selectedLinkUrl) {
                window.open(selectedLinkUrl, '_blank')
                return true
              }
              setLinkAnchorElement(true)
 
              if (selectedLinkUrl)
                setLinkOperatorShow(true)
              else
                setLinkOperatorShow(false)
            }
            else {
              setLinkAnchorElement()
              setLinkOperatorShow(false)
            }
          })
          return false
        },
        COMMAND_PRIORITY_LOW,
      ),
    )
  }, [editor, noteEditorStore])
}
 
export const useLink = () => {
  const { t } = useTranslation()
  const [editor] = useLexicalComposerContext()
  const noteEditorStore = useNoteEditorStore()
  const { notify } = useToastContext()
 
  const handleSaveLink = useCallback((url: string) => {
    if (url && !urlRegExp.test(url)) {
      notify({ type: 'error', message: t('workflow.nodes.note.editor.invalidUrl') })
      return
    }
    editor.dispatchCommand(TOGGLE_LINK_COMMAND, escape(url))
 
    const { setLinkAnchorElement } = noteEditorStore.getState()
    setLinkAnchorElement()
  }, [editor, noteEditorStore, notify, t])
 
  const handleUnlink = useCallback(() => {
    editor.dispatchCommand(TOGGLE_LINK_COMMAND, null)
 
    const { setLinkAnchorElement } = noteEditorStore.getState()
    setLinkAnchorElement()
  }, [editor, noteEditorStore])
 
  return {
    handleSaveLink,
    handleUnlink,
  }
}