51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
![]() |
import { Plugin } from 'prosemirror-state'
|
||
|
import type { DiscoursSchema } from '../schema'
|
||
|
|
||
|
const REGEX = /^!\[([^[\]]*?)]\((.+?)\)\s+/
|
||
|
const MAX_MATCH = 500
|
||
|
|
||
|
const isUrl = (str: string) => {
|
||
|
try {
|
||
|
const url = new URL(str)
|
||
|
return url.protocol === 'http:' || url.protocol === 'https:'
|
||
|
} catch {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const isBlank = (text: string) => text === ' ' || text === '\u00A0'
|
||
|
|
||
|
export const imageInput = (schema: DiscoursSchema) =>
|
||
|
new Plugin({
|
||
|
props: {
|
||
|
handleTextInput(view, from, to, text) {
|
||
|
if (view.composing || !isBlank(text)) return false
|
||
|
const $from = view.state.doc.resolve(from)
|
||
|
if ($from.parent.type.spec.code) return false
|
||
|
const textBefore =
|
||
|
$from.parent.textBetween(
|
||
|
Math.max(0, $from.parentOffset - MAX_MATCH),
|
||
|
$from.parentOffset,
|
||
|
null,
|
||
|
'\uFFFC'
|
||
|
) + text
|
||
|
|
||
|
const match = REGEX.exec(textBefore)
|
||
|
if (match) {
|
||
|
const [, title, src] = match
|
||
|
if (isUrl(src)) {
|
||
|
const node = schema.node('image', { src, title })
|
||
|
const start = from - (match[0].length - text.length)
|
||
|
const tr = view.state.tr
|
||
|
tr.delete(start, to)
|
||
|
tr.insert(start, node)
|
||
|
view.dispatch(tr)
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
})
|