Using CKEditor 3.6.6
Started using htmlFilter because I wanted to remove the style attributes (dimensions) from an image in a responsive project.
That was easy enough
CKEDITOR.on('instanceReady', function (ev) { ev.editor.dataProcessor.htmlFilter.addRules( { elements : { $ : function( element ) { if (element.name == 'img') { if(element.attributes.style) { delete element.attributes.style; } } } } }); });
I then wanted to replace any <p> with a direct <img> child with a <figure> element (that bit I got working). The tricky part for me is how do I create a <figcaption> element, populate it with the alt attribute from the image and inject it in the <figure> element I just renamed the <p> to.
In theory, it should be quite simple: store the alt attribute of the child element, create <figcaption> element and inject in current element. Spent quite a while and cannot find an easy way to do it. Also, cannot find a way to use CKEDITOR.dom.element functions like appendHtml() with htmlFilter.
Here is my custom config.js file.
CKEDITOR.on('instanceReady', function (ev) { //HTML output instead of XHTML ev.editor.dataProcessor.writer.selfClosingEnd = '>'; //avoid line breaks with common block elements var tags = ['p', 'ol', 'ul', 'li', 'h1', 'h2', 'h3', 'h4']; for (var key in tags) { ev.editor.dataProcessor.writer.setRules(tags[key], { indent : false, breakBeforeOpen : true, breakAfterOpen : false, breakBeforeClose : false, breakAfterClose : true }); } //add some HTML filters ev.editor.dataProcessor.htmlFilter.addRules( { elements : { $ : function( element ) { //remove style attributes from images and make sure they have an ALT text if (element.name == 'img') { if(element.attributes.style) { delete element.attributes.style; } if (!element.attributes.alt) { childImage.attributes.alt = "Dummy Alt Text"; } } //transform p containing images into <figure> with <figcation> based on image alt text if (element.name == 'p') { console.log("Paragraph Found"); //check if image is nearest child if (element.children[0].name == 'img') { console.log("Paragraph with IMG as direct children"); var childImage = element.children[0]; //add class and change to figure element.attributes['class'] = 'imageholder'; element.name = 'figure'; //create figcaption based on alt var captionText = childImage.attributes.alt; //create HTML ("<figcaption>"+captionText+"</figcaption>"") //inject HTML in current element } } } } }); });
Maybe htmlFilter is not the right way to go about this. If not, could you please provide me with some pointers?
I'm afraid that you'll need
I'm afraid that you'll need to update CKEditor to 4.1. In this version I rewrote nearly entire filters implementation what made it more reliable. In the previous versions is unsafe to do DOM structure operations when filtering data. Now it's safer, although I would rather use editor#toHtml and editor#toDataFormat events or combination of data processor's filters (to cache paragraphs that should be transformed to <figure>) and these events to make bigger changes (after applying filters, so with priorities 11-14).
Anyway - this solution usually works on 4.1 (check comments):
I tested it on 3.6.6 and as I thought it crashed the filter. And because editor#toHtml and editor#toDataFormat events were also introduced in 4.1 it's very hard to write reliable solution for <4.1.
BTW. Check Widgets feature on which we're currently worki on. Sample that shows this new issue is already ready and there will be widget that will do excatly what you want. However, thanks to widgets this solution will have great advantage over what can you achieve in <4.2 because the <figure> element will be non-editable - user won't be able to ruin it.
Piotrek (Reinmar) Koszuliński
CKEditor JavaScript Developer
--
CKSource - http://cksource.com
--
Follow CKEditor on: Twitter | Facebook | Google+
Thanks for the torough answer
Hey Piotrek,
Thanks for the very thorough answer, much appreciated!
Good to know that 4.1 offers better tools for solving such cases. I am using CKEditor in the context of a CMS so will have to wait until it upgrades to 4.x. I guess I'll have to solve this with custom fields and template logic rather than with CKEditor for the time beeing.
Again, thank you for your time and the very thorough explanations and pointers.
BTW. I just thought that in
BTW. I just thought that in old versions you can achieve satisfying results with regexp and editor#setData and editor#getData events.
You can also play with img on this level (e.g. remove styles) and using CKEDITOR.htmlParser.basicWriter write it back to string.
Piotrek (Reinmar) Koszuliński
CKEditor JavaScript Developer
--
CKSource - http://cksource.com
--
Follow CKEditor on: Twitter | Facebook | Google+
Trigger filter on insert
I've tried your code and it works great, BUT the filtering isn't triggered until I save the output or enter source mode. I would like the filter to trigger the moment I insert a new image.
Replace existing dom elements using dataProcessor.htmlFilter ..
Hello,
I'm using version 4.1 of the CKEditor. I recently saw this post and it is similar to what I have been tasked to do. Here is the use case. A user paste in an html table (shown below).
After pasteing I would like to use the filters to transform the table into the following.
To get started I added the below code to transform the <tr> tags into <row> tags.
This is the result:
The source shows that the <tr> tags are replaced with <row> tags however you can see the extraneous <row> tags. It seems the editor does not know where to add the <row> tags into the dom in all cases. Not sure why thead got replaced with <tbody>.
Do you think I can use this approch to generate this new table structure ?
If you have some sample code which works with tables in this way that would be gratly apraeciated. I am very new to the ckeditor but it is a great tool.
thanks
Followup to my post
I wanted to edit my post for spelling. After selecting preview there didn't seem to be a way to get back to the editor. It seems the spam filter is blocking me from editing the original post.. :-)
Ok I wanted to add one more important point The table does not render in the WYSIWYG editor.
Replace existing dom elements using dataProcessor.htmlFilter ..
Hi Folks,
Does anyone have any thoughts on my post on html table element tranformation in the above post (6, 7) using dataProcessor.htmlFilter, dataFilter.
@Stellatyler thanks for the tip.