One Image Per Paragraph

I’d like to limit a paragraph to have at most one image (in our schema this is an ‘embed’). Can this be done? I don’t understand how to write the paragraph valid content expression that does it.

I’ve tried variations such as:

inline* embed? inline* (while removing embed from the inline group)

This gives me an error that says Possibly ambiguous overlapping adjacent content expressions

This is the schema right now:

	nodes: {
		doc: {type: Doc, content: 'block+'},

		paragraph: {type: Paragraph, content: 'inline<_>*', group: 'block'},
		blockquote: {type: BlockQuote, content: 'block+', group: 'block'},
		ordered_list: {type: OrderedList, content: 'list_item+', group: 'block'},
		bullet_list: {type: BulletList, content: 'list_item+', group: 'block'},
		horizontal_rule: {type: HorizontalRule, group: 'block'},
		page_break: {type: PageBreak, group: 'block'},
		heading: {type: Heading, content: 'inline<_>*', group: 'block'},
		code_block: {type: CodeBlock, content: 'text*', group: 'block'},

		list_item: {type: ListItem, content: 'paragraph block*'},
	text: {type: Text, group: 'inline'},
	emoji: {type: Emoji, group: 'inline'},
		embed: {type: Embed, group: 'inline'},

That can’t be expressed by a ProseMirror schema. It also seems an odd constraint. Are you trying to model something else, like block images with a caption?

1 Like

Yes! Though I have to two things I want to accomplish.

First, I want to avoid cases in which two images (being floated for example) affect each other. For example, in Medium you can only have 1 picture on a line. If you move your mouse to a line which has a picture somewhere on it, there is no plus button:

Captions are the second, right now the code looks like

class BlockEmbed extends Block {
	get matchDOMTag() { return {'.block-embed': null}; }
	toDOM() { return ['div', {class: 'block-embed'}, 0]; }
exports.Block = BlockEmbed;

Embed also has attributes:

class Embed extends Inline {
	get attrs() {
		return {
			source: new Attribute,
			className: new Attribute({default: ''}),
			id: new Attribute({default: ''}),
      nodeId: new Attribute({default: null}),
			align: new Attribute({default: 'full'}),
			size: new Attribute({default: ''}),
			mode: new Attribute({default: 'embed'}), // mode = embed || cite
			data: new Attribute({default: {}}),
			selected: new Attribute({default: false}),
      figureName: new Attribute({default: {}}),

block_embed: {type: BlockEmbed, content: 'embed text*', group: 'block'},

I’m not sure how to use the content hole to pass in all the attributes that ‘embed’ needs while allowing a text field that is editable.

Why don’t you model these as separate block elements that sit between the textblocks?