diff --git a/vendor/ueditor/ueditor.all.js b/vendor/ueditor/ueditor.all.js index 4bf58480..a1139a1f 100644 --- a/vendor/ueditor/ueditor.all.js +++ b/vendor/ueditor/ueditor.all.js @@ -1,12 +1,12 @@ -/*! - * UEditor - * version: ueditor - * build: Mon Jan 07 2019 11:39:49 GMT+0800 (CST) - */ - -(function(){ - -// editor.js +/*! + * UEditor + * version: ueditor + * build: Mon Jan 07 2019 11:39:49 GMT+0800 (CST) + */ + +(function(){ + +// editor.js UEDITOR_CONFIG = window.UEDITOR_CONFIG || {}; var baidu = window.baidu || {}; @@ -27,9 +27,9 @@ UE._customizeUI = {}; UE.version = "1.4.3"; -var dom = UE.dom = {}; - -// core/browser.js +var dom = UE.dom = {}; + +// core/browser.js /** * 浏览器判断模块 * @file @@ -287,9 +287,9 @@ var browser = UE.browser = function(){ var ie = browser.ie, webkit = browser.webkit, gecko = browser.gecko, - opera = browser.opera; - -// core/utils.js + opera = browser.opera; + +// core/utils.js /** * 工具函数包 * @file @@ -1522,9 +1522,9 @@ utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date'] return Object.prototype.toString.apply(obj) == '[object ' + v + ']'; } }); - - -// core/EventBase.js + + +// core/EventBase.js /** * UE采用的事件基类 * @file @@ -1692,9 +1692,9 @@ function getListener(obj, type, force) { && ( allListeners[type] || force && ( allListeners[type] = [] ) ) ); } - - -// core/dtd.js + + +// core/dtd.js ///import editor.js ///import core/dom/dom.js ///import core/utils.js @@ -1874,9 +1874,9 @@ var dtd = dom.dtd = (function() { dfn : L }); })(); - - -// core/domUtils.js + + +// core/domUtils.js /** * Dom操作工具包 * @file @@ -4290,9 +4290,9 @@ var domUtils = dom.domUtils = { }, fillHtml : browser.ie11below ? ' ' : '
' }; -var fillCharReg = new RegExp(domUtils.fillChar, 'g'); - -// core/Range.js +var fillCharReg = new RegExp(domUtils.fillChar, 'g'); + +// core/Range.js /** * Range封装 * @file @@ -6137,9 +6137,9 @@ var fillCharReg = new RegExp(domUtils.fillChar, 'g'); return this.moveToBookmark(bookmark); } }; -})(); - -// core/Selection.js +})(); + +// core/Selection.js /** * 选集 * @file @@ -6528,9 +6528,9 @@ var fillCharReg = new RegExp(domUtils.fillChar, 'g'); this.getNative()[browser.ie9below ? 'empty' : 'removeAllRanges'](); } }; -})(); - -// core/Editor.js +})(); + +// core/Editor.js /** * 编辑器主类,包含编辑器提供的大部分公用接口 * @file @@ -8067,111 +8067,111 @@ var fillCharReg = new RegExp(domUtils.fillChar, 'g'); }; utils.inherits(Editor, EventBase); })(); - - -// core/Editor.defaultoptions.js -//维护编辑器一下默认的不在插件中的配置项 -UE.Editor.defaultOptions = function(editor){ - - var _url = editor.options.UEDITOR_HOME_URL; - return { - isShow: true, - initialContent: '', - initialStyle:'', - autoClearinitialContent: false, - iframeCssUrl: _url + 'themes/iframe.css', - textarea: 'editorValue', - focus: false, - focusInEnd: true, - autoClearEmptyNode: true, - fullscreen: false, - readonly: false, - zIndex: 999, - imagePopup: true, - enterTag: 'p', - customDomain: false, - lang: 'zh-cn', - langPath: _url + 'lang/', - theme: 'default', - themePath: _url + 'themes/', - allHtmlEnabled: false, - scaleEnabled: false, - tableNativeEditInFF: false, - autoSyncData : true, - fileNameFormat: '{time}{rand:6}' - } -}; - -// core/loadconfig.js -(function(){ - - UE.Editor.prototype.loadServerConfig = function(){ - var me = this; - setTimeout(function(){ - try{ - me.options.imageUrl && me.setOpt('serverUrl', me.options.imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2')); - - var configUrl = me.getActionUrl('config'), - isJsonp = utils.isCrossDomainUrl(configUrl); - - /* 发出ajax请求 */ - me._serverConfigLoaded = false; - - configUrl && UE.ajax.request(configUrl,{ - 'method': 'GET', - 'dataType': isJsonp ? 'jsonp':'', - 'onsuccess':function(r){ - try { - var config = isJsonp ? r:eval("("+r.responseText+")"); - utils.extend(me.options, config); - me.fireEvent('serverConfigLoaded'); - me._serverConfigLoaded = true; - } catch (e) { - showErrorMsg(me.getLang('loadconfigFormatError')); - } - }, - 'onerror':function(){ - showErrorMsg(me.getLang('loadconfigHttpError')); - } - }); - } catch(e){ - showErrorMsg(me.getLang('loadconfigError')); - } - }); - - function showErrorMsg(msg) { - console && msg && console.error(msg); - //me.fireEvent('showMessage', { - // 'title': msg, - // 'type': 'error' - //}); - } - }; - - UE.Editor.prototype.isServerConfigLoaded = function(){ - var me = this; - return me._serverConfigLoaded || false; - }; - - UE.Editor.prototype.afterConfigReady = function(handler){ - if (!handler || !utils.isFunction(handler)) return; - var me = this; - var readyHandler = function(){ - handler.apply(me, arguments); - me.removeListener('serverConfigLoaded', readyHandler); - }; - - if (me.isServerConfigLoaded()) { - handler.call(me, 'serverConfigLoaded'); - } else { - me.addListener('serverConfigLoaded', readyHandler); - } - }; - -})(); - - -// core/ajax.js + + +// core/Editor.defaultoptions.js +//维护编辑器一下默认的不在插件中的配置项 +UE.Editor.defaultOptions = function(editor){ + + var _url = editor.options.UEDITOR_HOME_URL; + return { + isShow: true, + initialContent: '', + initialStyle:'', + autoClearinitialContent: false, + iframeCssUrl: _url + 'themes/iframe.css', + textarea: 'editorValue', + focus: false, + focusInEnd: true, + autoClearEmptyNode: true, + fullscreen: false, + readonly: false, + zIndex: 999, + imagePopup: true, + enterTag: 'p', + customDomain: false, + lang: 'zh-cn', + langPath: _url + 'lang/', + theme: 'default', + themePath: _url + 'themes/', + allHtmlEnabled: false, + scaleEnabled: false, + tableNativeEditInFF: false, + autoSyncData : true, + fileNameFormat: '{time}{rand:6}' + } +}; + +// core/loadconfig.js +(function(){ + + UE.Editor.prototype.loadServerConfig = function(){ + var me = this; + setTimeout(function(){ + try{ + me.options.imageUrl && me.setOpt('serverUrl', me.options.imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2')); + + var configUrl = me.getActionUrl('config'), + isJsonp = utils.isCrossDomainUrl(configUrl); + + /* 发出ajax请求 */ + me._serverConfigLoaded = false; + + configUrl && UE.ajax.request(configUrl,{ + 'method': 'GET', + 'dataType': isJsonp ? 'jsonp':'', + 'onsuccess':function(r){ + try { + var config = isJsonp ? r:eval("("+r.responseText+")"); + utils.extend(me.options, config); + me.fireEvent('serverConfigLoaded'); + me._serverConfigLoaded = true; + } catch (e) { + showErrorMsg(me.getLang('loadconfigFormatError')); + } + }, + 'onerror':function(){ + showErrorMsg(me.getLang('loadconfigHttpError')); + } + }); + } catch(e){ + showErrorMsg(me.getLang('loadconfigError')); + } + }); + + function showErrorMsg(msg) { + console && msg && console.error(msg); + //me.fireEvent('showMessage', { + // 'title': msg, + // 'type': 'error' + //}); + } + }; + + UE.Editor.prototype.isServerConfigLoaded = function(){ + var me = this; + return me._serverConfigLoaded || false; + }; + + UE.Editor.prototype.afterConfigReady = function(handler){ + if (!handler || !utils.isFunction(handler)) return; + var me = this; + var readyHandler = function(){ + handler.apply(me, arguments); + me.removeListener('serverConfigLoaded', readyHandler); + }; + + if (me.isServerConfigLoaded()) { + handler.call(me, 'serverConfigLoaded'); + } else { + me.addListener('serverConfigLoaded', readyHandler); + } + }; + +})(); + + +// core/ajax.js /** * @file * @module UE.ajax @@ -8434,9 +8434,9 @@ UE.ajax = function() { }(); - - -// core/filterword.js + + +// core/filterword.js /** * UE过滤word的静态方法 * @file @@ -8625,20979 +8625,20979 @@ var filterWord = UE.filterWord = function () { return function ( html ) { return (isWordDocument( html ) ? filterPasteWord( html ) : html); }; -}(); - -// core/node.js -/** - * 编辑器模拟的节点类 - * @file - * @module UE - * @class uNode - * @since 1.2.6.1 - */ - -/** - * UEditor公用空间,UEditor所有的功能都挂载在该空间下 - * @unfile - * @module UE - */ - -(function () { - - /** - * 编辑器模拟的节点类 - * @unfile - * @module UE - * @class uNode - */ - - /** - * 通过一个键值对,创建一个uNode对象 - * @constructor - * @param { Object } attr 传入要创建的uNode的初始属性 - * @example - * ```javascript - * var node = new uNode({ - * type:'element', - * tagName:'span', - * attrs:{style:'font-size:14px;'} - * } - * ``` - */ - var uNode = UE.uNode = function (obj) { - this.type = obj.type; - this.data = obj.data; - this.tagName = obj.tagName; - this.parentNode = obj.parentNode; - this.attrs = obj.attrs || {}; - this.children = obj.children; - }; - - var notTransAttrs = { - 'href':1, - 'src':1, - '_src':1, - '_href':1, - 'cdata_data':1 - }; - - var notTransTagName = { - style:1, - script:1 - }; - - var indentChar = ' ', - breakChar = '\n'; - - function insertLine(arr, current, begin) { - arr.push(breakChar); - return current + (begin ? 1 : -1); - } - - function insertIndent(arr, current) { - //插入缩进 - for (var i = 0; i < current; i++) { - arr.push(indentChar); - } - } - - //创建uNode的静态方法 - //支持标签和html - uNode.createElement = function (html) { - if (/[<>]/.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 +}(); + +// core/node.js /** - * UE过滤节点的静态方法 + * 编辑器模拟的节点类 * @file + * @module UE + * @class uNode + * @since 1.2.6.1 */ /** * UEditor公用空间,UEditor所有的功能都挂载在该空间下 + * @unfile * @module UE */ +(function () { -/** - * 根据传入节点和过滤规则过滤相应节点 - * @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++; - } - } - } + /** + * 编辑器模拟的节点类 + * @unfile + * @module UE + * @class uNode + */ + /** + * 通过一个键值对,创建一个uNode对象 + * @constructor + * @param { Object } attr 传入要创建的uNode的初始属性 + * @example + * ```javascript + * var node = new uNode({ + * type:'element', + * tagName:'span', + * attrs:{style:'font-size:14px;'} + * } + * ``` + */ + var uNode = UE.uNode = function (obj) { + this.type = obj.type; + this.data = obj.data; + this.tagName = obj.tagName; + this.parentNode = obj.parentNode; + this.attrs = obj.attrs || {}; + this.children = obj.children; + }; - }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; - } + var notTransAttrs = { + 'href':1, + 'src':1, + '_src':1, + '_href':1, + 'cdata_data':1 + }; - } - 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++; - } - } + var notTransTagName = { + style:1, + script:1 + }; + + var indentChar = ' ', + breakChar = '\n'; + + function insertLine(arr, current, begin) { + arr.push(breakChar); + return current + (begin ? 1 : -1); + } + + function insertIndent(arr, current) { + //插入缩进 + for (var i = 0; i < current; i++) { + arr.push(indentChar); + } + } + + //创建uNode的静态方法 + //支持标签和html + uNode.createElement = function (html) { + if (/[<>]/.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': - node.parentNode.removeChild(node) + 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,'  ')) } } - return function(root,rules){ - if(utils.isEmptyObject(rules)){ - return root; + + 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(' '); } - var val; - if(val = rules['-']){ - utils.each(val.split(' '),function(k){ - rules[k] = '-' - }) + 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) + } + } - for(var i= 0,ci;ci=root.children[i];){ - filterNode(ci,rules); - if(ci.parentNode){ - i++; + 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) } } - return root; + 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 + '>'); + } + } -}(); - -// 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; + 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; } - 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) + } + + 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) } - return; + if(ci.parentNode) i++ } - 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); -// } - }) + }else{ + fn(root) + } - }); + } + uNode.prototype = { - //从编辑器出去的内容处理 - me.addOutputRule(function (root) { + /** + * 当前节点对象,转换成html文本 + * @method toHtml + * @return { String } 返回转换后的html字符串 + * @example + * ```javascript + * node.toHtml(); + * ``` + */ - var val; - root.traversal(function (node) { - if (node.type == 'element') { + /** + * 当前节点对象,转换成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('') + }, - if (me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) { + /** + * 获取节点的html内容 + * @method innerHTML + * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点 + * @return { String } 返回节点的html内容 + * @example + * ```javascript + * var htmlstr = node.innerHTML(); + * ``` + */ - if (!node.firstChild()) node.parentNode.removeChild(node); - else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) { - node.parentNode.removeChild(node, true) + /** + * 设置节点的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; } - 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': '' - }) - } + 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; + }, - }); -}; - - -// plugins/inserthtml.js -/** - * 插入html字符串插件 - * @file - * @since 1.2.6.1 - */ + /** + * 获取当前节点下的最后一个子节点 + * @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; + }, -/** - * 插入html代码 - * @command inserthtml - * @method execCommand - * @param { String } cmd 命令字符串 - * @param { String } html 插入的html字符串 - * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入 - * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。 - * @example - * ```javascript - * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本 - * //执行命令,插入CC - * //插入后的效果 xxxCCxxx - * //

    xx|xxx

    当前选区为闭合状态 - * //插入

    CC

    - * //结果

    xx

    CC

    xxx

    - * //

    xxxx

    |

    xxx

    当前选区在两个p标签之间 - * //插入 xxxx - * //结果

    xxxx

    xxxx

    xxx

    - * ``` - */ - -UE.commands['inserthtml'] = { - execCommand: function (command,html,notNeedFilter){ - var me = this, - range, - div; - if(!html){ - return; - } - if(me.fireEvent('beforeinserthtml',html) === true){ - return; - } - range = me.selection.getRange(); - div = range.document.createElement( 'div' ); - div.style.display = 'inline'; - if (!notNeedFilter) { - var root = UE.htmlparser(html); - //如果给了过滤规则就先进行过滤 - if(me.options.filterRules){ - UE.filterNode(root,me.options.filterRules); - } - //执行默认的处理 - me.filterInputRule(root); - html = root.toHtml() - } - div.innerHTML = utils.trim( html ); - if ( !range.collapsed ) { - var tmpNode = range.startContainer; - if(domUtils.isFillChar(tmpNode)){ - range.setStartBefore(tmpNode) - } - tmpNode = range.endContainer; - if(domUtils.isFillChar(tmpNode)){ - range.setEndAfter(tmpNode) + /** + * 获取和当前节点有相同父亲节点的前一个节点 + * @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]; + } } - 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); + + }, + + /** + * 获取和当前节点有相同父亲节点的后一个节点 + * @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]; } } - 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) + }, + /** + * 用新的节点替换当前节点 + * @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; } } } - !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); + }, + + /** + * 在节点的子节点列表最后位置插入一个节点 + * @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; } - domUtils.remove(child); } + this.children.push(node); + node.parentNode = this; + return node; } - } - - 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; + }, + /** + * 在传入节点的前面插入一个节点 + * @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); } - 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; + for (var i = 0, ci; ci = this.children[i]; i++) { + if (ci === source) { + this.children.splice(i, 0, target); + target.parentNode = this; + return target; } } - } - 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 + /** + * 在传入节点的后面插入一个节点 + * @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; } + } - 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; + /** + * 从当前节点的子节点列表中,移除节点 + * @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()] + }, - 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; + /** + * 设置当前节点所代表的元素属性,即设置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]; } } - var next = child.nextSibling; - if(!div.firstChild && next && domUtils.isBlockElm(next)){ - - range.setStart(next,0).collapse(true); - break; + } else { + if (!attrVal) { + delete this.attrs[attrName] + } else { + this.attrs[attrName.toLowerCase()] = attrVal; } - 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]){ + /** + * 获取当前节点在父节点下的位置索引 + * @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; + }, - range.setStart(nextNode,0).collapse(true).shrinkBoundary() + /** + * 在当前节点下,根据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; } - }else{ + } + } + }, - try{ - child.innerHTML = browser.ie ? domUtils.fillChar : '
    '; - }catch(e){ - range.setStartBefore(child); - domUtils.remove(child) + /** + * 在当前节点下,根据元素名称查找节点列表 + * @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 '' } - //加上true因为在删除表情等时会删两次,第一次是删的fillData - try{ - range.select(true); - }catch(e){} + 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)) + }, - setTimeout(function(){ - range = me.selection.getRange(); - range.scrollToView(me.autoHeightEnabled,me.autoHeightEnabled ? domUtils.getXY(me.iframe).y:0); - me.fireEvent('afterinserthtml', html); - },200); + /** + * 传入一个函数,递归遍历当前节点下的所有节点 + * @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; + } } -}; - - -// plugins/autotypeset.js +})(); + + +// core/htmlparser.js /** - * 自动排版 + * html字符串转换成uNode节点 * @file + * @module UE * @since 1.2.6.1 */ /** - * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。 - * @command autotypeset - * @method execCommand - * @param { String } cmd 命令字符串 + * 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 - * editor.execCommand( 'autotypeset' ); + * var root = UE.htmlparser('

    htmlparser

    ', true); * ``` */ -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 htmlparser = UE.htmlparser = function (htmlstr,ignoreBlank) { + //todo 原来的方式 [^"'<>\/] 有\/就不能配对上 这样的标签了 + //先去掉了,加上的原因忘了,这里先记录 + var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g, + re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g; - 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; + //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?'':' ')+']+$'),''); + }); } - readLocalOpts(); + var notTransAttrs = { + 'href':1, + 'src':1 + }; - 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; - } + 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' + }; - return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node,new RegExp('[\\s'+domUtils.fillChar - +']','g')); + 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 removeNotAttributeSpan(node){ - if(!node.style.cssText){ - domUtils.removeAttributes(node,['style']); - if(node.tagName.toLowerCase() == 'span' && domUtils.hasNoAttributes(node)){ - domUtils.remove(node,true); + 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 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,'*'); + function comment(parent, data) { + parent.children.push(new uNode({ + type:'comment', + data:data, + parentNode:parent + })); + } - // 行首缩进,段落方向,段间距,段内间距 - for(var i=0,ci;ci=nodes[i++];){ + var match, currentIndex = 0, nextIndex = 0; + //设置根节点 + var root = new uNode({ + type:'root', + children:[] + }); + var currentParent = root; - if(me.fireEvent('excludeNodeinautotype',ci) === true){ - continue; + while (match = re_tag.exec(htmlstr)) { + currentIndex = match.index; + try{ + if (currentIndex > nextIndex) { + //text node + text(currentParent, htmlstr.slice(nextIndex, currentIndex)); } - //font-size - if(opt.clearFontSize && ci.style.fontSize){ - domUtils.removeStyle(ci,'font-size'); + if (match[3]) { - removeNotAttributeSpan(ci); - - } - //font-family - if(opt.clearFontFamily && ci.style.fontFamily){ - domUtils.removeStyle(ci,'font-family'); - removeNotAttributeSpan(ci); - } + if(dtd.$cdata[currentParent.tagName]){ + text(currentParent, match[0]); + }else{ + //start tag + currentParent = element(currentParent, match[3].toLowerCase(), match[4]); + } - 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; + } 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; } - domUtils.remove(ci); - continue; } + } else if (match[2]) { + //comment + comment(currentParent, match[2]) } - 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'; + }catch(e){} - } + nextIndex = re_tag.lastIndex; - //去掉class,保留的class不去掉 - if(opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]){ + } + //如果结束是文本,就有可能丢掉,所以这里手动判断一下 + //例如
  • sdfsdfsdf
  • sdfsdfsdfsdf + if (nextIndex < htmlstr.length) { + text(currentParent, htmlstr.slice(nextIndex)); + } + return root; +}; - 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',''); - } +// 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++; + } + } + } - } - 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 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++; } - - + } } - } 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() + break; + case 'comment': + node.parentNode.removeChild(node) } - 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() + + } + return function(root,rules){ + if(utils.isEmptyObject(rules)){ + return root; } - if(html){ - html.html = cont.innerHTML; + var val; + if(val = rules['-']){ + utils.each(val.split(' '),function(k){ + rules[k] = '-' + }) } - } - 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); + for(var i= 0,ci;ci=root.children[i];){ + filterNode(ci,rules); + if(ci.parentNode){ + i++; } } - return result; + return root; } - 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); +}(); + +// 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) } } - return tmp; } +}(); - function readLocalOpts() { - var cookieOpt = me.getPreferences('autotypeset'); - utils.extend(me.options.autotypeset, cookieOpt); - } +// core/keymap.js +var keymap = UE.keymap = { + 'Backspace' : 8, + 'Tab' : 9, + 'Enter' : 13, - me.commands['autotypeset'] = { - execCommand:function () { - me.removeListener('beforepaste',autotype); - if(opt.pasteFilter){ - me.addListener('beforepaste',autotype); - } - autotype.call(me) - } + 'Shift':16, + 'Control':17, + 'Alt':18, + 'CapsLock':20, - }; + 'Esc':27, -}; + 'Spacebar':32, - - -// plugins/autosubmit.js -/** - * 快捷键提交 - * @file - * @since 1.2.6.1 - */ + 'PageUp':33, + 'PageDown':34, + 'End':35, + 'Home':36, -/** - * 提交表单 - * @command autosubmit - * @method execCommand - * @param { String } cmd 命令字符串 - * @example - * ```javascript - * editor.execCommand( 'autosubmit' ); - * ``` - */ + 'Left':37, + 'Up':38, + 'Right':39, + 'Down':40, -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'); + 'Insert':45, - 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; - } + 'Del':46, - 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方法 + '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'; - var orgFn = me.hasContents; - me.hasContents = function(){ - if(me.queryCommandValue('background')){ - return true - } - return orgFn.apply(me,arguments); - }; return { - bindEvents: { - 'getAllHtml': function (type, headHtml) { - var body = this.body, - su = domUtils.getComputedStyle(body, "background-image"), - url = ""; - if (su.indexOf(me.options.imagePath) > 0) { - url = su.substring(su.indexOf(me.options.imagePath), su.length - 1).replace(/"|\(|\)/ig, ""); - } else { - url = su != "none" ? su.replace(/url\("?|"?\)/ig, "") : ""; - } - var html = ' '; - headHtml.push(html); - }, - 'aftersetcontent': function () { - if(isSetColored == false) setBackground(); - } - }, - inputRule: function (root) { - isSetColored = false; - utils.each(root.getNodesByTagName('p'), function (p) { - var styles = p.getAttr('data-background'); - if (styles) { - isSetColored = true; - setBackground(stringToObj(styles)); - p.parentNode.removeChild(p); - } - }) - }, - outputRule: function (root) { - var me = this, - styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg); - if (styles) { - root.appendChild(UE.uNode.createElement('


    ')); - } - }, - commands: { - 'background': { - execCommand: function (cmd, obj) { - setBackground(obj); - }, - queryCommandValue: function () { - var me = this, - styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg); - return styles ? stringToObj(styles[1]) : null; - }, - notNeedUndo: true + + saveLocalData: function (key, data) { + + if (storage && data) { + storage.setItem(key, data); + return 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 = '' + ci.alt + ''; - 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' ); - * ``` - */ + return false; -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; + getLocalData: function (key) { - //闭合时单独处理 - if (range.collapsed) { - txt = this.document.createTextNode('p'); - range.insertNode(txt); - } - doJustify(range, align); - if (txt) { - range.setStartBefore(txt).collapse(true); - domUtils.remove(txt); + if (storage) { + return storage.getItem(key); } - range.select(); - + return null; - 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; + removeItem: function (key) { + + storage && storage.removeItem(key); + } }; -}; - - -// 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' ); - * ``` - */ + function getUserData() { -/** - * 字体背景颜色 - * @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' ); - * ``` - */ + var container = document.createElement("div"); + container.style.display = "none"; -/** - * 字体大小 - * @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' ); - * ``` - */ + if (!container.addBehavior) { + return null; + } -/** - * 字体样式 - * @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' ); - * ``` - */ + container.addBehavior("#default#userdata"); -/** - * 字体下划线,与删除线互斥 - * @command underline - * @method execCommand - * @param { String } cmd 命令字符串 - * @example - * ```javascript - * editor.execCommand( 'underline' ); - * ``` - */ + return { -/** - * 字体删除线,与下划线互斥 - * @command strikethrough - * @method execCommand - * @param { String } cmd 命令字符串 - * @example - * ```javascript - * editor.execCommand( 'strikethrough' ); - * ``` - */ + getItem: function (key) { -/** - * 字体边框 - * @command fontborder - * @method execCommand - * @param { String } cmd 命令字符串 - * @example - * ```javascript - * editor.execCommand( 'fontborder' ); - * ``` - */ + var result = null; -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' + try { + document.body.appendChild(container); + container.load(LOCAL_FILE); + result = container.getAttribute(key); + document.body.removeChild(container); + } catch (e) { + } - }; - 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] - }); + return result; - 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; - } - } + setItem: function (key, value) { - } - 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) - } - } - } + document.body.appendChild(container); + container.setAttribute(key, value); + container.save(LOCAL_FILE); + document.body.removeChild(container); - } - 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; - } - } + }, + //// 暂时没有用到 + //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); - 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(); +(function () { + var ROOTKEY = 'ueditor_preference'; - } else { - range.insertNode(text); - range.selectNode(text).select(); - span = range.document.createElement('span'); + 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)); + }; - if (needCmd[cmd]) { - //a标签内的不处理跳过 - if (domUtils.findParentByTagName(text, 'a', true)) { - range.setStartBefore(text).setCursor(); - domUtils.remove(text); - return; - } - me.execCommand('removeFormat', 'span,a', style); - } + UE.Editor.prototype.getPreferences = function(key){ + var data = LocalStorage.getLocalData(ROOTKEY); + if (data && (data = utils.str2json(data))) { + return key ? data[key] : data + } + return null; + }; - span.style.cssText = style + ':' + value; + 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)); + }; +})(); - 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; - } - } +// plugins/defaultfilter.js +///import core +///plugin 编辑器默认的过滤转换机制 - 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(); +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) } - - //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; + 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; } - - tmpNode = tmpNode.parentNode; + }); + if (!node.firstChild()) { + node.innerHTML(browser.ie ? ' ' : '
    ') } - 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; + 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); } } - tmp = tmp.parentNode; } - return '' - } + 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( cmdName == 'FontSize' ) { - var styleVal = domUtils.getComputedStyle(startNode, style), - tmp = /^([\d\.]+)(\w+)$/.exec( styleVal ); + } +// if(node.type == 'comment'){ +// node.parentNode.removeChild(node); +// } + }) - if( tmp ) { + }); - return Math.floor( tmp[1] ) + tmp[2]; + //从编辑器出去的内容处理 + me.addOutputRule(function (root) { - } + var val; + root.traversal(function (node) { + if (node.type == 'element') { - return styleVal; + 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': '' + }) + } - 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 + } + + }) + + + }); +}; + + +// plugins/inserthtml.js /** - * 超链接 + * 插入html字符串插件 * @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 + * 插入html代码 + * @command inserthtml * @method execCommand * @param { String } cmd 命令字符串 + * @param { String } html 插入的html字符串 + * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入 + * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。 * @example * ```javascript - * editor.execCommand( 'unlink'); + * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本 + * //执行命令,插入CC + * //插入后的效果 xxxCCxxx + * //

    xx|xxx

    当前选区为闭合状态 + * //插入

    CC

    + * //结果

    xx

    CC

    xxx

    + * //

    xxxx

    |

    xxx

    当前选区在两个p标签之间 + * //插入 xxxx + * //结果

    xxxx

    xxxx

    xxx

    * ``` */ -UE.plugins['link'] = function(){ - function optimize( range ) { - var start = range.startContainer,end = range.endContainer; - - if ( start = domUtils.findParentByTagName( start, 'a', true ) ) { - range.setStartBefore( start ); +UE.commands['inserthtml'] = { + execCommand: function (command,html,notNeedFilter){ + var me = this, + range, + div; + if(!html){ + return; } - if ( end = domUtils.findParentByTagName( end, 'a', true ) ) { - range.setEndAfter( end ); + if(me.fireEvent('beforeinserthtml',html) === true){ + return; } - } - - - UE.commands['unlink'] = { - execCommand : function() { - var range = this.selection.getRange(), - bookmark; - if(range.collapsed && !domUtils.findParentByTagName( range.startContainer, 'a', 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); } - bookmark = range.createBookmark(); - optimize( range ); - range.removeInlineStyle( 'a' ).moveToBookmark( bookmark ).select(); - }, - queryCommandState : function(){ - return !this.highlight && this.queryCommandValue('link') ? 0 : -1; + //执行默认的处理 + 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) - }; - 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(); + !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); + } + } + } - 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); + 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; + } + } } - domUtils.setAttributes( a, opt ); - start = domUtils.findParentByTagName( rngClone.startContainer, 'a', true ); - if(start && domUtils.isInNodeEndBoundary(rngClone,start)){ - range.setStartAfter(start).collapse(true); + li = domUtils.findParentByTagName(range.startContainer,'li',true); + if(domUtils.isEmptyBlock(li)){ + domUtils.remove(li) + } + if(last){ + range.setStartAfter(last).collapse(true).select(true) } - a[browser.ie ? 'innerText' : 'textContent'] = text; - range.insertNode(a).selectNode( a ); - } else { - range.applyInlineStyle( 'a', opt ); + }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){ - } - } - 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); + child = p + } + } + range.insertNode( child ); + nextNode = child.nextSibling; + if ( !hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm( child ) ){ - }, - 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; + 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; - 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; + 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占位 - 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; + if(!browser.ie && + (next = child.nextSibling) && + domUtils.isBlockElm(next) && + next.lastChild && + !domUtils.isBr(next.lastChild)){ + next.appendChild(me.document.createElement('br')); } + hadBreak = 1; } } - return node; + var next = child.nextSibling; + if(!div.firstChild && next && domUtils.isBlockElm(next)){ + + range.setStart(next,0).collapse(true); + break; + } + range.setEndAfter( child ).collapse(); + } - }, - 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; + 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/removeformat.js + + +// plugins/autotypeset.js /** - * 清除格式 + * 自动排版 * @file * @since 1.2.6.1 */ /** - * 清除文字样式 - * @command removeformat + * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。 + * @command autotypeset * @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' ); + * editor.execCommand( 'autotypeset' ); * ``` */ -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 ) { +UE.plugins['autotypeset'] = function(){ - 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; - }; + 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 + }}); - 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 - 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(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(!collapsed){ - node = range.endContainer; - while(node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]){ - tmp = node.parentNode; - range.setEndBefore(node); - domUtils.remove(node); + //表情不处理 + 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',''); + } - node = tmp; - } + + } + + + } + 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; + } - range = this.selection.getRange(); - doRemove( range ); - range.select(); + 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/blockquote.js + + + +// plugins/autosubmit.js /** - * 添加引用 + * 快捷键提交 * @file * @since 1.2.6.1 */ /** - * 添加引用 - * @command blockquote + * 提交表单 + * @command autosubmit * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript - * editor.execCommand( 'blockquote' ); + * 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 /** - * 添加引用 - * @command blockquote - * @method execCommand - * @param { String } cmd 命令字符串 - * @param { Object } attrs 节点属性 - * @example - * ```javascript - * editor.execCommand( 'blockquote',{ - * style: "color: red;" - * } ); - * ``` + * 背景插件,为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'); - -UE.plugins['blockquote'] = function(){ - var me = this; - function getObj(editor){ - return domUtils.filterNodeList(editor.selection.getStartElementPath(),'blockquote'); + 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; } - me.commands['blockquote'] = { - execCommand : function( cmdName, attrs ) { - var range = this.selection.getRange(), - obj = getObj(this), - blockquote = dtd.blockquote, - bookmark = range.createBookmark(); - if ( 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 start = range.startContainer, - startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start,function(node){return domUtils.isBlockElm(node)}), + var orgFn = me.hasContents; + me.hasContents = function(){ + if(me.queryCommandValue('background')){ + return true + } + return orgFn.apply(me,arguments); + }; + return { + bindEvents: { + 'getAllHtml': function (type, headHtml) { + var body = this.body, + su = domUtils.getComputedStyle(body, "background-image"), + url = ""; + if (su.indexOf(me.options.imagePath) > 0) { + url = su.substring(su.indexOf(me.options.imagePath), su.length - 1).replace(/"|\(|\)/ig, ""); + } else { + url = su != "none" ? su.replace(/url\("?|"?\)/ig, "") : ""; + } + var html = ' '; + headHtml.push(html); + }, + 'aftersetcontent': function () { + if(isSetColored == false) setBackground(); + } + }, + inputRule: function (root) { + isSetColored = false; + utils.each(root.getNodesByTagName('p'), function (p) { + var styles = p.getAttr('data-background'); + if (styles) { + isSetColored = true; + setBackground(stringToObj(styles)); + p.parentNode.removeChild(p); + } + }) + }, + outputRule: function (root) { + var me = this, + styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg); + if (styles) { + root.appendChild(UE.uNode.createElement('


    ')); + } + }, + commands: { + 'background': { + execCommand: function (cmd, obj) { + setBackground(obj); + }, + queryCommandValue: function () { + var me = this, + styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg); + return styles ? stringToObj(styles[1]) : null; + }, + notNeedUndo: true + } + } + } +}); - end = range.endContainer, - endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end,function(node){return domUtils.isBlockElm(node)}); +// plugins/image.js +/** + * 图片插入、排版插件 + * @file + * @since 1.2.6.1 + */ - //处理一下li - startBlock = domUtils.findParentByTagName(startBlock,'li',true) || startBlock; - endBlock = domUtils.findParentByTagName(endBlock,'li',true) || endBlock; +/** + * 图片对齐方式 + * @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', ''); + } - 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); } + range.selectNode(img).select(); } - } - - 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); + domUtils.setStyle(img, 'float', align == 'none' ? '' : align); + if(align == 'none'){ + domUtils.removeAttributes(img,'align'); } - } - - - - - } 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 ); + 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); } - }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; + break; } - //调整结束 - 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; - } + } + } + }, + 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'); - preNode = node; - node = node.parentNode; - } + 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; - 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); - } - } + if (range.collapsed) return -1; - } - range.moveToBookmark( bookmark ).select(); - }, - queryCommandState : function() { - return getObj(this) ? 1 : 0; + startNode = range.getClosedNode(); + if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') { + return 0; } - }; + return -1; + } }; - - -// plugins/convertcase.js -/** - * 大小写转换 - * @file - * @since 1.2.6.1 - */ /** - * 把选区内文本变大写,与“tolowercase”命令互斥 - * @command touppercase + * 插入图片 + * @command insertimage * @method execCommand * @param { String } cmd 命令字符串 + * @param { Object } opt 属性键值对,这些属性都将被复制到当前插入图片 + * @remind 该命令第二个参数可接受一个图片配置项对象的数组,可以插入多张图片, + * 此时数组的每一个元素都是一个Object类型的图片属性集合。 * @example * ```javascript - * editor.execCommand( 'touppercase' ); + * editor.execCommand( 'insertimage', { + * src:'a/b/c.jpg', + * width:'100', + * height:'100' + * } ); * ``` - */ - -/** - * 把选区内文本变小写,与“touppercase”命令互斥 - * @command tolowercase - * @method execCommand - * @param { String } cmd 命令字符串 * @example * ```javascript - * editor.execCommand( 'tolowercase' ); + * editor.execCommand( 'insertimage', [{ + * src:'a/b/c.jpg', + * width:'100', + * height:'100' + * },{ + * src:'a/b/d.jpg', + * width:'100', + * height:'100' + * }] ); * ``` */ -UE.commands['touppercase'] = -UE.commands['tolowercase'] = { - execCommand:function (cmd) { - var me = this; - var rng = me.selection.getRange(); - if(rng.collapsed){ - return rng; + +UE.commands['insertimage'] = { + execCommand:function (cmd, opt) { + + opt = utils.isArray(opt) ? opt : [opt]; + if (!opt.length) { + return; } - 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) ) { + var me = this, + range = me.selection.getRange(), + img = range.getClosedNode(); - if ( curNode.nodeType == 3 ) { - curNode.nodeValue = curNode.nodeValue[cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase'](); + 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); } - curNode = domUtils.getNextDomNode( curNode, true, filterFn ); - if(curNode === bkEnd){ - break; + + } else { + var html = [], str = '', ci; + ci = opt[0]; + if (opt.length == 1) { + unhtmlData(ci); + + str = '' + ci.alt + ''; + 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('')); } - rng.moveToBookmark(bk).select(); + + me.fireEvent('afterinsertimage', opt) } }; - - -// plugins/indent.js + +// plugins/justify.js /** - * 首行缩进 + * 段落格式 * @file * @since 1.2.6.1 */ /** - * 缩进 - * @command indent + * 段落对齐方式 + * @command justify * @method execCommand * @param { String } cmd 命令字符串 + * @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐 * @example * ```javascript - * editor.execCommand( 'indent' ); + * editor.execCommand( 'justify', 'center' ); * ``` */ -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; - } +/** + * 如果选区所在位置是段落区域,返回当前段落对齐方式 + * @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/print.js + + +// plugins/font.js /** - * 打印 + * 字体颜色,背景色,字号,字体,下划线,删除线 * @file * @since 1.2.6.1 */ /** - * 打印 - * @command print + * 字体颜色 + * @command forecolor * @method execCommand * @param { String } cmd 命令字符串 + * @param { String } value 色值(必须十六进制) * @example * ```javascript - * editor.execCommand( 'print' ); + * editor.execCommand( 'forecolor', '#000' ); * ``` */ -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 forecolor + * @method queryCommandValue + * @param { String } cmd 命令字符串 + * @return { String } 返回字体颜色 + * @example + * ```javascript + * editor.queryCommandValue( 'forecolor' ); + * ``` */ /** - * 选中所有内容 - * @command selectall + * 字体背景颜色 + * @command backcolor * @method execCommand * @param { String } cmd 命令字符串 + * @param { String } value 色值(必须十六进制) * @example * ```javascript - * editor.execCommand( 'selectall' ); + * editor.execCommand( 'backcolor', '#000' ); * ``` */ -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 backcolor + * @method queryCommandValue + * @param { String } cmd 命令字符串 + * @return { String } 返回字体背景颜色 + * @example + * ```javascript + * editor.queryCommandValue( 'backcolor' ); + * ``` */ /** - * 段落格式 - * @command paragraph + * 字体大小 + * @command fontsize * @method execCommand * @param { String } cmd 命令字符串 - * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' - * @param {Object} attrs 标签的属性 + * @param { String } value 字体大小 * @example * ```javascript - * editor.execCommand( 'Paragraph','h1','{ - * class:'test' - * }' ); + * editor.execCommand( 'fontsize', '14px' ); * ``` */ - /** - * 返回选区内节点标签名 - * @command paragraph + * 返回选区字体大小 + * @command fontsize * @method queryCommandValue * @param { String } cmd 命令字符串 - * @return { String } 节点标签名 + * @return { String } 返回字体大小 * @example * ```javascript - * editor.queryCommandValue( 'Paragraph' ); + * editor.queryCommandValue( 'fontsize' ); * ``` */ -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; +/** + * 字体样式 + * @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' ); + * ``` + */ - 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); - - } +/** + * 字体下划线,与删除线互斥 + * @command underline + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'underline' ); + * ``` + */ - tmpRange.insertNode( para ); +/** + * 字体删除线,与下划线互斥 + * @command strikethrough + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'strikethrough' ); + * ``` + */ - 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); - } +/** + * 字体边框 + * @command fontborder + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'fontborder' ); + * ``` + */ - //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 ); - } +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' - } - if( utils.indexOf(notExchange,parent.tagName)!=-1){ - current = parent; - }else{ - current = para; - } + }; + 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; + } + } - current = domUtils.getNextDomNode( current, false, filterFn ); - } else { - current = domUtils.getNextDomNode( current, true, filterFn ); + } + 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) } } - 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); + } + + } + 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; } - node = txt.nextSibling; - if(node && domUtils.isWhitespace(node)){ - domUtils.remove(node); + if (next.style.cssText == span.style.cssText) { + domUtils.moveChild(next, span); + domUtils.remove(next); } + if (span.nextSibling === next) + break; + next = span.nextSibling; } - } - 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); + 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; } } - //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了 - range.select(); + }); + rng.moveToBookmark(bk); + mergeChild(rng,cmdName,value) + } - 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; + 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') // } // } // } - return domUtils.filterNodeList(editor.selection.getStartElementPath(),function(n){return n && n.nodeType == 1 && n.getAttribute('dir')}); +// }); + }); +// 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; - }, - doDirectionality = function(range,editor,forward){ - - var bookmark, - filterFn = function( node ) { - return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); - }, + if (value == 'default') { - obj = getObj( editor ); + if (range.collapsed) { + text = me.document.createTextNode('font'); + range.insertNode(text).select(); - 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; + } + me.execCommand('removeFormat', 'span,a', style); + if (text) { + range.setStartBefore(text).collapse(true); + domUtils.remove(text); + } + mergesibling(range,cmdName,value); + range.select() } else { - //没有遍历到,添加一个block节点 - var p = range.document.createElement( 'p' ); - p.setAttribute( 'dir', forward ); - var frag = tmpRange.extractContents(); - p.appendChild( frag ); - tmpRange.insertNode( p ); - current = p; - } + if (!range.collapsed) { + if (needCmd[cmd] && me.queryCommandValue(cmd)) { + me.execCommand('removeFormat', 'span,a', style); + } + range = me.selection.getRange(); - current = domUtils.getNextDomNode( current, false, filterFn ); - } else { - current = domUtils.getNextDomNode( current, true, filterFn ); - } - } - return range.moveToBookmark( bookmark2 ).moveToBookmark( bookmark ); - }; + range.applyInlineStyle('span', {'style': style + ':' + value}); + mergesibling(range, cmdName,value); + range.select(); + } else { - /** - * 文字输入方向 - * @command directionality - * @method execCommand - * @param { String } cmdName 命令字符串 - * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入 - * @example - * ```javascript - * editor.execCommand( 'directionality', 'ltr'); - * ``` - */ + 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); - /** - * 查询当前选区的文字输入方向 - * @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); - } + span = domUtils.findParentByTagName(text, 'span', true); + range.setStartBefore(text); - range.select(); - return true; - }, - queryCommandValue : function() { - var node = getObj(this); - return node ? node.getAttribute('dir') : 'ltr'; - } - }; -})(); + } + span && (span.style.cssText += ';' + style + ':' + value); + range.collapse(true).select(); - - -// 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] ){ + } else { + range.insertNode(text); + range.selectNode(text).select(); + span = range.document.createElement('span'); - 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(); + if (needCmd[cmd]) { + //a标签内的不处理跳过 + if (domUtils.findParentByTagName(text, 'a', true)) { + range.setStartBefore(text).setCursor(); + domUtils.remove(text); + return; + } + me.execCommand('removeFormat', 'span,a', style); + } - }else{ - tmp = me.document.createElement('br'); - range.insertNode(tmp); - range.setStartBefore(tmp).setCursor(); + 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(); - } - return true; - } + //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; + } + } - }, - //边界在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; + 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/time.js +// plugins/link.js /** - * 插入时间和日期 + * 超链接 * @file * @since 1.2.6.1 */ /** - * 插入时间,默认格式:12:59:59 - * @command time + * 插入超链接 + * @command link * @method execCommand * @param { String } cmd 命令字符串 + * @param { Object } options 设置自定义属性,例如:url、title、target * @example * ```javascript - * editor.execCommand( 'time'); + * 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' ); * ``` */ /** - * 插入日期,默认格式:2013-08-30 - * @command date + * 取消超链接 + * @command unlink * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript - * editor.execCommand( 'date'); + * editor.execCommand( 'unlink'); * ``` */ -UE.commands['time'] = UE.commands["date"] = { - execCommand : function(cmd, format){ - var date = new Date; - function formatTime(date, format) { - var hh = ('0' + date.getHours()).slice(-2), - ii = ('0' + date.getMinutes()).slice(-2), - ss = ('0' + date.getSeconds()).slice(-2); - format = format || 'hh:ii:ss'; - return format.replace(/hh/ig, hh).replace(/ii/ig, ii).replace(/ss/ig, ss); +UE.plugins['link'] = function(){ + function optimize( range ) { + var start = range.startContainer,end = range.endContainer; + + if ( start = domUtils.findParentByTagName( start, 'a', true ) ) { + range.setStartBefore( start ); } - function formatDate(date, format) { - var yyyy = ('000' + date.getFullYear()).slice(-4), - yy = yyyy.slice(-2), - mm = ('0' + (date.getMonth()+1)).slice(-2), - dd = ('0' + date.getDate()).slice(-2); - format = format || 'yyyy-mm-dd'; - return format.replace(/yyyy/ig, yyyy).replace(/yy/ig, yy).replace(/mm/ig, mm).replace(/dd/ig, dd); + if ( end = domUtils.findParentByTagName( end, 'a', true ) ) { + range.setEndAfter( end ); } - - 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; + UE.commands['unlink'] = { + execCommand : function() { + var range = this.selection.getRange(), + bookmark; + if(range.collapsed && !domUtils.findParentByTagName( range.startContainer, 'a', true )){ + return; } - return 0; - + 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(); + } - - -// 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']}); + if ( rngClone.collapsed ) { + var a = range.document.createElement( 'a'), + text = ''; + if(opt.textValue){ - /** - * 行距 - * @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' ); - * ``` - */ + 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); - me.commands['lineheight'] = { - execCommand : function( cmdName,value ) { - this.execCommand('paragraph','p',{style:'line-height:'+ (value == "1" ? "normal" : value + 'em') }); - return true; }, queryCommandValue : function() { - var pN = domUtils.filterNodeList(this.selection.getStartElementPath(),function(node){return domUtils.isBlockElm(node)}); - if(pN){ - var value = domUtils.getComputedStyle(pN,'line-height'); - return value == 'normal' ? 1 : value.replace(/[^\d.]*/ig,""); + 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/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 +// plugins/removeformat.js /** - * 清空文档插件 + * 清除格式 * @file * @since 1.2.6.1 */ /** - * 清空文档 - * @command cleardoc + * 清除文字样式 + * @command removeformat * @method execCommand * @param { String } cmd 命令字符串 + * @param {String} tags 以逗号隔开的标签。如:strong + * @param {String} style 样式如:color + * @param {String} attrs 属性如:width * @example * ```javascript - * //editor 是编辑器实例 - * editor.execCommand('cleardoc'); + * editor.execCommand( 'removeformat', 'strong','color','width' ); * ``` */ -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); +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; + }; - - -// 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); + 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'); - 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); - } - }) + bookmark = range.createBookmark(); - }); + node = bookmark.start; - /** - * 插入分页符 - * @command pagebreak - * @method execCommand - * @param { String } cmd 命令字符串 - * @remind 在表格中插入分页符会把表格切分成两部分 - * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串, - * 以便于提交数据到服务器端后处理分页。 - * @example - * ```javascript - * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak - * ``` - */ + //切开始 + while ( (parent = node.parentNode) && !domUtils.isBlockElm( parent ) ) { + domUtils.breakParent( node, parent ); - 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), + domUtils.clearEmptySibling( node ); + } + if ( bookmark.end ) { + //切结束 + node = bookmark.end; + while ( (parent = node.parentNode) && !domUtils.isBlockElm( parent ) ) { + domUtils.breakParent( node, parent ); + domUtils.clearEmptySibling( node ); + } - 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); + //开始去除样式 + var current = domUtils.getNextDomNode( bookmark.start, false, filter ), + next; + while ( current ) { + if ( current == bookmark.end ) { + break; + } - } else { - pN.parentNode.insertBefore(hr, pN); - parents = domUtils.findParents(hr); + next = domUtils.getNextDomNode( current, true, filter ); - } - pN = parents[1]; - if (hr !== pN) { - domUtils.breakParent(hr, pN); + 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 ); + } + } + } } - //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; + current = next; } - } - 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; + //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 ); } - nextNode = hr.nextSibling; - var pre = hr.previousSibling; - if(isHr(pre)){ - domUtils.remove(pre); - }else{ - pre && fillNode(pre); + pN = bookmark.end.parentNode; + if(bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName]&& !dtd.$list[pN.tagName]){ + domUtils.removeAttributes( pN,removeFormatAttributes ); } - - 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.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--; } - range.setEndAfter(hr).collapse(false); + domUtils.remove(node); + node = tmp; } - range.select(true); - - } - - } - }; -}; - -// plugins/wordimage.js -///import core -///commands 本地图片引导上传 -///commandsName WordImage -///commandsTitle 本地图片引导上传 -///commandsDialog dialogs\wordimage + 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); -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; - } + node = tmp; } - 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'); + range = this.selection.getRange(); + doRemove( range ); + range.select(); - } + } - } + }; - }) - }); - 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 + + +// plugins/blockquote.js /** - * undo redo + * 添加引用 * @file * @since 1.2.6.1 */ /** - * 撤销上一次执行的命令 - * @command undo + * 添加引用 + * @command blockquote * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript - * editor.execCommand( 'undo' ); + * editor.execCommand( 'blockquote' ); * ``` */ /** - * 重做上一次执行的命令 - * @command redo + * 添加引用 + * @command blockquote * @method execCommand * @param { String } cmd 命令字符串 + * @param { Object } attrs 节点属性 * @example * ```javascript - * editor.execCommand( 'redo' ); + * editor.execCommand( 'blockquote',{ + * style: "color: red;" + * } ); * ``` */ -UE.plugins['undo'] = function () { - var saveSceneTimer; - var me = this, - maxUndoCount = me.options.maxUndoCount || 20, - maxInputCount = me.options.maxInputCount || 20, - fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi');// ie会产生多余的 - var noNeedFillCharTags = { - ol:1,ul:1,table:1,tbody:1,tr:1,body:1 - }; - var orgState = me.options.autoClearEmptyNode; - function compareAddr(indexA, indexB) { - if (indexA.length != indexB.length) - return 0; - for (var i = 0, l = indexA.length; i < l; i++) { - if (indexA[i] != indexB[i]) - return 0 - } - return 1; - } - function compareRangeAddress(rngAddrA, rngAddrB) { - if (rngAddrA.collapsed != rngAddrB.collapsed) { - return 0; - } - if (!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)) { - return 0; - } - return 1; +UE.plugins['blockquote'] = function(){ + var me = this; + function getObj(editor){ + return domUtils.filterNodeList(editor.selection.getStartElementPath(),'blockquote'); } - - 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); + 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); } - } - 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); + + 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); + } + + } } - } - 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); + 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); + } } - }) - } - 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]; + } else { - 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(); + var tmpRange = range.cloneRange(), + node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode, + preNode = node, + doEnd = 1; - }; - 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; - }; - } + //调整开始 + 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); + } - me.undoManger = new UndoManager(); - me.undoManger.editor = me; - function saveScene() { - this.undoManger.save(); - } + break; + } + if ( !blockquote[node.tagName] ) { + if ( range.collapsed ) { + tmpRange.selectNode( preNode ); + } else{ + tmpRange.setStartBefore( preNode); + } + break; + } - me.addListener('saveScene', function () { - var args = Array.prototype.splice.call(arguments,1); - this.undoManger.save.apply(this.undoManger,args); - }); + preNode = node; + node = node.parentNode; + } -// me.addListener('beforeexeccommand', saveScene); -// me.addListener('afterexeccommand', saveScene); + //调整结束 + if ( doEnd ) { + preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode; + while ( 1 ) { - 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 - }; + if ( domUtils.isBody( node ) ) { + if ( preNode !== node ) { - 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 + tmpRange.setEndAfter( preNode ); - }, - 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 + } else { + tmpRange.setEnd( node, node.childNodes.length ); + } - }); - var isCollapsed = true; - me.addListener('keydown', function (type, evt) { + break; + } + if ( !blockquote[node.tagName] ) { + tmpRange.setEndAfter( preNode ); + break; + } - var me = this; - var keyCode = evt.keyCode || evt.which; - if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) { - if (inputType) - return; + preNode = node; + node = node.parentNode; + } - 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; + + 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; } - }); - //扩展实例,添加关闭和开启命令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 + + + +// plugins/convertcase.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) +/** + * 把选区内文本变大写,与“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'](); } - 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()) - } + curNode = domUtils.getNextDomNode( curNode, true, filterFn ); + if(curNode === bkEnd){ + break; } - }() - }); - //暂时这里支持一下老版本的属性 - var pasteplain = me.options.pasteplain; - /** - * 启用或取消纯文本粘贴模式 - * @command pasteplain - * @method execCommand - * @param { String } cmd 命令字符串 - * @example - * ```javascript - * editor.queryCommandState( 'pasteplain' ); - * ``` - */ + } + rng.moveToBookmark(bk).select(); + } +}; - /** - * 查询当前是否处于纯文本粘贴模式 - * @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 + + +// plugins/indent.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' - }; +/** + * 缩进 + * @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; + } - 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{box-sizing:border-box;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); - } - } - } - } +// 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 +}; - 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) +// plugins/preview.js +/** + * 预览 + * @file + * @since 1.2.6.1 + */ - }else{ - n.setStyle('list-style-type',currentStyle) - } - }) +/** + * 预览 + * @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 +}; - } - 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); - } +// plugins/selectall.js +/** + * 全选 + * @file + * @since 1.2.6.1 + */ - index = newChildrens.length; +/** + * 选中所有内容 + * @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); } - }); - if(newChildrens.length){ - li.children = newChildrens; + range.collapse(true); } - }); + range.select(true); + }, + notNeedUndo : 1 + }; + + + //快捷键 + me.addshortcutkey({ + "selectAll" : "ctrl+65" }); - //进入编辑器的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]+\)/ + +// 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 ); }, - 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 + 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; } } - return 'disc' - } - for(var p in orderlisttype){ - if(orderlisttype[p].test(content)){ - return p; + para.appendChild( tmpRange.extractContents() ); + //需要内容占位 + if(domUtils.isEmptyNode(para)){ + domUtils.fillChar(range.document,para); + } - } - } - utils.each(root.getNodesByTagName('p'),function(node){ - if(node.getAttr('class') != 'MsoListParagraph'){ - return - } + tmpRange.insertNode( para ); - //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视 - node.setStyle('margin',''); - node.setStyle('margin-left',''); - node.setAttr('class',''); + 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); + } - 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); + //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{ - p.innerHTML(p.innerHTML().replace(orderlisttype[type],'')); + domUtils.remove( para.parentNode, true ); } + + } + if( utils.indexOf(notExchange,parent.tagName)!=-1){ + current = parent; }else{ - p.removeChild(p.firstChild()) + current = para; } - 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; + 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); } - if(!list.parentNode && node && node.parentNode){ - node.parentNode.insertBefore(list,node) + node = txt.nextSibling; + if(node && domUtils.isWhitespace(node)){ + domUtils.remove(node); } } - var span = cacheNode.firstChild(); - if(span && span.type == 'element' && span.tagName == 'span' && /^\s*( )+\s*$/.test(span.innerText())){ - span.parentNode.removeChild(span) - } - }) - } - }); + } + range = doParagraph(range,style,attrs,sourceCmdName); + if(txt){ + range.setStartBefore(txt).collapse(true); + pN = txt.parentNode; - //调整索引标签 - me.addListener('contentchange',function(){ - adjustListStyle(me.document) - }); + domUtils.remove(txt); - function adjustListStyle(doc,ignore){ - utils.each(domUtils.getElementsByTagName(doc,'ol ul'),function(node){ + if(domUtils.isBlockElm(pN)&&domUtils.isEmptyNode(pN)){ + domUtils.fillNode(this.document,pN); + } - 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]) + 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); } - } - 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) - } - } + //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了 + range.select(); - 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; + return true; + }, + queryCommandValue : function() { + var node = domUtils.filterNodeList(this.selection.getStartElementPath(),'p h1 h2 h3 h4 h5 h6'); + return node ? node.tagName.toLowerCase() : ''; } - 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(); +// 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); + }, - } - preventAndSave(); - return; + 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 { - 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; + //没有遍历到,添加一个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 ); + }; - 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 { + /** + * 文字输入方向 + * @command directionality + * @method execCommand + * @param { String } cmdName 命令字符串 + * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入 + * @example + * ```javascript + * editor.execCommand( 'directionality', 'ltr'); + * ``` + */ - parentList.parentNode.insertBefore(li, parentList.nextSibling); - if (domUtils.isEmptyNode(parentList)) { - domUtils.remove(parentList); - } - } - //嵌套不处理 - if (!dtd.$list[li.parentNode.tagName]) { + /** + * 查询当前选区的文字输入方向 + * @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); + } - 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(); + range.select(); + return true; + }, + queryCommandValue : function() { + var node = getObj(this); + return node ? node.getAttribute('dir') : 'ltr'; + } + }; +})(); - } 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) { +// plugins/horizontal.js +/** + * 插入分割线插件 + * @file + * @since 1.2.6.1 + */ - p.appendChild(li.firstChild); +/** + * 插入分割线 + * @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(); } - li.appendChild(p); - first = p; } + } - var span = me.document.createElement('span'); - - range.insertNode(span); - domUtils.breakParent(span, li); + } + return true; + } - var nextLi = span.nextSibling; - first = nextLi.firstChild; + }, + //边界在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; - 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(); - } +// plugins/time.js +/** + * 插入时间和日期 + * @file + * @since 1.2.6.1 + */ - } +/** + * 插入时间,默认格式:12:59:59 + * @command time + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'time'); + * ``` + */ +/** + * 插入日期,默认格式:2013-08-30 + * @command date + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'date'); + * ``` + */ +UE.commands['time'] = UE.commands["date"] = { + execCommand : function(cmd, format){ + var date = new Date; + function formatTime(date, format) { + var hh = ('0' + date.getHours()).slice(-2), + ii = ('0' + date.getMinutes()).slice(-2), + ss = ('0' + date.getSeconds()).slice(-2); + format = format || 'hh:ii:ss'; + return format.replace(/hh/ig, hh).replace(/ii/ig, ii).replace(/ss/ig, ss); + } + function formatDate(date, format) { + var yyyy = ('000' + date.getFullYear()).slice(-4), + yy = yyyy.slice(-2), + mm = ('0' + (date.getMonth()+1)).slice(-2), + dd = ('0' + date.getDate()).slice(-2); + format = format || 'yyyy-mm-dd'; + return format.replace(/yyyy/ig, yyyy).replace(/yy/ig, yy).replace(/mm/ig, mm).replace(/dd/ig, dd); } - 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); + this.execCommand('insertHtml',cmd == "time" ? formatTime(date, format):formatDate(date, format) ); + } +}; - 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; +// plugins/rowspacing.js +/** + * 段前段后间距插件 + * @file + * @since 1.2.6.1 + */ - } - //trace:980 +/** + * 设置段间距 + * @command rowspacing + * @method execCommand + * @param { String } cmd 命令字符串 + * @param { String } value 段间距的值,以px为单位 + * @param { String } dir 间距位置,top或bottom,分别表示段前和段后 + * @example + * ```javascript + * editor.execCommand( 'rowspacing', '10', 'top' ); + * ``` + */ - 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{ +UE.plugins['rowspacing'] = function(){ + var me = this; + me.setOpt({ + 'rowspacingtop':['5', '10', '15', '20', '25'], + 'rowspacingbottom':['5', '10', '15', '20', '25'] - while(li.firstChild){ - parentList.parentNode.insertBefore(li.firstChild,parentList); - } + }); + 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; - 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; - } - } +// plugins/lineheight.js +/** + * 设置行内间距 + * @file + * @since 1.2.6.1 + */ +UE.plugins['lineheight'] = function(){ + var me = this; + me.setOpt({'lineheight':['1', '1.5','1.75','2', '3', '4', '5']}); + /** + * 行距 + * @command lineheight + * @method execCommand + * @param { String } cmdName 命令字符串 + * @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75 + * @example + * ```javascript + * editor.execCommand( 'lineheight', 1.5); + * ``` + */ + /** + * 查询当前选区内容的行高大小 + * @command lineheight + * @method queryCommandValue + * @param { String } cmd 命令字符串 + * @return { String } 返回当前行高大小 + * @example + * ```javascript + * editor.queryCommandValue( 'lineheight' ); + * ``` + */ + me.commands['lineheight'] = { + execCommand : function( cmdName,value ) { + this.execCommand('paragraph','p',{style:'line-height:'+ (value == "1" ? "normal" : value + 'em') }); + return true; + }, + queryCommandValue : function() { + var pN = domUtils.filterNodeList(this.selection.getStartElementPath(),function(node){return domUtils.isBlockElm(node)}); + if(pN){ + var value = domUtils.getComputedStyle(pN,'line-height'); + return value == 'normal' ? 1 : value.replace(/[^\d.]*/ig,""); } - } - }); + }; +}; - 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) - } - } + + + +// 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' }); - //处理tab键 - me.addListener('tabkeydown',function(){ - var range = me.selection.getRange(); + /** + * 插入代码 + * @command insertcode + * @method execCommand + * @param { String } cmd 命令字符串 + * @param { String } lang 插入代码的语言 + * @example + * ```javascript + * editor.execCommand( 'insertcode', 'javascript' ); + * ``` + */ - //控制级数 - 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; + /** + * 如果选区所在位置是插入插入代码区域,返回代码的语言 + * @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 += '
    ' + } + } + + } + + }); } - if(levelNum >= me.options.maxListLevel){ - return true; + 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; } - //只以开始为准 - //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; + 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)); } - }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; + 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; } } - 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; + 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] } - 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; + + } + 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] } - current = li; + } - adjustList(list,list.tagName.toLowerCase(),currentStyle); - current = li; + + str = me.document.createTextNode(str); + rng.insertNode(str).setStartAfter(str); } + rng.collapse(true).select(); } - me.fireEvent('contentchange'); - range.moveToBookmark(bk).select(); - return true; + + } + me.fireEvent('saveScene'); + 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' ); - * ``` - */ + 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){ - /** - * 无序列表,与“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' ); - * ``` - */ + }else{ + if(!rng.collapsed){ + var bk = rng.createBookmark(); + var start = bk.start.previousSibling; - me.commands['insertorderedlist'] = - me.commands['insertunorderedlist'] = { - execCommand:function (command, style) { + while(start){ + if(pre.firstChild === start && !domUtils.isBr(start)){ + pre.insertBefore(me.document.createTextNode(' '),start); - 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; + break; + } + if(domUtils.isBr(start)){ + pre.insertBefore(me.document.createTextNode(' '),start.nextSibling); - if (start || end) { - start && (startParent = start.parentNode); - if (!bko.end) { - end = start; + break; + } + start = start.previousSibling; } - end && (endParent = end.parentNode); + var end = bk.end; + start = bk.start.nextSibling; + if(pre.firstChild === bk.start){ + pre.insertBefore(me.document.createTextNode(' '),start.nextSibling) - 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); + } + while(start && start !== end){ + if(domUtils.isBr(start) && start.nextSibling){ + if(start.nextSibling === end){ + break; } - frag.appendChild(tmp); + pre.insertBefore(me.document.createTextNode(' '),start.nextSibling) } - 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); - } - } + start = start.nextSibling; + } + rng.moveToBookmark(bk).select(); + }else{ + var tmpNode = me.document.createTextNode(' '); + rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true).select(true); + } + } - } - 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; + 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(); } - tmpfrag.appendChild(start.firstChild); - } - if (!hasBlock) { - var tmpP = me.document.createElement('p'); - tmpP.appendChild(tmpfrag); - frag.appendChild(tmpP); - } else { - frag.appendChild(tmpfrag); + }else{ + htmlstr += cn.data } - domUtils.remove(start); + }) + if(!/\n$/.test(htmlstr)){ + htmlstr += '\n'; } - - start = tmp; - } - startParent.parentNode.insertBefore(frag, startParent.nextSibling); - if (domUtils.isEmptyNode(startParent)) { - range.setStartBefore(startParent); - domUtils.remove(startParent); - } else { - range.setStartAfter(startParent); } - modifyStart = 1; + }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,' ')))); - 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); + }else{ + frag.appendChild(me.document.createTextNode(utils.html( cn.data.replace(/ /g,' ')))); + } - domUtils.remove(start); + }) + if(frag.lastChild.nodeName != 'BR'){ + frag.appendChild(me.document.createElement('br')) } - 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; + }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(); - if (!modifyStart) { - range.setStartBefore(me.document.getElementById(bko.start)); + } + + 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 (bko.end && !modifyEnd) { - range.setEndAfter(me.document.getElementById(bko.end)); + if(last === start || rng.startContainer === pre && rng.startOffset == pre.childNodes.length){ + me.execCommand('insertparagraph'); + domUtils.preventDefault(evt) } - range.enlarge(true, function (node) { - return notExchange[node.tagName]; - }); - frag = me.document.createDocumentFragment(); + } + } + }); + //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; + } + }) +}; - 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)) { +// plugins/cleardoc.js +/** + * 清空文档插件 + * @file + * @since 1.2.6.1 + */ - 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; +/** + * 清空文档 + * @command cleardoc + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * //editor 是编辑器实例 + * editor.execCommand('cleardoc'); + * ``` + */ - } - tmpNode = current; - tmpRange.setStartBefore(current); +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); - 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'); +// plugins/anchor.js +/** + * 锚点插件,为UEditor提供插入锚点支持 + * @file + * @since 1.2.6.1 + */ +UE.plugin.register('anchor', function (){ - 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(); + 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') - }, - 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; - } - }; + }, + 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/source.js + +// 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 (){ - 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'); + function fillNode(node){ + if(domUtils.isEmptyBlock(node)){ + var firstChild = node.firstChild,tmpNode; - me.setOpt({ - sourceEditorFirst:false - }); - function createSourceEditor(holder){ - return sourceEditors[opt.sourceEditor == 'codemirror' && window.CodeMirror ? 'codemirror' : 'textarea'](me, holder); + while(firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)){ + tmpNode = firstChild; + firstChild = firstChild.firstChild; + } + !tmpNode && (tmpNode = node); + domUtils.fillNode(me.document,tmpNode); } + } + //分页符样式添加 - 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.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); + } + }) - 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; - } + /** + * 插入分页符 + * @command pagebreak + * @method execCommand + * @param { String } cmd 命令字符串 + * @remind 在表格中插入分页符会把表格切分成两部分 + * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串, + * 以便于提交数据到服务器端后处理分页。 + * @example + * ```javascript + * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak + * ``` + */ - bakCssText = me.iframe.style.cssText; - me.iframe.style.cssText += 'position:absolute;left:-32768px;top:-32768px;'; + 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); - 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,' ')) + } else { + pN.parentNode.insertBefore(hr, pN); + parents = domUtils.findParents(hr); - } } - }); - - 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){} - }); - }); + pN = parents[1]; + if (hr !== pN) { + domUtils.breakParent(hr, pN); - //重置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,'') - }); + //table要重写绑定一下拖拽 + me.fireEvent('afteradjusttable',me.document); + } - me.setContent = orgSetContent; + } else { - 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; + 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); - //要在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); + 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); + } - 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); - }); + 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{ - //ie下有可能报错,比如在代码顶头的情况 - try{ - me.selection.getRange().moveToAddress(bakAddress).select(true); - }catch(e){} - + fillNode(nextNode); } + range.setEndAfter(hr).collapse(false); } - 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"){ + range.select(true); - 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 +// plugins/wordimage.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); +///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); } - - if (me.undoManger && doSave) { - me.undoManger.save(); + 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; + } } - } - //没有站位符,会出现多行的问题 - 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; + return -1; + }, + notNeedUndo:true } - 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; + }, + 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' + }) } - } - 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, '

    '); +// plugins/dragdrop.js +UE.plugins['dragdrop'] = function (){ - if (browser.gecko) { - range = me.selection.getRange(); - start = domUtils.findParentByTagName(range.startContainer, 'p', true); - start && domUtils.removeDirtyAttr(start); - } + 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'){ - } else { - hTag = start.tagName; - start.tagName.toLowerCase() == 'p' && browser.gecko && domUtils.removeDirtyAttr(start); + var pre = node.previousSibling,next; + while(next = node.nextSibling){ + if(next.nodeType == 1 && next.tagName == 'SPAN' && !next.firstChild){ + domUtils.remove(next) + }else{ + break; } - } - } 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(); + 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); } - - } 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); + if(pre && pre.tagName == 'P' && domUtils.isEmptyBlock(pre)){ + domUtils.remove(pre) } - range.setCursor(); + 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/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); +// plugins/undo.js +/** + * undo redo + * @file + * @since 1.2.6.1 + */ + +/** + * 撤销上一次执行的命令 + * @command undo + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'undo' ); + * ``` + */ + +/** + * 重做上一次执行的命令 + * @command redo + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'redo' ); + * ``` + */ + +UE.plugins['undo'] = function () { + var saveSceneTimer; + var me = this, + maxUndoCount = me.options.maxUndoCount || 20, + maxInputCount = me.options.maxInputCount || 20, + fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi');// ie会产生多余的 + var noNeedFillCharTags = { + ol:1,ul:1,table:1,tbody:1,tr:1,body:1 + }; + var orgState = me.options.autoClearEmptyNode; + function compareAddr(indexA, indexB) { + if (indexA.length != indexB.length) + return 0; + for (var i = 0, l = indexA.length; i < l; i++) { + if (indexA[i] != indexB[i]) + return 0 + } + return 1; + } + + function compareRangeAddress(rngAddrA, rngAddrB) { + if (rngAddrA.collapsed != rngAddrB.collapsed) { + return 0; + } + if (!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)) { + return 0; + } + return 1; + } + + function UndoManager() { + this.list = []; + this.index = 0; + this.hasUndo = false; + this.hasRedo = false; + this.undo = function () { + if (this.hasUndo) { + if (!this.list[this.index - 1] && this.list.length == 1) { + this.reset(); + return; + } + while (this.list[this.index].content == this.list[this.index - 1].content) { + this.index--; + if (this.index == 0) { + return this.restore(0); + } } + this.restore(--this.index); } - 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; + }; + 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); } - } + }; - //处理backspace - if (keyCode == keymap.Backspace) { - rng = me.selection.getRange(); - collapsed = rng.collapsed; - if(me.fireEvent('delkeydown',evt)){ - return; + 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); + } + }) } - 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) - } - } + try{ + var rng = new dom.Range(me.document).moveToAddress(scene.address); + rng.select(noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]); + }catch(e){} - //解决选中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; - } + 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]; - } - //处理tab键的逻辑 - if (keyCode == keymap.Tab) { - //不处理以下标签 - var excludeTagNameForTabKey = { - 'ol' : 1, - 'ul' : 1, - 'table':1 - }; - //处理组件里的tab按下事件 - if(me.fireEvent('tabkeydown',evt)){ - domUtils.preventDefault(evt); + if(lastScene && lastScene.content != currentScene.content){ + me.trigger('contentchange') + } + //内容相同位置相同不存 + if (lastScene && lastScene.content == currentScene.content && + ( notCompareRange ? 1 : compareRangeAddress(lastScene.address, currentScene.address) ) + ) { 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; + this.list = this.list.slice(0, this.index + 1); + this.list.push(currentScene); + //如果大于最大数量了,就把最前的剔除 + if (this.list.length > maxUndoCount) { + this.list.shift(); } - 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()] + this.index = this.list.length - 1; + this.clearKey(); + //跟新undo/redo状态 + this.update(); - }; - //普通的情况 - 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) + }; + 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(); } - //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(); + }); + 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 || (evt.shiftKey && /\w/.test(evt.key))) { + 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, - rng,me = this; - if(keyCode == keymap.Backspace){ - if(me.fireEvent('delkeyup')){ + 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; } - 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; - } - } + } + }); + //扩展实例,添加关闭和开启命令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(); + }); } } - //处理当删除到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() + }, + commands: { + 'copy': { + execCommand: function (cmd) { + if (!me.document.execCommand('copy')) { + alert(me.getLang('copymsg')); + } } - } } + } +}); - }) -}; - -// 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 +// plugins/paste.js ///import core -///commands 为非ie浏览器自动添加a标签 -///commandsName AutoLink -///commandsTitle 自动增加链接 +///import plugins/inserthtml.js +///import plugins/undo.js +///import plugins/serialize.js +///commands 粘贴 +///commandsName PastePlain +///commandsTitle 纯文本粘贴模式 /** - * @description 为非ie浏览器自动添加a标签 + * @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); -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) { + 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 sel = me.selection.getNative(), - range = sel.getRangeAt(0).cloneRange(), - offset, - charCode; + var me = this; - 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; - } + me.setOpt({ + retainOnlyLabelPasted : false + }); - do{ - if (range.startOffset == 0) { - start = range.startContainer.previousSibling; + var txtContent, htmlContent, address; - 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); + 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 { - 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; + return '<' + b + tagName + ' ' + utils.trim(attrs) + '>' + } - } - range.setStart(next,0); + }); + } + 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) { - } - //range的开始边界已经在a标签里的不再处理 - if(domUtils.findParentByTagName(range.startContainer,'a',true)){ - return; - } - var a = me.document.createElement('a'),text = me.document.createTextNode(' '),href; + 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); + } - me.undoManger && me.undoManger.save(); - a.appendChild(range.extractContents()); - a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g,''); - href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar,'g'),''); - href = /^(?:https?:\/\/)/ig.test(href) ? href : "http://"+ href; - a.setAttribute('_src',utils.html(href)); - a.href = utils.html(href); + var metas = div.querySelectorAll('meta'); + for (var i = 0, ci; ci = metas[i++];) { + domUtils.remove(ci); + } - 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(); - } + var brs = div.querySelectorAll('br'); + for (i = 0; ci = brs[i++];) { + if (/^apple-/i.test(ci.className)) { + domUtils.remove(ci); } } } - }:{} - },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 (browser.gecko) { + var dirtyNodes = div.querySelectorAll('[_moz_dirty]'); + for (i = 0; ci = dirtyNodes[i++];) { + ci.removeAttribute('_moz_dirty'); + } } - if(node.nodeName == 'A'){ - return node; + if (!browser.ie) { + var spans = div.querySelectorAll('span.Apple-style-span'); + for (var i = 0, ci; ci = spans[i++];) { + domUtils.remove(ci, true); + } } - var lastChild = node.lastChild; - while(lastChild){ - if(lastChild.nodeName == 'A'){ - return lastChild; + //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) } - if(lastChild.nodeType == 3){ - if(domUtils.isWhitespace(lastChild)){ - lastChild = lastChild.previousSibling; - continue; + utils.each(me.body.querySelectorAll('div'), function (node) { + if (domUtils.isEmptyBlock(node)) { + domUtils.remove(node,true) } - return null - } - lastChild = lastChild.lastChild; + }) + } + 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); } - 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'){ + 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 == 1){ - var pre = checkIsCludeLink(pre); - if(pre && !pre.getAttribute('_href')){ - domUtils.remove(pre,true); - } + + if(pre && pre.nodeType == 3 && new RegExp('^[\n\r\t '+domUtils.fillChar+']*$').test(pre.nodeValue)){ + range.setStartBefore(pre) } } - }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); - } + if(range.startOffset == 0){ + range.setStartBefore(range.startContainer); + }else{ + break; } - }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) + } + 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/autoheight.js -///import core -///commands 当输入内容超过编辑器高度时,编辑器自动增高 -///commandsName AutoHeight,autoHeightEnabled -///commandsTitle 自动增高 +}; + + + +// plugins/puretxtpaste.js /** - * @description 自动伸展 - * @author zhanyi + * 纯文本粘贴插件 + * @file + * @since 1.2.6.1 */ -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(){ - try { - 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'; +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); } - me.body.style.height = currentHeight + 'px'; - lastHeight = currentHeight; } - domUtils.removeStyle(node,'clear'); } - } catch (e) {} - },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){ - me.window.scrollTo(0,0); - lastScrollY = null; + 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/autofloat.js -///import core -///commands 悬浮工具栏 -///commandsName AutoFloat,autoFloatEnabled -///commandsTitle 悬浮工具栏 +// plugins/list.js /** - * modified by chengchao01 - * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉! + * 有序列表,无序列表插件 + * @file + * @since 1.2.6.1 */ -UE.plugins['autofloat'] = function() { - var me = this, - lang = me.getLang(); - me.setOpt({ - topOffset:0 - }); - var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false, - topOffset = me.options.topOffset; +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' + }; - //如果不固定toolbar的位置,则直接退出 - if(!optsAutoFloatEnabled){ - return; + 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 uiUtils = UE.ui.uiUtils, - LteIE6 = browser.ie && browser.version <= 6, - quirks = browser.quirks; + var listStyle = { + 'OL':listToArray(me.options.insertorderedlist), + 'UL':listToArray(me.options.insertunorderedlist) + }; + var liiconpath = me.options.listiconpath; - function checkHasUI(){ - if(!UE.ui){ - alert(lang.autofloatMsg); - return 0; + //根据用户配置,调整customStyle + for(var s in customStyle){ + if(!me.options.insertorderedlist.hasOwnProperty(s) && !me.options.insertunorderedlist.hasOwnProperty(s)){ + delete customStyle[s]; } - 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'; + + 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}'); } - 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'); + 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}'); } } - } - 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); + 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{box-sizing:border-box;margin:0;pading:0;'+(browser.ie ? '' : 'width:95%')+'}li{clear:both;}'+customCss.join('\n'), me.document); }); - - 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.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); + } + } + } } - }); - 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; + 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') - /** - * 创建插入视频字符窜 - * @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); + 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) - width = parseInt(width, 10) || 0; - height = parseInt(height, 10) || 0; + }else{ + n.setStyle('list-style-type',currentStyle) + } + }) - 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) + 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); + } - /** - * 插入视频 - * @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 ] ); - * ``` - */ + 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++; + } - /** - * 查询当前光标所在处是否是一个视频 - * @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') + } + //去掉末尾的空白 + 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; + } + } - //===以下为静态工具方法=== - 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); - }; + utils.each(root.getNodesByTagName('p'),function(node){ + if(node.getAttr('class') != 'MsoListParagraph'){ + return + } - /** - * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的 - * 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态; - * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组 - * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null - */ - UETable.getTableCellAlignState = function ( cells ) { + //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视 + node.setStyle('margin',''); + node.setStyle('margin-left',''); + node.setAttr('class',''); - !utils.isArray( cells ) && ( cells = [cells] ); + 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 result = {}, - status = ['align', 'valign'], - tempStatus = null, - isSame = true;//状态是否相同 + var li = UE.uNode.createElement('li'); + li.appendChild(p); + list.appendChild(li); + } + var tmp = node,type,cacheNode = node; - utils.each( cells, function( cellNode ){ - - utils.each( status, function( currentState ){ - - tempStatus = cellNode.getAttribute( currentState ); + if(node.parentNode.tagName != 'li' && (type = checkListType(node.innerText(),node))){ - if( !result[ currentState ] && tempStatus ) { - result[ currentState ] = tempStatus; - } else if( !result[ currentState ] || ( tempStatus !== result[ currentState ] ) ) { - isSame = false; - return false; + 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) } + }) + } - } ); + }); - return isSame; + //调整索引标签 + me.addListener('contentchange',function(){ + adjustListStyle(me.document) + }); - }); + function adjustListStyle(doc,ignore){ + utils.each(domUtils.getElementsByTagName(doc,'ol ul'),function(node){ - return isSame ? result : null; + 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]) + } - /** - * 根据当前选区获取相关的table信息 - * @return {Object} - */ - UETable.getTableItemsByRange = function (editor) { - var start = editor.selection.getStart(); + } + 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; + } + } - //ff下会选中bookmark - if( start && start.id && start.id.indexOf('_baidu_bookmark_start_') === 0 && start.nextSibling) { - start = start.nextSibling; + 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); + } } - - //在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 + if(nextList && domUtils.isFillChar(nextList)){ + domUtils.remove(nextList); } - }; - UETable.getUETableBySelected = function (editor) { - var table = UETable.getTableItemsByRange(editor).table; - if (table && table.ueTable && table.ueTable.selectedTds.length) { - return table.ueTable; + 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); } - 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 - }; + if(preList && domUtils.isFillChar(preList)){ + domUtils.remove(preList); } - }; - /** - * 根据当前点击的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); + !ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list); + if(getStyle(list)){ + adjustListStyle(list.ownerDocument,true) } - return tdOrTable.ueTable; - }; + } - UETable.cloneCell = function(cell,ignoreMerge,keepPro){ - if (!cell || utils.isString(cell)) { - return this.table.ownerDocument.createElement(cell || 'td'); + function setListStyle(list,style){ + if(customStyle[style]){ + list.className = 'custom_' + style; } - var flag = domUtils.hasClass(cell, "selectTdClass"); - flag && domUtils.removeClasses(cell, "selectTdClass"); - var tmpCell = cell.cloneNode(true); - if (ignoreMerge) { - tmpCell.rowSpan = tmpCell.colSpan = 1; + 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); } - //去掉宽高 - !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); + 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 { - cellRows['row_' + (i + k)]++ + 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; } } - 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; + li = domUtils.findParentByTagName(range.startContainer, 'li', true); - }, - /** - * 获取视觉上的后置单元格 - * @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; + if (li) { + if (domUtils.isEmptyBlock(li)) { + bk = range.createBookmark(); + var parentList = li.parentNode; + if (li !== parentList.lastChild) { + domUtils.breakParent(li, parentList); + clearEmptySibling(li); + } else { - 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); + parentList.parentNode.insertBefore(li, parentList.nextSibling); + if (domUtils.isEmptyNode(parentList)) { + domUtils.remove(parentList); } - 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; + //嵌套不处理 + 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); + } } - } - } - 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 + 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(); } + + } - //修复残缺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 + + + } + 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; + } + + } + + } - //当框选后删除行或者列后撤销,需要重建选区。 - 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 - }; + + } + }); + + 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) } - //给第一行设置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"); + } + }); + //处理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; } - } - }, - /** - * 获取单元格的索引信息 - */ - 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; + if(levelNum >= me.options.maxListLevel){ + return true; } } - }, - /** - * 根据行列号获取单元格 - */ - 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); - } - } + } + //只以开始为准 + //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; } - // 通过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); - } + }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; } } - // 检查是否有超出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); + 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; } - } - } - // 检查是否有超出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); + 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; } } - //递归调用直至所有完成所有框选单元格的扩展 - 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 - }; - } + me.fireEvent('contentchange'); + range.moveToBookmark(bk).select(); + return true; } + } - 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; + }); + function getLi(start){ + while(start && !domUtils.isBody(start)){ + if(start.nodeName == 'TABLE'){ + return null; } - }, - /** - * 依据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)); - } + if(start.nodeName == 'LI'){ + return start } - 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; + start = start.parentNode; + } + } - 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); + /** + * 有序列表,与“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' ); + * ``` + */ - 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)); - } + /** + * 无序列表,与“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' ); + * ``` + */ - // 删除剩余的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; - } + me.commands['insertorderedlist'] = + me.commands['insertunorderedlist'] = { + execCommand:function (command, style) { - 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); - } + if (!style) { + style = command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc'; } - 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'; + 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; - 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) + if (start || end) { + start && (startParent = start.parentNode); + if (!bko.end) { + end = start; } - } - } + end && (endParent = end.parentNode); - //首行直接插入,无需考虑部分单元格被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); + 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 { - if (nextRow.cells.length) nextRow.insertBefore(clone, nextRow.cells[0]) + list = me.document.createElement(tag); + setListStyle(list,style); + list.appendChild(frag); + tmp.parentNode.insertBefore(list, tmp); } - 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) + domUtils.remove(tmp); + list && adjustList(list, tag, style); + range.moveToBookmark(bko).select(); + return; } - }else{ - if (cell.tagName == 'TH') { - var td = cell.ownerDocument.createElement("td"); - td.appendChild(cell.firstChild); - tableRow.insertBefore(td, cell); - domUtils.remove(cell) + //开始 + 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; } - } - } - 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 (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(!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); + if (!modifyStart) { + range.setStartBefore(me.document.getElementById(bko.start)); } - 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; + if (bko.end && !modifyEnd) { + range.setEndAfter(me.document.getElementById(bko.end)); } - 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), + range.enlarge(true, function (node) { + return notExchange[node.tagName]; + }); - 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; + frag = me.document.createDocumentFragment(); - }, - 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 = ""; - }) - } + 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)) { - }; - 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); - }; + 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); - 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 '' + html.join('') + '
    ' - } - - 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; + while (current && current !== bk.end && (!block(current) || domUtils.isBookmarkNode(current) )) { + tmpNode = current; + current = domUtils.getNextDomNode(current, false, null, function (node) { + return !notExchange[node.tagName]; + }); + } - var defaultValue = getDefaultValue(me), - tableWidth = firstParentBlock.offsetWidth, - tdWidth = Math.floor(tableWidth / opt.numCols - defaultValue.tdPadding * 2 - defaultValue.tdBorder); + 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); - //todo其他属性 - !opt.tdvalign && (opt.tdvalign = me.options.tdvalign); - me.execCommand("inserthtml", createTable(opt, tdWidth)); - } - }; + current = domUtils.getNextDomNode(tmpNode, false, filterFn); - 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(); - } - } - }; + var li = range.document.createElement('li'); - 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); + 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); + } } - domUtils.remove(table); - rng = this.selection.getRange(); - if (next.nodeType == 3) { - rng.setStartBefore(next) - } else { - rng.setStart(next, 0) + 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) + } } - rng.setCursor(false, true) - this.fireEvent("tablehasdeleted") - - } + range.moveToBookmark(bko).select(); - } - }; - 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); + }, + 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 + }; } - } - } - }; - 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); + 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; } - } - }; - 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; + + +// 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'; + }; } - return -1; + 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; + } + }; }, - 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(); - } + codemirror: function (editor, holder){ - } - }; - 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]) + 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; } - } - 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; + 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'); - if (!table || !cell) return -1; - var ut = getUETable(table); - if (ut.selectedTds.length) return -1; + me.setOpt({ + sourceEditorFirst:false + }); + function createSourceEditor(holder){ + return sourceEditors[opt.sourceEditor == 'codemirror' && window.CodeMirror ? 'codemirror' : 'textarea'](me, holder); + } - var cellInfo = ut.getCellInfo(cell), - rightColIndex = cellInfo.colIndex + cellInfo.colSpan; - if (rightColIndex >= ut.colsNum) return -1; // 如果处于最右边则不能向右合并 + var bakCssText; + //解决在源码模式下getContent不能得到最新的内容问题 + var oldGetContent, + bakAddress; - 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不能相互合并 + /** + * 切换源码模式和编辑模式 + * @command source + * @method execCommand + * @param { String } cmd 命令字符串 + * @example + * ```javascript + * editor.execCommand( 'source'); + * ``` + */ - // 当且仅当两个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; + /** + * 查询当前编辑区域的状态是源码模式还是可视化模式 + * @command source + * @method queryCommandState + * @param { String } cmd 命令字符串 + * @return { int } 如果当前是源码编辑模式,返回1,否则返回0 + * @example + * ```javascript + * editor.queryCommandState( 'source' ); + * ``` + */ - if (!table || !cell) return -1; - var ut = getUETable(table); - if (ut.selectedTds.length)return -1; + me.commands['source'] = { + execCommand: function (){ - var cellInfo = ut.getCellInfo(cell), - downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan; - if (downRowIndex >= ut.rowsNum) return -1; // 如果处于最下边则不能向下合并 + sourceMode = !sourceMode; + if (sourceMode) { + bakAddress = me.selection.getRange().createAddress(false,true); + me.undoManger && me.undoManger.save(true); + if(browser.gecko){ + me.body.contentEditable = false; + } - 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不能相互合并 + bakCssText = me.iframe.style.cssText; + me.iframe.style.cssText += 'position:absolute;left:-32768px;top:-32768px;'; - // 当且仅当两个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(); - } + 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,' ')) - } - }; - 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(); - } - }; + me.fireEvent('aftergetcontent'); - 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(); + var content = root.toHtml(true); - 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); + 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 { - 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); + 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,''); } - } - } - } - } - }; - 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(); + return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g,'') + }); - } - }; + me.setContent = orgSetContent; - 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"); + 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; } - } - } - }; - //平均分配各列 - 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); + //要在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){} - 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; + 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); + }; - 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; + if(opt.sourceEditor == "codemirror"){ - utils.each(cells, function (node) { - if (node.colSpan == 1) { - node.setAttribute("width", averageWidth); + 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" + }); - if (ut && ut.selectedTds.length) { - setAverageWidth(getAverageWidth()); - } + }); } + }; - //平均分配各行 - UE.commands['averagedistributerow'] = { - queryCommandState: function () { - var ut = getUETableBySelected(this); - if (!ut) return -1; - if (ut.selectedTds && /th/ig.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; +// 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) { - if (captionArr.length > 0) { - captionHeight = captionArr[0].offsetHeight; - } - if (thArr.length > 0) { - thHeight = thArr[0].offsetHeight; + 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); + + } } - 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; + if (me.undoManger && doSave) { + me.undoManger.save(); } - 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; + //没有站位符,会出现多行的问题 + browser.opera && range.select(); + }else{ + me.fireEvent('saveScene',true,true) } + } + }); - 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); - } - }); + 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 = ''; - 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); + var range = me.selection.getRange(); - if (!ut) { - var start = me.selection.getStart(), - cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true); - if (!/caption/ig.test(cell.tagName)) { - domUtils.setAttributes(cell, data); - } else { - cell.style.textAlign = data.align; - cell.style.verticalAlign = data.vAlign; + 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; } - me.selection.getRange().setCursor(true); - } else { - utils.each(ut.selectedTds, function (cell) { - domUtils.setAttributes(cell, data); - }); } - }, - /** - * 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态 - * @see UE.UETable.getTableCellAlignState - */ - queryCommandValue: function (cmd) { + if (tag == 'p') { - var activeMenuCell = getTableItemsByRange( this).cell; - if( !activeMenuCell ) { - activeMenuCell = getSelectedArr(this)[0]; - } + if (!browser.ie) { - if (!activeMenuCell) { + start = domUtils.findParentByTagName(range.startContainer, ['ol','ul','p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6','blockquote','caption'], true); - return null; + //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); - //获取同时选中的其他单元格 - var cells = UE.UETable.getUETable(activeMenuCell).selectedTds; + 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(); - !cells.length && ( cells = activeMenuCell ); + } else { + range.setStart(start, 0).setCursor(); + } - return UE.UETable.getTableCellAlignState(cells); + + } 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(); + + } } } - }; - //表格对齐方式 - 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); + +// 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; + } + } } } - }; - //表格属性 - 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; - }); + //处理backspace + if (keyCode == keymap.Backspace) { + rng = me.selection.getRange(); + collapsed = rng.collapsed; + if(me.fireEvent('delkeydown',evt)){ + return; } - } - }; - //单元格属性 - UE.commands['edittd'] = { - queryCommandState: function () { - return getTableItemsByRange(this).table ? 0 : -1 - }, - execCommand: function (cmd, bkColor) { - var me = this, - ut = getUETableBySelected(me); + var start,end; + //避免按两次删除才能生效的问题 + if(rng.collapsed && rng.inFillChar()){ + start = rng.startContainer; - if (!ut) { - var start = me.selection.getStart(), - cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true); - if (cell) { - cell.style.backgroundColor = bkColor; + 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) } - } 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; + //解决选中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; + } } - 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; + } + //处理tab键的逻辑 + if (keyCode == keymap.Tab) { + //不处理以下标签 + var excludeTagNameForTabKey = { + 'ol' : 1, + 'ul' : 1, + 'table':1 + }; + //处理组件里的tab按下事件 + if(me.fireEvent('tabkeydown',evt)){ + domUtils.preventDefault(evt); + return; } - }, - execCommand: function (cmd, classList) { - var table = getTableItemsByRange(this).table; - if (cmd == "interlacetable") { - table.setAttribute("interlaced", "enabled"); - this.fireEvent("interlacetable", table, classList); + 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 { - table.setAttribute("interlaced", "disabled"); - this.fireEvent("uninterlacetable", table); + 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) } - }; - 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'; - }) + //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; + } + } } - }; - 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); - } + }); + 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); + } + } - 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); - }; + //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() + } - 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); +// 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}; + } - var tableCopyList, isFullCol, isFullRow; - //注册del/backspace事件 - me.addListener('keydown', function (cmd, evt) { - var me = this; - var keyCode = evt.keyCode || evt.which; + (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(); + }); - if (keyCode == 8) { + 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) + ';'; - var ut = getUETableBySelected(me); - if (ut && ut.selectedTds.length) { + me.editor.ui.getDom().appendChild(cover); + me.editor.ui.getDom().appendChild(resizer); - if (ut.isFullCol()) { - me.execCommand('deletecol') - } else if (ut.isFullRow()) { - me.execCommand('deleterow') - } else { - me.fireEvent('delcells'); - } - domUtils.preventDefault(evt); + 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; - 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 (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)); - if (keyCode == 46) { + me.showCover(); + me.editor.fireEvent('afterscaleshow', me); + me.editor.fireEvent('saveScene'); + }, + hide: function () { + var me = this; + me.hideCover(); + me.resizer.style.display = 'none'; - 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); + 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; - } - if (keyCode == 13) { + me.setOpt('imageScaleEnabled', true); - var rng = me.selection.getRange(), - caption = domUtils.findParentByTagName(rng.startContainer, 'caption', true); - if (caption) { - var table = domUtils.findParentByTagName(caption, 'table'); - if (!rng.collapsed) { + if ( !browser.ie && me.options.imageScaleEnabled) { + me.addListener('click', function (type, e) { - 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); + 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 ((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)); - } + }); + } - } + 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(); } - } - }); - 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) +// 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; } - } 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]; + + 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; } - } - 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']); + 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); - 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); + //range的开始边界已经在a标签里的不再处理 + if(domUtils.findParentByTagName(range.startContainer,'a',true)){ + return; } + var a = me.document.createElement('a'),text = me.document.createTextNode(' '),href; + + me.undoManger && me.undoManger.save(); + a.appendChild(range.extractContents()); + a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g,''); + href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar,'g'),''); + href = /^(?:https?:\/\/)/ig.test(href) ? href : "http://"+ href; + a.setAttribute('_src',utils.html(href)); + a.href = utils.html(href); + + range.insertNode(a); + a.parentNode.insertBefore(text, a.nextSibling); + range.setStart(text, 0); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + me.undoManger && me.undoManger.save(); } } - 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) + } + } + }:{} + },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); + } } - if (j == 2 && cloneTd.rowSpan > 1) { - cloneTd.rowSpan = 1; + } + }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(); - 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']; + domUtils.remove(start,true); + rng.moveToBookmark(bk).select(true) } - } 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); - }); +// 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; - //内容变化时触发索引更新 - //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; + function adjustHeight() { + var me = this; + clearTimeout(timer); + if(isFullscreen)return; + if (!me.queryCommandState || me.queryCommandState && me.queryCommandState('source') != 1) { + timer = setTimeout(function(){ + try { + var node = me.body.lastChild; + while(node && node.nodeType != 1){ + node = node.previousSibling; } - 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(); + 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'); } - }; - }); + } catch (e) {} + },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不给事件算得不对 - switchBorderColor(me, true); - }); + setTimeout(function () { + adjustHeight.call(me); + }, browser.gecko ? 100 : 0); + me.fireEvent('autoheightchanged', me.autoHeightEnabled); + }; + me.disableAutoHeight = function () { - domUtils.on(me.document, "mousemove", mouseMoveEvent); + 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); - 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 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; - }; +// 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 }); - /** - * 删除obj的宽高style,改成属性宽高 - * @param obj - * @param replaceToProperty - */ - function removeStyleSize(obj, replaceToProperty) { - removeStyle(obj, "width", true); - removeStyle(obj, "height", true); - } + var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false, + topOffset = me.options.topOffset; - 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; + //如果不固定toolbar的位置,则直接退出 + if(!optsAutoFloatEnabled){ + return; } + var uiUtils = UE.ui.uiUtils, + LteIE6 = browser.ie && browser.version <= 6, + quirks = browser.quirks; - function isEmptyBlock(node) { - var reg = new RegExp(domUtils.fillChar, 'g'); - if (node[browser.ie ? 'innerText' : 'textContent'].replace(/^\s*$/, '').replace(reg, '').length > 0) { + function checkHasUI(){ + if(!UE.ui){ + alert(lang.autofloatMsg); 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 }; + 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'); + } } - 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; + function unsetFloating(){ + flag = true; + if(placeHolder.parentNode){ + placeHolder.parentNode.removeChild(placeHolder); } - try { - - //普通状态下鼠标移动 - var target = getParentTdOrTh(evt.target || evt.srcElement), - pos; - - //区分用户的行为是拖动还是双击 - if( isInResizeBuffer ) { + toolbarBox.style.cssText = bakCssText; + } - me.body.style.webkitUserSelect = 'none'; + 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); - if( Math.abs( userActionStatus.x - evt.clientX ) > offsetOfTableCell || Math.abs( userActionStatus.y - evt.clientY ) > offsetOfTableCell ) { - clearTableDragTimer(); - isInResizeBuffer = false; - singleClickState = 0; - //drag action - tableBorderDrag(evt); - } - } + me.addListener('destroy',function(){ + domUtils.un(window, ['scroll','resize'], updateFloating); + me.removeListener('keydown', defer_updateFloating); + }); - //修改单元格大小时的鼠标移动 - 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"; - } + me.addListener('ready', function(){ + if(checkHasUI(me)){ + //加载了ui组件,但在new时,没有加载ui,导致编辑器实例上没有ui类,所以这里做判断 + if(!me.ui){ 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); + 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); - } 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); - } + 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); - 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); +// plugins/video.js +/** + * video插件, 为UEditor提供视频插入支持 + * @file + * @since 1.2.6.1 + */ - 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); - } - } +UE.plugins['video'] = function (){ + var me =this; /** - * 获取拖动时允许的X轴坐标 - * @param dragTd - * @param evt + * 创建插入视频字符窜 + * @param url 视频地址 + * @param width 视频宽度 + * @param height 视频高度 + * @param align 视频对齐 + * @param toEmbed 是否以flash代替显示 + * @param addParagraph 是否需要添加P 标签 */ - 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)); + function creatInsertStr(url,width,height,id,align,classname,type){ - left += cellMinWidth; - right -= cellMinWidth; + url = utils.unhtmlForUrl(url); + align = utils.unhtml(align); + classname = utils.unhtml(classname); - return mouseX < left ? left : mouseX > right ? right : mouseX; + 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; } - /** - * 获取拖动时允许的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 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 ); + * ``` */ - 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对象 + * 插入视频 + * @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 ] ); + * ``` */ - 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"); + /** + * 查询当前光标所在处是否是一个视频 + * @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 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); + }; - this.document.body.appendChild( line ); + /** + * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的 + * 条件时才会返回其状态值,否则将返回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] ); - return line; + var result = {}, + status = ['align', 'valign'], + tempStatus = null, + isSame = true;//状态是否相同 - } + utils.each( cells, function( cellNode ){ - /** - * 更新resize-line - */ - function updateResizeLine( cell, uetable ) { + utils.each( status, function( currentState ){ - 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' - }; + tempStatus = cellNode.getAttribute( currentState ); - utils.extend( line.style, styles ); + if( !result[ currentState ] && tempStatus ) { + result[ currentState ] = tempStatus; + } else if( !result[ currentState ] || ( tempStatus !== result[ currentState ] ) ) { + isSame = false; + return false; + } - } + } ); - /** - * 显示resize-line - */ - function showResizeLine( cell ) { + return isSame; - var uetable = getUETable( cell ); + }); - updateResizeLine.call( this, cell, uetable ); + return isSame ? result : null; - } + }; /** - * 获取鼠标与当前单元格的相对位置 - * @param ele - * @param mousePos + * 根据当前选区获取相关的table信息 + * @return {Object} */ - function getRelation(ele, mousePos) { - var elePos = domUtils.getXY(ele); + UETable.getTableItemsByRange = function (editor) { + var start = editor.selection.getStart(); - if( !elePos ) { - return ''; + //ff下会选中bookmark + if( start && start.id && start.id.indexOf('_baidu_bookmark_start_') === 0 && start.nextSibling) { + start = start.nextSibling; } - if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) { - return "h"; + //在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 } - if (mousePos.x - elePos.x < cellBorderWidth) { - return 'h1' + }; + UETable.getUETableBySelected = function (editor) { + var table = UETable.getTableItemsByRange(editor).table; + if (table && table.ueTable && table.ueTable.selectedTds.length) { + return table.ueTable; } - if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) { - return "v"; + 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 + }; } - if (mousePos.y - elePos.y < cellBorderWidth) { - return 'v1' + }; + /** + * 根据当前点击的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 ''; - } - - function mouseDownEvent(type, evt) { + return tdOrTable.ueTable; + }; - if( isEditorDisabled() ) { - return ; + UETable.cloneCell = function(cell,ignoreMerge,keepPro){ + if (!cell || utils.isString(cell)) { + return this.table.ownerDocument.createElement(cell || 'td'); } - - 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 ); + 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; } - //清除表格的计时器 - 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) + 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)]++ + } } + } } - if (h == 'h') { - var ut = getUETable(target), - table = ut.table, - cells = getCellsByMoveBorder( target, table, true ); + cellsNum += cellRows['row_' + i] || 0; + maxLen = Math.max(cellsNum, maxLen); + } + return maxLen; + }, + getCellColIndex:function (cell) { - cells = extractArray( cells, 'left' ); + }, + /** + * 获取当前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; - ut.width = ut.offsetWidth; + 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; - var oldWidth = [], - newWidth = []; + }, + /** + * 获取视觉上的后置单元格 + * @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; - 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; + 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); } - - 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; -// }); - + if (flag) break; + } + } } + return returns; + } catch (e) { + showError(e); } - } - } - - 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"); + }, + 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); } - - } - - 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); + }, + /** + * 更新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); } - - } - - 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; - + this.rowsNum = rowsNum; + this.colsNum = colsNum; + for (var i = 0, len = rows.length; i < len; i++) { + this.indexTable[i] = new Array(colsNum); } - - } - - 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() + //填充索引表 + 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 + } + } + } } - } 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: + //修复残缺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 + } + } } - 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); + //当框选后删除行或者列后撤销,需要重建选区。 + 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 + }; } - } 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); + //给第一行设置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"); } - } 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); + } + }, + /** + * 获取单元格的索引信息 + */ + 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 + }; + } } - 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; - } ); + 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; - function isEditorDisabled() { - return me.body.contentEditable === "false"; - } + 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; - 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); + 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)); + } - /** - * 获取调整单元格大小的相关单元格 - * @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); + // 删除剩余的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; } - 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 - }); + 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); } - - 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 ); + 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) + } + } + } - } ); - - - //修正越界 - 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; - + //首行直接插入,无需考虑部分单元格被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 { - tab.offsetVal = 0; + 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); + } } - - } - - 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\))/ig.test(color)) - domUtils.addClass(node, "noBorderTable") - } else { - domUtils.removeClasses(node, "noBorderTable") + //框选时插入不触发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; } - - } - } - - 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; + 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'; - } 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; + 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) + } + } } - } - - - //排除了非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; i1 || 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 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 '' + html.join('') + '
    ' + } + + 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/ig.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/ig.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 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 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\))/ig.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; i1 || 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.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; } } - }, - '-', - { - 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' + } + 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') }, - '-', - { - 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(); + //回调失败,本次请求超时 + 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(/[&]+/ig, '&'); + } + 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); } - }, - { - label:lang.setbordervisible, - cmdName:'setbordervisible' + }catch(e){ + alert(lang.callBackErrorMsg); } - ] - }, - { - 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' + } + 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); }, - { - 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"]}); + 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(); } - ] - }, - { - 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'} + + }); + //取消拖放图片时出现的文字光标位置提示 + 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 + }, + 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 () { + + 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 ) + } }, - { - 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" - } - ] + notNeedUndo: true, + ignoreContentChange:true + }, + + 'getlocaldata':{ + execCommand:function (cmd, name) { + return saveKey ? me.getPreferences( saveKey ) || '' : ''; }, - '-', - { - label:lang.insertparagraphbefore, - cmdName:'insertparagraph', - value:true + notNeedUndo: true, + ignoreContentChange:true + }, + + 'drafts':{ + execCommand:function (cmd, name) { + if ( saveKey ) { + me.body.innerHTML = me.getPreferences( saveKey ) || '

    '+domUtils.fillHtml+'

    '; + me.focus(true); + } }, - { - label:lang.insertparagraphafter, - cmdName:'insertparagraph' + queryCommandState: function () { + return saveKey ? ( me.getPreferences( saveKey ) === null ? -1 : 0 ) : -1; }, - { - label:lang['copy'], - cmdName:'copy' + 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" ); + + + }, - { - label:lang['paste'], - cmdName:'paste' + queryCommandState: function ( cmd, name ) { + + var tableNode = domUtils.findParentByTagName(this.selection.getRange().startContainer, 'table', true); + return tableNode && validData( tableNode ) ? 0 : -1; + } - ]; - if ( !items.length ) { - return; + } + }, + 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;"); + } + + }) + + } } - var uiUtils = UE.ui.uiUtils; - me.addListener( 'contextmenu', function ( type, evt ) { + function validData ( table ) { - var offset = uiUtils.getViewportOffsetByEvent( evt ); - me.fireEvent( 'beforeselectionchange' ); - if ( menu ) { - menu.destroy(); + var firstRows = null, + cellCount = 0; + + //行数不够 + if ( table.rows.length < 2 ) { + return false; } - 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( '-' ); + + //列数不够 + 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'); } - } 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); + } + } + }, + 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 { - 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 ); - } - } ); - } + child.nodeType === 1 && traversal(child, Directory); + tmpSection && tmpSection.endAddress[tmpSection.endAddress.length - 1] ++; } - })( 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 ''; + 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; } } - contextItems.push( { - //todo 修正成自动获取方式 - 'label':getLabel(), - className:'edui-for-' + item.icon, - 'subMenu':{ - items:subMenu, - editor:me + 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; - } 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 ) { + if(!section) return; - 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 ); - } - } ); + 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; - })( ti ); - } - if ( contextItems[contextItems.length - 1] == '-' ) { - contextItems.pop(); + 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 + } } + } +}); - menu = new UE.ui.Menu( { - items:contextItems, - className:"edui-contextmenu", - editor:me - } ); - menu.render(); - menu.showAt( offset ); +// plugins/simpleupload.js +/** + * @description + * 简单上传:点击按钮,直接选择文件上传 + * @author Jinqn + * @date 2014-03-31 + */ +UE.plugin.register('simpleupload', function (){ + var me = this, + isLoaded = false, + containerBtn; - me.fireEvent("aftershowcontextmenu",menu); + function initUploadBtn(){ + var w = containerBtn.offsetWidth || 20, + h = containerBtn.offsetHeight || 20, + btnIframe = document.createElement('iframe'), + 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;'; - 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 ); + domUtils.on(btnIframe, 'load', function(){ + + var timestrap = (+new Date()).toString(36), + wrapper, + btnIframeDoc, + btnIframeBody; + + btnIframeDoc = (btnIframe.contentDocument || btnIframe.contentWindow.document); + btnIframeBody = btnIframeDoc.body; + wrapper = btnIframeDoc.createElement('div'); + + wrapper.innerHTML = '
    ' + + '' + + '
    ' + + ''; + + wrapper.className = 'edui-' + me.options.theme; + wrapper.id = me.ui.id + '_iframeupload'; + btnIframeBody.style.cssText = btnStyle; + btnIframeBody.style.width = w + 'px'; + btnIframeBody.style.height = h + 'px'; + btnIframeBody.appendChild(wrapper); + + if (btnIframeBody.parentNode) { + btnIframeBody.parentNode.style.width = w + 'px'; + btnIframeBody.parentNode.style.height = w + 'px'; } - } - }); - // 添加复制的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()); + var form = btnIframeDoc.getElementById('edui_form_' + timestrap); + var input = btnIframeDoc.getElementById('edui_input_' + timestrap); + var iframe = btnIframeDoc.getElementById('edui_iframe_' + timestrap); + + domUtils.on(input, 'change', function(){ + if(!input.value) return; + var loadingId = 'loading_' + (+new Date()).toString(36); + var params = utils.serializeParam(me.queryCommandValue('serverparam')) || ''; + + var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName')); + var allowFiles = me.getOpt('imageAllowFiles'); + + me.focus(); + me.execCommand('inserthtml', ''); + + function callback(){ + try{ + var link, json, loader, + body = (iframe.contentDocument || iframe.contentWindow.document).body, + result = body.innerText || body.textContent || ''; + json = (new Function("return " + result))(); + link = me.options.imageUrlPrefix + json.url; + if(json.state == 'SUCCESS' && json.url) { + loader = me.document.getElementById(loadingId); + loader.setAttribute('src', link); + loader.setAttribute('_src', link); + loader.setAttribute('title', json.title || ''); + loader.setAttribute('alt', json.original || ''); + loader.removeAttribute('id'); + domUtils.removeClasses(loader, 'loadingclass'); + } else { + showErrorLoader && showErrorLoader(json.state); + } + }catch(er){ + showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError')); + } + form.reset(); + domUtils.un(iframe, 'load', callback); + } + 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')) { + errorHandler(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; + } + + domUtils.on(iframe, 'load', callback); + form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?':'&') + params); + form.submit(); + }); + + var stateTimer; + me.addListener('selectionchange', function () { + clearTimeout(stateTimer); + stateTimer = setTimeout(function() { + var state = me.queryCommandState('simpleupload'); + if (state == -1) { + input.disabled = 'disabled'; + } else { + input.disabled = false; + } + }, 400); + }); + isLoaded = true; + }); + + btnIframe.style.cssText = btnStyle; + containerBtn.appendChild(btnIframe); + } + + 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); + } + }); + }, + commands: { + 'simpleupload': { + queryCommandState: function () { + return isLoaded ? 0:-1; } } } - }); + } +}); -}; - - -// 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 +// plugins/serverparam.js /** - * B、I、sub、super命令支持 + * 服务器提交的额外参数列表设置插件 * @file * @since 1.2.6.1 */ +UE.plugin.register('serverparam', function (){ -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' ); - * ``` - */ + var me = this, + serverParam = {}; - /** - * 下标文本,与“superscript”命令互斥 - * @command subscript - * @method execCommand - * @remind 把选中的文本内容切换成下标文本, 如果当前选中的文本已经是下标, 则该操作会把文本内容还原成正常文本 - * @param { String } cmd 命令字符串 - * @example - * ```javascript - * //editor是编辑器实例 - * //对当前选中的文本内容执行下标操作 - * //第一次操作, 文本内容将变成下标文本 - * editor.execCommand( 'subscript' ); - * - * //再次对同一文本内容执行, 则文本内容将恢复正常 - * editor.execCommand( 'subscript' ); - * ``` - */ + 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'} + * ``` + */ - /** - * 上标文本,与“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); + /** + * 获取服务器提交的额外参数列表 + * @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 { - 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']); - } + serverParam[key] = value; } - obj ? range.removeInlineStyle( tagNames ) : range.applyInlineStyle( tagNames[0] ); + } else if (utils.isObject(key)) { //传入对象,覆盖列表项 + utils.extend(serverParam, key, true); + } else if (utils.isFunction(key)){ //传入函数,添加列表项 + utils.extend(serverParam, key(), true); } - range.select(); }, - queryCommandState : function() { - return getObj(this,tagNames) ? 1 : 0; + queryCommandValue: function(){ + return serverParam || {}; } - }; - })( style, basestyles[style] ); + } + } } -}; +}); + - - -// plugins/elementpath.js +// plugins/insertfile.js /** - * 选取路径命令 - * @file + * 插入附件 */ -UE.plugins['elementpath'] = function(){ - var currentLevel, - tagNames, - me = this; - me.setOpt('elementPathEnabled',true); - if(!me.options.elementPathEnabled){ - return; +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']; } - 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 { + 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); } } - 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 + + + +// plugins/xssFilter.js /** - * @description 查找替换 - * @author zhanyi + * @file xssFilter.js + * @desc xss过滤器 + * @author robbenmu */ -UE.plugin.register('searchreplace',function(){ - var me = this; +UE.plugins.xssFilter = function() { - var _blockElm = {'table':1,'tbody':1,'tr':1,'ol':1,'ul':1}; + var config = UEDITOR_CONFIG; + var whitList = config.whitList; - 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; + function filter(node) { - } - var reg = new RegExp(str,'g' + (opt.casesensitive ? '' : 'i')),match; + var tagName = node.tagName; + var attrs = node.attrs; - while(match = reg.exec(textContent)){ - if(match.index >= currentIndex){ - return opt.dir == -1 ? textContent.length - match.index - opt.searchStr.length : match.index; + 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 = []; } - } - 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 + 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); } } - node = domUtils[methodName](node); - while(node && _blockElm[node.nodeName.toLowerCase()]){ - node = domUtils[methodName](node,true); + if (src.className) { + domUtils.addClass(tgt,src.className); } - if(node){ - currentIndex = opt.dir == -1 ? (node.nodeType == 3 ? node.nodeValue : node[browser.ie ? 'innerText' : 'textContent']).length : 0; + if (src.style.cssText) { + tgt.style.cssText += ';' + src.style.cssText; } - - } - } - 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) - } + }, + 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; } - }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; - } + } + if (doc.addEventListener) { + function handleMouseUp(evt){ + doc.removeEventListener('mousemove', handleMouseMove, true); + doc.removeEventListener('mouseup', handleMouseUp, true); + window.removeEventListener('mouseup', handleMouseUp, true); + callbacks.ondragstop(); } - } - 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); + doc.addEventListener('mousemove', handleMouseMove, true); + doc.addEventListener('mouseup', handleMouseUp, true); + window.addEventListener('mouseup', handleMouseUp, 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) + 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; } - } - - - 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) + 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'; } - 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 layer; + }, + makeUnselectable: function (element){ + if (browser.opera || (browser.ie && browser.version < 9)) { + element.unselectable = 'on'; + if (element.hasChildNodes()) { + for (var i=0; i'; + } + }; + utils.inherits(Separator, UIBase); - bk = range.createBookmark(); - range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select(); - } - } +})(); + +// 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 '
    '; }, - queryCommandValue : function() { - var parent = domUtils.filterNodeList( - this.selection.getStartElementPath(), - function(node){return node.getAttribute('label')} - ); - return parent ? parent.getAttribute('label') : ''; + 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'; } }; - //当去掉customstyle是,如果是块元素,用p代替 - me.addListener('keyup', function(type, evt) { - var keyCode = evt.keyCode || evt.which; + utils.inherits(Mask, UIBase); +})(); - 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(); +// 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/ig.test(evt.type)&&pop.className=="edui-wordpastepop") return; + pop.hide(); } } } - }); -}; - -// 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 () { + if(allPopups.length) + pop.editor.fireEvent("afterhidepop"); + } - var catcherLocalDomain = me.getOpt('catcherLocalDomain'), - catcherActionUrl = me.getActionUrl(me.getOpt('catcherActionName')), - catcherUrlPrefix = me.getOpt('catcherUrlPrefix'), - catcherFieldName = me.getOpt('catcherFieldName'); + Popup.postHide = closeAllPopup; - 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; - } - } + 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 '
    ' + + '
    ' + + ' ' + + '
    ' + + '
    ' + + this.getContentHtmlTpl() + + '
    ' + + '
    ' + + '
    '; + }, + getContentHtmlTpl: function (){ + if(this.content){ + if (typeof this.content == 'string') { + return this.content; } - 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); + return this.content.renderHtml(); + }else{ + return '' } - } - - 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; + }, + _UIBase_postRender: UIBase.prototype.postRender, + postRender: function (){ - 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); - } + if (this.content instanceof UIBase) { + this.content.postRender(); + } - }); -}; - -// plugins/snapscreen.js -/** - * 截屏插件,为UEditor提供插入支持 - * @file - * @since 1.4.2 - */ -UE.plugin.register('snapscreen', function (){ + //捕获鼠标滚轮 + if( this.captureWheel && !this.captured ) { - var me = this; - var snapplugin; + this.captured = true; - function getLocation(url){ - var search, - a = document.createElement('a'), - params = utils.serializeParam(me.queryCommandValue('serverparam')) || ''; + 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; - a.href = url; - if (browser.ie) { - a.href = a.href; - } + ifr.length && ( ifr = ifr[0] ); + while( _top + _height > winHeight ) { + _height -= 30; + } + content.style.height = _height + 'px'; + //同步更改iframe高度 + ifr && ( ifr.style.height = _height + 'px' ); - search = a.search; - if (params) { - search = search + (search.indexOf('?') == -1 ? '?':'&')+ params; - search = search.replace(/[&]+/ig, '&'); - } - return { - 'port': a.port, - 'hostname': a.hostname, - 'path': a.pathname + search || + a.hash - } - } + //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解 + if( window.XMLHttpRequest ) { - 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"); + domUtils.on( content, ( 'onmousewheel' in document.body ) ? 'mousewheel' :'DOMMouseScroll' , function(e){ - 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; + if(e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; } - 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; - } + if( e.wheelDelta ) { - onSuccess(res); - }, 50); - }, - queryCommandState: function(){ - return (navigator.userAgent.indexOf("Windows",0) != -1) ? 0:-1; - } - } - } - } -}); - - -// plugins/insertparagraph.js -/** - * 插入段落 - * @file - * @since 1.2.6.1 - */ + content.scrollTop -= ( e.wheelDelta / 120 )*60; + } else { -/** - * 插入段落 - * @command insertparagraph - * @method execCommand - * @param { String } cmd 命令字符串 - * @example - * ```javascript - * //editor是编辑器实例 - * editor.execCommand( 'insertparagraph' ); - * ``` - */ + content.scrollTop -= ( e.detail / -3 )*60; -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 - */ + }); + + } else { + //ie6 + domUtils.on( this.getDom(), 'mousewheel' , function(e){ -/** - * 插入百度应用 - * @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: '百度应用的地址' - * } ); - * ``` - */ + e.returnValue = false; -//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 ) ); -// } -// }; -//}; + me.getDom('content').scrollTop -= ( e.wheelDelta / 120 )*60; -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); } - }) + } + this.fireEvent('postRenderAfter'); + this.hide(true); + this._UIBase_postRender(); }, - 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) { + _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 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; + 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'); } } - } - } -}); - -// 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); + }, + queryAutoHide: function (el){ + return !el || !uiUtils.contains(this.getDom(), el); } }; - 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; + 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); } - }, 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"]); - } + }, + _onTableOver: function (evt){ + var tgt = evt.target || evt.srcElement; + var color = tgt.getAttribute('data-color'); + if (color) { + this.getDom('preview').style.backgroundColor = color; } - } - }); -}; - - -// 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); - } - }) - + _onTableOut: function (){ + this.getDom('preview').style.backgroundColor = ''; }, - 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; - } + _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 +'
    ' + + '
    ' + + '' + + ''+ + ''; + for (var i=0; i':'')+''; } + html += i<70 ? '':''; } + html += '
    '+editor.getLang("themeColor")+'
    '+editor.getLang("standardColor")+'
    '; + return html; } -}); - -// 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 - }, - 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 () { - - 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 - * 简单上传:点击按钮,直接选择文件上传 - * @author Jinqn - * @date 2014-03-31 - */ -UE.plugin.register('simpleupload', function (){ - var me = this, - isLoaded = false, - containerBtn; - - function initUploadBtn(){ - var w = containerBtn.offsetWidth || 20, - h = containerBtn.offsetHeight || 20, - btnIframe = document.createElement('iframe'), - 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;'; - - domUtils.on(btnIframe, 'load', function(){ - - var timestrap = (+new Date()).toString(36), - wrapper, - btnIframeDoc, - btnIframeBody; - - btnIframeDoc = (btnIframe.contentDocument || btnIframe.contentWindow.document); - btnIframeBody = btnIframeDoc.body; - wrapper = btnIframeDoc.createElement('div'); - - wrapper.innerHTML = '
    ' + - '' + - '
    ' + - ''; - - wrapper.className = 'edui-' + me.options.theme; - wrapper.id = me.ui.id + '_iframeupload'; - btnIframeBody.style.cssText = btnStyle; - btnIframeBody.style.width = w + 'px'; - btnIframeBody.style.height = h + 'px'; - btnIframeBody.appendChild(wrapper); - - if (btnIframeBody.parentNode) { - btnIframeBody.parentNode.style.width = w + 'px'; - btnIframeBody.parentNode.style.height = w + 'px'; - } - - var form = btnIframeDoc.getElementById('edui_form_' + timestrap); - var input = btnIframeDoc.getElementById('edui_input_' + timestrap); - var iframe = btnIframeDoc.getElementById('edui_iframe_' + timestrap); - - domUtils.on(input, 'change', function(){ - if(!input.value) return; - var loadingId = 'loading_' + (+new Date()).toString(36); - var params = utils.serializeParam(me.queryCommandValue('serverparam')) || ''; - - var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName')); - var allowFiles = me.getOpt('imageAllowFiles'); - - me.focus(); - me.execCommand('inserthtml', ''); - - function callback(){ - try{ - var link, json, loader, - body = (iframe.contentDocument || iframe.contentWindow.document).body, - result = body.innerText || body.textContent || ''; - json = (new Function("return " + result))(); - link = me.options.imageUrlPrefix + json.url; - if(json.state == 'SUCCESS' && json.url) { - loader = me.document.getElementById(loadingId); - loader.setAttribute('src', link); - loader.setAttribute('_src', link); - loader.setAttribute('title', json.title || ''); - loader.setAttribute('alt', json.original || ''); - loader.removeAttribute('id'); - domUtils.removeClasses(loader, 'loadingclass'); - } else { - showErrorLoader && showErrorLoader(json.state); - } - }catch(er){ - showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError')); - } - form.reset(); - domUtils.un(iframe, 'load', callback); - } - 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')) { - errorHandler(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; - } - - domUtils.on(iframe, 'load', callback); - form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?':'&') + params); - form.submit(); - }); - - var stateTimer; - me.addListener('selectionchange', function () { - clearTimeout(stateTimer); - stateTimer = setTimeout(function() { - var state = me.queryCommandState('simpleupload'); - if (state == -1) { - input.disabled = 'disabled'; - } else { - input.disabled = false; - } - }, 400); - }); - isLoaded = true; - }); - - btnIframe.style.cssText = btnStyle; - containerBtn.appendChild(btnIframe); - } - - 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); - } - }); - }, - commands: { - 'simpleupload': { - queryCommandState: function () { - return isLoaded ? 0:-1; - } - } - } - } -}); - -// 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); +// 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(); }, - 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; + getHtmlTpl: function (){ + var me = this; + return '
    ' + + '
    ' + + '
    ' + + '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    '; }, - createElementByHtml: function (html){ - var el = document.createElement('div'); - el.innerHTML = html; - el = el.firstChild; - el.parentNode.removeChild(el); - return el; + _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"); }, - getViewportElement: function (){ - return (browser.ie && browser.quirks) ? - document.body : document.documentElement; + _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; }, - getClientRect: function (element){ - var bcr; - //trace IE6下在控制编辑器显隐时可能会报错,catch一下 - try{ - bcr = element.getBoundingClientRect(); - }catch(e){ - bcr={left:0,top:0,height:0,width:0} + _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 = ''; } - 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; + }, + _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'; } - 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 - }; + _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); }, - 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); - } + _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; }, - 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 - }; + Stateful_getHtmlTpl: function (){ + var tpl = this._Stateful_dGetHtmlTpl(); + // 使用function避免$转义 + return tpl.replace(/stateful/g, function (){ return TPL_STATEFUL; }); }, - 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; + Stateful_onMouseEnter: function (evt, el){ + this.target=el; + if (!this.isDisabled() || this.alwalysHoverable) { + this.addState('hover'); + this.fireEvent('over'); } - return offset; }, - setGlobal: function (id, obj){ - root[id] = obj; - return magic + '["' + id + '"]'; + Stateful_onMouseLeave: function (evt, el){ + if (!this.isDisabled() || this.alwalysHoverable) { + this.removeState('hover'); + this.removeState('active'); + this.fireEvent('out'); + } }, - unsetGlobal: function (id){ - delete root[id]; + Stateful_onMouseOver: function (evt, el){ + var rel = evt.relatedTarget; + if (!uiUtils.contains(el, rel) && el !== rel) { + this.Stateful_onMouseEnter(evt, el); + } }, - 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); - } + Stateful_onMouseOut: function (evt, el){ + var rel = evt.relatedTarget; + if (!uiUtils.contains(el, rel) && el !== rel) { + this.Stateful_onMouseLeave(evt, el); } - if (src.className) { - domUtils.addClass(tgt,src.className); + }, + Stateful_onMouseDown: function (evt, el){ + if (!this.isDisabled()) { + this.addState('active'); } - if (src.style.cssText) { - tgt.style.cssText += ';' + src.style.cssText; + }, + Stateful_onMouseUp: function (evt, el){ + if (!this.isDisabled()) { + this.removeState('active'); } }, - removeStyle: function (el, styleName){ - if (el.style.removeProperty) { - el.style.removeProperty(styleName); - } else if (el.style.removeAttribute) { - el.style.removeAttribute(styleName); - } else throw ''; + Stateful_postRender: function (){ + if (this.disabled && !this.hasState('disabled')) { + this.addState('disabled'); + } }, - contains: function (elA, elB){ - return elA && elB && (elA === elB ? false : ( - elA.contains ? elA.contains(elB) : - elA.compareDocumentPosition(elB) & 16 - )); + hasState: function (state){ + return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state); }, - 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; - } + addState: function (state){ + if (!this.hasState(state)) { + this.getStateDom().className += ' edui-state-' + state; } - 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; + }, + removeState: function (state){ + if (this.hasState(state)) { + domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state]); } - 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'; + 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'); } - return layer; }, - makeUnselectable: function (element){ - if (browser.opera || (browser.ie && browser.version < 9)) { - element.unselectable = 'on'; - if (element.hasChildNodes()) { - for (var i=0; i' + + '
    ' + + '
    ' + + (this.showIcon ? '
    ' : '') + + (this.showText ? '
    ' + this.label + '
    ' : '') + + '
    ' + + '
    ' + + '
    '; }, - getHtmlTpl:function () { - return ''; + postRender: function (){ + this.Stateful_postRender(); + this.setDisabled(this.disabled) }, - 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)); + _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; + } }, - renderHtml:function () { - return this.formatHtml(this.getHtmlTpl()); + _onClick: function (){ + if (!this.isDisabled()) { + this.fireEvent('click'); + } }, - dispose:function () { - var box = this.getDom(); - if (box) baidu.editor.dom.domUtils.remove(box); - uiUtils.unsetGlobal(this.id); + setTitle: function(text){ + var label = this.getDom('label'); + label.innerHTML = text; } }; - utils.inherits(UIBase, EventBase); + utils.inherits(Button, UIBase); + utils.extend(Button.prototype, Stateful); + })(); - - -// ui/separator.js + + +// 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, - Separator = baidu.editor.ui.Separator = function (options){ + Stateful = baidu.editor.ui.Stateful, + SplitButton = baidu.editor.ui.SplitButton = function (options){ this.initOptions(options); - this.initSeparator(); + this.initSplitButton(); }; - Separator.prototype = { - uiName: 'separator', - initSeparator: function (){ + 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 '
    '; + 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(Separator, UIBase); + utils.inherits(SplitButton, UIBase); + utils.extend(SplitButton.prototype, Stateful, true); })(); - - -// ui/mask.js + + +// 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, - 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 (){ + 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; - domUtils.on(window, 'resize', function (){ - setTimeout(function (){ - if (!me.isHidden()) { - me._fill(); + 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(); }, - 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'; + _SplitButton_postRender: SplitButton.prototype.postRender, + postRender: function (){ + this._SplitButton_postRender(); + this.getDom('button_body').appendChild( + uiUtils.createElementByHtml('
    ') + ); + this.getDom().className += ' edui-colorbutton'; }, - _onMouseDown: function (){ - return false; + setColor: function (color){ + this.getDom('colorlump').style.backgroundColor = color; + this.color = color; }, - _onClick: function (e, target){ - this.fireEvent('click', e, target); + _onPickColor: function (color){ + if (this.fireEvent('pickcolor', color) !== false) { + this.setColor(color); + this.popup.hide(); + } }, - _fill: function (){ - var el = this.getDom(); - var vpRect = uiUtils.getViewportRect(); - el.style.width = vpRect.width + 'px'; - el.style.height = vpRect.height + 'px'; + _onPickNoColor: function (color){ + if (this.fireEvent('picknocolor') !== false) { + this.popup.hide(); + } } }; - utils.inherits(Mask, UIBase); + utils.inherits(ColorButton, SplitButton); + })(); - - -// ui/popup.js + + +// ui/tablebutton.js ///import core ///import uicore -(function () { +///import ui/popup.js +///import ui/tablepicker.js +///import ui/splitbutton.js +(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){ + 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.initPopup(); + this.initTableButton(); }; - - 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/ig.test(evt.type)&&pop.className=="edui-wordpastepop") return; - pop.hide(); - } + 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); - 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 '
    ' + - '
    ' + - ' ' + - '
    ' + - '
    ' + - this.getContentHtmlTpl() + - '
    ' + - '
    ' + - '
    '; - }, - getContentHtmlTpl: function (){ - if(this.content){ - if (typeof this.content == 'string') { - return this.content; - } - return this.content.renderHtml(); - }else{ - return '' - } +// 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(); }, - _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] ); + getHtmlTpl:function () { + var me = this.editor, + opt = me.options.autotypeset, + lang = me.getLang("autoTypeSet"); - while( _top + _height > winHeight ) { - _height -= 30; - } - content.style.height = _height + 'px'; - //同步更改iframe高度 - ifr && ( ifr.style.height = _height + 'px' ); + var textAlignInputName = 'textAlignValue' + me.uid, + imageBlockInputName = 'imageBlockLineValue' + me.uid, + symbolConverInputName = 'symbolConverValue' + me.uid; - //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解 - if( window.XMLHttpRequest ) { + return '
    ' + + '
    ' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
    ' + lang.mergeLine + '' + lang.delLine + '
    ' + lang.removeFormat + '' + lang.indent + '
    ' + lang.alignment + '' + + '' + me.getLang("justifyleft") + + '' + me.getLang("justifycenter") + + '' + me.getLang("justifyright") + + '
    ' + lang.imageFloat + '' + + '' + me.getLang("default") + + '' + me.getLang("justifyleft") + + '' + me.getLang("justifycenter") + + '' + me.getLang("justifyright") + + '
    ' + lang.removeFontsize + '' + lang.removeFontFamily + '
    ' + lang.removeHtml + '
    ' + lang.pasteFilter + '
    ' + lang.symbol + '' + + '' + lang.bdc2sb + + '' + lang.tobdc + '' + + '
    ' + + '
    ' + + '
    '; - domUtils.on( content, ( 'onmousewheel' in document.body ) ? 'mousewheel' :'DOMMouseScroll' , function(e){ - if(e.preventDefault) { - e.preventDefault(); - } else { - e.returnValue = false; - } + }, + _UIBase_render:UIBase.prototype.render + }; + utils.inherits(AutoTypeSetPicker, UIBase); +})(); - if( e.wheelDelta ) { - content.scrollTop -= ( e.wheelDelta / 120 )*60; +// 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/ig.test(attrValue.tagName)){ + opt[attrName] = attrValue.value; } else { - - content.scrollTop -= ( e.detail / -3 )*60; - + 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; + } - //ie6 - domUtils.on( this.getDom(), 'mousewheel' , function(e){ + } - e.returnValue = false; + 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 : ''; + } - me.getDom('content').scrollTop -= ( e.wheelDelta / 120 )*60; + utils.extend(me.editor.options.autotypeset,opt); - }); + me.editor.setPreferences('autotypeset', opt); + } - } + AutoTypeSetButton.prototype = { + initAutoTypeSetButton: function (){ - } - 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 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]; - 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); - } + btn.onclick = function(){ + getPara(popupUI); + me.editor.execCommand('autotypeset'); + popupUI.hide() + }; - 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'; + domUtils.on(cont, 'click', function(e) { + var target = e.target || e.srcElement, + editorId = me.editor.uid; + if (target && target.tagName == 'INPUT') { - }, - 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); + // 点击图片浮动的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(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 ); - } ); + utils.inherits(AutoTypeSetButton, SplitButton); })(); - - -// ui/colorpicker.js + + +// ui/cellalignpicker.js ///import core ///import uicore -(function (){ +(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(); - }; + Popup = baidu.editor.ui.Popup, + Stateful = baidu.editor.ui.Stateful, + UIBase = baidu.editor.ui.UIBase; - 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); + /** + * 该参数将新增一个参数: 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 ]; } + }, - _onTableOver: function (evt){ - var tgt = evt.target || evt.srcElement; - var color = tgt.getAttribute('data-color'); - if (color) { - this.getDom('preview').style.backgroundColor = color; + 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'); + + tmpl.push( '
    ' ); + + tempIndex === 2 && tmpl.push(''); + } + + return '
    ' + + '
    ' + + '' + + tmpl.join('') + + '
    ' + + '
    ' + + '
    '; }, - _onTableOut: function (){ - this.getDom('preview').style.backgroundColor = ''; + getStateDom: function (){ + return this.target; }, - _onPickNoColor: function (){ - this.fireEvent('picknocolor'); - } + _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(ColorPicker, UIBase); + utils.inherits(CellAlignPicker, UIBase); + utils.extend(CellAlignPicker.prototype, Stateful,true); +})(); - 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 +'
    ' + - '
    ' + - '' + - ''+ - ''; - for (var i=0; i':'')+''; - } - html += i<70 ? '':''; - } - html += '
    '+editor.getLang("themeColor")+'
    '+editor.getLang("standardColor")+'
    '; - return html; - } -})(); - - -// ui/tablepicker.js + + +// ui/pastepicker.js ///import core ///import uicore -(function (){ +(function () { var utils = baidu.editor.utils, + Stateful = baidu.editor.ui.Stateful, uiUtils = baidu.editor.ui.uiUtils, UIBase = baidu.editor.ui.UIBase; - - var TablePicker = baidu.editor.ui.TablePicker = function (options){ + + var PastePicker = baidu.editor.ui.PastePicker = function (options) { this.initOptions(options); - this.initTablePicker(); + this.initPastePicker(); }; - TablePicker.prototype = { - defaultNumRows: 10, - defaultNumCols: 10, - maxNumRows: 20, - maxNumCols: 20, - numRows: 10, - numCols: 10, - lengthOfCellSide: 22, - initTablePicker: function (){ + PastePicker.prototype = { + initPastePicker:function () { this.initUIBase(); + this.Stateful_init(); }, - getHtmlTpl: function (){ - var me = this; - return '
    ' + - '
    ' + - '
    ' + - '' + - '
    ' + - '
    ' + - '
    ' + - '
    ' + - '
    ' + - '
    '; + getHtmlTpl:function () { + return '
    ' + + '
    ' + + '
    ' + this.editor.getLang("pasteOpt") + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '' }, - _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"); + getStateDom:function () { + return this.target; }, - _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; + format:function (param) { + this.editor.ui._isTransfer = true; + this.editor.fireEvent('pasteTransfer', param); }, - _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 = ''; + _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/ig.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") } }, - _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'; + _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) } + }, - _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); + getHtmlTpl: function (){ + var buff = []; + for (var i=0; i' + + buff.join('') + + '' + }, + postRender: function (){ + var box = this.getDom(); + for (var i=0; i
    '; }, - Stateful_getHtmlTpl: function (){ - var tpl = this._Stateful_dGetHtmlTpl(); - // 使用function避免$转义 - return tpl.replace(/stateful/g, function (){ return TPL_STATEFUL; }); + postRender:function () { }, - Stateful_onMouseEnter: function (evt, el){ - this.target=el; - if (!this.isDisabled() || this.alwalysHoverable) { - this.addState('hover'); - this.fireEvent('over'); - } + queryAutoHide:function () { + return true; + } + }; + Menu.prototype = { + items:null, + uiName:'menu', + initMenu:function () { + this.items = this.items || []; + this.initPopup(); + this.initItems(); }, - Stateful_onMouseLeave: function (evt, el){ - if (!this.isDisabled() || this.alwalysHoverable) { - this.removeState('hover'); - this.removeState('active'); - this.fireEvent('out'); + 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); + } } }, - Stateful_onMouseOver: function (evt, el){ - var rel = evt.relatedTarget; - if (!uiUtils.contains(el, rel) && el !== rel) { - this.Stateful_onMouseEnter(evt, el); - } + getSeparator:function () { + return menuSeparator; }, - Stateful_onMouseOut: function (evt, el){ - var rel = evt.relatedTarget; - if (!uiUtils.contains(el, rel) && el !== rel) { - this.Stateful_onMouseLeave(evt, el); + 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('') + '
    '); }, - Stateful_onMouseDown: function (evt, el){ - if (!this.isDisabled()) { - this.addState('active'); + _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(); }, - Stateful_onMouseUp: function (evt, el){ - if (!this.isDisabled()) { - this.removeState('active'); + 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; + } + } } }, - Stateful_postRender: function (){ - if (this.disabled && !this.hasState('disabled')) { - this.addState('disabled'); + 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 = []; }, - hasState: function (state){ - return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state); + destroy:function () { + if (this.getDom()) { + domUtils.remove(this.getDom()); + } + this.clearItems(); }, - addState: function (state){ - if (!this.hasState(state)) { - this.getStateDom().className += ' edui-state-' + state; + 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() + + '
    ' + + '
    '; }, - removeState: function (state){ - if (this.hasState(state)) { - domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state]); + 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(); }, - 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'); + 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); } }, - 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; + 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); } - 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 + '
    ' : '') + - '
    ' + - '
    ' + - '
    '; + renderLabelHtml:function () { + return '
    ' + + '
    ' + + '
    ' + (this.label || '') + '
    '; }, - postRender: function (){ - this.Stateful_postRender(); - this.setDisabled(this.disabled) + getStateDom:function () { + return this.getDom(); }, - _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; + queryAutoHide:function (el) { + if (this.subMenu && this.hasState('opened')) { + return this.subMenu.queryAutoHide(el); } }, - _onClick: function (){ - if (!this.isDisabled()) { - this.fireEvent('click'); + _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); + } } }, - setTitle: function(text){ - var label = this.getDom('label'); - label.innerHTML = text; + 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(Button, UIBase); - utils.extend(Button.prototype, Stateful); - + utils.inherits(MenuItem, UIBase); + utils.extend(MenuItem.prototype, Stateful, true); })(); - - -// ui/splitbutton.js + + +// ui/combox.js ///import core ///import uicore -///import ui/stateful.js +///import ui/menu.js +///import ui/splitbutton.js (function (){ + // todo: menu和item提成通用list 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){ + Menu = baidu.editor.ui.Menu, + SplitButton = baidu.editor.ui.SplitButton, + Combox = baidu.editor.ui.Combox = function (options){ this.initOptions(options); - this.initSplitButton(); + this.initCombox(); }; - SplitButton.prototype = { - popup: null, - uiName: 'splitbutton', - title: '', - initSplitButton: function (){ - this.initUIBase(); - this.Stateful_init(); + Combox.prototype = { + uiName: 'combox', + onbuttonclick:function () { + this.showPopup(); + }, + initCombox: function (){ var me = this; - if (this.popup != null) { - var popup = this.popup; - this.popup = null; - this.setPopup(popup); + this.items = this.items || []; + for (var i=0; i') - ); - popup.getDom().className += ' ' + this.className; - }, this)); - this.popup = popup; - }, - _onPopupShow: function (){ - this.addState('opened'); - }, - _onPopupHide: function (){ - this.removeState('opened'); - }, - getHtmlTpl: function (){ - return '
    ' + - '
    ' + - '
    ' + - '
    ' + - '
    ' + - '
    ' + - '
    ' + - '
    '; + this._SplitButton_postRender(); + this.setLabel(this.label || ''); + this.setValue(this.initValue || ''); }, showPopup: function (){ - // 当popup往上弹出的时候,做特殊处理 var rect = uiUtils.getClientRect(this.getDom()); - rect.top -= this.popup.SHADOW_RADIUS; - rect.height += this.popup.SHADOW_RADIUS; + rect.top += 1; + rect.bottom -= 1; + rect.height -= 2; this.popup.showAnchorRect(rect); }, - _onArrowClick: function (event, el){ - if (!this.isDisabled()) { - this.showPopup(); + 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.getDom().className += ' edui-colorbutton'; + 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 ); + + } ); + }, - setColor: function (color){ - this.getDom('colorlump').style.backgroundColor = color; - this.color = color; + 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(); }, - _onPickColor: function (color){ - if (this.fireEvent('pickcolor', color) !== false) { - this.setColor(color); - this.popup.hide(); + getContentHtml: function (){ + var contentHtml = ''; + if (typeof this.content == 'string') { + contentHtml = this.content; + } else if (this.iframeUrl) { + contentHtml = ''; } + return contentHtml; }, - _onPickNoColor: function (color){ - if (this.fireEvent('picknocolor') !== false) { - this.popup.hide(); + getHtmlTpl: function (){ + var footHtml = ''; + + if (this.buttons) { + var buff = []; + for (var i=0; i' + buff.join('') + '' + + ''; } - } - }; - 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 (){ + 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.popup = new Popup({ - content: new TablePicker({ - editor:me.editor, - onpicktable: function (t, numCols, numRows){ - me._onPickTable(numCols, numRows); + 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' + - '
    ' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
    ' + lang.mergeLine + '' + lang.delLine + '
    ' + lang.removeFormat + '' + lang.indent + '
    ' + lang.alignment + '' + - '' + me.getLang("justifyleft") + - '' + me.getLang("justifycenter") + - '' + me.getLang("justifyright") + - '
    ' + lang.imageFloat + '' + - '' + me.getLang("default") + - '' + me.getLang("justifyleft") + - '' + me.getLang("justifycenter") + - '' + me.getLang("justifyright") + - '
    ' + lang.removeFontsize + '' + lang.removeFontFamily + '
    ' + lang.removeHtml + '
    ' + lang.pasteFilter + '
    ' + lang.symbol + '' + - '' + lang.bdc2sb + - '' + lang.tobdc + '' + - '
    ' + - '
    ' + - ''; + //要高过编辑器的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; - }, - _UIBase_render:UIBase.prototype.render + } + 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(AutoTypeSetPicker, UIBase); + utils.inherits(Dialog, UIBase); })(); - - -// ui/autotypesetbutton.js + + +// ui/menubutton.js ///import core ///import uicore -///import ui/popup.js -///import ui/autotypesetpicker.js +///import ui/menu.js ///import ui/splitbutton.js (function (){ var utils = baidu.editor.utils, - Popup = baidu.editor.ui.Popup, - AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker, + Menu = baidu.editor.ui.Menu, SplitButton = baidu.editor.ui.SplitButton, - AutoTypeSetButton = baidu.editor.ui.AutoTypeSetButton = function (options){ + MenuButton = baidu.editor.ui.MenuButton = function (options){ this.initOptions(options); - this.initAutoTypeSetButton(); + this.initMenuButton(); }; - 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/ig.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 (){ - + MenuButton.prototype = { + initMenuButton: 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'); - } - } + this.uiName = "menubutton"; + this.popup = new Menu({ + items: me.items, + className: me.className, + editor:me.editor }); - 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); + this.popup.addListener('show', function (){ + var list = this; + for (var i=0; i'); - - tmpl.push( '
    ' ); - - tempIndex === 2 && tmpl.push(''); - - } - - return '
    ' + - '
    ' + - '' + - tmpl.join('') + - '
    ' + - '
    ' + - '
    '; - }, - 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/ig.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 (){ + +// ui/multiMenu.js +///import core +///import uicore + ///commands 表情 +(function(){ var utils = baidu.editor.utils, - uiUtils = baidu.editor.ui.uiUtils, - UIBase = baidu.editor.ui.UIBase, - Toolbar = baidu.editor.ui.Toolbar = function (options){ + Popup = baidu.editor.ui.Popup, + SplitButton = baidu.editor.ui.SplitButton, + MultiMenuPop = baidu.editor.ui.MultiMenuPop = function(options){ this.initOptions(options); - this.initToolbar(); + this.initMultiMenu(); }; - 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' + - buff.join('') + - '' - }, - postRender: function (){ - var box = this.getDom(); - for (var i=0; i'; + 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(Toolbar, UIBase); + utils.inherits(MultiMenuPop, SplitButton); })(); - - -// ui/menu.js -///import core -///import uicore -///import ui\popup.js -///import ui\stateful.js + + +// ui/shortcutmenu.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, + var UI = baidu.editor.ui, + UIBase = UI.UIBase, + uiUtils = UI.uiUtils, + utils = baidu.editor.utils, + domUtils = baidu.editor.dom.domUtils; - Menu = baidu.editor.ui.Menu = function (options) { - this.initOptions(options); - this.initMenu(); - }; + var allMenus = [],//存储所有快捷菜单 + timeID, + isSubMenuShow = false;//是否有子pop显示 - var menuSeparator = { - renderHtml:function () { - return '
    '; - }, - postRender:function () { - }, - queryAutoHide:function () { - return true; - } + var ShortCutMenu = UI.ShortCutMenu = function (options) { + this.initOptions (options); + this.initShortCutMenu (); }; - Menu.prototype = { - items:null, - uiName:'menu', - initMenu:function () { + + ShortCutMenu.postHide = hideAllMenu; + + ShortCutMenu.prototype = { + isHidden : true , + SPACE : 5 , + initShortCutMenu : 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.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 (); + } + }); } }); - 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; + + //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 (); } - } - } - }, - 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; + me.editor.addListener ("afterhidepop" , function () { + if (!me.isHidden) { + isSubMenuShow = true; + } + }); - //获取单元格对齐初始状态 - this.subMenu.selected = this.editor.queryCommandValue( 'cellalignment' ); + } , + initItems : function () { + if (utils.isArray (this.items)) { + for (var i = 0, len = this.items.length ; i < len ; i++) { + var item = this.items[i].toLowerCase (); - this.subMenu = new Popup({ - content:new CellAlignPicker(this.subMenu), - parentMenu:me, - editor:me.editor, - destroy:function () { - if (this.getDom()) { - domUtils.remove(this.getDom()); - } + if (UI[item]) { + this.items[i] = new UI[item] (this.editor); + this.items[i].className += " edui-shortcutsubmenu "; } - }); - this.subMenu.addListener("postRenderAfter", function () { - domUtils.on(this.getDom(), "mouseover", function () { - me.addState('opened'); - }); - }); + } + } + } , + setOpacity : function (el , value) { + if (browser.ie && browser.version < 9) { + el.style.filter = "alpha(opacity = " + parseFloat (value) * 100 + ");" } else { - this.subMenu = new Menu(this.subMenu); + 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; + } } - } - }; - 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(); + 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 (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); - }; + if (offset.top < 0) { + offset.top = 0; + } + el.style.cssText = "position:absolute;left:" + offset.left + "px;top:" + offset.top + "px;"; } - 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); + + 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); } - }, - 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); + + + 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); } - }, - renderLabelHtml:function () { - return '
    ' + - '
    ' + - '
    ' + (this.label || '') + '
    '; - }, - getStateDom:function () { - return this.getDom(); - }, - queryAutoHide:function (el) { - if (this.subMenu && this.hasState('opened')) { - return this.subMenu.queryAutoHide(el); + + + 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; } - }, - _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); + } , + 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(); }, - 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(); + getHtmlTpl: function (){ + return '
    '; } }; - utils.inherits(MenuItem, UIBase); - utils.extend(MenuItem.prototype, Stateful, true); + utils.inherits(Breakline, UIBase); + })(); - - -// ui/combox.js + + +// ui/message.js ///import core ///import uicore -///import ui/menu.js -///import ui/splitbutton.js -(function (){ - // todo: menu和item提成通用list +(function () { 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){ + domUtils = baidu.editor.dom.domUtils, + UIBase = baidu.editor.ui.UIBase, + Message = baidu.editor.ui.Message = function (options){ this.initOptions(options); - this.initCombox(); + this.initMessage(); }; - Combox.prototype = { - uiName: 'combox', - onbuttonclick:function () { - this.showPopup(); + + Message.prototype = { + initMessage: function (){ + this.initUIBase(); }, - initCombox: function (){ + getHtmlTpl: function (){ + return '
    ' + + '
    ×
    ' + + '
    ' + + ' ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    '; + }, + reset: function(opt){ var me = this; - this.items = this.items || []; - for (var i=0; i' + (this.label || '') + ''; } }); + }); - this.fullscreen && this.initResizeEvent(); + 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; + } + } - if (this.buttons) { - for (var i=0; i' + (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; + } + } - domUtils.on( window, "resize", function () { + 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); - if ( me._hidden || me._hidden === undefined ) { - return; } + } - if ( me.__resizeTimer ) { - window.clearTimeout( me.__resizeTimer ); - } + }); + return ui; + }; - me.__resizeTimer = window.setTimeout( function () { + 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')); + } + } - me.__resizeTimer = null; + }); + return ui; + }; - var dialogWrapNode = me.getDom(), - contentNode = me.getDom('content'), - wrapRect = UE.ui.uiUtils.getClientRect( dialogWrapNode ), - contentRect = UE.ui.uiUtils.getClientRect( contentNode ), - vpRect = uiUtils.getViewportRect(); + 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); + } + } + } - contentNode.style.width = ( vpRect.width - wrapRect.width + contentRect.width ) + "px"; - contentNode.style.height = ( vpRect.height - wrapRect.height + contentRect.height ) + "px"; + }); + return ui; + }; - dialogWrapNode.style.width = vpRect.width + "px"; - dialogWrapNode.style.height = vpRect.height + "px"; - me.fireEvent( "resize" ); + //自定义标题 + 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); + } - }, 100 ); + 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; + }; - }, - 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; + 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); } - var top = offset.top; - if (top + rect.height > vpRect.bottom) { - top = vpRect.bottom - rect.height; + }); + 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) } - el.style.left = Math.max(left, 0) + 'px'; - el.style.top = Math.max(top, 0) + 'px'; - }, - showAtCenter: function (){ - - var vpRect = uiUtils.getViewportRect(); + }); + return ui; + }; - 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) + 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); + } }); - if (!domUtils.hasClass(popEl, 'edui-state-centered')) { - popEl.className += ' edui-state-centered'; + 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 { - var dialogWrapNode = this.getDom(), - contentNode = this.getDom('content'); + if (!uiReady) { + ui.setDisabled(false); + ui.setChecked(state); + } + } + }); + return ui; + }; - dialogWrapNode.style.display = "block"; +})(); + + +// 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 = []; - var wrapRect = UE.ui.uiUtils.getClientRect( dialogWrapNode ), - contentRect = UE.ui.uiUtils.getClientRect( contentNode ); - dialogWrapNode.style.left = "-100000px"; + function EditorUI(options) { + this.initOptions(options); + this.initEditorUI(); + } - contentNode.style.width = ( vpRect.width - wrapRect.width + contentRect.width ) + "px"; - contentNode.style.height = ( vpRect.height - wrapRect.height + contentRect.height ) + "px"; + 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; - dialogWrapNode.style.width = vpRect.width + "px"; - dialogWrapNode.style.height = vpRect.height + "px"; - dialogWrapNode.style.left = 0; + UE.browser.ie && UE.browser.version === 6 && editor.container.ownerDocument.execCommand("BackgroundImageCache", false, true); - //保存环境的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 + //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"; + } - document.documentElement.style.overflowX = 'hidden'; - document.documentElement.style.overflowY = 'hidden'; - document.body.style.overflowX = 'hidden'; - document.body.style.overflowY = 'hidden'; + if (!editor.selection.isFocus())return; + editor.fireEvent('selectionchange', false, true); - } - 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' + buff.join('') + '' + - ''; - } + editor.getDialog('edittip').open(); + }); - 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); + 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; }); - this.addListener('hide', function (){ - me.modalMask.hide(); + + 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) }); - if (this.buttons) { - for (var i=0; i max) { + countDom.innerHTML = errMsg; + editor.fireEvent("wordcountoverflow"); + } else { + countDom.innerHTML = msg.replace("{#leave}", max - count).replace("{#count}", count); } } - domUtils.on(window, 'resize', function (){ - setTimeout(function (){ - if (!me.isHidden()) { - me.safeSetOffset(uiUtils.getClientRect(me.getDom())); + + 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/ig.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); + } + } - //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(); + 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(UE._customizeUI,function(obj,key){ + var itemUI,index; + if(obj.id && obj.id != editor.key){ + return true; + } + 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; }, - reset: function (){ - this.getDom('content').innerHTML = this.getContentHtml(); - this.fireEvent('dialogafterreset'); + getHtmlTpl:function () { + return '
    ' + + '
    ' + + (this.toolbars.length ? + '
    ' + + this.renderToolbarBoxHtml() + + '
    ' : '') + + '' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + //modify wdcount by matao + '
    ' + + '' + + '' + + '' + + '
    ' + + '
    ' + + '
    '; }, - _show: function (){ - if (this._hidden) { - this.getDom().style.display = ''; + 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(); + } - //要高过编辑器的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'); + _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){ + + } + + } } }, - open: function (){ - if (this.autoReset) { - //有可能还没有渲染 - try{ - this.reset(); - }catch(e){ - this.render(); - this.open() + _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' } - this.showAtCenter(); - if (this.iframeUrl) { - try { - this.getDom('iframe').focus(); - } catch(ex){} - } - activeDialog = this; }, - _onCloseButtonClick: function (evt, el){ - this.close(false); + disableElementPath:function () { + var bottom = this.getDom('elementpath'); + bottom.innerHTML = ''; + bottom.style.display = 'none'; + this.elementPathEnabled = false; + }, - close: function (ok){ - if (this.fireEvent('close', ok) !== false) { - //还原环境 - if ( this.fullscreen ) { + 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"); - 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; + var isMouseMove = false, + position = null, + minEditorHeight = 0, + minEditorWidth = editor.options.minFrameWidth, + pageX = 0, + pageY = 0, + scaleWidth = 0, + scaleHeight = 0; - } - this._hide(); + function down() { + position = domUtils.getXY(editorHolder); - //销毁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); + 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); } - } - }; - 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= 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); + }; }, - setValue : function(value){ - this._value = value; + 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(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(); - }; + utils.inherits(EditorUI, baidu.editor.ui.UIBase); - 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); + + 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/ig.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 { + if (holder) { + 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 && 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"); } - // canSideUp:false, - // canSideLeft:false - }); - this.onbuttonclick = function(){ - this.showPopup(); - }; - this.initSplitButton(); + }) + }; + 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] + } }; - utils.inherits(MultiMenuPop, SplitButton); + 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(); + 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(){ + if (me.ui) { + var toolbarbox = me.ui.getDom('toolbarbox'); + if (toolbarbox) { + holder.style.top = toolbarbox.offsetHeight + 3 + 'px'; + } + } + if (me.options) { + 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) + }) + +}); + + + })(); - - -// 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/ig.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(UE._customizeUI,function(obj,key){ - var itemUI,index; - if(obj.id && obj.id != editor.key){ - return true; - } - 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 '
    ' + - '
    ' + - (this.toolbars.length ? - '
    ' + - this.renderToolbarBoxHtml() + - '
    ' : '') + - '' + - '
    ' + - '
    ' + - '
    ' + - '
    ' + - //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/ig.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 { - if (holder) { - 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 && 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(); - 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(){ - if (me.ui) { - var toolbarbox = me.ui.getDom('toolbarbox'); - if (toolbarbox) { - holder.style.top = toolbarbox.offsetHeight + 3 + 'px'; - } - } - if (me.options) { - 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) - }) - -}); - - - -})();