Hi all,
I try to use prosemirror-inputrules with a custom schema that extends prosemirror-markdown ’s with an additional mark. It works just fine for marks, but my nodes (headings, blockquotes, etc.) aren’t replaced anymore. From what I see, the findWrapping()
function doesn’t return anything in prosemirror-inputrules ’s wrappingInputRule()
… Any idea why? Here’s how I created my schema:
import { Schema } from 'prosemirror-model'
import { schema, defaultMarkdownParser, defaultMarkdownSerializer } from 'prosemirror-markdown'
const newSchema = new Schema({
nodes: schema.nodeSpec,
marks: schema.markSpec.addToEnd('del', {
parseDOM: [{ tag: 'del' }],
toDOM() { return ['del'] }
})
})
Many thanks in advance!
marijn
December 23, 2016, 10:46am
2
Are you passing a node type from your schema when calling wrappingInputRule
?
@marijn Yes, I set up the prosemirror-inputrules plugin like this:
plugins: [
inputRules({ rules: allInputRules.concat(buildInputRules(newSchema)) })
]
const buildInputRules = (schema) => {
let result = [], type
if (type = schema.nodes.heading) result.push(headingRule(type, 6))
return result
}
…newSchema
being my custom schema that extends the one of prosemirror-markdown
marijn
December 25, 2016, 1:33pm
4
When I try the code you gave, the heading input rule works fine for me. Could you set up a full example?
Hey @marijn , thank you very much for replying on a Christmas day! Here is my full code:
import { Schema } from 'prosemirror-model'
import { EditorState } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
import { schema, defaultMarkdownParser, defaultMarkdownSerializer } from 'prosemirror-markdown'
import { InputRule, inputRules, allInputRules, headingRule, bulletListRule, orderedListRule, blockQuoteRule, codeBlockRule } from 'prosemirror-inputrules'
import { keymap } from 'prosemirror-keymap'
import { baseKeymap } from 'prosemirror-commands'
const newSchema = new Schema({
nodes: schema.nodeSpec,
marks: schema.markSpec.addToEnd('del', {
parseDOM: [{ tag: 'del' }],
toDOM() { return ['del'] }
})
})
const markInputRule = (regexp, markType, getAttrs) => {
const newRegexp = new RegExp(regexp.source.replace(/\$$/, '') + '(.)' + '$')
return new InputRule(newRegexp, (state, match, start, end) => {
const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs
const textStart = start + match[0].indexOf(match[1])
const textEnd = textStart + match[1].length
const tr = state.tr
start = (match[0].match(/^\s/)) ? start + 1 : start
if (textEnd < end) tr.delete(textEnd, end)
if (textStart > start) tr.delete(start, textStart)
end = start + match[1].length
return tr
.addMark(start, end, markType.create(attrs))
.insert(end, schema.text(match[2]))
})
}
const buildInputRules = (schema) => {
let result = [], type
if (type = schema.nodes.heading) result.push(headingRule(type, 6))
if (type = schema.nodes.bullet_list) result.push(bulletListRule(type))
if (type = schema.nodes.ordered_list) result.push(orderedListRule(type))
if (type = schema.nodes.blockquote) result.push(blockQuoteRule(type))
if (type = schema.nodes.code_block) result.push(codeBlockRule(type))
if (type = schema.marks.strong) result.push(markInputRule(/(?:\*\*|__)([^\*_]+)(?:\*\*|__)$/, type))
if (type = schema.marks.em) result.push(markInputRule(/(?:^|[^\*_])(?:\*|_)([^\*_]+)(?:\*|_)$/, type))
if (type = schema.marks.code) result.push(markInputRule(/(?:`)([^`]+)(?:`)$/, type))
if (type = schema.marks.del) result.push(markInputRule(/(?:~~)([^~]+)(?:~~)$/, type))
return result
}
const view = new EditorView(document.querySelector('#editor'), {
state: EditorState.create({
doc: defaultMarkdownParser.parse(document.querySelector('#content').textContent),
plugins: [
inputRules({ rules: allInputRules.concat(buildInputRules(newSchema)) }),
keymap(baseKeymap)
]
}),
onAction: action => view.updateState(view.state.applyAction(action))
})
Thank you again and Merry Christmas!
marijn
December 26, 2016, 9:03pm
6
I absolutely have my priorities wrong
Your problem is that defaultMarkdownParser
will return documents in the original markdown schema. You can do something like this to create a new parser for your schema:
const parser = new MarkdownParser(newSchema,
defaultMarkdownParser.tokenizer,
defaultMarkdownParser.tokens)
Many thanks @marijn , I’d never have thought about that myself! It works almost perfectly… The only problem is that this line (inside the markInputRule()
function) doesn’t insert the character anymore:
return tr
.addMark(start, end, markType.create(attrs))
.insert(end, schema.text(match[2]))
I don’t get why because schema.text(match[2])
seems to return the same object as before using the new parser…
marijn
December 27, 2016, 3:24pm
8
Are you sure you’re referring to your own schema with the schema
variable?
You’re absolutely right, sorry for taking your time for that! And thank you again for the help…
brecht
May 29, 2020, 8:35am
10
@davidgeilfus That markInputRule
function you wrote is pretty neat! Have you considered publishing it as a standalone module to NPM. Or maybe a PR for including it in the core prosemirror-inputrules
module, if @marijn is interested to merge it?