I'm trying to force CKE to stop modifying my HTML wildly, and trying to introduce our own rules.
For example, CKE will remove empty span and i tags, we can prevent it from doing it with
CKEDITOR.dtd.$removeEmpty.span = false
CKEDITOR.dtd.$removeEmpty.i = false
So far so good. Then we tried to make A tags to be able to support block level elements (HTML5), which we were able to do by manipulating the DTD as well.
But now it seems the DTD object is not enough for what we are trying to do.
For example, it's removing empty A tags, and I can't prevent it from doing it,
CKEDITOR.dtd.$removeEmpty.a = false
will not do the trick. It's doing the same thing with empty BR tags located at the end of the content.
I know CKE is using a filter, parser, processor or something that I need to hook onto and modify/alter it in order to stop it from doing those changes. Could you please give me any advise on how to achieve this ?
Cordially, Agustin.
UPDATE
I'm also looking forward in adding an extra supported children to SELECT tag. Select supports optgroup and option as children, I'm trying to add support for a custom_tag (inline), but I can't succeed in making it happen.
CKEDITOR.dtd.select.custom_tag = 1
Is not doing it. The custom tag is also declared on dtd.$inline
I guess there is some sort of external processing cleaning it up, and I can't control this from the DTD object. Any pointer on this regard ?
Unfortunately empty links are a special case and to stop removing them you will need to modify the source:
https://github.com/ckeditor/ckeditor-dev/blob/6f4c29002f4d6ecfa39308b641ae37c56bba1348/core/htmlparser/fragment.js#L59-L66
function isRemoveEmpty( node ) {
// Keep marked element event if it is empty.
if ( node.attributes[ 'data-cke-survive' ] )
return false;
// Empty link is to be removed when empty but not anchor. (#7894)
return node.name == 'a' && node.attributes.href || CKEDITOR.dtd.$removeEmpty[ node.name ];
}
BTW. CKEditor removes empty inline elements, because they are not editable (and some things may start working incorrectly). To ensure correct editability of these elements you can write widgets for them.
To disable filtering HTML (source) in CKEditor write in your config.js file this lines:
CKEDITOR.editorConfig = function( config ) {
config.allowedContent = true;
};
Source code here.
Related
We have a very large website that is quite old and has a lot of 'b' tags. My boss wants to change them to 'strong' tags but this will require a lot of time to change manually so she was hoping we could change it with some code.
I had a nice bit of JQuery code that worked (intermittently), but I couldn't get it to work on the site as it uses JQuery 1.9.1 and cannot be upgraded.
I then found this piece of Javascript which does what I need but only works on the first 'b' tag on the page and all others stay as 'b' tags. I don't know enough about Javascript selectors to change the firstChild selector.
<script>
function replaceElement(source, newType) {
// Create the document fragment
const frag = document.createDocumentFragment();
// Fill it with what's in the source element
while (source.firstChild) {
frag.appendChild(source.firstChild);
}
// Create the new element
const newElem = document.createElement(newType);
// Empty the document fragment into it
newElem.appendChild(frag);
// Replace the source element with the new element on the page
source.parentNode.replaceChild(newElem, source);
}
// Replace the <b> with a <div>
replaceElement(document.querySelector('b'), 'strong');
</script>
You might use querySelectorAll:
Array.from(document.querySelectorAll('b')).forEach(e=>{
replaceElement(e, 'strong');
});
But this is really a xy question. You really should do the change server side, for example by using some search/replace (learn to use your code editor). You're adding to the code debt here.
Note also that there's no obvious reason to prefer strong over b in HTML5.
Use getElementsByTagName(). It's more efficient than querySelectorAll because it doesn't have to parse selectors, and it describes better what you are really trying to do - get elements by tag name.
var elements = document.getElementsByTagName("b");
replaceElement(elements[0], "strong");
replaceElement(elements[1], "strong");
replaceElement(elements[2], "strong");
You can also iterate over this collection by using Array.from().
You would be better off finding the source of the <b> tags and changing them there as Denys has mentioned.
Updating the DOM would have little benefit and would cause performance issues when there are many tags on a page.
Does this system use a CMS or database to store the content? I would look to use something like these 2 SQL queries to replace them across the site:
update content_table set content_column = replace(content_column, '<b>','<strong>');
update content_table set content_column = replace(content_column, '</b>','</strong>');
I'm testing out CKEditor
I'm trying to get the display in the editor, to match my sites css style for displaying the end result.
What I'm trying to do is style the "wrap code" button to match the css of my site, by adding in a class.
I've seen on this page of the manual, that you can do stuff like this:
config.format_pre = { element: 'pre', attributes: { 'class': 'editorCode' } };
However, doing the same for a code block like so:
config.format_code = { element: 'code', attributes: { 'class': 'someclass' } };
Doesn't actually do anything. Anyone got a pointer on what I might be missing?
I've tested it working on other elements, so I know the config file changes are being picked up.
The one important thing is that every tag which is formatted via config.format_tagname should be also included in config.format_tags. However, this two settings (config.format_tagname and config.format_tags) works only form Block-Level elements (as stated in the manual page you referenced ).
As code element is considered as an inline one by CKEditor (see DTD), it is not possible to use this config here.
However, the easiest way to modify the elements added via Style dropdown is to edit styles.js file which is present in CKEditor directory. The dropdown styles are based on this file, so you can easily modify code element there. You can also define your custom stylesSet.
I have been using CKEditor for some time and it has worked great. I've pretty much gotten rid of any problems that ive had but this one i cant seem to figure out. When i add inline attributes to elements for instance style = "color: #ff0;" on a <p></p> tag they are stripped out when i switch from wysiwyg to source view. No saving or submission is done and ckeditor is has been added to my site which is my own script. Any ideas as to what would cause this. All of the search results i can find correspond to this happening in Drupal but Drupal seems to be the problem not the editor in all instances. Thanks again!
It feels like you're using CKEditor 4.1+ that comes with Advanced Content Filter (ACF). If so, you need to specify config.allowedContent and configure it to get your things working. You may also be interested in config.extraAllowedContent.
See this answer for more details.
For anyone looking for a simple sample on how to enabled additional markup in CKEditor without disabling ACF completely, here is a short snippet:
CKEDITOR.replace( 'editor1', {
extraAllowedContent: 'style;*[id,rel](*){*}'
} );
extraAllowedContent here enables the <style> element, allows two additional attributes (in square brackets) for all (* is a wildcard) already allowed elements, allows usage of any class names (*) for them and allows usage of any inline styles {*}
hi you can stop ACF easily . by default your configaration is---
function ckeditor($name,$value='',$height=300){
return '<textarea name="'.addslashes($name).'">'.htmlspecialchars($value).'</textarea>
<script>$(function(){CKEDITOR.replace("'.addslashes($name).'",{});});</script>';
}
just add this in the curly brackets:
allowedContent: true
now your configuration will be:
function ckeditor($name,$value='',$height=300){
return '<textarea name="'.addslashes($name).'">'.htmlspecialchars($value).'</textarea>
<script>$(function(){CKEDITOR.replace("'.addslashes($name).'",{allowedContent: true});});</script>';
}
I faced the same issue and below answer solved my problem:
config.allowedContent = true;
config.extraAllowedContent = '*(*);*{*}';
config.extraAllowedContent = 'span;ul;li;table;td;style;*[id];*(*);*{*}';
I had the same problem, that ck was stripping not only some attributes, but whole elements when pasting a block element, inside a block element (div with some attributes pasted inside a p) while using this method:
editor.insertHtml(html);
what solved the problem was using this workaround instead:
editor.insertElement(CKEDITOR.dom.element.createFromHtml(html));
I have successfully managed to set up an on paste event to capture the HTML pasted into the text area as it is pasted.
I need to automatically apply the removeFormat command to that HTML before or at the time it is pasted into the text area, so that I can strip it of classes, various tags, and other attributes. Could somebody point me in the right direction to apply the removeFormat command correctly?
Here's my code so far:
$(function(){
$('textarea').ckeditor(
function( textarea ){
var editor = this;
editor.on('paste', function( e ) {
//alert(e.data.html); // This shows the HTML
editor.execCommand( 'removeFormat', e.data.html ); // Doesn't seem to do anything, HTML is pasted with the attributes intact
});
}
)
});
Thanks!
P.S. Force plain text option is not viable as there are some HTML elements I wish to keep (p,table and others).
You can use
config.forcePasteAsPlainText = true;
cf http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html
You need to select the content before you can apply removeFormat to it.
You could try grabbing the range ( even if it's just the cursor sitting at the insertion point ) and saving a bookmark before you paste.
After you paste, use the bookmark to select that range again.
That should select everything that you pasted between the start and end of the range.
Then you can use removeFormat:
editor.execCommand( 'removeFormat', editor.selection );
Here are the links to the range and selection API pages:
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dom.range.html
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dom.selection.html
I've found it easier to work with ranges, the createBookmark method is good because it sets markers and you can grab the correct start and end points even if the DOM changes ( as it will when you paste in the new content ). You can use moveToBookmark() after the paste to select the range.
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dom.range.html#createBookmark
Because the documentation is sparse, I've found it helpful to search the source code for places where the methods are called. Looking at how they're used gives me a better idea of what kind of object I need to apply the methods to.
Be Well,
Joe
Starting from CKEditor 4.1 there is no need to do custom coding to define the list of elements that should be kept when pasting data into CKEditor, Advanced Content Filter should do the trick.
Either leave ACF enabled with the default configuration - CKEditor will accept all tags that can be created with it, or define your own set of rules with more or less strict set of allowed tags/attributes/styles. See documentation
I'm trying all day to set up a peristant style attribute to the body tag of the ckeditor instance. I could not find something like bodyStyle in ckeditor.config api (only bodyId and bodyClass).
So I was trying it myself, with the following solution (jQuery is used):
$(this).find('textarea.editor').ckeditor().ckeditorGet().on( 'instanceReady', function( e ){
var documentWrapper = e.editor.document,
documentNode = documentWrapper.$,
inh = $(documentNode.body);
inh.css('background', inheritParentBackground);
});
Wich is working quite well, but after I call .updateElement() or if i click the source button twice, it will removes all the styles again and 'instanceReady' is not called again.
I tried to fire it manually, but then it runs the style update first and gets directly overwritten from ckeditor.
What I'm actual trying to do: I want to edit a Div in an homepage, after klicking edit a ajax popup apears with the ckeditor and i want the Editor to have the same height, width and Background and i can not handle this over bodyId or bodyClass, so I guess I need a bodyStyle or somebody has a diffrent idea.
Is http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.html#.style what you're looking for?
I found out a dirty hack:
$(this).find('textarea.editor').ckeditor({
bodyId: Id+'" style="'+style,
});
not very nice but it works ;-)
You have two options. You can add an inline styleSheet in the instanceReady handler via:
var myStyleSheet = e.editor.document.appendStyleText("body {background:...}");
This appends an empty <style> element to the head of the editor's (iframed) document, containing the supplied text.
The return value is a CSSStyleSheet (a browser DOM object), so if you save it somewhere you can add, remove, or modify the style rules using DOM methods from javascript. I'm not sure if they persist through mode changes (i.e. after clicking "Source" twice), or calls to setData(), but you can capture these things using the 'mode' and 'contentDom' events, and reapply the styleSheet in the event handler. Note that (for the 'mode' handler at least) you need to check that editor.mode==='wysisyg', because editor.document is null in source mode.
On the other hand, if you really want to set your styles inline on the editor's <body> element, try defining a function:
function setEditorStyle(e)
{
var ed = e.editor;
if (ed.mode!=="wysiwyg") return; // don't set styles when in "Source" mode
// now change whatever styles you want, e.g.:
ed.document.getBody().setStyles({backgroundColor:"blue",color:"#FFFFFF",...});
// for setting just 1 style property, you can use .setStyle() instead
}
then within your editor config, you need to add:
..., on: { instanceReady: setEditorStyle, mode: setEditorStyle, ... }, ...
Which will set the style both after the editor iframe is first created, and after switching back to 'wysiwyg' mode (normal editing, not source mode).
I don't know why your styles are being reset by calls to updateElement(); I'm doing the same thing (using CKEditor v4) and updateElement() does not reset inline styles I've set on <body>. Perhaps it's something that's changed with CKeditor versions. In any case, if it's a problem you can simply manually reset the style again after calling updateElement(). (I'd say "just call setEditorStyle()", but as shown above that function is written to require an event parameter e. Instead you could rewrite it to use an externally defined "ed" variable (e.g. a global var) - i.e. change
var ed = e.editor;
to
if (!ed) ed = e.editor;
and then you can safely call setEditorStyle() from any point in your javascript after the editor has been created.)