@tiptap/extension-link 3.0.0 → 3.0.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +5 -1
- package/dist/index.cjs +410 -319
- package/dist/index.cjs.map +1 -1
- package/dist/{packages/extension-link/src/link.d.ts → index.d.cts} +57 -7
- package/dist/index.d.ts +149 -0
- package/dist/index.js +383 -315
- package/dist/index.js.map +1 -1
- package/package.json +14 -12
- package/src/helpers/autolink.ts +19 -31
- package/src/helpers/clickHandler.ts +25 -9
- package/src/helpers/pasteHandler.ts +6 -6
- package/src/helpers/whitespace.ts +7 -0
- package/src/link.ts +195 -47
- package/dist/index.umd.js +0 -344
- package/dist/index.umd.js.map +0 -1
- package/dist/packages/core/src/CommandManager.d.ts +0 -20
- package/dist/packages/core/src/Editor.d.ts +0 -161
- package/dist/packages/core/src/EventEmitter.d.ts +0 -11
- package/dist/packages/core/src/Extension.d.ts +0 -343
- package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
- package/dist/packages/core/src/InputRule.d.ts +0 -42
- package/dist/packages/core/src/Mark.d.ts +0 -451
- package/dist/packages/core/src/Node.d.ts +0 -611
- package/dist/packages/core/src/NodePos.d.ts +0 -44
- package/dist/packages/core/src/NodeView.d.ts +0 -31
- package/dist/packages/core/src/PasteRule.d.ts +0 -50
- package/dist/packages/core/src/Tracker.d.ts +0 -11
- package/dist/packages/core/src/commands/blur.d.ts +0 -13
- package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
- package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
- package/dist/packages/core/src/commands/command.d.ts +0 -18
- package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
- package/dist/packages/core/src/commands/cut.d.ts +0 -20
- package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
- package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
- package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
- package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
- package/dist/packages/core/src/commands/enter.d.ts +0 -13
- package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
- package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
- package/dist/packages/core/src/commands/first.d.ts +0 -14
- package/dist/packages/core/src/commands/focus.d.ts +0 -27
- package/dist/packages/core/src/commands/forEach.d.ts +0 -14
- package/dist/packages/core/src/commands/index.d.ts +0 -55
- package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
- package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
- package/dist/packages/core/src/commands/join.d.ts +0 -41
- package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
- package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
- package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
- package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
- package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
- package/dist/packages/core/src/commands/lift.d.ts +0 -17
- package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
- package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
- package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
- package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
- package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
- package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
- package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
- package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
- package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
- package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
- package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
- package/dist/packages/core/src/commands/setContent.d.ts +0 -40
- package/dist/packages/core/src/commands/setMark.d.ts +0 -15
- package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
- package/dist/packages/core/src/commands/setNode.d.ts +0 -16
- package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
- package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
- package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
- package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
- package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
- package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
- package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
- package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
- package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
- package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
- package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
- package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
- package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
- package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
- package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
- package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
- package/dist/packages/core/src/extensions/commands.d.ts +0 -3
- package/dist/packages/core/src/extensions/editable.d.ts +0 -2
- package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
- package/dist/packages/core/src/extensions/index.d.ts +0 -6
- package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
- package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
- package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
- package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
- package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
- package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
- package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
- package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
- package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
- package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
- package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
- package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
- package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
- package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
- package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
- package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
- package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
- package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
- package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
- package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
- package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
- package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
- package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
- package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
- package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
- package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
- package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
- package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
- package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
- package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
- package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
- package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
- package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
- package/dist/packages/core/src/helpers/getText.d.ts +0 -15
- package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
- package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
- package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
- package/dist/packages/core/src/helpers/index.d.ts +0 -50
- package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
- package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
- package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
- package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
- package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
- package/dist/packages/core/src/helpers/isList.d.ts +0 -2
- package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
- package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
- package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -2
- package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
- package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
- package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
- package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
- package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
- package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
- package/dist/packages/core/src/index.d.ts +0 -24
- package/dist/packages/core/src/inputRules/index.d.ts +0 -5
- package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
- package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
- package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
- package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
- package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
- package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
- package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
- package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
- package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
- package/dist/packages/core/src/style.d.ts +0 -1
- package/dist/packages/core/src/types.d.ts +0 -255
- package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
- package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
- package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
- package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
- package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
- package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
- package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
- package/dist/packages/core/src/utilities/index.d.ts +0 -20
- package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
- package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
- package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
- package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
- package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
- package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
- package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
- package/dist/packages/core/src/utilities/isString.d.ts +0 -1
- package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
- package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
- package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
- package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
- package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
- package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
- package/dist/packages/extension-link/src/helpers/autolink.d.ts +0 -14
- package/dist/packages/extension-link/src/helpers/clickHandler.d.ts +0 -7
- package/dist/packages/extension-link/src/helpers/pasteHandler.d.ts +0 -10
- package/dist/packages/extension-link/src/index.d.ts +0 -3
package/src/link.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from '@tiptap/
|
|
4
|
-
import { Plugin } from '@tiptap/pm/state'
|
|
1
|
+
import type { PasteRuleMatch } from '@tiptap/core'
|
|
2
|
+
import { Mark, markPasteRule, mergeAttributes } from '@tiptap/core'
|
|
3
|
+
import type { Plugin } from '@tiptap/pm/state'
|
|
5
4
|
import { find, registerCustomProtocol, reset } from 'linkifyjs'
|
|
6
5
|
|
|
7
6
|
import { autolink } from './helpers/autolink.js'
|
|
8
7
|
import { clickHandler } from './helpers/clickHandler.js'
|
|
9
8
|
import { pasteHandler } from './helpers/pasteHandler.js'
|
|
9
|
+
import { UNICODE_WHITESPACE_REGEX_GLOBAL } from './helpers/whitespace.js'
|
|
10
10
|
|
|
11
11
|
export interface LinkProtocolOptions {
|
|
12
12
|
/**
|
|
@@ -15,17 +15,23 @@ export interface LinkProtocolOptions {
|
|
|
15
15
|
* @example 'ftp'
|
|
16
16
|
* @example 'git'
|
|
17
17
|
*/
|
|
18
|
-
scheme: string
|
|
18
|
+
scheme: string
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* If enabled, it allows optional slashes after the protocol.
|
|
22
22
|
* @default false
|
|
23
23
|
* @example true
|
|
24
24
|
*/
|
|
25
|
-
optionalSlashes?: boolean
|
|
25
|
+
optionalSlashes?: boolean
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export const pasteRegex =
|
|
28
|
+
export const pasteRegex =
|
|
29
|
+
/https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated The default behavior is now to open links when the editor is not editable.
|
|
33
|
+
*/
|
|
34
|
+
type DeprecatedOpenWhenNotEditable = 'whenNotEditable'
|
|
29
35
|
|
|
30
36
|
export interface LinkOptions {
|
|
31
37
|
/**
|
|
@@ -51,9 +57,14 @@ export interface LinkOptions {
|
|
|
51
57
|
* If enabled, links will be opened on click.
|
|
52
58
|
* @default true
|
|
53
59
|
* @example false
|
|
54
|
-
* @example 'whenNotEditable'
|
|
55
60
|
*/
|
|
56
|
-
openOnClick: boolean
|
|
61
|
+
openOnClick: boolean | DeprecatedOpenWhenNotEditable
|
|
62
|
+
/**
|
|
63
|
+
* If enabled, the link will be selected when clicked.
|
|
64
|
+
* @default false
|
|
65
|
+
* @example true
|
|
66
|
+
*/
|
|
67
|
+
enableClickSelection: boolean
|
|
57
68
|
/**
|
|
58
69
|
* Adds a link to the current selection if the pasted content only contains an url.
|
|
59
70
|
* @default true
|
|
@@ -69,11 +80,52 @@ export interface LinkOptions {
|
|
|
69
80
|
HTMLAttributes: Record<string, any>
|
|
70
81
|
|
|
71
82
|
/**
|
|
83
|
+
* @deprecated Use the `shouldAutoLink` option instead.
|
|
72
84
|
* A validation function that modifies link verification for the auto linker.
|
|
73
85
|
* @param url - The url to be validated.
|
|
74
86
|
* @returns - True if the url is valid, false otherwise.
|
|
75
87
|
*/
|
|
76
88
|
validate: (url: string) => boolean
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* A validation function which is used for configuring link verification for preventing XSS attacks.
|
|
92
|
+
* Only modify this if you know what you're doing.
|
|
93
|
+
*
|
|
94
|
+
* @returns {boolean} `true` if the URL is valid, `false` otherwise.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* isAllowedUri: (url, { defaultValidate, protocols, defaultProtocol }) => {
|
|
98
|
+
* return url.startsWith('./') || defaultValidate(url)
|
|
99
|
+
* }
|
|
100
|
+
*/
|
|
101
|
+
isAllowedUri: (
|
|
102
|
+
/**
|
|
103
|
+
* The URL to be validated.
|
|
104
|
+
*/
|
|
105
|
+
url: string,
|
|
106
|
+
ctx: {
|
|
107
|
+
/**
|
|
108
|
+
* The default validation function.
|
|
109
|
+
*/
|
|
110
|
+
defaultValidate: (url: string) => boolean
|
|
111
|
+
/**
|
|
112
|
+
* An array of allowed protocols for the URL (e.g., "http", "https"). As defined in the `protocols` option.
|
|
113
|
+
*/
|
|
114
|
+
protocols: Array<LinkProtocolOptions | string>
|
|
115
|
+
/**
|
|
116
|
+
* A string that represents the default protocol (e.g., 'http'). As defined in the `defaultProtocol` option.
|
|
117
|
+
*/
|
|
118
|
+
defaultProtocol: string
|
|
119
|
+
},
|
|
120
|
+
) => boolean
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Determines whether a valid link should be automatically linked in the content.
|
|
124
|
+
*
|
|
125
|
+
* @param {string} url - The URL that has already been validated.
|
|
126
|
+
* @returns {boolean} - True if the link should be auto-linked; false if it should not be auto-linked.
|
|
127
|
+
*/
|
|
128
|
+
shouldAutoLink: (url: string) => boolean
|
|
77
129
|
}
|
|
78
130
|
|
|
79
131
|
declare module '@tiptap/core' {
|
|
@@ -84,13 +136,23 @@ declare module '@tiptap/core' {
|
|
|
84
136
|
* @param attributes The link attributes
|
|
85
137
|
* @example editor.commands.setLink({ href: 'https://tiptap.dev' })
|
|
86
138
|
*/
|
|
87
|
-
setLink: (attributes: {
|
|
139
|
+
setLink: (attributes: {
|
|
140
|
+
href: string
|
|
141
|
+
target?: string | null
|
|
142
|
+
rel?: string | null
|
|
143
|
+
class?: string | null
|
|
144
|
+
}) => ReturnType
|
|
88
145
|
/**
|
|
89
146
|
* Toggle a link mark
|
|
90
147
|
* @param attributes The link attributes
|
|
91
148
|
* @example editor.commands.toggleLink({ href: 'https://tiptap.dev' })
|
|
92
149
|
*/
|
|
93
|
-
toggleLink: (attributes
|
|
150
|
+
toggleLink: (attributes?: {
|
|
151
|
+
href: string
|
|
152
|
+
target?: string | null
|
|
153
|
+
rel?: string | null
|
|
154
|
+
class?: string | null
|
|
155
|
+
}) => ReturnType
|
|
94
156
|
/**
|
|
95
157
|
* Unset a link mark
|
|
96
158
|
* @example editor.commands.unsetLink()
|
|
@@ -100,13 +162,29 @@ declare module '@tiptap/core' {
|
|
|
100
162
|
}
|
|
101
163
|
}
|
|
102
164
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
106
|
-
const IS_ALLOWED_URI = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
165
|
+
export function isAllowedUri(uri: string | undefined, protocols?: LinkOptions['protocols']) {
|
|
166
|
+
const allowedProtocols: string[] = ['http', 'https', 'ftp', 'ftps', 'mailto', 'tel', 'callto', 'sms', 'cid', 'xmpp']
|
|
107
167
|
|
|
108
|
-
|
|
109
|
-
|
|
168
|
+
if (protocols) {
|
|
169
|
+
protocols.forEach(protocol => {
|
|
170
|
+
const nextProtocol = typeof protocol === 'string' ? protocol : protocol.scheme
|
|
171
|
+
|
|
172
|
+
if (nextProtocol) {
|
|
173
|
+
allowedProtocols.push(nextProtocol)
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
!uri ||
|
|
180
|
+
uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, '').match(
|
|
181
|
+
new RegExp(
|
|
182
|
+
// eslint-disable-next-line no-useless-escape
|
|
183
|
+
`^(?:(?:${allowedProtocols.join('|')}):|[^a-z]|[a-z0-9+.\-]+(?:[^a-z+.\-:]|$))`,
|
|
184
|
+
'i',
|
|
185
|
+
),
|
|
186
|
+
)
|
|
187
|
+
)
|
|
110
188
|
}
|
|
111
189
|
|
|
112
190
|
/**
|
|
@@ -123,6 +201,11 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
123
201
|
exitable: true,
|
|
124
202
|
|
|
125
203
|
onCreate() {
|
|
204
|
+
if (this.options.validate && !this.options.shouldAutoLink) {
|
|
205
|
+
// Copy the validate function to the shouldAutoLink option
|
|
206
|
+
this.options.shouldAutoLink = this.options.validate
|
|
207
|
+
console.warn('The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.')
|
|
208
|
+
}
|
|
126
209
|
this.options.protocols.forEach(protocol => {
|
|
127
210
|
if (typeof protocol === 'string') {
|
|
128
211
|
registerCustomProtocol(protocol)
|
|
@@ -143,6 +226,7 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
143
226
|
addOptions() {
|
|
144
227
|
return {
|
|
145
228
|
openOnClick: true,
|
|
229
|
+
enableClickSelection: false,
|
|
146
230
|
linkOnPaste: true,
|
|
147
231
|
autolink: true,
|
|
148
232
|
protocols: [],
|
|
@@ -152,7 +236,9 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
152
236
|
rel: 'noopener noreferrer nofollow',
|
|
153
237
|
class: null,
|
|
154
238
|
},
|
|
239
|
+
isAllowedUri: (url, ctx) => !!isAllowedUri(url, ctx.protocols),
|
|
155
240
|
validate: url => !!url,
|
|
241
|
+
shouldAutoLink: url => !!url,
|
|
156
242
|
}
|
|
157
243
|
},
|
|
158
244
|
|
|
@@ -160,6 +246,9 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
160
246
|
return {
|
|
161
247
|
href: {
|
|
162
248
|
default: null,
|
|
249
|
+
parseHTML(element) {
|
|
250
|
+
return element.getAttribute('href')
|
|
251
|
+
},
|
|
163
252
|
},
|
|
164
253
|
target: {
|
|
165
254
|
default: this.options.HTMLAttributes.target,
|
|
@@ -174,23 +263,38 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
174
263
|
},
|
|
175
264
|
|
|
176
265
|
parseHTML() {
|
|
177
|
-
return [
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
266
|
+
return [
|
|
267
|
+
{
|
|
268
|
+
tag: 'a[href]',
|
|
269
|
+
getAttrs: dom => {
|
|
270
|
+
const href = (dom as HTMLElement).getAttribute('href')
|
|
271
|
+
|
|
272
|
+
// prevent XSS attacks
|
|
273
|
+
if (
|
|
274
|
+
!href ||
|
|
275
|
+
!this.options.isAllowedUri(href, {
|
|
276
|
+
defaultValidate: url => !!isAllowedUri(url, this.options.protocols),
|
|
277
|
+
protocols: this.options.protocols,
|
|
278
|
+
defaultProtocol: this.options.defaultProtocol,
|
|
279
|
+
})
|
|
280
|
+
) {
|
|
281
|
+
return false
|
|
282
|
+
}
|
|
283
|
+
return null
|
|
284
|
+
},
|
|
187
285
|
},
|
|
188
|
-
|
|
286
|
+
]
|
|
189
287
|
},
|
|
190
288
|
|
|
191
289
|
renderHTML({ HTMLAttributes }) {
|
|
192
290
|
// prevent XSS attacks
|
|
193
|
-
if (
|
|
291
|
+
if (
|
|
292
|
+
!this.options.isAllowedUri(HTMLAttributes.href, {
|
|
293
|
+
defaultValidate: href => !!isAllowedUri(href, this.options.protocols),
|
|
294
|
+
protocols: this.options.protocols,
|
|
295
|
+
defaultProtocol: this.options.defaultProtocol,
|
|
296
|
+
})
|
|
297
|
+
) {
|
|
194
298
|
// strip out the href
|
|
195
299
|
return ['a', mergeAttributes(this.options.HTMLAttributes, { ...HTMLAttributes, href: '' }), 0]
|
|
196
300
|
}
|
|
@@ -201,12 +305,39 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
201
305
|
addCommands() {
|
|
202
306
|
return {
|
|
203
307
|
setLink:
|
|
204
|
-
attributes =>
|
|
308
|
+
attributes =>
|
|
309
|
+
({ chain }) => {
|
|
310
|
+
const { href } = attributes
|
|
311
|
+
|
|
312
|
+
if (
|
|
313
|
+
!this.options.isAllowedUri(href, {
|
|
314
|
+
defaultValidate: url => !!isAllowedUri(url, this.options.protocols),
|
|
315
|
+
protocols: this.options.protocols,
|
|
316
|
+
defaultProtocol: this.options.defaultProtocol,
|
|
317
|
+
})
|
|
318
|
+
) {
|
|
319
|
+
return false
|
|
320
|
+
}
|
|
321
|
+
|
|
205
322
|
return chain().setMark(this.name, attributes).setMeta('preventAutolink', true).run()
|
|
206
323
|
},
|
|
207
324
|
|
|
208
325
|
toggleLink:
|
|
209
|
-
attributes =>
|
|
326
|
+
attributes =>
|
|
327
|
+
({ chain }) => {
|
|
328
|
+
const { href } = attributes || {}
|
|
329
|
+
|
|
330
|
+
if (
|
|
331
|
+
href &&
|
|
332
|
+
!this.options.isAllowedUri(href, {
|
|
333
|
+
defaultValidate: url => !!isAllowedUri(url, this.options.protocols),
|
|
334
|
+
protocols: this.options.protocols,
|
|
335
|
+
defaultProtocol: this.options.defaultProtocol,
|
|
336
|
+
})
|
|
337
|
+
) {
|
|
338
|
+
return false
|
|
339
|
+
}
|
|
340
|
+
|
|
210
341
|
return chain()
|
|
211
342
|
.toggleMark(this.name, attributes, { extendEmptyMarkRange: true })
|
|
212
343
|
.setMeta('preventAutolink', true)
|
|
@@ -214,11 +345,9 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
214
345
|
},
|
|
215
346
|
|
|
216
347
|
unsetLink:
|
|
217
|
-
() =>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
.setMeta('preventAutolink', true)
|
|
221
|
-
.run()
|
|
348
|
+
() =>
|
|
349
|
+
({ chain }) => {
|
|
350
|
+
return chain().unsetMark(this.name, { extendEmptyMarkRange: true }).setMeta('preventAutolink', true).run()
|
|
222
351
|
},
|
|
223
352
|
}
|
|
224
353
|
},
|
|
@@ -230,17 +359,27 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
230
359
|
const foundLinks: PasteRuleMatch[] = []
|
|
231
360
|
|
|
232
361
|
if (text) {
|
|
233
|
-
const {
|
|
234
|
-
const links = find(text).filter(
|
|
362
|
+
const { protocols, defaultProtocol } = this.options
|
|
363
|
+
const links = find(text).filter(
|
|
364
|
+
item =>
|
|
365
|
+
item.isLink &&
|
|
366
|
+
this.options.isAllowedUri(item.value, {
|
|
367
|
+
defaultValidate: href => !!isAllowedUri(href, protocols),
|
|
368
|
+
protocols,
|
|
369
|
+
defaultProtocol,
|
|
370
|
+
}),
|
|
371
|
+
)
|
|
235
372
|
|
|
236
373
|
if (links.length) {
|
|
237
|
-
links.forEach(link =>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
374
|
+
links.forEach(link =>
|
|
375
|
+
foundLinks.push({
|
|
376
|
+
text: link.value,
|
|
377
|
+
data: {
|
|
378
|
+
href: link.href,
|
|
379
|
+
},
|
|
380
|
+
index: link.start,
|
|
381
|
+
}),
|
|
382
|
+
)
|
|
244
383
|
}
|
|
245
384
|
}
|
|
246
385
|
|
|
@@ -258,21 +397,30 @@ export const Link = Mark.create<LinkOptions>({
|
|
|
258
397
|
|
|
259
398
|
addProseMirrorPlugins() {
|
|
260
399
|
const plugins: Plugin[] = []
|
|
400
|
+
const { protocols, defaultProtocol } = this.options
|
|
261
401
|
|
|
262
402
|
if (this.options.autolink) {
|
|
263
403
|
plugins.push(
|
|
264
404
|
autolink({
|
|
265
405
|
type: this.type,
|
|
266
406
|
defaultProtocol: this.options.defaultProtocol,
|
|
267
|
-
validate:
|
|
407
|
+
validate: url =>
|
|
408
|
+
this.options.isAllowedUri(url, {
|
|
409
|
+
defaultValidate: href => !!isAllowedUri(href, protocols),
|
|
410
|
+
protocols,
|
|
411
|
+
defaultProtocol,
|
|
412
|
+
}),
|
|
413
|
+
shouldAutoLink: this.options.shouldAutoLink,
|
|
268
414
|
}),
|
|
269
415
|
)
|
|
270
416
|
}
|
|
271
417
|
|
|
272
|
-
if (this.options.openOnClick) {
|
|
418
|
+
if (this.options.openOnClick === true) {
|
|
273
419
|
plugins.push(
|
|
274
420
|
clickHandler({
|
|
275
421
|
type: this.type,
|
|
422
|
+
editor: this.editor,
|
|
423
|
+
enableClickSelection: this.options.enableClickSelection,
|
|
276
424
|
}),
|
|
277
425
|
)
|
|
278
426
|
}
|