3

How to let execCommand using span and style attribute to styling in rich text instead of font tag and color attribute?

This is a simple example for what I need.

Output using execCommand: <font color="#ff0000">Lorem ipsum</font>.

Which outputs:<span style="color:#ff0000">Lorem ipsum</span>.

function exec(a, b) {
  document.execCommand(a, false, b);
  console.log(document.getElementById('editor').innerHTML);
}
#editor {
  box-shadow: 0 0 .3rem #aaa;
  padding: .5rem 1rem;
  margin: .5rem 0;
  min-height: 3rem;
}
<select onchange="exec('forecolor',this.value); this.selectedIndex=0;">
  <option class="heading" selected>- color -</option>
  <option value="red">Red</option>
  <option value="blue">Blue</option>
  <option value="green">Green</option>
  <option value="black">Black</option>
</select>
<div contenteditable="true" id="editor">
  Lorem ipsum
</div>
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
ferhado
  • 2,363
  • 2
  • 12
  • 35

3 Answers3

1

Unfortunately, I doubt you can; but you can easily fix it after-the-fact:

// ES5 version
document.querySelectorAll("font").forEach(function(font) {
    var span = document.createElement("span");
    var color = font.getAttribute("color");
    if (color) {
        span.style.color = color;
    }
    while (font.firstChild) {
        span.appendChild(font.firstChild);
    }
    font.parentNode.insertBefore(span, font);
    font.parentNode.removeChild(font);
});

Live example using ES2015+ features:

function exec(a, b) {
    console.log(a, b);
    document.execCommand(a, false, b);
    for (const font of document.querySelectorAll("font")) {
        const span = document.createElement("span");
        const color = font.getAttribute("color");
        if (color) {
            span.style.color = color;
        }
        while (font.firstChild) {
            span.appendChild(font.firstChild);
        }
        font.parentNode.insertBefore(span, font);
        font.parentNode.removeChild(font);
    }
    console.log(document.getElementById("editor").innerHTML);
}
#editor {
  box-shadow: 0 0 .3rem #aaa;
  padding: .5rem 1rem;
  margin: .5rem 0;
  min-height: 3rem;
}
<select onchange="exec('forecolor',this.value); this.selectedIndex=0;">
  <option class="heading" selected>- color -</option>
  <option value="red">Red</option>
  <option value="blue">Blue</option>
  <option value="green">Green</option>
  <option value="black">Black</option>
</select>
<div contenteditable="true" id="editor">
  Lorem ipsum
</div>

The above relies on the relatively-new forEach on NodeList (ES5) or NodeList being iterable (ES2015+). See this answer for notes on polyfilling as necessary.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks this was helpful. – ferhado Oct 13 '18 at 12:52
  • I found the right way to do that, I wanted to share it with you:
    `document.execCommand("styleWithCSS", true, null);`
    – ferhado Oct 17 '18 at 23:32
  • @FerhadOthman - Great! You should post that as an answer, ideally with a runnable Stack Snippet (the `[<>]` toolbar button) like the above; [here's how to do one](https://meta.stackoverflow.com/questions/358992/). Along with support notes (what browsers support it), etc. Then, if it's a better answer, you should accept it. (Yes, it's perfectly fine to answer your own question, and accept your own answer [the site makes you wait a couple of days], provided it's really different from the one(s) you already have.) Happy coding! – T.J. Crowder Oct 18 '18 at 06:28
0

I found the right way to do that, I wanted to share it. The solution was very easy, is just using document.execCommand("styleWithCSS", true, null);

ferhado
  • 2,363
  • 2
  • 12
  • 35
  • ...until you learn to test with different engines. Don't test different browsers, you need to test different engines. I built an entire Rich Editor, you should minimize your reliance on `execCommand` and stick to events and you'll go a long way for *consistent cross-browser output*. – John Apr 10 '20 at 20:27
  • I'd recommend checking out the link in my profile, I've built an entire web platform from scratch without frameworks or libraries. ;-) – John Apr 11 '20 at 10:39
  • It is listed, just under Twitter: https://stackoverflow.com/users/606371/john?tab=profile Perhaps SO is showing activity tab? – John Apr 12 '20 at 10:01
  • jabcreations.com – John Apr 13 '20 at 15:00
0

Here is what worked for me

document.getElementById('color-picker').addEventListener('change',()=>{
    var colorP = document.getElementById('color-picker').value;
    document.designMode = 'on';
    document.execCommand('stylewithCSS',false,true)
    document.execCommand('foreColor',false,colorP);
    document.designMode = 'off';
});