Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <style>
  #editor {
    border: 1px solid black;
    min-height: 150px;
  }
  </style>
</head>
<body>
<p>DOM Changes in Editor: <span id="counter">0</span></p>
<div id="editor" contenteditable="true" >
  <h1>Composition in Shadow Root</h1>
  <p>This is to try the capabilities <b>of</b> using the <i>Shadow</i> DOM for IME so that the
    DOM is not updated during character composition.</p>
</div>
<script>
var editor = document.getElementById('editor'),
  beforeCompositionRange,
  compositionShadowRoot,
  selection = window.getSelection(),
  getRange = function (range) {
    var selectedElement,
      pathElement,
      rangeDes = {
        start: {
          path: [],
          offset: range.startOffset
        },
        end: {
          path: [],
          offset: range.endOffset
        }
      };
    selectedElement = range.startContainer;
    pathElement = 0;
    while (selectedElement != range.commonAncestorContainer) {
      while (selectedElement.previousSibling) {
        pathElement += 1;
        selectedElement = selectedElement.previousSibling;
      }
      rangeDes.start.path.push(pathElement);
      selectedElement = selectedElement.parentElement;
      pathElement = 0;
    }
    selectedElement = range.endContainer;
    pathElement = 0;
    while (selectedElement != range.commonAncestorContainer) {
      while (selectedElement.previousSibling) {
        pathElement += 1;
        selectedElement = selectedElement.previousSibling;
      }
      rangeDes.end.path.push(pathElement);
      selectedElement = selectedElement.parentElement;
      pathElement = 0;
    }
    return rangeDes;
  },
  setRange = function (rangeDes, element) {
    var range = document.createRange(),
    selectedElement,
    findPath;
    selectedElement = element;
    findPath = rangeDes.start.path.slice();
    while(findPath.length > 0) {
      selectedElement = selectedElement.childNodes[findPath.pop()];
    }
    range.setStart(selectedElement, rangeDes.start.offset);
    selectedElement = element;
    findPath = rangeDes.end.path.slice();
    while(findPath.length > 0) {
      selectedElement = selectedElement.childNodes[findPath.pop()];
    }
    range.setEnd(selectedElement, rangeDes.end.offset);
    return range;
  },
  moveCaret = function () {
    var beforeCompositionRange = selection.getRangeAt(0),
    rangeDes = getRange(beforeCompositionRange),
    pathElement = 0,
    moveCaretBack = function () {
      shadow.innerHTML ='<content>';
      selection.removeAllRanges();
      selection.addRange(beforeCompositionRange);
    },
    compositionShadowRoot = beforeCompositionRange.commonAncestorContainer,
    shadow, newRange, selectedElement;
    if (compositionShadowRoot.nodeType===3) {
      // start and end is in the same text node
      selectedElement = compositionShadowRoot;
      while (selectedElement.previousSibling) {
        pathElement += 1;
        selectedElement = selectedElement.previousSibling;
      }
      rangeDes.start.path.push(pathElement);
      rangeDes.end.path.push(pathElement);
      compositionShadowRoot = compositionShadowRoot.parentElement;
    }
    shadow = compositionShadowRoot.createShadowRoot(),
    cEShadow = document.createElement('span');
    cEShadow.setAttribute('contentEditable','true');
    cEShadow.innerHTML=compositionShadowRoot.innerHTML;
    shadow.appendChild(cEShadow);
    newRange = setRange(rangeDes, cEShadow);
    selection.removeAllRanges();
    selection.addRange(newRange);
    cEShadow.addEventListener('compositionend',moveCaretBack);
  };
editor.addEventListener('compositionstart',moveCaret);
// Observe changes
var observer = new MutationObserver(function(mutations) {
  changeCounter += 1;
  changeCounterElement.innerHTML = changeCounter;
}), changeCounter = 0, changeCounterElement = document.getElementById('counter');
observer.observe(editor, { attributes: true, childList: true, characterData: true, subtree: true });
</script>
</body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers