1711 lines
66 KiB
JavaScript
1711 lines
66 KiB
JavaScript
/**
|
||
* 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上移动时会把它切割,例如
|
||
// 一个文字node:ABCDE,当光标从E后面往左移,会把它分割成
|
||
// ABCD,E
|
||
// ABC,D,E
|
||
// AB,C,D,E
|
||
// A,B,C,D,E
|
||
// 这样如果我在ABCDE前面插入img,img的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后更新currentSelection,app调用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 + '"/> ';
|
||
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;
|
||
}
|
||
|