CKeditor removes style attribute even though set in allowedContent - javascript

I created a custom image browser/uploader plugin for ckeditor. I'm having some trouble integrating the advanced content filter
Basically what's happening is I have a field on a dialog tab that allows a user to edit the inline style for the image. This is working correctly it seems as the styles get added to the img tag and after saving to the database and when viewing the generated html the image is styled correctly. However when you go to edit the document again CKeditor has stripped out the style attribute.
in plugin.js I am setting the allowedContent property to include the style attribute
editor.addCommand( 'sbImageDialog', new CKEDITOR.dialogCommand( 'sbImageDialog',
{allowedContent: 'img[src][style]', requiredContent: 'img[src]' }
));
in the dialog js I am defining a tab called "advanced" that requires the style attribute to be allowed in order to show
{
id: 'advanced',
label: 'Advanced',
elements: [
{
type: 'text',
id: 'style',
label: 'Style',
requiredContent: 'img[style]',
setup: function( element ) {
this.setValue( element.getAttribute('style') );
},
commit: function ( element ) {
var style = this.getValue();
if ( style )
element.setAttribute( 'style', style );
else if ( !this.insertMode )
element.removeAttribute( 'style' );
}
},
]
}
since that tab does show up and the image is styled correctly when viewed it seems like I have it set up correctly.
So why is CKeditor stripping out the style attribute when I return to edit the document? Can anyone see what I'm missing?

I found the answer so I'll add it here in case it will help someone else.
Where in plugin.js I had
editor.addCommand( 'sbImageDialog', new CKEDITOR.dialogCommand( 'sbImageDialog',
{allowedContent: 'img[src][style]', requiredContent: 'img[src]' }
));
I had to change the allowedContent property from 'img[src][style]' to 'img[src][style]{*}'
The curly braces indicate what css style properties the element is allowed to have. By putting * I am allowing all css style properties.

Related

Add class style to CKEditor text with javascript

I'm building a self contained web page and am using CKEditor 4.6.2 for input. My last hurdle, for now, is trying to apply a css class style to text inserted via javascript. My css is in the head tag, nothing special there. I have defined a styleset as directed by CKEditor documentation.
CKEDITOR.stylesSet.add('my_custom_styles', [
// Block-level Styles
{ name: 'My Custom Block', element: 'p',
styles:{
'color': 'dimgray',
'padding-left':'15px',
'border-left-style':'solid',
'border-width':'3px',
'border-color':'#52bab3',
'margin-left':'2px',
}
},
{ name: 'MyCustomInline', element: 'span', attributes: {'class': 'redText'}
}
]);
And added it in CKEditor
CKEDITOR.replace('LogBook', {
language: 'en',
uiColor: '#9AB8F3',
toolbar: [
['Undo','Redo','-'],
['Bold','Italic','Underline','Strike','-'],
['RemoveFormat','-'],
['NumberedList','BulletedList','-'],
['HorizontalRule'],
'/',
['Styles','-','Source','-','About','Maximize'],
],
removeButtons: 'Subscript,Superscript,Cut,Copy,Paste,Anchor,Scayt,PasteText,PasteFromWord,Image,SpecialChar,Link,Unlink,Table,Indent,Outdent,Blockquote,Format',
removePlugins: 'wsc,scayt',
stylesSet:'my_custom_styles',
allowedContent: true
})
But for the life of me I can't figure out how to apply a class to an element in the editor with javascript like so...
<p class="My Custom Block">Some text here</p>
I have turned off content filtering and have a custom function that inserts the above code, but the paragraph element does not get styled.
I have also tried applying styles right from my style sheet like:
<p class="redText">Some text here</p>
But again the paragraph element isn't getting styled.
Any help would be great, thank you.
After a long search I finally ran across an answer (by surtyaar towards the bottom) to add a class to a CKEditor elements.
CKEDITOR.addCss( '.redText { border-bottom: 1px dotted red }' );
This needs to be called before the CKEditor instances are declared.
From the CKEditor docs.

TinyMCE update Toolbar (after init) when you have Editor on method

I'm working on a Google Fonts plugin for WordPress and I try to have the same effect as the core WYSIWYG editor. Basically when you click on element (inside the Editor) with font class I want to get the class and then based on that reload the font family/style listbox in the Toolbar.
(I found couple of hacks here on SO like this one Proper Way Of Modifying Toolbar After Init in TinyMCE but nothing that works like the WP core example)
There is the same functionality when you click on P, H1, H3, H3 ... How they do it? Can you point me at least to the JS file in WordPress distro; I think I can figure it out if see the code.
Here is GIF that demonstrates what I'm talking about. Thanks in advance.
I found the solution and because it's not a hack, like the other ones I found on SO, I will post it in here and hopes it will help anyone else that's trying to do something similar.
First to access the button/listbox need to use onpostrender with a callback function.
editor.addButton( 'developry_google_font_family_button', {
type : 'listbox',
onpostrender : fontFamilyNodeChange,
value : '',
...
Next the callback function should look something like this:
function fontFamilyNodeChange() {
var listbox = this;
editor.on('NodeChange', function( e ) {
// This next part is specific for my needs but I will post it as an example.
var selected = [];
if ( $( e.element ).hasClass( 'mce-ga' ) ) { // this a class I add to all elements that have google fonts format
// Then I strip the classes from classList that I don't need and add the rest into an array (e.g ['roboto', '100'])
var gfont_options = $( e.element ).attr('class')
.replace('mce-ga', '')
.replace('mce-family-', '')
.replace('mce-weight-', '')
.trim()
.split(' ');
selected.push( gfont_options );
// At end I add the new value to listbox select[0][0] (e.g. 'roboto')
listbox.value(selected[0][0]);
}
});
}
And here is an example:

Get style value of selection in CKEditor

I am using CKEditor's editing capabilities, but with my own ui controls that calls into CKEditor's api to perform its commands. E.g.,
var style = new CKEDITOR.style({
element: 'span',
attributes: {
'style': 'font-size: 20px'
}
});
editor.applyStyle(style);
to set the font size of the selected text.
Problem is that I need a way to know the status of the currently selected text so I can update the controls accordingly. Is it bold? Then the bold button should be in an activated state, and clicking it should remove the boldness instead of attempting to add it again.
Is there a way to query CKEditor for certain style attributes of the currently selected text? Much like how tinymce.activeEditor.queryCommandValue('bold') works in tinyMCE.
Usually, the best way to create a button-command-style trio is like it is done in the basicstyles plugin:
var style = new CKEDITOR.style( { ... } );
editor.attachStyleStateChange( style, function( state ) {
!editor.readOnly && editor.getCommand( 'commandName' ).setState( state );
} );
editor.addCommand( 'commandName', new CKEDITOR.styleCommand( style ) );
editor.ui.addButton( 'buttonName', {
label: 'buttonLabel',
command: 'commandName'
} );
This code will take care of everything - the command and the button state will be updated according to selection changes. You can also get the command state easily:
editor.getCommand( 'commandName' ).state; // Returns on of CKEDITOR.TRISTATE_*.
However, if you want to query the state of the style directly, then you can use the style.checkActive() method:
style.checkActive( editor.elementPath(), editor );
You don't need to create command and buttons for this to work.
Edit
The CKEditor styles system has its limitations. For example, you cannot have variable font size in the style. This means that to check the current font size you need to do a quick search in the DOM:
function getFontSize() {
var span = editor.elementPath().contains( isFontSizeSpan );
return span ? span.getStyle( 'font-size' ) : null;
function isFontSizeSpan( el ) {
return el.is( 'span' ) && el.getStyle( 'font-size' );
}
}
Now, just use this method in an editor#selectionChange event listener to update your control's value.

CKEditor Inline selection wrapping

I'm looking for a way to add a inline span element with attributes to a selection.
The hard part of this is getting it working with selections that pass over multiple block level elements.
I was looking in the sourcecode of the StyleCombobox and found this line.
var style = styles[ value ],
elementPath = editor.elementPath();
editor[ style.checkActive( elementPath ) ? 'removeStyle' : 'applyStyle' ]( style );
This way it already works on multiple block level elements.
The only thing is that i would like to apply attributes to the span that is made around the multiple selections for different block level elements instead of applying a style element.
Does anyone know how this can be done?
I used this as solution.
It is indeed possible to set attributes and element type.
this wasn't defined in the api. I found this in the CKEditor 3.0 api (older version)
var style = new CKEDITOR.style({attributes: {name:"changed"}});
editor.applyStyle(style);
The latest Solution for your Problem.
Get Selected Text:
editor.getSelection().getSelectedText();
Put tags and attributes
editor.applyStyle(new CKEDITOR.style({
element : 'span',
attributes : {'class':'YourClass','data-Otherattr':'otherattrvalue'},
style : {'background-color':'gray'}
});
);

IE doesn't apply dynamically loaded CSS

It appears as though IE (older versions at least) does not apply CSS that is loaded dynamically. This can be a pain point if you load a page containing CSS via ajax into a "lightbox" or "colorbox".
For example, say your HTML page has a div named "taco":
<style>#taco {color:green;}</style>
<div id="taco">Hola Mundo!</div>
"Hola Mundo!" will be green since the CSS was included in the original HTML page. Then some Javascript happens and appends this to "taco":
<style>#taco {color:green;}</style>
<div id="taco">
Hola Mundo!
<style>#burrito {color:red;}</style>
<span id="burrito">mmmm burrito</span>
</div>
In all browsers except IE, burrito's font will be red.
So is there a way to do this in IE? It seems as though there is not.
The style tag is only allowed in the head section. Placing it somewhere else is simply invalid and that has nothing to do with IE.
More information.
By the way, to solve your problem if you canĀ“t put the styles in a global style-sheet, you can use the 'style' attribute to modify elements:
<p style="...">
Or you can use an iframe but then you'd have to serve a whole page instead of just a few tags.
You might want to start using jQuery's .CSS methed for dynamic style changes like that.
$("#jane").css('color', '#0F0');
Or just plain jane Javascript:
document.getElementById['sally'].style.color = '#0F0';
EDIT:
Have your ajax inject this:
<div id="jane">
<div id="sally">Hi, I'm Sally!</div>
<script>document.getElementById['sally'].style.color = '#0F0';</script>
</div>
Or Why not just inject elements with inline styles computed server side?:
<div id="jane">
<div id="sally" style="color:#0F0">Hi, I'm Sally!</div>
</div>
If there is no way to do this, and you don't want to change your server-side code, here is a way for very simple style elements:
// In the callback function, let's assume you're using jQuery
success: function( data ) {
// Create a dummy DOM element
var el = document.createElement( 'div' );
// Add the html received to this dummy element
el.innerHTML = data;
// so that you can select its html:
var s = $( 'style', el ).text();
// Delegate to another function, it's going to get messy otherwise
addRules( s );
}
function addRules( s ) {
// First, separate your strings for each line
var lines = s.split( '\n' ),
// Declare some temporary variables
id,
rule,
rules;
// Then, loop through each line to handle it
$.each( lines, function() {
id = $( this ).split( ' ' )[ 0 ];
// Get the rules inside the brackets, thanks #Esailija
rules = /\{\s*([^}]*?)\s*\}/.exec( $( this ) )[ 1 ];
// Split the rules
rules = rules.split( ';' );
$.each( rules, function() {
rule = $( this ).split( ':' );
// Apply each rule to the id
$( id ).css( $.trim( rule[ 0 ] ), $.trim( rule[ 1 ] ) );
} );
} );
}
So, yeah, basically I'm making a CSS parser.
This is a very basic parser however.
It will parse the following rules only:
#some-id { some: rule; another: rule; }
#other-id { some: rule; yet: another; rule: baby; }
If you load a linked stylesheet dynamically (via AJAX) into a webpage, IE < 8 does not even recognize the LINK tag.
If you load a SCRIPT tag dynamically IE < 8 will not parse it.
Jeron is correct, the only way to dynamically load HTML and have it styled is via iframe, but I am testing the idea of reflowing the container.

Categories