# 富文本编辑器
事件绑定到 document 的好处是,总是元素在运行js 还未加载,也能绑定成功。
# 参考资料
$document.on('keypress','.my_editor',function(e){
   if(e.keyCode==13){ //enter && shift
    e.preventDefault(); //Prevent default browser behavior
    if (window.getSelection) {
        var selection = window.getSelection(),
            range = selection.getRangeAt(0),
            br = document.createTextNode("\r\n"),
            textNode = document.createTextNode("\u00a0"); //Passing " " directly will not end up being shown correctly
        range.deleteContents();//required or not?
        range.insertNode(br);
        range.collapse(false);
        range.insertNode(textNode);
        range.selectNodeContents(textNode);
        selection.removeAllRanges();
        selection.addRange(range);
        return false;
    }
  }
})
$document.on('paste', '.my_editor pre',function(e) {
  e.preventDefault();
  var text = (e.originalEvent || e).clipboardData.getData('text/html') || prompt('Paste something..');
  var $result = $('<div></div>').append($(text));
  // insert text manually
  document.execCommand("insertHTML", false, $result.text());
});
# 阻止插入 div
$('div[contenteditable]').keydown(function(e) {
    // trap the return key being pressed
    if (e.keyCode === 13) {
      // insert 2 br tags (if only one br tag is inserted the cursor won't go to the next line)
      document.execCommand('insertHTML', false, '<br><br>');
      // prevent the default behaviour of return key pressed
      return false;
    }
  });
# 粘贴的解决方法 paste
$document.on('paste', '.my_editor pre',function(e) {
  var text = (e.originalEvent || e).clipboardData.getData('text/html') // 获取不到纯文本
  if (text) {
    e.preventDefault();
    var $result = $('<div></div>').append($(text))
    $.each($result.find("*"), function(index, value) {
      var $item = $(value),
          tag = $item.prop('tagName').toLowerCase()
      if (['pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'section', 'code'].indexOf(tag) > -1) {
        console.log($item)
        $item.replaceWith($('<div></div>').append($item.html()))
      }
      if ($item.length > 0) {
        $item.removeAttr('style').removeClass()
      }
    })
    // insert text manually
    document.execCommand("insertHTML", false, $result.html().trim());
  }
})
# Selection Node
Selection.anchorNode - Returns the Node in which the selection begins.
Selection.focusNode - Returns the Node in which the selection ends.
because there were debates on naming, baseNode is alias for anchorNode, extentNode for focusNode
- 监听,选择变化
 
document.onselectionchange = function() {
}
# 知识点
// firefox ok chrome 不支持
document.execCommand('heading', false, 'H1')
// 全部选中国
document.execCommand('formatBlock', false, '<h1>')