@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.
Files changed (181) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +5 -1
  3. package/dist/index.cjs +410 -319
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/{packages/extension-link/src/link.d.ts → index.d.cts} +57 -7
  6. package/dist/index.d.ts +149 -0
  7. package/dist/index.js +383 -315
  8. package/dist/index.js.map +1 -1
  9. package/package.json +14 -12
  10. package/src/helpers/autolink.ts +19 -31
  11. package/src/helpers/clickHandler.ts +25 -9
  12. package/src/helpers/pasteHandler.ts +6 -6
  13. package/src/helpers/whitespace.ts +7 -0
  14. package/src/link.ts +195 -47
  15. package/dist/index.umd.js +0 -344
  16. package/dist/index.umd.js.map +0 -1
  17. package/dist/packages/core/src/CommandManager.d.ts +0 -20
  18. package/dist/packages/core/src/Editor.d.ts +0 -161
  19. package/dist/packages/core/src/EventEmitter.d.ts +0 -11
  20. package/dist/packages/core/src/Extension.d.ts +0 -343
  21. package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
  22. package/dist/packages/core/src/InputRule.d.ts +0 -42
  23. package/dist/packages/core/src/Mark.d.ts +0 -451
  24. package/dist/packages/core/src/Node.d.ts +0 -611
  25. package/dist/packages/core/src/NodePos.d.ts +0 -44
  26. package/dist/packages/core/src/NodeView.d.ts +0 -31
  27. package/dist/packages/core/src/PasteRule.d.ts +0 -50
  28. package/dist/packages/core/src/Tracker.d.ts +0 -11
  29. package/dist/packages/core/src/commands/blur.d.ts +0 -13
  30. package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
  31. package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
  32. package/dist/packages/core/src/commands/command.d.ts +0 -18
  33. package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
  34. package/dist/packages/core/src/commands/cut.d.ts +0 -20
  35. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
  36. package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
  37. package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
  38. package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
  39. package/dist/packages/core/src/commands/enter.d.ts +0 -13
  40. package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
  41. package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
  42. package/dist/packages/core/src/commands/first.d.ts +0 -14
  43. package/dist/packages/core/src/commands/focus.d.ts +0 -27
  44. package/dist/packages/core/src/commands/forEach.d.ts +0 -14
  45. package/dist/packages/core/src/commands/index.d.ts +0 -55
  46. package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
  47. package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
  48. package/dist/packages/core/src/commands/join.d.ts +0 -41
  49. package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
  50. package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
  51. package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
  52. package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
  53. package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
  54. package/dist/packages/core/src/commands/lift.d.ts +0 -17
  55. package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
  56. package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
  57. package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
  58. package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
  59. package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
  60. package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
  61. package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
  62. package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
  63. package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
  64. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
  65. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
  66. package/dist/packages/core/src/commands/setContent.d.ts +0 -40
  67. package/dist/packages/core/src/commands/setMark.d.ts +0 -15
  68. package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
  69. package/dist/packages/core/src/commands/setNode.d.ts +0 -16
  70. package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
  71. package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
  72. package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
  73. package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
  74. package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
  75. package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
  76. package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
  77. package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
  78. package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
  79. package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
  80. package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
  81. package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
  82. package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
  83. package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
  84. package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
  85. package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
  86. package/dist/packages/core/src/extensions/commands.d.ts +0 -3
  87. package/dist/packages/core/src/extensions/editable.d.ts +0 -2
  88. package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
  89. package/dist/packages/core/src/extensions/index.d.ts +0 -6
  90. package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
  91. package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
  92. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
  93. package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
  94. package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
  95. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
  96. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
  97. package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
  98. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
  99. package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
  100. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
  101. package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
  102. package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
  103. package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
  104. package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
  105. package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
  106. package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
  107. package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
  108. package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
  109. package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
  110. package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
  111. package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
  112. package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
  113. package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
  114. package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
  115. package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
  116. package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
  117. package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
  118. package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
  119. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
  120. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
  121. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
  122. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
  123. package/dist/packages/core/src/helpers/getText.d.ts +0 -15
  124. package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
  125. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
  126. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
  127. package/dist/packages/core/src/helpers/index.d.ts +0 -50
  128. package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
  129. package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
  130. package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
  131. package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
  132. package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
  133. package/dist/packages/core/src/helpers/isList.d.ts +0 -2
  134. package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
  135. package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
  136. package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -2
  137. package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
  138. package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
  139. package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
  140. package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
  141. package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
  142. package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
  143. package/dist/packages/core/src/index.d.ts +0 -24
  144. package/dist/packages/core/src/inputRules/index.d.ts +0 -5
  145. package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
  146. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
  147. package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
  148. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
  149. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
  150. package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
  151. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
  152. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
  153. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
  154. package/dist/packages/core/src/style.d.ts +0 -1
  155. package/dist/packages/core/src/types.d.ts +0 -255
  156. package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
  157. package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
  158. package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
  159. package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
  160. package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
  161. package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
  162. package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
  163. package/dist/packages/core/src/utilities/index.d.ts +0 -20
  164. package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
  165. package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
  166. package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
  167. package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
  168. package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
  169. package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
  170. package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
  171. package/dist/packages/core/src/utilities/isString.d.ts +0 -1
  172. package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
  173. package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
  174. package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
  175. package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
  176. package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
  177. package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
  178. package/dist/packages/extension-link/src/helpers/autolink.d.ts +0 -14
  179. package/dist/packages/extension-link/src/helpers/clickHandler.d.ts +0 -7
  180. package/dist/packages/extension-link/src/helpers/pasteHandler.d.ts +0 -10
  181. package/dist/packages/extension-link/src/index.d.ts +0 -3
package/src/link.ts CHANGED
@@ -1,12 +1,12 @@
1
- import {
2
- Mark, markPasteRule, mergeAttributes, PasteRuleMatch,
3
- } from '@tiptap/core'
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 = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)(?:[-a-zA-Z0-9@:%._+~#=?!&/]*)/gi
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: { href: string; target?: string | null; rel?: string | null; class?: string | null }) => ReturnType
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: { href: string; target?: string | null; rel?: string | null; class?: string | null }) => ReturnType
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
- // From DOMPurify
104
- // https://github.com/cure53/DOMPurify/blob/main/src/regexp.js
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
- function isAllowedUri(uri: string | undefined) {
109
- return !uri || uri.replace(ATTR_WHITESPACE, '').match(IS_ALLOWED_URI)
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
- tag: 'a[href]',
179
- getAttrs: dom => {
180
- const href = (dom as HTMLElement).getAttribute('href')
181
-
182
- // prevent XSS attacks
183
- if (!href || !isAllowedUri(href)) {
184
- return false
185
- }
186
- return { href }
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 (!isAllowedUri(HTMLAttributes.href)) {
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 => ({ chain }) => {
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 => ({ chain }) => {
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
- () => ({ chain }) => {
218
- return chain()
219
- .unsetMark(this.name, { extendEmptyMarkRange: true })
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 { validate } = this.options
234
- const links = find(text).filter(item => item.isLink && validate(item.value))
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 => (foundLinks.push({
238
- text: link.value,
239
- data: {
240
- href: link.href,
241
- },
242
- index: link.start,
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: this.options.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
  }