lambmj
lambmj

Reputation: 1843

How to set the font size of list item bullets and numbers in tinyMCE?

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:

Item fonts change but bullet fonts do not change

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

Answers (11)

AbhishekS
AbhishekS

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

Raj
Raj

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

mbaldo
mbaldo

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

Deepak
Deepak

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

SoundStage
SoundStage

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

alniks
alniks

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

Steve
Steve

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

Bernhard
Bernhard

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

adedip
adedip

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

lambmj
lambmj

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

S.P.
S.P.

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

Related Questions