div content editable
by techtiger255
HTML
<div id="textarea" contenteditable>I look like a textarea</div>
CSS
#textarea {
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
border: 1px solid gray;
font: medium -moz-fixed;
font: -webkit-small-control;
height: 28px;
overflow: auto;
padding: 2px;
resize: both;
width: 400px;
white-space: pre-wrap;
}
JavaScript
class Selection {
constructor($container) {
this.$container = $container;
}
getSelection() {
if (window.getSelection) {
return window.getSelection().getRangeAt(0);
} else if (document.selection) {
return document.selection.createRange();
}
}
sumCurrentOffset(root, node, startOffset) {
for (let ele of Array.from(root.childNodes)) {
if (node === ele) {
break;
}
if (ele.contains(node)) {
const result = this.sumCurrentOffset(ele, node, 0);
startOffset += result;
break;
} else {
startOffset += ele.textContent.length;
}
}
return startOffset;
}
findNodeForPosition($container, currentOffset) {
let node;
({ node, currentOffset } = this.findNode(
$container.childNodes,
currentOffset
));
if (node.childNodes.length === 0) {
return { node, currentOffset };
} else {
return this.findNodeForPosition(node, currentOffset);
}
}
findNode(childNodes, currentOffset) {
for (let node of Array.from(childNodes)) {
if (currentOffset - node.textContent.length <= 0) {
return { node, currentOffset };
} else {
currentOffset -= node.textContent.length;
}
}
}
saveCurrentSelection() {
this.currentSelection = this.getSelection();
this.startOffset = this.currentSelection.startOffset;
this.currentOffset = this.sumCurrentOffset(
this.$container,
this.currentSelection.startContainer,
this.startOffset
);
}
restoreSelection() {
let node;
if (this.currentOffset === 0) {
return;
}
const range = document.createRange();
({ node, currentOffset: this.currentOffset } = this.findNodeForPosition(
this.$container,
this.currentOffset
));
range.setStart(node, this.currentOffset);
range.collapse(true);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
}