]/.test(html)) {
return UE.htmlparser(html).children[0]
} else {
return new uNode({
type: 'element',
children: [],
tagName: html
})
}
};
uNode.createText = function(data, noTrans) {
return new UE.uNode({
type: 'text',
'data': noTrans ? data : utils.unhtml(data || '')
})
};
function nodeToHtml(node, arr, formatter, current) {
switch(node.type) {
case 'root':
for(var i = 0, ci; ci = node.children[i++];) {
//插入新行
if(formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
insertLine(arr, current, true);
insertIndent(arr, current)
}
nodeToHtml(ci, arr, formatter, current)
}
break;
case 'text':
isText(node, arr);
break;
case 'element':
isElement(node, arr, formatter, current);
break;
case 'comment':
isComment(node, arr, formatter);
}
return arr;
}
function isText(node, arr) {
if(node.parentNode.tagName == 'pre') {
//源码模式下输入html标签,不能做转换处理,直接输出
arr.push(node.data)
} else {
arr.push(notTransTagName[node.parentNode.tagName] ? utils.html(node.data) : node.data.replace(/[ ]{2}/g, ' '))
}
}
function isElement(node, arr, formatter, current) {
var attrhtml = '';
if(node.attrs) {
attrhtml = [];
var attrs = node.attrs;
for(var a in attrs) {
//这里就针对
//'
//这里边的\"做转换,要不用innerHTML直接被截断了,属性src
//有可能做的不够
attrhtml.push(a + (attrs[a] !== undefined ? '="' + (notTransAttrs[a] ? utils.html(attrs[a]).replace(/["]/g, function(a) {
return '"'
}) : utils.unhtml(attrs[a])) + '"' : ''))
}
attrhtml = attrhtml.join(' ');
}
arr.push('<' + node.tagName +
(attrhtml ? ' ' + attrhtml : '') +
(dtd.$empty[node.tagName] ? '\/' : '') + '>'
);
//插入新行
if(formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
if(node.children && node.children.length) {
current = insertLine(arr, current, true);
insertIndent(arr, current)
}
}
if(node.children && node.children.length) {
for(var i = 0, ci; ci = node.children[i++];) {
if(formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
insertLine(arr, current);
insertIndent(arr, current)
}
nodeToHtml(ci, arr, formatter, current)
}
}
if(!dtd.$empty[node.tagName]) {
if(formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
if(node.children && node.children.length) {
current = insertLine(arr, current);
insertIndent(arr, current)
}
}
arr.push('<\/' + node.tagName + '>');
}
}
function isComment(node, arr) {
arr.push('');
}
function getNodeById(root, id) {
var node;
if(root.type == 'element' && root.getAttr('id') == id) {
return root;
}
if(root.children && root.children.length) {
for(var i = 0, ci; ci = root.children[i++];) {
if(node = getNodeById(ci, id)) {
return node;
}
}
}
}
function getNodesByTagName(node, tagName, arr) {
if(node.type == 'element' && node.tagName == tagName) {
arr.push(node);
}
if(node.children && node.children.length) {
for(var i = 0, ci; ci = node.children[i++];) {
getNodesByTagName(ci, tagName, arr)
}
}
}
function nodeTraversal(root, fn) {
if(root.children && root.children.length) {
for(var i = 0, ci; ci = root.children[i];) {
nodeTraversal(ci, fn);
//ci被替换的情况,这里就不再走 fn了
if(ci.parentNode) {
if(ci.children && ci.children.length) {
fn(ci)
}
if(ci.parentNode) i++
}
}
} else {
fn(root)
}
}
uNode.prototype = {
/**
* 当前节点对象,转换成html文本
* @method toHtml
* @return { String } 返回转换后的html字符串
* @example
* ```javascript
* node.toHtml();
* ```
*/
/**
* 当前节点对象,转换成html文本
* @method toHtml
* @param { Boolean } formatter 是否格式化返回值
* @return { String } 返回转换后的html字符串
* @example
* ```javascript
* node.toHtml( true );
* ```
*/
toHtml: function(formatter) {
var arr = [];
nodeToHtml(this, arr, formatter, 0);
return arr.join('')
},
/**
* 获取节点的html内容
* @method innerHTML
* @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
* @return { String } 返回节点的html内容
* @example
* ```javascript
* var htmlstr = node.innerHTML();
* ```
*/
/**
* 设置节点的html内容
* @method innerHTML
* @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
* @param { String } htmlstr 传入要设置的html内容
* @return { UE.uNode } 返回节点本身
* @example
* ```javascript
* node.innerHTML('text');
* ```
*/
innerHTML: function(htmlstr) {
if(this.type != 'element' || dtd.$empty[this.tagName]) {
return this;
}
if(utils.isString(htmlstr)) {
if(this.children) {
for(var i = 0, ci; ci = this.children[i++];) {
ci.parentNode = null;
}
}
this.children = [];
var tmpRoot = UE.htmlparser(htmlstr);
for(var i = 0, ci; ci = tmpRoot.children[i++];) {
this.children.push(ci);
ci.parentNode = this;
}
return this;
} else {
var tmpRoot = new UE.uNode({
type: 'root',
children: this.children
});
return tmpRoot.toHtml();
}
},
/**
* 获取节点的纯文本内容
* @method innerText
* @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
* @return { String } 返回节点的存文本内容
* @example
* ```javascript
* var textStr = node.innerText();
* ```
*/
/**
* 设置节点的纯文本内容
* @method innerText
* @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
* @param { String } textStr 传入要设置的文本内容
* @return { UE.uNode } 返回节点本身
* @example
* ```javascript
* node.innerText('text');
* ```
*/
innerText: function(textStr, noTrans) {
if(this.type != 'element' || dtd.$empty[this.tagName]) {
return this;
}
if(textStr) {
if(this.children) {
for(var i = 0, ci; ci = this.children[i++];) {
ci.parentNode = null;
}
}
this.children = [];
this.appendChild(uNode.createText(textStr, noTrans));
return this;
} else {
return this.toHtml().replace(/<[^>]+>/g, '');
}
},
/**
* 获取当前对象的data属性
* @method getData
* @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
* @example
* ```javascript
* node.getData();
* ```
*/
getData: function() {
if(this.type == 'element')
return '';
return this.data
},
/**
* 获取当前节点下的第一个子节点
* @method firstChild
* @return { UE.uNode } 返回第一个子节点
* @example
* ```javascript
* node.firstChild(); //返回第一个子节点
* ```
*/
firstChild: function() {
// if (this.type != 'element' || dtd.$empty[this.tagName]) {
// return this;
// }
return this.children ? this.children[0] : null;
},
/**
* 获取当前节点下的最后一个子节点
* @method lastChild
* @return { UE.uNode } 返回最后一个子节点
* @example
* ```javascript
* node.lastChild(); //返回最后一个子节点
* ```
*/
lastChild: function() {
// if (this.type != 'element' || dtd.$empty[this.tagName] ) {
// return this;
// }
return this.children ? this.children[this.children.length - 1] : null;
},
/**
* 获取和当前节点有相同父亲节点的前一个节点
* @method previousSibling
* @return { UE.uNode } 返回前一个节点
* @example
* ```javascript
* node.children[2].previousSibling(); //返回子节点node.children[1]
* ```
*/
previousSibling: function() {
var parent = this.parentNode;
for(var i = 0, ci; ci = parent.children[i]; i++) {
if(ci === this) {
return i == 0 ? null : parent.children[i - 1];
}
}
},
/**
* 获取和当前节点有相同父亲节点的后一个节点
* @method nextSibling
* @return { UE.uNode } 返回后一个节点,找不到返回null
* @example
* ```javascript
* node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
* ```
*/
nextSibling: function() {
var parent = this.parentNode;
for(var i = 0, ci; ci = parent.children[i++];) {
if(ci === this) {
return parent.children[i];
}
}
},
/**
* 用新的节点替换当前节点
* @method replaceChild
* @param { UE.uNode } target 要替换成该节点参数
* @param { UE.uNode } source 要被替换掉的节点
* @return { UE.uNode } 返回替换之后的节点对象
* @example
* ```javascript
* node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
* ```
*/
replaceChild: function(target, source) {
if(this.children) {
if(target.parentNode) {
target.parentNode.removeChild(target);
}
for(var i = 0, ci; ci = this.children[i]; i++) {
if(ci === source) {
this.children.splice(i, 1, target);
source.parentNode = null;
target.parentNode = this;
return target;
}
}
}
},
/**
* 在节点的子节点列表最后位置插入一个节点
* @method appendChild
* @param { UE.uNode } node 要插入的节点
* @return { UE.uNode } 返回刚插入的子节点
* @example
* ```javascript
* node.appendChild( newNode ); //在node内插入子节点newNode
* ```
*/
appendChild: function(node) {
if(this.type == 'root' || (this.type == 'element' && !dtd.$empty[this.tagName])) {
if(!this.children) {
this.children = []
}
if(node.parentNode) {
node.parentNode.removeChild(node);
}
for(var i = 0, ci; ci = this.children[i]; i++) {
if(ci === node) {
this.children.splice(i, 1);
break;
}
}
this.children.push(node);
node.parentNode = this;
return node;
}
},
/**
* 在传入节点的前面插入一个节点
* @method insertBefore
* @param { UE.uNode } target 要插入的节点
* @param { UE.uNode } source 在该参数节点前面插入
* @return { UE.uNode } 返回刚插入的子节点
* @example
* ```javascript
* node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
* ```
*/
insertBefore: function(target, source) {
if(this.children) {
if(target.parentNode) {
target.parentNode.removeChild(target);
}
for(var i = 0, ci; ci = this.children[i]; i++) {
if(ci === source) {
this.children.splice(i, 0, target);
target.parentNode = this;
return target;
}
}
}
},
/**
* 在传入节点的后面插入一个节点
* @method insertAfter
* @param { UE.uNode } target 要插入的节点
* @param { UE.uNode } source 在该参数节点后面插入
* @return { UE.uNode } 返回刚插入的子节点
* @example
* ```javascript
* node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
* ```
*/
insertAfter: function(target, source) {
if(this.children) {
if(target.parentNode) {
target.parentNode.removeChild(target);
}
for(var i = 0, ci; ci = this.children[i]; i++) {
if(ci === source) {
this.children.splice(i + 1, 0, target);
target.parentNode = this;
return target;
}
}
}
},
/**
* 从当前节点的子节点列表中,移除节点
* @method removeChild
* @param { UE.uNode } node 要移除的节点引用
* @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
* @return { * } 返回刚移除的子节点
* @example
* ```javascript
* node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
* ```
*/
removeChild: function(node, keepChildren) {
if(this.children) {
for(var i = 0, ci; ci = this.children[i]; i++) {
if(ci === node) {
this.children.splice(i, 1);
ci.parentNode = null;
if(keepChildren && ci.children && ci.children.length) {
for(var j = 0, cj; cj = ci.children[j]; j++) {
this.children.splice(i + j, 0, cj);
cj.parentNode = this;
}
}
return ci;
}
}
}
},
/**
* 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
* @method getAttr
* @param { String } attrName 要获取的属性名称
* @return { * } 返回attrs对象下的属性值
* @example
* ```javascript
* node.getAttr('title');
* ```
*/
getAttr: function(attrName) {
return this.attrs && this.attrs[attrName.toLowerCase()]
},
/**
* 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
* @method setAttr
* @param { String } attrName 要设置的属性名称
* @param { * } attrVal 要设置的属性值,类型视设置的属性而定
* @return { * } 返回attrs对象下的属性值
* @example
* ```javascript
* node.setAttr('title','标题');
* ```
*/
setAttr: function(attrName, attrVal) {
if(!attrName) {
delete this.attrs;
return;
}
if(!this.attrs) {
this.attrs = {};
}
if(utils.isObject(attrName)) {
for(var a in attrName) {
if(!attrName[a]) {
delete this.attrs[a]
} else {
this.attrs[a.toLowerCase()] = attrName[a];
}
}
} else {
if(!attrVal) {
delete this.attrs[attrName]
} else {
this.attrs[attrName.toLowerCase()] = attrVal;
}
}
},
/**
* 获取当前节点在父节点下的位置索引
* @method getIndex
* @return { Number } 返回索引数值,如果没有父节点,返回-1
* @example
* ```javascript
* node.getIndex();
* ```
*/
getIndex: function() {
var parent = this.parentNode;
for(var i = 0, ci; ci = parent.children[i]; i++) {
if(ci === this) {
return i;
}
}
return -1;
},
/**
* 在当前节点下,根据id查找节点
* @method getNodeById
* @param { String } id 要查找的id
* @return { UE.uNode } 返回找到的节点
* @example
* ```javascript
* node.getNodeById('textId');
* ```
*/
getNodeById: function(id) {
var node;
if(this.children && this.children.length) {
for(var i = 0, ci; ci = this.children[i++];) {
if(node = getNodeById(ci, id)) {
return node;
}
}
}
},
/**
* 在当前节点下,根据元素名称查找节点列表
* @method getNodesByTagName
* @param { String } tagNames 要查找的元素名称
* @return { Array } 返回找到的节点列表
* @example
* ```javascript
* node.getNodesByTagName('span');
* ```
*/
getNodesByTagName: function(tagNames) {
tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, ' ').split(' ');
var arr = [],
me = this;
utils.each(tagNames, function(tagName) {
if(me.children && me.children.length) {
for(var i = 0, ci; ci = me.children[i++];) {
getNodesByTagName(ci, tagName, arr)
}
}
});
return arr;
},
/**
* 根据样式名称,获取节点的样式值
* @method getStyle
* @param { String } name 要获取的样式名称
* @return { String } 返回样式值
* @example
* ```javascript
* node.getStyle('font-size');
* ```
*/
getStyle: function(name) {
var cssStyle = this.getAttr('style');
if(!cssStyle) {
return ''
}
var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+)', 'i');
var match = cssStyle.match(reg);
if(match && match[0]) {
return match[2]
}
return '';
},
/**
* 给节点设置样式
* @method setStyle
* @param { String } name 要设置的的样式名称
* @param { String } val 要设置的的样值
* @example
* ```javascript
* node.setStyle('font-size', '12px');
* ```
*/
setStyle: function(name, val) {
function exec(name, val) {
var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+;?)', 'gi');
cssStyle = cssStyle.replace(reg, '$1');
if(val) {
cssStyle = name + ':' + utils.unhtml(val) + ';' + cssStyle
}
}
var cssStyle = this.getAttr('style');
if(!cssStyle) {
cssStyle = '';
}
if(utils.isObject(name)) {
for(var a in name) {
exec(a, name[a])
}
} else {
exec(name, val)
}
this.setAttr('style', utils.trim(cssStyle))
},
/**
* 传入一个函数,递归遍历当前节点下的所有节点
* @method traversal
* @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
* @example
* ```javascript
* traversal(node, function(){
* console.log(node.type);
* });
* ```
*/
traversal: function(fn) {
if(this.children && this.children.length) {
nodeTraversal(this, fn);
}
return this;
}
}
})();
// core/htmlparser.js
/**
* html字符串转换成uNode节点
* @file
* @module UE
* @since 1.2.6.1
*/
/**
* UEditor公用空间,UEditor所有的功能都挂载在该空间下
* @unfile
* @module UE
*/
/**
* html字符串转换成uNode节点的静态方法
* @method htmlparser
* @param { String } htmlstr 要转换的html代码
* @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符
* @return { uNode } 给定的html片段转换形成的uNode对象
* @example
* ```javascript
* var root = UE.htmlparser('htmlparser
', true);
* ```
*/
var htmlparser = UE.htmlparser = function(htmlstr, ignoreBlank) {
//todo 原来的方式 [^"'<>\/] 有\/就不能配对上 这样的标签了
//先去掉了,加上的原因忘了,这里先记录
var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
//ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
var allowEmptyTags = {
b: 1,
code: 1,
i: 1,
u: 1,
strike: 1,
s: 1,
tt: 1,
strong: 1,
q: 1,
samp: 1,
em: 1,
span: 1,
sub: 1,
img: 1,
sup: 1,
font: 1,
big: 1,
small: 1,
iframe: 1,
a: 1,
br: 1,
pre: 1
};
htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, 'g'), '');
if(!ignoreBlank) {
htmlstr = htmlstr.replace(new RegExp('[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*<\/?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*', 'g'), function(a, b) {
//br暂时单独处理
if(b && allowEmptyTags[b.toLowerCase()]) {
return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, '');
}
return a.replace(new RegExp('^[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+'), '').replace(new RegExp('[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+$'), '');
});
}
var notTransAttrs = {
'href': 1,
'src': 1
};
var uNode = UE.uNode,
needParentNode = {
'td': 'tr',
'tr': ['tbody', 'thead', 'tfoot'],
'tbody': 'table',
'th': 'tr',
'thead': 'table',
'tfoot': 'table',
'caption': 'table',
'li': ['ul', 'ol'],
'dt': 'dl',
'dd': 'dl',
'option': 'select'
},
needChild = {
'ol': 'li',
'ul': 'li'
};
function text(parent, data) {
if(needChild[parent.tagName]) {
var tmpNode = uNode.createElement(needChild[parent.tagName]);
parent.appendChild(tmpNode);
tmpNode.appendChild(uNode.createText(data));
parent = tmpNode;
} else {
parent.appendChild(uNode.createText(data));
}
}
function element(parent, tagName, htmlattr) {
var needParentTag;
if(needParentTag = needParentNode[tagName]) {
var tmpParent = parent,
hasParent;
while(tmpParent.type != 'root') {
if(utils.isArray(needParentTag) ? utils.indexOf(needParentTag, tmpParent.tagName) != -1 : needParentTag == tmpParent.tagName) {
parent = tmpParent;
hasParent = true;
break;
}
tmpParent = tmpParent.parentNode;
}
if(!hasParent) {
parent = element(parent, utils.isArray(needParentTag) ? needParentTag[0] : needParentTag)
}
}
//按dtd处理嵌套
// if(parent.type != 'root' && !dtd[parent.tagName][tagName])
// parent = parent.parentNode;
var elm = new uNode({
parentNode: parent,
type: 'element',
tagName: tagName.toLowerCase(),
//是自闭合的处理一下
children: dtd.$empty[tagName] ? null : []
});
//如果属性存在,处理属性
if(htmlattr) {
var attrs = {},
match;
while(match = re_attr.exec(htmlattr)) {
attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()] ? (match[2] || match[3] || match[4]) : utils.unhtml(match[2] || match[3] || match[4])
}
elm.attrs = attrs;
}
//trace:3970
// //如果parent下不能放elm
// if(dtd.$inline[parent.tagName] && dtd.$block[elm.tagName] && !dtd[parent.tagName][elm.tagName]){
// parent = parent.parentNode;
// elm.parentNode = parent;
// }
parent.children.push(elm);
//如果是自闭合节点返回父亲节点
return dtd.$empty[tagName] ? parent : elm
}
function comment(parent, data) {
parent.children.push(new uNode({
type: 'comment',
data: data,
parentNode: parent
}));
}
var match, currentIndex = 0,
nextIndex = 0;
//设置根节点
var root = new uNode({
type: 'root',
children: []
});
var currentParent = root;
while(match = re_tag.exec(htmlstr)) {
currentIndex = match.index;
try {
if(currentIndex > nextIndex) {
//text node
text(currentParent, htmlstr.slice(nextIndex, currentIndex));
}
if(match[3]) {
if(dtd.$cdata[currentParent.tagName]) {
text(currentParent, match[0]);
} else {
//start tag
currentParent = element(currentParent, match[3].toLowerCase(), match[4]);
}
} else if(match[1]) {
if(currentParent.type != 'root') {
if(dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]) {
text(currentParent, match[0]);
} else {
var tmpParent = currentParent;
while(currentParent.type == 'element' && currentParent.tagName != match[1].toLowerCase()) {
currentParent = currentParent.parentNode;
if(currentParent.type == 'root') {
currentParent = tmpParent;
throw 'break'
}
}
//end tag
currentParent = currentParent.parentNode;
}
}
} else if(match[2]) {
//comment
comment(currentParent, match[2])
}
} catch(e) {}
nextIndex = re_tag.lastIndex;
}
//如果结束是文本,就有可能丢掉,所以这里手动判断一下
//例如 sdfsdfsdfsdfsdfsdfsdf
if(nextIndex < htmlstr.length) {
text(currentParent, htmlstr.slice(nextIndex));
}
return root;
};
// core/filternode.js
/**
* UE过滤节点的静态方法
* @file
*/
/**
* UEditor公用空间,UEditor所有的功能都挂载在该空间下
* @module UE
*/
/**
* 根据传入节点和过滤规则过滤相应节点
* @module UE
* @since 1.2.6.1
* @method filterNode
* @param { Object } root 指定root节点
* @param { Object } rules 过滤规则json对象
* @example
* ```javascript
* UE.filterNode(root,editor.options.filterRules);
* ```
*/
var filterNode = UE.filterNode = function() {
function filterNode(node, rules) {
switch(node.type) {
case 'text':
break;
case 'element':
var val;
if(val = rules[node.tagName]) {
if(val === '-') {
node.parentNode.removeChild(node)
} else if(utils.isFunction(val)) {
var parentNode = node.parentNode,
index = node.getIndex();
val(node);
if(node.parentNode) {
if(node.children) {
for(var i = 0, ci; ci = node.children[i];) {
filterNode(ci, rules);
if(ci.parentNode) {
i++;
}
}
}
} else {
for(var i = index, ci; ci = parentNode.children[i];) {
filterNode(ci, rules);
if(ci.parentNode) {
i++;
}
}
}
} else {
var attrs = val['$'];
if(attrs && node.attrs) {
var tmpAttrs = {},
tmpVal;
for(var a in attrs) {
tmpVal = node.getAttr(a);
//todo 只先对style单独处理
if(a == 'style' && utils.isArray(attrs[a])) {
var tmpCssStyle = [];
utils.each(attrs[a], function(v) {
var tmp;
if(tmp = node.getStyle(v)) {
tmpCssStyle.push(v + ':' + tmp);
}
});
tmpVal = tmpCssStyle.join(';')
}
if(tmpVal) {
tmpAttrs[a] = tmpVal;
}
}
node.attrs = tmpAttrs;
}
if(node.children) {
for(var i = 0, ci; ci = node.children[i];) {
filterNode(ci, rules);
if(ci.parentNode) {
i++;
}
}
}
}
} else {
//如果不在名单里扣出子节点并删除该节点,cdata除外
if(dtd.$cdata[node.tagName]) {
node.parentNode.removeChild(node)
} else {
var parentNode = node.parentNode,
index = node.getIndex();
node.parentNode.removeChild(node, true);
for(var i = index, ci; ci = parentNode.children[i];) {
filterNode(ci, rules);
if(ci.parentNode) {
i++;
}
}
}
}
break;
case 'comment':
node.parentNode.removeChild(node)
}
}
return function(root, rules) {
if(utils.isEmptyObject(rules)) {
return root;
}
var val;
if(val = rules['-']) {
utils.each(val.split(' '), function(k) {
rules[k] = '-'
})
}
for(var i = 0, ci; ci = root.children[i];) {
filterNode(ci, rules);
if(ci.parentNode) {
i++;
}
}
return root;
}
}();
// core/plugin.js
/**
* Created with JetBrains PhpStorm.
* User: campaign
* Date: 10/8/13
* Time: 6:15 PM
* To change this template use File | Settings | File Templates.
*/
UE.plugin = function() {
var _plugins = {};
return {
register: function(pluginName, fn, oldOptionName, afterDisabled) {
if(oldOptionName && utils.isFunction(oldOptionName)) {
afterDisabled = oldOptionName;
oldOptionName = null
}
_plugins[pluginName] = {
optionName: oldOptionName || pluginName,
execFn: fn,
//当插件被禁用时执行
afterDisabled: afterDisabled
}
},
load: function(editor) {
utils.each(_plugins, function(plugin) {
var _export = plugin.execFn.call(editor);
if(editor.options[plugin.optionName] !== false) {
if(_export) {
//后边需要再做扩展
utils.each(_export, function(v, k) {
switch(k.toLowerCase()) {
case 'shortcutkey':
editor.addshortcutkey(v);
break;
case 'bindevents':
utils.each(v, function(fn, eventName) {
editor.addListener(eventName, fn);
});
break;
case 'bindmultievents':
utils.each(utils.isArray(v) ? v : [v], function(event) {
var types = utils.trim(event.type).split(/\s+/);
utils.each(types, function(eventName) {
editor.addListener(eventName, event.handler);
});
});
break;
case 'commands':
utils.each(v, function(execFn, execName) {
editor.commands[execName] = execFn
});
break;
case 'outputrule':
editor.addOutputRule(v);
break;
case 'inputrule':
editor.addInputRule(v);
break;
case 'defaultoptions':
editor.setOpt(v)
}
})
}
} else if(plugin.afterDisabled) {
plugin.afterDisabled.call(editor)
}
});
//向下兼容
utils.each(UE.plugins, function(plugin) {
plugin.call(editor);
});
},
run: function(pluginName, editor) {
var plugin = _plugins[pluginName];
if(plugin) {
plugin.exeFn.call(editor)
}
}
}
}();
// core/keymap.js
var keymap = UE.keymap = {
'Backspace': 8,
'Tab': 9,
'Enter': 13,
'Shift': 16,
'Control': 17,
'Alt': 18,
'CapsLock': 20,
'Esc': 27,
'Spacebar': 32,
'PageUp': 33,
'PageDown': 34,
'End': 35,
'Home': 36,
'Left': 37,
'Up': 38,
'Right': 39,
'Down': 40,
'Insert': 45,
'Del': 46,
'NumLock': 144,
'Cmd': 91,
'=': 187,
'-': 189,
"b": 66,
'i': 73,
//回退
'z': 90,
'y': 89,
//粘贴
'v': 86,
'x': 88,
's': 83,
'n': 78
};
// core/localstorage.js
//存储媒介封装
var LocalStorage = UE.LocalStorage = (function() {
var storage = window.localStorage || getUserData() || null,
LOCAL_FILE = 'localStorage';
return {
saveLocalData: function(key, data) {
if(storage && data) {
storage.setItem(key, data);
return true;
}
return false;
},
getLocalData: function(key) {
if(storage) {
return storage.getItem(key);
}
return null;
},
removeItem: function(key) {
storage && storage.removeItem(key);
}
};
function getUserData() {
var container = document.createElement("div");
container.style.display = "none";
if(!container.addBehavior) {
return null;
}
container.addBehavior("#default#userdata");
return {
getItem: function(key) {
var result = null;
try {
document.body.appendChild(container);
container.load(LOCAL_FILE);
result = container.getAttribute(key);
document.body.removeChild(container);
} catch(e) {}
return result;
},
setItem: function(key, value) {
document.body.appendChild(container);
container.setAttribute(key, value);
container.save(LOCAL_FILE);
document.body.removeChild(container);
},
//// 暂时没有用到
//clear: function () {
//
// var expiresTime = new Date();
// expiresTime.setFullYear(expiresTime.getFullYear() - 1);
// document.body.appendChild(container);
// container.expires = expiresTime.toUTCString();
// container.save(LOCAL_FILE);
// document.body.removeChild(container);
//
//},
removeItem: function(key) {
document.body.appendChild(container);
container.removeAttribute(key);
container.save(LOCAL_FILE);
document.body.removeChild(container);
}
};
}
})();
(function() {
var ROOTKEY = 'ueditor_preference';
UE.Editor.prototype.setPreferences = function(key, value) {
var obj = {};
if(utils.isString(key)) {
obj[key] = value;
} else {
obj = key;
}
var data = LocalStorage.getLocalData(ROOTKEY);
if(data && (data = utils.str2json(data))) {
utils.extend(data, obj);
} else {
data = obj;
}
data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
};
UE.Editor.prototype.getPreferences = function(key) {
var data = LocalStorage.getLocalData(ROOTKEY);
if(data && (data = utils.str2json(data))) {
return key ? data[key] : data
}
return null;
};
UE.Editor.prototype.removePreferences = function(key) {
var data = LocalStorage.getLocalData(ROOTKEY);
if(data && (data = utils.str2json(data))) {
data[key] = undefined;
delete data[key]
}
data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
};
})();
// plugins/defaultfilter.js
///import core
///plugin 编辑器默认的过滤转换机制
UE.plugins['defaultfilter'] = function() {
var me = this;
me.setOpt({
'allowDivTransToP': true,
'disabledTableInTable': true
});
//默认的过滤处理
//进入编辑器的内容处理
me.addInputRule(function(root) {
var allowDivTransToP = this.options.allowDivTransToP;
var val;
function tdParent(node) {
while(node && node.type == 'element') {
if(node.tagName == 'td') {
return true;
}
node = node.parentNode;
}
return false;
}
//进行默认的处理
root.traversal(function(node) {
if(node.type == 'element') {
if(!dtd.$cdata[node.tagName] && me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) {
if(!node.firstChild()) node.parentNode.removeChild(node);
else if(node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) {
node.parentNode.removeChild(node, true)
}
return;
}
switch(node.tagName) {
case 'style':
case 'script':
node.setAttr({
cdata_tag: node.tagName,
cdata_data: (node.innerHTML() || ''),
'_ue_custom_node_': 'true'
});
node.tagName = 'div';
node.innerHTML('');
break;
case 'a':
if(val = node.getAttr('href')) {
node.setAttr('_href', val)
}
break;
case 'img':
//todo base64暂时去掉,后边做远程图片上传后,干掉这个
if(val = node.getAttr('src')) {
if(/^data:/.test(val)) {
node.parentNode.removeChild(node);
break;
}
}
node.setAttr('_src', node.getAttr('src'));
break;
case 'span':
if(browser.webkit && (val = node.getStyle('white-space'))) {
if(/nowrap|normal/.test(val)) {
node.setStyle('white-space', '');
if(me.options.autoClearEmptyNode && utils.isEmptyObject(node.attrs)) {
node.parentNode.removeChild(node, true)
}
}
}
val = node.getAttr('id');
if(val && /^_baidu_bookmark_/i.test(val)) {
node.parentNode.removeChild(node)
}
break;
case 'p':
if(val = node.getAttr('align')) {
node.setAttr('align');
node.setStyle('text-align', val)
}
//trace:3431
// var cssStyle = node.getAttr('style');
// if (cssStyle) {
// cssStyle = cssStyle.replace(/(margin|padding)[^;]+/g, '');
// node.setAttr('style', cssStyle)
//
// }
//p标签不允许嵌套
utils.each(node.children, function(n) {
if(n.type == 'element' && n.tagName == 'p') {
var next = n.nextSibling();
node.parentNode.insertAfter(n, node);
var last = n;
while(next) {
var tmp = next.nextSibling();
node.parentNode.insertAfter(next, last);
last = next;
next = tmp;
}
return false;
}
});
if(!node.firstChild()) {
node.innerHTML(browser.ie ? ' ' : ' ')
}
break;
case 'div':
if(node.getAttr('cdata_tag')) {
break;
}
//针对代码这里不处理插入代码的div
val = node.getAttr('class');
if(val && /^line number\d+/.test(val)) {
break;
}
if(!allowDivTransToP) {
break;
}
var tmpNode, p = UE.uNode.createElement('p');
while(tmpNode = node.firstChild()) {
if(tmpNode.type == 'text' || !UE.dom.dtd.$block[tmpNode.tagName]) {
p.appendChild(tmpNode);
} else {
if(p.firstChild()) {
node.parentNode.insertBefore(p, node);
p = UE.uNode.createElement('p');
} else {
node.parentNode.insertBefore(tmpNode, node);
}
}
}
if(p.firstChild()) {
node.parentNode.insertBefore(p, node);
}
node.parentNode.removeChild(node);
break;
case 'dl':
node.tagName = 'ul';
break;
case 'dt':
case 'dd':
node.tagName = 'li';
break;
case 'li':
var className = node.getAttr('class');
if(!className || !/list\-/.test(className)) {
node.setAttr()
}
var tmpNodes = node.getNodesByTagName('ol ul');
UE.utils.each(tmpNodes, function(n) {
node.parentNode.insertAfter(n, node);
});
break;
case 'td':
case 'th':
case 'caption':
if(!node.children || !node.children.length) {
node.appendChild(browser.ie11below ? UE.uNode.createText(' ') : UE.uNode.createElement('br'))
}
break;
case 'table':
if(me.options.disabledTableInTable && tdParent(node)) {
node.parentNode.insertBefore(UE.uNode.createText(node.innerText()), node);
node.parentNode.removeChild(node)
}
}
}
// if(node.type == 'comment'){
// node.parentNode.removeChild(node);
// }
})
});
//从编辑器出去的内容处理
me.addOutputRule(function(root) {
var val;
root.traversal(function(node) {
if(node.type == 'element') {
if(me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) {
if(!node.firstChild()) node.parentNode.removeChild(node);
else if(node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) {
node.parentNode.removeChild(node, true)
}
return;
}
switch(node.tagName) {
case 'div':
if(val = node.getAttr('cdata_tag')) {
node.tagName = val;
node.appendChild(UE.uNode.createText(node.getAttr('cdata_data')));
node.setAttr({
cdata_tag: '',
cdata_data: '',
'_ue_custom_node_': ''
});
}
break;
case 'a':
if(val = node.getAttr('_href')) {
node.setAttr({
'href': utils.html(val),
'_href': ''
})
}
break;
break;
case 'span':
val = node.getAttr('id');
if(val && /^_baidu_bookmark_/i.test(val)) {
node.parentNode.removeChild(node)
}
break;
case 'img':
if(val = node.getAttr('_src')) {
node.setAttr({
'src': node.getAttr('_src'),
'_src': ''
})
}
}
}
})
});
};
// plugins/inserthtml.js
/**
* 插入html字符串插件
* @file
* @since 1.2.6.1
*/
/**
* 插入html代码
* @command inserthtml
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } html 插入的html字符串
* @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入
* @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。
* @example
* ```javascript
* //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本
* //执行命令,插入CC
* //插入后的效果 xxxCCxxx
* //xx|xxx 当前选区为闭合状态
* //插入CC
* //结果 xx CC xxx
* //xxxx |xxx 当前选区在两个p标签之间
* //插入 xxxx
* //结果 xxxx xxxx xxx
* ```
*/
UE.commands['inserthtml'] = {
execCommand: function(command, html, notNeedFilter) {
var me = this,
range,
div;
if(!html) {
return;
}
if(me.fireEvent('beforeinserthtml', html) === true) {
return;
}
range = me.selection.getRange();
div = range.document.createElement('div');
div.style.display = 'inline';
if(!notNeedFilter) {
var root = UE.htmlparser(html);
//如果给了过滤规则就先进行过滤
if(me.options.filterRules) {
UE.filterNode(root, me.options.filterRules);
}
//执行默认的处理
me.filterInputRule(root);
html = root.toHtml()
}
div.innerHTML = utils.trim(html);
if(!range.collapsed) {
var tmpNode = range.startContainer;
if(domUtils.isFillChar(tmpNode)) {
range.setStartBefore(tmpNode)
}
tmpNode = range.endContainer;
if(domUtils.isFillChar(tmpNode)) {
range.setEndAfter(tmpNode)
}
range.txtToElmBoundary();
//结束边界可能放到了br的前边,要把br包含进来
// x[xxx]
if(range.endContainer && range.endContainer.nodeType == 1) {
tmpNode = range.endContainer.childNodes[range.endOffset];
if(tmpNode && domUtils.isBr(tmpNode)) {
range.setEndAfter(tmpNode);
}
}
if(range.startOffset == 0) {
tmpNode = range.startContainer;
if(domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
tmpNode = range.endContainer;
if(range.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode, 'lastChild')) {
me.body.innerHTML = '' + (browser.ie ? '' : ' ') + ' ';
range.setStart(me.body.firstChild, 0).collapse(true)
}
}
}!range.collapsed && range.deleteContents();
if(range.startContainer.nodeType == 1) {
var child = range.startContainer.childNodes[range.startOffset],
pre;
if(child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)) {
range.setEnd(pre, pre.childNodes.length).collapse();
while(child.firstChild) {
pre.appendChild(child.firstChild);
}
domUtils.remove(child);
}
}
}
var child, parent, pre, tmp, hadBreak = 0,
nextNode;
//如果当前位置选中了fillchar要干掉,要不会产生空行
if(range.inFillChar()) {
child = range.startContainer;
if(domUtils.isFillChar(child)) {
range.setStartBefore(child).collapse(true);
domUtils.remove(child);
} else if(domUtils.isFillChar(child, true)) {
child.nodeValue = child.nodeValue.replace(fillCharReg, '');
range.startOffset--;
range.collapsed && range.collapse(true)
}
}
//列表单独处理
var li = domUtils.findParentByTagName(range.startContainer, 'li', true);
if(li) {
var next, last;
while(child = div.firstChild) {
//针对hr单独处理一下先
while(child && (child.nodeType == 3 || !domUtils.isBlockElm(child) || child.tagName == 'HR')) {
next = child.nextSibling;
range.insertNode(child).collapse();
last = child;
child = next;
}
if(child) {
if(/^(ol|ul)$/i.test(child.tagName)) {
while(child.firstChild) {
last = child.firstChild;
domUtils.insertAfter(li, child.firstChild);
li = li.nextSibling;
}
domUtils.remove(child)
} else {
var tmpLi;
next = child.nextSibling;
tmpLi = me.document.createElement('li');
domUtils.insertAfter(li, tmpLi);
tmpLi.appendChild(child);
last = child;
child = next;
li = tmpLi;
}
}
}
li = domUtils.findParentByTagName(range.startContainer, 'li', true);
if(domUtils.isEmptyBlock(li)) {
domUtils.remove(li)
}
if(last) {
range.setStartAfter(last).collapse(true).select(true)
}
} else {
while(child = div.firstChild) {
if(hadBreak) {
var p = me.document.createElement('p');
while(child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
nextNode = child.nextSibling;
p.appendChild(child);
child = nextNode;
}
if(p.firstChild) {
child = p
}
}
range.insertNode(child);
nextNode = child.nextSibling;
if(!hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm(child)) {
parent = domUtils.findParent(child, function(node) {
return domUtils.isBlockElm(node);
});
if(parent && parent.tagName.toLowerCase() != 'body' && !(dtd[parent.tagName][child.nodeName] && child.parentNode === parent)) {
if(!dtd[parent.tagName][child.nodeName]) {
pre = parent;
} else {
tmp = child.parentNode;
while(tmp !== parent) {
pre = tmp;
tmp = tmp.parentNode;
}
}
domUtils.breakParent(child, pre || tmp);
//去掉break后前一个多余的节点 |<[p> ==> |
var pre = child.previousSibling;
domUtils.trimWhiteTextNode(pre);
if(!pre.childNodes.length) {
domUtils.remove(pre);
}
//trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
if(!browser.ie &&
(next = child.nextSibling) &&
domUtils.isBlockElm(next) &&
next.lastChild &&
!domUtils.isBr(next.lastChild)) {
next.appendChild(me.document.createElement('br'));
}
hadBreak = 1;
}
}
var next = child.nextSibling;
if(!div.firstChild && next && domUtils.isBlockElm(next)) {
range.setStart(next, 0).collapse(true);
break;
}
range.setEndAfter(child).collapse();
}
child = range.startContainer;
if(nextNode && domUtils.isBr(nextNode)) {
domUtils.remove(nextNode)
}
//用chrome可能有空白展位符
if(domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
if(nextNode = child.nextSibling) {
domUtils.remove(child);
if(nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
range.setStart(nextNode, 0).collapse(true).shrinkBoundary()
}
} else {
try {
child.innerHTML = browser.ie ? domUtils.fillChar : ' ';
} catch(e) {
range.setStartBefore(child);
domUtils.remove(child)
}
}
}
//加上true因为在删除表情等时会删两次,第一次是删的fillData
try {
range.select(true);
} catch(e) {}
}
setTimeout(function() {
range = me.selection.getRange();
range.scrollToView(me.autoHeightEnabled, me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0);
me.fireEvent('afterinserthtml', html);
}, 200);
}
};
// plugins/autotypeset.js
/**
* 自动排版
* @file
* @since 1.2.6.1
*/
/**
* 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。
* @command autotypeset
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'autotypeset' );
* ```
*/
UE.plugins['autotypeset'] = function() {
this.setOpt({
'autotypeset': {
mergeEmptyline: true, //合并空行
removeClass: true, //去掉冗余的class
removeEmptyline: false, //去掉空行
textAlign: "left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
imageBlockLine: 'center', //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
pasteFilter: false, //根据规则过滤没事粘贴进来的内容
clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
removeEmptyNode: false, // 去掉空节点
//可以去掉的标签
removeTagNames: utils.extend({
div: 1
}, dtd.$removeEmpty),
indent: false, // 行首缩进
indentValue: '2em', //行首缩进的大小
bdc2sb: false,
tobdc: false
}
});
var me = this,
opt = me.options.autotypeset,
remainClass = {
'selectTdClass': 1,
'pagebreak': 1,
'anchorclass': 1
},
remainTag = {
'li': 1
},
tags = {
div: 1,
p: 1,
//trace:2183 这些也认为是行
blockquote: 1,
center: 1,
h1: 1,
h2: 1,
h3: 1,
h4: 1,
h5: 1,
h6: 1,
span: 1
},
highlightCont;
//升级了版本,但配置项目里没有autotypeset
if(!opt) {
return;
}
readLocalOpts();
function isLine(node, notEmpty) {
if(!node || node.nodeType == 3)
return 0;
if(domUtils.isBr(node))
return 1;
if(node && node.parentNode && tags[node.tagName.toLowerCase()]) {
if(highlightCont && highlightCont.contains(node) ||
node.getAttribute('pagebreak')
) {
return 0;
}
return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node, new RegExp('[\\s' + domUtils.fillChar +
']', 'g'));
}
}
function removeNotAttributeSpan(node) {
if(!node.style.cssText) {
domUtils.removeAttributes(node, ['style']);
if(node.tagName.toLowerCase() == 'span' && domUtils.hasNoAttributes(node)) {
domUtils.remove(node, true);
}
}
}
function autotype(type, html) {
var me = this,
cont;
if(html) {
if(!opt.pasteFilter) {
return;
}
cont = me.document.createElement('div');
cont.innerHTML = html.html;
} else {
cont = me.document.body;
}
var nodes = domUtils.getElementsByTagName(cont, '*');
// 行首缩进,段落方向,段间距,段内间距
for(var i = 0, ci; ci = nodes[i++];) {
if(me.fireEvent('excludeNodeinautotype', ci) === true) {
continue;
}
//font-size
if(opt.clearFontSize && ci.style.fontSize) {
domUtils.removeStyle(ci, 'font-size');
removeNotAttributeSpan(ci);
}
//font-family
if(opt.clearFontFamily && ci.style.fontFamily) {
domUtils.removeStyle(ci, 'font-family');
removeNotAttributeSpan(ci);
}
if(isLine(ci)) {
//合并空行
if(opt.mergeEmptyline) {
var next = ci.nextSibling,
tmpNode, isBr = domUtils.isBr(ci);
while(isLine(next)) {
tmpNode = next;
next = tmpNode.nextSibling;
if(isBr && (!next || next && !domUtils.isBr(next))) {
break;
}
domUtils.remove(tmpNode);
}
}
//去掉空行,保留占位的空行
if(opt.removeEmptyline && domUtils.inDoc(ci, cont) && !remainTag[ci.parentNode.tagName.toLowerCase()]) {
if(domUtils.isBr(ci)) {
next = ci.nextSibling;
if(next && !domUtils.isBr(next)) {
continue;
}
}
domUtils.remove(ci);
continue;
}
}
if(isLine(ci, true) && ci.tagName != 'SPAN') {
if(opt.indent) {
ci.style.textIndent = opt.indentValue;
}
if(opt.textAlign) {
ci.style.textAlign = opt.textAlign;
}
// if(opt.lineHeight)
// ci.style.lineHeight = opt.lineHeight + 'cm';
}
//去掉class,保留的class不去掉
if(opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]) {
if(highlightCont && highlightCont.contains(ci)) {
continue;
}
domUtils.removeAttributes(ci, ['class']);
}
//表情不处理
if(opt.imageBlockLine && ci.tagName.toLowerCase() == 'img' && !ci.getAttribute('emotion')) {
if(html) {
var img = ci;
switch(opt.imageBlockLine) {
case 'left':
case 'right':
case 'none':
var pN = img.parentNode,
tmpNode, pre, next;
while(dtd.$inline[pN.tagName] || pN.tagName == 'A') {
pN = pN.parentNode;
}
tmpNode = pN;
if(tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode, 'text-align') == 'center') {
if(!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function(node) {
return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
}) == 1) {
pre = tmpNode.previousSibling;
next = tmpNode.nextSibling;
if(pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)) {
pre.appendChild(tmpNode.firstChild);
while(next.firstChild) {
pre.appendChild(next.firstChild);
}
domUtils.remove(tmpNode);
domUtils.remove(next);
} else {
domUtils.setStyle(tmpNode, 'text-align', '');
}
}
}
domUtils.setStyle(img, 'float', opt.imageBlockLine);
break;
case 'center':
if(me.queryCommandValue('imagefloat') != 'center') {
pN = img.parentNode;
domUtils.setStyle(img, 'float', 'none');
tmpNode = img;
while(pN && domUtils.getChildCount(pN, function(node) {
return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
}) == 1 &&
(dtd.$inline[pN.tagName] || pN.tagName == 'A')) {
tmpNode = pN;
pN = pN.parentNode;
}
var pNode = me.document.createElement('p');
domUtils.setAttributes(pNode, {
style: 'text-align:center'
});
tmpNode.parentNode.insertBefore(pNode, tmpNode);
pNode.appendChild(tmpNode);
domUtils.setStyle(tmpNode, 'float', '');
}
}
} else {
var range = me.selection.getRange();
range.selectNode(ci).select();
me.execCommand('imagefloat', opt.imageBlockLine);
}
}
//去掉冗余的标签
if(opt.removeEmptyNode) {
if(opt.removeTagNames[ci.tagName.toLowerCase()] && domUtils.hasNoAttributes(ci) && domUtils.isEmptyBlock(ci)) {
domUtils.remove(ci);
}
}
}
if(opt.tobdc) {
var root = UE.htmlparser(cont.innerHTML);
root.traversal(function(node) {
if(node.type == 'text') {
node.data = ToDBC(node.data)
}
});
cont.innerHTML = root.toHtml()
}
if(opt.bdc2sb) {
var root = UE.htmlparser(cont.innerHTML);
root.traversal(function(node) {
if(node.type == 'text') {
node.data = DBC2SB(node.data)
}
});
cont.innerHTML = root.toHtml()
}
if(html) {
html.html = cont.innerHTML;
}
}
if(opt.pasteFilter) {
me.addListener('beforepaste', autotype);
}
function DBC2SB(str) {
var result = '';
for(var i = 0; i < str.length; i++) {
var code = str.charCodeAt(i); //获取当前字符的unicode编码
if(code >= 65281 && code <= 65373) //在这个unicode编码范围中的是所有的英文字母已经各种字符
{
result += String.fromCharCode(str.charCodeAt(i) - 65248); //把全角字符的unicode编码转换为对应半角字符的unicode码
} else if(code == 12288) //空格
{
result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
} else {
result += str.charAt(i);
}
}
return result;
}
function ToDBC(txtstring) {
txtstring = utils.html(txtstring);
var tmp = "";
var mark = ""; /*用于判断,如果是html尖括里的标记,则不进行全角的转换*/
for(var i = 0; i < txtstring.length; i++) {
if(txtstring.charCodeAt(i) == 32) {
tmp = tmp + String.fromCharCode(12288);
} else if(txtstring.charCodeAt(i) < 127) {
tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248);
} else {
tmp += txtstring.charAt(i);
}
}
return tmp;
}
function readLocalOpts() {
var cookieOpt = me.getPreferences('autotypeset');
utils.extend(me.options.autotypeset, cookieOpt);
}
me.commands['autotypeset'] = {
execCommand: function() {
me.removeListener('beforepaste', autotype);
if(opt.pasteFilter) {
me.addListener('beforepaste', autotype);
}
autotype.call(me)
}
};
};
// plugins/autosubmit.js
/**
* 快捷键提交
* @file
* @since 1.2.6.1
*/
/**
* 提交表单
* @command autosubmit
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'autosubmit' );
* ```
*/
UE.plugin.register('autosubmit', function() {
return {
shortcutkey: {
"autosubmit": "ctrl+13" //手动提交
},
commands: {
'autosubmit': {
execCommand: function() {
var me = this,
form = domUtils.findParentByTagName(me.iframe, "form", false);
if(form) {
if(me.fireEvent("beforesubmit") === false) {
return;
}
me.sync();
form.submit();
}
}
}
}
}
});
// plugins/background.js
/**
* 背景插件,为UEditor提供设置背景功能
* @file
* @since 1.2.6.1
*/
UE.plugin.register('background', function() {
var me = this,
cssRuleId = 'editor_background',
isSetColored,
reg = new RegExp('body[\\s]*\\{(.+)\\}', 'i');
function stringToObj(str) {
var obj = {},
styles = str.split(';');
utils.each(styles, function(v) {
var index = v.indexOf(':'),
key = utils.trim(v.substr(0, index)).toLowerCase();
key && (obj[key] = utils.trim(v.substr(index + 1) || ''));
});
return obj;
}
function setBackground(obj) {
if(obj) {
var styles = [];
for(var name in obj) {
if(obj.hasOwnProperty(name)) {
styles.push(name + ":" + obj[name] + '; ');
}
}
utils.cssRule(cssRuleId, styles.length ? ('body{' + styles.join("") + '}') : '', me.document);
} else {
utils.cssRule(cssRuleId, '', me.document)
}
}
//重写editor.hasContent方法
var orgFn = me.hasContents;
me.hasContents = function() {
if(me.queryCommandValue('background')) {
return true
}
return orgFn.apply(me, arguments);
};
return {
bindEvents: {
'getAllHtml': function(type, headHtml) {
var body = this.body,
su = domUtils.getComputedStyle(body, "background-image"),
url = "";
if(su.indexOf(me.options.imagePath) > 0) {
url = su.substring(su.indexOf(me.options.imagePath), su.length - 1).replace(/"|\(|\)/ig, "");
} else {
url = su != "none" ? su.replace(/url\("?|"?\)/ig, "") : "";
}
var html = ' ';
headHtml.push(html);
},
'aftersetcontent': function() {
if(isSetColored == false) setBackground();
}
},
inputRule: function(root) {
isSetColored = false;
utils.each(root.getNodesByTagName('p'), function(p) {
var styles = p.getAttr('data-background');
if(styles) {
isSetColored = true;
setBackground(stringToObj(styles));
p.parentNode.removeChild(p);
}
})
},
outputRule: function(root) {
var me = this,
styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg);
if(styles) {
root.appendChild(UE.uNode.createElement('
'));
}
},
commands: {
'background': {
execCommand: function(cmd, obj) {
setBackground(obj);
},
queryCommandValue: function() {
var me = this,
styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg);
return styles ? stringToObj(styles[1]) : null;
},
notNeedUndo: true
}
}
}
});
// plugins/image.js
/**
* 图片插入、排版插件
* @file
* @since 1.2.6.1
*/
/**
* 图片对齐方式
* @command imagefloat
* @method execCommand
* @remind 值center为独占一行居中
* @param { String } cmd 命令字符串
* @param { String } align 对齐方式,可传left、right、none、center
* @remaind center表示图片独占一行
* @example
* ```javascript
* editor.execCommand( 'imagefloat', 'center' );
* ```
*/
/**
* 如果选区所在位置是图片区域
* @command imagefloat
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回图片对齐方式
* @example
* ```javascript
* editor.queryCommandValue( 'imagefloat' );
* ```
*/
UE.commands['imagefloat'] = {
execCommand: function(cmd, align) {
var me = this,
range = me.selection.getRange();
if(!range.collapsed) {
var img = range.getClosedNode();
if(img && img.tagName == 'IMG') {
switch(align) {
case 'left':
case 'right':
case 'none':
var pN = img.parentNode,
tmpNode, pre, next;
while(dtd.$inline[pN.tagName] || pN.tagName == 'A') {
pN = pN.parentNode;
}
tmpNode = pN;
if(tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode, 'text-align') == 'center') {
if(!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function(node) {
return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
}) == 1) {
pre = tmpNode.previousSibling;
next = tmpNode.nextSibling;
if(pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)) {
pre.appendChild(tmpNode.firstChild);
while(next.firstChild) {
pre.appendChild(next.firstChild);
}
domUtils.remove(tmpNode);
domUtils.remove(next);
} else {
domUtils.setStyle(tmpNode, 'text-align', '');
}
}
range.selectNode(img).select();
}
domUtils.setStyle(img, 'float', align == 'none' ? '' : align);
if(align == 'none') {
domUtils.removeAttributes(img, 'align');
}
break;
case 'center':
if(me.queryCommandValue('imagefloat') != 'center') {
pN = img.parentNode;
domUtils.setStyle(img, 'float', '');
domUtils.removeAttributes(img, 'align');
tmpNode = img;
while(pN && domUtils.getChildCount(pN, function(node) {
return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
}) == 1 &&
(dtd.$inline[pN.tagName] || pN.tagName == 'A')) {
tmpNode = pN;
pN = pN.parentNode;
}
range.setStartBefore(tmpNode).setCursor(false);
pN = me.document.createElement('div');
pN.appendChild(tmpNode);
domUtils.setStyle(tmpNode, 'float', '');
me.execCommand('insertHtml', '' + pN.innerHTML + ' ');
tmpNode = me.document.getElementById('_img_parent_tmp');
tmpNode.removeAttribute('id');
tmpNode = tmpNode.firstChild;
range.selectNode(tmpNode).select();
//去掉后边多余的元素
next = tmpNode.parentNode.nextSibling;
if(next && domUtils.isEmptyNode(next)) {
domUtils.remove(next);
}
}
break;
}
}
}
},
queryCommandValue: function() {
var range = this.selection.getRange(),
startNode, floatStyle;
if(range.collapsed) {
return 'none';
}
startNode = range.getClosedNode();
if(startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
floatStyle = domUtils.getComputedStyle(startNode, 'float') || startNode.getAttribute('align');
if(floatStyle == 'none') {
floatStyle = domUtils.getComputedStyle(startNode.parentNode, 'text-align') == 'center' ? 'center' : floatStyle;
}
return {
left: 1,
right: 1,
center: 1
}[floatStyle] ? floatStyle: 'none';
}
return 'none';
},
queryCommandState: function() {
var range = this.selection.getRange(),
startNode;
if(range.collapsed) return -1;
startNode = range.getClosedNode();
if(startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
return 0;
}
return -1;
}
};
/**
* 插入图片
* @command insertimage
* @method execCommand
* @param { String } cmd 命令字符串
* @param { Object } opt 属性键值对,这些属性都将被复制到当前插入图片
* @remind 该命令第二个参数可接受一个图片配置项对象的数组,可以插入多张图片,
* 此时数组的每一个元素都是一个Object类型的图片属性集合。
* @example
* ```javascript
* editor.execCommand( 'insertimage', {
* src:'a/b/c.jpg',
* width:'100',
* height:'100'
* } );
* ```
* @example
* ```javascript
* editor.execCommand( 'insertimage', [{
* src:'a/b/c.jpg',
* width:'100',
* height:'100'
* },{
* src:'a/b/d.jpg',
* width:'100',
* height:'100'
* }] );
* ```
*/
UE.commands['insertimage'] = {
execCommand: function(cmd, opt) {
opt = utils.isArray(opt) ? opt : [opt];
if(!opt.length) {
return;
}
var me = this,
range = me.selection.getRange(),
img = range.getClosedNode();
if(me.fireEvent('beforeinsertimage', opt) === true) {
return;
}
function unhtmlData(imgCi) {
utils.each('width,height,border,hspace,vspace'.split(','), function(item) {
if(imgCi[item]) {
imgCi[item] = parseInt(imgCi[item], 10) || 0;
}
});
utils.each('src,_src'.split(','), function(item) {
if(imgCi[item]) {
imgCi[item] = utils.unhtmlForUrl(imgCi[item]);
}
});
utils.each('title,alt'.split(','), function(item) {
if(imgCi[item]) {
imgCi[item] = utils.unhtml(imgCi[item]);
}
});
}
if(img && /img/i.test(img.tagName) && (img.className != "edui-faked-video" || img.className.indexOf("edui-upload-video") != -1) && !img.getAttribute("word_img")) {
var first = opt.shift();
var floatStyle = first['floatStyle'];
delete first['floatStyle'];
//// img.style.border = (first.border||0) +"px solid #000";
//// img.style.margin = (first.margin||0) +"px";
// img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000";
domUtils.setAttributes(img, first);
me.execCommand('imagefloat', floatStyle);
if(opt.length > 0) {
range.setStartAfter(img).setCursor(false, true);
me.execCommand('insertimage', opt);
}
} else {
var html = [],
str = '',
ci;
ci = opt[0];
if(opt.length == 1) {
unhtmlData(ci);
str = ' ';
if(ci['floatStyle'] == 'center') {
str = '' + str + ' ';
}
html.push(str);
} else {
for(var i = 0; ci = opt[i++];) {
unhtmlData(ci);
str = ' ';
html.push(str);
}
}
me.execCommand('insertHtml', html.join(''));
}
me.fireEvent('afterinsertimage', opt)
}
};
// plugins/justify.js
/**
* 段落格式
* @file
* @since 1.2.6.1
*/
/**
* 段落对齐方式
* @command justify
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐
* @example
* ```javascript
* editor.execCommand( 'justify', 'center' );
* ```
*/
/**
* 如果选区所在位置是段落区域,返回当前段落对齐方式
* @command justify
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回段落对齐方式
* @example
* ```javascript
* editor.queryCommandValue( 'justify' );
* ```
*/
UE.plugins['justify'] = function() {
var me = this,
block = domUtils.isBlockElm,
defaultValue = {
left: 1,
right: 1,
center: 1,
justify: 1
},
doJustify = function(range, style) {
var bookmark = range.createBookmark(),
filterFn = function(node) {
return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
};
range.enlarge(true);
var bookmark2 = range.createBookmark(),
current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
tmpRange = range.cloneRange(),
tmpNode;
while(current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
if(current.nodeType == 3 || !block(current)) {
tmpRange.setStartBefore(current);
while(current && current !== bookmark2.end && !block(current)) {
tmpNode = current;
current = domUtils.getNextDomNode(current, false, null, function(node) {
return !block(node);
});
}
tmpRange.setEndAfter(tmpNode);
var common = tmpRange.getCommonAncestor();
if(!domUtils.isBody(common) && block(common)) {
domUtils.setStyles(common, utils.isString(style) ? {
'text-align': style
} : style);
current = common;
} else {
var p = range.document.createElement('p');
domUtils.setStyles(p, utils.isString(style) ? {
'text-align': style
} : style);
var frag = tmpRange.extractContents();
p.appendChild(frag);
tmpRange.insertNode(p);
current = p;
}
current = domUtils.getNextDomNode(current, false, filterFn);
} else {
current = domUtils.getNextDomNode(current, true, filterFn);
}
}
return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
};
UE.commands['justify'] = {
execCommand: function(cmdName, align) {
var range = this.selection.getRange(),
txt;
//闭合时单独处理
if(range.collapsed) {
txt = this.document.createTextNode('p');
range.insertNode(txt);
}
doJustify(range, align);
if(txt) {
range.setStartBefore(txt).collapse(true);
domUtils.remove(txt);
}
range.select();
return true;
},
queryCommandValue: function() {
var startNode = this.selection.getStart(),
value = domUtils.getComputedStyle(startNode, 'text-align');
return defaultValue[value] ? value : 'left';
},
queryCommandState: function() {
var start = this.selection.getStart(),
cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
return cell ? -1 : 0;
}
};
};
// plugins/font.js
/**
* 字体颜色,背景色,字号,字体,下划线,删除线
* @file
* @since 1.2.6.1
*/
/**
* 字体颜色
* @command forecolor
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } value 色值(必须十六进制)
* @example
* ```javascript
* editor.execCommand( 'forecolor', '#000' );
* ```
*/
/**
* 返回选区字体颜色
* @command forecolor
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回字体颜色
* @example
* ```javascript
* editor.queryCommandValue( 'forecolor' );
* ```
*/
/**
* 字体背景颜色
* @command backcolor
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } value 色值(必须十六进制)
* @example
* ```javascript
* editor.execCommand( 'backcolor', '#000' );
* ```
*/
/**
* 返回选区字体颜色
* @command backcolor
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回字体背景颜色
* @example
* ```javascript
* editor.queryCommandValue( 'backcolor' );
* ```
*/
/**
* 字体大小
* @command fontsize
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } value 字体大小
* @example
* ```javascript
* editor.execCommand( 'fontsize', '14px' );
* ```
*/
/**
* 返回选区字体大小
* @command fontsize
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回字体大小
* @example
* ```javascript
* editor.queryCommandValue( 'fontsize' );
* ```
*/
/**
* 字体样式
* @command fontfamily
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } value 字体样式
* @example
* ```javascript
* editor.execCommand( 'fontfamily', '微软雅黑' );
* ```
*/
/**
* 返回选区字体样式
* @command fontfamily
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回字体样式
* @example
* ```javascript
* editor.queryCommandValue( 'fontfamily' );
* ```
*/
/**
* 字体下划线,与删除线互斥
* @command underline
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'underline' );
* ```
*/
/**
* 字体删除线,与下划线互斥
* @command strikethrough
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'strikethrough' );
* ```
*/
/**
* 字体边框
* @command fontborder
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'fontborder' );
* ```
*/
UE.plugins['font'] = function() {
var me = this,
fonts = {
'forecolor': 'color',
'backcolor': 'background-color',
'fontsize': 'font-size',
'fontfamily': 'font-family',
'underline': 'text-decoration',
'strikethrough': 'text-decoration',
'fontborder': 'border'
},
needCmd = {
'underline': 1,
'strikethrough': 1,
'fontborder': 1
},
needSetChild = {
'forecolor': 'color',
'backcolor': 'background-color',
'fontsize': 'font-size',
'fontfamily': 'font-family'
};
me.setOpt({
'fontfamily': [{
name: 'songti',
val: '宋体,SimSun'
},
{
name: 'yahei',
val: '微软雅黑,Microsoft YaHei'
},
{
name: 'kaiti',
val: '楷体,楷体_GB2312, SimKai'
},
{
name: 'heiti',
val: '黑体, SimHei'
},
{
name: 'lishu',
val: '隶书, SimLi'
},
{
name: 'andaleMono',
val: 'andale mono'
},
{
name: 'arial',
val: 'arial, helvetica,sans-serif'
},
{
name: 'arialBlack',
val: 'arial black,avant garde'
},
{
name: 'comicSansMs',
val: 'comic sans ms'
},
{
name: 'impact',
val: 'impact,chicago'
},
{
name: 'timesNewRoman',
val: 'times new roman'
}
],
'fontsize': [10, 11, 12, 14, 16, 18, 20, 24, 36]
});
function mergeWithParent(node) {
var parent;
while(parent = node.parentNode) {
if(parent.tagName == 'SPAN' && domUtils.getChildCount(parent, function(child) {
return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child)
}) == 1) {
parent.style.cssText += node.style.cssText;
domUtils.remove(node, true);
node = parent;
} else {
break;
}
}
}
function mergeChild(rng, cmdName, value) {
if(needSetChild[cmdName]) {
rng.adjustmentBoundary();
if(!rng.collapsed && rng.startContainer.nodeType == 1) {
var start = rng.startContainer.childNodes[rng.startOffset];
if(start && domUtils.isTagNode(start, 'span')) {
var bk = rng.createBookmark();
utils.each(domUtils.getElementsByTagName(start, 'span'), function(span) {
if(!span.parentNode || domUtils.isBookmarkNode(span)) return;
if(cmdName == 'backcolor' && domUtils.getComputedStyle(span, 'background-color').toLowerCase() === value) {
return;
}
domUtils.removeStyle(span, needSetChild[cmdName]);
if(span.style.cssText.replace(/^\s+$/, '').length == 0) {
domUtils.remove(span, true)
}
});
rng.moveToBookmark(bk)
}
}
}
}
function mergesibling(rng, cmdName, value) {
var collapsed = rng.collapsed,
bk = rng.createBookmark(),
common;
if(collapsed) {
common = bk.start.parentNode;
while(dtd.$inline[common.tagName]) {
common = common.parentNode;
}
} else {
common = domUtils.getCommonAncestor(bk.start, bk.end);
}
utils.each(domUtils.getElementsByTagName(common, 'span'), function(span) {
if(!span.parentNode || domUtils.isBookmarkNode(span)) return;
if(/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
if(/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
domUtils.remove(span, true);
} else {
domUtils.removeStyle(span, 'border');
}
return
}
if(/border/i.test(span.style.cssText) && span.parentNode.tagName == 'SPAN' && /border/i.test(span.parentNode.style.cssText)) {
span.style.cssText = span.style.cssText.replace(/border[^:]*:[^;]+;?/gi, '');
}
if(!(cmdName == 'fontborder' && value == 'none')) {
var next = span.nextSibling;
while(next && next.nodeType == 1 && next.tagName == 'SPAN') {
if(domUtils.isBookmarkNode(next) && cmdName == 'fontborder') {
span.appendChild(next);
next = span.nextSibling;
continue;
}
if(next.style.cssText == span.style.cssText) {
domUtils.moveChild(next, span);
domUtils.remove(next);
}
if(span.nextSibling === next)
break;
next = span.nextSibling;
}
}
mergeWithParent(span);
if(browser.ie && browser.version > 8) {
//拷贝父亲们的特别的属性,这里只做背景颜色的处理
var parent = domUtils.findParent(span, function(n) {
return n.tagName == 'SPAN' && /background-color/.test(n.style.cssText)
});
if(parent && !/background-color/.test(span.style.cssText)) {
span.style.backgroundColor = parent.style.backgroundColor;
}
}
});
rng.moveToBookmark(bk);
mergeChild(rng, cmdName, value)
}
me.addInputRule(function(root) {
utils.each(root.getNodesByTagName('u s del font strike'), function(node) {
if(node.tagName == 'font') {
var cssStyle = [];
for(var p in node.attrs) {
switch(p) {
case 'size':
cssStyle.push('font-size:' +
({
'1': '10',
'2': '12',
'3': '16',
'4': '18',
'5': '24',
'6': '32',
'7': '48'
}[node.attrs[p]] || node.attrs[p]) + 'px');
break;
case 'color':
cssStyle.push('color:' + node.attrs[p]);
break;
case 'face':
cssStyle.push('font-family:' + node.attrs[p]);
break;
case 'style':
cssStyle.push(node.attrs[p]);
}
}
node.attrs = {
'style': cssStyle.join(';')
};
} else {
var val = node.tagName == 'u' ? 'underline' : 'line-through';
node.attrs = {
'style': (node.getAttr('style') || '') + 'text-decoration:' + val + ';'
}
}
node.tagName = 'span';
});
// utils.each(root.getNodesByTagName('span'), function (node) {
// var val;
// if(val = node.getAttr('class')){
// if(/fontstrikethrough/.test(val)){
// node.setStyle('text-decoration','line-through');
// if(node.attrs['class']){
// node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
// }else{
// node.setAttr('class')
// }
// }
// if(/fontborder/.test(val)){
// node.setStyle('border','1px solid #000');
// if(node.attrs['class']){
// node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
// }else{
// node.setAttr('class')
// }
// }
// }
// });
});
// me.addOutputRule(function(root){
// utils.each(root.getNodesByTagName('span'), function (node) {
// var val;
// if(val = node.getStyle('text-decoration')){
// if(/line-through/.test(val)){
// if(node.attrs['class']){
// node.attrs['class'] += ' fontstrikethrough';
// }else{
// node.setAttr('class','fontstrikethrough')
// }
// }
//
// node.setStyle('text-decoration')
// }
// if(val = node.getStyle('border')){
// if(/1px/.test(val) && /solid/.test(val)){
// if(node.attrs['class']){
// node.attrs['class'] += ' fontborder';
//
// }else{
// node.setAttr('class','fontborder')
// }
// }
// node.setStyle('border')
//
// }
// });
// });
for(var p in fonts) {
(function(cmd, style) {
UE.commands[cmd] = {
execCommand: function(cmdName, value) {
value = value || (this.queryCommandState(cmdName) ? 'none' : cmdName == 'underline' ? 'underline' :
cmdName == 'fontborder' ? '1px solid #000' :
'line-through');
var me = this,
range = this.selection.getRange(),
text;
if(value == 'default') {
if(range.collapsed) {
text = me.document.createTextNode('font');
range.insertNode(text).select();
}
me.execCommand('removeFormat', 'span,a', style);
if(text) {
range.setStartBefore(text).collapse(true);
domUtils.remove(text);
}
mergesibling(range, cmdName, value);
range.select()
} else {
if(!range.collapsed) {
if(needCmd[cmd] && me.queryCommandValue(cmd)) {
me.execCommand('removeFormat', 'span,a', style);
}
range = me.selection.getRange();
range.applyInlineStyle('span', {
'style': style + ':' + value
});
mergesibling(range, cmdName, value);
range.select();
} else {
var span = domUtils.findParentByTagName(range.startContainer, 'span', true);
text = me.document.createTextNode('font');
if(span && !span.children.length && !span[browser.ie ? 'innerText' : 'textContent'].replace(fillCharReg, '').length) {
//for ie hack when enter
range.insertNode(text);
if(needCmd[cmd]) {
range.selectNode(text).select();
me.execCommand('removeFormat', 'span,a', style, null);
span = domUtils.findParentByTagName(text, 'span', true);
range.setStartBefore(text);
}
span && (span.style.cssText += ';' + style + ':' + value);
range.collapse(true).select();
} else {
range.insertNode(text);
range.selectNode(text).select();
span = range.document.createElement('span');
if(needCmd[cmd]) {
//a标签内的不处理跳过
if(domUtils.findParentByTagName(text, 'a', true)) {
range.setStartBefore(text).setCursor();
domUtils.remove(text);
return;
}
me.execCommand('removeFormat', 'span,a', style);
}
span.style.cssText = style + ':' + value;
text.parentNode.insertBefore(span, text);
//修复,span套span 但样式不继承的问题
if(!browser.ie || browser.ie && browser.version == 9) {
var spanParent = span.parentNode;
while(!domUtils.isBlockElm(spanParent)) {
if(spanParent.tagName == 'SPAN') {
//opera合并style不会加入";"
span.style.cssText = spanParent.style.cssText + ";" + span.style.cssText;
}
spanParent = spanParent.parentNode;
}
}
if(opera) {
setTimeout(function() {
range.setStart(span, 0).collapse(true);
mergesibling(range, cmdName, value);
range.select();
});
} else {
range.setStart(span, 0).collapse(true);
mergesibling(range, cmdName, value);
range.select();
}
//trace:981
//domUtils.mergeToParent(span)
}
domUtils.remove(text);
}
}
return true;
},
queryCommandValue: function(cmdName) {
var startNode = this.selection.getStart();
//trace:946
if(cmdName == 'underline' || cmdName == 'strikethrough') {
var tmpNode = startNode,
value;
while(tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(tmpNode)) {
if(tmpNode.nodeType == 1) {
value = domUtils.getComputedStyle(tmpNode, style);
if(value != 'none') {
return value;
}
}
tmpNode = tmpNode.parentNode;
}
return 'none';
}
if(cmdName == 'fontborder') {
var tmp = startNode,
val;
while(tmp && dtd.$inline[tmp.tagName]) {
if(val = domUtils.getComputedStyle(tmp, 'border')) {
if(/1px/.test(val) && /solid/.test(val)) {
return val;
}
}
tmp = tmp.parentNode;
}
return ''
}
if(cmdName == 'FontSize') {
var styleVal = domUtils.getComputedStyle(startNode, style),
tmp = /^([\d\.]+)(\w+)$/.exec(styleVal);
if(tmp) {
return Math.floor(tmp[1]) + tmp[2];
}
return styleVal;
}
return domUtils.getComputedStyle(startNode, style);
},
queryCommandState: function(cmdName) {
if(!needCmd[cmdName])
return 0;
var val = this.queryCommandValue(cmdName);
if(cmdName == 'fontborder') {
return /1px/.test(val) && /solid/.test(val)
} else {
return cmdName == 'underline' ? /underline/.test(val) : /line\-through/.test(val);
}
}
};
})(p, fonts[p]);
}
};
// plugins/link.js
/**
* 超链接
* @file
* @since 1.2.6.1
*/
/**
* 插入超链接
* @command link
* @method execCommand
* @param { String } cmd 命令字符串
* @param { Object } options 设置自定义属性,例如:url、title、target
* @example
* ```javascript
* editor.execCommand( 'link', '{
* url:'ueditor.baidu.com',
* title:'ueditor',
* target:'_blank'
* }' );
* ```
*/
/**
* 返回当前选中的第一个超链接节点
* @command link
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { Element } 超链接节点
* @example
* ```javascript
* editor.queryCommandValue( 'link' );
* ```
*/
/**
* 取消超链接
* @command unlink
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'unlink');
* ```
*/
UE.plugins['link'] = function() {
function optimize(range) {
var start = range.startContainer,
end = range.endContainer;
if(start = domUtils.findParentByTagName(start, 'a', true)) {
range.setStartBefore(start);
}
if(end = domUtils.findParentByTagName(end, 'a', true)) {
range.setEndAfter(end);
}
}
UE.commands['unlink'] = {
execCommand: function() {
var range = this.selection.getRange(),
bookmark;
if(range.collapsed && !domUtils.findParentByTagName(range.startContainer, 'a', true)) {
return;
}
bookmark = range.createBookmark();
optimize(range);
range.removeInlineStyle('a').moveToBookmark(bookmark).select();
},
queryCommandState: function() {
return !this.highlight && this.queryCommandValue('link') ? 0 : -1;
}
};
function doLink(range, opt, me) {
var rngClone = range.cloneRange(),
link = me.queryCommandValue('link');
optimize(range = range.adjustmentBoundary());
var start = range.startContainer;
if(start.nodeType == 1 && link) {
start = start.childNodes[range.startOffset];
if(start && start.nodeType == 1 && start.tagName == 'A' && /^(?:https?|ftp|file)\s*:\s*\/\//.test(start[browser.ie ? 'innerText' : 'textContent'])) {
start[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue || opt.href);
}
}
if(!rngClone.collapsed || link) {
range.removeInlineStyle('a');
rngClone = range.cloneRange();
}
if(rngClone.collapsed) {
var a = range.document.createElement('a'),
text = '';
if(opt.textValue) {
text = utils.html(opt.textValue);
delete opt.textValue;
} else {
text = utils.html(opt.href);
}
domUtils.setAttributes(a, opt);
start = domUtils.findParentByTagName(rngClone.startContainer, 'a', true);
if(start && domUtils.isInNodeEndBoundary(rngClone, start)) {
range.setStartAfter(start).collapse(true);
}
a[browser.ie ? 'innerText' : 'textContent'] = text;
range.insertNode(a).selectNode(a);
} else {
range.applyInlineStyle('a', opt);
}
}
UE.commands['link'] = {
execCommand: function(cmdName, opt) {
var range;
opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g));
opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g));
opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g));
doLink(range = this.selection.getRange(), opt, this);
//闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
range.collapse().select(true);
},
queryCommandValue: function() {
var range = this.selection.getRange(),
node;
if(range.collapsed) {
// node = this.selection.getStart();
//在ie下getstart()取值偏上了
node = range.startContainer;
node = node.nodeType == 1 ? node : node.parentNode;
if(node && (node = domUtils.findParentByTagName(node, 'a', true)) && !domUtils.isInNodeEndBoundary(range, node)) {
return node;
}
} else {
//trace:1111 如果是xx startContainer是p就会找不到a
range.shrinkBoundary();
var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[range.startOffset] ? range.startContainer : range.startContainer.childNodes[range.startOffset],
end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range.endContainer : range.endContainer.childNodes[range.endOffset - 1],
common = range.getCommonAncestor();
node = domUtils.findParentByTagName(common, 'a', true);
if(!node && common.nodeType == 1) {
var as = common.getElementsByTagName('a'),
ps, pe;
for(var i = 0, ci; ci = as[i++];) {
ps = domUtils.getPosition(ci, start), pe = domUtils.getPosition(ci, end);
if((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS) &&
(pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)
) {
node = ci;
break;
}
}
}
return node;
}
},
queryCommandState: function() {
//判断如果是视频的话连接不可用
//fix 853
var img = this.selection.getRange().getClosedNode(),
flag = img && (img.className == "edui-faked-video" || img.className.indexOf("edui-upload-video") != -1);
return flag ? -1 : 0;
}
};
};
// plugins/iframe.js
///import core
///import plugins\inserthtml.js
///commands 插入框架
///commandsName InsertFrame
///commandsTitle 插入Iframe
///commandsDialog dialogs\insertframe
UE.plugins['insertframe'] = function() {
var me = this;
function deleteIframe() {
me._iframe && delete me._iframe;
}
me.addListener("selectionchange", function() {
deleteIframe();
});
};
// plugins/scrawl.js
///import core
///commands 涂鸦
///commandsName Scrawl
///commandsTitle 涂鸦
///commandsDialog dialogs\scrawl
UE.commands['scrawl'] = {
queryCommandState: function() {
return(browser.ie && browser.version <= 8) ? -1 : 0;
}
};
// plugins/removeformat.js
/**
* 清除格式
* @file
* @since 1.2.6.1
*/
/**
* 清除文字样式
* @command removeformat
* @method execCommand
* @param { String } cmd 命令字符串
* @param {String} tags 以逗号隔开的标签。如:strong
* @param {String} style 样式如:color
* @param {String} attrs 属性如:width
* @example
* ```javascript
* editor.execCommand( 'removeformat', 'strong','color','width' );
* ```
*/
UE.plugins['removeformat'] = function() {
var me = this;
me.setOpt({
'removeFormatTags': 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var',
'removeFormatAttributes': 'class,style,lang,width,height,align,hspace,valign'
});
me.commands['removeformat'] = {
execCommand: function(cmdName, tags, style, attrs, notIncludeA) {
var tagReg = new RegExp('^(?:' + (tags || this.options.removeFormatTags).replace(/,/g, '|') + ')$', 'i'),
removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes).split(','),
range = new dom.Range(this.document),
bookmark, node, parent,
filter = function(node) {
return node.nodeType == 1;
};
function isRedundantSpan(node) {
if(node.nodeType == 3 || node.tagName.toLowerCase() != 'span') {
return 0;
}
if(browser.ie) {
//ie 下判断实效,所以只能简单用style来判断
//return node.style.cssText == '' ? 1 : 0;
var attrs = node.attributes;
if(attrs.length) {
for(var i = 0, l = attrs.length; i < l; i++) {
if(attrs[i].specified) {
return 0;
}
}
return 1;
}
}
return !node.attributes.length;
}
function doRemove(range) {
var bookmark1 = range.createBookmark();
if(range.collapsed) {
range.enlarge(true);
}
//不能把a标签切了
if(!notIncludeA) {
var aNode = domUtils.findParentByTagName(range.startContainer, 'a', true);
if(aNode) {
range.setStartBefore(aNode);
}
aNode = domUtils.findParentByTagName(range.endContainer, 'a', true);
if(aNode) {
range.setEndAfter(aNode);
}
}
bookmark = range.createBookmark();
node = bookmark.start;
//切开始
while((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
domUtils.breakParent(node, parent);
domUtils.clearEmptySibling(node);
}
if(bookmark.end) {
//切结束
node = bookmark.end;
while((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
domUtils.breakParent(node, parent);
domUtils.clearEmptySibling(node);
}
//开始去除样式
var current = domUtils.getNextDomNode(bookmark.start, false, filter),
next;
while(current) {
if(current == bookmark.end) {
break;
}
next = domUtils.getNextDomNode(current, true, filter);
if(!dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode(current)) {
if(tagReg.test(current.tagName)) {
if(style) {
domUtils.removeStyle(current, style);
if(isRedundantSpan(current) && style != 'text-decoration') {
domUtils.remove(current, true);
}
} else {
domUtils.remove(current, true);
}
} else {
//trace:939 不能把list上的样式去掉
if(!dtd.$tableContent[current.tagName] && !dtd.$list[current.tagName]) {
domUtils.removeAttributes(current, removeFormatAttributes);
if(isRedundantSpan(current)) {
domUtils.remove(current, true);
}
}
}
}
current = next;
}
}
//trace:1035
//trace:1096 不能把td上的样式去掉,比如边框
var pN = bookmark.start.parentNode;
if(domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) {
domUtils.removeAttributes(pN, removeFormatAttributes);
}
pN = bookmark.end.parentNode;
if(bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) {
domUtils.removeAttributes(pN, removeFormatAttributes);
}
range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
//清除冗余的代码
var node = range.startContainer,
tmp,
collapsed = range.collapsed;
while(node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
tmp = node.parentNode;
range.setStartBefore(node);
//trace:937
//更新结束边界
if(range.startContainer === range.endContainer) {
range.endOffset--;
}
domUtils.remove(node);
node = tmp;
}
if(!collapsed) {
node = range.endContainer;
while(node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
tmp = node.parentNode;
range.setEndBefore(node);
domUtils.remove(node);
node = tmp;
}
}
}
range = this.selection.getRange();
doRemove(range);
range.select();
}
};
};
// plugins/blockquote.js
/**
* 添加引用
* @file
* @since 1.2.6.1
*/
/**
* 添加引用
* @command blockquote
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'blockquote' );
* ```
*/
/**
* 添加引用
* @command blockquote
* @method execCommand
* @param { String } cmd 命令字符串
* @param { Object } attrs 节点属性
* @example
* ```javascript
* editor.execCommand( 'blockquote',{
* style: "color: red;"
* } );
* ```
*/
UE.plugins['blockquote'] = function() {
var me = this;
function getObj(editor) {
return domUtils.filterNodeList(editor.selection.getStartElementPath(), 'blockquote');
}
me.commands['blockquote'] = {
execCommand: function(cmdName, attrs) {
var range = this.selection.getRange(),
obj = getObj(this),
blockquote = dtd.blockquote,
bookmark = range.createBookmark();
if(obj) {
var start = range.startContainer,
startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start, function(node) {
return domUtils.isBlockElm(node)
}),
end = range.endContainer,
endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end, function(node) {
return domUtils.isBlockElm(node)
});
//处理一下li
startBlock = domUtils.findParentByTagName(startBlock, 'li', true) || startBlock;
endBlock = domUtils.findParentByTagName(endBlock, 'li', true) || endBlock;
if(startBlock.tagName == 'LI' || startBlock.tagName == 'TD' || startBlock === obj || domUtils.isBody(startBlock)) {
domUtils.remove(obj, true);
} else {
domUtils.breakParent(startBlock, obj);
}
if(startBlock !== endBlock) {
obj = domUtils.findParentByTagName(endBlock, 'blockquote');
if(obj) {
if(endBlock.tagName == 'LI' || endBlock.tagName == 'TD' || domUtils.isBody(endBlock)) {
obj.parentNode && domUtils.remove(obj, true);
} else {
domUtils.breakParent(endBlock, obj);
}
}
}
var blockquotes = domUtils.getElementsByTagName(this.document, 'blockquote');
for(var i = 0, bi; bi = blockquotes[i++];) {
if(!bi.childNodes.length) {
domUtils.remove(bi);
} else if(domUtils.getPosition(bi, startBlock) & domUtils.POSITION_FOLLOWING && domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING) {
domUtils.remove(bi, true);
}
}
} else {
var tmpRange = range.cloneRange(),
node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode,
preNode = node,
doEnd = 1;
//调整开始
while(1) {
if(domUtils.isBody(node)) {
if(preNode !== node) {
if(range.collapsed) {
tmpRange.selectNode(preNode);
doEnd = 0;
} else {
tmpRange.setStartBefore(preNode);
}
} else {
tmpRange.setStart(node, 0);
}
break;
}
if(!blockquote[node.tagName]) {
if(range.collapsed) {
tmpRange.selectNode(preNode);
} else {
tmpRange.setStartBefore(preNode);
}
break;
}
preNode = node;
node = node.parentNode;
}
//调整结束
if(doEnd) {
preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode;
while(1) {
if(domUtils.isBody(node)) {
if(preNode !== node) {
tmpRange.setEndAfter(preNode);
} else {
tmpRange.setEnd(node, node.childNodes.length);
}
break;
}
if(!blockquote[node.tagName]) {
tmpRange.setEndAfter(preNode);
break;
}
preNode = node;
node = node.parentNode;
}
}
node = range.document.createElement('blockquote');
domUtils.setAttributes(node, attrs);
node.appendChild(tmpRange.extractContents());
tmpRange.insertNode(node);
//去除重复的
var childs = domUtils.getElementsByTagName(node, 'blockquote');
for(var i = 0, ci; ci = childs[i++];) {
if(ci.parentNode) {
domUtils.remove(ci, true);
}
}
}
range.moveToBookmark(bookmark).select();
},
queryCommandState: function() {
return getObj(this) ? 1 : 0;
}
};
};
// plugins/convertcase.js
/**
* 大小写转换
* @file
* @since 1.2.6.1
*/
/**
* 把选区内文本变大写,与“tolowercase”命令互斥
* @command touppercase
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'touppercase' );
* ```
*/
/**
* 把选区内文本变小写,与“touppercase”命令互斥
* @command tolowercase
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'tolowercase' );
* ```
*/
UE.commands['touppercase'] =
UE.commands['tolowercase'] = {
execCommand: function(cmd) {
var me = this;
var rng = me.selection.getRange();
if(rng.collapsed) {
return rng;
}
var bk = rng.createBookmark(),
bkEnd = bk.end,
filterFn = function(node) {
return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
},
curNode = domUtils.getNextDomNode(bk.start, false, filterFn);
while(curNode && (domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING)) {
if(curNode.nodeType == 3) {
curNode.nodeValue = curNode.nodeValue[cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase']();
}
curNode = domUtils.getNextDomNode(curNode, true, filterFn);
if(curNode === bkEnd) {
break;
}
}
rng.moveToBookmark(bk).select();
}
};
// plugins/indent.js
/**
* 首行缩进
* @file
* @since 1.2.6.1
*/
/**
* 缩进
* @command indent
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'indent' );
* ```
*/
UE.commands['indent'] = {
execCommand: function() {
var me = this,
value = me.queryCommandState("indent") ? "0em" : (me.options.indentValue || '2em');
me.execCommand('Paragraph', 'p', {
style: 'text-indent:' + value
});
},
queryCommandState: function() {
var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6');
return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0;
}
};
// plugins/print.js
/**
* 打印
* @file
* @since 1.2.6.1
*/
/**
* 打印
* @command print
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'print' );
* ```
*/
UE.commands['print'] = {
execCommand: function() {
this.window.print();
},
notNeedUndo: 1
};
// plugins/preview.js
/**
* 预览
* @file
* @since 1.2.6.1
*/
/**
* 预览
* @command preview
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'preview' );
* ```
*/
UE.commands['preview'] = {
execCommand: function() {
var w = window.open('', '_blank', ''),
d = w.document;
d.open();
d.write('' + this.getContent(null, null, true) + ' ');
d.close();
},
notNeedUndo: 1
};
// plugins/selectall.js
/**
* 全选
* @file
* @since 1.2.6.1
*/
/**
* 选中所有内容
* @command selectall
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'selectall' );
* ```
*/
UE.plugins['selectall'] = function() {
var me = this;
me.commands['selectall'] = {
execCommand: function() {
//去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
var me = this,
body = me.body,
range = me.selection.getRange();
range.selectNodeContents(body);
if(domUtils.isEmptyBlock(body)) {
//opera不能自动合并到元素的里边,要手动处理一下
if(browser.opera && body.firstChild && body.firstChild.nodeType == 1) {
range.setStartAtFirst(body.firstChild);
}
range.collapse(true);
}
range.select(true);
},
notNeedUndo: 1
};
//快捷键
me.addshortcutkey({
"selectAll": "ctrl+65"
});
};
// plugins/paragraph.js
/**
* 段落样式
* @file
* @since 1.2.6.1
*/
/**
* 段落格式
* @command paragraph
* @method execCommand
* @param { String } cmd 命令字符串
* @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
* @param {Object} attrs 标签的属性
* @example
* ```javascript
* editor.execCommand( 'Paragraph','h1','{
* class:'test'
* }' );
* ```
*/
/**
* 返回选区内节点标签名
* @command paragraph
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 节点标签名
* @example
* ```javascript
* editor.queryCommandValue( 'Paragraph' );
* ```
*/
UE.plugins['paragraph'] = function() {
var me = this,
block = domUtils.isBlockElm,
notExchange = ['TD', 'LI', 'PRE'],
doParagraph = function(range, style, attrs, sourceCmdName) {
var bookmark = range.createBookmark(),
filterFn = function(node) {
return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
},
para;
range.enlarge(true);
var bookmark2 = range.createBookmark(),
current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
tmpRange = range.cloneRange(),
tmpNode;
while(current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
if(current.nodeType == 3 || !block(current)) {
tmpRange.setStartBefore(current);
while(current && current !== bookmark2.end && !block(current)) {
tmpNode = current;
current = domUtils.getNextDomNode(current, false, null, function(node) {
return !block(node);
});
}
tmpRange.setEndAfter(tmpNode);
para = range.document.createElement(style);
if(attrs) {
domUtils.setAttributes(para, attrs);
if(sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) {
para.style.cssText = attrs.style;
}
}
para.appendChild(tmpRange.extractContents());
//需要内容占位
if(domUtils.isEmptyNode(para)) {
domUtils.fillChar(range.document, para);
}
tmpRange.insertNode(para);
var parent = para.parentNode;
//如果para上一级是一个block元素且不是body,td就删除它
if(block(parent) && !domUtils.isBody(para.parentNode) && utils.indexOf(notExchange, parent.tagName) == -1) {
//存储dir,style
if(!(sourceCmdName && sourceCmdName == 'customstyle')) {
parent.getAttribute('dir') && para.setAttribute('dir', parent.getAttribute('dir'));
//trace:1070
parent.style.cssText && (para.style.cssText = parent.style.cssText + ';' + para.style.cssText);
//trace:1030
parent.style.textAlign && !para.style.textAlign && (para.style.textAlign = parent.style.textAlign);
parent.style.textIndent && !para.style.textIndent && (para.style.textIndent = parent.style.textIndent);
parent.style.padding && !para.style.padding && (para.style.padding = parent.style.padding);
}
//trace:1706 选择的就是h1-6要删除
if(attrs && /h\d/i.test(parent.tagName) && !/h\d/i.test(para.tagName)) {
domUtils.setAttributes(parent, attrs);
if(sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) {
parent.style.cssText = attrs.style;
}
domUtils.remove(para, true);
para = parent;
} else {
domUtils.remove(para.parentNode, true);
}
}
if(utils.indexOf(notExchange, parent.tagName) != -1) {
current = parent;
} else {
current = para;
}
current = domUtils.getNextDomNode(current, false, filterFn);
} else {
current = domUtils.getNextDomNode(current, true, filterFn);
}
}
return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
};
me.setOpt('paragraph', {
'p': '',
'h1': '',
'h2': '',
'h3': '',
'h4': '',
'h5': '',
'h6': ''
});
me.commands['paragraph'] = {
execCommand: function(cmdName, style, attrs, sourceCmdName) {
var range = this.selection.getRange();
//闭合时单独处理
if(range.collapsed) {
var txt = this.document.createTextNode('p');
range.insertNode(txt);
//去掉冗余的fillchar
if(browser.ie) {
var node = txt.previousSibling;
if(node && domUtils.isWhitespace(node)) {
domUtils.remove(node);
}
node = txt.nextSibling;
if(node && domUtils.isWhitespace(node)) {
domUtils.remove(node);
}
}
}
range = doParagraph(range, style, attrs, sourceCmdName);
if(txt) {
range.setStartBefore(txt).collapse(true);
pN = txt.parentNode;
domUtils.remove(txt);
if(domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) {
domUtils.fillNode(this.document, pN);
}
}
if(browser.gecko && range.collapsed && range.startContainer.nodeType == 1) {
var child = range.startContainer.childNodes[range.startOffset];
if(child && child.nodeType == 1 && child.tagName.toLowerCase() == style) {
range.setStart(child, 0).collapse(true);
}
}
//trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
range.select();
return true;
},
queryCommandValue: function() {
var node = domUtils.filterNodeList(this.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6');
return node ? node.tagName.toLowerCase() : '';
}
};
};
// plugins/directionality.js
/**
* 设置文字输入的方向的插件
* @file
* @since 1.2.6.1
*/
(function() {
var block = domUtils.isBlockElm,
getObj = function(editor) {
// var startNode = editor.selection.getStart(),
// parents;
// if ( startNode ) {
// //查找所有的是block的父亲节点
// parents = domUtils.findParents( startNode, true, block, true );
// for ( var i = 0,ci; ci = parents[i++]; ) {
// if ( ci.getAttribute( 'dir' ) ) {
// return ci;
// }
// }
// }
return domUtils.filterNodeList(editor.selection.getStartElementPath(), function(n) {
return n && n.nodeType == 1 && n.getAttribute('dir')
});
},
doDirectionality = function(range, editor, forward) {
var bookmark,
filterFn = function(node) {
return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
},
obj = getObj(editor);
if(obj && range.collapsed) {
obj.setAttribute('dir', forward);
return range;
}
bookmark = range.createBookmark();
range.enlarge(true);
var bookmark2 = range.createBookmark(),
current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
tmpRange = range.cloneRange(),
tmpNode;
while(current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
if(current.nodeType == 3 || !block(current)) {
tmpRange.setStartBefore(current);
while(current && current !== bookmark2.end && !block(current)) {
tmpNode = current;
current = domUtils.getNextDomNode(current, false, null, function(node) {
return !block(node);
});
}
tmpRange.setEndAfter(tmpNode);
var common = tmpRange.getCommonAncestor();
if(!domUtils.isBody(common) && block(common)) {
//遍历到了block节点
common.setAttribute('dir', forward);
current = common;
} else {
//没有遍历到,添加一个block节点
var p = range.document.createElement('p');
p.setAttribute('dir', forward);
var frag = tmpRange.extractContents();
p.appendChild(frag);
tmpRange.insertNode(p);
current = p;
}
current = domUtils.getNextDomNode(current, false, filterFn);
} else {
current = domUtils.getNextDomNode(current, true, filterFn);
}
}
return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
};
/**
* 文字输入方向
* @command directionality
* @method execCommand
* @param { String } cmdName 命令字符串
* @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入
* @example
* ```javascript
* editor.execCommand( 'directionality', 'ltr');
* ```
*/
/**
* 查询当前选区的文字输入方向
* @command directionality
* @method queryCommandValue
* @param { String } cmdName 命令字符串
* @return { String } 返回'ltr'表示从左向右输入,返回'rtl'表示从右向左输入
* @example
* ```javascript
* editor.queryCommandValue( 'directionality');
* ```
*/
UE.commands['directionality'] = {
execCommand: function(cmdName, forward) {
var range = this.selection.getRange();
//闭合时单独处理
if(range.collapsed) {
var txt = this.document.createTextNode('d');
range.insertNode(txt);
}
doDirectionality(range, this, forward);
if(txt) {
range.setStartBefore(txt).collapse(true);
domUtils.remove(txt);
}
range.select();
return true;
},
queryCommandValue: function() {
var node = getObj(this);
return node ? node.getAttribute('dir') : 'ltr';
}
};
})();
// plugins/horizontal.js
/**
* 插入分割线插件
* @file
* @since 1.2.6.1
*/
/**
* 插入分割线
* @command horizontal
* @method execCommand
* @param { String } cmdName 命令字符串
* @example
* ```javascript
* editor.execCommand( 'horizontal' );
* ```
*/
UE.plugins['horizontal'] = function() {
var me = this;
me.commands['horizontal'] = {
execCommand: function(cmdName) {
var me = this;
if(me.queryCommandState(cmdName) !== -1) {
me.execCommand('insertHtml', ' ');
var range = me.selection.getRange(),
start = range.startContainer;
if(start.nodeType == 1 && !start.childNodes[range.startOffset]) {
var tmp;
if(tmp = start.childNodes[range.startOffset - 1]) {
if(tmp.nodeType == 1 && tmp.tagName == 'HR') {
if(me.options.enterTag == 'p') {
tmp = me.document.createElement('p');
range.insertNode(tmp);
range.setStart(tmp, 0).setCursor();
} else {
tmp = me.document.createElement('br');
range.insertNode(tmp);
range.setStartBefore(tmp).setCursor();
}
}
}
}
return true;
}
},
//边界在table里不能加分隔线
queryCommandState: function() {
return domUtils.filterNodeList(this.selection.getStartElementPath(), 'table') ? -1 : 0;
}
};
// me.addListener('delkeyup',function(){
// var rng = this.selection.getRange();
// if(browser.ie && browser.version > 8){
// rng.txtToElmBoundary(true);
// if(domUtils.isStartInblock(rng)){
// var tmpNode = rng.startContainer;
// var pre = tmpNode.previousSibling;
// if(pre && domUtils.isTagNode(pre,'hr')){
// domUtils.remove(pre);
// rng.select();
// return;
// }
// }
// }
// if(domUtils.isBody(rng.startContainer)){
// var hr = rng.startContainer.childNodes[rng.startOffset -1];
// if(hr && hr.nodeName == 'HR'){
// var next = hr.nextSibling;
// if(next){
// rng.setStart(next,0)
// }else if(hr.previousSibling){
// rng.setStartAtLast(hr.previousSibling)
// }else{
// var p = this.document.createElement('p');
// hr.parentNode.insertBefore(p,hr);
// domUtils.fillNode(this.document,p);
// rng.setStart(p,0);
// }
// domUtils.remove(hr);
// rng.setCursor(false,true);
// }
// }
// })
me.addListener('delkeydown', function(name, evt) {
var rng = this.selection.getRange();
rng.txtToElmBoundary(true);
if(domUtils.isStartInblock(rng)) {
var tmpNode = rng.startContainer;
var pre = tmpNode.previousSibling;
if(pre && domUtils.isTagNode(pre, 'hr')) {
domUtils.remove(pre);
rng.select();
domUtils.preventDefault(evt);
return true;
}
}
})
};
// plugins/time.js
/**
* 插入时间和日期
* @file
* @since 1.2.6.1
*/
/**
* 插入时间,默认格式:12:59:59
* @command time
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'time');
* ```
*/
/**
* 插入日期,默认格式:2013-08-30
* @command date
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'date');
* ```
*/
UE.commands['time'] = UE.commands["date"] = {
execCommand: function(cmd, format) {
var date = new Date;
function formatTime(date, format) {
var hh = ('0' + date.getHours()).slice(-2),
ii = ('0' + date.getMinutes()).slice(-2),
ss = ('0' + date.getSeconds()).slice(-2);
format = format || 'hh:ii:ss';
return format.replace(/hh/ig, hh).replace(/ii/ig, ii).replace(/ss/ig, ss);
}
function formatDate(date, format) {
var yyyy = ('000' + date.getFullYear()).slice(-4),
yy = yyyy.slice(-2),
mm = ('0' + (date.getMonth() + 1)).slice(-2),
dd = ('0' + date.getDate()).slice(-2);
format = format || 'yyyy-mm-dd';
return format.replace(/yyyy/ig, yyyy).replace(/yy/ig, yy).replace(/mm/ig, mm).replace(/dd/ig, dd);
}
this.execCommand('insertHtml', cmd == "time" ? formatTime(date, format) : formatDate(date, format));
}
};
// plugins/rowspacing.js
/**
* 段前段后间距插件
* @file
* @since 1.2.6.1
*/
/**
* 设置段间距
* @command rowspacing
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } value 段间距的值,以px为单位
* @param { String } dir 间距位置,top或bottom,分别表示段前和段后
* @example
* ```javascript
* editor.execCommand( 'rowspacing', '10', 'top' );
* ```
*/
UE.plugins['rowspacing'] = function() {
var me = this;
me.setOpt({
'rowspacingtop': ['5', '10', '15', '20', '25'],
'rowspacingbottom': ['5', '10', '15', '20', '25']
});
me.commands['rowspacing'] = {
execCommand: function(cmdName, value, dir) {
this.execCommand('paragraph', 'p', {
style: 'margin-' + dir + ':' + value + 'px'
});
return true;
},
queryCommandValue: function(cmdName, dir) {
var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function(node) {
return domUtils.isBlockElm(node)
}),
value;
//trace:1026
if(pN) {
value = domUtils.getComputedStyle(pN, 'margin-' + dir).replace(/[^\d]/g, '');
return !value ? 0 : value;
}
return 0;
}
};
};
// plugins/lineheight.js
/**
* 设置行内间距
* @file
* @since 1.2.6.1
*/
UE.plugins['lineheight'] = function() {
var me = this;
me.setOpt({
'lineheight': ['1', '1.5', '1.75', '2', '3', '4', '5']
});
/**
* 行距
* @command lineheight
* @method execCommand
* @param { String } cmdName 命令字符串
* @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75
* @example
* ```javascript
* editor.execCommand( 'lineheight', 1.5);
* ```
*/
/**
* 查询当前选区内容的行高大小
* @command lineheight
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回当前行高大小
* @example
* ```javascript
* editor.queryCommandValue( 'lineheight' );
* ```
*/
me.commands['lineheight'] = {
execCommand: function(cmdName, value) {
this.execCommand('paragraph', 'p', {
style: 'line-height:' + (value == "1" ? "normal" : value + 'em')
});
return true;
},
queryCommandValue: function() {
var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function(node) {
return domUtils.isBlockElm(node)
});
if(pN) {
var value = domUtils.getComputedStyle(pN, 'line-height');
return value == 'normal' ? 1 : value.replace(/[^\d.]*/ig, "");
}
}
};
};
// plugins/insertcode.js
/**
* 插入代码插件
* @file
* @since 1.2.6.1
*/
UE.plugins['insertcode'] = function() {
var me = this;
me.ready(function() {
utils.cssRule('pre', 'pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}',
me.document)
});
me.setOpt('insertcode', {
'as3': 'ActionScript3',
'bash': 'Bash/Shell',
'cpp': 'C/C++',
'css': 'Css',
'cf': 'CodeFunction',
'c#': 'C#',
'delphi': 'Delphi',
'diff': 'Diff',
'erlang': 'Erlang',
'groovy': 'Groovy',
'html': 'Html',
'java': 'Java',
'jfx': 'JavaFx',
'js': 'Javascript',
'pl': 'Perl',
'php': 'Php',
'plain': 'Plain Text',
'ps': 'PowerShell',
'python': 'Python',
'ruby': 'Ruby',
'scala': 'Scala',
'sql': 'Sql',
'vb': 'Vb',
'xml': 'Xml'
});
/**
* 插入代码
* @command insertcode
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } lang 插入代码的语言
* @example
* ```javascript
* editor.execCommand( 'insertcode', 'javascript' );
* ```
*/
/**
* 如果选区所在位置是插入插入代码区域,返回代码的语言
* @command insertcode
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回代码的语言
* @example
* ```javascript
* editor.queryCommandValue( 'insertcode' );
* ```
*/
me.commands['insertcode'] = {
execCommand: function(cmd, lang) {
var me = this,
rng = me.selection.getRange(),
pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
if(pre) {
pre.className = 'brush:' + lang + ';toolbar:false;';
} else {
var code = '';
if(rng.collapsed) {
code = browser.ie && browser.ie11below ? (browser.version <= 8 ? ' ' : '') : ' ';
} else {
var frag = rng.extractContents();
var div = me.document.createElement('div');
div.appendChild(frag);
utils.each(UE.filterNode(UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, '')), me.options.filterTxtRules).children, function(node) {
if(browser.ie && browser.ie11below && browser.version > 8) {
if(node.type == 'element') {
if(node.tagName == 'br') {
code += '\n'
} else if(!dtd.$empty[node.tagName]) {
utils.each(node.children, function(cn) {
if(cn.type == 'element') {
if(cn.tagName == 'br') {
code += '\n'
} else if(!dtd.$empty[node.tagName]) {
code += cn.innerText();
}
} else {
code += cn.data
}
})
if(!/\n$/.test(code)) {
code += '\n';
}
}
} else {
code += node.data + '\n'
}
if(!node.nextSibling() && /\n$/.test(code)) {
code = code.replace(/\n$/, '');
}
} else {
if(browser.ie && browser.ie11below) {
if(node.type == 'element') {
if(node.tagName == 'br') {
code += ' '
} else if(!dtd.$empty[node.tagName]) {
utils.each(node.children, function(cn) {
if(cn.type == 'element') {
if(cn.tagName == 'br') {
code += ' '
} else if(!dtd.$empty[node.tagName]) {
code += cn.innerText();
}
} else {
code += cn.data
}
});
if(!/br>$/.test(code)) {
code += ' ';
}
}
} else {
code += node.data + ' '
}
if(!node.nextSibling() && / $/.test(code)) {
code = code.replace(/ $/, '');
}
} else {
code += (node.type == 'element' ? (dtd.$empty[node.tagName] ? '' : node.innerText()) : node.data);
if(!/br\/?\s*>$/.test(code)) {
if(!node.nextSibling())
return;
code += ' '
}
}
}
});
}
me.execCommand('inserthtml', '' + code + ' ', true);
pre = me.document.getElementById('coder');
domUtils.removeAttributes(pre, 'id');
var tmpNode = pre.previousSibling;
if(tmpNode && (tmpNode.nodeType == 3 && tmpNode.nodeValue.length == 1 && browser.ie && browser.version == 6 || domUtils.isEmptyBlock(tmpNode))) {
domUtils.remove(tmpNode)
}
var rng = me.selection.getRange();
if(domUtils.isEmptyBlock(pre)) {
rng.setStart(pre, 0).setCursor(false, true)
} else {
rng.selectNodeContents(pre).select()
}
}
},
queryCommandValue: function() {
var path = this.selection.getStartElementPath();
var lang = '';
utils.each(path, function(node) {
if(node.nodeName == 'PRE') {
var match = node.className.match(/brush:([^;]+)/);
lang = match && match[1] ? match[1] : '';
return false;
}
});
return lang;
}
};
me.addInputRule(function(root) {
utils.each(root.getNodesByTagName('pre'), function(pre) {
var brs = pre.getNodesByTagName('br');
if(brs.length) {
browser.ie && browser.ie11below && browser.version > 8 && utils.each(brs, function(br) {
var txt = UE.uNode.createText('\n');
br.parentNode.insertBefore(txt, br);
br.parentNode.removeChild(br);
});
return;
}
if(browser.ie && browser.ie11below && browser.version > 8)
return;
var code = pre.innerText().split(/\n/);
pre.innerHTML('');
utils.each(code, function(c) {
if(c.length) {
pre.appendChild(UE.uNode.createText(c));
}
pre.appendChild(UE.uNode.createElement('br'))
})
})
});
me.addOutputRule(function(root) {
utils.each(root.getNodesByTagName('pre'), function(pre) {
var code = '';
utils.each(pre.children, function(n) {
if(n.type == 'text') {
//在ie下文本内容有可能末尾带有\n要去掉
//trace:3396
code += n.data.replace(/[ ]/g, ' ').replace(/\n$/, '');
} else {
if(n.tagName == 'br') {
code += '\n'
} else {
code += (!dtd.$empty[n.tagName] ? '' : n.innerText());
}
}
});
pre.innerText(code.replace(/( |\n)+$/, ''))
})
});
//不需要判断highlight的command列表
me.notNeedCodeQuery = {
help: 1,
undo: 1,
redo: 1,
source: 1,
print: 1,
searchreplace: 1,
fullscreen: 1,
preview: 1,
insertparagraph: 1,
elementpath: 1,
insertcode: 1,
inserthtml: 1,
selectall: 1
};
//将queyCommamndState重置
var orgQuery = me.queryCommandState;
me.queryCommandState = function(cmd) {
var me = this;
if(!me.notNeedCodeQuery[cmd.toLowerCase()] && me.selection && me.queryCommandValue('insertcode')) {
return -1;
}
return UE.Editor.prototype.queryCommandState.apply(this, arguments)
};
me.addListener('beforeenterkeydown', function() {
var rng = me.selection.getRange();
var pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
if(pre) {
me.fireEvent('saveScene');
if(!rng.collapsed) {
rng.deleteContents();
}
if(!browser.ie || browser.ie9above) {
var tmpNode = me.document.createElement('br'),
pre;
rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
var next = tmpNode.nextSibling;
if(!next && (!browser.ie || browser.version > 10)) {
rng.insertNode(tmpNode.cloneNode(false));
} else {
rng.setStartAfter(tmpNode);
}
pre = tmpNode.previousSibling;
var tmp;
while(pre) {
tmp = pre;
pre = pre.previousSibling;
if(!pre || pre.nodeName == 'BR') {
pre = tmp;
break;
}
}
if(pre) {
var str = '';
while(pre && pre.nodeName != 'BR' && new RegExp('^[\\s' + domUtils.fillChar + ']*$').test(pre.nodeValue)) {
str += pre.nodeValue;
pre = pre.nextSibling;
}
if(pre.nodeName != 'BR') {
var match = pre.nodeValue.match(new RegExp('^([\\s' + domUtils.fillChar + ']+)'));
if(match && match[1]) {
str += match[1]
}
}
if(str) {
str = me.document.createTextNode(str);
rng.insertNode(str).setStartAfter(str);
}
}
rng.collapse(true).select(true);
} else {
if(browser.version > 8) {
var txt = me.document.createTextNode('\n');
var start = rng.startContainer;
if(rng.startOffset == 0) {
var preNode = start.previousSibling;
if(preNode) {
rng.insertNode(txt);
var fillchar = me.document.createTextNode(' ');
rng.setStartAfter(txt).insertNode(fillchar).setStart(fillchar, 0).collapse(true).select(true)
}
} else {
rng.insertNode(txt).setStartAfter(txt);
var fillchar = me.document.createTextNode(' ');
start = rng.startContainer.childNodes[rng.startOffset];
if(start && !/^\n/.test(start.nodeValue)) {
rng.setStartBefore(txt)
}
rng.insertNode(fillchar).setStart(fillchar, 0).collapse(true).select(true)
}
} else {
var tmpNode = me.document.createElement('br');
rng.insertNode(tmpNode);
rng.insertNode(me.document.createTextNode(domUtils.fillChar));
rng.setStartAfter(tmpNode);
pre = tmpNode.previousSibling;
var tmp;
while(pre) {
tmp = pre;
pre = pre.previousSibling;
if(!pre || pre.nodeName == 'BR') {
pre = tmp;
break;
}
}
if(pre) {
var str = '';
while(pre && pre.nodeName != 'BR' && new RegExp('^[ ' + domUtils.fillChar + ']*$').test(pre.nodeValue)) {
str += pre.nodeValue;
pre = pre.nextSibling;
}
if(pre.nodeName != 'BR') {
var match = pre.nodeValue.match(new RegExp('^([ ' + domUtils.fillChar + ']+)'));
if(match && match[1]) {
str += match[1]
}
}
str = me.document.createTextNode(str);
rng.insertNode(str).setStartAfter(str);
}
rng.collapse(true).select();
}
}
me.fireEvent('saveScene');
return true;
}
});
me.addListener('tabkeydown', function(cmd, evt) {
var rng = me.selection.getRange();
var pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
if(pre) {
me.fireEvent('saveScene');
if(evt.shiftKey) {
} else {
if(!rng.collapsed) {
var bk = rng.createBookmark();
var start = bk.start.previousSibling;
while(start) {
if(pre.firstChild === start && !domUtils.isBr(start)) {
pre.insertBefore(me.document.createTextNode(' '), start);
break;
}
if(domUtils.isBr(start)) {
pre.insertBefore(me.document.createTextNode(' '), start.nextSibling);
break;
}
start = start.previousSibling;
}
var end = bk.end;
start = bk.start.nextSibling;
if(pre.firstChild === bk.start) {
pre.insertBefore(me.document.createTextNode(' '), start.nextSibling)
}
while(start && start !== end) {
if(domUtils.isBr(start) && start.nextSibling) {
if(start.nextSibling === end) {
break;
}
pre.insertBefore(me.document.createTextNode(' '), start.nextSibling)
}
start = start.nextSibling;
}
rng.moveToBookmark(bk).select();
} else {
var tmpNode = me.document.createTextNode(' ');
rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true).select(true);
}
}
me.fireEvent('saveScene');
return true;
}
});
me.addListener('beforeinserthtml', function(evtName, html) {
var me = this,
rng = me.selection.getRange(),
pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true);
if(pre) {
if(!rng.collapsed) {
rng.deleteContents()
}
var htmlstr = '';
if(browser.ie && browser.version > 8) {
utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children, function(node) {
if(node.type == 'element') {
if(node.tagName == 'br') {
htmlstr += '\n'
} else if(!dtd.$empty[node.tagName]) {
utils.each(node.children, function(cn) {
if(cn.type == 'element') {
if(cn.tagName == 'br') {
htmlstr += '\n'
} else if(!dtd.$empty[node.tagName]) {
htmlstr += cn.innerText();
}
} else {
htmlstr += cn.data
}
})
if(!/\n$/.test(htmlstr)) {
htmlstr += '\n';
}
}
} else {
htmlstr += node.data + '\n'
}
if(!node.nextSibling() && /\n$/.test(htmlstr)) {
htmlstr = htmlstr.replace(/\n$/, '');
}
});
var tmpNode = me.document.createTextNode(utils.html(htmlstr.replace(/ /g, ' ')));
rng.insertNode(tmpNode).selectNode(tmpNode).select();
} else {
var frag = me.document.createDocumentFragment();
utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children, function(node) {
if(node.type == 'element') {
if(node.tagName == 'br') {
frag.appendChild(me.document.createElement('br'))
} else if(!dtd.$empty[node.tagName]) {
utils.each(node.children, function(cn) {
if(cn.type == 'element') {
if(cn.tagName == 'br') {
frag.appendChild(me.document.createElement('br'))
} else if(!dtd.$empty[node.tagName]) {
frag.appendChild(me.document.createTextNode(utils.html(cn.innerText().replace(/ /g, ' '))));
}
} else {
frag.appendChild(me.document.createTextNode(utils.html(cn.data.replace(/ /g, ' '))));
}
})
if(frag.lastChild.nodeName != 'BR') {
frag.appendChild(me.document.createElement('br'))
}
}
} else {
frag.appendChild(me.document.createTextNode(utils.html(node.data.replace(/ /g, ' '))));
}
if(!node.nextSibling() && frag.lastChild.nodeName == 'BR') {
frag.removeChild(frag.lastChild)
}
});
rng.insertNode(frag).select();
}
return true;
}
});
//方向键的处理
me.addListener('keydown', function(cmd, evt) {
var me = this,
keyCode = evt.keyCode || evt.which;
if(keyCode == 40) {
var rng = me.selection.getRange(),
pre, start = rng.startContainer;
if(rng.collapsed && (pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true)) && !pre.nextSibling) {
var last = pre.lastChild
while(last && last.nodeName == 'BR') {
last = last.previousSibling;
}
if(last === start || rng.startContainer === pre && rng.startOffset == pre.childNodes.length) {
me.execCommand('insertparagraph');
domUtils.preventDefault(evt)
}
}
}
});
//trace:3395
me.addListener('delkeydown', function(type, evt) {
var rng = this.selection.getRange();
rng.txtToElmBoundary(true);
var start = rng.startContainer;
if(domUtils.isTagNode(start, 'pre') && rng.collapsed && domUtils.isStartInblock(rng)) {
var p = me.document.createElement('p');
domUtils.fillNode(me.document, p);
start.parentNode.insertBefore(p, start);
domUtils.remove(start);
rng.setStart(p, 0).setCursor(false, true);
domUtils.preventDefault(evt);
return true;
}
})
};
// plugins/cleardoc.js
/**
* 清空文档插件
* @file
* @since 1.2.6.1
*/
/**
* 清空文档
* @command cleardoc
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* //editor 是编辑器实例
* editor.execCommand('cleardoc');
* ```
*/
UE.commands['cleardoc'] = {
execCommand: function(cmdName) {
var me = this,
enterTag = me.options.enterTag,
range = me.selection.getRange();
if(enterTag == "br") {
me.body.innerHTML = " ";
range.setStart(me.body, 0).setCursor();
} else {
me.body.innerHTML = "" + (ie ? "" : " ") + " ";
range.setStart(me.body.firstChild, 0).setCursor(false, true);
}
setTimeout(function() {
me.fireEvent("clearDoc");
}, 0);
}
};
// plugins/anchor.js
/**
* 锚点插件,为UEditor提供插入锚点支持
* @file
* @since 1.2.6.1
*/
UE.plugin.register('anchor', function() {
return {
bindEvents: {
'ready': function() {
utils.cssRule('anchor',
'.anchorclass{background: url(\'' +
this.options.themePath +
this.options.theme + '/images/anchor.gif\') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}',
this.document);
}
},
outputRule: function(root) {
utils.each(root.getNodesByTagName('img'), function(a) {
var val;
if(val = a.getAttr('anchorname')) {
a.tagName = 'a';
a.setAttr({
anchorname: '',
name: val,
'class': ''
})
}
})
},
inputRule: function(root) {
utils.each(root.getNodesByTagName('a'), function(a) {
var val;
if((val = a.getAttr('name')) && !a.getAttr('href')) {
a.tagName = 'img';
a.setAttr({
anchorname: a.getAttr('name'),
'class': 'anchorclass'
});
a.setAttr('name')
}
})
},
commands: {
/**
* 插入锚点
* @command anchor
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } name 锚点名称字符串
* @example
* ```javascript
* //editor 是编辑器实例
* editor.execCommand('anchor', 'anchor1');
* ```
*/
'anchor': {
execCommand: function(cmd, name) {
var range = this.selection.getRange(),
img = range.getClosedNode();
if(img && img.getAttribute('anchorname')) {
if(name) {
img.setAttribute('anchorname', name);
} else {
range.setStartBefore(img).setCursor();
domUtils.remove(img);
}
} else {
if(name) {
//只在选区的开始插入
var anchor = this.document.createElement('img');
range.collapse(true);
domUtils.setAttributes(anchor, {
'anchorname': name,
'class': 'anchorclass'
});
range.insertNode(anchor).setStartAfter(anchor).setCursor(false, true);
}
}
}
}
}
}
});
// plugins/wordcount.js
///import core
///commands 字数统计
///commandsName WordCount,wordCount
///commandsTitle 字数统计
/*
* Created by JetBrains WebStorm.
* User: taoqili
* Date: 11-9-7
* Time: 下午8:18
* To change this template use File | Settings | File Templates.
*/
UE.plugins['wordcount'] = function() {
var me = this;
me.setOpt('wordCount', true);
me.addListener('contentchange', function() {
me.fireEvent('wordcount');
});
var timer;
me.addListener('ready', function() {
var me = this;
domUtils.on(me.body, "keyup", function(evt) {
var code = evt.keyCode || evt.which,
//忽略的按键,ctr,alt,shift,方向键
ignores = {
"16": 1,
"18": 1,
"20": 1,
"37": 1,
"38": 1,
"39": 1,
"40": 1
};
if(code in ignores) return;
clearTimeout(timer);
timer = setTimeout(function() {
me.fireEvent('wordcount');
}, 200)
})
});
};
// plugins/pagebreak.js
/**
* 分页功能插件
* @file
* @since 1.2.6.1
*/
UE.plugins['pagebreak'] = function() {
var me = this,
notBreakTags = ['td'];
me.setOpt('pageBreakTag', '_ueditor_page_break_tag_');
function fillNode(node) {
if(domUtils.isEmptyBlock(node)) {
var firstChild = node.firstChild,
tmpNode;
while(firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)) {
tmpNode = firstChild;
firstChild = firstChild.firstChild;
}!tmpNode && (tmpNode = node);
domUtils.fillNode(me.document, tmpNode);
}
}
//分页符样式添加
me.ready(function() {
utils.cssRule('pagebreak', '.pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}', me.document);
});
function isHr(node) {
return node && node.nodeType == 1 && node.tagName == 'HR' && node.className == 'pagebreak';
}
me.addInputRule(function(root) {
root.traversal(function(node) {
if(node.type == 'text' && node.data == me.options.pageBreakTag) {
var hr = UE.uNode.createElement(' ');
node.parentNode.insertBefore(hr, node);
node.parentNode.removeChild(node)
}
})
});
me.addOutputRule(function(node) {
utils.each(node.getNodesByTagName('hr'), function(n) {
if(n.getAttr('class') == 'pagebreak') {
var txt = UE.uNode.createText(me.options.pageBreakTag);
n.parentNode.insertBefore(txt, n);
n.parentNode.removeChild(n);
}
})
});
/**
* 插入分页符
* @command pagebreak
* @method execCommand
* @param { String } cmd 命令字符串
* @remind 在表格中插入分页符会把表格切分成两部分
* @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串,
* 以便于提交数据到服务器端后处理分页。
* @example
* ```javascript
* editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak
* ```
*/
me.commands['pagebreak'] = {
execCommand: function() {
var range = me.selection.getRange(),
hr = me.document.createElement('hr');
domUtils.setAttributes(hr, {
'class': 'pagebreak',
noshade: "noshade",
size: "5"
});
domUtils.unSelectable(hr);
//table单独处理
var node = domUtils.findParentByTagName(range.startContainer, notBreakTags, true),
parents = [],
pN;
if(node) {
switch(node.tagName) {
case 'TD':
pN = node.parentNode;
if(!pN.previousSibling) {
var table = domUtils.findParentByTagName(pN, 'table');
// var tableWrapDiv = table.parentNode;
// if(tableWrapDiv && tableWrapDiv.nodeType == 1
// && tableWrapDiv.tagName == 'DIV'
// && tableWrapDiv.getAttribute('dropdrag')
// ){
// domUtils.remove(tableWrapDiv,true);
// }
table.parentNode.insertBefore(hr, table);
parents = domUtils.findParents(hr, true);
} else {
pN.parentNode.insertBefore(hr, pN);
parents = domUtils.findParents(hr);
}
pN = parents[1];
if(hr !== pN) {
domUtils.breakParent(hr, pN);
}
//table要重写绑定一下拖拽
me.fireEvent('afteradjusttable', me.document);
}
} else {
if(!range.collapsed) {
range.deleteContents();
var start = range.startContainer;
while(!domUtils.isBody(start) && domUtils.isBlockElm(start) && domUtils.isEmptyNode(start)) {
range.setStartBefore(start).collapse(true);
domUtils.remove(start);
start = range.startContainer;
}
}
range.insertNode(hr);
var pN = hr.parentNode,
nextNode;
while(!domUtils.isBody(pN)) {
domUtils.breakParent(hr, pN);
nextNode = hr.nextSibling;
if(nextNode && domUtils.isEmptyBlock(nextNode)) {
domUtils.remove(nextNode);
}
pN = hr.parentNode;
}
nextNode = hr.nextSibling;
var pre = hr.previousSibling;
if(isHr(pre)) {
domUtils.remove(pre);
} else {
pre && fillNode(pre);
}
if(!nextNode) {
var p = me.document.createElement('p');
hr.parentNode.appendChild(p);
domUtils.fillNode(me.document, p);
range.setStart(p, 0).collapse(true);
} else {
if(isHr(nextNode)) {
domUtils.remove(nextNode);
} else {
fillNode(nextNode);
}
range.setEndAfter(hr).collapse(false);
}
range.select(true);
}
}
};
};
// plugins/wordimage.js
///import core
///commands 本地图片引导上传
///commandsName WordImage
///commandsTitle 本地图片引导上传
///commandsDialog dialogs\wordimage
UE.plugin.register('wordimage', function() {
var me = this,
images = [];
return {
commands: {
'wordimage': {
execCommand: function() {
var images = domUtils.getElementsByTagName(me.body, "img");
var urlList = [];
for(var i = 0, ci; ci = images[i++];) {
var url = ci.getAttribute("word_img");
url && urlList.push(url);
}
return urlList;
},
queryCommandState: function() {
images = domUtils.getElementsByTagName(me.body, "img");
for(var i = 0, ci; ci = images[i++];) {
if(ci.getAttribute("word_img")) {
return 1;
}
}
return -1;
},
notNeedUndo: true
}
},
inputRule: function(root) {
utils.each(root.getNodesByTagName('img'), function(img) {
var attrs = img.attrs,
flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
opt = me.options,
src = opt.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif';
if(attrs['src'] && /^(?:(file:\/+))/.test(attrs['src'])) {
img.setAttr({
width: attrs.width,
height: attrs.height,
alt: attrs.alt,
word_img: attrs.src,
src: src,
'style': 'background:url(' + (flag ? opt.themePath + opt.theme + '/images/word.gif' : opt.langPath + opt.lang + '/images/localimage.png') + ') no-repeat center center;border:1px solid #ddd'
})
}
})
}
}
});
// plugins/dragdrop.js
UE.plugins['dragdrop'] = function() {
var me = this;
me.ready(function() {
domUtils.on(this.body, 'dragend', function() {
var rng = me.selection.getRange();
var node = rng.getClosedNode() || me.selection.getStart();
if(node && node.tagName == 'IMG') {
var pre = node.previousSibling,
next;
while(next = node.nextSibling) {
if(next.nodeType == 1 && next.tagName == 'SPAN' && !next.firstChild) {
domUtils.remove(next)
} else {
break;
}
}
if((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre) || !pre) && (!next || next && !domUtils.isEmptyBlock(next))) {
if(pre && pre.tagName == 'P' && !domUtils.isEmptyBlock(pre)) {
pre.appendChild(node);
domUtils.moveChild(next, pre);
domUtils.remove(next);
} else if(next && next.tagName == 'P' && !domUtils.isEmptyBlock(next)) {
next.insertBefore(node, next.firstChild);
}
if(pre && pre.tagName == 'P' && domUtils.isEmptyBlock(pre)) {
domUtils.remove(pre)
}
if(next && next.tagName == 'P' && domUtils.isEmptyBlock(next)) {
domUtils.remove(next)
}
rng.selectNode(node).select();
me.fireEvent('saveScene');
}
}
})
});
me.addListener('keyup', function(type, evt) {
var keyCode = evt.keyCode || evt.which;
if(keyCode == 13) {
var rng = me.selection.getRange(),
node;
if(node = domUtils.findParentByTagName(rng.startContainer, 'p', true)) {
if(domUtils.getComputedStyle(node, 'text-align') == 'center') {
domUtils.removeStyle(node, 'text-align')
}
}
}
})
};
// plugins/undo.js
/**
* undo redo
* @file
* @since 1.2.6.1
*/
/**
* 撤销上一次执行的命令
* @command undo
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'undo' );
* ```
*/
/**
* 重做上一次执行的命令
* @command redo
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'redo' );
* ```
*/
UE.plugins['undo'] = function() {
var saveSceneTimer;
var me = this,
maxUndoCount = me.options.maxUndoCount || 20,
maxInputCount = me.options.maxInputCount || 20,
fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi'); // ie会产生多余的
var noNeedFillCharTags = {
ol: 1,
ul: 1,
table: 1,
tbody: 1,
tr: 1,
body: 1
};
var orgState = me.options.autoClearEmptyNode;
function compareAddr(indexA, indexB) {
if(indexA.length != indexB.length)
return 0;
for(var i = 0, l = indexA.length; i < l; i++) {
if(indexA[i] != indexB[i])
return 0
}
return 1;
}
function compareRangeAddress(rngAddrA, rngAddrB) {
if(rngAddrA.collapsed != rngAddrB.collapsed) {
return 0;
}
if(!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)) {
return 0;
}
return 1;
}
function UndoManager() {
this.list = [];
this.index = 0;
this.hasUndo = false;
this.hasRedo = false;
this.undo = function() {
if(this.hasUndo) {
if(!this.list[this.index - 1] && this.list.length == 1) {
this.reset();
return;
}
while(this.list[this.index].content == this.list[this.index - 1].content) {
this.index--;
if(this.index == 0) {
return this.restore(0);
}
}
this.restore(--this.index);
}
};
this.redo = function() {
if(this.hasRedo) {
while(this.list[this.index].content == this.list[this.index + 1].content) {
this.index++;
if(this.index == this.list.length - 1) {
return this.restore(this.index);
}
}
this.restore(++this.index);
}
};
this.restore = function() {
var me = this.editor;
var scene = this.list[this.index];
var root = UE.htmlparser(scene.content.replace(fillchar, ''));
me.options.autoClearEmptyNode = false;
me.filterInputRule(root);
me.options.autoClearEmptyNode = orgState;
//trace:873
//去掉展位符
me.document.body.innerHTML = root.toHtml();
me.fireEvent('afterscencerestore');
//处理undo后空格不展位的问题
if(browser.ie) {
utils.each(domUtils.getElementsByTagName(me.document, 'td th caption p'), function(node) {
if(domUtils.isEmptyNode(node)) {
domUtils.fillNode(me.document, node);
}
})
}
try {
var rng = new dom.Range(me.document).moveToAddress(scene.address);
rng.select(noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]);
} catch(e) {}
this.update();
this.clearKey();
//不能把自己reset了
me.fireEvent('reset', true);
};
this.getScene = function() {
var me = this.editor;
var rng = me.selection.getRange(),
rngAddress = rng.createAddress(false, true);
me.fireEvent('beforegetscene');
var root = UE.htmlparser(me.body.innerHTML);
me.options.autoClearEmptyNode = false;
me.filterOutputRule(root);
me.options.autoClearEmptyNode = orgState;
var cont = root.toHtml();
//trace:3461
//这个会引起回退时导致空格丢失的情况
// browser.ie && (cont = cont.replace(/> <').replace(/\s*\s*/g, '>'));
me.fireEvent('aftergetscene');
return {
address: rngAddress,
content: cont
}
};
this.save = function(notCompareRange, notSetCursor) {
clearTimeout(saveSceneTimer);
var currentScene = this.getScene(notSetCursor),
lastScene = this.list[this.index];
if(lastScene && lastScene.content != currentScene.content) {
me.trigger('contentchange')
}
//内容相同位置相同不存
if(lastScene && lastScene.content == currentScene.content &&
(notCompareRange ? 1 : compareRangeAddress(lastScene.address, currentScene.address))
) {
return;
}
this.list = this.list.slice(0, this.index + 1);
this.list.push(currentScene);
//如果大于最大数量了,就把最前的剔除
if(this.list.length > maxUndoCount) {
this.list.shift();
}
this.index = this.list.length - 1;
this.clearKey();
//跟新undo/redo状态
this.update();
};
this.update = function() {
this.hasRedo = !!this.list[this.index + 1];
this.hasUndo = !!this.list[this.index - 1];
};
this.reset = function() {
this.list = [];
this.index = 0;
this.hasUndo = false;
this.hasRedo = false;
this.clearKey();
};
this.clearKey = function() {
keycont = 0;
lastKeyCode = null;
};
}
me.undoManger = new UndoManager();
me.undoManger.editor = me;
function saveScene() {
this.undoManger.save();
}
me.addListener('saveScene', function() {
var args = Array.prototype.splice.call(arguments, 1);
this.undoManger.save.apply(this.undoManger, args);
});
// me.addListener('beforeexeccommand', saveScene);
// me.addListener('afterexeccommand', saveScene);
me.addListener('reset', function(type, exclude) {
if(!exclude) {
this.undoManger.reset();
}
});
me.commands['redo'] = me.commands['undo'] = {
execCommand: function(cmdName) {
this.undoManger[cmdName]();
},
queryCommandState: function(cmdName) {
return this.undoManger['has' + (cmdName.toLowerCase() == 'undo' ? 'Undo' : 'Redo')] ? 0 : -1;
},
notNeedUndo: 1
};
var keys = {
// /*Backspace*/ 8:1, /*Delete*/ 46:1,
/*Shift*/
16: 1,
/*Ctrl*/ 17: 1,
/*Alt*/ 18: 1,
37: 1,
38: 1,
39: 1,
40: 1
},
keycont = 0,
lastKeyCode;
//输入法状态下不计算字符数
var inputType = false;
me.addListener('ready', function() {
domUtils.on(this.body, 'compositionstart', function() {
inputType = true;
});
domUtils.on(this.body, 'compositionend', function() {
inputType = false;
})
});
//快捷键
me.addshortcutkey({
"Undo": "ctrl+90", //undo
"Redo": "ctrl+89" //redo
});
var isCollapsed = true;
me.addListener('keydown', function(type, evt) {
var me = this;
var keyCode = evt.keyCode || evt.which;
if(!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
if(inputType)
return;
if(!me.selection.getRange().collapsed) {
me.undoManger.save(false, true);
isCollapsed = false;
return;
}
if(me.undoManger.list.length == 0) {
me.undoManger.save(true);
}
clearTimeout(saveSceneTimer);
function save(cont) {
cont.undoManger.save(false, true);
cont.fireEvent('selectionchange');
}
saveSceneTimer = setTimeout(function() {
if(inputType) {
var interalTimer = setInterval(function() {
if(!inputType) {
save(me);
clearInterval(interalTimer)
}
}, 300)
return;
}
save(me);
}, 200);
lastKeyCode = keyCode;
keycont++;
if(keycont >= maxInputCount) {
save(me)
}
}
});
me.addListener('keyup', function(type, evt) {
var keyCode = evt.keyCode || evt.which;
if(!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
if(inputType)
return;
if(!isCollapsed) {
this.undoManger.save(false, true);
isCollapsed = true;
}
}
});
//扩展实例,添加关闭和开启命令undo
me.stopCmdUndo = function() {
me.__hasEnterExecCommand = true;
};
me.startCmdUndo = function() {
me.__hasEnterExecCommand = false;
}
};
// plugins/copy.js
UE.plugin.register('copy', function() {
var me = this;
function initZeroClipboard() {
ZeroClipboard.config({
debug: false,
swfPath: me.options.UEDITOR_HOME_URL + 'third-party/zeroclipboard/ZeroClipboard.swf'
});
var client = me.zeroclipboard = new ZeroClipboard();
// 复制内容
client.on('copy', function(e) {
var client = e.client,
rng = me.selection.getRange(),
div = document.createElement('div');
div.appendChild(rng.cloneContents());
client.setText(div.innerText || div.textContent);
client.setHtml(div.innerHTML);
rng.select();
});
// hover事件传递到target
client.on('mouseover mouseout', function(e) {
var target = e.target;
if(e.type == 'mouseover') {
domUtils.addClass(target, 'edui-state-hover');
} else if(e.type == 'mouseout') {
domUtils.removeClasses(target, 'edui-state-hover');
}
});
// flash加载不成功
client.on('wrongflash noflash', function() {
ZeroClipboard.destroy();
});
}
return {
bindEvents: {
'ready': function() {
if(!browser.ie) {
if(window.ZeroClipboard) {
initZeroClipboard();
} else {
utils.loadFile(document, {
src: me.options.UEDITOR_HOME_URL + "third-party/zeroclipboard/ZeroClipboard.js",
tag: "script",
type: "text/javascript",
defer: "defer"
}, function() {
initZeroClipboard();
});
}
}
}
},
commands: {
'copy': {
execCommand: function(cmd) {
if(!me.document.execCommand('copy')) {
alert(me.getLang('copymsg'));
}
}
}
}
}
});
// plugins/paste.js
///import core
///import plugins/inserthtml.js
///import plugins/undo.js
///import plugins/serialize.js
///commands 粘贴
///commandsName PastePlain
///commandsTitle 纯文本粘贴模式
/**
* @description 粘贴
* @author zhanyi
*/
UE.plugins['paste'] = function() {
function getClipboardData(callback) {
var doc = this.document;
if(doc.getElementById('baidu_pastebin')) {
return;
}
var range = this.selection.getRange(),
bk = range.createBookmark(),
//创建剪贴的容器div
pastebin = doc.createElement('div');
pastebin.id = 'baidu_pastebin';
// Safari 要求div必须有内容,才能粘贴内容进来
browser.webkit && pastebin.appendChild(doc.createTextNode(domUtils.fillChar + domUtils.fillChar));
doc.body.appendChild(pastebin);
//trace:717 隐藏的span不能得到top
//bk.start.innerHTML = ' ';
bk.start.style.display = '';
pastebin.style.cssText = "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
//要在现在光标平行的位置加入,否则会出现跳动的问题
domUtils.getXY(bk.start).y + 'px';
range.selectNodeContents(pastebin).select(true);
setTimeout(function() {
if(browser.webkit) {
for(var i = 0, pastebins = doc.querySelectorAll('#baidu_pastebin'), pi; pi = pastebins[i++];) {
if(domUtils.isEmptyNode(pi)) {
domUtils.remove(pi);
} else {
pastebin = pi;
break;
}
}
}
try {
pastebin.parentNode.removeChild(pastebin);
} catch(e) {}
range.moveToBookmark(bk).select(true);
callback(pastebin);
}, 0);
}
var me = this;
me.setOpt({
retainOnlyLabelPasted: false
});
var txtContent, htmlContent, address;
function getPureHtml(html) {
return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function(a, b, tagName, attrs) {
tagName = tagName.toLowerCase();
if({
img: 1
}[tagName]) {
return a;
}
attrs = attrs.replace(/([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi, function(str, atr, val) {
if({
'src': 1,
'href': 1,
'name': 1
}[atr.toLowerCase()]) {
return atr + '=' + val + ' '
}
return ''
});
if({
'span': 1,
'div': 1
}[tagName]) {
return ''
} else {
return '<' + b + tagName + ' ' + utils.trim(attrs) + '>'
}
});
}
function filter(div) {
var html;
if(div.firstChild) {
//去掉cut中添加的边界值
var nodes = domUtils.getElementsByTagName(div, 'span');
for(var i = 0, ni; ni = nodes[i++];) {
if(ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end') {
domUtils.remove(ni);
}
}
if(browser.webkit) {
var brs = div.querySelectorAll('div br');
for(var i = 0, bi; bi = brs[i++];) {
var pN = bi.parentNode;
if(pN.tagName == 'DIV' && pN.childNodes.length == 1) {
pN.innerHTML = '
';
domUtils.remove(pN);
}
}
var divs = div.querySelectorAll('#baidu_pastebin');
for(var i = 0, di; di = divs[i++];) {
var tmpP = me.document.createElement('p');
di.parentNode.insertBefore(tmpP, di);
while(di.firstChild) {
tmpP.appendChild(di.firstChild);
}
domUtils.remove(di);
}
var metas = div.querySelectorAll('meta');
for(var i = 0, ci; ci = metas[i++];) {
domUtils.remove(ci);
}
var brs = div.querySelectorAll('br');
for(i = 0; ci = brs[i++];) {
if(/^apple-/i.test(ci.className)) {
domUtils.remove(ci);
}
}
}
if(browser.gecko) {
var dirtyNodes = div.querySelectorAll('[_moz_dirty]');
for(i = 0; ci = dirtyNodes[i++];) {
ci.removeAttribute('_moz_dirty');
}
}
if(!browser.ie) {
var spans = div.querySelectorAll('span.Apple-style-span');
for(var i = 0, ci; ci = spans[i++];) {
domUtils.remove(ci, true);
}
}
//ie下使用innerHTML会产生多余的\r\n字符,也会产生 这里过滤掉
html = div.innerHTML; //.replace(/>(?:(\s| )*?)<');
//过滤word粘贴过来的冗余属性
html = UE.filterWord(html);
//取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
var root = UE.htmlparser(html);
//如果给了过滤规则就先进行过滤
if(me.options.filterRules) {
UE.filterNode(root, me.options.filterRules);
}
//执行默认的处理
me.filterInputRule(root);
//针对chrome的处理
if(browser.webkit) {
var br = root.lastChild();
if(br && br.type == 'element' && br.tagName == 'br') {
root.removeChild(br)
}
utils.each(me.body.querySelectorAll('div'), function(node) {
if(domUtils.isEmptyBlock(node)) {
domUtils.remove(node, true)
}
})
}
html = {
'html': root.toHtml()
};
me.fireEvent('beforepaste', html, root);
//抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
if(!html.html) {
return;
}
root = UE.htmlparser(html.html, true);
//如果开启了纯文本模式
if(me.queryCommandState('pasteplain') === 1) {
me.execCommand('insertHtml', UE.filterNode(root, me.options.filterTxtRules).toHtml(), true);
} else {
//文本模式
UE.filterNode(root, me.options.filterTxtRules);
txtContent = root.toHtml();
//完全模式
htmlContent = html.html;
address = me.selection.getRange().createAddress(true);
me.execCommand('insertHtml', me.getOpt('retainOnlyLabelPasted') === true ? getPureHtml(htmlContent) : htmlContent, true);
}
me.fireEvent("afterpaste", html);
}
}
me.addListener('pasteTransfer', function(cmd, plainType) {
if(address && txtContent && htmlContent && txtContent != htmlContent) {
var range = me.selection.getRange();
range.moveToAddress(address, true);
if(!range.collapsed) {
while(!domUtils.isBody(range.startContainer)) {
var start = range.startContainer;
if(start.nodeType == 1) {
start = start.childNodes[range.startOffset];
if(!start) {
range.setStartBefore(range.startContainer);
continue;
}
var pre = start.previousSibling;
if(pre && pre.nodeType == 3 && new RegExp('^[\n\r\t ' + domUtils.fillChar + ']*$').test(pre.nodeValue)) {
range.setStartBefore(pre)
}
}
if(range.startOffset == 0) {
range.setStartBefore(range.startContainer);
} else {
break;
}
}
while(!domUtils.isBody(range.endContainer)) {
var end = range.endContainer;
if(end.nodeType == 1) {
end = end.childNodes[range.endOffset];
if(!end) {
range.setEndAfter(range.endContainer);
continue;
}
var next = end.nextSibling;
if(next && next.nodeType == 3 && new RegExp('^[\n\r\t' + domUtils.fillChar + ']*$').test(next.nodeValue)) {
range.setEndAfter(next)
}
}
if(range.endOffset == range.endContainer[range.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length) {
range.setEndAfter(range.endContainer);
} else {
break;
}
}
}
range.deleteContents();
range.select(true);
me.__hasEnterExecCommand = true;
var html = htmlContent;
if(plainType === 2) {
html = getPureHtml(html);
} else if(plainType) {
html = txtContent;
}
me.execCommand('inserthtml', html, true);
me.__hasEnterExecCommand = false;
var rng = me.selection.getRange();
while(!domUtils.isBody(rng.startContainer) && !rng.startOffset &&
rng.startContainer[rng.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
) {
rng.setStartBefore(rng.startContainer);
}
var tmpAddress = rng.createAddress(true);
address.endAddress = tmpAddress.startAddress;
}
});
me.addListener('ready', function() {
domUtils.on(me.body, 'cut', function() {
var range = me.selection.getRange();
if(!range.collapsed && me.undoManger) {
me.undoManger.save();
}
});
//ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
domUtils.on(me.body, browser.ie || browser.opera ? 'keydown' : 'paste', function(e) {
if((browser.ie || browser.opera) && ((!e.ctrlKey && !e.metaKey) || e.keyCode != '86')) {
return;
}
getClipboardData.call(me, function(div) {
filter(div);
});
});
});
me.commands['paste'] = {
execCommand: function(cmd) {
if(browser.ie) {
getClipboardData.call(me, function(div) {
filter(div);
});
me.document.execCommand('paste');
} else {
alert(me.getLang('pastemsg'));
}
}
}
};
// plugins/puretxtpaste.js
/**
* 纯文本粘贴插件
* @file
* @since 1.2.6.1
*/
UE.plugins['pasteplain'] = function() {
var me = this;
me.setOpt({
'pasteplain': false,
'filterTxtRules': function() {
function transP(node) {
node.tagName = 'p';
node.setStyle();
}
function removeNode(node) {
node.parentNode.removeChild(node, true)
}
return {
//直接删除及其字节点内容
'-': 'script style object iframe embed input select',
'p': {
$: {}
},
'br': {
$: {}
},
div: function(node) {
var tmpNode, p = UE.uNode.createElement('p');
while(tmpNode = node.firstChild()) {
if(tmpNode.type == 'text' || !UE.dom.dtd.$block[tmpNode.tagName]) {
p.appendChild(tmpNode);
} else {
if(p.firstChild()) {
node.parentNode.insertBefore(p, node);
p = UE.uNode.createElement('p');
} else {
node.parentNode.insertBefore(tmpNode, node);
}
}
}
if(p.firstChild()) {
node.parentNode.insertBefore(p, node);
}
node.parentNode.removeChild(node);
},
ol: removeNode,
ul: removeNode,
dl: removeNode,
dt: removeNode,
dd: removeNode,
'li': removeNode,
'caption': transP,
'th': transP,
'tr': transP,
'h1': transP,
'h2': transP,
'h3': transP,
'h4': transP,
'h5': transP,
'h6': transP,
'td': function(node) {
//没有内容的td直接删掉
var txt = !!node.innerText();
if(txt) {
node.parentNode.insertAfter(UE.uNode.createText(' '), node);
}
node.parentNode.removeChild(node, node.innerText())
}
}
}()
});
//暂时这里支持一下老版本的属性
var pasteplain = me.options.pasteplain;
/**
* 启用或取消纯文本粘贴模式
* @command pasteplain
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.queryCommandState( 'pasteplain' );
* ```
*/
/**
* 查询当前是否处于纯文本粘贴模式
* @command pasteplain
* @method queryCommandState
* @param { String } cmd 命令字符串
* @return { int } 如果处于纯文本模式,返回1,否则,返回0
* @example
* ```javascript
* editor.queryCommandState( 'pasteplain' );
* ```
*/
me.commands['pasteplain'] = {
queryCommandState: function() {
return pasteplain ? 1 : 0;
},
execCommand: function() {
pasteplain = !pasteplain | 0;
},
notNeedUndo: 1
};
};
// plugins/list.js
/**
* 有序列表,无序列表插件
* @file
* @since 1.2.6.1
*/
UE.plugins['list'] = function() {
var me = this,
notExchange = {
'TD': 1,
'PRE': 1,
'BLOCKQUOTE': 1
};
var customStyle = {
'cn': 'cn-1-',
'cn1': 'cn-2-',
'cn2': 'cn-3-',
'num': 'num-1-',
'num1': 'num-2-',
'num2': 'num-3-',
'dash': 'dash',
'dot': 'dot'
};
me.setOpt({
'autoTransWordToList': false,
'insertorderedlist': {
'num': '',
'num1': '',
'num2': '',
'cn': '',
'cn1': '',
'cn2': '',
'decimal': '',
'lower-alpha': '',
'lower-roman': '',
'upper-alpha': '',
'upper-roman': ''
},
'insertunorderedlist': {
'circle': '',
'disc': '',
'square': '',
'dash': '',
'dot': ''
},
listDefaultPaddingLeft: '30',
listiconpath: 'http://bs.baidu.com/listicon/',
maxListLevel: -1, //-1不限制
disablePInList: false
});
function listToArray(list) {
var arr = [];
for(var p in list) {
arr.push(p)
}
return arr;
}
var listStyle = {
'OL': listToArray(me.options.insertorderedlist),
'UL': listToArray(me.options.insertunorderedlist)
};
var liiconpath = me.options.listiconpath;
//根据用户配置,调整customStyle
for(var s in customStyle) {
if(!me.options.insertorderedlist.hasOwnProperty(s) && !me.options.insertunorderedlist.hasOwnProperty(s)) {
delete customStyle[s];
}
}
me.ready(function() {
var customCss = [];
for(var p in customStyle) {
if(p == 'dash' || p == 'dot') {
customCss.push('li.list-' + customStyle[p] + '{background-image:url(' + liiconpath + customStyle[p] + '.gif)}');
customCss.push('ul.custom_' + p + '{list-style:none;}ul.custom_' + p + ' li{background-position:0 3px;background-repeat:no-repeat}');
} else {
for(var i = 0; i < 99; i++) {
customCss.push('li.list-' + customStyle[p] + i + '{background-image:url(' + liiconpath + 'list-' + customStyle[p] + i + '.gif)}')
}
customCss.push('ol.custom_' + p + '{list-style:none;}ol.custom_' + p + ' li{background-position:0 3px;background-repeat:no-repeat}');
}
switch(p) {
case 'cn':
customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}');
customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}');
customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}');
break;
case 'cn1':
customCss.push('li.list-' + p + '-paddingleft-1{padding-left:30px}');
customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}');
customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}');
break;
case 'cn2':
customCss.push('li.list-' + p + '-paddingleft-1{padding-left:40px}');
customCss.push('li.list-' + p + '-paddingleft-2{padding-left:55px}');
customCss.push('li.list-' + p + '-paddingleft-3{padding-left:68px}');
break;
case 'num':
case 'num1':
customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}');
break;
case 'num2':
customCss.push('li.list-' + p + '-paddingleft-1{padding-left:35px}');
customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}');
break;
case 'dash':
customCss.push('li.list-' + p + '-paddingleft{padding-left:35px}');
break;
case 'dot':
customCss.push('li.list-' + p + '-paddingleft{padding-left:20px}');
}
}
customCss.push('.list-paddingleft-1{padding-left:0}');
customCss.push('.list-paddingleft-2{padding-left:' + me.options.listDefaultPaddingLeft + 'px}');
customCss.push('.list-paddingleft-3{padding-left:' + me.options.listDefaultPaddingLeft * 2 + 'px}');
//如果不给宽度会在自定应样式里出现滚动条
utils.cssRule('list', 'ol,ul{margin:0;pading:0;' + (browser.ie ? '' : 'width:95%') + '}li{clear:both;}' + customCss.join('\n'), me.document);
});
//单独处理剪切的问题
me.ready(function() {
domUtils.on(me.body, 'cut', function() {
setTimeout(function() {
var rng = me.selection.getRange(),
li;
//trace:3416
if(!rng.collapsed) {
if(li = domUtils.findParentByTagName(rng.startContainer, 'li', true)) {
if(!li.nextSibling && domUtils.isEmptyBlock(li)) {
var pn = li.parentNode,
node;
if(node = pn.previousSibling) {
domUtils.remove(pn);
rng.setStartAtLast(node).collapse(true);
rng.select(true);
} else if(node = pn.nextSibling) {
domUtils.remove(pn);
rng.setStartAtFirst(node).collapse(true);
rng.select(true);
} else {
var tmpNode = me.document.createElement('p');
domUtils.fillNode(me.document, tmpNode);
pn.parentNode.insertBefore(tmpNode, pn);
domUtils.remove(pn);
rng.setStart(tmpNode, 0).collapse(true);
rng.select(true);
}
}
}
}
})
})
});
function getStyle(node) {
var cls = node.className;
if(domUtils.hasClass(node, /custom_/)) {
return cls.match(/custom_(\w+)/)[1]
}
return domUtils.getStyle(node, 'list-style-type')
}
me.addListener('beforepaste', function(type, html) {
var me = this,
rng = me.selection.getRange(),
li;
var root = UE.htmlparser(html.html, true);
if(li = domUtils.findParentByTagName(rng.startContainer, 'li', true)) {
var list = li.parentNode,
tagName = list.tagName == 'OL' ? 'ul' : 'ol';
utils.each(root.getNodesByTagName(tagName), function(n) {
n.tagName = list.tagName;
n.setAttr();
if(n.parentNode === root) {
type = getStyle(list) || (list.tagName == 'OL' ? 'decimal' : 'disc')
} else {
var className = n.parentNode.getAttr('class');
if(className && /custom_/.test(className)) {
type = className.match(/custom_(\w+)/)[1]
} else {
type = n.parentNode.getStyle('list-style-type');
}
if(!type) {
type = list.tagName == 'OL' ? 'decimal' : 'disc';
}
}
var index = utils.indexOf(listStyle[list.tagName], type);
if(n.parentNode !== root)
index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
var currentStyle = listStyle[list.tagName][index];
if(customStyle[currentStyle]) {
n.setAttr('class', 'custom_' + currentStyle)
} else {
n.setStyle('list-style-type', currentStyle)
}
})
}
html.html = root.toHtml();
});
//导出时,去掉p标签
me.getOpt('disablePInList') === true && me.addOutputRule(function(root) {
utils.each(root.getNodesByTagName('li'), function(li) {
var newChildrens = [],
index = 0;
utils.each(li.children, function(n) {
if(n.tagName == 'p') {
var tmpNode;
while(tmpNode = n.children.pop()) {
newChildrens.splice(index, 0, tmpNode);
tmpNode.parentNode = li;
lastNode = tmpNode;
}
tmpNode = newChildrens[newChildrens.length - 1];
if(!tmpNode || tmpNode.type != 'element' || tmpNode.tagName != 'br') {
var br = UE.uNode.createElement('br');
br.parentNode = li;
newChildrens.push(br);
}
index = newChildrens.length;
}
});
if(newChildrens.length) {
li.children = newChildrens;
}
});
});
//进入编辑器的li要套p标签
me.addInputRule(function(root) {
utils.each(root.getNodesByTagName('li'), function(li) {
var tmpP = UE.uNode.createElement('p');
for(var i = 0, ci; ci = li.children[i];) {
if(ci.type == 'text' || dtd.p[ci.tagName]) {
tmpP.appendChild(ci);
} else {
if(tmpP.firstChild()) {
li.insertBefore(tmpP, ci);
tmpP = UE.uNode.createElement('p');
i = i + 2;
} else {
i++;
}
}
}
if(tmpP.firstChild() && !tmpP.parentNode || !li.firstChild()) {
li.appendChild(tmpP);
}
//trace:3357
//p不能为空
if(!tmpP.firstChild()) {
tmpP.innerHTML(browser.ie ? ' ' : ' ')
}
//去掉末尾的空白
var p = li.firstChild();
var lastChild = p.lastChild();
if(lastChild && lastChild.type == 'text' && /^\s*$/.test(lastChild.data)) {
p.removeChild(lastChild)
}
});
if(me.options.autoTransWordToList) {
var orderlisttype = {
'num1': /^\d+\)/,
'decimal': /^\d+\./,
'lower-alpha': /^[a-z]+\)/,
'upper-alpha': /^[A-Z]+\./,
'cn': /^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
'cn2': /^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/
},
unorderlisttype = {
'square': 'n'
};
function checkListType(content, container) {
var span = container.firstChild();
if(span && span.type == 'element' && span.tagName == 'span' && /Wingdings|Symbol/.test(span.getStyle('font-family'))) {
for(var p in unorderlisttype) {
if(unorderlisttype[p] == span.data) {
return p
}
}
return 'disc'
}
for(var p in orderlisttype) {
if(orderlisttype[p].test(content)) {
return p;
}
}
}
utils.each(root.getNodesByTagName('p'), function(node) {
if(node.getAttr('class') != 'MsoListParagraph') {
return
}
//word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视
node.setStyle('margin', '');
node.setStyle('margin-left', '');
node.setAttr('class', '');
function appendLi(list, p, type) {
if(list.tagName == 'ol') {
if(browser.ie) {
var first = p.firstChild();
if(first.type == 'element' && first.tagName == 'span' && orderlisttype[type].test(first.innerText())) {
p.removeChild(first);
}
} else {
p.innerHTML(p.innerHTML().replace(orderlisttype[type], ''));
}
} else {
p.removeChild(p.firstChild())
}
var li = UE.uNode.createElement('li');
li.appendChild(p);
list.appendChild(li);
}
var tmp = node,
type, cacheNode = node;
if(node.parentNode.tagName != 'li' && (type = checkListType(node.innerText(), node))) {
var list = UE.uNode.createElement(me.options.insertorderedlist.hasOwnProperty(type) ? 'ol' : 'ul');
if(customStyle[type]) {
list.setAttr('class', 'custom_' + type)
} else {
list.setStyle('list-style-type', type)
}
while(node && node.parentNode.tagName != 'li' && checkListType(node.innerText(), node)) {
tmp = node.nextSibling();
if(!tmp) {
node.parentNode.insertBefore(list, node)
}
appendLi(list, node, type);
node = tmp;
}
if(!list.parentNode && node && node.parentNode) {
node.parentNode.insertBefore(list, node)
}
}
var span = cacheNode.firstChild();
if(span && span.type == 'element' && span.tagName == 'span' && /^\s*( )+\s*$/.test(span.innerText())) {
span.parentNode.removeChild(span)
}
})
}
});
//调整索引标签
me.addListener('contentchange', function() {
adjustListStyle(me.document)
});
function adjustListStyle(doc, ignore) {
utils.each(domUtils.getElementsByTagName(doc, 'ol ul'), function(node) {
if(!domUtils.inDoc(node, doc))
return;
var parent = node.parentNode;
if(parent.tagName == node.tagName) {
var nodeStyleType = getStyle(node) || (node.tagName == 'OL' ? 'decimal' : 'disc'),
parentStyleType = getStyle(parent) || (parent.tagName == 'OL' ? 'decimal' : 'disc');
if(nodeStyleType == parentStyleType) {
var styleIndex = utils.indexOf(listStyle[node.tagName], nodeStyleType);
styleIndex = styleIndex + 1 == listStyle[node.tagName].length ? 0 : styleIndex + 1;
setListStyle(node, listStyle[node.tagName][styleIndex])
}
}
var index = 0,
type = 2;
if(domUtils.hasClass(node, /custom_/)) {
if(!(/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent, /custom_/))) {
type = 1;
}
} else {
if(/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent, /custom_/)) {
type = 3;
}
}
var style = domUtils.getStyle(node, 'list-style-type');
style && (node.style.cssText = 'list-style-type:' + style);
node.className = utils.trim(node.className.replace(/list-paddingleft-\w+/, '')) + ' list-paddingleft-' + type;
utils.each(domUtils.getElementsByTagName(node, 'li'), function(li) {
li.style.cssText && (li.style.cssText = '');
if(!li.firstChild) {
domUtils.remove(li);
return;
}
if(li.parentNode !== node) {
return;
}
index++;
if(domUtils.hasClass(node, /custom_/)) {
var paddingLeft = 1,
currentStyle = getStyle(node);
if(node.tagName == 'OL') {
if(currentStyle) {
switch(currentStyle) {
case 'cn':
case 'cn1':
case 'cn2':
if(index > 10 && (index % 10 == 0 || index > 10 && index < 20)) {
paddingLeft = 2
} else if(index > 20) {
paddingLeft = 3
}
break;
case 'num2':
if(index > 9) {
paddingLeft = 2
}
}
}
li.className = 'list-' + customStyle[currentStyle] + index + ' ' + 'list-' + currentStyle + '-paddingleft-' + paddingLeft;
} else {
li.className = 'list-' + customStyle[currentStyle] + ' ' + 'list-' + currentStyle + '-paddingleft';
}
} else {
li.className = li.className.replace(/list-[\w\-]+/gi, '');
}
var className = li.getAttribute('class');
if(className !== null && !className.replace(/\s/g, '')) {
domUtils.removeAttributes(li, 'class')
}
});
!ignore && adjustList(node, node.tagName.toLowerCase(), getStyle(node) || domUtils.getStyle(node, 'list-style-type'), true);
})
}
function adjustList(list, tag, style, ignoreEmpty) {
var nextList = list.nextSibling;
if(nextList && nextList.nodeType == 1 && nextList.tagName.toLowerCase() == tag && (getStyle(nextList) || domUtils.getStyle(nextList, 'list-style-type') || (tag == 'ol' ? 'decimal' : 'disc')) == style) {
domUtils.moveChild(nextList, list);
if(nextList.childNodes.length == 0) {
domUtils.remove(nextList);
}
}
if(nextList && domUtils.isFillChar(nextList)) {
domUtils.remove(nextList);
}
var preList = list.previousSibling;
if(preList && preList.nodeType == 1 && preList.tagName.toLowerCase() == tag && (getStyle(preList) || domUtils.getStyle(preList, 'list-style-type') || (tag == 'ol' ? 'decimal' : 'disc')) == style) {
domUtils.moveChild(list, preList);
}
if(preList && domUtils.isFillChar(preList)) {
domUtils.remove(preList);
}!ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list);
if(getStyle(list)) {
adjustListStyle(list.ownerDocument, true)
}
}
function setListStyle(list, style) {
if(customStyle[style]) {
list.className = 'custom_' + style;
}
try {
domUtils.setStyle(list, 'list-style-type', style);
} catch(e) {}
}
function clearEmptySibling(node) {
var tmpNode = node.previousSibling;
if(tmpNode && domUtils.isEmptyBlock(tmpNode)) {
domUtils.remove(tmpNode);
}
tmpNode = node.nextSibling;
if(tmpNode && domUtils.isEmptyBlock(tmpNode)) {
domUtils.remove(tmpNode);
}
}
me.addListener('keydown', function(type, evt) {
function preventAndSave() {
evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
me.fireEvent('contentchange');
me.undoManger && me.undoManger.save();
}
function findList(node, filterFn) {
while(node && !domUtils.isBody(node)) {
if(filterFn(node)) {
return null
}
if(node.nodeType == 1 && /[ou]l/i.test(node.tagName)) {
return node;
}
node = node.parentNode;
}
return null;
}
var keyCode = evt.keyCode || evt.which;
if(keyCode == 13 && !evt.shiftKey) { //回车
var rng = me.selection.getRange(),
parent = domUtils.findParent(rng.startContainer, function(node) {
return domUtils.isBlockElm(node)
}, true),
li = domUtils.findParentByTagName(rng.startContainer, 'li', true);
if(parent && parent.tagName != 'PRE' && !li) {
var html = parent.innerHTML.replace(new RegExp(domUtils.fillChar, 'g'), '');
if(/^\s*1\s*\.[^\d]/.test(html)) {
parent.innerHTML = html.replace(/^\s*1\s*\./, '');
rng.setStartAtLast(parent).collapse(true).select();
me.__hasEnterExecCommand = true;
me.execCommand('insertorderedlist');
me.__hasEnterExecCommand = false;
}
}
var range = me.selection.getRange(),
start = findList(range.startContainer, function(node) {
return node.tagName == 'TABLE';
}),
end = range.collapsed ? start : findList(range.endContainer, function(node) {
return node.tagName == 'TABLE';
});
if(start && end && start === end) {
if(!range.collapsed) {
start = domUtils.findParentByTagName(range.startContainer, 'li', true);
end = domUtils.findParentByTagName(range.endContainer, 'li', true);
if(start && end && start === end) {
range.deleteContents();
li = domUtils.findParentByTagName(range.startContainer, 'li', true);
if(li && domUtils.isEmptyBlock(li)) {
pre = li.previousSibling;
next = li.nextSibling;
p = me.document.createElement('p');
domUtils.fillNode(me.document, p);
parentList = li.parentNode;
if(pre && next) {
range.setStart(next, 0).collapse(true).select(true);
domUtils.remove(li);
} else {
if(!pre && !next || !pre) {
parentList.parentNode.insertBefore(p, parentList);
} else {
li.parentNode.parentNode.insertBefore(p, parentList.nextSibling);
}
domUtils.remove(li);
if(!parentList.firstChild) {
domUtils.remove(parentList);
}
range.setStart(p, 0).setCursor();
}
preventAndSave();
return;
}
} else {
var tmpRange = range.cloneRange(),
bk = tmpRange.collapse(false).createBookmark();
range.deleteContents();
tmpRange.moveToBookmark(bk);
var li = domUtils.findParentByTagName(tmpRange.startContainer, 'li', true);
clearEmptySibling(li);
tmpRange.select();
preventAndSave();
return;
}
}
li = domUtils.findParentByTagName(range.startContainer, 'li', true);
if(li) {
if(domUtils.isEmptyBlock(li)) {
bk = range.createBookmark();
var parentList = li.parentNode;
if(li !== parentList.lastChild) {
domUtils.breakParent(li, parentList);
clearEmptySibling(li);
} else {
parentList.parentNode.insertBefore(li, parentList.nextSibling);
if(domUtils.isEmptyNode(parentList)) {
domUtils.remove(parentList);
}
}
//嵌套不处理
if(!dtd.$list[li.parentNode.tagName]) {
if(!domUtils.isBlockElm(li.firstChild)) {
p = me.document.createElement('p');
li.parentNode.insertBefore(p, li);
while(li.firstChild) {
p.appendChild(li.firstChild);
}
domUtils.remove(li);
} else {
domUtils.remove(li, true);
}
}
range.moveToBookmark(bk).select();
} else {
var first = li.firstChild;
if(!first || !domUtils.isBlockElm(first)) {
var p = me.document.createElement('p');
!li.firstChild && domUtils.fillNode(me.document, p);
while(li.firstChild) {
p.appendChild(li.firstChild);
}
li.appendChild(p);
first = p;
}
var span = me.document.createElement('span');
range.insertNode(span);
domUtils.breakParent(span, li);
var nextLi = span.nextSibling;
first = nextLi.firstChild;
if(!first) {
p = me.document.createElement('p');
domUtils.fillNode(me.document, p);
nextLi.appendChild(p);
first = p;
}
if(domUtils.isEmptyNode(first)) {
first.innerHTML = '';
domUtils.fillNode(me.document, first);
}
range.setStart(first, 0).collapse(true).shrinkBoundary().select();
domUtils.remove(span);
var pre = nextLi.previousSibling;
if(pre && domUtils.isEmptyBlock(pre)) {
pre.innerHTML = '';
domUtils.fillNode(me.document, pre.firstChild);
}
}
// }
preventAndSave();
}
}
}
if(keyCode == 8) {
//修中ie中li下的问题
range = me.selection.getRange();
if(range.collapsed && domUtils.isStartInblock(range)) {
tmpRange = range.cloneRange().trimBoundary();
li = domUtils.findParentByTagName(range.startContainer, 'li', true);
//要在li的最左边,才能处理
if(li && domUtils.isStartInblock(tmpRange)) {
start = domUtils.findParentByTagName(range.startContainer, 'p', true);
if(start && start !== li.firstChild) {
var parentList = domUtils.findParentByTagName(start, ['ol', 'ul']);
domUtils.breakParent(start, parentList);
clearEmptySibling(start);
me.fireEvent('contentchange');
range.setStart(start, 0).setCursor(false, true);
me.fireEvent('saveScene');
domUtils.preventDefault(evt);
return;
}
if(li && (pre = li.previousSibling)) {
if(keyCode == 46 && li.childNodes.length) {
return;
}
//有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
if(dtd.$list[pre.tagName]) {
pre = pre.lastChild;
}
me.undoManger && me.undoManger.save();
first = li.firstChild;
if(domUtils.isBlockElm(first)) {
if(domUtils.isEmptyNode(first)) {
// range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
pre.appendChild(first);
range.setStart(first, 0).setCursor(false, true);
//first不是唯一的节点
while(li.firstChild) {
pre.appendChild(li.firstChild);
}
} else {
span = me.document.createElement('span');
range.insertNode(span);
//判断pre是否是空的节点,如果是
类型的空节点,干掉p标签防止它占位
if(domUtils.isEmptyBlock(pre)) {
pre.innerHTML = '';
}
domUtils.moveChild(li, pre);
range.setStartBefore(span).collapse(true).select(true);
domUtils.remove(span);
}
} else {
if(domUtils.isEmptyNode(li)) {
var p = me.document.createElement('p');
pre.appendChild(p);
range.setStart(p, 0).setCursor();
// range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
} else {
range.setEnd(pre, pre.childNodes.length).collapse().select(true);
while(li.firstChild) {
pre.appendChild(li.firstChild);
}
}
}
domUtils.remove(li);
me.fireEvent('contentchange');
me.fireEvent('saveScene');
domUtils.preventDefault(evt);
return;
}
//trace:980
if(li && !li.previousSibling) {
var parentList = li.parentNode;
var bk = range.createBookmark();
if(domUtils.isTagNode(parentList.parentNode, 'ol ul')) {
parentList.parentNode.insertBefore(li, parentList);
if(domUtils.isEmptyNode(parentList)) {
domUtils.remove(parentList)
}
} else {
while(li.firstChild) {
parentList.parentNode.insertBefore(li.firstChild, parentList);
}
domUtils.remove(li);
if(domUtils.isEmptyNode(parentList)) {
domUtils.remove(parentList)
}
}
range.moveToBookmark(bk).setCursor(false, true);
me.fireEvent('contentchange');
me.fireEvent('saveScene');
domUtils.preventDefault(evt);
return;
}
}
}
}
});
me.addListener('keyup', function(type, evt) {
var keyCode = evt.keyCode || evt.which;
if(keyCode == 8) {
var rng = me.selection.getRange(),
list;
if(list = domUtils.findParentByTagName(rng.startContainer, ['ol', 'ul'], true)) {
adjustList(list, list.tagName.toLowerCase(), getStyle(list) || domUtils.getComputedStyle(list, 'list-style-type'), true)
}
}
});
//处理tab键
me.addListener('tabkeydown', function() {
var range = me.selection.getRange();
//控制级数
function checkLevel(li) {
if(me.options.maxListLevel != -1) {
var level = li.parentNode,
levelNum = 0;
while(/[ou]l/i.test(level.tagName)) {
levelNum++;
level = level.parentNode;
}
if(levelNum >= me.options.maxListLevel) {
return true;
}
}
}
//只以开始为准
//todo 后续改进
var li = domUtils.findParentByTagName(range.startContainer, 'li', true);
if(li) {
var bk;
if(range.collapsed) {
if(checkLevel(li))
return true;
var parentLi = li.parentNode,
list = me.document.createElement(parentLi.tagName),
index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) || domUtils.getComputedStyle(parentLi, 'list-style-type'));
index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
var currentStyle = listStyle[list.tagName][index];
setListStyle(list, currentStyle);
if(domUtils.isStartInblock(range)) {
me.fireEvent('saveScene');
bk = range.createBookmark();
parentLi.insertBefore(list, li);
list.appendChild(li);
adjustList(list, list.tagName.toLowerCase(), currentStyle);
me.fireEvent('contentchange');
range.moveToBookmark(bk).select(true);
return true;
}
} else {
me.fireEvent('saveScene');
bk = range.createBookmark();
for(var i = 0, closeList, parents = domUtils.findParents(li), ci; ci = parents[i++];) {
if(domUtils.isTagNode(ci, 'ol ul')) {
closeList = ci;
break;
}
}
var current = li;
if(bk.end) {
while(current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)) {
if(checkLevel(current)) {
current = domUtils.getNextDomNode(current, false, null, function(node) {
return node !== closeList
});
continue;
}
var parentLi = current.parentNode,
list = me.document.createElement(parentLi.tagName),
index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) || domUtils.getComputedStyle(parentLi, 'list-style-type'));
var currentIndex = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
var currentStyle = listStyle[list.tagName][currentIndex];
setListStyle(list, currentStyle);
parentLi.insertBefore(list, current);
while(current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)) {
li = current.nextSibling;
list.appendChild(current);
if(!li || domUtils.isTagNode(li, 'ol ul')) {
if(li) {
while(li = li.firstChild) {
if(li.tagName == 'LI') {
break;
}
}
} else {
li = domUtils.getNextDomNode(current, false, null, function(node) {
return node !== closeList
});
}
break;
}
current = li;
}
adjustList(list, list.tagName.toLowerCase(), currentStyle);
current = li;
}
}
me.fireEvent('contentchange');
range.moveToBookmark(bk).select();
return true;
}
}
});
function getLi(start) {
while(start && !domUtils.isBody(start)) {
if(start.nodeName == 'TABLE') {
return null;
}
if(start.nodeName == 'LI') {
return start
}
start = start.parentNode;
}
}
/**
* 有序列表,与“insertunorderedlist”命令互斥
* @command insertorderedlist
* @method execCommand
* @param { String } command 命令字符串
* @param { String } style 插入的有序列表类型,值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
* @example
* ```javascript
* editor.execCommand( 'insertorderedlist','decimal');
* ```
*/
/**
* 查询当前选区内容是否有序列表
* @command insertorderedlist
* @method queryCommandState
* @param { String } cmd 命令字符串
* @return { int } 如果当前选区是有序列表返回1,否则返回0
* @example
* ```javascript
* editor.queryCommandState( 'insertorderedlist' );
* ```
*/
/**
* 查询当前选区内容是否有序列表
* @command insertorderedlist
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @return { String } 返回当前有序列表的类型,值为null或decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
* @example
* ```javascript
* editor.queryCommandValue( 'insertorderedlist' );
* ```
*/
/**
* 无序列表,与“insertorderedlist”命令互斥
* @command insertunorderedlist
* @method execCommand
* @param { String } command 命令字符串
* @param { String } style 插入的无序列表类型,值为:circle,disc,square,dash,dot
* @example
* ```javascript
* editor.execCommand( 'insertunorderedlist','circle');
* ```
*/
/**
* 查询当前是否有word文档粘贴进来的图片
* @command insertunorderedlist
* @method insertunorderedlist
* @param { String } command 命令字符串
* @return { int } 如果当前选区是无序列表返回1,否则返回0
* @example
* ```javascript
* editor.queryCommandState( 'insertunorderedlist' );
* ```
*/
/**
* 查询当前选区内容是否有序列表
* @command insertunorderedlist
* @method queryCommandValue
* @param { String } command 命令字符串
* @return { String } 返回当前无序列表的类型,值为null或circle,disc,square,dash,dot
* @example
* ```javascript
* editor.queryCommandValue( 'insertunorderedlist' );
* ```
*/
me.commands['insertorderedlist'] =
me.commands['insertunorderedlist'] = {
execCommand: function(command, style) {
if(!style) {
style = command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc';
}
var me = this,
range = this.selection.getRange(),
filterFn = function(node) {
return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace(node);
},
tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul',
frag = me.document.createDocumentFragment();
//去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
//range.shrinkBoundary();//.adjustmentBoundary();
range.adjustmentBoundary().shrinkBoundary();
var bko = range.createBookmark(true),
start = getLi(me.document.getElementById(bko.start)),
modifyStart = 0,
end = getLi(me.document.getElementById(bko.end)),
modifyEnd = 0,
startParent, endParent,
list, tmp;
if(start || end) {
start && (startParent = start.parentNode);
if(!bko.end) {
end = start;
}
end && (endParent = end.parentNode);
if(startParent === endParent) {
while(start !== end) {
tmp = start;
start = start.nextSibling;
if(!domUtils.isBlockElm(tmp.firstChild)) {
var p = me.document.createElement('p');
while(tmp.firstChild) {
p.appendChild(tmp.firstChild);
}
tmp.appendChild(p);
}
frag.appendChild(tmp);
}
tmp = me.document.createElement('span');
startParent.insertBefore(tmp, end);
if(!domUtils.isBlockElm(end.firstChild)) {
p = me.document.createElement('p');
while(end.firstChild) {
p.appendChild(end.firstChild);
}
end.appendChild(p);
}
frag.appendChild(end);
domUtils.breakParent(tmp, startParent);
if(domUtils.isEmptyNode(tmp.previousSibling)) {
domUtils.remove(tmp.previousSibling);
}
if(domUtils.isEmptyNode(tmp.nextSibling)) {
domUtils.remove(tmp.nextSibling)
}
var nodeStyle = getStyle(startParent) || domUtils.getComputedStyle(startParent, 'list-style-type') || (command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc');
if(startParent.tagName.toLowerCase() == tag && nodeStyle == style) {
for(var i = 0, ci, tmpFrag = me.document.createDocumentFragment(); ci = frag.firstChild;) {
if(domUtils.isTagNode(ci, 'ol ul')) {
// 删除时,子列表不处理
// utils.each(domUtils.getElementsByTagName(ci,'li'),function(li){
// while(li.firstChild){
// tmpFrag.appendChild(li.firstChild);
// }
//
// });
tmpFrag.appendChild(ci);
} else {
while(ci.firstChild) {
tmpFrag.appendChild(ci.firstChild);
domUtils.remove(ci);
}
}
}
tmp.parentNode.insertBefore(tmpFrag, tmp);
} else {
list = me.document.createElement(tag);
setListStyle(list, style);
list.appendChild(frag);
tmp.parentNode.insertBefore(list, tmp);
}
domUtils.remove(tmp);
list && adjustList(list, tag, style);
range.moveToBookmark(bko).select();
return;
}
//开始
if(start) {
while(start) {
tmp = start.nextSibling;
if(domUtils.isTagNode(start, 'ol ul')) {
frag.appendChild(start);
} else {
var tmpfrag = me.document.createDocumentFragment(),
hasBlock = 0;
while(start.firstChild) {
if(domUtils.isBlockElm(start.firstChild)) {
hasBlock = 1;
}
tmpfrag.appendChild(start.firstChild);
}
if(!hasBlock) {
var tmpP = me.document.createElement('p');
tmpP.appendChild(tmpfrag);
frag.appendChild(tmpP);
} else {
frag.appendChild(tmpfrag);
}
domUtils.remove(start);
}
start = tmp;
}
startParent.parentNode.insertBefore(frag, startParent.nextSibling);
if(domUtils.isEmptyNode(startParent)) {
range.setStartBefore(startParent);
domUtils.remove(startParent);
} else {
range.setStartAfter(startParent);
}
modifyStart = 1;
}
if(end && domUtils.inDoc(endParent, me.document)) {
//结束
start = endParent.firstChild;
while(start && start !== end) {
tmp = start.nextSibling;
if(domUtils.isTagNode(start, 'ol ul')) {
frag.appendChild(start);
} else {
tmpfrag = me.document.createDocumentFragment();
hasBlock = 0;
while(start.firstChild) {
if(domUtils.isBlockElm(start.firstChild)) {
hasBlock = 1;
}
tmpfrag.appendChild(start.firstChild);
}
if(!hasBlock) {
tmpP = me.document.createElement('p');
tmpP.appendChild(tmpfrag);
frag.appendChild(tmpP);
} else {
frag.appendChild(tmpfrag);
}
domUtils.remove(start);
}
start = tmp;
}
var tmpDiv = domUtils.createElement(me.document, 'div', {
'tmpDiv': 1
});
domUtils.moveChild(end, tmpDiv);
frag.appendChild(tmpDiv);
domUtils.remove(end);
endParent.parentNode.insertBefore(frag, endParent);
range.setEndBefore(endParent);
if(domUtils.isEmptyNode(endParent)) {
domUtils.remove(endParent);
}
modifyEnd = 1;
}
}
if(!modifyStart) {
range.setStartBefore(me.document.getElementById(bko.start));
}
if(bko.end && !modifyEnd) {
range.setEndAfter(me.document.getElementById(bko.end));
}
range.enlarge(true, function(node) {
return notExchange[node.tagName];
});
frag = me.document.createDocumentFragment();
var bk = range.createBookmark(),
current = domUtils.getNextDomNode(bk.start, false, filterFn),
tmpRange = range.cloneRange(),
tmpNode,
block = domUtils.isBlockElm;
while(current && current !== bk.end && (domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING)) {
if(current.nodeType == 3 || dtd.li[current.tagName]) {
if(current.nodeType == 1 && dtd.$list[current.tagName]) {
while(current.firstChild) {
frag.appendChild(current.firstChild);
}
tmpNode = domUtils.getNextDomNode(current, false, filterFn);
domUtils.remove(current);
current = tmpNode;
continue;
}
tmpNode = current;
tmpRange.setStartBefore(current);
while(current && current !== bk.end && (!block(current) || domUtils.isBookmarkNode(current))) {
tmpNode = current;
current = domUtils.getNextDomNode(current, false, null, function(node) {
return !notExchange[node.tagName];
});
}
if(current && block(current)) {
tmp = domUtils.getNextDomNode(tmpNode, false, filterFn);
if(tmp && domUtils.isBookmarkNode(tmp)) {
current = domUtils.getNextDomNode(tmp, false, filterFn);
tmpNode = tmp;
}
}
tmpRange.setEndAfter(tmpNode);
current = domUtils.getNextDomNode(tmpNode, false, filterFn);
var li = range.document.createElement('li');
li.appendChild(tmpRange.extractContents());
if(domUtils.isEmptyNode(li)) {
var tmpNode = range.document.createElement('p');
while(li.firstChild) {
tmpNode.appendChild(li.firstChild)
}
li.appendChild(tmpNode);
}
frag.appendChild(li);
} else {
current = domUtils.getNextDomNode(current, true, filterFn);
}
}
range.moveToBookmark(bk).collapse(true);
list = me.document.createElement(tag);
setListStyle(list, style);
list.appendChild(frag);
range.insertNode(list);
//当前list上下看能否合并
adjustList(list, tag, style);
//去掉冗余的tmpDiv
for(var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, 'div'); ci = tmpDivs[i++];) {
if(ci.getAttribute('tmpDiv')) {
domUtils.remove(ci, true)
}
}
range.moveToBookmark(bko).select();
},
queryCommandState: function(command) {
var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul';
var path = this.selection.getStartElementPath();
for(var i = 0, ci; ci = path[i++];) {
if(ci.nodeName == 'TABLE') {
return 0
}
if(tag == ci.nodeName.toLowerCase()) {
return 1
};
}
return 0;
},
queryCommandValue: function(command) {
var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul';
var path = this.selection.getStartElementPath(),
node;
for(var i = 0, ci; ci = path[i++];) {
if(ci.nodeName == 'TABLE') {
node = null;
break;
}
if(tag == ci.nodeName.toLowerCase()) {
node = ci;
break;
};
}
return node ? getStyle(node) || domUtils.getComputedStyle(node, 'list-style-type') : null;
}
};
};
// plugins/source.js
/**
* 源码编辑插件
* @file
* @since 1.2.6.1
*/
(function() {
var sourceEditors = {
textarea: function(editor, holder) {
var textarea = holder.ownerDocument.createElement('textarea');
textarea.style.cssText = 'position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;';
// todo: IE下只有onresize属性可用... 很纠结
if(browser.ie && browser.version < 8) {
textarea.style.width = holder.offsetWidth + 'px';
textarea.style.height = holder.offsetHeight + 'px';
holder.onresize = function() {
textarea.style.width = holder.offsetWidth + 'px';
textarea.style.height = holder.offsetHeight + 'px';
};
}
holder.appendChild(textarea);
return {
setContent: function(content) {
textarea.value = content;
},
getContent: function() {
return textarea.value;
},
select: function() {
var range;
if(browser.ie) {
range = textarea.createTextRange();
range.collapse(true);
range.select();
} else {
//todo: chrome下无法设置焦点
textarea.setSelectionRange(0, 0);
textarea.focus();
}
},
dispose: function() {
holder.removeChild(textarea);
// todo
holder.onresize = null;
textarea = null;
holder = null;
}
};
},
codemirror: function(editor, holder) {
var codeEditor = window.CodeMirror(holder, {
mode: "text/html",
tabMode: "indent",
lineNumbers: true,
lineWrapping: true
});
var dom = codeEditor.getWrapperElement();
dom.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
codeEditor.getScrollerElement().style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;';
codeEditor.refresh();
return {
getCodeMirror: function() {
return codeEditor;
},
setContent: function(content) {
codeEditor.setValue(content);
},
getContent: function() {
return codeEditor.getValue();
},
select: function() {
codeEditor.focus();
},
dispose: function() {
holder.removeChild(dom);
dom = null;
codeEditor = null;
}
};
}
};
UE.plugins['source'] = function() {
var me = this;
var opt = this.options;
var sourceMode = false;
var sourceEditor;
var orgSetContent;
opt.sourceEditor = browser.ie ? 'textarea' : (opt.sourceEditor || 'codemirror');
me.setOpt({
sourceEditorFirst: false
});
function createSourceEditor(holder) {
return sourceEditors[opt.sourceEditor == 'codemirror' && window.CodeMirror ? 'codemirror' : 'textarea'](me, holder);
}
var bakCssText;
//解决在源码模式下getContent不能得到最新的内容问题
var oldGetContent,
bakAddress;
/**
* 切换源码模式和编辑模式
* @command source
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'source');
* ```
*/
/**
* 查询当前编辑区域的状态是源码模式还是可视化模式
* @command source
* @method queryCommandState
* @param { String } cmd 命令字符串
* @return { int } 如果当前是源码编辑模式,返回1,否则返回0
* @example
* ```javascript
* editor.queryCommandState( 'source' );
* ```
*/
me.commands['source'] = {
execCommand: function() {
sourceMode = !sourceMode;
if(sourceMode) {
bakAddress = me.selection.getRange().createAddress(false, true);
me.undoManger && me.undoManger.save(true);
if(browser.gecko) {
me.body.contentEditable = false;
}
bakCssText = me.iframe.style.cssText;
me.iframe.style.cssText += 'position:absolute;left:-32768px;top:-32768px;';
me.fireEvent('beforegetcontent');
var root = UE.htmlparser(me.body.innerHTML);
me.filterOutputRule(root);
root.traversal(function(node) {
if(node.type == 'element') {
switch(node.tagName) {
case 'td':
case 'th':
case 'caption':
if(node.children && node.children.length == 1) {
if(node.firstChild().tagName == 'br') {
node.removeChild(node.firstChild())
}
};
break;
case 'pre':
node.innerText(node.innerText().replace(/ /g, ' '))
}
}
});
me.fireEvent('aftergetcontent');
var content = root.toHtml(true);
sourceEditor = createSourceEditor(me.iframe.parentNode);
sourceEditor.setContent(content);
orgSetContent = me.setContent;
me.setContent = function(html) {
//这里暂时不触发事件,防止报错
var root = UE.htmlparser(html);
me.filterInputRule(root);
html = root.toHtml();
sourceEditor.setContent(html);
};
setTimeout(function() {
sourceEditor.select();
me.addListener('fullscreenchanged', function() {
try {
sourceEditor.getCodeMirror().refresh()
} catch(e) {}
});
});
//重置getContent,源码模式下取值也能是最新的数据
oldGetContent = me.getContent;
me.getContent = function() {
return sourceEditor.getContent() || '' + (browser.ie ? '' : ' ') + ' ';
};
} else {
me.iframe.style.cssText = bakCssText;
var cont = sourceEditor.getContent() || '' + (browser.ie ? '' : ' ') + ' ';
//处理掉block节点前后的空格,有可能会误命中,暂时不考虑
cont = cont.replace(new RegExp('[\\r\\t\\n ]*<\/?(\\w+)\\s*(?:[^>]*)>', 'g'), function(a, b) {
if(b && !dtd.$inlineWithA[b.toLowerCase()]) {
return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, '');
}
return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, '')
});
me.setContent = orgSetContent;
me.setContent(cont);
sourceEditor.dispose();
sourceEditor = null;
//还原getContent方法
me.getContent = oldGetContent;
var first = me.body.firstChild;
//trace:1106 都删除空了,下边会报错,所以补充一个p占位
if(!first) {
me.body.innerHTML = '' + (browser.ie ? '' : ' ') + ' ';
first = me.body.firstChild;
}
//要在ifm为显示时ff才能取到selection,否则报错
//这里不能比较位置了
me.undoManger && me.undoManger.save(true);
if(browser.gecko) {
var input = document.createElement('input');
input.style.cssText = 'position:absolute;left:0;top:-32768px';
document.body.appendChild(input);
me.body.contentEditable = false;
setTimeout(function() {
domUtils.setViewportOffset(input, {
left: -32768,
top: 0
});
input.focus();
setTimeout(function() {
me.body.contentEditable = true;
me.selection.getRange().moveToAddress(bakAddress).select(true);
domUtils.remove(input);
});
});
} else {
//ie下有可能报错,比如在代码顶头的情况
try {
me.selection.getRange().moveToAddress(bakAddress).select(true);
} catch(e) {}
}
}
this.fireEvent('sourcemodechanged', sourceMode);
},
queryCommandState: function() {
return sourceMode | 0;
},
notNeedUndo: 1
};
var oldQueryCommandState = me.queryCommandState;
me.queryCommandState = function(cmdName) {
cmdName = cmdName.toLowerCase();
if(sourceMode) {
//源码模式下可以开启的命令
return cmdName in {
'source': 1,
'fullscreen': 1
} ? 1 : -1
}
return oldQueryCommandState.apply(this, arguments);
};
if(opt.sourceEditor == "codemirror") {
me.addListener("ready", function() {
utils.loadFile(document, {
src: opt.codeMirrorJsUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.js",
tag: "script",
type: "text/javascript",
defer: "defer"
}, function() {
if(opt.sourceEditorFirst) {
setTimeout(function() {
me.execCommand("source");
}, 0);
}
});
utils.loadFile(document, {
tag: "link",
rel: "stylesheet",
type: "text/css",
href: opt.codeMirrorCssUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.css"
});
});
}
};
})();
// plugins/enterkey.js
///import core
///import plugins/undo.js
///commands 设置回车标签p或br
///commandsName EnterKey
///commandsTitle 设置回车标签p或br
/**
* @description 处理回车
* @author zhanyi
*/
UE.plugins['enterkey'] = function() {
var hTag,
me = this,
tag = me.options.enterTag;
me.addListener('keyup', function(type, evt) {
var keyCode = evt.keyCode || evt.which;
if(keyCode == 13) {
var range = me.selection.getRange(),
start = range.startContainer,
doSave;
//修正在h1-h6里边回车后不能嵌套p的问题
if(!browser.ie) {
if(/h\d/i.test(hTag)) {
if(browser.gecko) {
var h = domUtils.findParentByTagName(start, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption', 'table'], true);
if(!h) {
me.document.execCommand('formatBlock', false, '');
doSave = 1;
}
} else {
//chrome remove div
if(start.nodeType == 1) {
var tmp = me.document.createTextNode(''),
div;
range.insertNode(tmp);
div = domUtils.findParentByTagName(tmp, 'div', true);
if(div) {
var p = me.document.createElement('p');
while(div.firstChild) {
p.appendChild(div.firstChild);
}
div.parentNode.insertBefore(p, div);
domUtils.remove(div);
range.setStartBefore(tmp).setCursor();
doSave = 1;
}
domUtils.remove(tmp);
}
}
if(me.undoManger && doSave) {
me.undoManger.save();
}
}
//没有站位符,会出现多行的问题
browser.opera && range.select();
} else {
me.fireEvent('saveScene', true, true)
}
}
});
me.addListener('keydown', function(type, evt) {
var keyCode = evt.keyCode || evt.which;
if(keyCode == 13) { //回车
if(me.fireEvent('beforeenterkeydown')) {
domUtils.preventDefault(evt);
return;
}
me.fireEvent('saveScene', true, true);
hTag = '';
var range = me.selection.getRange();
if(!range.collapsed) {
//跨td不能删
var start = range.startContainer,
end = range.endContainer,
startTd = domUtils.findParentByTagName(start, 'td', true),
endTd = domUtils.findParentByTagName(end, 'td', true);
if(startTd && endTd && startTd !== endTd || !startTd && endTd || startTd && !endTd) {
evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
return;
}
}
if(tag == 'p') {
if(!browser.ie) {
start = domUtils.findParentByTagName(range.startContainer, ['ol', 'ul', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption'], true);
//opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
//trace:2431
if(!start && !browser.opera) {
me.document.execCommand('formatBlock', false, ' ');
if(browser.gecko) {
range = me.selection.getRange();
start = domUtils.findParentByTagName(range.startContainer, 'p', true);
start && domUtils.removeDirtyAttr(start);
}
} else {
hTag = start.tagName;
start.tagName.toLowerCase() == 'p' && browser.gecko && domUtils.removeDirtyAttr(start);
}
}
} else {
evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
if(!range.collapsed) {
range.deleteContents();
start = range.startContainer;
if(start.nodeType == 1 && (start = start.childNodes[range.startOffset])) {
while(start.nodeType == 1) {
if(dtd.$empty[start.tagName]) {
range.setStartBefore(start).setCursor();
if(me.undoManger) {
me.undoManger.save();
}
return false;
}
if(!start.firstChild) {
var br = range.document.createElement('br');
start.appendChild(br);
range.setStart(start, 0).setCursor();
if(me.undoManger) {
me.undoManger.save();
}
return false;
}
start = start.firstChild;
}
if(start === range.startContainer.childNodes[range.startOffset]) {
br = range.document.createElement('br');
range.insertNode(br).setCursor();
} else {
range.setStart(start, 0).setCursor();
}
} else {
br = range.document.createElement('br');
range.insertNode(br).setStartAfter(br).setCursor();
}
} else {
br = range.document.createElement('br');
range.insertNode(br);
var parent = br.parentNode;
if(parent.lastChild === br) {
br.parentNode.insertBefore(br.cloneNode(true), br);
range.setStartBefore(br);
} else {
range.setStartAfter(br);
}
range.setCursor();
}
}
}
});
};
// plugins/keystrokes.js
/* 处理特殊键的兼容性问题 */
UE.plugins['keystrokes'] = function() {
var me = this;
var collapsed = true;
me.addListener('keydown', function(type, evt) {
var keyCode = evt.keyCode || evt.which,
rng = me.selection.getRange();
//处理全选的情况
if(!rng.collapsed && !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) && (keyCode >= 65 && keyCode <= 90 ||
keyCode >= 48 && keyCode <= 57 ||
keyCode >= 96 && keyCode <= 111 || {
13: 1,
8: 1,
46: 1
}[keyCode])) {
var tmpNode = rng.startContainer;
if(domUtils.isFillChar(tmpNode)) {
rng.setStartBefore(tmpNode)
}
tmpNode = rng.endContainer;
if(domUtils.isFillChar(tmpNode)) {
rng.setEndAfter(tmpNode)
}
rng.txtToElmBoundary();
//结束边界可能放到了br的前边,要把br包含进来
// x[xxx]
if(rng.endContainer && rng.endContainer.nodeType == 1) {
tmpNode = rng.endContainer.childNodes[rng.endOffset];
if(tmpNode && domUtils.isBr(tmpNode)) {
rng.setEndAfter(tmpNode);
}
}
if(rng.startOffset == 0) {
tmpNode = rng.startContainer;
if(domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
tmpNode = rng.endContainer;
if(rng.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode, 'lastChild')) {
me.fireEvent('saveScene');
me.body.innerHTML = ' ' + (browser.ie ? '' : ' ') + ' ';
rng.setStart(me.body.firstChild, 0).setCursor(false, true);
me._selectionChange();
return;
}
}
}
}
//处理backspace
if(keyCode == keymap.Backspace) {
rng = me.selection.getRange();
collapsed = rng.collapsed;
if(me.fireEvent('delkeydown', evt)) {
return;
}
var start, end;
//避免按两次删除才能生效的问题
if(rng.collapsed && rng.inFillChar()) {
start = rng.startContainer;
if(domUtils.isFillChar(start)) {
rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
domUtils.remove(start)
} else {
start.nodeValue = start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), '');
rng.startOffset--;
rng.collapse(true).select(true)
}
}
//解决选中control元素不能删除的问题
if(start = rng.getClosedNode()) {
me.fireEvent('saveScene');
rng.setStartBefore(start);
domUtils.remove(start);
rng.setCursor();
me.fireEvent('saveScene');
domUtils.preventDefault(evt);
return;
}
//阻止在table上的删除
if(!browser.ie) {
start = domUtils.findParentByTagName(rng.startContainer, 'table', true);
end = domUtils.findParentByTagName(rng.endContainer, 'table', true);
if(start && !end || !start && end || start !== end) {
evt.preventDefault();
return;
}
}
}
//处理tab键的逻辑
if(keyCode == keymap.Tab) {
//不处理以下标签
var excludeTagNameForTabKey = {
'ol': 1,
'ul': 1,
'table': 1
};
//处理组件里的tab按下事件
if(me.fireEvent('tabkeydown', evt)) {
domUtils.preventDefault(evt);
return;
}
var range = me.selection.getRange();
me.fireEvent('saveScene');
for(var i = 0, txt = '', tabSize = me.options.tabSize || 4, tabNode = me.options.tabNode || ' '; i < tabSize; i++) {
txt += tabNode;
}
var span = me.document.createElement('span');
span.innerHTML = txt + domUtils.fillChar;
if(range.collapsed) {
range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
} else {
var filterFn = function(node) {
return domUtils.isBlockElm(node) && !excludeTagNameForTabKey[node.tagName.toLowerCase()]
};
//普通的情况
start = domUtils.findParent(range.startContainer, filterFn, true);
end = domUtils.findParent(range.endContainer, filterFn, true);
if(start && end && start === end) {
range.deleteContents();
range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
} else {
var bookmark = range.createBookmark();
range.enlarge(true);
var bookmark2 = range.createBookmark(),
current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
while(current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
current.insertBefore(span.cloneNode(true).firstChild, current.firstChild);
current = domUtils.getNextDomNode(current, false, filterFn);
}
range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select();
}
}
domUtils.preventDefault(evt)
}
//trace:1634
//ff的del键在容器空的时候,也会删除
if(browser.gecko && keyCode == 46) {
range = me.selection.getRange();
if(range.collapsed) {
start = range.startContainer;
if(domUtils.isEmptyBlock(start)) {
var parent = start.parentNode;
while(domUtils.getChildCount(parent) == 1 && !domUtils.isBody(parent)) {
start = parent;
parent = parent.parentNode;
}
if(start === parent.lastChild)
evt.preventDefault();
return;
}
}
}
});
me.addListener('keyup', function(type, evt) {
var keyCode = evt.keyCode || evt.which,
rng, me = this;
if(keyCode == keymap.Backspace) {
if(me.fireEvent('delkeyup')) {
return;
}
rng = me.selection.getRange();
if(rng.collapsed) {
var tmpNode,
autoClearTagName = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
if(tmpNode = domUtils.findParentByTagName(rng.startContainer, autoClearTagName, true)) {
if(domUtils.isEmptyBlock(tmpNode)) {
var pre = tmpNode.previousSibling;
if(pre && pre.nodeName != 'TABLE') {
domUtils.remove(tmpNode);
rng.setStartAtLast(pre).setCursor(false, true);
return;
} else {
var next = tmpNode.nextSibling;
if(next && next.nodeName != 'TABLE') {
domUtils.remove(tmpNode);
rng.setStartAtFirst(next).setCursor(false, true);
return;
}
}
}
}
//处理当删除到body时,要重新给p标签展位
if(domUtils.isBody(rng.startContainer)) {
var tmpNode = domUtils.createElement(me.document, 'p', {
'innerHTML': browser.ie ? domUtils.fillChar : ' '
});
rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true);
}
}
//chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
if(!collapsed && (rng.startContainer.nodeType == 3 || rng.startContainer.nodeType == 1 && domUtils.isEmptyBlock(rng.startContainer))) {
if(browser.ie) {
var span = rng.document.createElement('span');
rng.insertNode(span).setStartBefore(span).collapse(true);
rng.select();
domUtils.remove(span)
} else {
rng.select()
}
}
}
})
};
// plugins/fiximgclick.js
///import core
///commands 修复chrome下图片不能点击的问题,出现八个角可改变大小
///commandsName FixImgClick
///commandsTitle 修复chrome下图片不能点击的问题,出现八个角可改变大小
//修复chrome下图片不能点击的问题,出现八个角可改变大小
UE.plugins['fiximgclick'] = (function() {
var elementUpdated = false;
function Scale() {
this.editor = null;
this.resizer = null;
this.cover = null;
this.doc = document;
this.prePos = {
x: 0,
y: 0
};
this.startPos = {
x: 0,
y: 0
};
}
(function() {
var rect = [
//[left, top, width, height]
[0, 0, -1, -1],
[0, 0, 0, -1],
[0, 0, 1, -1],
[0, 0, -1, 0],
[0, 0, 1, 0],
[0, 0, -1, 1],
[0, 0, 0, 1],
[0, 0, 1, 1]
];
Scale.prototype = {
init: function(editor) {
var me = this;
me.editor = editor;
me.startPos = this.prePos = {
x: 0,
y: 0
};
me.dragId = -1;
var hands = [],
cover = me.cover = document.createElement('div'),
resizer = me.resizer = document.createElement('div');
cover.id = me.editor.ui.id + '_imagescale_cover';
cover.style.cssText = 'position:absolute;display:none;z-index:' + (me.editor.options.zIndex) + ';filter:alpha(opacity=0); opacity:0;background:#CCC;';
domUtils.on(cover, 'mousedown click', function() {
me.hide();
});
for(i = 0; i < 8; i++) {
hands.push('');
}
resizer.id = me.editor.ui.id + '_imagescale';
resizer.className = 'edui-editor-imagescale';
resizer.innerHTML = hands.join('');
resizer.style.cssText += ';display:none;border:1px solid #3b77ff;z-index:' + (me.editor.options.zIndex) + ';';
me.editor.ui.getDom().appendChild(cover);
me.editor.ui.getDom().appendChild(resizer);
me.initStyle();
me.initEvents();
},
initStyle: function() {
utils.cssRule('imagescale', '.edui-editor-imagescale{display:none;position:absolute;border:1px solid #38B2CE;cursor:hand;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;}' +
'.edui-editor-imagescale span{position:absolute;width:6px;height:6px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}' +
'.edui-editor-imagescale .edui-editor-imagescale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}');
},
initEvents: function() {
var me = this;
me.startPos.x = me.startPos.y = 0;
me.isDraging = false;
},
_eventHandler: function(e) {
var me = this;
switch(e.type) {
case 'mousedown':
var hand = e.target || e.srcElement,
hand;
if(hand.className.indexOf('edui-editor-imagescale-hand') != -1 && me.dragId == -1) {
me.dragId = hand.className.slice(-1);
me.startPos.x = me.prePos.x = e.clientX;
me.startPos.y = me.prePos.y = e.clientY;
domUtils.on(me.doc, 'mousemove', me.proxy(me._eventHandler, me));
}
break;
case 'mousemove':
if(me.dragId != -1) {
me.updateContainerStyle(me.dragId, {
x: e.clientX - me.prePos.x,
y: e.clientY - me.prePos.y
});
me.prePos.x = e.clientX;
me.prePos.y = e.clientY;
elementUpdated = true;
me.updateTargetElement();
}
break;
case 'mouseup':
if(me.dragId != -1) {
me.updateContainerStyle(me.dragId, {
x: e.clientX - me.prePos.x,
y: e.clientY - me.prePos.y
});
me.updateTargetElement();
if(me.target.parentNode) me.attachTo(me.target);
me.dragId = -1;
}
domUtils.un(me.doc, 'mousemove', me.proxy(me._eventHandler, me));
//修复只是点击挪动点,但没有改变大小,不应该触发contentchange
if(elementUpdated) {
elementUpdated = false;
me.editor.fireEvent('contentchange');
}
break;
default:
break;
}
},
updateTargetElement: function() {
var me = this;
domUtils.setStyles(me.target, {
'width': me.resizer.style.width,
'height': me.resizer.style.height
});
me.target.width = parseInt(me.resizer.style.width);
me.target.height = parseInt(me.resizer.style.height);
me.attachTo(me.target);
},
updateContainerStyle: function(dir, offset) {
var me = this,
dom = me.resizer,
tmp;
if(rect[dir][0] != 0) {
tmp = parseInt(dom.style.left) + offset.x;
dom.style.left = me._validScaledProp('left', tmp) + 'px';
}
if(rect[dir][1] != 0) {
tmp = parseInt(dom.style.top) + offset.y;
dom.style.top = me._validScaledProp('top', tmp) + 'px';
}
if(rect[dir][2] != 0) {
tmp = dom.clientWidth + rect[dir][2] * offset.x;
dom.style.width = me._validScaledProp('width', tmp) + 'px';
}
if(rect[dir][3] != 0) {
tmp = dom.clientHeight + rect[dir][3] * offset.y;
dom.style.height = me._validScaledProp('height', tmp) + 'px';
}
},
_validScaledProp: function(prop, value) {
var ele = this.resizer,
wrap = document;
value = isNaN(value) ? 0 : value;
switch(prop) {
case 'left':
return value < 0 ? 0 : (value + ele.clientWidth) > wrap.clientWidth ? wrap.clientWidth - ele.clientWidth : value;
case 'top':
return value < 0 ? 0 : (value + ele.clientHeight) > wrap.clientHeight ? wrap.clientHeight - ele.clientHeight : value;
case 'width':
return value <= 0 ? 1 : (value + ele.offsetLeft) > wrap.clientWidth ? wrap.clientWidth - ele.offsetLeft : value;
case 'height':
return value <= 0 ? 1 : (value + ele.offsetTop) > wrap.clientHeight ? wrap.clientHeight - ele.offsetTop : value;
}
},
hideCover: function() {
this.cover.style.display = 'none';
},
showCover: function() {
var me = this,
editorPos = domUtils.getXY(me.editor.ui.getDom()),
iframePos = domUtils.getXY(me.editor.iframe);
domUtils.setStyles(me.cover, {
'width': me.editor.iframe.offsetWidth + 'px',
'height': me.editor.iframe.offsetHeight + 'px',
'top': iframePos.y - editorPos.y + 'px',
'left': iframePos.x - editorPos.x + 'px',
'position': 'absolute',
'display': ''
})
},
show: function(targetObj) {
var me = this;
me.resizer.style.display = 'block';
if(targetObj) me.attachTo(targetObj);
domUtils.on(this.resizer, 'mousedown', me.proxy(me._eventHandler, me));
domUtils.on(me.doc, 'mouseup', me.proxy(me._eventHandler, me));
me.showCover();
me.editor.fireEvent('afterscaleshow', me);
me.editor.fireEvent('saveScene');
},
hide: function() {
var me = this;
me.hideCover();
me.resizer.style.display = 'none';
domUtils.un(me.resizer, 'mousedown', me.proxy(me._eventHandler, me));
domUtils.un(me.doc, 'mouseup', me.proxy(me._eventHandler, me));
me.editor.fireEvent('afterscalehide', me);
},
proxy: function(fn, context) {
return function(e) {
return fn.apply(context || this, arguments);
};
},
attachTo: function(targetObj) {
var me = this,
target = me.target = targetObj,
resizer = this.resizer,
imgPos = domUtils.getXY(target),
iframePos = domUtils.getXY(me.editor.iframe),
editorPos = domUtils.getXY(resizer.parentNode);
domUtils.setStyles(resizer, {
'width': target.width + 'px',
'height': target.height + 'px',
'left': iframePos.x + imgPos.x - me.editor.document.body.scrollLeft - editorPos.x - parseInt(resizer.style.borderLeftWidth) + 'px',
'top': iframePos.y + imgPos.y - me.editor.document.body.scrollTop - editorPos.y - parseInt(resizer.style.borderTopWidth) + 'px'
});
}
}
})();
return function() {
var me = this,
imageScale;
me.setOpt('imageScaleEnabled', true);
if(!browser.ie && me.options.imageScaleEnabled) {
me.addListener('click', function(type, e) {
var range = me.selection.getRange(),
img = range.getClosedNode();
if(img && img.tagName == 'IMG' && me.body.contentEditable != "false") {
if(img.className.indexOf("edui-faked-music") != -1 ||
img.getAttribute("anchorname") ||
domUtils.hasClass(img, 'loadingclass') ||
domUtils.hasClass(img, 'loaderrorclass')) {
return
}
if(!imageScale) {
imageScale = new Scale();
imageScale.init(me);
me.ui.getDom().appendChild(imageScale.resizer);
var _keyDownHandler = function(e) {
imageScale.hide();
if(imageScale.target) me.selection.getRange().selectNode(imageScale.target).select();
},
_mouseDownHandler = function(e) {
var ele = e.target || e.srcElement;
if(ele && (ele.className === undefined || ele.className.indexOf('edui-editor-imagescale') == -1)) {
_keyDownHandler(e);
}
},
timer;
me.addListener('afterscaleshow', function(e) {
me.addListener('beforekeydown', _keyDownHandler);
me.addListener('beforemousedown', _mouseDownHandler);
domUtils.on(document, 'keydown', _keyDownHandler);
domUtils.on(document, 'mousedown', _mouseDownHandler);
me.selection.getNative().removeAllRanges();
});
me.addListener('afterscalehide', function(e) {
me.removeListener('beforekeydown', _keyDownHandler);
me.removeListener('beforemousedown', _mouseDownHandler);
domUtils.un(document, 'keydown', _keyDownHandler);
domUtils.un(document, 'mousedown', _mouseDownHandler);
var target = imageScale.target;
if(target.parentNode) {
me.selection.getRange().selectNode(target).select();
}
});
//TODO 有iframe的情况,mousedown不能往下传。。
domUtils.on(imageScale.resizer, 'mousedown', function(e) {
me.selection.getNative().removeAllRanges();
var ele = e.target || e.srcElement;
if(ele && ele.className.indexOf('edui-editor-imagescale-hand') == -1) {
timer = setTimeout(function() {
imageScale.hide();
if(imageScale.target) me.selection.getRange().selectNode(ele).select();
}, 200);
}
});
domUtils.on(imageScale.resizer, 'mouseup', function(e) {
var ele = e.target || e.srcElement;
if(ele && ele.className.indexOf('edui-editor-imagescale-hand') == -1) {
clearTimeout(timer);
}
});
}
imageScale.show(img);
} else {
if(imageScale && imageScale.resizer.style.display != 'none') imageScale.hide();
}
});
}
if(browser.webkit) {
me.addListener('click', function(type, e) {
if(e.target.tagName == 'IMG' && me.body.contentEditable != "false") {
var range = new dom.Range(me.document);
range.selectNode(e.target).select();
}
});
}
}
})();
// plugins/autolink.js
///import core
///commands 为非ie浏览器自动添加a标签
///commandsName AutoLink
///commandsTitle 自动增加链接
/**
* @description 为非ie浏览器自动添加a标签
* @author zhanyi
*/
UE.plugin.register('autolink', function() {
var cont = 0;
return !browser.ie ? {
bindEvents: {
'reset': function() {
cont = 0;
},
'keydown': function(type, evt) {
var me = this;
var keyCode = evt.keyCode || evt.which;
if(keyCode == 32 || keyCode == 13) {
var sel = me.selection.getNative(),
range = sel.getRangeAt(0).cloneRange(),
offset,
charCode;
var start = range.startContainer;
while(start.nodeType == 1 && range.startOffset > 0) {
start = range.startContainer.childNodes[range.startOffset - 1];
if(!start) {
break;
}
range.setStart(start, start.nodeType == 1 ? start.childNodes.length : start.nodeValue.length);
range.collapse(true);
start = range.startContainer;
}
do {
if(range.startOffset == 0) {
start = range.startContainer.previousSibling;
while(start && start.nodeType == 1) {
start = start.lastChild;
}
if(!start || domUtils.isFillChar(start)) {
break;
}
offset = start.nodeValue.length;
} else {
start = range.startContainer;
offset = range.startOffset;
}
range.setStart(start, offset - 1);
charCode = range.toString().charCodeAt(0);
} while (charCode != 160 && charCode != 32);
if(range.toString().replace(new RegExp(domUtils.fillChar, 'g'), '').match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)) {
while(range.toString().length) {
if(/^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(range.toString())) {
break;
}
try {
range.setStart(range.startContainer, range.startOffset + 1);
} catch(e) {
//trace:2121
var start = range.startContainer;
while(!(next = start.nextSibling)) {
if(domUtils.isBody(start)) {
return;
}
start = start.parentNode;
}
range.setStart(next, 0);
}
}
//range的开始边界已经在a标签里的不再处理
if(domUtils.findParentByTagName(range.startContainer, 'a', true)) {
return;
}
var a = me.document.createElement('a'),
text = me.document.createTextNode(' '),
href;
me.undoManger && me.undoManger.save();
a.appendChild(range.extractContents());
a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, '');
href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar, 'g'), '');
href = /^(?:https?:\/\/)/ig.test(href) ? href : "http://" + href;
a.setAttribute('_src', utils.html(href));
a.href = utils.html(href);
range.insertNode(a);
a.parentNode.insertBefore(text, a.nextSibling);
range.setStart(text, 0);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
me.undoManger && me.undoManger.save();
}
}
}
}
} : {}
}, function() {
var keyCodes = {
37: 1,
38: 1,
39: 1,
40: 1,
13: 1,
32: 1
};
function checkIsCludeLink(node) {
if(node.nodeType == 3) {
return null
}
if(node.nodeName == 'A') {
return node;
}
var lastChild = node.lastChild;
while(lastChild) {
if(lastChild.nodeName == 'A') {
return lastChild;
}
if(lastChild.nodeType == 3) {
if(domUtils.isWhitespace(lastChild)) {
lastChild = lastChild.previousSibling;
continue;
}
return null
}
lastChild = lastChild.lastChild;
}
}
browser.ie && this.addListener('keyup', function(cmd, evt) {
var me = this,
keyCode = evt.keyCode;
if(keyCodes[keyCode]) {
var rng = me.selection.getRange();
var start = rng.startContainer;
if(keyCode == 13) {
while(start && !domUtils.isBody(start) && !domUtils.isBlockElm(start)) {
start = start.parentNode;
}
if(start && !domUtils.isBody(start) && start.nodeName == 'P') {
var pre = start.previousSibling;
if(pre && pre.nodeType == 1) {
var pre = checkIsCludeLink(pre);
if(pre && !pre.getAttribute('_href')) {
domUtils.remove(pre, true);
}
}
}
} else if(keyCode == 32) {
if(start.nodeType == 3 && /^\s$/.test(start.nodeValue)) {
start = start.previousSibling;
if(start && start.nodeName == 'A' && !start.getAttribute('_href')) {
domUtils.remove(start, true);
}
}
} else {
start = domUtils.findParentByTagName(start, 'a', true);
if(start && !start.getAttribute('_href')) {
var bk = rng.createBookmark();
domUtils.remove(start, true);
rng.moveToBookmark(bk).select(true)
}
}
}
});
});
// plugins/autoheight.js
///import core
///commands 当输入内容超过编辑器高度时,编辑器自动增高
///commandsName AutoHeight,autoHeightEnabled
///commandsTitle 自动增高
/**
* @description 自动伸展
* @author zhanyi
*/
UE.plugins['autoheight'] = function() {
var me = this;
//提供开关,就算加载也可以关闭
me.autoHeightEnabled = me.options.autoHeightEnabled !== false;
if(!me.autoHeightEnabled) {
return;
}
var bakOverflow,
lastHeight = 0,
options = me.options,
currentHeight,
timer;
function adjustHeight() {
var me = this;
clearTimeout(timer);
if(isFullscreen) return;
if(!me.queryCommandState || me.queryCommandState && me.queryCommandState('source') != 1) {
timer = setTimeout(function() {
var node = me.body.lastChild;
while(node && node.nodeType != 1) {
node = node.previousSibling;
}
if(node && node.nodeType == 1) {
node.style.clear = 'both';
currentHeight = Math.max(domUtils.getXY(node).y + node.offsetHeight + 25, Math.max(options.minFrameHeight, options.initialFrameHeight));
if(currentHeight != lastHeight) {
if(currentHeight !== parseInt(me.iframe.parentNode.style.height)) {
me.iframe.parentNode.style.height = currentHeight + 'px';
}
me.body.style.height = currentHeight + 'px';
lastHeight = currentHeight;
}
domUtils.removeStyle(node, 'clear');
}
}, 50)
}
}
var isFullscreen;
me.addListener('fullscreenchanged', function(cmd, f) {
isFullscreen = f
});
me.addListener('destroy', function() {
me.removeListener('contentchange afterinserthtml keyup mouseup', adjustHeight)
});
me.enableAutoHeight = function() {
var me = this;
if(!me.autoHeightEnabled) {
return;
}
var doc = me.document;
me.autoHeightEnabled = true;
bakOverflow = doc.body.style.overflowY;
doc.body.style.overflowY = 'hidden';
me.addListener('contentchange afterinserthtml keyup mouseup', adjustHeight);
//ff不给事件算得不对
setTimeout(function() {
adjustHeight.call(me);
}, browser.gecko ? 100 : 0);
me.fireEvent('autoheightchanged', me.autoHeightEnabled);
};
me.disableAutoHeight = function() {
me.body.style.overflowY = bakOverflow || '';
me.removeListener('contentchange', adjustHeight);
me.removeListener('keyup', adjustHeight);
me.removeListener('mouseup', adjustHeight);
me.autoHeightEnabled = false;
me.fireEvent('autoheightchanged', me.autoHeightEnabled);
};
me.on('setHeight', function() {
me.disableAutoHeight()
});
me.addListener('ready', function() {
me.enableAutoHeight();
//trace:1764
var timer;
domUtils.on(browser.ie ? me.body : me.document, browser.webkit ? 'dragover' : 'drop', function() {
clearTimeout(timer);
timer = setTimeout(function() {
//trace:3681
adjustHeight.call(me);
}, 100);
});
//修复内容过多时,回到顶部,顶部内容被工具栏遮挡问题
var lastScrollY;
window.onscroll = function() {
if(lastScrollY === null) {
lastScrollY = this.scrollY
} else if(this.scrollY == 0 && lastScrollY != 0) {
me.window.scrollTo(0, 0);
lastScrollY = null;
}
}
});
};
// plugins/autofloat.js
///import core
///commands 悬浮工具栏
///commandsName AutoFloat,autoFloatEnabled
///commandsTitle 悬浮工具栏
/**
* modified by chengchao01
* 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
*/
UE.plugins['autofloat'] = function() {
var me = this,
lang = me.getLang();
me.setOpt({
topOffset: 0
});
var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
topOffset = me.options.topOffset;
//如果不固定toolbar的位置,则直接退出
if(!optsAutoFloatEnabled) {
return;
}
var uiUtils = UE.ui.uiUtils,
LteIE6 = browser.ie && browser.version <= 6,
quirks = browser.quirks;
function checkHasUI() {
if(!UE.ui) {
alert(lang.autofloatMsg);
return 0;
}
return 1;
}
function fixIE6FixedPos() {
var docStyle = document.body.style;
docStyle.backgroundImage = 'url("about:blank")';
docStyle.backgroundAttachment = 'fixed';
}
var bakCssText,
placeHolder = document.createElement('div'),
toolbarBox, orgTop,
getPosition,
flag = true; //ie7模式下需要偏移
function setFloating() {
var toobarBoxPos = domUtils.getXY(toolbarBox),
origalFloat = domUtils.getComputedStyle(toolbarBox, 'position'),
origalLeft = domUtils.getComputedStyle(toolbarBox, 'left');
toolbarBox.style.width = toolbarBox.offsetWidth + 'px';
toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
if(LteIE6 || (quirks && browser.ie)) {
if(toolbarBox.style.position != 'absolute') {
toolbarBox.style.position = 'absolute';
}
toolbarBox.style.top = (document.body.scrollTop || document.documentElement.scrollTop) - orgTop + topOffset + 'px';
} else {
if(browser.ie7Compat && flag) {
flag = false;
toolbarBox.style.left = domUtils.getXY(toolbarBox).x - document.documentElement.getBoundingClientRect().left + 2 + 'px';
}
if(toolbarBox.style.position != 'fixed') {
toolbarBox.style.position = 'fixed';
toolbarBox.style.top = topOffset + "px";
((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px');
}
}
}
function unsetFloating() {
flag = true;
if(placeHolder.parentNode) {
placeHolder.parentNode.removeChild(placeHolder);
}
toolbarBox.style.cssText = bakCssText;
}
function updateFloating() {
var rect3 = getPosition(me.container);
var offset = me.options.toolbarTopOffset || 0;
if(rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
setFloating();
} else {
unsetFloating();
}
}
var defer_updateFloating = utils.defer(function() {
updateFloating();
}, browser.ie ? 200 : 100, true);
me.addListener('destroy', function() {
domUtils.un(window, ['scroll', 'resize'], updateFloating);
me.removeListener('keydown', defer_updateFloating);
});
me.addListener('ready', function() {
if(checkHasUI(me)) {
//加载了ui组件,但在new时,没有加载ui,导致编辑器实例上没有ui类,所以这里做判断
if(!me.ui) {
return;
}
getPosition = uiUtils.getClientRect;
toolbarBox = me.ui.getDom('toolbarbox');
orgTop = getPosition(toolbarBox).top;
bakCssText = toolbarBox.style.cssText;
placeHolder.style.height = toolbarBox.offsetHeight + 'px';
if(LteIE6) {
fixIE6FixedPos();
}
domUtils.on(window, ['scroll', 'resize'], updateFloating);
me.addListener('keydown', defer_updateFloating);
me.addListener('beforefullscreenchange', function(t, enabled) {
if(enabled) {
unsetFloating();
}
});
me.addListener('fullscreenchanged', function(t, enabled) {
if(!enabled) {
updateFloating();
}
});
me.addListener('sourcemodechanged', function(t, enabled) {
setTimeout(function() {
updateFloating();
}, 0);
});
me.addListener("clearDoc", function() {
setTimeout(function() {
updateFloating();
}, 0);
})
}
});
};
// plugins/video.js
/**
* video插件, 为UEditor提供视频插入支持
* @file
* @since 1.2.6.1
*/
UE.plugins['video'] = function() {
var me = this;
/**
* 创建插入视频字符窜
* @param url 视频地址
* @param width 视频宽度
* @param height 视频高度
* @param align 视频对齐
* @param toEmbed 是否以flash代替显示
* @param addParagraph 是否需要添加P 标签
*/
function creatInsertStr(url, width, height, id, align, classname, type) {
url = utils.unhtmlForUrl(url);
align = utils.unhtml(align);
classname = utils.unhtml(classname);
width = parseInt(width, 10) || 0;
height = parseInt(height, 10) || 0;
var str;
switch(type) {
case 'image':
str = ' '
break;
case 'embed':
str = ' |