TinyMce has a noneditable plugin that allows to make an element non editable. If an element has the mceNonEditable
class, then TinyMce will make the element non editable.
I want to be able to wrap this non editable element with basic styling tags.
For example if I have :
Hello <span class="mceNonEditable">user_name</span> how are you today ?
If I click on user_name
to select the non editable span and click on the TinyMce Blod button.
I would like the result to be :
Hello <b><span class="mceNonEditable">user_name</span></b> how are you today ?
But instead of this, nothing happens. When I click the TinyMce Blod button, the code doesn't change.
I created a small jsFiddle to demonstrate this : https://jsfiddle.net/timotheejeannin/2hhpenm5/
data-mce-contenteditable
attribute to override the non editable behavior when a button is clicked. (See usage in TinyMce source code in DOMUtils.js line 1739)I really hope you can help!
I figured out a "slightly" less hacky way to do this. Essentially, I register a "BeforeExecCommand" event that, for certain events, removes the contenteditable attribute, allows the command to run, and readds the contenteditable false attribute in the "ExecCommand" event. Doing so allowed me to avoid having to custom handle the various possible events that I have seen in other proposed solutions. I have forked your original example to demonstrate the solution (and added a couple of additional formatting options and a "Variables" feature) which can be found here: https://jsfiddle.net/hunterae/8fsnv3h6/40/
Here are the most relevant pieces of the solution:
tinymce.init({
// Additional options here
setup: function (editor) {
var $ = tinymce.dom.DomQuery;
var nonEditableClass = editor.getParam('noneditable_noneditable_class', 'mceNonEditable');
// Register a event before certain commands run that will turn contenteditable off temporarilly on noneditable fields
editor.on('BeforeExecCommand', function (e) {
// The commands we want to permit formatting noneditable items for
var textFormatCommands = [
'mceToggleFormat',
'mceApplyTextcolor',
'mceRemoveTextcolor'
];
if (textFormatCommands.indexOf(e.command) !== -1) {
// Find all elements in the editor body that have the noneditable class on them
// and turn contenteditable off
$(editor.getBody()).find('.' + nonEditableClass).attr('contenteditable', null);
}
});
// Turn the contenteditable attribute back to false after the command has executed
editor.on('ExecCommand', function (e) {
// Find all elements in the editor body that have the noneditable class on them
// and turn contenteditable back to false
$(editor.getBody()).find('.' + nonEditableClass).attr('contenteditable', false);
});
},
init_instance_callback: function (editor) {
/*
The following two hacks fix some weirdness with the way the textcolor
plugin works - namely, it was attemping to apply color and background-color
directly on the element that had the noneditable css class on it instead of putting
a span around it as underline does.
*/
editor.formatter.get('forecolor')[0].exact = true;
editor.formatter.get('hilitecolor')[0].exact = true;
}
});
That is my workaround for that. Might be glitchy though.
tinyMCE.init({
/*your initializer settings*/
setup: function (ed) {
ed.on('ExecCommand', function(e) {
var selection = tinyMCE.activeEditor.selection.getContent();
var el = document.createElement( 'html' );
el.innerHTML = "<head></head><body>"+selection+"</body>";
var datapoints = Array.from(el.getElementsByClassName('mceNonEditable'));
if (datapoints.length>0) {
var styleToggle = function(key, value) {
var criteria = (datapoints.map(function(datapoint){
return (datapoint.style[key] == value);
}).reduce(function(a,b) {
return a&&b;
}));
if (criteria) {
datapoints.forEach(function(datapoint){
datapoint.style[key] = "";
datapoint.contentEditable = false;
});
} else {
datapoints.forEach(function(datapoint){
datapoint.style[key] = value;
datapoint.contentEditable = false;
});
};
}
switch (e.command) {
case 'mceToggleFormat':
switch (e.value) {
case 'bold':
styleToggle("font-weight", "bold");
break;
case 'italic':
styleToggle ("font-style", "italic");
break;
case 'strikethrough':
styleToggle ("text-decoration", "line-through");
break;
case 'underline':
styleToggle ("text-decoration", "underline");
};
tinyMCE.activeEditor.selection.setContent(el.children[1].innerHTML);
break;
case ("mceApplyTextcolor"):
styleToggle ("color", e.value);
tinyMCE.activeEditor.selection.setContent(el.children[1].innerHTML);
break;
case ("FontName"):
styleToggle ("font-family", e.value);
tinyMCE.activeEditor.selection.setContent(el.children[1].innerHTML);
break;
case ("FontSize"):
styleToggle ("font-size", e.value);
tinyMCE.activeEditor.selection.setContent(el.children[1].innerHTML);
break;
case ("RemoveFormat"):
datapoints.forEach(function(datapoint){
["font-weight", "font-style", "text-decoration",
"text-decoration", "color", "font-family", "font-size"].forEach(function(key){
datapoint.style[key]="";
})
datapoint.contentEditable = false;
});
tinyMCE.activeEditor.selection.setContent(el.children[1].innerHTML);
break;
};
}
});
/*more stuff*/
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With