UEDITOR_CONFIG = window.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] = [] ) ) ); } /** * @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 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 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 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 || {}),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 ) { 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{ 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().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 ); })(); /* * 处理特殊键的兼容性问题 */ 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 ///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(); } } } }); }; ///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 ///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); } ); }); }); }; })(); 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'; } }; 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':'')+''; } 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' + buff.join('') + '' }, postRender: function (){ var box = this.getDom(); for (var i=0; i
'; }, 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 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' + 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.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 + "/css/ueditor.css", tag:"link", type:"text/css", rel:"stylesheet" }); var oldRender = editor.render; editor.render = function (holder) { if (holder.constructor === String) { editor.key = holder; instances[holder] = editor; } utils.domReady(function () { editor.langIsReady ? renderUI() : editor.addListener("langReady", renderUI); function renderUI() { editor.setOpt({ labelMap:editor.options.labelMap || editor.getLang('labelMap') }); new EditorUI(editor.options); if (holder) { if (holder.constructor === String) { holder = document.getElementById(holder); } holder && holder.getAttribute('name') && ( editor.options.textarea = holder.getAttribute('name')); if (holder && /script|textarea/ig.test(holder.tagName)) { var newDiv = document.createElement('div'); holder.parentNode.insertBefore(newDiv, holder); var cont = holder.value || holder.innerHTML; editor.options.initialContent = /^[\t\r\n ]*$/.test(cont) ? editor.options.initialContent : cont.replace(/>[\n\r\t]+([ ]{4})+/g, '>') .replace(/[\n\r\t]+([ ]{4})+[\n\r\t]+<'); holder.className && (newDiv.className = holder.className); holder.style.cssText && (newDiv.style.cssText = holder.style.cssText); if (/textarea/i.test(holder.tagName)) { editor.textarea = holder; editor.textarea.style.display = 'none'; } else { holder.parentNode.removeChild(holder); 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); })(); ///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
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 ///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 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 () { 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{ rng.moveToAddress(restoreAddress).select(true); }catch(e){} return { address:rngAddress, content:cont } }; this.save = function (notCompareRange) { var currentScene = this.getScene(), 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); 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(); me.undoManger.mousedown = false; } } }); me.addListener('mousedown',function(){ me.undoManger.mousedown = true; }) }; ///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 /** * @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 ///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 ///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
'+this.getContent(null,null,true)+'
'); d.close(); }, notNeedUndo : 1 }; ///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 ///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 为非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 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 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 ///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 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 ///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); } } };