(function () { UEDITOR_CONFIG = window.UEDITOR_CONFIG || {}; MY_UEDITOR_CONFIG = window.MY_UEDITOR_CONFIG || {}; var baidu = window.baidu || {}; window.baidu = baidu; window.UE = baidu.editor = {}; UE.plugins = {}; UE.commands = {}; UE.instants = {}; UE.I18N = {}; UE.version = "1.2.5.0"; var dom = UE.dom = {}; /** * @file * @name UE.browser * @short Browser * @desc UEditor中采用的浏览器判断模块 */ var browser = UE.browser = function () { var agent = navigator.userAgent.toLowerCase(), opera = window.opera, browser = { /** * 检测浏览器是否为IE * @name ie * @grammar UE.browser.ie => true|false */ ie: !!window.ActiveXObject, /** * 检测浏览器是否为Opera * @name opera * @grammar UE.browser.opera => true|false */ opera: ( !!opera && opera.version ), /** * 检测浏览器是否为webkit内核 * @name webkit * @grammar UE.browser.webkit => true|false */ webkit: ( agent.indexOf(' applewebkit/') > -1 ), /** * 检测浏览器是否为mac系统下的浏览器 * @name mac * @grammar UE.browser.mac => true|false */ mac: ( agent.indexOf('macintosh') > -1 ), /** * 检测浏览器是否处于怪异模式 * @name quirks * @grammar UE.browser.quirks => true|false */ quirks: ( document.compatMode == 'BackCompat' ) }; /** * 检测浏览器是否处为gecko内核 * @name gecko * @grammar UE.browser.gecko => true|false */ browser.gecko = ( navigator.product == 'Gecko' && !browser.webkit && !browser.opera ); var version = 0; // Internet Explorer 6.0+ if (browser.ie) { version = parseFloat(agent.match(/msie (\d+)/)[1]); /** * 检测浏览器是否为 IE9 模式 * @name ie9Compat * @grammar UE.browser.ie9Compat => true|false */ browser.ie9Compat = document.documentMode == 9; /** * 检测浏览器是否为 IE8 浏览器 * @name ie8 * @grammar UE.browser.ie8 => true|false */ browser.ie8 = !!document.documentMode; /** * 检测浏览器是否为 IE8 模式 * @name ie8Compat * @grammar UE.browser.ie8Compat => true|false */ browser.ie8Compat = document.documentMode == 8; /** * 检测浏览器是否运行在 兼容IE7模式 * @name ie7Compat * @grammar UE.browser.ie7Compat => true|false */ browser.ie7Compat = ( ( version == 7 && !document.documentMode ) || document.documentMode == 7 ); /** * 检测浏览器是否IE6模式或怪异模式 * @name ie6Compat * @grammar UE.browser.ie6Compat => true|false */ browser.ie6Compat = ( version < 7 || browser.quirks ); } // Gecko. if (browser.gecko) { var geckoRelease = agent.match(/rv:([\d\.]+)/); if (geckoRelease) { geckoRelease = geckoRelease[1].split('.'); version = geckoRelease[0] * 10000 + ( geckoRelease[1] || 0 ) * 100 + ( geckoRelease[2] || 0 ) * 1; } } /** * 检测浏览器是否为chrome * @name chrome * @grammar UE.browser.chrome => true|false */ if (/chrome\/(\d+\.\d)/i.test(agent)) { browser.chrome = +RegExp['\x241']; } /** * 检测浏览器是否为safari * @name safari * @grammar UE.browser.safari => true|false */ if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)) { browser.safari = +(RegExp['\x241'] || RegExp['\x242']); } // Opera 9.50+ if (browser.opera) version = parseFloat(opera.version()); // WebKit 522+ (Safari 3+) if (browser.webkit) version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]); /** * 浏览器版本判断 * IE系列返回值为5,6,7,8,9,10等 * gecko系列会返回10900,158900等. * webkit系列会返回其build号 (如 522等). * @name version * @grammar UE.browser.version => number * @example * if ( UE.browser.ie && UE.browser.version == 6 ){ * alert( "Ouch!居然是万恶的IE6!" ); * } */ browser.version = version; /** * 是否是兼容模式的浏览器 * @name isCompatible * @grammar UE.browser.isCompatible => true|false * @example * if ( UE.browser.isCompatible ){ * alert( "你的浏览器相当不错哦!" ); * } */ browser.isCompatible = !browser.mobile && ( ( browser.ie && version >= 6 ) || ( browser.gecko && version >= 10801 ) || ( browser.opera && version >= 9.5 ) || ( browser.air && version >= 1 ) || ( browser.webkit && version >= 522 ) || false ); return browser; }(); //快捷方式 var ie = browser.ie, webkit = browser.webkit, gecko = browser.gecko, opera = browser.opera; /** * @file * @name UE.Utils * @short Utils * @desc UEditor封装使用的静态工具函数 * @import editor.js */ var utils = UE.utils = { /** * 遍历数组,对象,nodeList * @name each * @grammar UE.utils.each(obj,iterator,[context]) * @since 1.2.4+ * @desc * * obj 要遍历的对象 * * iterator 遍历的方法,方法的第一个是遍历的值,第二个是索引,第三个是obj * * context iterator的上下文 * @example * UE.utils.each([1,2],function(v,i){ * console.log(v)//值 * console.log(i)//索引 * }) * UE.utils.each(document.getElementsByTagName('*'),function(n){ * console.log(n.tagName) * }) */ each: function (obj, iterator, context) { if (obj == null) return; if (obj.length === +obj.length) { for (var i = 0, l = obj.length; i < l; i++) { if (iterator.call(context, obj[i], i, obj) === false) return false; } } else { for (var key in obj) { if (obj.hasOwnProperty(key)) { if (iterator.call(context, obj[key], key, obj) === false) return false; } } } }, makeInstance: function (obj) { var noop = new Function(); noop.prototype = obj; obj = new noop; noop.prototype = null; return obj; }, /** * 将source对象中的属性扩展到target对象上 * @name extend * @grammar UE.utils.extend(target,source) => Object //覆盖扩展 * @grammar UE.utils.extend(target,source,true) ==> Object //保留扩展 */ extend: function (t, s, b) { if (s) { for (var k in s) { if (!b || !t.hasOwnProperty(k)) { t[k] = s[k]; } } } return t; }, /** * 模拟继承机制,subClass继承superClass * @name inherits * @grammar UE.utils.inherits(subClass,superClass) => subClass * @example * function SuperClass(){ * this.name = "小李"; * } * SuperClass.prototype = { * hello:function(str){ * console.log(this.name + str); * } * } * function SubClass(){ * this.name = "小张"; * } * UE.utils.inherits(SubClass,SuperClass); * var sub = new SubClass(); * sub.hello("早上好!"); ==> "小张早上好!" */ inherits: function (subClass, superClass) { var oldP = subClass.prototype, newP = utils.makeInstance(superClass.prototype); utils.extend(newP, oldP, true); subClass.prototype = newP; return (newP.constructor = subClass); }, /** * 用指定的context作为fn上下文,也就是this * @name bind * @grammar UE.utils.bind(fn,context) => fn */ bind: function (fn, context) { return function () { return fn.apply(context, arguments); }; }, /** * 创建延迟delay执行的函数fn * @name defer * @grammar UE.utils.defer(fn,delay) =>fn //延迟delay毫秒执行fn,返回fn * @grammar UE.utils.defer(fn,delay,exclusion) =>fn //延迟delay毫秒执行fn,若exclusion为真,则互斥执行fn * @example * function test(){ * console.log("延迟输出!"); * } * //非互斥延迟执行 * var testDefer = UE.utils.defer(test,1000); * testDefer(); => "延迟输出!"; * testDefer(); => "延迟输出!"; * //互斥延迟执行 * var testDefer1 = UE.utils.defer(test,1000,true); * testDefer1(); => //本次不执行 * testDefer1(); => "延迟输出!"; */ defer: function (fn, delay, exclusion) { var timerID; return function () { if (exclusion) { clearTimeout(timerID); } timerID = setTimeout(fn, delay); }; }, /** * 查找元素item在数组array中的索引, 若找不到返回-1 * @name indexOf * @grammar UE.utils.indexOf(array,item) => index|-1 //默认从数组开头部开始搜索 * @grammar UE.utils.indexOf(array,item,start) => index|-1 //start指定开始查找的位置 */ indexOf: function (array, item, start) { var index = -1; start = this.isNumber(start) ? start : 0; this.each(array, function (v, i) { if (i >= start && v === item) { index = i; return false; } }); return index; }, /** * 移除数组array中的元素item * @name removeItem * @grammar UE.utils.removeItem(array,item) */ removeItem: function (array, item) { for (var i = 0, l = array.length; i < l; i++) { if (array[i] === item) { array.splice(i, 1); i--; } } }, /** * 删除字符串str的首尾空格 * @name trim * @grammar UE.utils.trim(str) => String */ trim: function (str) { return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, ''); }, /** * 将字符串list(以','分隔)或者数组list转成哈希对象 * @name listToMap * @grammar UE.utils.listToMap(list) => Object //Object形如{test:1,br:1,textarea:1} */ listToMap: function (list) { if (!list)return {}; list = utils.isArray(list) ? list : list.split(','); for (var i = 0, ci, obj = {}; ci = list[i++];) { obj[ci.toUpperCase()] = obj[ci] = 1; } return obj; }, /** * 将str中的html符号转义,默认将转义''&<">''四个字符,可自定义reg来确定需要转义的字符 * @name unhtml * @grammar UE.utils.unhtml(str); => String * @grammar UE.utils.unhtml(str,reg) => String * @example * var html = 'You say:"你好!Baidu & UEditor!"'; * UE.utils.unhtml(html); ==> <body>You say:"你好!Baidu & UEditor!"</body> * UE.utils.unhtml(html,/[<>]/g) ==> <body>You say:"你好!Baidu & UEditor!"</body> */ unhtml: function (str, reg) { return str ? str.replace(reg || /[&<">]/g, function (m) { return { '<': '<', '&': '&', '"': '"', '>': '>' }[m] }) : ''; }, /** * 将str中的转义字符还原成html字符 * @name html * @grammar UE.utils.html(str) => String //详细参见unhtml */ html: function (str) { return str ? str.replace(/&((g|l|quo)t|amp);/g, function (m) { return { '<': '<', '&': '&', '"': '"', '>': '>' }[m] }) : ''; }, /** * 将css样式转换为驼峰的形式。如font-size => fontSize * @name cssStyleToDomStyle * @grammar UE.utils.cssStyleToDomStyle(cssName) => String */ cssStyleToDomStyle: function () { var test = document.createElement('div').style, cache = { 'float': test.cssFloat != undefined ? 'cssFloat' : test.styleFloat != undefined ? 'styleFloat' : 'float' }; return function (cssName) { return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g, function (match) { return match.charAt(1).toUpperCase(); })); }; }(), /** * 动态加载文件到doc中,并依据obj来设置属性,加载成功后执行回调函数fn * @name loadFile * @grammar UE.utils.loadFile(doc,obj) * @grammar UE.utils.loadFile(doc,obj,fn) * @example * //指定加载到当前document中一个script文件,加载成功后执行function * utils.loadFile( document, { * src:"test.js", * tag:"script", * type:"text/javascript", * defer:"defer" * }, function () { * console.log('加载成功!') * }); */ loadFile: function () { var tmpList = []; function getItem(doc, obj) { try { for (var i = 0, ci; ci = tmpList[i++];) { if (ci.doc === doc && ci.url == (obj.src || obj.href)) { return ci; } } } catch (e) { return null; } } return function (doc, obj, fn) { var item = getItem(doc, obj); if (item) { if (item.ready) { fn && fn(); } else { item.funs.push(fn) } return; } tmpList.push({ doc: doc, url: obj.src || obj.href, funs: [fn] }); if (!doc.body) { var html = []; for (var p in obj) { if (p == 'tag')continue; html.push(p + '="' + obj[p] + '"') } doc.write('<' + obj.tag + ' ' + html.join(' ') + ' >'); return; } if (obj.id && doc.getElementById(obj.id)) { return; } var element = doc.createElement(obj.tag); delete obj.tag; for (var p in obj) { element.setAttribute(p, obj[p]); } element.onload = element.onreadystatechange = function () { if (!this.readyState || /loaded|complete/.test(this.readyState)) { item = getItem(doc, obj); if (item.funs.length > 0) { item.ready = 1; for (var fi; fi = item.funs.pop();) { fi(); } } element.onload = element.onreadystatechange = null; } }; element.onerror = function () { throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file editor_config.js ') }; doc.getElementsByTagName("head")[0].appendChild(element); } }(), /** * 判断obj对象是否为空 * @name isEmptyObject * @grammar UE.utils.isEmptyObject(obj) => true|false * @example * UE.utils.isEmptyObject({}) ==>true * UE.utils.isEmptyObject([]) ==>true * UE.utils.isEmptyObject("") ==>true */ isEmptyObject: function (obj) { if (obj == null) return true; if (this.isArray(obj) || this.isString(obj)) return obj.length === 0; for (var key in obj) if (obj.hasOwnProperty(key)) return false; return true; }, /** * 统一将颜色值使用16进制形式表示 * @name fixColor * @grammar UE.utils.fixColor(name,value) => value * @example * rgb(255,255,255) => "#ffffff" */ fixColor: function (name, value) { if (/color/i.test(name) && /rgba?/.test(value)) { var array = value.split(","); if (array.length > 3) return ""; value = "#"; for (var i = 0, color; color = array[i++];) { color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16); value += color.length == 1 ? "0" + color : color; } value = value.toUpperCase(); } return value; }, /** * 只针对border,padding,margin做了处理,因为性能问题 * @public * @function * @param {String} val style字符串 */ optCss: function (val) { var padding, margin, border; val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi, function (str, key, name, val) { if (val.split(' ').length == 1) { switch (key) { case 'padding': !padding && (padding = {}); padding[name] = val; return ''; case 'margin': !margin && (margin = {}); margin[name] = val; return ''; case 'border': return val == 'initial' ? '' : str; } } return str; }); function opt(obj, name) { if (!obj) { return ''; } var t = obj.top , b = obj.bottom, l = obj.left, r = obj.right, val = ''; if (!t || !l || !b || !r) { for (var p in obj) { val += ';' + name + '-' + p + ':' + obj[p] + ';'; } } else { val += ';' + name + ':' + (t == b && b == l && l == r ? t : t == b && l == r ? (t + ' ' + l) : l == r ? (t + ' ' + l + ' ' + b) : (t + ' ' + r + ' ' + b + ' ' + l)) + ';' } return val; } val += opt(padding, 'padding') + opt(margin, 'margin'); return val.replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, '').replace(/;([ \n\r\t]+)|\1;/g, ';') .replace(/(&((l|g)t|quot|#39))?;{2,}/g, function (a, b) { return b ? b + ";;" : ';' }); }, /** * 深度克隆对象,从source到target * @name clone * @grammar UE.utils.clone(source) => anthorObj 新的对象是完整的source的副本 * @grammar UE.utils.clone(source,target) => target包含了source的所有内容,重名会覆盖 */ clone: function (source, target) { var tmp; target = target || {}; for (var i in source) { if (source.hasOwnProperty(i)) { tmp = source[i]; if (typeof tmp == 'object') { target[i] = utils.isArray(tmp) ? [] : {}; utils.clone(source[i], target[i]) } else { target[i] = tmp; } } } return target; }, /** * 转换cm/pt到px * @name transUnitToPx * @grammar UE.utils.transUnitToPx('20pt') => '27px' * @grammar UE.utils.transUnitToPx('0pt') => '0' */ transUnitToPx: function (val) { if (!/(pt|cm)/.test(val)) { return val } var unit; val.replace(/([\d.]+)(\w+)/, function (str, v, u) { val = v; unit = u; }); switch (unit) { case 'cm': val = parseFloat(val) * 25; break; case 'pt': val = Math.round(parseFloat(val) * 96 / 72); } return val + (val ? 'px' : ''); }, /** * DomReady方法,回调函数将在dom树ready完成后执行 * @name domReady * @grammar UE.utils.domReady(fn) => fn //返回一个延迟执行的方法 */ domReady: function () { var fnArr = []; function doReady(doc) { //确保onready只执行一次 doc.isReady = true; for (var ci; ci = fnArr.pop(); ci()) { } } return function (onready, win) { win = win || window; var doc = win.document; onready && fnArr.push(onready); if (doc.readyState === "complete") { doReady(doc); } else { doc.isReady && doReady(doc); if (browser.ie) { (function () { if (doc.isReady) return; try { doc.documentElement.doScroll("left"); } catch (error) { setTimeout(arguments.callee, 0); return; } doReady(doc); })(); win.attachEvent('onload', function () { doReady(doc) }); } else { doc.addEventListener("DOMContentLoaded", function () { doc.removeEventListener("DOMContentLoaded", arguments.callee, false); doReady(doc); }, false); win.addEventListener('load', function () { doReady(doc) }, false); } } } }(), /** * 动态添加css样式 * @name cssRule * @grammar UE.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上']) * @grammar UE.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色 * @grammar UE.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc} * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色 */ cssRule: browser.ie ? function (key, style, doc) { var indexList, index; doc = doc || document; if (doc.indexList) { indexList = doc.indexList; } else { indexList = doc.indexList = {}; } var sheetStyle; if (!indexList[key]) { if (style === undefined) { return '' } sheetStyle = doc.createStyleSheet('', index = doc.styleSheets.length); indexList[key] = index; } else { sheetStyle = doc.styleSheets[indexList[key]]; } if (style === undefined) { return sheetStyle.cssText } sheetStyle.cssText = style || '' } : function (key, style, doc) { doc = doc || document; var head = doc.getElementsByTagName('head')[0], node; if (!(node = doc.getElementById(key))) { if (style === undefined) { return '' } node = doc.createElement('style'); node.id = key; head.appendChild(node) } if (style === undefined) { return node.innerHTML } if (style !== '') { node.innerHTML = style; } else { head.removeChild(node) } } }; /** * 判断str是否为字符串 * @name isString * @grammar UE.utils.isString(str) => true|false */ /** * 判断array是否为数组 * @name isArray * @grammar UE.utils.isArray(obj) => true|false */ /** * 判断obj对象是否为方法 * @name isFunction * @grammar UE.utils.isFunction(obj) => true|false */ /** * 判断obj对象是否为数字 * @name isNumber * @grammar UE.utils.isNumber(obj) => true|false */ utils.each(['String', 'Function', 'Array', 'Number', 'RegExp'], function (v) { UE.utils['is' + v] = function (obj) { return Object.prototype.toString.apply(obj) == '[object ' + v + ']'; } }); /** * @file * @name UE.EventBase * @short EventBase * @import editor.js,core/utils.js * @desc UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。 * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。 */ var EventBase = UE.EventBase = function () { }; EventBase.prototype = { /** * 注册事件监听器 * @name addListener * @grammar editor.addListener(types,fn) //types为事件名称,多个可用空格分隔 * @example * editor.addListener('selectionchange',function(){ * console.log("选区已经变化!"); * }) * editor.addListener('beforegetcontent aftergetcontent',function(type){ * if(type == 'beforegetcontent'){ * //do something * }else{ * //do something * } * console.log(this.getContent) // this是注册的事件的编辑器实例 * }) */ addListener: function (types, listener) { types = utils.trim(types).split(' '); for (var i = 0, ti; ti = types[i++];) { getListener(this, ti, true).push(listener); } }, /** * 移除事件监听器 * @name removeListener * @grammar editor.removeListener(types,fn) //types为事件名称,多个可用空格分隔 * @example * //changeCallback为方法体 * editor.removeListener("selectionchange",changeCallback); */ removeListener: function (types, listener) { types = utils.trim(types).split(' '); for (var i = 0, ti; ti = types[i++];) { utils.removeItem(getListener(this, ti) || [], listener); } }, /** * 触发事件 * @name fireEvent * @grammar editor.fireEvent(types) //types为事件名称,多个可用空格分隔 * @example * editor.fireEvent("selectionchange"); */ fireEvent: function (types) { types = utils.trim(types).split(' '); for (var i = 0, ti; ti = types[i++];) { var listeners = getListener(this, ti), r, t, k; if (listeners) { k = listeners.length; while (k--) { if (!listeners[k])continue; t = listeners[k].apply(this, arguments); if (t === true) { return t; } if (t !== undefined) { r = t; } } } if (t = this['on' + ti.toLowerCase()]) { r = t.apply(this, arguments); } } return r; } }; /** * 获得对象所拥有监听类型的所有监听器 * @public * @function * @param {Object} obj 查询监听器的对象 * @param {String} type 事件类型 * @param {Boolean} force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组 * @returns {Array} 监听器数组 */ function getListener(obj, type, force) { var allListeners; type = type.toLowerCase(); return ( ( allListeners = ( obj.__allListeners || force && ( obj.__allListeners = {} ) ) ) && ( allListeners[type] || force && ( allListeners[type] = [] ) ) ); } ///import editor.js ///import core/dom/dom.js /** * dtd html语义化的体现类 * @constructor * @namespace dtd */ var dtd = dom.dtd = (function () { function _(s) { for (var k in s) { s[k.toUpperCase()] = s[k]; } return s; } function X(t) { var a = arguments; for (var i = 1; i < a.length; i++) { var x = a[i]; for (var k in x) { if (!t.hasOwnProperty(k)) { t[k] = x[k]; } } } return t; } var A = _({isindex: 1, fieldset: 1}), B = _({input: 1, button: 1, select: 1, textarea: 1, label: 1}), C = X(_({a: 1}), B), D = X({iframe: 1}, C), E = _({hr: 1, ul: 1, menu: 1, div: 1, blockquote: 1, noscript: 1, table: 1, center: 1, address: 1, dir: 1, pre: 1, h5: 1, dl: 1, h4: 1, noframes: 1, h6: 1, ol: 1, h1: 1, h3: 1, h2: 1}), F = _({ins: 1, del: 1, script: 1, style: 1}), G = X(_({b: 1, acronym: 1, bdo: 1, 'var': 1, '#': 1, abbr: 1, code: 1, br: 1, i: 1, cite: 1, kbd: 1, u: 1, strike: 1, s: 1, tt: 1, strong: 1, q: 1, samp: 1, em: 1, dfn: 1, span: 1}), F), H = X(_({sub: 1, img: 1, embed: 1, object: 1, sup: 1, basefont: 1, map: 1, applet: 1, font: 1, big: 1, small: 1}), G), I = X(_({p: 1}), H), J = X(_({iframe: 1}), H, B), K = _({img: 1, embed: 1, noscript: 1, br: 1, kbd: 1, center: 1, button: 1, basefont: 1, h5: 1, h4: 1, samp: 1, h6: 1, ol: 1, h1: 1, h3: 1, h2: 1, form: 1, font: 1, '#': 1, select: 1, menu: 1, ins: 1, abbr: 1, label: 1, code: 1, table: 1, script: 1, cite: 1, input: 1, iframe: 1, strong: 1, textarea: 1, noframes: 1, big: 1, small: 1, span: 1, hr: 1, sub: 1, bdo: 1, 'var': 1, div: 1, object: 1, sup: 1, strike: 1, dir: 1, map: 1, dl: 1, applet: 1, del: 1, isindex: 1, fieldset: 1, ul: 1, b: 1, acronym: 1, a: 1, blockquote: 1, i: 1, u: 1, s: 1, tt: 1, address: 1, q: 1, pre: 1, p: 1, em: 1, dfn: 1}), L = X(_({a: 0}), J),//a不能被切开,所以把他 M = _({tr: 1}), N = _({'#': 1}), O = X(_({param: 1}), K), P = X(_({form: 1}), A, D, E, I), Q = _({li: 1}), R = _({style: 1, script: 1}), S = _({base: 1, link: 1, meta: 1, title: 1}), T = X(S, R), U = _({head: 1, body: 1}), V = _({html: 1}); var block = _({address: 1, blockquote: 1, center: 1, dir: 1, div: 1, dl: 1, fieldset: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, hr: 1, isindex: 1, menu: 1, noframes: 1, ol: 1, p: 1, pre: 1, table: 1, ul: 1}), //针对优酷的embed他添加了结束标识,导致粘贴进来会变成两个,暂时去掉 ,embed:1 empty = _({area: 1, base: 1, br: 1, col: 1, hr: 1, img: 1, input: 1, link: 1, meta: 1, param: 1, embed: 1}); return _({ // $ 表示自定的属性 // body外的元素列表. $nonBodyContent: X(V, U, S), //块结构元素列表 $block: block, //内联元素列表 $inline: L, $body: X(_({script: 1, style: 1}), block), $cdata: _({script: 1, style: 1}), //自闭和元素 $empty: empty, //不是自闭合,但不能让range选中里边 $nonChild: _({iframe: 1, textarea: 1}), //列表元素列表 $listItem: _({dd: 1, dt: 1, li: 1}), //列表根元素列表 $list: _({ul: 1, ol: 1, dl: 1}), //不能认为是空的元素 $isNotEmpty: _({table: 1, ul: 1, ol: 1, dl: 1, iframe: 1, area: 1, base: 1, col: 1, hr: 1, img: 1, embed: 1, input: 1, link: 1, meta: 1, param: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1}), //如果没有子节点就可以删除的元素列表,像span,a $removeEmpty: _({a: 1, abbr: 1, acronym: 1, address: 1, b: 1, bdo: 1, big: 1, cite: 1, code: 1, del: 1, dfn: 1, em: 1, font: 1, i: 1, ins: 1, label: 1, kbd: 1, q: 1, s: 1, samp: 1, small: 1, span: 1, strike: 1, strong: 1, sub: 1, sup: 1, tt: 1, u: 1, 'var': 1}), $removeEmptyBlock: _({'p': 1, 'div': 1}), //在table元素里的元素列表 $tableContent: _({caption: 1, col: 1, colgroup: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1, table: 1}), //不转换的标签 $notTransContent: _({pre: 1, script: 1, style: 1, textarea: 1}), html: U, head: T, style: N, script: N, body: P, base: {}, link: {}, meta: {}, title: N, col: {}, tr: _({td: 1, th: 1}), img: {}, embed: {}, colgroup: _({thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1}), noscript: P, td: P, br: {}, th: P, center: P, kbd: L, button: X(I, E), basefont: {}, h5: L, h4: L, samp: L, h6: L, ol: Q, h1: L, h3: L, option: N, h2: L, form: X(A, D, E, I), select: _({optgroup: 1, option: 1}), font: L, ins: L, menu: Q, abbr: L, label: L, table: _({thead: 1, col: 1, tbody: 1, tr: 1, colgroup: 1, caption: 1, tfoot: 1}), code: L, tfoot: M, cite: L, li: P, input: {}, iframe: P, strong: L, textarea: N, noframes: P, big: L, small: L, span: _({'#': 1, br: 1}), hr: L, dt: L, sub: L, optgroup: _({option: 1}), param: {}, bdo: L, 'var': L, div: P, object: O, sup: L, dd: P, strike: L, area: {}, dir: Q, map: X(_({area: 1, form: 1, p: 1}), A, F, E), applet: O, dl: _({dt: 1, dd: 1}), del: L, isindex: {}, fieldset: X(_({legend: 1}), K), thead: M, ul: Q, acronym: L, b: L, a: X(_({a: 1}), J), blockquote: X(_({td: 1, tr: 1, tbody: 1, li: 1}), P), caption: L, i: L, u: L, tbody: M, s: L, address: X(D, I), tt: L, legend: L, q: L, pre: X(G, C), p: X(_({'a': 1}), L), em: L, dfn: L }); })(); /** * @file * @name UE.dom.domUtils * @short DomUtils * @import editor.js, core/utils.js,core/browser.js,core/dom/dtd.js * @desc UEditor封装的底层dom操作库 */ function getDomNode(node, start, ltr, startFromChild, fn, guard) { var tmpNode = startFromChild && node[start], parent; !tmpNode && (tmpNode = node[ltr]); while (!tmpNode && (parent = (parent || node).parentNode)) { if (parent.tagName == 'BODY' || guard && !guard(parent)) { return null; } tmpNode = parent[ltr]; } if (tmpNode && fn && !fn(tmpNode)) { return getDomNode(tmpNode, start, ltr, false, fn); } return tmpNode; } var attrFix = ie && browser.version < 9 ? { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder" } : { tabindex: "tabIndex", readonly: "readOnly" }, styleBlock = utils.listToMap([ '-webkit-box', '-moz-box', 'block' , 'list-item' , 'table' , 'table-row-group' , 'table-header-group', 'table-footer-group' , 'table-row' , 'table-column-group' , 'table-column' , 'table-cell' , 'table-caption' ]); var domUtils = dom.domUtils = { //节点常量 NODE_ELEMENT: 1, NODE_DOCUMENT: 9, NODE_TEXT: 3, NODE_COMMENT: 8, NODE_DOCUMENT_FRAGMENT: 11, //位置关系 POSITION_IDENTICAL: 0, POSITION_DISCONNECTED: 1, POSITION_FOLLOWING: 2, POSITION_PRECEDING: 4, POSITION_IS_CONTAINED: 8, POSITION_CONTAINS: 16, //ie6使用其他的会有一段空白出现 fillChar: ie && browser.version == '6' ? '\ufeff' : '\u200B', //-------------------------Node部分-------------------------------- keys: { /*Backspace*/ 8: 1, /*Delete*/ 46: 1, /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1, 37: 1, 38: 1, 39: 1, 40: 1, 13: 1 /*enter*/ }, /** * 获取节点A相对于节点B的位置关系 * @name getPosition * @grammar UE.dom.domUtils.getPosition(nodeA,nodeB) => Number * @example * switch (returnValue) { * case 0: //相等,同一节点 * case 1: //无关,节点不相连 * case 2: //跟随,即节点A头部位于节点B头部的后面 * case 4: //前置,即节点A头部位于节点B头部的前面 * case 8: //被包含,即节点A被节点B包含 * case 10://组合类型,即节点A满足跟随节点B且被节点B包含。实际上,如果被包含,必定跟随,所以returnValue事实上不会存在8的情况。 * case 16://包含,即节点A包含节点B * case 20://组合类型,即节点A满足前置节点A且包含节点B。同样,如果包含,必定前置,所以returnValue事实上也不会存在16的情况 * } */ getPosition: function (nodeA, nodeB) { // 如果两个节点是同一个节点 if (nodeA === nodeB) { // domUtils.POSITION_IDENTICAL return 0; } var node, parentsA = [nodeA], parentsB = [nodeB]; node = nodeA; while (node = node.parentNode) { // 如果nodeB是nodeA的祖先节点 if (node === nodeB) { // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING return 10; } parentsA.push(node); } node = nodeB; while (node = node.parentNode) { // 如果nodeA是nodeB的祖先节点 if (node === nodeA) { // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING return 20; } parentsB.push(node); } parentsA.reverse(); parentsB.reverse(); if (parentsA[0] !== parentsB[0]) { // domUtils.POSITION_DISCONNECTED return 1; } var i = -1; while (i++, parentsA[i] === parentsB[i]) { } nodeA = parentsA[i]; nodeB = parentsB[i]; while (nodeA = nodeA.nextSibling) { if (nodeA === nodeB) { // domUtils.POSITION_PRECEDING return 4 } } // domUtils.POSITION_FOLLOWING return 2; }, /** * 返回节点node在父节点中的索引位置 * @name getNodeIndex * @grammar UE.dom.domUtils.getNodeIndex(node) => Number //索引值从0开始 */ getNodeIndex: function (node, ignoreTextNode) { var preNode = node, i = 0; while (preNode = preNode.previousSibling) { if (ignoreTextNode && preNode.nodeType == 3) { if (preNode.nodeType != preNode.nextSibling.nodeType) { i++; } continue; } i++; } return i; }, /** * 检测节点node是否在节点doc的树上,实质上是检测是否被doc包含 * @name inDoc * @grammar UE.dom.domUtils.inDoc(node,doc) => true|false */ inDoc: function (node, doc) { return domUtils.getPosition(node, doc) == 10; }, /** * 查找node节点的祖先节点 * @name findParent * @grammar UE.dom.domUtils.findParent(node) => Element // 直接返回node节点的父节点 * @grammar UE.dom.domUtils.findParent(node,filterFn) => Element //filterFn为过滤函数,node作为参数,返回true时才会将node作为符合要求的节点返回 * @grammar UE.dom.domUtils.findParent(node,filterFn,includeSelf) => Element //includeSelf指定是否包含自身 */ findParent: function (node, filterFn, includeSelf) { if (node && !domUtils.isBody(node)) { node = includeSelf ? node : node.parentNode; while (node) { if (!filterFn || filterFn(node) || domUtils.isBody(node)) { return filterFn && !filterFn(node) && domUtils.isBody(node) ? null : node; } node = node.parentNode; } } return null; }, /** * 通过tagName查找node节点的祖先节点 * @name findParentByTagName * @grammar UE.dom.domUtils.findParentByTagName(node,tagNames) => Element //tagNames支持数组,区分大小写 * @grammar UE.dom.domUtils.findParentByTagName(node,tagNames,includeSelf) => Element //includeSelf指定是否包含自身 * @grammar UE.dom.domUtils.findParentByTagName(node,tagNames,includeSelf,excludeFn) => Element //excludeFn指定例外过滤条件,返回true时忽略该节点 */ findParentByTagName: function (node, tagNames, includeSelf, excludeFn) { tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]); return domUtils.findParent(node, function (node) { return tagNames[node.tagName] && !(excludeFn && excludeFn(node)); }, includeSelf); }, /** * 查找节点node的祖先节点集合 * @name findParents * @grammar UE.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身 * @grammar UE.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身 * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取 * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个 */ findParents: function (node, includeSelf, filterFn, closerFirst) { var parents = includeSelf && ( filterFn && filterFn(node) || !filterFn ) ? [node] : []; while (node = domUtils.findParent(node, filterFn)) { parents.push(node); } return closerFirst ? parents : parents.reverse(); }, /** * 在节点node后面插入新节点newNode * @name insertAfter * @grammar UE.dom.domUtils.insertAfter(node,newNode) => newNode */ insertAfter: function (node, newNode) { return node.parentNode.insertBefore(newNode, node.nextSibling); }, /** * 删除节点node,并根据keepChildren指定是否保留子节点 * @name remove * @grammar UE.dom.domUtils.remove(node) => node * @grammar UE.dom.domUtils.remove(node,keepChildren) => node */ remove: function (node, keepChildren) { var parent = node.parentNode, child; if (parent) { if (keepChildren && node.hasChildNodes()) { while (child = node.firstChild) { parent.insertBefore(child, node); } } parent.removeChild(node); } return node; }, /** * 取得node节点在dom树上的下一个节点,即多叉树遍历 * @name getNextDomNode * @grammar UE.dom.domUtils.getNextDomNode(node) => Element * @example */ getNextDomNode: function (node, startFromChild, filterFn, guard) { return getDomNode(node, 'firstChild', 'nextSibling', startFromChild, filterFn, guard); }, /** * 检测节点node是否属于bookmark节点 * @name isBookmarkNode * @grammar UE.dom.domUtils.isBookmarkNode(node) => true|false */ isBookmarkNode: function (node) { return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id); }, /** * 获取节点node所在的window对象 * @name getWindow * @grammar UE.dom.domUtils.getWindow(node) => window对象 */ getWindow: function (node) { var doc = node.ownerDocument || node; return doc.defaultView || doc.parentWindow; }, /** * 得到nodeA与nodeB公共的祖先节点 * @name getCommonAncestor * @grammar UE.dom.domUtils.getCommonAncestor(nodeA,nodeB) => Element */ getCommonAncestor: function (nodeA, nodeB) { if (nodeA === nodeB) return nodeA; var parentsA = [nodeA] , parentsB = [nodeB], parent = nodeA, i = -1; while (parent = parent.parentNode) { if (parent === nodeB) { return parent; } parentsA.push(parent); } parent = nodeB; while (parent = parent.parentNode) { if (parent === nodeA) return parent; parentsB.push(parent); } parentsA.reverse(); parentsB.reverse(); while (i++, parentsA[i] === parentsB[i]) { } return i == 0 ? null : parentsA[i - 1]; }, /** * 清除node节点左右兄弟为空的inline节点 * @name clearEmptySibling * @grammar UE.dom.domUtils.clearEmptySibling(node) * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点 * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点 * @example * xxxxbb --> xxxxbb */ clearEmptySibling: function (node, ignoreNext, ignorePre) { function clear(next, dir) { var tmpNode; while (next && !domUtils.isBookmarkNode(next) && (domUtils.isEmptyInlineElement(next) //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了 || !new RegExp('[^\t\n\r' + domUtils.fillChar + ']').test(next.nodeValue) )) { tmpNode = next[dir]; domUtils.remove(next); next = tmpNode; } } !ignoreNext && clear(node.nextSibling, 'nextSibling'); !ignorePre && clear(node.previousSibling, 'previousSibling'); }, /** * 将一个文本节点node拆分成两个文本节点,offset指定拆分位置 * @name split * @grammar UE.dom.domUtils.split(node,offset) => TextNode //返回从切分位置开始的后一个文本节点 */ split: function (node, offset) { var doc = node.ownerDocument; if (browser.ie && offset == node.nodeValue.length) { var next = doc.createTextNode(''); return domUtils.insertAfter(node, next); } var retval = node.splitText(offset); //ie8下splitText不会跟新childNodes,我们手动触发他的更新 if (browser.ie8) { var tmpNode = doc.createTextNode(''); domUtils.insertAfter(retval, tmpNode); domUtils.remove(tmpNode); } return retval; }, /** * 检测节点node是否为空节点(包括空格、换行、占位符等字符) * @name isWhitespace * @grammar UE.dom.domUtils.isWhitespace(node) => true|false */ isWhitespace: function (node) { return !new RegExp('[^ \t\n\r' + domUtils.fillChar + ']').test(node.nodeValue); }, /** * 获取元素element相对于viewport的位置坐标 * @name getXY * @grammar UE.dom.domUtils.getXY(element) => Object //返回坐标对象{x:left,y:top} */ getXY: function (element) { var x = 0, y = 0; while (element.offsetParent) { y += element.offsetTop; x += element.offsetLeft; element = element.offsetParent; } return { 'x': x, 'y': y}; }, /** * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数 * @name on * @grammar UE.dom.domUtils.on(element,type,handler) //type支持数组传入 * @example * UE.dom.domUtils.on(document.body,"click",function(e){ * //e为事件对象,this为被点击元素对戏那个 * }) * @example * UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){ * //evt为事件对象,this为被点击元素对象 * }) */ on: function (element, type, handler) { var types = utils.isArray(type) ? type : [type], k = types.length; if (k) while (k--) { type = types[k]; if (element.addEventListener) { element.addEventListener(type, handler, false); } else { if (!handler._d) { handler._d = { els: [] }; } var key = type + handler.toString(), index = utils.indexOf(handler._d.els, element); if (!handler._d[key] || index == -1) { if (index == -1) { handler._d.els.push(element); } if (!handler._d[key]) { handler._d[key] = function (evt) { return handler.call(evt.srcElement, evt || window.event); }; } element.attachEvent('on' + type, handler._d[key]); } } } element = null; }, /** * 解除原生DOM事件绑定 * @name un * @grammar UE.dom.donUtils.un(element,type,handler) //参见on */ un: function (element, type, handler) { var types = utils.isArray(type) ? type : [type], k = types.length; if (k) while (k--) { type = types[k]; if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else { var key = type + handler.toString(); try { element.detachEvent('on' + type, handler._d ? handler._d[key] : handler); } catch (e) { } if (handler._d && handler._d[key]) { var index = utils.indexOf(handler._d.els, element); if (index != -1) { handler._d.els.splice(index, 1); } handler._d.els.length == 0 && delete handler._d[key]; } } } }, /** * 比较节点nodeA与节点nodeB是否具有相同的标签名、属性名以及属性值 * @name isSameElement * @grammar UE.dom.domUtils.isSameElement(nodeA,nodeB) => true|false * @example * ssss and bbbbb => true * ssss and bbbbb => false */ isSameElement: function (nodeA, nodeB) { if (nodeA.tagName != nodeB.tagName) { return false; } var thisAttrs = nodeA.attributes, otherAttrs = nodeB.attributes; if (!ie && thisAttrs.length != otherAttrs.length) { return false; } var attrA, attrB, al = 0, bl = 0; for (var i = 0; attrA = thisAttrs[i++];) { if (attrA.nodeName == 'style') { if (attrA.specified) { al++; } if (domUtils.isSameStyle(nodeA, nodeB)) { continue; } else { return false; } } if (ie) { if (attrA.specified) { al++; attrB = otherAttrs.getNamedItem(attrA.nodeName); } else { continue; } } else { attrB = nodeB.attributes[attrA.nodeName]; } if (!attrB.specified || attrA.nodeValue != attrB.nodeValue) { return false; } } // 有可能attrB的属性包含了attrA的属性之外还有自己的属性 if (ie) { for (i = 0; attrB = otherAttrs[i++];) { if (attrB.specified) { bl++; } } if (al != bl) { return false; } } return true; }, /** * 判断节点nodeA与节点nodeB的元素属性是否一致 * @name isSameStyle * @grammar UE.dom.domUtils.isSameStyle(nodeA,nodeB) => true|false */ isSameStyle: function (nodeA, nodeB) { var styleA = nodeA.style.cssText.replace(/( ?; ?)/g, ';').replace(/( ?: ?)/g, ':'), styleB = nodeB.style.cssText.replace(/( ?; ?)/g, ';').replace(/( ?: ?)/g, ':'); if (browser.opera) { styleA = nodeA.style; styleB = nodeB.style; if (styleA.length != styleB.length) return false; for (var p in styleA) { if (/^(\d+|csstext)$/i.test(p)) { continue; } if (styleA[p] != styleB[p]) { return false; } } return true; } if (!styleA || !styleB) { return styleA == styleB; } styleA = styleA.split(';'); styleB = styleB.split(';'); if (styleA.length != styleB.length) { return false; } for (var i = 0, ci; ci = styleA[i++];) { if (utils.indexOf(styleB, ci) == -1) { return false; } } return true; }, /** * 检查节点node是否为块元素 * @name isBlockElm * @grammar UE.dom.domUtils.isBlockElm(node) => true|false */ isBlockElm: function (node) { return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(node, 'display')]) && !dtd.$nonChild[node.tagName]; }, /** * 检测node节点是否为body节点 * @name isBody * @grammar UE.dom.domUtils.isBody(node) => true|false */ isBody: function (node) { return node && node.nodeType == 1 && node.tagName.toLowerCase() == 'body'; }, /** * 以node节点为中心,将该节点的指定祖先节点parent拆分成2块 * @name breakParent * @grammar UE.dom.domUtils.breakParent(node,parent) => node * @desc * ooo是node节点 *

xxxxoooxxx

==>

xxx

ooo

xxx

*

xxxxxxxxxoooxxxxxx

=>

xxxxxxxxx

ooo

xxxxxx

*/ breakParent: function (node, parent) { var tmpNode, parentClone = node, clone = node, leftNodes, rightNodes; do { parentClone = parentClone.parentNode; if (leftNodes) { tmpNode = parentClone.cloneNode(false); tmpNode.appendChild(leftNodes); leftNodes = tmpNode; tmpNode = parentClone.cloneNode(false); tmpNode.appendChild(rightNodes); rightNodes = tmpNode; } else { leftNodes = parentClone.cloneNode(false); rightNodes = leftNodes.cloneNode(false); } while (tmpNode = clone.previousSibling) { leftNodes.insertBefore(tmpNode, leftNodes.firstChild); } while (tmpNode = clone.nextSibling) { rightNodes.appendChild(tmpNode); } clone = parentClone; } while (parent !== parentClone); tmpNode = parent.parentNode; tmpNode.insertBefore(leftNodes, parent); tmpNode.insertBefore(rightNodes, parent); tmpNode.insertBefore(node, rightNodes); domUtils.remove(parent); return node; }, /** * 检查节点node是否是空inline节点 * @name isEmptyInlineElement * @grammar UE.dom.domUtils.isEmptyInlineElement(node) => 1|0 * @example * => 1 * => 1 * => 1 * xx => 0 */ isEmptyInlineElement: function (node) { if (node.nodeType != 1 || !dtd.$removeEmpty[ node.tagName ]) { return 0; } node = node.firstChild; while (node) { //如果是创建的bookmark就跳过 if (domUtils.isBookmarkNode(node)) { return 0; } if (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node) || node.nodeType == 3 && !domUtils.isWhitespace(node) ) { return 0; } node = node.nextSibling; } return 1; }, /** * 删除node节点下的左右空白文本子节点 * @name trimWhiteTextNode * @grammar UE.dom.domUtils.trimWhiteTextNode(node) */ trimWhiteTextNode: function (node) { function remove(dir) { var child; while ((child = node[dir]) && child.nodeType == 3 && domUtils.isWhitespace(child)) { node.removeChild(child); } } remove('firstChild'); remove('lastChild'); }, /** * 合并node节点下相同的子节点 * @name mergeChild * @desc * UE.dom.domUtils.mergeChild(node,tagName) //tagName要合并的子节点的标签 * @example *

xxaaxx

* ==> UE.dom.domUtils.mergeChild(node,'span') *

xxaaxx

*/ mergeChild: function (node, tagName, attrs) { var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase()); for (var i = 0, ci; ci = list[i++];) { if (!ci.parentNode || domUtils.isBookmarkNode(ci)) { continue; } //span单独处理 if (ci.tagName.toLowerCase() == 'span') { if (node === ci.parentNode) { domUtils.trimWhiteTextNode(node); if (node.childNodes.length == 1) { node.style.cssText = ci.style.cssText + ";" + node.style.cssText; domUtils.remove(ci, true); continue; } } ci.style.cssText = node.style.cssText + ';' + ci.style.cssText; if (attrs) { var style = attrs.style; if (style) { style = style.split(';'); for (var j = 0, s; s = style[j++];) { ci.style[utils.cssStyleToDomStyle(s.split(':')[0])] = s.split(':')[1]; } } } if (domUtils.isSameStyle(ci, node)) { domUtils.remove(ci, true); } continue; } if (domUtils.isSameElement(node, ci)) { domUtils.remove(ci, true); } } }, /** * 原生方法getElementsByTagName的封装 * @name getElementsByTagName * @grammar UE.dom.domUtils.getElementsByTagName(node,tagName) => Array //节点集合数组 */ getElementsByTagName: function (node, name, filter) { if (filter && utils.isString(filter)) { var className = filter; filter = function (node) { return domUtils.hasClass(node, className) } } name = utils.trim(name).replace(/[ ]{2,}/g, ' ').split(' '); var arr = []; for (var n = 0, ni; ni = name[n++];) { var list = node.getElementsByTagName(ni); for (var i = 0, ci; ci = list[i++];) { if (!filter || filter(ci)) arr.push(ci); } } return arr; }, /** * 将节点node合并到父节点上 * @name mergeToParent * @grammar UE.dom.domUtils.mergeToParent(node) * @example * xxx ==> xxx */ mergeToParent: function (node) { var parent = node.parentNode; while (parent && dtd.$removeEmpty[parent.tagName]) { if (parent.tagName == node.tagName || parent.tagName == 'A') {//针对a标签单独处理 domUtils.trimWhiteTextNode(parent); //span需要特殊处理 不处理这样的情况 xxxxxxxxx if (parent.tagName == 'SPAN' && !domUtils.isSameStyle(parent, node) || (parent.tagName == 'A' && node.tagName == 'SPAN')) { if (parent.childNodes.length > 1 || parent !== node.parentNode) { node.style.cssText = parent.style.cssText + ";" + node.style.cssText; parent = parent.parentNode; continue; } else { parent.style.cssText += ";" + node.style.cssText; //trace:952 a标签要保持下划线 if (parent.tagName == 'A') { parent.style.textDecoration = 'underline'; } } } if (parent.tagName != 'A') { parent === node.parentNode && domUtils.remove(node, true); break; } } parent = parent.parentNode; } }, /** * 合并节点node的左右兄弟节点 * @name mergeSibling * @grammar UE.dom.domUtils.mergeSibling(node) * @grammar UE.dom.domUtils.mergeSibling(node,ignorePre) //ignorePre指定是否忽略左兄弟 * @grammar UE.dom.domUtils.mergeSibling(node,ignorePre,ignoreNext) //ignoreNext指定是否忽略右兄弟 * @example * xxxxoooxxxx ==> xxxxoooxxxx */ mergeSibling: function (node, ignorePre, ignoreNext) { function merge(rtl, start, node) { var next; if ((next = node[rtl]) && !domUtils.isBookmarkNode(next) && next.nodeType == 1 && domUtils.isSameElement(node, next)) { while (next.firstChild) { if (start == 'firstChild') { node.insertBefore(next.lastChild, node.firstChild); } else { node.appendChild(next.firstChild); } } domUtils.remove(next); } } !ignorePre && merge('previousSibling', 'firstChild', node); !ignoreNext && merge('nextSibling', 'lastChild', node); }, /** * 设置节点node及其子节点不会被选中 * @name unSelectable * @grammar UE.dom.domUtils.unSelectable(node) */ unSelectable: ie || browser.opera ? function (node) { //for ie9 node.onselectstart = function () { return false; }; node.onclick = node.onkeyup = node.onkeydown = function () { return false; }; node.unselectable = 'on'; node.setAttribute("unselectable", "on"); for (var i = 0, ci; ci = node.all[i++];) { switch (ci.tagName.toLowerCase()) { case 'iframe' : case 'textarea' : case 'input' : case 'select' : break; default : ci.unselectable = 'on'; node.setAttribute("unselectable", "on"); } } } : function (node) { node.style.MozUserSelect = node.style.webkitUserSelect = node.style.KhtmlUserSelect = 'none'; }, /** * 删除节点node上的属性attrNames,attrNames为属性名称数组 * @name removeAttributes * @grammar UE.dom.domUtils.removeAttributes(node,attrNames) * @example * //Before remove * xxxxx * //Remove * UE.dom.domUtils.removeAttributes(node,["id","name"]); * //After remove * xxxxx */ removeAttributes: function (node, attrNames) { attrNames = utils.isArray(attrNames) ? attrNames : utils.trim(attrNames).replace(/[ ]{2,}/g, ' ').split(' '); for (var i = 0, ci; ci = attrNames[i++];) { ci = attrFix[ci] || ci; switch (ci) { case 'className': node[ci] = ''; break; case 'style': node.style.cssText = ''; !browser.ie && node.removeAttributeNode(node.getAttributeNode('style')) } node.removeAttribute(ci); } }, /** * 在doc下创建一个标签名为tag,属性为attrs的元素 * @name createElement * @grammar UE.dom.domUtils.createElement(doc,tag,attrs) => Node //返回创建的节点 */ createElement: function (doc, tag, attrs) { return domUtils.setAttributes(doc.createElement(tag), attrs) }, /** * 为节点node添加属性attrs,attrs为属性键值对 * @name setAttributes * @grammar UE.dom.domUtils.setAttributes(node,attrs) => node */ setAttributes: function (node, attrs) { for (var attr in attrs) { if (attrs.hasOwnProperty(attr)) { var value = attrs[attr]; switch (attr) { case 'class': //ie下要这样赋值,setAttribute不起作用 node.className = value; break; case 'style' : node.style.cssText = node.style.cssText + ";" + value; break; case 'innerHTML': node[attr] = value; break; case 'value': node.value = value; break; default: node.setAttribute(attrFix[attr] || attr, value); } } } return node; }, /** * 获取元素element的计算样式 * @name getComputedStyle * @grammar UE.dom.domUtils.getComputedStyle(element,styleName) => String //返回对应样式名称的样式值 * @example * getComputedStyle(document.body,"font-size") => "15px" * getComputedStyle(form,"color") => "#ffccdd" */ getComputedStyle: function (element, styleName) { //一下的属性单独处理 var pros = 'width height top left'; if (pros.indexOf(styleName) > -1) { return element['offset' + styleName.replace(/^\w/, function (s) { return s.toUpperCase() })] + 'px'; } //忽略文本节点 if (element.nodeType == 3) { element = element.parentNode; } //ie下font-size若body下定义了font-size,则从currentStyle里会取到这个font-size. 取不到实际值,故此修改. if (browser.ie && browser.version < 9 && styleName == 'font-size' && !element.style.fontSize && !dtd.$empty[element.tagName] && !dtd.$nonChild[element.tagName]) { var span = element.ownerDocument.createElement('span'); span.style.cssText = 'padding:0;border:0;font-family:simsun;'; span.innerHTML = '.'; element.appendChild(span); var result = span.offsetHeight; element.removeChild(span); span = null; return result + 'px'; } try { var value = domUtils.getStyle(element, styleName) || (window.getComputedStyle ? domUtils.getWindow(element).getComputedStyle(element, '').getPropertyValue(styleName) : ( element.currentStyle || element.style )[utils.cssStyleToDomStyle(styleName)]); } catch (e) { return ""; } return utils.transUnitToPx(utils.fixColor(styleName, value)); }, /** * 在元素element上删除classNames,支持同时删除多个 * @name removeClasses * @grammar UE.dom.domUtils.removeClasses(element,classNames) * @example * //执行方法前的dom结构 * xxx * //执行方法 * UE.dom.domUtils.removeClasses(element,["test1","test3"]) * //执行方法后的dom结构 * xxx */ removeClasses: function (elm, classNames) { classNames = utils.isArray(classNames) ? classNames : utils.trim(classNames).replace(/[ ]{2,}/g, ' ').split(' '); for (var i = 0, ci, cls = elm.className; ci = classNames[i++];) { cls = cls.replace(new RegExp('\\b' + ci + '\\b'), '') } cls = utils.trim(cls).replace(/[ ]{2,}/g, ' '); if (cls) { elm.className = cls; } else { domUtils.removeAttributes(elm, ['class']); } }, /** * 在元素element上增加一个样式类className,支持以空格分开的多个类名 * 如果相同的类名将不会添加 * @name addClass * @grammar UE.dom.domUtils.addClass(element,classNames) */ addClass: function (elm, classNames) { if (!elm)return; classNames = utils.trim(classNames).replace(/[ ]{2,}/g, ' ').split(' '); for (var i = 0, ci, cls = elm.className; ci = classNames[i++];) { if (!new RegExp('\\b' + ci + '\\b').test(cls)) { elm.className += ' ' + ci; } } }, /** * 判断元素element是否包含样式类名className,支持以空格分开的多个类名,多个类名顺序不同也可以比较 * @name hasClass * @grammar UE.dom.domUtils.hasClass(element,className) =>true|false */ hasClass: function (element, className) { if (utils.isRegExp(className)) { return className.test(element.className) } className = utils.trim(className).replace(/[ ]{2,}/g, ' ').split(' '); for (var i = 0, ci, cls = element.className; ci = className[i++];) { if (!new RegExp('\\b' + ci + '\\b', 'i').test(cls)) { return false; } } return i - 1 == className.length; }, /** * 阻止事件默认行为 * @param {Event} evt 需要组织的事件对象 */ preventDefault: function (evt) { evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false); }, /** * 删除元素element的样式 * @grammar UE.dom.domUtils.removeStyle(element,name) 删除的样式名称 */ removeStyle: function (element, name) { if (browser.ie && browser.version > 8) { element.style.cssText = element.style.cssText.replace(new RegExp(name + '\s*:\s*[^;]+;?'), '') } else { if (element.style.removeProperty) { element.style.removeProperty(name); } else { element.style.removeAttribute(utils.cssStyleToDomStyle(name)); } } if (!element.style.cssText) { domUtils.removeAttributes(element, ['style']); } }, /** * 获取元素element的某个样式值 * @name getStyle * @grammar UE.dom.domUtils.getStyle(element,name) => String */ getStyle: function (element, name) { var value = element.style[ utils.cssStyleToDomStyle(name) ]; return utils.fixColor(name, value); }, /** * 为元素element设置样式属性值 * @name setStyle * @grammar UE.dom.domUtils.setStyle(element,name,value) */ setStyle: function (element, name, value) { element.style[utils.cssStyleToDomStyle(name)] = value; }, /** * 为元素element设置样式属性值 * @name setStyles * @grammar UE.dom.domUtils.setStyle(element,styles) //styles为样式键值对 */ setStyles: function (element, styles) { for (var name in styles) { if (styles.hasOwnProperty(name)) { domUtils.setStyle(element, name, styles[name]); } } }, /** * 删除_moz_dirty属性 * @function */ removeDirtyAttr: function (node) { for (var i = 0, ci, nodes = node.getElementsByTagName('*'); ci = nodes[i++];) { ci.removeAttribute('_moz_dirty'); } node.removeAttribute('_moz_dirty'); }, /** * 返回子节点的数量 * @function * @param {Node} node 父节点 * @param {Function} fn 过滤子节点的规则,若为空,则得到所有子节点的数量 * @return {Number} 符合条件子节点的数量 */ getChildCount: function (node, fn) { var count = 0, first = node.firstChild; fn = fn || function () { return 1; }; while (first) { if (fn(first)) { count++; } first = first.nextSibling; } return count; }, /** * 判断是否为空节点 * @function * @param {Node} node 节点 * @return {Boolean} 是否为空节点 */ isEmptyNode: function (node) { return !node.firstChild || domUtils.getChildCount(node, function (node) { return !domUtils.isBr(node) && !domUtils.isBookmarkNode(node) && !domUtils.isWhitespace(node) }) == 0 }, /** * 清空节点所有的className * @function * @param {Array} nodes 节点数组 */ clearSelectedArr: function (nodes) { var node; while (node = nodes.pop()) { domUtils.removeAttributes(node, ['class']); } }, /** * 将显示区域滚动到显示节点的位置 * @function * @param {Node} node 节点 * @param {window} win window对象 * @param {Number} offsetTop 距离上方的偏移量 */ scrollToView: function (node, win, offsetTop) { var getViewPaneSize = function () { var doc = win.document, mode = doc.compatMode == 'CSS1Compat'; return { width: ( mode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0, height: ( mode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0 }; }, getScrollPosition = function (win) { if ('pageXOffset' in win) { return { x: win.pageXOffset || 0, y: win.pageYOffset || 0 }; } else { var doc = win.document; return { x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0, y: doc.documentElement.scrollTop || doc.body.scrollTop || 0 }; } }; var winHeight = getViewPaneSize().height, offset = winHeight * -1 + offsetTop; offset += (node.offsetHeight || 0); var elementPosition = domUtils.getXY(node); offset += elementPosition.y; var currentScroll = getScrollPosition(win).y; // offset += 50; if (offset > currentScroll || offset < currentScroll - winHeight) { win.scrollTo(0, offset + (offset < 0 ? -20 : 20)); } }, /** * 判断节点是否为br * @function * @param {Node} node 节点 */ isBr: function (node) { return node.nodeType == 1 && node.tagName == 'BR'; }, isFillChar: function (node, isInStart) { return node.nodeType == 3 && !node.nodeValue.replace(new RegExp((isInStart ? '^' : '' ) + domUtils.fillChar), '').length }, isStartInblock: function (range) { var tmpRange = range.cloneRange(), flag = 0, start = tmpRange.startContainer, tmp; if (start.nodeType == 1 && start.childNodes[tmpRange.startOffset]) { start = start.childNodes[tmpRange.startOffset]; var pre = start.previousSibling; while (pre && domUtils.isFillChar(pre)) { start = pre; pre = pre.previousSibling; } } if (this.isFillChar(start, true) && tmpRange.startOffset == 1) { tmpRange.setStartBefore(start); start = tmpRange.startContainer; } while (start && domUtils.isFillChar(start)) { tmp = start; start = start.previousSibling } if (tmp) { tmpRange.setStartBefore(tmp); start = tmpRange.startContainer; } if (start.nodeType == 1 && domUtils.isEmptyNode(start) && tmpRange.startOffset == 1) { tmpRange.setStart(start, 0).collapse(true); } while (!tmpRange.startOffset) { start = tmpRange.startContainer; if (domUtils.isBlockElm(start) || domUtils.isBody(start)) { flag = 1; break; } var pre = tmpRange.startContainer.previousSibling, tmpNode; if (!pre) { tmpRange.setStartBefore(tmpRange.startContainer); } else { while (pre && domUtils.isFillChar(pre)) { tmpNode = pre; pre = pre.previousSibling; } if (tmpNode) { tmpRange.setStartBefore(tmpNode); } else { tmpRange.setStartBefore(tmpRange.startContainer); } } } return flag && !domUtils.isBody(tmpRange.startContainer) ? 1 : 0; }, isEmptyBlock: function (node) { var reg = new RegExp('[ \t\r\n' + domUtils.fillChar + ']', 'g'); if (node[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').length > 0) { return 0; } for (var n in dtd.$isNotEmpty) { if (node.getElementsByTagName(n).length) { return 0; } } return 1; }, setViewportOffset: function (element, offset) { var left = parseInt(element.style.left) | 0; var top = parseInt(element.style.top) | 0; var rect = element.getBoundingClientRect(); var offsetLeft = offset.left - rect.left; var offsetTop = offset.top - rect.top; if (offsetLeft) { element.style.left = left + offsetLeft + 'px'; } if (offsetTop) { element.style.top = top + offsetTop + 'px'; } }, fillNode: function (doc, node) { var tmpNode = browser.ie ? doc.createTextNode(domUtils.fillChar) : doc.createElement('br'); node.innerHTML = ''; node.appendChild(tmpNode); }, moveChild: function (src, tag, dir) { while (src.firstChild) { if (dir && tag.firstChild) { tag.insertBefore(src.lastChild, tag.firstChild); } else { tag.appendChild(src.firstChild); } } }, //判断是否有额外属性 hasNoAttributes: function (node) { return browser.ie ? /^<\w+\s*?>/.test(node.outerHTML) : node.attributes.length == 0; }, //判断是否是编辑器自定义的参数 isCustomeNode: function (node) { return node.nodeType == 1 && node.getAttribute('_ue_custom_node_'); }, isTagNode: function (node, tagName) { return node.nodeType == 1 && new RegExp(node.tagName, 'i').test(tagName) }, /** * 对于nodelist用filter进行过滤 * @name filterNodeList * @since 1.2.4+ * @grammar UE.dom.domUtils.filterNodeList(nodelist,filter,onlyFirst) => 节点 * @example * UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),'div p') //返回第一个是div或者p的节点 * UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),function(n){return n.getAttribute('src')}) * //返回第一个带src属性的节点 * UE.dom.domUtils.filterNodeList(document.getElementsByTagName('*'),'i',true) //返回数组,里边都是i节点 */ filterNodeList: function (nodelist, filter, forAll) { var results = []; if (!utils.isFunction(filter)) { var str = filter; filter = function (n) { return utils.indexOf(utils.isArray(str) ? str : str.split(' '), n.tagName.toLowerCase()) != -1 }; } utils.each(nodelist, function (n) { filter(n) && results.push(n) }); return results.length == 0 ? null : results.length == 1 || !forAll ? results[0] : results }, isInNodeEndBoundary: function (rng, node) { var start = rng.startContainer; if (start.nodeType == 3 && rng.startOffset != start.nodeValue.length) { return 0; } if (start.nodeType == 1 && rng.startOffset != start.childNodes.length) { return 0; } while (start !== node) { if (start.nextSibling) { return 0 } ; start = start.parentNode; } return 1; }, isBoundaryNode: function (node, dir) { var tmp; while (!domUtils.isBody(node)) { tmp = node; node = node.parentNode; if (tmp !== node[dir]) { return false; } } return true; } }; var fillCharReg = new RegExp(domUtils.fillChar, 'g'); ///import editor.js ///import core/utils.js ///import core/browser.js ///import core/dom/dom.js ///import core/dom/dtd.js ///import core/dom/domUtils.js /** * @file * @name UE.dom.Range * @anthor zhanyi * @short Range * @import editor.js,core/utils.js,core/browser.js,core/dom/domUtils.js,core/dom/dtd.js * @desc Range范围实现类,本类是UEditor底层核心类,统一w3cRange和ieRange之间的差异,包括接口和属性 */ (function () { var guid = 0, fillChar = domUtils.fillChar, fillData; /** * 更新range的collapse状态 * @param {Range} range range对象 */ function updateCollapse(range) { range.collapsed = range.startContainer && range.endContainer && range.startContainer === range.endContainer && range.startOffset == range.endOffset; } function selectOneNode(rng) { return !rng.collapsed && rng.startContainer.nodeType == 1 && rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset == 1 } function setEndPoint(toStart, node, offset, range) { //如果node是自闭合标签要处理 if (node.nodeType == 1 && (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])) { offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1); node = node.parentNode; } if (toStart) { range.startContainer = node; range.startOffset = offset; if (!range.endContainer) { range.collapse(true); } } else { range.endContainer = node; range.endOffset = offset; if (!range.startContainer) { range.collapse(false); } } updateCollapse(range); return range; } function execContentsAction(range, action) { //调整边界 //range.includeBookmark(); var start = range.startContainer, end = range.endContainer, startOffset = range.startOffset, endOffset = range.endOffset, doc = range.document, frag = doc.createDocumentFragment(), tmpStart, tmpEnd; if (start.nodeType == 1) { start = start.childNodes[startOffset] || (tmpStart = start.appendChild(doc.createTextNode(''))); } if (end.nodeType == 1) { end = end.childNodes[endOffset] || (tmpEnd = end.appendChild(doc.createTextNode(''))); } if (start === end && start.nodeType == 3) { frag.appendChild(doc.createTextNode(start.substringData(startOffset, endOffset - startOffset))); //is not clone if (action) { start.deleteData(startOffset, endOffset - startOffset); range.collapse(true); } return frag; } var current, currentLevel, clone = frag, startParents = domUtils.findParents(start, true), endParents = domUtils.findParents(end, true); for (var i = 0; startParents[i] == endParents[i];) { i++; } for (var j = i, si; si = startParents[j]; j++) { current = si.nextSibling; if (si == start) { if (!tmpStart) { if (range.startContainer.nodeType == 3) { clone.appendChild(doc.createTextNode(start.nodeValue.slice(startOffset))); //is not clone if (action) { start.deleteData(startOffset, start.nodeValue.length - startOffset); } } else { clone.appendChild(!action ? start.cloneNode(true) : start); } } } else { currentLevel = si.cloneNode(false); clone.appendChild(currentLevel); } while (current) { if (current === end || current === endParents[j]) { break; } si = current.nextSibling; clone.appendChild(!action ? current.cloneNode(true) : current); current = si; } clone = currentLevel; } clone = frag; if (!startParents[i]) { clone.appendChild(startParents[i - 1].cloneNode(false)); clone = clone.firstChild; } for (var j = i, ei; ei = endParents[j]; j++) { current = ei.previousSibling; if (ei == end) { if (!tmpEnd && range.endContainer.nodeType == 3) { clone.appendChild(doc.createTextNode(end.substringData(0, endOffset))); //is not clone if (action) { end.deleteData(0, endOffset); } } } else { currentLevel = ei.cloneNode(false); clone.appendChild(currentLevel); } //如果两端同级,右边第一次已经被开始做了 if (j != i || !startParents[i]) { while (current) { if (current === start) { break; } ei = current.previousSibling; clone.insertBefore(!action ? current.cloneNode(true) : current, clone.firstChild); current = ei; } } clone = currentLevel; } if (action) { range.setStartBefore(!endParents[i] ? endParents[i - 1] : !startParents[i] ? startParents[i - 1] : endParents[i]).collapse(true); } tmpStart && domUtils.remove(tmpStart); tmpEnd && domUtils.remove(tmpEnd); return frag; } /** * @name Range * @grammar new UE.dom.Range(document) => Range 实例 * @desc 创建一个跟document绑定的空的Range实例 * - ***startContainer*** 开始边界的容器节点,可以是elementNode或者是textNode * - ***startOffset*** 容器节点中的偏移量,如果是elementNode就是childNodes中的第几个,如果是textNode就是nodeValue的第几个字符 * - ***endContainer*** 结束边界的容器节点,可以是elementNode或者是textNode * - ***endOffset*** 容器节点中的偏移量,如果是elementNode就是childNodes中的第几个,如果是textNode就是nodeValue的第几个字符 * - ***document*** 跟range关联的document对象 * - ***collapsed*** 是否是闭合状态 */ var Range = dom.Range = function (document) { var me = this; me.startContainer = me.startOffset = me.endContainer = me.endOffset = null; me.document = document; me.collapsed = true; }; /** * 删除fillData * @param doc * @param excludeNode */ function removeFillData(doc, excludeNode) { try { if (fillData && domUtils.inDoc(fillData, doc)) { if (!fillData.nodeValue.replace(fillCharReg, '').length) { var tmpNode = fillData.parentNode; domUtils.remove(fillData); while (tmpNode && domUtils.isEmptyInlineElement(tmpNode) && //safari的contains有bug (browser.safari ? !(domUtils.getPosition(tmpNode, excludeNode) & domUtils.POSITION_CONTAINS) : !tmpNode.contains(excludeNode)) ) { fillData = tmpNode.parentNode; domUtils.remove(tmpNode); tmpNode = fillData; } } else { fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, ''); } } } catch (e) { } } /** * * @param node * @param dir */ function mergeSibling(node, dir) { var tmpNode; node = node[dir]; while (node && domUtils.isFillChar(node)) { tmpNode = node[dir]; domUtils.remove(node); node = tmpNode; } } Range.prototype = { /** * @name cloneContents * @grammar range.cloneContents() => DocumentFragment * @desc 克隆选中的内容到一个fragment里,如果选区是空的将返回null */ cloneContents: function () { return this.collapsed ? null : execContentsAction(this, 0); }, /** * @name deleteContents * @grammar range.deleteContents() => Range * @desc 删除当前选区范围中的所有内容并返回range实例,这时的range已经变成了闭合状态 * @example * DOM Element : * xx[xxx]x * //执行方法后 * xx|x * 注意range改变了 * range.startContainer => b * range.startOffset => 2 * range.endContainer => b * range.endOffset => 2 * range.collapsed => true */ deleteContents: function () { var txt; if (!this.collapsed) { execContentsAction(this, 1); } if (browser.webkit) { txt = this.startContainer; if (txt.nodeType == 3 && !txt.nodeValue.length) { this.setStartBefore(txt).collapse(true); domUtils.remove(txt); } } return this; }, /** * @name extractContents * @grammar range.extractContents() => DocumentFragment * @desc 将当前的内容放到一个fragment里并返回这个fragment,这时的range已经变成了闭合状态 * @example * DOM Element : * xx[xxx]x * //执行方法后 * 返回的fragment里的 dom结构是 * xxx * dom树上的结构是 * xx|x * 注意range改变了 * range.startContainer => b * range.startOffset => 2 * range.endContainer => b * range.endOffset => 2 * range.collapsed => true */ extractContents: function () { return this.collapsed ? null : execContentsAction(this, 2); }, /** * @name setStart * @grammar range.setStart(node,offset) => Range * @desc 设置range的开始位置位于node节点内,偏移量为offset * 如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符 */ setStart: function (node, offset) { return setEndPoint(true, node, offset, this); }, /** * 设置range的结束位置位于node节点,偏移量为offset * 如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符 * @name setEnd * @grammar range.setEnd(node,offset) => Range */ setEnd: function (node, offset) { return setEndPoint(false, node, offset, this); }, /** * 将Range开始位置设置到node节点之后 * @name setStartAfter * @grammar range.setStartAfter(node) => Range * @example * xxx|xx * 执行setStartAfter(i)后 * range.startContainer =>b * range.startOffset =>2 */ setStartAfter: function (node) { return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1); }, /** * 将Range开始位置设置到node节点之前 * @name setStartBefore * @grammar range.setStartBefore(node) => Range * @example * xxx|xx * 执行setStartBefore(i)后 * range.startContainer =>b * range.startOffset =>1 */ setStartBefore: function (node) { return this.setStart(node.parentNode, domUtils.getNodeIndex(node)); }, /** * 将Range结束位置设置到node节点之后 * @name setEndAfter * @grammar range.setEndAfter(node) => Range * @example * xxx|xx * setEndAfter(i)后 * range.endContainer =>b * range.endtOffset =>2 */ setEndAfter: function (node) { return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1); }, /** * 将Range结束位置设置到node节点之前 * @name setEndBefore * @grammar range.setEndBefore(node) => Range * @example * xxx|xx * 执行setEndBefore(i)后 * range.endContainer =>b * range.endtOffset =>1 */ setEndBefore: function (node) { return this.setEnd(node.parentNode, domUtils.getNodeIndex(node)); }, /** * 将Range开始位置设置到node节点内的开始位置 * @name setStartAtFirst * @grammar range.setStartAtFirst(node) => Range */ setStartAtFirst: function (node) { return this.setStart(node, 0); }, /** * 将Range开始位置设置到node节点内的结束位置 * @name setStartAtLast * @grammar range.setStartAtLast(node) => Range */ setStartAtLast: function (node) { return this.setStart(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length); }, /** * 将Range结束位置设置到node节点内的开始位置 * @name setEndAtFirst * @grammar range.setEndAtFirst(node) => Range */ setEndAtFirst: function (node) { return this.setEnd(node, 0); }, /** * 将Range结束位置设置到node节点内的结束位置 * @name setEndAtLast * @grammar range.setEndAtLast(node) => Range */ setEndAtLast: function (node) { return this.setEnd(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length); }, /** * 选中完整的指定节点,并返回包含该节点的range * @name selectNode * @grammar range.selectNode(node) => Range */ selectNode: function (node) { return this.setStartBefore(node).setEndAfter(node); }, /** * 选中node内部的所有节点,并返回对应的range * @name selectNodeContents * @grammar range.selectNodeContents(node) => Range * @example * xx[xxxx]xxx * 执行后 * [xxxxxxxxx] * range.startContainer =>b * range.startOffset =>0 * range.endContainer =>b * range.endOffset =>3 */ selectNodeContents: function (node) { return this.setStart(node, 0).setEndAtLast(node); }, /** * 克隆一个新的range对象 * @name cloneRange * @grammar range.cloneRange() => Range */ cloneRange: function () { var me = this; return new Range(me.document).setStart(me.startContainer, me.startOffset).setEnd(me.endContainer, me.endOffset); }, /** * 让选区闭合到尾部,若toStart为真,则闭合到头部 * @name collapse * @grammar range.collapse() => Range * @grammar range.collapse(true) => Range //闭合选区到头部 */ collapse: function (toStart) { var me = this; if (toStart) { me.endContainer = me.startContainer; me.endOffset = me.startOffset; } else { me.startContainer = me.endContainer; me.startOffset = me.endOffset; } me.collapsed = true; return me; }, /** * 调整range的边界,使其"收缩"到最小的位置 * @name shrinkBoundary * @grammar range.shrinkBoundary() => Range //range开始位置和结束位置都调整,参见adjustmentBoundary * @grammar range.shrinkBoundary(true) => Range //仅调整开始位置,忽略结束位置 * @example * xx[xxxxx] ==> xx[xxxxx] * x[xx]xxx ==> x[xx]xxx * [xxxxxxxxxxx] ==> [xxxxxxxxxxx] */ shrinkBoundary: function (ignoreEnd) { var me = this, child, collapsed = me.collapsed; function check(node) { return node.nodeType == 1 && !domUtils.isBookmarkNode(node) && !dtd.$empty[node.tagName] && !dtd.$nonChild[node.tagName] } while (me.startContainer.nodeType == 1 //是element && (child = me.startContainer.childNodes[me.startOffset]) //子节点也是element && check(child)) { me.setStart(child, 0); } if (collapsed) { return me.collapse(true); } if (!ignoreEnd) { while (me.endContainer.nodeType == 1//是element && me.endOffset > 0 //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错 && (child = me.endContainer.childNodes[me.endOffset - 1]) //子节点也是element && check(child)) { me.setEnd(child, child.childNodes.length); } } return me; }, /** * 获取当前range所在位置的公共祖先节点,当前range位置可以位于文本节点内,也可以包含整个元素节点,也可以位于两个节点之间 * @name getCommonAncestor * @grammar range.getCommonAncestor([includeSelf, ignoreTextNode]) => Element * @example * xx[xxxx]xxxx ==>getCommonAncestor() ==> b * [] * range.startContainer ==> b * range.startOffset ==> 0 * range.endContainer ==> b * range.endOffset ==> 1 * range.getCommonAncestor() ==> b * range.getCommonAncestor(true) ==> img * xxx|xx * range.startContainer ==> textNode * range.startOffset ==> 3 * range.endContainer ==> textNode * range.endOffset ==> 3 * range.getCommonAncestor() ==> textNode * range.getCommonAncestor(null,true) ==> b */ getCommonAncestor: function (includeSelf, ignoreTextNode) { var me = this, start = me.startContainer, end = me.endContainer; if (start === end) { if (includeSelf && selectOneNode(this)) { start = start.childNodes[me.startOffset]; if (start.nodeType == 1) return start; } //只有在上来就相等的情况下才会出现是文本的情况 return ignoreTextNode && start.nodeType == 3 ? start.parentNode : start; } return domUtils.getCommonAncestor(start, end); }, /** * 调整边界容器,如果是textNode,就调整到elementNode上 * @name trimBoundary * @grammar range.trimBoundary([ignoreEnd]) => Range //true忽略结束边界 * @example * DOM Element : * |xxx * startContainer = xxx; startOffset = 0 * //执行后本方法后 * startContainer = ; startOffset = 0 * @example * Dom Element : * xx|x * startContainer = xxx; startOffset = 2 * //执行本方法后,xxx被实实在在地切分成两个TextNode * startContainer = ; startOffset = 1 */ trimBoundary: function (ignoreEnd) { this.txtToElmBoundary(); var start = this.startContainer, offset = this.startOffset, collapsed = this.collapsed, end = this.endContainer; if (start.nodeType == 3) { if (offset == 0) { this.setStartBefore(start); } else { if (offset >= start.nodeValue.length) { this.setStartAfter(start); } else { var textNode = domUtils.split(start, offset); //跟新结束边界 if (start === end) { this.setEnd(textNode, this.endOffset - offset); } else if (start.parentNode === end) { this.endOffset += 1; } this.setStartBefore(textNode); } } if (collapsed) { return this.collapse(true); } } if (!ignoreEnd) { offset = this.endOffset; end = this.endContainer; if (end.nodeType == 3) { if (offset == 0) { this.setEndBefore(end); } else { offset < end.nodeValue.length && domUtils.split(end, offset); this.setEndAfter(end); } } } return this; }, /** * 如果选区在文本的边界上,就扩展选区到文本的父节点上 * @name txtToElmBoundary * @example * Dom Element : * |xxx * startContainer = xxx; startOffset = 0 * //本方法执行后 * startContainer = ; startOffset = 0 * @example * Dom Element : * xxx| * startContainer = xxx; startOffset = 3 * //本方法执行后 * startContainer = ; startOffset = 1 */ txtToElmBoundary: function () { function adjust(r, c) { var container = r[c + 'Container'], offset = r[c + 'Offset']; if (container.nodeType == 3) { if (!offset) { r['set' + c.replace(/(\w)/, function (a) { return a.toUpperCase(); }) + 'Before'](container); } else if (offset >= container.nodeValue.length) { r['set' + c.replace(/(\w)/, function (a) { return a.toUpperCase(); }) + 'After' ](container); } } } if (!this.collapsed) { adjust(this, 'start'); adjust(this, 'end'); } return this; }, /** * 在当前选区的开始位置前插入一个节点或者fragment,range的开始位置会在插入节点的前边 * @name insertNode * @grammar range.insertNode(node) => Range //node可以是textNode,elementNode,fragment * @example * Range : * xxx[x

xxxx

xxxx]x

sdfsdf

* 待插入Node : *

ssss

* 执行本方法后的Range : * xxx[

ssss

x

xxxx

xxxx]x

sdfsdf

*/ insertNode: function (node) { var first = node, length = 1; if (node.nodeType == 11) { first = node.firstChild; length = node.childNodes.length; } this.trimBoundary(true); var start = this.startContainer, offset = this.startOffset; var nextNode = start.childNodes[ offset ]; if (nextNode) { start.insertBefore(node, nextNode); } else { start.appendChild(node); } if (first.parentNode === this.endContainer) { this.endOffset = this.endOffset + length; } return this.setStartBefore(first); }, /** * 设置光标闭合位置,toEnd设置为true时光标将闭合到选区的结尾 * @name setCursor * @grammar range.setCursor([toEnd]) => Range //toEnd为true时,光标闭合到选区的末尾 */ setCursor: function (toEnd, noFillData) { return this.collapse(!toEnd).select(noFillData); }, /** * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置 * @name createBookmark * @grammar range.createBookmark([serialize]) => Object //{start:开始标记,end:结束标记,id:serialize} serialize为真时,开始结束标记是插入节点的id,否则是插入节点的引用 */ createBookmark: function (serialize, same) { var endNode, startNode = this.document.createElement('span'); startNode.style.cssText = 'display:none;line-height:0px;'; startNode.appendChild(this.document.createTextNode('\u200D')); startNode.id = '_baidu_bookmark_start_' + (same ? '' : guid++); if (!this.collapsed) { endNode = startNode.cloneNode(true); endNode.id = '_baidu_bookmark_end_' + (same ? '' : guid++); } this.insertNode(startNode); if (endNode) { this.collapse().insertNode(endNode).setEndBefore(endNode); } this.setStartAfter(startNode); return { start: serialize ? startNode.id : startNode, end: endNode ? serialize ? endNode.id : endNode : null, id: serialize } }, /** * 移动边界到书签位置,并删除插入的书签节点 * @name moveToBookmark * @grammar range.moveToBookmark(bookmark) => Range //让当前的range选到给定bookmark的位置,bookmark对象是由range.createBookmark创建的 */ moveToBookmark: function (bookmark) { var start = bookmark.id ? this.document.getElementById(bookmark.start) : bookmark.start, end = bookmark.end && bookmark.id ? this.document.getElementById(bookmark.end) : bookmark.end; this.setStartBefore(start); domUtils.remove(start); if (end) { this.setEndBefore(end); domUtils.remove(end); } else { this.collapse(true); } return this; }, /** * 调整range的边界,使其"放大"到最近的父block节点 * @name enlarge * @grammar range.enlarge() => Range * @example *

xxxx[xxxxxx]

xxx

==> [

xxxxxxxxxx

]

xxx

*/ enlarge: function (toBlock, stopFn) { var isBody = domUtils.isBody, pre, node, tmp = this.document.createTextNode(''); if (toBlock) { node = this.startContainer; if (node.nodeType == 1) { if (node.childNodes[this.startOffset]) { pre = node = node.childNodes[this.startOffset] } else { node.appendChild(tmp); pre = node = tmp; } } else { pre = node; } while (1) { if (domUtils.isBlockElm(node)) { node = pre; while ((pre = node.previousSibling) && !domUtils.isBlockElm(pre)) { node = pre; } this.setStartBefore(node); break; } pre = node; node = node.parentNode; } node = this.endContainer; if (node.nodeType == 1) { if (pre = node.childNodes[this.endOffset]) { node.insertBefore(tmp, pre); } else { node.appendChild(tmp); } pre = node = tmp; } else { pre = node; } while (1) { if (domUtils.isBlockElm(node)) { node = pre; while ((pre = node.nextSibling) && !domUtils.isBlockElm(pre)) { node = pre; } this.setEndAfter(node); break; } pre = node; node = node.parentNode; } if (tmp.parentNode === this.endContainer) { this.endOffset--; } domUtils.remove(tmp); } // 扩展边界到最大 if (!this.collapsed) { while (this.startOffset == 0) { if (stopFn && stopFn(this.startContainer)) { break; } if (isBody(this.startContainer)) { break; } this.setStartBefore(this.startContainer); } while (this.endOffset == (this.endContainer.nodeType == 1 ? this.endContainer.childNodes.length : this.endContainer.nodeValue.length)) { if (stopFn && stopFn(this.endContainer)) { break; } if (isBody(this.endContainer)) { break; } this.setEndAfter(this.endContainer); } } return this; }, /** * 调整Range的边界,使其"缩小"到最合适的位置 * @name adjustmentBoundary * @grammar range.adjustmentBoundary() => Range //参见shrinkBoundary * @example * xx[xxxxx] ==> xx[xxxxx] * x[xx]xxx ==> x[xx]xxx */ adjustmentBoundary: function () { if (!this.collapsed) { while (!domUtils.isBody(this.startContainer) && this.startOffset == this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length ) { this.setStartAfter(this.startContainer); } while (!domUtils.isBody(this.endContainer) && !this.endOffset) { this.setEndBefore(this.endContainer); } } return this; }, /** * 给range选区中的内容添加给定的标签,主要用于inline标签 * @name applyInlineStyle * @grammar range.applyInlineStyle(tagName) => Range //tagName为需要添加的样式标签名 * @grammar range.applyInlineStyle(tagName,attrs) => Range //attrs为属性json对象 * @desc *

xxxx[xxxx]x

==> range.applyInlineStyle("strong") ==>

xxxx[xxxx]x

*

xx[ddyyyy]x

==> range.applyInlineStyle("strong") ==>

xx[ddyyyy]x

*

xxxx[xxxx]x

==> range.applyInlineStyle("strong",{"style":"font-size:12px"}) ==>

xxxx[xxxx]x

*/ applyInlineStyle: function (tagName, attrs, list) { if (this.collapsed)return this; this.trimBoundary().enlarge(false, function (node) { return node.nodeType == 1 && domUtils.isBlockElm(node) }).adjustmentBoundary(); var bookmark = this.createBookmark(), end = bookmark.end, filterFn = function (node) { return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace(node); }, current = domUtils.getNextDomNode(bookmark.start, false, filterFn), node, pre, range = this.cloneRange(); while (current && (domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING)) { if (current.nodeType == 3 || dtd[tagName][current.tagName]) { range.setStartBefore(current); node = current; while (node && (node.nodeType == 3 || dtd[tagName][node.tagName]) && node !== end) { pre = node; node = domUtils.getNextDomNode(node, node.nodeType == 1, null, function (parent) { return dtd[tagName][parent.tagName]; }); } var frag = range.setEndAfter(pre).extractContents(), elm; if (list && list.length > 0) { var level, top; top = level = list[0].cloneNode(false); for (var i = 1, ci; ci = list[i++];) { level.appendChild(ci.cloneNode(false)); level = level.firstChild; } elm = level; } else { elm = range.document.createElement(tagName); } if (attrs) { domUtils.setAttributes(elm, attrs); } elm.appendChild(frag); range.insertNode(list ? top : elm); //处理下滑线在a上的情况 var aNode; if (tagName == 'span' && attrs.style && /text\-decoration/.test(attrs.style) && (aNode = domUtils.findParentByTagName(elm, 'a', true))) { domUtils.setAttributes(aNode, attrs); domUtils.remove(elm, true); elm = aNode; } else { domUtils.mergeSibling(elm); domUtils.clearEmptySibling(elm); } //去除子节点相同的 domUtils.mergeChild(elm, attrs); current = domUtils.getNextDomNode(elm, false, filterFn); domUtils.mergeToParent(elm); if (node === end) { break; } } else { current = domUtils.getNextDomNode(current, true, filterFn); } } return this.moveToBookmark(bookmark); }, /** * 对当前range选中的节点,去掉给定的标签节点,但标签中的内容保留,主要用于处理inline元素 * @name removeInlineStyle * @grammar range.removeInlineStyle(tagNames) => Range //tagNames 为需要去掉的样式标签名,支持"b"或者["b","i","u"] * @desc * xx[xxxxyyyzz]z => range.removeInlineStyle(["em"]) => xx[xxxxyyyzz]z */ removeInlineStyle: function (tagNames) { if (this.collapsed)return this; tagNames = utils.isArray(tagNames) ? tagNames : [tagNames]; this.shrinkBoundary().adjustmentBoundary(); var start = this.startContainer, end = this.endContainer; while (1) { if (start.nodeType == 1) { if (utils.indexOf(tagNames, start.tagName.toLowerCase()) > -1) { break; } if (start.tagName.toLowerCase() == 'body') { start = null; break; } } start = start.parentNode; } while (1) { if (end.nodeType == 1) { if (utils.indexOf(tagNames, end.tagName.toLowerCase()) > -1) { break; } if (end.tagName.toLowerCase() == 'body') { end = null; break; } } end = end.parentNode; } var bookmark = this.createBookmark(), frag, tmpRange; if (start) { tmpRange = this.cloneRange().setEndBefore(bookmark.start).setStartBefore(start); frag = tmpRange.extractContents(); tmpRange.insertNode(frag); domUtils.clearEmptySibling(start, true); start.parentNode.insertBefore(bookmark.start, start); } if (end) { tmpRange = this.cloneRange().setStartAfter(bookmark.end).setEndAfter(end); frag = tmpRange.extractContents(); tmpRange.insertNode(frag); domUtils.clearEmptySibling(end, false, true); end.parentNode.insertBefore(bookmark.end, end.nextSibling); } var current = domUtils.getNextDomNode(bookmark.start, false, function (node) { return node.nodeType == 1; }), next; while (current && current !== bookmark.end) { next = domUtils.getNextDomNode(current, true, function (node) { return node.nodeType == 1; }); if (utils.indexOf(tagNames, current.tagName.toLowerCase()) > -1) { domUtils.remove(current, true); } current = next; } return this.moveToBookmark(bookmark); }, /** * 得到一个自闭合的节点,常用于获取自闭和的节点,例如图片节点 * @name getClosedNode * @grammar range.getClosedNode() => node|null * @example * xxxx[]xxx */ getClosedNode: function () { var node; if (!this.collapsed) { var range = this.cloneRange().adjustmentBoundary().shrinkBoundary(); if (selectOneNode(range)) { var child = range.startContainer.childNodes[range.startOffset]; if (child && child.nodeType == 1 && (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName])) { node = child; } } } return node; }, /** * 根据当前range选中内容节点(在页面上表现为反白显示) * @name select * @grammar range.select(); => Range */ select: browser.ie ? function (noFillData, textRange) { var nativeRange; if (!this.collapsed) this.shrinkBoundary(); var node = this.getClosedNode(); if (node && !textRange) { try { nativeRange = this.document.body.createControlRange(); nativeRange.addElement(node); nativeRange.select(); } catch (e) { } return this; } var bookmark = this.createBookmark(), start = bookmark.start, end; nativeRange = this.document.body.createTextRange(); nativeRange.moveToElementText(start); nativeRange.moveStart('character', 1); if (!this.collapsed) { var nativeRangeEnd = this.document.body.createTextRange(); end = bookmark.end; nativeRangeEnd.moveToElementText(end); nativeRange.setEndPoint('EndToEnd', nativeRangeEnd); } else { if (!noFillData && this.startContainer.nodeType != 3) { //使用|x固定住光标 var tmpText = this.document.createTextNode(fillChar), tmp = this.document.createElement('span'); tmp.appendChild(this.document.createTextNode(fillChar)); start.parentNode.insertBefore(tmp, start); start.parentNode.insertBefore(tmpText, start); //当点b,i,u时,不能清除i上边的b removeFillData(this.document, tmpText); fillData = tmpText; mergeSibling(tmp, 'previousSibling'); mergeSibling(start, 'nextSibling'); nativeRange.moveStart('character', -1); nativeRange.collapse(true); } } this.moveToBookmark(bookmark); tmp && domUtils.remove(tmp); //IE在隐藏状态下不支持range操作,catch一下 try { nativeRange.select(); } catch (e) { } return this; } : function (notInsertFillData) { function checkOffset(rng) { function check(node, offset, dir) { if (node.nodeType == 3 && node.nodeValue.length < offset) { rng[dir + 'Offset'] = node.nodeValue.length } } check(rng.startContainer, rng.startOffset, 'start'); check(rng.endContainer, rng.endOffset, 'end'); } var win = domUtils.getWindow(this.document), sel = win.getSelection(), txtNode; //FF下关闭自动长高时滚动条在关闭dialog时会跳 //ff下如果不body.focus将不能定位闭合光标到编辑器内 browser.gecko ? this.document.body.focus() : win.focus(); if (sel) { sel.removeAllRanges(); // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断 // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR' if (this.collapsed && !notInsertFillData) { // //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点 // if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) { // var tmp = this.document.createTextNode(''); // this.insertNode(tmp).setStart(tmp, 0).collapse(true); // } // //处理光标落在文本节点的情况 //处理以下的情况 //|xxxx //xxxx|xxxx //xxxx| var start = this.startContainer, child = start; if (start.nodeType == 1) { child = start.childNodes[this.startOffset]; } if (!(start.nodeType == 3 && this.startOffset) && (child ? (!child.previousSibling || child.previousSibling.nodeType != 3) : (!start.lastChild || start.lastChild.nodeType != 3) ) ) { txtNode = this.document.createTextNode(fillChar); //跟着前边走 this.insertNode(txtNode); removeFillData(this.document, txtNode); mergeSibling(txtNode, 'previousSibling'); mergeSibling(txtNode, 'nextSibling'); fillData = txtNode; this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true); } } var nativeRange = this.document.createRange(); if (this.collapsed && browser.opera && this.startContainer.nodeType == 1) { var child = this.startContainer.childNodes[this.startOffset]; if (!child) { //往前靠拢 child = this.startContainer.lastChild; if (child && domUtils.isBr(child)) { this.setStartBefore(child).collapse(true); } } else { //向后靠拢 while (child && domUtils.isBlockElm(child)) { if (child.nodeType == 1 && child.childNodes[0]) { child = child.childNodes[0] } else { break; } } child && this.setStartBefore(child).collapse(true) } } //是createAddress最后一位算的不准,现在这里进行微调 checkOffset(this); nativeRange.setStart(this.startContainer, this.startOffset); nativeRange.setEnd(this.endContainer, this.endOffset); sel.addRange(nativeRange); } return this; }, /** * 滚动条跳到当然range开始的位置 * @name scrollToView * @grammar range.scrollToView([win,offset]) => Range //针对window对象,若不指定,将以编辑区域的窗口为准,offset偏移量 */ scrollToView: function (win, offset) { win = win ? window : domUtils.getWindow(this.document); var me = this, span = me.document.createElement('span'); //trace:717 span.innerHTML = ' '; me.cloneRange().insertNode(span); domUtils.scrollToView(span, win, offset); domUtils.remove(span); return me; }, inFillChar: function () { var start = this.startContainer; if (this.collapsed && start.nodeType == 3 && start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), '').length + 1 == start.nodeValue.length ) { return true; } return false; }, createAddress: function (ignoreEnd, ignoreTxt) { var addr = {}, me = this; function getAddress(isStart) { var node = isStart ? me.startContainer : me.endContainer; var parents = domUtils.findParents(node, true, function (node) { return !domUtils.isBody(node) }), addrs = []; for (var i = 0, ci; ci = parents[i++];) { addrs.push(domUtils.getNodeIndex(ci, ignoreTxt)); } var firstIndex = 0; if (ignoreTxt) { if (node.nodeType == 3) { var tmpNode = node; while (tmpNode = tmpNode.previousSibling) { if (tmpNode.nodeType == 3) { firstIndex += tmpNode.nodeValue.replace(fillCharReg, '').length; } else { break; } } firstIndex += (isStart ? me.startOffset : me.endOffset) - (fillCharReg.test(node.nodeValue) ? 1 : 0 ) } else { node = node.childNodes[ isStart ? me.startOffset : me.endOffset]; if (node) { firstIndex = domUtils.getNodeIndex(node, ignoreTxt); } else { node = isStart ? me.startContainer : me.endContainer; var first = node.firstChild; while (first) { if (domUtils.isFillChar(first)) { first = first.nextSibling; continue; } firstIndex++; if (first.nodeType == 3) { while (first && first.nodeType == 3) { first = first.nextSibling; } } else { first = first.nextSibling; } } } } } else { firstIndex = isStart ? me.startOffset : me.endOffset } if (firstIndex < 0) { firstIndex = 0; } addrs.push(firstIndex); return addrs; } addr.startAddress = getAddress(true); if (!ignoreEnd) { addr.endAddress = me.collapsed ? [].concat(addr.startAddress) : getAddress(); } return addr; }, moveToAddress: function (addr, ignoreEnd) { var me = this; function getNode(address, isStart) { var tmpNode = me.document.body, parentNode, offset; for (var i = 0, ci, l = address.length; i < l; i++) { ci = address[i]; parentNode = tmpNode; tmpNode = tmpNode.childNodes[ci]; if (!tmpNode) { offset = ci; break; } } if (isStart) { if (tmpNode) { me.setStartBefore(tmpNode) } else { me.setStart(parentNode, offset) } } else { if (tmpNode) { me.setEndBefore(tmpNode) } else { me.setEnd(parentNode, offset) } } } getNode(addr.startAddress, true); !ignoreEnd && addr.endAddress && getNode(addr.endAddress); return me; }, equals: function (rng) { for (var p in this) { if (this.hasOwnProperty(p)) { if (this[p] !== rng[p]) return false } } return true; } }; })(); ///import editor.js ///import core/browser.js ///import core/dom/dom.js ///import core/dom/dtd.js ///import core/dom/domUtils.js ///import core/dom/Range.js /** * @class baidu.editor.dom.Selection Selection类 */ (function () { function getBoundaryInformation(range, start) { var getIndex = domUtils.getNodeIndex; range = range.duplicate(); range.collapse(start); var parent = range.parentElement(); //如果节点里没有子节点,直接退出 if (!parent.hasChildNodes()) { return {container: parent, offset: 0}; } var siblings = parent.children, child, testRange = range.duplicate(), startIndex = 0, endIndex = siblings.length - 1, index = -1, distance; while (startIndex <= endIndex) { index = Math.floor((startIndex + endIndex) / 2); child = siblings[index]; testRange.moveToElementText(child); var position = testRange.compareEndPoints('StartToStart', range); if (position > 0) { endIndex = index - 1; } else if (position < 0) { startIndex = index + 1; } else { //trace:1043 return {container: parent, offset: getIndex(child)}; } } if (index == -1) { testRange.moveToElementText(parent); testRange.setEndPoint('StartToStart', range); distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length; siblings = parent.childNodes; if (!distance) { child = siblings[siblings.length - 1]; return {container: child, offset: child.nodeValue.length}; } var i = siblings.length; while (distance > 0) { distance -= siblings[ --i ].nodeValue.length; } return {container: siblings[i], offset: -distance}; } testRange.collapse(position > 0); testRange.setEndPoint(position > 0 ? 'StartToStart' : 'EndToStart', range); distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length; if (!distance) { return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ? {container: parent, offset: getIndex(child) + (position > 0 ? 0 : 1)} : {container: child, offset: position > 0 ? 0 : child.childNodes.length} } while (distance > 0) { try { var pre = child; child = child[position > 0 ? 'previousSibling' : 'nextSibling']; distance -= child.nodeValue.length; } catch (e) { return {container: parent, offset: getIndex(pre)}; } } return {container: child, offset: position > 0 ? -distance : child.nodeValue.length + distance} } /** * 将ieRange转换为Range对象 * @param {Range} ieRange ieRange对象 * @param {Range} range Range对象 * @return {Range} range 返回转换后的Range对象 */ function transformIERangeToRange(ieRange, range) { if (ieRange.item) { range.selectNode(ieRange.item(0)); } else { var bi = getBoundaryInformation(ieRange, true); range.setStart(bi.container, bi.offset); if (ieRange.compareEndPoints('StartToEnd', ieRange) != 0) { bi = getBoundaryInformation(ieRange, false); range.setEnd(bi.container, bi.offset); } } return range; } /** * 获得ieRange * @param {Selection} sel Selection对象 * @return {ieRange} 得到ieRange */ function _getIERange(sel) { var ieRange; //ie下有可能报错 try { ieRange = sel.getNative().createRange(); } catch (e) { return null; } var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement(); if (( el.ownerDocument || el ) === sel.document) { return ieRange; } return null; } var Selection = dom.Selection = function (doc) { var me = this, iframe; me.document = doc; if (ie) { iframe = domUtils.getWindow(doc).frameElement; domUtils.on(iframe, 'beforedeactivate', function () { me._bakIERange = me.getIERange(); }); domUtils.on(iframe, 'activate', function () { try { if (!_getIERange(me) && me._bakIERange) { me._bakIERange.select(); } } catch (ex) { } me._bakIERange = null; }); } iframe = doc = null; }; Selection.prototype = { /** * 获取原生seleciton对象 * @public * @function * @name baidu.editor.dom.Selection.getNative * @return {Selection} 获得selection对象 */ getNative: function () { var doc = this.document; try { return !doc ? null : ie ? doc.selection : domUtils.getWindow(doc).getSelection(); } catch (e) { return null; } }, /** * 获得ieRange * @public * @function * @name baidu.editor.dom.Selection.getIERange * @return {ieRange} 返回ie原生的Range */ getIERange: function () { var ieRange = _getIERange(this); if (!ieRange) { if (this._bakIERange) { return this._bakIERange; } } return ieRange; }, /** * 缓存当前选区的range和选区的开始节点 * @public * @function * @name baidu.editor.dom.Selection.cache */ cache: function () { this.clear(); this._cachedRange = this.getRange(); this._cachedStartElement = this.getStart(); this._cachedStartElementPath = this.getStartElementPath(); }, getStartElementPath: function () { if (this._cachedStartElementPath) { return this._cachedStartElementPath; } var start = this.getStart(); if (start) { return domUtils.findParents(start, true, null, true) } return []; }, /** * 清空缓存 * @public * @function * @name baidu.editor.dom.Selection.clear */ clear: function () { this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null; }, /** * 编辑器是否得到了选区 */ isFocus: function () { try { return browser.ie && _getIERange(this) || !browser.ie && this.getNative().rangeCount ? true : false; } catch (e) { return false; } }, /** * 获取选区对应的Range * @public * @function * @name baidu.editor.dom.Selection.getRange * @returns {baidu.editor.dom.Range} 得到Range对象 */ getRange: function () { var me = this; function optimze(range) { var child = me.document.body.firstChild, collapsed = range.collapsed; while (child && child.firstChild) { range.setStart(child, 0); child = child.firstChild; } if (!range.startContainer) { range.setStart(me.document.body, 0) } if (collapsed) { range.collapse(true); } } if (me._cachedRange != null) { return this._cachedRange; } var range = new baidu.editor.dom.Range(me.document); if (ie) { var nativeRange = me.getIERange(); if (nativeRange) { //备份的_bakIERange可能已经实效了,dom树发生了变化比如从源码模式切回来,所以try一下,实效就放到body开始位置 try { transformIERangeToRange(nativeRange, range); } catch (e) { optimze(range); } } else { optimze(range); } } else { var sel = me.getNative(); if (sel && sel.rangeCount) { var firstRange = sel.getRangeAt(0); var lastRange = sel.getRangeAt(sel.rangeCount - 1); range.setStart(firstRange.startContainer, firstRange.startOffset).setEnd(lastRange.endContainer, lastRange.endOffset); if (range.collapsed && domUtils.isBody(range.startContainer) && !range.startOffset) { optimze(range); } } else { //trace:1734 有可能已经不在dom树上了,标识的节点 if (this._bakRange && domUtils.inDoc(this._bakRange.startContainer, this.document)) { return this._bakRange; } optimze(range); } } return this._bakRange = range; }, /** * 获取开始元素,用于状态反射 * @public * @function * @name baidu.editor.dom.Selection.getStart * @return {Element} 获得开始元素 */ getStart: function () { if (this._cachedStartElement) { return this._cachedStartElement; } var range = ie ? this.getIERange() : this.getRange(), tmpRange, start, tmp, parent; if (ie) { if (!range) { //todo 给第一个值可能会有问题 return this.document.body.firstChild; } //control元素 if (range.item) { return range.item(0); } tmpRange = range.duplicate(); //修正ie下x[xx] 闭合后 x|xx tmpRange.text.length > 0 && tmpRange.moveStart('character', 1); tmpRange.collapse(1); start = tmpRange.parentElement(); parent = tmp = range.parentElement(); while (tmp = tmp.parentNode) { if (tmp == start) { start = parent; break; } } } else { range.shrinkBoundary(); start = range.startContainer; if (start.nodeType == 1 && start.hasChildNodes()) { start = start.childNodes[Math.min(start.childNodes.length - 1, range.startOffset)]; } if (start.nodeType == 3) { return start.parentNode; } } return start; }, /** * 得到选区中的文本 * @public * @function * @name baidu.editor.dom.Selection.getText * @return {String} 选区中包含的文本 */ getText: function () { var nativeSel, nativeRange; if (this.isFocus() && (nativeSel = this.getNative())) { nativeRange = browser.ie ? nativeSel.createRange() : nativeSel.getRangeAt(0); return browser.ie ? nativeRange.text : nativeRange.toString(); } return ''; }, clearRange: function () { this.getNative()[browser.ie ? 'empty' : 'removeAllRanges'](); } }; })(); /** * @file * @name UE.Editor * @short Editor * @import editor.js,core/utils.js,core/EventBase.js,core/browser.js,core/dom/dtd.js,core/dom/domUtils.js,core/dom/Range.js,core/dom/Selection.js,plugins/serialize.js * @desc 编辑器主类,包含编辑器提供的大部分公用接口 */ (function () { var uid = 0, _selectionChangeTimer; /** * 替换src和href * @private * @ignore * @param div */ function replaceSrc(div) { var imgs = div.getElementsByTagName("img"), orgSrc; for (var i = 0, img; img = imgs[i++];) { if (orgSrc = img.getAttribute("orgSrc")) { img.src = orgSrc; img.removeAttribute("orgSrc"); } } var as = div.getElementsByTagName("a"); for (var i = 0, ai; ai = as[i++]; i++) { if (ai.getAttribute('data_ue_src')) { ai.setAttribute('href', ai.getAttribute('data_ue_src')) } } } /** * @private * @ignore * @param form 编辑器所在的form元素 * @param editor 编辑器实例对象 */ function setValue(form, editor) { var textarea; if (editor.textarea) { if (utils.isString(editor.textarea)) { for (var i = 0, ti, tis = domUtils.getElementsByTagName(form, 'textarea'); ti = tis[i++];) { if (ti.id == 'ueditor_textarea_' + editor.options.textarea) { textarea = ti; break; } } } else { textarea = editor.textarea; } } if (!textarea) { form.appendChild(textarea = domUtils.createElement(document, 'textarea', { 'name': editor.options.textarea, 'id': 'ueditor_textarea_' + editor.options.textarea, 'style': "display:none" })); //不要产生多个textarea editor.textarea = textarea; } textarea.value = editor.hasContents() ? (editor.options.allHtmlEnabled ? editor.getAllHtml() : editor.getContent(null, null, true)) : '' } /** * UEditor编辑器类 * @name Editor * @desc 创建一个跟编辑器实例 * - ***container*** 编辑器容器对象 * - ***iframe*** 编辑区域所在的iframe对象 * - ***window*** 编辑区域所在的window * - ***document*** 编辑区域所在的document对象 * - ***body*** 编辑区域所在的body对象 * - ***selection*** 编辑区域的选区对象 */ var Editor = UE.Editor = function (options) { var me = this; me.uid = uid++; EventBase.call(me); me.commands = {}; me.options = utils.extend(utils.clone(options || {}), utils.extend(UEDITOR_CONFIG, MY_UEDITOR_CONFIG), true); me.shortcutkeys = {}; //设置默认的常用属性 me.setOpt({ isShow: true, initialContent: '欢迎使用ueditor!', autoClearinitialContent: false, iframeCssUrl: me.options.UEDITOR_HOME_URL + 'themes/iframe.css', textarea: 'editorValue', focus: false, initialFrameWidth: 1000, initialFrameHeight: me.options.minFrameHeight || 320,//兼容老版本配置项 minFrameWidth: 800, minFrameHeight: 220, autoClearEmptyNode: true, fullscreen: false, readonly: false, zIndex: 999, imagePopup: true, enterTag: 'p', pageBreakTag: '_baidu_page_break_tag_', customDomain: false, lang: 'zh-cn', langPath: me.options.UEDITOR_HOME_URL + 'lang/', theme: 'default', themePath: me.options.UEDITOR_HOME_URL + 'themes/', allHtmlEnabled: false, scaleEnabled: false, tableNativeEditInFF: false }); utils.loadFile(document, { src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js", tag: "script", type: "text/javascript", defer: "defer" }, function () { //初始化插件 for (var pi in UE.plugins) { UE.plugins[pi].call(me); } me.langIsReady = true; me.fireEvent("langReady"); }); UE.instants['ueditorInstant' + me.uid] = me; }; Editor.prototype = { /** * 当编辑器ready后执行传入的fn,如果编辑器已经完成ready,就马上执行fn,fn的中的this是编辑器实例。 * 大部分的实例接口都需要放在该方法内部执行,否则在IE下可能会报错。 * @name ready * @grammar editor.ready(fn) fn是当编辑器渲染好后执行的function * @example * var editor = new UE.ui.Editor(); * editor.render("myEditor"); * editor.ready(function(){ * editor.setContent("欢迎使用UEditor!"); * }) */ ready: function (fn) { var me = this; if (fn) { me.isReady ? fn.apply(me) : me.addListener('ready', fn); } }, /** * 为编辑器设置默认参数值。若用户配置为空,则以默认配置为准 * @grammar editor.setOpt(key,value); //传入一个键、值对 * @grammar editor.setOpt({ key:value}); //传入一个json对象 */ setOpt: function (key, val) { var obj = {}; if (utils.isString(key)) { obj[key] = val } else { obj = key; } utils.extend(this.options, obj, true); }, /** * 销毁编辑器实例对象 * @name destroy * @grammar editor.destroy(); */ destroy: function () { var me = this; me.fireEvent('destroy'); var container = me.container.parentNode; var textarea = me.textarea; if (!textarea) { textarea = document.createElement('textarea'); container.parentNode.insertBefore(textarea, container); } else { textarea.style.display = '' } textarea.style.width = container.offsetWidth + 'px'; textarea.style.height = container.offsetHeight + 'px'; textarea.value = me.getContent(); textarea.id = me.key; container.innerHTML = ''; domUtils.remove(container); var key = me.key; //trace:2004 for (var p in me) { if (me.hasOwnProperty(p)) { delete this[p]; } } UE.delEditor(key); }, /** * 渲染编辑器的DOM到指定容器,必须且只能调用一次 * @name render * @grammar editor.render(containerId); //可以指定一个容器ID * @grammar editor.render(containerDom); //也可以直接指定容器对象 */ render: function (container) { var me = this, options = me.options; if (utils.isString(container)) { container = document.getElementById(container); } if (container) { var useBodyAsViewport = ie && browser.version < 9, html = ( ie && browser.version < 9 ? '' : '') + '' + ( options.iframeCssUrl ? '' : '' ) + ''; if (options.customDomain && document.domain != location.hostname) { html += ''; container.appendChild(domUtils.createElement(document, 'iframe', { id: 'baidu_editor_' + me.uid, width: "100%", height: "100%", frameborder: "0", src: 'javascript:void(function(){document.open();document.domain="' + document.domain + '";' + 'document.write("' + html + '");document.close();}())' })); } else { container.innerHTML = ''; var doc = container.firstChild.contentWindow.document; //去掉了原来的判断!browser.webkit,因为会导致onload注册的事件不触发 doc.open(); doc.write(html + ''); doc.close(); me._setup(doc); } container.style.overflow = 'hidden'; } }, /** * 编辑器初始化 * @private * @ignore * @param {Element} doc 编辑器Iframe中的文档对象 */ _setup: function (doc) { var me = this, options = me.options; if (ie) { doc.body.disabled = true; doc.body.contentEditable = true; doc.body.disabled = false; } else { doc.body.contentEditable = true; doc.body.spellcheck = false; } me.document = doc; me.window = doc.defaultView || doc.parentWindow; me.iframe = me.window.frameElement; me.body = doc.body; //设置编辑器最小高度 me.setHeight(Math.max(options.minFrameHeight, options.initialFrameHeight)); me.selection = new dom.Selection(doc); //gecko初始化就能得到range,无法判断isFocus了 var geckoSel; if (browser.gecko && (geckoSel = this.selection.getNative())) { geckoSel.removeAllRanges(); } this._initEvents(); if (options.initialContent) { if (options.autoClearinitialContent) { var oldExecCommand = me.execCommand; me.execCommand = function () { me.fireEvent('firstBeforeExecCommand'); return oldExecCommand.apply(me, arguments); }; this._setDefaultContent(options.initialContent); } else this.setContent(options.initialContent, false, true); } //为form提交提供一个隐藏的textarea for (var form = this.iframe.parentNode; !domUtils.isBody(form); form = form.parentNode) { if (form.tagName == 'FORM') { domUtils.on(form, 'submit', function () { setValue(this, me); }); break; } } //编辑器不能为空内容 if (domUtils.isEmptyNode(me.body)) { me.body.innerHTML = '

' + (browser.ie ? '' : '
') + '

'; } //如果要求focus, 就把光标定位到内容开始 if (options.focus) { setTimeout(function () { me.focus(); //如果自动清除开着,就不需要做selectionchange; !me.options.autoClearinitialContent && me._selectionChange(); }, 0); } if (!me.container) { me.container = this.iframe.parentNode; } if (options.fullscreen && me.ui) { me.ui.setFullScreen(true); } try { me.document.execCommand('2D-position', false, false); } catch (e) { } try { me.document.execCommand('enableInlineTableEditing', false, false); } catch (e) { } try { me.document.execCommand('enableObjectResizing', false, false); } catch (e) { // domUtils.on(me.body,browser.ie ? 'resizestart' : 'resize', function( evt ) { // domUtils.preventDefault(evt) // }); } me._bindshortcutKeys(); me.isReady = 1; me.fireEvent('ready'); options.onready && options.onready.call(me); if (!browser.ie) { domUtils.on(me.window, ['blur', 'focus'], function (e) { //chrome下会出现alt+tab切换时,导致选区位置不对 if (e.type == 'blur') { me._bakRange = me.selection.getRange(); try { me.selection.getNative().removeAllRanges(); } catch (e) { } } else { try { me._bakRange && me._bakRange.select(); } catch (e) { } } }); } //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点 if (browser.gecko && browser.version <= 10902) { //修复ff3.6初始化进来,不能点击获得焦点 me.body.contentEditable = false; setTimeout(function () { me.body.contentEditable = true; }, 100); setInterval(function () { me.body.style.height = me.iframe.offsetHeight - 20 + 'px' }, 100) } !options.isShow && me.setHide(); options.readonly && me.setDisabled(); }, /** * 同步编辑器的数据,为提交数据做准备,主要用于你是手动提交的情况 * @name sync * @grammar editor.sync(); //从编辑器的容器向上查找,如果找到就同步数据 * @grammar editor.sync(formID); //formID制定一个要同步数据的form的id,编辑器的数据会同步到你指定form下 * @desc * 后台取得数据得键值使用你容器上得''name''属性,如果没有就使用参数传入的''textarea'' * @example * editor.sync(); * form.sumbit(); //form变量已经指向了form元素 * */ sync: function (formId) { var me = this, form = formId ? document.getElementById(formId) : domUtils.findParent(me.iframe.parentNode, function (node) { return node.tagName == 'FORM' }, true); form && setValue(form, me); }, /** * 设置编辑器高度 * @name setHeight * @grammar editor.setHeight(number); //纯数值,不带单位 */ setHeight: function (height) { if (height !== parseInt(this.iframe.parentNode.style.height)) { this.iframe.parentNode.style.height = height + 'px'; } this.document.body.style.height = height - 20 + 'px'; }, addshortcutkey: function (cmd, keys) { var obj = {}; if (keys) { obj[cmd] = keys } else { obj = cmd; } utils.extend(this.shortcutkeys, obj) }, _bindshortcutKeys: function () { var me = this, shortcutkeys = this.shortcutkeys; me.addListener('keydown', function (type, e) { var keyCode = e.keyCode || e.which; for (var i in shortcutkeys) { var tmp = shortcutkeys[i].split(','); for (var t = 0, ti; ti = tmp[t++];) { ti = ti.split(':'); var key = ti[0], param = ti[1]; if (/^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) || /^(\d+)$/.test(key)) { if (( (RegExp.$1 == 'ctrl' ? (e.ctrlKey || e.metaKey) : 0) && (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1) && keyCode == RegExp.$3 ) || keyCode == RegExp.$1 ) { me.execCommand(i, param); domUtils.preventDefault(e); } } } } }); }, /** * 获取编辑器内容 * @name getContent * @grammar editor.getContent() => String //若编辑器中只包含字符"<p><br /></p/>"会返回空。 * @grammar editor.getContent(fn) => String * @example * getContent默认是会现调用hasContents来判断编辑器是否为空,如果是,就直接返回空字符串 * 你也可以传入一个fn来接替hasContents的工作,定制判断的规则 * editor.getContent(function(){ * return false //编辑器没有内容 ,getContent直接返回空 * }) */ getContent: function (cmd, fn, isPreview, notSetCursor) { var me = this; if (cmd && utils.isFunction(cmd)) { fn = cmd; cmd = ''; } if (fn ? !fn() : !this.hasContents()) { return ''; } var range = me.selection.getRange(), address = range.createAddress(); me.fireEvent('beforegetcontent', cmd); var reg = new RegExp(domUtils.fillChar, 'g'), //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除 html = me.body.innerHTML.replace(reg, '').replace(/>[\t\r\n]*?<'); me.fireEvent('aftergetcontent', cmd); try { !notSetCursor && range.moveToAddress(address).select(true); } catch (e) { } if (me.serialize) { var node = me.serialize.parseHTML(html); node = me.serialize.transformOutput(node); html = me.serialize.toHTML(node); } if (ie && isPreview) { //trace:2471 //两个br会导致空行,所以这里先注视掉 html = html//.replace(/<\s*br\s*\/?\s*>/gi,'

') .replace(/

\s*?<\/p>/g, '

 

'); } else { //多个 要转换成空格加 的形式,要不预览时会所成一个 html = html.replace(/( )+/g, function (s) { for (var i = 0, str = [], l = s.split(';').length - 1; i < l; i++) { str.push(i % 2 == 0 ? ' ' : ' '); } return str.join(''); }); } return html; }, /** * 取得完整的html代码,可以直接显示成完整的html文档 * @name getAllHtml * @grammar editor.getAllHtml() => String */ getAllHtml: function () { var me = this, headHtml = [], html = ''; me.fireEvent('getAllHtml', headHtml); if (browser.ie && browser.version > 8) { var headHtmlForIE9 = ''; utils.each(me.document.styleSheets, function (si) { headHtmlForIE9 += ( si.href ? '' : ''); }); utils.each(me.document.getElementsByTagName('script'), function (si) { headHtmlForIE9 += si.outerHTML; }); } return '' + (me.options.charset ? '' : '') + (headHtmlForIE9 || me.document.getElementsByTagName('head')[0].innerHTML) + headHtml.join('\n') + '' + '' + me.getContent(null, null, true) + ''; }, /** * 得到编辑器的纯文本内容,但会保留段落格式 * @name getPlainTxt * @grammar editor.getPlainTxt() => String */ getPlainTxt: function () { var reg = new RegExp(domUtils.fillChar, 'g'), html = this.body.innerHTML.replace(/[\n\r]/g, '');//ie要先去了\n在处理 html = html.replace(/<(p|div)[^>]*>(| )<\/\1>/gi, '\n') .replace(//gi, '\n') .replace(/<[^>/]+>/g, '') .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) { return dtd.$block[c] ? '\n' : b ? b : ''; }); //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0 return html.replace(reg, '').replace(/\u00a0/g, ' ').replace(/ /g, ' '); }, /** * 获取编辑器中的纯文本内容,没有段落格式 * @name getContentTxt * @grammar editor.getContentTxt() => String */ getContentTxt: function () { var reg = new RegExp(domUtils.fillChar, 'g'); //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0 return this.body[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').replace(/\u00a0/g, ' '); }, /** * 将html设置到编辑器中, 如果是用于初始化时给编辑器赋初值,则必须放在ready方法内部执行 * @name setContent * @grammar editor.setContent(html) * @example * var editor = new UE.ui.Editor() * editor.ready(function(){ * //需要ready后执行,否则可能报错 * editor.setContent("欢迎使用UEditor!"); * }) */ setContent: function (html, isAppendTo, notFireSelectionchange) { var me = this, inline = utils.extend({a: 1, A: 1}, dtd.$inline, true), lastTagName; html = html .replace(/^[ \t\r\n]*?[ \t\r\n]*?$/, '>') //ie有时的源码会有> <的情况 .replace(/>(?:(\s| )*?)<')//代码高量的\n不能去除 .replace(/[\s\/]?(\w+)?>[ \t\r\n]*?<\/?(\w+)/gi, function (a, b, c) { if (b) { lastTagName = c; } else { b = lastTagName; } return !inline[b] && !inline[c] ? a.replace(/>[ \t\r\n]*?<') : a; }); html = {'html': html}; me.fireEvent('beforesetcontent', html); html = html.html; var serialize = this.serialize; if (serialize) { var node = serialize.parseHTML(html); node = serialize.transformInput(node); node = serialize.filter(node); html = serialize.toHTML(node); } //html.replace(new RegExp('[\t\n\r' + domUtils.fillChar + ']*','g'),''); //去掉了\t\n\r 如果有插入的代码,在源码切换所见即所得模式时,换行都丢掉了 //\r在ie下的不可见字符,在源码切换时会变成多个  //trace:1559 this.body.innerHTML = (isAppendTo ? this.getContent() : '') + html.replace(new RegExp('[\r' + domUtils.fillChar + ']*', 'g'), ''); //处理ie6下innerHTML自动将相对路径转化成绝对路径的问题 if (browser.ie && browser.version < 7) { replaceSrc(this.document.body); } //给文本或者inline节点套p标签 if (me.options.enterTag == 'p') { var child = this.body.firstChild, tmpNode; if (!child || child.nodeType == 1 && (dtd.$cdata[child.tagName] || domUtils.isCustomeNode(child) ) && child === this.body.lastChild) { this.body.innerHTML = '

' + (browser.ie ? ' ' : '
') + '

' + this.body.innerHTML; } else { var p = me.document.createElement('p'); while (child) { while (child && (child.nodeType == 3 || child.nodeType == 1 && dtd.p[child.tagName] && !dtd.$cdata[child.tagName])) { tmpNode = child.nextSibling; p.appendChild(child); child = tmpNode; } if (p.firstChild) { if (!child) { me.body.appendChild(p); break; } else { child.parentNode.insertBefore(p, child); p = me.document.createElement('p'); } } child = child.nextSibling; } } } me.fireEvent('aftersetcontent'); me.fireEvent('contentchange'); !notFireSelectionchange && me._selectionChange(); //清除保存的选区 me._bakRange = me._bakIERange = null; //trace:1742 setContent后gecko能得到焦点问题 var geckoSel; if (browser.gecko && (geckoSel = this.selection.getNative())) { geckoSel.removeAllRanges(); } }, /** * 让编辑器获得焦点,toEnd确定focus位置 * @name focus * @grammar editor.focus([toEnd]) //默认focus到编辑器头部,toEnd为true时focus到内容尾部 */ focus: function (toEnd) { try { var me = this, rng = me.selection.getRange(); if (toEnd) { rng.setStartAtLast(me.body.lastChild).setCursor(false, true); } else { rng.select(true); } } catch (e) { } }, /** * 初始化UE事件及部分事件代理 * @private * @ignore */ _initEvents: function () { var me = this, doc = me.document, win = me.window; me._proxyDomEvent = utils.bind(me._proxyDomEvent, me); domUtils.on(doc, ['click', 'contextmenu', 'mousedown', 'keydown', 'keyup', 'keypress', 'mouseup', 'mouseover', 'mouseout', 'selectstart'], me._proxyDomEvent); domUtils.on(win, ['focus', 'blur'], me._proxyDomEvent); domUtils.on(doc, ['mouseup', 'keydown'], function (evt) { //特殊键不触发selectionchange if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) { return; } if (evt.button == 2)return; me._selectionChange(250, evt); }); //处理拖拽 //ie ff不能从外边拖入 //chrome只针对从外边拖入的内容过滤 var innerDrag = 0, source = browser.ie ? me.body : me.document, dragoverHandler; domUtils.on(source, 'dragstart', function () { innerDrag = 1; }); domUtils.on(source, browser.webkit ? 'dragover' : 'drop', function () { return browser.webkit ? function () { clearTimeout(dragoverHandler); dragoverHandler = setTimeout(function () { if (!innerDrag) { var sel = me.selection, range = sel.getRange(); if (range) { var common = range.getCommonAncestor(); if (common && me.serialize) { var f = me.serialize, node = f.filter( f.transformInput( f.parseHTML( f.word(common.innerHTML) ) ) ); common.innerHTML = f.toHTML(node); } } } innerDrag = 0; }, 200); } : function (e) { if (!innerDrag) { e.preventDefault ? e.preventDefault() : (e.returnValue = false); } innerDrag = 0; } }()); }, /** * 触发事件代理 * @private * @ignore */ _proxyDomEvent: function (evt) { return this.fireEvent(evt.type.replace(/^on/, ''), evt); }, /** * 变化选区 * @private * @ignore */ _selectionChange: function (delay, evt) { var me = this; //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1) // if ( !me.selection.isFocus() ){ // return; // } var hackForMouseUp = false; var mouseX, mouseY; if (browser.ie && browser.version < 9 && evt && evt.type == 'mouseup') { var range = this.selection.getRange(); if (!range.collapsed) { hackForMouseUp = true; mouseX = evt.clientX; mouseY = evt.clientY; } } clearTimeout(_selectionChangeTimer); _selectionChangeTimer = setTimeout(function () { if (!me.selection.getNative()) { return; } //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值. //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响 var ieRange; if (hackForMouseUp && me.selection.getNative().type == 'None') { ieRange = me.document.body.createTextRange(); try { ieRange.moveToPoint(mouseX, mouseY); } catch (ex) { ieRange = null; } } var bakGetIERange; if (ieRange) { bakGetIERange = me.selection.getIERange; me.selection.getIERange = function () { return ieRange; }; } me.selection.cache(); if (bakGetIERange) { me.selection.getIERange = bakGetIERange; } if (me.selection._cachedRange && me.selection._cachedStartElement) { me.fireEvent('beforeselectionchange'); // 第二个参数causeByUi为true代表由用户交互造成的selectionchange. me.fireEvent('selectionchange', !!evt); me.fireEvent('afterselectionchange'); me.selection.clear(); } }, delay || 50); }, _callCmdFn: function (fnName, args) { var cmdName = args[0].toLowerCase(), cmd, cmdFn; cmd = this.commands[cmdName] || UE.commands[cmdName]; cmdFn = cmd && cmd[fnName]; //没有querycommandstate或者没有command的都默认返回0 if ((!cmd || !cmdFn) && fnName == 'queryCommandState') { return 0; } else if (cmdFn) { return cmdFn.apply(this, args); } }, /** * 执行编辑命令cmdName,完成富文本编辑效果 * @name execCommand * @grammar editor.execCommand(cmdName) => {*} */ execCommand: function (cmdName) { cmdName = cmdName.toLowerCase(); var me = this, result, cmd = me.commands[cmdName] || UE.commands[cmdName]; if (!cmd || !cmd.execCommand) { return null; } if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) { me.__hasEnterExecCommand = true; if (me.queryCommandState(cmdName) != -1) { me.fireEvent('beforeexeccommand', cmdName); result = this._callCmdFn('execCommand', arguments); !me._ignoreContentChange && me.fireEvent('contentchange'); me.fireEvent('afterexeccommand', cmdName); } me.__hasEnterExecCommand = false; } else { result = this._callCmdFn('execCommand', arguments); !me._ignoreContentChange && me.fireEvent('contentchange') } !me._ignoreContentChange && me._selectionChange(); return result; }, /** * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态 * @name queryCommandState * @grammar editor.queryCommandState(cmdName) => (-1|0|1) * @desc * * ''-1'' 当前命令不可用 * * ''0'' 当前命令可用 * * ''1'' 当前命令已经执行过了 */ queryCommandState: function (cmdName) { return this._callCmdFn('queryCommandState', arguments); }, /** * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值 * @name queryCommandValue * @grammar editor.queryCommandValue(cmdName) => {*} */ queryCommandValue: function (cmdName) { return this._callCmdFn('queryCommandValue', arguments); }, /** * 检查编辑区域中是否有内容,若包含tags中的节点类型,直接返回true * @name hasContents * @desc * 默认有文本内容,或者有以下节点都不认为是空 * {table:1,ul:1,ol:1,dl:1,iframe:1,area:1,base:1,col:1,hr:1,img:1,embed:1,input:1,link:1,meta:1,param:1} * @grammar editor.hasContents() => (true|false) * @grammar editor.hasContents(tags) => (true|false) //若文档中包含tags数组里对应的tag,直接返回true * @example * editor.hasContents(['span']) //如果编辑器里有这些,不认为是空 */ hasContents: function (tags) { if (tags) { for (var i = 0, ci; ci = tags[i++];) { if (this.document.getElementsByTagName(ci).length > 0) { return true; } } } if (!domUtils.isEmptyBlock(this.body)) { return true } //随时添加,定义的特殊标签如果存在,不能认为是空 tags = ['div']; for (i = 0; ci = tags[i++];) { var nodes = domUtils.getElementsByTagName(this.document, ci); for (var n = 0, cn; cn = nodes[n++];) { if (domUtils.isCustomeNode(cn)) { return true; } } } return false; }, /** * 重置编辑器,可用来做多个tab使用同一个编辑器实例 * @name reset * @desc * * 清空编辑器内容 * * 清空回退列表 * @grammar editor.reset() */ reset: function () { this.fireEvent('reset'); }, setEnabled: function () { var me = this, range; if (me.body.contentEditable == 'false') { me.body.contentEditable = true; range = me.selection.getRange(); //有可能内容丢失了 try { range.moveToBookmark(me.lastBk); delete me.lastBk } catch (e) { range.setStartAtFirst(me.body).collapse(true) } range.select(true); if (me.bkqueryCommandState) { me.queryCommandState = me.bkqueryCommandState; delete me.bkqueryCommandState; } me.fireEvent('selectionchange'); } }, /** * 设置当前编辑区域可以编辑 * @name enable * @grammar editor.enable() */ enable: function () { return this.setEnabled(); }, setDisabled: function (except) { var me = this; except = except ? utils.isArray(except) ? except : [except] : []; if (me.body.contentEditable == 'true') { if (!me.lastBk) { me.lastBk = me.selection.getRange().createBookmark(true); } me.body.contentEditable = false; me.bkqueryCommandState = me.queryCommandState; me.queryCommandState = function (type) { if (utils.indexOf(except, type) != -1) { return me.bkqueryCommandState.apply(me, arguments); } return -1; }; me.fireEvent('selectionchange'); } }, /** 设置当前编辑区域不可编辑,except中的命令除外 * @name disable * @grammar editor.disable() * @grammar editor.disable(except) //例外的命令,也即即使设置了disable,此处配置的命令仍然可以执行 * @example * //禁用工具栏中除加粗和插入图片之外的所有功能 * editor.disable(['bold','insertimage']);//可以是单一的String,也可以是Array */ disable: function (except) { return this.setDisabled(except); }, /** * 设置默认内容 * @ignore * @private * @param {String} cont 要存入的内容 */ _setDefaultContent: function () { function clear() { var me = this; if (me.document.getElementById('initContent')) { me.body.innerHTML = '

' + (ie ? '' : '
') + '

'; me.removeListener('firstBeforeExecCommand focus', clear); setTimeout(function () { me.focus(); me._selectionChange(); }, 0) } } return function (cont) { var me = this; me.body.innerHTML = '

' + cont + '

'; if (browser.ie && browser.version < 7) { replaceSrc(me.body); } me.addListener('firstBeforeExecCommand focus', clear); } }(), /** * show方法的兼容版本 * @private * @ignore */ setShow: function () { var me = this, range = me.selection.getRange(); if (me.container.style.display == 'none') { //有可能内容丢失了 try { range.moveToBookmark(me.lastBk); delete me.lastBk } catch (e) { range.setStartAtFirst(me.body).collapse(true) } //ie下focus实效,所以做了个延迟 setTimeout(function () { range.select(true); }, 100); me.container.style.display = ''; } }, /** * 显示编辑器 * @name show * @grammar editor.show() */ show: function () { return this.setShow(); }, /** * hide方法的兼容版本 * @private * @ignore */ setHide: function () { var me = this; if (!me.lastBk) { me.lastBk = me.selection.getRange().createBookmark(true); } me.container.style.display = 'none' }, /** * 隐藏编辑器 * @name hide * @grammar editor.hide() */ hide: function () { return this.setHide(); }, /** * 根据制定的路径,获取对应的语言资源 * @name getLang * @grammar editor.getLang(path) => (JSON|String) 路径根据的是lang目录下的语言文件的路径结构 * @example * editor.getLang('contextMenu.delete') //如果当前是中文,那返回是的是删除 */ getLang: function (path) { var lang = UE.I18N[this.options.lang]; if (!lang) { throw Error("not import language file"); } path = (path || "").split("."); for (var i = 0, ci; ci = path[i++];) { lang = lang[ci]; if (!lang)break; } return lang; }, /** * 计算编辑器当前内容的长度 * @name getContentLength * @grammar editor.getContentLength(ingoneHtml,tagNames) => * @example * editor.getLang(true) */ getContentLength: function (ingoneHtml, tagNames) { var count = this.getContent(false, false, false, true).length; if (ingoneHtml) { tagNames = (tagNames || []).concat([ 'hr', 'img', 'iframe']); count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length; for (var i = 0, ci; ci = tagNames[i++];) { count += this.document.getElementsByTagName(ci).length; } } return count; } /** * 得到dialog实例对象 * @name getDialog * @grammar editor.getDialog(dialogName) => Object * @example * var dialog = editor.getDialog("insertimage"); * dialog.open(); //打开dialog * dialog.close(); //关闭dialog */ }; utils.inherits(Editor, EventBase); })(); /** * @file * @name UE.ajax * @short Ajax * @desc UEditor内置的ajax请求模块 * @import core/utils.js * @user: taoqili * @date: 11-8-18 * @time: 下午3:18 */ UE.ajax = function () { /** * 创建一个ajaxRequest对象 */ var fnStr = 'XMLHttpRequest()'; try { new ActiveXObject("Msxml2.XMLHTTP"); fnStr = 'ActiveXObject(\'Msxml2.XMLHTTP\')'; } catch (e) { try { new ActiveXObject("Microsoft.XMLHTTP"); fnStr = 'ActiveXObject(\'Microsoft.XMLHTTP\')' } catch (e) { } } var creatAjaxRequest = new Function('return new ' + fnStr); /** * 将json参数转化成适合ajax提交的参数列表 * @param json */ function json2str(json) { var strArr = []; for (var i in json) { //忽略默认的几个参数 if (i == "method" || i == "timeout" || i == "async") continue; //传递过来的对象和函数不在提交之列 if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) { strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i])); } } return strArr.join("&"); } return { /** * @name request * @desc 发出ajax请求,ajaxOpt中默认包含method,timeout,async,data,onsuccess以及onerror等六个,支持自定义添加参数 * @grammar UE.ajax.request(url,ajaxOpt); * @example * UE.ajax.request('http://www.xxxx.com/test.php',{ * //可省略,默认POST * method:'POST', * //可以自定义参数 * content:'这里是提交的内容', * //也可以直接传json,但是只能命名为data,否则当做一般字符串处理 * data:{ * name:'UEditor', * age:'1' * } * onsuccess:function(xhr){ * console.log(xhr.responseText); * }, * onerror:function(xhr){ * console.log(xhr.responseText); * } * }) * @param ajaxOptions */ request: function (url, ajaxOptions) { var ajaxRequest = creatAjaxRequest(), //是否超时 timeIsOut = false, //默认参数 defaultAjaxOptions = { method: "POST", timeout: 5000, async: true, data: {},//需要传递对象的话只能覆盖 onsuccess: function () { }, onerror: function () { } }; if (typeof url === "object") { ajaxOptions = url; url = ajaxOptions.url; } if (!ajaxRequest || !url) return; var ajaxOpts = ajaxOptions ? utils.extend(defaultAjaxOptions, ajaxOptions) : defaultAjaxOptions; var submitStr = json2str(ajaxOpts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing" //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串 if (!utils.isEmptyObject(ajaxOpts.data)) { submitStr += (submitStr ? "&" : "") + json2str(ajaxOpts.data); } //超时检测 var timerID = setTimeout(function () { if (ajaxRequest.readyState != 4) { timeIsOut = true; ajaxRequest.abort(); clearTimeout(timerID); } }, ajaxOpts.timeout); var method = ajaxOpts.method.toUpperCase(); var str = url + (url.indexOf("?") == -1 ? "?" : "&") + (method == "POST" ? "" : submitStr + "&noCache=" + +new Date); ajaxRequest.open(method, str, ajaxOpts.async); ajaxRequest.onreadystatechange = function () { if (ajaxRequest.readyState == 4) { if (!timeIsOut && ajaxRequest.status == 200) { ajaxOpts.onsuccess(ajaxRequest); } else { ajaxOpts.onerror(ajaxRequest); } } }; if (method == "POST") { ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); ajaxRequest.send(submitStr); } else { ajaxRequest.send(null); } } }; }(); /** * @file * @name UE.filterWord * @short filterWord * @desc 用来过滤word粘贴过来的字符串 * @import editor.js,core/utils.js * @anthor zhanyi */ var filterWord = UE.filterWord = function () { //是否是word过来的内容 function isWordDocument(str) { return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|/ig, "") //转换图片 .replace(/]*>[\s\S]*?.<\/v:shape>/gi, function (str) { //opera能自己解析出image所这里直接返回空 if (browser.opera) { return ''; } try { var width = str.match(/width:([ \d.]*p[tx])/i)[1], height = str.match(/height:([ \d.]*p[tx])/i)[1], src = str.match(/src=\s*"([^"]*)"/i)[1]; return ''; } catch (e) { return ''; } }) //针对wps添加的多余标签处理 .replace(/<\/?div[^>]*>/g, '') //去掉多余的属性 .replace(/v:\w+=(["']?)[^'"]+\1/g, '') .replace(/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi, "") .replace(/

]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "

$1

") //去掉多余的属性 .replace(/\s+(class|lang|align)\s*=\s*(['"]?)[\w-]+\2/ig, "") //清除多余的font/span不能匹配 有可能是空格 .replace(/<(font|span)[^>]*>\s*<\/\1>/gi, '') //处理style的问题 .replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function (str, tag, tmp, style) { var n = [], s = style.replace(/^\s+|\s+$/, '') .replace(/'/g, '\'') .replace(/"/gi, "'") .split(/;\s*/g); for (var i = 0, v; v = s[i]; i++) { var name, value, parts = v.split(":"); if (parts.length == 2) { name = parts[0].toLowerCase(); value = parts[1].toLowerCase(); if (/^(background)\w*/.test(name) && value.replace(/(initial|\s)/g, '').length == 0 || /^(margin)\w*/.test(name) && /^0\w+$/.test(value) ) { continue; } switch (name) { case "mso-padding-alt": case "mso-padding-top-alt": case "mso-padding-right-alt": case "mso-padding-bottom-alt": case "mso-padding-left-alt": case "mso-margin-alt": case "mso-margin-top-alt": case "mso-margin-right-alt": case "mso-margin-bottom-alt": case "mso-margin-left-alt": //ie下会出现挤到一起的情况 //case "mso-table-layout-alt": case "mso-height": case "mso-width": case "mso-vertical-align-alt": //trace:1819 ff下会解析出padding在table上 if (!/[ \t\r\n]*<'); }; }(); ///import core /** * @description 插入内容 * @name baidu.editor.execCommand * @param {String} cmdName inserthtml插入内容的命令 * @param {String} html 要插入的内容 * @author zhanyi */ UE.commands['inserthtml'] = { execCommand: function (command, html, notSerialize) { var me = this, range, div; if (!html) { return; } range = me.selection.getRange(); div = range.document.createElement('div'); div.style.display = 'inline'; var serialize = me.serialize; if (!notSerialize && serialize) { var node = serialize.parseHTML(html); node = serialize.transformInput(node); node = serialize.filter(node); html = serialize.toHTML(node); } div.innerHTML = utils.trim(html); if (!range.collapsed) { var tmpNode = range.startContainer; if (domUtils.isFillChar(tmpNode)) { range.setStartBefore(tmpNode) } tmpNode = range.endContainer; if (domUtils.isFillChar(tmpNode)) { range.setEndAfter(tmpNode) } range.txtToElmBoundary(); //结束边界可能放到了br的前边,要把br包含进来 // x[xxx]
if (range.endContainer && range.endContainer.nodeType == 1) { tmpNode = range.endContainer.childNodes[range.endOffset]; if (tmpNode && domUtils.isBr(tmpNode)) { range.setEndAfter(tmpNode); } } if (range.startOffset == 0) { tmpNode = range.startContainer; if (domUtils.isBoundaryNode(tmpNode, 'firstChild')) { tmpNode = range.endContainer; if (range.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode, 'lastChild')) { me.body.innerHTML = '

' + (browser.ie ? '' : '
') + '

'; range.setStart(me.body.firstChild, 0).collapse(true) } } } !range.collapsed && range.deleteContents(); if (range.startContainer.nodeType == 1) { var child = range.startContainer.childNodes[range.startOffset], pre; if (child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)) { range.setEnd(pre, pre.childNodes.length).collapse(); while (child.firstChild) { pre.appendChild(child.firstChild); } domUtils.remove(child); } } } var child, parent, pre, tmp, hadBreak = 0, nextNode; //如果当前位置选中了fillchar要干掉,要不会产生空行 if (range.inFillChar()) { child = range.startContainer; range.setStartBefore(child).collapse(true); domUtils.remove(child); } while (child = div.firstChild) { range.insertNode(child); nextNode = child.nextSibling; if (!hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm(child)) { parent = domUtils.findParent(child, function (node) { return domUtils.isBlockElm(node); }); if (parent && parent.tagName.toLowerCase() != 'body' && !(dtd[parent.tagName][child.nodeName] && child.parentNode === parent)) { if (!dtd[parent.tagName][child.nodeName]) { pre = parent; } else { tmp = child.parentNode; while (tmp !== parent) { pre = tmp; tmp = tmp.parentNode; } } domUtils.breakParent(child, pre || tmp); //去掉break后前一个多余的节点

|<[p> ==>

|

var pre = child.previousSibling; domUtils.trimWhiteTextNode(pre); if (!pre.childNodes.length) { domUtils.remove(pre); } //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位 if (!browser.ie && (next = child.nextSibling) && domUtils.isBlockElm(next) && next.lastChild && !domUtils.isBr(next.lastChild)) { next.appendChild(me.document.createElement('br')); } hadBreak = 1; } } var next = child.nextSibling; if (!div.firstChild && next && domUtils.isBlockElm(next)) { range.setStart(next, 0).collapse(true); break; } range.setEndAfter(child).collapse(); } child = range.startContainer; if (nextNode && domUtils.isBr(nextNode)) { domUtils.remove(nextNode) } //用chrome可能有空白展位符 if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) { if (nextNode = child.nextSibling) { domUtils.remove(child); if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) { range.setStart(nextNode, 0).collapse(true).shrinkBoundary() } } else { child.innerHTML = browser.ie ? domUtils.fillChar : '
'; } } //加上true因为在删除表情等时会删两次,第一次是删的fillData range.select(true); setTimeout(function () { range = me.selection.getRange(); range.scrollToView(me.autoHeightEnabled, me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0); me.fireEvent('afterinserthtml'); }, 200); } }; ///import core ///commands 自动排版 ///commandsName autotypeset ///commandsTitle 自动排版 /** * 自动排版 * @function * @name baidu.editor.execCommands */ 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' //行首缩进的大小 }}); 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; } function isLine(node, notEmpty) { if (!node || node.nodeType == 3) return 0; if (domUtils.isBr(node)) return 1; if (node && node.parentNode && tags[node.tagName.toLowerCase()]) { if (highlightCont && highlightCont.contains(node) || node.getAttribute('pagebreak') ) { return 0; } return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node); } } function removeNotAttributeSpan(node) { if (!node.style.cssText) { domUtils.removeAttributes(node, ['style']); if (node.tagName.toLowerCase() == 'span' && domUtils.hasNoAttributes(node)) { domUtils.remove(node, true); } } } function autotype(type, html) { var me = this, cont; if (html) { if (!opt.pasteFilter) { return; } cont = me.document.createElement('div'); cont.innerHTML = html.html; } else { cont = me.document.body; } var nodes = domUtils.getElementsByTagName(cont, '*'); // 行首缩进,段落方向,段间距,段内间距 for (var i = 0, ci; ci = nodes[i++];) { if (me.fireEvent('excludeNodeinautotype', ci) === true) { continue; } //font-size if (opt.clearFontSize && ci.style.fontSize) { domUtils.removeStyle(ci, 'font-size'); removeNotAttributeSpan(ci); } //font-family if (opt.clearFontFamily && ci.style.fontFamily) { domUtils.removeStyle(ci, 'font-family'); removeNotAttributeSpan(ci); } if (isLine(ci)) { //合并空行 if (opt.mergeEmptyline) { var next = ci.nextSibling, tmpNode, isBr = domUtils.isBr(ci); while (isLine(next)) { tmpNode = next; next = tmpNode.nextSibling; if (isBr && (!next || next && !domUtils.isBr(next))) { break; } domUtils.remove(tmpNode); } } //去掉空行,保留占位的空行 if (opt.removeEmptyline && domUtils.inDoc(ci, cont) && !remainTag[ci.parentNode.tagName.toLowerCase()]) { if (domUtils.isBr(ci)) { next = ci.nextSibling; if (next && !domUtils.isBr(next)) { continue; } } domUtils.remove(ci); continue; } } if (isLine(ci, true) && ci.tagName != 'SPAN') { if (opt.indent) { ci.style.textIndent = opt.indentValue; } if (opt.textAlign) { ci.style.textAlign = opt.textAlign; } // if(opt.lineHeight) // ci.style.lineHeight = opt.lineHeight + 'cm'; } //去掉class,保留的class不去掉 if (opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]) { if (highlightCont && highlightCont.contains(ci)) { continue; } domUtils.removeAttributes(ci, ['class']); } //表情不处理 if (opt.imageBlockLine && ci.tagName.toLowerCase() == 'img' && !ci.getAttribute('emotion')) { if (html) { var img = ci; switch (opt.imageBlockLine) { case 'left': case 'right': case 'none': var pN = img.parentNode, tmpNode, pre, next; while (dtd.$inline[pN.tagName] || pN.tagName == 'A') { pN = pN.parentNode; } tmpNode = pN; if (tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode, 'text-align') == 'center') { if (!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function (node) { return !domUtils.isBr(node) && !domUtils.isWhitespace(node) }) == 1) { pre = tmpNode.previousSibling; next = tmpNode.nextSibling; if (pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)) { pre.appendChild(tmpNode.firstChild); while (next.firstChild) { pre.appendChild(next.firstChild); } domUtils.remove(tmpNode); domUtils.remove(next); } else { domUtils.setStyle(tmpNode, 'text-align', ''); } } } domUtils.setStyle(img, 'float', opt.imageBlockLine); break; case 'center': if (me.queryCommandValue('imagefloat') != 'center') { pN = img.parentNode; domUtils.setStyle(img, 'float', 'none'); tmpNode = img; while (pN && domUtils.getChildCount(pN, function (node) { return !domUtils.isBr(node) && !domUtils.isWhitespace(node) }) == 1 && (dtd.$inline[pN.tagName] || pN.tagName == 'A')) { tmpNode = pN; pN = pN.parentNode; } var pNode = me.document.createElement('p'); domUtils.setAttributes(pNode, { style: 'text-align:center' }); tmpNode.parentNode.insertBefore(pNode, tmpNode); pNode.appendChild(tmpNode); domUtils.setStyle(tmpNode, 'float', ''); } } } else { var range = me.selection.getRange(); range.selectNode(ci).select(); me.execCommand('imagefloat', opt.imageBlockLine); } } //去掉冗余的标签 if (opt.removeEmptyNode) { if (opt.removeTagNames[ci.tagName.toLowerCase()] && domUtils.hasNoAttributes(ci) && domUtils.isEmptyBlock(ci)) { domUtils.remove(ci); } } } if (html) { html.html = cont.innerHTML; } } if (opt.pasteFilter) { me.addListener('beforepaste', autotype); } me.commands['autotypeset'] = { execCommand: function () { me.removeListener('beforepaste', autotype); if (opt.pasteFilter) { me.addListener('beforepaste', autotype); } autotype.call(me) } }; }; ///import core ///commands 自动提交 ///commandsName autosubmit ///commandsTitle 自动提交 UE.plugins['autosubmit'] = function () { var me = this; me.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(); } } }; //快捷键 me.addshortcutkey({ "autosubmit": "ctrl+13" //手动提交 }); }; ///import core ///commands 插入背景 ///commandsName background ///commandsTitle 插入背景 ///commandsDialog dialogs\background UE.plugins['background'] = function () { var me = this; me.addListener("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); }); } ///import core ///import plugins\inserthtml.js ///commands 插入图片,操作图片的对齐方式 ///commandsName InsertImage,ImageNone,ImageLeft,ImageRight,ImageCenter ///commandsTitle 图片,默认,居左,居右,居中 ///commandsDialog dialogs\image /** * Created by . * User: zhanyi * for image */ 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 = startNode.getAttribute('align') || domUtils.getComputedStyle(startNode, 'float'); 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; } }; 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 (img && /img/i.test(img.tagName) && img.className != "edui-faked-video" && !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) { str = '' + ci.alt + ''; if (ci['floatStyle'] == 'center') { str = '

' + str + '

'; } html.push(str); } else { for (var i = 0; ci = opt[i++];) { str = '

'; html.push(str); } } me.execCommand('insertHtml', html.join('')); } } }; ///import core ///commands 段落格式,居左,居右,居中,两端对齐 ///commandsName JustifyLeft,JustifyCenter,JustifyRight,JustifyJustify ///commandsTitle 居左对齐,居中对齐,居右对齐,两端对齐 /** * @description 居左右中 * @name baidu.editor.execCommand * @param {String} cmdName justify执行对齐方式的命令 * @param {String} align 对齐方式:left居左,right居右,center居中,justify两端对齐 * @author zhanyi */ 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; } }; }; ///import core ///import plugins\removeformat.js ///commands 字体颜色,背景色,字号,字体,下划线,删除线 ///commandsName ForeColor,BackColor,FontSize,FontFamily,Underline,StrikeThrough ///commandsTitle 字体颜色,背景色,字号,字体,下划线,删除线 /** * @description 字体 * @name baidu.editor.execCommand * @param {String} cmdName 执行的功能名称 * @param {String} value 传入的值 */ 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' }; 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] }); for (var p in fonts) { (function (cmd, style) { UE.commands[cmd] = { execCommand: function (cmdName, value) { value = value || (this.queryCommandState(cmdName) ? 'none' : cmdName == 'underline' ? 'underline' : '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).setCursor(); domUtils.remove(text); } } else { if (!range.collapsed) { if ((cmd == 'underline' || cmd == 'strikethrough') && me.queryCommandValue(cmd)) { me.execCommand('removeFormat', 'span,a', style); } range = me.selection.getRange(); range.applyInlineStyle('span', {'style': style + ':' + value}).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 (cmd == 'underline' || cmd == 'strikethrough') { range.selectNode(text).select(); me.execCommand('removeFormat', 'span,a', style, null); span = domUtils.findParentByTagName(text, 'span', true); range.setStartBefore(text); } span.style.cssText += ';' + style + ':' + value; range.collapse(true).select(); } else { range.insertNode(text); range.selectNode(text).select(); span = range.document.createElement('span'); if (cmd == 'underline' || cmd == 'strikethrough') { //a标签内的不处理跳过 if (domUtils.findParentByTagName(text, 'a', true)) { range.setStartBefore(text).setCursor(); domUtils.remove(text); return; } me.execCommand('removeFormat', 'span,a', style); } span.style.cssText = style + ':' + value; text.parentNode.insertBefore(span, text); //修复,span套span 但样式不继承的问题 if (!browser.ie || browser.ie && browser.version == 9) { var spanParent = span.parentNode; while (!domUtils.isBlockElm(spanParent)) { if (spanParent.tagName == 'SPAN') { //opera合并style不会加入";" span.style.cssText = spanParent.style.cssText + ";" + span.style.cssText; } spanParent = spanParent.parentNode; } } if (opera) { setTimeout(function () { range.setStart(span, 0).setCursor(); }); } else { range.setStart(span, 0).setCursor(); } //trace:981 //domUtils.mergeToParent(span) } domUtils.remove(text); } } return true; }, queryCommandValue: function (cmdName) { var startNode = this.selection.getStart(); //trace:946 if (cmdName == 'underline' || cmdName == 'strikethrough') { var tmpNode = startNode, value; while (tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(tmpNode)) { if (tmpNode.nodeType == 1) { value = domUtils.getComputedStyle(tmpNode, style); if (value != 'none') { return value; } } tmpNode = tmpNode.parentNode; } return 'none'; } return domUtils.getComputedStyle(startNode, style); }, queryCommandState: function (cmdName) { if (!(cmdName == 'underline' || cmdName == 'strikethrough')) { return 0; } return this.queryCommandValue(cmdName) == (cmdName == 'underline' ? 'underline' : 'line-through'); } }; })(p, fonts[p]); } }; ///import core ///commands 超链接,取消链接 ///commandsName Link,Unlink ///commandsTitle 超链接,取消链接 ///commandsDialog dialogs\link /** * 超链接 * @function * @name baidu.editor.execCommand * @param {String} cmdName link插入超链接 * @param {Object} options url地址,title标题,target是否打开新页 * @author zhanyi */ /** * 取消链接 * @function * @name baidu.editor.execCommand * @param {String} cmdName unlink取消链接 * @author zhanyi */ (function () { function optimize(range) { var start = range.startContainer, end = range.endContainer; if (start = domUtils.findParentByTagName(start, 'a', true)) { range.setStartBefore(start); } if (end = domUtils.findParentByTagName(end, 'a', true)) { range.setEndAfter(end); } } UE.commands['unlink'] = { execCommand: function () { var range = this.selection.getRange(), bookmark; if (range.collapsed && !domUtils.findParentByTagName(range.startContainer, 'a', true)) { return; } bookmark = range.createBookmark(); optimize(range); range.removeInlineStyle('a').moveToBookmark(bookmark).select(); }, queryCommandState: function () { return !this.highlight && this.queryCommandValue('link') ? 0 : -1; } }; function doLink(range, opt, me) { var rngClone = range.cloneRange(), link = me.queryCommandValue('link'); optimize(range = range.adjustmentBoundary()); var start = range.startContainer; if (start.nodeType == 1 && link) { start = start.childNodes[range.startOffset]; if (start && start.nodeType == 1 && start.tagName == 'A' && /^(?:https?|ftp|file)\s*:\s*\/\//.test(start[browser.ie ? 'innerText' : 'textContent'])) { start[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue || opt.href); } } if (!rngClone.collapsed || link) { range.removeInlineStyle('a'); rngClone = range.cloneRange(); } if (rngClone.collapsed) { var a = range.document.createElement('a'), text = ''; if (opt.textValue) { text = utils.html(opt.textValue); delete opt.textValue; } else { text = utils.html(opt.href); } domUtils.setAttributes(a, opt); start = domUtils.findParentByTagName(rngClone.startContainer, 'a', true); if (start && domUtils.isInNodeEndBoundary(rngClone, start)) { range.setStartAfter(start).collapse(true); } a[browser.ie ? 'innerText' : 'textContent'] = text; range.insertNode(a).selectNode(a); } else { range.applyInlineStyle('a', opt); } } UE.commands['link'] = { execCommand: function (cmdName, opt) { var range; opt.data_ue_src && (opt.data_ue_src = utils.unhtml(opt.data_ue_src, /[<">]/g)); opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g)); opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g)); doLink(range = this.selection.getRange(), opt, this); //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题 range.collapse().select(true); }, queryCommandValue: function () { var range = this.selection.getRange(), node; if (range.collapsed) { // node = this.selection.getStart(); //在ie下getstart()取值偏上了 node = range.startContainer; node = node.nodeType == 1 ? node : node.parentNode; if (node && (node = domUtils.findParentByTagName(node, 'a', true)) && !domUtils.isInNodeEndBoundary(range, node)) { return node; } } else { //trace:1111 如果是

xx

startContainer是p就会找不到a range.shrinkBoundary(); var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[range.startOffset] ? range.startContainer : range.startContainer.childNodes[range.startOffset], end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range.endContainer : range.endContainer.childNodes[range.endOffset - 1], common = range.getCommonAncestor(); node = domUtils.findParentByTagName(common, 'a', true); if (!node && common.nodeType == 1) { var as = common.getElementsByTagName('a'), ps, pe; for (var i = 0, ci; ci = as[i++];) { ps = domUtils.getPosition(ci, start), pe = domUtils.getPosition(ci, end); if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS) && (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS) ) { node = ci; break; } } } return node; } }, queryCommandState: function () { //判断如果是视频的话连接不可用 //fix 853 var img = this.selection.getRange().getClosedNode(), flag = img && (img.className == "edui-faked-video"); return flag ? -1 : 0; } }; })(); ///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(); }); }; ///import core ///commands 涂鸦 ///commandsName Scrawl ///commandsTitle 涂鸦 ///commandsDialog dialogs\scrawl UE.commands['scrawl'] = { queryCommandState: function () { return ( browser.ie && browser.version <= 8 ) ? -1 : 0; } }; ///import core ///commands 清除格式 ///commandsName RemoveFormat ///commandsTitle 清除格式 /** * @description 清除格式 * @name baidu.editor.execCommand * @param {String} cmdName removeformat清除格式命令 * @param {String} tags 以逗号隔开的标签。如:span,a * @param {String} style 样式 * @param {String} attrs 属性 * @param {String} notIncluedA 是否把a标签切开 * @author zhanyi */ UE.plugins['removeformat'] = function () { var me = this; me.setOpt({ 'removeFormatTags': 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var', 'removeFormatAttributes': 'class,style,lang,width,height,align,hspace,valign' }); me.commands['removeformat'] = { execCommand: function (cmdName, tags, style, attrs, notIncludeA) { var tagReg = new RegExp('^(?:' + (tags || this.options.removeFormatTags).replace(/,/g, '|') + ')$', 'i') , removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes).split(','), range = new dom.Range(this.document), bookmark, node, parent, filter = function (node) { return node.nodeType == 1; }; function isRedundantSpan(node) { if (node.nodeType == 3 || node.tagName.toLowerCase() != 'span') { return 0; } if (browser.ie) { //ie 下判断实效,所以只能简单用style来判断 //return node.style.cssText == '' ? 1 : 0; var attrs = node.attributes; if (attrs.length) { for (var i = 0, l = attrs.length; i < l; i++) { if (attrs[i].specified) { return 0; } } return 1; } } return !node.attributes.length; } function doRemove(range) { var bookmark1 = range.createBookmark(); if (range.collapsed) { range.enlarge(true); } //不能把a标签切了 if (!notIncludeA) { var aNode = domUtils.findParentByTagName(range.startContainer, 'a', true); if (aNode) { range.setStartBefore(aNode); } aNode = domUtils.findParentByTagName(range.endContainer, 'a', true); if (aNode) { range.setEndAfter(aNode); } } bookmark = range.createBookmark(); node = bookmark.start; //切开始 while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) { domUtils.breakParent(node, parent); domUtils.clearEmptySibling(node); } if (bookmark.end) { //切结束 node = bookmark.end; while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) { domUtils.breakParent(node, parent); domUtils.clearEmptySibling(node); } //开始去除样式 var current = domUtils.getNextDomNode(bookmark.start, false, filter), next; while (current) { if (current == bookmark.end) { break; } next = domUtils.getNextDomNode(current, true, filter); if (!dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode(current)) { if (tagReg.test(current.tagName)) { if (style) { domUtils.removeStyle(current, style); if (isRedundantSpan(current) && style != 'text-decoration') { domUtils.remove(current, true); } } else { domUtils.remove(current, true); } } else { //trace:939 不能把list上的样式去掉 if (!dtd.$tableContent[current.tagName] && !dtd.$list[current.tagName]) { domUtils.removeAttributes(current, removeFormatAttributes); if (isRedundantSpan(current)) { domUtils.remove(current, true); } } } } current = next; } } //trace:1035 //trace:1096 不能把td上的样式去掉,比如边框 var pN = bookmark.start.parentNode; if (domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) { domUtils.removeAttributes(pN, removeFormatAttributes); } pN = bookmark.end.parentNode; if (bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) { domUtils.removeAttributes(pN, removeFormatAttributes); } range.moveToBookmark(bookmark).moveToBookmark(bookmark1); //清除冗余的代码 var node = range.startContainer, tmp, collapsed = range.collapsed; while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) { tmp = node.parentNode; range.setStartBefore(node); //trace:937 //更新结束边界 if (range.startContainer === range.endContainer) { range.endOffset--; } domUtils.remove(node); node = tmp; } if (!collapsed) { node = range.endContainer; while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) { tmp = node.parentNode; range.setEndBefore(node); domUtils.remove(node); node = tmp; } } } range = this.selection.getRange(); doRemove(range); range.select(); } }; }; ///import core ///commands 引用 ///commandsName BlockQuote ///commandsTitle 引用 /** * * 引用模块实现 * @function * @name baidu.editor.execCommand * @param {String} cmdName blockquote引用 */ UE.plugins['blockquote'] = function () { var me = this; function getObj(editor) { return domUtils.filterNodeList(editor.selection.getStartElementPath(), 'blockquote'); }; me.commands['blockquote'] = { execCommand: function (cmdName, attrs) { var range = this.selection.getRange(), obj = getObj(this), blockquote = dtd.blockquote, bookmark = range.createBookmark(); if (obj) { var start = range.startContainer, startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start, function (node) { return domUtils.isBlockElm(node) }), end = range.endContainer, endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end, function (node) { return domUtils.isBlockElm(node) }); //处理一下li startBlock = domUtils.findParentByTagName(startBlock, 'li', true) || startBlock; endBlock = domUtils.findParentByTagName(endBlock, 'li', true) || endBlock; if (startBlock.tagName == 'LI' || startBlock.tagName == 'TD' || startBlock === obj) { domUtils.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.remove(obj, true); } else { domUtils.breakParent(endBlock, obj); } } } var blockquotes = domUtils.getElementsByTagName(this.document, 'blockquote'); for (var i = 0, bi; bi = blockquotes[i++];) { if (!bi.childNodes.length) { domUtils.remove(bi); } else if (domUtils.getPosition(bi, startBlock) & domUtils.POSITION_FOLLOWING && domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING) { domUtils.remove(bi, true); } } } else { var tmpRange = range.cloneRange(), node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode, preNode = node, doEnd = 1; //调整开始 while (1) { if (domUtils.isBody(node)) { if (preNode !== node) { if (range.collapsed) { tmpRange.selectNode(preNode); doEnd = 0; } else { tmpRange.setStartBefore(preNode); } } else { tmpRange.setStart(node, 0); } break; } if (!blockquote[node.tagName]) { if (range.collapsed) { tmpRange.selectNode(preNode); } else { tmpRange.setStartBefore(preNode); } break; } preNode = node; node = node.parentNode; } //调整结束 if (doEnd) { preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode; while (1) { if (domUtils.isBody(node)) { if (preNode !== node) { tmpRange.setEndAfter(preNode); } else { tmpRange.setEnd(node, node.childNodes.length); } break; } if (!blockquote[node.tagName]) { tmpRange.setEndAfter(preNode); break; } preNode = node; node = node.parentNode; } } node = range.document.createElement('blockquote'); domUtils.setAttributes(node, attrs); node.appendChild(tmpRange.extractContents()); tmpRange.insertNode(node); //去除重复的 var childs = domUtils.getElementsByTagName(node, 'blockquote'); for (var i = 0, ci; ci = childs[i++];) { if (ci.parentNode) { domUtils.remove(ci, true); } } } range.moveToBookmark(bookmark).select(); }, queryCommandState: function () { return getObj(this) ? 1 : 0; } }; }; ///import core ///commands 大小写转换 ///commandsName touppercase,tolowercase ///commandsTitle 大写,小写 /** * 大小写转换 * @function * @name baidu.editor.execCommands * @param {String} cmdName cmdName="convertcase" */ UE.commands['touppercase'] = UE.commands['tolowercase'] = { execCommand: function (cmd) { var me = this; var rng = me.selection.getRange(); if (rng.collapsed) { return rng; } var bk = rng.createBookmark(), bkEnd = bk.end, filterFn = function (node) { return !domUtils.isBr(node) && !domUtils.isWhitespace(node); }, curNode = domUtils.getNextDomNode(bk.start, false, filterFn); while (curNode && (domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING)) { if (curNode.nodeType == 3) { curNode.nodeValue = curNode.nodeValue[cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase'](); } curNode = domUtils.getNextDomNode(curNode, true, filterFn); if (curNode === bkEnd) { break; } } rng.moveToBookmark(bk).select(); } }; ///import core ///import plugins\paragraph.js ///commands 首行缩进 ///commandsName Outdent,Indent ///commandsTitle 取消缩进,首行缩进 /** * 首行缩进 * @function * @name baidu.editor.execCommand * @param {String} cmdName outdent取消缩进,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; } }; ///import core ///commands 打印 ///commandsName Print ///commandsTitle 打印 /** * @description 打印 * @name baidu.editor.execCommand * @param {String} cmdName print打印编辑器内容 * @author zhanyi */ UE.commands['print'] = { execCommand: function () { this.window.print(); }, notNeedUndo: 1 }; ///import core ///commands 预览 ///commandsName Preview ///commandsTitle 预览 /** * 预览 * @function * @name baidu.editor.execCommand * @param {String} cmdName 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 }; ///import core ///commands 全选 ///commandsName SelectAll ///commandsTitle 全选 /** * 选中所有 * @function * @name baidu.editor.execCommand * @param {String} cmdName selectall选中编辑器里的所有内容 * @author zhanyi */ 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 }; function isBoundaryNode(node, dir) { var tmp; while (!domUtils.isBody(node)) { tmp = node; node = node.parentNode; if (tmp !== node[dir]) { return false; } } return true; } me.addListener('keydown', function (type, evt) { var rng = me.selection.getRange(); if (!rng.collapsed && !(evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) { var tmpNode = rng.startContainer; if (domUtils.isFillChar(tmpNode)) { rng.setStartBefore(tmpNode) } tmpNode = rng.endContainer; if (domUtils.isFillChar(tmpNode)) { rng.setEndAfter(tmpNode) } rng.txtToElmBoundary(); if (rng.startOffset == 0) { tmpNode = rng.startContainer; if (isBoundaryNode(tmpNode, 'firstChild')) { tmpNode = rng.endContainer; if (rng.endOffset == rng.endContainer.childNodes.length && isBoundaryNode(tmpNode, 'lastChild')) { me.fireEvent('saveScene'); me.body.innerHTML = '

' + (browser.ie ? '' : '
') + '

'; rng.setStart(me.body.firstChild, 0).setCursor(false, true); me.fireEvent('saveScene'); browser.ie && me._selectionChange(); return; } } } } }); //快捷键 me.addshortcutkey({ "selectAll": "ctrl+65" }); }; ///import core ///commands 格式 ///commandsName Paragraph ///commandsTitle 段落格式 /** * 段落样式 * @function * @name baidu.editor.execCommand * @param {String} cmdName paragraph插入段落执行命令 * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' * @param {String} attrs 标签的属性 * @author zhanyi */ UE.plugins['paragraph'] = function () { var me = this, block = domUtils.isBlockElm, notExchange = ['TD', 'LI', 'PRE'], doParagraph = function (range, style, attrs, sourceCmdName) { var bookmark = range.createBookmark(), filterFn = function (node) { return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); }, para; range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode; while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { if (current.nodeType == 3 || !block(current)) { tmpRange.setStartBefore(current); while (current && current !== bookmark2.end && !block(current)) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !block(node); }); } tmpRange.setEndAfter(tmpNode); para = range.document.createElement(style); if (attrs) { domUtils.setAttributes(para, attrs); if (sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) { para.style.cssText = attrs.style; } } para.appendChild(tmpRange.extractContents()); //需要内容占位 if (domUtils.isEmptyNode(para)) { domUtils.fillChar(range.document, para); } tmpRange.insertNode(para); var parent = para.parentNode; //如果para上一级是一个block元素且不是body,td就删除它 if (block(parent) && !domUtils.isBody(para.parentNode) && utils.indexOf(notExchange, parent.tagName) == -1) { //存储dir,style if (!(sourceCmdName && sourceCmdName == 'customstyle')) { parent.getAttribute('dir') && para.setAttribute('dir', parent.getAttribute('dir')); //trace:1070 parent.style.cssText && (para.style.cssText = parent.style.cssText + ';' + para.style.cssText); //trace:1030 parent.style.textAlign && !para.style.textAlign && (para.style.textAlign = parent.style.textAlign); parent.style.textIndent && !para.style.textIndent && (para.style.textIndent = parent.style.textIndent); parent.style.padding && !para.style.padding && (para.style.padding = parent.style.padding); } //trace:1706 选择的就是h1-6要删除 if (attrs && /h\d/i.test(parent.tagName) && !/h\d/i.test(para.tagName)) { domUtils.setAttributes(parent, attrs); if (sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) { parent.style.cssText = attrs.style; } domUtils.remove(para, true); para = parent; } else { domUtils.remove(para.parentNode, true); } } if (utils.indexOf(notExchange, parent.tagName) != -1) { current = parent; } else { current = para; } current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } return range.moveToBookmark(bookmark2).moveToBookmark(bookmark); }; me.setOpt('paragraph', {'p': '', 'h1': '', 'h2': '', 'h3': '', 'h4': '', 'h5': '', 'h6': ''}); me.commands['paragraph'] = { execCommand: function (cmdName, style, attrs, sourceCmdName) { var range = this.selection.getRange(); //闭合时单独处理 if (range.collapsed) { var txt = this.document.createTextNode('p'); range.insertNode(txt); //去掉冗余的fillchar if (browser.ie) { var node = txt.previousSibling; if (node && domUtils.isWhitespace(node)) { domUtils.remove(node); } node = txt.nextSibling; if (node && domUtils.isWhitespace(node)) { domUtils.remove(node); } } } range = doParagraph(range, style, attrs, sourceCmdName); if (txt) { range.setStartBefore(txt).collapse(true); pN = txt.parentNode; domUtils.remove(txt); if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) { domUtils.fillNode(this.document, pN); } } if (browser.gecko && range.collapsed && range.startContainer.nodeType == 1) { var child = range.startContainer.childNodes[range.startOffset]; if (child && child.nodeType == 1 && child.tagName.toLowerCase() == style) { range.setStart(child, 0).collapse(true); } } //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了 range.select(); return true; }, queryCommandValue: function () { var node = domUtils.filterNodeList(this.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6'); return node ? node.tagName.toLowerCase() : ''; } }; }; ///import core ///commands 输入的方向 ///commandsName DirectionalityLtr,DirectionalityRtl ///commandsTitle 从左向右输入,从右向左输入 /** * 输入的方向 * @function * @name baidu.editor.execCommand * @param {String} cmdName directionality执行函数的参数 * @param {String} forward ltr从左向右输入,rtl从右向左输入 */ (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.getAttribute('dir') }); }, doDirectionality = function (range, editor, forward) { var bookmark, filterFn = function (node) { return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); }, obj = getObj(editor); if (obj && range.collapsed) { obj.setAttribute('dir', forward); return range; } bookmark = range.createBookmark(); range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode; while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { if (current.nodeType == 3 || !block(current)) { tmpRange.setStartBefore(current); while (current && current !== bookmark2.end && !block(current)) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !block(node); }); } tmpRange.setEndAfter(tmpNode); var common = tmpRange.getCommonAncestor(); if (!domUtils.isBody(common) && block(common)) { //遍历到了block节点 common.setAttribute('dir', forward); current = common; } else { //没有遍历到,添加一个block节点 var p = range.document.createElement('p'); p.setAttribute('dir', forward); var frag = tmpRange.extractContents(); p.appendChild(frag); tmpRange.insertNode(p); current = p; } current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } return range.moveToBookmark(bookmark2).moveToBookmark(bookmark); }; UE.commands['directionality'] = { execCommand: function (cmdName, forward) { var range = this.selection.getRange(); //闭合时单独处理 if (range.collapsed) { var txt = this.document.createTextNode('d'); range.insertNode(txt); } doDirectionality(range, this, forward); if (txt) { range.setStartBefore(txt).collapse(true); domUtils.remove(txt); } range.select(); return true; }, queryCommandValue: function () { var node = getObj(this); return node ? node.getAttribute('dir') : 'ltr'; } }; })(); ///import core ///import plugins\inserthtml.js ///commands 分割线 ///commandsName Horizontal ///commandsTitle 分隔线 /** * 分割线 * @function * @name baidu.editor.execCommand * @param {String} cmdName horizontal插入分割线 */ UE.commands['horizontal'] = { execCommand: function (cmdName) { var me = this; if (me.queryCommandState(cmdName) !== -1) { me.execCommand('insertHtml', '
'); var range = me.selection.getRange(), start = range.startContainer; if (start.nodeType == 1 && !start.childNodes[range.startOffset]) { var tmp; if (tmp = start.childNodes[range.startOffset - 1]) { if (tmp.nodeType == 1 && tmp.tagName == 'HR') { if (me.options.enterTag == 'p') { tmp = me.document.createElement('p'); range.insertNode(tmp); range.setStart(tmp, 0).setCursor(); } else { tmp = me.document.createElement('br'); range.insertNode(tmp); range.setStartBefore(tmp).setCursor(); } } } } return true; } }, //边界在table里不能加分隔线 queryCommandState: function () { return domUtils.filterNodeList(this.selection.getStartElementPath(), 'table') ? -1 : 0; } }; ///import core ///import plugins\inserthtml.js ///commands 日期,时间 ///commandsName Date,Time ///commandsTitle 日期,时间 /** * 插入日期 * @function * @name baidu.editor.execCommand * @param {String} cmdName date插入日期 * @author zhuwenxuan */ /** * 插入时间 * @function * @name baidu.editor.execCommand * @param {String} cmdName time插入时间 * @author zhuwenxuan */ UE.commands['time'] = UE.commands["date"] = { execCommand: function (cmd) { var date = new Date; this.execCommand('insertHtml', cmd == "time" ? (date.getHours() + ":" + (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":" + (date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds())) : (date.getFullYear() + "-" + ((date.getMonth() + 1) < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-" + (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()))); } }; ///import core ///import plugins\paragraph.js ///commands 段间距 ///commandsName RowSpacingBottom,RowSpacingTop ///commandsTitle 段间距 /** * @description 设置段前距,段后距 * @name baidu.editor.execCommand * @param {String} cmdName rowspacing设置段间距 * @param {String} value 值,以px为单位 * @param {String} dir top或bottom段前后段后 * @author zhanyi */ UE.plugins['rowspacing'] = function () { var me = this; me.setOpt({ 'rowspacingtop': ['5', '10', '15', '20', '25'], 'rowspacingbottom': ['5', '10', '15', '20', '25'] }); me.commands['rowspacing'] = { execCommand: function (cmdName, value, dir) { this.execCommand('paragraph', 'p', {style: 'margin-' + dir + ':' + value + 'px'}); return true; }, queryCommandValue: function (cmdName, dir) { var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function (node) { return domUtils.isBlockElm(node) }), value; //trace:1026 if (pN) { value = domUtils.getComputedStyle(pN, 'margin-' + dir).replace(/[^\d]/g, ''); return !value ? 0 : value; } return 0; } }; }; ///import core ///import plugins\paragraph.js ///commands 行间距 ///commandsName LineHeight ///commandsTitle 行间距 /** * @description 设置行内间距 * @name baidu.editor.execCommand * @param {String} cmdName lineheight设置行内间距 * @param {String} value 值 * @author zhuwenxuan */ UE.plugins['lineheight'] = function () { var me = this; me.setOpt({'lineheight': ['1', '1.5', '1.75', '2', '3', '4', '5']}); 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, ""); } } }; }; ///import core ///commands 清空文档 ///commandsName ClearDoc ///commandsTitle 清空文档 /** * * 清空文档 * @function * @name baidu.editor.execCommand * @param {String} cmdName cleardoc清空文档 */ UE.commands['cleardoc'] = { execCommand: function (cmdName) { var me = this, enterTag = me.options.enterTag, range = me.selection.getRange(); if (enterTag == "br") { me.body.innerHTML = "
"; range.setStart(me.body, 0).setCursor(); } else { me.body.innerHTML = "

" + (ie ? "" : "
") + "

"; range.setStart(me.body.firstChild, 0).setCursor(false, true); } me.fireEvent("clearDoc"); } }; ///import core ///commands 锚点 ///commandsName Anchor ///commandsTitle 锚点 ///commandsDialog dialogs\anchor /** * 锚点 * @function * @name baidu.editor.execCommands * @param {String} cmdName cmdName="anchor"插入锚点 */ UE.plugins['anchor'] = function () { var me = this; me.ready(function () { utils.cssRule('anchor', '.anchorclass{background: url(\'' + me.options.UEDITOR_HOME_URL + 'themes/default/images/anchor.gif\') no-repeat scroll left center transparent;border: 1px dotted #0000FF;cursor: auto;display: inline-block;height: 16px;width: 15px;}', me.document) }); me.commands['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); } } } }; }; ///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.addListener('contentchange', function () { me.fireEvent('wordcount') }); var timer; me.addListener('keyup', function () { clearTimeout(timer); var me = this; timer = setTimeout(function () { me.fireEvent('wordcount') }, 200) }); }; ///import core ///commands 添加分页功能 ///commandsName PageBreak ///commandsTitle 分页 /** * @description 添加分页功能 * @author zhanyi */ UE.plugins['pagebreak'] = function () { var me = this, notBreakTags = ['td']; function fillNode(node) { if (domUtils.isEmptyBlock(node)) { var firstChild = node.firstChild, tmpNode; while (firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)) { tmpNode = firstChild; firstChild = firstChild.firstChild; } !tmpNode && (tmpNode = node); domUtils.fillNode(me.document, tmpNode); } } //分页符样式添加 me.ready(function () { utils.cssRule('pagebreak', '.pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}', me.document); }); function isHr(node) { return node && node.nodeType == 1 && node.tagName == 'HR' && node.className == 'pagebreak'; } me.commands['pagebreak'] = { execCommand: function () { var range = me.selection.getRange(), hr = me.document.createElement('hr'); domUtils.setAttributes(hr, { 'class': 'pagebreak', noshade: "noshade", size: "5" }); domUtils.unSelectable(hr); //table单独处理 var node = domUtils.findParentByTagName(range.startContainer, notBreakTags, true), parents = [], pN; if (node) { switch (node.tagName) { case 'TD': pN = node.parentNode; if (!pN.previousSibling) { var table = domUtils.findParentByTagName(pN, 'table'); // var tableWrapDiv = table.parentNode; // if(tableWrapDiv && tableWrapDiv.nodeType == 1 // && tableWrapDiv.tagName == 'DIV' // && tableWrapDiv.getAttribute('dropdrag') // ){ // domUtils.remove(tableWrapDiv,true); // } table.parentNode.insertBefore(hr, table); parents = domUtils.findParents(hr, true); } else { pN.parentNode.insertBefore(hr, pN); parents = domUtils.findParents(hr); } pN = parents[1]; if (hr !== pN) { domUtils.breakParent(hr, pN); } //table要重写绑定一下拖拽 me.fireEvent('afteradjusttable', me.document); } } else { if (!range.collapsed) { range.deleteContents(); var start = range.startContainer; while (!domUtils.isBody(start) && domUtils.isBlockElm(start) && domUtils.isEmptyNode(start)) { range.setStartBefore(start).collapse(true); domUtils.remove(start); start = range.startContainer; } } range.insertNode(hr); var pN = hr.parentNode, nextNode; while (!domUtils.isBody(pN)) { domUtils.breakParent(hr, pN); nextNode = hr.nextSibling; if (nextNode && domUtils.isEmptyBlock(nextNode)) { domUtils.remove(nextNode); } pN = hr.parentNode; } nextNode = hr.nextSibling; var pre = hr.previousSibling; if (isHr(pre)) { domUtils.remove(pre); } else { pre && fillNode(pre); } if (!nextNode) { var p = me.document.createElement('p'); hr.parentNode.appendChild(p); domUtils.fillNode(me.document, p); range.setStart(p, 0).collapse(true); } else { if (isHr(nextNode)) { domUtils.remove(nextNode); } else { fillNode(nextNode); } range.setEndAfter(hr).collapse(false); } range.select(true); } } }; }; ///import core ///commands 本地图片引导上传 ///commandsName WordImage ///commandsTitle 本地图片引导上传 ///commandsDialog dialogs\wordimage UE.plugins["wordimage"] = function () { var me = this, images; me.commands['wordimage'] = { execCommand: function () { images = domUtils.getElementsByTagName(me.document.body, "img"); var urlList = []; for (var i = 0, ci; ci = images[i++];) { var url = ci.getAttribute("word_img"); url && urlList.push(url); } if (images.length) { this["word_img"] = urlList; } }, queryCommandState: function () { images = domUtils.getElementsByTagName(me.document.body, "img"); for (var i = 0, ci; ci = images[i++];) { if (ci.getAttribute("word_img")) { return 1; } } return -1; } }; }; ///import core ///commands 撤销和重做 ///commandsName Undo,Redo ///commandsTitle 撤销,重做 /** * @description 回退 * @author zhanyi */ UE.plugins['undo'] = function () { var me = this, maxUndoCount = me.options.maxUndoCount || 20, maxInputCount = me.options.maxInputCount || 20, fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi');// ie会产生多余的 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 adjustContent(cont) { var specialAttr = /\b(?:href|src|name)="[^"]*?"/gi; return cont.replace(specialAttr, '') .replace(/([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi, function (a, b, c) { return b.toLowerCase() + '=' + c.replace(/['"]/g, '').toLowerCase() }) .replace(/(<[\w\-]+)|([\w\-]+>)/gi, function (a, b, c) { return (b || c).toLowerCase() }); } function UndoManager() { this.list = []; this.index = 0; this.hasUndo = false; this.hasRedo = false; this.undo = function () { if (this.hasUndo) { var currentScene = this.getScene(), lastScene = this.list[this.index], lastContent = adjustContent(lastScene.content), currentContent = adjustContent(currentScene.content); if (lastContent != currentContent) { this.save(); } if (!this.list[this.index - 1] && this.list.length == 1) { this.reset(); return; } while (this.list[this.index].content == this.list[this.index - 1].content) { this.index--; if (this.index == 0) { return this.restore(0); } } this.restore(--this.index); } }; this.redo = function () { if (this.hasRedo) { while (this.list[this.index].content == this.list[this.index + 1].content) { this.index++; if (this.index == this.list.length - 1) { return this.restore(this.index); } } this.restore(++this.index); } }; this.restore = function () { var scene = this.list[this.index]; //trace:873 //去掉展位符 me.document.body.innerHTML = scene.content.replace(fillchar, ''); //处理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); } }) } new dom.Range(me.document).moveToAddress(scene.address).select(); this.update(); this.clearKey(); //不能把自己reset了 me.fireEvent('reset', true); }; this.getScene = function (notSetCursor) { var rng = me.selection.getRange(), restoreAddress = rng.createAddress(), rngAddress = rng.createAddress(false, true); me.fireEvent('beforegetscene'); var cont = me.body.innerHTML.replace(fillchar, ''); browser.ie && (cont = cont.replace(/> <').replace(/\s*\s*/g, '>')); me.fireEvent('aftergetscene'); try { !notSetCursor && rng.moveToAddress(restoreAddress).select(true); } catch (e) { } return { address: rngAddress, content: cont } }; this.save = function (notCompareRange, notSetCursor) { var currentScene = this.getScene(notSetCursor), lastScene = this.list[this.index]; //内容相同位置相同不存 if (lastScene && lastScene.content == currentScene.content && ( notCompareRange ? 1 : compareRangeAddress(lastScene.address, currentScene.address) ) ) { return; } this.list = this.list.slice(0, this.index + 1); this.list.push(currentScene); //如果大于最大数量了,就把最前的剔除 if (this.list.length > maxUndoCount) { this.list.shift(); } this.index = this.list.length - 1; this.clearKey(); //跟新undo/redo状态 this.update(); }; this.update = function () { this.hasRedo = !!this.list[this.index + 1]; this.hasUndo = !!this.list[this.index - 1]; }; this.reset = function () { this.list = []; this.index = 0; this.hasUndo = false; this.hasRedo = false; this.clearKey(); }; this.clearKey = function () { keycont = 0; lastKeyCode = null; }; } me.undoManger = new UndoManager(); function saveScene() { this.undoManger.save(); } me.addListener('saveScene', function () { me.undoManger.save(); }); me.addListener('beforeexeccommand', saveScene); me.addListener('afterexeccommand', saveScene); me.addListener('reset', function (type, exclude) { if (!exclude) { me.undoManger.reset(); } }); me.commands['redo'] = me.commands['undo'] = { execCommand: function (cmdName) { me.undoManger[cmdName](); }, queryCommandState: function (cmdName) { return me.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, 13: 1 /*enter*/ }, keycont = 0, lastKeyCode; //输入法状态下不计算字符数 var inputType = false; me.addListener('ready', function () { domUtils.on(me.body, 'compositionstart', function () { inputType = true; }); domUtils.on(me.body, 'compositionend', function () { inputType = false; }) }); //快捷键 me.addshortcutkey({ "Undo": "ctrl+90", //undo "Redo": "ctrl+89" //redo }); me.addListener('keydown', function (type, evt) { var keyCode = evt.keyCode || evt.which; if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) { if (inputType) return; if (me.undoManger.list.length == 0 || ((keyCode == 8 || keyCode == 46) && lastKeyCode != keyCode)) { me.fireEvent('contentchange'); me.undoManger.save(true, true); lastKeyCode = keyCode; return; } //trace:856 //修正第一次输入后,回退,再输入要到keycont>maxInputCount才能在回退的问题 if (me.undoManger.list.length == 2 && me.undoManger.index == 0 && keycont == 0) { me.undoManger.list.splice(1, 1); me.undoManger.update(); } lastKeyCode = keyCode; keycont++; if (keycont >= maxInputCount || me.undoManger.mousedown) { if (me.selection.getRange().collapsed) me.fireEvent('contentchange'); me.undoManger.save(false, true); me.undoManger.mousedown = false; } } }); me.addListener('mousedown', function () { me.undoManger.mousedown = true; }) }; ///import core ///import plugins/inserthtml.js ///import plugins/undo.js ///import plugins/serialize.js ///commands 粘贴 ///commandsName PastePlain ///commandsTitle 纯文本粘贴模式 /* ** @description 粘贴 * @author zhanyi */ (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); } UE.plugins['paste'] = function () { var me = this; var word_img_flag = {flag: ""}; var pasteplain = me.options.pasteplain === true; var modify_num = {flag: ""}; me.commands['pasteplain'] = { queryCommandState: function () { return pasteplain; }, execCommand: function () { pasteplain = !pasteplain | 0; }, notNeedUndo: 1 }; var txtContent, htmlContent, address; 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-/.test(ci)) { domUtils.remove(ci); } } utils.each(domUtils.getElementsByTagName(div, 'span', function (node) { if (node.style.cssText) { node.style.cssText = node.style.cssText.replace(/white-space[^;]+;/g, ''); if (!node.style.cssText) { domUtils.removeAttributes(node, 'style'); if (domUtils.hasNoAttributes(node)) { return 1 } } } return 0 }), function (si) { domUtils.remove(si, true) }) } 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| )*?)<'); var f = me.serialize; if (f) { //如果过滤出现问题,捕获它,直接插入内容,避免出现错误导致粘贴整个失败 try { html = UE.filterWord(html); var node = f.transformInput( f.parseHTML( //todo: 暂时不走dtd的过滤 html//, true ), word_img_flag ); //trace:924 //纯文本模式也要保留段落 node = f.filter(node, pasteplain ? { whiteList: { 'p': {'br': 1, 'BR': 1, $: {}}, 'br': {'$': {}}, 'div': {'br': 1, 'BR': 1, '$': {}}, 'li': {'$': {}}, 'tr': {'td': 1, '$': {}}, 'td': {'$': {}} }, blackList: { 'style': 1, 'script': 1, 'object': 1 } } : null, !pasteplain ? modify_num : null); if (browser.webkit) { var length = node.children.length, child; while ((child = node.children[length - 1]) && child.tag == 'br') { node.children.splice(length - 1, 1); length = node.children.length; } } html = f.toHTML(node, pasteplain); txtContent = f.filter(node, { whiteList: { 'p': {'br': 1, 'BR': 1, $: {}}, 'br': {'$': {}}, 'div': {'br': 1, 'BR': 1, '$': {}, 'table': 1, 'ul': 1, 'ol': 1}, 'li': {'$': {}}, 'ul': {'li': 1, '$': {}}, 'ol': {'li': 1, '$': {}}, 'tr': {'td': 1, '$': {}}, 'td': {'$': {}}, 'table': {'tr': 1, 'tbody': 1, 'td': 1, '$': {}}, 'tbody': {'tr': 1, 'td': 1, '$': {}}, h1: {'$': {}}, h2: {'$': {}}, h3: {'$': {}}, h4: {'$': {}}, h5: {'$': {}}, h6: {'$': {}} }, blackList: { 'style': 1, 'script': 1, 'object': 1 } }); txtContent = f.toHTML(txtContent, true) } catch (e) { } } //自定义的处理 html = {'html': html, 'txtContent': txtContent}; me.fireEvent('beforepaste', html); //不用在走过滤了 if (html.html) { htmlContent = html.html; address = me.selection.getRange().createAddress(true); me.execCommand('insertHtml', htmlContent, true); me.fireEvent("afterpaste"); } } } me.addListener('pasteTransfer', function (cmd, plainType) { if (address && txtContent && htmlContent && txtContent != htmlContent) { var range = me.selection.getRange(); range.moveToAddress(address, true).deleteContents(); range.select(true); me.__hasEnterExecCommand = true; var html = htmlContent; if (plainType === 2) { html = 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) + '>' } }); } else if (plainType) { html = txtContent; } me.execCommand('inserthtml', html, true); me.__hasEnterExecCommand = false; var tmpAddress = me.selection.getRange().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); }); }); }); }; })(); ///import core ///commands 有序列表,无序列表 ///commandsName InsertOrderedList,InsertUnorderedList ///commandsTitle 有序列表,无序列表 /** * 有序列表 * @function * @name baidu.editor.execCommand * @param {String} cmdName insertorderlist插入有序列表 * @param {String} style 值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman * @author zhanyi */ /** * 无序链接 * @function * @name baidu.editor.execCommand * @param {String} cmdName insertunorderlist插入无序列表 * * @param {String} style 值为:circle,disc,square * @author zhanyi */ UE.plugins['list'] = function () { var me = this, notExchange = { 'TD': 1, 'PRE': 1, 'BLOCKQUOTE': 1 }; var customStyle = { 'cn': 'cn-1-', 'cn1': 'cn-2-', 'cn2': 'cn-3-', 'num': 'num-1-', 'num1': 'num-2-', 'num2': 'num-3-', 'dash': 'dash', 'dot': 'dot' }; me.setOpt({ '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: 3//-1不限制 }); var liiconpath = me.options.listiconpath; //根据用户配置,调整customStyle for (var s in customStyle) { if (!me.options.insertorderedlist.hasOwnProperty(s) && !me.options.insertunorderedlist.hasOwnProperty(s)) { delete customStyle[s]; } } me.ready(function () { var customCss = []; for (var p in customStyle) { if (p == 'dash' || p == 'dot') { customCss.push('li.list-' + customStyle[p] + '{background-image:url(' + liiconpath + customStyle[p] + '.gif)}'); customCss.push('ul.custom_' + p + '{list-style:none;}ul.custom_' + p + ' li{background-position:0 3px;background-repeat:no-repeat}'); } else { for (var i = 0; i < 99; i++) { customCss.push('li.list-' + customStyle[p] + i + '{background-image:url(' + liiconpath + 'list-' + customStyle[p] + i + '.gif)}') } customCss.push('ol.custom_' + p + '{list-style:none;}ol.custom_' + p + ' li{background-position:0 3px;background-repeat:no-repeat}'); } switch (p) { case 'cn': customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}'); customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}'); customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}'); break; case 'cn1': customCss.push('li.list-' + p + '-paddingleft-1{padding-left:30px}'); customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}'); customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}'); break; case 'cn2': customCss.push('li.list-' + p + '-paddingleft-1{padding-left:40px}'); customCss.push('li.list-' + p + '-paddingleft-2{padding-left:55px}'); customCss.push('li.list-' + p + '-paddingleft-3{padding-left:68px}'); break; case 'num': case 'num1': customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}'); break; case 'num2': customCss.push('li.list-' + p + '-paddingleft-1{padding-left:35px}'); customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}'); break; case 'dash': customCss.push('li.list-' + p + '-paddingleft{padding-left:35px}'); break; case 'dot': customCss.push('li.list-' + p + '-paddingleft{padding-left:20px}'); } } customCss.push('.list-paddingleft-1{padding-left:0}'); customCss.push('.list-paddingleft-2{padding-left:' + me.options.listDefaultPaddingLeft + 'px}'); customCss.push('.list-paddingleft-3{padding-left:' + me.options.listDefaultPaddingLeft * 2 + 'px}'); //如果不给宽度会在自定应样式里出现滚动条 utils.cssRule('list', 'ol,ul{margin:0;pading:0;' + (browser.ie ? '' : 'width:95%') + '}li{clear:both;}' + customCss.join('\n'), me.document); }); function getStyle(node) { var cls = node.className; if (domUtils.hasClass(node, /custom_/)) { return cls.match(/custom_(\w+)/)[1] } return '' } // function checkCustomStyle(list){ // if(domUtils.hasClass(list,/custom_/)){ // return '' // } // var style; // utils.each(list.childNodes,function(li){ // if(li.tagName == 'LI'){ // if(domUtils.hasClass(li,/list-/)){ // var tmpStyle = li.className.match(/list-(\w+)-(\d+)?/); // style = tmpStyle[1]+(tmpStyle[2] && tmpStyle[2] != '1'? tmpStyle[2]:''); // return false // } // } // }) // return style; // } //调整索引标签 me.addListener('contentchange', function () { utils.each(domUtils.getElementsByTagName(me.document, 'ol ul'), function (node) { if (!domUtils.inDoc(node, me.document)) return; // var style; // if(style = checkCustomStyle(node)){ // node.className = 'custom_' + style; // } var index = 0, type = 2, parent = node.parentNode; 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; } } style = domUtils.getStyle(node, 'list-style-type'); node.style.cssText = style ? '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') } }); 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); } function setListStyle(list, style) { if (customStyle[style]) { list.className = 'custom_' + style; } try { domUtils.setStyle(list, 'list-style-type', style); } catch (e) { } } function clearEmptySibling(node) { var tmpNode = node.previousSibling; if (tmpNode && domUtils.isEmptyBlock(tmpNode)) { domUtils.remove(tmpNode); } tmpNode = node.nextSibling; if (tmpNode && domUtils.isEmptyBlock(tmpNode)) { domUtils.remove(tmpNode); } } me.addListener('keydown', function (type, evt) { function preventAndSave() { evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false); me.fireEvent('contentchange'); me.undoManger && me.undoManger.save(); } function findList(node, filterFn) { while (node && !domUtils.isBody(node)) { if (filterFn(node)) { return null } if (node.nodeType == 1 && /[ou]l/i.test(node.tagName)) { return node; } node = node.parentNode; } return null; } var keyCode = evt.keyCode || evt.which; if (keyCode == 13 && !evt.shiftKey) {//回车 var range = me.selection.getRange(), start = findList(range.startContainer, function (node) { return node.tagName == 'TABLE'; }), end = range.collapsed ? start : findList(range.endContainer, function (node) { return node.tagName == 'TABLE'; }); if (start && end && start === end) { if (!range.collapsed) { start = domUtils.findParentByTagName(range.startContainer, 'li', true); end = domUtils.findParentByTagName(range.endContainer, 'li', true); if (start && end && start === end) { range.deleteContents(); li = domUtils.findParentByTagName(range.startContainer, 'li', true); if (li && domUtils.isEmptyBlock(li)) { pre = li.previousSibling; next = li.nextSibling; p = me.document.createElement('p'); domUtils.fillNode(me.document, p); parentList = li.parentNode; if (pre && next) { range.setStart(next, 0).collapse(true).select(true); domUtils.remove(li); } else { if (!pre && !next || !pre) { parentList.parentNode.insertBefore(p, parentList); } else { li.parentNode.parentNode.insertBefore(p, parentList.nextSibling); } domUtils.remove(li); if (!parentList.firstChild) { domUtils.remove(parentList); } range.setStart(p, 0).setCursor(); } preventAndSave(); return; } } else { var tmpRange = range.cloneRange(), bk = tmpRange.collapse(false).createBookmark(); range.deleteContents(); tmpRange.moveToBookmark(bk); var li = domUtils.findParentByTagName(tmpRange.startContainer, 'li', true); clearEmptySibling(li); tmpRange.select(); preventAndSave(); return; } } li = domUtils.findParentByTagName(range.startContainer, 'li', true); if (li) { if (domUtils.isEmptyBlock(li)) { bk = range.createBookmark(); var parentList = li.parentNode; if (li !== parentList.lastChild) { domUtils.breakParent(li, parentList); clearEmptySibling(li); } else { parentList.parentNode.insertBefore(li, parentList.nextSibling); if (domUtils.isEmptyNode(parentList)) { domUtils.remove(parentList); } } //嵌套不处理 if (!dtd.$list[li.parentNode.tagName]) { if (!domUtils.isBlockElm(li.firstChild)) { p = me.document.createElement('p'); li.parentNode.insertBefore(p, li); while (li.firstChild) { p.appendChild(li.firstChild); } domUtils.remove(li); } else { domUtils.remove(li, true); } } range.moveToBookmark(bk).select(); } else { var first = li.firstChild; if (!first || !domUtils.isBlockElm(first)) { var p = me.document.createElement('p'); !li.firstChild && domUtils.fillNode(me.document, p); while (li.firstChild) { p.appendChild(li.firstChild); } li.appendChild(p); first = p; } var span = me.document.createElement('span'); range.insertNode(span); domUtils.breakParent(span, li); var nextLi = span.nextSibling; first = nextLi.firstChild; if (!first) { p = me.document.createElement('p'); domUtils.fillNode(me.document, p); nextLi.appendChild(p); first = p; } if (domUtils.isEmptyNode(first)) { first.innerHTML = ''; domUtils.fillNode(me.document, first); } range.setStart(first, 0).collapse(true).shrinkBoundary().select(); domUtils.remove(span); var pre = nextLi.previousSibling; if (pre && domUtils.isEmptyBlock(pre)) { pre.innerHTML = '

'; domUtils.fillNode(me.document, pre.firstChild); } } // } preventAndSave(); } } } if (keyCode == 8) { //修中ie中li下的问题 range = me.selection.getRange(); if (range.collapsed && domUtils.isStartInblock(range)) { tmpRange = range.cloneRange().trimBoundary(); li = domUtils.findParentByTagName(range.startContainer, 'li', true); //要在li的最左边,才能处理 if (li && domUtils.isStartInblock(tmpRange)) { start = domUtils.findParentByTagName(range.startContainer, 'p', true); if (start && start !== li.firstChild) { var parentList = domUtils.findParentByTagName(start, ['ol', 'ul']); domUtils.breakParent(start, parentList); clearEmptySibling(start); me.fireEvent('contentchange'); range.setStart(start, 0).setCursor(false, true); me.fireEvent('saveScene'); domUtils.preventDefault(evt); return; } if (li && (pre = li.previousSibling)) { if (keyCode == 46 && li.childNodes.length) { return; } //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li if (dtd.$list[pre.tagName]) { pre = pre.lastChild; } me.undoManger && me.undoManger.save(); first = li.firstChild; if (domUtils.isBlockElm(first)) { if (domUtils.isEmptyNode(first)) { // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true); pre.appendChild(first); range.setStart(first, 0).setCursor(false, true); //first不是唯一的节点 while (li.firstChild) { pre.appendChild(li.firstChild); } } else { span = me.document.createElement('span'); range.insertNode(span); //判断pre是否是空的节点,如果是


类型的空节点,干掉p标签防止它占位 if (domUtils.isEmptyBlock(pre)) { pre.innerHTML = ''; } domUtils.moveChild(li, pre); range.setStartBefore(span).collapse(true).select(true); domUtils.remove(span); } } else { if (domUtils.isEmptyNode(li)) { var p = me.document.createElement('p'); pre.appendChild(p); range.setStart(p, 0).setCursor(); // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true); } else { range.setEnd(pre, pre.childNodes.length).collapse().select(true); while (li.firstChild) { pre.appendChild(li.firstChild); } } } domUtils.remove(li); me.fireEvent('contentchange'); me.fireEvent('saveScene'); domUtils.preventDefault(evt); return; } //trace:980 if (li && !li.previousSibling) { var parentList = li.parentNode; var bk = range.createBookmark(); if (domUtils.isTagNode(parentList.parentNode, 'ol ul')) { parentList.parentNode.insertBefore(li, parentList); if (domUtils.isEmptyNode(parentList)) { domUtils.remove(parentList) } } else { while (li.firstChild) { parentList.parentNode.insertBefore(li.firstChild, parentList); } domUtils.remove(li); if (domUtils.isEmptyNode(parentList)) { domUtils.remove(parentList) } } range.moveToBookmark(bk).setCursor(false, true); me.fireEvent('contentchange'); me.fireEvent('saveScene'); domUtils.preventDefault(evt); return; } } } } }); //处理tab键 me.addListener('tabkeydown', function () { function listToArray(list) { var arr = []; for (var p in list) { arr.push(p) } return arr; } var range = me.selection.getRange(), listStyle = { 'OL': listToArray(me.options.insertorderedlist), 'UL': listToArray(me.options.insertunorderedlist) }; //控制级数 function checkLevel(li) { if (me.options.maxListLevel != -1) { var level = li.parentNode, levelNum = 0; while (/[ou]l/i.test(level.tagName)) { levelNum++; level = level.parentNode; } if (levelNum >= me.options.maxListLevel) { return true; } } } //只以开始为准 //todo 后续改进 var li = domUtils.findParentByTagName(range.startContainer, 'li', true); if (li) { var bk; if (range.collapsed) { if (checkLevel(li)) return true; var parentLi = li.parentNode, list = me.document.createElement(parentLi.tagName), index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) || domUtils.getComputedStyle(parentLi, 'list-style-type')); index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1; var currentStyle = listStyle[list.tagName][index]; setListStyle(list, currentStyle); if (domUtils.isStartInblock(range)) { me.fireEvent('saveScene'); bk = range.createBookmark(); parentLi.insertBefore(list, li); list.appendChild(li); adjustList(list, list.tagName.toLowerCase(), currentStyle); me.fireEvent('contentchange'); range.moveToBookmark(bk).select(true); return true; } } else { me.fireEvent('saveScene'); bk = range.createBookmark(); for (var i = 0, closeList, parents = domUtils.findParents(li), ci; ci = parents[i++];) { if (domUtils.isTagNode(ci, 'ol ul')) { closeList = ci; break; } } var current = li; if (bk.end) { while (current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)) { if (checkLevel(current)) { current = domUtils.getNextDomNode(current, false, null, function (node) { return node !== closeList }); continue; } var parentLi = current.parentNode, list = me.document.createElement(parentLi.tagName), index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi) || domUtils.getComputedStyle(parentLi, 'list-style-type')); var currentIndex = index + 1 == listStyle[list.tagName].length ? 0 : index + 1; var currentStyle = listStyle[list.tagName][currentIndex]; setListStyle(list, currentStyle); parentLi.insertBefore(list, current); while (current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)) { li = current.nextSibling; list.appendChild(current); if (!li || domUtils.isTagNode(li, 'ol ul')) { if (li) { while (li = li.firstChild) { if (li.tagName == 'LI') { break; } } } else { li = domUtils.getNextDomNode(current, false, null, function (node) { return node !== closeList }); } break; } current = li; } adjustList(list, list.tagName.toLowerCase(), currentStyle); current = li; } } me.fireEvent('contentchange'); range.moveToBookmark(bk).select(); return true; } } }); me.commands['insertorderedlist'] = me.commands['insertunorderedlist'] = { execCommand: function (command, style) { if (!style) { style = command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc'; } var me = this, range = this.selection.getRange(), filterFn = function (node) { return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace(node); }, tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul', frag = me.document.createDocumentFragment(); //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置 //range.shrinkBoundary();//.adjustmentBoundary(); range.adjustmentBoundary().shrinkBoundary(); var bko = range.createBookmark(true), start = domUtils.findParentByTagName(me.document.getElementById(bko.start), 'li'), modifyStart = 0, end = domUtils.findParentByTagName(me.document.getElementById(bko.end), 'li'), modifyEnd = 0, startParent, endParent, list, tmp; if (start || end) { start && (startParent = start.parentNode); if (!bko.end) { end = start; } end && (endParent = end.parentNode); if (startParent === endParent) { while (start !== end) { tmp = start; start = start.nextSibling; if (!domUtils.isBlockElm(tmp.firstChild)) { var p = me.document.createElement('p'); while (tmp.firstChild) { p.appendChild(tmp.firstChild); } tmp.appendChild(p); } frag.appendChild(tmp); } tmp = me.document.createElement('span'); startParent.insertBefore(tmp, end); if (!domUtils.isBlockElm(end.firstChild)) { p = me.document.createElement('p'); while (end.firstChild) { p.appendChild(end.firstChild); } end.appendChild(p); } frag.appendChild(end); domUtils.breakParent(tmp, startParent); if (domUtils.isEmptyNode(tmp.previousSibling)) { domUtils.remove(tmp.previousSibling); } if (domUtils.isEmptyNode(tmp.nextSibling)) { domUtils.remove(tmp.nextSibling) } var nodeStyle = getStyle(startParent) || domUtils.getComputedStyle(startParent, 'list-style-type') || (command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc'); if (startParent.tagName.toLowerCase() == tag && nodeStyle == style) { for (var i = 0, ci, tmpFrag = me.document.createDocumentFragment(); ci = frag.childNodes[i++];) { if (domUtils.isTagNode(ci, 'ol ul')) { utils.each(domUtils.getElementsByTagName(ci, 'li'), function (li) { while (li.firstChild) { tmpFrag.appendChild(li.firstChild); } }); } else { while (ci.firstChild) { tmpFrag.appendChild(ci.firstChild); } } } tmp.parentNode.insertBefore(tmpFrag, tmp); } else { list = me.document.createElement(tag); setListStyle(list, style); list.appendChild(frag); tmp.parentNode.insertBefore(list, tmp); } domUtils.remove(tmp); list && adjustList(list, tag, style); range.moveToBookmark(bko).select(); return; } //开始 if (start) { while (start) { tmp = start.nextSibling; if (domUtils.isTagNode(start, 'ol ul')) { frag.appendChild(start); } else { var tmpfrag = me.document.createDocumentFragment(), hasBlock = 0; while (start.firstChild) { if (domUtils.isBlockElm(start.firstChild)) { hasBlock = 1; } tmpfrag.appendChild(start.firstChild); } if (!hasBlock) { var tmpP = me.document.createElement('p'); tmpP.appendChild(tmpfrag); frag.appendChild(tmpP); } else { frag.appendChild(tmpfrag); } domUtils.remove(start); } start = tmp; } startParent.parentNode.insertBefore(frag, startParent.nextSibling); if (domUtils.isEmptyNode(startParent)) { range.setStartBefore(startParent); domUtils.remove(startParent); } else { range.setStartAfter(startParent); } modifyStart = 1; } if (end && domUtils.inDoc(endParent, me.document)) { //结束 start = endParent.firstChild; while (start && start !== end) { tmp = start.nextSibling; if (domUtils.isTagNode(start, 'ol ul')) { frag.appendChild(start); } else { tmpfrag = me.document.createDocumentFragment(); hasBlock = 0; while (start.firstChild) { if (domUtils.isBlockElm(start.firstChild)) { hasBlock = 1; } tmpfrag.appendChild(start.firstChild); } if (!hasBlock) { tmpP = me.document.createElement('p'); tmpP.appendChild(tmpfrag); frag.appendChild(tmpP); } else { frag.appendChild(tmpfrag); } domUtils.remove(start); } start = tmp; } var tmpDiv = domUtils.createElement(me.document, 'div', { 'tmpDiv': 1 }); domUtils.moveChild(end, tmpDiv); frag.appendChild(tmpDiv); domUtils.remove(end); endParent.parentNode.insertBefore(frag, endParent); range.setEndBefore(endParent); if (domUtils.isEmptyNode(endParent)) { domUtils.remove(endParent); } modifyEnd = 1; } } if (!modifyStart) { range.setStartBefore(me.document.getElementById(bko.start)); } if (bko.end && !modifyEnd) { range.setEndAfter(me.document.getElementById(bko.end)); } range.enlarge(true, function (node) { return notExchange[node.tagName]; }); frag = me.document.createDocumentFragment(); var bk = range.createBookmark(), current = domUtils.getNextDomNode(bk.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode, block = domUtils.isBlockElm; while (current && current !== bk.end && (domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING)) { if (current.nodeType == 3 || dtd.li[current.tagName]) { if (current.nodeType == 1 && dtd.$list[current.tagName]) { while (current.firstChild) { frag.appendChild(current.firstChild); } tmpNode = domUtils.getNextDomNode(current, false, filterFn); domUtils.remove(current); current = tmpNode; continue; } tmpNode = current; tmpRange.setStartBefore(current); while (current && current !== bk.end && (!block(current) || domUtils.isBookmarkNode(current) )) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !notExchange[node.tagName]; }); } if (current && block(current)) { tmp = domUtils.getNextDomNode(tmpNode, false, filterFn); if (tmp && domUtils.isBookmarkNode(tmp)) { current = domUtils.getNextDomNode(tmp, false, filterFn); tmpNode = tmp; } } tmpRange.setEndAfter(tmpNode); current = domUtils.getNextDomNode(tmpNode, false, filterFn); var li = range.document.createElement('li'); li.appendChild(tmpRange.extractContents()); if (domUtils.isEmptyNode(li)) { var tmpNode = range.document.createElement('p'); while (li.firstChild) { tmpNode.appendChild(li.firstChild) } li.appendChild(tmpNode); } frag.appendChild(li); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } range.moveToBookmark(bk).collapse(true); list = me.document.createElement(tag); setListStyle(list, style); list.appendChild(frag); range.insertNode(list); //当前list上下看能否合并 adjustList(list, tag, style, true); //去掉冗余的tmpDiv for (var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, 'div'); ci = tmpDivs[i++];) { if (ci.getAttribute('tmpDiv')) { domUtils.remove(ci, true) } } range.moveToBookmark(bko).select(); }, queryCommandState: function (command) { return domUtils.filterNodeList(this.selection.getStartElementPath(), command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul') ? 1 : 0; }, queryCommandValue: function (command) { var node = domUtils.filterNodeList(this.selection.getStartElementPath(), command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul'); return node ? getStyle(node) || domUtils.getComputedStyle(node, 'list-style-type') : null; } }; }; ///import core ///import plugins/serialize.js ///import plugins/undo.js ///commands 查看源码 ///commandsName Source ///commandsTitle 查看源码 (function () { function SourceFormater(config) { config = config || {}; this.indentChar = config.indentChar || ' '; this.breakChar = config.breakChar || '\n'; this.selfClosingEnd = config.selfClosingEnd || ' />'; } var unhtml1 = function () { var map = { '<': '<', '>': '>', '"': '"', "'": ''' }; function rep(m) { return map[m]; } return function (str) { str = str + ''; return str ? str.replace(/[<>"']/g, rep) : ''; }; }(); var inline = utils.extend({a: 1, A: 1}, dtd.$inline, true); function printAttrs(attrs) { var buff = []; for (var k in attrs) { buff.push(k + '="' + unhtml1(attrs[k]) + '"'); } return buff.join(' '); } SourceFormater.prototype = { format: function (html) { var node = UE.serialize.parseHTML(html); this.buff = []; this.indents = ''; this.indenting = 1; this.visitNode(node); return this.buff.join(''); }, visitNode: function (node) { if (node.type == 'fragment') { this.visitChildren(node.children); } else if (node.type == 'element') { var selfClosing = dtd.$empty[node.tag]; this.visitTag(node.tag, node.attributes, selfClosing); this.visitChildren(node.children); if (!selfClosing) { this.visitEndTag(node.tag); } } else if (node.type == 'comment') { this.visitComment(node.data); } else { this.visitText(node.data, dtd.$notTransContent[node.parent.tag]); } }, visitChildren: function (children) { for (var i = 0; i < children.length; i++) { this.visitNode(children[i]); } }, visitTag: function (tag, attrs, selfClosing) { if (this.indenting) { this.indent(); } else if (!inline[tag]) { // todo: 去掉a, 因为dtd的inline里面没有a this.newline(); this.indent(); } this.buff.push('<', tag); var attrPart = printAttrs(attrs); if (attrPart) { this.buff.push(' ', attrPart); } if (selfClosing) { this.buff.push(this.selfClosingEnd); if (tag == 'br') { this.newline(); } } else { this.buff.push('>'); this.indents += this.indentChar; } if (!inline[tag]) { this.newline(); } }, indent: function () { this.buff.push(this.indents); this.indenting = 0; }, newline: function () { this.buff.push(this.breakChar); this.indenting = 1; }, visitEndTag: function (tag) { this.indents = this.indents.slice(0, -this.indentChar.length); if (this.indenting) { this.indent(); } else if (!inline[tag]) { this.newline(); this.indent(); } this.buff.push(''); }, visitText: function (text, notTrans) { if (this.indenting) { this.indent(); } // if(!notTrans){ // text = text.replace(/ /g, ' ').replace(/[ ][ ]+/g, function (m){ // return new Array(m.length + 1).join(' '); // }).replace(/(?:^ )|(?: $)/g, ' '); // } text = text.replace(/ /g, ' '); this.buff.push(text); }, visitComment: function (text) { if (this.indenting) { this.indent(); } this.buff.push(''); } }; 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 formatter = new SourceFormater(opt.source); var sourceMode = false; var sourceEditor; opt.sourceEditor = browser.ie ? 'textarea' : (opt.sourceEditor || 'codemirror'); me.setOpt({ sourceEditorFirst: false }); function createSourceEditor(holder) { return sourceEditors[opt.sourceEditor == 'codemirror' && window.CodeMirror ? 'codemirror' : 'textarea'](me, holder); } var bakCssText; //解决在源码模式下getContent不能得到最新的内容问题 var oldGetContent = me.getContent, bakAddress; me.commands['source'] = { execCommand: function () { sourceMode = !sourceMode; if (sourceMode) { bakAddress = me.selection.getRange().createAddress(false, true); me.undoManger && me.undoManger.save(true); if (browser.gecko) { me.body.contentEditable = false; } bakCssText = me.iframe.style.cssText; me.iframe.style.cssText += 'position:absolute;left:-32768px;top:-32768px;'; var content = formatter.format(me.hasContents() ? me.getContent() : ''); sourceEditor = createSourceEditor(me.iframe.parentNode); sourceEditor.setContent(content); setTimeout(function () { sourceEditor.select(); me.addListener('fullscreenchanged', function () { try { sourceEditor.getCodeMirror().refresh() } catch (e) { } }); }); //重置getContent,源码模式下取值也能是最新的数据 me.getContent = function () { var cont = sourceEditor.getContent() || '

' + (browser.ie ? '' : '
') + '

'; return cont.replace(/>[\n\r\t]+([ ]{4})+/g, '>').replace(/[\n\r\t]+([ ]{4})+[\n\r\t]+<'); }; } else { me.iframe.style.cssText = bakCssText; var cont = sourceEditor.getContent() || '

' + (browser.ie ? '' : '
') + '

'; cont = cont.replace(/>[\n\r\t]+([ ]{4})+/g, '>').replace(/[\n\r\t]+([ ]{4})+[\n\r\t]+<'); me.setContent(cont); sourceEditor.dispose(); sourceEditor = null; //还原getContent方法 me.getContent = oldGetContent; var first = me.body.firstChild; //trace:1106 都删除空了,下边会报错,所以补充一个p占位 if (!first) { me.body.innerHTML = '

' + (browser.ie ? '' : '
') + '

'; first = me.body.firstChild; } //要在ifm为显示时ff才能取到selection,否则报错 //这里不能比较位置了 me.undoManger && me.undoManger.save(true); if (browser.gecko) { var input = document.createElement('input'); input.style.cssText = 'position:absolute;left:0;top:-32768px'; document.body.appendChild(input); me.body.contentEditable = false; setTimeout(function () { domUtils.setViewportOffset(input, { left: -32768, top: 0 }); input.focus(); setTimeout(function () { me.body.contentEditable = true; me.selection.getRange().moveToAddress(bakAddress).select(); domUtils.remove(input); }); }); } else { //ie下有可能报错,比如在代码顶头的情况 try { me.selection.getRange().moveToAddress(bakAddress).select(); } catch (e) { } } } this.fireEvent('sourcemodechanged', sourceMode); }, queryCommandState: function () { return sourceMode | 0; }, notNeedUndo: 1 }; var oldQueryCommandState = me.queryCommandState; me.queryCommandState = function (cmdName) { cmdName = cmdName.toLowerCase(); if (sourceMode) { //源码模式下可以开启的命令 return cmdName in { 'source': 1, 'fullscreen': 1 } ? 1 : -1 } return oldQueryCommandState.apply(this, arguments); }; if (opt.sourceEditor == "codemirror") { me.addListener("ready", function () { utils.loadFile(document, { src: opt.codeMirrorJsUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.js", tag: "script", type: "text/javascript", defer: "defer" }, function () { if (opt.sourceEditorFirst) { setTimeout(function () { me.execCommand("source"); }, 0); } }); utils.loadFile(document, { tag: "link", rel: "stylesheet", type: "text/css", href: opt.codeMirrorCssUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.css" }); }); } }; })(); ///import core ///import plugins/undo.js ///commands 设置回车标签p或br ///commandsName EnterKey ///commandsTitle 设置回车标签p或br /** * @description 处理回车 * @author zhanyi */ UE.plugins['enterkey'] = function () { var hTag, me = this, tag = me.options.enterTag; me.addListener('keyup', function (type, evt) { var keyCode = evt.keyCode || evt.which; if (keyCode == 13) { var range = me.selection.getRange(), start = range.startContainer, doSave; //修正在h1-h6里边回车后不能嵌套p的问题 if (!browser.ie) { if (/h\d/i.test(hTag)) { if (browser.gecko) { var h = domUtils.findParentByTagName(start, [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption', 'table'], true); if (!h) { me.document.execCommand('formatBlock', false, '

'); doSave = 1; } } else { //chrome remove div if (start.nodeType == 1) { var tmp = me.document.createTextNode(''), div; range.insertNode(tmp); div = domUtils.findParentByTagName(tmp, 'div', true); if (div) { var p = me.document.createElement('p'); while (div.firstChild) { p.appendChild(div.firstChild); } div.parentNode.insertBefore(p, div); domUtils.remove(div); range.setStartBefore(tmp).setCursor(); doSave = 1; } domUtils.remove(tmp); } } if (me.undoManger && doSave) { me.undoManger.save(); } } //没有站位符,会出现多行的问题 browser.opera && range.select(); } // if(browser.ie){ // range = me.selection.getRange(); // start = range.startContainer; // while(start){ // if(start.nodeType == 1 && start.tagName == 'P'){ // break; // } // start = start.parentNode; // } // if(start && domUtils.isEmptyBlock(start)){ // start.innerHTML = ' '; // var rng = me.selection.getRange(); // rng.setStart(start,0).setCursor(false,true); // } // } setTimeout(function () { me.selection.getRange().scrollToView(me.autoHeightEnabled, me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0); }, 50); } }); me.addListener('keydown', function (type, evt) { var keyCode = evt.keyCode || evt.which; if (keyCode == 13) {//回车 if (me.undoManger) { me.undoManger.save(); } hTag = ''; var range = me.selection.getRange(); if (!range.collapsed) { //跨td不能删 var start = range.startContainer, end = range.endContainer, startTd = domUtils.findParentByTagName(start, 'td', true), endTd = domUtils.findParentByTagName(end, 'td', true); if (startTd && endTd && startTd !== endTd || !startTd && endTd || startTd && !endTd) { evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false); return; } } if (tag == 'p') { if (!browser.ie) { start = domUtils.findParentByTagName(range.startContainer, ['ol', 'ul', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption'], true); //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command //trace:2431 if (!start && !browser.opera) { me.document.execCommand('formatBlock', false, '

'); if (browser.gecko) { range = me.selection.getRange(); start = domUtils.findParentByTagName(range.startContainer, 'p', true); start && domUtils.removeDirtyAttr(start); } } else { hTag = start.tagName; start.tagName.toLowerCase() == 'p' && browser.gecko && domUtils.removeDirtyAttr(start); } } } else { evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false); if (!range.collapsed) { range.deleteContents(); start = range.startContainer; if (start.nodeType == 1 && (start = start.childNodes[range.startOffset])) { while (start.nodeType == 1) { if (dtd.$empty[start.tagName]) { range.setStartBefore(start).setCursor(); if (me.undoManger) { me.undoManger.save(); } return false; } if (!start.firstChild) { var br = range.document.createElement('br'); start.appendChild(br); range.setStart(start, 0).setCursor(); if (me.undoManger) { me.undoManger.save(); } return false; } start = start.firstChild; } if (start === range.startContainer.childNodes[range.startOffset]) { br = range.document.createElement('br'); range.insertNode(br).setCursor(); } else { range.setStart(start, 0).setCursor(); } } else { br = range.document.createElement('br'); range.insertNode(br).setStartAfter(br).setCursor(); } } else { br = range.document.createElement('br'); range.insertNode(br); var parent = br.parentNode; if (parent.lastChild === br) { br.parentNode.insertBefore(br.cloneNode(true), br); range.setStartBefore(br); } else { range.setStartAfter(br); } range.setCursor(); } } } }); }; /* * 处理特殊键的兼容性问题 */ UE.plugins['keystrokes'] = function () { var me = this; me.addListener('keydown', function (type, evt) { var keyCode = evt.keyCode || evt.which, rng = me.selection.getRange(); //处理全选的情况 if (!rng.collapsed && !(evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey || keyCode == 9 )) { 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); browser.ie && me._selectionChange(); domUtils.preventDefault(evt); return; } } } } //处理backspace/del if (keyCode == 8) {//|| keyCode == 46 var start, end; //避免按两次删除才能生效的问题 if (rng.inFillChar()) { start = rng.startContainer; rng.setStartBefore(start).shrinkBoundary(true).collapse(true); if (domUtils.isFillChar(start)) { domUtils.remove(start) } else { start.nodeValue = start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), ''); } } //解决选中control元素不能删除的问题 if (start = rng.getClosedNode()) { me.fireEvent('saveScene'); rng.setStartBefore(start); domUtils.remove(start); rng.setCursor(); me.fireEvent('saveScene'); domUtils.preventDefault(evt); return; } //阻止在table上的删除 if (!browser.ie) { start = domUtils.findParentByTagName(rng.startContainer, 'table', true); end = domUtils.findParentByTagName(rng.endContainer, 'table', true); if (start && !end || !start && end || start !== end) { evt.preventDefault(); return; } } } //处理tab键的逻辑 if (keyCode == 9) { //不处理以下标签 var excludeTagNameForTabKey = { 'ol': 1, 'ul': 1, 'table': 1 }; //处理组件里的tab按下事件 if (me.fireEvent('tabkeydown')) { domUtils.preventDefault(evt); return; } 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 { //普通的情况 start = domUtils.findParent(range.startContainer, filterFn); end = domUtils.findParent(range.endContainer, filterFn); if (start && end && start === end) { range.deleteContents(); range.insertNode(span.cloneNode(true).firstChild).setCursor(true); } else { var bookmark = range.createBookmark(), filterFn = function (node) { return domUtils.isBlockElm(node) && !excludeTagNameForTabKey[node.tagName.toLowerCase()] }; range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn); while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { current.insertBefore(span.cloneNode(true).firstChild, current.firstChild); current = domUtils.getNextDomNode(current, false, filterFn); } range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select(); } } domUtils.preventDefault(evt) } //trace:1634 //ff的del键在容器空的时候,也会删除 if (browser.gecko && keyCode == 46) { range = me.selection.getRange(); if (range.collapsed) { start = range.startContainer; if (domUtils.isEmptyBlock(start)) { var parent = start.parentNode; while (domUtils.getChildCount(parent) == 1 && !domUtils.isBody(parent)) { start = parent; parent = parent.parentNode; } if (start === parent.lastChild) evt.preventDefault(); return; } } } }); me.addListener('keyup', function (type, evt) { var keyCode = evt.keyCode || evt.which, rng; if (keyCode == 8) { rng = me.selection.getRange(); //处理当删除到body时,要重新给p标签展位 if (rng.collapsed && 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 (browser.chrome && rng.collapsed && rng.startContainer.nodeType == 1 && domUtils.isEmptyBlock(rng.startContainer)) { rng.select(true); } } }) }; ///import core ///commands 修复chrome下图片不能点击的问题 ///commandsName FixImgClick ///commandsTitle 修复chrome下图片不能点击的问题 //修复chrome下图片不能点击的问题 //todo 可以改大小 UE.plugins['fiximgclick'] = function () { var me = this; if (browser.webkit) { me.addListener('click', function (type, e) { if (e.target.tagName == 'IMG') { var range = new dom.Range(me.document); range.selectNode(e.target).select(); } }); } }; ///import core ///commands 为非ie浏览器自动添加a标签 ///commandsName AutoLink ///commandsTitle 自动增加链接 /** * @description 为非ie浏览器自动添加a标签 * @author zhanyi */ UE.plugins['autolink'] = function () { var cont = 0; if (browser.ie) { return; } var me = this; me.addListener('reset', function () { cont = 0; }); me.addListener('keydown', function (type, evt) { var keyCode = evt.keyCode || evt.which; if (keyCode == 32 || keyCode == 13) { var sel = me.selection.getNative(), range = sel.getRangeAt(0).cloneRange(), offset, charCode; var start = range.startContainer; while (start.nodeType == 1 && range.startOffset > 0) { start = range.startContainer.childNodes[range.startOffset - 1]; if (!start) { break; } range.setStart(start, start.nodeType == 1 ? start.childNodes.length : start.nodeValue.length); range.collapse(true); start = range.startContainer; } do { if (range.startOffset == 0) { start = range.startContainer.previousSibling; while (start && start.nodeType == 1) { start = start.lastChild; } if (!start || domUtils.isFillChar(start)) { break; } offset = start.nodeValue.length; } else { start = range.startContainer; offset = range.startOffset; } range.setStart(start, offset - 1); charCode = range.toString().charCodeAt(0); } while (charCode != 160 && charCode != 32); if (range.toString().replace(new RegExp(domUtils.fillChar, 'g'), '').match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)) { while (range.toString().length) { if (/^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(range.toString())) { break; } try { range.setStart(range.startContainer, range.startOffset + 1); } catch (e) { //trace:2121 var start = range.startContainer; while (!(next = start.nextSibling)) { if (domUtils.isBody(start)) { return; } start = start.parentNode; } range.setStart(next, 0); } } //range的开始边界已经在a标签里的不再处理 if (domUtils.findParentByTagName(range.startContainer, 'a', true)) { return; } var a = me.document.createElement('a'), text = me.document.createTextNode(' '), href; me.undoManger && me.undoManger.save(); a.appendChild(range.extractContents()); a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, ''); href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar, 'g'), ''); href = /^(?:https?:\/\/)/ig.test(href) ? href : "http://" + href; a.setAttribute('data_ue_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(); } } }); }; ///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, span, tmpNode, lastHeight = 0, options = me.options, currentHeight, timer; function adjustHeight() { var me = this; clearTimeout(timer); if (isFullscreen)return; timer = setTimeout(function () { if (me.queryCommandState && me.queryCommandState('source') != 1) { if (!span) { span = me.document.createElement('span'); //trace:1764 span.style.cssText = 'display:block;width:0;margin:0;padding:0;border:0;clear:both;'; span.innerHTML = '.'; } tmpNode = span.cloneNode(true); me.body.appendChild(tmpNode); currentHeight = Math.max(domUtils.getXY(tmpNode).y + tmpNode.offsetHeight, Math.max(options.minFrameHeight, options.initialFrameHeight)); if (currentHeight != lastHeight) { me.setHeight(currentHeight); lastHeight = currentHeight; } domUtils.remove(tmpNode); } }, 50); } var isFullscreen; me.addListener('fullscreenchanged', function (cmd, f) { isFullscreen = f }); me.addListener('destroy', function () { me.removeListener('contentchange', adjustHeight); me.removeListener('afterinserthtml', adjustHeight); me.removeListener('keyup', adjustHeight); me.removeListener('mouseup', adjustHeight); }); me.enableAutoHeight = function () { if (!me.autoHeightEnabled) { return; } var doc = me.document; me.autoHeightEnabled = true; bakOverflow = doc.body.style.overflowY; doc.body.style.overflowY = 'hidden'; me.addListener('contentchange', adjustHeight); me.addListener('afterinserthtml', adjustHeight) me.addListener('keyup', adjustHeight); me.addListener('mouseup', adjustHeight); //ff不给事件算得不对 setTimeout(function () { adjustHeight.call(this); }, 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.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 () { adjustHeight.call(this); }, 100); }); }); }; ///import core ///commands 悬浮工具栏 ///commandsName AutoFloat,autoFloatEnabled ///commandsTitle 悬浮工具栏 /* * modified by chengchao01 * * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉! */ UE.plugins['autofloat'] = function () { var me = this, lang = me.getLang(); me.setOpt({ topOffset: 0 }); var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false, topOffset = me.options.topOffset; //如果不固定toolbar的位置,则直接退出 if (!optsAutoFloatEnabled) { return; } var uiUtils = UE.ui.uiUtils, LteIE6 = browser.ie && browser.version <= 6, quirks = browser.quirks; function checkHasUI(editor) { if (!editor.ui) { alert(lang.autofloatMsg); return 0; } return 1; } function fixIE6FixedPos() { var docStyle = document.body.style; docStyle.backgroundImage = 'url("about:blank")'; docStyle.backgroundAttachment = 'fixed'; } var bakCssText, placeHolder = document.createElement('div'), toolbarBox, orgTop, getPosition, flag = true; //ie7模式下需要偏移 function setFloating() { var toobarBoxPos = domUtils.getXY(toolbarBox), origalFloat = domUtils.getComputedStyle(toolbarBox, 'position'), origalLeft = domUtils.getComputedStyle(toolbarBox, 'left'); toolbarBox.style.width = toolbarBox.offsetWidth + 'px'; toolbarBox.style.zIndex = me.options.zIndex * 1 + 1; toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox); if (LteIE6 || (quirks && browser.ie)) { if (toolbarBox.style.position != 'absolute') { toolbarBox.style.position = 'absolute'; } toolbarBox.style.top = (document.body.scrollTop || document.documentElement.scrollTop) - orgTop + topOffset + 'px'; } else { if (browser.ie7Compat && flag) { flag = false; toolbarBox.style.left = domUtils.getXY(toolbarBox).x - document.documentElement.getBoundingClientRect().left + 2 + 'px'; } if (toolbarBox.style.position != 'fixed') { toolbarBox.style.position = 'fixed'; toolbarBox.style.top = topOffset + "px"; ((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px'); } } } function unsetFloating() { flag = true; if (placeHolder.parentNode) { placeHolder.parentNode.removeChild(placeHolder); } toolbarBox.style.cssText = bakCssText; } function updateFloating() { var rect3 = getPosition(me.container); if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > 0) { setFloating(); } else { unsetFloating(); } } var defer_updateFloating = utils.defer(function () { updateFloating(); }, browser.ie ? 200 : 100, true); me.addListener('destroy', function () { domUtils.un(window, ['scroll', 'resize'], updateFloating); me.removeListener('keydown', defer_updateFloating); }); me.addListener('ready', function () { if (checkHasUI(me)) { getPosition = uiUtils.getClientRect; toolbarBox = me.ui.getDom('toolbarbox'); orgTop = getPosition(toolbarBox).top; bakCssText = toolbarBox.style.cssText; placeHolder.style.height = toolbarBox.offsetHeight + 'px'; if (LteIE6) { fixIE6FixedPos(); } domUtils.on(window, ['scroll', 'resize'], updateFloating); me.addListener('keydown', defer_updateFloating); me.addListener('beforefullscreenchange', function (t, enabled) { if (enabled) { unsetFloating(); } }); me.addListener('fullscreenchanged', function (t, enabled) { if (!enabled) { updateFloating(); } }); me.addListener('sourcemodechanged', function (t, enabled) { setTimeout(function () { updateFloating(); }, 0); }); me.addListener("clearDoc", function () { setTimeout(function () { updateFloating(); }, 0); }) } }); }; ///import core ///import plugins/inserthtml.js ///commands 插入代码 ///commandsName HighlightCode ///commandsTitle 插入代码 ///commandsDialog dialogs\highlightcode UE.plugins['highlightcode'] = function () { var me = this; if (!/highlightcode/i.test(me.options.toolbars.join(''))) { return; } me.commands['highlightcode'] = { execCommand: function (cmdName, code, syntax) { var range = this.selection.getRange(), start = domUtils.findParentByTagName(range.startContainer, 'table', true), end = domUtils.findParentByTagName(range.endContainer, 'table', true); if (start && end && start === end && domUtils.hasClass(start, 'syntaxhighlighter')) { if (start.nextSibling) { range.setStart(start.nextSibling, 0) } else { if (start.previousSibling) { range.setStartAtLast(start.previousSibling) } else { var p = me.document.createElement('p'); domUtils.fillNode(me.document, p); start.parentNode.insertBefore(p, start); range.setStart(p, 0) } } range.setCursor(false, true); domUtils.remove(start); } if (code && syntax) { me.execCommand('inserthtml', '
' + utils.unhtml(code) + '
', true); var pre = me.document.getElementById('highlightcode_id'); if (pre) { domUtils.removeAttributes(pre, 'id'); me.window.SyntaxHighlighter.highlight(pre); } } }, queryCommandState: function () { return queryHighlight.call(this); } }; function queryHighlight() { try { var range = this.selection.getRange(), start, end; range.adjustmentBoundary(); start = domUtils.findParent(range.startContainer, function (node) { return node.nodeType == 1 && node.tagName == 'TABLE' && domUtils.hasClass(node, 'syntaxhighlighter'); }, true); end = domUtils.findParent(range.endContainer, function (node) { return node.nodeType == 1 && node.tagName == 'TABLE' && domUtils.hasClass(node, 'syntaxhighlighter'); }, true); return start && end && start == end ? 1 : 0; } catch (e) { return 0; } } //不需要判断highlight的command列表 me.notNeedHighlightQuery = { help: 1, undo: 1, redo: 1, source: 1, print: 1, searchreplace: 1, fullscreen: 1, preview: 1, insertparagraph: 1, elementpath: 1, highlightcode: 1 }; //将queyCommamndState重置 var orgQuery = me.queryCommandState; me.queryCommandState = function (cmd) { if (!me.notNeedHighlightQuery[cmd.toLowerCase()] && queryHighlight.call(this) == 1) { return -1; } return orgQuery.apply(this, arguments) }; me.addListener('beforeselectionchange afterselectionchange', function (type) { me.highlight = /^b/.test(type) ? me.queryCommandState('highlightcode') : 0; }); me.addListener("ready", function () { //避免重复加载高亮文件 if (typeof me.XRegExp == "undefined") { utils.loadFile(me.document, { id: "syntaxhighlighter_js", src: me.options.highlightJsUrl || me.options.UEDITOR_HOME_URL + "third-party/SyntaxHighlighter/shCore.js", tag: "script", type: "text/javascript", defer: "defer" }, function () { changePre.call(me); }); } if (!me.document.getElementById("syntaxhighlighter_css")) { utils.loadFile(me.document, { id: "syntaxhighlighter_css", tag: "link", rel: "stylesheet", type: "text/css", href: me.options.highlightCssUrl || me.options.UEDITOR_HOME_URL + "third-party/SyntaxHighlighter/shCoreDefault.css" }); } }); me.addListener("beforegetcontent beforegetscene", function () { utils.each(domUtils.getElementsByTagName(me.body, 'table', 'syntaxhighlighter'), function (di) { var str = [], parentCode = ''; utils.each(di.getElementsByTagName('code'), function (ci) { if (parentCode !== ci.parentNode) { parentCode = ci.parentNode; //去掉左右空格,针对ie的不能回退的问题 str.push(utils.trim(parentCode[browser.ie ? 'innerText' : 'textContent'])) } }); var pre = domUtils.createElement(me.document, 'pre', { 'class': 'brush: ' + di.className.replace(/\s+/g, ' ').split(' ')[1] + ';toolbar:false;' }); pre.appendChild(me.document.createTextNode(str.join('\n'))); di.parentNode.replaceChild(pre, di); }); }); me.addListener("aftergetcontent aftersetcontent aftergetscene", changePre); //避免table插件对于代码高亮的影响 me.addListener('excludetable excludeNodeinautotype', function (cmd, target) { if (target && domUtils.findParent(target, function (node) { return domUtils.hasClass(node, 'syntaxhighlighter'); }, true)) { return true; } }); function changePre() { var me = this; if (!me.window || !me.window.SyntaxHighlighter)return; utils.each(domUtils.getElementsByTagName(me.document, "pre"), function (pi) { if (domUtils.hasClass(pi, 'brush')) { me.window.SyntaxHighlighter.highlight(pi); } }); } me.addListener('getAllHtml', function (type, headHtml) { var coreHtml = ''; for (var i = 0, ci, divs = domUtils.getElementsByTagName(me.document, 'table'); ci = divs[i++];) { if (domUtils.hasClass(ci, 'syntaxhighlighter')) { coreHtml = '' break; } } if (!coreHtml) { var tmpNode; if (tmpNode = me.document.getElementById('syntaxhighlighter_css')) { domUtils.remove(tmpNode) } if (tmpNode = me.document.getElementById('syntaxhighlighter_js')) { domUtils.remove(tmpNode) } } coreHtml && headHtml.push(coreHtml) }); }; ///import core ///commands 定制过滤规则 ///commandsName Serialize ///commandsTitle 定制过滤规则 UE.plugins['serialize'] = function () { var ie = browser.ie, version = browser.version; function ptToPx(value) { return /pt/.test(value) ? value.replace(/([\d.]+)pt/g, function (str) { return Math.round(parseFloat(str) * 96 / 72) + "px"; }) : value; } var me = this, autoClearEmptyNode = me.options.autoClearEmptyNode, EMPTY_TAG = dtd.$empty, parseHTML = function () { //干掉 后便变得空格,保留 这样的空格 var RE_PART = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g, RE_ATTR = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g, EMPTY_ATTR = {checked: 1, compact: 1, declare: 1, defer: 1, disabled: 1, ismap: 1, multiple: 1, nohref: 1, noresize: 1, noshade: 1, nowrap: 1, readonly: 1, selected: 1}, CDATA_TAG = {script: 1, style: 1}, NEED_PARENT_TAG = { "li": { "$": 'ul', "ul": 1, "ol": 1 }, "dd": { "$": "dl", "dl": 1 }, "dt": { "$": "dl", "dl": 1 }, "option": { "$": "select", "select": 1 }, "td": { "$": "tr", "tr": 1 }, "th": { "$": "tr", "tr": 1 }, "tr": { "$": "tbody", "tbody": 1, "thead": 1, "tfoot": 1, "table": 1 }, "tbody": { "$": "table", 'table': 1, "colgroup": 1 }, "thead": { "$": "table", "table": 1 }, "tfoot": { "$": "table", "table": 1 }, "col": { "$": "colgroup", "colgroup": 1 } }; var NEED_CHILD_TAG = { "table": "td", "tbody": "td", "thead": "td", "tfoot": "td", //"tr": "td", "colgroup": "col", "ul": "li", "ol": "li", "dl": "dd", "select": "option" }; function parse(html, callbacks) { var match, nextIndex = 0, tagName, cdata; RE_PART.exec(""); while ((match = RE_PART.exec(html))) { var tagIndex = match.index; if (tagIndex > nextIndex) { var text = html.slice(nextIndex, tagIndex); if (cdata) { cdata.push(text); } else { callbacks.onText(text); } } nextIndex = RE_PART.lastIndex; if ((tagName = match[1])) { tagName = tagName.toLowerCase(); if (cdata && tagName == cdata._tag_name) { callbacks.onCDATA(cdata.join('')); cdata = null; } if (!cdata) { callbacks.onTagClose(tagName); continue; } } if (cdata) { cdata.push(match[0]); continue; } if ((tagName = match[3])) { if (/="/.test(tagName)) { continue; } tagName = tagName.toLowerCase(); var attrPart = match[4], attrMatch, attrMap = {}, selfClosing = attrPart && attrPart.slice(-1) == '/'; if (attrPart) { RE_ATTR.exec(""); while ((attrMatch = RE_ATTR.exec(attrPart))) { var attrName = attrMatch[1].toLowerCase(), attrValue = attrMatch[2] || attrMatch[3] || attrMatch[4] || ''; if (!attrValue && EMPTY_ATTR[attrName]) { attrValue = attrName; } if (attrName == 'style') { if (ie && version <= 6) { attrValue = attrValue.replace(/(?!;)\s*([\w-]+):/g, function (m, p1) { return p1.toLowerCase() + ':'; }); } } //没有值的属性不添加 if (attrValue) { attrMap[attrName] = attrValue.replace(/:\s*/g, ':') } } } callbacks.onTagOpen(tagName, attrMap, selfClosing); if (!cdata && CDATA_TAG[tagName]) { cdata = []; cdata._tag_name = tagName; } continue; } if ((tagName = match[2])) { callbacks.onComment(tagName); } } if (html.length > nextIndex) { callbacks.onText(html.slice(nextIndex, html.length)); } } return function (html, forceDtd) { var fragment = { type: 'fragment', parent: null, children: [] }; var currentNode = fragment; function addChild(node) { node.parent = currentNode; currentNode.children.push(node); } function addElement(element, open) { var node = element; // 遇到结构化标签的时候 if (NEED_PARENT_TAG[node.tag]) { // 考虑这种情况的时候, 结束之前的标签 // e.g.
`4566 while (NEED_PARENT_TAG[currentNode.tag] && NEED_PARENT_TAG[currentNode.tag][node.tag]) { currentNode = currentNode.parent; } // 如果前一个标签和这个标签是同一级, 结束之前的标签 // e.g.
  • 123
  • if (currentNode.tag == node.tag) { currentNode = currentNode.parent; } // 向上补齐父标签 while (NEED_PARENT_TAG[node.tag]) { if (NEED_PARENT_TAG[node.tag][currentNode.tag]) break; node = node.parent = { type: 'element', tag: NEED_PARENT_TAG[node.tag]['$'], attributes: {}, children: [node] }; } } if (forceDtd) { // 如果遇到这个标签不能放在前一个标签内部,则结束前一个标签,span单独处理 while (dtd[node.tag] && !(currentNode.tag == 'span' ? utils.extend(dtd['strong'], {'a': 1, 'A': 1}) : (dtd[currentNode.tag] || dtd['div']))[node.tag]) { if (tagEnd(currentNode)) continue; if (!currentNode.parent) break; currentNode = currentNode.parent; } } node.parent = currentNode; currentNode.children.push(node); if (open) { currentNode = element; } if (element.attributes.style) { element.attributes.style = element.attributes.style.toLowerCase(); } return element; } // 结束一个标签的时候,需要判断一下它是否缺少子标签 // e.g.
12312`
function tagEnd(node) { var needTag; if (!node.children.length && (needTag = NEED_CHILD_TAG[node.tag])) { addElement({ type: 'element', tag: needTag, attributes: {}, children: [] }, true); return true; } return false; } parse(html, { onText: function (text) { while (!(dtd[currentNode.tag] || dtd['div'])['#']) { //节点之间的空白不能当作节点处理 // if(/^[ \t\r\n]+$/.test( text )){ // return; // } if (tagEnd(currentNode)) continue; currentNode = currentNode.parent; } //if(/^[ \t\n\r]*/.test(text)) addChild({ type: 'text', data: text }); }, onComment: function (text) { addChild({ type: 'comment', data: text }); }, onCDATA: function (text) { while (!(dtd[currentNode.tag] || dtd['div'])['#']) { if (tagEnd(currentNode)) continue; currentNode = currentNode.parent; } addChild({ type: 'cdata', data: text }); }, onTagOpen: function (tag, attrs, closed) { closed = closed || EMPTY_TAG[tag]; addElement({ type: 'element', tag: tag, attributes: attrs, closed: closed, children: [] }, !closed); }, onTagClose: function (tag) { var node = currentNode; // 向上找匹配的标签, 这里不考虑dtd的情况是因为tagOpen的时候已经处理过了, 这里不会遇到 while (node && tag != node.tag) { node = node.parent; } if (node) { // 关闭中间的标签 for (var tnode = currentNode; tnode !== node.parent; tnode = tnode.parent) { tagEnd(tnode); } //去掉空白的inline节点 //分页,锚点保留 //|| dtd.$removeEmptyBlock[node.tag]) // if ( !node.children.length && dtd.$removeEmpty[node.tag] && !node.attributes.anchorname && node.attributes['class'] != 'pagebreak' && node.tag != 'a') { // // node.parent.children.pop(); // } currentNode = node.parent; } else { // 如果没有找到开始标签, 则创建新标签 // eg. =>
//针对视屏网站embed会给结束符,这里特殊处理一下 if (!(dtd.$removeEmpty[tag] || dtd.$removeEmptyBlock[tag] || tag == 'embed')) { node = { type: 'element', tag: tag, attributes: {}, children: [] }; addElement(node, true); tagEnd(node); currentNode = node.parent; } } } }); // 处理这种情况, 只有开始标签没有结束标签的情况, 需要关闭开始标签 // eg. while (currentNode !== fragment) { tagEnd(currentNode); currentNode = currentNode.parent; } return fragment; }; }(); var unhtml1 = function () { var map = { '<': '<', '>': '>', '"': '"', "'": ''' }; function rep(m) { return map[m]; } return function (str) { str = str + ''; return str ? str.replace(/[<>"']/g, rep) : ''; }; }(); var toHTML = function () { function printChildren(node, pasteplain) { var children = node.children; var buff = []; for (var i = 0, ci; ci = children[i]; i++) { buff.push(toHTML(ci, pasteplain)); } return buff.join(''); } function printAttrs(attrs) { var buff = []; for (var k in attrs) { var value = attrs[k]; if (k == 'style') { //pt==>px value = ptToPx(value); //color rgb ==> hex if (/rgba?\s*\([^)]*\)/.test(value)) { value = value.replace(/rgba?\s*\(([^)]*)\)/g, function (str) { return utils.fixColor('color', str); }) } //过滤掉所有的white-space,在纯文本编辑器里粘贴过来的内容,到chrome中会带有span和white-space属性,导致出现不能折行的情况 //所以在这里去掉这个属性 attrs[k] = utils.optCss(value.replace(/windowtext/g, '#000')) .replace(/white-space[^;]+;/g, ''); if (!attrs[k]) { continue; } } buff.push(k + '="' + unhtml1(attrs[k]) + '"'); } return buff.join(' ') } function printData(node, notTrans) { //trace:1399 输入html代码时空格转换成为  //node.data.replace(/ /g,' ') 针对pre中的空格和出现的 把他们在得到的html代码中都转换成为空格,为了在源码模式下显示为空格而不是  return notTrans ? node.data.replace(/ /g, ' ') : unhtml1(node.data).replace(/ /g, ' '); } //纯文本模式下标签转换 var transHtml = { 'li': 'p', 'h1': 'p', 'h2': 'p', 'h3': 'p', 'h4': 'p', 'h5': 'p', 'h6': 'p', 'tr': 'p', 'br': 'br', 'div': 'p', 'p': 'p'//trace:1398 碰到p标签自己要加上p,否则transHtml[tag]是undefined }; var clearTagName = { 'table': 1, 'tbody': 1, 'ol': 1, 'ul': 1, 'dt': 1 } function printElement(node, pasteplain) { if (node.type == 'element' && !node.children.length && (dtd.$removeEmpty[node.tag]) && node.tag != 'a' && utils.isEmptyObject(node.attributes) && autoClearEmptyNode) {// 锚点保留 return html; } var tag = node.tag; if (pasteplain && tag == 'td') { if (!html) html = ''; html += printChildren(node, pasteplain) + '   '; } else { var attrs = printAttrs(node.attributes); var html = pasteplain && clearTagName[tag] ? '' : '<' + (pasteplain && transHtml[tag] !== undefined ? transHtml[tag] : tag) + (attrs ? ' ' + attrs : '') + (EMPTY_TAG[tag] ? ' />' : '>'); if (!EMPTY_TAG[tag]) { //trace:1627 ,2070 //p标签为空,将不占位这里占位符不起作用,用 或者br if (tag == 'p' && !node.children.length) { html += browser.ie ? ' ' : '
'; } html += printChildren(node, pasteplain); html += (pasteplain && clearTagName[tag] ? '' : ''); } } return html; } return function (node, pasteplain) { if (node.type == 'fragment') { return printChildren(node, pasteplain); } else if (node.type == 'element') { return printElement(node, pasteplain); } else if (node.type == 'text' || node.type == 'cdata') { return printData(node, dtd.$notTransContent[node.parent.tag]); } else if (node.type == 'comment') { return ''; } return ''; }; }(); var NODE_NAME_MAP = { 'text': '#text', 'comment': '#comment', 'cdata': '#cdata-section', 'fragment': '#document-fragment' }; //写入编辑器时,调用,进行转换操作 function transNode(node, word_img_flag) { var sizeMap = [0, 10, 12, 16, 18, 24, 32, 48], attr, indexOf = utils.indexOf; switch (node.tag) { case 'script': node.tag = 'div'; node.attributes._ue_org_tagName = 'script'; node.attributes._ue_div_script = 1; node.attributes._ue_script_data = node.children[0] ? encodeURIComponent(node.children[0].data) : ''; node.attributes._ue_custom_node_ = 1; node.children = []; break; case 'style': node.tag = 'div'; node.attributes._ue_div_style = 1; node.attributes._ue_org_tagName = 'style'; node.attributes._ue_style_data = node.children[0] ? encodeURIComponent(node.children[0].data) : ''; node.attributes._ue_custom_node_ = 1; node.children = []; break; case 'img': //todo base64暂时去掉,后边做远程图片上传后,干掉这个 if (node.attributes.src && /^data:/.test(node.attributes.src)) { return { type: 'fragment', children: [] } } if (node.attributes.src && /^(?:file)/.test(node.attributes.src)) { if (!/(gif|bmp|png|jpg|jpeg)$/.test(node.attributes.src)) { return { type: 'fragment', children: [] } } node.attributes.word_img = node.attributes.src; node.attributes.src = me.options.UEDITOR_HOME_URL + 'themes/default/spacer.gif'; var flag = parseInt(node.attributes.width) < 128 || parseInt(node.attributes.height) < 43; node.attributes.style = "background:url(" + (flag ? me.options.themePath + me.options.theme + "/word.gif" : me.options.langPath + me.options.lang + "/localimage.png") + ") no-repeat center center;border:1px solid #ddd"; //node.attributes.style = 'width:395px;height:173px;'; word_img_flag && (word_img_flag.flag = 1); } if (browser.ie && browser.version < 7) node.attributes.orgSrc = node.attributes.src; node.attributes.data_ue_src = node.attributes.data_ue_src || node.attributes.src; break; case 'li': var child = node.children[0]; if (!child || child.type != 'element' || child.tag != 'p' && dtd.p[child.tag]) { var tmpPNode = { type: 'element', tag: 'p', attributes: {}, parent: node }; tmpPNode.children = child ? node.children : [ browser.ie ? { type: 'text', data: domUtils.fillChar, parent: tmpPNode } : { type: 'element', tag: 'br', attributes: {}, closed: true, children: [], parent: tmpPNode } ]; node.children = [tmpPNode]; } break; case 'table': case 'td': optStyle(node); break; case 'a'://锚点,a==>img if (node.attributes['anchorname']) { node.tag = 'img'; node.attributes = { 'class': 'anchorclass', 'anchorname': node.attributes['name'] }; node.closed = 1; } node.attributes.href && (node.attributes.data_ue_src = node.attributes.href); break; case 'b': node.tag = node.name = 'strong'; break; case 'i': node.tag = node.name = 'em'; break; case 'u': node.tag = node.name = 'span'; node.attributes.style = (node.attributes.style || '') + ';text-decoration:underline;'; break; case 's': case 'del': node.tag = node.name = 'span'; node.attributes.style = (node.attributes.style || '') + ';text-decoration:line-through;'; if (node.children.length == 1) { child = node.children[0]; if (child.tag == node.tag) { node.attributes.style += ";" + child.attributes.style; node.children = child.children; } } break; case 'span': var style = node.attributes.style; if (style) { if (!node.attributes.style || browser.webkit && style == "white-space:nowrap;") { delete node.attributes.style; } } //针对ff3.6span的样式不能正确继承的修复 if (browser.gecko && browser.version <= 10902 && node.parent) { var parent = node.parent; if (parent.tag == 'span' && parent.attributes && parent.attributes.style) { node.attributes.style = parent.attributes.style + ';' + node.attributes.style; } } if (utils.isEmptyObject(node.attributes) && autoClearEmptyNode) { node.type = 'fragment' } break; case 'font': node.tag = node.name = 'span'; attr = node.attributes; node.attributes = { 'style': (attr.size ? 'font-size:' + (sizeMap[attr.size] || 12) + 'px' : '') + ';' + (attr.color ? 'color:' + attr.color : '') + ';' + (attr.face ? 'font-family:' + attr.face : '') + ';' + (attr.style || '') }; while (node.parent.tag == node.tag && node.parent.children.length == 1) { node.attributes.style && (node.parent.attributes.style ? (node.parent.attributes.style += ";" + node.attributes.style) : (node.parent.attributes.style = node.attributes.style)); node.parent.children = node.children; node = node.parent; } break; case 'p': if (node.attributes.align) { node.attributes.style = (node.attributes.style || '') + ';text-align:' + node.attributes.align + ';'; delete node.attributes.align; } } return node; } function optStyle(node) { if (ie && node.attributes.style) { var style = node.attributes.style; node.attributes.style = style.replace(/;\s*/g, ';'); node.attributes.style = node.attributes.style.replace(/^\s*|\s*$/, '') } } //getContent调用转换 function transOutNode(node) { switch (node.tag) { case 'div' : if (node.attributes._ue_div_script) { node.tag = 'script'; node.children = [ {type: 'cdata', data: node.attributes._ue_script_data ? decodeURIComponent(node.attributes._ue_script_data) : '', parent: node} ]; delete node.attributes._ue_div_script; delete node.attributes._ue_script_data; delete node.attributes._ue_custom_node_; delete node.attributes._ue_org_tagName; } if (node.attributes._ue_div_style) { node.tag = 'style'; node.children = [ {type: 'cdata', data: node.attributes._ue_style_data ? decodeURIComponent(node.attributes._ue_style_data) : '', parent: node} ]; delete node.attributes._ue_div_style; delete node.attributes._ue_style_data; delete node.attributes._ue_custom_node_; delete node.attributes._ue_org_tagName; } break; case 'table': !node.attributes.style && delete node.attributes.style; if (ie && node.attributes.style) { optStyle(node); } break; case 'td': case 'th': if (/display\s*:\s*none/i.test(node.attributes.style)) { return { type: 'fragment', children: [] }; } if (ie && !node.children.length) { var txtNode = { type: 'text', data: domUtils.fillChar, parent: node }; node.children[0] = txtNode; } if (ie && node.attributes.style) { optStyle(node); } break; case 'img'://锚点,img==>a if (node.attributes.anchorname) { node.tag = 'a'; node.attributes = { name: node.attributes.anchorname, anchorname: 1 }; node.closed = null; } else { if (node.attributes.data_ue_src) { node.attributes.src = node.attributes.data_ue_src; delete node.attributes.data_ue_src; } } break; case 'a': if (node.attributes.data_ue_src) { node.attributes.href = node.attributes.data_ue_src; delete node.attributes.data_ue_src; } } return node; } function childrenAccept(node, visit, ctx) { if (!node.children || !node.children.length) { return node; } var children = node.children; for (var i = 0; i < children.length; i++) { var newNode = visit(children[i], ctx); if (newNode.type == 'fragment') { var args = [i, 1]; args.push.apply(args, newNode.children); children.splice.apply(children, args); //节点为空的就干掉,不然后边的补全操作会添加多余的节点 if (!children.length) { node = { type: 'fragment', children: [] } } i--; } else { children[i] = newNode; } } return node; } function Serialize(rules) { this.rules = rules; } Serialize.prototype = { // NOTE: selector目前只支持tagName rules: null, // NOTE: node必须是fragment filter: function (node, rules, modify) { rules = rules || this.rules; var whiteList = rules && rules.whiteList; var blackList = rules && rules.blackList; function visitNode(node, parent) { node.name = node.type == 'element' ? node.tag : NODE_NAME_MAP[node.type]; if (parent == null) { return childrenAccept(node, visitNode, node); } if (blackList && (blackList[node.name] || (node.attributes && node.attributes._ue_org_tagName && blackList[node.attributes._ue_org_tagName]))) { modify && (modify.flag = 1); return { type: 'fragment', children: [] }; } if (whiteList) { if (node.type == 'element') { if (parent.type == 'fragment' ? whiteList[node.name] : whiteList[node.name] && whiteList[parent.name][node.name]) { var props; if ((props = whiteList[node.name].$)) { var oldAttrs = node.attributes; var newAttrs = {}; for (var k in props) { if (oldAttrs[k]) { newAttrs[k] = oldAttrs[k]; } } node.attributes = newAttrs; } } else { modify && (modify.flag = 1); node.type = 'fragment'; // NOTE: 这里算是一个hack node.name = parent.name; } } else { // NOTE: 文本默认允许 } } if (blackList || whiteList) { childrenAccept(node, visitNode, node); } return node; } return visitNode(node, null); }, transformInput: function (node, word_img_flag) { function visitNode(node) { node = transNode(node, word_img_flag); node = childrenAccept(node, visitNode, node); if (me.options.pageBreakTag && node.type == 'text' && node.data.replace(/\s/g, '') == me.options.pageBreakTag) { node.type = 'element'; node.name = node.tag = 'hr'; delete node.data; node.attributes = { 'class': 'pagebreak', noshade: "noshade", size: "5", 'unselectable': 'on', 'style': 'moz-user-select:none;-khtml-user-select: none;' }; node.children = []; } //去掉多余的空格和换行 if (node.type == 'text' && !dtd.$notTransContent[node.parent.tag]) { node.data = node.data.replace(/[\r\t\n]*/g, '')//.replace(/[ ]*$/g,'') } return node; } return visitNode(node); }, transformOutput: function (node) { function visitNode(node) { if (node.tag == 'hr' && node.attributes['class'] == 'pagebreak') { delete node.tag; node.type = 'text'; node.data = me.options.pageBreakTag; delete node.children; } node = transOutNode(node); node = childrenAccept(node, visitNode, node); return node; } return visitNode(node); }, toHTML: toHTML, parseHTML: parseHTML, word: UE.filterWord }; me.serialize = new Serialize(me.options.serialize || {}); UE.serialize = new Serialize({}); }; ///import core ///import plugins/inserthtml.js ///commands 视频 ///commandsName InsertVideo ///commandsTitle 插入视频 ///commandsDialog dialogs\video UE.plugins['video'] = function () { var me = this, div; /** * 创建插入视频字符窜 * @param url 视频地址 * @param width 视频宽度 * @param height 视频高度 * @param align 视频对齐 * @param toEmbed 是否以flash代替显示 * @param addParagraph 是否需要添加P 标签 */ function creatInsertStr(url, width, height, align, toEmbed, addParagraph) { return !toEmbed ? (addParagraph ? ('

') : '') + '' + (addParagraph ? '

' : '') : ''; } function switchImgAndEmbed(img2embed) { var tmpdiv, nodes = domUtils.getElementsByTagName(me.document, !img2embed ? "embed" : "img"); for (var i = 0, node; node = nodes[i++];) { if (node.className != "edui-faked-video") { continue; } tmpdiv = me.document.createElement("div"); //先看float在看align,浮动有的是时候是在float上定义的 var align = domUtils.getComputedStyle(node, 'float'); align = align == 'none' ? (node.getAttribute('align') || '') : align; tmpdiv.innerHTML = creatInsertStr(img2embed ? node.getAttribute("_url") : node.getAttribute("src"), node.width, node.height, align, img2embed); node.parentNode.replaceChild(tmpdiv.firstChild, node); } } me.addListener("beforegetcontent", function () { switchImgAndEmbed(true); }); me.addListener('aftersetcontent', function () { switchImgAndEmbed(false); }); me.addListener('aftergetcontent', function (cmdName) { if (cmdName == 'aftergetcontent' && me.queryCommandState('source')) { return; } switchImgAndEmbed(false); }); me.commands["insertvideo"] = { execCommand: function (cmd, videoObjs) { videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs]; var html = []; for (var i = 0, vi, len = videoObjs.length; i < len; i++) { vi = videoObjs[i]; html.push(creatInsertStr(vi.url, vi.width || 420, vi.height || 280, vi.align || "none", false, true)); } me.execCommand("inserthtml", html.join("")); }, queryCommandState: function () { var img = me.selection.getRange().getClosedNode(), flag = img && (img.className == "edui-faked-video"); return flag ? 1 : 0; } }; }; /** * 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, debug = true; function showError(e) { if (debug) throw e; } //处理拖动及框选相关方法 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/cursor_", 'tableDragable': false }); 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, "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{ background:white; padding: 5px 10px;border: 1px solid #DDD;}' + 'caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}' + 'th{border-top:2px solid #BBB;background:#F7F7F7;}' + '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) { me.fireEvent('saveScene'); 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)) { me.execCommand('insertparagraphbeforetable'); domUtils.preventDefault(evt); } } } } if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == '67') { tableCopyList = null; table = getUETableBySelected(me); if (table) { var tds = table.selectedTds; isFullCol = table.isFullCol(); isFullRow = table.isFullRow(); tableCopyList = [ [cloneCell(tds[0])] ]; for (var i = 1, ci; ci = tds[i]; i++) { if (ci.parentNode !== tds[i - 1].parentNode) { tableCopyList.push([cloneCell(ci)]) } else { tableCopyList[tableCopyList.length - 1].push(cloneCell(ci)) } } } } }); 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; html.html = div[browser.ie ? '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 = cloneCell(cj); 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 = ''; } 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 () { toggleDragableState(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 UETable(table); 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.onmousemove = function () { me.options.tableDragable && toggleDragButton(true, this, me); }; table.onmouseout = function () { toggleDragableState(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(); } } } }; table.ondblclick = function (evt) { evt = me.window.event || evt; var target = getParentTdOrTh(evt.target || evt.srcElement); if (target) { var h; if (h = getRelation(target, mouseCoords(evt))) { 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) } } } h == 'h' && me.execCommand('adaptbytext'); } } } }); switchBoderColor(true); }); //仅IE8以上支持 if (!browser.ie || (browser.ie && browser.version > 7)) { domUtils.on(me.document, "mousemove", mouseMoveEvent); } domUtils.on(me.document, "mouseout", function (evt) { var target = evt.target || evt.srcElement; if (target.tagName == "TABLE") { toggleDragableState(me, false, "", null); } }); me.addListener("mousedown", mouseDownEvent); me.addListener("mouseup", mouseUpEvent); var currentRowIndex = 0; me.addListener("mousedown", function () { currentRowIndex = 0; }); me.addListener('tabkeydown', function () { var range = this.selection.getRange(), common = range.getCommonAncestor(true, true), table = domUtils.findParentByTagName(common, 'table'); if (table) { if (domUtils.findParentByTagName(common, 'caption', true)) { var cell = domUtils.getElementsByTagName(table, 'th td'); if (cell && cell.length) { range.setStart(cell[0], 0).setCursor(false, true) } } else { var cell = domUtils.findParentByTagName(common, ['td', 'th'], true), ua = getUETable(cell); currentRowIndex = cell.rowSpan > 1 ? currentRowIndex : ua.getCellInfo(cell).rowIndex; var nextCell = ua.getTabNextCell(cell, currentRowIndex); if (nextCell) { if (isEmptyBlock(nextCell)) { range.setStart(nextCell, 0).setCursor(false, true) } else { range.selectNodeContents(nextCell).select() } } else { me.fireEvent('saveScene'); me.__hasEnterExecCommand = true; this.execCommand('insertrownext'); me.__hasEnterExecCommand = false; range = this.selection.getRange(); range.setStart(table.rows[table.rows.length - 1].cells[0], 0).setCursor(); me.fireEvent('saveScene'); } } return true; } }); browser.ie && me.addListener('selectionchange', function () { toggleDragableState(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 () { switchBoderColor(false); browser.ie && utils.each(me.document.getElementsByTagName('caption'), function (ci) { if (domUtils.isEmptyNode(ci)) { ci.innerHTML = ' ' } }); }); me.addListener("aftergetcontent", function () { switchBoderColor(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) { var me = this; 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.selectNodeContents(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) { try { //普通状态下鼠标移动 var target = getParentTdOrTh(evt.target || evt.srcElement), pos; //修改单元格大小时的鼠标移动 if (onDrag && dragTd) { me.document.body.style.webkitUserSelect = 'none'; me.selection.getNative()[browser.ie ? 'empty' : 'removeAllRanges'](); pos = mouseCoords(evt); toggleDragableState(me, true, "", 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)) { //toggleCursor(pos,true,"_h"); if (me.fireEvent("excludetable", table) === true) return; me.body.style.cursor = "url(" + me.options.cursorpath + "h.png),pointer"; } else if (inTableSide(table, target, evt)) { //toggleCursor(pos,true,"_v"); if (me.fireEvent("excludetable", table) === true) return; me.body.style.cursor = "url(" + me.options.cursorpath + "v.png),pointer"; } else { //toggleCursor(pos,false,""); me.body.style.cursor = "text"; if (/\d/.test(state)) { state = state.replace(/\d/, ''); target = getUETable(target).getPreviewCell(target, state == "v"); } //位于第一行的顶部或者第一列的左边时不可拖动 toggleDragableState(me, target ? !!state : false, target ? state : '', pos, target); } // toggleDragButton(inTable(pos,table),table); } else { toggleDragButton(false, table, me); } } catch (e) { showError(e); } } var dragButtomTimer; function toggleDragButton(show, table, editor) { if (!show) { if (dragOver)return; dragButtomTimer = 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)); return mouseX < left ? left : mouseX > right ? right : mouseX; } } /** * 获取拖动时允许的Y轴坐标 * @param dragTd * @param evt */ function getPermissionY(dragTd, evt) { try { var top = domUtils.getXY(dragTd).y, mousePosY = mouseCoords(evt).y; return mousePosY < top ? top : mousePosY; } catch (e) { showError(e); } } /** * 移动状态切换 * @param dragable * @param dir */ function toggleDragableState(editor, dragable, 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 = dragable; } catch (e) { showError(e); } } /** * 获取鼠标与当前单元格的相对位置 * @param ele * @param mousePos */ function getRelation(ele, mousePos) { var elePos = domUtils.getXY(ele); if (elePos.x + ele.offsetWidth - mousePos.x < 4) { return "h"; } if (mousePos.x - elePos.x < 4) { return 'h1' } if (elePos.y + ele.offsetHeight - mousePos.y < 4) { return "v"; } if (mousePos.y - elePos.y < 4) { return 'v1' } return ''; } function mouseDownEvent(type, evt) { //右键菜单单独处理 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, "td")); removeSelectedClass(domUtils.getElementsByTagName(me.body, "th")); ut.clearSelected() } else { td = ut.selectedTds[0]; setTimeout(function () { me.selection.getRange().setStart(td, 0).setCursor(false, true); }, 0); } } return; } if (evt.shiftKey) { return; } removeSelectedClass(domUtils.getElementsByTagName(me.body, "td")); removeSelectedClass(domUtils.getElementsByTagName(me.body, "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 { if (browser.ie && browser.version < 8) 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); showDragLineAt(state, startTd); mousedown = true; //拖动开始 onDrag = state; dragTd = startTd; } } function removeSelectedClass(cells) { utils.each(cells, function (cell) { domUtils.removeClasses(cell, "selectTdClass"); }) } function addSelectedClass(cells) { utils.each(cells, function (cell) { domUtils.addClass(cell, "selectTdClass"); }) } function getWidth(cell) { if (!cell)return 0; return parseInt(domUtils.getComputedStyle(cell, "width"), 10); } function changeColWidth(cell, changeValue) { if (Math.abs(changeValue) < 10) return; var ut = getUETable(cell); if (ut) { var table = ut.table, backTableWidth = getWidth(table), defaultValue = getDefaultValue(me, table), //这里不考虑一个都没有情况,如果一个都没有,可以认为该表格的结构可以精简 leftCells = ut.getSameEndPosCells(cell, "x"), backLeftWidth = getWidth(leftCells[0]) - defaultValue.tdPadding * 2 - defaultValue.tdBorder, rightCells = ut.getSameStartPosXCells(cell), backRightWidth = getWidth(rightCells[0]) - defaultValue.tdPadding * 2 - defaultValue.tdBorder; //整列被rowspan时存在 utils.each(leftCells, function (cell) { if (cell.style.width) cell.style.width = ""; if (changeValue < 0)cell.style.wordBreak = "break-all"; cell.setAttribute("width", backLeftWidth + changeValue); }); utils.each(rightCells, function (cell) { if (cell.style.width) cell.style.width = ""; if (changeValue > 0)cell.style.wordBreak = "break-all"; cell.setAttribute("width", backRightWidth - changeValue); }); //如果是在表格最右边拖动,则还需要调整表格宽度,否则在合并过的单元格中输入文字,表格会被撑开 if (!cell.nextSibling) { if (table.style.width) table.style.width = ""; table.setAttribute("width", backTableWidth + changeValue); } } } 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); } } } 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 mouseUpEvent(type, evt) { 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 ((!browser.ie || (browser.ie && browser.version > 7)) && onDrag && dragTd) { dragLine = me.document.getElementById('ue_tableDragLine'); var dragTdPos = domUtils.getXY(dragTd), dragLinePos = domUtils.getXY(dragLine); switch (onDrag) { case "h": changeColWidth(dragTd, dragLinePos.x - dragTdPos.x - dragTd.offsetWidth); break; case "v": changeRowHeight(dragTd, dragLinePos.y - dragTdPos.y - dragTd.offsetHeight); break; default: } onDrag = ""; dragTd = null; hideDragLine(me); 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) { 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.ie ? '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); } /** * 根据当前点击的td或者table获取索引对象 * @param tdOrTable */ function getUETable(tdOrTable) { var tag = tdOrTable.tagName.toLowerCase(); tdOrTable = (tag == "td" || tag == "th" || tag == 'caption') ? domUtils.findParentByTagName(tdOrTable, "table", true) : tdOrTable; if (!tdOrTable.ueTable) { tdOrTable.ueTable = new UETable(tdOrTable); } return tdOrTable.ueTable; } /** * 根据当前框选的td来获取ueTable对象 */ function getUETableBySelected(editor) { var table = getTableItemsByRange(editor).table; if (table && table.ueTable && table.ueTable.selectedTds.length) { return table.ueTable; } return null; } 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)" }); // domUtils.on(dragLine,['resizestart','dragstart','selectstart'],function(evt){ // domUtils.preventDefault(evt); // }); 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 - 2); 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 - 2 ); //必须加上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 flag */ function switchBoderColor(flag) { var tableArr = domUtils.getElementsByTagName(me.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,f55,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); } UE.commands['inserttable'] = { queryCommandState: function () { return getTableItemsByRange(this).table ? -1 : 0; }, execCommand: function (cmd, opt) { function createTable(opt, tableWidth, 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 ? domUtils.fillChar : '
') + '') } html.push('') } return '' + html.join('') + '
' } if (!opt) { opt = utils.extend({}, { numCols: this.options.defaultCols, numRows: this.options.defaultRows, tdvalign: this.options.tdvalign }) } var range = this.selection.getRange(), start = range.startContainer, firstParentBlock = domUtils.findParent(start, function (node) { return domUtils.isBlockElm(node); }, true); var me = this, defaultValue = getDefaultValue(me), tableWidth = getTableWidth(me, needIEHack, defaultValue) - (firstParentBlock ? parseInt(domUtils.getXY(firstParentBlock).x, 10) : 0), tdWidth = Math.floor(tableWidth / opt.numCols - defaultValue.tdPadding * 2 - defaultValue.tdBorder); //todo其他属性 !opt.tdvalign && (opt.tdvalign = me.options.tdvalign); me.execCommand("inserthtml", createTable(opt, tableWidth, 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) toggleDragableState(this, false, "", null); if (dragButton)domUtils.remove(dragButton); } } }; 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.getElementsByTagName('th').length == 0 ? 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.getElementsByTagName('th').length ? 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["mergeright"] = { queryCommandState: function (cmd) { var tableItems = getTableItemsByRange(this); if (!tableItems.cell) return -1; var ut = getUETable(tableItems.table); if (ut.selectedTds.length) return -1; var cellInfo = ut.getCellInfo(tableItems.cell), rightColIndex = cellInfo.colIndex + cellInfo.colSpan; if (rightColIndex >= ut.colsNum) return -1; var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex]; 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), cell = tableItems.cell; if (!cell || cell.tagName == "TH") return -1; var ut = getUETable(tableItems.table); if (ut.selectedTds.length)return -1; var cellInfo = ut.getCellInfo(tableItems.cell), downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan; // 如果处于最下边则不能f向右合并 if (downRowIndex >= ut.rowsNum) return -1; var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex]; // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并 return (downCellInfo.colIndex == cellInfo.colIndex && downCellInfo.colSpan == cellInfo.colSpan) && tableItems.cell.tagName !== 'TH' ? 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]; getUETableBySelected(this).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" && getUETable(tableItems.table).rowsNum < this.options.maxRowNum ? 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.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(); } }; //后插入行 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 cell = getTableItemsByRange(this).cell, ut = getUETable(cell), 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(); } }; UE.commands["deleterow"] = { queryCommandState: function () { var tableItems = getTableItemsByRange(this); if (!tableItems.cell) { return -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); } } } }; UE.commands["insertcol"] = { queryCommandState: function (cmd) { var tableItems = getTableItemsByRange(this), cell = tableItems.cell; return cell && (cell.tagName == "TD" || cell.tagName == 'TH') && 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); if (!tableItems.cell) return -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(); } }; function getDefaultValue(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 }; } } 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) { var tds = table.getElementsByTagName("td"); utils.each(tds, function (td) { td.removeAttribute("width"); }); if (cmd == 'adaptbywindow') { table.setAttribute('width', getTableWidth(this, needIEHack, getDefaultValue(this, table))); utils.each(tds, function (td) { td.setAttribute("width", td.offsetWidth + ""); }); } else { table.style.width = ""; table.removeAttribute("width"); var defaultValue = getDefaultValue(me, table); var width = table.offsetWidth, bodyWidth = me.body.offsetWidth; if (width > bodyWidth) { table.setAttribute('width', getTableWidth(me, needIEHack, defaultValue)); } } } } }; //平均分配各列 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); }); } } }; //表格对齐方式 UE.commands['tablealignment'] = { queryCommandState: function () { return getTableItemsByRange(this).table ? 0 : -1 }, execCommand: function (cmd, data) { var me = this, start = me.selection.getStart(), table = start && domUtils.findParentByTagName(start, ["table"], true); if (table) { var obj = {}; obj[data[0]] = data[1]; table.style[utils.cssStyleToDomStyle("float")] = ""; table.style.margin = ""; domUtils.setStyles(table, obj); } } }; //表格属性 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表格操作类 * @param table * @constructor */ function UETable(table) { this.table = table; this.indexTable = []; this.selectedTds = []; this.cellsRange = {}; this.update(table); } UETable.prototype = { getMaxRows: function () { var rows = this.table.rows, maxLen = 1; for (var i = 0, row; row = rows[i]; i++) { var currentMax = 1; for (var j = 0, cj; cj = row.cells[j++];) { currentMax = Math.max(cj.rowSpan || 1, currentMax); } maxLen = Math.max(currentMax + i, maxLen); } return maxLen; }, /** * 获取当前表格的最大列数 */ getMaxCols: function () { var rows = this.table.rows, maxLen = 0, cellRows = {}; for (var i = 0, row; row = rows[i]; i++) { var cellsNum = 0; for (var j = 0, cj; cj = row.cells[j++];) { cellsNum += (cj.colSpan || 1); if (cj.rowSpan && cj.rowSpan > 1) { for (var k = 1; k < cj.rowSpan; k++) { if (!cellRows['row_' + (i + k)]) { cellRows['row_' + (i + k)] = (cj.colSpan || 1); } else { cellRows['row_' + (i + k)]++ } } } } cellsNum += cellRows['row_' + i] || 0; maxLen = Math.max(cellsNum, maxLen); } return maxLen; }, getCellColIndex: function (cell) { }, /** * 获取当前cell旁边的单元格, * @param cell * @param right */ getHSideCell: function (cell, right) { try { var cellInfo = this.getCellInfo(cell), previewRowIndex, previewColIndex; var len = this.selectedTds.length, range = this.cellsRange; //首行或者首列没有前置单元格 if ((!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) || (right && (!len ? (cellInfo.colIndex == (this.colsNum - 1)) : (range.endColIndex == this.colsNum - 1)))) return null; previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex; previewColIndex = !right ? ( !len ? (cellInfo.colIndex < 1 ? 0 : (cellInfo.colIndex - 1)) : range.beginColIndex - 1) : ( !len ? cellInfo.colIndex + 1 : range.endColIndex + 1); return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this.indexTable[previewRowIndex][previewColIndex].cellIndex); } catch (e) { showError(e); } }, getTabNextCell: function (cell, preRowIndex) { var cellInfo = this.getCellInfo(cell), rowIndex = preRowIndex || cellInfo.rowIndex, colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1), nextCell; try { nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this.indexTable[rowIndex][colIndex].cellIndex); } catch (e) { try { rowIndex = rowIndex * 1 + 1; colIndex = 0; nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this.indexTable[rowIndex][colIndex].cellIndex); } catch (e) { } } return nextCell; }, /** * 获取视觉上的后置单元格 * @param cell * @param bottom */ getVSideCell: function (cell, bottom, ignoreRange) { try { var cellInfo = this.getCellInfo(cell), nextRowIndex, nextColIndex; var len = this.selectedTds.length && !ignoreRange, range = this.cellsRange; //末行或者末列没有后置单元格 if ((!bottom && (cellInfo.rowIndex == 0)) || (bottom && (!len ? (cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1) : (range.endRowIndex == this.rowsNum - 1)))) return null; nextRowIndex = !bottom ? ( !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1) : ( !len ? (cellInfo.rowIndex + cellInfo.rowSpan) : range.endRowIndex + 1); nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex; return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this.indexTable[nextRowIndex][nextColIndex].cellIndex); } catch (e) { showError(e); } }, /** * 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同 */ getSameEndPosCells: function (cell, xOrY) { try { var flag = (xOrY.toLowerCase() === "x"), end = domUtils.getXY(cell)[flag ? 'x' : 'y'] + cell["offset" + (flag ? 'Width' : 'Height')], rows = this.table.rows, cells = null, returns = []; for (var i = 0; i < this.rowsNum; i++) { cells = rows[i].cells; for (var j = 0, tmpCell; tmpCell = cells[j++];) { var tmpEnd = domUtils.getXY(tmpCell)[flag ? 'x' : 'y'] + tmpCell["offset" + (flag ? 'Width' : 'Height')]; //对应行的td已经被上面行rowSpan了 if (tmpEnd > end && flag) break; if (cell == tmpCell || end == tmpEnd) { //只获取单一的单元格 //todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能 if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) { returns.push(tmpCell); } if (flag) break; } } } return returns; } catch (e) { showError(e); } }, setCellContent: function (cell, content) { cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "
"); }, cloneCell: cloneCell, /** * 获取跟当前单元格的右边竖线为左边的所有未合并单元格 */ getSameStartPosXCells: function (cell) { try { var start = domUtils.getXY(cell).x + cell.offsetWidth, rows = this.table.rows, cells , returns = []; for (var i = 0; i < this.rowsNum; i++) { cells = rows[i].cells; for (var j = 0, tmpCell; tmpCell = cells[j++];) { var tmpStart = domUtils.getXY(tmpCell).x; if (tmpStart > start) break; if (tmpStart == start && tmpCell.colSpan == 1) { returns.push(tmpCell); break; } } } return returns; } catch (e) { showError(e); } }, /** * 更新table对应的索引表 */ update: function (table) { this.table = table || this.table; this.selectedTds = []; this.cellsRange = {}; this.indexTable = []; var rows = this.table.rows, //暂时采用rows Length,对残缺表格可能存在问题, //todo 可以考虑取最大值 rowsNum = rows.length, colsNum = this.getMaxCols(); this.rowsNum = rowsNum; this.colsNum = colsNum; for (var i = 0, len = rows.length; i < len; i++) { this.indexTable[i] = new Array(colsNum); } //填充索引表 for (var rowIndex = 0, row; row = rows[rowIndex]; rowIndex++) { for (var cellIndex = 0, cell, cells = row.cells; cell = cells[cellIndex]; cellIndex++) { //修正整行被rowSpan时导致的行数计算错误 if (cell.rowSpan > rowsNum) { cell.rowSpan = rowsNum; } var colIndex = cellIndex, rowSpan = cell.rowSpan || 1, colSpan = cell.colSpan || 1; //当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行 while (this.indexTable[rowIndex][colIndex]) colIndex++; for (var j = 0; j < rowSpan; j++) { for (var k = 0; k < colSpan; k++) { this.indexTable[rowIndex + j][colIndex + k] = { rowIndex: rowIndex, cellIndex: cellIndex, colIndex: colIndex, rowSpan: rowSpan, colSpan: colSpan } } } } } //修复残缺td for (j = 0; j < rowsNum; j++) { for (k = 0; k < colsNum; k++) { if (this.indexTable[j][k] === undefined) { row = rows[j]; cell = row.cells[row.cells.length - 1]; cell = cell ? cell.cloneNode(true) : this.table.ownerDocument.createElement("td"); this.setCellContent(cell); if (cell.colSpan !== 1)cell.colSpan = 1; if (cell.rowSpan !== 1)cell.rowSpan = 1; row.appendChild(cell); this.indexTable[j][k] = { rowIndex: j, cellIndex: cell.cellIndex, colIndex: k, rowSpan: 1, colSpan: 1 } } } } //当框选后删除行或者列后撤销,需要重建选区。 var tds = domUtils.getElementsByTagName(this.table, "td"), selectTds = []; utils.each(tds, function (td) { if (domUtils.hasClass(td, "selectTdClass")) { selectTds.push(td); } }); if (selectTds.length) { var start = selectTds[0], end = selectTds[selectTds.length - 1], startInfo = this.getCellInfo(start), endInfo = this.getCellInfo(end); this.selectedTds = selectTds; this.cellsRange = { beginRowIndex: startInfo.rowIndex, beginColIndex: startInfo.colIndex, endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1, endColIndex: endInfo.colIndex + endInfo.colSpan - 1 }; } }, /** * 获取单元格的索引信息 */ getCellInfo: function (cell) { if (!cell) return; var cellIndex = cell.cellIndex, rowIndex = cell.parentNode.rowIndex, rowInfo = this.indexTable[rowIndex], numCols = this.colsNum; for (var colIndex = cellIndex; colIndex < numCols; colIndex++) { var cellInfo = rowInfo[colIndex]; if (cellInfo.rowIndex === rowIndex && cellInfo.cellIndex === cellIndex) { return cellInfo; } } }, /** * 根据行列号获取单元格 */ getCell: function (rowIndex, cellIndex) { return rowIndex < this.rowsNum && this.table.rows[rowIndex].cells[cellIndex] || null; }, /** * 删除单元格 */ deleteCell: function (cell, rowIndex) { rowIndex = typeof rowIndex == 'number' ? rowIndex : cell.parentNode.rowIndex; var row = this.table.rows[rowIndex]; row.deleteCell(cell.cellIndex); }, /** * 根据始末两个单元格获取被框选的所有单元格范围 */ getCellsRange: function (cellA, cellB) { function checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex) { var tmpBeginRowIndex = beginRowIndex, tmpBeginColIndex = beginColIndex, tmpEndRowIndex = endRowIndex, tmpEndColIndex = endColIndex, cellInfo, colIndex, rowIndex; // 通过indexTable检查是否存在超出TableRange上边界的情况 if (beginRowIndex > 0) { for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) { cellInfo = me.indexTable[beginRowIndex][colIndex]; rowIndex = cellInfo.rowIndex; if (rowIndex < beginRowIndex) { tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex); } } } // 通过indexTable检查是否存在超出TableRange右边界的情况 if (endColIndex < me.colsNum) { for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) { cellInfo = me.indexTable[rowIndex][endColIndex]; colIndex = cellInfo.colIndex + cellInfo.colSpan - 1; if (colIndex > endColIndex) { tmpEndColIndex = Math.max(colIndex, tmpEndColIndex); } } } // 检查是否有超出TableRange下边界的情况 if (endRowIndex < me.rowsNum) { for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) { cellInfo = me.indexTable[endRowIndex][colIndex]; rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1; if (rowIndex > endRowIndex) { tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex); } } } // 检查是否有超出TableRange左边界的情况 if (beginColIndex > 0) { for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) { cellInfo = me.indexTable[rowIndex][beginColIndex]; colIndex = cellInfo.colIndex; if (colIndex < beginColIndex) { tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex); } } } //递归调用直至所有完成所有框选单元格的扩展 if (tmpBeginRowIndex != beginRowIndex || tmpBeginColIndex != beginColIndex || tmpEndRowIndex != endRowIndex || tmpEndColIndex != endColIndex) { return checkRange(tmpBeginRowIndex, tmpBeginColIndex, tmpEndRowIndex, tmpEndColIndex); } else { // 不需要扩展TableRange的情况 return { beginRowIndex: beginRowIndex, beginColIndex: beginColIndex, endRowIndex: endRowIndex, endColIndex: endColIndex }; } } try { var me = this, cellAInfo = me.getCellInfo(cellA); if (cellA === cellB) { return { beginRowIndex: cellAInfo.rowIndex, beginColIndex: cellAInfo.colIndex, endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1, endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1 }; } var cellBInfo = me.getCellInfo(cellB); // 计算TableRange的四个边 var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex), beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex), endRowIndex = Math.max(cellAInfo.rowIndex + cellAInfo.rowSpan - 1, cellBInfo.rowIndex + cellBInfo.rowSpan - 1), endColIndex = Math.max(cellAInfo.colIndex + cellAInfo.colSpan - 1, cellBInfo.colIndex + cellBInfo.colSpan - 1); return checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex); } catch (e) { if (debug) 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 () { removeSelectedClass(this.selectedTds); this.selectedTds = []; this.cellsRange = {}; }, /** * 根据range设置已经选中的单元格 */ setSelected: function (range) { var cells = this.getCells(range); addSelectedClass(cells); this.selectedTds = cells; this.cellsRange = range; }, isFullRow: function () { var range = this.cellsRange; return (range.endColIndex - range.beginColIndex + 1) == this.colsNum; }, isFullCol: function () { var range = this.cellsRange, table = this.table, ths = table.getElementsByTagName("th"), rows = range.endRowIndex - range.beginRowIndex + 1; return !ths.length ? rows == this.rowsNum : rows == this.rowsNum || (rows == this.rowsNum - 1); }, /** * 获取视觉上的前置单元格,默认是左边,top传入时 * @param cell * @param top */ getNextCell: function (cell, bottom, ignoreRange) { try { var cellInfo = this.getCellInfo(cell), nextRowIndex, nextColIndex; var len = this.selectedTds.length && !ignoreRange, range = this.cellsRange; //末行或者末列没有后置单元格 if ((!bottom && (cellInfo.rowIndex == 0)) || (bottom && (!len ? (cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1) : (range.endRowIndex == this.rowsNum - 1)))) return null; nextRowIndex = !bottom ? ( !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1) : ( !len ? (cellInfo.rowIndex + cellInfo.rowSpan) : range.endRowIndex + 1); nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex; return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this.indexTable[nextRowIndex][nextColIndex].cellIndex); } catch (e) { showError(e); } }, getPreviewCell: function (cell, top) { try { var cellInfo = this.getCellInfo(cell), previewRowIndex, previewColIndex; var len = this.selectedTds.length, range = this.cellsRange; //首行或者首列没有前置单元格 if ((!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) || (top && (!len ? (cellInfo.rowIndex > (this.colsNum - 1)) : (range.endColIndex == this.colsNum - 1)))) return null; previewRowIndex = !top ? ( !len ? cellInfo.rowIndex : range.beginRowIndex ) : ( !len ? (cellInfo.rowIndex < 1 ? 0 : (cellInfo.rowIndex - 1)) : range.beginRowIndex); previewColIndex = !top ? ( !len ? (cellInfo.colIndex < 1 ? 0 : (cellInfo.colIndex - 1)) : range.beginColIndex - 1) : ( !len ? cellInfo.colIndex : range.endColIndex + 1); return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this.indexTable[previewRowIndex][previewColIndex].cellIndex); } catch (e) { showError(e); } }, /** * 移动单元格中的内容 */ moveContent: function (cellTo, cellFrom) { if (isEmptyBlock(cellFrom)) return; if (isEmptyBlock(cellTo)) { cellTo.innerHTML = cellFrom.innerHTML; return; } var child = cellTo.lastChild; if (child.nodeType == 3 || !dtd.$block[child.tagName]) { cellTo.appendChild(cellTo.ownerDocument.createElement('br')) } while (child = cellFrom.firstChild) { cellTo.appendChild(child); } }, /** * 向右合并单元格 */ mergeRight: function (cell) { var cellInfo = this.getCellInfo(cell), rightColIndex = cellInfo.colIndex + cellInfo.colSpan, rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex], rightCell = this.getCell(rightCellInfo.rowIndex, rightCellInfo.cellIndex); //合并 cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan; //被合并的单元格不应存在宽度属性 cell.removeAttribute("width"); //移动内容 this.moveContent(cell, rightCell); //删掉被合并的Cell this.deleteCell(rightCell, rightCellInfo.rowIndex); this.update(); }, /** * 向下合并单元格 */ mergeDown: function (cell) { var cellInfo = this.getCellInfo(cell), downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan, downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex], downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex); cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan; cell.removeAttribute("height"); this.moveContent(cell, downCell); this.deleteCell(downCell, downCellInfo.rowIndex); this.update(); }, /** * 合并整个range中的内容 */ mergeRange: function () { //由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问 var range = this.cellsRange, leftTopCell = this.getCell(range.beginRowIndex, this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex); if (leftTopCell.tagName == "TH" && range.endRowIndex !== range.beginRowIndex) { var index = this.indexTable, info = this.getCellInfo(leftTopCell); leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex); range = this.getCellsRange(leftTopCell, this.getCell(index[this.rowsNum - 1][info.colIndex].rowIndex, index[this.rowsNum - 1][info.colIndex].cellIndex)); } // 删除剩余的Cells var cells = this.getCells(range), len = cells.length, cell; while (len--) { cell = cells[len]; if (cell !== leftTopCell) { this.moveContent(leftTopCell, cell); this.deleteCell(cell); } } // 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置 leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1; leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height"); leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1; leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width"); if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) { leftTopCell.colSpan = 1; } if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) { var rowIndex = leftTopCell.parentNode.rowIndex; for (var i = 0; i < leftTopCell.rowSpan - 1; i++) { var row = this.table.rows[rowIndex + 1]; row.parentNode.removeChild(row); } leftTopCell.rowSpan = 1; } this.update(); }, /** * 插入一行单元格 */ insertRow: function (rowIndex, sourceCell) { var numCols = this.colsNum, table = this.table, row = table.insertRow(rowIndex), cell, width = parseInt((table.offsetWidth - numCols * 20 - numCols - 1) / numCols, 10); //首行直接插入,无需考虑部分单元格被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); } } 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); } } } //框选时插入不触发contentchange,需要手动更新索引。 this.update(); return row; }, /** * 删除一行单元格 * @param rowIndex */ deleteRow: function (rowIndex) { var row = this.table.rows[rowIndex], infoRow = this.indexTable[rowIndex], colsNum = this.colsNum, count = 0; //处理计数 for (var colIndex = 0; colIndex < colsNum;) { var cellInfo = infoRow[colIndex], cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex); if (cell.rowSpan > 1) { if (cellInfo.rowIndex == rowIndex) { var clone = cell.cloneNode(true); clone.rowSpan = cell.rowSpan - 1; clone.innerHTML = ""; cell.rowSpan = 1; var nextRowIndex = rowIndex + 1, nextRow = this.table.rows[nextRowIndex], insertCellIndex, preMerged = this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count; if (preMerged < colIndex) { insertCellIndex = colIndex - preMerged - 1; //nextRow.insertCell(insertCellIndex); domUtils.insertAfter(nextRow.cells[insertCellIndex], clone); } else { if (nextRow.cells.length) nextRow.insertBefore(clone, nextRow.cells[0]) } count += 1; //cell.parentNode.removeChild(cell); } } colIndex += cell.colSpan || 1; } var deleteTds = [], cacheMap = {}; for (colIndex = 0; colIndex < colsNum; colIndex++) { var tmpRowIndex = infoRow[colIndex].rowIndex, tmpCellIndex = infoRow[colIndex].cellIndex, key = tmpRowIndex + "_" + tmpCellIndex; if (cacheMap[key])continue; cacheMap[key] = 1; cell = this.getCell(tmpRowIndex, tmpCellIndex); deleteTds.push(cell); } var mergeTds = []; utils.each(deleteTds, function (td) { if (td.rowSpan == 1) { td.parentNode.removeChild(td); } else { mergeTds.push(td); } }); utils.each(mergeTds, function (td) { td.rowSpan--; }); row.parentNode.removeChild(row); //浏览器方法本身存在bug,采用自定义方法删除 //this.table.deleteRow(rowIndex); this.update(); }, insertCol: function (colIndex, sourceCell, defaultValue) { var rowsNum = this.rowsNum, rowIndex = 0, tableRow, cell, backWidth = parseInt((this.table.offsetWidth - (this.colsNum + 1) * 20 - (this.colsNum + 1)) / (this.colsNum + 1), 10); 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) } } } 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); } 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')) tableRow.insertBefore(cell, preCell); } replaceTdToTh(rowIndex, cell, tableRow); } } //框选时插入不触发contentchange,需要手动更新索引 this.update(); this.updateWidth(backWidth, defaultValue || {tdPadding: 10, tdBorder: 1}); }, updateWidth: function (width, defaultValue) { var table = this.table, tmpWidth = 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"); 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); } }; function getSelectedArr(editor) { var ut = getTableItemsByRange(editor).cell || getUETableBySelected(editor); return ut ? (ut.nodeType ? [ut] : ut.selectedTds) : []; } /** * 根据当前选区获取相关的table信息 * @return {Object} */ function getTableItemsByRange(editor) { var start = editor.selection.getStart(), //在table或者td边缘有可能存在选中tr的情况 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 } } /** * 获取需要触发对应点击或者move事件的td对象 * @param evt */ function getTargetTd(editor, evt) { var target = domUtils.findParentByTagName(evt.target || evt.srcElement, ["td", "th"], true); //排除了非td内部以及用于代码高亮部分的td return target && !(editor.fireEvent("excludetable", target) === true) ? target : null; } function cloneCell(cell, ingoreMerge) { if (!cell || utils.isString(cell)) { return this.table.ownerDocument.createElement(cell || 'td'); } var flag = domUtils.hasClass(cell, "selectTdClass"); flag && domUtils.removeClasses(cell, "selectTdClass"); var tmpCell = cell.cloneNode(true); if (ingoreMerge) { tmpCell.rowSpan = tmpCell.colSpan = 1; } 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; } }; ///import core ///commands 右键菜单 ///commandsName ContextMenu ///commandsTitle 右键菜单 /** * 右键菜单 * @function * @name baidu.editor.plugins.contextmenu * @author zhanyi */ UE.plugins['contextmenu'] = function () { var me = this, lang = me.getLang("contextMenu"), menu, items = me.options.contextMenu || [ {label: lang['selectall'], cmdName: 'selectall'}, { label: lang.deletecode, cmdName: 'highlightcode', icon: 'deletehighlightcode' }, { 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.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(); } } ] }, { 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', label: lang.tableleft, value: ['float', 'left'] }, { cmdName: 'tablealignment', label: lang.tablecenter, value: ['margin', '0 auto'] }, { cmdName: 'tablealignment', label: lang.tableright, value: ['float', 'right'] } ] }, '-', { label: lang.insertparagraphbefore, cmdName: 'insertparagraph', value: true }, { label: lang.insertparagraphafter, cmdName: 'insertparagraph' }, { label: lang['copy'], cmdName: 'copy', exec: function () { alert(lang.copymsg); }, query: function () { return 0; } }, { label: lang['paste'], cmdName: 'paste', exec: function () { alert(lang.pastemsg); }, query: function () { return 0; } }, { label: lang['highlightcode'], cmdName: 'highlightcode', exec: function () { if (UE.ui['highlightcode']) { new UE.ui['highlightcode'](this); } this.ui._dialogs['highlightcodeDialog'].open(); } } ]; 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, 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"); 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) { //highlight todo if (item.cmdName == 'highlightcode') { if (me.queryCommandState(item.cmdName) == 1 && item.icon != 'deletehighlightcode') { return; } if (me.queryCommandState(item.cmdName) != 1 && item.icon == 'deletehighlightcode') { 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); } }); } } })(ti); } if (contextItems[contextItems.length - 1] == '-') { contextItems.pop(); } menu = new UE.ui.Menu({ items: contextItems, editor: me }); menu.render(); menu.showAt(offset); 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); } } }); }; ///import core ///commands 加粗,斜体,上标,下标 ///commandsName Bold,Italic,Subscript,Superscript ///commandsTitle 加粗,加斜,下标,上标 /** * b u i等基础功能实现 * @function * @name baidu.editor.execCommands * @param {String} cmdName bold加粗。italic斜体。subscript上标。superscript下标。 */ UE.plugins['basestyle'] = function () { 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 }); 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]); } }; ///import core ///commands 选区路径 ///commandsName ElementPath,elementPathEnabled ///commandsTitle 选区路径 /** * 选区路径 * @function * @name baidu.editor.execCommand * @param {String} cmdName elementpath选区路径 */ 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; } }; }; ///import core ///import plugins\removeformat.js ///commands 格式刷 ///commandsName FormatMatch ///commandsTitle 格式刷 /** * 格式刷,只格式inline的 * @function * @name baidu.editor.execCommand * @param {String} cmdName 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 }; }; ///import core ///commands 查找替换 ///commandsName SearchReplace ///commandsTitle 查询替换 ///commandsDialog dialogs\searchreplace /** * @description 查找替换 * @author zhanyi */ UE.plugins['searchreplace'] = function () { var currentRange, first, me = this; me.addListener('reset', function () { currentRange = null; first = null; }); me.commands['searchreplace'] = { execCommand: function (cmdName, opt) { var me = this, sel = me.selection, range, nativeRange, num = 0, opt = utils.extend(opt, { all: false, casesensitive: false, dir: 1 }, true); if (browser.ie) { while (1) { var tmpRange; nativeRange = me.document.selection.createRange(); tmpRange = nativeRange.duplicate(); tmpRange.moveToElementText(me.document.body); if (opt.all) { first = 0; opt.dir = 1; if (currentRange) { tmpRange.setEndPoint(opt.dir == -1 ? 'EndToStart' : 'StartToEnd', currentRange); } tmpRange.moveToElementText(me.document.body); } else { tmpRange.setEndPoint(opt.dir == -1 ? 'EndToStart' : 'StartToEnd', nativeRange); if (opt.hasOwnProperty("replaceStr")) { tmpRange.setEndPoint(opt.dir == -1 ? 'StartToEnd' : 'EndToStart', nativeRange); } } nativeRange = tmpRange.duplicate(); if (!tmpRange.findText(opt.searchStr, opt.dir, opt.casesensitive ? 4 : 0)) { currentRange = null; tmpRange = me.document.selection.createRange(); tmpRange.scrollIntoView(); return num; } tmpRange.select(); //替换 if (opt.hasOwnProperty("replaceStr")) { range = sel.getRange(); range.deleteContents().insertNode(range.document.createTextNode(opt.replaceStr)).select(); currentRange = sel.getNative().createRange(); } num++; if (!opt.all) { break; } } } else { var w = me.window, nativeSel = sel.getNative(), tmpRange; while (1) { if (opt.all) { if (currentRange) { currentRange.collapse(false); nativeRange = currentRange; } else { nativeRange = me.document.createRange(); } nativeRange.setStart(me.document.body, 0); nativeRange.collapse(true); nativeSel.removeAllRanges(); nativeSel.addRange(nativeRange); first = 0; opt.dir = 1; } else { //safari弹出层,原生已经找不到range了,所以需要先选回来,再取原生 if (browser.safari) { me.selection.getRange().select(); } nativeRange = w.getSelection().getRangeAt(0); if (opt.hasOwnProperty("replaceStr")) { nativeRange.collapse(opt.dir == 1 ? true : false); } } //如果是第一次并且海选中了内容那就要清除,为find做准备 if (!first) { nativeRange.collapse(opt.dir < 0 ? true : false); nativeSel.removeAllRanges(); nativeSel.addRange(nativeRange); } else { nativeSel.removeAllRanges(); } if (!w.find(opt.searchStr, opt.casesensitive, opt.dir < 0 ? true : false)) { currentRange = null; nativeSel.removeAllRanges(); return num; } first = 0; range = w.getSelection().getRangeAt(0); if (!range.collapsed) { if (opt.hasOwnProperty("replaceStr")) { range.deleteContents(); var text = w.document.createTextNode(opt.replaceStr); range.insertNode(text); range.selectNode(text); nativeSel.addRange(range); currentRange = range.cloneRange(); } } num++; if (!opt.all) { break; } } } return true; } }; }; ///import core ///commands 自定义样式 ///commandsName CustomStyle ///commandsTitle 自定义样式 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(); } } } }); }; ///import core ///commands 远程图片抓取 ///commandsName catchRemoteImage,catchremoteimageenable ///commandsTitle 远程图片抓取 /** * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片 * */ UE.plugins['catchremoteimage'] = function () { if (this.options.catchRemoteImageEnable === false) { return; } var me = this; this.setOpt({ localDomain: ["127.0.0.1", "localhost", "img.baidu.com"], separater: 'ue_separate_ue', catchFieldName: "upfile", catchRemoteImageEnable: true }); var ajax = UE.ajax, localDomain = me.options.localDomain , catcherUrl = me.options.catcherUrl, separater = me.options.separater; function catchremoteimage(imgs, callbacks) { var submitStr = imgs.join(separater); var tmpOption = { timeout: 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值 onsuccess: callbacks["success"], onerror: callbacks["error"] }; tmpOption[me.options.catchFieldName] = submitStr; ajax.request(catcherUrl, tmpOption); } me.addListener("afterpaste", function () { me.fireEvent("catchRemoteImage"); }); me.addListener("catchRemoteImage", function () { var remoteImages = []; var imgs = domUtils.getElementsByTagName(me.document, "img"); var test = function (src, urls) { for (var j = 0, url; url = urls[j++];) { if (src.indexOf(url) !== -1) { return true; } } return false; }; for (var i = 0, ci; ci = imgs[i++];) { if (ci.getAttribute("word_img")) { continue; } var src = ci.getAttribute("data_ue_src") || ci.src || ""; if (/^(https?|ftp):/i.test(src) && !test(src, localDomain)) { remoteImages.push(src); } } if (remoteImages.length) { catchremoteimage(remoteImages, { //成功抓取 success: function (xhr) { try { var info = eval("(" + xhr.responseText + ")"); } catch (e) { return; } var srcUrls = info.srcUrl.split(separater), urls = info.url.split(separater); for (var i = 0, ci; ci = imgs[i++];) { var src = ci.getAttribute("data_ue_src") || ci.src || ""; for (var j = 0, cj; cj = srcUrls[j++];) { var url = urls[j - 1]; if (src == cj && url != "error") { //抓取失败时不做替换处理 //地址修正 var newSrc = me.options.catcherPath + url; domUtils.setAttributes(ci, { "src": newSrc, "data_ue_src": newSrc }); break; } } } me.fireEvent('catchremotesuccess') }, //回调失败,本次请求超时 error: function () { me.fireEvent("catchremoteerror"); } }); } }); }; ///import core ///import plugins\inserthtml.js ///import plugins\image.js ///commandsName snapscreen ///commandsTitle 截屏 /** * 截屏插件 */ UE.plugins['snapscreen'] = function () { var me = this, doc, snapplugin; me.addListener("ready", function () { var container = me.container; doc = container.ownerDocument || container.document; snapplugin = doc.createElement("object"); snapplugin.type = "application/x-pluginbaidusnap"; snapplugin.style.cssText = "position:absolute;left:-9999px;"; snapplugin.setAttribute("width", "0"); snapplugin.setAttribute("height", "0"); container.appendChild(snapplugin); }); me.commands['snapscreen'] = { execCommand: function () { var me = this, lang = me.getLang("snapScreen_plugin"); me.setOpt({ snapscreenServerPort: 80 //屏幕截图的server端端口 , snapscreenImgAlign: '' //截图的图片默认的排版方式 }); var editorOptions = me.options; var onSuccess = function (rs) { try { rs = eval("(" + rs + ")"); } catch (e) { alert(lang.callBackErrorMsg); return; } if (rs.state != 'SUCCESS') { alert(rs.state); return; } me.execCommand('insertimage', { src: editorOptions.snapscreenPath + rs.url, floatStyle: editorOptions.snapscreenImgAlign, data_ue_src: editorOptions.snapscreenPath + rs.url }); }; var onStartUpload = function () { //开始截图上传 }; var onError = function () { alert(lang.uploadErrorMsg); }; try { var ret = snapplugin.saveSnapshot(editorOptions.snapscreenHost, editorOptions.snapscreenServerUrl, editorOptions.snapscreenServerPort.toString()); onSuccess(ret); } catch (e) { me.ui._dialogs['snapscreenDialog'].open(); } }, queryCommandState: function () { return this.highlight ? -1 : 0; } }; } ///import core ///commands 插入空行 ///commandsName insertparagraph ///commandsTitle 插入空行 /** * 插入空行 * @function * @name baidu.editor.execCommand * @param {String} cmdName 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); } } }; ///import core ///import plugins/inserthtml.js ///commands 百度应用 ///commandsName webapp ///commandsTitle 百度应用 ///commandsDialog dialogs\webapp 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)); } }; }; ///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"]); } } } }); }; ///import core ///import plugins/inserthtml.js ///commands 音乐 ///commandsName Music ///commandsTitle 插入音乐 ///commandsDialog dialogs\music UE.plugins['music'] = function () { var me = this, div; /** * 创建插入音乐字符窜 * @param url 音乐地址 * @param width 音乐宽度 * @param height 音乐高度 * @param align 阴雨对齐 * @param toEmbed 是否以flash代替显示 * @param addParagraph 是否需要添加P标签 */ function creatInsertStr(url, width, height, align, toEmbed, addParagraph) { return !toEmbed ? (addParagraph ? ('

') : '') + '' + (addParagraph ? '

' : '') : ''; } function switchImgAndEmbed(img2embed) { var tmpdiv, nodes = domUtils.getElementsByTagName(me.document, !img2embed ? "embed" : "img"); for (var i = 0, node; node = nodes[i++];) { if (node.className != "edui-faked-music") { continue; } tmpdiv = me.document.createElement("div"); //先看float在看align,浮动有的是时候是在float上定义的 var align = domUtils.getComputedStyle(node, 'float'); align = align == 'none' ? (node.getAttribute('align') || '') : align; tmpdiv.innerHTML = creatInsertStr(img2embed ? node.getAttribute("_url") : node.getAttribute("src"), node.width, node.height, align, img2embed); node.parentNode.replaceChild(tmpdiv.firstChild, node); } } me.addListener("beforegetcontent", function () { switchImgAndEmbed(true); }); me.addListener('aftersetcontent', function () { switchImgAndEmbed(false); }); me.addListener('aftergetcontent', function (cmdName) { if (cmdName == 'aftergetcontent' && me.queryCommandState('source')) { return; } switchImgAndEmbed(false); }); me.commands["music"] = { execCommand: function (cmd, musicObj) { var me = this, str = creatInsertStr(musicObj.url, musicObj.width || 400, musicObj.height || 95, "none", false, true); 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; } }; }; var baidu = baidu || {}; baidu.editor = baidu.editor || {}; baidu.editor.ui = {}; (function () { var browser = baidu.editor.browser, domUtils = baidu.editor.dom.domUtils; var magic = '$EDITORUI'; var root = window[magic] = {}; var uidMagic = 'ID' + magic; var uidCount = 0; var uiUtils = baidu.editor.ui.uiUtils = { uid: function (obj) { return (obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount); }, hook: function (fn, callback) { var dg; if (fn && fn._callbacks) { dg = fn; } else { dg = function () { var q; if (fn) { q = fn.apply(this, arguments); } var callbacks = dg._callbacks; var k = callbacks.length; while (k--) { var r = callbacks[k].apply(this, arguments); if (q === undefined) { q = r; } } return q; }; dg._callbacks = []; } dg._callbacks.push(callback); return dg; }, createElementByHtml: function (html) { var el = document.createElement('div'); el.innerHTML = html; el = el.firstChild; el.parentNode.removeChild(el); return el; }, getViewportElement: function () { return (browser.ie && browser.quirks) ? document.body : document.documentElement; }, getClientRect: function (element) { var bcr; //trace IE6下在控制编辑器显隐时可能会报错,catch一下 try { bcr = element.getBoundingClientRect(); } catch (e) { bcr = {left: 0, top: 0, height: 0, width: 0} } var rect = { left: Math.round(bcr.left), top: Math.round(bcr.top), height: Math.round(bcr.bottom - bcr.top), width: Math.round(bcr.right - bcr.left) }; var doc; while ((doc = element.ownerDocument) !== document && (element = domUtils.getWindow(doc).frameElement)) { bcr = element.getBoundingClientRect(); rect.left += bcr.left; rect.top += bcr.top; } rect.bottom = rect.top + rect.height; rect.right = rect.left + rect.width; return rect; }, getViewportRect: function () { var viewportEl = uiUtils.getViewportElement(); var width = (window.innerWidth || viewportEl.clientWidth) | 0; var height = (window.innerHeight || viewportEl.clientHeight) | 0; return { left: 0, top: 0, height: height, width: width, bottom: height, right: width }; }, setViewportOffset: function (element, offset) { var rect; var fixedLayer = uiUtils.getFixedLayer(); if (element.parentNode === fixedLayer) { element.style.left = offset.left + 'px'; element.style.top = offset.top + 'px'; } else { domUtils.setViewportOffset(element, offset); } }, getEventOffset: function (evt) { var el = evt.target || evt.srcElement; var rect = uiUtils.getClientRect(el); var offset = uiUtils.getViewportOffsetByEvent(evt); return { left: offset.left - rect.left, top: offset.top - rect.top }; }, getViewportOffsetByEvent: function (evt) { var el = evt.target || evt.srcElement; var frameEl = domUtils.getWindow(el).frameElement; var offset = { left: evt.clientX, top: evt.clientY }; if (frameEl && el.ownerDocument !== document) { var rect = uiUtils.getClientRect(frameEl); offset.left += rect.left; offset.top += rect.top; } return offset; }, setGlobal: function (id, obj) { root[id] = obj; return magic + '["' + id + '"]'; }, unsetGlobal: function (id) { delete root[id]; }, copyAttributes: function (tgt, src) { var attributes = src.attributes; var k = attributes.length; while (k--) { var attrNode = attributes[k]; if (attrNode.nodeName != 'style' && attrNode.nodeName != 'class' && (!browser.ie || attrNode.specified)) { tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue); } } if (src.className) { domUtils.addClass(tgt, src.className); } if (src.style.cssText) { tgt.style.cssText += ';' + src.style.cssText; } }, removeStyle: function (el, styleName) { if (el.style.removeProperty) { el.style.removeProperty(styleName); } else if (el.style.removeAttribute) { el.style.removeAttribute(styleName); } else throw ''; }, contains: function (elA, elB) { return elA && elB && (elA === elB ? false : ( elA.contains ? elA.contains(elB) : elA.compareDocumentPosition(elB) & 16 )); }, startDrag: function (evt, callbacks, doc) { var doc = doc || document; var startX = evt.clientX; var startY = evt.clientY; function handleMouseMove(evt) { var x = evt.clientX - startX; var y = evt.clientY - startY; callbacks.ondragmove(x, y); if (evt.stopPropagation) { evt.stopPropagation(); } else { evt.cancelBubble = true; } } if (doc.addEventListener) { function handleMouseUp(evt) { doc.removeEventListener('mousemove', handleMouseMove, true); doc.removeEventListener('mouseup', handleMouseMove, true); window.removeEventListener('mouseup', handleMouseUp, true); callbacks.ondragstop(); } doc.addEventListener('mousemove', handleMouseMove, true); doc.addEventListener('mouseup', handleMouseUp, true); window.addEventListener('mouseup', handleMouseUp, true); evt.preventDefault(); } else { var elm = evt.srcElement; elm.setCapture(); function releaseCaptrue() { elm.releaseCapture(); elm.detachEvent('onmousemove', handleMouseMove); elm.detachEvent('onmouseup', releaseCaptrue); elm.detachEvent('onlosecaptrue', releaseCaptrue); callbacks.ondragstop(); } elm.attachEvent('onmousemove', handleMouseMove); elm.attachEvent('onmouseup', releaseCaptrue); elm.attachEvent('onlosecaptrue', releaseCaptrue); evt.returnValue = false; } callbacks.ondragstart(); }, getFixedLayer: function () { var layer = document.getElementById('edui_fixedlayer'); if (layer == null) { layer = document.createElement('div'); layer.id = 'edui_fixedlayer'; document.body.appendChild(layer); if (browser.ie && browser.version <= 8) { layer.style.position = 'absolute'; bindFixedLayer(); setTimeout(updateFixedOffset); } else { layer.style.position = 'fixed'; } layer.style.left = '0'; layer.style.top = '0'; layer.style.width = '0'; layer.style.height = '0'; } return layer; }, makeUnselectable: function (element) { if (browser.opera || (browser.ie && browser.version < 9)) { element.unselectable = 'on'; if (element.hasChildNodes()) { for (var i = 0; i < element.childNodes.length; i++) { if (element.childNodes[i].nodeType == 1) { uiUtils.makeUnselectable(element.childNodes[i]); } } } } else { if (element.style.MozUserSelect !== undefined) { element.style.MozUserSelect = 'none'; } else if (element.style.WebkitUserSelect !== undefined) { element.style.WebkitUserSelect = 'none'; } else if (element.style.KhtmlUserSelect !== undefined) { element.style.KhtmlUserSelect = 'none'; } } } }; function updateFixedOffset() { var layer = document.getElementById('edui_fixedlayer'); uiUtils.setViewportOffset(layer, { left: 0, top: 0 }); // layer.style.display = 'none'; // layer.style.display = 'block'; //#trace: 1354 // setTimeout(updateFixedOffset); } function bindFixedLayer(adjOffset) { domUtils.on(window, 'scroll', updateFixedOffset); domUtils.on(window, 'resize', baidu.editor.utils.defer(updateFixedOffset, 0, true)); } })(); (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, EventBase = baidu.editor.EventBase, UIBase = baidu.editor.ui.UIBase = function () { }; UIBase.prototype = { className: '', uiName: '', initOptions: function (options) { var me = this; for (var k in options) { me[k] = options[k]; } this.id = this.id || 'edui' + uiUtils.uid(); }, initUIBase: function () { this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this)); }, render: function (holder) { var html = this.renderHtml(); var el = uiUtils.createElementByHtml(html); //by xuheng 给每个node添加class var list = domUtils.getElementsByTagName(el, "*"); var theme = "edui-" + (this.theme || this.editor.options.theme); var layer = document.getElementById('edui_fixedlayer'); for (var i = 0, node; node = list[i++];) { domUtils.addClass(node, theme); } domUtils.addClass(el, theme); if (layer) { layer.className = ""; domUtils.addClass(layer, theme); } var seatEl = this.getDom(); if (seatEl != null) { seatEl.parentNode.replaceChild(el, seatEl); uiUtils.copyAttributes(el, seatEl); } else { if (typeof holder == 'string') { holder = document.getElementById(holder); } holder = holder || uiUtils.getFixedLayer(); domUtils.addClass(holder, theme); holder.appendChild(el); } this.postRender(); }, getDom: function (name) { if (!name) { return document.getElementById(this.id); } else { return document.getElementById(this.id + '_' + name); } }, postRender: function () { this.fireEvent('postrender'); }, getHtmlTpl: function () { return ''; }, formatHtml: function (tpl) { var prefix = 'edui-' + this.uiName; return (tpl .replace(/##/g, this.id) .replace(/%%-/g, this.uiName ? prefix + '-' : '') .replace(/%%/g, (this.uiName ? prefix : '') + ' ' + this.className) .replace(/\$\$/g, this._globalKey)); }, renderHtml: function () { return this.formatHtml(this.getHtmlTpl()); }, dispose: function () { var box = this.getDom(); if (box) baidu.editor.dom.domUtils.remove(box); uiUtils.unsetGlobal(this.id); } }; utils.inherits(UIBase, EventBase); })(); (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase, Separator = baidu.editor.ui.Separator = function (options) { this.initOptions(options); this.initSeparator(); }; Separator.prototype = { uiName: 'separator', initSeparator: function () { this.initUIBase(); }, getHtmlTpl: function () { return '
'; } }; utils.inherits(Separator, UIBase); })(); ///import core ///import uicore (function () { var utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils, UIBase = baidu.editor.ui.UIBase, uiUtils = baidu.editor.ui.uiUtils; var Mask = baidu.editor.ui.Mask = function (options) { this.initOptions(options); this.initUIBase(); }; Mask.prototype = { getHtmlTpl: function () { return '
'; }, postRender: function () { var me = this; domUtils.on(window, 'resize', function () { setTimeout(function () { if (!me.isHidden()) { me._fill(); } }); }); }, show: function (zIndex) { this._fill(); this.getDom().style.display = ''; this.getDom().style.zIndex = zIndex; }, hide: function () { this.getDom().style.display = 'none'; this.getDom().style.zIndex = ''; }, isHidden: function () { return this.getDom().style.display == 'none'; }, _onMouseDown: function () { return false; }, _fill: function () { var el = this.getDom(); var vpRect = uiUtils.getViewportRect(); el.style.width = vpRect.width + 'px'; el.style.height = vpRect.height + 'px'; } }; utils.inherits(Mask, UIBase); })(); ///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) { var newAll = []; 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(); } } } } 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 '' } }, _UIBase_postRender: UIBase.prototype.postRender, postRender: function () { if (this.content instanceof UIBase) { this.content.postRender(); } 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 () { var popBodyEl = this.getDom('body'); popBodyEl.style.width = ''; popBodyEl.style.height = ''; var size = this.mesureSize(); popBodyEl.style.width = size.width + 'px'; popBodyEl.style.height = size.height + 'px'; return size; }, showAnchor: function (element, hoz) { this.showAnchorRect(uiUtils.getClientRect(element), hoz); }, showAnchorRect: function (rect, hoz, adj) { this._doAutoRender(); var vpRect = uiUtils.getViewportRect(); this._show(); var popSize = this.fitSize(); var sideLeft, sideUp, left, top; if (hoz) { sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width); sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height); left = (sideLeft ? rect.left - popSize.width : rect.right); top = (sideUp ? rect.bottom - popSize.height : rect.top); } else { sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width); sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height); left = (sideLeft ? rect.right - popSize.width : rect.left); top = (sideUp ? rect.top - popSize.height : rect.bottom); } var popEl = this.getDom(); uiUtils.setViewportOffset(popEl, { left: left, top: top }); domUtils.removeClasses(popEl, ANCHOR_CLASSES); popEl.className += ' ' + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)]; if (this.editor) { popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10; baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = popEl.style.zIndex - 1; } }, 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.visibility = 'hidden'; this.getDom().style.display = 'none'; this._hidden = true; if (!notNofity) { this.fireEvent('hide'); } } }, queryAutoHide: function (el) { return !el || !uiUtils.contains(this.getDom(), el); } }; utils.inherits(Popup, UIBase); domUtils.on(document, 'mousedown', function (evt) { var el = evt.target || evt.srcElement; closeAllPopup(evt, el); }); domUtils.on(window, 'scroll', function (evt, el) { closeAllPopup(evt, el); }); // var lastVpRect = uiUtils.getViewportRect(); // domUtils.on( window, 'resize', function () { // var vpRect = uiUtils.getViewportRect(); // if (vpRect.width != lastVpRect.width || vpRect.height != lastVpRect.height) { // closeAllPopup(); // } // } ); })(); ///import core ///import uicore (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase, ColorPicker = baidu.editor.ui.ColorPicker = function (options) { this.initOptions(options); this.noColorText = this.noColorText || this.editor.getLang("clearColor"); this.initUIBase(); }; ColorPicker.prototype = { getHtmlTpl: function () { return genColorPicker(this.noColorText, this.editor); }, _onTableClick: function (evt) { var tgt = evt.target || evt.srcElement; var color = tgt.getAttribute('data-color'); if (color) { this.fireEvent('pickcolor', color); } }, _onTableOver: function (evt) { var tgt = evt.target || evt.srcElement; var color = tgt.getAttribute('data-color'); if (color) { this.getDom('preview').style.backgroundColor = color; } }, _onTableOut: function () { this.getDom('preview').style.backgroundColor = ''; }, _onPickNoColor: function () { this.fireEvent('picknocolor'); } }; utils.inherits(ColorPicker, UIBase); var COLORS = ( 'ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646,' + 'f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada,' + 'd8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5,' + 'bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f,' + 'a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09,' + '7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806,' + 'c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,').split(','); function genColorPicker(noColorText, editor) { var html = '
' + '
' + '
' + '
' + noColorText + '
' + '
' + '' + '' + ''; for (var i = 0; i < COLORS.length; i++) { if (i && i % 10 === 0) { html += '' + (i == 60 ? '' : '') + ''; } html += i < 70 ? '' : ''; } html += '
' + editor.getLang("themeColor") + '
' + editor.getLang("standardColor") + '
'; return html; } })(); ///import core ///import uicore (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, UIBase = baidu.editor.ui.UIBase; var TablePicker = baidu.editor.ui.TablePicker = function (options) { this.initOptions(options); this.initTablePicker(); }; TablePicker.prototype = { defaultNumRows: 10, defaultNumCols: 10, maxNumRows: 20, maxNumCols: 20, numRows: 10, numCols: 10, lengthOfCellSide: 22, initTablePicker: function () { this.initUIBase(); }, getHtmlTpl: function () { var me = this; return '
' + '
' + '
' + '' + '
' + '
' + '
' + '
' + '
' + '
'; }, _UIBase_render: UIBase.prototype.render, render: function (holder) { this._UIBase_render(holder); this.getDom('label').innerHTML = '0' + this.editor.getLang("t_row") + ' x 0' + this.editor.getLang("t_col"); }, _track: function (numCols, numRows) { var style = this.getDom('overlay').style; var sideLen = this.lengthOfCellSide; style.width = numCols * sideLen + 'px'; style.height = numRows * sideLen + 'px'; var label = this.getDom('label'); label.innerHTML = numCols + this.editor.getLang("t_col") + ' x ' + numRows + this.editor.getLang("t_row"); this.numCols = numCols; this.numRows = numRows; }, _onMouseOver: function (evt, el) { var rel = evt.relatedTarget || evt.fromElement; if (!uiUtils.contains(el, rel) && el !== rel) { this.getDom('label').innerHTML = '0' + this.editor.getLang("t_col") + ' x 0' + this.editor.getLang("t_row"); this.getDom('overlay').style.visibility = ''; } }, _onMouseOut: function (evt, el) { var rel = evt.relatedTarget || evt.toElement; if (!uiUtils.contains(el, rel) && el !== rel) { this.getDom('label').innerHTML = '0' + this.editor.getLang("t_col") + ' x 0' + this.editor.getLang("t_row"); this.getDom('overlay').style.visibility = 'hidden'; } }, _onMouseMove: function (evt, el) { var style = this.getDom('overlay').style; var offset = uiUtils.getEventOffset(evt); var sideLen = this.lengthOfCellSide; var numCols = Math.ceil(offset.left / sideLen); var numRows = Math.ceil(offset.top / sideLen); this._track(numCols, numRows); }, _onClick: function () { this.fireEvent('picktable', this.numCols, this.numRows); } }; utils.inherits(TablePicker, UIBase); })(); (function () { var browser = baidu.editor.browser, domUtils = baidu.editor.dom.domUtils, uiUtils = baidu.editor.ui.uiUtils; var TPL_STATEFUL = 'onmousedown="$$.Stateful_onMouseDown(event, this);"' + ' onmouseup="$$.Stateful_onMouseUp(event, this);"' + ( browser.ie ? ( ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' + ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"' ) : ( ' onmouseover="$$.Stateful_onMouseOver(event, this);"' + ' onmouseout="$$.Stateful_onMouseOut(event, this);"' )); baidu.editor.ui.Stateful = { alwalysHoverable: false, target: null,//目标元素和this指向dom不一样 Stateful_init: function () { this._Stateful_dGetHtmlTpl = this.getHtmlTpl; this.getHtmlTpl = this.Stateful_getHtmlTpl; }, Stateful_getHtmlTpl: function () { var tpl = this._Stateful_dGetHtmlTpl(); // 使用function避免$转义 return tpl.replace(/stateful/g, function () { return TPL_STATEFUL; }); }, Stateful_onMouseEnter: function (evt, el) { this.target = el; if (!this.isDisabled() || this.alwalysHoverable) { this.addState('hover'); this.fireEvent('over'); } }, Stateful_onMouseLeave: function (evt, el) { if (!this.isDisabled() || this.alwalysHoverable) { this.removeState('hover'); this.removeState('active'); this.fireEvent('out'); } }, Stateful_onMouseOver: function (evt, el) { var rel = evt.relatedTarget; if (!uiUtils.contains(el, rel) && el !== rel) { this.Stateful_onMouseEnter(evt, el); } }, Stateful_onMouseOut: function (evt, el) { var rel = evt.relatedTarget; if (!uiUtils.contains(el, rel) && el !== rel) { this.Stateful_onMouseLeave(evt, el); } }, Stateful_onMouseDown: function (evt, el) { if (!this.isDisabled()) { this.addState('active'); } }, Stateful_onMouseUp: function (evt, el) { if (!this.isDisabled()) { this.removeState('active'); } }, Stateful_postRender: function () { if (this.disabled && !this.hasState('disabled')) { this.addState('disabled'); } }, hasState: function (state) { return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state); }, addState: function (state) { if (!this.hasState(state)) { this.getStateDom().className += ' edui-state-' + state; } }, removeState: function (state) { if (this.hasState(state)) { domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state]); } }, getStateDom: function () { return this.getDom('state'); }, isChecked: function () { return this.hasState('checked'); }, setChecked: function (checked) { if (!this.isDisabled() && checked) { this.addState('checked'); } else { this.removeState('checked'); } }, isDisabled: function () { return this.hasState('disabled'); }, setDisabled: function (disabled) { if (disabled) { this.removeState('hover'); this.removeState('checked'); this.removeState('active'); this.addState('disabled'); } else { this.removeState('disabled'); } } }; })(); ///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) { this.initOptions(options); this.initButton(); }; Button.prototype = { uiName: 'button', label: '', title: '', showIcon: true, showText: true, initButton: function () { this.initUIBase(); this.Stateful_init(); }, getHtmlTpl: function () { return '
' + '
' + '
' + (this.showIcon ? '
' : '') + (this.showText ? '
' + this.label + '
' : '') + '
' + '
' + '
'; }, postRender: function () { this.Stateful_postRender(); this.setDisabled(this.disabled) }, _onClick: function () { if (!this.isDisabled()) { this.fireEvent('click'); } } }; utils.inherits(Button, UIBase); utils.extend(Button.prototype, Stateful); })(); ///import core ///import uicore ///import ui/stateful.js (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, domUtils = baidu.editor.dom.domUtils, UIBase = baidu.editor.ui.UIBase, Stateful = baidu.editor.ui.Stateful, SplitButton = baidu.editor.ui.SplitButton = function (options) { this.initOptions(options); this.initSplitButton(); }; SplitButton.prototype = { popup: null, uiName: 'splitbutton', title: '', initSplitButton: function () { this.initUIBase(); this.Stateful_init(); var me = this; if (this.popup != null) { var popup = this.popup; this.popup = null; this.setPopup(popup); } }, _UIBase_postRender: UIBase.prototype.postRender, postRender: function () { this.Stateful_postRender(); this._UIBase_postRender(); }, setPopup: function (popup) { if (this.popup === popup) return; if (this.popup != null) { this.popup.dispose(); } popup.addListener('show', utils.bind(this._onPopupShow, this)); popup.addListener('hide', utils.bind(this._onPopupHide, this)); popup.addListener('postrender', utils.bind(function () { popup.getDom('body').appendChild( uiUtils.createElementByHtml('
') ); popup.getDom().className += ' ' + this.className; }, this)); this.popup = popup; }, _onPopupShow: function () { this.addState('opened'); }, _onPopupHide: function () { this.removeState('opened'); }, getHtmlTpl: function () { return '
' + '
' + '
' + '
' + '
' + '
' + '
' + '
'; }, showPopup: function () { // 当popup往上弹出的时候,做特殊处理 var rect = uiUtils.getClientRect(this.getDom()); rect.top -= this.popup.SHADOW_RADIUS; rect.height += this.popup.SHADOW_RADIUS; this.popup.showAnchorRect(rect); }, _onArrowClick: function (event, el) { if (!this.isDisabled()) { this.showPopup(); } }, _onButtonClick: function () { if (!this.isDisabled()) { this.fireEvent('buttonclick'); } } }; utils.inherits(SplitButton, UIBase); utils.extend(SplitButton.prototype, Stateful, true); })(); ///import core ///import uicore ///import ui/colorpicker.js ///import ui/popup.js ///import ui/splitbutton.js (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, ColorPicker = baidu.editor.ui.ColorPicker, Popup = baidu.editor.ui.Popup, SplitButton = baidu.editor.ui.SplitButton, ColorButton = baidu.editor.ui.ColorButton = function (options) { this.initOptions(options); this.initColorButton(); }; ColorButton.prototype = { initColorButton: function () { var me = this; this.popup = new Popup({ content: new ColorPicker({ noColorText: me.editor.getLang("clearColor"), editor: me.editor, onpickcolor: function (t, color) { me._onPickColor(color); }, onpicknocolor: function (t, color) { me._onPickNoColor(color); } }), editor: me.editor }); this.initSplitButton(); }, _SplitButton_postRender: SplitButton.prototype.postRender, postRender: function () { this._SplitButton_postRender(); this.getDom('button_body').appendChild( uiUtils.createElementByHtml('
') ); this.getDom().className += ' edui-colorbutton'; }, setColor: function (color) { this.getDom('colorlump').style.backgroundColor = color; this.color = color; }, _onPickColor: function (color) { if (this.fireEvent('pickcolor', color) !== false) { this.setColor(color); this.popup.hide(); } }, _onPickNoColor: function (color) { if (this.fireEvent('picknocolor') !== false) { this.popup.hide(); } } }; utils.inherits(ColorButton, SplitButton); })(); ///import core ///import uicore ///import ui/popup.js ///import ui/tablepicker.js ///import ui/splitbutton.js (function () { var utils = baidu.editor.utils, Popup = baidu.editor.ui.Popup, TablePicker = baidu.editor.ui.TablePicker, SplitButton = baidu.editor.ui.SplitButton, TableButton = baidu.editor.ui.TableButton = function (options) { this.initOptions(options); this.initTableButton(); }; TableButton.prototype = { initTableButton: function () { var me = this; this.popup = new Popup({ content: new TablePicker({ editor: me.editor, onpicktable: function (t, numCols, numRows) { me._onPickTable(numCols, numRows); } }), 'editor': me.editor }); this.initSplitButton(); }, _onPickTable: function (numCols, numRows) { if (this.fireEvent('picktable', numCols, numRows) !== false) { this.popup.hide(); } } }; utils.inherits(TableButton, SplitButton); })(); ///import core ///import uicore (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase; var AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker = function (options) { this.initOptions(options); this.initAutoTypeSetPicker(); }; AutoTypeSetPicker.prototype = { initAutoTypeSetPicker: function () { this.initUIBase(); }, getHtmlTpl: function () { var me = this.editor, opt = me.options.autotypeset, lang = me.getLang("autoTypeSet"); 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 + '
' + '
' + '
'; }, _UIBase_render: UIBase.prototype.render }; utils.inherits(AutoTypeSetPicker, UIBase); })(); ///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 = me.editor.options.autotypeset, cont = me.getDom(), ipts = domUtils.getElementsByTagName(cont, "input"); for (var i = ipts.length - 1, ipt; ipt = ipts[i--];) { if (ipt.getAttribute("type") == "checkbox") { var attrName = ipt.getAttribute("name"); opt[attrName] && delete opt[attrName]; if (ipt.checked) { var attrValue = document.getElementById(attrName + "Value"); 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; } } } } 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.editor.options.autotypeset = opt; } AutoTypeSetButton.prototype = { initAutoTypeSetButton: function () { var me = this; this.popup = new Popup({ //传入配置参数 content: new AutoTypeSetPicker({editor: me.editor}), 'editor': me.editor, hide: function () { if (!this._hidden && this.getDom()) { getPara(this); this.getDom().style.display = 'none'; this._hidden = true; this.fireEvent('hide'); } } }); var flag = 0; this.popup.addListener('postRenderAfter', function () { var popupUI = this; if (flag)return; var cont = this.getDom(), btn = cont.getElementsByTagName('button')[0]; btn.onclick = function () { getPara(popupUI); me.editor.execCommand('autotypeset'); popupUI.hide() }; flag = 1; }); this.initSplitButton(); } }; utils.inherits(AutoTypeSetButton, SplitButton); })(); ///import core ///import uicore (function () { var utils = baidu.editor.utils, Popup = baidu.editor.ui.Popup, Stateful = baidu.editor.ui.Stateful, UIBase = baidu.editor.ui.UIBase; var CellAlignPicker = baidu.editor.ui.CellAlignPicker = function (options) { this.initOptions(options); this.initCellAlignPicker(); }; CellAlignPicker.prototype = { initCellAlignPicker: function () { this.initUIBase(); this.Stateful_init(); }, getHtmlTpl: function () { return '
' + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + '
' + '
'; }, getStateDom: function () { return this.target; }, _onClick: function (evt) { var target = evt.target || evt.srcElement; if (/icon/.test(target.className)) { this.items[target.parentNode.getAttribute("index")].onclick(); Popup.postHide(evt); } }, _UIBase_render: UIBase.prototype.render }; utils.inherits(CellAlignPicker, UIBase); utils.extend(CellAlignPicker.prototype, Stateful, true); })(); ///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); })(); (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) { this.items.push(item); }, getHtmlTpl: function () { var buff = []; for (var i = 0; i < this.items.length; i++) { buff[i] = this.items[i].renderHtml(); } return '
' + buff.join('') + '
' }, postRender: function () { var box = this.getDom(); for (var i = 0; i < this.items.length; i++) { this.items[i].postRender(); } uiUtils.makeUnselectable(box); }, _onMouseDown: function () { return false; } }; utils.inherits(Toolbar, UIBase); })(); ///import core ///import uicore ///import ui\popup.js ///import ui\stateful.js (function () { var utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils, uiUtils = baidu.editor.ui.uiUtils, UIBase = baidu.editor.ui.UIBase, Popup = baidu.editor.ui.Popup, Stateful = baidu.editor.ui.Stateful, CellAlignPicker = baidu.editor.ui.CellAlignPicker, Menu = baidu.editor.ui.Menu = function (options) { this.initOptions(options); this.initMenu(); }; var menuSeparator = { renderHtml: function () { return '
'; }, postRender: function () { }, queryAutoHide: function () { return true; } }; Menu.prototype = { items: null, uiName: 'menu', initMenu: function () { this.items = this.items || []; this.initPopup(); this.initItems(); }, initItems: function () { for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; if (item == '-') { this.items[i] = this.getSeparator(); } else if (!(item instanceof MenuItem)) { item.editor = this.editor; item.theme = this.editor.options.theme; this.items[i] = this.createItem(item); } } }, getSeparator: function () { return menuSeparator; }, createItem: function (item) { return new MenuItem(item); }, _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl, getContentHtmlTpl: function () { if (this.items.length == 0) { return this._Popup_getContentHtmlTpl(); } var buff = []; for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; buff[i] = item.renderHtml(); } return ('
' + buff.join('') + '
'); }, _Popup_postRender: Popup.prototype.postRender, postRender: function () { var me = this; for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; item.ownerMenu = this; item.postRender(); } domUtils.on(this.getDom(), 'mouseover', function (evt) { evt = evt || event; var rel = evt.relatedTarget || evt.fromElement; var el = me.getDom(); if (!uiUtils.contains(el, rel) && el !== rel) { me.fireEvent('over'); } }); this._Popup_postRender(); }, queryAutoHide: function (el) { if (el) { if (uiUtils.contains(this.getDom(), el)) { return false; } for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; if (item.queryAutoHide(el) === false) { return false; } } } }, clearItems: function () { for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; clearTimeout(item._showingTimer); clearTimeout(item._closingTimer); if (item.subMenu) { item.subMenu.destroy(); } } this.items = []; }, destroy: function () { if (this.getDom()) { domUtils.remove(this.getDom()); } this.clearItems(); }, dispose: function () { this.destroy(); } }; utils.inherits(Menu, Popup); 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 = new Popup({ content: new CellAlignPicker(this.subMenu), parentMenu: me, editor: me.editor, destroy: function () { if (this.getDom()) { domUtils.remove(this.getDom()); } } }); this.subMenu.addListener("postRenderAfter", function () { domUtils.on(this.getDom(), "mouseover", function () { me.addState('opened'); }); }); } else { this.subMenu = new Menu(this.subMenu); } } }; MenuItem.prototype = { label: '', subMenu: null, ownerMenu: null, uiName: 'menuitem', alwalysHoverable: true, getHtmlTpl: function () { return '
' + '
' + this.renderLabelHtml() + '
' + '
'; }, postRender: function () { var me = this; this.addListener('over', function () { me.ownerMenu.fireEvent('submenuover', me); if (me.subMenu) { me.delayShowSubMenu(); } }); if (this.subMenu) { this.getDom().className += ' edui-hassubmenu'; this.subMenu.render(); this.addListener('out', function () { me.delayHideSubMenu(); }); this.subMenu.addListener('over', function () { clearTimeout(me._closingTimer); me._closingTimer = null; me.addState('opened'); }); this.ownerMenu.addListener('hide', function () { me.hideSubMenu(); }); this.ownerMenu.addListener('submenuover', function (t, subMenu) { if (subMenu !== me) { me.delayHideSubMenu(); } }); this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide; this.subMenu.queryAutoHide = function (el) { if (el && uiUtils.contains(me.getDom(), el)) { return false; } return this._bakQueryAutoHide(el); }; } this.getDom().style.tabIndex = '-1'; uiUtils.makeUnselectable(this.getDom()); this.Stateful_postRender(); }, delayShowSubMenu: function () { var me = this; if (!me.isDisabled()) { me.addState('opened'); clearTimeout(me._showingTimer); clearTimeout(me._closingTimer); me._closingTimer = null; me._showingTimer = setTimeout(function () { me.showSubMenu(); }, 250); } }, delayHideSubMenu: function () { var me = this; if (!me.isDisabled()) { me.removeState('opened'); clearTimeout(me._showingTimer); if (!me._closingTimer) { me._closingTimer = setTimeout(function () { if (!me.hasState('opened')) { me.hideSubMenu(); } me._closingTimer = null; }, 400); } } }, renderLabelHtml: function () { return '
' + '
' + '
' + (this.label || '') + '
'; }, getStateDom: function () { return this.getDom(); }, queryAutoHide: function (el) { if (this.subMenu && this.hasState('opened')) { return this.subMenu.queryAutoHide(el); } }, _onClick: function (event, this_) { if (this.hasState('disabled')) return; if (this.fireEvent('click', event, this_) !== false) { if (this.subMenu) { this.showSubMenu(); } else { Popup.postHide(event); } } }, showSubMenu: function () { var rect = uiUtils.getClientRect(this.getDom()); rect.right -= 5; rect.left += 2; rect.width -= 7; rect.top -= 4; rect.bottom += 4; rect.height += 8; this.subMenu.showAnchorRect(rect, true, true); }, hideSubMenu: function () { this.subMenu.hide(); } }; utils.inherits(MenuItem, UIBase); utils.extend(MenuItem.prototype, Stateful, true); })(); ///import core ///import uicore ///import ui/menu.js ///import ui/splitbutton.js (function () { // todo: menu和item提成通用list var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, Menu = baidu.editor.ui.Menu, SplitButton = baidu.editor.ui.SplitButton, Combox = baidu.editor.ui.Combox = function (options) { this.initOptions(options); this.initCombox(); }; Combox.prototype = { uiName: 'combox', initCombox: function () { var me = this; this.items = this.items || []; for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; item.uiName = 'listitem'; item.index = i; item.onclick = function () { me.selectByIndex(this.index); }; } this.popup = new Menu({ items: this.items, uiName: 'list', editor: this.editor }); this.initSplitButton(); }, _SplitButton_postRender: SplitButton.prototype.postRender, postRender: function () { this._SplitButton_postRender(); this.setLabel(this.label || ''); this.setValue(this.initValue || ''); }, showPopup: function () { var rect = uiUtils.getClientRect(this.getDom()); rect.top += 1; rect.bottom -= 1; rect.height -= 2; this.popup.showAnchorRect(rect); }, getValue: function () { return this.value; }, setValue: function (value) { var index = this.indexByValue(value); if (index != -1) { this.selectedIndex = index; this.setLabel(this.items[index].label); this.value = this.items[index].value; } else { this.selectedIndex = -1; this.setLabel(this.getLabelForUnknowValue(value)); this.value = value; } }, setLabel: function (label) { this.getDom('button_body').innerHTML = label; this.label = label; }, getLabelForUnknowValue: function (value) { return value; }, indexByValue: function (value) { for (var i = 0; i < this.items.length; i++) { if (value == this.items[i].value) { return i; } } return -1; }, getItem: function (index) { return this.items[index]; }, selectByIndex: function (index) { if (index < this.items.length && this.fireEvent('select', index) !== false) { this.selectedIndex = index; this.value = this.items[index].value; this.setLabel(this.items[index].label); } } }; utils.inherits(Combox, SplitButton); })(); ///import core ///import uicore ///import ui/mask.js ///import ui/button.js (function () { var utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils, uiUtils = baidu.editor.ui.uiUtils, Mask = baidu.editor.ui.Mask, UIBase = baidu.editor.ui.UIBase, Button = baidu.editor.ui.Button, Dialog = baidu.editor.ui.Dialog = function (options) { this.initOptions(utils.extend({ autoReset: true, draggable: true, onok: function () { }, oncancel: function () { }, onclose: function (t, ok) { return ok ? this.onok() : this.oncancel(); } }, options)); this.initDialog(); }; var modalMask; var dragMask; Dialog.prototype = { draggable: false, uiName: 'dialog', initDialog: function () { var me = this, theme = this.editor.options.theme; this.initUIBase(); this.modalMask = (modalMask || (modalMask = new Mask({ className: 'edui-dialog-modalmask', theme: theme }))); this.dragMask = (dragMask || (dragMask = new Mask({ className: 'edui-dialog-dragmask', theme: theme }))); this.closeButton = new Button({ className: 'edui-dialog-closebutton', title: me.closeDialog, theme: theme, onclick: function () { me.close(false); } }); if (this.buttons) { for (var i = 0; i < this.buttons.length; i++) { if (!(this.buttons[i] instanceof Button)) { this.buttons[i] = new Button(this.buttons[i]); } } } }, 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 () { this.getDom().style.display = ''; var vpRect = uiUtils.getViewportRect(); 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'; } this._show(); }, getContentHtml: function () { var contentHtml = ''; if (typeof this.content == 'string') { contentHtml = this.content; } else if (this.iframeUrl) { contentHtml = ''; } return contentHtml; }, getHtmlTpl: function () { var footHtml = ''; if (this.buttons) { var buff = []; for (var i = 0; i < this.buttons.length; i++) { buff[i] = this.buttons[i].renderHtml(); } footHtml = '
' + '
' + buff.join('') + '
' + '
'; } return '
' + '
' + '
' + '
' + '' + (this.title || '') + '' + '
' + this.closeButton.renderHtml() + '
' + '
' + ( this.autoReset ? '' : this.getContentHtml()) + '
' + footHtml + '
'; }, postRender: function () { // todo: 保持居中/记住上次关闭位置选项 if (!this.modalMask.getDom()) { this.modalMask.render(); this.modalMask.hide(); } if (!this.dragMask.getDom()) { this.dragMask.render(); this.dragMask.hide(); } var me = this; this.addListener('show', function () { me.modalMask.show(this.getDom().style.zIndex - 2); }); this.addListener('hide', function () { me.modalMask.hide(); }); if (this.buttons) { for (var i = 0; i < this.buttons.length; i++) { this.buttons[i].postRender(); } } domUtils.on(window, 'resize', function () { setTimeout(function () { if (!me.isHidden()) { me.safeSetOffset(uiUtils.getClientRect(me.getDom())); } }); }); this._hide(); }, mesureSize: function () { var body = this.getDom('body'); var width = uiUtils.getClientRect(this.getDom('content')).width; var dialogBodyStyle = body.style; dialogBodyStyle.width = width; return uiUtils.getClientRect(body); }, _onTitlebarMouseDown: function (evt, el) { if (this.draggable) { var rect; var vpRect = uiUtils.getViewportRect(); var me = this; uiUtils.startDrag(evt, { ondragstart: function () { rect = uiUtils.getClientRect(me.getDom()); me.getDom('contmask').style.visibility = 'visible'; me.dragMask.show(me.getDom().style.zIndex - 1); }, ondragmove: function (x, y) { var left = rect.left + x; var top = rect.top + y; me.safeSetOffset({ left: left, top: top }); }, ondragstop: function () { me.getDom('contmask').style.visibility = 'hidden'; domUtils.removeClasses(me.getDom(), ['edui-state-centered']); me.dragMask.hide(); } }); } }, reset: function () { this.getDom('content').innerHTML = this.getContentHtml(); }, _show: function () { if (this._hidden) { this.getDom().style.display = ''; //要高过编辑器的zindxe this.editor.container.style.zIndex && (this.getDom().style.zIndex = this.editor.container.style.zIndex * 1 + 10); this._hidden = false; this.fireEvent('show'); baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = this.getDom().style.zIndex - 4; } }, isHidden: function () { return this._hidden; }, _hide: function () { if (!this._hidden) { this.getDom().style.display = 'none'; this.getDom().style.zIndex = ''; 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) { } } }, _onCloseButtonClick: function (evt, el) { this.close(false); }, close: function (ok) { if (this.fireEvent('close', ok) !== false) { this._hide(); } } }; utils.inherits(Dialog, UIBase); })(); ///import core ///import uicore ///import ui/menu.js ///import ui/splitbutton.js (function () { var utils = baidu.editor.utils, Menu = baidu.editor.ui.Menu, SplitButton = baidu.editor.ui.SplitButton, MenuButton = baidu.editor.ui.MenuButton = function (options) { this.initOptions(options); this.initMenuButton(); }; MenuButton.prototype = { initMenuButton: function () { var me = this; this.uiName = "menubutton"; this.popup = new Menu({ items: me.items, className: me.className, editor: me.editor }); this.popup.addListener('show', function () { var list = this; for (var i = 0; i < list.items.length; i++) { list.items[i].removeState('checked'); if (list.items[i].value == me._value) { list.items[i].addState('checked'); this.value = me._value; } } }); this.initSplitButton(); }, setValue: function (value) { this._value = value; } }; utils.inherits(MenuButton, SplitButton); })(); //ui跟编辑器的适配層 //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置 //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据editor_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': '<%= UeditorRails::Engine.routes.url_helpers.dialogs_image_path %>', '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', 'highlightcode': '~/dialogs/highlightcode/highlightcode.html', 'emotion': '~/dialogs/emotion/emotion.html', 'wordimage': '<%= UeditorRails::Engine.routes.url_helpers.dialogs_wordimage_path %>', 'attachment': '<%= UeditorRails::Engine.routes.url_helpers.dialogs_attachment_path %>', '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': '<%= UeditorRails::Engine.routes.url_helpers.dialogs_scrawl_path %>', 'music': '~/dialogs/music/music.html', 'template': '~/dialogs/template/template.html', 'background': '~/dialogs/background/background.html' }; //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起 var btnCmds = ['undo', 'redo', 'formatmatch', 'bold', 'italic', 'underline', 'touppercase', 'tolowercase', 'strikethrough', 'subscript', 'superscript', 'source', 'indent', 'outdent', 'blockquote', 'pasteplain', 'pagebreak', 'selectall', 'print', 'preview', 'horizontal', 'removeformat', 'time', 'date', 'unlink', 'insertparagraphbeforetable', 'insertrow', 'insertcol', 'mergeright', 'mergedown', 'deleterow', 'deletecol', 'splittorows', 'splittocols', 'splittocells', 'mergecells', 'deletetable']; 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'], ok: ['attachment', 'anchor', 'link', 'insertimage', 'map', 'gmap', 'insertframe', 'wordimage', 'insertvideo', 'highlightcode', 'insertframe', 'edittip', 'edittable', 'edittd', 'scrawl', 'template', 'music', 'background'] }; 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, 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": editor.execCommand("wordimage", "word_img"); if (editor.word_img) { 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 }); 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.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 ui = new editorui.MultiMenuPop({ title: editor.options.labelMap['emotion'] || editor.getLang("labelMap.emotion") || '', editor: editor, className: 'edui-for-emotion', iframeUrl: editor.ui.mapUrl(iframeUrl || (editor.options.iframeUrlMap || {})['emotion'] || iframeUrlMap['emotion']) }); editorui.buttons['emotion'] = ui; editor.addListener('selectionchange', function () { ui.setDisabled(editor.queryCommandState('emotion') == -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; }; })(); ///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; //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); }); 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; 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)) { var span = domUtils.createElement(editor.document, 'span', { 'style': "line-height:0px;", 'innerHTML': '\ufeff' }), range = editor.selection.getRange(); range.insertNode(span); pastePop.showAnchor(span); domUtils.remove(span); 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 () { editor._iframe = popup.anchorEl; 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) { 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 (!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('data_ue_src') || 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 (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; } this.toolbars = toolbarUis; }, getHtmlTpl: function () { return '
' + '
' + (this.toolbars.length ? '
' + this.renderToolbarBoxHtml() + '
' : '') + '' + '
' + '
' + //modify wdcount by matao '
' + '' + '' + '' + '
' + '
' + '
'; }, showWordImageDialog: function () { this.editor.execCommand("wordimage", "word_img"); 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); if (this._bakAutoHeight) { //当全屏时不能执行自动长高 editor.autoHeightEnabled = false; this.editor.disableAutoHeight(); } document.documentElement.style.overflow = 'hidden'; document.body.style.overflow = 'hidden'; this._bakCssText = this.getDom().style.cssText; this._bakCssText1 = this.getDom('iframeholder').style.cssText; 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; window.scrollTo(0, this._bakScrollTop); } if (baidu.editor.browser.gecko) { var input = document.createElement('input'); document.body.appendChild(input); editor.body.contentEditable = false; setTimeout(function () { input.focus(); setTimeout(function () { editor.body.contentEditable = true; editor.selection.getRange().moveToBookmark(bk).select(true); baidu.editor.dom.domUtils.remove(input); fullscreen && window.scroll(0, 0); }, 0) }, 0) } 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)); } }, _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); } 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 baidu.editor.Editor(options); editor.options.editor = editor; utils.loadFile(document, { href: editor.options.themePath + editor.options.theme + "/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); holder.id && (newDiv.id = holder.id); } holder = newDiv; holder.innerHTML = ''; } } domUtils.addClass(holder, "edui-" + editor.options.theme); editor.ui.render(holder); var iframeholder = editor.ui.getDom('iframeholder'); //给实例添加一个编辑器的容器引用 editor.container = editor.ui.getDom(); var width = editor.options.initialFrameWidth; if (!/%/g.test(width)) width += "px"; editor.container.style.cssText = "z-index:" + editor.options.zIndex + ";width:" + width; oldRender.call(editor, iframeholder); } }) }; 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] } } })(); ///import core ///import uicore ///commands 表情 (function () { var utils = baidu.editor.utils, Popup = baidu.editor.ui.Popup, SplitButton = baidu.editor.ui.SplitButton, MultiMenuPop = baidu.editor.ui.MultiMenuPop = function (options) { this.initOptions(options); this.initMultiMenu(); }; MultiMenuPop.prototype = { initMultiMenu: function () { var me = this; this.popup = new Popup({ content: '', editor: me.editor, iframe_rendered: false, onshow: function () { if (!this.iframe_rendered) { this.iframe_rendered = true; this.getDom('content').innerHTML = ''; me.editor.container.style.zIndex && (this.getDom().style.zIndex = me.editor.container.style.zIndex * 1 + 1); } } // canSideUp:false, // canSideLeft:false }); this.onbuttonclick = function () { this.showPopup(); }; this.initSplitButton(); } }; utils.inherits(MultiMenuPop, SplitButton); })(); })();