I like Quill because it offers limited editing capabilities. But I need to accommodate custom block styles beyond h1-h5, p, code, and blockquote. To do this I'm using divs with a different class attribute for each custom block style. I do this by creating custom blots for each style, but all of them have tagName='div'. This works nicely if you enter/mark the div's after the document is loaded in Quill.
But in parsing the initial HTML, I'm guessing that Quill just thinks "a div is a div" and assigns the same style to all the divs. Specifically, it assigns the last custom blot with tagName='div' that I defined. If you swap the definition order of Quill.register for TipBlot and SubtitleBlot, all divs are parsed as whatever Blot was registered last.
Here's the basic Quill Playground modified to show what I'm trying to do: https://codepen.io/anon/pen/zwNgEq
I'll reproduce it here in case that gets erased:
.tip{color:red;}
.subtitle{color:green;}
<div id="editor-container">
<div class="tip">Hello</div>
<div class="subtitle">Goodbye</div>
</div>
let Block = Quill.import('blots/block');
class SubtitleBlot extends Block {
static create(url) {
let node = super.create();
node.setAttribute('class', 'subtitle');
return node;
}
}
SubtitleBlot.blotName = 'subtitle';
SubtitleBlot.tagName = 'div';
Quill.register(SubtitleBlot);
class TipBlot extends Block {
static create(url) {
let node = super.create();
node.setAttribute('class', 'tip');
return node;
}
}
TipBlot.blotName = 'tip';
TipBlot.tagName = 'div';
Quill.register(TipBlot);
var quill = new Quill('#editor-container');
Expected behavior:
I expected that if Quill could create the HTML, then Quill could parse that same HTML. So that I'd see a red Hello followed by a green Goodbye on the next line.
Actual behavior:
Both Hello and Goodbye are the same color (the color of whichever custom blot was defined last). I think Quill only considers the tag name and not the class when parsing, so when it parses a div, it ignores the class attribute.
Search for a Work-Around:
Is this something I could do with a custom matcher?
let Delta = Quill.import('delta');
quill.clipboard.addMatcher('div', function(node, delta) {
console.log(node);
let clz = node.attributes['class'];
let c = (clz == null) ? null : clz.value;
console.log(c);
var delta2 = new Delta(c).insert(node.data);
return delta2;
});
quill.clipboard.dangerouslyPasteHTML($('#sourceDoc').html());
I'm not creating my delta correctly but hopefully this will work when I figure out what the heck I'm doing.
Platforms:
Google Chrome 58.0.3029.81 (64-bit), Ubuntu 16.04.
Version:
1.2.4
Ooo! Ooo! I know this one. :raising_hand_man:
The SubtitleBlot.blotName is used to distinguish one register/import/blotType from another.
The SubtitleBlot.className will _automatically_ set the class attribute on your <div> without the call to node.setAttribute('class', 'subtitle');. This will also let Quill distinguish one div from another when interpreting the HTML.
Case in point - check out this fork of your codepen: https://codepen.io/percipient24/pen/RVpPqX specifically lines 10 and 20 of the JS.
I recommend reading https://github.com/quilljs/parchment#blots for more details on what a Blot has.
All of that said, according to the contribution rules we're _supposed_ to post questions like this over in Stack Overflow, tagged with quill. But this hit my inbox and I knew the answer, so I got excited. (I've been working with Quill for a couple months now, and making heavy use of Issues / StackOverflow written by other folks, I figure it's my turn to give back!)
Thank you for this! This is what I see when I inspect the result:
<div class="ql-editor" contenteditable="true">
<div class="align align-right">
<figure class="figure">Hello</figure>
</div>
<div class="align">
<figcaption class="caption">Goodbye</figcaption>
</div>
</div>
I was looking for:
<div class="ql-editor" contenteditable="true">
<div class="figure">Hello</div>
<div class="caption">Goodbye</div>
</div>
Your solution works, but there are no figure or figcaption tags in HTML. Those would be "custom elements" that only work on Chrome, Opera, and Android. If I went this route (no idea what I'd do for IE, Safari, Edge, and Firefox users), I'd have to parse the html on the server side to turn the first example into the second. I'd like to avoid that if possible.
I apologize for posting in the wrong forum. I expected Quill to read the HTML it can write, so thought of this as a bug. My search for a work-around is definitely not a bug or enhancement, so maybe I should delete that part from this issue and post it on StackExchange instead? I'm going to edit my issue to clarify that.
@GlenKPeterson So sorry! I had done something else (figure/caption related) on my own - thinking I was working off of a Fork of the codepen I linked above. Instead, I was overwriting the same fork. Try the link again! It's back to what I intended now, which is closer to what you expected.
Brilliant! In the meantime I made my work-around work. It intercepts the 'div' tags and corrects the class attribute in the delta:
quill.clipboard.addMatcher('div', function(node, delta) {
let clz = node.attributes['class'];
let c = (clz == null) ? null : clz.value;
let attr = delta.ops[0].attributes;
if ((c != null) && !(c in attr)) {
delete attr['caption'];
attr[c] = true;
}
return delta;
});
quill.clipboard.dangerouslyPasteHTML($('#sourceDoc').html());
But I like your way much better! All you did was set each blot's className equal to the blotName:
SubtitleBlot.className = 'subtitle';
TipBlot.className = 'tip';
That's what I'll use. It's so simple, I'm a little embarrassed that I didn't figure it out on my own. Thanks again! 馃憦馃槃
Thanks for your help @Percipient24 !
Most helpful comment
@GlenKPeterson So sorry! I had done something else (figure/caption related) on my own - thinking I was working off of a Fork of the codepen I linked above. Instead, I was overwriting the same fork. Try the link again! It's back to what I intended now, which is closer to what you expected.