]/.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
}
//如果结束是文本,就有可能丢掉,所以这里手动判断一下
//例如 sdfsdfsdf sdfsdfsdfsdf
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
* //插入后的效果 xxxCC xxx
* //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(/"|\(|\)/gi, '')
} else {
url = su != 'none' ? su.replace(/url\("?|"?\)/gi, '') : ''
}
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/gi, hh)
.replace(/ii/gi, ii)
.replace(/ss/gi, 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/gi, yyyy)
.replace(/yy/gi, yy)
.replace(/mm/gi, mm)
.replace(/dd/gi, 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.]*/gi, '')
}
}
}
}
// 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 + '|', '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?:\/\/)/gi.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).trim()
width = parseInt(width, 10) || 0
height = parseInt(height, 10) || 0
var str
switch (type) {
case 'image':
str =
' '
break
case 'embed':
str =
''
break
case 'video':
var ext = url.substr(url.lastIndexOf('.') + 1)
if (ext == 'ogv') ext = 'ogg'
str =
'' +
' '
break
}
return str
}
function switchImgAndVideo(root, img2video) {
utils.each(
root.getNodesByTagName(img2video ? 'img' : 'embed video'),
function (node) {
var className = node.getAttr('class')
if (className && className.indexOf('edui-faked-video') != -1) {
var html = creatInsertStr(
img2video ? node.getAttr('_url') : node.getAttr('src'),
node.getAttr('width'),
node.getAttr('height'),
null,
node.getStyle('float') || '',
className,
img2video ? 'embed' : 'image'
)
node.parentNode.replaceChild(UE.uNode.createElement(html), node)
}
if (className && className.indexOf('edui-upload-video') != -1) {
var html = creatInsertStr(
img2video ? node.getAttr('_url') : node.getAttr('src'),
node.getAttr('width'),
node.getAttr('height'),
null,
node.getStyle('float') || '',
className,
img2video ? 'video' : 'image'
)
node.parentNode.replaceChild(UE.uNode.createElement(html), node)
}
}
)
}
me.addOutputRule(function (root) {
switchImgAndVideo(root, true)
})
me.addInputRule(function (root) {
switchImgAndVideo(root)
})
/**
* 插入视频
* @command insertvideo
* @method execCommand
* @param { String } cmd 命令字符串
* @param { Object } videoAttr 键值对对象, 描述一个视频的所有属性
* @example
* ```javascript
*
* var videoAttr = {
* //视频地址
* url: 'http://www.youku.com/xxx',
* //视频宽高值, 单位px
* width: 200,
* height: 100
* };
*
* //editor 是编辑器实例
* //向编辑器插入单个视频
* editor.execCommand( 'insertvideo', videoAttr );
* ```
*/
/**
* 插入视频
* @command insertvideo
* @method execCommand
* @param { String } cmd 命令字符串
* @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性
* @example
* ```javascript
*
* var videoAttr1 = {
* //视频地址
* url: 'http://www.youku.com/xxx',
* //视频宽高值, 单位px
* width: 200,
* height: 100
* },
* videoAttr2 = {
* //视频地址
* url: 'http://www.youku.com/xxx',
* //视频宽高值, 单位px
* width: 200,
* height: 100
* }
*
* //editor 是编辑器实例
* //该方法将会向编辑器内插入两个视频
* editor.execCommand( 'insertvideo', [ videoAttr1, videoAttr2 ] );
* ```
*/
/**
* 查询当前光标所在处是否是一个视频
* @command insertvideo
* @method queryCommandState
* @param { String } cmd 需要查询的命令字符串
* @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0
* @example
* ```javascript
*
* //editor 是编辑器实例
* editor.queryCommandState( 'insertvideo' );
* ```
*/
me.commands['insertvideo'] = {
execCommand: function (cmd, videoObjs, type) {
videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs]
var html = [],
id = 'tmpVedio',
cl
for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
vi = videoObjs[i]
cl =
type == 'upload'
? 'edui-upload-video video-js vjs-default-skin'
: 'edui-faked-video'
html.push(
creatInsertStr(
vi.url,
vi.width || 420,
vi.height || 280,
id + i,
null,
cl,
'image'
)
)
}
me.execCommand('inserthtml', html.join(''), true)
var rng = this.selection.getRange()
for (var i = 0, len = videoObjs.length; i < len; i++) {
var img = this.document.getElementById('tmpVedio' + i)
domUtils.removeAttributes(img, 'id')
rng.selectNode(img).select()
me.execCommand('imagefloat', videoObjs[i].align)
}
},
queryCommandState: function () {
var img = me.selection.getRange().getClosedNode(),
flag =
img &&
(img.className == 'edui-faked-video' ||
img.className.indexOf('edui-upload-video') != -1)
return flag ? 1 : 0
}
}
}
// plugins/table.core.js
/**
* Created with JetBrains WebStorm.
* User: taoqili
* Date: 13-1-18
* Time: 上午11:09
* To change this template use File | Settings | File Templates.
*/
/**
* UE表格操作类
* @param table
* @constructor
*/
;(function () {
var UETable = (UE.UETable = function (table) {
this.table = table
this.indexTable = []
this.selectedTds = []
this.cellsRange = {}
this.update(table)
})
//===以下为静态工具方法===
UETable.removeSelectedClass = function (cells) {
utils.each(cells, function (cell) {
domUtils.removeClasses(cell, 'selectTdClass')
})
}
UETable.addSelectedClass = function (cells) {
utils.each(cells, function (cell) {
domUtils.addClass(cell, 'selectTdClass')
})
}
UETable.isEmptyBlock = function (node) {
var reg = new RegExp(domUtils.fillChar, 'g')
if (
node[browser.ie ? 'innerText' : 'textContent']
.replace(/^\s*$/, '')
.replace(reg, '').length > 0
) {
return 0
}
for (var i in dtd.$isNotEmpty)
if (dtd.$isNotEmpty.hasOwnProperty(i)) {
if (node.getElementsByTagName(i).length) {
return 0
}
}
return 1
}
UETable.getWidth = function (cell) {
if (!cell) return 0
return parseInt(domUtils.getComputedStyle(cell, 'width'), 10)
}
/**
* 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
* 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态;
* @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
* @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
*/
UETable.getTableCellAlignState = function (cells) {
!utils.isArray(cells) && (cells = [cells])
var result = {},
status = ['align', 'valign'],
tempStatus = null,
isSame = true //状态是否相同
utils.each(cells, function (cellNode) {
utils.each(status, function (currentState) {
tempStatus = cellNode.getAttribute(currentState)
if (!result[currentState] && tempStatus) {
result[currentState] = tempStatus
} else if (
!result[currentState] ||
tempStatus !== result[currentState]
) {
isSame = false
return false
}
})
return isSame
})
return isSame ? result : null
}
/**
* 根据当前选区获取相关的table信息
* @return {Object}
*/
UETable.getTableItemsByRange = function (editor) {
var start = editor.selection.getStart()
//ff下会选中bookmark
if (
start &&
start.id &&
start.id.indexOf('_baidu_bookmark_start_') === 0 &&
start.nextSibling
) {
start = start.nextSibling
}
//在table或者td边缘有可能存在选中tr的情况
var cell =
start && domUtils.findParentByTagName(start, ['td', 'th'], true),
tr = cell && cell.parentNode,
caption = start && domUtils.findParentByTagName(start, 'caption', true),
table = caption ? caption.parentNode : tr && tr.parentNode.parentNode
return {
cell: cell,
tr: tr,
table: table,
caption: caption
}
}
UETable.getUETableBySelected = function (editor) {
var table = UETable.getTableItemsByRange(editor).table
if (table && table.ueTable && table.ueTable.selectedTds.length) {
return table.ueTable
}
return null
}
UETable.getDefaultValue = function (editor, table) {
var borderMap = {
thin: '0px',
medium: '1px',
thick: '2px'
},
tableBorder,
tdPadding,
tdBorder,
tmpValue
if (!table) {
table = editor.document.createElement('table')
table.insertRow(0).insertCell(0).innerHTML = 'xxx'
editor.body.appendChild(table)
var td = table.getElementsByTagName('td')[0]
tmpValue = domUtils.getComputedStyle(table, 'border-left-width')
tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
tmpValue = domUtils.getComputedStyle(td, 'padding-left')
tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10)
tmpValue = domUtils.getComputedStyle(td, 'border-left-width')
tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
domUtils.remove(table)
return {
tableBorder: tableBorder,
tdPadding: tdPadding,
tdBorder: tdBorder
}
} else {
td = table.getElementsByTagName('td')[0]
tmpValue = domUtils.getComputedStyle(table, 'border-left-width')
tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
tmpValue = domUtils.getComputedStyle(td, 'padding-left')
tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10)
tmpValue = domUtils.getComputedStyle(td, 'border-left-width')
tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
return {
tableBorder: tableBorder,
tdPadding: tdPadding,
tdBorder: tdBorder
}
}
}
/**
* 根据当前点击的td或者table获取索引对象
* @param tdOrTable
*/
UETable.getUETable = function (tdOrTable) {
var tag = tdOrTable.tagName.toLowerCase()
tdOrTable =
tag == 'td' || tag == 'th' || tag == 'caption'
? domUtils.findParentByTagName(tdOrTable, 'table', true)
: tdOrTable
if (!tdOrTable.ueTable) {
tdOrTable.ueTable = new UETable(tdOrTable)
}
return tdOrTable.ueTable
}
UETable.cloneCell = function (cell, ignoreMerge, keepPro) {
if (!cell || utils.isString(cell)) {
return this.table.ownerDocument.createElement(cell || 'td')
}
var flag = domUtils.hasClass(cell, 'selectTdClass')
flag && domUtils.removeClasses(cell, 'selectTdClass')
var tmpCell = cell.cloneNode(true)
if (ignoreMerge) {
tmpCell.rowSpan = tmpCell.colSpan = 1
}
//去掉宽高
!keepPro && domUtils.removeAttributes(tmpCell, 'width height')
!keepPro && domUtils.removeAttributes(tmpCell, 'style')
tmpCell.style.borderLeftStyle = ''
tmpCell.style.borderTopStyle = ''
tmpCell.style.borderLeftColor = cell.style.borderRightColor
tmpCell.style.borderLeftWidth = cell.style.borderRightWidth
tmpCell.style.borderTopColor = cell.style.borderBottomColor
tmpCell.style.borderTopWidth = cell.style.borderBottomWidth
flag && domUtils.addClass(cell, 'selectTdClass')
return tmpCell
}
UETable.prototype = {
getMaxRows: function () {
var rows = this.table.rows,
maxLen = 1
for (var i = 0, row; (row = rows[i]); i++) {
var currentMax = 1
for (var j = 0, cj; (cj = row.cells[j++]); ) {
currentMax = Math.max(cj.rowSpan || 1, currentMax)
}
maxLen = Math.max(currentMax + i, maxLen)
}
return maxLen
},
/**
* 获取当前表格的最大列数
*/
getMaxCols: function () {
var rows = this.table.rows,
maxLen = 0,
cellRows = {}
for (var i = 0, row; (row = rows[i]); i++) {
var cellsNum = 0
for (var j = 0, cj; (cj = row.cells[j++]); ) {
cellsNum += cj.colSpan || 1
if (cj.rowSpan && cj.rowSpan > 1) {
for (var k = 1; k < cj.rowSpan; k++) {
if (!cellRows['row_' + (i + k)]) {
cellRows['row_' + (i + k)] = cj.colSpan || 1
} else {
cellRows['row_' + (i + k)]++
}
}
}
}
cellsNum += cellRows['row_' + i] || 0
maxLen = Math.max(cellsNum, maxLen)
}
return maxLen
},
getCellColIndex: function (cell) {},
/**
* 获取当前cell旁边的单元格,
* @param cell
* @param right
*/
getHSideCell: function (cell, right) {
try {
var cellInfo = this.getCellInfo(cell),
previewRowIndex,
previewColIndex
var len = this.selectedTds.length,
range = this.cellsRange
//首行或者首列没有前置单元格
if (
(!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
(right &&
(!len
? cellInfo.colIndex == this.colsNum - 1
: range.endColIndex == this.colsNum - 1))
)
return null
previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex
previewColIndex = !right
? !len
? cellInfo.colIndex < 1
? 0
: cellInfo.colIndex - 1
: range.beginColIndex - 1
: !len
? cellInfo.colIndex + 1
: range.endColIndex + 1
return this.getCell(
this.indexTable[previewRowIndex][previewColIndex].rowIndex,
this.indexTable[previewRowIndex][previewColIndex].cellIndex
)
} catch (e) {
showError(e)
}
},
getTabNextCell: function (cell, preRowIndex) {
var cellInfo = this.getCellInfo(cell),
rowIndex = preRowIndex || cellInfo.rowIndex,
colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
nextCell
try {
nextCell = this.getCell(
this.indexTable[rowIndex][colIndex].rowIndex,
this.indexTable[rowIndex][colIndex].cellIndex
)
} catch (e) {
try {
rowIndex = rowIndex * 1 + 1
colIndex = 0
nextCell = this.getCell(
this.indexTable[rowIndex][colIndex].rowIndex,
this.indexTable[rowIndex][colIndex].cellIndex
)
} catch (e) {}
}
return nextCell
},
/**
* 获取视觉上的后置单元格
* @param cell
* @param bottom
*/
getVSideCell: function (cell, bottom, ignoreRange) {
try {
var cellInfo = this.getCellInfo(cell),
nextRowIndex,
nextColIndex
var len = this.selectedTds.length && !ignoreRange,
range = this.cellsRange
//末行或者末列没有后置单元格
if (
(!bottom && cellInfo.rowIndex == 0) ||
(bottom &&
(!len
? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
: range.endRowIndex == this.rowsNum - 1))
)
return null
nextRowIndex = !bottom
? !len
? cellInfo.rowIndex - 1
: range.beginRowIndex - 1
: !len
? cellInfo.rowIndex + cellInfo.rowSpan
: range.endRowIndex + 1
nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex
return this.getCell(
this.indexTable[nextRowIndex][nextColIndex].rowIndex,
this.indexTable[nextRowIndex][nextColIndex].cellIndex
)
} catch (e) {
showError(e)
}
},
/**
* 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同
*/
getSameEndPosCells: function (cell, xOrY) {
try {
var flag = xOrY.toLowerCase() === 'x',
end =
domUtils.getXY(cell)[flag ? 'x' : 'y'] +
cell['offset' + (flag ? 'Width' : 'Height')],
rows = this.table.rows,
cells = null,
returns = []
for (var i = 0; i < this.rowsNum; i++) {
cells = rows[i].cells
for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
var tmpEnd =
domUtils.getXY(tmpCell)[flag ? 'x' : 'y'] +
tmpCell['offset' + (flag ? 'Width' : 'Height')]
//对应行的td已经被上面行rowSpan了
if (tmpEnd > end && flag) break
if (cell == tmpCell || end == tmpEnd) {
//只获取单一的单元格
//todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能
if (tmpCell[flag ? 'colSpan' : 'rowSpan'] == 1) {
returns.push(tmpCell)
}
if (flag) break
}
}
}
return returns
} catch (e) {
showError(e)
}
},
setCellContent: function (cell, content) {
cell.innerHTML = content || (browser.ie ? domUtils.fillChar : ' ')
},
cloneCell: UETable.cloneCell,
/**
* 获取跟当前单元格的右边竖线为左边的所有未合并单元格
*/
getSameStartPosXCells: function (cell) {
try {
var start = domUtils.getXY(cell).x + cell.offsetWidth,
rows = this.table.rows,
cells,
returns = []
for (var i = 0; i < this.rowsNum; i++) {
cells = rows[i].cells
for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
var tmpStart = domUtils.getXY(tmpCell).x
if (tmpStart > start) break
if (tmpStart == start && tmpCell.colSpan == 1) {
returns.push(tmpCell)
break
}
}
}
return returns
} catch (e) {
showError(e)
}
},
/**
* 更新table对应的索引表
*/
update: function (table) {
this.table = table || this.table
this.selectedTds = []
this.cellsRange = {}
this.indexTable = []
var rows = this.table.rows,
rowsNum = this.getMaxRows(),
dNum = rowsNum - rows.length,
colsNum = this.getMaxCols()
while (dNum--) {
this.table.insertRow(rows.length)
}
this.rowsNum = rowsNum
this.colsNum = colsNum
for (var i = 0, len = rows.length; i < len; i++) {
this.indexTable[i] = new Array(colsNum)
}
//填充索引表
for (var rowIndex = 0, row; (row = rows[rowIndex]); rowIndex++) {
for (
var cellIndex = 0, cell, cells = row.cells;
(cell = cells[cellIndex]);
cellIndex++
) {
//修正整行被rowSpan时导致的行数计算错误
if (cell.rowSpan > rowsNum) {
cell.rowSpan = rowsNum
}
var colIndex = cellIndex,
rowSpan = cell.rowSpan || 1,
colSpan = cell.colSpan || 1
//当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行
while (this.indexTable[rowIndex][colIndex]) colIndex++
for (var j = 0; j < rowSpan; j++) {
for (var k = 0; k < colSpan; k++) {
this.indexTable[rowIndex + j][colIndex + k] = {
rowIndex: rowIndex,
cellIndex: cellIndex,
colIndex: colIndex,
rowSpan: rowSpan,
colSpan: colSpan
}
}
}
}
}
//修复残缺td
for (j = 0; j < rowsNum; j++) {
for (k = 0; k < colsNum; k++) {
if (this.indexTable[j][k] === undefined) {
row = rows[j]
cell = row.cells[row.cells.length - 1]
cell = cell
? cell.cloneNode(true)
: this.table.ownerDocument.createElement('td')
this.setCellContent(cell)
if (cell.colSpan !== 1) cell.colSpan = 1
if (cell.rowSpan !== 1) cell.rowSpan = 1
row.appendChild(cell)
this.indexTable[j][k] = {
rowIndex: j,
cellIndex: cell.cellIndex,
colIndex: k,
rowSpan: 1,
colSpan: 1
}
}
}
}
//当框选后删除行或者列后撤销,需要重建选区。
var tds = domUtils.getElementsByTagName(this.table, 'td'),
selectTds = []
utils.each(tds, function (td) {
if (domUtils.hasClass(td, 'selectTdClass')) {
selectTds.push(td)
}
})
if (selectTds.length) {
var start = selectTds[0],
end = selectTds[selectTds.length - 1],
startInfo = this.getCellInfo(start),
endInfo = this.getCellInfo(end)
this.selectedTds = selectTds
this.cellsRange = {
beginRowIndex: startInfo.rowIndex,
beginColIndex: startInfo.colIndex,
endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
endColIndex: endInfo.colIndex + endInfo.colSpan - 1
}
}
//给第一行设置firstRow的样式名称,在排序图标的样式上使用到
if (!domUtils.hasClass(this.table.rows[0], 'firstRow')) {
domUtils.addClass(this.table.rows[0], 'firstRow')
for (var i = 1; i < this.table.rows.length; i++) {
domUtils.removeClasses(this.table.rows[i], 'firstRow')
}
}
},
/**
* 获取单元格的索引信息
*/
getCellInfo: function (cell) {
if (!cell) return
var cellIndex = cell.cellIndex,
rowIndex = cell.parentNode.rowIndex,
rowInfo = this.indexTable[rowIndex],
numCols = this.colsNum
for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
var cellInfo = rowInfo[colIndex]
if (
cellInfo.rowIndex === rowIndex &&
cellInfo.cellIndex === cellIndex
) {
return cellInfo
}
}
},
/**
* 根据行列号获取单元格
*/
getCell: function (rowIndex, cellIndex) {
return (
(rowIndex < this.rowsNum &&
this.table.rows[rowIndex].cells[cellIndex]) ||
null
)
},
/**
* 删除单元格
*/
deleteCell: function (cell, rowIndex) {
rowIndex =
typeof rowIndex == 'number' ? rowIndex : cell.parentNode.rowIndex
var row = this.table.rows[rowIndex]
row.deleteCell(cell.cellIndex)
},
/**
* 根据始末两个单元格获取被框选的所有单元格范围
*/
getCellsRange: function (cellA, cellB) {
function checkRange(
beginRowIndex,
beginColIndex,
endRowIndex,
endColIndex
) {
var tmpBeginRowIndex = beginRowIndex,
tmpBeginColIndex = beginColIndex,
tmpEndRowIndex = endRowIndex,
tmpEndColIndex = endColIndex,
cellInfo,
colIndex,
rowIndex
// 通过indexTable检查是否存在超出TableRange上边界的情况
if (beginRowIndex > 0) {
for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
cellInfo = me.indexTable[beginRowIndex][colIndex]
rowIndex = cellInfo.rowIndex
if (rowIndex < beginRowIndex) {
tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex)
}
}
}
// 通过indexTable检查是否存在超出TableRange右边界的情况
if (endColIndex < me.colsNum) {
for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
cellInfo = me.indexTable[rowIndex][endColIndex]
colIndex = cellInfo.colIndex + cellInfo.colSpan - 1
if (colIndex > endColIndex) {
tmpEndColIndex = Math.max(colIndex, tmpEndColIndex)
}
}
}
// 检查是否有超出TableRange下边界的情况
if (endRowIndex < me.rowsNum) {
for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
cellInfo = me.indexTable[endRowIndex][colIndex]
rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1
if (rowIndex > endRowIndex) {
tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex)
}
}
}
// 检查是否有超出TableRange左边界的情况
if (beginColIndex > 0) {
for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
cellInfo = me.indexTable[rowIndex][beginColIndex]
colIndex = cellInfo.colIndex
if (colIndex < beginColIndex) {
tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex)
}
}
}
//递归调用直至所有完成所有框选单元格的扩展
if (
tmpBeginRowIndex != beginRowIndex ||
tmpBeginColIndex != beginColIndex ||
tmpEndRowIndex != endRowIndex ||
tmpEndColIndex != endColIndex
) {
return checkRange(
tmpBeginRowIndex,
tmpBeginColIndex,
tmpEndRowIndex,
tmpEndColIndex
)
} else {
// 不需要扩展TableRange的情况
return {
beginRowIndex: beginRowIndex,
beginColIndex: beginColIndex,
endRowIndex: endRowIndex,
endColIndex: endColIndex
}
}
}
try {
var me = this,
cellAInfo = me.getCellInfo(cellA)
if (cellA === cellB) {
return {
beginRowIndex: cellAInfo.rowIndex,
beginColIndex: cellAInfo.colIndex,
endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1
}
}
var cellBInfo = me.getCellInfo(cellB)
// 计算TableRange的四个边
var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
endRowIndex = Math.max(
cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
cellBInfo.rowIndex + cellBInfo.rowSpan - 1
),
endColIndex = Math.max(
cellAInfo.colIndex + cellAInfo.colSpan - 1,
cellBInfo.colIndex + cellBInfo.colSpan - 1
)
return checkRange(
beginRowIndex,
beginColIndex,
endRowIndex,
endColIndex
)
} catch (e) {
//throw e;
}
},
/**
* 依据cellsRange获取对应的单元格集合
*/
getCells: function (range) {
//每次获取cells之前必须先清除上次的选择,否则会对后续获取操作造成影响
this.clearSelected()
var beginRowIndex = range.beginRowIndex,
beginColIndex = range.beginColIndex,
endRowIndex = range.endRowIndex,
endColIndex = range.endColIndex,
cellInfo,
rowIndex,
colIndex,
tdHash = {},
returnTds = []
for (var i = beginRowIndex; i <= endRowIndex; i++) {
for (var j = beginColIndex; j <= endColIndex; j++) {
cellInfo = this.indexTable[i][j]
rowIndex = cellInfo.rowIndex
colIndex = cellInfo.colIndex
// 如果Cells里已经包含了此Cell则跳过
var key = rowIndex + '|' + colIndex
if (tdHash[key]) continue
tdHash[key] = 1
if (
rowIndex < i ||
colIndex < j ||
rowIndex + cellInfo.rowSpan - 1 > endRowIndex ||
colIndex + cellInfo.colSpan - 1 > endColIndex
) {
return null
}
returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex))
}
}
return returnTds
},
/**
* 清理已经选中的单元格
*/
clearSelected: function () {
UETable.removeSelectedClass(this.selectedTds)
this.selectedTds = []
this.cellsRange = {}
},
/**
* 根据range设置已经选中的单元格
*/
setSelected: function (range) {
var cells = this.getCells(range)
UETable.addSelectedClass(cells)
this.selectedTds = cells
this.cellsRange = range
},
isFullRow: function () {
var range = this.cellsRange
return range.endColIndex - range.beginColIndex + 1 == this.colsNum
},
isFullCol: function () {
var range = this.cellsRange,
table = this.table,
ths = table.getElementsByTagName('th'),
rows = range.endRowIndex - range.beginRowIndex + 1
return !ths.length
? rows == this.rowsNum
: rows == this.rowsNum || rows == this.rowsNum - 1
},
/**
* 获取视觉上的前置单元格,默认是左边,top传入时
* @param cell
* @param top
*/
getNextCell: function (cell, bottom, ignoreRange) {
try {
var cellInfo = this.getCellInfo(cell),
nextRowIndex,
nextColIndex
var len = this.selectedTds.length && !ignoreRange,
range = this.cellsRange
//末行或者末列没有后置单元格
if (
(!bottom && cellInfo.rowIndex == 0) ||
(bottom &&
(!len
? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
: range.endRowIndex == this.rowsNum - 1))
)
return null
nextRowIndex = !bottom
? !len
? cellInfo.rowIndex - 1
: range.beginRowIndex - 1
: !len
? cellInfo.rowIndex + cellInfo.rowSpan
: range.endRowIndex + 1
nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex
return this.getCell(
this.indexTable[nextRowIndex][nextColIndex].rowIndex,
this.indexTable[nextRowIndex][nextColIndex].cellIndex
)
} catch (e) {
showError(e)
}
},
getPreviewCell: function (cell, top) {
try {
var cellInfo = this.getCellInfo(cell),
previewRowIndex,
previewColIndex
var len = this.selectedTds.length,
range = this.cellsRange
//首行或者首列没有前置单元格
if (
(!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
(top &&
(!len
? cellInfo.rowIndex > this.colsNum - 1
: range.endColIndex == this.colsNum - 1))
)
return null
previewRowIndex = !top
? !len
? cellInfo.rowIndex
: range.beginRowIndex
: !len
? cellInfo.rowIndex < 1
? 0
: cellInfo.rowIndex - 1
: range.beginRowIndex
previewColIndex = !top
? !len
? cellInfo.colIndex < 1
? 0
: cellInfo.colIndex - 1
: range.beginColIndex - 1
: !len
? cellInfo.colIndex
: range.endColIndex + 1
return this.getCell(
this.indexTable[previewRowIndex][previewColIndex].rowIndex,
this.indexTable[previewRowIndex][previewColIndex].cellIndex
)
} catch (e) {
showError(e)
}
},
/**
* 移动单元格中的内容
*/
moveContent: function (cellTo, cellFrom) {
if (UETable.isEmptyBlock(cellFrom)) return
if (UETable.isEmptyBlock(cellTo)) {
cellTo.innerHTML = cellFrom.innerHTML
return
}
var child = cellTo.lastChild
if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
cellTo.appendChild(cellTo.ownerDocument.createElement('br'))
}
while ((child = cellFrom.firstChild)) {
cellTo.appendChild(child)
}
},
/**
* 向右合并单元格
*/
mergeRight: function (cell) {
var cellInfo = this.getCellInfo(cell),
rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
rightCell = this.getCell(
rightCellInfo.rowIndex,
rightCellInfo.cellIndex
)
//合并
cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan
//被合并的单元格不应存在宽度属性
cell.removeAttribute('width')
//移动内容
this.moveContent(cell, rightCell)
//删掉被合并的Cell
this.deleteCell(rightCell, rightCellInfo.rowIndex)
this.update()
},
/**
* 向下合并单元格
*/
mergeDown: function (cell) {
var cellInfo = this.getCellInfo(cell),
downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex)
cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan
cell.removeAttribute('height')
this.moveContent(cell, downCell)
this.deleteCell(downCell, downCellInfo.rowIndex)
this.update()
},
/**
* 合并整个range中的内容
*/
mergeRange: function () {
//由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问
var range = this.cellsRange,
leftTopCell = this.getCell(
range.beginRowIndex,
this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex
)
if (
leftTopCell.tagName == 'TH' &&
range.endRowIndex !== range.beginRowIndex
) {
var index = this.indexTable,
info = this.getCellInfo(leftTopCell)
leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex)
range = this.getCellsRange(
leftTopCell,
this.getCell(
index[this.rowsNum - 1][info.colIndex].rowIndex,
index[this.rowsNum - 1][info.colIndex].cellIndex
)
)
}
// 删除剩余的Cells
var cells = this.getCells(range)
for (var i = 0, ci; (ci = cells[i++]); ) {
if (ci !== leftTopCell) {
this.moveContent(leftTopCell, ci)
this.deleteCell(ci)
}
}
// 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置
leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1
leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute('height')
leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1
leftTopCell.colSpan > 1 && leftTopCell.removeAttribute('width')
if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
leftTopCell.colSpan = 1
}
if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
var rowIndex = leftTopCell.parentNode.rowIndex
//解决IE下的表格操作问题
if (this.table.deleteRow) {
for (
var i = rowIndex + 1,
curIndex = rowIndex + 1,
len = leftTopCell.rowSpan;
i < len;
i++
) {
this.table.deleteRow(curIndex)
}
} else {
for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
var row = this.table.rows[rowIndex + 1]
row.parentNode.removeChild(row)
}
}
leftTopCell.rowSpan = 1
}
this.update()
},
/**
* 插入一行单元格
*/
insertRow: function (rowIndex, sourceCell) {
var numCols = this.colsNum,
table = this.table,
row = table.insertRow(rowIndex),
cell,
isInsertTitle =
typeof sourceCell == 'string' && sourceCell.toUpperCase() == 'TH'
function replaceTdToTh(colIndex, cell, tableRow) {
if (colIndex == 0) {
var tr = tableRow.nextSibling || tableRow.previousSibling,
th = tr.cells[colIndex]
if (th.tagName == 'TH') {
th = cell.ownerDocument.createElement('th')
th.appendChild(cell.firstChild)
tableRow.insertBefore(th, cell)
domUtils.remove(cell)
}
} else {
if (cell.tagName == 'TH') {
var td = cell.ownerDocument.createElement('td')
td.appendChild(cell.firstChild)
tableRow.insertBefore(td, cell)
domUtils.remove(cell)
}
}
}
//首行直接插入,无需考虑部分单元格被rowspan的情况
if (rowIndex == 0 || rowIndex == this.rowsNum) {
for (var colIndex = 0; colIndex < numCols; colIndex++) {
cell = this.cloneCell(sourceCell, true)
this.setCellContent(cell)
cell.getAttribute('vAlign') &&
cell.setAttribute('vAlign', cell.getAttribute('vAlign'))
row.appendChild(cell)
if (!isInsertTitle) replaceTdToTh(colIndex, cell, row)
}
} else {
var infoRow = this.indexTable[rowIndex],
cellIndex = 0
for (colIndex = 0; colIndex < numCols; colIndex++) {
var cellInfo = infoRow[colIndex]
//如果存在某个单元格的rowspan穿过待插入行的位置,则修改该单元格的rowspan即可,无需插入单元格
if (cellInfo.rowIndex < rowIndex) {
cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
cell.rowSpan = cellInfo.rowSpan + 1
} else {
cell = this.cloneCell(sourceCell, true)
this.setCellContent(cell)
row.appendChild(cell)
}
if (!isInsertTitle) replaceTdToTh(colIndex, cell, row)
}
}
//框选时插入不触发contentchange,需要手动更新索引。
this.update()
return row
},
/**
* 删除一行单元格
* @param rowIndex
*/
deleteRow: function (rowIndex) {
var row = this.table.rows[rowIndex],
infoRow = this.indexTable[rowIndex],
colsNum = this.colsNum,
count = 0 //处理计数
for (var colIndex = 0; colIndex < colsNum; ) {
var cellInfo = infoRow[colIndex],
cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
if (cell.rowSpan > 1) {
if (cellInfo.rowIndex == rowIndex) {
var clone = cell.cloneNode(true)
clone.rowSpan = cell.rowSpan - 1
clone.innerHTML = ''
cell.rowSpan = 1
var nextRowIndex = rowIndex + 1,
nextRow = this.table.rows[nextRowIndex],
insertCellIndex,
preMerged =
this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count
if (preMerged < colIndex) {
insertCellIndex = colIndex - preMerged - 1
//nextRow.insertCell(insertCellIndex);
domUtils.insertAfter(nextRow.cells[insertCellIndex], clone)
} else {
if (nextRow.cells.length)
nextRow.insertBefore(clone, nextRow.cells[0])
}
count += 1
//cell.parentNode.removeChild(cell);
}
}
colIndex += cell.colSpan || 1
}
var deleteTds = [],
cacheMap = {}
for (colIndex = 0; colIndex < colsNum; colIndex++) {
var tmpRowIndex = infoRow[colIndex].rowIndex,
tmpCellIndex = infoRow[colIndex].cellIndex,
key = tmpRowIndex + '_' + tmpCellIndex
if (cacheMap[key]) continue
cacheMap[key] = 1
cell = this.getCell(tmpRowIndex, tmpCellIndex)
deleteTds.push(cell)
}
var mergeTds = []
utils.each(deleteTds, function (td) {
if (td.rowSpan == 1) {
td.parentNode.removeChild(td)
} else {
mergeTds.push(td)
}
})
utils.each(mergeTds, function (td) {
td.rowSpan--
})
row.parentNode.removeChild(row)
//浏览器方法本身存在bug,采用自定义方法删除
//this.table.deleteRow(rowIndex);
this.update()
},
insertCol: function (colIndex, sourceCell, defaultValue) {
var rowsNum = this.rowsNum,
rowIndex = 0,
tableRow,
cell,
backWidth = parseInt(
(this.table.offsetWidth -
(this.colsNum + 1) * 20 -
(this.colsNum + 1)) /
(this.colsNum + 1),
10
),
isInsertTitleCol =
typeof sourceCell == 'string' && sourceCell.toUpperCase() == 'TH'
function replaceTdToTh(rowIndex, cell, tableRow) {
if (rowIndex == 0) {
var th = cell.nextSibling || cell.previousSibling
if (th.tagName == 'TH') {
th = cell.ownerDocument.createElement('th')
th.appendChild(cell.firstChild)
tableRow.insertBefore(th, cell)
domUtils.remove(cell)
}
} else {
if (cell.tagName == 'TH') {
var td = cell.ownerDocument.createElement('td')
td.appendChild(cell.firstChild)
tableRow.insertBefore(td, cell)
domUtils.remove(cell)
}
}
}
var preCell
if (colIndex == 0 || colIndex == this.colsNum) {
for (; rowIndex < rowsNum; rowIndex++) {
tableRow = this.table.rows[rowIndex]
preCell =
tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length]
cell = this.cloneCell(sourceCell, true) //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
this.setCellContent(cell)
cell.setAttribute('vAlign', cell.getAttribute('vAlign'))
preCell && cell.setAttribute('width', preCell.getAttribute('width'))
if (!colIndex) {
tableRow.insertBefore(cell, tableRow.cells[0])
} else {
domUtils.insertAfter(
tableRow.cells[tableRow.cells.length - 1],
cell
)
}
if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow)
}
} else {
for (; rowIndex < rowsNum; rowIndex++) {
var cellInfo = this.indexTable[rowIndex][colIndex]
if (cellInfo.colIndex < colIndex) {
cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
cell.colSpan = cellInfo.colSpan + 1
} else {
tableRow = this.table.rows[rowIndex]
preCell = tableRow.cells[cellInfo.cellIndex]
cell = this.cloneCell(sourceCell, true) //tableRow.insertCell(cellInfo.cellIndex);
this.setCellContent(cell)
cell.setAttribute('vAlign', cell.getAttribute('vAlign'))
preCell &&
cell.setAttribute('width', preCell.getAttribute('width'))
//防止IE下报错
preCell
? tableRow.insertBefore(cell, preCell)
: tableRow.appendChild(cell)
}
if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow)
}
}
//框选时插入不触发contentchange,需要手动更新索引
this.update()
this.updateWidth(
backWidth,
defaultValue || { tdPadding: 10, tdBorder: 1 }
)
},
updateWidth: function (width, defaultValue) {
var table = this.table,
tmpWidth =
UETable.getWidth(table) -
defaultValue.tdPadding * 2 -
defaultValue.tdBorder +
width
if (tmpWidth < table.ownerDocument.body.offsetWidth) {
table.setAttribute('width', tmpWidth)
return
}
var tds = domUtils.getElementsByTagName(this.table, 'td th')
utils.each(tds, function (td) {
td.setAttribute('width', width)
})
},
deleteCol: function (colIndex) {
var indexTable = this.indexTable,
tableRows = this.table.rows,
backTableWidth = this.table.getAttribute('width'),
backTdWidth = 0,
rowsNum = this.rowsNum,
cacheMap = {}
for (var rowIndex = 0; rowIndex < rowsNum; ) {
var infoRow = indexTable[rowIndex],
cellInfo = infoRow[colIndex],
key = cellInfo.rowIndex + '_' + cellInfo.colIndex
// 跳过已经处理过的Cell
if (cacheMap[key]) continue
cacheMap[key] = 1
var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
if (!backTdWidth)
backTdWidth =
cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0)
// 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
if (cell.colSpan > 1) {
cell.colSpan--
} else {
tableRows[rowIndex].deleteCell(cellInfo.cellIndex)
}
rowIndex += cellInfo.rowSpan || 1
}
this.table.setAttribute('width', backTableWidth - backTdWidth)
this.update()
},
splitToCells: function (cell) {
var me = this,
cells = this.splitToRows(cell)
utils.each(cells, function (cell) {
me.splitToCols(cell)
})
},
splitToRows: function (cell) {
var cellInfo = this.getCellInfo(cell),
rowIndex = cellInfo.rowIndex,
colIndex = cellInfo.colIndex,
results = []
// 修改Cell的rowSpan
cell.rowSpan = 1
results.push(cell)
// 补齐单元格
for (
var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan;
i < endRow;
i++
) {
if (i == rowIndex) continue
var tableRow = this.table.rows[i],
tmpCell = tableRow.insertCell(
colIndex - this.getPreviewMergedCellsNum(i, colIndex)
)
tmpCell.colSpan = cellInfo.colSpan
this.setCellContent(tmpCell)
tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'))
tmpCell.setAttribute('align', cell.getAttribute('align'))
if (cell.style.cssText) {
tmpCell.style.cssText = cell.style.cssText
}
results.push(tmpCell)
}
this.update()
return results
},
getPreviewMergedCellsNum: function (rowIndex, colIndex) {
var indexRow = this.indexTable[rowIndex],
num = 0
for (var i = 0; i < colIndex; ) {
var colSpan = indexRow[i].colSpan,
tmpRowIndex = indexRow[i].rowIndex
num += colSpan - (tmpRowIndex == rowIndex ? 1 : 0)
i += colSpan
}
return num
},
splitToCols: function (cell) {
var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
cellInfo = this.getCellInfo(cell),
rowIndex = cellInfo.rowIndex,
colIndex = cellInfo.colIndex,
results = []
// 修改Cell的rowSpan
cell.colSpan = 1
cell.setAttribute('width', backWidth)
results.push(cell)
// 补齐单元格
for (
var j = colIndex, endCol = colIndex + cellInfo.colSpan;
j < endCol;
j++
) {
if (j == colIndex) continue
var tableRow = this.table.rows[rowIndex],
tmpCell = tableRow.insertCell(
this.indexTable[rowIndex][j].cellIndex + 1
)
tmpCell.rowSpan = cellInfo.rowSpan
this.setCellContent(tmpCell)
tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'))
tmpCell.setAttribute('align', cell.getAttribute('align'))
tmpCell.setAttribute('width', backWidth)
if (cell.style.cssText) {
tmpCell.style.cssText = cell.style.cssText
}
//处理th的情况
if (cell.tagName == 'TH') {
var th = cell.ownerDocument.createElement('th')
th.appendChild(tmpCell.firstChild)
th.setAttribute('vAlign', cell.getAttribute('vAlign'))
th.rowSpan = tmpCell.rowSpan
tableRow.insertBefore(th, tmpCell)
domUtils.remove(tmpCell)
}
results.push(tmpCell)
}
this.update()
return results
},
isLastCell: function (cell, rowsNum, colsNum) {
rowsNum = rowsNum || this.rowsNum
colsNum = colsNum || this.colsNum
var cellInfo = this.getCellInfo(cell)
return (
cellInfo.rowIndex + cellInfo.rowSpan == rowsNum &&
cellInfo.colIndex + cellInfo.colSpan == colsNum
)
},
getLastCell: function (cells) {
cells = cells || this.table.getElementsByTagName('td')
var firstInfo = this.getCellInfo(cells[0])
var me = this,
last = cells[0],
tr = last.parentNode,
cellsNum = 0,
cols = 0,
rows
utils.each(cells, function (cell) {
if (cell.parentNode == tr) cols += cell.colSpan || 1
cellsNum += cell.rowSpan * cell.colSpan || 1
})
rows = cellsNum / cols
utils.each(cells, function (cell) {
if (me.isLastCell(cell, rows, cols)) {
last = cell
return false
}
})
return last
},
selectRow: function (rowIndex) {
var indexRow = this.indexTable[rowIndex],
start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
end = this.getCell(
indexRow[this.colsNum - 1].rowIndex,
indexRow[this.colsNum - 1].cellIndex
),
range = this.getCellsRange(start, end)
this.setSelected(range)
},
selectTable: function () {
var tds = this.table.getElementsByTagName('td'),
range = this.getCellsRange(tds[0], tds[tds.length - 1])
this.setSelected(range)
},
setBackground: function (cells, value) {
if (typeof value === 'string') {
utils.each(cells, function (cell) {
cell.style.backgroundColor = value
})
} else if (typeof value === 'object') {
value = utils.extend(
{
repeat: true,
colorList: ['#ddd', '#fff']
},
value
)
var rowIndex = this.getCellInfo(cells[0]).rowIndex,
count = 0,
colors = value.colorList,
getColor = function (list, index, repeat) {
return list[index]
? list[index]
: repeat
? list[index % list.length]
: ''
}
for (var i = 0, cell; (cell = cells[i++]); ) {
var cellInfo = this.getCellInfo(cell)
cell.style.backgroundColor = getColor(
colors,
rowIndex + count == cellInfo.rowIndex ? count : ++count,
value.repeat
)
}
}
},
removeBackground: function (cells) {
utils.each(cells, function (cell) {
cell.style.backgroundColor = ''
})
}
}
function showError(e) {}
})()
// plugins/table.cmds.js
/**
* Created with JetBrains PhpStorm.
* User: taoqili
* Date: 13-2-20
* Time: 下午6:25
* To change this template use File | Settings | File Templates.
*/
;(function () {
var UT = UE.UETable,
getTableItemsByRange = function (editor) {
return UT.getTableItemsByRange(editor)
},
getUETableBySelected = function (editor) {
return UT.getUETableBySelected(editor)
},
getDefaultValue = function (editor, table) {
return UT.getDefaultValue(editor, table)
},
getUETable = function (tdOrTable) {
return UT.getUETable(tdOrTable)
}
UE.commands['inserttable'] = {
queryCommandState: function () {
return getTableItemsByRange(this).table ? -1 : 0
},
execCommand: function (cmd, opt) {
function createTable(opt, tdWidth) {
var html = [],
rowsNum = opt.numRows,
colsNum = opt.numCols
for (var r = 0; r < rowsNum; r++) {
html.push('')
for (var c = 0; c < colsNum; c++) {
html.push(
'' +
(browser.ie && browser.version < 11
? domUtils.fillChar
: ' ') +
' '
)
}
html.push(' ')
}
//禁止指定table-width
return ''
}
if (!opt) {
opt = utils.extend(
{},
{
numCols: this.options.defaultCols,
numRows: this.options.defaultRows,
tdvalign: this.options.tdvalign
}
)
}
var me = this
var range = this.selection.getRange(),
start = range.startContainer,
firstParentBlock =
domUtils.findParent(
start,
function (node) {
return domUtils.isBlockElm(node)
},
true
) || me.body
var defaultValue = getDefaultValue(me),
tableWidth = firstParentBlock.offsetWidth,
tdWidth = Math.floor(
tableWidth / opt.numCols -
defaultValue.tdPadding * 2 -
defaultValue.tdBorder
)
//todo其他属性
!opt.tdvalign && (opt.tdvalign = me.options.tdvalign)
me.execCommand('inserthtml', createTable(opt, tdWidth))
}
}
UE.commands['insertparagraphbeforetable'] = {
queryCommandState: function () {
return getTableItemsByRange(this).cell ? 0 : -1
},
execCommand: function () {
var table = getTableItemsByRange(this).table
if (table) {
var p = this.document.createElement('p')
p.innerHTML = browser.ie ? ' ' : ' '
table.parentNode.insertBefore(p, table)
this.selection.getRange().setStart(p, 0).setCursor()
}
}
}
UE.commands['deletetable'] = {
queryCommandState: function () {
var rng = this.selection.getRange()
return domUtils.findParentByTagName(rng.startContainer, 'table', true)
? 0
: -1
},
execCommand: function (cmd, table) {
var rng = this.selection.getRange()
table =
table ||
domUtils.findParentByTagName(rng.startContainer, 'table', true)
if (table) {
var next = table.nextSibling
if (!next) {
next = domUtils.createElement(this.document, 'p', {
innerHTML: browser.ie ? domUtils.fillChar : ' '
})
table.parentNode.insertBefore(next, table)
}
domUtils.remove(table)
rng = this.selection.getRange()
if (next.nodeType == 3) {
rng.setStartBefore(next)
} else {
rng.setStart(next, 0)
}
rng.setCursor(false, true)
this.fireEvent('tablehasdeleted')
}
}
}
UE.commands['cellalign'] = {
queryCommandState: function () {
return getSelectedArr(this).length ? 0 : -1
},
execCommand: function (cmd, align) {
var selectedTds = getSelectedArr(this)
if (selectedTds.length) {
for (var i = 0, ci; (ci = selectedTds[i++]); ) {
ci.setAttribute('align', align)
}
}
}
}
UE.commands['cellvalign'] = {
queryCommandState: function () {
return getSelectedArr(this).length ? 0 : -1
},
execCommand: function (cmd, valign) {
var selectedTds = getSelectedArr(this)
if (selectedTds.length) {
for (var i = 0, ci; (ci = selectedTds[i++]); ) {
ci.setAttribute('vAlign', valign)
}
}
}
}
UE.commands['insertcaption'] = {
queryCommandState: function () {
var table = getTableItemsByRange(this).table
if (table) {
return table.getElementsByTagName('caption').length == 0 ? 1 : -1
}
return -1
},
execCommand: function () {
var table = getTableItemsByRange(this).table
if (table) {
var caption = this.document.createElement('caption')
caption.innerHTML = browser.ie ? domUtils.fillChar : ' '
table.insertBefore(caption, table.firstChild)
var range = this.selection.getRange()
range.setStart(caption, 0).setCursor()
}
}
}
UE.commands['deletecaption'] = {
queryCommandState: function () {
var rng = this.selection.getRange(),
table = domUtils.findParentByTagName(rng.startContainer, 'table')
if (table) {
return table.getElementsByTagName('caption').length == 0 ? -1 : 1
}
return -1
},
execCommand: function () {
var rng = this.selection.getRange(),
table = domUtils.findParentByTagName(rng.startContainer, 'table')
if (table) {
domUtils.remove(table.getElementsByTagName('caption')[0])
var range = this.selection.getRange()
range.setStart(table.rows[0].cells[0], 0).setCursor()
}
}
}
UE.commands['inserttitle'] = {
queryCommandState: function () {
var table = getTableItemsByRange(this).table
if (table) {
var firstRow = table.rows[0]
return firstRow.cells[
firstRow.cells.length - 1
].tagName.toLowerCase() != 'th'
? 0
: -1
}
return -1
},
execCommand: function () {
var table = getTableItemsByRange(this).table
if (table) {
getUETable(table).insertRow(0, 'th')
}
var th = table.getElementsByTagName('th')[0]
this.selection.getRange().setStart(th, 0).setCursor(false, true)
}
}
UE.commands['deletetitle'] = {
queryCommandState: function () {
var table = getTableItemsByRange(this).table
if (table) {
var firstRow = table.rows[0]
return firstRow.cells[
firstRow.cells.length - 1
].tagName.toLowerCase() == 'th'
? 0
: -1
}
return -1
},
execCommand: function () {
var table = getTableItemsByRange(this).table
if (table) {
domUtils.remove(table.rows[0])
}
var td = table.getElementsByTagName('td')[0]
this.selection.getRange().setStart(td, 0).setCursor(false, true)
}
}
UE.commands['inserttitlecol'] = {
queryCommandState: function () {
var table = getTableItemsByRange(this).table
if (table) {
var lastRow = table.rows[table.rows.length - 1]
return lastRow.getElementsByTagName('th').length ? -1 : 0
}
return -1
},
execCommand: function (cmd) {
var table = getTableItemsByRange(this).table
if (table) {
getUETable(table).insertCol(0, 'th')
}
resetTdWidth(table, this)
var th = table.getElementsByTagName('th')[0]
this.selection.getRange().setStart(th, 0).setCursor(false, true)
}
}
UE.commands['deletetitlecol'] = {
queryCommandState: function () {
var table = getTableItemsByRange(this).table
if (table) {
var lastRow = table.rows[table.rows.length - 1]
return lastRow.getElementsByTagName('th').length ? 0 : -1
}
return -1
},
execCommand: function () {
var table = getTableItemsByRange(this).table
if (table) {
for (var i = 0; i < table.rows.length; i++) {
domUtils.remove(table.rows[i].children[0])
}
}
resetTdWidth(table, this)
var td = table.getElementsByTagName('td')[0]
this.selection.getRange().setStart(td, 0).setCursor(false, true)
}
}
UE.commands['mergeright'] = {
queryCommandState: function (cmd) {
var tableItems = getTableItemsByRange(this),
table = tableItems.table,
cell = tableItems.cell
if (!table || !cell) return -1
var ut = getUETable(table)
if (ut.selectedTds.length) return -1
var cellInfo = ut.getCellInfo(cell),
rightColIndex = cellInfo.colIndex + cellInfo.colSpan
if (rightColIndex >= ut.colsNum) return -1 // 如果处于最右边则不能向右合并
var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
rightCell =
table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex]
if (!rightCell || cell.tagName != rightCell.tagName) return -1 // TH和TD不能相互合并
// 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
return rightCellInfo.rowIndex == cellInfo.rowIndex &&
rightCellInfo.rowSpan == cellInfo.rowSpan
? 0
: -1
},
execCommand: function (cmd) {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell)
ut.mergeRight(cell)
rng.moveToBookmark(bk).select()
}
}
UE.commands['mergedown'] = {
queryCommandState: function (cmd) {
var tableItems = getTableItemsByRange(this),
table = tableItems.table,
cell = tableItems.cell
if (!table || !cell) return -1
var ut = getUETable(table)
if (ut.selectedTds.length) return -1
var cellInfo = ut.getCellInfo(cell),
downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan
if (downRowIndex >= ut.rowsNum) return -1 // 如果处于最下边则不能向下合并
var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
downCell =
table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex]
if (!downCell || cell.tagName != downCell.tagName) return -1 // TH和TD不能相互合并
// 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
return downCellInfo.colIndex == cellInfo.colIndex &&
downCellInfo.colSpan == cellInfo.colSpan
? 0
: -1
},
execCommand: function () {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell)
ut.mergeDown(cell)
rng.moveToBookmark(bk).select()
}
}
UE.commands['mergecells'] = {
queryCommandState: function () {
return getUETableBySelected(this) ? 0 : -1
},
execCommand: function () {
var ut = getUETableBySelected(this)
if (ut && ut.selectedTds.length) {
var cell = ut.selectedTds[0]
ut.mergeRange()
var rng = this.selection.getRange()
if (domUtils.isEmptyBlock(cell)) {
rng.setStart(cell, 0).collapse(true)
} else {
rng.selectNodeContents(cell)
}
rng.select()
}
}
}
UE.commands['insertrow'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell
return cell &&
(cell.tagName == 'TD' ||
(cell.tagName == 'TH' &&
tableItems.tr !== tableItems.table.rows[0])) &&
getUETable(tableItems.table).rowsNum < this.options.maxRowNum
? 0
: -1
},
execCommand: function () {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell,
table = tableItems.table,
ut = getUETable(table),
cellInfo = ut.getCellInfo(cell)
//ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
if (!ut.selectedTds.length) {
ut.insertRow(cellInfo.rowIndex, cell)
} else {
var range = ut.cellsRange
for (
var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
i < len;
i++
) {
ut.insertRow(range.beginRowIndex, cell)
}
}
rng.moveToBookmark(bk).select()
if (table.getAttribute('interlaced') === 'enabled')
this.fireEvent('interlacetable', table)
}
}
//后插入行
UE.commands['insertrownext'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell
return cell &&
cell.tagName == 'TD' &&
getUETable(tableItems.table).rowsNum < this.options.maxRowNum
? 0
: -1
},
execCommand: function () {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell,
table = tableItems.table,
ut = getUETable(table),
cellInfo = ut.getCellInfo(cell)
//ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
if (!ut.selectedTds.length) {
ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell)
} else {
var range = ut.cellsRange
for (
var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
i < len;
i++
) {
ut.insertRow(range.endRowIndex + 1, cell)
}
}
rng.moveToBookmark(bk).select()
if (table.getAttribute('interlaced') === 'enabled')
this.fireEvent('interlacetable', table)
}
}
UE.commands['deleterow'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this)
return tableItems.cell ? 0 : -1
},
execCommand: function () {
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell),
cellsRange = ut.cellsRange,
cellInfo = ut.getCellInfo(cell),
preCell = ut.getVSideCell(cell),
nextCell = ut.getVSideCell(cell, true),
rng = this.selection.getRange()
if (utils.isEmptyObject(cellsRange)) {
ut.deleteRow(cellInfo.rowIndex)
} else {
for (
var i = cellsRange.beginRowIndex;
i < cellsRange.endRowIndex + 1;
i++
) {
ut.deleteRow(cellsRange.beginRowIndex)
}
}
var table = ut.table
if (!table.getElementsByTagName('td').length) {
var nextSibling = table.nextSibling
domUtils.remove(table)
if (nextSibling) {
rng.setStart(nextSibling, 0).setCursor(false, true)
}
} else {
if (
cellInfo.rowSpan == 1 ||
cellInfo.rowSpan ==
cellsRange.endRowIndex - cellsRange.beginRowIndex + 1
) {
if (nextCell || preCell)
rng.selectNodeContents(nextCell || preCell).setCursor(false, true)
} else {
var newCell = ut.getCell(
cellInfo.rowIndex,
ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex
)
if (newCell) rng.selectNodeContents(newCell).setCursor(false, true)
}
}
if (table.getAttribute('interlaced') === 'enabled')
this.fireEvent('interlacetable', table)
}
}
UE.commands['insertcol'] = {
queryCommandState: function (cmd) {
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell
return cell &&
(cell.tagName == 'TD' ||
(cell.tagName == 'TH' && cell !== tableItems.tr.cells[0])) &&
getUETable(tableItems.table).colsNum < this.options.maxColNum
? 0
: -1
},
execCommand: function (cmd) {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
if (this.queryCommandState(cmd) == -1) return
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell),
cellInfo = ut.getCellInfo(cell)
//ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
if (!ut.selectedTds.length) {
ut.insertCol(cellInfo.colIndex, cell)
} else {
var range = ut.cellsRange
for (
var i = 0, len = range.endColIndex - range.beginColIndex + 1;
i < len;
i++
) {
ut.insertCol(range.beginColIndex, cell)
}
}
rng.moveToBookmark(bk).select(true)
}
}
UE.commands['insertcolnext'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell
return cell &&
getUETable(tableItems.table).colsNum < this.options.maxColNum
? 0
: -1
},
execCommand: function () {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell),
cellInfo = ut.getCellInfo(cell)
//ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
if (!ut.selectedTds.length) {
ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell)
} else {
var range = ut.cellsRange
for (
var i = 0, len = range.endColIndex - range.beginColIndex + 1;
i < len;
i++
) {
ut.insertCol(range.endColIndex + 1, cell)
}
}
rng.moveToBookmark(bk).select()
}
}
UE.commands['deletecol'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this)
return tableItems.cell ? 0 : -1
},
execCommand: function () {
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell),
range = ut.cellsRange,
cellInfo = ut.getCellInfo(cell),
preCell = ut.getHSideCell(cell),
nextCell = ut.getHSideCell(cell, true)
if (utils.isEmptyObject(range)) {
ut.deleteCol(cellInfo.colIndex)
} else {
for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
ut.deleteCol(range.beginColIndex)
}
}
var table = ut.table,
rng = this.selection.getRange()
if (!table.getElementsByTagName('td').length) {
var nextSibling = table.nextSibling
domUtils.remove(table)
if (nextSibling) {
rng.setStart(nextSibling, 0).setCursor(false, true)
}
} else {
if (domUtils.inDoc(cell, this.document)) {
rng.setStart(cell, 0).setCursor(false, true)
} else {
if (nextCell && domUtils.inDoc(nextCell, this.document)) {
rng.selectNodeContents(nextCell).setCursor(false, true)
} else {
if (preCell && domUtils.inDoc(preCell, this.document)) {
rng.selectNodeContents(preCell).setCursor(true, true)
}
}
}
}
}
}
UE.commands['splittocells'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell
if (!cell) return -1
var ut = getUETable(tableItems.table)
if (ut.selectedTds.length > 0) return -1
return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1
},
execCommand: function () {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell)
ut.splitToCells(cell)
rng.moveToBookmark(bk).select()
}
}
UE.commands['splittorows'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell
if (!cell) return -1
var ut = getUETable(tableItems.table)
if (ut.selectedTds.length > 0) return -1
return cell && cell.rowSpan > 1 ? 0 : -1
},
execCommand: function () {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell)
ut.splitToRows(cell)
rng.moveToBookmark(bk).select()
}
}
UE.commands['splittocols'] = {
queryCommandState: function () {
var tableItems = getTableItemsByRange(this),
cell = tableItems.cell
if (!cell) return -1
var ut = getUETable(tableItems.table)
if (ut.selectedTds.length > 0) return -1
return cell && cell.colSpan > 1 ? 0 : -1
},
execCommand: function () {
var rng = this.selection.getRange(),
bk = rng.createBookmark(true)
var cell = getTableItemsByRange(this).cell,
ut = getUETable(cell)
ut.splitToCols(cell)
rng.moveToBookmark(bk).select()
}
}
UE.commands['adaptbytext'] = UE.commands['adaptbywindow'] = {
queryCommandState: function () {
return getTableItemsByRange(this).table ? 0 : -1
},
execCommand: function (cmd) {
var tableItems = getTableItemsByRange(this),
table = tableItems.table
if (table) {
if (cmd == 'adaptbywindow') {
resetTdWidth(table, this)
} else {
var cells = domUtils.getElementsByTagName(table, 'td th')
utils.each(cells, function (cell) {
cell.removeAttribute('width')
})
table.removeAttribute('width')
}
}
}
}
//平均分配各列
UE.commands['averagedistributecol'] = {
queryCommandState: function () {
var ut = getUETableBySelected(this)
if (!ut) return -1
return ut.isFullRow() || ut.isFullCol() ? 0 : -1
},
execCommand: function (cmd) {
var me = this,
ut = getUETableBySelected(me)
function getAverageWidth() {
var tb = ut.table,
averageWidth,
sumWidth = 0,
colsNum = 0,
tbAttr = getDefaultValue(me, tb)
if (ut.isFullRow()) {
sumWidth = tb.offsetWidth
colsNum = ut.colsNum
} else {
var begin = ut.cellsRange.beginColIndex,
end = ut.cellsRange.endColIndex,
node
for (var i = begin; i <= end; ) {
node = ut.selectedTds[i]
sumWidth += node.offsetWidth
i += node.colSpan
colsNum += 1
}
}
averageWidth =
Math.ceil(sumWidth / colsNum) -
tbAttr.tdBorder * 2 -
tbAttr.tdPadding * 2
return averageWidth
}
function setAverageWidth(averageWidth) {
utils.each(
domUtils.getElementsByTagName(ut.table, 'th'),
function (node) {
node.setAttribute('width', '')
}
)
var cells = ut.isFullRow()
? domUtils.getElementsByTagName(ut.table, 'td')
: ut.selectedTds
utils.each(cells, function (node) {
if (node.colSpan == 1) {
node.setAttribute('width', averageWidth)
}
})
}
if (ut && ut.selectedTds.length) {
setAverageWidth(getAverageWidth())
}
}
}
//平均分配各行
UE.commands['averagedistributerow'] = {
queryCommandState: function () {
var ut = getUETableBySelected(this)
if (!ut) return -1
if (ut.selectedTds && /th/gi.test(ut.selectedTds[0].tagName)) return -1
return ut.isFullRow() || ut.isFullCol() ? 0 : -1
},
execCommand: function (cmd) {
var me = this,
ut = getUETableBySelected(me)
function getAverageHeight() {
var averageHeight,
rowNum,
sumHeight = 0,
tb = ut.table,
tbAttr = getDefaultValue(me, tb),
tdpadding = parseInt(
domUtils.getComputedStyle(
tb.getElementsByTagName('td')[0],
'padding-top'
)
)
if (ut.isFullCol()) {
var captionArr = domUtils.getElementsByTagName(tb, 'caption'),
thArr = domUtils.getElementsByTagName(tb, 'th'),
captionHeight,
thHeight
if (captionArr.length > 0) {
captionHeight = captionArr[0].offsetHeight
}
if (thArr.length > 0) {
thHeight = thArr[0].offsetHeight
}
sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0)
rowNum = thArr.length == 0 ? ut.rowsNum : ut.rowsNum - 1
} else {
var begin = ut.cellsRange.beginRowIndex,
end = ut.cellsRange.endRowIndex,
count = 0,
trs = domUtils.getElementsByTagName(tb, 'tr')
for (var i = begin; i <= end; i++) {
sumHeight += trs[i].offsetHeight
count += 1
}
rowNum = count
}
//ie8下是混杂模式
if (browser.ie && browser.version < 9) {
averageHeight = Math.ceil(sumHeight / rowNum)
} else {
averageHeight =
Math.ceil(sumHeight / rowNum) -
tbAttr.tdBorder * 2 -
tdpadding * 2
}
return averageHeight
}
function setAverageHeight(averageHeight) {
var cells = ut.isFullCol()
? domUtils.getElementsByTagName(ut.table, 'td')
: ut.selectedTds
utils.each(cells, function (node) {
if (node.rowSpan == 1) {
node.setAttribute('height', averageHeight)
}
})
}
if (ut && ut.selectedTds.length) {
setAverageHeight(getAverageHeight())
}
}
}
//单元格对齐方式
UE.commands['cellalignment'] = {
queryCommandState: function () {
return getTableItemsByRange(this).table ? 0 : -1
},
execCommand: function (cmd, data) {
var me = this,
ut = getUETableBySelected(me)
if (!ut) {
var start = me.selection.getStart(),
cell =
start &&
domUtils.findParentByTagName(start, ['td', 'th', 'caption'], true)
if (!/caption/gi.test(cell.tagName)) {
domUtils.setAttributes(cell, data)
} else {
cell.style.textAlign = data.align
cell.style.verticalAlign = data.vAlign
}
me.selection.getRange().setCursor(true)
} else {
utils.each(ut.selectedTds, function (cell) {
domUtils.setAttributes(cell, data)
})
}
},
/**
* 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态
* @see UE.UETable.getTableCellAlignState
*/
queryCommandValue: function (cmd) {
var activeMenuCell = getTableItemsByRange(this).cell
if (!activeMenuCell) {
activeMenuCell = getSelectedArr(this)[0]
}
if (!activeMenuCell) {
return null
} else {
//获取同时选中的其他单元格
var cells = UE.UETable.getUETable(activeMenuCell).selectedTds
!cells.length && (cells = activeMenuCell)
return UE.UETable.getTableCellAlignState(cells)
}
}
}
//表格对齐方式
UE.commands['tablealignment'] = {
queryCommandState: function () {
if (browser.ie && browser.version < 8) {
return -1
}
return getTableItemsByRange(this).table ? 0 : -1
},
execCommand: function (cmd, value) {
var me = this,
start = me.selection.getStart(),
table = start && domUtils.findParentByTagName(start, ['table'], true)
if (table) {
table.setAttribute('align', value)
}
}
}
//表格属性
UE.commands['edittable'] = {
queryCommandState: function () {
return getTableItemsByRange(this).table ? 0 : -1
},
execCommand: function (cmd, color) {
var rng = this.selection.getRange(),
table = domUtils.findParentByTagName(rng.startContainer, 'table')
if (table) {
var arr = domUtils
.getElementsByTagName(table, 'td')
.concat(
domUtils.getElementsByTagName(table, 'th'),
domUtils.getElementsByTagName(table, 'caption')
)
utils.each(arr, function (node) {
node.style.borderColor = color
})
}
}
}
//单元格属性
UE.commands['edittd'] = {
queryCommandState: function () {
return getTableItemsByRange(this).table ? 0 : -1
},
execCommand: function (cmd, bkColor) {
var me = this,
ut = getUETableBySelected(me)
if (!ut) {
var start = me.selection.getStart(),
cell =
start &&
domUtils.findParentByTagName(start, ['td', 'th', 'caption'], true)
if (cell) {
cell.style.backgroundColor = bkColor
}
} else {
utils.each(ut.selectedTds, function (cell) {
cell.style.backgroundColor = bkColor
})
}
}
}
UE.commands['settablebackground'] = {
queryCommandState: function () {
return getSelectedArr(this).length > 1 ? 0 : -1
},
execCommand: function (cmd, value) {
var cells, ut
cells = getSelectedArr(this)
ut = getUETable(cells[0])
ut.setBackground(cells, value)
}
}
UE.commands['cleartablebackground'] = {
queryCommandState: function () {
var cells = getSelectedArr(this)
if (!cells.length) return -1
for (var i = 0, cell; (cell = cells[i++]); ) {
if (cell.style.backgroundColor !== '') return 0
}
return -1
},
execCommand: function () {
var cells = getSelectedArr(this),
ut = getUETable(cells[0])
ut.removeBackground(cells)
}
}
UE.commands['interlacetable'] = UE.commands['uninterlacetable'] = {
queryCommandState: function (cmd) {
var table = getTableItemsByRange(this).table
if (!table) return -1
var interlaced = table.getAttribute('interlaced')
if (cmd == 'interlacetable') {
//TODO 待定
//是否需要待定,如果设置,则命令只能单次执行成功,但反射具备toggle效果;否则可以覆盖前次命令,但反射将不存在toggle效果
return interlaced === 'enabled' ? -1 : 0
} else {
return !interlaced || interlaced === 'disabled' ? -1 : 0
}
},
execCommand: function (cmd, classList) {
var table = getTableItemsByRange(this).table
if (cmd == 'interlacetable') {
table.setAttribute('interlaced', 'enabled')
this.fireEvent('interlacetable', table, classList)
} else {
table.setAttribute('interlaced', 'disabled')
this.fireEvent('uninterlacetable', table)
}
}
}
UE.commands['setbordervisible'] = {
queryCommandState: function (cmd) {
var table = getTableItemsByRange(this).table
if (!table) return -1
return 0
},
execCommand: function () {
var table = getTableItemsByRange(this).table
utils.each(domUtils.getElementsByTagName(table, 'td'), function (td) {
td.style.borderWidth = '1px'
td.style.borderStyle = 'solid'
})
}
}
function resetTdWidth(table, editor) {
var tds = domUtils.getElementsByTagName(table, 'td th')
utils.each(tds, function (td) {
td.removeAttribute('width')
})
table.setAttribute(
'width',
getTableWidth(editor, true, getDefaultValue(editor, table))
)
var tdsWidths = []
setTimeout(function () {
utils.each(tds, function (td) {
td.colSpan == 1 && tdsWidths.push(td.offsetWidth)
})
utils.each(tds, function (td, i) {
td.colSpan == 1 && td.setAttribute('width', tdsWidths[i] + '')
})
}, 0)
}
function getTableWidth(editor, needIEHack, defaultValue) {
var body = editor.body
return (
body.offsetWidth -
(needIEHack
? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2
: 0) -
defaultValue.tableBorder * 2 -
(editor.options.offsetWidth || 0)
)
}
function getSelectedArr(editor) {
var cell = getTableItemsByRange(editor).cell
if (cell) {
var ut = getUETable(cell)
return ut.selectedTds.length ? ut.selectedTds : [cell]
} else {
return []
}
}
})()
// plugins/table.action.js
/**
* Created with JetBrains PhpStorm.
* User: taoqili
* Date: 12-10-12
* Time: 上午10:05
* To change this template use File | Settings | File Templates.
*/
UE.plugins['table'] = function () {
var me = this,
tabTimer = null,
//拖动计时器
tableDragTimer = null,
//双击计时器
tableResizeTimer = null,
//单元格最小宽度
cellMinWidth = 5,
isInResizeBuffer = false,
//单元格边框大小
cellBorderWidth = 5,
//鼠标偏移距离
offsetOfTableCell = 10,
//记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
singleClickState = 0,
userActionStatus = null,
//双击允许的时间范围
dblclickTime = 360,
UT = UE.UETable,
getUETable = function (tdOrTable) {
return UT.getUETable(tdOrTable)
},
getUETableBySelected = function (editor) {
return UT.getUETableBySelected(editor)
},
getDefaultValue = function (editor, table) {
return UT.getDefaultValue(editor, table)
},
removeSelectedClass = function (cells) {
return UT.removeSelectedClass(cells)
}
function showError(e) {
// throw e;
}
me.ready(function () {
var me = this
var orgGetText = me.selection.getText
me.selection.getText = function () {
var table = getUETableBySelected(me)
if (table) {
var str = ''
utils.each(table.selectedTds, function (td) {
str += td[browser.ie ? 'innerText' : 'textContent']
})
return str
} else {
return orgGetText.call(me.selection)
}
}
})
//处理拖动及框选相关方法
var startTd = null, //鼠标按下时的锚点td
currentTd = null, //当前鼠标经过时的td
onDrag = '', //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
dragButton = null,
dragOver = false,
dragLine = null, //模拟的拖动线
dragTd = null //发生拖动的目标td
var mousedown = false,
//todo 判断混乱模式
needIEHack = true
me.setOpt({
maxColNum: 20,
maxRowNum: 100,
defaultCols: 5,
defaultRows: 5,
tdvalign: 'top',
cursorpath: me.options.UEDITOR_HOME_URL + 'themes/default/images/cursor_',
tableDragable: false,
classList: [
'ue-table-interlace-color-single',
'ue-table-interlace-color-double'
]
})
me.getUETable = getUETable
var commands = {
deletetable: 1,
inserttable: 1,
cellvalign: 1,
insertcaption: 1,
deletecaption: 1,
inserttitle: 1,
deletetitle: 1,
mergeright: 1,
mergedown: 1,
mergecells: 1,
insertrow: 1,
insertrownext: 1,
deleterow: 1,
insertcol: 1,
insertcolnext: 1,
deletecol: 1,
splittocells: 1,
splittorows: 1,
splittocols: 1,
adaptbytext: 1,
adaptbywindow: 1,
adaptbycustomer: 1,
insertparagraph: 1,
insertparagraphbeforetable: 1,
averagedistributecol: 1,
averagedistributerow: 1
}
me.ready(function () {
utils.cssRule(
'table',
//选中的td上的样式
'.selectTdClass{background-color:#edf5fa !important}' +
'table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}' +
//插入的表格的默认样式
'table{margin-bottom:10px;border-collapse:collapse;display:table;}' +
'td,th{padding: 5px 10px;border: 1px solid #DDD;}' +
'caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}' +
'th{border-top:1px solid #BBB;background-color:#F7F7F7;}' +
'table tr.firstRow th{border-top-width:2px;}' +
'.ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }' +
'td p{margin:0;padding:0;}',
me.document
)
var tableCopyList, isFullCol, isFullRow
//注册del/backspace事件
me.addListener('keydown', function (cmd, evt) {
var me = this
var keyCode = evt.keyCode || evt.which
if (keyCode == 8) {
var ut = getUETableBySelected(me)
if (ut && ut.selectedTds.length) {
if (ut.isFullCol()) {
me.execCommand('deletecol')
} else if (ut.isFullRow()) {
me.execCommand('deleterow')
} else {
me.fireEvent('delcells')
}
domUtils.preventDefault(evt)
}
var caption = domUtils.findParentByTagName(
me.selection.getStart(),
'caption',
true
),
range = me.selection.getRange()
if (range.collapsed && caption && isEmptyBlock(caption)) {
me.fireEvent('saveScene')
var table = caption.parentNode
domUtils.remove(caption)
if (table) {
range.setStart(table.rows[0].cells[0], 0).setCursor(false, true)
}
me.fireEvent('saveScene')
}
}
if (keyCode == 46) {
ut = getUETableBySelected(me)
if (ut) {
me.fireEvent('saveScene')
for (var i = 0, ci; (ci = ut.selectedTds[i++]); ) {
domUtils.fillNode(me.document, ci)
}
me.fireEvent('saveScene')
domUtils.preventDefault(evt)
}
}
if (keyCode == 13) {
var rng = me.selection.getRange(),
caption = domUtils.findParentByTagName(
rng.startContainer,
'caption',
true
)
if (caption) {
var table = domUtils.findParentByTagName(caption, 'table')
if (!rng.collapsed) {
rng.deleteContents()
me.fireEvent('saveScene')
} else {
if (caption) {
rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true)
}
}
domUtils.preventDefault(evt)
return
}
if (rng.collapsed) {
var table = domUtils.findParentByTagName(
rng.startContainer,
'table'
)
if (table) {
var cell = table.rows[0].cells[0],
start = domUtils.findParentByTagName(
me.selection.getStart(),
['td', 'th'],
true
),
preNode = table.previousSibling
if (
cell === start &&
(!preNode ||
(preNode.nodeType == 1 && preNode.tagName == 'TABLE')) &&
domUtils.isStartInblock(rng)
) {
var first = domUtils.findParent(
me.selection.getStart(),
function (n) {
return domUtils.isBlockElm(n)
},
true
)
if (
first &&
(/t(h|d)/i.test(first.tagName) || first === start.firstChild)
) {
me.execCommand('insertparagraphbeforetable')
domUtils.preventDefault(evt)
}
}
}
}
}
if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == '67') {
tableCopyList = null
var ut = getUETableBySelected(me)
if (ut) {
var tds = ut.selectedTds
isFullCol = ut.isFullCol()
isFullRow = ut.isFullRow()
tableCopyList = [[ut.cloneCell(tds[0], null, true)]]
for (var i = 1, ci; (ci = tds[i]); i++) {
if (ci.parentNode !== tds[i - 1].parentNode) {
tableCopyList.push([ut.cloneCell(ci, null, true)])
} else {
tableCopyList[tableCopyList.length - 1].push(
ut.cloneCell(ci, null, true)
)
}
}
}
}
})
me.addListener('tablehasdeleted', function () {
toggleDraggableState(this, false, '', null)
if (dragButton) domUtils.remove(dragButton)
})
me.addListener('beforepaste', function (cmd, html) {
var me = this
var rng = me.selection.getRange()
if (domUtils.findParentByTagName(rng.startContainer, 'caption', true)) {
var div = me.document.createElement('div')
div.innerHTML = html.html
//trace:3729
html.html = div[browser.ie9below ? 'innerText' : 'textContent']
return
}
var table = getUETableBySelected(me)
if (tableCopyList) {
me.fireEvent('saveScene')
var rng = me.selection.getRange()
var td = domUtils.findParentByTagName(
rng.startContainer,
['td', 'th'],
true
),
tmpNode,
preNode
if (td) {
var ut = getUETable(td)
if (isFullRow) {
var rowIndex = ut.getCellInfo(td).rowIndex
if (td.tagName == 'TH') {
rowIndex++
}
for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
var tr = ut.insertRow(rowIndex++, 'td')
for (var j = 0, cj; (cj = ci[j]); j++) {
var cell = tr.cells[j]
if (!cell) {
cell = tr.insertCell(j)
}
cell.innerHTML = cj.innerHTML
cj.getAttribute('width') &&
cell.setAttribute('width', cj.getAttribute('width'))
cj.getAttribute('vAlign') &&
cell.setAttribute('vAlign', cj.getAttribute('vAlign'))
cj.getAttribute('align') &&
cell.setAttribute('align', cj.getAttribute('align'))
cj.style.cssText && (cell.style.cssText = cj.style.cssText)
}
for (var j = 0, cj; (cj = tr.cells[j]); j++) {
if (!ci[j]) break
cj.innerHTML = ci[j].innerHTML
ci[j].getAttribute('width') &&
cj.setAttribute('width', ci[j].getAttribute('width'))
ci[j].getAttribute('vAlign') &&
cj.setAttribute('vAlign', ci[j].getAttribute('vAlign'))
ci[j].getAttribute('align') &&
cj.setAttribute('align', ci[j].getAttribute('align'))
ci[j].style.cssText &&
(cj.style.cssText = ci[j].style.cssText)
}
}
} else {
if (isFullCol) {
cellInfo = ut.getCellInfo(td)
var maxColNum = 0
for (var j = 0, ci = tableCopyList[0], cj; (cj = ci[j++]); ) {
maxColNum += cj.colSpan || 1
}
me.__hasEnterExecCommand = true
for (i = 0; i < maxColNum; i++) {
me.execCommand('insertcol')
}
me.__hasEnterExecCommand = false
td = ut.table.rows[0].cells[cellInfo.cellIndex]
if (td.tagName == 'TH') {
td = ut.table.rows[1].cells[cellInfo.cellIndex]
}
}
for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
tmpNode = td
for (var j = 0, cj; (cj = ci[j++]); ) {
if (td) {
td.innerHTML = cj.innerHTML
//todo 定制处理
cj.getAttribute('width') &&
td.setAttribute('width', cj.getAttribute('width'))
cj.getAttribute('vAlign') &&
td.setAttribute('vAlign', cj.getAttribute('vAlign'))
cj.getAttribute('align') &&
td.setAttribute('align', cj.getAttribute('align'))
cj.style.cssText && (td.style.cssText = cj.style.cssText)
preNode = td
td = td.nextSibling
} else {
var cloneTd = cj.cloneNode(true)
domUtils.removeAttributes(cloneTd, [
'class',
'rowSpan',
'colSpan'
])
preNode.parentNode.appendChild(cloneTd)
}
}
td = ut.getNextCell(tmpNode, true, true)
if (!tableCopyList[i]) break
if (!td) {
var cellInfo = ut.getCellInfo(tmpNode)
ut.table.insertRow(ut.table.rows.length)
ut.update()
td = ut.getVSideCell(tmpNode, true)
}
}
}
ut.update()
} else {
table = me.document.createElement('table')
for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
var tr = table.insertRow(table.rows.length)
for (var j = 0, cj; (cj = ci[j++]); ) {
cloneTd = UT.cloneCell(cj, null, true)
domUtils.removeAttributes(cloneTd, ['class'])
tr.appendChild(cloneTd)
}
if (j == 2 && cloneTd.rowSpan > 1) {
cloneTd.rowSpan = 1
}
}
var defaultValue = getDefaultValue(me),
width =
me.body.offsetWidth -
(needIEHack
? parseInt(
domUtils.getComputedStyle(me.body, 'margin-left'),
10
) * 2
: 0) -
defaultValue.tableBorder * 2 -
(me.options.offsetWidth || 0)
me.execCommand(
'insertHTML',
'' +
table.innerHTML
.replace(/>\s*<')
.replace(/\bth\b/gi, 'td') +
'
'
)
}
me.fireEvent('contentchange')
me.fireEvent('saveScene')
html.html = ''
return true
} else {
var div = me.document.createElement('div'),
tables
div.innerHTML = html.html
tables = div.getElementsByTagName('table')
if (domUtils.findParentByTagName(me.selection.getStart(), 'table')) {
utils.each(tables, function (t) {
domUtils.remove(t)
})
if (
domUtils.findParentByTagName(
me.selection.getStart(),
'caption',
true
)
) {
div.innerHTML = div[browser.ie ? 'innerText' : 'textContent']
}
} else {
utils.each(tables, function (table) {
removeStyleSize(table, true)
domUtils.removeAttributes(table, ['style', 'border'])
utils.each(
domUtils.getElementsByTagName(table, 'td'),
function (td) {
if (isEmptyBlock(td)) {
domUtils.fillNode(me.document, td)
}
removeStyleSize(td, true)
// domUtils.removeAttributes(td, ['style'])
}
)
})
}
html.html = div.innerHTML
}
})
me.addListener('afterpaste', function () {
utils.each(
domUtils.getElementsByTagName(me.body, 'table'),
function (table) {
if (table.offsetWidth > me.body.offsetWidth) {
var defaultValue = getDefaultValue(me, table)
table.style.width =
me.body.offsetWidth -
(needIEHack
? parseInt(
domUtils.getComputedStyle(me.body, 'margin-left'),
10
) * 2
: 0) -
defaultValue.tableBorder * 2 -
(me.options.offsetWidth || 0) +
'px'
}
}
)
})
me.addListener('blur', function () {
tableCopyList = null
})
var timer
me.addListener('keydown', function () {
clearTimeout(timer)
timer = setTimeout(function () {
var rng = me.selection.getRange(),
cell = domUtils.findParentByTagName(
rng.startContainer,
['th', 'td'],
true
)
if (cell) {
var table = cell.parentNode.parentNode.parentNode
if (table.offsetWidth > table.getAttribute('width')) {
cell.style.wordBreak = 'break-all'
}
}
}, 100)
})
me.addListener('selectionchange', function () {
toggleDraggableState(me, false, '', null)
})
//内容变化时触发索引更新
//todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
me.addListener('contentchange', function () {
var me = this
//尽可能排除一些不需要更新的状况
hideDragLine(me)
if (getUETableBySelected(me)) return
var rng = me.selection.getRange()
var start = rng.startContainer
start = domUtils.findParentByTagName(start, ['td', 'th'], true)
utils.each(
domUtils.getElementsByTagName(me.document, 'table'),
function (table) {
if (me.fireEvent('excludetable', table) === true) return
table.ueTable = new UT(table)
//trace:3742
// utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
//
// if (domUtils.isEmptyBlock(td) && td !== start) {
// domUtils.fillNode(me.document, td);
// if (browser.ie && browser.version == 6) {
// td.innerHTML = ' '
// }
// }
// });
// utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
// if (domUtils.isEmptyBlock(th) && th !== start) {
// domUtils.fillNode(me.document, th);
// if (browser.ie && browser.version == 6) {
// th.innerHTML = ' '
// }
// }
// });
table.onmouseover = function () {
me.fireEvent('tablemouseover', table)
}
table.onmousemove = function () {
me.fireEvent('tablemousemove', table)
me.options.tableDragable && toggleDragButton(true, this, me)
utils.defer(function () {
me.fireEvent('contentchange', 50)
}, true)
}
table.onmouseout = function () {
me.fireEvent('tablemouseout', table)
toggleDraggableState(me, false, '', null)
hideDragLine(me)
}
table.onclick = function (evt) {
evt = me.window.event || evt
var target = getParentTdOrTh(evt.target || evt.srcElement)
if (!target) return
var ut = getUETable(target),
table = ut.table,
cellInfo = ut.getCellInfo(target),
cellsRange,
rng = me.selection.getRange()
// if ("topLeft" == inPosition(table, mouseCoords(evt))) {
// cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
// ut.setSelected(cellsRange);
// return;
// }
// if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
//
// return;
// }
if (inTableSide(table, target, evt, true)) {
var endTdCol = ut.getCell(
ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex,
ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex
)
if (evt.shiftKey && ut.selectedTds.length) {
if (ut.selectedTds[0] !== endTdCol) {
cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol)
ut.setSelected(cellsRange)
} else {
rng && rng.selectNodeContents(endTdCol).select()
}
} else {
if (target !== endTdCol) {
cellsRange = ut.getCellsRange(target, endTdCol)
ut.setSelected(cellsRange)
} else {
rng && rng.selectNodeContents(endTdCol).select()
}
}
return
}
if (inTableSide(table, target, evt)) {
var endTdRow = ut.getCell(
ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex,
ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex
)
if (evt.shiftKey && ut.selectedTds.length) {
if (ut.selectedTds[0] !== endTdRow) {
cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow)
ut.setSelected(cellsRange)
} else {
rng && rng.selectNodeContents(endTdRow).select()
}
} else {
if (target !== endTdRow) {
cellsRange = ut.getCellsRange(target, endTdRow)
ut.setSelected(cellsRange)
} else {
rng && rng.selectNodeContents(endTdRow).select()
}
}
}
}
}
)
switchBorderColor(me, true)
})
domUtils.on(me.document, 'mousemove', mouseMoveEvent)
domUtils.on(me.document, 'mouseout', function (evt) {
var target = evt.target || evt.srcElement
if (target.tagName == 'TABLE') {
toggleDraggableState(me, false, '', null)
}
})
/**
* 表格隔行变色
*/
me.addListener('interlacetable', function (type, table, classList) {
if (!table) return
var me = this,
rows = table.rows,
len = rows.length,
getClass = function (list, index, repeat) {
return list[index]
? list[index]
: repeat
? list[index % list.length]
: ''
}
for (var i = 0; i < len; i++) {
rows[i].className = getClass(
classList || me.options.classList,
i,
true
)
}
})
me.addListener('uninterlacetable', function (type, table) {
if (!table) return
var me = this,
rows = table.rows,
classList = me.options.classList,
len = rows.length
for (var i = 0; i < len; i++) {
domUtils.removeClasses(rows[i], classList)
}
})
me.addListener('mousedown', mouseDownEvent)
me.addListener('mouseup', mouseUpEvent)
//拖动的时候触发mouseup
domUtils.on(me.body, 'dragstart', function (evt) {
mouseUpEvent.call(me, 'dragstart', evt)
})
me.addOutputRule(function (root) {
utils.each(root.getNodesByTagName('div'), function (n) {
if (n.getAttr('id') == 'ue_tableDragLine') {
n.parentNode.removeChild(n)
}
})
})
var currentRowIndex = 0
me.addListener('mousedown', function () {
currentRowIndex = 0
})
me.addListener('tabkeydown', function () {
var range = this.selection.getRange(),
common = range.getCommonAncestor(true, true),
table = domUtils.findParentByTagName(common, 'table')
if (table) {
if (domUtils.findParentByTagName(common, 'caption', true)) {
var cell = domUtils.getElementsByTagName(table, 'th td')
if (cell && cell.length) {
range.setStart(cell[0], 0).setCursor(false, true)
}
} else {
var cell = domUtils.findParentByTagName(common, ['td', 'th'], true),
ua = getUETable(cell)
currentRowIndex =
cell.rowSpan > 1 ? currentRowIndex : ua.getCellInfo(cell).rowIndex
var nextCell = ua.getTabNextCell(cell, currentRowIndex)
if (nextCell) {
if (isEmptyBlock(nextCell)) {
range.setStart(nextCell, 0).setCursor(false, true)
} else {
range.selectNodeContents(nextCell).select()
}
} else {
me.fireEvent('saveScene')
me.__hasEnterExecCommand = true
this.execCommand('insertrownext')
me.__hasEnterExecCommand = false
range = this.selection.getRange()
range
.setStart(table.rows[table.rows.length - 1].cells[0], 0)
.setCursor()
me.fireEvent('saveScene')
}
}
return true
}
})
browser.ie &&
me.addListener('selectionchange', function () {
toggleDraggableState(this, false, '', null)
})
me.addListener('keydown', function (type, evt) {
var me = this
//处理在表格的最后一个输入tab产生新的表格
var keyCode = evt.keyCode || evt.which
if (keyCode == 8 || keyCode == 46) {
return
}
var notCtrlKey =
!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey
notCtrlKey &&
removeSelectedClass(domUtils.getElementsByTagName(me.body, 'td'))
var ut = getUETableBySelected(me)
if (!ut) return
notCtrlKey && ut.clearSelected()
})
me.addListener('beforegetcontent', function () {
switchBorderColor(this, false)
browser.ie &&
utils.each(
this.document.getElementsByTagName('caption'),
function (ci) {
if (domUtils.isEmptyNode(ci)) {
ci.innerHTML = ' '
}
}
)
})
me.addListener('aftergetcontent', function () {
switchBorderColor(this, true)
})
me.addListener('getAllHtml', function () {
removeSelectedClass(me.document.getElementsByTagName('td'))
})
//修正全屏状态下插入的表格宽度在非全屏状态下撑开编辑器的情况
me.addListener('fullscreenchanged', function (type, fullscreen) {
if (!fullscreen) {
var ratio = this.body.offsetWidth / document.body.offsetWidth,
tables = domUtils.getElementsByTagName(this.body, 'table')
utils.each(tables, function (table) {
if (table.offsetWidth < me.body.offsetWidth) return false
var tds = domUtils.getElementsByTagName(table, 'td'),
backWidths = []
utils.each(tds, function (td) {
backWidths.push(td.offsetWidth)
})
for (var i = 0, td; (td = tds[i]); i++) {
td.setAttribute('width', Math.floor(backWidths[i] * ratio))
}
table.setAttribute(
'width',
Math.floor(getTableWidth(me, needIEHack, getDefaultValue(me)))
)
})
}
})
//重写execCommand命令,用于处理框选时的处理
var oldExecCommand = me.execCommand
me.execCommand = function (cmd, datatat) {
var me = this,
args = arguments
cmd = cmd.toLowerCase()
var ut = getUETableBySelected(me),
tds,
range = new dom.Range(me.document),
cmdFun = me.commands[cmd] || UE.commands[cmd],
result
if (!cmdFun) return
if (
ut &&
!commands[cmd] &&
!cmdFun.notNeedUndo &&
!me.__hasEnterExecCommand
) {
me.__hasEnterExecCommand = true
me.fireEvent('beforeexeccommand', cmd)
tds = ut.selectedTds
var lastState = -2,
lastValue = -2,
value,
state
for (var i = 0, td; (td = tds[i]); i++) {
if (isEmptyBlock(td)) {
range.setStart(td, 0).setCursor(false, true)
} else {
range.selectNode(td).select(true)
}
state = me.queryCommandState(cmd)
value = me.queryCommandValue(cmd)
if (state != -1) {
if (lastState !== state || lastValue !== value) {
me._ignoreContentChange = true
result = oldExecCommand.apply(me, arguments)
me._ignoreContentChange = false
}
lastState = me.queryCommandState(cmd)
lastValue = me.queryCommandValue(cmd)
if (domUtils.isEmptyBlock(td)) {
domUtils.fillNode(me.document, td)
}
}
}
range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true)
me.fireEvent('contentchange')
me.fireEvent('afterexeccommand', cmd)
me.__hasEnterExecCommand = false
me._selectionChange()
} else {
result = oldExecCommand.apply(me, arguments)
}
return result
}
})
/**
* 删除obj的宽高style,改成属性宽高
* @param obj
* @param replaceToProperty
*/
function removeStyleSize(obj, replaceToProperty) {
removeStyle(obj, 'width', true)
removeStyle(obj, 'height', true)
}
function removeStyle(obj, styleName, replaceToProperty) {
if (obj.style[styleName]) {
replaceToProperty &&
obj.setAttribute(styleName, parseInt(obj.style[styleName], 10))
obj.style[styleName] = ''
}
}
function getParentTdOrTh(ele) {
if (ele.tagName == 'TD' || ele.tagName == 'TH') return ele
var td
if (
(td =
domUtils.findParentByTagName(ele, 'td', true) ||
domUtils.findParentByTagName(ele, 'th', true))
)
return td
return null
}
function isEmptyBlock(node) {
var reg = new RegExp(domUtils.fillChar, 'g')
if (
node[browser.ie ? 'innerText' : 'textContent']
.replace(/^\s*$/, '')
.replace(reg, '').length > 0
) {
return 0
}
for (var n in dtd.$isNotEmpty) {
if (node.getElementsByTagName(n).length) {
return 0
}
}
return 1
}
function mouseCoords(evt) {
if (evt.pageX || evt.pageY) {
return { x: evt.pageX, y: evt.pageY }
}
return {
x:
evt.clientX +
me.document.body.scrollLeft -
me.document.body.clientLeft,
y: evt.clientY + me.document.body.scrollTop - me.document.body.clientTop
}
}
function mouseMoveEvent(evt) {
if (isEditorDisabled()) {
return
}
try {
//普通状态下鼠标移动
var target = getParentTdOrTh(evt.target || evt.srcElement),
pos
//区分用户的行为是拖动还是双击
if (isInResizeBuffer) {
me.body.style.webkitUserSelect = 'none'
if (
Math.abs(userActionStatus.x - evt.clientX) > offsetOfTableCell ||
Math.abs(userActionStatus.y - evt.clientY) > offsetOfTableCell
) {
clearTableDragTimer()
isInResizeBuffer = false
singleClickState = 0
//drag action
tableBorderDrag(evt)
}
}
//修改单元格大小时的鼠标移动
if (onDrag && dragTd) {
singleClickState = 0
me.body.style.webkitUserSelect = 'none'
me.selection
.getNative()
[browser.ie9below ? 'empty' : 'removeAllRanges']()
pos = mouseCoords(evt)
toggleDraggableState(me, true, onDrag, pos, target)
if (onDrag == 'h') {
dragLine.style.left = getPermissionX(dragTd, evt) + 'px'
} else if (onDrag == 'v') {
dragLine.style.top = getPermissionY(dragTd, evt) + 'px'
}
return
}
//当鼠标处于table上时,修改移动过程中的光标状态
if (target) {
//针对使用table作为容器的组件不触发拖拽效果
if (me.fireEvent('excludetable', target) === true) return
pos = mouseCoords(evt)
var state = getRelation(target, pos),
table = domUtils.findParentByTagName(target, 'table', true)
if (inTableSide(table, target, evt, true)) {
if (me.fireEvent('excludetable', table) === true) return
me.body.style.cursor =
'url(' + me.options.cursorpath + 'h.png),pointer'
} else if (inTableSide(table, target, evt)) {
if (me.fireEvent('excludetable', table) === true) return
me.body.style.cursor =
'url(' + me.options.cursorpath + 'v.png),pointer'
} else {
me.body.style.cursor = 'text'
var curCell = target
if (/\d/.test(state)) {
state = state.replace(/\d/, '')
target = getUETable(target).getPreviewCell(target, state == 'v')
}
//位于第一行的顶部或者第一列的左边时不可拖动
toggleDraggableState(
me,
target ? !!state : false,
target ? state : '',
pos,
target
)
}
} else {
toggleDragButton(false, table, me)
}
} catch (e) {
showError(e)
}
}
var dragButtonTimer
function toggleDragButton(show, table, editor) {
if (!show) {
if (dragOver) return
dragButtonTimer = setTimeout(function () {
!dragOver &&
dragButton &&
dragButton.parentNode &&
dragButton.parentNode.removeChild(dragButton)
}, 2000)
} else {
createDragButton(table, editor)
}
}
function createDragButton(table, editor) {
var pos = domUtils.getXY(table),
doc = table.ownerDocument
if (dragButton && dragButton.parentNode) return dragButton
dragButton = doc.createElement('div')
dragButton.contentEditable = false
dragButton.innerHTML = ''
dragButton.style.cssText =
'width:15px;height:15px;background-image:url(' +
editor.options.UEDITOR_HOME_URL +
'dialogs/table/dragicon.png);position: absolute;cursor:move;top:' +
(pos.y - 15) +
'px;left:' +
pos.x +
'px;'
domUtils.unSelectable(dragButton)
dragButton.onmouseover = function (evt) {
dragOver = true
}
dragButton.onmouseout = function (evt) {
dragOver = false
}
domUtils.on(dragButton, 'click', function (type, evt) {
doClick(evt, this)
})
domUtils.on(dragButton, 'dblclick', function (type, evt) {
doDblClick(evt)
})
domUtils.on(dragButton, 'dragstart', function (type, evt) {
domUtils.preventDefault(evt)
})
var timer
function doClick(evt, button) {
// 部分浏览器下需要清理
clearTimeout(timer)
timer = setTimeout(function () {
editor.fireEvent('tableClicked', table, button)
}, 300)
}
function doDblClick(evt) {
clearTimeout(timer)
var ut = getUETable(table),
start = table.rows[0].cells[0],
end = ut.getLastCell(),
range = ut.getCellsRange(start, end)
editor.selection.getRange().setStart(start, 0).setCursor(false, true)
ut.setSelected(range)
}
doc.body.appendChild(dragButton)
}
// function inPosition(table, pos) {
// var tablePos = domUtils.getXY(table),
// width = table.offsetWidth,
// height = table.offsetHeight;
// if (pos.x - tablePos.x < 5 && pos.y - tablePos.y < 5) {
// return "topLeft";
// } else if (tablePos.x + width - pos.x < 5 && tablePos.y + height - pos.y < 5) {
// return "bottomRight";
// }
// }
function inTableSide(table, cell, evt, top) {
var pos = mouseCoords(evt),
state = getRelation(cell, pos)
if (top) {
var caption = table.getElementsByTagName('caption')[0],
capHeight = caption ? caption.offsetHeight : 0
return state == 'v1' && pos.y - domUtils.getXY(table).y - capHeight < 8
} else {
return state == 'h1' && pos.x - domUtils.getXY(table).x < 8
}
}
/**
* 获取拖动时允许的X轴坐标
* @param dragTd
* @param evt
*/
function getPermissionX(dragTd, evt) {
var ut = getUETable(dragTd)
if (ut) {
var preTd = ut.getSameEndPosCells(dragTd, 'x')[0],
nextTd = ut.getSameStartPosXCells(dragTd)[0],
mouseX = mouseCoords(evt).x,
left =
(preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20,
right = nextTd
? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20
: me.body.offsetWidth + 5 ||
parseInt(domUtils.getComputedStyle(me.body, 'width'), 10)
left += cellMinWidth
right -= cellMinWidth
return mouseX < left ? left : mouseX > right ? right : mouseX
}
}
/**
* 获取拖动时允许的Y轴坐标
*/
function getPermissionY(dragTd, evt) {
try {
var top = domUtils.getXY(dragTd).y,
mousePosY = mouseCoords(evt).y
return mousePosY < top ? top : mousePosY
} catch (e) {
showError(e)
}
}
/**
* 移动状态切换
*/
function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
try {
editor.body.style.cursor =
dir == 'h' ? 'col-resize' : dir == 'v' ? 'row-resize' : 'text'
if (browser.ie) {
if (dir && !mousedown && !getUETableBySelected(editor)) {
getDragLine(editor, editor.document)
showDragLineAt(dir, cell)
} else {
hideDragLine(editor)
}
}
onBorder = draggable
} catch (e) {
showError(e)
}
}
/**
* 获取与UETable相关的resize line
* @param uetable UETable对象
*/
function getResizeLineByUETable() {
var lineId = '_UETableResizeLine',
line = this.document.getElementById(lineId)
if (!line) {
line = this.document.createElement('div')
line.id = lineId
line.contnetEditable = false
line.setAttribute('unselectable', 'on')
var styles = {
width: 2 * cellBorderWidth + 1 + 'px',
position: 'absolute',
'z-index': 100000,
cursor: 'col-resize',
background: 'red',
display: 'none'
}
//切换状态
line.onmouseout = function () {
this.style.display = 'none'
}
utils.extend(line.style, styles)
this.document.body.appendChild(line)
}
return line
}
/**
* 更新resize-line
*/
function updateResizeLine(cell, uetable) {
var line = getResizeLineByUETable.call(this),
table = uetable.table,
styles = {
top: domUtils.getXY(table).y + 'px',
left:
domUtils.getXY(cell).x + cell.offsetWidth - cellBorderWidth + 'px',
display: 'block',
height: table.offsetHeight + 'px'
}
utils.extend(line.style, styles)
}
/**
* 显示resize-line
*/
function showResizeLine(cell) {
var uetable = getUETable(cell)
updateResizeLine.call(this, cell, uetable)
}
/**
* 获取鼠标与当前单元格的相对位置
* @param ele
* @param mousePos
*/
function getRelation(ele, mousePos) {
var elePos = domUtils.getXY(ele)
if (!elePos) {
return ''
}
if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
return 'h'
}
if (mousePos.x - elePos.x < cellBorderWidth) {
return 'h1'
}
if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
return 'v'
}
if (mousePos.y - elePos.y < cellBorderWidth) {
return 'v1'
}
return ''
}
function mouseDownEvent(type, evt) {
if (isEditorDisabled()) {
return
}
userActionStatus = {
x: evt.clientX,
y: evt.clientY
}
//右键菜单单独处理
if (evt.button == 2) {
var ut = getUETableBySelected(me),
flag = false
if (ut) {
var td = getTargetTd(me, evt)
utils.each(ut.selectedTds, function (ti) {
if (ti === td) {
flag = true
}
})
if (!flag) {
removeSelectedClass(domUtils.getElementsByTagName(me.body, 'th td'))
ut.clearSelected()
} else {
td = ut.selectedTds[0]
setTimeout(function () {
me.selection.getRange().setStart(td, 0).setCursor(false, true)
}, 0)
}
}
} else {
tableClickHander(evt)
}
}
//清除表格的计时器
function clearTableTimer() {
tabTimer && clearTimeout(tabTimer)
tabTimer = null
}
//双击收缩
function tableDbclickHandler(evt) {
singleClickState = 0
evt = evt || me.window.event
var target = getParentTdOrTh(evt.target || evt.srcElement)
if (target) {
var h
if ((h = getRelation(target, mouseCoords(evt)))) {
hideDragLine(me)
if (h == 'h1') {
h = 'h'
if (
inTableSide(
domUtils.findParentByTagName(target, 'table'),
target,
evt
)
) {
me.execCommand('adaptbywindow')
} else {
target = getUETable(target).getPreviewCell(target)
if (target) {
var rng = me.selection.getRange()
rng.selectNodeContents(target).setCursor(true, true)
}
}
}
if (h == 'h') {
var ut = getUETable(target),
table = ut.table,
cells = getCellsByMoveBorder(target, table, true)
cells = extractArray(cells, 'left')
ut.width = ut.offsetWidth
var oldWidth = [],
newWidth = []
utils.each(cells, function (cell) {
oldWidth.push(cell.offsetWidth)
})
utils.each(cells, function (cell) {
cell.removeAttribute('width')
})
window.setTimeout(function () {
//是否允许改变
var changeable = true
utils.each(cells, function (cell, index) {
var width = cell.offsetWidth
if (width > oldWidth[index]) {
changeable = false
return false
}
newWidth.push(width)
})
var change = changeable ? newWidth : oldWidth
utils.each(cells, function (cell, index) {
cell.width = change[index] - getTabcellSpace()
})
}, 0)
// minWidth -= cellMinWidth;
//
// table.removeAttribute("width");
// utils.each(cells, function (cell) {
// cell.style.width = "";
// cell.width -= minWidth;
// });
}
}
}
}
function tableClickHander(evt) {
removeSelectedClass(domUtils.getElementsByTagName(me.body, 'td th'))
//trace:3113
//选中单元格,点击table外部,不会清掉table上挂的ueTable,会引起getUETableBySelected方法返回值
utils.each(me.document.getElementsByTagName('table'), function (t) {
t.ueTable = null
})
startTd = getTargetTd(me, evt)
if (!startTd) return
var table = domUtils.findParentByTagName(startTd, 'table', true)
ut = getUETable(table)
ut && ut.clearSelected()
//判断当前鼠标状态
if (!onBorder) {
me.document.body.style.webkitUserSelect = ''
mousedown = true
me.addListener('mouseover', mouseOverEvent)
} else {
//边框上的动作处理
borderActionHandler(evt)
}
}
//处理表格边框上的动作, 这里做延时处理,避免两种动作互相影响
function borderActionHandler(evt) {
if (browser.ie) {
evt = reconstruct(evt)
}
clearTableDragTimer()
//是否正在等待resize的缓冲中
isInResizeBuffer = true
tableDragTimer = setTimeout(function () {
tableBorderDrag(evt)
}, dblclickTime)
}
function extractArray(originArr, key) {
var result = [],
tmp = null
for (var i = 0, len = originArr.length; i < len; i++) {
tmp = originArr[i][key]
if (tmp) {
result.push(tmp)
}
}
return result
}
function clearTableDragTimer() {
tableDragTimer && clearTimeout(tableDragTimer)
tableDragTimer = null
}
function reconstruct(obj) {
var attrs = [
'pageX',
'pageY',
'clientX',
'clientY',
'srcElement',
'target'
],
newObj = {}
if (obj) {
for (var i = 0, key, val; (key = attrs[i]); i++) {
val = obj[key]
val && (newObj[key] = val)
}
}
return newObj
}
//边框拖动
function tableBorderDrag(evt) {
isInResizeBuffer = false
startTd = evt.target || evt.srcElement
if (!startTd) return
var state = getRelation(startTd, mouseCoords(evt))
if (/\d/.test(state)) {
state = state.replace(/\d/, '')
startTd = getUETable(startTd).getPreviewCell(startTd, state == 'v')
}
hideDragLine(me)
getDragLine(me, me.document)
me.fireEvent('saveScene')
showDragLineAt(state, startTd)
mousedown = true
//拖动开始
onDrag = state
dragTd = startTd
}
function mouseUpEvent(type, evt) {
if (isEditorDisabled()) {
return
}
clearTableDragTimer()
isInResizeBuffer = false
if (onBorder) {
singleClickState = ++singleClickState % 3
userActionStatus = {
x: evt.clientX,
y: evt.clientY
}
tableResizeTimer = setTimeout(function () {
singleClickState > 0 && singleClickState--
}, dblclickTime)
if (singleClickState === 2) {
singleClickState = 0
tableDbclickHandler(evt)
return
}
}
if (evt.button == 2) return
var me = this
//清除表格上原生跨选问题
var range = me.selection.getRange(),
start = domUtils.findParentByTagName(
range.startContainer,
'table',
true
),
end = domUtils.findParentByTagName(range.endContainer, 'table', true)
if (start || end) {
if (start === end) {
start = domUtils.findParentByTagName(
range.startContainer,
['td', 'th', 'caption'],
true
)
end = domUtils.findParentByTagName(
range.endContainer,
['td', 'th', 'caption'],
true
)
if (start !== end) {
me.selection.clearRange()
}
} else {
me.selection.clearRange()
}
}
mousedown = false
me.document.body.style.webkitUserSelect = ''
//拖拽状态下的mouseUP
if (onDrag && dragTd) {
me.selection
.getNative()
[browser.ie9below ? 'empty' : 'removeAllRanges']()
singleClickState = 0
dragLine = me.document.getElementById('ue_tableDragLine')
// trace 3973
if (dragLine) {
var dragTdPos = domUtils.getXY(dragTd),
dragLinePos = domUtils.getXY(dragLine)
switch (onDrag) {
case 'h':
changeColWidth(dragTd, dragLinePos.x - dragTdPos.x)
break
case 'v':
changeRowHeight(
dragTd,
dragLinePos.y - dragTdPos.y - dragTd.offsetHeight
)
break
default:
}
onDrag = ''
dragTd = null
hideDragLine(me)
me.fireEvent('saveScene')
return
}
}
//正常状态下的mouseup
if (!startTd) {
var target = domUtils.findParentByTagName(
evt.target || evt.srcElement,
'td',
true
)
if (!target)
target = domUtils.findParentByTagName(
evt.target || evt.srcElement,
'th',
true
)
if (target && (target.tagName == 'TD' || target.tagName == 'TH')) {
if (me.fireEvent('excludetable', target) === true) return
range = new dom.Range(me.document)
range.setStart(target, 0).setCursor(false, true)
}
} else {
var ut = getUETable(startTd),
cell = ut ? ut.selectedTds[0] : null
if (cell) {
range = new dom.Range(me.document)
if (domUtils.isEmptyBlock(cell)) {
range.setStart(cell, 0).setCursor(false, true)
} else {
range
.selectNodeContents(cell)
.shrinkBoundary()
.setCursor(false, true)
}
} else {
range = me.selection.getRange().shrinkBoundary()
if (!range.collapsed) {
var start = domUtils.findParentByTagName(
range.startContainer,
['td', 'th'],
true
),
end = domUtils.findParentByTagName(
range.endContainer,
['td', 'th'],
true
)
//在table里边的不能清除
if (
(start && !end) ||
(!start && end) ||
(start && end && start !== end)
) {
range.setCursor(false, true)
}
}
}
startTd = null
me.removeListener('mouseover', mouseOverEvent)
}
me._selectionChange(250, evt)
}
function mouseOverEvent(type, evt) {
if (isEditorDisabled()) {
return
}
var me = this,
tar = evt.target || evt.srcElement
currentTd =
domUtils.findParentByTagName(tar, 'td', true) ||
domUtils.findParentByTagName(tar, 'th', true)
//需要判断两个TD是否位于同一个表格内
if (
startTd &&
currentTd &&
((startTd.tagName == 'TD' && currentTd.tagName == 'TD') ||
(startTd.tagName == 'TH' && currentTd.tagName == 'TH')) &&
domUtils.findParentByTagName(startTd, 'table') ==
domUtils.findParentByTagName(currentTd, 'table')
) {
var ut = getUETable(currentTd)
if (startTd != currentTd) {
me.document.body.style.webkitUserSelect = 'none'
me.selection
.getNative()
[browser.ie9below ? 'empty' : 'removeAllRanges']()
var range = ut.getCellsRange(startTd, currentTd)
ut.setSelected(range)
} else {
me.document.body.style.webkitUserSelect = ''
ut.clearSelected()
}
}
evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false)
}
function setCellHeight(cell, height, backHeight) {
var lineHight = parseInt(
domUtils.getComputedStyle(cell, 'line-height'),
10
),
tmpHeight = backHeight + height
height = tmpHeight < lineHight ? lineHight : tmpHeight
if (cell.style.height) cell.style.height = ''
cell.rowSpan == 1
? cell.setAttribute('height', height)
: cell.removeAttribute && cell.removeAttribute('height')
}
function getWidth(cell) {
if (!cell) return 0
return parseInt(domUtils.getComputedStyle(cell, 'width'), 10)
}
function changeColWidth(cell, changeValue) {
var ut = getUETable(cell)
if (ut) {
//根据当前移动的边框获取相关的单元格
var table = ut.table,
cells = getCellsByMoveBorder(cell, table)
table.style.width = ''
table.removeAttribute('width')
//修正改变量
changeValue = correctChangeValue(changeValue, cell, cells)
if (cell.nextSibling) {
var i = 0
utils.each(cells, function (cellGroup) {
cellGroup.left.width = +cellGroup.left.width + changeValue
cellGroup.right &&
(cellGroup.right.width = +cellGroup.right.width - changeValue)
})
} else {
utils.each(cells, function (cellGroup) {
cellGroup.left.width -= -changeValue
})
}
}
}
function isEditorDisabled() {
return me.body.contentEditable === 'false'
}
function changeRowHeight(td, changeValue) {
if (Math.abs(changeValue) < 10) return
var ut = getUETable(td)
if (ut) {
var cells = ut.getSameEndPosCells(td, 'y'),
//备份需要连带变化的td的原始高度,否则后期无法获取正确的值
backHeight = cells[0] ? cells[0].offsetHeight : 0
for (var i = 0, cell; (cell = cells[i++]); ) {
setCellHeight(cell, changeValue, backHeight)
}
}
}
/**
* 获取调整单元格大小的相关单元格
* @isContainMergeCell 返回的结果中是否包含发生合并后的单元格
*/
function getCellsByMoveBorder(cell, table, isContainMergeCell) {
if (!table) {
table = domUtils.findParentByTagName(cell, 'table')
}
if (!table) {
return null
}
//获取到该单元格所在行的序列号
var index = domUtils.getNodeIndex(cell),
temp = cell,
rows = table.rows,
colIndex = 0
while (temp) {
//获取到当前单元格在未发生单元格合并时的序列
if (temp.nodeType === 1) {
colIndex += temp.colSpan || 1
}
temp = temp.previousSibling
}
temp = null
//记录想关的单元格
var borderCells = []
utils.each(rows, function (tabRow) {
var cells = tabRow.cells,
currIndex = 0
utils.each(cells, function (tabCell) {
currIndex += tabCell.colSpan || 1
if (currIndex === colIndex) {
borderCells.push({
left: tabCell,
right: tabCell.nextSibling || null
})
return false
} else if (currIndex > colIndex) {
if (isContainMergeCell) {
borderCells.push({
left: tabCell
})
}
return false
}
})
})
return borderCells
}
/**
* 通过给定的单元格集合获取最小的单元格width
*/
function getMinWidthByTableCells(cells) {
var minWidth = Number.MAX_VALUE
for (var i = 0, curCell; (curCell = cells[i]); i++) {
minWidth = Math.min(
minWidth,
curCell.width || getTableCellWidth(curCell)
)
}
return minWidth
}
function correctChangeValue(changeValue, relatedCell, cells) {
//为单元格的paading预留空间
changeValue -= getTabcellSpace()
if (changeValue < 0) {
return 0
}
changeValue -= getTableCellWidth(relatedCell)
//确定方向
var direction = changeValue < 0 ? 'left' : 'right'
changeValue = Math.abs(changeValue)
//只关心非最后一个单元格就可以
utils.each(cells, function (cellGroup) {
var curCell = cellGroup[direction]
//为单元格保留最小空间
if (curCell) {
changeValue = Math.min(
changeValue,
getTableCellWidth(curCell) - cellMinWidth
)
}
})
//修正越界
changeValue = changeValue < 0 ? 0 : changeValue
return direction === 'left' ? -changeValue : changeValue
}
function getTableCellWidth(cell) {
var width = 0,
//偏移纠正量
offset = 0,
width = cell.offsetWidth - getTabcellSpace()
//最后一个节点纠正一下
if (!cell.nextSibling) {
width -= getTableCellOffset(cell)
}
width = width < 0 ? 0 : width
try {
cell.width = width
} catch (e) {}
return width
}
/**
* 获取单元格所在表格的最末单元格的偏移量
*/
function getTableCellOffset(cell) {
tab = domUtils.findParentByTagName(cell, 'table', false)
if (tab.offsetVal === undefined) {
var prev = cell.previousSibling
if (prev) {
//最后一个单元格和前一个单元格的width diff结果 如果恰好为一个border width, 则条件成立
tab.offsetVal =
cell.offsetWidth - prev.offsetWidth === UT.borderWidth
? UT.borderWidth
: 0
} else {
tab.offsetVal = 0
}
}
return tab.offsetVal
}
function getTabcellSpace() {
if (UT.tabcellSpace === undefined) {
var cell = null,
tab = me.document.createElement('table'),
tbody = me.document.createElement('tbody'),
trow = me.document.createElement('tr'),
tabcell = me.document.createElement('td'),
mirror = null
tabcell.style.cssText = 'border: 0;'
tabcell.width = 1
trow.appendChild(tabcell)
trow.appendChild((mirror = tabcell.cloneNode(false)))
tbody.appendChild(trow)
tab.appendChild(tbody)
tab.style.cssText = 'visibility: hidden;'
me.body.appendChild(tab)
UT.paddingSpace = tabcell.offsetWidth - 1
var tmpTabWidth = tab.offsetWidth
tabcell.style.cssText = ''
mirror.style.cssText = ''
UT.borderWidth = (tab.offsetWidth - tmpTabWidth) / 3
UT.tabcellSpace = UT.paddingSpace + UT.borderWidth
me.body.removeChild(tab)
}
getTabcellSpace = function () {
return UT.tabcellSpace
}
return UT.tabcellSpace
}
function getDragLine(editor, doc) {
if (mousedown) return
dragLine = editor.document.createElement('div')
domUtils.setAttributes(dragLine, {
id: 'ue_tableDragLine',
unselectable: 'on',
contenteditable: false,
onresizestart: 'return false',
ondragstart: 'return false',
onselectstart: 'return false',
style:
'background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)'
})
editor.body.appendChild(dragLine)
}
function hideDragLine(editor) {
if (mousedown) return
var line
while ((line = editor.document.getElementById('ue_tableDragLine'))) {
domUtils.remove(line)
}
}
/**
* 依据state(v|h)在cell位置显示横线
* @param state
* @param cell
*/
function showDragLineAt(state, cell) {
if (!cell) return
var table = domUtils.findParentByTagName(cell, 'table'),
caption = table.getElementsByTagName('caption'),
width = table.offsetWidth,
height =
table.offsetHeight -
(caption.length > 0 ? caption[0].offsetHeight : 0),
tablePos = domUtils.getXY(table),
cellPos = domUtils.getXY(cell),
css
switch (state) {
case 'h':
css =
'height:' +
height +
'px;top:' +
(tablePos.y + (caption.length > 0 ? caption[0].offsetHeight : 0)) +
'px;left:' +
(cellPos.x + cell.offsetWidth)
dragLine.style.cssText =
css +
'px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)'
break
case 'v':
css =
'width:' +
width +
'px;left:' +
tablePos.x +
'px;top:' +
(cellPos.y + cell.offsetHeight)
//必须加上border:0和color:blue,否则低版ie不支持背景色显示
dragLine.style.cssText =
css +
'px;overflow:hidden;position: absolute;display:block;background-color:blue;height:1px;border:0;color:blue;opacity:.2;filter:alpha(opacity=20)'
break
default:
}
}
/**
* 当表格边框颜色为白色时设置为虚线,true为添加虚线
* @param editor
* @param flag
*/
function switchBorderColor(editor, flag) {
var tableArr = domUtils.getElementsByTagName(editor.body, 'table'),
color
for (var i = 0, node; (node = tableArr[i++]); ) {
var td = domUtils.getElementsByTagName(node, 'td')
if (td[0]) {
if (flag) {
color = td[0].style.borderColor.replace(/\s/g, '')
if (/(#ffffff)|(rgb\(255,255,255\))/gi.test(color))
domUtils.addClass(node, 'noBorderTable')
} else {
domUtils.removeClasses(node, 'noBorderTable')
}
}
}
}
function getTableWidth(editor, needIEHack, defaultValue) {
var body = editor.body
return (
body.offsetWidth -
(needIEHack
? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2
: 0) -
defaultValue.tableBorder * 2 -
(editor.options.offsetWidth || 0)
)
}
/**
* 获取当前拖动的单元格
*/
function getTargetTd(editor, evt) {
var target = domUtils.findParentByTagName(
evt.target || evt.srcElement,
['td', 'th'],
true
),
dir = null
if (!target) {
return null
}
dir = getRelation(target, mouseCoords(evt))
//如果有前一个节点, 需要做一个修正, 否则可能会得到一个错误的td
if (!target) {
return null
}
if (dir === 'h1' && target.previousSibling) {
var position = domUtils.getXY(target),
cellWidth = target.offsetWidth
if (Math.abs(position.x + cellWidth - evt.clientX) > cellWidth / 3) {
target = target.previousSibling
}
} else if (dir === 'v1' && target.parentNode.previousSibling) {
var position = domUtils.getXY(target),
cellHeight = target.offsetHeight
if (Math.abs(position.y + cellHeight - evt.clientY) > cellHeight / 3) {
target = target.parentNode.previousSibling.firstChild
}
}
//排除了非td内部以及用于代码高亮部分的td
return target && !(editor.fireEvent('excludetable', target) === true)
? target
: null
}
}
// plugins/table.sort.js
/**
* Created with JetBrains PhpStorm.
* User: Jinqn
* Date: 13-10-12
* Time: 上午10:20
* To change this template use File | Settings | File Templates.
*/
UE.UETable.prototype.sortTable = function (sortByCellIndex, compareFn) {
var table = this.table,
rows = table.rows,
trArray = [],
flag = rows[0].cells[0].tagName === 'TH',
lastRowIndex = 0
if (this.selectedTds.length) {
var range = this.cellsRange,
len = range.endRowIndex + 1
for (var i = range.beginRowIndex; i < len; i++) {
trArray[i] = rows[i]
}
trArray.splice(0, range.beginRowIndex)
lastRowIndex =
range.endRowIndex + 1 === this.rowsNum ? 0 : range.endRowIndex + 1
} else {
for (var i = 0, len = rows.length; i < len; i++) {
trArray[i] = rows[i]
}
}
var Fn = {
reversecurrent: function (td1, td2) {
return 1
},
orderbyasc: function (td1, td2) {
var value1 = td1.innerText || td1.textContent,
value2 = td2.innerText || td2.textContent
return value1.localeCompare(value2)
},
reversebyasc: function (td1, td2) {
var value1 = td1.innerHTML,
value2 = td2.innerHTML
return value2.localeCompare(value1)
},
orderbynum: function (td1, td2) {
var value1 = td1[browser.ie ? 'innerText' : 'textContent'].match(/\d+/),
value2 = td2[browser.ie ? 'innerText' : 'textContent'].match(/\d+/)
if (value1) value1 = +value1[0]
if (value2) value2 = +value2[0]
return (value1 || 0) - (value2 || 0)
},
reversebynum: function (td1, td2) {
var value1 = td1[browser.ie ? 'innerText' : 'textContent'].match(/\d+/),
value2 = td2[browser.ie ? 'innerText' : 'textContent'].match(/\d+/)
if (value1) value1 = +value1[0]
if (value2) value2 = +value2[0]
return (value2 || 0) - (value1 || 0)
}
}
//对表格设置排序的标记data-sort-type
table.setAttribute(
'data-sort-type',
compareFn && typeof compareFn === 'string' && Fn[compareFn]
? compareFn
: ''
)
//th不参与排序
flag && trArray.splice(0, 1)
trArray = utils.sort(trArray, function (tr1, tr2) {
var result
if (compareFn && typeof compareFn === 'function') {
result = compareFn.call(
this,
tr1.cells[sortByCellIndex],
tr2.cells[sortByCellIndex]
)
} else if (compareFn && typeof compareFn === 'number') {
result = 1
} else if (compareFn && typeof compareFn === 'string' && Fn[compareFn]) {
result = Fn[compareFn].call(
this,
tr1.cells[sortByCellIndex],
tr2.cells[sortByCellIndex]
)
} else {
result = Fn['orderbyasc'].call(
this,
tr1.cells[sortByCellIndex],
tr2.cells[sortByCellIndex]
)
}
return result
})
var fragment = table.ownerDocument.createDocumentFragment()
for (var j = 0, len = trArray.length; j < len; j++) {
fragment.appendChild(trArray[j])
}
var tbody = table.getElementsByTagName('tbody')[0]
if (!lastRowIndex) {
tbody.appendChild(fragment)
} else {
tbody.insertBefore(
fragment,
rows[lastRowIndex - range.endRowIndex + range.beginRowIndex - 1]
)
}
}
UE.plugins['tablesort'] = function () {
var me = this,
UT = UE.UETable,
getUETable = function (tdOrTable) {
return UT.getUETable(tdOrTable)
},
getTableItemsByRange = function (editor) {
return UT.getTableItemsByRange(editor)
}
me.ready(function () {
//添加表格可排序的样式
utils.cssRule(
'tablesort',
'table.sortEnabled tr.firstRow th,table.sortEnabled tr.firstRow td{padding-right:20px;background-repeat: no-repeat;background-position: center right;' +
' background-image:url(' +
me.options.themePath +
me.options.theme +
'/images/sortable.png);}',
me.document
)
//做单元格合并操作时,清除可排序标识
me.addListener('afterexeccommand', function (type, cmd) {
if (cmd == 'mergeright' || cmd == 'mergedown' || cmd == 'mergecells') {
this.execCommand('disablesort')
}
})
})
//表格排序
UE.commands['sorttable'] = {
queryCommandState: function () {
var me = this,
tableItems = getTableItemsByRange(me)
if (!tableItems.cell) return -1
var table = tableItems.table,
cells = table.getElementsByTagName('td')
for (var i = 0, cell; (cell = cells[i++]); ) {
if (cell.rowSpan != 1 || cell.colSpan != 1) return -1
}
return 0
},
execCommand: function (cmd, fn) {
var me = this,
range = me.selection.getRange(),
bk = range.createBookmark(true),
tableItems = getTableItemsByRange(me),
cell = tableItems.cell,
ut = getUETable(tableItems.table),
cellInfo = ut.getCellInfo(cell)
ut.sortTable(cellInfo.cellIndex, fn)
range.moveToBookmark(bk)
try {
range.select()
} catch (e) {}
}
}
//设置表格可排序,清除表格可排序
UE.commands['enablesort'] = UE.commands['disablesort'] = {
queryCommandState: function (cmd) {
var table = getTableItemsByRange(this).table
if (table && cmd == 'enablesort') {
var cells = domUtils.getElementsByTagName(table, 'th td')
for (var i = 0; i < cells.length; i++) {
if (
cells[i].getAttribute('colspan') > 1 ||
cells[i].getAttribute('rowspan') > 1
)
return -1
}
}
return !table
? -1
: (cmd == 'enablesort') ^
(table.getAttribute('data-sort') != 'sortEnabled')
? -1
: 0
},
execCommand: function (cmd) {
var table = getTableItemsByRange(this).table
table.setAttribute(
'data-sort',
cmd == 'enablesort' ? 'sortEnabled' : 'sortDisabled'
)
cmd == 'enablesort'
? domUtils.addClass(table, 'sortEnabled')
: domUtils.removeClasses(table, 'sortEnabled')
}
}
}
// plugins/contextmenu.js
///import core
///commands 右键菜单
///commandsName ContextMenu
///commandsTitle 右键菜单
/**
* 右键菜单
* @function
* @name baidu.editor.plugins.contextmenu
* @author zhanyi
*/
UE.plugins['contextmenu'] = function () {
var me = this
me.setOpt('enableContextMenu', true)
if (me.getOpt('enableContextMenu') === false) {
return
}
var lang = me.getLang('contextMenu'),
menu,
items = me.options.contextMenu || [
{ label: lang['selectall'], cmdName: 'selectall' },
{
label: lang.cleardoc,
cmdName: 'cleardoc',
exec: function () {
if (confirm(lang.confirmclear)) {
this.execCommand('cleardoc')
}
}
},
'-',
{
label: lang.unlink,
cmdName: 'unlink'
},
'-',
{
group: lang.paragraph,
icon: 'justifyjustify',
subMenu: [
{
label: lang.justifyleft,
cmdName: 'justify',
value: 'left'
},
{
label: lang.justifyright,
cmdName: 'justify',
value: 'right'
},
{
label: lang.justifycenter,
cmdName: 'justify',
value: 'center'
},
{
label: lang.justifyjustify,
cmdName: 'justify',
value: 'justify'
}
]
},
'-',
{
group: lang.table,
icon: 'table',
subMenu: [
{
label: lang.inserttable,
cmdName: 'inserttable'
},
{
label: lang.deletetable,
cmdName: 'deletetable'
},
'-',
{
label: lang.deleterow,
cmdName: 'deleterow'
},
{
label: lang.deletecol,
cmdName: 'deletecol'
},
{
label: lang.insertcol,
cmdName: 'insertcol'
},
{
label: lang.insertcolnext,
cmdName: 'insertcolnext'
},
{
label: lang.insertrow,
cmdName: 'insertrow'
},
{
label: lang.insertrownext,
cmdName: 'insertrownext'
},
'-',
{
label: lang.insertcaption,
cmdName: 'insertcaption'
},
{
label: lang.deletecaption,
cmdName: 'deletecaption'
},
{
label: lang.inserttitle,
cmdName: 'inserttitle'
},
{
label: lang.deletetitle,
cmdName: 'deletetitle'
},
{
label: lang.inserttitlecol,
cmdName: 'inserttitlecol'
},
{
label: lang.deletetitlecol,
cmdName: 'deletetitlecol'
},
'-',
{
label: lang.mergecells,
cmdName: 'mergecells'
},
{
label: lang.mergeright,
cmdName: 'mergeright'
},
{
label: lang.mergedown,
cmdName: 'mergedown'
},
'-',
{
label: lang.splittorows,
cmdName: 'splittorows'
},
{
label: lang.splittocols,
cmdName: 'splittocols'
},
{
label: lang.splittocells,
cmdName: 'splittocells'
},
'-',
{
label: lang.averageDiseRow,
cmdName: 'averagedistributerow'
},
{
label: lang.averageDisCol,
cmdName: 'averagedistributecol'
},
'-',
{
label: lang.edittd,
cmdName: 'edittd',
exec: function () {
if (UE.ui['edittd']) {
new UE.ui['edittd'](this)
}
this.getDialog('edittd').open()
}
},
{
label: lang.edittable,
cmdName: 'edittable',
exec: function () {
if (UE.ui['edittable']) {
new UE.ui['edittable'](this)
}
this.getDialog('edittable').open()
}
},
{
label: lang.setbordervisible,
cmdName: 'setbordervisible'
}
]
},
{
group: lang.tablesort,
icon: 'tablesort',
subMenu: [
{
label: lang.enablesort,
cmdName: 'enablesort'
},
{
label: lang.disablesort,
cmdName: 'disablesort'
},
'-',
{
label: lang.reversecurrent,
cmdName: 'sorttable',
value: 'reversecurrent'
},
{
label: lang.orderbyasc,
cmdName: 'sorttable',
value: 'orderbyasc'
},
{
label: lang.reversebyasc,
cmdName: 'sorttable',
value: 'reversebyasc'
},
{
label: lang.orderbynum,
cmdName: 'sorttable',
value: 'orderbynum'
},
{
label: lang.reversebynum,
cmdName: 'sorttable',
value: 'reversebynum'
}
]
},
{
group: lang.borderbk,
icon: 'borderBack',
subMenu: [
{
label: lang.setcolor,
cmdName: 'interlacetable',
exec: function () {
this.execCommand('interlacetable')
}
},
{
label: lang.unsetcolor,
cmdName: 'uninterlacetable',
exec: function () {
this.execCommand('uninterlacetable')
}
},
{
label: lang.setbackground,
cmdName: 'settablebackground',
exec: function () {
this.execCommand('settablebackground', {
repeat: true,
colorList: ['#bbb', '#ccc']
})
}
},
{
label: lang.unsetbackground,
cmdName: 'cleartablebackground',
exec: function () {
this.execCommand('cleartablebackground')
}
},
{
label: lang.redandblue,
cmdName: 'settablebackground',
exec: function () {
this.execCommand('settablebackground', {
repeat: true,
colorList: ['red', 'blue']
})
}
},
{
label: lang.threecolorgradient,
cmdName: 'settablebackground',
exec: function () {
this.execCommand('settablebackground', {
repeat: true,
colorList: ['#aaa', '#bbb', '#ccc']
})
}
}
]
},
{
group: lang.aligntd,
icon: 'aligntd',
subMenu: [
{
cmdName: 'cellalignment',
value: { align: 'left', vAlign: 'top' }
},
{
cmdName: 'cellalignment',
value: { align: 'center', vAlign: 'top' }
},
{
cmdName: 'cellalignment',
value: { align: 'right', vAlign: 'top' }
},
{
cmdName: 'cellalignment',
value: { align: 'left', vAlign: 'middle' }
},
{
cmdName: 'cellalignment',
value: { align: 'center', vAlign: 'middle' }
},
{
cmdName: 'cellalignment',
value: { align: 'right', vAlign: 'middle' }
},
{
cmdName: 'cellalignment',
value: { align: 'left', vAlign: 'bottom' }
},
{
cmdName: 'cellalignment',
value: { align: 'center', vAlign: 'bottom' }
},
{
cmdName: 'cellalignment',
value: { align: 'right', vAlign: 'bottom' }
}
]
},
{
group: lang.aligntable,
icon: 'aligntable',
subMenu: [
{
cmdName: 'tablealignment',
className: 'left',
label: lang.tableleft,
value: 'left'
},
{
cmdName: 'tablealignment',
className: 'center',
label: lang.tablecenter,
value: 'center'
},
{
cmdName: 'tablealignment',
className: 'right',
label: lang.tableright,
value: 'right'
}
]
},
'-',
{
label: lang.insertparagraphbefore,
cmdName: 'insertparagraph',
value: true
},
{
label: lang.insertparagraphafter,
cmdName: 'insertparagraph'
},
{
label: lang['copy'],
cmdName: 'copy'
},
{
label: lang['paste'],
cmdName: 'paste'
}
]
if (!items.length) {
return
}
var uiUtils = UE.ui.uiUtils
me.addListener('contextmenu', function (type, evt) {
var offset = uiUtils.getViewportOffsetByEvent(evt)
me.fireEvent('beforeselectionchange')
if (menu) {
menu.destroy()
}
for (var i = 0, ti, contextItems = []; (ti = items[i]); i++) {
var last
;(function (item) {
if (item == '-') {
if (
(last = contextItems[contextItems.length - 1]) &&
last !== '-'
) {
contextItems.push('-')
}
} else if (item.hasOwnProperty('group')) {
for (var j = 0, cj, subMenu = []; (cj = item.subMenu[j]); j++) {
;(function (subItem) {
if (subItem == '-') {
if ((last = subMenu[subMenu.length - 1]) && last !== '-') {
subMenu.push('-')
} else {
subMenu.splice(subMenu.length - 1)
}
} else {
if (
(me.commands[subItem.cmdName] ||
UE.commands[subItem.cmdName] ||
subItem.query) &&
(subItem.query
? subItem.query()
: me.queryCommandState(subItem.cmdName)) > -1
) {
subMenu.push({
label:
subItem.label ||
me.getLang(
'contextMenu.' +
subItem.cmdName +
(subItem.value || '')
) ||
'',
className:
'edui-for-' +
subItem.cmdName +
(subItem.className
? ' edui-for-' +
subItem.cmdName +
'-' +
subItem.className
: ''),
onclick: subItem.exec
? function () {
subItem.exec.call(me)
}
: function () {
me.execCommand(subItem.cmdName, subItem.value)
}
})
}
}
})(cj)
}
if (subMenu.length) {
function getLabel() {
switch (item.icon) {
case 'table':
return me.getLang('contextMenu.table')
case 'justifyjustify':
return me.getLang('contextMenu.paragraph')
case 'aligntd':
return me.getLang('contextMenu.aligntd')
case 'aligntable':
return me.getLang('contextMenu.aligntable')
case 'tablesort':
return lang.tablesort
case 'borderBack':
return lang.borderbk
default:
return ''
}
}
contextItems.push({
//todo 修正成自动获取方式
label: getLabel(),
className: 'edui-for-' + item.icon,
subMenu: {
items: subMenu,
editor: me
}
})
}
} else {
//有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
if (
(me.commands[item.cmdName] ||
UE.commands[item.cmdName] ||
item.query) &&
(item.query
? item.query.call(me)
: me.queryCommandState(item.cmdName)) > -1
) {
contextItems.push({
label: item.label || me.getLang('contextMenu.' + item.cmdName),
className:
'edui-for-' +
(item.icon ? item.icon : item.cmdName + (item.value || '')),
onclick: item.exec
? function () {
item.exec.call(me)
}
: function () {
me.execCommand(item.cmdName, item.value)
}
})
}
}
})(ti)
}
if (contextItems[contextItems.length - 1] == '-') {
contextItems.pop()
}
menu = new UE.ui.Menu({
items: contextItems,
className: 'edui-contextmenu',
editor: me
})
menu.render()
menu.showAt(offset)
me.fireEvent('aftershowcontextmenu', menu)
domUtils.preventDefault(evt)
if (browser.ie) {
var ieRange
try {
ieRange = me.selection.getNative().createRange()
} catch (e) {
return
}
if (ieRange.item) {
var range = new dom.Range(me.document)
range.selectNode(ieRange.item(0)).select(true, true)
}
}
})
// 添加复制的flash按钮
me.addListener('aftershowcontextmenu', function (type, menu) {
if (me.zeroclipboard) {
var items = menu.items
for (var key in items) {
if (items[key].className == 'edui-for-copy') {
me.zeroclipboard.clip(items[key].getDom())
}
}
}
})
}
// plugins/shortcutmenu.js
///import core
///commands 弹出菜单
// commandsName popupmenu
///commandsTitle 弹出菜单
/**
* 弹出菜单
* @function
* @name baidu.editor.plugins.popupmenu
* @author xuheng
*/
UE.plugins['shortcutmenu'] = function () {
var me = this,
menu,
items = me.options.shortcutMenu || []
if (!items.length) {
return
}
me.addListener('contextmenu mouseup', function (type, e) {
var me = this,
customEvt = {
type: type,
target: e.target || e.srcElement,
screenX: e.screenX,
screenY: e.screenY,
clientX: e.clientX,
clientY: e.clientY
}
setTimeout(function () {
var rng = me.selection.getRange()
if (rng.collapsed === false || type == 'contextmenu') {
if (!menu) {
menu = new baidu.editor.ui.ShortCutMenu({
editor: me,
items: items,
theme: me.options.theme,
className: 'edui-shortcutmenu'
})
menu.render()
me.fireEvent('afterrendershortcutmenu', menu)
}
menu.show(customEvt, !!UE.plugins['contextmenu'])
}
})
if (type == 'contextmenu') {
domUtils.preventDefault(e)
if (browser.ie9below) {
var ieRange
try {
ieRange = me.selection.getNative().createRange()
} catch (e) {
return
}
if (ieRange.item) {
var range = new dom.Range(me.document)
range.selectNode(ieRange.item(0)).select(true, true)
}
}
}
})
me.addListener('keydown', function (type) {
if (type == 'keydown') {
menu && !menu.isHidden && menu.hide()
}
})
}
// plugins/basestyle.js
/**
* B、I、sub、super命令支持
* @file
* @since 1.2.6.1
*/
UE.plugins['basestyle'] = function () {
/**
* 字体加粗
* @command bold
* @param { String } cmd 命令字符串
* @remind 对已加粗的文本内容执行该命令, 将取消加粗
* @method execCommand
* @example
* ```javascript
* //editor是编辑器实例
* //对当前选中的文本内容执行加粗操作
* //第一次执行, 文本内容加粗
* editor.execCommand( 'bold' );
*
* //第二次执行, 文本内容取消加粗
* editor.execCommand( 'bold' );
* ```
*/
/**
* 字体倾斜
* @command italic
* @method execCommand
* @param { String } cmd 命令字符串
* @remind 对已倾斜的文本内容执行该命令, 将取消倾斜
* @example
* ```javascript
* //editor是编辑器实例
* //对当前选中的文本内容执行斜体操作
* //第一次操作, 文本内容将变成斜体
* editor.execCommand( 'italic' );
*
* //再次对同一文本内容执行, 则文本内容将恢复正常
* editor.execCommand( 'italic' );
* ```
*/
/**
* 下标文本,与“superscript”命令互斥
* @command subscript
* @method execCommand
* @remind 把选中的文本内容切换成下标文本, 如果当前选中的文本已经是下标, 则该操作会把文本内容还原成正常文本
* @param { String } cmd 命令字符串
* @example
* ```javascript
* //editor是编辑器实例
* //对当前选中的文本内容执行下标操作
* //第一次操作, 文本内容将变成下标文本
* editor.execCommand( 'subscript' );
*
* //再次对同一文本内容执行, 则文本内容将恢复正常
* editor.execCommand( 'subscript' );
* ```
*/
/**
* 上标文本,与“subscript”命令互斥
* @command superscript
* @method execCommand
* @remind 把选中的文本内容切换成上标文本, 如果当前选中的文本已经是上标, 则该操作会把文本内容还原成正常文本
* @param { String } cmd 命令字符串
* @example
* ```javascript
* //editor是编辑器实例
* //对当前选中的文本内容执行上标操作
* //第一次操作, 文本内容将变成上标文本
* editor.execCommand( 'superscript' );
*
* //再次对同一文本内容执行, 则文本内容将恢复正常
* editor.execCommand( 'superscript' );
* ```
*/
var basestyles = {
bold: ['strong', 'b'],
italic: ['em', 'i'],
subscript: ['sub'],
superscript: ['sup']
},
getObj = function (editor, tagNames) {
return domUtils.filterNodeList(
editor.selection.getStartElementPath(),
tagNames
)
},
me = this
//添加快捷键
me.addshortcutkey({
Bold: 'ctrl+66', //^B
Italic: 'ctrl+73', //^I
Underline: 'ctrl+85' //^U
})
me.addInputRule(function (root) {
utils.each(root.getNodesByTagName('b i'), function (node) {
switch (node.tagName) {
case 'b':
node.tagName = 'strong'
break
case 'i':
node.tagName = 'em'
}
})
})
for (var style in basestyles) {
;(function (cmd, tagNames) {
me.commands[cmd] = {
execCommand: function (cmdName) {
var range = me.selection.getRange(),
obj = getObj(this, tagNames)
if (range.collapsed) {
if (obj) {
var tmpText = me.document.createTextNode('')
range.insertNode(tmpText).removeInlineStyle(tagNames)
range.setStartBefore(tmpText)
domUtils.remove(tmpText)
} else {
var tmpNode = range.document.createElement(tagNames[0])
if (cmdName == 'superscript' || cmdName == 'subscript') {
tmpText = me.document.createTextNode('')
range
.insertNode(tmpText)
.removeInlineStyle(['sub', 'sup'])
.setStartBefore(tmpText)
.collapse(true)
}
range.insertNode(tmpNode).setStart(tmpNode, 0)
}
range.collapse(true)
} else {
if (cmdName == 'superscript' || cmdName == 'subscript') {
if (!obj || obj.tagName.toLowerCase() != cmdName) {
range.removeInlineStyle(['sub', 'sup'])
}
}
obj
? range.removeInlineStyle(tagNames)
: range.applyInlineStyle(tagNames[0])
}
range.select()
},
queryCommandState: function () {
return getObj(this, tagNames) ? 1 : 0
}
}
})(style, basestyles[style])
}
}
// plugins/elementpath.js
/**
* 选取路径命令
* @file
*/
UE.plugins['elementpath'] = function () {
var currentLevel,
tagNames,
me = this
me.setOpt('elementPathEnabled', true)
if (!me.options.elementPathEnabled) {
return
}
me.commands['elementpath'] = {
execCommand: function (cmdName, level) {
var start = tagNames[level],
range = me.selection.getRange()
currentLevel = level * 1
range.selectNode(start).select()
},
queryCommandValue: function () {
//产生一个副本,不能修改原来的startElementPath;
var parents = [].concat(this.selection.getStartElementPath()).reverse(),
names = []
tagNames = parents
for (var i = 0, ci; (ci = parents[i]); i++) {
if (ci.nodeType == 3) {
continue
}
var name = ci.tagName.toLowerCase()
if (name == 'img' && ci.getAttribute('anchorname')) {
name = 'anchor'
}
names[i] = name
if (currentLevel == i) {
currentLevel = -1
break
}
}
return names
}
}
}
// plugins/formatmatch.js
/**
* 格式刷,只格式inline的
* @file
* @since 1.2.6.1
*/
/**
* 格式刷
* @command formatmatch
* @method execCommand
* @remind 该操作不能复制段落格式
* @param { String } cmd 命令字符串
* @example
* ```javascript
* //editor是编辑器实例
* //获取格式刷
* editor.execCommand( 'formatmatch' );
* ```
*/
UE.plugins['formatmatch'] = function () {
var me = this,
list = [],
img,
flag = 0
me.addListener('reset', function () {
list = []
flag = 0
})
function addList(type, evt) {
if (browser.webkit) {
var target = evt.target.tagName == 'IMG' ? evt.target : null
}
function addFormat(range) {
if (text) {
range.selectNode(text)
}
return range.applyInlineStyle(list[list.length - 1].tagName, null, list)
}
me.undoManger && me.undoManger.save()
var range = me.selection.getRange(),
imgT = target || range.getClosedNode()
if (img && imgT && imgT.tagName == 'IMG') {
//trace:964
imgT.style.cssText +=
';float:' +
(img.style.cssFloat || img.style.styleFloat || 'none') +
';display:' +
(img.style.display || 'inline')
img = null
} else {
if (!img) {
var collapsed = range.collapsed
if (collapsed) {
var text = me.document.createTextNode('match')
range.insertNode(text).select()
}
me.__hasEnterExecCommand = true
//不能把block上的属性干掉
//trace:1553
var removeFormatAttributes = me.options.removeFormatAttributes
me.options.removeFormatAttributes = ''
me.execCommand('removeformat')
me.options.removeFormatAttributes = removeFormatAttributes
me.__hasEnterExecCommand = false
//trace:969
range = me.selection.getRange()
if (list.length) {
addFormat(range)
}
if (text) {
range.setStartBefore(text).collapse(true)
}
range.select()
text && domUtils.remove(text)
}
}
me.undoManger && me.undoManger.save()
me.removeListener('mouseup', addList)
flag = 0
}
me.commands['formatmatch'] = {
execCommand: function (cmdName) {
if (flag) {
flag = 0
list = []
me.removeListener('mouseup', addList)
return
}
var range = me.selection.getRange()
img = range.getClosedNode()
if (!img || img.tagName != 'IMG') {
range.collapse(true).shrinkBoundary()
var start = range.startContainer
list = domUtils.findParents(start, true, function (node) {
return !domUtils.isBlockElm(node) && node.nodeType == 1
})
//a不能加入格式刷, 并且克隆节点
for (var i = 0, ci; (ci = list[i]); i++) {
if (ci.tagName == 'A') {
list.splice(i, 1)
break
}
}
}
me.addListener('mouseup', addList)
flag = 1
},
queryCommandState: function () {
return flag
},
notNeedUndo: 1
}
}
// plugins/searchreplace.js
///import core
///commands 查找替换
///commandsName SearchReplace
///commandsTitle 查询替换
///commandsDialog dialogs\searchreplace
/**
* @description 查找替换
* @author zhanyi
*/
UE.plugin.register('searchreplace', function () {
var me = this
var _blockElm = { table: 1, tbody: 1, tr: 1, ol: 1, ul: 1 }
function findTextInString(textContent, opt, currentIndex) {
var str = opt.searchStr
if (opt.dir == -1) {
textContent = textContent.split('').reverse().join('')
str = str.split('').reverse().join('')
currentIndex = textContent.length - currentIndex
}
var reg = new RegExp(str, 'g' + (opt.casesensitive ? '' : 'i')),
match
while ((match = reg.exec(textContent))) {
if (match.index >= currentIndex) {
return opt.dir == -1
? textContent.length - match.index - opt.searchStr.length
: match.index
}
}
return -1
}
function findTextBlockElm(node, currentIndex, opt) {
var textContent,
index,
methodName =
opt.all || opt.dir == 1 ? 'getNextDomNode' : 'getPreDomNode'
if (domUtils.isBody(node)) {
node = node.firstChild
}
var first = 1
while (node) {
textContent =
node.nodeType == 3
? node.nodeValue
: node[browser.ie ? 'innerText' : 'textContent']
index = findTextInString(textContent, opt, currentIndex)
first = 0
if (index != -1) {
return {
node: node,
index: index
}
}
node = domUtils[methodName](node)
while (node && _blockElm[node.nodeName.toLowerCase()]) {
node = domUtils[methodName](node, true)
}
if (node) {
currentIndex =
opt.dir == -1
? (node.nodeType == 3
? node.nodeValue
: node[browser.ie ? 'innerText' : 'textContent']
).length
: 0
}
}
}
function findNTextInBlockElm(node, index, str) {
var currentIndex = 0,
currentNode = node.firstChild,
currentNodeLength = 0,
result
while (currentNode) {
if (currentNode.nodeType == 3) {
currentNodeLength = currentNode.nodeValue.replace(
/(^[\t\r\n]+)|([\t\r\n]+$)/,
''
).length
currentIndex += currentNodeLength
if (currentIndex >= index) {
return {
node: currentNode,
index: currentNodeLength - (currentIndex - index)
}
}
} else if (!dtd.$empty[currentNode.tagName]) {
currentNodeLength = currentNode[
browser.ie ? 'innerText' : 'textContent'
].replace(/(^[\t\r\n]+)|([\t\r\n]+$)/, '').length
currentIndex += currentNodeLength
if (currentIndex >= index) {
result = findNTextInBlockElm(
currentNode,
currentNodeLength - (currentIndex - index),
str
)
if (result) {
return result
}
}
}
currentNode = domUtils.getNextDomNode(currentNode)
}
}
function searchReplace(me, opt) {
var rng = me.selection.getRange(),
startBlockNode,
searchStr = opt.searchStr,
span = me.document.createElement('span')
span.innerHTML = '$$ueditor_searchreplace_key$$'
rng.shrinkBoundary(true)
//判断是不是第一次选中
if (!rng.collapsed) {
rng.select()
var rngText = me.selection.getText()
if (
new RegExp(
'^' + opt.searchStr + '$',
opt.casesensitive ? '' : 'i'
).test(rngText)
) {
if (opt.replaceStr != undefined) {
replaceText(rng, opt.replaceStr)
rng.select()
return true
} else {
rng.collapse(opt.dir == -1)
}
}
}
rng.insertNode(span)
rng.enlargeToBlockElm(true)
startBlockNode = rng.startContainer
var currentIndex = startBlockNode[
browser.ie ? 'innerText' : 'textContent'
].indexOf('$$ueditor_searchreplace_key$$')
rng.setStartBefore(span)
domUtils.remove(span)
var result = findTextBlockElm(startBlockNode, currentIndex, opt)
if (result) {
var rngStart = findNTextInBlockElm(result.node, result.index, searchStr)
var rngEnd = findNTextInBlockElm(
result.node,
result.index + searchStr.length,
searchStr
)
rng
.setStart(rngStart.node, rngStart.index)
.setEnd(rngEnd.node, rngEnd.index)
if (opt.replaceStr !== undefined) {
replaceText(rng, opt.replaceStr)
}
rng.select()
return true
} else {
rng.setCursor()
}
}
function replaceText(rng, str) {
str = me.document.createTextNode(str)
rng.deleteContents().insertNode(str)
}
return {
commands: {
searchreplace: {
execCommand: function (cmdName, opt) {
utils.extend(
opt,
{
all: false,
casesensitive: false,
dir: 1
},
true
)
var num = 0
if (opt.all) {
var rng = me.selection.getRange(),
first = me.body.firstChild
if (first && first.nodeType == 1) {
rng.setStart(first, 0)
rng.shrinkBoundary(true)
} else if (first.nodeType == 3) {
rng.setStartBefore(first)
}
rng.collapse(true).select(true)
if (opt.replaceStr !== undefined) {
me.fireEvent('saveScene')
}
while (searchReplace(this, opt)) {
num++
}
if (num) {
me.fireEvent('saveScene')
}
} else {
if (opt.replaceStr !== undefined) {
me.fireEvent('saveScene')
}
if (searchReplace(this, opt)) {
num++
}
if (num) {
me.fireEvent('saveScene')
}
}
return num
},
notNeedUndo: 1
}
}
}
})
// plugins/customstyle.js
/**
* 自定义样式
* @file
* @since 1.2.6.1
*/
/**
* 根据config配置文件里“customstyle”选项的值对匹配的标签执行样式替换。
* @command customstyle
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand( 'customstyle' );
* ```
*/
UE.plugins['customstyle'] = function () {
var me = this
me.setOpt({
customstyle: [
{
tag: 'h1',
name: 'tc',
style:
'font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;margin:0 0 20px 0;'
},
{
tag: 'h1',
name: 'tl',
style:
'font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:left;margin:0 0 10px 0;'
},
{
tag: 'span',
name: 'im',
style:
'font-size:16px;font-style:italic;font-weight:bold;line-height:18px;'
},
{
tag: 'span',
name: 'hi',
style:
'font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;'
}
]
})
me.commands['customstyle'] = {
execCommand: function (cmdName, obj) {
var me = this,
tagName = obj.tag,
node = domUtils.findParent(
me.selection.getStart(),
function (node) {
return node.getAttribute('label')
},
true
),
range,
bk,
tmpObj = {}
for (var p in obj) {
if (obj[p] !== undefined) tmpObj[p] = obj[p]
}
delete tmpObj.tag
if (node && node.getAttribute('label') == obj.label) {
range = this.selection.getRange()
bk = range.createBookmark()
if (range.collapsed) {
//trace:1732 删掉自定义标签,要有p来回填站位
if (dtd.$block[node.tagName]) {
var fillNode = me.document.createElement('p')
domUtils.moveChild(node, fillNode)
node.parentNode.insertBefore(fillNode, node)
domUtils.remove(node)
} else {
domUtils.remove(node, true)
}
} else {
var common = domUtils.getCommonAncestor(bk.start, bk.end),
nodes = domUtils.getElementsByTagName(common, tagName)
if (new RegExp(tagName, 'i').test(common.tagName)) {
nodes.push(common)
}
for (var i = 0, ni; (ni = nodes[i++]); ) {
if (ni.getAttribute('label') == obj.label) {
var ps = domUtils.getPosition(ni, bk.start),
pe = domUtils.getPosition(ni, bk.end)
if (
(ps & domUtils.POSITION_FOLLOWING ||
ps & domUtils.POSITION_CONTAINS) &&
(pe & domUtils.POSITION_PRECEDING ||
pe & domUtils.POSITION_CONTAINS)
)
if (dtd.$block[tagName]) {
var fillNode = me.document.createElement('p')
domUtils.moveChild(ni, fillNode)
ni.parentNode.insertBefore(fillNode, ni)
}
domUtils.remove(ni, true)
}
}
node = domUtils.findParent(
common,
function (node) {
return node.getAttribute('label') == obj.label
},
true
)
if (node) {
domUtils.remove(node, true)
}
}
range.moveToBookmark(bk).select()
} else {
if (dtd.$block[tagName]) {
this.execCommand('paragraph', tagName, tmpObj, 'customstyle')
range = me.selection.getRange()
if (!range.collapsed) {
range.collapse()
node = domUtils.findParent(
me.selection.getStart(),
function (node) {
return node.getAttribute('label') == obj.label
},
true
)
var pNode = me.document.createElement('p')
domUtils.insertAfter(node, pNode)
domUtils.fillNode(me.document, pNode)
range.setStart(pNode, 0).setCursor()
}
} else {
range = me.selection.getRange()
if (range.collapsed) {
node = me.document.createElement(tagName)
domUtils.setAttributes(node, tmpObj)
range.insertNode(node).setStart(node, 0).setCursor()
return
}
bk = range.createBookmark()
range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select()
}
}
},
queryCommandValue: function () {
var parent = domUtils.filterNodeList(
this.selection.getStartElementPath(),
function (node) {
return node.getAttribute('label')
}
)
return parent ? parent.getAttribute('label') : ''
}
}
//当去掉customstyle是,如果是块元素,用p代替
me.addListener('keyup', function (type, evt) {
var keyCode = evt.keyCode || evt.which
if (keyCode == 32 || keyCode == 13) {
var range = me.selection.getRange()
if (range.collapsed) {
var node = domUtils.findParent(
me.selection.getStart(),
function (node) {
return node.getAttribute('label')
},
true
)
if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
var p = me.document.createElement('p')
domUtils.insertAfter(node, p)
domUtils.fillNode(me.document, p)
domUtils.remove(node)
range.setStart(p, 0).setCursor()
}
}
}
})
}
// plugins/catchremoteimage.js
///import core
///commands 远程图片抓取
///commandsName catchRemoteImage,catchremoteimageenable
///commandsTitle 远程图片抓取
/**
* 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
*/
UE.plugins['catchremoteimage'] = function () {
var me = this,
ajax = UE.ajax
/* 设置默认值 */
if (me.options.catchRemoteImageEnable === false) return
me.setOpt({
catchRemoteImageEnable: false
})
me.addListener('afterpaste', function () {
me.fireEvent('catchRemoteImage')
})
me.addListener('catchRemoteImage', function () {
var catcherLocalDomain = me.getOpt('catcherLocalDomain'),
catcherActionUrl = me.getActionUrl(me.getOpt('catcherActionName')),
catcherUrlPrefix = me.getOpt('catcherUrlPrefix'),
catcherFieldName = me.getOpt('catcherFieldName')
var remoteImages = [],
imgs = domUtils.getElementsByTagName(me.document, 'img'),
test = function (src, urls) {
if (src.indexOf(location.host) != -1 || /(^\.)|(^\/)/.test(src)) {
return true
}
if (urls) {
for (var j = 0, url; (url = urls[j++]); ) {
if (src.indexOf(url) !== -1) {
return true
}
}
}
return false
}
for (var i = 0, ci; (ci = imgs[i++]); ) {
if (ci.getAttribute('word_img')) {
continue
}
var src = ci.getAttribute('_src') || ci.src || ''
if (/^(https?|ftp):/i.test(src) && !test(src, catcherLocalDomain)) {
remoteImages.push(src)
}
}
if (remoteImages.length) {
catchremoteimage(remoteImages, {
//成功抓取
success: function (r) {
try {
var info =
r.state !== undefined ? r : eval('(' + r.responseText + ')')
} catch (e) {
return
}
/* 获取源路径和新路径 */
var i,
j,
ci,
cj,
oldSrc,
newSrc,
list = info.list
for (i = 0; (ci = imgs[i++]); ) {
oldSrc = ci.getAttribute('_src') || ci.src || ''
for (j = 0; (cj = list[j++]); ) {
if (oldSrc == cj.source && cj.state == 'SUCCESS') {
//抓取失败时不做替换处理
newSrc = catcherUrlPrefix + cj.url
domUtils.setAttributes(ci, {
src: newSrc,
_src: newSrc
})
break
}
}
}
me.fireEvent('catchremotesuccess')
},
//回调失败,本次请求超时
error: function () {
me.fireEvent('catchremoteerror')
}
})
}
function catchremoteimage(imgs, callbacks) {
var params =
utils.serializeParam(me.queryCommandValue('serverparam')) || '',
url = utils.formatUrl(
catcherActionUrl +
(catcherActionUrl.indexOf('?') == -1 ? '?' : '&') +
params
),
isJsonp = utils.isCrossDomainUrl(url),
opt = {
method: 'POST',
dataType: isJsonp ? 'jsonp' : '',
timeout: 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
onsuccess: callbacks['success'],
onerror: callbacks['error']
}
opt[catcherFieldName] = imgs
ajax.request(url, opt)
}
})
}
// plugins/snapscreen.js
/**
* 截屏插件,为UEditor提供插入支持
* @file
* @since 1.4.2
*/
UE.plugin.register('snapscreen', function () {
var me = this
var snapplugin
function getLocation(url) {
var search,
a = document.createElement('a'),
params = utils.serializeParam(me.queryCommandValue('serverparam')) || ''
a.href = url
if (browser.ie) {
a.href = a.href
}
search = a.search
if (params) {
search = search + (search.indexOf('?') == -1 ? '?' : '&') + params
search = search.replace(/[&]+/gi, '&')
}
return {
port: a.port,
hostname: a.hostname,
path: a.pathname + search || +a.hash
}
}
return {
commands: {
/**
* 字体背景颜色
* @command snapscreen
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand('snapscreen');
* ```
*/
snapscreen: {
execCommand: function (cmd) {
var url, local, res
var lang = me.getLang('snapScreen_plugin')
if (!snapplugin) {
var container = me.container
var doc = me.container.ownerDocument || me.container.document
snapplugin = doc.createElement('object')
try {
snapplugin.type = 'application/x-pluginbaidusnap'
} catch (e) {
return
}
snapplugin.style.cssText =
'position:absolute;left:-9999px;width:0;height:0;'
snapplugin.setAttribute('width', '0')
snapplugin.setAttribute('height', '0')
container.appendChild(snapplugin)
}
function onSuccess(rs) {
try {
rs = eval('(' + rs + ')')
if (rs.state == 'SUCCESS') {
var opt = me.options
me.execCommand('insertimage', {
src: opt.snapscreenUrlPrefix + rs.url,
_src: opt.snapscreenUrlPrefix + rs.url,
alt: rs.title || '',
floatStyle: opt.snapscreenImgAlign
})
} else {
alert(rs.state)
}
} catch (e) {
alert(lang.callBackErrorMsg)
}
}
url = me.getActionUrl(me.getOpt('snapscreenActionName'))
local = getLocation(url)
setTimeout(function () {
try {
res = snapplugin.saveSnapshot(
local.hostname,
local.path,
local.port
)
} catch (e) {
me.ui._dialogs['snapscreenDialog'].open()
return
}
onSuccess(res)
}, 50)
},
queryCommandState: function () {
return navigator.userAgent.indexOf('Windows', 0) != -1 ? 0 : -1
}
}
}
}
})
// plugins/insertparagraph.js
/**
* 插入段落
* @file
* @since 1.2.6.1
*/
/**
* 插入段落
* @command insertparagraph
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* //editor是编辑器实例
* editor.execCommand( 'insertparagraph' );
* ```
*/
UE.commands['insertparagraph'] = {
execCommand: function (cmdName, front) {
var me = this,
range = me.selection.getRange(),
start = range.startContainer,
tmpNode
while (start) {
if (domUtils.isBody(start)) {
break
}
tmpNode = start
start = start.parentNode
}
if (tmpNode) {
var p = me.document.createElement('p')
if (front) {
tmpNode.parentNode.insertBefore(p, tmpNode)
} else {
tmpNode.parentNode.insertBefore(p, tmpNode.nextSibling)
}
domUtils.fillNode(me.document, p)
range.setStart(p, 0).setCursor(false, true)
}
}
}
// plugins/webapp.js
/**
* 百度应用
* @file
* @since 1.2.6.1
*/
/**
* 插入百度应用
* @command webapp
* @method execCommand
* @remind 需要百度APPKey
* @remind 百度应用主页: http://app.baidu.com/
* @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
* height=>应用容器高度,logo=>应用logo,url=>应用地址
* @example
* ```javascript
* //editor是编辑器实例
* //在编辑器里插入一个“植物大战僵尸”的APP
* editor.execCommand( 'webapp' , {
* title: '植物大战僵尸',
* width: 560,
* height: 465,
* logo: '应用展示的图片',
* url: '百度应用的地址'
* } );
* ```
*/
//UE.plugins['webapp'] = function () {
// var me = this;
// function createInsertStr( obj, toIframe, addParagraph ) {
// return !toIframe ?
// (addParagraph ? '' : '') + ' ' +
// (addParagraph ? '
' : '')
// :
// '';
// }
//
// function switchImgAndIframe( img2frame ) {
// var tmpdiv,
// nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
// for ( var i = 0, node; node = nodes[i++]; ) {
// if ( node.className != "edui-faked-webapp" ){
// continue;
// }
// tmpdiv = me.document.createElement( "div" );
// tmpdiv.innerHTML = createInsertStr( img2frame ? {url:node.getAttribute( "_url" ), width:node.width, height:node.height,title:node.title,logo:node.style.backgroundImage.replace("url(","").replace(")","")} : {url:node.getAttribute( "src", 2 ),title:node.title, width:node.width, height:node.height,logo:node.getAttribute("logo_url")}, img2frame ? true : false,false );
// node.parentNode.replaceChild( tmpdiv.firstChild, node );
// }
// }
//
// me.addListener( "beforegetcontent", function () {
// switchImgAndIframe( true );
// } );
// me.addListener( 'aftersetcontent', function () {
// switchImgAndIframe( false );
// } );
// me.addListener( 'aftergetcontent', function ( cmdName ) {
// if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
// return;
// }
// switchImgAndIframe( false );
// } );
//
// me.commands['webapp'] = {
// execCommand:function ( cmd, obj ) {
// me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
// }
// };
//};
UE.plugin.register('webapp', function () {
var me = this
function createInsertStr(obj, toEmbed) {
return !toEmbed
? ' '
: ''
}
return {
outputRule: function (root) {
utils.each(root.getNodesByTagName('img'), function (node) {
var html
if (node.getAttr('class') == 'edui-faked-webapp') {
html = createInsertStr(
{
title: node.getAttr('title'),
width: node.getAttr('width'),
height: node.getAttr('height'),
align: node.getAttr('align'),
cssfloat: node.getStyle('float'),
url: node.getAttr('_url'),
logo: node.getAttr('_logo_url')
},
true
)
var embed = UE.uNode.createElement(html)
node.parentNode.replaceChild(embed, node)
}
})
},
inputRule: function (root) {
utils.each(root.getNodesByTagName('iframe'), function (node) {
if (node.getAttr('class') == 'edui-faked-webapp') {
var img = UE.uNode.createElement(
createInsertStr({
title: node.getAttr('title'),
width: node.getAttr('width'),
height: node.getAttr('height'),
align: node.getAttr('align'),
cssfloat: node.getStyle('float'),
url: node.getAttr('src'),
logo: node.getAttr('logo_url')
})
)
node.parentNode.replaceChild(img, node)
}
})
},
commands: {
/**
* 插入百度应用
* @command webapp
* @method execCommand
* @remind 需要百度APPKey
* @remind 百度应用主页: http://app.baidu.com/
* @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
* height=>应用容器高度,logo=>应用logo,url=>应用地址
* @example
* ```javascript
* //editor是编辑器实例
* //在编辑器里插入一个“植物大战僵尸”的APP
* editor.execCommand( 'webapp' , {
* title: '植物大战僵尸',
* width: 560,
* height: 465,
* logo: '应用展示的图片',
* url: '百度应用的地址'
* } );
* ```
*/
webapp: {
execCommand: function (cmd, obj) {
var me = this,
str = createInsertStr(
utils.extend(obj, {
align: 'none'
}),
false
)
me.execCommand('inserthtml', str)
},
queryCommandState: function () {
var me = this,
img = me.selection.getRange().getClosedNode(),
flag = img && img.className == 'edui-faked-webapp'
return flag ? 1 : 0
}
}
}
}
})
// plugins/template.js
///import core
///import plugins\inserthtml.js
///import plugins\cleardoc.js
///commands 模板
///commandsName template
///commandsTitle 模板
///commandsDialog dialogs\template
UE.plugins['template'] = function () {
UE.commands['template'] = {
execCommand: function (cmd, obj) {
obj.html && this.execCommand('inserthtml', obj.html)
}
}
this.addListener('click', function (type, evt) {
var el = evt.target || evt.srcElement,
range = this.selection.getRange()
var tnode = domUtils.findParent(
el,
function (node) {
if (node.className && domUtils.hasClass(node, 'ue_t')) {
return node
}
},
true
)
tnode && range.selectNode(tnode).shrinkBoundary().select()
})
this.addListener('keydown', function (type, evt) {
var range = this.selection.getRange()
if (!range.collapsed) {
if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
var tnode = domUtils.findParent(
range.startContainer,
function (node) {
if (node.className && domUtils.hasClass(node, 'ue_t')) {
return node
}
},
true
)
if (tnode) {
domUtils.removeClasses(tnode, ['ue_t'])
}
}
}
})
}
// plugins/music.js
/**
* 插入音乐命令
* @file
*/
UE.plugin.register('music', function () {
var me = this
function creatInsertStr(url, width, height, align, cssfloat, toEmbed) {
return !toEmbed
? ' '
: ''
}
return {
outputRule: function (root) {
utils.each(root.getNodesByTagName('img'), function (node) {
var html
if (node.getAttr('class') == 'edui-faked-music') {
var cssfloat = node.getStyle('float')
var align = node.getAttr('align')
html = creatInsertStr(
node.getAttr('_url'),
node.getAttr('width'),
node.getAttr('height'),
align,
cssfloat,
true
)
var embed = UE.uNode.createElement(html)
node.parentNode.replaceChild(embed, node)
}
})
},
inputRule: function (root) {
utils.each(root.getNodesByTagName('embed'), function (node) {
if (node.getAttr('class') == 'edui-faked-music') {
var cssfloat = node.getStyle('float')
var align = node.getAttr('align')
html = creatInsertStr(
node.getAttr('src'),
node.getAttr('width'),
node.getAttr('height'),
align,
cssfloat,
false
)
var img = UE.uNode.createElement(html)
node.parentNode.replaceChild(img, node)
}
})
},
commands: {
/**
* 插入音乐
* @command music
* @method execCommand
* @param { Object } musicOptions 插入音乐的参数项, 支持的key有: url=>音乐地址;
* width=>音乐容器宽度;height=>音乐容器高度;align=>音乐文件的对齐方式, 可选值有: left, center, right, none
* @example
* ```javascript
* //editor是编辑器实例
* //在编辑器里插入一个“植物大战僵尸”的APP
* editor.execCommand( 'music' , {
* width: 400,
* height: 95,
* align: "center",
* url: "音乐地址"
* } );
* ```
*/
music: {
execCommand: function (cmd, musicObj) {
var me = this,
str = creatInsertStr(
musicObj.url,
musicObj.width || 400,
musicObj.height || 95,
'none',
false
)
me.execCommand('inserthtml', str)
},
queryCommandState: function () {
var me = this,
img = me.selection.getRange().getClosedNode(),
flag = img && img.className == 'edui-faked-music'
return flag ? 1 : 0
}
}
}
}
})
// plugins/autoupload.js
/**
* @description
* 1.拖放文件到编辑区域,自动上传并插入到选区
* 2.插入粘贴板的图片,自动上传并插入到选区
* @author Jinqn
* @date 2013-10-14
*/
UE.plugin.register('autoupload', function () {
function sendAndInsertFile(file, editor) {
var me = editor
//模拟数据
var fieldName,
urlPrefix,
maxSize,
allowFiles,
actionUrl,
loadingHtml,
errorHandler,
successHandler,
filetype = /image\/\w+/i.test(file.type) ? 'image' : 'file',
loadingId = 'loading_' + (+new Date()).toString(36)
fieldName = me.getOpt(filetype + 'FieldName')
urlPrefix = me.getOpt(filetype + 'UrlPrefix')
maxSize = me.getOpt(filetype + 'MaxSize')
allowFiles = me.getOpt(filetype + 'AllowFiles')
actionUrl = me.getActionUrl(me.getOpt(filetype + 'ActionName'))
errorHandler = function (title) {
var loader = me.document.getElementById(loadingId)
loader && domUtils.remove(loader)
me.fireEvent('showmessage', {
id: loadingId,
content: title,
type: 'error',
timeout: 4000
})
}
if (filetype == 'image') {
loadingHtml =
' '
successHandler = function (data) {
var link = urlPrefix + data.url,
loader = me.document.getElementById(loadingId)
if (loader) {
loader.setAttribute('src', link)
loader.setAttribute('_src', link)
loader.setAttribute('title', data.title || '')
loader.setAttribute('alt', data.original || '')
loader.removeAttribute('id')
domUtils.removeClasses(loader, 'loadingclass')
}
}
} else {
loadingHtml =
'' +
' ' +
'
'
successHandler = function (data) {
var link = urlPrefix + data.url,
loader = me.document.getElementById(loadingId)
var rng = me.selection.getRange(),
bk = rng.createBookmark()
rng.selectNode(loader).select()
me.execCommand('insertfile', { url: link })
rng.moveToBookmark(bk).select()
}
}
/* 插入loading的占位符 */
me.execCommand('inserthtml', loadingHtml)
/* 判断后端配置是否没有加载成功 */
if (!me.getOpt(filetype + 'ActionName')) {
errorHandler(me.getLang('autoupload.errorLoadConfig'))
return
}
/* 判断文件大小是否超出限制 */
if (file.size > maxSize) {
errorHandler(me.getLang('autoupload.exceedSizeError'))
return
}
/* 判断文件格式是否超出允许 */
var fileext = file.name
? file.name.substr(file.name.lastIndexOf('.'))
: ''
if (
(fileext && filetype != 'image') ||
(allowFiles &&
(allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') ==
-1)
) {
errorHandler(me.getLang('autoupload.exceedTypeError'))
return
}
/* 创建Ajax并提交 */
var xhr = new XMLHttpRequest(),
fd = new FormData(),
params =
utils.serializeParam(me.queryCommandValue('serverparam')) || '',
url = utils.formatUrl(
actionUrl + (actionUrl.indexOf('?') == -1 ? '?' : '&') + params
)
fd.append(
fieldName,
file,
file.name || 'blob.' + file.type.substr('image/'.length)
)
fd.append('type', 'ajax')
xhr.open('post', url, true)
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
xhr.addEventListener('load', function (e) {
try {
var json = new Function('return ' + utils.trim(e.target.response))()
if (json.state == 'SUCCESS' && json.url) {
successHandler(json)
} else {
errorHandler(json.state)
}
} catch (er) {
errorHandler(me.getLang('autoupload.loadError'))
}
})
xhr.send(fd)
}
function getPasteImage(e) {
return e.clipboardData &&
e.clipboardData.items &&
e.clipboardData.items.length == 1 &&
/^image\//.test(e.clipboardData.items[0].type)
? e.clipboardData.items
: null
}
function getDropImage(e) {
return e.dataTransfer && e.dataTransfer.files
? e.dataTransfer.files
: null
}
return {
outputRule: function (root) {
utils.each(root.getNodesByTagName('img'), function (n) {
if (
/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))
) {
n.parentNode.removeChild(n)
}
})
utils.each(root.getNodesByTagName('p'), function (n) {
if (/\bloadpara\b/.test(n.getAttr('class'))) {
n.parentNode.removeChild(n)
}
})
},
bindEvents: {
//插入粘贴板的图片,拖放插入图片
ready: function (e) {
var me = this
if (window.FormData && window.FileReader) {
domUtils.on(me.body, 'paste drop', function (e) {
var hasImg = false,
items
//获取粘贴板文件列表或者拖放文件列表
items = e.type == 'paste' ? getPasteImage(e) : getDropImage(e)
if (items) {
var len = items.length,
file
while (len--) {
file = items[len]
if (file.getAsFile) file = file.getAsFile()
if (file && file.size > 0) {
sendAndInsertFile(file, me)
hasImg = true
}
}
hasImg && e.preventDefault()
}
})
//取消拖放图片时出现的文字光标位置提示
domUtils.on(me.body, 'dragover', function (e) {
if (e.dataTransfer.types[0] == 'Files') {
e.preventDefault()
}
})
//设置loading的样式
utils.cssRule(
'loading',
".loadingclass{display:inline-block;cursor:default;background: url('" +
this.options.themePath +
this.options.theme +
"/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-left:1px;height: 22px;width: 22px;}\n" +
".loaderrorclass{display:inline-block;cursor:default;background: url('" +
this.options.themePath +
this.options.theme +
"/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
'}',
this.document
)
}
}
}
}
})
// plugins/autosave.js
UE.plugin.register('autosave', function () {
var me = this,
//无限循环保护
lastSaveTime = new Date(),
//最小保存间隔时间
MIN_TIME = 20,
//auto save key
saveKey = null
function save(editor) {
var saveData
if (new Date() - lastSaveTime < MIN_TIME) {
return
}
if (!editor.hasContents()) {
//这里不能调用命令来删除, 会造成事件死循环
saveKey && me.removePreferences(saveKey)
return
}
lastSaveTime = new Date()
editor._saveFlag = null
saveData = me.body.innerHTML
if (
editor.fireEvent('beforeautosave', {
content: saveData
}) === false
) {
return
}
me.setPreferences(saveKey, saveData)
editor.fireEvent('afterautosave', {
content: saveData
})
}
return {
defaultOptions: {
//默认间隔时间
saveInterval: 500,
enableAutoSave: true // HaoChuan9421
},
bindEvents: {
ready: function () {
var _suffix = '-drafts-data',
key = null
if (me.key) {
key = me.key + _suffix
} else {
key = (me.container.parentNode.id || 'ue-common') + _suffix
}
//页面地址+编辑器ID 保持唯一
saveKey =
(location.protocol + location.host + location.pathname).replace(
/[.:\/]/g,
'_'
) + key
},
contentchange: function () {
// HaoChuan9421
if (!me.getOpt('enableAutoSave')) {
return
}
if (!saveKey) {
return
}
if (me._saveFlag) {
window.clearTimeout(me._saveFlag)
}
if (me.options.saveInterval > 0) {
me._saveFlag = window.setTimeout(function () {
save(me)
}, me.options.saveInterval)
} else {
save(me)
}
}
},
commands: {
clearlocaldata: {
execCommand: function (cmd, name) {
if (saveKey && me.getPreferences(saveKey)) {
me.removePreferences(saveKey)
}
},
notNeedUndo: true,
ignoreContentChange: true
},
getlocaldata: {
execCommand: function (cmd, name) {
return saveKey ? me.getPreferences(saveKey) || '' : ''
},
notNeedUndo: true,
ignoreContentChange: true
},
drafts: {
execCommand: function (cmd, name) {
if (saveKey) {
me.body.innerHTML =
me.getPreferences(saveKey) || '' + domUtils.fillHtml + '
'
me.focus(true)
}
},
queryCommandState: function () {
return saveKey ? (me.getPreferences(saveKey) === null ? -1 : 0) : -1
},
notNeedUndo: true,
ignoreContentChange: true
}
}
}
})
// plugins/charts.js
UE.plugin.register('charts', function () {
var me = this
return {
bindEvents: {
chartserror: function () {}
},
commands: {
charts: {
execCommand: function (cmd, data) {
var tableNode = domUtils.findParentByTagName(
this.selection.getRange().startContainer,
'table',
true
),
flagText = [],
config = {}
if (!tableNode) {
return false
}
if (!validData(tableNode)) {
me.fireEvent('chartserror')
return false
}
config.title = data.title || ''
config.subTitle = data.subTitle || ''
config.xTitle = data.xTitle || ''
config.yTitle = data.yTitle || ''
config.suffix = data.suffix || ''
config.tip = data.tip || ''
//数据对齐方式
config.dataFormat = data.tableDataFormat || ''
//图表类型
config.chartType = data.chartType || 0
for (var key in config) {
if (!config.hasOwnProperty(key)) {
continue
}
flagText.push(key + ':' + config[key])
}
tableNode.setAttribute('data-chart', flagText.join(';'))
domUtils.addClass(tableNode, 'edui-charts-table')
},
queryCommandState: function (cmd, name) {
var tableNode = domUtils.findParentByTagName(
this.selection.getRange().startContainer,
'table',
true
)
return tableNode && validData(tableNode) ? 0 : -1
}
}
},
inputRule: function (root) {
utils.each(root.getNodesByTagName('table'), function (tableNode) {
if (tableNode.getAttr('data-chart') !== undefined) {
tableNode.setAttr('style')
}
})
},
outputRule: function (root) {
utils.each(root.getNodesByTagName('table'), function (tableNode) {
if (tableNode.getAttr('data-chart') !== undefined) {
tableNode.setAttr('style', 'display: none;')
}
})
}
}
function validData(table) {
var firstRows = null,
cellCount = 0
//行数不够
if (table.rows.length < 2) {
return false
}
//列数不够
if (table.rows[0].cells.length < 2) {
return false
}
//第一行所有cell必须是th
firstRows = table.rows[0].cells
cellCount = firstRows.length
for (var i = 0, cell; (cell = firstRows[i]); i++) {
if (cell.tagName.toLowerCase() !== 'th') {
return false
}
}
for (var i = 1, row; (row = table.rows[i]); i++) {
//每行单元格数不匹配, 返回false
if (row.cells.length != cellCount) {
return false
}
//第一列不是th也返回false
if (row.cells[0].tagName.toLowerCase() !== 'th') {
return false
}
for (var j = 1, cell; (cell = row.cells[j]); j++) {
var value = utils.trim(cell.innerText || cell.textContent || '')
value = value
.replace(new RegExp(UE.dom.domUtils.fillChar, 'g'), '')
.replace(/^\s+|\s+$/g, '')
//必须是数字
if (!/^\d*\.?\d+$/.test(value)) {
return false
}
}
}
return true
}
})
// plugins/section.js
/**
* 目录大纲支持插件
* @file
* @since 1.3.0
*/
UE.plugin.register('section', function () {
/* 目录节点对象 */
function Section(option) {
this.tag = ''
;(this.level = -1), (this.dom = null)
this.nextSection = null
this.previousSection = null
this.parentSection = null
this.startAddress = []
this.endAddress = []
this.children = []
}
function getSection(option) {
var section = new Section()
return utils.extend(section, option)
}
function getNodeFromAddress(startAddress, root) {
var current = root
for (var i = 0; i < startAddress.length; i++) {
if (!current.childNodes) return null
current = current.childNodes[startAddress[i]]
}
return current
}
var me = this
return {
bindMultiEvents: {
type: 'aftersetcontent afterscencerestore',
handler: function () {
me.fireEvent('updateSections')
}
},
bindEvents: {
/* 初始化、拖拽、粘贴、执行setcontent之后 */
ready: function () {
me.fireEvent('updateSections')
domUtils.on(me.body, 'drop paste', function () {
me.fireEvent('updateSections')
})
},
/* 执行paragraph命令之后 */
afterexeccommand: function (type, cmd) {
if (cmd == 'paragraph') {
me.fireEvent('updateSections')
}
},
/* 部分键盘操作,触发updateSections事件 */
keyup: function (type, e) {
var me = this,
range = me.selection.getRange()
if (range.collapsed != true) {
me.fireEvent('updateSections')
} else {
var keyCode = e.keyCode || e.which
if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
me.fireEvent('updateSections')
}
}
}
},
commands: {
getsections: {
execCommand: function (cmd, levels) {
var levelFn = levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
for (var i = 0; i < levelFn.length; i++) {
if (typeof levelFn[i] == 'string') {
levelFn[i] = (function (fn) {
return function (node) {
return node.tagName == fn.toUpperCase()
}
})(levelFn[i])
} else if (typeof levelFn[i] != 'function') {
levelFn[i] = function (node) {
return null
}
}
}
function getSectionLevel(node) {
for (var i = 0; i < levelFn.length; i++) {
if (levelFn[i](node)) return i
}
return -1
}
var me = this,
Directory = getSection({ level: -1, title: 'root' }),
previous = Directory
function traversal(node, Directory) {
var level,
tmpSection = null,
parent,
child,
children = node.childNodes
for (var i = 0, len = children.length; i < len; i++) {
child = children[i]
level = getSectionLevel(child)
if (level >= 0) {
var address = me.selection
.getRange()
.selectNode(child)
.createAddress(true).startAddress,
current = getSection({
tag: child.tagName,
title: child.innerText || child.textContent || '',
level: level,
dom: child,
startAddress: utils.clone(address, []),
endAddress: utils.clone(address, []),
children: []
})
previous.nextSection = current
current.previousSection = previous
parent = previous
while (level <= parent.level) {
parent = parent.parentSection
}
current.parentSection = parent
parent.children.push(current)
tmpSection = previous = current
} else {
child.nodeType === 1 && traversal(child, Directory)
tmpSection &&
tmpSection.endAddress[tmpSection.endAddress.length - 1]++
}
}
}
traversal(me.body, Directory)
return Directory
},
notNeedUndo: true
},
movesection: {
execCommand: function (cmd, sourceSection, targetSection, isAfter) {
var me = this,
targetAddress,
target
if (!sourceSection || !targetSection || targetSection.level == -1)
return
targetAddress = isAfter
? targetSection.endAddress
: targetSection.startAddress
target = getNodeFromAddress(targetAddress, me.body)
/* 判断目标地址是否被源章节包含 */
if (
!targetAddress ||
!target ||
isContainsAddress(
sourceSection.startAddress,
sourceSection.endAddress,
targetAddress
)
)
return
var startNode = getNodeFromAddress(
sourceSection.startAddress,
me.body
),
endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
current,
nextNode
if (isAfter) {
current = endNode
while (
current &&
!(
domUtils.getPosition(startNode, current) &
domUtils.POSITION_FOLLOWING
)
) {
nextNode = current.previousSibling
domUtils.insertAfter(target, current)
if (current == startNode) break
current = nextNode
}
} else {
current = startNode
while (
current &&
!(
domUtils.getPosition(current, endNode) &
domUtils.POSITION_FOLLOWING
)
) {
nextNode = current.nextSibling
target.parentNode.insertBefore(current, target)
if (current == endNode) break
current = nextNode
}
}
me.fireEvent('updateSections')
/* 获取地址的包含关系 */
function isContainsAddress(
startAddress,
endAddress,
addressTarget
) {
var isAfterStartAddress = false,
isBeforeEndAddress = false
for (var i = 0; i < startAddress.length; i++) {
if (i >= addressTarget.length) break
if (addressTarget[i] > startAddress[i]) {
isAfterStartAddress = true
break
} else if (addressTarget[i] < startAddress[i]) {
break
}
}
for (var i = 0; i < endAddress.length; i++) {
if (i >= addressTarget.length) break
if (addressTarget[i] < startAddress[i]) {
isBeforeEndAddress = true
break
} else if (addressTarget[i] > startAddress[i]) {
break
}
}
return isAfterStartAddress && isBeforeEndAddress
}
}
},
deletesection: {
execCommand: function (cmd, section, keepChildren) {
var me = this
if (!section) return
function getNodeFromAddress(startAddress) {
var current = me.body
for (var i = 0; i < startAddress.length; i++) {
if (!current.childNodes) return null
current = current.childNodes[startAddress[i]]
}
return current
}
var startNode = getNodeFromAddress(section.startAddress),
endNode = getNodeFromAddress(section.endAddress),
current = startNode,
nextNode
if (!keepChildren) {
while (
current &&
domUtils.inDoc(endNode, me.document) &&
!(
domUtils.getPosition(current, endNode) &
domUtils.POSITION_FOLLOWING
)
) {
nextNode = current.nextSibling
domUtils.remove(current)
current = nextNode
}
} else {
domUtils.remove(current)
}
me.fireEvent('updateSections')
}
},
selectsection: {
execCommand: function (cmd, section) {
if (!section && !section.dom) return false
var me = this,
range = me.selection.getRange(),
address = {
startAddress: utils.clone(section.startAddress, []),
endAddress: utils.clone(section.endAddress, [])
}
address.endAddress[address.endAddress.length - 1]++
range.moveToAddress(address).select().scrollToView()
return true
},
notNeedUndo: true
},
scrolltosection: {
execCommand: function (cmd, section) {
if (!section && !section.dom) return false
var me = this,
range = me.selection.getRange(),
address = {
startAddress: section.startAddress,
endAddress: section.endAddress
}
address.endAddress[address.endAddress.length - 1]++
range.moveToAddress(address).scrollToView()
return true
},
notNeedUndo: true
}
}
}
})
// plugins/simpleupload.js
/**
* @description
* 简单上传:点击按钮,直接选择文件上传。
* 原 UEditor 作者使用了 form 表单 + iframe 的方式上传
* 但由于同源策略的限制,父页面无法访问跨域的 iframe 内容
* 导致无法获取接口返回的数据,使得单图上传无法在跨域的情况下使用
* 这里改为普通的XHR上传,兼容到IE10+
* @author HaoChuan9421
* @date 2018-12-20
*/
UE.plugin.register('simpleupload', function () {
var me = this,
containerBtn,
timestrap = (+new Date()).toString(36)
function initUploadBtn() {
var w = containerBtn.offsetWidth || 20,
h = containerBtn.offsetHeight || 20,
btnStyle =
'display:block;width:' +
w +
'px;height:' +
h +
'px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;'
var form = document.createElement('form')
var input = document.createElement('input')
form.id = 'edui_form_' + timestrap
form.enctype = 'multipart/form-data'
form.style = btnStyle
input.id = 'edui_input_' + timestrap
input.type = 'file'
input.accept = 'image/*'
input.name = me.options.imageFieldName
input.style = btnStyle
form.appendChild(input)
containerBtn.appendChild(form)
input.addEventListener('change', function (event) {
if (!input.value) return
var loadingId = 'loading_' + (+new Date()).toString(36)
var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName'))
var params =
utils.serializeParam(me.queryCommandValue('serverparam')) || ''
var action = utils.formatUrl(
imageActionUrl +
(imageActionUrl.indexOf('?') == -1 ? '?' : '&') +
params
)
var allowFiles = me.getOpt('imageAllowFiles')
console.log(action, 'action', 'allowFiles', allowFiles)
me.focus()
me.execCommand(
'inserthtml',
' '
)
function showErrorLoader(title) {
if (loadingId) {
var loader = me.document.getElementById(loadingId)
loader && domUtils.remove(loader)
me.fireEvent('showmessage', {
id: loadingId,
content: title,
type: 'error',
timeout: 4000
})
}
}
/* 判断后端配置是否没有加载成功 */
if (!me.getOpt('imageActionName')) {
showErrorLoader(me.getLang('autoupload.errorLoadConfig'))
return
}
// 判断文件格式是否错误
var filename = input.value,
fileext = filename ? filename.substr(filename.lastIndexOf('.')) : ''
if (
!fileext ||
(allowFiles &&
(allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') ==
-1)
) {
showErrorLoader(me.getLang('simpleupload.exceedTypeError'))
return
}
console.log('filename', input.value)
console.log('准备上传action', action, input)
let formData = new FormData()
let files = input.files[0]
formData.append('file', files)
var xhr = new XMLHttpRequest()
// xhr.setRequestHeader('Content-Type', 'multipart/form-data')
xhr.open('post', action, true)
xhr.send(formData)
if (
me.options.headers &&
Object.prototype.toString.apply(me.options.headers) ===
'[object Object]'
) {
for (var key in me.options.headers) {
xhr.setRequestHeader(key, me.options.headers[key])
}
}
xhr.onload = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
var res = JSON.parse(xhr.responseText)
var link = res.data.url
if (res.code == 200 && res.data.url) {
loader = me.document.getElementById(loadingId)
loader.setAttribute('src', link)
loader.setAttribute('_src', link)
loader.setAttribute('title', res.title || '')
loader.setAttribute('alt', res.original || '')
loader.removeAttribute('id')
domUtils.removeClasses(loader, 'loadingclass')
me.fireEvent('contentchange')
} else {
showErrorLoader(res.state)
}
} else {
console.log('请求失败')
showErrorLoader(me.getLang('simpleupload.loadError'))
}
}
xhr.onerror = function () {
console.log('请求失败onerror')
showErrorLoader(me.getLang('simpleupload.loadError'))
}
form.reset()
})
}
return {
bindEvents: {
ready: function () {
//设置loading的样式
utils.cssRule(
'loading',
".loadingclass{display:inline-block;cursor:default;background: url('" +
this.options.themePath +
this.options.theme +
"/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n" +
".loaderrorclass{display:inline-block;cursor:default;background: url('" +
this.options.themePath +
this.options.theme +
"/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
'}',
this.document
)
},
/* 初始化简单上传按钮 */
simpleuploadbtnready: function (type, container) {
containerBtn = container
me.afterConfigReady(initUploadBtn)
}
},
outputRule: function (root) {
utils.each(root.getNodesByTagName('img'), function (n) {
if (
/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))
) {
n.parentNode.removeChild(n)
}
})
}
}
})
// plugins/serverparam.js
/**
* 服务器提交的额外参数列表设置插件
* @file
* @since 1.2.6.1
*/
UE.plugin.register('serverparam', function () {
var me = this,
serverParam = {}
return {
commands: {
/**
* 修改服务器提交的额外参数列表,清除所有项
* @command serverparam
* @method execCommand
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.execCommand('serverparam');
* editor.queryCommandValue('serverparam'); //返回空
* ```
*/
/**
* 修改服务器提交的额外参数列表,删除指定项
* @command serverparam
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } key 要清除的属性
* @example
* ```javascript
* editor.execCommand('serverparam', 'name'); //删除属性name
* ```
*/
/**
* 修改服务器提交的额外参数列表,使用键值添加项
* @command serverparam
* @method execCommand
* @param { String } cmd 命令字符串
* @param { String } key 要添加的属性
* @param { String } value 要添加属性的值
* @example
* ```javascript
* editor.execCommand('serverparam', 'name', 'hello');
* editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
* ```
*/
/**
* 修改服务器提交的额外参数列表,传入键值对对象添加多项
* @command serverparam
* @method execCommand
* @param { String } cmd 命令字符串
* @param { Object } key 传入的键值对对象
* @example
* ```javascript
* editor.execCommand('serverparam', {'name': 'hello'});
* editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
* ```
*/
/**
* 修改服务器提交的额外参数列表,使用自定义函数添加多项
* @command serverparam
* @method execCommand
* @param { String } cmd 命令字符串
* @param { Function } key 自定义获取参数的函数
* @example
* ```javascript
* editor.execCommand('serverparam', function(editor){
* return {'key': 'value'};
* });
* editor.queryCommandValue('serverparam'); //返回对象 {'key': 'value'}
* ```
*/
/**
* 获取服务器提交的额外参数列表
* @command serverparam
* @method queryCommandValue
* @param { String } cmd 命令字符串
* @example
* ```javascript
* editor.queryCommandValue( 'serverparam' ); //返回对象 {'key': 'value'}
* ```
*/
serverparam: {
execCommand: function (cmd, key, value) {
if (key === undefined || key === null) {
//不传参数,清空列表
serverParam = {}
} else if (utils.isString(key)) {
//传入键值
if (value === undefined || value === null) {
delete serverParam[key]
} else {
serverParam[key] = value
}
} else if (utils.isObject(key)) {
//传入对象,覆盖列表项
utils.extend(serverParam, key, true)
} else if (utils.isFunction(key)) {
//传入函数,添加列表项
utils.extend(serverParam, key(), true)
}
},
queryCommandValue: function () {
return serverParam || {}
}
}
}
}
})
// plugins/insertfile.js
/**
* 插入附件
*/
UE.plugin.register('insertfile', function () {
var me = this
function getFileIcon(url) {
var ext = url.substr(url.lastIndexOf('.') + 1).toLowerCase(),
maps = {
rar: 'icon_rar.gif',
zip: 'icon_rar.gif',
tar: 'icon_rar.gif',
gz: 'icon_rar.gif',
bz2: 'icon_rar.gif',
doc: 'icon_doc.gif',
docx: 'icon_doc.gif',
pdf: 'icon_pdf.gif',
mp3: 'icon_mp3.gif',
xls: 'icon_xls.gif',
chm: 'icon_chm.gif',
ppt: 'icon_ppt.gif',
pptx: 'icon_ppt.gif',
avi: 'icon_mv.gif',
rmvb: 'icon_mv.gif',
wmv: 'icon_mv.gif',
flv: 'icon_mv.gif',
swf: 'icon_mv.gif',
rm: 'icon_mv.gif',
exe: 'icon_exe.gif',
psd: 'icon_psd.gif',
txt: 'icon_txt.gif',
jpg: 'icon_jpg.gif',
png: 'icon_jpg.gif',
jpeg: 'icon_jpg.gif',
gif: 'icon_jpg.gif',
ico: 'icon_jpg.gif',
bmp: 'icon_jpg.gif'
}
return maps[ext] ? maps[ext] : maps['txt']
}
return {
commands: {
insertfile: {
execCommand: function (command, filelist) {
filelist = utils.isArray(filelist) ? filelist : [filelist]
var i,
item,
icon,
title,
html = '',
URL = me.getOpt('UEDITOR_HOME_URL'),
iconDir =
URL +
(URL.substr(URL.length - 1) == '/' ? '' : '/') +
'dialogs/attachment/fileTypeImages/'
for (i = 0; i < filelist.length; i++) {
item = filelist[i]
icon = iconDir + getFileIcon(item.url)
title =
item.title || item.url.substr(item.url.lastIndexOf('/') + 1)
html +=
'' +
' ' +
'' +
title +
' ' +
'
'
}
me.execCommand('insertHtml', html)
}
}
}
}
})
// plugins/xssFilter.js
/**
* @file xssFilter.js
* @desc xss过滤器
* @author robbenmu
*/
UE.plugins.xssFilter = function () {
var config = UEDITOR_CONFIG
var whitList = config.whitList
function filter(node) {
var tagName = node.tagName
var attrs = node.attrs
if (!whitList.hasOwnProperty(tagName)) {
node.parentNode.removeChild(node)
return false
}
UE.utils.each(attrs, function (val, key) {
if (whitList[tagName].indexOf(key) === -1) {
node.setAttr(key)
}
})
}
// 添加inserthtml\paste等操作用的过滤规则
if (whitList && config.xssFilterRules) {
this.options.filterRules = (function () {
var result = {}
UE.utils.each(whitList, function (val, key) {
result[key] = function (node) {
return filter(node)
}
})
return result
})()
}
var tagList = []
UE.utils.each(whitList, function (val, key) {
tagList.push(key)
})
// 添加input过滤规则
//
if (whitList && config.inputXssFilter) {
this.addInputRule(function (root) {
root.traversal(function (node) {
if (node.type !== 'element') {
return false
}
filter(node)
})
})
}
// 添加output过滤规则
//
if (whitList && config.outputXssFilter) {
this.addOutputRule(function (root) {
root.traversal(function (node) {
if (node.type !== 'element') {
return false
}
filter(node)
})
})
}
}
// ui/ui.js
var baidu = baidu || {}
baidu.editor = baidu.editor || {}
UE.ui = baidu.editor.ui = {}
// ui/uiutils.js
;(function () {
var browser = baidu.editor.browser,
domUtils = baidu.editor.dom.domUtils
var magic = '$EDITORUI'
var root = (window[magic] = {})
var uidMagic = 'ID' + magic
var uidCount = 0
var uiUtils = (baidu.editor.ui.uiUtils = {
uid: function (obj) {
return obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount
},
hook: function (fn, callback) {
var dg
if (fn && fn._callbacks) {
dg = fn
} else {
dg = function () {
var q
if (fn) {
q = fn.apply(this, arguments)
}
var callbacks = dg._callbacks
var k = callbacks.length
while (k--) {
var r = callbacks[k].apply(this, arguments)
if (q === undefined) {
q = r
}
}
return q
}
dg._callbacks = []
}
dg._callbacks.push(callback)
return dg
},
createElementByHtml: function (html) {
var el = document.createElement('div')
el.innerHTML = html
el = el.firstChild
el.parentNode.removeChild(el)
return el
},
getViewportElement: function () {
return browser.ie && browser.quirks
? document.body
: document.documentElement
},
getClientRect: function (element) {
var bcr
//trace IE6下在控制编辑器显隐时可能会报错,catch一下
try {
bcr = element.getBoundingClientRect()
} catch (e) {
bcr = { left: 0, top: 0, height: 0, width: 0 }
}
var rect = {
left: Math.round(bcr.left),
top: Math.round(bcr.top),
height: Math.round(bcr.bottom - bcr.top),
width: Math.round(bcr.right - bcr.left)
}
var doc
while (
(doc = element.ownerDocument) !== document &&
(element = domUtils.getWindow(doc).frameElement)
) {
bcr = element.getBoundingClientRect()
rect.left += bcr.left
rect.top += bcr.top
}
rect.bottom = rect.top + rect.height
rect.right = rect.left + rect.width
return rect
},
getViewportRect: function () {
var viewportEl = uiUtils.getViewportElement()
var width = (window.innerWidth || viewportEl.clientWidth) | 0
var height = (window.innerHeight || viewportEl.clientHeight) | 0
return {
left: 0,
top: 0,
height: height,
width: width,
bottom: height,
right: width
}
},
setViewportOffset: function (element, offset) {
var rect
var fixedLayer = uiUtils.getFixedLayer()
if (element.parentNode === fixedLayer) {
element.style.left = offset.left + 'px'
element.style.top = offset.top + 'px'
} else {
domUtils.setViewportOffset(element, offset)
}
},
getEventOffset: function (evt) {
var el = evt.target || evt.srcElement
var rect = uiUtils.getClientRect(el)
var offset = uiUtils.getViewportOffsetByEvent(evt)
return {
left: offset.left - rect.left,
top: offset.top - rect.top
}
},
getViewportOffsetByEvent: function (evt) {
var el = evt.target || evt.srcElement
var frameEl = domUtils.getWindow(el).frameElement
var offset = {
left: evt.clientX,
top: evt.clientY
}
if (frameEl && el.ownerDocument !== document) {
var rect = uiUtils.getClientRect(frameEl)
offset.left += rect.left
offset.top += rect.top
}
return offset
},
setGlobal: function (id, obj) {
root[id] = obj
return magic + '["' + id + '"]'
},
unsetGlobal: function (id) {
delete root[id]
},
copyAttributes: function (tgt, src) {
var attributes = src.attributes
var k = attributes.length
while (k--) {
var attrNode = attributes[k]
if (
attrNode.nodeName != 'style' &&
attrNode.nodeName != 'class' &&
(!browser.ie || attrNode.specified)
) {
tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue)
}
}
if (src.className) {
domUtils.addClass(tgt, src.className)
}
if (src.style.cssText) {
tgt.style.cssText += ';' + src.style.cssText
}
},
removeStyle: function (el, styleName) {
if (el.style.removeProperty) {
el.style.removeProperty(styleName)
} else if (el.style.removeAttribute) {
el.style.removeAttribute(styleName)
} else throw ''
},
contains: function (elA, elB) {
return (
elA &&
elB &&
(elA === elB
? false
: elA.contains
? elA.contains(elB)
: elA.compareDocumentPosition(elB) & 16)
)
},
startDrag: function (evt, callbacks, doc) {
var doc = doc || document
var startX = evt.clientX
var startY = evt.clientY
function handleMouseMove(evt) {
var x = evt.clientX - startX
var y = evt.clientY - startY
callbacks.ondragmove(x, y, evt)
if (evt.stopPropagation) {
evt.stopPropagation()
} else {
evt.cancelBubble = true
}
}
if (doc.addEventListener) {
function handleMouseUp(evt) {
doc.removeEventListener('mousemove', handleMouseMove, true)
doc.removeEventListener('mouseup', handleMouseUp, true)
window.removeEventListener('mouseup', handleMouseUp, true)
callbacks.ondragstop()
}
doc.addEventListener('mousemove', handleMouseMove, true)
doc.addEventListener('mouseup', handleMouseUp, true)
window.addEventListener('mouseup', handleMouseUp, true)
evt.preventDefault()
} else {
var elm = evt.srcElement
elm.setCapture()
function releaseCaptrue() {
elm.releaseCapture()
elm.detachEvent('onmousemove', handleMouseMove)
elm.detachEvent('onmouseup', releaseCaptrue)
elm.detachEvent('onlosecaptrue', releaseCaptrue)
callbacks.ondragstop()
}
elm.attachEvent('onmousemove', handleMouseMove)
elm.attachEvent('onmouseup', releaseCaptrue)
elm.attachEvent('onlosecaptrue', releaseCaptrue)
evt.returnValue = false
}
callbacks.ondragstart()
},
getFixedLayer: function () {
var layer = document.getElementById('edui_fixedlayer')
if (layer == null) {
layer = document.createElement('div')
layer.id = 'edui_fixedlayer'
document.body.appendChild(layer)
if (browser.ie && browser.version <= 8) {
layer.style.position = 'absolute'
bindFixedLayer()
setTimeout(updateFixedOffset)
} else {
layer.style.position = 'fixed'
}
layer.style.left = '0'
layer.style.top = '0'
layer.style.width = '0'
layer.style.height = '0'
layer.style.zIndex = '3005'
}
return layer
},
makeUnselectable: function (element) {
if (browser.opera || (browser.ie && browser.version < 9)) {
element.unselectable = 'on'
if (element.hasChildNodes()) {
for (var i = 0; i < element.childNodes.length; i++) {
if (element.childNodes[i].nodeType == 1) {
uiUtils.makeUnselectable(element.childNodes[i])
}
}
}
} else {
if (element.style.MozUserSelect !== undefined) {
element.style.MozUserSelect = 'none'
} else if (element.style.WebkitUserSelect !== undefined) {
element.style.WebkitUserSelect = 'none'
} else if (element.style.KhtmlUserSelect !== undefined) {
element.style.KhtmlUserSelect = 'none'
}
}
}
})
function updateFixedOffset() {
var layer = document.getElementById('edui_fixedlayer')
uiUtils.setViewportOffset(layer, {
left: 0,
top: 0
})
// layer.style.display = 'none';
// layer.style.display = 'block';
//#trace: 1354
// setTimeout(updateFixedOffset);
}
function bindFixedLayer(adjOffset) {
domUtils.on(window, 'scroll', updateFixedOffset)
domUtils.on(
window,
'resize',
baidu.editor.utils.defer(updateFixedOffset, 0, true)
)
}
})()
// ui/uibase.js
;(function () {
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
EventBase = baidu.editor.EventBase,
UIBase = (baidu.editor.ui.UIBase = function () {})
UIBase.prototype = {
className: '',
uiName: '',
initOptions: function (options) {
var me = this
for (var k in options) {
me[k] = options[k]
}
this.id = this.id || 'edui' + uiUtils.uid()
},
initUIBase: function () {
this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this))
},
render: function (holder) {
var html = this.renderHtml()
var el = uiUtils.createElementByHtml(html)
//by xuheng 给每个node添加class
var list = domUtils.getElementsByTagName(el, '*')
var theme = 'edui-' + (this.theme || this.editor.options.theme)
var layer = document.getElementById('edui_fixedlayer')
for (var i = 0, node; (node = list[i++]); ) {
domUtils.addClass(node, theme)
}
domUtils.addClass(el, theme)
if (layer) {
layer.className = ''
domUtils.addClass(layer, theme)
}
var seatEl = this.getDom()
if (seatEl != null) {
seatEl.parentNode.replaceChild(el, seatEl)
uiUtils.copyAttributes(el, seatEl)
} else {
if (typeof holder == 'string') {
holder = document.getElementById(holder)
}
holder = holder || uiUtils.getFixedLayer()
domUtils.addClass(holder, theme)
holder.appendChild(el)
}
this.postRender()
},
getDom: function (name) {
if (!name) {
return document.getElementById(this.id)
} else {
return document.getElementById(this.id + '_' + name)
}
},
postRender: function () {
this.fireEvent('postrender')
},
getHtmlTpl: function () {
return ''
},
formatHtml: function (tpl) {
var prefix = 'edui-' + this.uiName
return tpl
.replace(/##/g, this.id)
.replace(/%%-/g, this.uiName ? prefix + '-' : '')
.replace(/%%/g, (this.uiName ? prefix : '') + ' ' + this.className)
.replace(/\$\$/g, this._globalKey)
},
renderHtml: function () {
return this.formatHtml(this.getHtmlTpl())
},
dispose: function () {
var box = this.getDom()
if (box) baidu.editor.dom.domUtils.remove(box)
uiUtils.unsetGlobal(this.id)
}
}
utils.inherits(UIBase, EventBase)
})()
// ui/separator.js
;(function () {
var utils = baidu.editor.utils,
UIBase = baidu.editor.ui.UIBase,
Separator = (baidu.editor.ui.Separator = function (options) {
this.initOptions(options)
this.initSeparator()
})
Separator.prototype = {
uiName: 'separator',
initSeparator: function () {
this.initUIBase()
},
getHtmlTpl: function () {
return '
'
}
}
utils.inherits(Separator, UIBase)
})()
// ui/mask.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
domUtils = baidu.editor.dom.domUtils,
UIBase = baidu.editor.ui.UIBase,
uiUtils = baidu.editor.ui.uiUtils
var Mask = (baidu.editor.ui.Mask = function (options) {
this.initOptions(options)
this.initUIBase()
})
Mask.prototype = {
getHtmlTpl: function () {
return '
'
},
postRender: function () {
var me = this
domUtils.on(window, 'resize', function () {
setTimeout(function () {
if (!me.isHidden()) {
me._fill()
}
})
})
},
show: function (zIndex) {
this._fill()
this.getDom().style.display = ''
this.getDom().style.zIndex = zIndex
},
hide: function () {
this.getDom().style.display = 'none'
this.getDom().style.zIndex = ''
},
isHidden: function () {
return this.getDom().style.display == 'none'
},
_onMouseDown: function () {
return false
},
_onClick: function (e, target) {
this.fireEvent('click', e, target)
},
_fill: function () {
var el = this.getDom()
var vpRect = uiUtils.getViewportRect()
el.style.width = vpRect.width + 'px'
el.style.height = vpRect.height + 'px'
}
}
utils.inherits(Mask, UIBase)
})()
// ui/popup.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
domUtils = baidu.editor.dom.domUtils,
UIBase = baidu.editor.ui.UIBase,
Popup = (baidu.editor.ui.Popup = function (options) {
this.initOptions(options)
this.initPopup()
})
var allPopups = []
function closeAllPopup(evt, el) {
for (var i = 0; i < allPopups.length; i++) {
var pop = allPopups[i]
if (!pop.isHidden()) {
if (pop.queryAutoHide(el) !== false) {
if (
evt &&
/scroll/gi.test(evt.type) &&
pop.className == 'edui-wordpastepop'
)
return
pop.hide()
}
}
}
if (allPopups.length) pop.editor.fireEvent('afterhidepop')
}
Popup.postHide = closeAllPopup
var ANCHOR_CLASSES = [
'edui-anchor-topleft',
'edui-anchor-topright',
'edui-anchor-bottomleft',
'edui-anchor-bottomright'
]
Popup.prototype = {
SHADOW_RADIUS: 5,
content: null,
_hidden: false,
autoRender: true,
canSideLeft: true,
canSideUp: true,
initPopup: function () {
this.initUIBase()
allPopups.push(this)
},
getHtmlTpl: function () {
return (
''
)
},
getContentHtmlTpl: function () {
if (this.content) {
if (typeof this.content == 'string') {
return this.content
}
return this.content.renderHtml()
} else {
return ''
}
},
_UIBase_postRender: UIBase.prototype.postRender,
postRender: function () {
if (this.content instanceof UIBase) {
this.content.postRender()
}
//捕获鼠标滚轮
if (this.captureWheel && !this.captured) {
this.captured = true
var winHeight =
(document.documentElement.clientHeight ||
document.body.clientHeight) - 80,
_height = this.getDom().offsetHeight,
_top = uiUtils.getClientRect(this.combox.getDom()).top,
content = this.getDom('content'),
ifr = this.getDom('body').getElementsByTagName('iframe'),
me = this
ifr.length && (ifr = ifr[0])
while (_top + _height > winHeight) {
_height -= 30
}
content.style.height = _height + 'px'
//同步更改iframe高度
ifr && (ifr.style.height = _height + 'px')
//阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解
if (window.XMLHttpRequest) {
domUtils.on(
content,
'onmousewheel' in document.body ? 'mousewheel' : 'DOMMouseScroll',
function (e) {
if (e.preventDefault) {
e.preventDefault()
} else {
e.returnValue = false
}
if (e.wheelDelta) {
content.scrollTop -= (e.wheelDelta / 120) * 60
} else {
content.scrollTop -= (e.detail / -3) * 60
}
}
)
} else {
//ie6
domUtils.on(this.getDom(), 'mousewheel', function (e) {
e.returnValue = false
me.getDom('content').scrollTop -= (e.wheelDelta / 120) * 60
})
}
}
this.fireEvent('postRenderAfter')
this.hide(true)
this._UIBase_postRender()
},
_doAutoRender: function () {
if (!this.getDom() && this.autoRender) {
this.render()
}
},
mesureSize: function () {
var box = this.getDom('content')
return uiUtils.getClientRect(box)
},
fitSize: function () {
if (this.captureWheel && this.sized) {
return this.__size
}
this.sized = true
var popBodyEl = this.getDom('body')
popBodyEl.style.width = ''
popBodyEl.style.height = ''
var size = this.mesureSize()
if (this.captureWheel) {
popBodyEl.style.width = -(-20 - size.width) + 'px'
var height = parseInt(this.getDom('content').style.height, 10)
!window.isNaN(height) && (size.height = height)
} else {
popBodyEl.style.width = size.width + 'px'
}
popBodyEl.style.height = size.height + 'px'
this.__size = size
this.captureWheel && (this.getDom('content').style.overflow = 'auto')
return size
},
showAnchor: function (element, hoz) {
this.showAnchorRect(uiUtils.getClientRect(element), hoz)
},
showAnchorRect: function (rect, hoz, adj) {
this._doAutoRender()
var vpRect = uiUtils.getViewportRect()
this.getDom().style.visibility = 'hidden'
this._show()
var popSize = this.fitSize()
var sideLeft, sideUp, left, top
if (hoz) {
sideLeft =
this.canSideLeft &&
rect.right + popSize.width > vpRect.right &&
rect.left > popSize.width
sideUp =
this.canSideUp &&
rect.top + popSize.height > vpRect.bottom &&
rect.bottom > popSize.height
left = sideLeft ? rect.left - popSize.width : rect.right
top = sideUp ? rect.bottom - popSize.height : rect.top
} else {
sideLeft =
this.canSideLeft &&
rect.right + popSize.width > vpRect.right &&
rect.left > popSize.width
sideUp =
this.canSideUp &&
rect.top + popSize.height > vpRect.bottom &&
rect.bottom > popSize.height
left = sideLeft ? rect.right - popSize.width : rect.left
top = sideUp ? rect.top - popSize.height : rect.bottom
}
var popEl = this.getDom()
uiUtils.setViewportOffset(popEl, {
left: left,
top: top
})
domUtils.removeClasses(popEl, ANCHOR_CLASSES)
popEl.className +=
' ' + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)]
if (this.editor) {
popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10
baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
popEl.style.zIndex - 1
}
this.getDom().style.visibility = 'visible'
},
showAt: function (offset) {
var left = offset.left
var top = offset.top
var rect = {
left: left,
top: top,
right: left,
bottom: top,
height: 0,
width: 0
}
this.showAnchorRect(rect, false, true)
},
_show: function () {
if (this._hidden) {
var box = this.getDom()
box.style.display = ''
this._hidden = false
// if (box.setActive) {
// box.setActive();
// }
this.fireEvent('show')
}
},
isHidden: function () {
return this._hidden
},
show: function () {
this._doAutoRender()
this._show()
},
hide: function (notNofity) {
if (!this._hidden && this.getDom()) {
this.getDom().style.display = 'none'
this._hidden = true
if (!notNofity) {
this.fireEvent('hide')
}
}
},
queryAutoHide: function (el) {
return !el || !uiUtils.contains(this.getDom(), el)
}
}
utils.inherits(Popup, UIBase)
domUtils.on(document, 'mousedown', function (evt) {
var el = evt.target || evt.srcElement
closeAllPopup(evt, el)
})
domUtils.on(window, 'scroll', function (evt, el) {
closeAllPopup(evt, el)
})
})()
// ui/colorpicker.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
UIBase = baidu.editor.ui.UIBase,
ColorPicker = (baidu.editor.ui.ColorPicker = function (options) {
this.initOptions(options)
this.noColorText = this.noColorText || this.editor.getLang('clearColor')
this.initUIBase()
})
ColorPicker.prototype = {
getHtmlTpl: function () {
return genColorPicker(this.noColorText, this.editor)
},
_onTableClick: function (evt) {
var tgt = evt.target || evt.srcElement
var color = tgt.getAttribute('data-color')
if (color) {
this.fireEvent('pickcolor', color)
}
},
_onTableOver: function (evt) {
var tgt = evt.target || evt.srcElement
var color = tgt.getAttribute('data-color')
if (color) {
this.getDom('preview').style.backgroundColor = color
}
},
_onTableOut: function () {
this.getDom('preview').style.backgroundColor = ''
},
_onPickNoColor: function () {
this.fireEvent('picknocolor')
}
}
utils.inherits(ColorPicker, UIBase)
var COLORS = (
'ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646,' +
'f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada,' +
'd8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5,' +
'bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f,' +
'a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09,' +
'7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806,' +
'c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,'
).split(',')
function genColorPicker(noColorText, editor) {
var html =
'' +
'
' +
'
' +
'
' +
noColorText +
'
' +
'
' +
'
' +
'' +
editor.getLang('themeColor') +
' ' +
''
for (var i = 0; i < COLORS.length; i++) {
if (i && i % 10 === 0) {
html +=
' ' +
(i == 60
? '' +
editor.getLang('standardColor') +
' '
: '') +
''
}
html +=
i < 70
? ' '
: ''
}
html += '
'
return html
}
})()
// ui/tablepicker.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
UIBase = baidu.editor.ui.UIBase
var TablePicker = (baidu.editor.ui.TablePicker = function (options) {
this.initOptions(options)
this.initTablePicker()
})
TablePicker.prototype = {
defaultNumRows: 10,
defaultNumCols: 10,
maxNumRows: 20,
maxNumCols: 20,
numRows: 10,
numCols: 10,
lengthOfCellSide: 22,
initTablePicker: function () {
this.initUIBase()
},
getHtmlTpl: function () {
var me = this
return (
'' +
'
' +
'
' +
' ' +
'
' +
'
' +
'
' +
'
'
)
},
_UIBase_render: UIBase.prototype.render,
render: function (holder) {
this._UIBase_render(holder)
this.getDom('label').innerHTML =
'0' +
this.editor.getLang('t_row') +
' x 0' +
this.editor.getLang('t_col')
},
_track: function (numCols, numRows) {
var style = this.getDom('overlay').style
var sideLen = this.lengthOfCellSide
style.width = numCols * sideLen + 'px'
style.height = numRows * sideLen + 'px'
var label = this.getDom('label')
label.innerHTML =
numCols +
this.editor.getLang('t_col') +
' x ' +
numRows +
this.editor.getLang('t_row')
this.numCols = numCols
this.numRows = numRows
},
_onMouseOver: function (evt, el) {
var rel = evt.relatedTarget || evt.fromElement
if (!uiUtils.contains(el, rel) && el !== rel) {
this.getDom('label').innerHTML =
'0' +
this.editor.getLang('t_col') +
' x 0' +
this.editor.getLang('t_row')
this.getDom('overlay').style.visibility = ''
}
},
_onMouseOut: function (evt, el) {
var rel = evt.relatedTarget || evt.toElement
if (!uiUtils.contains(el, rel) && el !== rel) {
this.getDom('label').innerHTML =
'0' +
this.editor.getLang('t_col') +
' x 0' +
this.editor.getLang('t_row')
this.getDom('overlay').style.visibility = 'hidden'
}
},
_onMouseMove: function (evt, el) {
var style = this.getDom('overlay').style
var offset = uiUtils.getEventOffset(evt)
var sideLen = this.lengthOfCellSide
var numCols = Math.ceil(offset.left / sideLen)
var numRows = Math.ceil(offset.top / sideLen)
this._track(numCols, numRows)
},
_onClick: function () {
this.fireEvent('picktable', this.numCols, this.numRows)
}
}
utils.inherits(TablePicker, UIBase)
})()
// ui/stateful.js
;(function () {
var browser = baidu.editor.browser,
domUtils = baidu.editor.dom.domUtils,
uiUtils = baidu.editor.ui.uiUtils
var TPL_STATEFUL =
'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
(browser.ie
? ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
' onmouseleave="$$.Stateful_onMouseLeave(event, this);"'
: ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
' onmouseout="$$.Stateful_onMouseOut(event, this);"')
baidu.editor.ui.Stateful = {
alwalysHoverable: false,
target: null, //目标元素和this指向dom不一样
Stateful_init: function () {
this._Stateful_dGetHtmlTpl = this.getHtmlTpl
this.getHtmlTpl = this.Stateful_getHtmlTpl
},
Stateful_getHtmlTpl: function () {
var tpl = this._Stateful_dGetHtmlTpl()
// 使用function避免$转义
return tpl.replace(/stateful/g, function () {
return TPL_STATEFUL
})
},
Stateful_onMouseEnter: function (evt, el) {
this.target = el
if (!this.isDisabled() || this.alwalysHoverable) {
this.addState('hover')
this.fireEvent('over')
}
},
Stateful_onMouseLeave: function (evt, el) {
if (!this.isDisabled() || this.alwalysHoverable) {
this.removeState('hover')
this.removeState('active')
this.fireEvent('out')
}
},
Stateful_onMouseOver: function (evt, el) {
var rel = evt.relatedTarget
if (!uiUtils.contains(el, rel) && el !== rel) {
this.Stateful_onMouseEnter(evt, el)
}
},
Stateful_onMouseOut: function (evt, el) {
var rel = evt.relatedTarget
if (!uiUtils.contains(el, rel) && el !== rel) {
this.Stateful_onMouseLeave(evt, el)
}
},
Stateful_onMouseDown: function (evt, el) {
if (!this.isDisabled()) {
this.addState('active')
}
},
Stateful_onMouseUp: function (evt, el) {
if (!this.isDisabled()) {
this.removeState('active')
}
},
Stateful_postRender: function () {
if (this.disabled && !this.hasState('disabled')) {
this.addState('disabled')
}
},
hasState: function (state) {
return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state)
},
addState: function (state) {
if (!this.hasState(state)) {
this.getStateDom().className += ' edui-state-' + state
}
},
removeState: function (state) {
if (this.hasState(state)) {
domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state])
}
},
getStateDom: function () {
return this.getDom('state')
},
isChecked: function () {
return this.hasState('checked')
},
setChecked: function (checked) {
if (!this.isDisabled() && checked) {
this.addState('checked')
} else {
this.removeState('checked')
}
},
isDisabled: function () {
return this.hasState('disabled')
},
setDisabled: function (disabled) {
if (disabled) {
this.removeState('hover')
this.removeState('checked')
this.removeState('active')
this.addState('disabled')
} else {
this.removeState('disabled')
}
}
}
})()
// ui/button.js
///import core
///import uicore
///import ui/stateful.js
;(function () {
var utils = baidu.editor.utils,
UIBase = baidu.editor.ui.UIBase,
Stateful = baidu.editor.ui.Stateful,
Button = (baidu.editor.ui.Button = function (options) {
if (options.name) {
var btnName = options.name
var cssRules = options.cssRules
if (!options.className) {
options.className = 'edui-for-' + btnName
}
options.cssRules =
'.edui-default .edui-for-' +
btnName +
' .edui-icon {' +
cssRules +
'}'
}
this.initOptions(options)
this.initButton()
})
Button.prototype = {
uiName: 'button',
label: '',
title: '',
showIcon: true,
showText: true,
cssRules: '',
initButton: function () {
this.initUIBase()
this.Stateful_init()
if (this.cssRules) {
utils.cssRule('edui-customize-' + this.name + '-style', this.cssRules)
}
},
getHtmlTpl: function () {
return (
'' +
'
' +
'
' +
(this.showIcon ? '
' : '') +
(this.showText
? '
' + this.label + '
'
: '') +
'
' +
'
' +
'
'
)
},
postRender: function () {
this.Stateful_postRender()
this.setDisabled(this.disabled)
},
_onMouseDown: function (e) {
var target = e.target || e.srcElement,
tagName = target && target.tagName && target.tagName.toLowerCase()
if (tagName == 'input' || tagName == 'object' || tagName == 'object') {
return false
}
},
_onClick: function () {
if (!this.isDisabled()) {
this.fireEvent('click')
}
},
setTitle: function (text) {
var label = this.getDom('label')
label.innerHTML = text
}
}
utils.inherits(Button, UIBase)
utils.extend(Button.prototype, Stateful)
})()
// ui/splitbutton.js
///import core
///import uicore
///import ui/stateful.js
;(function () {
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
domUtils = baidu.editor.dom.domUtils,
UIBase = baidu.editor.ui.UIBase,
Stateful = baidu.editor.ui.Stateful,
SplitButton = (baidu.editor.ui.SplitButton = function (options) {
this.initOptions(options)
this.initSplitButton()
})
SplitButton.prototype = {
popup: null,
uiName: 'splitbutton',
title: '',
initSplitButton: function () {
this.initUIBase()
this.Stateful_init()
var me = this
if (this.popup != null) {
var popup = this.popup
this.popup = null
this.setPopup(popup)
}
},
_UIBase_postRender: UIBase.prototype.postRender,
postRender: function () {
this.Stateful_postRender()
this._UIBase_postRender()
},
setPopup: function (popup) {
if (this.popup === popup) return
if (this.popup != null) {
this.popup.dispose()
}
popup.addListener('show', utils.bind(this._onPopupShow, this))
popup.addListener('hide', utils.bind(this._onPopupHide, this))
popup.addListener(
'postrender',
utils.bind(function () {
popup
.getDom('body')
.appendChild(
uiUtils.createElementByHtml(
''
)
)
popup.getDom().className += ' ' + this.className
}, this)
)
this.popup = popup
},
_onPopupShow: function () {
this.addState('opened')
},
_onPopupHide: function () {
this.removeState('opened')
},
getHtmlTpl: function () {
return (
''
)
},
showPopup: function () {
// 当popup往上弹出的时候,做特殊处理
var rect = uiUtils.getClientRect(this.getDom())
rect.top -= this.popup.SHADOW_RADIUS
rect.height += this.popup.SHADOW_RADIUS
this.popup.showAnchorRect(rect)
},
_onArrowClick: function (event, el) {
if (!this.isDisabled()) {
this.showPopup()
}
},
_onButtonClick: function () {
if (!this.isDisabled()) {
this.fireEvent('buttonclick')
}
}
}
utils.inherits(SplitButton, UIBase)
utils.extend(SplitButton.prototype, Stateful, true)
})()
// ui/colorbutton.js
///import core
///import uicore
///import ui/colorpicker.js
///import ui/popup.js
///import ui/splitbutton.js
;(function () {
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
ColorPicker = baidu.editor.ui.ColorPicker,
Popup = baidu.editor.ui.Popup,
SplitButton = baidu.editor.ui.SplitButton,
ColorButton = (baidu.editor.ui.ColorButton = function (options) {
this.initOptions(options)
this.initColorButton()
})
ColorButton.prototype = {
initColorButton: function () {
var me = this
this.popup = new Popup({
content: new ColorPicker({
noColorText: me.editor.getLang('clearColor'),
editor: me.editor,
onpickcolor: function (t, color) {
me._onPickColor(color)
},
onpicknocolor: function (t, color) {
me._onPickNoColor(color)
}
}),
editor: me.editor
})
this.initSplitButton()
},
_SplitButton_postRender: SplitButton.prototype.postRender,
postRender: function () {
this._SplitButton_postRender()
this.getDom('button_body').appendChild(
uiUtils.createElementByHtml(
'
'
)
)
this.getDom().className += ' edui-colorbutton'
},
setColor: function (color) {
this.getDom('colorlump').style.backgroundColor = color
this.color = color
},
_onPickColor: function (color) {
if (this.fireEvent('pickcolor', color) !== false) {
this.setColor(color)
this.popup.hide()
}
},
_onPickNoColor: function (color) {
if (this.fireEvent('picknocolor') !== false) {
this.popup.hide()
}
}
}
utils.inherits(ColorButton, SplitButton)
})()
// ui/tablebutton.js
///import core
///import uicore
///import ui/popup.js
///import ui/tablepicker.js
///import ui/splitbutton.js
;(function () {
var utils = baidu.editor.utils,
Popup = baidu.editor.ui.Popup,
TablePicker = baidu.editor.ui.TablePicker,
SplitButton = baidu.editor.ui.SplitButton,
TableButton = (baidu.editor.ui.TableButton = function (options) {
this.initOptions(options)
this.initTableButton()
})
TableButton.prototype = {
initTableButton: function () {
var me = this
this.popup = new Popup({
content: new TablePicker({
editor: me.editor,
onpicktable: function (t, numCols, numRows) {
me._onPickTable(numCols, numRows)
}
}),
editor: me.editor
})
this.initSplitButton()
},
_onPickTable: function (numCols, numRows) {
if (this.fireEvent('picktable', numCols, numRows) !== false) {
this.popup.hide()
}
}
}
utils.inherits(TableButton, SplitButton)
})()
// ui/autotypesetpicker.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
UIBase = baidu.editor.ui.UIBase
var AutoTypeSetPicker = (baidu.editor.ui.AutoTypeSetPicker = function (
options
) {
this.initOptions(options)
this.initAutoTypeSetPicker()
})
AutoTypeSetPicker.prototype = {
initAutoTypeSetPicker: function () {
this.initUIBase()
},
getHtmlTpl: function () {
var me = this.editor,
opt = me.options.autotypeset,
lang = me.getLang('autoTypeSet')
var textAlignInputName = 'textAlignValue' + me.uid,
imageBlockInputName = 'imageBlockLineValue' + me.uid,
symbolConverInputName = 'symbolConverValue' + me.uid
return (
''
)
},
_UIBase_render: UIBase.prototype.render
}
utils.inherits(AutoTypeSetPicker, UIBase)
})()
// ui/autotypesetbutton.js
///import core
///import uicore
///import ui/popup.js
///import ui/autotypesetpicker.js
///import ui/splitbutton.js
;(function () {
var utils = baidu.editor.utils,
Popup = baidu.editor.ui.Popup,
AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
SplitButton = baidu.editor.ui.SplitButton,
AutoTypeSetButton = (baidu.editor.ui.AutoTypeSetButton = function (
options
) {
this.initOptions(options)
this.initAutoTypeSetButton()
})
function getPara(me) {
var opt = {},
cont = me.getDom(),
editorId = me.editor.uid,
inputType = null,
attrName = null,
ipts = domUtils.getElementsByTagName(cont, 'input')
for (var i = ipts.length - 1, ipt; (ipt = ipts[i--]); ) {
inputType = ipt.getAttribute('type')
if (inputType == 'checkbox') {
attrName = ipt.getAttribute('name')
opt[attrName] && delete opt[attrName]
if (ipt.checked) {
var attrValue = document.getElementById(
attrName + 'Value' + editorId
)
if (attrValue) {
if (/input/gi.test(attrValue.tagName)) {
opt[attrName] = attrValue.value
} else {
var iptChilds = attrValue.getElementsByTagName('input')
for (
var j = iptChilds.length - 1, iptchild;
(iptchild = iptChilds[j--]);
) {
if (iptchild.checked) {
opt[attrName] = iptchild.value
break
}
}
}
} else {
opt[attrName] = true
}
} else {
opt[attrName] = false
}
} else {
opt[ipt.getAttribute('value')] = ipt.checked
}
}
var selects = domUtils.getElementsByTagName(cont, 'select')
for (var i = 0, si; (si = selects[i++]); ) {
var attr = si.getAttribute('name')
opt[attr] = opt[attr] ? si.value : ''
}
utils.extend(me.editor.options.autotypeset, opt)
me.editor.setPreferences('autotypeset', opt)
}
AutoTypeSetButton.prototype = {
initAutoTypeSetButton: function () {
var me = this
this.popup = new Popup({
//传入配置参数
content: new AutoTypeSetPicker({ editor: me.editor }),
editor: me.editor,
hide: function () {
if (!this._hidden && this.getDom()) {
getPara(this)
this.getDom().style.display = 'none'
this._hidden = true
this.fireEvent('hide')
}
}
})
var flag = 0
this.popup.addListener('postRenderAfter', function () {
var popupUI = this
if (flag) return
var cont = this.getDom(),
btn = cont.getElementsByTagName('button')[0]
btn.onclick = function () {
getPara(popupUI)
me.editor.execCommand('autotypeset')
popupUI.hide()
}
domUtils.on(cont, 'click', function (e) {
var target = e.target || e.srcElement,
editorId = me.editor.uid
if (target && target.tagName == 'INPUT') {
// 点击图片浮动的checkbox,去除对应的radio
if (
target.name == 'imageBlockLine' ||
target.name == 'textAlign' ||
target.name == 'symbolConver'
) {
var checked = target.checked,
radioTd = document.getElementById(
target.name + 'Value' + editorId
),
radios = radioTd.getElementsByTagName('input'),
defalutSelect = {
imageBlockLine: 'none',
textAlign: 'left',
symbolConver: 'tobdc'
}
for (var i = 0; i < radios.length; i++) {
if (checked) {
if (radios[i].value == defalutSelect[target.name]) {
radios[i].checked = 'checked'
}
} else {
radios[i].checked = false
}
}
}
// 点击radio,选中对应的checkbox
if (
target.name == 'imageBlockLineValue' + editorId ||
target.name == 'textAlignValue' + editorId ||
target.name == 'bdc'
) {
var checkboxs =
target.parentNode.previousSibling.getElementsByTagName(
'input'
)
checkboxs && (checkboxs[0].checked = true)
}
getPara(popupUI)
}
})
flag = 1
})
this.initSplitButton()
}
}
utils.inherits(AutoTypeSetButton, SplitButton)
})()
// ui/cellalignpicker.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
Popup = baidu.editor.ui.Popup,
Stateful = baidu.editor.ui.Stateful,
UIBase = baidu.editor.ui.UIBase
/**
* 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始
* 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom'
* @update 2013/4/2 hancong03@baidu.com
*/
var CellAlignPicker = (baidu.editor.ui.CellAlignPicker = function (
options
) {
this.initOptions(options)
this.initSelected()
this.initCellAlignPicker()
})
CellAlignPicker.prototype = {
//初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引
initSelected: function () {
var status = {
valign: {
top: 0,
middle: 1,
bottom: 2
},
align: {
left: 0,
center: 1,
right: 2
},
count: 3
},
result = -1
if (this.selected) {
this.selectedIndex =
status.valign[this.selected.valign] * status.count +
status.align[this.selected.align]
}
},
initCellAlignPicker: function () {
this.initUIBase()
this.Stateful_init()
},
getHtmlTpl: function () {
var alignType = ['left', 'center', 'right'],
COUNT = 9,
tempClassName = null,
tempIndex = -1,
tmpl = []
for (var i = 0; i < COUNT; i++) {
tempClassName =
this.selectedIndex === i ? ' class="edui-cellalign-selected" ' : ''
tempIndex = i % 3
tempIndex === 0 && tmpl.push('')
tmpl.push(
'
'
)
tempIndex === 2 && tmpl.push(' ')
}
return (
''
)
},
getStateDom: function () {
return this.target
},
_onClick: function (evt) {
var target = evt.target || evt.srcElement
if (/icon/.test(target.className)) {
this.items[target.parentNode.getAttribute('index')].onclick()
Popup.postHide(evt)
}
},
_UIBase_render: UIBase.prototype.render
}
utils.inherits(CellAlignPicker, UIBase)
utils.extend(CellAlignPicker.prototype, Stateful, true)
})()
// ui/pastepicker.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
Stateful = baidu.editor.ui.Stateful,
uiUtils = baidu.editor.ui.uiUtils,
UIBase = baidu.editor.ui.UIBase
var PastePicker = (baidu.editor.ui.PastePicker = function (options) {
this.initOptions(options)
this.initPastePicker()
})
PastePicker.prototype = {
initPastePicker: function () {
this.initUIBase()
this.Stateful_init()
},
getHtmlTpl: function () {
return (
'
' +
'' +
'
' +
this.editor.getLang('pasteOpt') +
'
' +
'
' +
'
' +
''
)
},
getStateDom: function () {
return this.target
},
format: function (param) {
this.editor.ui._isTransfer = true
this.editor.fireEvent('pasteTransfer', param)
},
_onClick: function (cur) {
var node = domUtils.getNextDomNode(cur),
screenHt = uiUtils.getViewportRect().height,
subPop = uiUtils.getClientRect(node)
if (subPop.top + subPop.height > screenHt)
node.style.top = -subPop.height - cur.offsetHeight + 'px'
else node.style.top = ''
if (/hidden/gi.test(domUtils.getComputedStyle(node, 'visibility'))) {
node.style.visibility = 'visible'
domUtils.addClass(cur, 'edui-state-opened')
} else {
node.style.visibility = 'hidden'
domUtils.removeClasses(cur, 'edui-state-opened')
}
},
_UIBase_render: UIBase.prototype.render
}
utils.inherits(PastePicker, UIBase)
utils.extend(PastePicker.prototype, Stateful, true)
})()
// ui/toolbar.js
;(function () {
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
UIBase = baidu.editor.ui.UIBase,
Toolbar = (baidu.editor.ui.Toolbar = function (options) {
this.initOptions(options)
this.initToolbar()
})
Toolbar.prototype = {
items: null,
initToolbar: function () {
this.items = this.items || []
this.initUIBase()
},
add: function (item, index) {
if (index === undefined) {
this.items.push(item)
} else {
this.items.splice(index, 0, item)
}
},
getHtmlTpl: function () {
var buff = []
for (var i = 0; i < this.items.length; i++) {
buff[i] = this.items[i].renderHtml()
}
return (
'' +
buff.join('') +
'
'
)
},
postRender: function () {
var box = this.getDom()
for (var i = 0; i < this.items.length; i++) {
this.items[i].postRender()
}
uiUtils.makeUnselectable(box)
},
_onMouseDown: function (e) {
var target = e.target || e.srcElement,
tagName = target && target.tagName && target.tagName.toLowerCase()
if (tagName == 'input' || tagName == 'object' || tagName == 'object') {
return false
}
}
}
utils.inherits(Toolbar, UIBase)
})()
// ui/menu.js
///import core
///import uicore
///import ui\popup.js
///import ui\stateful.js
;(function () {
var utils = baidu.editor.utils,
domUtils = baidu.editor.dom.domUtils,
uiUtils = baidu.editor.ui.uiUtils,
UIBase = baidu.editor.ui.UIBase,
Popup = baidu.editor.ui.Popup,
Stateful = baidu.editor.ui.Stateful,
CellAlignPicker = baidu.editor.ui.CellAlignPicker,
Menu = (baidu.editor.ui.Menu = function (options) {
this.initOptions(options)
this.initMenu()
})
var menuSeparator = {
renderHtml: function () {
return ''
},
postRender: function () {},
queryAutoHide: function () {
return true
}
}
Menu.prototype = {
items: null,
uiName: 'menu',
initMenu: function () {
this.items = this.items || []
this.initPopup()
this.initItems()
},
initItems: function () {
for (var i = 0; i < this.items.length; i++) {
var item = this.items[i]
if (item == '-') {
this.items[i] = this.getSeparator()
} else if (!(item instanceof MenuItem)) {
item.editor = this.editor
item.theme = this.editor.options.theme
this.items[i] = this.createItem(item)
}
}
},
getSeparator: function () {
return menuSeparator
},
createItem: function (item) {
//新增一个参数menu, 该参数存储了menuItem所对应的menu引用
item.menu = this
return new MenuItem(item)
},
_Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
getContentHtmlTpl: function () {
if (this.items.length == 0) {
return this._Popup_getContentHtmlTpl()
}
var buff = []
for (var i = 0; i < this.items.length; i++) {
var item = this.items[i]
buff[i] = item.renderHtml()
}
return '' + buff.join('') + '
'
},
_Popup_postRender: Popup.prototype.postRender,
postRender: function () {
var me = this
for (var i = 0; i < this.items.length; i++) {
var item = this.items[i]
item.ownerMenu = this
item.postRender()
}
domUtils.on(this.getDom(), 'mouseover', function (evt) {
evt = evt || event
var rel = evt.relatedTarget || evt.fromElement
var el = me.getDom()
if (!uiUtils.contains(el, rel) && el !== rel) {
me.fireEvent('over')
}
})
this._Popup_postRender()
},
queryAutoHide: function (el) {
if (el) {
if (uiUtils.contains(this.getDom(), el)) {
return false
}
for (var i = 0; i < this.items.length; i++) {
var item = this.items[i]
if (item.queryAutoHide(el) === false) {
return false
}
}
}
},
clearItems: function () {
for (var i = 0; i < this.items.length; i++) {
var item = this.items[i]
clearTimeout(item._showingTimer)
clearTimeout(item._closingTimer)
if (item.subMenu) {
item.subMenu.destroy()
}
}
this.items = []
},
destroy: function () {
if (this.getDom()) {
domUtils.remove(this.getDom())
}
this.clearItems()
},
dispose: function () {
this.destroy()
}
}
utils.inherits(Menu, Popup)
/**
* @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
* @type {Function}
*/
var MenuItem = (baidu.editor.ui.MenuItem = function (options) {
this.initOptions(options)
this.initUIBase()
this.Stateful_init()
if (this.subMenu && !(this.subMenu instanceof Menu)) {
if (options.className && options.className.indexOf('aligntd') != -1) {
var me = this
//获取单元格对齐初始状态
this.subMenu.selected = this.editor.queryCommandValue('cellalignment')
this.subMenu = new Popup({
content: new CellAlignPicker(this.subMenu),
parentMenu: me,
editor: me.editor,
destroy: function () {
if (this.getDom()) {
domUtils.remove(this.getDom())
}
}
})
this.subMenu.addListener('postRenderAfter', function () {
domUtils.on(this.getDom(), 'mouseover', function () {
me.addState('opened')
})
})
} else {
this.subMenu = new Menu(this.subMenu)
}
}
})
MenuItem.prototype = {
label: '',
subMenu: null,
ownerMenu: null,
uiName: 'menuitem',
alwalysHoverable: true,
getHtmlTpl: function () {
return (
'' +
'
' +
this.renderLabelHtml() +
'
' +
'
'
)
},
postRender: function () {
var me = this
this.addListener('over', function () {
me.ownerMenu.fireEvent('submenuover', me)
if (me.subMenu) {
me.delayShowSubMenu()
}
})
if (this.subMenu) {
this.getDom().className += ' edui-hassubmenu'
this.subMenu.render()
this.addListener('out', function () {
me.delayHideSubMenu()
})
this.subMenu.addListener('over', function () {
clearTimeout(me._closingTimer)
me._closingTimer = null
me.addState('opened')
})
this.ownerMenu.addListener('hide', function () {
me.hideSubMenu()
})
this.ownerMenu.addListener('submenuover', function (t, subMenu) {
if (subMenu !== me) {
me.delayHideSubMenu()
}
})
this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide
this.subMenu.queryAutoHide = function (el) {
if (el && uiUtils.contains(me.getDom(), el)) {
return false
}
return this._bakQueryAutoHide(el)
}
}
this.getDom().style.tabIndex = '-1'
uiUtils.makeUnselectable(this.getDom())
this.Stateful_postRender()
},
delayShowSubMenu: function () {
var me = this
if (!me.isDisabled()) {
me.addState('opened')
clearTimeout(me._showingTimer)
clearTimeout(me._closingTimer)
me._closingTimer = null
me._showingTimer = setTimeout(function () {
me.showSubMenu()
}, 250)
}
},
delayHideSubMenu: function () {
var me = this
if (!me.isDisabled()) {
me.removeState('opened')
clearTimeout(me._showingTimer)
if (!me._closingTimer) {
me._closingTimer = setTimeout(function () {
if (!me.hasState('opened')) {
me.hideSubMenu()
}
me._closingTimer = null
}, 400)
}
}
},
renderLabelHtml: function () {
return (
'
' +
'
' +
'' +
(this.label || '') +
'
'
)
},
getStateDom: function () {
return this.getDom()
},
queryAutoHide: function (el) {
if (this.subMenu && this.hasState('opened')) {
return this.subMenu.queryAutoHide(el)
}
},
_onClick: function (event, this_) {
if (this.hasState('disabled')) return
if (this.fireEvent('click', event, this_) !== false) {
if (this.subMenu) {
this.showSubMenu()
} else {
Popup.postHide(event)
}
}
},
showSubMenu: function () {
var rect = uiUtils.getClientRect(this.getDom())
rect.right -= 5
rect.left += 2
rect.width -= 7
rect.top -= 4
rect.bottom += 4
rect.height += 8
this.subMenu.showAnchorRect(rect, true, true)
},
hideSubMenu: function () {
this.subMenu.hide()
}
}
utils.inherits(MenuItem, UIBase)
utils.extend(MenuItem.prototype, Stateful, true)
})()
// ui/combox.js
///import core
///import uicore
///import ui/menu.js
///import ui/splitbutton.js
;(function () {
// todo: menu和item提成通用list
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
Menu = baidu.editor.ui.Menu,
SplitButton = baidu.editor.ui.SplitButton,
Combox = (baidu.editor.ui.Combox = function (options) {
this.initOptions(options)
this.initCombox()
})
Combox.prototype = {
uiName: 'combox',
onbuttonclick: function () {
this.showPopup()
},
initCombox: function () {
var me = this
this.items = this.items || []
for (var i = 0; i < this.items.length; i++) {
var item = this.items[i]
item.uiName = 'listitem'
item.index = i
item.onclick = function () {
me.selectByIndex(this.index)
}
}
this.popup = new Menu({
items: this.items,
uiName: 'list',
editor: this.editor,
captureWheel: true,
combox: this
})
this.initSplitButton()
},
_SplitButton_postRender: SplitButton.prototype.postRender,
postRender: function () {
this._SplitButton_postRender()
this.setLabel(this.label || '')
this.setValue(this.initValue || '')
},
showPopup: function () {
var rect = uiUtils.getClientRect(this.getDom())
rect.top += 1
rect.bottom -= 1
rect.height -= 2
this.popup.showAnchorRect(rect)
},
getValue: function () {
return this.value
},
setValue: function (value) {
var index = this.indexByValue(value)
if (index != -1) {
this.selectedIndex = index
this.setLabel(this.items[index].label)
this.value = this.items[index].value
} else {
this.selectedIndex = -1
this.setLabel(this.getLabelForUnknowValue(value))
this.value = value
}
},
setLabel: function (label) {
this.getDom('button_body').innerHTML = label
this.label = label
},
getLabelForUnknowValue: function (value) {
return value
},
indexByValue: function (value) {
for (var i = 0; i < this.items.length; i++) {
if (value == this.items[i].value) {
return i
}
}
return -1
},
getItem: function (index) {
return this.items[index]
},
selectByIndex: function (index) {
if (
index < this.items.length &&
this.fireEvent('select', index) !== false
) {
this.selectedIndex = index
this.value = this.items[index].value
this.setLabel(this.items[index].label)
}
}
}
utils.inherits(Combox, SplitButton)
})()
// ui/dialog.js
///import core
///import uicore
///import ui/mask.js
///import ui/button.js
;(function () {
var utils = baidu.editor.utils,
domUtils = baidu.editor.dom.domUtils,
uiUtils = baidu.editor.ui.uiUtils,
Mask = baidu.editor.ui.Mask,
UIBase = baidu.editor.ui.UIBase,
Button = baidu.editor.ui.Button,
Dialog = (baidu.editor.ui.Dialog = function (options) {
if (options.name) {
var name = options.name
var cssRules = options.cssRules
if (!options.className) {
options.className = 'edui-for-' + name
}
if (cssRules) {
options.cssRules =
'.edui-default .edui-for-' +
name +
' .edui-dialog-content {' +
cssRules +
'}'
}
}
this.initOptions(
utils.extend(
{
autoReset: true,
draggable: true,
onok: function () {},
oncancel: function () {},
onclose: function (t, ok) {
return ok ? this.onok() : this.oncancel()
},
//是否控制dialog中的scroll事件, 默认为不阻止
holdScroll: false
},
options
)
)
this.initDialog()
})
var modalMask
var dragMask
var activeDialog
Dialog.prototype = {
draggable: false,
uiName: 'dialog',
initDialog: function () {
var me = this,
theme = this.editor.options.theme
if (this.cssRules) {
utils.cssRule('edui-customize-' + this.name + '-style', this.cssRules)
}
this.initUIBase()
this.modalMask =
modalMask ||
(modalMask = new Mask({
className: 'edui-dialog-modalmask',
theme: theme,
onclick: function () {
activeDialog && activeDialog.close(false)
}
}))
this.dragMask =
dragMask ||
(dragMask = new Mask({
className: 'edui-dialog-dragmask',
theme: theme
}))
this.closeButton = new Button({
className: 'edui-dialog-closebutton',
title: me.closeDialog,
theme: theme,
onclick: function () {
me.close(false)
}
})
this.fullscreen && this.initResizeEvent()
if (this.buttons) {
for (var i = 0; i < this.buttons.length; i++) {
if (!(this.buttons[i] instanceof Button)) {
this.buttons[i] = new Button(
utils.extend(
this.buttons[i],
{
editor: this.editor
},
true
)
)
}
}
}
},
initResizeEvent: function () {
var me = this
domUtils.on(window, 'resize', function () {
if (me._hidden || me._hidden === undefined) {
return
}
if (me.__resizeTimer) {
window.clearTimeout(me.__resizeTimer)
}
me.__resizeTimer = window.setTimeout(function () {
me.__resizeTimer = null
var dialogWrapNode = me.getDom(),
contentNode = me.getDom('content'),
wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
contentRect = UE.ui.uiUtils.getClientRect(contentNode),
vpRect = uiUtils.getViewportRect()
contentNode.style.width =
vpRect.width - wrapRect.width + contentRect.width + 'px'
contentNode.style.height =
vpRect.height - wrapRect.height + contentRect.height + 'px'
dialogWrapNode.style.width = vpRect.width + 'px'
dialogWrapNode.style.height = vpRect.height + 'px'
me.fireEvent('resize')
}, 100)
})
},
fitSize: function () {
var popBodyEl = this.getDom('body')
// if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
// uiUtils.removeStyle(popBodyEl, 'width');
// uiUtils.removeStyle(popBodyEl, 'height');
// }
var size = this.mesureSize()
popBodyEl.style.width = size.width + 'px'
popBodyEl.style.height = size.height + 'px'
return size
},
safeSetOffset: function (offset) {
var me = this
var el = me.getDom()
var vpRect = uiUtils.getViewportRect()
var rect = uiUtils.getClientRect(el)
var left = offset.left
if (left + rect.width > vpRect.right) {
left = vpRect.right - rect.width
}
var top = offset.top
if (top + rect.height > vpRect.bottom) {
top = vpRect.bottom - rect.height
}
el.style.left = Math.max(left, 0) + 'px'
el.style.top = Math.max(top, 0) + 'px'
},
showAtCenter: function () {
var vpRect = uiUtils.getViewportRect()
if (!this.fullscreen) {
this.getDom().style.display = ''
var popSize = this.fitSize()
var titleHeight = this.getDom('titlebar').offsetHeight | 0
var left = vpRect.width / 2 - popSize.width / 2
var top =
vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight
var popEl = this.getDom()
this.safeSetOffset({
left: Math.max(left | 0, 0),
top: Math.max(top | 0, 0)
})
if (!domUtils.hasClass(popEl, 'edui-state-centered')) {
popEl.className += ' edui-state-centered'
}
} else {
var dialogWrapNode = this.getDom(),
contentNode = this.getDom('content')
dialogWrapNode.style.display = 'block'
var wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
contentRect = UE.ui.uiUtils.getClientRect(contentNode)
dialogWrapNode.style.left = '-100000px'
contentNode.style.width =
vpRect.width - wrapRect.width + contentRect.width + 'px'
contentNode.style.height =
vpRect.height - wrapRect.height + contentRect.height + 'px'
dialogWrapNode.style.width = vpRect.width + 'px'
dialogWrapNode.style.height = vpRect.height + 'px'
dialogWrapNode.style.left = 0
//保存环境的overflow值
this._originalContext = {
html: {
overflowX: document.documentElement.style.overflowX,
overflowY: document.documentElement.style.overflowY
},
body: {
overflowX: document.body.style.overflowX,
overflowY: document.body.style.overflowY
}
}
document.documentElement.style.overflowX = 'hidden'
document.documentElement.style.overflowY = 'hidden'
document.body.style.overflowX = 'hidden'
document.body.style.overflowY = 'hidden'
}
this._show()
},
getContentHtml: function () {
var contentHtml = ''
if (typeof this.content == 'string') {
contentHtml = this.content
} else if (this.iframeUrl) {
contentHtml =
' '
}
return contentHtml
},
getHtmlTpl: function () {
var footHtml = ''
if (this.buttons) {
var buff = []
for (var i = 0; i < this.buttons.length; i++) {
buff[i] = this.buttons[i].renderHtml()
}
footHtml =
''
}
return (
'' +
'
' +
'
' +
'
' +
'' +
(this.title || '') +
' ' +
'
' +
this.closeButton.renderHtml() +
'
' +
'
' +
(this.autoReset ? '' : this.getContentHtml()) +
'
' +
footHtml +
'
'
)
},
postRender: function () {
// todo: 保持居中/记住上次关闭位置选项
if (!this.modalMask.getDom()) {
this.modalMask.render()
this.modalMask.hide()
}
if (!this.dragMask.getDom()) {
this.dragMask.render()
this.dragMask.hide()
}
var me = this
this.addListener('show', function () {
me.modalMask.show(this.getDom().style.zIndex - 2)
})
this.addListener('hide', function () {
me.modalMask.hide()
})
if (this.buttons) {
for (var i = 0; i < this.buttons.length; i++) {
this.buttons[i].postRender()
}
}
domUtils.on(window, 'resize', function () {
setTimeout(function () {
if (!me.isHidden()) {
me.safeSetOffset(uiUtils.getClientRect(me.getDom()))
}
})
})
//hold住scroll事件,防止dialog的滚动影响页面
// if( this.holdScroll ) {
//
// if( !me.iframeUrl ) {
// domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
// domUtils.preventDefault(e);
// } );
// } else {
// me.addListener('dialogafterreset', function(){
// window.setTimeout(function(){
// var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow;
//
// if( browser.ie ) {
//
// var timer = window.setInterval(function(){
//
// if( iframeWindow.document && iframeWindow.document.body ) {
// window.clearInterval( timer );
// timer = null;
// domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
// domUtils.preventDefault(e);
// } );
// }
//
// }, 100);
//
// } else {
// domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
// domUtils.preventDefault(e);
// } );
// }
//
// }, 1);
// });
// }
//
// }
this._hide()
},
mesureSize: function () {
var body = this.getDom('body')
var width = uiUtils.getClientRect(this.getDom('content')).width
var dialogBodyStyle = body.style
dialogBodyStyle.width = width
return uiUtils.getClientRect(body)
},
_onTitlebarMouseDown: function (evt, el) {
if (this.draggable) {
var rect
var vpRect = uiUtils.getViewportRect()
var me = this
uiUtils.startDrag(evt, {
ondragstart: function () {
rect = uiUtils.getClientRect(me.getDom())
me.getDom('contmask').style.visibility = 'visible'
me.dragMask.show(me.getDom().style.zIndex - 1)
},
ondragmove: function (x, y) {
var left = rect.left + x
var top = rect.top + y
me.safeSetOffset({
left: left,
top: top
})
},
ondragstop: function () {
me.getDom('contmask').style.visibility = 'hidden'
domUtils.removeClasses(me.getDom(), ['edui-state-centered'])
me.dragMask.hide()
}
})
}
},
reset: function () {
this.getDom('content').innerHTML = this.getContentHtml()
this.fireEvent('dialogafterreset')
},
_show: function () {
if (this._hidden) {
this.getDom().style.display = ''
//要高过编辑器的zindxe
this.editor.container.style.zIndex &&
(this.getDom().style.zIndex =
this.editor.container.style.zIndex * 1 + 10)
this._hidden = false
this.fireEvent('show')
baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
this.getDom().style.zIndex - 4
}
},
isHidden: function () {
return this._hidden
},
_hide: function () {
if (!this._hidden) {
var wrapNode = this.getDom()
wrapNode.style.display = 'none'
wrapNode.style.zIndex = ''
wrapNode.style.width = ''
wrapNode.style.height = ''
this._hidden = true
this.fireEvent('hide')
}
},
open: function () {
if (this.autoReset) {
//有可能还没有渲染
try {
this.reset()
} catch (e) {
this.render()
this.open()
}
}
this.showAtCenter()
if (this.iframeUrl) {
try {
this.getDom('iframe').focus()
} catch (ex) {}
}
activeDialog = this
},
_onCloseButtonClick: function (evt, el) {
this.close(false)
},
close: function (ok) {
if (this.fireEvent('close', ok) !== false) {
//还原环境
if (this.fullscreen) {
document.documentElement.style.overflowX =
this._originalContext.html.overflowX
document.documentElement.style.overflowY =
this._originalContext.html.overflowY
document.body.style.overflowX = this._originalContext.body.overflowX
document.body.style.overflowY = this._originalContext.body.overflowY
delete this._originalContext
}
this._hide()
//销毁content
var content = this.getDom('content')
var iframe = this.getDom('iframe')
if (content && iframe) {
var doc = iframe.contentDocument || iframe.contentWindow.document
doc && (doc.body.innerHTML = '')
domUtils.remove(content)
}
}
}
}
utils.inherits(Dialog, UIBase)
})()
// ui/menubutton.js
///import core
///import uicore
///import ui/menu.js
///import ui/splitbutton.js
;(function () {
var utils = baidu.editor.utils,
Menu = baidu.editor.ui.Menu,
SplitButton = baidu.editor.ui.SplitButton,
MenuButton = (baidu.editor.ui.MenuButton = function (options) {
this.initOptions(options)
this.initMenuButton()
})
MenuButton.prototype = {
initMenuButton: function () {
var me = this
this.uiName = 'menubutton'
this.popup = new Menu({
items: me.items,
className: me.className,
editor: me.editor
})
this.popup.addListener('show', function () {
var list = this
for (var i = 0; i < list.items.length; i++) {
list.items[i].removeState('checked')
if (list.items[i].value == me._value) {
list.items[i].addState('checked')
this.value = me._value
}
}
})
this.initSplitButton()
},
setValue: function (value) {
this._value = value
}
}
utils.inherits(MenuButton, SplitButton)
})()
// ui/multiMenu.js
///import core
///import uicore
///commands 表情
;(function () {
var utils = baidu.editor.utils,
Popup = baidu.editor.ui.Popup,
SplitButton = baidu.editor.ui.SplitButton,
MultiMenuPop = (baidu.editor.ui.MultiMenuPop = function (options) {
this.initOptions(options)
this.initMultiMenu()
})
MultiMenuPop.prototype = {
initMultiMenu: function () {
var me = this
this.popup = new Popup({
content: '',
editor: me.editor,
iframe_rendered: false,
onshow: function () {
if (!this.iframe_rendered) {
this.iframe_rendered = true
this.getDom('content').innerHTML =
''
me.editor.container.style.zIndex &&
(this.getDom().style.zIndex =
me.editor.container.style.zIndex * 1 + 1)
}
}
// canSideUp:false,
// canSideLeft:false
})
this.onbuttonclick = function () {
this.showPopup()
}
this.initSplitButton()
}
}
utils.inherits(MultiMenuPop, SplitButton)
})()
// ui/shortcutmenu.js
;(function () {
var UI = baidu.editor.ui,
UIBase = UI.UIBase,
uiUtils = UI.uiUtils,
utils = baidu.editor.utils,
domUtils = baidu.editor.dom.domUtils
var allMenus = [], //存储所有快捷菜单
timeID,
isSubMenuShow = false //是否有子pop显示
var ShortCutMenu = (UI.ShortCutMenu = function (options) {
this.initOptions(options)
this.initShortCutMenu()
})
ShortCutMenu.postHide = hideAllMenu
ShortCutMenu.prototype = {
isHidden: true,
SPACE: 5,
initShortCutMenu: function () {
this.items = this.items || []
this.initUIBase()
this.initItems()
this.initEvent()
allMenus.push(this)
},
initEvent: function () {
var me = this,
doc = me.editor.document
domUtils.on(doc, 'mousemove', function (e) {
if (me.isHidden === false) {
//有pop显示就不隐藏快捷菜单
if (me.getSubMenuMark() || me.eventType == 'contextmenu') return
var flag = true,
el = me.getDom(),
wt = el.offsetWidth,
ht = el.offsetHeight,
distanceX = wt / 2 + me.SPACE, //距离中心X标准
distanceY = ht / 2, //距离中心Y标准
x = Math.abs(e.screenX - me.left), //离中心距离横坐标
y = Math.abs(e.screenY - me.top) //离中心距离纵坐标
clearTimeout(timeID)
timeID = setTimeout(function () {
if (y > 0 && y < distanceY) {
me.setOpacity(el, '1')
} else if (y > distanceY && y < distanceY + 70) {
me.setOpacity(el, '0.5')
flag = false
} else if (y > distanceY + 70 && y < distanceY + 140) {
me.hide()
}
if (flag && x > 0 && x < distanceX) {
me.setOpacity(el, '1')
} else if (x > distanceX && x < distanceX + 70) {
me.setOpacity(el, '0.5')
} else if (x > distanceX + 70 && x < distanceX + 140) {
me.hide()
}
})
}
})
//ie\ff下 mouseout不准
if (browser.chrome) {
domUtils.on(doc, 'mouseout', function (e) {
var relatedTgt = e.relatedTarget || e.toElement
if (relatedTgt == null || relatedTgt.tagName == 'HTML') {
me.hide()
}
})
}
me.editor.addListener('afterhidepop', function () {
if (!me.isHidden) {
isSubMenuShow = true
}
})
},
initItems: function () {
if (utils.isArray(this.items)) {
for (var i = 0, len = this.items.length; i < len; i++) {
var item = this.items[i].toLowerCase()
if (UI[item]) {
this.items[i] = new UI[item](this.editor)
this.items[i].className += ' edui-shortcutsubmenu '
}
}
}
},
setOpacity: function (el, value) {
if (browser.ie && browser.version < 9) {
el.style.filter = 'alpha(opacity = ' + parseFloat(value) * 100 + ');'
} else {
el.style.opacity = value
}
},
getSubMenuMark: function () {
isSubMenuShow = false
var layerEle = uiUtils.getFixedLayer()
var list = domUtils.getElementsByTagName(
layerEle,
'div',
function (node) {
return domUtils.hasClass(node, 'edui-shortcutsubmenu edui-popup')
}
)
for (var i = 0, node; (node = list[i++]); ) {
if (node.style.display != 'none') {
isSubMenuShow = true
}
}
return isSubMenuShow
},
show: function (e, hasContextmenu) {
var me = this,
offset = {},
el = this.getDom(),
fixedlayer = uiUtils.getFixedLayer()
function setPos(offset) {
if (offset.left < 0) {
offset.left = 0
}
if (offset.top < 0) {
offset.top = 0
}
el.style.cssText =
'position:absolute;left:' +
offset.left +
'px;top:' +
offset.top +
'px;'
}
function setPosByCxtMenu(menu) {
if (!menu.tagName) {
menu = menu.getDom()
}
offset.left = parseInt(menu.style.left)
offset.top = parseInt(menu.style.top)
offset.top -= el.offsetHeight + 15
setPos(offset)
}
me.eventType = e.type
el.style.cssText = 'display:block;left:-9999px'
if (e.type == 'contextmenu' && hasContextmenu) {
var menu = domUtils.getElementsByTagName(
fixedlayer,
'div',
'edui-contextmenu'
)[0]
if (menu) {
setPosByCxtMenu(menu)
} else {
me.editor.addListener(
'aftershowcontextmenu',
function (type, menu) {
setPosByCxtMenu(menu)
}
)
}
} else {
offset = uiUtils.getViewportOffsetByEvent(e)
offset.top -= el.offsetHeight + me.SPACE
offset.left += me.SPACE + 20
setPos(offset)
me.setOpacity(el, 0.2)
}
me.isHidden = false
me.left = e.screenX + el.offsetWidth / 2 - me.SPACE
me.top = e.screenY - el.offsetHeight / 2 - me.SPACE
if (me.editor) {
el.style.zIndex = me.editor.container.style.zIndex * 1 + 10
fixedlayer.style.zIndex = el.style.zIndex - 1
}
},
hide: function () {
if (this.getDom()) {
this.getDom().style.display = 'none'
}
this.isHidden = true
},
postRender: function () {
if (utils.isArray(this.items)) {
for (var i = 0, item; (item = this.items[i++]); ) {
item.postRender()
}
}
},
getHtmlTpl: function () {
var buff
if (utils.isArray(this.items)) {
buff = []
for (var i = 0; i < this.items.length; i++) {
buff[i] = this.items[i].renderHtml()
}
buff = buff.join('')
} else {
buff = this.items
}
return (
'' +
buff +
'
'
)
}
}
utils.inherits(ShortCutMenu, UIBase)
function hideAllMenu(e) {
var tgt = e.target || e.srcElement,
cur = domUtils.findParent(
tgt,
function (node) {
return (
domUtils.hasClass(node, 'edui-shortcutmenu') ||
domUtils.hasClass(node, 'edui-popup')
)
},
true
)
if (!cur) {
for (var i = 0, menu; (menu = allMenus[i++]); ) {
menu.hide()
}
}
}
domUtils.on(document, 'mousedown', function (e) {
hideAllMenu(e)
})
domUtils.on(window, 'scroll', function (e) {
hideAllMenu(e)
})
})()
// ui/breakline.js
;(function () {
var utils = baidu.editor.utils,
UIBase = baidu.editor.ui.UIBase,
Breakline = (baidu.editor.ui.Breakline = function (options) {
this.initOptions(options)
this.initSeparator()
})
Breakline.prototype = {
uiName: 'Breakline',
initSeparator: function () {
this.initUIBase()
},
getHtmlTpl: function () {
return ' '
}
}
utils.inherits(Breakline, UIBase)
})()
// ui/message.js
///import core
///import uicore
;(function () {
var utils = baidu.editor.utils,
domUtils = baidu.editor.dom.domUtils,
UIBase = baidu.editor.ui.UIBase,
Message = (baidu.editor.ui.Message = function (options) {
this.initOptions(options)
this.initMessage()
})
Message.prototype = {
initMessage: function () {
this.initUIBase()
},
getHtmlTpl: function () {
return (
'' +
'
×
' +
'
' +
'
' +
'
' +
'
' +
'
' +
'
' +
'
'
)
},
reset: function (opt) {
var me = this
if (!opt.keepshow) {
clearTimeout(this.timer)
me.timer = setTimeout(function () {
me.hide()
}, opt.timeout || 4000)
}
opt.content !== undefined && me.setContent(opt.content)
opt.type !== undefined && me.setType(opt.type)
me.show()
},
postRender: function () {
var me = this,
closer = this.getDom('closer')
closer &&
domUtils.on(closer, 'click', function () {
me.hide()
})
},
setContent: function (content) {
this.getDom('content').innerHTML = content
},
setType: function (type) {
type = type || 'info'
var body = this.getDom('body')
body.className = body.className.replace(
/edui-message-type-[\w-]+/,
'edui-message-type-' + type
)
},
getContent: function () {
return this.getDom('content').innerHTML
},
getType: function () {
var arr = this.getDom('body').match(/edui-message-type-([\w-]+)/)
return arr ? arr[1] : ''
},
show: function () {
this.getDom().style.display = 'block'
},
hide: function () {
var dom = this.getDom()
if (dom) {
dom.style.display = 'none'
dom.parentNode && dom.parentNode.removeChild(dom)
}
}
}
utils.inherits(Message, UIBase)
})()
// adapter/editorui.js
//ui跟编辑器的适配層
//那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
//自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据ueditor.config中的toolbars找到相应的进行实例化
;(function () {
var utils = baidu.editor.utils
var editorui = baidu.editor.ui
var _Dialog = editorui.Dialog
editorui.buttons = {}
editorui.Dialog = function (options) {
var dialog = new _Dialog(options)
dialog.addListener('hide', function () {
if (dialog.editor) {
var editor = dialog.editor
try {
if (browser.gecko) {
var y = editor.window.scrollY,
x = editor.window.scrollX
editor.body.focus()
editor.window.scrollTo(x, y)
} else {
editor.focus()
}
} catch (ex) {}
}
})
return dialog
}
var iframeUrlMap = {
anchor: '~/dialogs/anchor/anchor.html',
insertimage: '~/dialogs/image/image.html',
link: '~/dialogs/link/link.html',
spechars: '~/dialogs/spechars/spechars.html',
searchreplace: '~/dialogs/searchreplace/searchreplace.html',
map: '~/dialogs/map/map.html',
gmap: '~/dialogs/gmap/gmap.html',
insertvideo: '~/dialogs/video/video.html',
help: '~/dialogs/help/help.html',
preview: '~/dialogs/preview/preview.html',
emotion: '~/dialogs/emotion/emotion.html',
wordimage: '~/dialogs/wordimage/wordimage.html',
attachment: '~/dialogs/attachment/attachment.html',
insertframe: '~/dialogs/insertframe/insertframe.html',
edittip: '~/dialogs/table/edittip.html',
edittable: '~/dialogs/table/edittable.html',
edittd: '~/dialogs/table/edittd.html',
webapp: '~/dialogs/webapp/webapp.html',
snapscreen: '~/dialogs/snapscreen/snapscreen.html',
scrawl: '~/dialogs/scrawl/scrawl.html',
music: '~/dialogs/music/music.html',
template: '~/dialogs/template/template.html',
background: '~/dialogs/background/background.html',
charts: '~/dialogs/charts/charts.html'
}
//为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
var btnCmds = [
'undo',
'redo',
'formatmatch',
'bold',
'italic',
'underline',
'fontborder',
'touppercase',
'tolowercase',
'strikethrough',
'subscript',
'superscript',
'source',
'indent',
'outdent',
'blockquote',
'pasteplain',
'pagebreak',
'selectall',
'print',
'horizontal',
'removeformat',
'time',
'date',
'unlink',
'insertparagraphbeforetable',
'insertrow',
'insertcol',
'mergeright',
'mergedown',
'deleterow',
'deletecol',
'splittorows',
'splittocols',
'splittocells',
'mergecells',
'deletetable',
'drafts'
]
for (var i = 0, ci; (ci = btnCmds[i++]); ) {
ci = ci.toLowerCase()
editorui[ci] = (function (cmd) {
return function (editor) {
var ui = new editorui.Button({
className: 'edui-for-' + cmd,
title:
editor.options.labelMap[cmd] ||
editor.getLang('labelMap.' + cmd) ||
'',
onclick: function () {
editor.execCommand(cmd)
},
theme: editor.options.theme,
showText: false
})
editorui.buttons[cmd] = ui
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
var state = editor.queryCommandState(cmd)
if (state == -1) {
ui.setDisabled(true)
ui.setChecked(false)
} else {
if (!uiReady) {
ui.setDisabled(false)
ui.setChecked(state)
}
}
}
)
return ui
}
})(ci)
}
//清除文档
editorui.cleardoc = function (editor) {
var ui = new editorui.Button({
className: 'edui-for-cleardoc',
title:
editor.options.labelMap.cleardoc ||
editor.getLang('labelMap.cleardoc') ||
'',
theme: editor.options.theme,
onclick: function () {
if (confirm(editor.getLang('confirmClear'))) {
editor.execCommand('cleardoc')
}
}
})
editorui.buttons['cleardoc'] = ui
editor.addListener('selectionchange', function () {
ui.setDisabled(editor.queryCommandState('cleardoc') == -1)
})
return ui
}
//排版,图片排版,文字方向
var typeset = {
justify: ['left', 'right', 'center', 'justify'],
imagefloat: ['none', 'left', 'center', 'right'],
directionality: ['ltr', 'rtl']
}
for (var p in typeset) {
;(function (cmd, val) {
for (var i = 0, ci; (ci = val[i++]); ) {
;(function (cmd2) {
editorui[cmd.replace('float', '') + cmd2] = function (editor) {
var ui = new editorui.Button({
className: 'edui-for-' + cmd.replace('float', '') + cmd2,
title:
editor.options.labelMap[cmd.replace('float', '') + cmd2] ||
editor.getLang(
'labelMap.' + cmd.replace('float', '') + cmd2
) ||
'',
theme: editor.options.theme,
onclick: function () {
editor.execCommand(cmd, cmd2)
}
})
editorui.buttons[cmd] = ui
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
ui.setDisabled(editor.queryCommandState(cmd) == -1)
ui.setChecked(
editor.queryCommandValue(cmd) == cmd2 && !uiReady
)
}
)
return ui
}
})(ci)
}
})(p, typeset[p])
}
//字体颜色和背景颜色
for (var i = 0, ci; (ci = ['backcolor', 'forecolor'][i++]); ) {
editorui[ci] = (function (cmd) {
return function (editor) {
var ui = new editorui.ColorButton({
className: 'edui-for-' + cmd,
color: 'default',
title:
editor.options.labelMap[cmd] ||
editor.getLang('labelMap.' + cmd) ||
'',
editor: editor,
onpickcolor: function (t, color) {
editor.execCommand(cmd, color)
},
onpicknocolor: function () {
editor.execCommand(cmd, 'default')
this.setColor('transparent')
this.color = 'default'
},
onbuttonclick: function () {
editor.execCommand(cmd, this.color)
}
})
editorui.buttons[cmd] = ui
editor.addListener('selectionchange', function () {
ui.setDisabled(editor.queryCommandState(cmd) == -1)
})
return ui
}
})(ci)
}
var dialogBtns = {
noOk: ['searchreplace', 'help', 'spechars', 'webapp', 'preview'],
ok: [
'attachment',
'anchor',
'link',
'insertimage',
'map',
'gmap',
'insertframe',
'wordimage',
'insertvideo',
'insertframe',
'edittip',
'edittable',
'edittd',
'scrawl',
'template',
'music',
'background',
'charts'
]
}
for (var p in dialogBtns) {
;(function (type, vals) {
for (var i = 0, ci; (ci = vals[i++]); ) {
//todo opera下存在问题
if (browser.opera && ci === 'searchreplace') {
continue
}
;(function (cmd) {
editorui[cmd] = function (editor, iframeUrl, title) {
iframeUrl =
iframeUrl ||
(editor.options.iframeUrlMap || {})[cmd] ||
iframeUrlMap[cmd]
title =
editor.options.labelMap[cmd] ||
editor.getLang('labelMap.' + cmd) ||
''
var dialog
//没有iframeUrl不创建dialog
if (iframeUrl) {
dialog = new editorui.Dialog(
utils.extend(
{
iframeUrl: editor.ui.mapUrl(iframeUrl),
editor: editor,
className: 'edui-for-' + cmd,
title: title,
holdScroll: cmd === 'insertimage',
fullscreen: /charts|preview/.test(cmd),
closeDialog: editor.getLang('closeDialog')
},
type == 'ok'
? {
buttons: [
{
className: 'edui-okbutton',
label: editor.getLang('ok'),
editor: editor,
onclick: function () {
dialog.close(true)
}
},
{
className: 'edui-cancelbutton',
label: editor.getLang('cancel'),
editor: editor,
onclick: function () {
dialog.close(false)
}
}
]
}
: {}
)
)
editor.ui._dialogs[cmd + 'Dialog'] = dialog
}
var ui = new editorui.Button({
className: 'edui-for-' + cmd,
title: title,
onclick: function () {
if (dialog) {
switch (cmd) {
case 'wordimage':
var images = editor.execCommand('wordimage')
if (images && images.length) {
dialog.render()
dialog.open()
}
break
case 'scrawl':
if (editor.queryCommandState('scrawl') != -1) {
dialog.render()
dialog.open()
}
break
default:
dialog.render()
dialog.open()
}
}
},
theme: editor.options.theme,
disabled:
(cmd == 'scrawl' &&
editor.queryCommandState('scrawl') == -1) ||
cmd == 'charts'
})
editorui.buttons[cmd] = ui
editor.addListener('selectionchange', function () {
//只存在于右键菜单而无工具栏按钮的ui不需要检测状态
var unNeedCheckState = { edittable: 1 }
if (cmd in unNeedCheckState) return
var state = editor.queryCommandState(cmd)
if (ui.getDom()) {
ui.setDisabled(state == -1)
ui.setChecked(state)
}
})
return ui
}
})(ci.toLowerCase())
}
})(p, dialogBtns[p])
}
editorui.snapscreen = function (editor, iframeUrl, title) {
title =
editor.options.labelMap['snapscreen'] ||
editor.getLang('labelMap.snapscreen') ||
''
var ui = new editorui.Button({
className: 'edui-for-snapscreen',
title: title,
onclick: function () {
editor.execCommand('snapscreen')
},
theme: editor.options.theme
})
editorui.buttons['snapscreen'] = ui
iframeUrl =
iframeUrl ||
(editor.options.iframeUrlMap || {})['snapscreen'] ||
iframeUrlMap['snapscreen']
if (iframeUrl) {
var dialog = new editorui.Dialog({
iframeUrl: editor.ui.mapUrl(iframeUrl),
editor: editor,
className: 'edui-for-snapscreen',
title: title,
buttons: [
{
className: 'edui-okbutton',
label: editor.getLang('ok'),
editor: editor,
onclick: function () {
dialog.close(true)
}
},
{
className: 'edui-cancelbutton',
label: editor.getLang('cancel'),
editor: editor,
onclick: function () {
dialog.close(false)
}
}
]
})
dialog.render()
editor.ui._dialogs['snapscreenDialog'] = dialog
}
editor.addListener('selectionchange', function () {
ui.setDisabled(editor.queryCommandState('snapscreen') == -1)
})
return ui
}
editorui.insertcode = function (editor, list, title) {
list = editor.options['insertcode'] || []
title =
editor.options.labelMap['insertcode'] ||
editor.getLang('labelMap.insertcode') ||
''
// if (!list.length) return;
var items = []
utils.each(list, function (key, val) {
items.push({
label: key,
value: val,
theme: editor.options.theme,
renderLabelHtml: function () {
return (
'' +
(this.label || '') +
'
'
)
}
})
})
var ui = new editorui.Combox({
editor: editor,
items: items,
onselect: function (t, index) {
editor.execCommand('insertcode', this.items[index].value)
},
onbuttonclick: function () {
this.showPopup()
},
title: title,
initValue: title,
className: 'edui-for-insertcode',
indexByValue: function (value) {
if (value) {
for (var i = 0, ci; (ci = this.items[i]); i++) {
if (ci.value.indexOf(value) != -1) return i
}
}
return -1
}
})
editorui.buttons['insertcode'] = ui
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
if (!uiReady) {
var state = editor.queryCommandState('insertcode')
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
var value = editor.queryCommandValue('insertcode')
if (!value) {
ui.setValue(title)
return
}
//trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
value && (value = value.replace(/['"]/g, '').split(',')[0])
ui.setValue(value)
}
}
}
)
return ui
}
editorui.fontfamily = function (editor, list, title) {
list = editor.options['fontfamily'] || []
title =
editor.options.labelMap['fontfamily'] ||
editor.getLang('labelMap.fontfamily') ||
''
if (!list.length) return
for (var i = 0, ci, items = []; (ci = list[i]); i++) {
var langLabel = editor.getLang('fontfamily')[ci.name] || ''
;(function (key, val) {
items.push({
label: key,
value: val,
theme: editor.options.theme,
renderLabelHtml: function () {
return (
'' +
(this.label || '') +
'
'
)
}
})
})(ci.label || langLabel, ci.val)
}
var ui = new editorui.Combox({
editor: editor,
items: items,
onselect: function (t, index) {
editor.execCommand('FontFamily', this.items[index].value)
},
onbuttonclick: function () {
this.showPopup()
},
title: title,
initValue: title,
className: 'edui-for-fontfamily',
indexByValue: function (value) {
if (value) {
for (var i = 0, ci; (ci = this.items[i]); i++) {
if (ci.value.indexOf(value) != -1) return i
}
}
return -1
}
})
editorui.buttons['fontfamily'] = ui
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
if (!uiReady) {
var state = editor.queryCommandState('FontFamily')
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
var value = editor.queryCommandValue('FontFamily')
//trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
value && (value = value.replace(/['"]/g, '').split(',')[0])
ui.setValue(value)
}
}
}
)
return ui
}
editorui.fontsize = function (editor, list, title) {
title =
editor.options.labelMap['fontsize'] ||
editor.getLang('labelMap.fontsize') ||
''
list = list || editor.options['fontsize'] || []
if (!list.length) return
var items = []
for (var i = 0; i < list.length; i++) {
var size = list[i] + 'px'
items.push({
label: size,
value: size,
theme: editor.options.theme,
renderLabelHtml: function () {
return (
'' +
(this.label || '') +
'
'
)
}
})
}
var ui = new editorui.Combox({
editor: editor,
items: items,
title: title,
initValue: title,
onselect: function (t, index) {
editor.execCommand('FontSize', this.items[index].value)
},
onbuttonclick: function () {
this.showPopup()
},
className: 'edui-for-fontsize'
})
editorui.buttons['fontsize'] = ui
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
if (!uiReady) {
var state = editor.queryCommandState('FontSize')
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
ui.setValue(editor.queryCommandValue('FontSize'))
}
}
}
)
return ui
}
editorui.paragraph = function (editor, list, title) {
title =
editor.options.labelMap['paragraph'] ||
editor.getLang('labelMap.paragraph') ||
''
list = editor.options['paragraph'] || []
if (utils.isEmptyObject(list)) return
var items = []
for (var i in list) {
items.push({
value: i,
label: list[i] || editor.getLang('paragraph')[i],
theme: editor.options.theme,
renderLabelHtml: function () {
return (
'' +
(this.label || '') +
'
'
)
}
})
}
var ui = new editorui.Combox({
editor: editor,
items: items,
title: title,
initValue: title,
className: 'edui-for-paragraph',
onselect: function (t, index) {
editor.execCommand('Paragraph', this.items[index].value)
},
onbuttonclick: function () {
this.showPopup()
}
})
editorui.buttons['paragraph'] = ui
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
if (!uiReady) {
var state = editor.queryCommandState('Paragraph')
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
var value = editor.queryCommandValue('Paragraph')
var index = ui.indexByValue(value)
if (index != -1) {
ui.setValue(value)
} else {
ui.setValue(ui.initValue)
}
}
}
}
)
return ui
}
//自定义标题
editorui.customstyle = function (editor) {
var list = editor.options['customstyle'] || [],
title =
editor.options.labelMap['customstyle'] ||
editor.getLang('labelMap.customstyle') ||
''
if (!list.length) return
var langCs = editor.getLang('customstyle')
for (var i = 0, items = [], t; (t = list[i++]); ) {
;(function (t) {
var ck = {}
ck.label = t.label ? t.label : langCs[t.name]
ck.style = t.style
ck.className = t.className
ck.tag = t.tag
items.push({
label: ck.label,
value: ck,
theme: editor.options.theme,
renderLabelHtml: function () {
return (
'' +
'<' +
ck.tag +
' ' +
(ck.className ? ' class="' + ck.className + '"' : '') +
(ck.style ? ' style="' + ck.style + '"' : '') +
'>' +
ck.label +
'' +
ck.tag +
'>' +
'
'
)
}
})
})(t)
}
var ui = new editorui.Combox({
editor: editor,
items: items,
title: title,
initValue: title,
className: 'edui-for-customstyle',
onselect: function (t, index) {
editor.execCommand('customstyle', this.items[index].value)
},
onbuttonclick: function () {
this.showPopup()
},
indexByValue: function (value) {
for (var i = 0, ti; (ti = this.items[i++]); ) {
if (ti.label == value) {
return i - 1
}
}
return -1
}
})
editorui.buttons['customstyle'] = ui
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
if (!uiReady) {
var state = editor.queryCommandState('customstyle')
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
var value = editor.queryCommandValue('customstyle')
var index = ui.indexByValue(value)
if (index != -1) {
ui.setValue(value)
} else {
ui.setValue(ui.initValue)
}
}
}
}
)
return ui
}
editorui.inserttable = function (editor, iframeUrl, title) {
title =
editor.options.labelMap['inserttable'] ||
editor.getLang('labelMap.inserttable') ||
''
var ui = new editorui.TableButton({
editor: editor,
title: title,
className: 'edui-for-inserttable',
onpicktable: function (t, numCols, numRows) {
editor.execCommand('InsertTable', {
numRows: numRows,
numCols: numCols,
border: 1
})
},
onbuttonclick: function () {
this.showPopup()
}
})
editorui.buttons['inserttable'] = ui
editor.addListener('selectionchange', function () {
ui.setDisabled(editor.queryCommandState('inserttable') == -1)
})
return ui
}
editorui.lineheight = function (editor) {
var val = editor.options.lineheight || []
if (!val.length) return
for (var i = 0, ci, items = []; (ci = val[i++]); ) {
items.push({
//todo:写死了
label: ci,
value: ci,
theme: editor.options.theme,
onclick: function () {
editor.execCommand('lineheight', this.value)
}
})
}
var ui = new editorui.MenuButton({
editor: editor,
className: 'edui-for-lineheight',
title:
editor.options.labelMap['lineheight'] ||
editor.getLang('labelMap.lineheight') ||
'',
items: items,
onbuttonclick: function () {
var value = editor.queryCommandValue('LineHeight') || this.value
editor.execCommand('LineHeight', value)
}
})
editorui.buttons['lineheight'] = ui
editor.addListener('selectionchange', function () {
var state = editor.queryCommandState('LineHeight')
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
var value = editor.queryCommandValue('LineHeight')
value && ui.setValue((value + '').replace(/cm/, ''))
ui.setChecked(state)
}
})
return ui
}
var rowspacings = ['top', 'bottom']
for (var r = 0, ri; (ri = rowspacings[r++]); ) {
;(function (cmd) {
editorui['rowspacing' + cmd] = function (editor) {
var val = editor.options['rowspacing' + cmd] || []
if (!val.length) return null
for (var i = 0, ci, items = []; (ci = val[i++]); ) {
items.push({
label: ci,
value: ci,
theme: editor.options.theme,
onclick: function () {
editor.execCommand('rowspacing', this.value, cmd)
}
})
}
var ui = new editorui.MenuButton({
editor: editor,
className: 'edui-for-rowspacing' + cmd,
title:
editor.options.labelMap['rowspacing' + cmd] ||
editor.getLang('labelMap.rowspacing' + cmd) ||
'',
items: items,
onbuttonclick: function () {
var value =
editor.queryCommandValue('rowspacing', cmd) || this.value
editor.execCommand('rowspacing', value, cmd)
}
})
editorui.buttons[cmd] = ui
editor.addListener('selectionchange', function () {
var state = editor.queryCommandState('rowspacing', cmd)
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
var value = editor.queryCommandValue('rowspacing', cmd)
value && ui.setValue((value + '').replace(/%/, ''))
ui.setChecked(state)
}
})
return ui
}
})(ri)
}
//有序,无序列表
var lists = ['insertorderedlist', 'insertunorderedlist']
for (var l = 0, cl; (cl = lists[l++]); ) {
;(function (cmd) {
editorui[cmd] = function (editor) {
var vals = editor.options[cmd],
_onMenuClick = function () {
editor.execCommand(cmd, this.value)
},
items = []
for (var i in vals) {
items.push({
label: vals[i] || editor.getLang()[cmd][i] || '',
value: i,
theme: editor.options.theme,
onclick: _onMenuClick
})
}
var ui = new editorui.MenuButton({
editor: editor,
className: 'edui-for-' + cmd,
title: editor.getLang('labelMap.' + cmd) || '',
items: items,
onbuttonclick: function () {
var value = editor.queryCommandValue(cmd) || this.value
editor.execCommand(cmd, value)
}
})
editorui.buttons[cmd] = ui
editor.addListener('selectionchange', function () {
var state = editor.queryCommandState(cmd)
if (state == -1) {
ui.setDisabled(true)
} else {
ui.setDisabled(false)
var value = editor.queryCommandValue(cmd)
ui.setValue(value)
ui.setChecked(state)
}
})
return ui
}
})(cl)
}
editorui.fullscreen = function (editor, title) {
title =
editor.options.labelMap['fullscreen'] ||
editor.getLang('labelMap.fullscreen') ||
''
var ui = new editorui.Button({
className: 'edui-for-fullscreen',
title: title,
theme: editor.options.theme,
onclick: function () {
if (editor.ui) {
editor.ui.setFullScreen(!editor.ui.isFullScreen())
}
this.setChecked(editor.ui.isFullScreen())
}
})
editorui.buttons['fullscreen'] = ui
editor.addListener('selectionchange', function () {
var state = editor.queryCommandState('fullscreen')
ui.setDisabled(state == -1)
ui.setChecked(editor.ui.isFullScreen())
})
return ui
}
// 表情
editorui['emotion'] = function (editor, iframeUrl) {
var cmd = 'emotion'
var ui = new editorui.MultiMenuPop({
title:
editor.options.labelMap[cmd] ||
editor.getLang('labelMap.' + cmd + '') ||
'',
editor: editor,
className: 'edui-for-' + cmd,
iframeUrl: editor.ui.mapUrl(
iframeUrl ||
(editor.options.iframeUrlMap || {})[cmd] ||
iframeUrlMap[cmd]
)
})
editorui.buttons[cmd] = ui
editor.addListener('selectionchange', function () {
ui.setDisabled(editor.queryCommandState(cmd) == -1)
})
return ui
}
editorui.autotypeset = function (editor) {
var ui = new editorui.AutoTypeSetButton({
editor: editor,
title:
editor.options.labelMap['autotypeset'] ||
editor.getLang('labelMap.autotypeset') ||
'',
className: 'edui-for-autotypeset',
onbuttonclick: function () {
editor.execCommand('autotypeset')
}
})
editorui.buttons['autotypeset'] = ui
editor.addListener('selectionchange', function () {
ui.setDisabled(editor.queryCommandState('autotypeset') == -1)
})
return ui
}
/* 简单上传插件 */
editorui['simpleupload'] = function (editor) {
var name = 'simpleupload',
ui = new editorui.Button({
className: 'edui-for-' + name,
title:
editor.options.labelMap[name] ||
editor.getLang('labelMap.' + name) ||
'',
onclick: function () {},
theme: editor.options.theme,
showText: false
})
editorui.buttons[name] = ui
editor.addListener('ready', function () {
var b = ui.getDom('body'),
iconSpan = b.children[0]
editor.fireEvent('simpleuploadbtnready', iconSpan)
})
editor.addListener(
'selectionchange',
function (type, causeByUi, uiReady) {
var state = editor.queryCommandState(name)
if (state == -1) {
ui.setDisabled(true)
ui.setChecked(false)
} else {
if (!uiReady) {
ui.setDisabled(false)
ui.setChecked(state)
}
}
}
)
return ui
}
})()
// adapter/editor.js
///import core
///commands 全屏
///commandsName FullScreen
///commandsTitle 全屏
;(function () {
var utils = baidu.editor.utils,
uiUtils = baidu.editor.ui.uiUtils,
UIBase = baidu.editor.ui.UIBase,
domUtils = baidu.editor.dom.domUtils
var nodeStack = []
function EditorUI(options) {
this.initOptions(options)
this.initEditorUI()
}
EditorUI.prototype = {
uiName: 'editor',
initEditorUI: function () {
this.editor.ui = this
this._dialogs = {}
this.initUIBase()
this._initToolbars()
var editor = this.editor,
me = this
editor.addListener('ready', function () {
//提供getDialog方法
editor.getDialog = function (name) {
return editor.ui._dialogs[name + 'Dialog']
}
domUtils.on(editor.window, 'scroll', function (evt) {
baidu.editor.ui.Popup.postHide(evt)
})
//提供编辑器实时宽高(全屏时宽高不变化)
editor.ui._actualFrameWidth = editor.options.initialFrameWidth
UE.browser.ie &&
UE.browser.version === 6 &&
editor.container.ownerDocument.execCommand(
'BackgroundImageCache',
false,
true
)
//display bottom-bar label based on config
if (editor.options.elementPathEnabled) {
editor.ui.getDom('elementpath').innerHTML =
'' +
editor.getLang('elementPathTip') +
':
'
}
if (editor.options.wordCount) {
function countFn() {
setCount(editor, me)
domUtils.un(editor.document, 'click', arguments.callee)
}
domUtils.on(editor.document, 'click', countFn)
editor.ui.getDom('wordcount').innerHTML =
editor.getLang('wordCountTip')
}
editor.ui._scale()
if (editor.options.scaleEnabled) {
if (editor.autoHeightEnabled) {
editor.disableAutoHeight()
}
me.enableScale()
} else {
me.disableScale()
}
if (
!editor.options.elementPathEnabled &&
!editor.options.wordCount &&
!editor.options.scaleEnabled
) {
editor.ui.getDom('elementpath').style.display = 'none'
editor.ui.getDom('wordcount').style.display = 'none'
editor.ui.getDom('scale').style.display = 'none'
}
if (!editor.selection.isFocus()) return
editor.fireEvent('selectionchange', false, true)
})
editor.addListener('mousedown', function (t, evt) {
var el = evt.target || evt.srcElement
baidu.editor.ui.Popup.postHide(evt, el)
baidu.editor.ui.ShortCutMenu.postHide(evt)
})
editor.addListener('delcells', function () {
if (UE.ui['edittip']) {
new UE.ui['edittip'](editor)
}
editor.getDialog('edittip').open()
})
var pastePop,
isPaste = false,
timer
editor.addListener('afterpaste', function () {
if (editor.queryCommandState('pasteplain')) return
if (baidu.editor.ui.PastePicker) {
pastePop = new baidu.editor.ui.Popup({
content: new baidu.editor.ui.PastePicker({ editor: editor }),
editor: editor,
className: 'edui-wordpastepop'
})
pastePop.render()
}
isPaste = true
})
editor.addListener('afterinserthtml', function () {
clearTimeout(timer)
timer = setTimeout(function () {
if (pastePop && (isPaste || editor.ui._isTransfer)) {
if (pastePop.isHidden()) {
var span = domUtils.createElement(editor.document, 'span', {
style: 'line-height:0px;',
innerHTML: '\ufeff'
}),
range = editor.selection.getRange()
range.insertNode(span)
var tmp = getDomNode(span, 'firstChild', 'previousSibling')
tmp &&
pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp)
domUtils.remove(span)
} else {
pastePop.show()
}
delete editor.ui._isTransfer
isPaste = false
}
}, 200)
})
editor.addListener('contextmenu', function (t, evt) {
baidu.editor.ui.Popup.postHide(evt)
})
editor.addListener('keydown', function (t, evt) {
if (pastePop) pastePop.dispose(evt)
var keyCode = evt.keyCode || evt.which
if (evt.altKey && keyCode == 90) {
UE.ui.buttons['fullscreen'].onclick()
}
})
editor.addListener('wordcount', function (type) {
setCount(this, me)
})
function setCount(editor, ui) {
editor.setOpt({
wordCount: true,
maximumWords: 10000,
wordCountMsg:
editor.options.wordCountMsg || editor.getLang('wordCountMsg'),
wordOverFlowMsg:
editor.options.wordOverFlowMsg ||
editor.getLang('wordOverFlowMsg')
})
var opt = editor.options,
max = opt.maximumWords,
msg = opt.wordCountMsg,
errMsg = opt.wordOverFlowMsg,
countDom = ui.getDom('wordcount')
if (!opt.wordCount) {
return
}
var count = editor.getContentLength(true)
if (count > max) {
countDom.innerHTML = errMsg
editor.fireEvent('wordcountoverflow')
} else {
countDom.innerHTML = msg
.replace('{#leave}', max - count)
.replace('{#count}', count)
}
}
editor.addListener('selectionchange', function () {
if (editor.options.elementPathEnabled) {
me[
(editor.queryCommandState('elementpath') == -1 ? 'dis' : 'en') +
'ableElementPath'
]()
}
if (editor.options.scaleEnabled) {
me[
(editor.queryCommandState('scale') == -1 ? 'dis' : 'en') +
'ableScale'
]()
}
})
var popup = new baidu.editor.ui.Popup({
editor: editor,
content: '',
className: 'edui-bubble',
_onEditButtonClick: function () {
this.hide()
editor.ui._dialogs.linkDialog.open()
},
_onImgEditButtonClick: function (name) {
this.hide()
editor.ui._dialogs[name] && editor.ui._dialogs[name].open()
},
_onImgSetFloat: function (value) {
this.hide()
editor.execCommand('imagefloat', value)
},
_setIframeAlign: function (value) {
var frame = popup.anchorEl
var newFrame = frame.cloneNode(true)
switch (value) {
case -2:
newFrame.setAttribute('align', '')
break
case -1:
newFrame.setAttribute('align', 'left')
break
case 1:
newFrame.setAttribute('align', 'right')
break
}
frame.parentNode.insertBefore(newFrame, frame)
domUtils.remove(frame)
popup.anchorEl = newFrame
popup.showAnchor(popup.anchorEl)
},
_updateIframe: function () {
var frame = (editor._iframe = popup.anchorEl)
if (domUtils.hasClass(frame, 'ueditor_baidumap')) {
editor.selection.getRange().selectNode(frame).select()
editor.ui._dialogs.mapDialog.open()
popup.hide()
} else {
editor.ui._dialogs.insertframeDialog.open()
popup.hide()
}
},
_onRemoveButtonClick: function (cmdName) {
editor.execCommand(cmdName)
this.hide()
},
queryAutoHide: function (el) {
if (el && el.ownerDocument == editor.document) {
if (
el.tagName.toLowerCase() == 'img' ||
domUtils.findParentByTagName(el, 'a', true)
) {
return el !== popup.anchorEl
}
}
return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el)
}
})
popup.render()
if (editor.options.imagePopup) {
editor.addListener('mouseover', function (t, evt) {
evt = evt || window.event
var el = evt.target || evt.srcElement
if (
editor.ui._dialogs.insertframeDialog &&
/iframe/gi.test(el.tagName)
) {
var html = popup.formatHtml(
'' +
editor.getLang('property') +
': ' +
editor.getLang('default') +
' ' +
editor.getLang('justifyleft') +
' ' +
editor.getLang('justifyright') +
' ' +
' ' +
editor.getLang('modify') +
' '
)
if (html) {
popup.getDom('content').innerHTML = html
popup.anchorEl = el
popup.showAnchor(popup.anchorEl)
} else {
popup.hide()
}
}
})
editor.addListener('selectionchange', function (t, causeByUi) {
if (!causeByUi) return
var html = '',
str = '',
img = editor.selection.getRange().getClosedNode(),
dialogs = editor.ui._dialogs
if (img && img.tagName == 'IMG') {
var dialogName = 'insertimageDialog'
if (
img.className.indexOf('edui-faked-video') != -1 ||
img.className.indexOf('edui-upload-video') != -1
) {
dialogName = 'insertvideoDialog'
}
if (img.className.indexOf('edui-faked-webapp') != -1) {
dialogName = 'webappDialog'
}
if (img.src.indexOf('http://api.map.baidu.com') != -1) {
dialogName = 'mapDialog'
}
if (img.className.indexOf('edui-faked-music') != -1) {
dialogName = 'musicDialog'
}
if (
img.src.indexOf('http://maps.google.com/maps/api/staticmap') !=
-1
) {
dialogName = 'gmapDialog'
}
if (img.getAttribute('anchorname')) {
dialogName = 'anchorDialog'
html = popup.formatHtml(
'' +
editor.getLang('property') +
': ' +
editor.getLang('modify') +
' ' +
'' +
editor.getLang('delete') +
' '
)
}
if (img.getAttribute('word_img')) {
//todo 放到dialog去做查询
editor.word_img = [img.getAttribute('word_img')]
dialogName = 'wordimageDialog'
}
if (
domUtils.hasClass(img, 'loadingclass') ||
domUtils.hasClass(img, 'loaderrorclass')
) {
dialogName = ''
}
if (!dialogs[dialogName]) {
return
}
str =
'' +
editor.getLang('property') +
': ' +
'' +
editor.getLang('default') +
' ' +
'' +
editor.getLang('justifyleft') +
' ' +
'' +
editor.getLang('justifyright') +
' ' +
'' +
editor.getLang('justifycenter') +
' ' +
'' +
editor.getLang('modify') +
' '
!html && (html = popup.formatHtml(str))
}
if (editor.ui._dialogs.linkDialog) {
var link = editor.queryCommandValue('link')
var url
if (
link &&
(url =
link.getAttribute('_href') || link.getAttribute('href', 2))
) {
var txt = url
if (url.length > 30) {
txt = url.substring(0, 20) + '...'
}
if (html) {
html += '
'
}
html += popup.formatHtml(
'' +
editor.getLang('anthorMsg') +
': ' +
txt +
' ' +
' ' +
editor.getLang('modify') +
' ' +
' ' +
editor.getLang('clear') +
' '
)
popup.showAnchor(link)
}
}
if (html) {
popup.getDom('content').innerHTML = html
popup.anchorEl = img || link
popup.showAnchor(popup.anchorEl)
} else {
popup.hide()
}
})
}
},
_initToolbars: function () {
var editor = this.editor
var toolbars = this.toolbars || []
var toolbarUis = []
for (var i = 0; i < toolbars.length; i++) {
var toolbar = toolbars[i]
var toolbarUi = new baidu.editor.ui.Toolbar({
theme: editor.options.theme
})
for (var j = 0; j < toolbar.length; j++) {
var toolbarItem = toolbar[j]
var toolbarItemUi = null
if (typeof toolbarItem == 'string') {
toolbarItem = toolbarItem.toLowerCase()
if (toolbarItem == '|') {
toolbarItem = 'Separator'
}
if (toolbarItem == '||') {
toolbarItem = 'Breakline'
}
if (baidu.editor.ui[toolbarItem]) {
toolbarItemUi = new baidu.editor.ui[toolbarItem](editor)
}
//fullscreen这里单独处理一下,放到首行去
if (toolbarItem == 'fullscreen') {
if (toolbarUis && toolbarUis[0]) {
toolbarUis[0].items.splice(0, 0, toolbarItemUi)
} else {
toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi)
}
continue
}
} else {
toolbarItemUi = toolbarItem
}
if (toolbarItemUi && toolbarItemUi.id) {
toolbarUi.add(toolbarItemUi)
}
}
toolbarUis[i] = toolbarUi
}
//接受外部定制的UI(修复因 utils.each 无法准确的循环出对象的全部元素而导致的自定义 UI 不符合预期的 BUG by HaoChuan9421)
// utils.each(UE._customizeUI,function(obj,key){
// var itemUI,index;
// if(obj.id && obj.id != editor.key){
// return false;
// }
// itemUI = obj.execFn.call(editor,editor,key);
// if(itemUI){
// index = obj.index;
// if(index === undefined){
// index = toolbarUi.items.length;
// }
// toolbarUi.add(itemUI,index)
// }
// });
for (var key in UE._customizeUI) {
var obj = UE._customizeUI[key]
var itemUI, index
if (!obj.id || obj.id == editor.key) {
itemUI = obj.execFn.call(editor, editor, key)
if (itemUI) {
index = obj.index
if (index === undefined) {
index = toolbarUi.items.length
}
toolbarUi.add(itemUI, index)
}
}
}
this.toolbars = toolbarUis
},
getHtmlTpl: function () {
return (
'' +
'
' +
'
' +
'
' +
//modify wdcount by matao
'
' +
'
' +
'
'
)
},
showWordImageDialog: function () {
this._dialogs['wordimageDialog'].open()
},
renderToolbarBoxHtml: function () {
var buff = []
for (var i = 0; i < this.toolbars.length; i++) {
buff.push(this.toolbars[i].renderHtml())
}
return buff.join('')
},
setFullScreen: function (fullscreen) {
var editor = this.editor,
container = editor.container.parentNode.parentNode
if (this._fullscreen != fullscreen) {
this._fullscreen = fullscreen
this.editor.fireEvent('beforefullscreenchange', fullscreen)
if (baidu.editor.browser.gecko) {
var bk = editor.selection.getRange().createBookmark()
}
if (fullscreen) {
while (container.tagName != 'BODY') {
var position = baidu.editor.dom.domUtils.getComputedStyle(
container,
'position'
)
nodeStack.push(position)
container.style.position = 'static'
container = container.parentNode
}
this._bakHtmlOverflow = document.documentElement.style.overflow
this._bakBodyOverflow = document.body.style.overflow
this._bakAutoHeight = this.editor.autoHeightEnabled
this._bakScrollTop = Math.max(
document.documentElement.scrollTop,
document.body.scrollTop
)
this._bakEditorContaninerWidth =
editor.iframe.parentNode.offsetWidth
if (this._bakAutoHeight) {
//当全屏时不能执行自动长高
editor.autoHeightEnabled = false
this.editor.disableAutoHeight()
}
document.documentElement.style.overflow = 'hidden'
//修复,滚动条不收起的问题
window.scrollTo(0, window.scrollY)
this._bakCssText = this.getDom().style.cssText
this._bakCssText1 = this.getDom('iframeholder').style.cssText
editor.iframe.parentNode.style.width = ''
this._updateFullScreen()
} else {
while (container.tagName != 'BODY') {
container.style.position = nodeStack.shift()
container = container.parentNode
}
this.getDom().style.cssText = this._bakCssText
this.getDom('iframeholder').style.cssText = this._bakCssText1
if (this._bakAutoHeight) {
editor.autoHeightEnabled = true
this.editor.enableAutoHeight()
}
document.documentElement.style.overflow = this._bakHtmlOverflow
document.body.style.overflow = this._bakBodyOverflow
editor.iframe.parentNode.style.width =
this._bakEditorContaninerWidth + 'px'
window.scrollTo(0, this._bakScrollTop)
}
if (browser.gecko && editor.body.contentEditable === 'true') {
var input = document.createElement('input')
document.body.appendChild(input)
editor.body.contentEditable = false
setTimeout(function () {
input.focus()
setTimeout(function () {
editor.body.contentEditable = true
editor.fireEvent('fullscreenchanged', fullscreen)
editor.selection.getRange().moveToBookmark(bk).select(true)
baidu.editor.dom.domUtils.remove(input)
fullscreen && window.scroll(0, 0)
}, 0)
}, 0)
}
if (editor.body.contentEditable === 'true') {
this.editor.fireEvent('fullscreenchanged', fullscreen)
this.triggerLayout()
}
}
},
_updateFullScreen: function () {
if (this._fullscreen) {
var vpRect = uiUtils.getViewportRect()
this.getDom().style.cssText =
'border:0;position:absolute;left:0;top:' +
(this.editor.options.topOffset || 0) +
'px;width:' +
vpRect.width +
'px;height:' +
vpRect.height +
'px;z-index:' +
(this.getDom().style.zIndex * 1 + 100)
uiUtils.setViewportOffset(this.getDom(), {
left: 0,
top: this.editor.options.topOffset || 0
})
this.editor.setHeight(
vpRect.height -
this.getDom('toolbarbox').offsetHeight -
this.getDom('bottombar').offsetHeight -
(this.editor.options.topOffset || 0),
true
)
//不手动调一下,会导致全屏失效
if (browser.gecko) {
try {
window.onresize()
} catch (e) {}
}
}
},
_updateElementPath: function () {
var bottom = this.getDom('elementpath'),
list
if (
this.elementPathEnabled &&
(list = this.editor.queryCommandValue('elementpath'))
) {
var buff = []
for (var i = 0, ci; (ci = list[i]); i++) {
buff[i] = this.formatHtml(
'' +
ci +
' '
)
}
bottom.innerHTML =
'' +
this.editor.getLang('elementPathTip') +
': ' +
buff.join(' > ') +
'
'
} else {
bottom.style.display = 'none'
}
},
disableElementPath: function () {
var bottom = this.getDom('elementpath')
bottom.innerHTML = ''
bottom.style.display = 'none'
this.elementPathEnabled = false
},
enableElementPath: function () {
var bottom = this.getDom('elementpath')
bottom.style.display = ''
this.elementPathEnabled = true
this._updateElementPath()
},
_scale: function () {
var doc = document,
editor = this.editor,
editorHolder = editor.container,
editorDocument = editor.document,
toolbarBox = this.getDom('toolbarbox'),
bottombar = this.getDom('bottombar'),
scale = this.getDom('scale'),
scalelayer = this.getDom('scalelayer')
var isMouseMove = false,
position = null,
minEditorHeight = 0,
minEditorWidth = editor.options.minFrameWidth,
pageX = 0,
pageY = 0,
scaleWidth = 0,
scaleHeight = 0
function down() {
position = domUtils.getXY(editorHolder)
if (!minEditorHeight) {
minEditorHeight =
editor.options.minFrameHeight +
toolbarBox.offsetHeight +
bottombar.offsetHeight
}
scalelayer.style.cssText =
'position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:' +
editorHolder.offsetWidth +
'px;height:' +
editorHolder.offsetHeight +
'px;z-index:' +
(editor.options.zIndex + 1)
domUtils.on(doc, 'mousemove', move)
domUtils.on(editorDocument, 'mouseup', up)
domUtils.on(doc, 'mouseup', up)
}
var me = this
//by xuheng 全屏时关掉缩放
this.editor.addListener('fullscreenchanged', function (e, fullScreen) {
if (fullScreen) {
me.disableScale()
} else {
if (me.editor.options.scaleEnabled) {
me.enableScale()
var tmpNode = me.editor.document.createElement('span')
me.editor.body.appendChild(tmpNode)
me.editor.body.style.height =
Math.max(
domUtils.getXY(tmpNode).y,
me.editor.iframe.offsetHeight - 20
) + 'px'
domUtils.remove(tmpNode)
}
}
})
function move(event) {
clearSelection()
var e = event || window.event
pageX = e.pageX || doc.documentElement.scrollLeft + e.clientX
pageY = e.pageY || doc.documentElement.scrollTop + e.clientY
scaleWidth = pageX - position.x
scaleHeight = pageY - position.y
if (scaleWidth >= minEditorWidth) {
isMouseMove = true
scalelayer.style.width = scaleWidth + 'px'
}
if (scaleHeight >= minEditorHeight) {
isMouseMove = true
scalelayer.style.height = scaleHeight + 'px'
}
}
function up() {
if (isMouseMove) {
isMouseMove = false
editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2
editorHolder.style.width = editor.ui._actualFrameWidth + 'px'
editor.setHeight(
scalelayer.offsetHeight -
bottombar.offsetHeight -
toolbarBox.offsetHeight -
2,
true
)
}
if (scalelayer) {
scalelayer.style.display = 'none'
}
clearSelection()
domUtils.un(doc, 'mousemove', move)
domUtils.un(editorDocument, 'mouseup', up)
domUtils.un(doc, 'mouseup', up)
}
function clearSelection() {
if (browser.ie) doc.selection.clear()
else window.getSelection().removeAllRanges()
}
this.enableScale = function () {
//trace:2868
if (editor.queryCommandState('source') == 1) return
scale.style.display = ''
this.scaleEnabled = true
domUtils.on(scale, 'mousedown', down)
}
this.disableScale = function () {
scale.style.display = 'none'
this.scaleEnabled = false
domUtils.un(scale, 'mousedown', down)
}
},
isFullScreen: function () {
return this._fullscreen
},
postRender: function () {
UIBase.prototype.postRender.call(this)
for (var i = 0; i < this.toolbars.length; i++) {
this.toolbars[i].postRender()
}
var me = this
var timerId,
domUtils = baidu.editor.dom.domUtils,
updateFullScreenTime = function () {
clearTimeout(timerId)
timerId = setTimeout(function () {
me._updateFullScreen()
})
}
domUtils.on(window, 'resize', updateFullScreenTime)
me.addListener('destroy', function () {
domUtils.un(window, 'resize', updateFullScreenTime)
clearTimeout(timerId)
})
},
showToolbarMsg: function (msg, flag) {
this.getDom('toolbarmsg_label').innerHTML = msg
this.getDom('toolbarmsg').style.display = ''
//
if (!flag) {
var w = this.getDom('upload_dialog')
w.style.display = 'none'
}
},
hideToolbarMsg: function () {
this.getDom('toolbarmsg').style.display = 'none'
},
mapUrl: function (url) {
return url
? url.replace('~/', this.editor.options.UEDITOR_HOME_URL || '')
: ''
},
triggerLayout: function () {
var dom = this.getDom()
if (dom.style.zoom == '1') {
dom.style.zoom = '100%'
} else {
dom.style.zoom = '1'
}
}
}
utils.inherits(EditorUI, baidu.editor.ui.UIBase)
var instances = {}
UE.ui.Editor = function (options) {
var editor = new UE.Editor(options)
editor.options.editor = editor
utils.loadFile(document, {
href:
editor.options.themePath + editor.options.theme + '/css/ueditor.css',
tag: 'link',
type: 'text/css',
rel: 'stylesheet'
})
var oldRender = editor.render
editor.render = function (holder) {
if (holder.constructor === String) {
editor.key = holder
instances[holder] = editor
}
utils.domReady(function () {
editor.langIsReady
? renderUI()
: editor.addListener('langReady', renderUI)
function renderUI() {
editor.setOpt({
labelMap: editor.options.labelMap || editor.getLang('labelMap')
})
new EditorUI(editor.options)
if (holder) {
if (holder.constructor === String) {
holder = document.getElementById(holder)
}
holder &&
holder.getAttribute('name') &&
(editor.options.textarea = holder.getAttribute('name'))
if (holder && /script|textarea/gi.test(holder.tagName)) {
var newDiv = document.createElement('div')
holder.parentNode.insertBefore(newDiv, holder)
var cont = holder.value || holder.innerHTML
editor.options.initialContent = /^[\t\r\n ]*$/.test(cont)
? editor.options.initialContent
: cont
.replace(/>[\n\r\t]+([ ]{4})+/g, '>')
.replace(/[\n\r\t]+([ ]{4})+[\n\r\t]+<')
holder.className && (newDiv.className = holder.className)
holder.style.cssText &&
(newDiv.style.cssText = holder.style.cssText)
if (/textarea/i.test(holder.tagName)) {
editor.textarea = holder
editor.textarea.style.display = 'none'
} else {
holder.parentNode.removeChild(holder)
}
if (holder.id) {
newDiv.id = holder.id
domUtils.removeAttributes(holder, 'id')
}
holder = newDiv
holder.innerHTML = ''
}
}
domUtils.addClass(holder, 'edui-' + editor.options.theme)
editor.ui.render(holder)
var opt = editor.options
//给实例添加一个编辑器的容器引用
editor.container = editor.ui.getDom()
var parents = domUtils.findParents(holder, true)
var displays = []
for (var i = 0, ci; (ci = parents[i]); i++) {
displays[i] = ci.style.display
ci.style.display = 'block'
}
if (opt.initialFrameWidth) {
opt.minFrameWidth = opt.initialFrameWidth
} else {
opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth
var styleWidth = holder.style.width
if (/%$/.test(styleWidth)) {
opt.initialFrameWidth = styleWidth
}
}
if (opt.initialFrameHeight) {
opt.minFrameHeight = opt.initialFrameHeight
} else {
opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight
}
for (var i = 0, ci; (ci = parents[i]); i++) {
ci.style.display = displays[i]
}
//编辑器最外容器设置了高度,会导致,编辑器不占位
//todo 先去掉,没有找到原因
if (holder.style.height) {
holder.style.height = ''
}
editor.container.style.width =
opt.initialFrameWidth +
(/%$/.test(opt.initialFrameWidth) ? '' : 'px')
editor.container.style.zIndex = opt.zIndex
oldRender.call(editor, editor.ui.getDom('iframeholder'))
editor.fireEvent('afteruiready')
}
})
}
return editor
}
/**
* @file
* @name UE
* @short UE
* @desc UEditor的顶部命名空间
*/
/**
* @name getEditor
* @since 1.2.4+
* @grammar UE.getEditor(id,[opt]) => Editor实例
* @desc 提供一个全局的方法得到编辑器实例
*
* * ''id'' 放置编辑器的容器id, 如果容器下的编辑器已经存在,就直接返回
* * ''opt'' 编辑器的可选参数
* @example
* UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
* this.setContent('hello')
* }});
* UE.getEditor('containerId'); //返回刚创建的实例
*
*/
UE.getEditor = function (id, opt) {
var editor = instances[id]
if (!editor) {
editor = instances[id] = new UE.ui.Editor(opt)
editor.render(id)
}
return editor
}
UE.delEditor = function (id) {
var editor
if ((editor = instances[id])) {
editor.key && editor.destroy()
delete instances[id]
}
}
UE.registerUI = function (uiName, fn, index, editorId) {
utils.each(uiName.split(/\s+/), function (name) {
UE._customizeUI[name] = {
id: editorId,
execFn: fn,
index: index
}
})
}
})()
// adapter/message.js
UE.registerUI('message', function (editor) {
var editorui = baidu.editor.ui
var Message = editorui.Message
var holder
var _messageItems = []
var me = editor
me.addListener('ready', function () {
holder = document.getElementById(me.ui.id + '_message_holder')
updateHolderPos()
// HaoChuan9421
// setTimeout(function(){
// updateHolderPos();
// }, 500);
})
me.addListener('showmessage', function (type, opt) {
opt = utils.isString(opt)
? {
content: opt
}
: opt
var message = new Message({
timeout: opt.timeout,
type: opt.type,
content: opt.content,
keepshow: opt.keepshow,
editor: me
}),
mid = opt.id || 'msg_' + (+new Date()).toString(36)
message.render(holder)
_messageItems[mid] = message
message.reset(opt)
updateHolderPos()
return mid
})
me.addListener('updatemessage', function (type, id, opt) {
opt = utils.isString(opt)
? {
content: opt
}
: opt
var message = _messageItems[id]
message.render(holder)
message && message.reset(opt)
})
me.addListener('hidemessage', function (type, id) {
var message = _messageItems[id]
message && message.hide()
})
function updateHolderPos() {
var toolbarbox = me.ui.getDom('toolbarbox')
if (toolbarbox) {
holder.style.top = toolbarbox.offsetHeight + 3 + 'px'
}
holder.style.zIndex =
Math.max(me.options.zIndex, me.iframe.style.zIndex) + 1
}
})
// adapter/autosave.js
UE.registerUI('autosave', function (editor) {
var timer = null,
uid = null
editor.on('afterautosave', function () {
clearTimeout(timer)
timer = setTimeout(function () {
if (uid) {
editor.trigger('hidemessage', uid)
}
uid = editor.trigger('showmessage', {
content: editor.getLang('autosave.success'),
timeout: 2000
})
}, 2000)
})
})
})()