Custom blot fails to be recognized as blockGroup in `converter.getGroupedOps()`
laukaichung opened this issue · 4 comments
Here's a custom image blot "imageBlock" that is an extension of BlockEmbed. This is not a replacement of the default "image" blot.
import React, { Component } from 'react';
import ReactQuill from 'react-quill';
// / Custom ImageBlot to add alt text to inline images / ///
const Quill = ReactQuill.Quill;
const BlockEmbed = Quill.import('blots/block/embed');
class ImageBlot extends BlockEmbed {
static create(value) {
const node = super.create();
node.setAttribute('alt', value.alt);
node.setAttribute('src', value.url);
return node;
}
static value(node) {
return {
alt: node.getAttribute('alt'),
url: node.getAttribute('src'),
};
}
}
ImageBlot.blotName = 'imageBlock';
ImageBlot.tagName = 'img';
ImageBlot.className = 'inline-img';
Quill.register(ImageBlot);
When I run the converter, this custom blot is recognized as InsertDataCustom
but it falls into the inlineGroup
group instead of blockGroup
. Is there any problem with the custom blot above that makes it fail to be recognized as blockGroup
?
let converter = new QuillDeltaToHtmlConverter(html.ops);
let groupedOps = converter.getGroupedOps();
console.log(groupedOps)
I may have figured it out.
The custom image blot generates an op like this:
{"ops":[{"insert":{"customImageBlot":{"height":150,"width":150,"url":"https://xxx.cloudfront.net/image/i@Hy81U57G7.png"}}}
In order to be treated as a block, it must pass the check in the DeltaInsertOp.isContainerBlock()
method .
isContainerBlock() {
var attrs = this.attributes;
return !!(
attrs.blockquote || attrs.list || attrs['code-block'] ||
attrs.header || attrs.align || attrs.direction || attrs.indent);
}
I must get the custom blot to store an attribute like {header:true}
in the op object. What do you think?
I just pushed an update for this. It is tagged as v0.10.2
. Now, if you like your custom blot to be treated as a block, add renderAsBlock: true
in its attributes like:
attributes: { renderAsBlock: true}
Also, please note that after the version v0.10.0, I updated the way we import/require this library. See the readme under breaking changes.
P.S. When you get grouped ops via
let converter = new QuillDeltaToHtmlConverter(html.ops);
let groupedOps = converter.getGroupedOps();
console.log(groupedOps)
custom blots that are categorized as block will be of type BlotBlock
not BlockGroup
This library is just getting better and better. Thanks to the recent updates, I can render delta into native components in react native! I'm also using it in node.js to extract temporary images from delta and upload them to s3.
Here's the updated custom image blot:
const Embed = Quill.import('blots/block/embed');
class ImageBlot extends Embed {
static create(value: EditorMediaValues) {
let {src, height, width} = value;
const node = super.create();
node.setAttribute('height', getSize(height));
node.setAttribute('width', getSize(width));
node.setAttribute('src', src);
return node;
}
formats() {
return {renderAsBlock:true};
}
static value(node) {
return {
src: node.getAttribute("src"),
height: node.getAttribute("height"),
width: node.getAttribute("width"),
}
}
}
ImageBlot.blotName = "imageblock";
ImageBlot.tagName = 'img';
Quill.register(ImageBlot);
This blot will generate an op like this:
{
"ops": [
{
"insert": {
"imageblock": {
"src": "https://some.cloudfront.net/image/i@picture.png",
"height": "150",
"width": "150"
}
},
"attributes": {
"renderAsBlock": true
}
}
]
}
And yes, the type will be BlotBlock
instead of BlockGroup
, so I have to add one more case to the switch statement.
return groupedOps.map((group, key) => {
switch (group.constructor) {
case InlineGroup:
return rules.inlineGroup(group, key);
case ListGroup:
return rules.listGroup(group, key);
case BlockGroup:
return rules.blockGroup(group, key);
case VideoItem:
return rules.videoItem(group, key);
case BlotBlock:
return rules.blotBlock(group,key);
default:
console.log(`Unknown instance`);
return;
}
})