JSFiddle - React, Tailwind, and code Playground
by ivanchaer
HTML
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<div class="col col1">
<h2>reference</h2>
<h4>This is just a reference. Edit the right column.</h4>
<div class="reference">
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi provident, nemo incidunt voluptate officia, ipsa nulla itaque laudantium aperiam cupiditate vero, nesciunt consequuntur, facilis aliquam enim quis ad. Fugiat, magni.
</p>
</div>
</div>
<div class="col col2">
<h2>editable</h2>
<h4>Click the paragraph text below to start to edit.</h4>
<div contenteditable="true" class="editable" id="editable">
<p>
<!-- Text will be copied from the reference div -->
</p>
</div>
</div>
CSS
div.col {
width: 50%;
overflow: hidden;
font-size: 1.2em;
float: left;
box-sizing: border-box;
padding: 20px;
}
p {
overflow: hidden;
}
div.reference p {
text-align: justify;
}
div span {
display: block;
float: left;
}
.first-line-char {
content: ' ';
display: block;
clear: left;
}
.last-line-space {
display: none;
}
JavaScript
var selectors = {
'wrapper': '#editable',
'paragraphs': '#editable > p',
'spans': '#editable > p > span'
}
function get_cursor_position(element) {
var caretOffset = 0;
var doc = element.ownerDocument || element.document;
var win = doc.defaultView || doc.parentWindow;
var sel;
if (typeof win.getSelection != "undefined") {
sel = win.getSelection();
if (sel.rangeCount > 0) {
var range = win.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
}
} else if ((sel = doc.selection) && sel.type != "Control") {
var textRange = sel.createRange();
var preCaretTextRange = doc.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
function set_cursor_position(pos) {
if (document.selection) {
sel = document.selection.createRange();
sel.moveStart('character', pos);
sel.select();
} else {
sel = window.getSelection();
sel.collapse($(selectors['spans'])[pos].firstChild, 0);
}
}
function set_cursor_position_to_element(el) {
if (document.selection) {
sel = document.selection.createRange();
sel.moveStart('character', pos);
sel.select();
} else {
sel = window.getSelection();
sel.collapse(el, 0);
}
}
function justify(wrapper_selector, children_selector) {
var line_width = 0,
first_line_char = 0,
wrapper = $(wrapper_selector),
wrapper_width = wrapper.width(),
children = $(children_selector),
position_of_last_space_found,
filled_line_width_at_last_space_found;
// refresh
children.removeAttr("padding-right").removeClass("spaced first-line-char last-line-space");
for (var space_positions = [], l = children.length,...