Reputation: 1107
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
Reputation: 1107
Finally, I have figured out a workaround to achieve my needs as mentioned below.
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
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