diff --git a/docs/src/demos/Extensions/Image/index.vue b/docs/src/demos/Extensions/Image/index.vue index 52615a3b..f390a7ac 100644 --- a/docs/src/demos/Extensions/Image/index.vue +++ b/docs/src/demos/Extensions/Image/index.vue @@ -1,5 +1,8 @@ @@ -23,6 +26,14 @@ export default { } }, + methods: { + addImage() { + const url = window.prompt('URL') + + this.editor.chain().focus().image({ src: url }).run() + }, + }, + mounted() { this.editor = new Editor({ extensions: [ @@ -33,7 +44,7 @@ export default { ], content: `

This is basic example of implementing images. Try to drop new images here. Reordering also works.

- + `, }) }, diff --git a/docs/src/layouts/App/base.scss b/docs/src/layouts/App/base.scss index 95b824ad..2efeb9e1 100644 --- a/docs/src/layouts/App/base.scss +++ b/docs/src/layouts/App/base.scss @@ -109,6 +109,11 @@ code { } } + img { + max-width: 100%; + height: auto; + } + hr { margin: 1rem 0; } diff --git a/packages/extension-image/index.ts b/packages/extension-image/index.ts index 605a4b52..424cffc5 100644 --- a/packages/extension-image/index.ts +++ b/packages/extension-image/index.ts @@ -1,7 +1,6 @@ import { Command, createNode, nodeInputRule } from '@tiptap/core' -import { Plugin } from 'prosemirror-state' -const IMAGE_INPUT_REGEX = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/ +export const inputRegex = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/ const Image = createNode({ name: 'image', @@ -10,6 +9,8 @@ const Image = createNode({ group: 'inline', + draggable: true, + addAttributes() { return { src: { @@ -38,13 +39,11 @@ const Image = createNode({ addCommands() { return { - image: (attrs: any): Command => ({ tr }) => { + image: (options: { src: string, alt?: string, title?: string }): Command => ({ tr }) => { const { selection } = tr - console.log({ selection }) - // const position = selection.$cursor ? selection.$cursor.pos : selection.$to.pos - const position = selection.$anchor ? selection.$anchor.pos : selection.$to.pos - const node = this.type.create(attrs) - tr.insert(position, node) + const node = this.type.create(options) + + tr.replaceRangeWith(selection.from, selection.to, node) return true }, @@ -53,64 +52,10 @@ const Image = createNode({ addInputRules() { return [ - nodeInputRule(IMAGE_INPUT_REGEX, this.type, match => { + nodeInputRule(inputRegex, this.type, match => { const [, alt, src, title] = match - return { - src, - alt, - title, - } - }), - ] - }, - addProseMirrorPlugins() { - return [ - new Plugin({ - props: { - handleDOMEvents: { - drop(view, event) { - const hasFiles = event.dataTransfer - && event.dataTransfer.files - && event.dataTransfer.files.length - - if (!hasFiles) { - return false - } - - const images = Array - // @ts-ignore - .from(event.dataTransfer.files) - .filter(file => (/image/i).test(file.type)) - - if (images.length === 0) { - return false - } - - event.preventDefault() - - const { schema } = view.state - const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY }) - - images.forEach(image => { - const reader = new FileReader() - - reader.onload = readerEvent => { - const node = schema.nodes.image.create({ - // @ts-ignore - src: readerEvent.target.result, - }) - // @ts-ignore - const transaction = view.state.tr.insert(coordinates.pos, node) - view.dispatch(transaction) - } - reader.readAsDataURL(image) - }) - - return true - }, - }, - }, + return { src, alt, title } }), ] },