maulik kansara
maulik kansara

Reputation: 1107

contenteditable div set font size in PX at cursor position

I have a contenteditable div and a combobx for various font size selection to apply on it.

I have done javascript implementation for changing font size for selected text but no idea on how to set font size for next user imput.

for example,

1) in a content editable div, user first select font size and then start typing then that selected fontsize should be applied on user input text.

2) user entered text "hello" now he change font size to 24px and type "world" then word "world" should be in font size 24 px.

Below is the HTML page with javascript code to apply font size on selected text.

    <!DOCTYPE html>
    <html>
    <head>
        <script type="text/javascript">
            function GetNextLeaf (node) {
                while (!node.nextSibling) {
                    node = node.parentNode;
                    if (!node) {
                        return node;
                    }
                }
                var leaf = node.nextSibling;
                while (leaf.firstChild) {
                    leaf = leaf.firstChild;
                }
                return leaf;
            }
    
            function GetPreviousLeaf (node) {
                while (!node.previousSibling) {
                    node = node.parentNode;
                    if (!node) {
                        return node;
                    }
                }
                var leaf = node.previousSibling;
                while (leaf.lastChild) {
                    leaf = leaf.lastChild;
                }
                return leaf;
            }
    
                // If the text content of an element contains white-spaces only, then does not need to colorize
            function IsTextVisible (text) {
                for (var i = 0; i < text.length; i++) {
                    if (text[i] != ' ' && text[i] != '\t' && text[i] != '\r' && text[i] != '\n')
                        return true;
                }
                return false;
            }
    
            function ColorizeLeaf (node, size) {
                if (!IsTextVisible (node.textContent))
                    return;
    
                var parentNode = node.parentNode;
                    // if the node does not have siblings and the parent is a span element, then modify its color
                if (!node.previousSibling && !node.nextSibling) {
                    if (parentNode.tagName.toLowerCase () == "span") {
                        //parentNode.style.color = color;
                        parentNode.style.fontSize = size+"px";
                        return;
                    }
                }
    
                    // Create a span element around the node
                var span = document.createElement("span");
                //span.style.color = color;
                span.style.fontSize = size + "px";
                var nextSibling = node.nextSibling;
    
                parentNode.removeChild (node);
                span.appendChild (node);
                parentNode.insertBefore (span, nextSibling);
            }
    
            function ColorizeLeafFromTo (node, size, from, to) {
                var text = node.textContent;
                if (!IsTextVisible (text))
                    return;
    
                if (from < 0)
                    from = 0;
                if (to < 0)
                    to = text.length;
    
                if (from == 0 && to >= text.length) {
                        // to avoid unnecessary span elements
                    ColorizeLeaf(node, size);
                    return;
                }
    
                var part1 = text.substring (0, from);
                var part2 = text.substring (from, to);
                var part3 = text.substring (to, text.length);
    
                var parentNode = node.parentNode;
                var nextSibling = node.nextSibling;
    
                parentNode.removeChild (node);
                if (part1.length > 0) {
                    var textNode = document.createTextNode (part1);
                    parentNode.insertBefore (textNode, nextSibling);
                }
                if (part2.length > 0) {
                    var span = document.createElement ("span");
                    //span.style.color = color;
                    span.style.fontSize = size+"px";
                    var textNode = document.createTextNode (part2);
                    span.appendChild (textNode);
                    parentNode.insertBefore (span, nextSibling);
                }
                if (part3.length > 0) {
                    var textNode = document.createTextNode (part3);
                    parentNode.insertBefore (textNode, nextSibling);
                }
            }
    
            function ColorizeNode (node, size) {
                var childNode = node.firstChild;
                if (!childNode) {
                    ColorizeLeaf(node, size);
                    return;
                }
    
                while (childNode) {
                        // store the next sibling of the childNode, because colorizing modifies the DOM structure
                    var nextSibling = childNode.nextSibling;
                    ColorizeNode(childNode, size);
                    childNode = nextSibling;
                }
            }
    
            function ColorizeNodeFromTo(node, size, from, to) {
                var childNode = node.firstChild;
                if (!childNode) {
                    ColorizeLeafFromTo(node, size, from, to);
                    return;
                }
    
                for (var i = from; i < to; i++) {
                    ColorizeNode(node.childNodes[i], size);
                }
            }
    
            function ColorizeSelection(size) {
    
                if (window.getSelection) {  // all browsers, except IE before version 9
                    var selectionRange = window.getSelection ();
    
                    if (selectionRange.isCollapsed) {
                       // no idea on how to apply font size here. at cursor point.
                    }                            
                    else {
                        var range = selectionRange.getRangeAt (0);
                            // store the start and end points of the current selection, because the selection will be removed
                        var startContainer = range.startContainer;
                        var startOffset = range.startOffset;
                        var endContainer = range.endContainer;
                        var endOffset = range.endOffset;
                            // because of Opera, we need to remove the selection before modifying the DOM hierarchy
                        selectionRange.removeAllRanges ();
    
                        if (startContainer == endContainer) {
                            ColorizeNodeFromTo(startContainer, size, startOffset, endOffset);
                        }
                        else {
                            if (startContainer.firstChild) {
                                var startLeaf = startContainer.childNodes[startOffset];
                            }
                            else {
                                var startLeaf = GetNextLeaf (startContainer);
                                ColorizeLeafFromTo(startContainer, size, startOffset, -1);
                            }
    
                            if (endContainer.firstChild) {
                                if (endOffset > 0) {
                                    var endLeaf = endContainer.childNodes[endOffset - 1];
                                }
                                else {
                                    var endLeaf = GetPreviousLeaf (endContainer);
                                }
                            }
                            else {
                                var endLeaf = GetPreviousLeaf (endContainer);
                                ColorizeLeafFromTo(endContainer, size, 0, endOffset);
                            }
    
                            while (startLeaf) {
                                var nextLeaf = GetNextLeaf (startLeaf);
                                ColorizeLeaf(startLeaf, size);
                                if (startLeaf == endLeaf) {
                                    break;
                                }
                                startLeaf = nextLeaf;
                            }
                        }
                    }
                }
                else {
                        // Internet Explorer before version 9
                    alert ("Your browser does not support this example!");
                }
            }
    
          

        </script>
    </head>
    <body contenteditable="true">
        Select some content on this page and use the buttons below to colorize the selected text.<br /><br />
        <button onclick="ColorizeSelection (12);">Font 12</button>
        <button onclick="ColorizeSelection (14);">Font 14</button>
        <button onclick="ColorizeSelection (18);">Font 18</button>
        <button onclick="ColorizeSelection (28);">Font 28</button>
        <br />
        <div>Some text for selection</div>
        <div contentEditable="true" id="editor"><b>Some bold text for selection.</b></div>
        <ul>
            <li>One </li>
            <li>Two </li>
            <li>Three </li>
            <li>Four </li>
        </ul>
    </body>
    </html>

Upvotes: 1

Views: 955

Answers (2)

maulik kansara
maulik kansara

Reputation: 1107

Finally, I have figured out a workaround to achieve my needs as mentioned below.

  • declared a variable "font_size" with default size as 14.
  • declared a click handler to trigger on key press
  • declared a function "updateFontSizeForNewText" to create new span element on key press and apply font size saved in above-mentioned variable.
  • append text by capturing pressed key into the newly created span.

The complete updated code is mentioned below.

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript">
        function GetNextLeaf(node) {
            while (!node.nextSibling) {
                node = node.parentNode;
                if (!node) {
                    return node;
                }
            }
            var leaf = node.nextSibling;
            while (leaf.firstChild) {
                leaf = leaf.firstChild;
            }
            return leaf;
        }

        function GetPreviousLeaf(node) {
            while (!node.previousSibling) {
                node = node.parentNode;
                if (!node) {
                    return node;
                }
            }
            var leaf = node.previousSibling;
            while (leaf.lastChild) {
                leaf = leaf.lastChild;
            }
            return leaf;
        }

        // If the text content of an element contains white-spaces only, then does not need to colorize
        function IsTextVisible(text) {
            for (var i = 0; i < text.length; i++) {
                if (text[i] != ' ' && text[i] != '\t' && text[i] != '\r' && text[i] != '\n')
                    return true;
            }
            return false;
        }

        function ColorizeLeaf(node, size) {
            if (!IsTextVisible(node.textContent))
                return;

            var parentNode = node.parentNode;
            // if the node does not have siblings and the parent is a span element, then modify its color
            if (!node.previousSibling && !node.nextSibling) {
                if (parentNode.tagName.toLowerCase() == "span") {
                    //parentNode.style.color = color;
                    parentNode.style.fontSize = size + "px";
                    return;
                }
            }

            // Create a span element around the node
            var span = document.createElement("span");
            //span.style.color = color;
            span.style.fontSize = size + "px";
            var nextSibling = node.nextSibling;

            parentNode.removeChild(node);
            span.appendChild(node);
            parentNode.insertBefore(span, nextSibling);
        }

        function ColorizeLeafFromTo(node, size, from, to) {
            var text = node.textContent;
            if (!IsTextVisible(text))
                return;

            if (from < 0)
                from = 0;
            if (to < 0)
                to = text.length;

            if (from == 0 && to >= text.length) {
                // to avoid unnecessary span elements
                ColorizeLeaf(node, size);
                return;
            }

            var part1 = text.substring(0, from);
            var part2 = text.substring(from, to);
            var part3 = text.substring(to, text.length);

            var parentNode = node.parentNode;
            var nextSibling = node.nextSibling;

            parentNode.removeChild(node);
            if (part1.length > 0) {
                var textNode = document.createTextNode(part1);
                parentNode.insertBefore(textNode, nextSibling);
            }
            if (part2.length > 0) {
                var span = document.createElement("span");
                //span.style.color = color;
                span.style.fontSize = size + "px";
                var textNode = document.createTextNode(part2);
                span.appendChild(textNode);
                parentNode.insertBefore(span, nextSibling);
            }
            if (part3.length > 0) {
                var textNode = document.createTextNode(part3);
                parentNode.insertBefore(textNode, nextSibling);
            }
        }

        function ColorizeNode(node, size) {
            var childNode = node.firstChild;
            if (!childNode) {
                ColorizeLeaf(node, size);
                return;
            }

            while (childNode) {
                // store the next sibling of the childNode, because colorizing modifies the DOM structure
                var nextSibling = childNode.nextSibling;
                ColorizeNode(childNode, size);
                childNode = nextSibling;
            }
        }

        function ColorizeNodeFromTo(node, size, from, to) {
            var childNode = node.firstChild;
            if (!childNode) {
                ColorizeLeafFromTo(node, size, from, to);
                return;
            }

            for (var i = from; i < to; i++) {
                ColorizeNode(node.childNodes[i], size);
            }
        }
        var font_size = 14;
        var selection_range;
        function ColorizeSelection(size) {

            if (window.getSelection) {  // all browsers, except IE before version 9
                var selectionRange = window.getSelection();

                if (selectionRange.isCollapsed) {
                    font_size = size;
                    document.getElementById("editor").addEventListener("keypress", clickHandler);
                    selection_range = selectionRange;
                }
                else {
                    var range = selectionRange.getRangeAt(0);
                    // store the start and end points of the current selection, because the selection will be removed
                    var startContainer = range.startContainer;
                    var startOffset = range.startOffset;
                    var endContainer = range.endContainer;
                    var endOffset = range.endOffset;
                    // because of Opera, we need to remove the selection before modifying the DOM hierarchy
                    selectionRange.removeAllRanges();

                    if (startContainer == endContainer) {
                        ColorizeNodeFromTo(startContainer, size, startOffset, endOffset);
                    }
                    else {
                        if (startContainer.firstChild) {
                            var startLeaf = startContainer.childNodes[startOffset];
                        }
                        else {
                            var startLeaf = GetNextLeaf(startContainer);
                            ColorizeLeafFromTo(startContainer, size, startOffset, -1);
                        }

                        if (endContainer.firstChild) {
                            if (endOffset > 0) {
                                var endLeaf = endContainer.childNodes[endOffset - 1];
                            }
                            else {
                                var endLeaf = GetPreviousLeaf(endContainer);
                            }
                        }
                        else {
                            var endLeaf = GetPreviousLeaf(endContainer);
                            ColorizeLeafFromTo(endContainer, size, 0, endOffset);
                        }

                        while (startLeaf) {
                            var nextLeaf = GetNextLeaf(startLeaf);
                            ColorizeLeaf(startLeaf, size);
                            if (startLeaf == endLeaf) {
                                break;
                            }
                            startLeaf = nextLeaf;
                        }
                    }
                }
            }
            else {
                // Internet Explorer before version 9
                alert("Your browser does not support this example!");
            }
        }

        function pasteHtmlAtCaret(html) {
            var sel, range;
            if (window.getSelection) {
                // IE9 and non-IE
                sel = window.getSelection();
                if (sel.getRangeAt && sel.rangeCount) {
                    range = sel.getRangeAt(0);
                    range.deleteContents();

                    // Range.createContextualFragment() would be useful here but is
                    // non-standard and not supported in all browsers (IE9, for one)
                    var el = document.createElement("div");
                    el.innerHTML = html;
                    var frag = document.createDocumentFragment(), node, lastNode;
                    while ((node = el.firstChild)) {
                        lastNode = frag.appendChild(node);
                    }
                    range.insertNode(frag);

                    // Preserve the selection
                    if (lastNode) {
                        range = range.cloneRange();
                        range.setStartAfter(lastNode);
                        range.collapse(lastNode);
                        sel.removeAllRanges();
                        sel.addRange(range);
                    }
                }
            } else if (document.selection && document.selection.type != "Control") {
                // IE < 9
                document.selection.createRange().pasteHTML(html);
            }
        }

        var clickHandler = function (event) {
            document.getElementById("editor").removeEventListener("keypress", clickHandler);
            updateFontSizeForNewText(event);
        };

        function updateFontSizeForNewText(e) {

            var timestamp = new Date().getUTCMilliseconds();
            var key="";
            if (isValidKeyPress(e)) {

                event.preventDefault();
                key = e.key;
                var span = document.createElement("span");
                span.id = timestamp;
                var txt = document.createTextNode(key);
                span.style.fontSize = font_size + "px";
                span.appendChild(txt);
                var wrap = document.createElement('div');
                wrap.appendChild(span.cloneNode(true));
                pasteHtmlAtCaret(wrap.innerHTML);
            }

        }
        function isValidKeyPress(e) {
            var keycode = e.keyCode;
            var valid =
                (keycode > 47 && keycode < 58) || // number keys
                (keycode > 64 && keycode < 91) || // letter keys
                (keycode > 95 && keycode < 112) || // numpad keys
                (keycode > 185 && keycode < 193) || // ;=,-./` (in order)
                (keycode > 218 && keycode < 223);   // [\]' (in order)
            return valid;
        }
    </script>
</head>
<body>
    Select some content on this page and use the buttons below to colorize the selected text.<br /><br />
    <button onclick="ColorizeSelection (12);">Font 12</button>
    <button onclick="ColorizeSelection (14);">Font 14</button>
    <button onclick="ColorizeSelection (18);">Font 18</button>
    <button onclick="ColorizeSelection (28)">Font 28</button>
    <!--<button onclick="ColorizeSelection ('#FF0000');">Set color to red!</button>
    <button onclick="ColorizeSelection ('#0000FF');">Set color to blue!</button>-->
    <br />
    <div>Some text for selection</div>
    <div contentEditable="true" id="editor"><b>Some bold text for selection.</b></div>
    <ul>
        <li>One </li>
        <li>Two </li>
        <li>Three </li>
        <li>Four </li>
    </ul>
</body>
</html>

Upvotes: 1

Rajit
Rajit

Reputation: 808

You're using the click event handler to trigger everything. At this point you calculate what is selected and go from there. The problem is, when you click on something anything that is selected is unselected. You lose any current selection due to click events triggering a change of focus!

Below I've changed your onclick handlers to onmousedown handlers. This gets the code working but might not be exactly what you want. The mousedown event triggers repeatedly for as long as any mouse button is pressed. You can either detect the mouseup event and ensure that you only run your code once until the next mouseup or there is a way you could adapt this to work with onclick. To do that, you can also implement an onselect handler.

With onselect, every time you make a selection the handler will run. You could fetch the current selection at this point and save it in a variable. Then, when the click handler fires you can check the saved variable, which will have the last known selection in it.

                function GetNextLeaf (node) {
                    while (!node.nextSibling) {
                        node = node.parentNode;
                        if (!node) {
                            return node;
                        }
                    }
                    var leaf = node.nextSibling;
                    while (leaf.firstChild) {
                        leaf = leaf.firstChild;
                    }
                    return leaf;
                }
        
                function GetPreviousLeaf (node) {
                    while (!node.previousSibling) {
                        node = node.parentNode;
                        if (!node) {
                            return node;
                        }
                    }
                    var leaf = node.previousSibling;
                    while (leaf.lastChild) {
                        leaf = leaf.lastChild;
                    }
                    return leaf;
                }
        
                    // If the text content of an element contains white-spaces only, then does not need to colorize
                function IsTextVisible (text) {
                    for (var i = 0; i < text.length; i++) {
                        if (text[i] != ' ' && text[i] != '\t' && text[i] != '\r' && text[i] != '\n')
                            return true;
                    }
                    return false;
                }
        
                function ColorizeLeaf (node, size) {
                    if (!IsTextVisible (node.textContent))
                        return;
        
                    var parentNode = node.parentNode;
                        // if the node does not have siblings and the parent is a span element, then modify its color
                    if (!node.previousSibling && !node.nextSibling) {
                        if (parentNode.tagName.toLowerCase () == "span") {
                            //parentNode.style.color = color;
                            parentNode.style.fontSize = size+"px";
                            return;
                        }
                    }
        
                        // Create a span element around the node
                    var span = document.createElement("span");
                    //span.style.color = color;
                    span.style.fontSize = size + "px";
                    var nextSibling = node.nextSibling;
        
                    parentNode.removeChild (node);
                    span.appendChild (node);
                    parentNode.insertBefore (span, nextSibling);
                }
        
                function ColorizeLeafFromTo (node, size, from, to) {
                    var text = node.textContent;
                    if (!IsTextVisible (text))
                        return;
        
                    if (from < 0)
                        from = 0;
                    if (to < 0)
                        to = text.length;
        
                    if (from == 0 && to >= text.length) {
                            // to avoid unnecessary span elements
                        ColorizeLeaf(node, size);
                        return;
                    }
        
                    var part1 = text.substring (0, from);
                    var part2 = text.substring (from, to);
                    var part3 = text.substring (to, text.length);
        
                    var parentNode = node.parentNode;
                    var nextSibling = node.nextSibling;
        
                    parentNode.removeChild (node);
                    if (part1.length > 0) {
                        var textNode = document.createTextNode (part1);
                        parentNode.insertBefore (textNode, nextSibling);
                    }
                    if (part2.length > 0) {
                        var span = document.createElement ("span");
                        //span.style.color = color;
                        span.style.fontSize = size+"px";
                        var textNode = document.createTextNode (part2);
                        span.appendChild (textNode);
                        parentNode.insertBefore (span, nextSibling);
                    }
                    if (part3.length > 0) {
                        var textNode = document.createTextNode (part3);
                        parentNode.insertBefore (textNode, nextSibling);
                    }
                }
        
                function ColorizeNode (node, size) {
                    var childNode = node.firstChild;
                    if (!childNode) {
                        ColorizeLeaf(node, size);
                        return;
                    }
        
                    while (childNode) {
                            // store the next sibling of the childNode, because colorizing modifies the DOM structure
                        var nextSibling = childNode.nextSibling;
                        ColorizeNode(childNode, size);
                        childNode = nextSibling;
                    }
                }
        
                function ColorizeNodeFromTo(node, size, from, to) {
                    var childNode = node.firstChild;
                    if (!childNode) {
                        ColorizeLeafFromTo(node, size, from, to);
                        return;
                    }
        
                    for (var i = from; i < to; i++) {
                        ColorizeNode(node.childNodes[i], size);
                    }
                }
                
                function UpdateCurrentSelection(event) {
                  var selection = window.getSelection();
                  
                }
        
                function ColorizeSelection(size) {
                    if (window.getSelection) {  // all browsers, except IE before version 9
                        var selectionRange = window.getSelection ();
        
                        if (selectionRange.isCollapsed) {
                           // no idea on how to apply font size here. at cursor point.
                        }                            
                        else {
                            var range = selectionRange.getRangeAt (0);
                                // store the start and end points of the current selection, because the selection will be removed
                            var startContainer = range.startContainer;
                            var startOffset = range.startOffset;
                            var endContainer = range.endContainer;
                            var endOffset = range.endOffset;
                                // because of Opera, we need to remove the selection before modifying the DOM hierarchy
                            selectionRange.removeAllRanges ();
        
                            if (startContainer == endContainer) {
                                ColorizeNodeFromTo(startContainer, size, startOffset, endOffset);
                            }
                            else {
                                if (startContainer.firstChild) {
                                    var startLeaf = startContainer.childNodes[startOffset];
                                }
                                else {
                                    var startLeaf = GetNextLeaf (startContainer);
                                    ColorizeLeafFromTo(startContainer, size, startOffset, -1);
                                }
        
                                if (endContainer.firstChild) {
                                    if (endOffset > 0) {
                                        var endLeaf = endContainer.childNodes[endOffset - 1];
                                    }
                                    else {
                                        var endLeaf = GetPreviousLeaf (endContainer);
                                    }
                                }
                                else {
                                    var endLeaf = GetPreviousLeaf (endContainer);
                                    ColorizeLeafFromTo(endContainer, size, 0, endOffset);
                                }
        
                                while (startLeaf) {
                                    var nextLeaf = GetNextLeaf (startLeaf);
                                    ColorizeLeaf(startLeaf, size);
                                    if (startLeaf == endLeaf) {
                                        break;
                                    }
                                    startLeaf = nextLeaf;
                                }
                            }
                        }
                    }
                    else {
                            // Internet Explorer before version 9
                        alert ("Your browser does not support this example!");
                    }
                }
        
              
        <!DOCTYPE html>
        <html>
        <body contenteditable="true">
            Select some content on this page and use the buttons below to colorize the selected text.<br /><br />
            <button onmousedown="ColorizeSelection (12);">Font 12</button>
            <button onmousedown="ColorizeSelection (14);">Font 14</button>
            <button onmousedown="ColorizeSelection (18);">Font 18</button>
            <button onmousedown="ColorizeSelection (28);">Font 28</button>
            <br />
            <div>Some text for selection</div>
            <div contentEditable="true" id="editor"><b>Some bold text for selection.</b></div>
            <ul>
                <li>One </li>
                <li>Two </li>
                <li>Three </li>
                <li>Four </li>
            </ul>
        </body>
        </html>

Upvotes: 0

Related Questions