ReadViewSDK/Doc/WXRead/resources/js/Text/rich_editor.js
2026-05-21 19:40:51 +08:00

1711 lines
66 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (C) 2015 Wasabeef
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var KEY_LEFT = 37,
KEY_RIGHT = 39,
KEY_AT_CODE = 50,
KEY_HASH_CODE = 51,
KEY_BACKSPACE = 'U+0008',
KEY_BACKSPACE_CODE = 8,
KEY_AT_CHAR = '@',
KEY_HASH_CHAR = '#';
var RE = {};
RE.editor = document.getElementById('editor');
RE.fakeEditor = document.getElementById('fakeEditor');
RE.currentEditingLink; //当前光标前的link
RE.currentEditingAfterLink; //当前光标后的link
RE.currentEditingImage; //当前光标前的img
RE.lastInsertLink; // 最后一次插入的link
RE.dataSeparator = 'r_e_ds';
RE.faceSplitStrLeft = 'l_f_s';
RE.faceSplitStrRight = 'r_f_s';
RE.originalHTML = '';
RE.hasSelectionChange = 0;
RE.currentSelection = {
'startContainer': 0,
'startOffset': 0,
'endContainer': 0,
'endOffset': 0
};
RE.init = function() {
RE.editor.classList.add('re_iOS');
// 统一段落标签为p
document.execCommand('defaultParagraphSeparator', false, 'p');
}
RE.insertAfter = function(newElement, targetElement) {
if (targetElement.parentNode) {
var parent = targetElement.parentNode;
if (targetElement.nextSibling) {
parent.insertBefore(newElement, targetElement.nextSibling);
} else {
parent.appendChild(newElement);
}
}
}
RE.isSpecifiedTag = function(node, tagName) {
if (!node) {
return false;
}
if (tagName instanceof Array) {
return tagName.indexOf(node.nodeName.toLowerCase()) < 0 ? false : true;
}
return node.nodeName.toLowerCase() == tagName;
}
RE.isInTag = function(node, targetTagName) {
// 判断光标是否在指定标签内并返回相应的node
var result = null;
if (typeof(node) == 'undefined') {
return result;
}
if(targetTagName instanceof Array){
for(var i = 0; i<targetTagName.length; i++){
var tagName = targetTagName[i];
result = checkIf(node, tagName);
if(result){
break;
}
}
}else{
var result = checkIf(node, targetTagName);
}
return result;
function checkIf(node, targetTagName){
if (RE.isSpecifiedTag(node, targetTagName)) {
// 坑:
// 要从自己开始匹配不能直接从parentElement开始匹配。
// 例如当点击引用的时候没输入内容之前取消引用这个时候无法取消引用因为传进来的note和targetTagName一样
return {
'is': true,
'tagNode': node
}
} else {
var p = node.parentNode;
while (p && (!RE.isSpecifiedTag(p, targetTagName) && !RE.isSpecifiedTag(p, 'body'))) {
p = p.parentElement
}
if (RE.isSpecifiedTag(p, targetTagName)) {
return {
'is': true,
'tagNode': p
}
} else {
return false;
}
}
}
};
RE.nodeIndexInParent = function(node) {
return Array.prototype.indexOf.call(node.parentNode.childNodes, node);
}
RE.updatePlaceholder = function(){
if(RE.isHTMLEmpty()){
RE.editor.classList.add('re_placeholder');
}else{
RE.editor.classList.remove('re_placeholder');
}
}
// Initializations
RE.editor.addEventListener('input', function(e) {
// 编辑器首行包个p这里用js在设置一次是因为
// 单纯在html写一个p是可以被删除的
if(RE.getHtml().length == 0){
RE.setHeading('p',false);
RE.editor.classList.add('re_placeholder');
}else{
RE.editor.classList.remove('re_placeholder');
// 在编辑器最末尾补一个空行
if (RE.editor.lastChild) {
var lastChild = RE.editor.lastChild;
if (lastChild.tagName && (lastChild.tagName.toLowerCase() == 'p') && (lastChild.innerHTML == '<br />' || lastChild.innerHTML == '<br>' || lastChild.innerHTML.length == 0)) {
} else {
var newEmptyLine = RE.generateEmptyPara();
RE.editor.appendChild(newEmptyLine);
}
}
}
// 判断图片所处段落中图片前后有没有文字补充相应的class
RE.addImgMarginForSiblingText();
});
RE.addImgMarginForSiblingText = function(){
// 输入时判断当前node文字或段落有没有包含img有的话再按需要加上margin
var sel = window.getSelection(),
currentNode = sel.focusNode,
targetContainer;
if(currentNode.nodeType == 3){
targetContainer = currentNode.parentNode;
}else if((currentNode.nodeType == 1) && (currentNode.nodeName.toLowerCase() != 'br')){
targetContainer = currentNode;
}
if(targetContainer.querySelectorAll('.re_img').length > 0){
var tempDom = document.createElement('p'),
imgs = targetContainer.querySelectorAll('.re_img');
tempDom.innerHTML = targetContainer.innerHTML;//做这一步是为了保证拿到正确的sibling避免移动光标导致文字node被切割成单独一个字符的node
for(var i=0; i<imgs.length; i++){
var img = imgs[i],
id = img.getAttribute('data-id');
var tempImg = tempDom.querySelector('[data-id="'+id+'"]'),
tempImgNext = tempImg.nextSibling,
tempImgPrev = tempImg.previousSibling;
console.log(tempImg.previousSibling)
console.log(tempImg.nextSibling)
if(tempImgPrev){
img.classList.add('re_img_MarginTop');
}else{
img.classList.remove('re_img_MarginTop');
}
if(tempImgNext){
img.classList.add('re_img_MarginBottom');
}else{
img.classList.remove('re_img_MarginBottom');
}
// 这些class在发布的时候需要去掉
}
}
}
RE.editor.addEventListener('compositionupdate', function(e) { //奇技淫巧存在一个问题就是系统输入法汉字输入的时候会有联想字符串如果没有选择联想字符而是直接选择topic或者username面板替换link的内容再次编辑的时候由于上次联系的过程没有打断同时联想的内容已经没有了光标会跑出街这里做的是如果发现出界了restorage回来
var selection = window.getSelection();
if (selection && selection.anchorNode == selection.focusNode && !selection.anchorNode.parentNode && selection.anchorNode != RE.editor) {
RE.restorerange();
}
});
document.addEventListener('selectionchange', function(e) {
if (RE.isFocus()) {
RE.backuprange();
}
RE.contentChanged(e);
if ((window.getSelection().toString().length <= 0 && RE.isFocus())){
RE.calculateEditorHeightWithCaretPosition();
}
});
// 将编辑框滚动到正确的位置
RE.calculateEditorHeightWithCaretPosition = function() {
var currentSelectionY = RE.getCaretYPosition();
var scrollOffsetY = window.document.body.scrollTop;
var containerHeight = document.documentElement.clientHeight;
var newPosotion = window.pageYOffset;
if (currentSelectionY - RE.preSpanHeight < scrollOffsetY) {
// 这里滚到光标头部位置
// 光标所在位置被滚动到顶部
newPosotion = currentSelectionY - RE.preSpanHeight;
window.scrollTo(0, newPosotion);
} else if (currentSelectionY >= (scrollOffsetY + containerHeight)) {
// 光标位置在界面下面看不到
// 这里滚到光标底部位置
newPosotion = currentSelectionY - containerHeight;
window.scrollTo(0, newPosotion);
}
}
// 获取当前光标的位置
RE.preSpanHeight = 0;
RE.getCaretYPosition = function() {
if (RE.isFocus()) {
var selection = window.getSelection();
var baseNode = selection.baseNode;
var baseOffset = selection.baseOffset;
var charRange = null;
if (baseNode.nodeType == Node.TEXT_NODE) {//如果是文本node直接使用前面一个字符的位置就好了换行所在位置也不会有问题避免insert remove带来的性能损耗
charRange = document.createRange();
var newBaseOff = baseOffset - 1
if (newBaseOff < 0) {
newBaseOff = 0;
}
charRange.setStart(baseNode, newBaseOff);
charRange.setEnd(baseNode, baseOffset);
var position = RE.getCoords(charRange);
RE.preSpanHeight = position.height == 0 ? RE.preSpanHeight : position.height;
var topPosition = position.top + RE.preSpanHeight;
return topPosition;
}
if(window.getSelection().rangeCount > 0){
range = selection.getRangeAt(0);
}else{
range = document.createRange();
if(RE.currentSelection.startContainer == 0 || RE.currentSelection.endContainer == 0){
range.setStart(RE.editor, RE.currentSelection.startOffset);
range.setEnd(RE.editor, RE.currentSelection.endOffset);
}else{
range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);
range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);
}
}
} else {
var selection = RE.currentSelection;
var range = document.createRange();
if((RE.currentSelection.startContainer == 0) || (RE.currentSelection.endContainer == 0)){
range.setStart(RE.editor, 0);
range.setEnd(RE.editor, 0);
}else{
range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);
range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);
}
}
var spanNode = document.createElement('span');
spanNode.innerHTML = '<br>';
spanNode.style.cssText = 'display: inline-block;';
// collapse的意思是位到这个range的头部还是尾部如果参数是true则定位到头部如果是false则定位到尾部
range.collapse(false);
range.insertNode(spanNode);
// 插入一个临时的标签然后计算这个标签的位置就是光标的位置。操作完之后再把这个标签remove掉
var position = RE.getCoords(spanNode);
RE.preSpanHeight = position.height == 0 ? RE.preSpanHeight : position.height;
var topPosition = position.top + RE.preSpanHeight;
spanNode.parentNode.removeChild(spanNode);
return topPosition;
}
RE.getCoords = function(elem) {
var box = elem.getBoundingClientRect();
var body = document.body;
var docEl = document.documentElement;
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
var clientTop = docEl.clientTop || body.clientTop || 0;
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return {
top: Math.round(top),
left: Math.round(left),
height: box.height,
width: box.width
};
}
// 设置样式class切换日夜模式
RE.setEditorTheme = function(theme) {
if (theme == 'night') {
RE.editor.classList.add('re_Night');
} else {
RE.editor.classList.remove('re_Night');
}
}
// 获取当前光标的node需要
// 1当输入框只有纯文本时返回当前文本node
// 2当文本处于link内则返回文本所在的link
// so按目前需求判断当前node是否在link内是则返回link否则返回文本。需要正多层嵌套如a>b>i的时候是否有问题这个在contentChanged里的isInLink里面判断
RE.getSelectedNode = function() {
var node = RE.getSelectedBaseNode();
if (node) {
var inLink = RE.isInTag(node, 'a'),
isLink = RE.isSpecifiedTag(node, 'a');
return isLink ? node : (inLink.is ? inLink.tagNode : node);
}
};
// 获取当前光标的node
RE.getSelectedBaseNode = function() {
if (!RE.isFocus()) {
return RE.currentSelection.endContainer;
}
var node, selection;
if (window.getSelection) {
selection = getSelection();
if (selection.focusNode != selection.anchorNode) {
// 跨node的选择返回起始node的共同父元素
var range = selection.getRangeAt(0);
node = range.commonAncestorContainer;
} else {
node = selection.anchorNode; // 返回该选区起点所在的节点Node
}
}
return node;
};
RE.setHtml = function(contents) {
RE.editor.innerHTML = decodeURIComponent(contents.replace(/\+/g, '%20'));
RE.contentChanged({});
}
RE.emptyEditor = function() {
RE.currentSelection = {
'startContainer': 0,
'startOffset': 0,
'endContainer': 0,
'endOffset': 0
};
RE.editor.innerHTML = '';
RE.contentChanged({});
}
RE.getHtml = function() {
return RE.editor.innerHTML;
}
RE.getHtmlForEpub = function() {
// 去掉给re_img加的特殊class
var html = RE.editor.innerHTML.replace('re_img_MarginBottom', '')
.replace('re_img_MarginTop', '');
// 发布时处理blockquote里面的段落
return correctArticle(html, {pInQuote: true});
}
RE.getText = function() {
var tempDom = document.createElement('div');
// 过滤掉插入的书dom里的文字这里需要过滤掉零宽连字符不然牛逼的ios里面会出现乱码
tempDom.innerHTML = RE.editor.innerHTML.replace(new RegExp('\u200D', 'g'), '')
.replace('<br>', '')
.replace('<br />', '');
// getText时将插入的书籍和图片转化成 [书籍] [图片]
var books = tempDom.querySelectorAll('.re_bookItem'),
imgs = tempDom.querySelectorAll('.re_img');
if(books.length > 0){
for(var i=0; i<books.length; i++){
var bookDom = books[i],
bookTextNode = document.createTextNode('[书籍]');
bookDom.parentNode.insertBefore(bookTextNode, bookDom);
bookDom.parentNode.removeChild(bookDom);
}
}
if(imgs.length > 0){
for(var i=0; i<imgs.length; i++){
var imgDom = imgs[i],
imgTextNode = document.createTextNode('[图片]');
imgDom.parentNode.insertBefore(imgTextNode, imgDom);
imgDom.parentNode.removeChild(imgDom);
}
}
return tempDom.innerText;
}
RE.isHTMLEmpty = function () {
var html = RE.getHtml();
if(html.indexOf('<img') !== -1) {
return false
}
if(typeof(RE.editor.innerText) == 'undefined') {
return true;
}
return RE.editor.innerText.trim().length == 0;
}
RE.setPlaceholder = function(placeholder) {
RE.editor.setAttribute('placeholder', placeholder);
}
RE.undo = function() {
document.execCommand('undo', false, null);
}
RE.redo = function() {
document.execCommand('redo', false, null);
}
RE.setBold = function() {
if (!RE.isFocus()) {
RE.focus(); // 表情键盘情况下点击加粗,无法聚焦。
}
document.execCommand('bold', false, null);
RE.contentChanged({});
}
RE.setItalic = function() {
document.execCommand('italic', false, null);
RE.contentChanged({});
}
RE.setUnorderedList = function(check) {
if (!RE.isFocus()) {
RE.focus();
}
var needCheck = false;
if (typeof(check) == 'undefined' || check) {
needCheck = true;
}
// h2、block、order 不可以共存,设置其中一个都需要取消另外两个
var formatBlock = document.queryCommandValue('formatBlock');
if (formatBlock == 'h2' && needCheck) {
RE.setHeading(formatBlock,false);
}
if(needCheck) {
var curNode = RE.getSelectedBaseNode()
var inQuoteBlock = RE.isInTag(curNode, 'blockquote');
if (inQuoteBlock.is) {
RE.setBlockquote(false);
}
}
document.execCommand('InsertUnorderedList', false, null);
RE.contentChanged({});
}
RE.setOrderedList = function() {
document.execCommand('InsertOrderedList', false, null);
RE.contentChanged({});
}
RE.setFontSize = function(fontSize) {
if (fontSize >= 1 && fontSize <= 7) {
document.execCommand('fontSize', false, fontSize + '');
}
RE.contentChanged({});
}
RE.setHeading = function(heading,check) {
if (!RE.isFocus()) {
RE.focus();
}
var needCheck = false;
if (typeof(check) == 'undefined' || check) {
needCheck = true;
}
// h2、block、list 不可以共存,设置其中一个都需要取消另外两个
var formatBlock = document.queryCommandValue('formatBlock');
if (RE.isCommandEnabled('insertUnorderedList') && needCheck) {
RE.setUnorderedList(false);
}
if(needCheck) {
var curNode = RE.getSelectedBaseNode()
var inQuoteBlock = RE.isInTag(curNode, 'blockquote');
if (inQuoteBlock.is) {
RE.setBlockquote(false);
}
}
var formatTag = heading;
var formatBlock = document.queryCommandValue('formatBlock');
if (formatBlock.length > 0 && formatBlock.toLowerCase() == formatTag) {
document.execCommand('formatBlock', false, '<p>');
} else {
document.execCommand('formatBlock', false, '<' + formatTag + '>');
}
RE.contentChanged({});
}
RE.setJustifyLeft = function() {
document.execCommand('justifyLeft', false, null);
RE.contentChanged({});
}
RE.setJustifyCenter = function() {
document.execCommand('justifyCenter', false, null);
RE.contentChanged({});
}
RE.setJustifyRight = function() {
document.execCommand('justifyRight', false, null);
RE.contentChanged({});
}
RE.setBlockquote = function(check) {
if (!RE.isFocus()) {
RE.focus();
}
var needCheck = false;
if (typeof(check) == 'undefined' || check) {
needCheck = true;
}
// h2、block、list 不可以共存,设置其中一个都需要取消另外两个
var formatBlock = document.queryCommandValue('formatBlock');
if (RE.isCommandEnabled('insertUnorderedList') && needCheck) {
RE.setUnorderedList(false);
}
if (formatBlock == 'h2' && needCheck) {
RE.setHeading('h2',false);
}
var selection = window.getSelection();
var range = selection.getRangeAt(0).cloneRange();
var parentElement = range.commonAncestorContainer;
var formatBlock = document.queryCommandValue('formatBlock');
if (formatBlock == 'blockquote') {
document.execCommand('formatBlock', false, '<p>')
} else {
var inQuoteBlock = RE.isInTag(parentElement, 'blockquote');
if (inQuoteBlock.is) {
var blockquoteNode = inQuoteBlock.tagNode
var len = blockquoteNode.childNodes.length;
var preNode = blockquoteNode;
//生成一个新的不带blockquote标签的node
for (var i = 0; i < len; i++) {
tempDom = blockquoteNode.childNodes[i]
var nodeName = tempDom.nodeName.toLowerCase()
if (nodeName == '#text' || nodeName == 'br') {
var text = ''
if (nodeName == '#text') {
text = tempDom.textContent
}
if (text == '') {
text = '<br>'
}
tempDom = document.createElement('p')
tempDom.innerHTML = text
} else {
if (tempDom.innerText == '') {
tempDom = document.createElement('p')
tempDom.innerHTML = '<br>'
} else {
tempDom = tempDom.cloneNode(true)
}
}
RE.insertAfter(tempDom,preNode)
preNode = tempDom;
}
blockquoteNode.parentNode.removeChild(blockquoteNode)
//document.execCommand('formatBlock', false, '<p>')
} else {
document.execCommand('formatBlock', false, '<blockquote>')
}
}
RE.contentChanged({});
}
// 生成空段落
RE.generateEmptyPara = function(){
var emptyPara = document.createElement('p');
emptyPara.innerHTML = '<br>';
return emptyPara;
}
// 插入书籍
RE.insertBook = function(id, title, author, cover) {
function generateSpaceNode(){
var n = document.createTextNode('\u200D');
return n;
}
function generateLineBreakNode(){
var n = document.createElement('br');
return n;
}
// 下面两个找前后节点的方法之所以这样实现是因为
// ios里当光标在一个文字node上移动时会把它切割例如
// 一个文字nodeABCDE当光标从E后面往左移会把它分割成
// ABCD,E
// ABC,D,E
// AB,C,D,E
// A,B,C,D,E
// 这样如果我在ABCDE前面插入imgimg的nextSibling有可能只拿到A而拿不到整个文字node不符合预期
function findBookNextSibling(bookItem){
var tempDom = document.createElement('div');
tempDom.innerHTML = bookItem.parentNode.innerHTML;
var target = tempDom.querySelector('.re_bookItem').nextSibling;
return target;
}
function findBookPrevSibling(bookItem){
var tempDom = document.createElement('div');
tempDom.innerHTML = bookItem.parentNode.innerHTML;
var target = tempDom.querySelector('.re_bookItem').previousSibling;
return target;
}
function resetBookItemParentNodeHtml(bookItem){
var pnode = bookItem.parentNode,
tempDom = document.createElement('div');
tempDom.innerHTML = pnode.innerHTML;
pnode.innerHTML = tempDom.innerHTML;
}
var bookItem = document.createElement('div');
bookItem.className = 're_bookItem';
bookItem.setAttribute('contenteditable', false);
bookItem.setAttribute('data-id', id); // 点击相关的事件在rich_display.js里根据data-id处理
bookItem.innerHTML = '<div class="re_bookItem_cover"><img class="re_bookItem_cover_img" src="' + cover + '" alt="' + title + '"></div>' +
'<div class="re_bookItem_title">' + title + '</div>' +
'<div class="re_bookItem_author">' + author + '</div>';
// hack for timing
setTimeout(function(){
var selection = window.getSelection(),
range;
if (window.getSelection().rangeCount > 0) {
range = selection.getRangeAt(0);
} else {
range = document.createRange();
if(RE.currentSelection.startContainer == 0 || RE.currentSelection.endContainer == 0){
range.setStart(RE.editor, RE.currentSelection.startOffset);
range.setEnd(RE.editor, RE.currentSelection.endOffset);
}else{
range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);
range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);
}
}
var rangeNode = range.endContainer; // 光标所在的node
if (RE.isInTag(rangeNode, ['h1' ,'h2' ,'ul' ,'blockquote'])){
// 列表和引用内不插书籍,把书籍看成一个独立的段落处理
var inTagNode = RE.isInTag(rangeNode, ['h1' ,'h2' ,'ul' ,'blockquote']).tagNode;
if (inTagNode.textContent.length == 0) {
// 如果当前block没有文本则把block删掉
inTagNode.parentNode.insertBefore(bookItem, inTagNode);
if (bookItem.previousSibling.getAttribute('contenteditable') == 'false') {
bookItem.parentNode.insertBefore(generateSpaceNode(), bookItem);
}
inTagNode.remove();
} else {
RE.insertAfter(bookItem, inTagNode);
}
if (bookItem.nextSibling) {
range.selectNodeContents(bookItem.nextSibling);
range.collapse();
} else {
var newEmptyLine = RE.generateEmptyPara();
RE.insertAfter(newEmptyLine, bookItem);
range.selectNodeContents(newEmptyLine);
range.collapse(false);
}
}else{
// 在第一行或者在一个p里这里把图片和图片前后的node包个p
range.collapse(false);
range.insertNode(bookItem);
var flagId = bookItem.getAttribute('data-id'),
bookItemParentNode = bookItem.parentNode;
resetBookItemParentNodeHtml(bookItem);
var theBookItem = bookItemParentNode.querySelector('[data-id="'+flagId+'"]'),
theBookItemPreviousSibling = null || theBookItem.previousSibling,
theBookItemNextSibling = null || theBookItem.nextSibling;
if(bookItemParentNode == RE.editor){
// 这是在第一行没被p包住的情况
// 图片前面包一个p
if(theBookItemPreviousSibling){
if((theBookItemPreviousSibling.nodeType == 3 ) || (theBookItemPreviousSibling.nodeType == 1 && theBookItemPreviousSibling.tagName.toLowerCase() == "br")){
var newPreviousPara = document.createElement('p');
range.selectNodeContents(theBookItemPreviousSibling);
range.surroundContents(newPreviousPara);
}
}else{
theBookItem.parentNode.insertBefore(generateSpaceNode(), theBookItem);
}
// 图片后面包一个p
if(theBookItemNextSibling){
if((theBookItemNextSibling.nodeType == 3 ) || (theBookItemNextSibling.nodeType == 1 && theBookItemNextSibling.tagName.toLowerCase() == "br")){
var newNextPara = document.createElement('p');
range.selectNodeContents(theBookItemNextSibling);
range.surroundContents(newNextPara);
range.selectNodeContents(newNextPara);
}else{
range.selectNodeContents(theBookItemNextSibling);
range.collapse();
}
}else{
var newEmptyLine = RE.generateEmptyPara();
RE.insertAfter(newEmptyLine, theBookItem);
range.selectNodeContents(newEmptyLine);
range.collapse(false);
}
}else{
// 这是在一个段落里面的
// 先把图片挪到parent外面
RE.insertAfter(theBookItem, bookItemParentNode);
// 如果原来有nextSibling则把图片原来的nextSibling包一个p并插到图片后面
if(theBookItemNextSibling && !(theBookItemNextSibling.nodeType == 1 && theBookItemNextSibling.tagName.toLowerCase() == "br")){
var newNextPara;
if((theBookItemNextSibling.nodeType == 3 ) || (theBookItemNextSibling.nodeType == 1 && theBookItemNextSibling.tagName.toLowerCase() == "br")){
newNextPara = document.createElement('p');
range.selectNodeContents(theBookItemNextSibling);
range.surroundContents(newNextPara);
}else{
newNextPara = theBookItemNextSibling;
}
RE.insertAfter(newNextPara, theBookItem);
}
if((bookItemParentNode.childNodes.length == 0) || (bookItemParentNode.innerHTML == '<br>') || (bookItemParentNode.innerText == '')){
// 书和next移除出来后parent空了移除掉
bookItemParentNode.parentNode.removeChild(bookItemParentNode);
}
if(theBookItem.nextSibling){
// 处理完之后重新那book的next并做相应处理
range.selectNodeContents(theBookItem.nextSibling);
}else{
var newEmptyLine = RE.generateEmptyPara();
RE.insertAfter(newEmptyLine, theBookItem);
range.selectNodeContents(newEmptyLine);
}
if(!theBookItem.previousSibling || (theBookItem.previousSibling.getAttribute('contenteditable') == 'false')){
theBookItem.parentNode.insertBefore(generateSpaceNode(), theBookItem);
}
}
}
RE.backuprange();
selection.removeAllRanges();
selection.addRange(range);
selection.collapseToStart();
//插完书滚动编辑器到合适的位置
RE.calculateEditorHeightWithCaretPosition();
//判断placeholder
RE.updatePlaceholder();
}, 30);
}
RE.getAllBookIds = function() {
var books = RE.editor.querySelectorAll('.re_bookItem'),
idArray = [];
for (var i = 0; i < books.length; i++) {
idArray.push(books[i].getAttribute('data-id'))
}
var bookIds = "";
if (idArray.length > 0) {
bookIds = idArray.join(RE.dataSeparator);
}
return bookIds;
}
// 插入图片
/*
params: [img,img,img,...]
img:
{
url:,
w:,
h:,
ratio:,
oriw:
}
*/
RE.insertImage = function(imgArray) {
function generateSpaceNode(){
var n = document.createTextNode('\u200D');
return n;
}
function generateLineBreakNode(){
var n = document.createElement('br');
return n;
}
function findImageNextSibling(imgItem){
var tempDom = document.createElement('div');
tempDom.innerHTML = imgItem.parentNode.innerHTML;
var target = tempDom.querySelector('.re_img').nextSibling;
return target;
}
function findImagePrevSibling(imgItem){
var tempDom = document.createElement('div');
tempDom.innerHTML = imgItem.parentNode.innerHTML;
var target = tempDom.querySelector('.re_img').previousSibling;
return target;
}
function resetImageParentNodeHtml(imgItem){
var pnode = imgItem.parentNode,
tempDom = document.createElement('div');
tempDom.innerHTML = pnode.innerHTML;
pnode.innerHTML = tempDom.innerHTML;
}
var imgItem = document.createElement('p'),
imgItemContent = '',
flagId = '';
for(var i=0; i<imgArray.length; i++){
var img = imgArray[i];
imgItemContent += '<img data-id="'+(img.url+''+new Date().getTime())+'" ori-width="'+img.oriw+'" data-ratio="'+img.ratio+'" src="'+img.url+'" class="re_img" active="true" '+((img.w > 0 && img.h > 0)?('width="'+img.w+'" height="'+img.h+'">'):'>');
flagId += img.url;
}
imgItem.setAttribute('data-id', flagId);
imgItem.innerHTML = imgItemContent;
// hack for timing
setTimeout(function(){
var selection = window.getSelection(),
range;
if (window.getSelection().rangeCount > 0) {
range = selection.getRangeAt(0);
} else {
range = document.createRange();
if(RE.currentSelection.startContainer == 0 || RE.currentSelection.endContainer == 0){
range.setStart(RE.editor, RE.currentSelection.startOffset);
range.setEnd(RE.editor, RE.currentSelection.endOffset);
}else{
range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);
range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);
}
}
var rangeNode = range.endContainer; // 光标所在的node
if (RE.isInTag(rangeNode, ['h1' ,'h2' ,'ul' ,'blockquote'])){
// 列表和引用内不插书籍,把书籍看成一个独立的段落处理
var inTagNode = RE.isInTag(rangeNode, ['h1' ,'h2' ,'ul' ,'blockquote']).tagNode;
imgItem.removeAttribute('data-id');
if (inTagNode.textContent.length == 0) {
// 如果当前block没有文本则把block删掉
inTagNode.parentNode.insertBefore(imgItem, inTagNode);
if (imgItem.previousSibling.getAttribute('contenteditable') == 'false') {
imgItem.parentNode.insertBefore(generateSpaceNode(), imgItem);
}
inTagNode.remove();
} else {
RE.insertAfter(imgItem, inTagNode);
}
if (imgItem.nextSibling) {
range.selectNodeContents(imgItem.nextSibling);
range.collapse();
} else {
var newEmptyLine = RE.generateEmptyPara();
RE.insertAfter(newEmptyLine, imgItem);
range.selectNodeContents(newEmptyLine);
range.collapse(false);
}
}else{
// 在第一行或者在一个p里这里把图片和图片前后的node包个p
range.collapse(false);
range.insertNode(imgItem);
var flagId = imgItem.getAttribute('data-id'),
imgItemParentNode = imgItem.parentNode;
resetImageParentNodeHtml(imgItem);
var theImgItem = imgItemParentNode.querySelector('[data-id="'+flagId+'"]'),
theImgItemPreviousSibling = null || theImgItem.previousSibling,
theImgItemNextSibling = null || theImgItem.nextSibling;
theImgItem.removeAttribute('data-id');
if(imgItemParentNode == RE.editor){
// 这是在第一行没被p包住的情况
// 图片前面包一个p
if(theImgItemPreviousSibling){
if((theImgItemPreviousSibling.nodeType == 3 ) || (theImgItemPreviousSibling.nodeType == 1 && theImgItemPreviousSibling.tagName.toLowerCase() == "br")){
var newPreviousPara = document.createElement('p');
range.selectNodeContents(theImgItemPreviousSibling);
range.surroundContents(newPreviousPara);
}
}
// 图片后面包一个p
if(theImgItemNextSibling){
if((theImgItemNextSibling.nodeType == 3 ) || (theImgItemNextSibling.nodeType == 1 && theImgItemNextSibling.tagName.toLowerCase() == "br")){
var newNextPara = document.createElement('p');
range.selectNodeContents(theImgItemNextSibling);
range.surroundContents(newNextPara);
range.selectNodeContents(newNextPara);
}else{
range.selectNodeContents(theImgItemNextSibling);
range.collapse();
}
}else{
var newEmptyLine = RE.generateEmptyPara();
RE.insertAfter(newEmptyLine, theImgItem);
range.selectNodeContents(newEmptyLine);
range.collapse(false);
}
}else{
// 这是在一个段落里面的
// 先把图片挪到parent外面
RE.insertAfter(theImgItem, imgItemParentNode);
// 如果原来有nextSibling则把图片原来的nextSibling包一个p并插到图片后面
if(theImgItemNextSibling && !(theImgItemNextSibling.nodeType == 1 && theImgItemNextSibling.tagName.toLowerCase() == "br")){
var newNextPara;
if((theImgItemNextSibling.nodeType == 3 ) || (theImgItemNextSibling.nodeType == 1 && theImgItemNextSibling.tagName.toLowerCase() == "br")){
newNextPara = document.createElement('p');
range.selectNodeContents(theImgItemNextSibling);
range.surroundContents(newNextPara);
}else{
newNextPara = theImgItemNextSibling;
}
RE.insertAfter(newNextPara, theImgItem);
}
if((imgItemParentNode.childNodes.length == 0) || (imgItemParentNode.innerHTML == '<br>') || (imgItemParentNode.innerText == '')){
// 书和next移除出来后parent空了移除掉
imgItemParentNode.parentNode.removeChild(imgItemParentNode);
}
if(theImgItem.nextSibling){
// 处理完之后重新那img的next并做相应处理
range.selectNodeContents(theImgItem.nextSibling);
}else{
var newEmptyLine = RE.generateEmptyPara();
RE.insertAfter(newEmptyLine, theImgItem);
range.selectNodeContents(newEmptyLine);
}
}
}
RE.backuprange();
selection.removeAllRanges();
selection.addRange(range);
//插完书滚动编辑器到合适的位置
RE.calculateEditorHeightWithCaretPosition();
selection.collapseToStart();
wereadBridge.handleWithRichEditor('onInsertImage', {
'param': ''
}, '', '');
//判断placeholder
RE.updatePlaceholder();
//insert dom之后立刻滚动未必能够得到正确的位置
var delaytime = 50;
if (imgArray.length > 2) {
delaytime = 100;
}
setTimeout(function(){
RE.calculateEditorHeightWithCaretPosition();
},delaytime);
}, 50);
}
// 插入QQ表情
RE.insertQQEmoticon = function(url, alt, w, h) {
// blur掉的时候直接操作dom插入imgNode后更新currentSelectionapp调用RE.focus会在里面restorerange
var imgNode = document.createElement('img');
imgNode.setAttribute('src', url);
imgNode.setAttribute('alt', alt);
imgNode.className = 're_QQEmoticon';
if (w > 0 && h > 0) {
imgNode.setAttribute('style', 'width: ' + h + 'px;height: ' + h + 'px;');
}
// blur状态下直接从备份获取range
var range = document.createRange();
range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);
range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);
// 将node插入到range并将光标置于最新加入的node后面
range.collapse(false);
range.insertNode(imgNode);
range.setStartAfter(imgNode);
range.collapse(true);
RE.currentSelection = {
'startContainer': range.startContainer,
'startOffset': range.startOffset,
'endContainer': range.endContainer,
'endOffset': range.endOffset
};
RE.calculateEditorHeightWithCaretPosition();
RE.contentChanged({});
//判断placeholder
RE.updatePlaceholder();
}
// https://github.com/mathiasbynens/emoji-regex
RE.emojiUnicodeReg = /((?:0\u20E3|1\u20E3|2\u20E3|3\u20E3|4\u20E3|5\u20E3|6\u20E3|7\u20E3|8\u20E3|9\u20E3|#\u20E3|\*\u20E3|\uD83C(?:\uDDE6\uD83C(?:\uDDE8|\uDDE9|\uDDEA|\uDDEB|\uDDEC|\uDDEE|\uDDF1|\uDDF2|\uDDF4|\uDDF6|\uDDF7|\uDDF8|\uDDF9|\uDDFA|\uDDFC|\uDDFD|\uDDFF)|\uDDE7\uD83C(?:\uDDE6|\uDDE7|\uDDE9|\uDDEA|\uDDEB|\uDDEC|\uDDED|\uDDEE|\uDDEF|\uDDF1|\uDDF2|\uDDF3|\uDDF4|\uDDF6|\uDDF7|\uDDF8|\uDDF9|\uDDFB|\uDDFC|\uDDFE|\uDDFF)|\uDDE8\uD83C(?:\uDDE6|\uDDE8|\uDDE9|\uDDEB|\uDDEC|\uDDED|\uDDEE|\uDDF0|\uDDF1|\uDDF2|\uDDF3|\uDDF4|\uDDF5|\uDDF7|\uDDFA|\uDDFB|\uDDFC|\uDDFD|\uDDFE|\uDDFF)|\uDDE9\uD83C(?:\uDDEA|\uDDEC|\uDDEF|\uDDF0|\uDDF2|\uDDF4|\uDDFF)|\uDDEA\uD83C(?:\uDDE6|\uDDE8|\uDDEA|\uDDEC|\uDDED|\uDDF7|\uDDF8|\uDDF9|\uDDFA)|\uDDEB\uD83C(?:\uDDEE|\uDDEF|\uDDF0|\uDDF2|\uDDF4|\uDDF7)|\uDDEC\uD83C(?:\uDDE6|\uDDE7|\uDDE9|\uDDEA|\uDDEB|\uDDEC|\uDDED|\uDDEE|\uDDF1|\uDDF2|\uDDF3|\uDDF5|\uDDF6|\uDDF7|\uDDF8|\uDDF9|\uDDFA|\uDDFC|\uDDFE)|\uDDED\uD83C(?:\uDDF0|\uDDF2|\uDDF3|\uDDF7|\uDDF9|\uDDFA)|\uDDEE\uD83C(?:\uDDE8|\uDDE9|\uDDEA|\uDDF1|\uDDF2|\uDDF3|\uDDF4|\uDDF6|\uDDF7|\uDDF8|\uDDF9)|\uDDEF\uD83C(?:\uDDEA|\uDDF2|\uDDF4|\uDDF5)|\uDDF0\uD83C(?:\uDDEA|\uDDEC|\uDDED|\uDDEE|\uDDF2|\uDDF3|\uDDF5|\uDDF7|\uDDFC|\uDDFE|\uDDFF)|\uDDF1\uD83C(?:\uDDE6|\uDDE7|\uDDE8|\uDDEE|\uDDF0|\uDDF7|\uDDF8|\uDDF9|\uDDFA|\uDDFB|\uDDFE)|\uDDF2\uD83C(?:\uDDE6|\uDDE8|\uDDE9|\uDDEA|\uDDEB|\uDDEC|\uDDED|\uDDF0|\uDDF1|\uDDF2|\uDDF3|\uDDF4|\uDDF5|\uDDF6|\uDDF7|\uDDF8|\uDDF9|\uDDFA|\uDDFB|\uDDFC|\uDDFD|\uDDFE|\uDDFF)|\uDDF3\uD83C(?:\uDDE6|\uDDE8|\uDDEA|\uDDEB|\uDDEC|\uDDEE|\uDDF1|\uDDF4|\uDDF5|\uDDF7|\uDDFA|\uDDFF)|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C(?:\uDDE6|\uDDEA|\uDDEB|\uDDEC|\uDDED|\uDDF0|\uDDF1|\uDDF2|\uDDF3|\uDDF7|\uDDF8|\uDDF9|\uDDFC|\uDDFE)|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C(?:\uDDEA|\uDDF4|\uDDF8|\uDDFA|\uDDFC)|\uDDF8\uD83C(?:\uDDE6|\uDDE7|\uDDE8|\uDDE9|\uDDEA|\uDDEC|\uDDED|\uDDEE|\uDDEF|\uDDF0|\uDDF1|\uDDF2|\uDDF3|\uDDF4|\uDDF7|\uDDF8|\uDDF9|\uDDFB|\uDDFD|\uDDFE|\uDDFF)|\uDDF9\uD83C(?:\uDDE6|\uDDE8|\uDDE9|\uDDEB|\uDDEC|\uDDED|\uDDEF|\uDDF0|\uDDF1|\uDDF2|\uDDF3|\uDDF4|\uDDF7|\uDDF9|\uDDFB|\uDDFC|\uDDFF)|\uDDFA\uD83C(?:\uDDE6|\uDDEC|\uDDF2|\uDDF8|\uDDFE|\uDDFF)|\uDDFB\uD83C(?:\uDDE6|\uDDE8|\uDDEA|\uDDEC|\uDDEE|\uDDF3|\uDDFA)|\uDDFC\uD83C(?:\uDDEB|\uDDF8)|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C(?:\uDDEA|\uDDF9)|\uDDFF\uD83C(?:\uDDE6|\uDDF2|\uDDFC)))|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0])$/g;
// 表情面板中点击退格
RE.removeInQQEmoticonPanel = function() {
var selection = RE.currentSelection,
node = selection.endContainer,
offset = selection.endOffset;
if (node == RE.editor) {
var theRemovedNode = node.childNodes[offset - 1];
if(theRemovedNode){
var theRemovedNodePrevSibling = theRemovedNode.previousSibling;
node.removeChild(theRemovedNode);
if(theRemovedNodePrevSibling){
if (theRemovedNodePrevSibling.nodeType == 3) {
var range = document.createRange();
range.selectNodeContents(theRemovedNodePrevSibling);
range.collapse(false);
RE.currentSelection = {
'startContainer': range.startContainer,
'startOffset': range.startOffset,
'endContainer': range.endContainer,
'endOffset': range.endOffset
};
} else {
RE.currentSelection = {
'startContainer': node,
'startOffset': offset - 1,
'endContainer': node,
'endOffset': offset - 1
};
}
}
}
} else if (node.nodeType == 3) {
if (offset == node.length && node.length > 0) {
if (new RegExp(RE.emojiUnicodeReg).exec(RE.currentSelection.endContainer.textContent)) {
var lastEmojiIndex = new RegExp(RE.emojiUnicodeReg).exec(RE.currentSelection.endContainer.textContent).index;
node.textContent = node.textContent.substring(0, lastEmojiIndex);
} else {
node.textContent = node.textContent.slice(0, -1);
}
var range = document.createRange();
range.selectNodeContents(node);
range.collapse(false);
RE.currentSelection = {
'startContainer': range.startContainer,
'startOffset': range.startOffset,
'endContainer': range.endContainer,
'endOffset': range.endOffset
};
} else if (offset == 0 || node.length == 0) {
var previousNode = node.previousSibling;
if (previousNode.nodeType == 3 && previousNode.length > 0) {
previousNode.textContent = previousNode.textContent.slice(0, -1);
var range = document.createRange();
range.selectNodeContents(previousNode);
range.collapse(false);
RE.currentSelection = {
'startContainer': range.startContainer,
'startOffset': range.startOffset,
'endContainer': range.endContainer,
'endOffset': range.endOffset
};
} else {
RE.currentSelection = {
'startContainer': previousNode.parentNode,
'startOffset': RE.nodeIndexInParent(previousNode, previousNode.parentNode),
'endContainer': previousNode.parentNode,
'endOffset': RE.nodeIndexInParent(previousNode, previousNode.parentNode)
};
previousNode.parentNode.removeChild(previousNode);
}
} else {
node.textContent = node.textContent.substring(0, offset - 1) + node.textContent.substring(offset);
RE.currentSelection = {
'startContainer': node,
'startOffset': offset - 1,
'endContainer': node,
'endOffset': offset - 1
};
}
} else {
var theRemovedNode = node.childNodes[offset - 1];
if(theRemovedNode){
var theRemovedNodePrevSibling = theRemovedNode.previousSibling;
node.removeChild(theRemovedNode);
if(theRemovedNodePrevSibling){
if (theRemovedNodePrevSibling.nodeType == 3) {
var range = document.createRange();
range.selectNodeContents(theRemovedNodePrevSibling);
range.collapse(false);
RE.currentSelection = {
'startContainer': range.startContainer,
'startOffset': range.startOffset,
'endContainer': range.endContainer,
'endOffset': range.endOffset
};
} else {
RE.currentSelection = {
'startContainer': node,
'startOffset': offset - 1,
'endContainer': node,
'endOffset': offset - 1
};
}
}
}
}
//判断placeholder
RE.updatePlaceholder();
}
RE.insertHTML = function(html) {
setTimeout(function(){
//blockqupte h2 <li> 标签不能共存
var sel = getSelection();
var focusNode = sel.focusNode;
var needRemoveFlag = false;
if (typeof(focusNode) != 'undefined') {
var inQuoteBlock = RE.isInTag(focusNode, 'blockquote');
if (inQuoteBlock.is) {
needRemoveFlag = true;
}
}
var formatBlock = document.queryCommandValue('formatBlock');
if (RE.isCommandEnabled('insertUnorderedList')) {
needRemoveFlag = true;
}
if (formatBlock == 'h2') {
needRemoveFlag = true;
}
if (needRemoveFlag) {
html = RE.removeExcluedFlag(html);
} else {
var range = getSelection().getRangeAt(0).cloneRange()
var endOffset = range.endOffset;
if (endOffset != 0) {//不是起始位置
if (html.indexOf('<blockquote>') == 0) {
document.execCommand('insertHTML', false, '<p><br></p>');
}
}
}
document.execCommand('insertHTML', false, html);
RE.contentChanged({});
//判断placeholder
RE.updatePlaceholder();
//RE.calculateEditorHeightWithCaretPosition();
},30);
}
RE.insertText = function(text) {
document.execCommand('insertText', false, text);
RE.contentChanged({});
}
RE.removeExcluedFlag = function(str) {
str = str.replace(/blockquote>/g,'p>')
.replace(/h2>/g,'p>')
.replace(/<ul>/g,'')
.replace(/<\/ul>/g,'')
.replace(/li>/g,'p>')
str = correctArticle(str, {pInQuote: true});
return str;
}
//光标前移动一位
RE.cursorGoBackForAtClick = function() {
var curNode = getSelection().anchorNode;
if (typeof(curNode) != 'undefined') {
var curText = curNode.textContent;
var curLen = curText.length;
if (curText.length > 1) {
var range = getSelection().getRangeAt(0).cloneRange();
var fixedOffset = range.startOffset - 1;
if (fixedOffset > 0) {
range.setStart(range.startContainer, fixedOffset);
range.setEnd(range.endContainer, fixedOffset);
getSelection().removeAllRanges();
getSelection().addRange(range);
}
}
}
}
RE.delFieldBeforeFocus = function() {
var sel = getSelection();
var focusNode = sel.focusNode;
if (typeof(focusNode) != 'undefined') {
var curText = focusNode.textContent;
var curLen = curText.length;
if (curLen >= 1 && sel.focusOffset > 0) {
// 保证当前node有字符且光标不在最前面
var range = sel.getRangeAt(0);
var fixedOffset = range.startOffset - 1;
var focusOffset = sel.focusOffset;
var newText = curText.substr(0, focusOffset - 1);
if (curLen > focusOffset) {
newText = newText + curText.substr(focusOffset, curLen - focusOffset);
}
focusNode.textContent = newText;
range.setStart(range.startContainer, fixedOffset);
range.setEnd(range.endContainer, fixedOffset);
getSelection().removeAllRanges();
getSelection().addRange(range);
RE.backuprange(); //字符减少后光标变化,需记录
} else {
focusNode.textContent = '';
}
}
RE.contentChanged({});
}
RE.insertLink = function(text, href, title) {
if (!RE.isFocus()) {
RE.focusEditor();
}
/*
href='topic:name/at:vid' 初始状态'topic:0/at:0'
title='#content#/@username' 初始状态'##/@\u00A0'
初始化后title,href在选中用户或者选择话题的时候才进行更新
*/
var selection = window.getSelection(),
currentNode = selection.focusNode;
if (selection && selection.rangeCount > 0) {
var aElement = document.createElement('a');
aElement.setAttribute('href', href ? href : '');
aElement.setAttribute('title', title ? title : '');
aElement.className = 're_link';
if (RE.currentEditingLink) {
// 避免重复link
aElement.innerText = text ? text : '';
RE.insertAfter(aElement, RE.currentEditingLink);
var range = document.createRange();
range.selectNode(aElement);
range.collapse(false);
} else {
// 纯文本
var range = selection.getRangeAt(0).cloneRange();
range.surroundContents(aElement); // surroundContents后link的innertText为光标选择的内容需要重新设定为需要的text
aElement.innerText = text ? text : '';
range.collapse(false);
}
selection.removeAllRanges();
selection.addRange(range);
RE.contentChanged({});
}
//判断placeholder
RE.updatePlaceholder();
}
// unlink光标前的link
RE.unlink = function() {
// document.execCommand('unlink', false, false);
if (RE.currentEditingLink) {
RE.unlinkFor(RE.currentEditingLink);
}
RE.contentChanged({});
}
// unlink光标后的link
RE.unlinkAfter = function() {
// document.execCommand('unlink', false, false);
if (RE.currentEditingAfterLink) {
RE.unlinkFor(RE.currentEditingAfterLink);
}
RE.contentChanged({});
}
// unlink指定的link
RE.unlinkFor = function(link) {
var parent = link.parentElement,
newEl = document.createTextNode(link.innerText);
var selection = window.getSelection();
var range = document.createRange();
range.selectNode(link);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand('unlink', false, null);
RE.restorerange();
RE.contentChanged({});
}
RE.updateLink = function(text, href, title) {
if (RE.currentEditingLink) {
//replace innerhtml
var currentLink = RE.currentEditingLink;
currentLink.setAttribute('href', href);
currentLink.setAttribute('title', title);
currentLink.innerHTML = text;
//move cursor
var iteratorNode = currentLink;
while (iteratorNode.lastChild) {
iteratorNode = iteratorNode.lastChild;
}
var range = document.createRange();
range.selectNodeContents(iteratorNode);
range.collapse(false);
var len = iteratorNode.textContent.length;
range.setStart(range.startContainer, len);
range.setEnd(range.endContainer, len);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
RE.contentChanged({});
}
RE.updateLinkAttribute = function(href, title) {
if (RE.currentEditingLink) {
var currentLink = RE.currentEditingLink;
currentLink.setAttribute('href', href);
currentLink.setAttribute('title', title);
}
}
// 键盘监听
RE.keyupCallback = function(e) {
if (e.keyCode != 0 || e.which != 0) {
if (e.which != KEY_BACKSPACE_CODE) {
// 若不是退格行为则判断当前keyup后光标前一位的字符
var currentAnchorCode = window.getSelection().focusNode.textContent[window.getSelection().focusOffset - 1];
if (currentAnchorCode == KEY_AT_CHAR && e.which == KEY_AT_CODE) {
RE.handleAtClick();
} else if (currentAnchorCode == KEY_HASH_CHAR && e.which == KEY_HASH_CODE) {
RE.handleTopicClick();
}
}
}
}
RE.delete = function() {
document.execCommand('delete', false, null);
RE.contentChanged({});
}
RE.setTodo = function(text) {
var html = '<input type="checkbox" name="' + text + '" value="' + text + '"/> &nbsp;';
document.execCommand('insertHTML', false, html);
RE.contentChanged({});
}
RE.prepareInsert = function() {
RE.backuprange();
}
RE.backuprange = function() {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
RE.currentSelection = {
'startContainer': range.startContainer,
'startOffset': range.startOffset,
'endContainer': range.endContainer,
'endOffset': range.endOffset
};
}
}
RE.restorerange = function() {
var selection = window.getSelection();
selection.removeAllRanges();
var range = document.createRange();
range.setStart(RE.currentSelection.startContainer, RE.currentSelection.startOffset);
range.setEnd(RE.currentSelection.endContainer, RE.currentSelection.endOffset);
selection.addRange(range);
}
RE.isCommandEnabled = function(commandName) {
return document.queryCommandState(commandName);
}
RE.removeSpecifiedLink = function(link) {
var parent = link.parentElement;
if (parent) {
var newEl = document.createTextNode(link.innerText);
parent.insertBefore(newEl, link);
parent.removeChild(link);
}
}
RE.contentChanged = function(e) {
var items = [];
if (RE.isCommandEnabled('bold')) {
items.push('bold');
}
if (RE.isCommandEnabled('italic')) {
items.push('italic');
}
if (RE.isCommandEnabled('insertOrderedList')) {
items.push('orderedList');
}
if (RE.isCommandEnabled('insertUnorderedList')) {
items.push('unorderedList');
}
if (RE.isCommandEnabled('justifyCenter')) {
items.push('justifyCenter');
}
if (RE.isCommandEnabled('justifyLeft')) {
items.push('justifyLeft');
}
if (RE.isCommandEnabled('justifyRight')) {
items.push('justifyRight');
}
var formatBlock = document.queryCommandValue('formatBlock');
if (formatBlock.length > 0) {
items.push(formatBlock);
}
if (typeof(e) != 'undefined') {
var node = RE.getSelectedNode();
if (node) {
var inQuoteBlock = RE.isInTag(node, 'blockquote');
if (inQuoteBlock.is) {
items.push('blockquote');
}
var nodeName = node.nodeName.toLowerCase();
// Link
if (RE.isSpecifiedTag(node, 'a')) {
RE.currentEditingLink = node;
} else if (RE.isInTag(node, 'a').is) {
var plink = RE.isInTag(node, 'a').tagNode;
RE.currentEditingLink = plink;
} else {
if (RE.currentEditingLink) {
//ios 离开link的时候需要判断Link是否还没完成
if (RE.currentEditingLink.href.indexOf('at:') == 0) {
//at link
var parsedTitle = RE.editor.decodeFaceStr(RE.currentEditingLink.title);
if (RE.currentEditingLink.href.indexOf('at:0') == 0 || parsedTitle != RE.currentEditingLink.text) {
RE.removeSpecifiedLink(RE.currentEditingLink);
}
} else if (RE.currentEditingLink.href.indexOf('topic:') == 0) {
//ios 离开link的时候需要判断Link是否被破坏
if (typeof(RE.currentEditingLink.innerText) == 'undefined' || RE.currentEditingLink.innerText.length < 2 || RE.currentEditingLink.innerText.indexOf('#') != 0 || RE.currentEditingLink.innerText.lastIndexOf('#') != RE.currentEditingLink.innerText.length - 1) {
RE.removeSpecifiedLink(RE.currentEditingLink);
}
}
}
RE.currentEditingLink = null;
}
// 判断光标后面是不是link
if (node.nextElementSibling || node.nextSibling) {
var next = node.nextElementSibling || node.nextSibling;
if (next && RE.isSpecifiedTag(next, 'a')) {
RE.currentEditingAfterLink = next;
var title = next.getAttribute('title');
var href = next.getAttribute('href');
if (href != undefined) {
items.push('afterLink:' + href);
}
if (title !== undefined) {
items.push('afterLink-title:' + title);
}
items.push('afterLink-text:' + next.innerText)
items.push('afterLink-html:' + next.innerHTML)
} else if (RE.isInTag(node, 'a').is) {
var plink = RE.isInTag(node, 'a').tagNode;
RE.currentEditingAfterLink = plink;
var title = plink.getAttribute('title');
var href = plink.getAttribute('href');
if (href != undefined) {
items.push('afterLink:' + href);
}
if (title !== undefined) {
items.push('afterLink-title:' + title);
}
items.push('afterLink-text:' + plink.innerText);
items.push('afterLink-html:' + next.innerHTML)
} else {
RE.currentEditingAfterLink = null;
}
}
// Blockquote
if (RE.isSpecifiedTag(node, 'blockquote')) {
items.push('indent');
}
// Image
if (RE.isSpecifiedTag(node, 'img')) {
RE.currentEditingImage = node;
var src = node.getAttribute('src');
var alt = node.getAttribute('alt');
if (src != undefined) {
items.push('image:' + src);
}
if (alt != undefined) {
items.push('image-alt:' + node.getAttribute('alt'));
}
} else {
RE.currentEditingImage = null;
}
}
}
if (RE.currentEditingLink) {
//放在这里是因为保证即使是失焦也能传递Link数据
items.push('isEditingLink:1')
var title = RE.currentEditingLink.getAttribute('title');
var href = RE.currentEditingLink.getAttribute('href');
if (href != undefined) {
items.push('link:' + href);
}
if (title !== undefined) {
items.push('link-title:' + title);
}
items.push('link-text:' + RE.currentEditingLink.innerText);
items.push('link-html:' + RE.currentEditingLink.innerHTML)
} else {
items.push('isEditingLink:0')
}
if (window.getSelection().toString().length > 0) {
items.push('hasSelectedText');
}
wereadBridge.handleWithRichEditor('onSelectionChange', {
'param': items.join(RE.dataSeparator)
}, '', '');
}
RE.handleAtClick = function() {
var items = [];
RE.fillEditingStatus(items);
wereadBridge.handleWithRichEditor('onAtClicked', {
'param': items.join(RE.dataSeparator)
}, '', '');
}
RE.handleTopicClick = function() {
var items = [];
RE.fillEditingStatus(items);
wereadBridge.handleWithRichEditor('onTopicClicked', {
'param': items.join(RE.dataSeparator)
}, '', '');
}
RE.fillEditingStatus = function(items) {
if (RE.currentEditingLink) {
items.push('isEditingLink:1')
} else {
items.push('isEditingLink:0')
}
}
RE.isEditingLink = function() {
if (RE.currentEditingLink) {
return true;
} else {
return false;
}
}
RE.isFocus = function() {
return document.activeElement === RE.editor;
}
RE.focus = function() {
// 这个focus会将光标置于编辑器的最后
if (RE.currentSelection.startContainer != 0) {
//当currentSelection有值才进入,这里是为了避免ios从其他界面调回来光标能定位到原来的位置
RE.restorerange();
RE.editor.focus();
return;
}
var range = document.createRange();
range.selectNodeContents(RE.editor);
range.collapse(false);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
RE.editor.focus();
RE.backuprange();
}
RE.focusEditor = function() {
// 这个focus没有有处理光标的位置
RE.editor.focus()
}
RE.blurEditor = function() {
RE.editor.blur();
}
//这里将做表情的解码 l_f_s微笑r_f_s --》[微笑]
RE.editor.decodeFaceStr = function(str) {
var regular = RE.faceSplitStrLeft + '.{1,3}';
regular = regular + RE.faceSplitStrRight;
if (typeof(str) != 'undefined' && str) {
var matchedArr = str.match(regular);
if (matchedArr && matchedArr.length > 0) {
for (var index = 0; index < matchedArr.length; index++) {
var matchedStr = matchedArr[index]
while (matchedStr && str && str.indexOf(matchedStr) != -1) {
if (matchedStr && matchedStr.length > RE.faceSplitStrRight.length + RE.faceSplitStrLeft.length) {
var originalStr = matchedStr.substr(RE.faceSplitStrLeft.length, matchedStr.length - RE.faceSplitStrRight.length - RE.faceSplitStrLeft.length);
originalStr = '[' + originalStr;
originalStr = originalStr + ']';
str = str.replace(matchedStr, originalStr);
} else {
break;
}
}
}
}
}
return str;
};
RE.editor.addEventListener('paste', function(e) {
e.preventDefault();
wereadBridge.handleWithRichEditor('onPaste', {
'param': ''
}, '', '')
});
//由于Android,@和#需要跳出页面,回来时WebView请求focus时自动滚动到顶部,因此需要重新滚动至光标处
RE.triggerCursorScroll = function() {
wereadBridge.handleWithRichEditor('onCursorScroll', {
'param': 'scroll'
}, '', '');
}
RE.removeFormat = function() {
document.execCommand('removeFormat', false, null);
}
// Event Listeners
RE.editor.addEventListener('keyup', RE.keyupCallback);
RE.editor.addEventListener('keydown', RE.keydownCallback);
RE.editor.addEventListener('click', RE.contentChanged);
RE.init();
RE.isHTMLChange = function() {
var curHTML = RE.editor.innerHTML;
if(curHTML != RE.originalHTML) return true;
return false;
}
window.onload = function(){
RE.originalHTML= RE.editor.innerHTML;
if(RE.isHTMLEmpty() || (RE.editor.innerHTML == RE.defaultHml)){
RE.editor.classList.add('re_placeholder');
}else{
RE.editor.classList.remove('re_placeholder');
}
}
RE.saveCurrentHTML = function () {
RE.originalHTML = RE.editor.innerHTML;
}