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,...