CKEditor 5: How to prevent cascading of linkHref attribute changes to all child nodes of a custom element structure? - ckeditor

The Setup
Currently, CKEditor 5 does not support image captions for inline images. As our CMS needs to utilize both block and inline images, I wrote a plugin that extends schema and conversions with a custom <caption> element that works both for <imageInline> and <imageBlock> (and a custom, plaintext-only <alt> element for also have a nested editable for the image alternative text, but that's omitted here because it's not part of the issue).
It starts with a schema extension for <caption> to work for both image types:
schema.register('caption', {
allowIn: ['imageBlock', 'imageInline'],
allowContentOf: '$block',
isLimit: true
});
Then, several conversions and up-/downcast helpers from the original image packages #ckeditor/ckeditor5-image/... (image/imageblockediting.js, image/imageinlineediting.js, image/converters.js, image/utils.js, imagecaption/imagecaptionediting.js) are adapted and/or overwritten with higher priority custom versions to have an editable <caption> element both inside <imageBlock> and <imageInline>.
Both image types can have a linkHref attribute, which is implemented by extended, higher priority versions of upcastImageLink() and downcastImageLink() from #ckeditor/ckeditor5-link/src/linkimageediting.js.
Also, we need to backup and restore the <caption> element and all its child nodes when changing between block and inline images by listening to the imageStyleCommand, because the command itself obviously does not care for our custom <caption> structure (the caption should be visible all the time, so there is no need for a toggle as in the original caption package).
All in all, it's 400+ lines of code, so I won't post it here - you can get the idea by looking at the original code mentioned above.
Working Code
Now, for block images we have the same model/view structure and functionality as the original <imageBlock> version, and for <imageInline> the model looks like this (including the parent paragraph and some text; please ignore the <altContainer> structure):
Which gets converted to this view structure (again, ignore the <altcontainer> structure):
The Problem
When selecting an <inlineImage> and adding a link, the linkHref attribute is not only set on the <inlineImage> element itself (that's what we want), but also on all of the <caption>'s child nodes. So the model is looking like this:
And the view:
As you can see, the linked text from the original caption gets lost, too.
So how do you prevent this?
I'm assuming this is happening because <imageInline> is obviously registered as isInline:true, because when linking an <imageBlock> image this is not an issue! I've tried to fix this with a registerPostFixer() routine, but that can fix only parts of the problem.
I'm working around this problem now by cloning the whole <caption> structure before linking an image, and replacing the "buggy" version with the cloned one after the link command has finished.
There should be a more elegant way to tell the engine not to apply the linkHref attribute to the <caption> child nodes, and leaving existing linkHref attributes inside as is; which is also an issue when removing the link for the image: existing child linkHref attributes get also removed.

Related

How do I tell CKEditor 5 to use inline styling on the elements which it creates instead of them being class-based?

I'm using CKEditor 5 on my website in order to allow users to generate PDF templates for their company.
My issues is, that once I take the data out of the ckEditor, every styled element has a class="CSS-Class-Here", which is problematic due to the fact that when I convert the HTML contents of the CKEditor to PDF, the PDF doesnt know any of these classes.
Is there any way to get CKEditor to save these classes as inline styles?
I know that its possible to create a plugin for a specific element for a specific style, but I want everything to act this way, not something specific.
Also, It's impossible to just inject the styles into the PDF itself, due to the fact that ckEditor keeps their styles in javascript functions and creates them on demand.
For example:
Yellow highlighted text comes out as:
<mark class="" marker-yellow "">Random Text</mark>
I would like it to come out as:
<mark style="background: yellow">Random Text</mark>
Meaning that the style that's present in the marker-yellow class should be applied inline directly to the element itself.

CKEditor Adding Extra Classes To Widget

I've created a CKEditor widget to allow a user to input a section of text into a colored box once it is output to a report. My code is almost exactly like the simplebox example on the CK site
While I can get the widget to work and add the correct classes, 'simplebox-title' etc, it is also adding a ton of extra wrapper classes, data tags, and even an img (for the move button) when I save it into the database. So instead of having a clean:
<div class="simplebox-title"></div>
I end up with about 4 lines of code like:
<div data-cke-widget-id="0" data-cke-display-name="div" class="cke_widget_wrapper cke_widget_block" data-cke-filter="off".....etc>
All of this is going into the database. It even transfers the image of the "+" sign to move the div around. I don't want any of this as it comes through from the database into the report page.
I'm sure I'm missing something (probably obvious), but I can't find it. And blowing up the DB + having that move button won't work on a report.
I'm using PHP/Laravel, mysql, standard (not floating) CKEditor, CKEditor Save plugin.
Any help?

CKEditor: Paste into editable field in widget

I have a CKEditor widget resembling a tab-module.
As editables I have defined a span.title and div.content.
When I am in editing mode inside a span.title and then paste something using CTRL+V, the span gets broken and I have two spans. As if it gets divided on whatever position I paste.
When I am in editing mode inside a div.content and then paste something using CTRL+V, the contents of the clipboard are correctly inserted into that div.
Is it because span is an inline-element and div is a block-element and CKEditor doesnt allow pasting into inline-elements?
Can I somehow change this behaviour?
CKEditor allows pasting of block and inline elements (keep in mind that content filtering (ACF) can be used which also affects pasting) so it is probably not the issue in this case.
I would also make sure that the content which you are trying to paste does not contain any HTML which may cause the behavior you described.
If you could provide widget HTML/template or code which you are using I will be glad to investigate this issue in more depth.
I had this issue when trying to have a <cite> element as an editable. Trick was to tweak the CKEDITOR.dtd properties.
// This prevents the pasting from splitting parent element.
delete CKEDITOR.dtd.$removeEmpty.cite;
// This tells the editor to allow editing in this element.
CKEDITOR.dtd.$editable.cite = 1;
I imagine this would affect the behavior of all <cite> elements in any editor currently loaded. Not ideal in all cases for most elements, but for our requirements for a blockquote/pullquote widget, the <cite> element is only allowed inside our <blockquote> elements in any editor.

Ace code Editor with XML, hide specific xml attribute?

sorry, a newbie Q. Is it possible to hide a specific attribute throughout an XML doc?
I need a way to synchronize the contents of the editor with non-Ace objects elsewhere on the DOM (unfortunately a SWF file that loads the xml seperately...). I thought to label each node throughout the doc, e.g. tag='1', so that if a node with a given tag is manipulated in Ace, I can just use the tag to figure out what exactly was manipulated (and vice versa, update Ace when the xml is manipulated outside of Ace).
Best that people do not manipuate these tags, hence wanting to hide them from view.
Thanks :)
you can create folds to hide text, but i think for tracking changes it is better to use anchors which keep their position relative to text
a=ace.session.doc.createAnchor(row,col); // create
a.getPosition();
a.detach(); // remove when not needed anymore

how to disable tag validation in ckeditor?

CKeditor apparently automatically creates matching end tags when you enter a start tag. Is there a way to turn this behavior off?
I have a situation where I am creating two blocks of text in an admin program using CKeditor, then I'm using these to paint a page with the first block, some static content, and then the second block. Now I've got a case where I want to wrap the static content in a table. I was thinking, No problem, I'll just put the <table> tag in the first block and the </table> tag in the second block, and the static content will be inside the table. But no, CKeditor insists on closing the table tag in the first block.
In general, I can go to source mode and enter HTML directly, but CKeditor then decides to reformat my tagging. This seems to rather defeat the purpose of having a source mode. (I hate it when I tell the computer what I want and it tells me, No, you're wrong, I know better than you what you want!)
CKEditor produces valid HTML. Valid HTML has to include both - start and end tags. There's no way to change this behaviour without hacking editor. Note that even if you'll force editor to produce content without one of these tags it will then try to fix this and won't do this as you expect. E.g. load:
<p>foo</p></td></tr></table>
And you'll completely loose this table so only regexp based fix on data loading could help. In the opposite case:
<table><tr><td><p>foo</p>
You'll end up with paragraph wrapped with table, so it's better. But what if someone would remove this table from editor contents?
Therefore you should do this integration outside editor - prepend table to contents of one editor and append to contents of second one. You simply cannot force editor to work on partial HTML.

Resources