Reputation: 1843
TinyMCE is a great tool and it has solved many problems for us. However there is a problem that has been difficult to solve. While TinyMCE will change the size of the font of items in a list it doesn't change the size of the bullets (unordered list) or numbers (ordered list) that proceed those items.
What the user winds up with is something that looks like this:
As you can see in the image, the size of the fonts in the two lists are different but the size of the bullets is the same.
Does anyone know how to get TinyMCE to change the bullets to match the font?
Upvotes: 8
Views: 4689
Reputation: 71
Following is what works for me, All above failed for me as test required NOT selection but very start of list should be based on Font Size selected
editor.on('ExecCommand', function checkListNodes(evt) {
var cmd = evt.command;
var val = evt.value;
var node = evt.target.selection.getNode();
var nodeParent = node.parentNode;
if (cmd === 'FontSize' || cmd === 'FontName') {
if (node.nodeName === 'SPAN') {//(nodeParent.parentNode.nodeName === 'LI')
{
var whileNode = node;
var count = 1;//dont want to be endless for with no list in editor
while (whileNode.nodeName !== 'LI' && count<6) {
whileNode = whileNode.parentNode;
count++;
}
editor.dom.setStyle(nodeParent.parentNode, 'font-size', val);
}
else if (node.nodeName === 'UL' || node.nodeName === 'OL')
{
var li = editor.dom.select('li', node);
if (cmd === 'FontSize') {
editor.dom.setStyle(li, 'font-size', val);
}
if (cmd === 'FontName') {
editor.dom.setStyle(li, 'font-family', val);
}
}
}
//if (cmd === 'InsertOrderedList' || cmd === 'InsertUnorderedList') {
// var fontSize = $("span.tox-tbtn__select-label:eq(1)").text().replace('pt', '');
//}
});
Upvotes: 0
Reputation: 1
This worked for me
tinymce.init({
init_instance_callback: function (editor) {
editor.on('ExecCommand', function (e) {
var node = editor.selection.getNode();
if (node) {
var children = $(node).children("li");
if (children) {
children.removeAttr('data-mce-style');
children.css("font-size", e.value);
}
}
});
}
});
Upvotes: 0
Reputation: 11
As S.P. mentions, TinyMCE wraps inner <li>
content with a <span>
that includes the style set in the editor. You can target that span and copy the style over to the matching <li>
programmatically:
$('.content-custom li').each(function() {
var spanStyle = $(this).find('span').attr('style');
$(this).attr('style', spanStyle);
});
Upvotes: 1
Reputation: 11
tinymce.on('AddEditor', function(ea) {
ea.editor.on('ExecCommand',function(e) {
var cmd = e.command;
var val = e.value;
var node = e.target.selection.getNode();
var nodeParent = node.parentNode;
nodeParent$ = $(nodeParent);
node$=$(node);
if (cmd === "FontSize" || cmd === "FontName") {
while(nodeParent.nodeName !='LI' && nodeParent.nodeName!='BODY'){
nodeParent = nodeParent.parentNode;
}
nodeParent$ = $(nodeParent);
if(node.nodeName==='OL' || node.nodeName==='UL'){
if(cmd === "FontSize") {
$(node.children).each(function (){
$(this).css('font-size',val);
});
}
if(cmd === "FontName") {
$(node.children).each(function (){
$(this).css('font-family',val);
});
}
}
if (nodeParent.nodeName === "LI" ) {
nodeParent$.removeAttr('data-mce-style');
if(cmd === "FontSize") {
nodeParent$.css('font-size',val);
}
if(cmd === "FontName") {
nodeParent$.css('font-family',val);
}
}
}
if(cmd==='mceToggleFormat' && e.value==='bold'){
while(nodeParent.nodeName !='LI' && nodeParent.nodeName!='BODY'){
nodeParent = nodeParent.parentNode;
}
nodeParent$ = $(nodeParent);
var strg=$(node).find('STRONG');
if(node.childNodes[0].nodeName==='LI' && $(node).find('STRONG').length >1)
{
$(node.children).each(function (){
$(this).css("font-weight", "bold");
});
}
else if(node.childNodes[0].nodeName==='LI' && $(node).find('STRONG').length ==0 ){
$(node.children).each(function (){
$(this).css("font-weight", "normal");
});
}
else if($(nodeParent).find('STRONG').length ==1)
{
if(nodeParent.nodeName==='LI'){
nodeParent$.css("font-weight", "bold");
}
}
else if($(nodeParent).find('STRONG').length ==0)
{
nodeParent$.css("font-weight", "normal");
}
}
});
});
Upvotes: 1
Reputation: 833
I have tweaked Steve's answer to be used in Typescript,
editor.on('ExecCommand', function(lob) {
contentBlockElement.text = editor.getContent({ format: 'raw' });
var cmd = lob.command;
if (cmd === "FontSize" || cmd === "FontName") {
var val = lob.value;
var node = lob.target.selection.getNode();
var nodeChild = node.childNodes;
if (node.nodeName === "UL" && nodeChild[0].nodeName === "LI") {
this.nodeChild$ = $(nodeChild);
this.nodeChild$.removeAttr('data-mce-style');
if (cmd === "FontSize") {
this.nodeChild$.css('font-size', val);
}
if (cmd === "FontName") {
this.nodeChild$.css('font-family', val);
}
}
}
});
Upvotes: 0
Reputation: 415
I have slightly edited Steve's answer to use tinymce domutils instead of jquery. I've also added check for the whole list selection:
ed.on('ExecCommand', function checkListNodes(evt) {
let cmd = evt.command;
if (cmd === 'FontSize' || cmd === 'FontName') {
let val = evt.value;
let node = evt.target.selection.getNode();
let nodeParent = node.parentNode;
if (node.nodeName === 'SPAN' && nodeParent.nodeName === 'LI') {
if (cmd === 'FontSize') {
ed.dom.setStyle(nodeParent, 'font-size', val);
}
if (cmd === 'FontName') {
ed.dom.setStyle(nodeParent, 'font-family', val);
}
} else if (node.nodeName === 'UL' || node.nodeName === 'OL') {
let li = ed.dom.select('li', node);
if (cmd === 'FontSize') {
ed.dom.setStyle(li, 'font-size', val);
}
if (cmd === 'FontName') {
ed.dom.setStyle(li, 'font-family', val);
}
}
}
});
Note that this, unfortunately, will not work for color change. More info is here Can't catch the ForeColor command anymore, tinymce 4.1.4
Upvotes: 5
Reputation: 4908
Bernhard's solution didn't work for me in TinyMCE 4.1.7 but the code below does. I included a bit of context to hopefully make it as clear as possible.
This is from a website builder. The user opens an editor by right-clicking the DIV they want to edit and selecting "text" from the context menu. This executes a tinymce.init that attaches an inline edit panel to the DIV. Control comes here when the editor has been added.
The first editor.on
lays in a callback to catch the end of the editor creation and at that time fires focusin to show the editor. The second editor.on
catches a change to a span inside an li and makes the update to the li. The third editor.on
catches the editor closing.
/************************************************************************************/
/* TinyMCE Events */
/************************************************************************************/
tinymce.on('AddEditor', function(e) {
// Once editor has been added show it by firing 'focusin' instead of waiting for a click
e.editor.on('NodeChange',function(e) {
e.target.fire('focusin'); // show the editor
});
// Update parent <li> to match a font-size or font-family change in text
e.editor.on('ExecCommand',function(e) {
var cmd = e.command;
if (cmd === "FontSize" || cmd === "FontName") {
var val = e.value;
var node = e.target.selection.getNode(); // editor in this event object is at target
var nodeParent = node.parentNode;
if (node.nodeName === "SPAN" && nodeParent.nodeName === "LI") {
// We're changing the style of a <span> that's inside an <li>.
// Change the <li> to match the new font-size or font-family.
// (B, U, and forecolor buttons don't come here so we can't update li here for those)
nodeParent$ = $(nodeParent);
nodeParent$.removeAttr('data-mce-style');
if(cmd === "FontSize") {
nodeParent$.css('font-size',val);
}
if(cmd === "FontName") {
nodeParent$.css('font-family',val);
}
}
}
});
// When editor is removed (by clicking in a blank area of the inline panel)
// restore draggability to the DIV (had to kill before tinymce.init because draggability
// and contenteditable don't work together).
e.editor.on('RemoveEditor',function(e) {
g.currentElement$.attr('editor_state', "off")
.draggable('enable') // make DIV draggable again
.removeClass('textCursor'); // give DIV back its pointer cursor
});
});
Upvotes: 2
Reputation: 11
I've worked on the issues and added some nice features. This works for me now:
ed.onExecCommand.add(function(editor, cmd, ui, val) {
if (cmd === "FontSize" || cmd === "FontName" || cmd === "ForeColor" || cmd === "Bold" || cmd === "Italic") {
var node = editor.selection.getNode();
if (node) {
var children = $(node).closest("li");
if(children.length == 0)
var children = $(node).find("li");
if (children) {
children.removeAttr('data-mce-style');
if(cmd === "FontSize")
children.css("font-size", val);
if(cmd === "FontName")
children.css("font-family", val);
if(cmd === "ForeColor")
children.css("color", val);
if(cmd === "Bold") {
if(children.find("strong").length > 0) {
children.removeAttr('data-mce-style');
children.css("font-weight", "bold");
} else {
children.removeAttr('data-mce-style');
children.css("font-weight", "normal");
}
}
if(cmd === "Italic") {
if(children.find("em").length > 0) {
children.removeAttr('data-mce-style');
children.css("font-style", "italic");
} else {
children.removeAttr('data-mce-style');
children.css("font-style", "normal");
}
}
}
}
}
if (cmd === "InsertOrderedList" || cmd === "InsertUnorderedList") {
var node = editor.selection.getNode();
if (node) {
$(node).find("li").each(function() {
var children = $(this).find("span:first");
if (children.length > 0) {
$(this).removeAttr('data-mce-style');
if(children.css("font-size") != "undefined")
$(this).css("font-size", children.css("font-size"));
if(children.css("font-family") != "undefined")
$(this).css("font-family", children.css("font-family"));
if(children.css("color") != "undefined")
$(this).css("color", children.css("color"));
if($(this).find("em").length > 0)
$(this).css("font-style", "italic");
if($(this).find("strong").length > 0)
$(this).css("font-weight", "bold");
}
});
}
}
});
Upvotes: 1
Reputation: 89
This works for me:
on tinyMCE.init I've added a callback on setup:
setup: function(ed) {
ed.onKeyDown.add(function(ed, e) {
tinyMceKeyDownCallbacks(ed,tiny_id);
});
}
then the jquery functions that update every li having a span with their span class and or style:
function tinyMceKeyDownCallbacks(inst,tiny_id){
var spans = $(inst.getBody()).find("li span");
console.log("S: "+spans.length);
spans.each(function(){
var span = $(this);
span.parents('li').addClass(span.attr('class'));
span.parentsUntil('li').attr('style',span.attr('style'));
});
}
Upvotes: 1
Reputation: 1843
After searching the TinyMCE forums here and here I came up with this solution.
tinyMCE.onAddEditor.add(function(manager, editor) {
// TinyMCE doesn't change the font of the li portions of the list,
// we have do that ourselves here. See http://www.tinymce.com/forum/viewtopic.php?id=26100
editor.onExecCommand.add(function(editor, cmd, ui, val) {
if (cmd === "FontSize") {
var node = editor.selection.getNode();
if (node) {
var children = $(node).children("li");
if (children) {
// TinyMCE keeps an attribute that we want it to recompute,
// clear it. See http://www.tinymce.com/forum/viewtopic.php?id=25676
children.removeAttr('data-mce-style');
children.css("font-size", val);
}
}
}
});
});
Upvotes: 6
Reputation: 3054
Since TinyMCE wraps everything in span. To circumvent problems like you have had I have done this :
<ol>
<li style="font-size: <something you want>;">one</li>
<li style="font-size: <something you want>;">two</li>
</ol>
Upvotes: 0