diff --git a/demos/src/Marks/Link/React/index.jsx b/demos/src/Marks/Link/React/index.jsx index b5593cc3d..39c6d2df0 100644 --- a/demos/src/Marks/Link/React/index.jsx +++ b/demos/src/Marks/Link/React/index.jsx @@ -20,6 +20,7 @@ export default () => { Link.configure({ openOnClick: false, autolink: true, + defaultProtocol: 'https', }), ], content: ` diff --git a/demos/src/Marks/Link/React/index.spec.js b/demos/src/Marks/Link/React/index.spec.js index 21418b58b..b182ab861 100644 --- a/demos/src/Marks/Link/React/index.spec.js +++ b/demos/src/Marks/Link/React/index.spec.js @@ -62,6 +62,16 @@ context('/src/Marks/Link/React/', () => { .should('have.attr', 'href', 'https://tiptap4u.com') }) + it('uses the default protocol', () => { + cy.get('.tiptap').type('example.com ').find('a').should('contain', 'example.com') + .should('have.attr', 'href', 'https://example.com') + }) + + it('uses a non-default protocol if present', () => { + cy.get('.tiptap').type('http://example.com ').find('a').should('contain', 'http://example.com') + .should('have.attr', 'href', 'http://example.com') + }) + it('detects a pasted URL within a text', () => { cy.get('.tiptap') .paste({ diff --git a/demos/src/Marks/Link/Vue/index.spec.js b/demos/src/Marks/Link/Vue/index.spec.js index d659f6cde..34d1eced9 100644 --- a/demos/src/Marks/Link/Vue/index.spec.js +++ b/demos/src/Marks/Link/Vue/index.spec.js @@ -73,6 +73,16 @@ context('/src/Marks/Link/Vue/', () => { .should('have.attr', 'href', 'https://tiptap4u.com') }) + it('uses the default protocol', () => { + cy.get('.tiptap').type('example.com ').find('a').should('contain', 'example.com') + .should('have.attr', 'href', 'https://example.com') + }) + + it('uses a non-default protocol if present', () => { + cy.get('.tiptap').type('http://example.com ').find('a').should('contain', 'http://example.com') + .should('have.attr', 'href', 'http://example.com') + }) + it('detects a pasted URL with query params', () => { cy.get('.tiptap') .type('{backspace}') diff --git a/demos/src/Marks/Link/Vue/index.vue b/demos/src/Marks/Link/Vue/index.vue index dc9bada81..7771ca823 100644 --- a/demos/src/Marks/Link/Vue/index.vue +++ b/demos/src/Marks/Link/Vue/index.vue @@ -38,6 +38,7 @@ export default { Code, Link.configure({ openOnClick: false, + defaultProtocol: 'https', }), ], content: ` diff --git a/docs/api/marks/link.md b/docs/api/marks/link.md index 8f550351f..adba65e5b 100644 --- a/docs/api/marks/link.md +++ b/docs/api/marks/link.md @@ -76,6 +76,20 @@ Link.configure({ }) ``` + +### default protocol +The default protocol used by `linkOnPaste` and `autolink` when no protocol is defined. + +By default, the href generated for example.com is http://example.com and this option allows that protocol to be customized. + +Default: `http` + +```js +Link.configure({ + defaultProtocol: 'https', +}) +``` + ### HTMLAttributes Custom HTML attributes that should be added to the rendered HTML tag. diff --git a/packages/extension-link/src/helpers/autolink.ts b/packages/extension-link/src/helpers/autolink.ts index bb38f92b8..c15efa9a1 100644 --- a/packages/extension-link/src/helpers/autolink.ts +++ b/packages/extension-link/src/helpers/autolink.ts @@ -33,6 +33,7 @@ function isValidLinkStructure(tokens: Array>) type AutolinkOptions = { type: MarkType + defaultProtocol: string validate: (url: string) => boolean } @@ -115,7 +116,7 @@ export function autolink(options: AutolinkOptions): Plugin { return false } - const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t => t.toObject()) + const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(t => t.toObject(options.defaultProtocol)) if (!isValidLinkStructure(linksBeforeSpace)) { return false diff --git a/packages/extension-link/src/helpers/pasteHandler.ts b/packages/extension-link/src/helpers/pasteHandler.ts index ed03e6903..a93541ee9 100644 --- a/packages/extension-link/src/helpers/pasteHandler.ts +++ b/packages/extension-link/src/helpers/pasteHandler.ts @@ -5,6 +5,7 @@ import { find } from 'linkifyjs' type PasteHandlerOptions = { editor: Editor + defaultProtocol: string type: MarkType } @@ -27,7 +28,7 @@ export function pasteHandler(options: PasteHandlerOptions): Plugin { textContent += node.textContent }) - const link = find(textContent).find(item => item.isLink && item.value === textContent) + const link = find(textContent, { defaultProtocol: options.defaultProtocol }).find(item => item.isLink && item.value === textContent) if (!textContent || !link) { return false diff --git a/packages/extension-link/src/link.ts b/packages/extension-link/src/link.ts index 610173e28..8e90993fa 100644 --- a/packages/extension-link/src/link.ts +++ b/packages/extension-link/src/link.ts @@ -42,6 +42,11 @@ export interface LinkOptions { */ protocols: Array + /** + * Default protocol to use when no protocol is specified. + * @default 'http' + */ + defaultProtocol: string /** * If enabled, links will be opened on click. * @default true @@ -139,6 +144,7 @@ export const Link = Mark.create({ linkOnPaste: true, autolink: true, protocols: [], + defaultProtocol: 'http', HTMLAttributes: { target: '_blank', rel: 'noopener noreferrer nofollow', @@ -255,6 +261,7 @@ export const Link = Mark.create({ plugins.push( autolink({ type: this.type, + defaultProtocol: this.options.defaultProtocol, validate: this.options.validate, }), ) @@ -272,6 +279,7 @@ export const Link = Mark.create({ plugins.push( pasteHandler({ editor: this.editor, + defaultProtocol: this.options.defaultProtocol, type: this.type, }), )