/*! * UEditor * version: ueditor * build: Wed Aug 10 2016 11:06:16 GMT+0800 (CST) */ var isOneFile = true; //发通知那边用,记录单次是否只上传(拖拽)一个文件 (function () { // editor.js UEDITOR_CONFIG = window.UEDITOR_CONFIG || {}; var baidu = window.baidu || {}; window.baidu = baidu; window.UE = baidu.editor = window.UE || {}; UE.plugins = {}; UE.commands = {}; UE.instants = {}; UE.I18N = {}; UE._customizeUI = {}; UE.XTSendData = []; UE.version = "1.4.3"; UE.account = {}; UE.addressList = []; UE.lastTime = { "time": 0 }; UE.isSendEnter = false; UE.isSendDelete = false; UE.isDeleteAll = false; //UE.deleteReturn = false; var dom = UE.dom = {}; //复制表格用到的变量 var tableCopyList, isFullCol, isFullRow; //特殊字符 var inputkeycodes = ['BracketLeft', 'BracketRight', 'Backquote', 'Minus', 'Equal', 'Backslash', 'Semicolon', 'Quote', 'Comma', 'Period', 'Slash']; var inputType = false;//判断输入法输入状态 //判断是否是在发通知页面 var isNotice = window.location.host == 'notice.chaoxing.com'; var myLoadingId = ''; //发通知那边用,当标题为空时记录第一个上传的附件 //视频附件后缀 var videoReg = new RegExp(/mp4|3gp|avi|rmvb|asf|divx|mpg|mpeg|mpe|mkv|vob|flv|m4v|mov|f4v|wmv/) function RMap() { this.elements = new Array(); //向MAP中增加元素(key, value) this.put = function (_key, _value) { this.removeByKey(_key); this.elements.push({ key: _key, value: _value }); }; //获取指定KEY的元素值VALUE,失败返回NULL this.get = function (_key) { try { for (i = 0; i < this.elements.length; i++) { if (this.elements[i].key == _key) { return this.elements[i].value; } } } catch (e) { return false; } return false; }; //删除指定KEY的元素,成功返回True,失败返回False this.removeByKey = function (_key) { var bln = false; try { for (i = 0; i < this.elements.length; i++) { if (this.elements[i].key == _key) { this.elements.splice(i, 1); return true; } } } catch (e) { bln = false; } return bln; }; } // core/browser.js /** * 浏览器判断模块 * @file * @module UE.browser * @since 1.2.6.1RichTextUitl.puid */ /** * 提供浏览器检测的模块 * @unfile * @module UE.browser */ var browser = UE.browser = function () { var agent = navigator.userAgent.toLowerCase(), opera = window.opera, browser = { /** * @property {boolean} ie 检测当前浏览器是否为IE * @example * ```javascript * if ( UE.browser.ie ) { * console.log( '当前浏览器是IE' ); * } * ``` */ ie: /(msie\s|trident.*rv:)([\w.]+)/.test(agent), /** * @property {boolean} opera 检测当前浏览器是否为Opera * @example * ```javascript * if ( UE.browser.opera ) { * console.log( '当前浏览器是Opera' ); * } * ``` */ opera: (!!opera && opera.version), /** * @property {boolean} firefox 检测当前浏览器是否为Firefox * @example * ```javascript * if ( UE.browser.firefox ) { * console.log( '当前浏览器是Firefox' ); * } * ``` */ firefox: (agent.indexOf("firefox") > -1), /** * @property {boolean} webkit 检测当前浏览器是否是webkit内核的浏览器 * @example * ```javascript * if ( UE.browser.webkit ) { * console.log( '当前浏览器是webkit内核浏览器' ); * } * ``` */ webkit: (agent.indexOf(' applewebkit/') > -1), /** * @property {boolean} mac 检测当前浏览器是否是运行在mac平台下 * @example * ```javascript * if ( UE.browser.mac ) { * console.log( '当前浏览器运行在mac平台下' ); * } * ``` */ mac: (agent.indexOf('macintosh') > -1), /** * @property {boolean} quirks 检测当前浏览器是否处于“怪异模式”下 * @example * ```javascript * if ( UE.browser.quirks ) { * console.log( '当前浏览器运行处于“怪异模式”' ); * } * ``` */ quirks: (document.compatMode == 'BackCompat') }; /** * @property {boolean} gecko 检测当前浏览器内核是否是gecko内核 * @example * ```javascript * if ( UE.browser.gecko ) { * console.log( '当前浏览器内核是gecko内核' ); * } * ``` */ browser.gecko = (navigator.product == 'Gecko' && !browser.webkit && !browser.opera && !browser.ie); var version = 0; // Internet Explorer 6.0+ if (browser.ie) { var v1 = agent.match(/(?:msie\s([\w.]+))/); var v2 = agent.match(/(?:trident.*rv:([\w.]+))/); if (v1 && v2 && v1[1] && v2[1]) { version = Math.max(v1[1] * 1, v2[1] * 1); } else if (v1 && v1[1]) { version = v1[1] * 1; } else if (v2 && v2[1]) { version = v2[1] * 1; } else { version = 0; } browser.ie11Compat = document.documentMode == 11; /** * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式 * @warning 如果浏览器不是IE, 则该值为undefined * @example * ```javascript * if ( UE.browser.ie9Compat ) { * console.log( '当前浏览器运行在IE9兼容模式下' ); * } * ``` */ browser.ie9Compat = document.documentMode == 9; /** * @property { boolean } ie8 检测浏览器是否是IE8浏览器 * @warning 如果浏览器不是IE, 则该值为undefined * @example * ```javascript * if ( UE.browser.ie8 ) { * console.log( '当前浏览器是IE8浏览器' ); * } * ``` */ browser.ie8 = !!document.documentMode; /** * @property { boolean } ie8Compat 检测浏览器模式是否为 IE8 兼容模式 * @warning 如果浏览器不是IE, 则该值为undefined * @example * ```javascript * if ( UE.browser.ie8Compat ) { * console.log( '当前浏览器运行在IE8兼容模式下' ); * } * ``` */ browser.ie8Compat = document.documentMode == 8; /** * @property { boolean } ie7Compat 检测浏览器模式是否为 IE7 兼容模式 * @warning 如果浏览器不是IE, 则该值为undefined * @example * ```javascript * if ( UE.browser.ie7Compat ) { * console.log( '当前浏览器运行在IE7兼容模式下' ); * } * ``` */ browser.ie7Compat = ((version == 7 && !document.documentMode) || document.documentMode == 7); /** * @property { boolean } ie6Compat 检测浏览器模式是否为 IE6 模式 或者怪异模式 * @warning 如果浏览器不是IE, 则该值为undefined * @example * ```javascript * if ( UE.browser.ie6Compat ) { * console.log( '当前浏览器运行在IE6模式或者怪异模式下' ); * } * ``` */ browser.ie6Compat = (version < 7 || browser.quirks); browser.ie9above = version > 8; browser.ie9below = version < 9; browser.ie11above = version > 10; browser.ie11below = version < 11; } // 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; } } /** * @property { Number } chrome 检测当前浏览器是否为Chrome, 如果是,则返回Chrome的大版本号 * @warning 如果浏览器不是chrome, 则该值为undefined * @example * ```javascript * if ( UE.browser.chrome ) { * console.log( '当前浏览器是Chrome' ); * } * ``` */ if (/chrome\/(\d+\.\d)/i.test(agent)) { browser.chrome = +RegExp['\x241']; } /** * @property { Number } safari 检测当前浏览器是否为Safari, 如果是,则返回Safari的大版本号 * @warning 如果浏览器不是safari, 则该值为undefined * @example * ```javascript * if ( UE.browser.safari ) { * console.log( '当前浏览器是Safari' ); * } * ``` */ 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]); /** * @property { Number } version 检测当前浏览器版本号 * @remind * * @example * ```javascript * console.log( '当前浏览器版本号是: ' + UE.browser.version ); * ``` */ browser.version = version; /** * @property { boolean } isCompatible 检测当前浏览器是否能够与UEditor良好兼容 * @example * ```javascript * if ( UE.browser.isCompatible ) { * console.log( '浏览器与UEditor能够良好兼容' ); * } * ``` */ 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; // core/utils.js /** * 工具函数包 * @file * @module UE.utils * @since 1.2.6.1 */ /** * UEditor封装使用的静态工具函数 * @module UE.utils * @unfile */ var utils = UE.utils = { /** * 用给定的迭代器遍历对象 * @method each * @param { Object } obj 需要遍历的对象 * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key * @example * ```javascript * var demoObj = { * key1: 1, * key2: 2 * }; * * //output: key1: 1, key2: 2 * UE.utils.each( demoObj, funciton ( value, key ) { * * console.log( key + ":" + value ); * * } ); * ``` */ /** * 用给定的迭代器遍历数组或类数组对象 * @method each * @param { Array } array 需要遍历的数组或者类数组 * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key * @example * ```javascript * var divs = document.getElmentByTagNames( "div" ); * * //output: 0: DIV, 1: DIV ... * UE.utils.each( divs, funciton ( value, key ) { * * console.log( key + ":" + value.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; } } } }, /** * 以给定对象作为原型创建一个新对象 * @method makeInstance * @param { Object } protoObject 该对象将作为新创建对象的原型 * @return { Object } 新的对象, 该对象的原型是给定的protoObject对象 * @example * ```javascript * * var protoObject = { sayHello: function () { console.log('Hello UEditor!'); } }; * * var newObject = UE.utils.makeInstance( protoObject ); * //output: Hello UEditor! * newObject.sayHello(); * ``` */ makeInstance: function (obj) { var noop = new Function(); noop.prototype = obj; obj = new noop; noop.prototype = null; return obj; }, /** * 将source对象中的属性扩展到target对象上 * @method extend * @remind 该方法将强制把source对象上的属性复制到target对象上 * @see UE.utils.extend(Object,Object,Boolean) * @param { Object } target 目标对象, 新的属性将附加到该对象上 * @param { Object } source 源对象, 该对象的属性会被附加到target对象上 * @return { Object } 返回target对象 * @example * ```javascript * * var target = { name: 'target', sex: 1 }, * source = { name: 'source', age: 17 }; * * UE.utils.extend( target, source ); * * //output: { name: 'source', sex: 1, age: 17 } * console.log( target ); * * ``` */ /** * 将source对象中的属性扩展到target对象上, 根据指定的isKeepTarget值决定是否保留目标对象中与 * 源对象属性名相同的属性值。 * @method extend * @param { Object } target 目标对象, 新的属性将附加到该对象上 * @param { Object } source 源对象, 该对象的属性会被附加到target对象上 * @param { Boolean } isKeepTarget 是否保留目标对象中与源对象中属性名相同的属性 * @return { Object } 返回target对象 * @example * ```javascript * * var target = { name: 'target', sex: 1 }, * source = { name: 'source', age: 17 }; * * UE.utils.extend( target, source, true ); * * //output: { name: 'target', sex: 1, age: 17 } * console.log( target ); * * ``` */ extend: function (t, s, b) { if (s) { for (var k in s) { if (!b || !t.hasOwnProperty(k)) { t[k] = s[k]; } } } return t; }, /** * 将给定的多个对象的属性复制到目标对象target上 * @method extend2 * @remind 该方法将强制把源对象上的属性复制到target对象上 * @remind 该方法支持两个及以上的参数, 从第二个参数开始, 其属性都会被复制到第一个参数上。 如果遇到同名的属性, * 将会覆盖掉之前的值。 * @param { Object } target 目标对象, 新的属性将附加到该对象上 * @param { Object... } source 源对象, 支持多个对象, 该对象的属性会被附加到target对象上 * @return { Object } 返回target对象 * @example * ```javascript * * var target = {}, * source1 = { name: 'source', age: 17 }, * source2 = { title: 'dev' }; * * UE.utils.extend2( target, source1, source2 ); * * //output: { name: 'source', age: 17, title: 'dev' } * console.log( target ); * * ``` */ extend2: function (t) { var a = arguments; for (var i = 1; i < a.length; i++) { var x = a[i]; for (var k in x) { if (!t.hasOwnProperty(k)) { t[k] = x[k]; } } } return t; }, /** * 模拟继承机制, 使得subClass继承自superClass * @method inherits * @param { Object } subClass 子类对象 * @param { Object } superClass 超类对象 * @warning 该方法只能让subClass继承超类的原型, subClass对象自身的属性和方法不会被继承 * @return { Object } 继承superClass后的子类对象 * @example * ```javascript * 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(); * //output: '小张早上好! * 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的上下文 * @method bind * @param { Function } fn 需要绑定上下文的函数对象 * @param { Object } content 函数fn新的上下文对象 * @return { Function } 一个新的函数, 该函数作为原始函数fn的代理, 将完成fn的上下文调换工作。 * @example * ```javascript * * var name = 'window', * newTest = null; * * function test () { * console.log( this.name ); * } * * newTest = UE.utils.bind( test, { name: 'object' } ); * * //output: object * newTest(); * * //output: window * test(); * * ``` */ bind: function (fn, context) { return function () { return fn.apply(context, arguments); }; }, /** * 创建延迟指定时间后执行的函数fn * @method defer * @param { Function } fn 需要延迟执行的函数对象 * @param { int } delay 延迟的时间, 单位是毫秒 * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后, * 而不能保证刚好到达延迟时间时执行。 * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果 * @example * ```javascript * var start = 0; * * function test(){ * console.log( new Date() - start ); * } * * var testDefer = UE.utils.defer( test, 1000 ); * // * start = new Date(); * //output: (大约在1000毫秒之后输出) 1000 * testDefer(); * ``` */ /** * 创建延迟指定时间后执行的函数fn, 如果在延迟时间内再次执行该方法, 将会根据指定的exclusion的值, * 决定是否取消前一次函数的执行, 如果exclusion的值为true, 则取消执行,反之,将继续执行前一个方法。 * @method defer * @param { Function } fn 需要延迟执行的函数对象 * @param { int } delay 延迟的时间, 单位是毫秒 * @param { Boolean } exclusion 如果在延迟时间内再次执行该函数,该值将决定是否取消执行前一次函数的执行, * 值为true表示取消执行, 反之则将在执行前一次函数之后才执行本次函数调用。 * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后, * 而不能保证刚好到达延迟时间时执行。 * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果 * @example * ```javascript * * function test(){ * console.log(1); * } * * var testDefer = UE.utils.defer( test, 1000, true ); * * //output: (两次调用仅有一次输出) 1 * testDefer(); * testDefer(); * ``` */ defer: function (fn, delay, exclusion) { var timerID; return function () { if (exclusion) { clearTimeout(timerID); } timerID = setTimeout(fn, delay); }; }, /** * 获取元素item在数组array中首次出现的位置, 如果未找到item, 则返回-1 * @method indexOf * @remind 该方法的匹配过程使用的是恒等“===” * @param { Array } array 需要查找的数组对象 * @param { * } item 需要在目标数组中查找的值 * @return { int } 返回item在目标数组array中首次出现的位置, 如果在数组中未找到item, 则返回-1 * @example * ```javascript * var item = 1, * arr = [ 3, 4, 6, 8, 1, 1, 2 ]; * * //output: 4 * console.log( UE.utils.indexOf( arr, item ) ); * ``` */ /** * 获取元素item数组array中首次出现的位置, 如果未找到item, 则返回-1。通过start的值可以指定搜索的起始位置。 * @method indexOf * @remind 该方法的匹配过程使用的是恒等“===” * @param { Array } array 需要查找的数组对象 * @param { * } item 需要在目标数组中查找的值 * @param { int } start 搜索的起始位置 * @return { int } 返回item在目标数组array中的start位置之后首次出现的位置, 如果在数组中未找到item, 则返回-1 * @example * ```javascript * var item = 1, * arr = [ 3, 4, 6, 8, 1, 2, 8, 3, 2, 1, 1, 4 ]; * * //output: 9 * console.log( UE.utils.indexOf( arr, item, 5 ) ); * ``` */ 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 * @method removeItem * @param { Array } array 要移除元素的目标数组 * @param { * } item 将要被移除的元素 * @remind 该方法的匹配过程使用的是恒等“===” * @example * ```javascript * var arr = [ 4, 5, 7, 1, 3, 4, 6 ]; * * UE.utils.removeItem( arr, 4 ); * //output: [ 5, 7, 1, 3, 6 ] * console.log( arr ); * * ``` */ removeItem: function (array, item) { for (var i = 0, l = array.length; i < l; i++) { if (array[i] === item) { array.splice(i, 1); i--; } } }, /** * 删除字符串str的首尾空格 * @method trim * @param { String } str 需要删除首尾空格的字符串 * @return { String } 删除了首尾的空格后的字符串 * @example * ```javascript * * var str = " UEdtior "; * * //output: 9 * console.log( str.length ); * * //output: 7 * console.log( UE.utils.trim( " UEdtior " ).length ); * * //output: 9 * console.log( str.length ); * * ``` */ trim: function (str) { return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, ''); }, /** * 将字符串str以','分隔成数组后,将该数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1 * @method listToMap * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。 * @param { String } str 该字符串将被以','分割为数组, 然后进行转化 * @return { Object } 转化之后的hash对象 * @example * ```javascript * * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1} * console.log( UE.utils.listToMap( 'UEdtior,Hello' ) ); * * ``` */ /** * 将字符串数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1 * @method listToMap * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。 * @param { Array } arr 字符串数组 * @return { Object } 转化之后的hash对象 * @example * ```javascript * * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1} * console.log( UE.utils.listToMap( [ 'UEdtior', 'Hello' ] ) ); * * ``` */ 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符号转义,将转义“',&,<,",>”五个字符 * @method unhtml * @param { String } str 需要转义的字符串 * @return { String } 转义后的字符串 * @example * ```javascript * var html = '&'; * * //output: <body>&</body> * console.log( UE.utils.unhtml( html ) ); * * ``` */ unhtml: function (str, reg) { return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|apos|nbsp|#\d+);)?/g, function (a, b) { if (b) { return a; } else { return { '<': '<', '&': '&', '"': '"', '>': '>', "'": ''' }[a] } }) : ''; }, /** * 将url中的html字符转义, 仅转义 ', ", <, > 四个字符 * @param { String } str 需要转义的字符串 * @param { RegExp } reg 自定义的正则 * @return { String } 转义后的字符串 */ unhtmlForUrl: function (str, reg) { return str ? str.replace(reg || /[<">']/g, function (a) { return { '<': '<', '&': '&', '"': '"', '>': '>', "'": ''' }[a] }) : ''; }, /** * 将str中的转义字符还原成html字符 * @see UE.utils.unhtml(String); * @method html * @param { String } str 需要逆转义的字符串 * @return { String } 逆转义后的字符串 * @example * ```javascript * * var str = '<body>&</body>'; * * //output: & * console.log( UE.utils.html( str ) ); * * ``` */ html: function (str) { return str ? str.replace(/&((g|l|quo)t|amp|#39|nbsp|apos);/g, function (m) { return { '<': '<', '&': '&', '"': '"', '>': '>', ''': "'", ' ': ' ', ''': "'" }[m] }) : ''; }, /** * 将css样式转换为驼峰的形式 * @method cssStyleToDomStyle * @param { String } cssName 需要转换的css样式名 * @return { String } 转换成驼峰形式后的css样式名 * @example * ```javascript * * var str = 'border-top'; * * //output: borderTop * console.log( UE.utils.cssStyleToDomStyle( str ) ); * * ``` */ 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中 * @method loadFile * @param { DomDocument } document 需要加载资源文件的文档对象 * @param { Object } options 加载资源文件的属性集合, 取值请参考代码示例 * @example * ```javascript * * UE.utils.loadFile( document, { * src:"test.js", * tag:"script", * type:"text/javascript", * defer:"defer" * } ); * * ``` */ /** * 动态加载文件到doc中,加载成功后执行的回调函数fn * @method loadFile * @param { DomDocument } document 需要加载资源文件的文档对象 * @param { Object } options 加载资源文件的属性集合, 该集合支持的值是script标签和style标签支持的所有属性。 * @param { Function } fn 资源文件加载成功之后执行的回调 * @warning 对于在同一个文档中多次加载同一URL的文件, 该方法会在第一次加载之后缓存该请求, * 在此之后的所有同一URL的请求, 将会直接触发回调。 * @example * ```javascript * * UE.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 ueditor.config.js ') }; doc.getElementsByTagName("head")[0].appendChild(element); } }(), /** * 判断obj对象是否为空 * @method isEmptyObject * @param { * } obj 需要判断的对象 * @remind 如果判断的对象是NULL, 将直接返回true, 如果是数组且为空, 返回true, 如果是字符串, 且字符串为空, * 返回true, 如果是普通对象, 且该对象没有任何实例属性, 返回true * @return { Boolean } 对象是否为空 * @example * ```javascript * * //output: true * console.log( UE.utils.isEmptyObject( {} ) ); * * //output: true * console.log( UE.utils.isEmptyObject( [] ) ); * * //output: true * console.log( UE.utils.isEmptyObject( "" ) ); * * //output: false * console.log( UE.utils.isEmptyObject( { key: 1 } ) ); * * //output: false * console.log( UE.utils.isEmptyObject( [1] ) ); * * //output: false * console.log( UE.utils.isEmptyObject( "1" ) ); * * ``` */ 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; }, /** * 把rgb格式的颜色值转换成16进制格式 * @method fixColor * @param { String } rgb格式的颜色值 * @param { String } * @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 + ";;" : ';' }); }, /** * 克隆对象 * @method clone * @param { Object } source 源对象 * @return { Object } source的一个副本 */ /** * 深度克隆对象,将source的属性克隆到target对象, 会覆盖target重名的属性。 * @method clone * @param { Object } source 源对象 * @param { Object } target 目标对象 * @return { Object } 附加了source对象所有属性的target对象 */ 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为单位的值 * @method transUnitToPx * @param { String } 待转换的带单位的字符串 * @return { String } 转换为px为计量单位的值的字符串 * @example * ```javascript * * //output: 500px * console.log( UE.utils.transUnitToPx( '20cm' ) ); * * //output: 27px * console.log( UE.utils.transUnitToPx( '20pt' ) ); * * ``` */ 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' : ''); }, /** * 在dom树ready之后执行给定的回调函数 * @method domReady * @remind 如果在执行该方法的时候, dom树已经ready, 那么回调函数将立刻执行 * @param { Function } fn dom树ready之后的回调函数 * @example * ```javascript * * UE.utils.domReady( function () { * * console.log('123'); * * } ); * * ``` */ 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 && browser.version != 11) { (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样式 * @method cssRule * @param { String } 节点名称 * @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',document) => 返回指定key的样式,并且指定是哪个document * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色 */ cssRule: browser.ie && browser.version != 11 ? function (key, style, doc) { var indexList, index; if (style === undefined || style && style.nodeType && style.nodeType == 9) { //获取样式 doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document); indexList = doc.indexList || (doc.indexList = {}); index = indexList[key]; if (index !== undefined) { return doc.styleSheets[index].cssText } return undefined; } doc = doc || document; indexList = doc.indexList || (doc.indexList = {}); index = indexList[key]; //清除样式 if (style === '') { if (index !== undefined) { doc.styleSheets[index].cssText = ''; delete indexList[key]; return true } return false; } //添加样式 if (index !== undefined) { sheetStyle = doc.styleSheets[index]; } else { sheetStyle = doc.createStyleSheet('', index = doc.styleSheets.length); indexList[key] = index; } sheetStyle.cssText = style; } : function (key, style, doc) { var head, node; if (style === undefined || style && style.nodeType && style.nodeType == 9) { //获取样式 doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document); node = doc.getElementById(key); return node ? node.innerHTML : undefined; } doc = doc || document; node = doc.getElementById(key); //清除样式 if (style === '') { if (node) { node.parentNode.removeChild(node); return true } return false; } //添加样式 if (node) { node.innerHTML = style; } else { node = doc.createElement('style'); node.id = key; node.innerHTML = style; doc.getElementsByTagName('head')[0].appendChild(node); } }, sort: function (array, compareFn) { compareFn = compareFn || function (item1, item2) { return item1.localeCompare(item2); }; for (var i = 0, len = array.length; i < len; i++) { for (var j = i, length = array.length; j < length; j++) { if (compareFn(array[i], array[j]) > 0) { var t = array[i]; array[i] = array[j]; array[j] = t; } } } return array; }, serializeParam: function (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])); } else if (utils.isArray(json[i])) { //支持传数组内容 for (var j = 0; j < json[i].length; j++) { strArr.push(encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j])); } } } return strArr.join("&"); }, formatUrl: function (url) { var u = url.replace(/&&/g, '&'); u = u.replace(/\?&/g, '?'); u = u.replace(/&$/g, ''); u = u.replace(/&#/g, '#'); u = u.replace(/&+/g, '&'); return u; }, isCrossDomainUrl: function (url) { var a = document.createElement('a'); a.href = url; if (browser.ie) { a.href = a.href; } return !(a.protocol == location.protocol && a.hostname == location.hostname && (a.port == location.port || (a.port == '80' && location.port == '') || (a.port == '' && location.port == '80'))); }, clearEmptyAttrs: function (obj) { for (var p in obj) { if (obj[p] === '') { delete obj[p] } } return obj; }, str2json: function (s) { if (!utils.isString(s)) return null; if (window.JSON) { return JSON.parse(s); } else { return (new Function("return " + utils.trim(s || '')))(); } }, json2str: (function () { if (window.JSON) { return JSON.stringify; } else { var escapeMap = { "\b": '\\b', "\t": '\\t', "\n": '\\n', "\f": '\\f', "\r": '\\r', '"': '\\"', "\\": '\\\\' }; function encodeString(source) { if (/["\\\x00-\x1f]/.test(source)) { source = source.replace( /["\\\x00-\x1f]/g, function (match) { var c = escapeMap[match]; if (c) { return c; } c = match.charCodeAt(); return "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16); }); } return '"' + source + '"'; } function encodeArray(source) { var result = ["["], l = source.length, preComma, i, item; for (i = 0; i < l; i++) { item = source[i]; switch (typeof item) { case "undefined": case "function": case "unknown": break; default: if (preComma) { result.push(','); } result.push(utils.json2str(item)); preComma = 1; } } result.push("]"); return result.join(""); } function pad(source) { return source < 10 ? '0' + source : source; } function encodeDate(source) { return '"' + source.getFullYear() + "-" + pad(source.getMonth() + 1) + "-" + pad(source.getDate()) + "T" + pad(source.getHours()) + ":" + pad(source.getMinutes()) + ":" + pad(source.getSeconds()) + '"'; } return function (value) { switch (typeof value) { case 'undefined': return 'undefined'; case 'number': return isFinite(value) ? String(value) : "null"; case 'string': return encodeString(value); case 'boolean': return String(value); default: if (value === null) { return 'null'; } else if (utils.isArray(value)) { return encodeArray(value); } else if (utils.isDate(value)) { return encodeDate(value); } else { var result = ['{'], encode = utils.json2str, preComma, item; for (var key in value) { if (Object.prototype.hasOwnProperty.call(value, key)) { item = value[key]; switch (typeof item) { case 'undefined': case 'unknown': case 'function': break; default: if (preComma) { result.push(','); } preComma = 1; result.push(encode(key) + ':' + encode(item)); } } } result.push('}'); return result.join(''); } } }; } })() }; /** * 判断给定的对象是否是字符串 * @method isString * @param { * } object 需要判断的对象 * @return { Boolean } 给定的对象是否是字符串 */ /** * 判断给定的对象是否是数组 * @method isArray * @param { * } object 需要判断的对象 * @return { Boolean } 给定的对象是否是数组 */ /** * 判断给定的对象是否是一个Function * @method isFunction * @param { * } object 需要判断的对象 * @return { Boolean } 给定的对象是否是Function */ /** * 判断给定的对象是否是Number * @method isNumber * @param { * } object 需要判断的对象 * @return { Boolean } 给定的对象是否是Number */ /** * 判断给定的对象是否是一个正则表达式 * @method isRegExp * @param { * } object 需要判断的对象 * @return { Boolean } 给定的对象是否是正则表达式 */ /** * 判断给定的对象是否是一个普通对象 * @method isObject * @param { * } object 需要判断的对象 * @return { Boolean } 给定的对象是否是普通对象 */ utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date'], function (v) { UE.utils['is' + v] = function (obj) { return Object.prototype.toString.apply(obj) == '[object ' + v + ']'; } }); // core/EventBase.js /** * UE采用的事件基类 * @file * @module UE * @class EventBase * @since 1.2.6.1 */ /** * UEditor公用空间,UEditor所有的功能都挂载在该空间下 * @unfile * @module UE */ /** * UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。 * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。 * @unfile * @module UE * @class EventBase */ /** * 通过此构造器,子类可以继承EventBase获取事件监听的方法 * @constructor * @example * ```javascript * UE.EventBase.call(editor); * ``` */ var EventBase = UE.EventBase = function () { }; EventBase.prototype = { /** * 注册事件监听器 * @method addListener * @param { String } types 监听的事件名称,同时监听多个事件使用空格分隔 * @param { Function } fn 监听的事件被触发时,会执行该回调函数 * @waining 事件被触发时,监听的函数假如返回的值恒等于true,回调函数的队列中后面的函数将不执行 * @example * ```javascript * 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是注册的事件的编辑器实例 * }) * ``` * @see UE.EventBase:fireEvent(String) */ addListener: function (types, listener) { types = utils.trim(types).split(/\s+/); for (var i = 0, ti; ti = types[i++];) { getListener(this, ti, true).push(listener); } }, on: function (types, listener) { return this.addListener(types, listener); }, off: function (types, listener) { return this.removeListener(types, listener) }, trigger: function () { return this.fireEvent.apply(this, arguments); }, /** * 移除事件监听器 * @method removeListener * @param { String } types 移除的事件名称,同时移除多个事件使用空格分隔 * @param { Function } fn 移除监听事件的函数引用 * @example * ```javascript * //changeCallback为方法体 * editor.removeListener("selectionchange",changeCallback); * ``` */ removeListener: function (types, listener) { types = utils.trim(types).split(/\s+/); for (var i = 0, ti; ti = types[i++];) { utils.removeItem(getListener(this, ti) || [], listener); } }, /** * 触发事件 * @method fireEvent * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔 * @remind 该方法会触发addListener * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值 * @example * ```javascript * editor.fireEvent("selectionchange"); * ``` */ /** * 触发事件 * @method fireEvent * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔 * @param { *... } options 可选参数,可以传入一个或多个参数,会传给事件触发的回调函数 * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值 * @example * ```javascript * * editor.addListener( "selectionchange", function ( type, arg1, arg2 ) { * * console.log( arg1 + " " + arg2 ); * * } ); * * //触发selectionchange事件, 会执行上面的事件监听器 * //output: Hello World * editor.fireEvent("selectionchange", "Hello", "World"); * ``` */ fireEvent: function () { var types = arguments[0]; 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; } }; /** * 获得对象所拥有监听类型的所有监听器 * @unfile * @module UE * @since 1.2.6.1 * @method getListener * @public * @param { Object } obj 查询监听器的对象 * @param { String } type 事件类型 * @param { Boolean } force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组 * @return { Array } 监听器数组 */ function getListener(obj, type, force) { var allListeners; type = type.toLowerCase(); return ((allListeners = (obj.__allListeners || force && (obj.__allListeners = {}))) && (allListeners[type] || force && (allListeners[type] = []))); } // core/dtd.js ///import editor.js ///import core/dom/dom.js ///import core/utils.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; } var X = utils.extend2; var A = _({ isindex: 1, fieldset: 1 }), B = _({ input: 1, button: 1, select: 1, textarea: 1, label: 1 }), C = X(_({ a: 1 }), B), D = X({ iframe: 1 }, C), E = _({ hr: 1, ul: 1, menu: 1, div: 1, blockquote: 1, noscript: 1, table: 1, center: 1, address: 1, dir: 1, pre: 1, h5: 1, dl: 1, h4: 1, noframes: 1, h6: 1, ol: 1, h1: 1, h3: 1, h2: 1 }), F = _({ ins: 1, del: 1, script: 1, style: 1 }), G = X(_({ b: 1, acronym: 1, bdo: 1, 'var': 1, '#': 1, abbr: 1, code: 1, br: 1, i: 1, cite: 1, kbd: 1, u: 1, strike: 1, mark: 1, s: 1, tt: 1, strong: 1, q: 1, samp: 1, em: 1, dfn: 1, span: 1 }), F), H = X(_({ sub: 1, img: 1, embed: 1, object: 1, sup: 1, basefont: 1, map: 1, applet: 1, font: 1, big: 1, small: 1 }), G), I = X(_({ p: 1 }), H), J = X(_({ iframe: 1 }), H, B), K = _({ img: 1, embed: 1, noscript: 1, br: 1, kbd: 1, center: 1, button: 1, basefont: 1, h5: 1, h4: 1, samp: 1, h6: 1, ol: 1, h1: 1, h3: 1, h2: 1, form: 1, font: 1, '#': 1, select: 1, menu: 1, ins: 1, abbr: 1, label: 1, code: 1, table: 1, script: 1, cite: 1, input: 1, iframe: 1, strong: 1, textarea: 1, noframes: 1, big: 1, small: 1, span: 1, hr: 1, sub: 1, bdo: 1, 'var': 1, div: 1, object: 1, sup: 1, strike: 1, mark: 1, dir: 1, map: 1, dl: 1, applet: 1, del: 1, isindex: 1, fieldset: 1, ul: 1, b: 1, acronym: 1, a: 1, blockquote: 1, i: 1, u: 1, s: 1, tt: 1, address: 1, q: 1, pre: 1, p: 1, em: 1, dfn: 1 }), L = X(_({ a: 0 }), J), //a不能被切开,所以把他 M = _({ tr: 1 }), N = _({ '#': 1 }), O = X(_({ param: 1 }), K), P = X(_({ form: 1 }), A, D, E, I), Q = _({ li: 1, ol: 1, ul: 1 }), R = _({ style: 1, script: 1 }), S = _({ base: 1, link: 1, meta: 1, title: 1 }), T = X(S, R), U = _({ head: 1, body: 1 }), V = _({ html: 1 }); var block = _({ address: 1, blockquote: 1, center: 1, dir: 1, div: 1, dl: 1, fieldset: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, // hr: 1, isindex: 1, menu: 1, noframes: 1, ol: 1, p: 1, pre: 1, code: 1, table: 1, ul: 1 }), empty = _({ area: 1, base: 1, basefont: 1, br: 1, col: 1, command: 1, dialog: 1, embed: 1, hr: 1, img: 1, input: 1, isindex: 1, keygen: 1, link: 1, meta: 1, param: 1, source: 1, track: 1, wbr: 1 }); // 上标数字映射:普通数字 → 上标数字 var supNumberMap = {'0': '⁰', '1': '¹', '2': '²', '3': '³', '4': '⁴', '5': '⁵', '6': '⁶', '7': '⁷', '8': '⁸', '9': '⁹'}; // 下标数字映射:普通数字 → 下标数字 var subNumberMap = {'0': '₀', '1': '₁', '2': '₂', '3': '₃', '4': '₄', '5': '₅', '6': '₆', '7': '₇', '8': '₈', '9': '₉'}; // 上标字母映射:普通字母 → 上标字母 var supLetterMap = {'a': 'ᵃ', 'b': 'ᵇ', 'c': 'ᶜ', 'd': 'ᵈ', 'e': 'ᵉ', 'f': 'ᶠ', 'g': 'ᵍ', 'h': 'ʰ', 'i': 'ⁱ', 'j': 'ʲ', 'k': 'ᵏ', 'l': 'ˡ', 'm': 'ᵐ', 'n': 'ⁿ', 'o': 'ᵒ', 'p': 'ᵖ', 'r': 'ʳ', 's': 'ˢ', 't': 'ᵗ', 'u': 'ᵘ', 'v': 'ᵛ', 'w': 'ʷ', 'x': 'ˣ', 'y': 'ʸ', 'z': 'ᶻ'}; //下标字母映射:普通字母 → 下标字母 var subLetterMap = {'a': 'ₐ', 'e': 'ₑ', 'h': 'ₕ', 'i': 'ᵢ', 'j': 'ⱼ', 'k': 'ₖ', 'l': 'ₗ', 'm': 'ₘ', 'n': 'ₙ', 'o': 'ₒ', 'p': 'ₚ', 'r': 'ᵣ', 's': 'ₛ', 't': 'ₜ', 'u': 'ᵤ', 'v': 'ᵥ', 'x': 'ₓ'}; return _({ // $ 表示自定的属性 $supNumberMap: supNumberMap, $subNumberMap: subNumberMap, $supLetterMap: supLetterMap, $subLetterMap: subLetterMap, // body外的元素列表. $nonBodyContent: X(V, U, S), //块结构元素列表 $block: block, //内联元素列表 $inline: L, $inlineWithA: X(_({ a: 1 }), L), $body: X(_({ script: 1, style: 1 }), block), $cdata: _({ script: 1, style: 1 }), //自闭和元素 $empty: empty, //不是自闭合,但不能让range选中里边 $nonChild: _({ iframe: 1, textarea: 1 }), //列表元素列表 $listItem: _({ dd: 1, dt: 1, li: 1 }), //列表根元素列表 $list: _({ ul: 1, ol: 1, dl: 1 }), //不能认为是空的元素 $isNotEmpty: _({ table: 1, ul: 1, ol: 1, dl: 1, iframe: 1, area: 1, base: 1, col: 1, hr: 1, img: 1, embed: 1, input: 1, link: 1, meta: 1, param: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1 }), //如果没有子节点就可以删除的元素列表,像span,a $removeEmpty: _({ a: 1, abbr: 1, acronym: 1, address: 1, b: 1, bdo: 1, big: 1, cite: 1, code: 1, del: 1, dfn: 1, em: 1, font: 1, i: 1, ins: 1, label: 1, kbd: 1, q: 1, s: 1, samp: 1, small: 1, span: 1, strike: 1, mark: 1, strong: 1, sub: 1, sup: 1, tt: 1, u: 1, 'var': 1 }), $removeEmptyBlock: _({ 'p': 1, 'div': 1 }), //在table元素里的元素列表 $tableContent: _({ caption: 1, col: 1, colgroup: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1, table: 1 }), //不转换的标签 $notTransContent: _({ pre: 1, script: 1, style: 1, textarea: 1 }), html: U, head: T, style: N, script: N, body: P, base: {}, link: {}, meta: {}, title: N, col: {}, tr: _({ td: 1, th: 1 }), img: {}, embed: {}, colgroup: _({ thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1 }), noscript: P, td: P, br: {}, th: P, center: P, kbd: L, button: X(I, E), basefont: {}, h5: L, h4: L, samp: L, h6: L, ol: Q, h1: L, h3: L, option: N, h2: L, form: X(A, D, E, I), select: _({ optgroup: 1, option: 1 }), font: L, ins: L, menu: Q, abbr: L, label: L, table: _({ thead: 1, col: 1, tbody: 1, tr: 1, colgroup: 1, caption: 1, tfoot: 1 }), code: L, tfoot: M, cite: L, li: P, input: {}, iframe: P, strong: L, textarea: N, noframes: P, big: L, small: L, //trace: span: _({ '#': 1, br: 1, b: 1, strong: 1, u: 1, i: 1, em: 1, sub: 1, sup: 1, strike: 1, mark: 1, span: 1 }), hr: L, dt: L, sub: L, optgroup: _({ option: 1 }), param: {}, bdo: L, 'var': L, div: P, section:P, object: O, sup: L, dd: P, strike: L, mark: L, area: {}, dir: Q, map: X(_({ area: 1, form: 1, p: 1 }), A, F, E), applet: O, dl: _({ dt: 1, dd: 1 }), del: L, isindex: {}, fieldset: X(_({ legend: 1 }), K), thead: M, ul: Q, acronym: L, b: L, a: X(_({ a: 1 }), J), blockquote: X(_({ td: 1, tr: 1, tbody: 1, li: 1 }), P), caption: L, i: L, u: L, tbody: M, s: L, address: X(D, I), tt: L, legend: L, q: L, pre: X(G, C), p: X(_({ 'a': 1 }), L), em: L, dfn: L }); })(); // core/domUtils.js /** * Dom操作工具包 * @file * @module UE.dom.domUtils * @since 1.2.6.1 */ /** * Dom操作工具包 * @unfile * @module UE.dom.domUtils */ function getDomNode(node, start, ltr, startFromChild, fn, guard) { var tmpNode = startFromChild && node[start], parent; !tmpNode && (tmpNode = node[ltr]); while (!tmpNode && (parent = (parent || node).parentNode)) { if (parent.tagName == 'BODY' || guard && !guard(parent)) { return null; } tmpNode = parent[ltr]; } if (tmpNode && fn && !fn(tmpNode)) { return getDomNode(tmpNode, start, ltr, false, fn); } return tmpNode; } var attrFix = ie && browser.version < 9 ? { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder" } : { tabindex: "tabIndex", readonly: "readOnly" }, styleBlock = utils.listToMap([ '-webkit-box', '-moz-box', 'block', 'list-item', 'table', 'table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 'table-column-group', 'table-column', 'table-cell', 'table-caption' ]); var domUtils = dom.domUtils = { //节点常量 NODE_ELEMENT: 1, NODE_DOCUMENT: 9, NODE_TEXT: 3, NODE_COMMENT: 8, NODE_DOCUMENT_FRAGMENT: 11, //位置关系 POSITION_IDENTICAL: 0, POSITION_DISCONNECTED: 1, POSITION_FOLLOWING: 2, POSITION_PRECEDING: 4, POSITION_IS_CONTAINED: 8, POSITION_CONTAINS: 16, //ie6使用其他的会有一段空白出现 fillChar: ie && browser.version == '6' ? '\ufeff' : '\u200B', //-------------------------Node部分-------------------------------- keys: { /*Backspace*/ 8: 1, /*Delete*/ 46: 1, /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1, 37: 1, 38: 1, 39: 1, 40: 1, 13: 1 /*enter*/ }, /** * 获取节点A相对于节点B的位置关系 * @method getPosition * @param { Node } nodeA 需要查询位置关系的节点A * @param { Node } nodeB 需要查询位置关系的节点B * @return { Number } 节点A与节点B的关系 * @example * ```javascript * //output: 20 * var position = UE.dom.domUtils.getPosition( document.documentElement, document.body ); * * switch ( position ) { * * //0 * case UE.dom.domUtils.POSITION_IDENTICAL: * console.log('元素相同'); * break; * //1 * case UE.dom.domUtils.POSITION_DISCONNECTED: * console.log('两个节点在不同的文档中'); * break; * //2 * case UE.dom.domUtils.POSITION_FOLLOWING: * console.log('节点A在节点B之后'); * break; * //4 * case UE.dom.domUtils.POSITION_PRECEDING; * console.log('节点A在节点B之前'); * break; * //8 * case UE.dom.domUtils.POSITION_IS_CONTAINED: * console.log('节点A被节点B包含'); * break; * case 10: * console.log('节点A被节点B包含且节点A在节点B之后'); * break; * //16 * case UE.dom.domUtils.POSITION_CONTAINS: * console.log('节点A包含节点B'); * break; * case 20: * console.log('节点A包含节点B且节点A在节点B之前'); * break; * * } * ``` */ 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在父节点中的索引位置 * @method getNodeIndex * @param { Node } node 需要检测的节点对象 * @return { Number } 该节点在父节点中的位置 * @see UE.dom.domUtils.getNodeIndex(Node,Boolean) */ /** * 检测节点node在父节点中的索引位置, 根据给定的mergeTextNode参数决定是否要合并多个连续的文本节点为一个节点 * @method getNodeIndex * @param { Node } node 需要检测的节点对象 * @param { Boolean } mergeTextNode 是否合并多个连续的文本节点为一个节点 * @return { Number } 该节点在父节点中的位置 * @example * ```javascript * * var node = document.createElement("div"); * * node.appendChild( document.createTextNode( "hello" ) ); * node.appendChild( document.createTextNode( "world" ) ); * node.appendChild( node = document.createElement( "div" ) ); * * //output: 2 * console.log( UE.dom.domUtils.getNodeIndex( node ) ); * * //output: 1 * console.log( UE.dom.domUtils.getNodeIndex( node, true ) ); * * ``` */ 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是否在给定的document对象上 * @method inDoc * @param { Node } node 需要检测的节点对象 * @param { DomDocument } doc 需要检测的document对象 * @return { Boolean } 该节点node是否在给定的document的dom树上 * @example * ```javascript * * var node = document.createElement("div"); * * //output: false * console.log( UE.do.domUtils.inDoc( node, document ) ); * * document.body.appendChild( node ); * * //output: true * console.log( UE.do.domUtils.inDoc( node, document ) ); * * ``` */ inDoc: function (node, doc) { return domUtils.getPosition(node, doc) == 10; }, /** * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点, * 查找的起点是给定node节点的父节点。 * @method findParent * @param { Node } node 需要查找的节点 * @param { Function } filterFn 自定义的过滤方法。 * @warning 查找的终点是到body节点为止 * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该 * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。 * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL * @example * ```javascript * var filterNode = UE.dom.domUtils.findParent( document.body.firstChild, function ( node ) { * * //由于查找的终点是body节点, 所以永远也不会匹配当前过滤器的条件, 即这里永远会返回false * return node.tagName === "HTML"; * * } ); * * //output: true * console.log( filterNode === null ); * ``` */ /** * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点, * 如果includeSelf的值为true,则查找的起点是给定的节点node, 否则, 起点是node的父节点 * @method findParent * @param { Node } node 需要查找的节点 * @param { Function } filterFn 自定义的过滤方法。 * @param { Boolean } includeSelf 查找过程是否包含自身 * @warning 查找的终点是到body节点为止 * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该 * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。 * @remind 如果includeSelf为true, 则过滤器第一次执行时的参数会是节点本身。 * 反之, 过滤器第一次执行时的参数将是该节点的父节点。 * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL * @example * ```html * * *
*
* * * * ``` */ 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; }, /** * 查找node的节点名为tagName的第一个祖先节点, 查找的起点是node节点的父节点。 * @method findParentByTagName * @param { Node } node 需要查找的节点对象 * @param { Array } tagNames 需要查找的父节点的名称数组 * @warning 查找的终点是到body节点为止 * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL * @example * ```javascript * var node = UE.dom.domUtils.findParentByTagName( document.getElementsByTagName("div")[0], [ "BODY" ] ); * //output: BODY * console.log( node.tagName ); * ``` */ /** * 查找node的节点名为tagName的祖先节点, 如果includeSelf的值为true,则查找的起点是给定的节点node, * 否则, 起点是node的父节点。 * @method findParentByTagName * @param { Node } node 需要查找的节点对象 * @param { Array } tagNames 需要查找的父节点的名称数组 * @param { Boolean } includeSelf 查找过程是否包含node节点自身 * @warning 查找的终点是到body节点为止 * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL * @example * ```javascript * var queryTarget = document.getElementsByTagName("div")[0]; * var node = UE.dom.domUtils.findParentByTagName( queryTarget, [ "DIV" ], true ); * //output: true * console.log( queryTarget === node ); * ``` */ 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的祖先节点集合, 查找的起点是给定节点的父节点,结果集中不包含给定的节点。 * @method findParents * @param { Node } node 需要查找的节点对象 * @return { Array } 给定节点的祖先节点数组 * @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个 */ /** * 查找节点node的祖先节点集合, 如果includeSelf的值为true, * 则返回的结果集中允许出现当前给定的节点, 否则, 该节点不会出现在其结果集中。 * @method findParents * @param { Node } node 需要查找的节点对象 * @param { Boolean } includeSelf 查找的结果中是否允许包含当前查找的节点对象 * @return { Array } 给定节点的祖先节点数组 */ 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 * @method insertAfter * @param { Node } node 目标节点 * @param { Node } newNode 新插入的节点, 该节点将置于目标节点之后 * @return { Node } 新插入的节点 */ insertAfter: function (node, newNode) { return node.nextSibling ? node.parentNode.insertBefore(newNode, node.nextSibling) : node.parentNode.appendChild(newNode); }, /** * 删除节点node及其下属的所有节点 * @method remove * @param { Node } node 需要删除的节点对象 * @return { Node } 返回刚删除的节点对象 * @example * ```html *
*
你好
*
* * ``` */ /** * 删除节点node,并根据keepChildren的值决定是否保留子节点 * @method remove * @param { Node } node 需要删除的节点对象 * @param { Boolean } keepChildren 是否需要保留子节点 * @return { Node } 返回刚删除的节点对象 * @example * ```html *
*
你好
*
* * ``` */ 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节点的下一个兄弟节点, 如果该节点其后没有兄弟节点, 则递归查找其父节点之后的第一个兄弟节点, * 直到找到满足条件的节点或者递归到BODY节点之后才会结束。 * @method getNextDomNode * @param { Node } node 需要获取其后的兄弟节点的节点对象 * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL * @example * ```html * *
* *
* xxx * * * ``` * @example * ```html * *
* * xxx *
* xxx * * * ``` */ /** * 取得node节点的下一个兄弟节点, 如果startFromChild的值为ture,则先获取其子节点, * 如果有子节点则直接返回第一个子节点;如果没有子节点或者startFromChild的值为false, * 则执行getNextDomNode(Node node)的查找过程。 * @method getNextDomNode * @param { Node } node 需要获取其后的兄弟节点的节点对象 * @param { Boolean } startFromChild 查找过程是否从其子节点开始 * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL * @see UE.dom.domUtils.getNextDomNode(Node) */ getNextDomNode: function (node, startFromChild, filterFn, guard) { return getDomNode(node, 'firstChild', 'nextSibling', startFromChild, filterFn, guard); }, getPreDomNode: function (node, startFromChild, filterFn, guard) { return getDomNode(node, 'lastChild', 'previousSibling', startFromChild, filterFn, guard); }, /** * 检测节点node是否属是UEditor定义的bookmark节点 * @method isBookmarkNode * @private * @param { Node } node 需要检测的节点对象 * @return { Boolean } 是否是bookmark节点 * @example * ```html * * * ``` */ isBookmarkNode: function (node) { return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id); }, /** * 获取节点node所属的window对象 * @method getWindow * @param { Node } node 节点对象 * @return { Window } 当前节点所属的window对象 * @example * ```javascript * //output: true * console.log( UE.dom.domUtils.getWindow( document.body ) === window ); * ``` */ getWindow: function (node) { var doc = node.ownerDocument || node; return doc.defaultView || doc.parentWindow; }, /** * 获取离nodeA与nodeB最近的公共的祖先节点 * @method getCommonAncestor * @param { Node } nodeA 第一个节点 * @param { Node } nodeB 第二个节点 * @remind 如果给定的两个节点是同一个节点, 将直接返回该节点。 * @return { Node | NULL } 如果未找到公共节点, 返回NULL, 否则返回最近的公共祖先节点。 * @example * ```javascript * var commonAncestor = UE.dom.domUtils.getCommonAncestor( document.body, document.body.firstChild ); * //output: true * console.log( commonAncestor.tagName.toLowerCase() === 'body' ); * ``` */ 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节点 * @method clearEmptySibling * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点, * 则这些兄弟节点将被删除 * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点 * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点 * @example * ```html * *
* * * * xxx * * * * ``` */ /** * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true, * 则忽略对右边兄弟节点的操作。 * @method clearEmptySibling * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点, * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作 * 则这些兄弟节点将被删除 * @see UE.dom.domUtils.clearEmptySibling(Node) */ /** * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true, * 则忽略对右边兄弟节点的操作, 如果ignorePre的值为true,则忽略对左边兄弟节点的操作。 * @method clearEmptySibling * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点, * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作 * @param { Boolean } ignorePre 是否忽略忽略对左边的兄弟节点的操作 * 则这些兄弟节点将被删除 * @see UE.dom.domUtils.clearEmptySibling(Node) */ 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'); }, /** * 将一个文本节点textNode拆分成两个文本节点,offset指定拆分位置 * @method split * @param { Node } textNode 需要拆分的文本节点对象 * @param { int } offset 需要拆分的位置, 位置计算从0开始 * @return { Node } 拆分后形成的新节点 * @example * ```html *
abcdef
* * ``` */ 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; }, /** * 检测文本节点textNode是否为空节点(包括空格、换行、占位符等字符) * @method isWhitespace * @param { Node } node 需要检测的节点对象 * @return { Boolean } 检测的节点是否为空 * @example * ```html *
* *
* * ``` */ isWhitespace: function (node) { return !new RegExp('[^ \t\n\r' + domUtils.fillChar + ']').test(node.nodeValue); }, /** * 获取元素element相对于viewport的位置坐标 * @method getXY * @param { Node } element 需要计算位置的节点对象 * @return { Object } 返回形如{x:left,y:top}的一个key-value映射对象, 其中键x代表水平偏移距离, * y代表垂直偏移距离。 * * @example * ```javascript * var location = UE.dom.domUtils.getXY( document.getElementById("test") ); * //output: test的坐标为: 12, 24 * console.log( 'test的坐标为: ', location.x, ',', location.y ); * ``` */ 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为处理函数 * @method on * @param { Node } element 需要绑定事件的节点对象 * @param { String } type 绑定的事件类型 * @param { Function } handler 事件处理器 * @example * ```javascript * UE.dom.domUtils.on(document.body,"click",function(e){ * //e为事件对象,this为被点击元素对戏那个 * }); * ``` */ /** * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数 * @method on * @param { Node } element 需要绑定事件的节点对象 * @param { Array } type 绑定的事件类型数组 * @param { Function } handler 事件处理器 * @example * ```javascript * UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){ * //evt为事件对象,this为被点击元素对象 * }); * ``` */ on: function (element, type, handler) { var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/), 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事件绑定 * @method un * @param { Node } element 需要解除事件绑定的节点对象 * @param { String } type 需要接触绑定的事件类型 * @param { Function } handler 对应的事件处理器 * @example * ```javascript * UE.dom.domUtils.un(document.body,"click",function(evt){ * //evt为事件对象,this为被点击元素对象 * }); * ``` */ /** * 解除DOM事件绑定 * @method un * @param { Node } element 需要解除事件绑定的节点对象 * @param { Array } type 需要接触绑定的事件类型数组 * @param { Function } handler 对应的事件处理器 * @example * ```javascript * UE.dom.domUtils.un(document.body, ["click","mousedown"],function(evt){ * //evt为事件对象,this为被点击元素对象 * }); * ``` */ un: function (element, type, handler) { var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/), 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是否具有相同的标签名、属性名以及属性值 * @method isSameElement * @param { Node } nodeA 需要比较的节点 * @param { Node } nodeB 需要比较的节点 * @return { Boolean } 两个节点是否具有相同的标签名、属性名以及属性值 * @example * ```html * ssss * bbbbb * ssss * bbbbb * * * ``` */ 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的元素的style属性是否一致 * @method isSameStyle * @param { Node } nodeA 需要比较的节点 * @param { Node } nodeB 需要比较的节点 * @return { Boolean } 两个节点是否具有相同的style属性值 * @example * ```html * ssss * bbbbb * ssss * bbbbb * * * ``` */ 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是否为block元素 * @method isBlockElm * @param { Node } node 需要检测的节点对象 * @return { Boolean } 是否是block元素节点 * @warning 该方法的判断规则如下: 如果该元素原本是block元素, 则不论该元素当前的css样式是什么都会返回true; * 否则,检测该元素的css样式, 如果该元素当前是block元素, 则返回true。 其余情况下都返回false。 * @example * ```html * * *
* * * ``` */ isBlockElm: function (node) { return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(node, 'display')]) && !dtd.$nonChild[node.tagName]; }, /** * 检测node节点是否为body节点 * @method isBody * @param { Element } node 需要检测的dom元素 * @return { Boolean } 给定的元素是否是body元素 * @example * ```javascript * //output: true * console.log( UE.dom.domUtils.isBody( document.body ) ); * ``` */ isBody: function (node) { return node && node.nodeType == 1 && node.tagName.toLowerCase() == 'body'; }, // 20200603 协同编辑 生成element-id getRandomId: function () { var str = "abcdefghijklmnopqrstuvwxyz0123456789"; var tmp = []; var random; for (var i = 0; i < 8; i++) { random = Math.floor(Math.random() * (str.length)); if (tmp.indexOf(str[random]) === -1) { tmp.push(str[random]) } else { i--; } } return tmp.join(''); }, //数字转小写罗马数字 intToRoman: function (num) { var result = ""; if (num >= 1000) { result = domUtils.repeatC('m', Math.floor(num / 1000)); num %= 1000; } if (num >= 100) { result += domUtils.generBase(Math.floor(num / 100), ['c', 'd', 'm']); num %= 100; } if (num >= 10) { result += domUtils.generBase(Math.floor(num / 10), ['x', 'l', 'c']); num %= 10; } if (num >= 1) { result += domUtils.generBase(Math.floor(num), ['i', 'v', 'x']); } return result; }, generBase: function (num, arr) { var result = ""; if (num >= 1 && num <= 3) { result = domUtils.repeatC(arr[0], num); } if (num === 4) { result = arr[0] + '' + arr[1]; } if (num >= 5 && num <= 8) { result = arr[1] + '' + domUtils.repeatC(arr[0], num - 5); } if (num === 9) { result = arr[0] + "" + arr[2]; } return result; }, repeatC: function (char, count) { var result = ""; for (var i = 0; i < count; i++) { result += char; } return result; }, //小写罗马数字转数字 romanToInt: function (s) { //定义一个对象来存放数据 var map = {'i': 1, 'v': 5, 'x': 10, 'l': 50, 'c': 100, 'd': 500, 'm': 1000}; //罗马数分割成数组 var sArr = s.split(''); //总数 var sum = 0; for (var i = 0; i < sArr.length; i++) { //sArr[i]拿到的是key,只要比较前一个比后一个小就行,大的话相减,并且这个时候,i+1已经不用计算了,我们可以把i+1,跳过下一个数字的比对操作 var value = map[sArr[i]] if (value < map[sArr[i + 1]]) { value = map[sArr[i + 1]] - value; i++; } sum += value; } return sum; }, //整数转字母 intToAlpha: function (num) { var str = ""; while (num > 0) { var m = num % 26; if (m == 0) { m = 26; } str = String.fromCharCode(m + 96) + str; num = (num - m) / 26; } return str; }, alphaToInt: function (str) { var n = 0; var s = str.match(/./g);//求出字符数组 var j = 0; for (var i = str.length - 1, j = 1; i >= 0; i--, j *= 26) { var c = s[i].toLowerCase(); if (c < 'a' || c > 'z') { return 0; } n += (c.charCodeAt(0) - 96) * j; } return n; }, //列表序号转整数 serialnumToInt: function (serialstr, level) { var serialnum; level = parseInt(level); if (level % 3 == 0) { serialnum = domUtils.romanToInt(serialstr); } else if (level % 3 == 1) { serialnum = parseInt(serialstr); } else { serialnum = domUtils.alphaToInt(serialstr); } return serialnum; }, //列表序号转字符串 serialnumToString: function (serialnum, level) { var serialstr; level = parseInt(level); if (level % 3 == 0) { serialstr = domUtils.intToRoman(serialnum); } else if (level % 3 == 1) { serialstr = serialnum.toString(); } else { serialstr = domUtils.intToAlpha(serialnum); } return serialstr; }, //列表序号加1 addSerialNum: function (serialstr, level) { var serialnum; serialnum = domUtils.serialnumToInt(serialstr, level); serialnum++; serialstr = domUtils.serialnumToString(serialnum, level); return serialstr; }, //列表序号减1 minusSerialNum: function (serialstr, level) { var serialnum; serialnum = domUtils.serialnumToInt(serialstr, level); if (serialnum > 1) { serialnum--; } serialstr = domUtils.serialnumToString(serialnum, level); return serialstr; }, /** * 以node节点为分界,将该节点的指定祖先节点parent拆分成两个独立的节点, * 拆分形成的两个节点之间是node节点 * @method breakParent * @param { Node } node 作为分界的节点对象 * @param { Node } parent 该节点必须是node节点的祖先节点, 且是block节点。 * @return { Node } 给定的node分界节点 * @example * ```javascript * * var node = document.createElement("span"), * wrapNode = document.createElement( "div" ), * parent = document.createElement("p"); * * parent.appendChild( node ); * wrapNode.appendChild( parent ); * * //拆分前 * //output:

* console.log( wrapNode.innerHTML ); * * * UE.dom.domUtils.breakParent( node, parent ); * //拆分后 * //output:

* console.log( wrapNode.innerHTML ); * * ``` */ 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); var elementId = parent.getAttribute('element-id') domUtils.remove(parent); //20200603 协同编辑 加id if (leftNodes && domUtils.isBlockElm(leftNodes)) { leftNodes.setAttribute('element-id', elementId); } if (rightNodes && domUtils.isBlockElm(rightNodes)) { rightNodes.setAttribute('element-id', domUtils.getRandomId()); } return node; }, /** * 检查节点node是否是空inline节点 * @method isEmptyInlineElement * @param { Node } node 需要检测的节点对象 * @return { Number } 如果给定的节点是空的inline节点, 则返回1, 否则返回0。 * @example * ```html * => 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节点下首尾两端的空白文本子节点 * @method trimWhiteTextNode * @param { Element } node 需要执行删除操作的元素对象 * @example * ```javascript * var node = document.createElement("div"); * * node.appendChild( document.createTextNode( "" ) ); * * node.appendChild( document.createElement("div") ); * * node.appendChild( document.createTextNode( "" ) ); * * //3 * console.log( node.childNodes.length ); * * UE.dom.domUtils.trimWhiteTextNode( node ); * * //1 * console.log( node.childNodes.length ); * ``` */ 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') { //20200513 classname带todo的不处理 解决多选框设置字体删除框 if (node === ci.parentNode && !(ci.className && ci.className.indexOf('todo') != -1)) { domUtils.trimWhiteTextNode(node); if (node.childNodes.length == 1) { // 遍历ci元素的所有属性 for (var t = 0, attr; attr = ci.attributes[t++];) { // 将每个属性设置到node元素上 if(attr.name == 'style'){ continue; } node.setAttribute(attr.name, attr.value); } 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]; } } } //20200513 classname带todo的不处理 解决多选框设置字体删除框 if (domUtils.isSameStyle(ci, node) && !(ci.className && ci.className.indexOf('todo') != -1)) { domUtils.remove(ci, true); } continue; } if (domUtils.isSameElement(node, ci)) { domUtils.remove(ci, true); } } }, /** * 原生方法getElementsByTagName的封装 * @method getElementsByTagName * @param { Node } node 目标节点对象 * @param { String } tagName 需要查找的节点的tagName, 多个tagName以空格分割 * @return { 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提取到父节点上 * @method mergeToParent * @param { Element } node 需要提取的元素对象 * @example * ```html *
*
* *
*
* * * ``` */ 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的左右兄弟节点 * @method mergeSibling * @param { Element } node 需要合并的目标节点 * @example * ```html * xxxxoooxxxx * * * ``` */ /** * 合并节点node的左右兄弟节点, 可以根据给定的条件选择是否忽略合并左节点。 * @method mergeSibling * @param { Element } node 需要合并的目标节点 * @param { Boolean } ignorePre 是否忽略合并左节点 * @example * ```html * xxxxoooxxxx * * * ``` */ /** * 合并节点node的左右兄弟节点,可以根据给定的条件选择是否忽略合并左右节点。 * @method mergeSibling * @param { Element } node 需要合并的目标节点 * @param { Boolean } ignorePre 是否忽略合并左节点 * @param { Boolean } ignoreNext 是否忽略合并右节点 * @remind 如果同时忽略左右节点, 则该操作什么也不会做 * @example * ```html * 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及其子节点不会被选中 * @method unSelectable * @param { Element } node 需要执行操作的dom元素 * @remind 执行该操作后的节点, 将不能被鼠标选中 * @example * ```javascript * UE.dom.domUtils.unSelectable( document.body ); * ``` */ unSelectable: ie && browser.ie9below || 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.msUserSelect = node.style.KhtmlUserSelect = 'none'; }, /** * 删除节点node上的指定属性名称的属性 * @method removeAttributes * @param { Node } node 需要删除属性的节点对象 * @param { String } attrNames 可以是空格隔开的多个属性名称,该操作将会依次删除相应的属性 * @example * ```html *
* xxxxx *
* * * ``` */ /** * 删除节点node上的指定属性名称的属性 * @method removeAttributes * @param { Node } node 需要删除属性的节点对象 * @param { Array } attrNames 需要删除的属性名数组 * @example * ```html *
* 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 = ''; var val = node.getAttributeNode('style'); !browser.ie && val && node.removeAttributeNode(val); } node.removeAttribute(ci); } }, /** * 在doc下创建一个标签名为tag,属性为attrs的元素 * @method createElement * @param { DomDocument } doc 新创建的元素属于该document节点创建 * @param { String } tagName 需要创建的元素的标签名 * @param { Object } attrs 新创建的元素的属性key-value集合 * @return { Element } 新创建的元素对象 * @example * ```javascript * var ele = UE.dom.domUtils.createElement( document, 'div', { * id: 'test' * } ); * * //output: DIV * console.log( ele.tagName ); * * //output: test * console.log( ele.id ); * * ``` */ createElement: function (doc, tag, attrs) { return domUtils.setAttributes(doc.createElement(tag), attrs) }, /** * 为节点node添加属性attrs,attrs为属性键值对 * @method setAttributes * @param { Element } node 需要设置属性的元素对象 * @param { Object } attrs 需要设置的属性名-值对 * @return { Element } 设置属性的元素对象 * @example * ```html * * * * */ 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经过计算后的样式值 * @method getComputedStyle * @param { Element } element 需要获取样式的元素对象 * @param { String } styleName 需要获取的样式名 * @return { String } 获取到的样式值 * @example * ```html * * * * * * ``` */ 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指定的className * @method removeClasses * @param { Element } ele 需要删除class的元素节点 * @param { String } classNames 需要删除的className, 多个className之间以空格分开 * @example * ```html * xxx * * * ``` */ /** * 删除元素element指定的className * @method removeClasses * @param { Element } ele 需要删除class的元素节点 * @param { Array } classNames 需要删除的className数组 * @example * ```html * 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 * @method addClass * @param { Node } ele 需要增加className的元素 * @param { String } classNames 需要添加的className, 多个className之间以空格分割 * @remind 相同的类名不会被重复添加 * @example * ```html * * * * ``` */ /** * 判断元素element是否包含给定的样式类名className * @method hasClass * @param { Node } ele 需要检测的元素 * @param { Array } classNames 需要检测的className数组 * @return { Boolean } 元素是否包含所有给定的className * @example * ```html * * * * ``` */ 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; }, /** * 阻止事件默认行为 * @method preventDefault * @param { Event } evt 需要阻止默认行为的事件对象 * @example * ```javascript * UE.dom.domUtils.preventDefault( evt ); * ``` */ preventDefault: function (evt) { evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false); }, /** * 删除元素element指定的样式 * @method removeStyle * @param { Element } element 需要删除样式的元素 * @param { String } styleName 需要删除的样式名 * @example * ```html * * * * ``` */ removeStyle: function (element, name) { if (browser.ie) { //针对color先单独处理一下 if (name == 'color') { name = '(^|;)' + name; } element.style.cssText = element.style.cssText.replace(new RegExp(name + '[^:]*:[^;]+;?', 'ig'), '') } 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的style属性的指定值 * @method getStyle * @param { Element } element 需要获取属性值的元素 * @param { String } styleName 需要获取的style的名称 * @warning 该方法仅获取元素style属性中所标明的值 * @return { String } 该元素包含指定的style属性值 * @example * ```html *
* * * ``` */ getStyle: function (element, name) { var value = element.style[utils.cssStyleToDomStyle(name)]; return utils.fixColor(name, value); }, /** * 为元素element设置样式属性值 * @method setStyle * @param { Element } element 需要设置样式的元素 * @param { String } styleName 样式名 * @param { String } styleValue 样式值 * @example * ```html *
* * * ``` */ setStyle: function (element, name, value) { element.style[utils.cssStyleToDomStyle(name)] = value; if (!utils.trim(element.style.cssText)) { this.removeAttributes(element, 'style') } }, /** * 为元素element设置多个样式属性值 * @method setStyles * @param { Element } element 需要设置样式的元素 * @param { Object } styles 样式名值对 * @example * ```html *
* * * ``` */ setStyles: function (element, styles) { for (var name in styles) { if (styles.hasOwnProperty(name)) { domUtils.setStyle(element, name, styles[name]); } } }, /** * 删除_moz_dirty属性 * @private * @method removeDirtyAttr */ removeDirtyAttr: function (node) { for (var i = 0, ci, nodes = node.getElementsByTagName('*'); ci = nodes[i++];) { ci.removeAttribute('_moz_dirty'); } node.removeAttribute('_moz_dirty'); }, /** * 获取子节点的数量 * @method getChildCount * @param { Element } node 需要检测的元素 * @return { Number } 给定的node元素的子节点数量 * @example * ```html *
* *
* * * ``` */ /** * 根据给定的过滤规则, 获取符合条件的子节点的数量 * @method getChildCount * @param { Element } node 需要检测的元素 * @param { Function } fn 过滤器, 要求对符合条件的子节点返回true, 反之则要求返回false * @return { Number } 符合过滤条件的node元素的子节点数量 * @example * ```html *
* *
* * * ``` */ 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; }, /** * 判断给定节点是否为占位的空节点 * @method isEmptyNode * @param { Node } node 需要检测的节点对象 * @return { Boolean } 节点是否为空 * @example * ```javascript * UE.dom.domUtils.isEmptyNode( document.body ); * ``` */ isEmptyNode: function (node) { return !node.firstChild || domUtils.getChildCount(node, function (node) { return !domUtils.isBr(node) && !domUtils.isBookmarkNode(node) && !domUtils.isWhitespace(node) }) == 0 }, /*没有子元素的不占位的空节点*/ isNodeEmpty: function (node) { return !node.firstChild || (node.innerText == '' && !node.querySelector('br') && !node.querySelector('img') && !node.querySelector('canvas') && !node.querySelector('iframe') && !node.querySelector('hr')) || domUtils.getChildCount(node, function (node) { return !domUtils.isBookmarkNode(node) //是bk,返回false }) == 0 }, clearSelectedArr: function (nodes) { var node; while (node = nodes.pop()) { domUtils.removeAttributes(node, ['class']); } }, /** * 将显示区域滚动到指定节点的位置 * @method scrollToView * @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; if(RichTextUitl.topOffsetScrollDiv){ offset = document.querySelector(RichTextUitl.topOffsetScrollDiv).clientHeight * -1 + offsetTop; } offset += (node.offsetHeight || 0); var elementPosition = domUtils.getXY(node); offset += elementPosition.y; var currentScroll = getScrollPosition(win).y; // offset += 50; if(RichTextUitl.topOffsetScrollDiv){ currentScroll = document.querySelector(RichTextUitl.topOffsetScrollDiv).scrollTop; if (offset > currentScroll || offset < currentScroll - winHeight) { document.querySelector(RichTextUitl.topOffsetScrollDiv).scrollTo(0, offset + (offset < 0 ? -20 : 20)); } }else{ if (offset > currentScroll || offset < currentScroll - winHeight) { win.scrollTo(0, offset + (offset < 0 ? -20 : 20)); } } }, /** * 判断给定节点是否为br * @method isBr * @param { Node } node 需要判断的节点对象 * @return { Boolean } 给定的节点是否是br节点 */ isBr: function (node) { return node.nodeType == 1 && node.tagName == 'BR'; }, /** * 判断给定的节点是否是一个“填充”节点 * @private * @method isFillChar * @param { Node } node 需要判断的节点 * @param { Boolean } isInStart 是否从节点内容的开始位置匹配 * @returns { Boolean } 节点是否是填充节点 */ isFillChar: function (node, isInStart) { if (node.nodeType != 3) return false; var text = node.nodeValue; if (isInStart) { return new RegExp('^' + domUtils.fillChar).test(text) } return !text.replace(new RegExp(domUtils.fillChar, 'g'), '').length }, /* * 是否在段落的末尾 * range:光标 * dom:是否在dom的末尾 * 只考虑了没有选区的情况 * */ isEndInBlock: function (range, tagName) { var tmpRange = range.cloneRange(); if (tagName) { //如果是在一段的最后,移动光标到最后 while (!domUtils.isBody(tmpRange.startContainer) && tmpRange.startContainer.nodeName != tagName && (tmpRange.startOffset == (tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer.childNodes.length : tmpRange.startContainer.nodeValue.length) || tmpRange.startContainer.lastChild.nodeName == 'BR' && tmpRange.startOffset == (tmpRange.startContainer.nodeType == 1 ? tmpRange.endContainer.childNodes.length - 1 : tmpRange.startContainer.nodeValue.length - 1))) { tmpRange.setEndAfter(tmpRange.startContainer).collapse(); } } else { //如果是在一段的最后,移动光标到最后 while (!domUtils.isBlockElm(tmpRange.startContainer) && tmpRange.startOffset == (tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer.childNodes.length : tmpRange.startContainer.nodeValue.length)) { tmpRange.setEndAfter(tmpRange.startContainer).collapse(); } } if (domUtils.isBlockElm(tmpRange.startContainer) && (tmpRange.startOffset == tmpRange.startContainer.childNodes.length || (tmpRange.startContainer.lastChild.nodeName == 'BR' && tmpRange.startOffset == tmpRange.startContainer.childNodes.length - 1))) { return true; } else { return false; } }, 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; }, /** * 判断给定的元素是否是一个空元素 * @method isEmptyBlock * @param { Element } node 需要判断的元素 * @return { Boolean } 是否是空元素 * @example * ```html *
* * * ``` */ /** * 根据指定的判断规则判断给定的元素是否是一个空元素 * @method isEmptyBlock * @param { Element } node 需要判断的元素 * @param { RegExp } reg 对内容执行判断的正则表达式对象 * @return { Boolean } 是否是空元素 */ isEmptyBlock: function (node, reg) { if (node.nodeType != 1) return 0; reg = reg || new RegExp('[ \xa0\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; }, /** * 移动元素使得该元素的位置移动指定的偏移量的距离 * @method setViewportOffset * @param { Element } element 需要设置偏移量的元素 * @param { Object } offset 偏移量, 形如{ left: 100, top: 50 }的一个键值对, 表示该元素将在 * 现有的位置上向水平方向偏移offset.left的距离, 在竖直方向上偏移 * offset.top的距离 * @example * ```html *
* * * ``` */ setViewportOffset: function (element, offset) { var left = parseInt(element.style.left) | 0; var ttop = 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 = ttop + offsetTop + 'px'; } }, /** * 用“填充字符”填充节点 * @method fillNode * @private * @param { DomDocument } doc 填充的节点所在的docment对象 * @param { Node } node 需要填充的节点对象 * @example * ```html *
* * * ``` */ fillNode: function (doc, node) { var tmpNode = browser.ie ? doc.createTextNode(domUtils.fillChar) : doc.createElement('br'); node.innerHTML = ''; node.appendChild(tmpNode); }, /** * 把节点src的所有子节点追加到另一个节点tag上去 * @method moveChild * @param { Node } src 源节点, 该节点下的所有子节点将被移除 * @param { Node } tag 目标节点, 从源节点移除的子节点将被追加到该节点下 * @example * ```html *
* *
*
*
*
* * * ``` */ /** * 把节点src的所有子节点移动到另一个节点tag上去, 可以通过dir参数控制附加的行为是“追加”还是“插入顶部” * @method moveChild * @param { Node } src 源节点, 该节点下的所有子节点将被移除 * @param { Node } tag 目标节点, 从源节点移除的子节点将被附加到该节点下 * @param { Boolean } dir 附加方式, 如果为true, 则附加进去的节点将被放到目标节点的顶部, 反之,则放到末尾 * @example * ```html *
* *
*
*
*
* * * ``` */ moveChild: function (src, tag, dir) { while (src.firstChild) { if (dir && tag.firstChild) { tag.insertBefore(src.lastChild, tag.firstChild); } else { tag.appendChild(src.firstChild); } } }, /** * 判断节点的标签上是否不存在任何属性 * @method hasNoAttributes * @private * @param { Node } node 需要检测的节点对象 * @return { Boolean } 节点是否不包含任何属性 * @example * ```html *
xxxx
* * * ``` */ hasNoAttributes: function (node) { return browser.ie ? /^<\w+\s*?>/.test(node.outerHTML) : node.attributes.length == 0; }, /** * 检测节点是否是UEditor所使用的辅助节点 * @method isCustomeNode * @private * @param { Node } node 需要检测的节点 * @remind 辅助节点是指编辑器要完成工作临时添加的节点, 在输出的时候将会从编辑器内移除, 不会影响最终的结果。 * @return { Boolean } 给定的节点是否是一个辅助节点 */ isCustomeNode: function (node) { return node.nodeType == 1 && node.getAttribute('_ue_custom_node_'); }, /** * 检测节点的标签是否是给定的标签 * @method isTagNode * @param { Node } node 需要检测的节点对象 * @param { String } tagName 标签 * @return { Boolean } 节点的标签是否是给定的标签 * @example * ```html *
* * * ``` */ isTagNode: function (node, tagNames) { return node.nodeType == 1 && new RegExp('\\b' + node.tagName + '\\b', 'i').test(tagNames) }, /** * 给定一个节点数组,在通过指定的过滤器过滤后, 获取其中满足过滤条件的第一个节点 * @method filterNodeList * @param { Array } nodeList 需要过滤的节点数组 * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false * @return { Node | NULL } 如果找到符合过滤条件的节点, 则返回该节点, 否则返回NULL * @example * ```javascript * var divNodes = document.getElementsByTagName("div"); * divNodes = [].slice.call( divNodes, 0 ); * * //output: null * console.log( UE.dom.domUtils.filterNodeList( divNodes, function ( node ) { * return node.tagName.toLowerCase() !== 'div'; * } ) ); * ``` */ /** * 给定一个节点数组nodeList和一组标签名tagNames, 获取其中能够匹配标签名的节点集合中的第一个节点 * @method filterNodeList * @param { Array } nodeList 需要过滤的节点数组 * @param { String } tagNames 需要匹配的标签名, 多个标签名之间用空格分割 * @return { Node | NULL } 如果找到标签名匹配的节点, 则返回该节点, 否则返回NULL * @example * ```javascript * var divNodes = document.getElementsByTagName("div"); * divNodes = [].slice.call( divNodes, 0 ); * * //output: null * console.log( UE.dom.domUtils.filterNodeList( divNodes, 'a span' ) ); * ``` */ /** * 给定一个节点数组,在通过指定的过滤器过滤后, 如果参数forAll为true, 则会返回所有满足过滤 * 条件的节点集合, 否则, 返回满足条件的节点集合中的第一个节点 * @method filterNodeList * @param { Array } nodeList 需要过滤的节点数组 * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false * @param { Boolean } forAll 是否返回整个节点数组, 如果该参数为false, 则返回节点集合中的第一个节点 * @return { Array | Node | NULL } 如果找到符合过滤条件的节点, 则根据参数forAll的值决定返回满足 * 过滤条件的节点数组或第一个节点, 否则返回NULL * @example * ```javascript * var divNodes = document.getElementsByTagName("div"); * divNodes = [].slice.call( divNodes, 0 ); * * //output: 3(假定有3个div) * console.log( divNodes.length ); * * var nodes = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) { * return node.tagName.toLowerCase() === 'div'; * }, true ); * * //output: 3 * console.log( nodes.length ); * * var node = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) { * return node.tagName.toLowerCase() === 'div'; * }, false ); * * //output: div * console.log( node.nodeName ); * ``` */ 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 }, /** * 查询给定的range选区是否在给定的node节点内,且在该节点的最末尾 * @method isInNodeEndBoundary * @param { UE.dom.Range } rng 需要判断的range对象, 该对象的startContainer不能为NULL * @param node 需要检测的节点对象 * @return { Number } 如果给定的选取range对象是在node内部的最末端, 则返回1, 否则返回0 */ 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 || start.lastChild.nodeName == 'BR' && rng.startOffset == start.childNodes.length - 1)) { return 0; } while (start !== node) { if (start.nextSibling && start.nextSibling.nodeName != 'BR') { 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; }, fillHtml: browser.ie11below ? ' ' : '
' }; var fillCharReg = new RegExp(domUtils.fillChar, 'g'); // core/Range.js /** * Range封装 * @file * @module UE.dom * @class Range * @since 1.2.6.1 */ /** * dom操作封装 * @unfile * @module UE.dom */ /** * Range实现类,本类是UEditor底层核心类,封装不同浏览器之间的Range操作。 * @unfile * @module UE.dom * @class Range */ (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 && 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; } /** * 创建一个跟document绑定的空的Range实例 * @constructor * @param { Document } document 新建的选区所属的文档对象 */ /** * @property { Node } startContainer 当前Range的开始边界的容器节点, 可以是一个元素节点或者是文本节点 */ /** * @property { Node } startOffset 当前Range的开始边界容器节点的偏移量, 如果是元素节点, * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符 */ /** * @property { Node } endContainer 当前Range的结束边界的容器节点, 可以是一个元素节点或者是文本节点 */ /** * @property { Node } endOffset 当前Range的结束边界容器节点的偏移量, 如果是元素节点, * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符 */ /** * @property { Boolean } collapsed 当前Range是否闭合 * @default true * @remind Range是闭合的时候, startContainer === endContainer && startOffset === endOffset */ /** * @property { Document } document 当前Range所属的Document对象 * @remind 不同range的的document属性可以是不同的 */ 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 = { /** * 克隆选区的内容到一个DocumentFragment里 * @method cloneContents * @return { DocumentFragment | NULL } 如果选区是闭合的将返回null, 否则, 返回包含所clone内容的DocumentFragment元素 * @example * ```html * * * xx[xxx]x * * * * ``` */ cloneContents: function () { return this.collapsed ? null : execContentsAction(this, 0); }, /** * 删除当前选区范围中的所有内容 * @method deleteContents * @remind 执行完该操作后, 当前Range对象变成了闭合状态 * @return { UE.dom.Range } 当前操作的Range对象 * @example * ```html * * * xx[xxx]x * * * * ``` */ 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; }, /** * 将当前选区的内容提取到一个DocumentFragment里 * @method extractContents * @remind 执行该操作后, 选区将变成闭合状态 * @warning 执行该操作后, 原来选区所选中的内容将从dom树上剥离出来 * @return { DocumentFragment } 返回包含所提取内容的DocumentFragment对象 * @example * ```html * * * xx[xxx]x * * * */ extractContents: function () { return this.collapsed ? null : execContentsAction(this, 2); }, /** * 设置Range的开始容器节点和偏移量 * @method setStart * @remind 如果给定的节点是元素节点,那么offset指的是其子元素中索引为offset的元素, * 如果是文本节点,那么offset指的是其文本内容的第offset个字符 * @remind 如果提供的容器节点是一个不能包含子元素的节点, 则该选区的开始容器将被设置 * 为该节点的父节点, 此时, 其距离开始容器的偏移量也变成了该节点在其父节点 * 中的索引 * @param { Node } node 将被设为当前选区开始边界容器的节点对象 * @param { int } offset 选区的开始位置偏移量 * @return { UE.dom.Range } 当前range对象 * @example * ```html * * xxxxxxxxxxxxx[xxx] * * * ``` * @example * ```html * * xxx[xx]x * * * ``` */ setStart: function (node, offset) { return setEndPoint(true, node, offset, this); }, /** * 设置Range的结束容器和偏移量 * @method setEnd * @param { Node } node 作为当前选区结束边界容器的节点对象 * @param { int } offset 结束边界的偏移量 * @see UE.dom.Range:setStart(Node,int) * @return { UE.dom.Range } 当前range对象 */ setEnd: function (node, offset) { return setEndPoint(false, node, offset, this); }, /** * 将Range开始位置设置到node节点之后 * @method setStartAfter * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引+1 * @param { Node } node 选区的开始边界将紧接着该节点之后 * @return { UE.dom.Range } 当前range对象 * @example * ```html * * xxxxxxx[xxxx] * * * ``` */ setStartAfter: function (node) { return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1); }, /** * 将Range开始位置设置到node节点之前 * @method setStartBefore * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引 * @param { Node } node 新的选区开始位置在该节点之前 * @see UE.dom.Range:setStartAfter(Node) * @return { UE.dom.Range } 当前range对象 */ setStartBefore: function (node) { return this.setStart(node.parentNode, domUtils.getNodeIndex(node)); }, /** * 将Range结束位置设置到node节点之后 * @method setEndAfter * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引+1 * @param { Node } node 目标节点 * @see UE.dom.Range:setStartAfter(Node) * @return { UE.dom.Range } 当前range对象 * @example * ```html * * [xxxxxxx]xxxx * * * ``` */ setEndAfter: function (node) { return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1); }, /** * 将Range结束位置设置到node节点之前 * @method setEndBefore * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引 * @param { Node } node 目标节点 * @see UE.dom.Range:setEndAfter(Node) * @return { UE.dom.Range } 当前range对象 */ setEndBefore: function (node) { return this.setEnd(node.parentNode, domUtils.getNodeIndex(node)); }, /** * 设置Range的开始位置到node节点内的第一个子节点之前 * @method setStartAtFirst * @remind 选区的开始容器将变成给定的节点, 且偏移量为0 * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。 * @param { Node } node 目标节点 * @see UE.dom.Range:setStartBefore(Node) * @return { UE.dom.Range } 当前range对象 * @example * ```html * * xxxxx[xx]xxxx * * * ``` */ setStartAtFirst: function (node) { return this.setStart(node, 0); }, /** * 设置Range的开始位置到node节点内的最后一个节点之后 * @method setStartAtLast * @remind 选区的开始容器将变成给定的节点, 且偏移量为该节点的子节点数 * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。 * @param { Node } node 目标节点 * @see UE.dom.Range:setStartAtFirst(Node) * @return { UE.dom.Range } 当前range对象 */ setStartAtLast: function (node) { return this.setStart(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length); }, /** * 设置Range的结束位置到node节点内的第一个节点之前 * @method setEndAtFirst * @param { Node } node 目标节点 * @remind 选区的结束容器将变成给定的节点, 且偏移量为0 * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。 * @see UE.dom.Range:setStartAtFirst(Node) * @return { UE.dom.Range } 当前range对象 */ setEndAtFirst: function (node) { return this.setEnd(node, 0); }, /** * 设置Range的结束位置到node节点内的最后一个节点之后 * @method setEndAtLast * @param { Node } node 目标节点 * @remind 选区的结束容器将变成给定的节点, 且偏移量为该节点的子节点数量 * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。 * @see UE.dom.Range:setStartAtFirst(Node) * @return { UE.dom.Range } 当前range对象 */ setEndAtLast: function (node) { return this.setEnd(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length); }, /** * 选中给定节点 * @method selectNode * @remind 此时, 选区的开始容器和结束容器都是该节点的父节点, 其startOffset是该节点在父节点中的位置索引, * 而endOffset为startOffset+1 * @param { Node } node 需要选中的节点 * @return { UE.dom.Range } 当前range对象,此时的range仅包含当前给定的节点对象 * @example * ```html * * xxxxx[xx]xxxx * * * ``` */ selectNode: function (node) { return this.setStartBefore(node).setEndAfter(node); }, /** * 选中给定节点内部的所有节点 * @method selectNodeContents * @remind 此时, 选区的开始容器和结束容器都是该节点, 其startOffset为0, * 而endOffset是该节点的子节点数。 * @param { Node } node 目标节点, 当前range将包含该节点内的所有节点 * @return { UE.dom.Range } 当前range对象, 此时range仅包含给定节点的所有子节点 * @example * ```html * * xxxxx[xx]xxxx * * * ``` */ selectNodeContents: function (node) { return this.setStart(node, 0).setEndAtLast(node); }, /** * clone当前Range对象 * @method cloneRange * @remind 返回的range是一个全新的range对象, 其内部所有属性与当前被clone的range相同。 * @return { UE.dom.Range } 当前range对象的一个副本 */ cloneRange: function () { var me = this; return new Range(me.document).setStart(me.startContainer, me.startOffset).setEnd(me.endContainer, me.endOffset); }, /** * 向当前选区的结束处闭合选区 * @method collapse * @return { UE.dom.Range } 当前range对象 * @example * ```html * * xxxxx[xx]xxxx * * * ``` */ /** * 闭合当前选区,根据给定的toStart参数项决定是向当前选区开始处闭合还是向结束处闭合, * 如果toStart的值为true,则向开始位置闭合, 反之,向结束位置闭合。 * @method collapse * @param { Boolean } toStart 是否向选区开始处闭合 * @return { UE.dom.Range } 当前range对象,此时range对象处于闭合状态 * @see UE.dom.Range:collapse() * @example * ```html * * xxxxx[xx]xxxx * * * ``` */ 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的开始位置和结束位置,使其"收缩"到最小的位置 * @method shrinkBoundary * @return { UE.dom.Range } 当前range对象 * @example * ```html * xxxx[xxxxx] => xxxx[xxxxx] * ``` * * @example * ```html * * x[xx]xxx * * * ``` * * @example * ```html * [xxxxxxxxxxx] => [xxxxxxxxxxx] * ``` */ /** * 调整range的开始位置和结束位置,使其"收缩"到最小的位置, * 如果ignoreEnd的值为true,则忽略对结束位置的调整 * @method shrinkBoundary * @param { Boolean } ignoreEnd 是否忽略对结束位置的调整 * @param { Boolean } toStart 是否调整到前一个元素的最后 * @return { UE.dom.Range } 当前range对象 * @see UE.dom.domUtils.Range:shrinkBoundary() */ shrinkBoundary: function (ignoreEnd, toStart) { 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] } //2022-7-5 如果光标后的元素是不可编辑的元素,移到前一个元素后 if (!toStart && me.startContainer.childNodes[me.startOffset] && !(me.startContainer.childNodes[me.startOffset].nodeType == 1 && me.startContainer.childNodes[me.startOffset].getAttribute('contenteditable'))) { while (me.startContainer.nodeType == 1 //是element && (child = me.startContainer.childNodes[me.startOffset]) //子节点也是element && check(child)) { me.setStart(child, 0); } } else { while (me.startContainer.nodeType == 1 //是element && (child = me.startContainer.childNodes[me.startOffset - 1]) //子节点也是element && !(child.nodeType == 1 && child.getAttribute('contenteditable')) && check(child)) { me.setStart(child, child.childNodes.length); } } 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; }, /** * 获取离当前选区内包含的所有节点最近的公共祖先节点, * @method getCommonAncestor * @remind 返回的公共祖先节点一定不是range自身的容器节点, 但有可能是一个文本节点 * @return { Node } 当前range对象内所有节点的公共祖先节点 * @example * ```html * //选区示例 * xxxx[xxx]xxxxxx * * ``` */ /** * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到 * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点 * @method getCommonAncestor * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点 * @return { Node } 当前range对象内所有节点的公共祖先节点 * @see UE.dom.Range:getCommonAncestor() * @example * ```html * * * * xxxxxxxxx[xxx]xxxxxxxx * * * * * ``` */ /** * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到 * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点; 同时可以根据 * ignoreTextNode 参数的取值决定是否忽略类型为文本节点的祖先节点。 * @method getCommonAncestor * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点 * @param { Boolean } ignoreTextNode 获取祖先节点的过程中是否忽略类型为文本节点的祖先节点 * @return { Node } 当前range对象内所有节点的公共祖先节点 * @see UE.dom.Range:getCommonAncestor() * @see UE.dom.Range:getCommonAncestor(Boolean) * @example * ```html * * * * xxxxxxxx[x]xxxxxxxxxxx * * * * * ``` */ 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); }, /** * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上 * @method trimBoundary * @remind 该操作有可能会引起文本节点被切开 * @return { UE.dom.Range } 当前range对象 * @example * ```html * * //选区示例 * xxx[xxxxx]xxx * * * ``` */ /** * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上, * 可以根据 ignoreEnd 参数的值决定是否调整对结束边界的调整 * @method trimBoundary * @param { Boolean } ignoreEnd 是否忽略对结束边界的调整 * @return { UE.dom.Range } 当前range对象 * @example * ```html * * //选区示例 * xxx[xxxxx]xxx * * * ``` */ 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; }, /** * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则什么也不做 * @method txtToElmBoundary * @remind 该操作不会修改dom节点 * @return { UE.dom.Range } 当前range对象 */ /** * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则根据参数项 * ignoreCollapsed 的值决定是否执行该调整 * @method txtToElmBoundary * @param { Boolean } ignoreCollapsed 是否忽略选区的闭合状态, 如果该参数取值为true, 则 * 不论选区是否闭合, 都会执行该操作, 反之, 则不会对闭合的选区执行该操作 * @return { UE.dom.Range } 当前range对象 */ txtToElmBoundary: function (ignoreCollapsed) { 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 (ignoreCollapsed || !this.collapsed) { adjust(this, 'start'); adjust(this, 'end'); } return this; }, /** * 在当前选区的开始位置前插入节点,新插入的节点会被该range包含 * @method insertNode * @param { Node } node 需要插入的节点 * @remind 插入的节点可以是一个DocumentFragment依次插入多个节点 * @return { UE.dom.Range } 当前range对象 */ 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); }, /** * 闭合选区到当前选区的开始位置, 并且定位光标到闭合后的位置 * @method setCursor * @return { UE.dom.Range } 当前range对象 * @see UE.dom.Range:collapse() */ /** * 闭合选区,可以根据参数toEnd的值控制选区是向前闭合还是向后闭合, 并且定位光标到闭合后的位置。 * @method setCursor * @param { Boolean } toEnd 是否向后闭合, 如果为true, 则闭合选区时, 将向结束容器方向闭合, * 反之,则向开始容器方向闭合 * @return { UE.dom.Range } 当前range对象 * @see UE.dom.Range:collapse(Boolean) */ setCursor: function (toEnd, noFillData) { return this.collapse(!toEnd).select(noFillData); }, /** * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置 * @method createBookmark * @param { Boolean } serialize 控制返回的标记位置是对当前位置的引用还是ID,如果该值为true,则 * 返回标记位置的ID, 反之则返回标记位置节点的引用 * @return { Object } 返回一个书签记录键值对, 其包含的key有: start => 开始标记的ID或者引用, * end => 结束标记的ID或引用, id => 当前标记的类型, 如果为true,则表示 * 返回的记录的类型为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 } }, /** * 调整当前range的边界到书签位置,并删除该书签对象所标记的位置内的节点 * @method moveToBookmark * @param { BookMark } bookmark createBookmark所创建的标签对象 * @return { UE.dom.Range } 当前range对象 * @see UE.dom.Range:createBookmark(Boolean) */ 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的边界,使其"放大"到最近的父节点 * @method enlarge * @remind 会引起选区的变化 * @return { UE.dom.Range } 当前range对象 */ /** * 调整range的边界,使其"放大"到最近的父节点,根据参数 toBlock 的取值, 可以 * 要求扩大之后的父节点是block节点 * @method enlarge * @param { Boolean } toBlock 是否要求扩大之后的父节点必须是block节点 * @return { UE.dom.Range } 当前range对象 */ 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; }, enlargeToBlockElm: function (ignoreEnd) { while (!domUtils.isBlockElm(this.startContainer)) { this.setStartBefore(this.startContainer); } if (!ignoreEnd) { while (!domUtils.isBlockElm(this.endContainer)) { this.setEndAfter(this.endContainer); } } return this; }, /** * 调整Range的边界,使其"缩小"到最合适的位置 * @method adjustmentBoundary * @return { UE.dom.Range } 当前range对象 * @see UE.dom.Range:shrinkBoundary() */ adjustmentBoundary: function () { if (!this.collapsed) { while (!domUtils.isBody(this.startContainer) && this.startOffset == this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length && this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length ) { this.setStartAfter(this.startContainer); } while (!domUtils.isBody(this.endContainer) && !this.endOffset && this.endContainer[this.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length ) { this.setEndBefore(this.endContainer); } } return this; }, /** * 给range选区中的内容添加给定的inline标签 * @method applyInlineStyle * @param { String } tagName 需要添加的标签名 * @example * ```html *

xxxx[xxxx]x

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

xxxx[xxxx]x

* ``` */ /** * 给range选区中的内容添加给定的inline标签, 并且为标签附加上一些初始化属性。 * @method applyInlineStyle * @param { String } tagName 需要添加的标签名 * @param { Object } attrs 跟随新添加的标签的属性 * @return { UE.dom.Range } 当前选区 * @example * ```html *

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)) { // 20200526 多选框设置字体后多选框外层套span font-size,导致多选框上移 // if (current.nodeType == 3 || dtd[tagName][current.tagName]) { //解决a标签不能设置颜色和 if ((current.nodeType == 3 || (dtd[tagName][current.tagName] && current.tagName != 'A' && current.tagName != 'SPAN' && current.tagName != 'STRIKE')) && !(current.className && current.className.indexOf('todo') > -1)) { 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); if (tagName == 'em') { elm.className = 'sqp-emphasize-dot' } //处理下滑线在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); }, /** * 移除当前选区内指定的inline标签,但保留其中的内容 * @method removeInlineStyle * @param { String } tagName 需要移除的标签名 * @return { UE.dom.Range } 当前的range对象 * @example * ```html * xx[xxxxyyyzz]z => range.removeInlineStyle(["em"]) => xx[xxxxyyyzz]z * ``` */ /** * 移除当前选区内指定的一组inline标签,但保留其中的内容 * @method removeInlineStyle * @param { Array } tagNameArr 需要移除的标签名的数组 * @return { UE.dom.Range } 当前的range对象 * @see UE.dom.Range:removeInlineStyle(String) */ 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; } //20200107去掉拆分后的空标签 if (next && next.nextSibling && next.nextSibling.nodeType == 1) { next = next.nextSibling; var nextvalue = next.innerText.replace(new RegExp(UE.dom.domUtils.fillChar, 'g'), '').replace(/^\s+|\s+$/g, ''); if (nextvalue == '' && next.nodeType == 1 && next.childNodes.length <= 1) { domUtils.remove(next); } } return this.moveToBookmark(bookmark); }, /** * 获取当前选中的自闭合的节点 * @method getClosedNode * @return { Node | NULL } 如果当前选中的是自闭合节点, 则返回该节点, 否则返回NULL */ 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所表示的选区 * @method select * @return { UE.dom.Range } 返回当前Range对象 */ //这里不区分ie9以上,trace:3824 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(domUtils.fillChar), tmp = this.document.createElement('span'); tmp.appendChild(this.document.createTextNode(domUtils.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(domUtils.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开始的位置 * @method scrollToView * @param { Window } win 当前range对象所属的window对象 * @return { UE.dom.Range } 当前Range对象 */ /** * 滚动到距离当前range开始位置 offset 的位置处 * @method scrollToView * @param { Window } win 当前range对象所属的window对象 * @param { Number } offset 距离range开始位置处的偏移量, 如果为正数, 则向下偏移, 反之, 则向上偏移 * @return { UE.dom.Range } 当前Range对象 */ 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; }, /** * 判断当前选区内容是否占位符 * @private * @method inFillChar * @return { Boolean } 如果是占位符返回true,否则返回false */ 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; }, /** * 保存 * @method createAddress * @private * @return { Boolean } 返回开始和结束的位置 * @example * ```html * *

* aaaa * * * bbbb * * *

* * * * ``` */ createAddress: function (ignoreEnd, ignoreTxt) { var addr = {}, me = this; function getAddress(isStart) { var node = isStart ? me.startContainer : me.endContainer; var hasFillChar = 0; var parents = domUtils.findParents(node, true, function (node) { return !domUtils.isBody(node) }), addrs = []; for (var i = 0, ci; ci = parents[i++];) { hasFillChar = 0; var index = domUtils.getNodeIndex(ci, ignoreTxt); if (domUtils.isFillChar(ci) && index == 0) { //20200702 8203不计 break; } else { //20200619 去除8203,还原不准 if (ci.parentNode && ci.parentNode.firstChild && domUtils.isFillChar(ci.parentNode.firstChild)) { hasFillChar = 1; } if (index > 0) { addrs.push(index - hasFillChar); } else { addrs.push(index); } } } var firstIndex = 0; hasFillChar = 0; if (ignoreTxt) { if (node.nodeType == 3) { var tmpNode = node.previousSibling; while (tmpNode && tmpNode.nodeType == 3) { firstIndex += tmpNode.nodeValue.replace(fillCharReg, '').length; tmpNode = tmpNode.previousSibling; } if (node.nodeValue.indexOf(domUtils.fillChar) > -1) { //8203和文字连在一起 hasFillChar = 1; } firstIndex += (isStart ? me.startOffset : me.endOffset) - hasFillChar; // firstIndex += (isStart ? me.startOffset : me.endOffset)// - (fillCharReg.test(node.nodeValue) ? 1 : 0 ) } else { if (node && node.firstChild && domUtils.isFillChar(node.firstChild)) { //

"8203" "XXX"

hasFillChar = 1; } node = node.childNodes[isStart ? me.startOffset : me.endOffset]; if (node) { firstIndex = domUtils.getNodeIndex(node, ignoreTxt) - hasFillChar; } 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 { if (node.nodeType == 3) { if (node.nodeValue.indexOf(domUtils.fillChar) > -1) { //8203和文字连在一起 hasFillChar = 1; } } else { if (node && node.firstChild && domUtils.isFillChar(node.firstChild)) { //

"8203" "XXX"

hasFillChar = 1; } } firstIndex = (isStart ? me.startOffset : me.endOffset) - hasFillChar; // firstIndex = isStart ? domUtils.isFillChar(node) ? 0 : 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(); } // if(addr.startAddress.length == 1){ // addr.startAddress.push(0) // } // if(addr.endAddress.length == 1){ // addr.endAddress.push(0) // } return addr; }, /** * 保存 * @method createAddress * @private * @return { Boolean } 返回开始和结束的位置 * @example * ```html * *

* aaaa * * * bbbb * * *

* * * * ``` */ moveToAddress: function (addr, ignoreEnd) { var me = this; function getNode(address, isStart) { var tmpNode = me.document.body, parentNode, offset; for (var i = 0, ci, l = address.length; i < l; i++) { ci = address[i]; parentNode = tmpNode; //20200619 去除8203,还原不准 if (tmpNode && tmpNode.firstChild && domUtils.isFillChar(tmpNode.firstChild) && tmpNode.childNodes.length > 1) { domUtils.remove(tmpNode.firstChild); } tmpNode = tmpNode.childNodes[ci]; if (!tmpNode) { offset = ci; break; } } if (isStart) { if (tmpNode) { me.setStartBefore(tmpNode) } else { me.setStart(parentNode, offset) } } else { if (tmpNode) { me.setEndBefore(tmpNode) } else { me.setEnd(parentNode, offset) } } } getNode(addr.startAddress, true); !ignoreEnd && addr.endAddress && getNode(addr.endAddress); return me; }, /** * 判断给定的Range对象是否和当前Range对象表示的是同一个选区 * @method equals * @param { UE.dom.Range } 需要判断的Range对象 * @return { Boolean } 如果给定的Range对象与当前Range对象表示的是同一个选区, 则返回true, 否则返回false */ equals: function (rng) { for (var p in this) { if (this.hasOwnProperty(p)) { if (this[p] !== rng[p]) return false } } return true; }, /** * 遍历range内的节点。每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点 * 作为其参数。 * @method traversal * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数 * @return { UE.dom.Range } 当前range对象 * @example * ```html * * * * * * * * * * * ``` */ /** * 遍历range内的节点。 * 每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点 * 作为其参数。 * 可以通过参数项 filterFn 来指定一个过滤器, 只有符合该过滤器过滤规则的节点才会触 * 发doFn函数的执行 * @method traversal * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数 * @param { Function } filterFn 过滤器, 该函数接受当前遍历的节点作为参数, 如果该节点满足过滤 * 规则, 请返回true, 该节点会触发doFn, 否则, 请返回false, 则该节点不 * 会触发doFn。 * @return { UE.dom.Range } 当前range对象 * @see UE.dom.Range:traversal(Function) * @example * ```html * * * * * * * * * * * ``` */ traversal: function (doFn, filterFn) { if (this.collapsed) return this; var bookmark = this.createBookmark(), end = bookmark.end, current = domUtils.getNextDomNode(bookmark.start, false, filterFn); while (current && current !== end && (domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING)) { var tmpNode = domUtils.getNextDomNode(current, false, filterFn); doFn(current); current = tmpNode; } return this.moveToBookmark(bookmark); } }; })(); // core/Selection.js /** * 选集 * @file * @module UE.dom * @class Selection * @since 1.2.6.1 */ /** * 选区集合 * @unfile * @module UE.dom * @class Selection */ (function () { function getBoundaryInformation(range, start) { var getIndex = domUtils.getNodeIndex; range = range.duplicate(); range.collapse(start); var parent = range.parentElement(); //如果节点里没有子节点,直接退出 if (!parent.hasChildNodes()) { return { container: parent, offset: 0 }; } var siblings = parent.children, child, testRange = range.duplicate(), startIndex = 0, endIndex = siblings.length - 1, index = -1, distance; while (startIndex <= endIndex) { index = Math.floor((startIndex + endIndex) / 2); child = siblings[index]; testRange.moveToElementText(child); var position = testRange.compareEndPoints('StartToStart', range); if (position > 0) { endIndex = index - 1; } else if (position < 0) { startIndex = index + 1; } else { //trace:1043 return { container: parent, offset: getIndex(child) }; } } if (index == -1) { testRange.moveToElementText(parent); testRange.setEndPoint('StartToStart', range); distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length; siblings = parent.childNodes; if (!distance) { child = siblings[siblings.length - 1]; return { container: child, offset: child.nodeValue.length }; } var i = siblings.length; while (distance > 0) { distance -= siblings[--i].nodeValue.length; } return { container: siblings[i], offset: -distance }; } testRange.collapse(position > 0); testRange.setEndPoint(position > 0 ? 'StartToStart' : 'EndToStart', range); distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length; if (!distance) { return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ? { container: parent, offset: getIndex(child) + (position > 0 ? 0 : 1) } : { container: child, offset: position > 0 ? 0 : child.childNodes.length } } while (distance > 0) { try { var pre = child; child = child[position > 0 ? 'previousSibling' : 'nextSibling']; distance -= child.nodeValue.length; } catch (e) { return { container: parent, offset: getIndex(pre) }; } } return { container: child, offset: position > 0 ? -distance : child.nodeValue.length + distance } } /** * 将ieRange转换为Range对象 * @param {Range} ieRange ieRange对象 * @param {Range} range Range对象 * @return {Range} range 返回转换后的Range对象 */ function transformIERangeToRange(ieRange, range) { if (ieRange.item) { range.selectNode(ieRange.item(0)); } else { var bi = getBoundaryInformation(ieRange, true); range.setStart(bi.container, bi.offset); if (ieRange.compareEndPoints('StartToEnd', ieRange) != 0) { bi = getBoundaryInformation(ieRange, false); range.setEnd(bi.container, bi.offset); } } return range; } /** * 获得ieRange * @param {Selection} sel Selection对象 * @return {ieRange} 得到ieRange */ function _getIERange(sel) { var ieRange; //ie下有可能报错 try { ieRange = sel.getNative().createRange(); } catch (e) { return null; } var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement(); if ((el.ownerDocument || el) === sel.document) { return ieRange; } return null; } var Selection = dom.Selection = function (doc) { var me = this, iframe; me.document = doc; if (browser.ie9below) { 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 = { rangeInBody: function (rng, txtRange) { var node = browser.ie9below || txtRange ? rng.item ? rng.item() : rng.parentElement() : rng.startContainer; return node === this.document.body || domUtils.inDoc(node, this.document); }, /** * 获取原生seleciton对象 * @method getNative * @return { Object } 获得selection对象 * @example * ```javascript * editor.selection.getNative(); * ``` */ getNative: function () { var doc = this.document; try { return !doc ? null : browser.ie9below ? doc.selection : domUtils.getWindow(doc).getSelection(); } catch (e) { return null; } }, /** * 获得ieRange * @method getIERange * @return { Object } 返回ie原生的Range * @example * ```javascript * editor.selection.getIERange(); * ``` */ getIERange: function () { var ieRange = _getIERange(this); if (!ieRange) { if (this._bakIERange) { return this._bakIERange; } } return ieRange; }, /** * 缓存当前选区的range和选区的开始节点 * @method cache */ cache: function () { this.clear(); this._cachedRange = this.getRange(); this._cachedStartElement = this.getStart(); this._cachedStartElementPath = this.getStartElementPath(); }, /** * 获取选区开始位置的父节点到body * @method getStartElementPath * @return { Array } 返回父节点集合 * @example * ```javascript * editor.selection.getStartElementPath(); * ``` */ getStartElementPath: function () { if (this._cachedStartElementPath) { return this._cachedStartElementPath; } var start = this.getStart(); if (start) { return domUtils.findParents(start, true, null, true) } return []; }, /** * 清空缓存 * @method clear */ clear: function () { this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null; }, /** * 编辑器是否得到了选区 * @method isFocus */ isFocus: function () { try { if (browser.ie9below) { var nativeRange = _getIERange(this); return !!(nativeRange && this.rangeInBody(nativeRange)); } else { return !!this.getNative().rangeCount; } } catch (e) { return false; } }, /** * 获取选区对应的Range * @method getRange * @return { Object } 得到Range对象 * @example * ```javascript * editor.selection.getRange(); * ``` */ 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 (browser.ie9below) { 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; }, /** * 获取开始元素,用于状态反射 * @method getStart * @return { Element } 获得开始元素 * @example * ```javascript * editor.selection.getStart(); * ``` */ getStart: function () { if (this._cachedStartElement) { return this._cachedStartElement; } var range = browser.ie9below ? this.getIERange() : this.getRange(), tmpRange, start, tmp, parent; if (browser.ie9below) { 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; }, /** * 得到选区中的文本 * @method getText * @return { String } 选区中包含的文本 * @example * ```javascript * editor.selection.getText(); * ``` */ getText: function () { var nativeSel, nativeRange; if (this.isFocus() && (nativeSel = this.getNative())) { nativeRange = browser.ie9below ? nativeSel.createRange() : nativeSel.getRangeAt(0); return browser.ie9below ? nativeRange.text : nativeRange.toString(); } return ''; }, /** * 清除选区 * @method clearRange * @example * ```javascript * editor.selection.clearRange(); * ``` */ clearRange: function () { this.getNative()[browser.ie9below ? 'empty' : 'removeAllRanges'](); } }; })(); // core/Editor.js /** * 编辑器主类,包含编辑器提供的大部分公用接口 * @file * @module UE * @class Editor * @since 1.2.6.1 */ /** * UEditor公用空间,UEditor所有的功能都挂载在该空间下 * @unfile * @module UE */ /** * UEditor的核心类,为用户提供与编辑器交互的接口。 * @unfile * @module UE * @class Editor */ (function () { var uid = 0, _selectionChangeTimer; /** * 获取编辑器的html内容,赋值到编辑器所在表单的textarea文本域里面 * @private * @method setValue * @param { UE.Editor } 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.getAttribute('name') && textarea.setAttribute('name', editor.options.textarea); textarea.value = editor.hasContents() ? (editor.options.allHtmlEnabled ? editor.getAllHtml() : editor.getContent(null, null, true)) : '' } function loadPlugins(me) { //初始化插件 for (var pi in UE.plugins) { UE.plugins[pi].call(me); } } function checkCurLang(I18N) { for (var lang in I18N) { return lang } } function langReadied(me) { me.langIsReady = true; me.fireEvent("langReady"); } /** * 编辑器准备就绪后会触发该事件 * @module UE * @class Editor * @event ready * @remind render方法执行完成之后,会触发该事件 * @remind * @example * ```javascript * editor.addListener( 'ready', function( editor ) { * editor.execCommand( 'focus' ); //编辑器家在完成后,让编辑器拿到焦点 * } ); * ``` */ /** * 执行destroy方法,会触发该事件 * @module UE * @class Editor * @event destroy * @see UE.Editor:destroy() */ /** * 执行reset方法,会触发该事件 * @module UE * @class Editor * @event reset * @see UE.Editor:reset() */ /** * 执行focus方法,会触发该事件 * @module UE * @class Editor * @event focus * @see UE.Editor:focus(Boolean) */ /** * 语言加载完成会触发该事件 * @module UE * @class Editor * @event langReady */ /** * 运行命令之后会触发该命令 * @module UE * @class Editor * @event beforeExecCommand */ /** * 运行命令之后会触发该命令 * @module UE * @class Editor * @event afterExecCommand */ /** * 运行命令之前会触发该命令 * @module UE * @class Editor * @event firstBeforeExecCommand */ /** * 在getContent方法执行之前会触发该事件 * @module UE * @class Editor * @event beforeGetContent * @see UE.Editor:getContent() */ /** * 在getContent方法执行之后会触发该事件 * @module UE * @class Editor * @event afterGetContent * @see UE.Editor:getContent() */ /** * 在getAllHtml方法执行时会触发该事件 * @module UE * @class Editor * @event getAllHtml * @see UE.Editor:getAllHtml() */ /** * 在setContent方法执行之前会触发该事件 * @module UE * @class Editor * @event beforeSetContent * @see UE.Editor:setContent(String) */ /** * 在setContent方法执行之后会触发该事件 * @module UE * @class Editor * @event afterSetContent * @see UE.Editor:setContent(String) */ /** * 每当编辑器内部选区发生改变时,将触发该事件 * @event selectionchange * @warning 该事件的触发非常频繁,不建议在该事件的处理过程中做重量级的处理 * @example * ```javascript * editor.addListener( 'selectionchange', function( editor ) { * console.log('选区发生改变'); * } */ /** * 在所有selectionchange的监听函数执行之前,会触发该事件 * @module UE * @class Editor * @event beforeSelectionChange * @see UE.Editor:selectionchange */ /** * 在所有selectionchange的监听函数执行完之后,会触发该事件 * @module UE * @class Editor * @event afterSelectionChange * @see UE.Editor:selectionchange */ /** * 编辑器内容发生改变时会触发该事件 * @module UE * @class Editor * @event contentChange */ /** * 以默认参数构建一个编辑器实例 * @constructor * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面 * @example * ```javascript * var editor = new UE.Editor(); * editor.execCommand('blod'); * ``` * @see UE.Config */ /** * 以给定的参数集合创建一个编辑器实例,对于未指定的参数,将应用默认参数。 * @constructor * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面 * @param { Object } setting 创建编辑器的参数 * @example * ```javascript * var editor = new UE.Editor(); * editor.execCommand('blod'); * ``` * @see UE.Config */ var Editor = UE.Editor = function (options) { var me = this; var FILE_MAX_SIZE = 15 * 1024 * 1024 * 1024 me.uid = uid++; EventBase.call(me); me.commands = {}; me.options = utils.extend(utils.clone(options || {}), UEDITOR_CONFIG, true); me.shortcutkeys = {}; me.inputRules = []; me.outputRules = []; //设置默认的常用属性 me.setOpt(Editor.defaultOptions(me)); /* 尝试异步加载后台配置 */ me.loadServerConfig(); // 分片上传最大支持 15G if(me.options.fileMaxSize > FILE_MAX_SIZE) { me.options.fileMaxSize = FILE_MAX_SIZE } if (!utils.isEmptyObject(UE.I18N)) { //修改默认的语言类型 me.options.lang = checkCurLang(UE.I18N); UE.plugin.load(me); langReadied(me); } else { utils.loadFile(document, { src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js", tag: "script", type: "text/javascript", defer: "defer" }, function () { try { UE.plugin.load(me); langReadied(me); }catch (e) { } }); } UE.instants['ueditorInstant' + me.uid] = me; }; Editor.prototype = { registerCommand: function (name, obj) { this.commands[name] = obj; }, /** * 编辑器对外提供的监听ready事件的接口, 通过调用该方法,达到的效果与监听ready事件是一致的 * @method ready * @param { Function } fn 编辑器ready之后所执行的回调, 如果在注册事件之前编辑器已经ready,将会 * 立即触发该回调。 * @remind 需要等待编辑器加载完成后才能执行的代码,可以使用该方法传入 * @example * ```javascript * editor.ready( function( editor ) { * editor.setContent('初始化完毕'); * } ); * ``` * @see UE.Editor.event:ready */ ready: function (fn) { var me = this; if (fn) { me.isReady ? fn.apply(me) : me.addListener('ready', fn); } }, /** * 该方法是提供给插件里面使用,设置配置项默认值 * @method setOpt * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置 * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。 * @param { String } key 编辑器的可接受的选项名称 * @param { * } val 该选项可接受的值 * @example * ```javascript * editor.setOpt( 'initContent', '欢迎使用编辑器' ); * ``` */ /** * 该方法是提供给插件里面使用,以{key:value}集合的方式设置插件内用到的配置项默认值 * @method setOpt * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置 * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。 * @param { Object } options 将要设置的选项的键值对对象 * @example * ```javascript * editor.setOpt( { * 'initContent': '欢迎使用编辑器' * } ); * ``` */ setOpt: function (key, val) { var obj = {}; if (utils.isString(key)) { obj[key] = val } else { obj = key; } utils.extend(this.options, obj, true); }, getOpt: function (key) { return this.options[key] }, /** * 销毁编辑器实例,使用textarea代替 * @method destroy * @example * ```javascript * 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 = me.iframe.offsetWidth + 'px'; textarea.style.height = me.iframe.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到指定容器 * @method render * @param { String } containerId 指定一个容器ID * @remind 执行该方法,会触发ready事件 * @warning 必须且只能调用一次 */ /** * 渲染编辑器的DOM到指定容器 * @method render * @param { Element } containerDom 直接指定容器对象 * @remind 执行该方法,会触发ready事件 * @warning 必须且只能调用一次 */ render: function (container) { var me = this, options = me.options, getStyleValue = function (attr) { return parseInt(domUtils.getComputedStyle(container, attr)); }; if (utils.isString(container)) { container = document.getElementById(container); } if (container) { if (options.initialFrameWidth) { options.minFrameWidth = options.initialFrameWidth } else { options.minFrameWidth = options.initialFrameWidth = container.offsetWidth; } if (options.initialFrameHeight) { options.minFrameHeight = options.initialFrameHeight } else { options.initialFrameHeight = options.minFrameHeight = container.offsetHeight; } container.style.width = /%$/.test(options.initialFrameWidth) ? '100%' : options.initialFrameWidth - getStyleValue("padding-left") - getStyleValue("padding-right") + 'px'; container.style.height = /%$/.test(options.initialFrameHeight) ? '100%' : options.initialFrameHeight - getStyleValue("padding-top") - getStyleValue("padding-bottom") + 'px'; container.style.zIndex = options.zIndex; //附件预览大窗口 var addclass = '',style = ''; if (options.largePreview) { addclass = 'largePreview'; } if (me.OSnow() == 'mac') { addclass += "mac" } style = ' style=\''; if(options.themeColor){ style += 'color:'+ options.themeColor + ';'; } // 默认字体 if(options.defaultFont){ style += options.defaultFont + ';'; } style += '\'' var html = (ie && browser.version < 9 ? '' : '') + '' + '' + (options.iframeCssUrl ? '' : '') + (options.viewerCssurl ? '' : '') + (options.increaseCssurl ? '' : '') + (options.initialStyle ? '' : '') + '' + ''; container.appendChild(domUtils.createElement(document, 'iframe', { id: 'ueditor_' + me.uid, width: "100%", height: "100%", frameborder: "0", //先注释掉了,加的原因忘记了,但开启会直接导致全屏模式下内容多时不会出现滚动条 // scrolling :'no', src: 'javascript:void(function(){document.open();' + (options.customDomain && document.domain != location.hostname ? 'document.domain="' + document.domain + '";' : '') + 'document.write("' + html + '");document.close();}())' })); container.style.overflow = 'hidden'; //解决如果是给定的百分比,会导致高度算不对的问题 setTimeout(function () { if (/%$/.test(options.initialFrameWidth)) { options.minFrameWidth = options.initialFrameWidth = container.offsetWidth; //如果这里给定宽度,会导致ie在拖动窗口大小时,编辑区域不随着变化 // container.style.width = options.initialFrameWidth + 'px'; } if (/%$/.test(options.initialFrameHeight)) { options.minFrameHeight = options.initialFrameHeight = container.offsetHeight; container.style.height = options.initialFrameHeight + 'px'; } }) } if(me.options.from){ RichTextUitl.from = me.options.from } //添加删除弹窗 var imgPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ imgPrefix = RichTextUitl.prefix } if ($('.popUeditorDelShowHide').length == 0) { var div = document.createElement('div'); div.className = 'maskDiv popUeditorDelShowHide editorMaskDiv'; div.style.cssText = 'display: none;' div.innerHTML = '
' + '
' + '' + '

' + me.getLang('popModal.hint') + '

' + '
' + '
' + '

' + me.getLang('popModal.sureDelete') + '

' + '' + '
' + '
'; document.body.appendChild(div); } $('body').on('click', '.popUeditorReConnectShowHide .confirm', function () { if (UE.account.noteCid && UE.account.puid) { me.initWebSocket(UE.account.noteCid, UE.account.puid, me.webscoketSync); me.webscoketSync(); $('.popUeditorReConnectShowHide').removeClass('maskFadeOut').hide() $('body').removeClass('popOverflow'); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } } }); //删除弹窗--关闭按钮 $('body').on('click', '.popUeditorDelShowHide .popClose,.popUeditorDelShowHide .btn-white', function () { $('.popUeditorDelShowHide').removeClass('maskFadeOut').hide() $('body').removeClass('popOverflow'); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } }); //删除弹窗--确定按钮 $('body').on('click', '.popUeditorDelShowHide .confirm', function () { var delType = $('.popUeditorDelShowHide').attr('deltype'); var delIndex = $('.popUeditorDelShowHide').attr('delindex'); var editorId = $('.popUeditorDelShowHide').attr('editorId'); if (delType == 1) { //图片 me.deleteElement(delIndex, 'img', null, editorId) } else if (delType == 2) { //附件 me.deleteElement(delIndex, 'iframe', null, editorId) } else if (delType == 3) { //图片 me.deleteElement(delIndex, 'table', null, editorId) } else if (delType == 4) { //文本附件 me.deleteElement(delIndex, 'a', null, editorId) } else if (delType == 5) { //代码块 me.deleteElement(delIndex, 'pre', null, editorId) } $('.popUeditorDelShowHide').removeClass('maskFadeOut').attr('deltype', '').attr('delindex', '').attr('editorId', '').hide() $('body').removeClass('popOverflow'); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } }); //20201016 确认删除弹窗弹出时--enter $('body').on('keydown', function (e) { if (e.keyCode == 13) { if ($('.popUeditorDelShowHide').hasClass('maskFadeOut')) { var delType = $('.popUeditorDelShowHide').attr('deltype'); var delIndex = $('.popUeditorDelShowHide').attr('delindex'); var editorId = $('.popUeditorDelShowHide').attr('editorId'); if (delType == 1) { //图片 me.deleteElement(delIndex, 'img', null, editorId) } else if (delType == 2) { //附件 me.deleteElement(delIndex, 'iframe', null, editorId) } else if (delType == 3) { //图片 me.deleteElement(delIndex, 'table', null, editorId) } else if (delType == 4) { //文本附件 me.deleteElement(delIndex, 'a', null, editorId) } else if (delType == 5) { //代码块 me.deleteElement(delIndex, 'pre', null, editorId) } $('.popUeditorDelShowHide').removeClass('maskFadeOut').attr('deltype', '').attr('delindex', '').attr('editorId', '').hide() $('body').removeClass('popOverflow'); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } } } }) }, OSnow: function () { var agent = navigator.userAgent.toLowerCase(); var isMac = /macintosh|mac os x/i.test(navigator.userAgent); if (agent.indexOf("win32") >= 0 || agent.indexOf("wow32") >= 0) { //your code return 'windows'; } if (agent.indexOf("win64") >= 0 || agent.indexOf("wow64") >= 0) { //your code return 'windows'; } if (isMac) { //your code return 'mac'; } }, /** * 编辑器初始化 * @method _setup * @private * @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.selection = new dom.Selection(doc); //gecko初始化就能得到range,无法判断isFocus了 var geckoSel; if (browser.gecko && (geckoSel = this.selection.getNative())) { geckoSel.removeAllRanges(); } this._initEvents(); //为form提交提供一个隐藏的textarea for (var form = this.iframe.parentNode; !domUtils.isBody(form); form = form.parentNode) { if (form.tagName == 'FORM') { me.form = form; if (me.options.autoSyncData) { domUtils.on(me.window, 'blur', function () { setValue(form, me); }); } else { domUtils.on(form, 'submit', function () { setValue(this, me); }); } break; } } 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); } //编辑器不能为空内容 if (domUtils.isEmptyNode(me.body)) { me.body.innerHTML = '

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

'; } //如果要求focus, 就把光标定位到内容开始 if (options.focus) { setTimeout(function () { me.focus(me.options.focusInEnd); //如果自动清除开着,就不需要做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) { } //挂接快捷键 me._bindshortcutKeys(); me.isReady = 1; me.fireEvent('ready'); options.onready && options.onready.call(me); if (!browser.ie9below) { domUtils.on(me.window, ['blur', 'focus'], function (e) { //chrome下会出现alt+tab切换时,导致选区位置不对 if (e.type == 'blur') { me._bakRange = me.selection.getRange(); try { me._bakNativeRange = me.selection.getNative().getRangeAt(0); me.selection.getNative().removeAllRanges(); } catch (e) { me._bakNativeRange = null; } } else { try { me._bakRange && me._bakRange.select(true); } 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(); }, /** * 同步数据到编辑器所在的form * 从编辑器的容器节点向上查找form元素,若找到,就同步编辑内容到找到的form里,为提交数据做准备,主要用于是手动提交的情况 * 后台取得数据的键值,使用你容器上的name属性,如果没有就使用参数里的textarea项 * @method sync * @example * ```javascript * editor.sync(); * form.sumbit(); //form变量已经指向了form元素 * ``` */ /** * 根据传入的formId,在页面上查找要同步数据的表单,若找到,就同步编辑内容到找到的form里,为提交数据做准备 * 后台取得数据的键值,该键值默认使用给定的编辑器容器的name属性,如果没有name属性则使用参数项里给定的“textarea”项 * @method sync * @param { String } formID 指定一个要同步数据的form的id,编辑器的数据会同步到你指定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); }, /** * 设置编辑器高度 * @method setHeight * @remind 当配置项autoHeightEnabled为真时,该方法无效 * @param { Number } number 设置的高度值,纯数值,不带单位 * @example * ```javascript * editor.setHeight(number); * ``` */ setHeight: function (height, notSetHeight) { if (height !== parseInt(this.iframe.parentNode.style.height)) { this.iframe.parentNode.style.height = height + 'px'; } !notSetHeight && (this.options.minFrameHeight = this.options.initialFrameHeight = height); this.body.style.height = height + 'px'; !notSetHeight && this.trigger('setHeight') }, /** * 为编辑器的编辑命令提供快捷键 * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口 * @method addshortcutkey * @param { Object } keyset 命令名和快捷键键值对对象,多个按钮的快捷键用“+”分隔 * @example * ```javascript * editor.addshortcutkey({ * "Bold" : "ctrl+66",//^B * "Italic" : "ctrl+73", //^I * }); * ``` */ /** * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口 * @method addshortcutkey * @param { String } cmd 触发快捷键时,响应的命令 * @param { String } keys 快捷键的字符串,多个按钮用“+”分隔 * @example * ```javascript * editor.addshortcutkey("Underline", "ctrl+85"); //^U * ``` */ addshortcutkey: function (cmd, keys) { var obj = {}; if (keys) { obj[cmd] = keys } else { obj = cmd; } utils.extend(this.shortcutkeys, obj) }, /** * 对编辑器设置keydown事件监听,绑定快捷键和命令,当快捷键组合触发成功,会响应对应的命令 * @method _bindshortcutKeys * @private */ _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 ) { if (me.queryCommandState(i, param) != -1) { //20200703 协同编辑快捷键支持 // if(me.options.cooperation){ // if(i == "Undo" || i == "Redo" || i == 'Bold' || i == 'Italic' || i == 'Underline'){ // var data = {}; // data.name='execCommand'; // data.cmdName = i; // data.value = null; // data.address = me.selection.getRange().createAddress(false,true); // me.sendJoinData(data); // } // } me.execCommand(i, param); } domUtils.preventDefault(e); } } } } }); }, /** * 获取编辑器的内容 * @method getContent * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容 * @return { String } 编辑器的内容字符串, 如果编辑器的内容为空,或者是空的标签内容(如:”<p><br/></p>“), 则返回空字符串 * @example * ```javascript * //编辑器html内容:

123456

* var content = editor.getContent(); //返回值:

123456

* ``` */ /** * 获取编辑器的内容。 可以通过参数定义编辑器内置的判空规则 * @method getContent * @param { Function } fn 自定的判空规则, 要求该方法返回一个boolean类型的值, * 代表当前编辑器的内容是否空, * 如果返回true, 则该方法将直接返回空字符串;如果返回false,则编辑器将返回 * 经过内置过滤规则处理后的内容。 * @remind 该方法在处理包含有初始化内容的时候能起到很好的作用。 * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容 * @return { String } 编辑器的内容字符串 * @example * ```javascript * // editor 是一个编辑器的实例 * var content = editor.getContent( function ( editor ) { * return editor.body.innerHTML === '欢迎使用UEditor'; //返回空字符串 * } ); * ``` */ getContent: function (cmd, fn, notSetCursor, ignoreBlank, formatter) { var me = this; if (cmd && utils.isFunction(cmd)) { fn = cmd; cmd = ''; } if (fn ? !fn() : !this.hasContents()) { return ''; } //PC出去的表格没有套.table的全部套上.table var tables = me.body.querySelectorAll('table'); for (var i = 0; table = tables[i++];) { if (!(table.parentNode.className && table.parentNode.className == 'table')) { var tempdiv = document.createElement('div'); tempdiv.setAttribute('element-id', domUtils.getRandomId()) tempdiv.setAttribute("class", "table"); tempdiv.setAttribute('style', 'width:100%;max-width:100%;overflow-x:auto;'); table.parentNode.insertBefore(tempdiv, table); tempdiv.appendChild(table); } } //标题没有elementid的加上id,避免出现每次getContent()不一样的情况 $(me.body).find('h1:not([element-id]),h2:not([element-id]),h3:not([element-id]),h4:not([element-id]),h5:not([element-id]),h6:not([element-id])').each(function () { $(this).attr('element-id', domUtils.getRandomId()); }) var url = ''; try { url = top.location.href || ''; } catch (e) { url = document.referrer || ''; } if (url && url.indexOf('notice') == -1) { //最后一个元素是不可编辑,后面加一个空行 if (me.body.lastChild.nodeType == 1 && me.body.lastChild.getAttribute('contenteditable') && me.body.lastChild.getAttribute('contenteditable') == 'false' && !$(me.body.lastChild).is('#ue_tableDragLine')) { if (!me.body.lastChild.nextSibling) { var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) p.appendChild(document.createElement('br')); me.body.appendChild(p); } } } me.fireEvent('beforegetcontent'); var html = me.body.innerHTML; //xss攻击 var xssReg = new RegExp("(\\baler(?=t\\s*\\())|(\\bhref(?=\\s*=\\s*['\"]?\\s*javascript:))|(\\bsrc(?=\\s*=\\s*['\"]?\\s*javascript:))|((data|src)\\s*=['\"]?\\s*data(?=:)(?!:\\s*image))|(^[^<]*<(?=/textarea\\s*>))|(<(?=(script)|(/script)))|(<(?=(details)|(/details)))|(\\b(onstart|onafterprint|onbeforeprint|onbeforeunload|onerror|onhaschange|onload|onmessage|onoffline|ononline|onpagehide|onpageshow|onpopstate|onredo|onresize|onstorage|onundo|onunload|onblur|onchange|oncontextmenu|onfocus|onformchange|onforminput|oninput|oninvalid|onreset|onreset|onsubmit|onkey\\w*|onclick|ondblclick|ondrag\\w*|ondrop|onmouse\\w*|onscroll|ontouch\\w*)(?=(\\s*)=))", 'gi'); html = html.replace(xssReg, function () { return arguments[0] + ' '; }) // 去掉rtf_content公式中的内容 if($(me.body).find('span[data-latexstr]').length > 0){ //去掉rtf_content中span[data-latexstr]中的内容 var div = document.createElement('div'); div.innerHTML = html; $(div).find('span[data-latexstr]').each(function (i, elm){ elm.innerHTML = ' '; }) //去掉ai纠错的样式 $(div).find('.error_word').contents().unwrap() html = div.innerHTML; //删除div domUtils.remove(div) } var root = UE.htmlparser(html, ignoreBlank); if(html.indexOf('
') == -1 && html.indexOf('
') == -1){ me.filterOutputRule(root); }else{ root.traversal(function (node) { if (node.type !== 'element') { return false; } if(node.tagName == 'img'){ if ((!node.getAttr('src') || node.getAttr('src') == '' || node.getAttr('src') == 'null') && !node.getAttr('_src') && !node.getAttr('name')) { node.parentNode.removeChild(node) } } me.filterWhiteList(node); }); } //完成时才需要处理的 root.traversal(function (node) { switch (node.tagName) { // case 'code': // node.innerText(node.innerHTML().replace(/]+>/g, ' ').replace(/<[^>]+>/g, '')); // break; case 'div': // 去除视频iframe wrap宽高 if(node.attrs && node.attrs.class && node.attrs.class.includes('editor-iframe') && node.attrs.style && node.innerHTML().includes('insertVideo')) { node.setAttr('style'); } break; } if (node.getStyle('display') && node.getStyle('display') == 'none') { //标题折叠:完成时需要展开折叠标题 node.setStyle('display', ''); } }) me.fireEvent('aftergetcontent', cmd, root); return root.toHtml(formatter); }, /** * 取得完整的html代码,可以直接显示成完整的html文档 * @method getAllHtml * @return { String } 编辑器的内容html文档字符串 * @eaxmple * ```javascript * editor.getAllHtml(); //返回格式大致是: ...... * ``` */ 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) + ''; }, /** * 得到编辑器的纯文本内容,但会保留段落格式 * @method getPlainTxt * @return { String } 编辑器带段落格式的纯文本内容字符串 * @example * ```javascript * //编辑器html内容:

1

2

* console.log(editor.getPlainTxt()); //输出:"1\n2\n * ``` */ getPlainTxt: function () { var $wrap = $(this.body).clone(true); //把富文本里的上标标签和下标标签换成ASCII码和Unicode上下标专用码位 // 数字上标 ⁰¹²³⁴⁵⁶⁷⁸⁹ //数字下标 ₀₁₂₃₄₅₆₇₈₉ //部分字母 ᵃ ᵇ ᶜ ᵈ ᵉ ᶠ ᵍ ʰ ⁱ ʲ ᵏ ˡ ᵐ ⁿ ᵒ ᵖ ʳ ˢ ᵗ ᵘ ᵛ ʷ ˣ ʸ ᶻ //下标字母 ₐ ₑ ₕ ᵢ ⱼ ₖ ₗ ₘ ₙ ₒ ₚ ᵣ ₛ ₜ ᵤ ᵥ ₓ // 通用替换函数 function replaceChars(text, charMap) { for (var char in charMap) { text = text.replace(new RegExp(char, 'g'), charMap[char]); } return text; } $wrap.find("sup").each(function () { var text = $(this).text(); text = replaceChars(text, dtd.$supNumberMap); text = replaceChars(text, dtd.$supLetterMap); $(this).text(text); }); $wrap.find("sub").each(function () { var text = $(this).text(); text = replaceChars(text, dtd.$subNumberMap); text = replaceChars(text, dtd.$subLetterMap); $(this).text(text); }); $wrap.find("ol li").each(function () { $(this).prepend($(this).attr('serialnum') + ". "); }); $wrap.find("ul li").each(function () { var level = parseInt($(this).parent().attr('level')) || 1; switch (level % 3) { case 0: $(this).prepend(" ▪ "); break; case 1: $(this).prepend("• "); break; case 2: $(this).prepend(" ◦ "); break; default: break; } }); //避免生成的图片后多一个空行 $wrap.find(".drag-image-wrap .editor-image").each(function () { $(this).unwrap(); }); //清空公式 $wrap.find("span[data-latexstr]").each(function () { this.innerHTML = ' ' }); var html = $wrap.html(); var me = this; var root = UE.htmlparser($wrap.html(), true); me.filterOutputRule(root); html = root.toHtml(); var reg = new RegExp(domUtils.fillChar, 'g'); html = html.replace(/[\n\r]/g, ''); //ie要先去了\n在处理 html = html.replace(/<(ol|ul|li)[^>]*>/g, '').replace(/<(\/ol|\/ul|\/li)>/g, ''); 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 : ''; }) // .replace(/<[^(img)][^>]+>/g, ''); //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0 return html.replace(reg, '').replace(/\u00a0/g, ' ').replace(/ /g, ' '); }, /** * 获取编辑器中的纯文本内容,没有段落格式 * @method getContentTxt * @return { String } 编辑器不带段落格式的纯文本内容字符串 * @example * ```javascript * //编辑器html内容:

1

2

* console.log(editor.getPlainTxt()); //输出:"12 * ``` */ getContentTxt: function () { var reg = new RegExp(domUtils.fillChar, 'g'); //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0 return this.body[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').replace(/\u00a0/g, ' '); }, /** * 根据图片地址后的宽高设置图片占位符 */ getImgurlParam: function (url, name) { if (url.indexOf("?") != -1) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = url.split("?")[1].match(reg); if (r != null) return unescape(r[2]); return null; } else { return null; } }, loadImg: function () { var me = this; var imgList = me.body.querySelectorAll('img'); for (var i = 0; i < imgList.length; i++) { // 计算固定宽高图片排版的老数据操作 if($(imgList[i]).parents('.column-img-b').find('img').length > 1 ){ me.resetColumnImgWdith(imgList[i],2); continue; }else if(RichTextUitl.imageLayout == true){ if($(imgList[i]).parents('.drag-image-wrap').find('img').length > 1){ var width = parseInt($(imgList[i]).parents('.drag-image-wrap').width()/$(imgList[i]).parents('.drag-image-wrap').find('img').length) - 14; imgList[i].style.width = width + 'px'; imgList[i].style.height = parseInt(width / 1.5) + 'px'; } continue; } if ($(imgList[i]).parents('.drag-image-wrap').find('img').length > 1 && !$(imgList[i]).parents('.drag-image-wrap').attr('totalWidth')) { //计算并排图片的总宽度,记录原始图片宽度 var totalWidth = 0; $(imgList[i]).parents('.drag-image-wrap').find('img').each(function (index, item) { totalWidth += parseInt(item.getAttribute('width') || item.style.width.replace('px', '')); item.setAttribute('owidth', parseInt(item.getAttribute('width') || item.style.width.replace('px', '')) + 2); }) $(imgList[i]).parents('.drag-image-wrap').attr('totalWidth', totalWidth) } if(imgList[i].style.width && imgList[i].style.width == '100%') {imgList[i].style.width = ''} var attrwidth = parseInt(imgList[i].getAttribute("width")) || imgList[i].style.width; if(imgList[i].style.width && imgList[i].style.width.indexOf('px') > -1){ attrwidth = parseInt(imgList[i].style.width.replace('px', '')) } var attrheight = parseInt(imgList[i].getAttribute("height")) || parseInt(imgList[i].style.height.replace('px', '') || 0); var addr = imgList[i].getAttribute("src"); if (!addr) { continue; } addr = addr.replace(/&/g, '&'); var winWidth = $(me.body).width() || 800; //最大宽度 var imgW1 = parseInt(attrwidth || me.getImgurlParam(addr, 'rw') || imgList[i].clientWidth || imgList[i].naturalWidth || 0); //原始图片宽度 var imgH1 = parseInt(attrheight || me.getImgurlParam(addr, 'rh') || imgList[i].clientHeight || imgList[i].naturalHeight || 0); //原始图片高度 var imgW2, imgH2; if (imgW1 && typeof imgW1 == 'string' && imgW1.indexOf('%') > -1) { imgList[i].style.width = imgW1; imgList[i].style.height = 'auto'; }else if (imgW1 && imgH1) { imgList[i].parentNode.style.backgroundColor = "#F5F6F8"; if (attrwidth && attrwidth < winWidth) { imgW2 = attrwidth; } else if(imgW1 > winWidth){ imgW2 = winWidth; } else{ imgW2 = imgW1; } imgH2 = parseInt(imgW2 * imgH1 / imgW1); imgList[i].style.width = imgW2 + 'px'; imgList[i].style.height = imgH2 + 'px'; imgList[i].setAttribute('width', imgW2); imgList[i].onload = function () { this.style.opacity = 1; this.parentNode.style.backgroundColor = ""; this.style.height = ""; this.setAttribute('height', ''); if ($(this).parents('.drag-image-wrap').find('img').length > 1) { me.resetImgWidth($(this).parents('.drag-image-wrap').find('img')) } me.fireEvent("contentchange") } } else { imgList[i].parentNode.style.backgroundColor = "#F5F6F8"; if (!(imgList[i].style.width && imgList[i].style.width.replace('px', ''))) { imgList[i].style.height = "auto"; imgList[i].style.minHeight = "200px"; } else { imgList[i].style.height = "auto"; } imgList[i].onload = function () { this.style.minHeight = ""; this.parentNode.style.backgroundColor = ""; if (this.getAttribute("width")) { this.style.width = this.getAttribute("width"); // this.style.height = parseInt(this.getAttribute("width") * this.clientHeight / this.clientWidth) + 'px'; // this.setAttribute('height', parseInt(this.getAttribute("width") * this.clientHeight / this.clientWidth)); } else { this.style.height = ""; this.setAttribute('height', ''); } if ($(this).parents('.drag-image-wrap').find('img').length > 1) { me.resetImgWidth($(this).parents('.drag-image-wrap').find('img')) } me.fireEvent("contentchange") } } } }, //并排图片按比例设置图片宽度 resetImgWidth: function (imgList) { var me = this; if (!imgList.parents('.drag-image-wrap').attr('totalWidth')) { return } var totalWidth = parseInt(imgList.parents('.drag-image-wrap').attr('totalWidth')); if (totalWidth + imgList.length * 6 > $(me.body).width()) { //防止图片没加载完就开始计算宽度 for (var i = 0; i < imgList.length; i++) { if (!imgList[i].clientHeight) return } for (var i = 0; i < imgList.length; i++) { var scale = imgList[i].clientWidth / imgList[i].clientHeight; var width = parseInt(($(me.body).width() - imgList.length * 6) * imgList.eq(i).attr('owidth') / totalWidth); imgList[i].width = width; imgList[i].style.width = width + 'px'; imgList[i].style.height = parseInt(width / scale) + 'px'; imgList[i].height = ''; } imgList.parents('.drag-image-wrap').removeAttr('totalWidth'); imgList.removeAttr('owidth'); } me.fireEvent("contentchange") }, // 计算固定宽高图片排版 resetColumnImgWdith:function (img,columnNum){ var me = this; var scale = 589/415; var width = parseInt($(me.body).width()/columnNum) - 6; img.style.width = width + 'px'; img.style.height = parseInt(width / scale) + 'px'; }, /** * 设置编辑器的内容,可修改编辑器当前的html内容 * @method setContent * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容 * @warning 该方法会触发selectionchange事件 * @param { String } html 要插入的html内容 * @example * ```javascript * editor.getContent('

test

'); * ``` */ /** * 设置编辑器的内容,可修改编辑器当前的html内容 * @method setContent * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容 * @warning 该方法会触发selectionchange事件 * @param { String } html 要插入的html内容 * @param { Boolean } isAppendTo 若传入true,不清空原来的内容,在最后插入内容,否则,清空内容再插入 * @example * ```javascript * //假设设置前的编辑器内容是

old text

* editor.setContent('

new text

', true); //插入的结果是

old text

new text

* ``` */ setContent: function (html, isAppendTo, notFireSelectionchange) { var me = this; if (html && html.length > 1 && html.substr(0, 1) == ' ') { html = '​' + html.substr(1, html.length); } //xss攻击 var xssReg = new RegExp("(\\baler(?=t\\s*\\())|(\\bhref(?=\\s*=\\s*['\"]?\\s*javascript:))|(\\bsrc(?=\\s*=\\s*['\"]?\\s*javascript:))|((data|src)\\s*=['\"]?\\s*data(?=:)(?!:\\s*image))|(^[^<]*<(?=/textarea\\s*>))|(<(?=(script)|(/script)))|(<(?=(details)|(/details)))|(\\b(onstart|onafterprint|onbeforeprint|onbeforeunload|onerror|onhaschange|onload|onmessage|onoffline|ononline|onpagehide|onpageshow|onpopstate|onredo|onresize|onstorage|onundo|onunload|onblur|onchange|oncontextmenu|onfocus|onformchange|onforminput|oninput|oninvalid|onreset|onreset|onsubmit|onkey\\w*|onclick|ondblclick|ondrag\\w*|ondrop|onmouse\\w*|onscroll|ontouch\\w*)(?=(\\s*)=))", 'gi'); html = html.replace(xssReg, function () { return arguments[0] + ' '; }) //把英文字母中间的 换成空格 20201104 html = html.replace(/\b( )+\b/gi, function () { html = arguments[0].replace(/ /gi, ' '); return html; }); me.fireEvent('beforesetcontent', html); var root = UE.htmlparser(html); if(html.indexOf('
') == -1 && html.indexOf('
') == -1){ me.filterInputRule(root); }else{ root.traversal(function (node) { if (node.type !== 'element') { return false; } me.filterWhiteList(node); }); } html = root.toHtml(); if (browser.firefox && html.trim() == '') { html = '

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

'; } me.body.innerHTML = (isAppendTo ? me.body.innerHTML : '') + html; //默认先去掉排版图片特定标识,否则第一张会被删除 $(me.body).find(".drag-image-wrap").removeClass("column-img-b"); // 处理固定宽高图片排版的老数据图片结构 $(me.body).find('.editor-image').each(function (index, node) { if($(node).find("img").is(".width-column-img")){ node.setAttribute("class","editor-image column-img-block"); if( $(me.body).find(".column-img-b").length == 0){ var div = document.createElement('div'); var divClass = "drag-image-wrap column-img-b"; div.setAttribute('element-id', domUtils.getRandomId()); div.setAttribute('class', divClass); div.setAttribute('contenteditable', 'false'); div.appendChild(node.cloneNode(true)); me.body.appendChild(div); }else{ $(me.body).find(".column-img-b").append(node.cloneNode(true)); } node.parentNode.remove() } }); if(html.indexOf('
') == -1 && html.indexOf('
') == -1){ this.loadImg(); } //标题折叠:如果h在div里,移出,表格、录音打点、课程报告、勾选框、收件箱签名里的不移出 $(me.body).find('h1,h2,h3,h4,h5,h6').each(function (index, node) { node.classList.remove('hover'); node.classList.remove('fold'); //原站内信函、多选框、签名、录音打点、表格、课程报告不断开 if ($(node).parents('.notice_main').length > 0 || $(node).parents('.todo-view').length == 0 || $(node).parents('.signDiv').length == 0 || !$(node).hasClass('signTitle') || $(node).parents('.callout-block').length == 0 || $(node).parents('.record-box').length == 0 || $(node).parents('table').length == 0 || !$(node).hasClass('top-cover-title') || $(node).parents('.report_main').length == 0) { return } if (!$(node).parent().is('body') && node.parentNode.nodeName != 'LI') { var parent = node.parentNode; while (!domUtils.isBody(parent.parentNode)) { parent = parent.parentNode; } domUtils.breakParent(node, parent); //20200323 清除上一个li里的最后一个空标签 var pre = node.previousSibling; if (pre.nodeType == 1 && domUtils.isNodeEmpty(pre)) { domUtils.remove(pre) } var next = node.previousSibling; if (next.nodeType == 1 && domUtils.isNodeEmpty(next)) { domUtils.remove(next) } } }); //处理图片div里有图片以外内容,移出 $(me.body).find('.editor-image').each(function (index, node) { if (node.children.length > 1) { var hasimg = false, tmpNode = node.firstChild, nextnode = node.nextSibling || node.parentNode.lastChild; while ((hasimg && node.firstChild.nextSibling) || (!hasimg && node.firstChild)) { if (hasimg) {//已经有了第一个图片,取图片后面一个图片 tmpNode = node.firstChild.nextSibling; } else { tmpNode = node.firstChild; } if (!hasimg && tmpNode.tagName == 'img') { hasimg = true; } else if (!hasimg) {//移到图片前 if (UE.dom.dtd.$block[tmpNode.tagName]) { node.parentNode.insertBefore(tmpNode, node); } else { p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()); p.appendChild(tmpNode); node.parentNode.insertBefore(p, node); } } else {//已经有了第一个图片,移到图片后 if (UE.dom.dtd.$block[tmpNode.tagName]) { node.parentNode.insertBefore(tmpNode, nextnode); } else { p = UE.uNode.createElement('p'); p.setAttr('element-id', domUtils.getRandomId()); p.appendChild(tmpNode); node.parentNode.insertBefore(p, nextnode); } } } } }); //渲染公式 RichTextUitl.renderLatex(me.body) //base64图片改为云盘图片 setTimeout(function () { //不加延迟puid和token还没有获取到 $(me.body).find('img').each(function (index, image) { if (image.src.indexOf('base64') > -1 && image.src.indexOf('data:') == 0) { me.replaceBase64Img(image); } }) }, 1000) me.iframeload() //移除a标签前面的8203 var link = $(me.body).find('a.dynacALink'); link.each(function (index, item) { if (item.previousSibling && domUtils.isFillChar(item.previousSibling)) { domUtils.remove(item.previousSibling); } }) //20210317 更新目录 if (typeof (updateAllCatalog) == "function") { updateAllCatalog(me.body); if ($('#noteTitle').val() && $('#noteTitle').val().trim() != '') { $('.catalogList li[attr=title]').text($('#noteTitle').val().trim()).addClass('active'); } } if (me.autoHeightEnabled) { setTimeout(function () { me.adjustHeight(); }, 50) } var url = ''; try { url = top.location.href || ''; } catch (e) { url = document.referrer || ''; } if (url && url.indexOf('notice') == -1 && me.options && !me.options.notScroll) { // 编辑通知时,光标不需要定位到底部 var times = 0; var timesnum = $(me.body).find('iframe').length / 2; var scrolltimer = setInterval(function () { times++; if (times >= timesnum) { clearInterval(scrolltimer); } if (me.options && typeof me.options.topOffsetOne != 'undefined' && !me.options.topOffsetOne && !me.options.blurHideToolbar) { me.focus(true); } //focus后光标定在br后面的改成定到br前面 var range = me.selection.getRange(); if (range.startContainer.nodeType == 1 && range.startContainer.lastChild && range.startContainer.lastChild.nodeType == 'BR') { range.setStartBefore(range.startContainer.lastChild).collapse(true); } if (me.body.lastChild.offsetTop + me.body.lastChild.clientHeight + 240 > $(window).height()) { $(window).scrollTop(me.body.lastChild.offsetTop + 240) } else { $(window).scrollTop(0) } }, 200); } function isCdataDiv(node) { return node.tagName == 'DIV' && node.getAttribute('cdata_tag'); } //给文本或者inline节点套p标签 if (me.options.enterTag == 'p') { var child = this.body.firstChild, tmpNode; if (!child || child.nodeType == 1 && (dtd.$cdata[child.tagName] || isCdataDiv(child) || domUtils.isCustomeNode(child) ) && child === this.body.lastChild) { this.body.innerHTML = '

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

' + this.body.innerHTML; } else { var p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) 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'); p.setAttribute('element-id', domUtils.getRandomId()) } } child = child.nextSibling; } } } me.fireEvent('aftersetcontent'); me.fireEvent('contentchange'); me.fireEvent('saveScene'); !notFireSelectionchange && me._selectionChange(); //清除保存的选区 me._bakRange = me._bakIERange = me._bakNativeRange = null; //trace:1742 setContent后gecko能得到焦点问题 var geckoSel; if (browser.gecko && (geckoSel = this.selection.getNative())) { geckoSel.removeAllRanges(); } if (me.options.autoSyncData) { me.form && setValue(me.form, me); } }, //进编辑页时的附件处理 iframeload: function () { var me = this; //附件加载完成后重新计算body高度,滚动到底部 $(me.body).find('iframe').each(function (index, iframe) { //iframe加上allowfullscreen=true iframe.setAttribute('allowfullscreen', "true"); if(iframe.getAttribute('src')){ iframe.setAttribute('src', iframe.getAttribute('src')); } iframe.onload = function () { if ($(this).height() > 74 && me.autoHeightEnabled) { setTimeout(function () { me.adjustHeight(); }, 100) } if ($(this).attr('module') == 'insertVideo') { var attachment = RichTextUitl.b64DecodeUnicode($(this).attr('name')); $(this)[0].contentWindow.postMessage({ 'cid': attachment.cid, 'msgType': 'config', 'isDetailPage': false, 'isGetVideoDataFromCenter': RichTextUitl.isGetVideoDataFromCenter, 'videoWidth': $(this).attr('video-width'), 'videoHeight': $(this).attr('video-height'), 'cloudUrl': RichTextUitl.cloudUrl, 'isHdVideo': window.obj && window.obj.mirrorDomain && window.obj.mirrorDomain.isMirrorDeploy ? true : '', 'videoWidthMax': RichTextUitl.videoWidthMax ? me.body.clientWidth || 0 : 0, }, '*'); }else if($(this).attr('module') == 'insertCloud' && typeof iframeOnload == 'function'){ iframeOnload(this,me.body) } } }); //并排视频重新计算高度 if(RichTextUitl.iframeDragColumn) { $(me.body).find('.drag-iframe-wrap').each(function (index, item) { var totalWidth = 0; var iframeList = $(item).find('iframe') iframeList.each(function (i, iframe) { totalWidth += iframe.getAttribute('video-width') / (iframe.getAttribute('video-height') - 36) }) var height = ($(me.body).width() - iframeList.length * 29) / totalWidth; setTimeout(function () { for (var i = 0; i < iframeList.length; i++) { var width = parseInt((iframeList[i].clientWidth / (iframeList[i].clientHeight - 36)) * height); iframeList[i].parentNode.style.width = (width + 4) + 'px'; iframeList[i].parentNode.style.height = (parseInt(height) + 46) + 'px'; // 设置视频封面高度 iframeList[i].contentWindow.postMessage({ msgType: 'changeVideoCoverHeight', cid: iframeList[i].getAttribute('cid'), coverHeight: parseInt(height), }, '*') } }, 200) }) } }, //找到有prev的父级元素 getParentNode: function (node) { var prev = node.previousSibling; if (!prev) { //没有前一个元素,找到前一个元素 while (!node.previousSibling && node.parentNode.tagName != "BODY") { node = node.parentNode; } prev = node.previousSibling; } return node; }, //20200811找到前一个元素 getprevNode: function (node) { var prev = node.previousSibling; if (!prev) { //没有前一个元素,找到前一个元素 while (!node.previousSibling && node.parentNode.tagName != "BODY") { node = node.parentNode; } prev = node.previousSibling; } if (prev && (!domUtils.isBlockElm(prev) || domUtils.isNodeEmpty(prev) || prev.style.display && prev.style.display == 'none')) { //有但不是块状元素,找到块状元素 while (prev && (!domUtils.isBlockElm(prev) || domUtils.isNodeEmpty(prev) || prev.style.display && prev.style.display == 'none')) { if (prev.previousSibling) { prev = prev.previousSibling; } else { prev = prev.parentNode.previousSibling; } } } if (prev) { return prev; } else { return null; } }, //20200603 获取当前node的前一个块状元素 getPreBlockNode: function (node) { var prev = node.previousSibling; if (!prev) { //没有前一个元素,找到前一个元素 while (!node.previousSibling && node.parentNode.tagName != "BODY") { node = node.parentNode; } prev = node.previousSibling; } if (prev) { if (!domUtils.isBlockElm(prev)) { //有但不是块状元素,找到块状元素 while (prev && !domUtils.isBlockElm(prev)) { if (prev.previousSibling) { prev = prev.previousSibling; } else { prev = prev.parentNode.previousSibling; } } } //是块状元素--找到prev里的最后一个块状元素 while (prev) { if (domUtils.isBlockElm(prev)) { if (!domUtils.isNodeEmpty(prev)) { prev = prev.lastChild; } else { prev = prev.previousSibling; } } else { if (prev.nodeType == 3 && prev.nodeValue.trim() != '' || prev.nodeType == 1) { //是文本节点或行内元素 prev = prev.parentNode; break; } else { //其他节点,比如注释节点 prev = prev.previousSibling; } } } return prev; } else { return null; } }, //删除遗留的空列表 removeNullList: function () { var me = this; $(me.body).find('li').each(function () { if ($(this).text() == '' && $(this).find('img').length == 0 && $(this).find('iframe').length == 0 && $(this).find('canvas').length == 0 && $(this).find('br').length == 0 && $(this).find('hr').length == 0) { $(this).remove() } }); $(me.body).find('ul,ol').each(function (index, item) { if ($(this).html() == '') { $(this).remove() } }); }, //加假光标 addFakeRange: function (id, cursorRect, username) { var cursor = document.getElementById("cursor-" + id); if (!cursor) { var usernameHmtl = ''; if (username && username != '') { usernameHmtl = '
' + username + '
' } var html = '
' + usernameHmtl + '
'; $('#cursors').append(html); cursor = document.getElementById("cursor-" + id); cursor.onmouseenter = function () { $(cursor).addClass('copr-cursor-active'); } cursor.onmouseleave = function () { $(cursor).removeClass('copr-cursor-active'); } } cursor.style.top = cursorRect.y + 'px'; cursor.style.left = (cursorRect.x - 1) + 'px'; if (cursorRect.height) { cursor.querySelector('.copr-cursor-caret').style.height = cursorRect.height + 'px'; } }, getRangePos: function (range) { var me = this; var cloneRange = range.cloneRange(); cloneRange.collapse(); var span = me.document.createElement('span'); span.innerHTML = 'span'; cloneRange.insertNode(span); var rangeRect = span.getBoundingClientRect(); domUtils.remove(span); cloneRange.startContainer.normalize(); return rangeRect; }, //移除假光标 removeFakeRange: function (id) { var cursor = document.getElementById("cursor-" + id); if (cursor) { $(cursor).remove(); } }, //向服务器同步数据 webscoketSync: function () { if (new Date().getTime() - UE.lastTime.time >= 3000) { console.log('重新拉取数据...') //获取不到id,重新拉取数据 if (!(typeof (NoteDraftUtil) == "undefined") && NoteDraftUtil) { NoteDraftUtil.getNoteDraft(); } UE.lastTime.time = new Date().getTime(); } }, // 20200604 关闭长连接 closeWebScocket: function () { if (window.ws) { window.ws.close(); } }, // 20200604 初始化长连接 (笔记id,用户id,打开后发送的数据) initWebSocket: function (noteCid, puid, cb) { var me = this; UE.account.noteCid = noteCid; UE.account.puid = puid; me.options.cooperation = true; if (me.options.cooperation && $('.popUeditorReConnectShowHide').length == 0) { //添加协作重新连接弹窗 var div2 = document.createElement('div'); div2.className = 'maskDiv popUeditorReConnectShowHide editorMaskDiv'; div2.style.cssText = 'display: none;' div2.innerHTML = '
' + '
' + '

' + me.getLang('popModal.hint') + '

' + '
' + '
' + '

' + me.getLang('popModal.reconnectTips') + '

' + '' + '
' + '
'; document.body.appendChild(div2); } if ("WebSocket" in window) { var url = 'wss://cooperateyd.chaoxing.com/websocket/' + noteCid + '/' + puid; window.ws = new WebSocket(url); ws.onopen = function () { if (cb) cb(); $('.editorContainer').append('
'); // console.log("websocket:开始发送数据"); }; ws.onmessage = function (evt) { var received_msg = evt.data; // console.log('receivejson:' + received_msg) var data = JSON.parse(received_msg); // 0:发送页面的上的操作,1、清空操作历史,2、获取上一次页面内容保存之后的操作历史, // 3、有新的人连接进来,4、用户断开连接, // 5、发送消息给服务端后服务端返回接收到消息的时间,用来当做消息的真实发送时间 //在线人员变动 NoteCooperateUtil.changeOnlineCooperator(data.onlineCooperator); if ((typeof data.operationType == 'undefined' || data.operationType == 0) && (typeof data.puid == 'undefined' || data.puid != puid)) { // 不是自己发的数据才需要处理 me.setJointEditData(data); } else if (data.operationType == 2) { var operateHistory = data.list; if (operateHistory && operateHistory.length > 0) { for (var i = 0; i < operateHistory.length; i++) { me.setJointEditData(JSON.parse(operateHistory[i])); } } } else if (data.operationType == 3) { // if(!(typeof(NoteCooperateUtil) == "undefined") && NoteCooperateUtil) { // NoteCooperateUtil.newUserConnection(data.user); // } } else if (data.operationType == 4) { me.removeFakeRange(data.puid); // if(!(typeof(NoteCooperateUtil) == "undefined") && NoteCooperateUtil) { // NoteCooperateUtil.userDisconnect(data.puid); // } } else if (data.operationType == 5) { RichTextUitl.lastExecutiveMessageTime = data.sendTime; } }; ws.onclose = function (e) { // console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean); //打开重新连接弹窗 if (browser.firefox) { setTimeout(function () { //新泛雅弹窗覆盖顶部和左侧 if (top) { top.postMessage('{"cmd":1,"toggle":true}', "*"); } $('.popUeditorReConnectShowHide').addClass('maskFadeOut').show(); }, 100) } else { //新泛雅弹窗覆盖顶部和左侧 if (top) { top.postMessage('{"cmd":1,"toggle":true}', "*"); } $('.popUeditorReConnectShowHide').addClass('maskFadeOut').show(); } $('body').addClass('popOverflow'); $('.popUeditorReConnectShowHide .popDiv').css({ top: function () { return ($(window).height() - $(this).height()) / 2; }, left: function () { return ($(window).width() - $(this).width()) / 2; }, transform: 'none' }); }; } }, // 发送协同编辑数据 sendJoinData: function (data) { var me = this; var range = me.selection.getRange(); //同步光标 data.puid = UE.puid; if (!data.rangeRect) { data.rangeRect = me.getRangePos(range); } data.operationType = 0; var json = JSON.stringify(data); if (window.ws && window.ws.readyState == 1) { // console.log((new Date()).getHours() + ':' + (new Date()).getMinutes() + ' sendjson:' + json) ws.send(json); if (typeof RichTextUitl != 'undefined' && RichTextUitl.lastSendMessageTime) { // 发消息后更新最后一次发消息的时间,用于判断无操作的时间大于1小时时,不再发送心跳检测保持长连接 RichTextUitl.lastSendMessageTime = new Date().getTime(); } } else { console.log('连接未开启或连接已关闭,重新连接...') //20200616 连接断开后重新连接 me.initWebSocket(UE.account.noteCid, UE.account.puid); me.webscoketSync(); } }, //20200601 接收协同编辑数据 setJointEditData: function (data) { // 记录执行到的消息的对应的发送时间 RichTextUitl.lastExecutiveMessageTime = data.sentTime || ''; var me = this; //一开始内容为空时,保存,和对方保持同步 if (me.undoManger.list.length == 0) { me.undoManger.save(true); } var range = me.selection.getRange(); var tmpRange = range.cloneRange(); function getTextNodesDeep(elem, opt_filter) { var textNodes = []; if (elem) { var nodes = elem.childNodes, nub = nodes.length; for (var i = 0; i < nub; i++) { var node = nodes[i], nodeType = node.nodeType; if (nodeType === 3) { //文本节点 if (!opt_filter || opt_filter(node, elem)) { node.nodeValue = node.nodeValue.replace(new RegExp(domUtils.fillChar, 'g'), ''); textNodes.push(node); } } else if (nodeType === 1) { //元素节点 textNodes = textNodes.concat(getTextNodesDeep(node, opt_filter)) } } } return textNodes; } function setRangeAt(pack, len) { var textArr = getTextNodesDeep(pack); var first = pack.firstChild; var firstLen = 0; var l = 0; var useLen = 0; if (textArr.length == 1) { first = textArr[0]; if (first.length > len) { useLen = len; } else { useLen = first.length; } } else { while (textArr[l]) { first = textArr[l]; firstLen += first.length; if (firstLen >= len) { useLen = len - (firstLen - first.length); break; } l++; } } tmpRange.selectNodeContents(pack); tmpRange.collapse(true); tmpRange.setStart(first, useLen); tmpRange.setEnd(first, useLen); // tmpRange.select(); } 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; } if (!(data.delLen == 0)) { if (data.name == "delete") { var pack = me.body.querySelector("[element-id = '" + data.elementId + "']"); } else if (data.name == "enter") { var pack = me.body.querySelector("[element-id = '" + data.preId + "']"); } else if (data.name == "inserthtml") { var pack = me.body.querySelector("[element-id = '" + data.startId + "']"); } else { var pack = me.body.querySelector("[element-id = '" + data.elementId + "']"); } var len = data.startPos; var insertText = data.insertText; } if (data.name == 'notetitle') { $('#noteTitle').val(data.text); } else if (data.name == "insert") { tmpRange = tmpRange.moveToAddress(data.address); //记录光标原始位置 var span = me.document.createElement('span'); range.insertNode(span); if (data.insertType && data.insertType == 'selectinsert') { tmpRange.deleteContents() } var text = me.document.createTextNode(insertText); tmpRange.insertNode(text); tmpRange.startContainer.normalize(); tmpRange.collapse(true); //如果有前一个元素 if (span.previousSibling && span.previousSibling.length) { range.setStart(span.previousSibling, span.previousSibling.length).setEndBefore(span.previousSibling, span.previousSibling.length).collapse(true); } else { range.setStartBefore(span).setEndBefore(span).collapse(true); } span.parentNode.removeChild(span); } else if (data.name == "delete") { if (data.address) { tmpRange = tmpRange.moveToAddress(data.address); } else { me.webscoketSync(); return; } if (data.address && data.address.startAddress.length > 2 && tmpRange.startContainer.nodeName == 'BODY') { me.webscoketSync(); return; } if (data.cmdName && data.cmdName == 'listDelete') { tmpRange = tmpRange.moveToAddress(data.address); //列表删除 me.listDelete(tmpRange); } else if (data.cmdName && data.cmdName == 'todoListDelete') { tmpRange = tmpRange.moveToAddress(data.address); //勾选框删除 me.todoListDelete(tmpRange); } else if (data.cmdName == 'deleteAll') { //全选删除 me.body.innerHTML = '

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

'; tmpRange.setStart(me.body.firstChild, 0).setCursor(false, true); } else if (data.isCollapsed == "false") { tmpRange = tmpRange.moveToAddress(data.address); var isText = false; if (tmpRange.startContainer.nodeType == 3) { isText = true; } tmpRange.deleteContents(); if (isText) { var child = tmpRange.startContainer.childNodes[tmpRange.startOffset], pre; if (child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)) { while (child.firstChild) { pre.appendChild(child.firstChild); } pre.normalize() domUtils.remove(child); } } tmpRange.collapse(true); } else if (data.delLen == 0) { var prev = me.body.querySelector("[element-id = '" + data.elementId + "']"); if (prev) { if (data.eleLen != 0) { if (prev.lastChild.nodeName == "BR") { domUtils.remove(prev.lastChild); } var prevParent; if ($(prev).parents(".todo-view").length > 0) { prevParent = $(prev).parents(".todo-view")[$(prev).parents(".todo-view").length - 1] } var parentList = domUtils.findParents(prev, false, function (node) { return node.tagName == 'OL' || node.tagName == 'UL' }, true); if (parentList.length > 0) { prevParent = parentList[0]; } if (prevParent) { var pack = prevParent.nextSibling; } else { var pack = prev.nextSibling; } //判断prev是否是空的节点,如果是


类型的空节点,干掉
标签防止它占位 if (domUtils.isEmptyBlock(prev)) { prev.innerHTML = ''; } while (pack.firstChild) { prev.appendChild(pack.firstChild); } domUtils.remove(pack); prev.normalize(); } else { var pack = prev.nextSibling; if (pack) { domUtils.remove(pack); } } } else { me.webscoketSync(); return; } } else { if (data.address) { tmpRange = tmpRange.moveToAddress(data.address); } //记录光标原始位置 if (range.collapse) { var span = me.document.createElement('span'); range.insertNode(span); } var pack = me.body.querySelector("[element-id = '" + data.elementId + "']"); if (pack) { var bookmark = tmpRange.createBookmark(); var newlen = 0; if (len >= data.delLen) { newlen = len - data.delLen; setRangeAt(pack, newlen); tmpRange.setEndBefore(bookmark.start); tmpRange.deleteContents(); tmpRange.moveToBookmark(bookmark); } tmpRange.startContainer.normalize(); var prev = span.previousSibling; if (prev && prev.length) { range.setStart(prev, prev.length).setEndBefore(prev, prev.length).collapse(true); } domUtils.remove(span); } else { me.webscoketSync(); return; } } } else if (data.name == "enter") { if (data.address) { tmpRange = tmpRange.moveToAddress(data.address); } else { me.webscoketSync(); return; } if ((data.address && data.address.startAddress.length > 2 && domUtils.isBody(tmpRange.startContainer)) || (tmpRange.startContainer.nodeType == 3 && tmpRange.startOffset > tmpRange.startContainer.nodeValue.length)) { me.webscoketSync(); return; } if (data.cmdName && data.cmdName == 'listEnter') { //列表换行 me.listEnter(tmpRange, null, data.elementId, data.preId); } else if (data.cmdName && data.cmdName == 'todoListEnter') { //多选框换行 me.todoListEnter(tmpRange, null, data.elementId); } else { var prev = me.body.querySelector("[element-id = '" + data.preId + "']"); if (prev) { var prevLen = prev.innerText.replace(new RegExp(domUtils.fillChar, 'g'), '').replace(/^\s+|\s+$/g, '').length; var start = tmpRange.startContainer; if (start.nodeType == 3) { start = domUtils.findParent(tmpRange.startContainer, function (node) { return domUtils.isBlockElm(node); }, true); } if (data.startPos == 0) { tmpRange.insertNode(me.document.createTextNode(domUtils.fillChar)).collapse(false); } else if (data.startPos == prevLen) { if (start && !domUtils.isBody(start) && start.lastChild && start.lastChild.nodeName != "BR") { start.appendChild(me.document.createElement('br')); } } if (domUtils.isBody(start)) { me.webscoketSync(); return; } else if (start.nodeName.indexOf('H') != -1) { //标题后换行 var newp = document.createElement('p'); newp.innerHTML = "
"; newp.setAttribute("element-id", data.elementId); $(prev).after(newp); } else { var span = me.document.createElement('span'); tmpRange.insertNode(span); if (pack && !domUtils.isBody(pack)) { try { domUtils.breakParent(span, pack); } catch (e) { me.webscoketSync(); return; } domUtils.clearEmptySibling(span); var newPrev = span.previousSibling; var next = span.nextSibling; newPrev.setAttribute("element-id", data.preId); next.setAttribute("element-id", data.elementId); domUtils.remove(span); } else { me.webscoketSync(); return; } } } else { if (tmpRange.startContainer.nodeType == 3) { prev = domUtils.findParent(tmpRange.startContainer, function (node) { return domUtils.isBlockElm(node); }, true); } else { prev = tmpRange.startContainer; } //如果文本节点的父元素就是body,会丢body,所以同步一下 if ((prev && domUtils.isBody(prev)) || !prev) { me.webscoketSync(); return; } prev.setAttribute("element-id", data.preId); if (data.startPos == 0) { var newp = document.createElement('p'); newp.innerHTML = prev.innerHTML; newp.setAttribute("element-id", data.elementId); prev.innerHTML = "
"; $(prev).after(newp); } else if (data.startPos == prevLen) { var newp = document.createElement('p'); newp.innerHTML = "
"; newp.setAttribute("element-id", data.elementId); $(prev).after(newp); } else { var span = me.document.createElement('span'); tmpRange.insertNode(span); var spanParent = domUtils.findParent(span, function (node) { return domUtils.isBlockElm(node); }, true); if (!domUtils.isBody(spanParent)) { domUtils.breakParent(span, spanParent); var newPrev = span.previousSibling; var next = span.nextSibling; newPrev.setAttribute("element-id", data.preId); next.setAttribute("element-id", data.elementId); domUtils.remove(span); } } } } } else if (data.name == 'inserthtml') { //插入html tmpRange = tmpRange.moveToAddress(data.address); var html = data.html; me.execCommand('inserthtml', html, false, tmpRange); if (data.pasteTag) { me.fireEvent("afterpaste", html); } } else if (data.name == 'replacefile') { //拖拽文件替换文件html tmpRange = tmpRange.moveToAddress(data.address); me.execCommand('replacefile', data.fileArray); } else if (data.name == 'replace') { //替换已改成线上地址的图片 var node = me.body.querySelector("[element-id = '" + data.elementId + "']"); if (node) { node.style.background = ''; node.style.width = ''; node.style.height = ''; node.innerHTML = data.html; } else { me.webscoketSync(); return; } } else if (data.name == 'execCommand') { //执行命令 if (data.address.startAddress.length == 1 && data.address.startAddress[0] == 0 && data.address.endAddress.length == 1 && data.address.endAddress[0] == 0) { data.address.startAddress.push(0); data.address.endAddress.push(0); } tmpRange = tmpRange.moveToAddress(data.address); //如果光标位置的文本节点的父元素就是body,会丢body,所以同步一下 var element; if (tmpRange.startContainer.nodeType == 3) { element = domUtils.findParent(tmpRange.startContainer, function (node) { return domUtils.isBlockElm(node); }, true); } else { element = tmpRange.startContainer; } if ((element && domUtils.isBody(element)) || !element) { me.webscoketSync(); return; } if (data.cmdName.toLowerCase() == 'paragraph') { me.execCommand(data.cmdName, data.value, null, null, tmpRange); } else if (data.cmdName.toLowerCase() == 'removeformat') { me.execCommand('removeformat', null, null, null, null, tmpRange) } else if (data.cmdName.toLowerCase() == 'checkbox') { me.execCommand(data.cmdName, data.value, tmpRange, data.elementId); } else if ((data.cmdName.toLowerCase() == 'undo' && me.undoManger.index == 0) || (data.cmdName.toLowerCase() == 'redo' && me.undoManger.index == me.undoManger.length - 1)) { //撤回队列不同步到底时同步 me.webscoketSync(); return; } else { me.execCommand(data.cmdName, data.value, tmpRange); } } else if (data.name == 'cut') { //剪切图片 tmpRange = tmpRange.moveToAddress(data.address); tmpRange.deleteContents(); if (tmpRange.startContainer.nodeType == 1) { tmpRange.startContainer.normalize(); var child = tmpRange.startContainer.childNodes[tmpRange.startOffset], pre; if (child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)) { while (child.firstChild) { pre.appendChild(child.firstChild); } domUtils.remove(child); } } else if (tmpRange.startContainer.nodeType == 3) { tmpRange.startContainer.parentNode.normalize(); } tmpRange.collapse(true); } else if (data.name == 'deleteElement') { //删除元素 me.deleteElement(data.elementIndex, data.tagName, true) } else if (data.name == 'numListEnter') { //1.换行变列表 tmpRange = tmpRange.moveToAddress(data.address); parent = domUtils.findParent(tmpRange.startContainer, function (node) { return domUtils.isBlockElm(node) }, true); var html = parent.innerHTML.replace(new RegExp(domUtils.fillChar, 'g'), ''); parent.innerHTML = html.replace(/^\s*1\s*\./, ''); tmpRange.setStartAtLast(parent).collapse(true); me.execCommand('insertorderedlist'); } else if (data.name == 'todoCheck') { //勾选框选中 if (data.elementId && me.body.querySelector("[element-id = '" + data.elementId + "']")) { var target = me.body.querySelector("[element-id = '" + data.elementId + "']"); if (data.checkType == 'add') { $(target).addClass('checked') } else { $(target).removeClass('checked') } } else { me.webscoketSync(); return; } } else if (data.name == 'format') { function addFormat(range) { if (text) { range.selectNode(text); } return range.applyInlineStyle(list[list.length - 1].tagName, null, list); } tmpRange = tmpRange.moveToAddress(data.startAddress) var list = domUtils.findParents(tmpRange.startContainer, true, function (node) { return !domUtils.isBlockElm(node) && node.nodeType == 1; }); //获取设置了对齐方式的块状元素 var blocklist = domUtils.findParents(tmpRange.startContainer, true, function (node) { return domUtils.isBlockElm(node) && !domUtils.isBody(node) && node.nodeType == 1 && node.style.cssText.indexOf('text-align') > -1; }); //a不能加入格式刷, 并且克隆节点 for (var i = 0, ci; ci = list[i]; i++) { if (ci.tagName == 'A') { list.splice(i, 1); break; } } tmpRange = tmpRange.moveToAddress(data.address); var collapsed = tmpRange.collapsed; if (collapsed) { var text = me.document.createTextNode('match'); tmpRange.insertNode(text).select(); if (text.nextSibling && domUtils.isFillChar(text.nextSibling)) { domUtils.remove(text.nextSibling) } } me.__hasEnterExecCommand = true; //不能把block上的属性干掉 var removeFormatAttributes = me.options.removeFormatAttributes; me.options.removeFormatAttributes = ''; me.execCommand('removeformat', null, null, null, null, tmpRange); me.options.removeFormatAttributes = removeFormatAttributes; me.__hasEnterExecCommand = false; if (list.length) { addFormat(tmpRange); } if (blocklist && blocklist.length > 0) { var alignNode = blocklist[blocklist.length - 1]; var align; if (alignNode && alignNode.style) { align = alignNode.style.textAlign; me.doJustify(tmpRange, align) } } if (text) { tmpRange.setStartBefore(text).insertNode(document.createTextNode(domUtils.fillChar)).collapse(true); } text && domUtils.remove(text); } else if (data.name == 'refreshLiveState') { //TODO 更新直播状态 // me.refreshLiveStatus(data.iframeId,data.backdata); } else if (data.name == 'changeAnnex') { //TODO 替换音视频 // me.changeAnnex(data.changedata,data.iframeId) } else if (data.name == 'changeAnnexImg') { //替换音视频封面 // me.changeAnnexImg(data.changedata,data.iframeId) } else if (data.name == 'syncjoinFakeRange') { //A输入,B还原,A显示B还原后的光标 if (data.puid != UE.puid) { me.addFakeRange(data.puid, data.rangeRect, data.user.name) } } if (data.name != 'syncjoinFakeRange') { //A输入,B还原,B显示A输入后的光标 if (data.rangeRect && data.puid != UE.puid) { me.addFakeRange(data.puid, data.rangeRect, data.user.name); setTimeout(function () { //B还原后发送B的光标位置 range = me.selection.getRange(); var rangect = me.getRangePos(range); var senddata = {}; senddata.name = 'syncjoinFakeRange'; senddata.puid = UE.puid; senddata.rangeRect = rangect; me.sendJoinData(senddata); }, 100) } } me.body.normalize(); if (data.name == 'execCommand' && (data.cmdName == 'undo' || data.cmdName == 'redo')) { //撤销和反撤销不保存,保存后两边list会不一致 } else { me.fireEvent('saveScene'); me.fireEvent('contentchange'); me.fireEvent('aftersetcontent'); } }, doJustify: function (range, style) { var bookmark = range.createBookmark(), filterFn = function (node) { return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); }; range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode; while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { if (current.nodeType == 3 || !block(current)) { tmpRange.setStartBefore(current); while (current && current !== bookmark2.end && !block(current)) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !block(node); }); } tmpRange.setEndAfter(tmpNode); var common = tmpRange.getCommonAncestor(); if (!domUtils.isBody(common) && block(common)) { domUtils.setStyles(common, utils.isString(style) ? { 'text-align': style } : style); current = common; } else { var p = range.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) domUtils.setStyles(p, utils.isString(style) ? { 'text-align': style } : style); var frag = tmpRange.extractContents(); p.appendChild(frag); tmpRange.insertNode(p); current = p; } current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } return range.moveToBookmark(bookmark2).moveToBookmark(bookmark); }, //列表换行2020.06.24 listEnter: function (range, evt, newId, preId) { var me = this; function preventAndSave() { me.normalList() if (!!evt) { evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false); // me.fireEvent('contentchange'); me.undoManger && me.undoManger.save(); } } range = range.shrinkBoundary(); var start = range.startContainer; if (start.nodeName == 'UL' || start.nodeName == 'OL') { if (range.startOffset == 0 && start.firstChild && start.firstChild.nodeName == 'LI') { start = start.firstChild.firstChild; //p range.setStart(start, 0).collapse(true).select(); } else if (start.lastChild && start.lastChild.nodeName == 'LI' && start.lastChild.lastChild) { start = start.lastChild.lastChild; //p range.setStart(start, start.childNodes.length).collapse(true).select(); } } else if (start.nodeName == 'LI') { if (range.startOffset == 0 && start.firstChild) { start = start.firstChild; //p range.setStart(start, 0).collapse(true).select(); } else if (start.lastChild) { start = start.lastChild; //p range.setStart(start, start.childNodes.length).collapse(true).select(); } } else if (start.nodeType == 3 && start.parentNode.nodeName != 'LI') { //文本节点且父级不是li start = start.parentNode; } var li = domUtils.findParentByTagName(range.startContainer, 'li', true); var list = domUtils.findParent(range.startContainer, function (node) { return node.tagName == 'OL' || node.tagName == 'UL' }, true); //换行变上一级列表 if (li && parseInt(li.parentNode.getAttribute('level')) > 1 && (range.startOffset == 0 || range.startOffset == 1 && range.startContainer.firstChild && (range.startContainer.firstChild.nodeName == 'BR' || domUtils.isFillChar(range.startContainer.firstChild)) || range.startOffset == 1 && domUtils.isFillChar(range.startContainer) )) { me.execCommand('indent', 'outdent'); preventAndSave(); return; } else 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'); p.setAttribute('element-id', domUtils.getRandomId()) 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); domUtils.clearEmptySibling(li); if (evt) { tmpRange.select(); } preventAndSave(); return; } } if (range.startOffset == 1 && range.startContainer.firstChild && range.startContainer.firstChild.nodeName == 'BR') { range.setStart(range.startContainer, 0); } //非选中换行 li = domUtils.findParentByTagName(range.startContainer, 'li', true); parent = domUtils.findParentByTagName(range.startContainer, ['p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption', 'table'], true); start = parent; var prev = start.previousSibling; while (start.parentNode != li) { //start的父级是li时停止循环 if (prev && prev.innerHTML == "" && (prev.nodeName != 'BR' || prev.nodeName != 'HR' || prev.nodeName != 'IMG' || prev.nodeName != 'INPUT' || prev.nodeName != 'CANVAS')) { //存在prev,但prev是空节点,不占位 prev = prev.previousSibling; } else if (prev) { //存在prev,不处理 break; } else { //不存在prev start = start.parentNode; prev = start.previousSibling; } } if (li) { if (domUtils.isStartInblock(range) && start == li.firstChild && (domUtils.isEmptyBlock(li) || (range.startOffset == 0 || (range.startOffset == 1 && parent && parent.parentNode == li && !parent.previousSibling && (domUtils.isFillChar(range.startContainer) || (range.startContainer.nodeType == 3 && range.startContainer.nodeValue.substr(0, 1).charCodeAt(0) == '8203')) ) ) )) { //第一级空列表下换行,退出列表 //列表为一级,下一列表 if (list.getAttribute('data-origin-start') || list.getAttribute('data-start')) { //编辑器第一个列表的第一行换行,前面加空行 if (me.body.firstChild == list && !((list.innerText.replace(/\s/gi, "") == "" || list.innerText.trim() == domUtils.fillChar) && !list.querySelector('img') && !list.querySelector('iframe'))) { var p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) var br = me.document.createElement('br'); p.appendChild(br); me.body.insertBefore(p, list); range.setStart(p, 0).collapse(true).select(); return; } //找到下一个list,(level一致,serialnum+1) var level = list.getAttribute('level'); var serialnum = domUtils.addSerialNum(list.getAttribute('serialnum'), level); var listnext = list.nextSibling; while (listnext) { if ((listnext.nodeName == 'OL' || listnext.nodeName == 'UL') && listnext.getAttribute('level') == level && (listnext.getAttribute('data-start') || listnext.getAttribute('data-origin-start'))) { break; } else if (listnext.tagName == 'OL' && listnext.getAttribute('level') == level && listnext.getAttribute('serialnum') == serialnum) { if (list.getAttribute('data-origin-start')) { listnext.setAttribute('data-origin-start', list.getAttribute('data-origin-start')); } else { listnext.setAttribute('data-start', list.getAttribute('data-start')); } listnext.setAttribute('serialnum', list.getAttribute('serialnum')); listnext.firstChild.setAttribute('serialnum', list.getAttribute('serialnum')) break; } else { listnext = listnext.nextSibling; } } } var listnext = list.nextSibling; //处理ol下有其他li的情况 var linext = li.nextSibling; while (linext) { var newlist = document.createElement(list.tagName); newlist.setAttribute('element-id', domUtils.getRandomId()) newlist.appendChild(linext); newlist.setAttribute('level', list.getAttribute('level')); if (list.tagName == 'OL') { newlist.setAttribute('serialnum', linext.getAttribute('serialnum')); } list.parentNode.insertBefore(newlist, listnext); linext = li.nextSibling; } listnext = list.nextSibling; while (li.firstChild) { if (listnext) { list.parentNode.insertBefore(li.firstChild, listnext); } else { list.parentNode.appendChild(li.firstChild) } } domUtils.remove(list); if (evt) { range.collapse().select(); } else { range.collapse(); } } else { //正常文字后换行 var first = li.firstChild; if (!first || !domUtils.isBlockElm(first)) { var p = me.document.createElement('p'); p.setAttribute('element-id', preId ? preId : domUtils.getRandomId()) !li.firstChild && domUtils.fillNode(me.document, p); while (li.firstChild) { p.appendChild(li.firstChild); } li.appendChild(p); first = p; } var nowEle = range.startContainer; //2022-3-31 添加条件有选区且选区以块状元素开始,解决列表下粘贴QQ截图图片后换行会多一个空行 if (!range.collapsed && domUtils.isStartInblock(range) && nowEle.previousSibling && nowEle.previousSibling.nodeType == 1 && nowEle.previousSibling.getAttribute('contenteditable') == 'false') { var newp = document.createElement('p'); newp.setAttribute('element-id', domUtils.getRandomId()) newp.innerHTML = '
'; nowEle.parentNode.insertBefore(newp, nowEle) } //20210813 插入零宽字符占位,避免设置文字大小的列表换行后不能继续输入 var text = me.document.createTextNode(domUtils.fillChar); range.insertNode(text).collapse(true); var span = me.document.createElement('span'); range.insertNode(span); domUtils.breakParent(span, li.parentNode); //20200323 清除上一个li里的最后一个空标签 var preLi = span.previousSibling; if (preLi.lastChild.lastChild && preLi.lastChild.lastChild.nodeType == 1 && !preLi.lastChild.lastChild.firstChild) { domUtils.remove(preLi.lastChild.lastChild) } var nextList = span.nextSibling; nextList.style.cssText = ''; //列表改版 var serialstr, serialnum, level = nextList.getAttribute('level'); if (nextList.tagName.toLowerCase() == 'ol') { serialstr = li.getAttribute('serialnum'); nextList.setAttribute('serialnum', domUtils.addSerialNum(serialstr, level)); nextList.firstChild.setAttribute('serialnum', domUtils.addSerialNum(serialstr, level)); } nextList.removeAttribute('data-origin-start'); nextList.removeAttribute('data-start'); first = nextList.firstChild.firstChild; //p //标题后换行变成p if (/h\d/i.test(first.tagName)) { var p = document.createElement('p'); p.innerHTML = first.innerHTML; p.setAttribute('element-id', first.getAttribute('element-id')) first.parentNode.insertBefore(p, first); domUtils.remove(first); first = p; } //新增: 列表下换行后没有br,会导致删除序号后光标跑到上一行 if (first && (first.childNodes.length == 0 || ((first.innerText.trim() == domUtils.fillChar || first.innerText.trim() == '') && !first.querySelector('img') && !first.querySelector('iframe') && !first.querySelector('br') && !first.querySelector('canvas') && !first.querySelector('hr')))) { var br = me.document.createElement('br'); first.appendChild(br); } if (!first) { p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) domUtils.fillNode(me.document, p); nextList.firstChild.appendChild(p); first = p; } if (!first.getAttribute('element-id')) { first.setAttribute('element-id', newId); } //注释原因:文字后shfit+enter换行生成的br在enter时丢失 /*if (domUtils.isEmptyNode(first)) { first.innerHTML = ''; domUtils.fillNode(me.document, first); }*/ var firstChild = first; while (firstChild.firstChild && firstChild.firstChild.tagName != 'BR') { firstChild = firstChild.firstChild; } if (firstChild.nodeType == 3 && domUtils.isFillChar(firstChild)) { range.setStart(firstChild, 1).collapse(true).select(true); } else { range.setStart(firstChild, 0).collapse(true).select(true); } if (evt) { range.select(true); } domUtils.remove(span); var pre = nextList.previousSibling; if (pre && domUtils.isEmptyBlock(pre)) { pre.firstChild.innerHTML = '


'; // domUtils.fillNode(me.document, pre.firstChild); } if ((nextList.offsetTop - document.scrollingElement.scrollTop) >= window.height) { document.scrollingElement.scrollBy(0, (nextList.offsetTop - document.scrollingElement.scrollTop - window.height + nextList.clientHeight)) } } preventAndSave(); } }, //勾选框换行20200628 todoListEnter: function (range, evt, elementId) { var me = this; function preventAndSave() { if (!!evt) { evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false); // me.fireEvent('contentchange'); me.undoManger && me.undoManger.save(); } } var start = range.startContainer; if (start.nodeType == 3) { start = start.parentNode; } var todoList = domUtils.findParents(start, false, function (node) { return node.className && node.className.indexOf('todo-view') > -1 }, true); if (!todoList[0]) { me.webscoketSync(); return; } var todo = todoList[0]; var todoText = $(start).parents('.todo-view').find(".todo-text")[0]; if (todoText && domUtils.isEmptyBlock(todoText)) { //离开to do列表 var div = document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()) while (todoText.firstChild) { //是块状元素直接移出去,不是块状元素移到div里 if (todoText.firstChild.nodeType == 1 && domUtils.isBlockElm(todoText.firstChild)) { if (!todoText.firstChild.firstChild) { todoText.firstChild.innerHTML = "
" } todo.parentNode.insertBefore(todoText.firstChild, todo); if (todo.previousSibling.firstChild && domUtils.isFillChar(todo.previousSibling.firstChild)) { range.setStart(todo.previousSibling, 1).collapse(true); } else { range.setStart(todo.previousSibling, 0).collapse(true); } } else { div.appendChild(todoText.firstChild); } } if (div && div.childNodes.length == 0) { domUtils.remove(div); } else { range.setStart(div, 0); range.setEnd(div, 0); } domUtils.remove(todo); if (evt) { range.select(true); } preventAndSave(); return; } else { var span = document.createElement('span'); range.insertNode(span); // domUtils.insertAfter(todoText,span); if (todo.className && todo.className.indexOf('todo-view') > -1) { domUtils.breakParent(span, todo); } else { me.webscoketSync(); return; } var nextLi = span.nextSibling; if (!nextLi.getAttribute('element-id')) { nextLi.setAttribute('element-id', elementId); } nextLi.classList.remove("checked"); first = $(nextLi).find(".todo-text")[0]; var todoMark = '' + '' + ''; first.parentNode.insertBefore($(todoMark)[0], first); if (!first.firstChild || !domUtils.isBlockElm(first.firstChild)) { var p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()); p.appendChild(document.createElement('br')); // p.appendChild( document.createTextNode("\u200b") ); while (first.firstChild) { if (first.firstChild == 'BR') { domUtils.remove(first.firstChild); } else { p.appendChild(first.firstChild); } } first.appendChild(p); first = p; } if (first && first.childNodes.length == 0) { first.appendChild(document.createElement('br')); // first.appendChild( document.createTextNode("\u200b") ); } if (!first) { p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()); p.appendChild(document.createElement('br')); // p.appendChild( document.createTextNode("\u200b") ); nextLi.appendChild(p); first = p; } if (first) { while (first && first.nodeType == 1 && first.nodeName != 'BR' && first.nodeName != 'HR') { if (first && first.innerHTML == "") { first.appendChild(document.createElement('br')); // first.appendChild( document.createTextNode("\u200b") ); break; } first = first.firstChild; } } var firstChild = first; while (firstChild.firstChild) { firstChild = firstChild.firstChild; } if (evt) { range.setStart(firstChild, 0).collapse(true).select(); } else { range.setStart(firstChild, 0).collapse(true); } domUtils.remove(span); var pre = nextLi.previousSibling; if (pre && domUtils.isEmptyBlock(pre)) { var prevTodoText = $(pre).find(".todo-text")[0]; if (prevTodoText && domUtils.isEmptyBlock(prevTodoText)) { prevTodoText.innerHTML = '

'; prevTodoText.firstChild.appendChild(document.createElement('br')); // prevTodoText.firstChild.appendChild( document.createTextNode("\u200b") ); } } preventAndSave(); return; } }, //列表删除 listDelete: function (range, evt) { var me = this; if (!!evt) { var keyCode = evt.keyCode || evt.which; } var li = domUtils.findParentByTagName(range.startContainer, 'li', true); var list = domUtils.findParentByTagName(range.startContainer, ['ol', 'ul'], true); if (list.getAttribute('data-origin-start') || list.getAttribute('data-start')) { //找到下一个list,(level一致,serialnum+1) var level = list.getAttribute('level'); var serialnum = domUtils.addSerialNum(list.getAttribute('serialnum'), level); var listnext = list.nextSibling; while (listnext) { if ((listnext.nodeName == 'OL' || listnext.nodeName == 'UL') && listnext.getAttribute('level') == level && (listnext.getAttribute('data-start') || listnext.getAttribute('data-origin-start'))) { break; } else if (listnext.tagName == 'OL' && listnext.getAttribute('level') == level && listnext.getAttribute('serialnum') == serialnum) { if (list.getAttribute('data-origin-start')) { listnext.setAttribute('data-origin-start', list.getAttribute('data-origin-start')); } else { listnext.setAttribute('data-start', list.getAttribute('data-start')); } listnext.setAttribute('serialnum', list.getAttribute('serialnum')); listnext.firstChild.setAttribute('serialnum', list.getAttribute('serialnum')) break; } else { listnext = listnext.nextSibling; } } } var start = li.firstChild; if (!domUtils.isBlockElm(start)) { var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) li.insertBefore(p, start); p.appendChild(start); start = p; } var listnext = list.nextSibling; //处理ol下有其他li的情况 var linext = li.nextSibling; while (linext) { var newlist = document.createElement(list.tagName); newlist.setAttribute('element-id', domUtils.getRandomId()) newlist.appendChild(linext); newlist.setAttribute('level', list.getAttribute('level')); if (list.tagName == 'OL') { newlist.setAttribute('serialnum', linext.getAttribute('serialnum')); } list.parentNode.insertBefore(newlist, listnext); linext = li.nextSibling; } listnext = list.nextSibling; while (li.firstChild) { if (listnext) { list.parentNode.insertBefore(li.firstChild, listnext); } else { list.parentNode.appendChild(li.firstChild); } } domUtils.remove(list); range.setStart(start, 0); range.setEnd(start, 0); range.select(); me.normalList(); if (!!evt) { evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false); me.fireEvent('contentchange'); me.fireEvent('saveScene'); me.undoManger && me.undoManger.save(); } return; }, //勾选框删除 todoListDelete: function (range, evt) { var me = this; var start = range.startContainer; if (start.nodeType == 3) { start = start.parentNode; } if ($(start).parents(".todo-text").length > 0) { startParent = $(start).parents(".todo-text")[$(start).parents(".todo-text").length - 1]; } else if ($(start).is('.todo-text')) { startParent = start; } else { return; } startParentParent = startParent.parentNode; //todo-view nowstart = start; if (!domUtils.isBody(startParentParent)) { while (startParent.firstChild) { startParentParent.parentNode.insertBefore(startParent.firstChild, startParentParent); } domUtils.remove(startParentParent); if (!nowstart.firstChild) { nowstart.innerHTML = '
' } range.setStart(nowstart, 0); range.setEnd(nowstart, 0); if (evt) { me.fireEvent('contentchange'); me.fireEvent('saveScene'); range.select(); } } }, //遍历所有节点,给所有块状元素加element-id addBlockElementId: function (html) { var root = UE.htmlparser(html, true); root.traversal(function (node) { if (node.type == 'element') { if ((dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(node, 'display')]) && !dtd.$nonChild[node.tagName]) { node.setAttr('element-id', domUtils.getRandomId()) } } }) html = root.toHtml(); return html; }, // 20200605 inserthtml后发送html数据 sendhtml: function (html, pasteTag) { var me = this; if (me.options.cooperation) { var data = {}; data.name = 'inserthtml'; var range = me.selection.getRange(); data.address = range.createAddress(false, true); data.html = html; if (pasteTag) { data.pasteTag = pasteTag; } me.sendJoinData(data); } }, //标题1后换行 enterAfterH: function (range, hTag) { var me = this, start = range.startContainer, doSave; // 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) { //折叠标题后换行的,换到折叠标题的最后一行 if (range.startContainer.previousElementSibling && domUtils.isBlockElm(range.startContainer.previousElementSibling) && range.startContainer.previousElementSibling.className.indexOf('tempShow') > -1) { var p = range.startContainer; p.previousElementSibling.style.display = 'none' p.previousElementSibling.classList.remove('tempShow'); var h = document.createElement(hTag); h.innerHTML = p.innerHTML; h.setAttribute('element-id', p.getAttribute('element-id')); p.parentNode.insertBefore(h, p); range.setStart(h, 0).collapse(true).select(true); p.parentNode.removeChild(p); } else { var tmp = me.document.createTextNode(''), div; range.insertNode(tmp); div = domUtils.findParentByTagName(tmp, 'div', true); if (div) { var p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) while (div.firstChild) { p.appendChild(div.firstChild); } div.parentNode.insertBefore(p, div); domUtils.remove(div); range.setStartBefore(tmp).setCursor(); doSave = 1; } domUtils.remove(tmp); } } // } $(me.body).find('.tempShow').removeClass('tempShow').removeAttr('style') if (me.undoManger && doSave) { me.undoManger.save(); } }, //20200324 设置签名 setSign: function (html) { var me = this; me.fireEvent('beforesetcontent', html); if (html == '无') { if (me.body.querySelector('#signDiv') && me.body.querySelector('#signDiv').parentNode.tagName.toLowerCase() == 'body') { domUtils.remove(me.body.querySelector('#signDiv')); } } else { var div = document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()) div.id = 'signDiv'; div.className = 'signDiv'; div.style.cssText = 'padding-top: 90px;' div.innerHTML = html; div.contentEditable = 'false'; if (me.body.querySelector('#notice_main')) { me.body.insertBefore(div, me.body.querySelector('#notice_main')) } else { me.body.appendChild(div) } //点击签名,光标定到编辑器 $(me.body).find('#signDiv').off('click').on('click', function () { var range = me.selection.getRange(); var node = this.previousSibling; if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) { while (node.lastChild && node.lastChild.nodeType == 1 && !dtd.$empty[node.lastChild.tagName]) { node = node.lastChild; } if (domUtils.isEmptyBlock(node)) { range.setStartAtFirst(node) } else { range.setStartAtLast(node) } range.collapse(true); } range.select(true); }) } me.fireEvent('aftersetcontent'); me.fireEvent('contentchange'); }, //20200527 选择模版 setNoticeTemplate: function (html) { var me = this; me.fireEvent('beforesetcontent', html); if (html) { var div = document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()) div.innerHTML = html; if (me.body.querySelector('#signDiv') && me.body.querySelector('#signDiv').parentNode.tagName.toLowerCase() == 'body') { //有签名,在签名前插入 me.body.insertBefore(div, me.body.querySelector('#signDiv')); } else if (me.body.querySelector('#notice_main')) { //有原站内信函,在原站内信函前插入 me.body.insertBefore(div, me.body.querySelector('#notice_main')); } else { //没有签名,在编辑器最后插入 me.body.appendChild(div); } me.focus(true); var rng = me.selection.getRange(); rng.setStartAfter(div).collapse(true).select(); me.fireEvent('aftersetcontent'); me.fireEvent('contentchange'); } }, //将base64转换为file dataURLtoFile: function (dataurl) {//将base64转换为文件 var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], domUtils.getRandomId() + '.' + mime.split('/')[1], {type: mime}); }, //base64图片替换为云盘地址 replaceBase64Img: function (img) { // if (!RichTextUitl.puid || !RichTextUitl.yunToken) { // RichTextUitl.getUploadConfig(true); // } var me = this; /* 创建Ajax并提交 */ var actionUrl = me.getActionUrl(me.getOpt('imageActionName')); var xhr = new XMLHttpRequest(), fd = new FormData(); var file = me.dataURLtoFile((img.getAttribute('src') || img.getAttribute('_src'))); fd.append('file', file, file.name); fd.append('type', 'ajax'); if(RichTextUitl.puid && RichTextUitl.yunToken){ fd.append("puid", RichTextUitl.puid); fd.append("_token", RichTextUitl.yunToken); } xhr.open("post", actionUrl, true); xhr.addEventListener('load', function (e) { try { var json = JSON.parse(e.target.response); if (RichTextUitl.intranetMode && typeof RichTextUitl.customUploadDataAnalysis == 'function') { // 镜像版本需要处理下接口返回值 json = RichTextUitl.customUploadDataAnalysis(json); } if (json.result) { var suffix = json.data.suffix || 'jpg'; var imgUrl; if (RichTextUitl.intranetMode) { imgUrl = data.data.imgUrl; } else { imgUrl = json.data.previewUrl; } img.src = imgUrl; img.onload = function(){ imgUrl = imgUrl + '?rw=' + img.clientWidth + '&rh=' + img.clientHeight + '&_fileSize=' + json.data.size + '&_orientation=1'; img.setAttribute('_src', imgUrl); } img.setAttribute('_src', imgUrl); } else { domUtils.setAttributes(img, { "src": RichTextUitl.downloadFailedImg, "_src": RichTextUitl.downloadFailedImg, "objectid": RichTextUitl.randomUUID(), }); img.removeAttribute('style','') img.removeAttribute('width','') img.removeAttribute('height','') domUtils.addClass(img, 'image-package failImg'); RichTextUitl.showTips(json.msg, 0); } img.parentNode.classList.remove('remoteImage') } catch (er) { domUtils.setAttributes(img, { "src": RichTextUitl.downloadFailedImg, "_src": RichTextUitl.downloadFailedImg, "objectid": RichTextUitl.randomUUID(), }); img.removeAttribute('style','') img.removeAttribute('width','') img.removeAttribute('height','') domUtils.addClass(img, 'image-package failImg'); RichTextUitl.showTips('上传图片失败', 0) } }); xhr.send(fd); }, //打开删除弹窗 openDeleteModal: function (delType, delIndex, editorId) { // if(delType == '1'){ // $('.popUeditorDelShowHide .typeText').text('图片') // }else if(delType == '2'){ // $('.popUeditorDelShowHide .typeText').text('附件') // }else if(delType == '3'){ // $('.popUeditorDelShowHide .typeText').text('表格') // } //新泛雅弹窗覆盖顶部和左侧 if (top) { top.postMessage('{"cmd":1,"toggle":true}', "*"); } $('.popUeditorDelShowHide').addClass('maskFadeOut').attr('deltype', delType).attr('delindex', delIndex).attr('editorId', editorId).show(); $('body').addClass('popOverflow'); $('.popUeditorDelShowHide .popDiv').css({ top: function () { return ($(window).height() - $(this).height()) / 2; }, left: function () { return ($(window).width() - $(this).width()) / 2; }, transform: 'none' }); }, //删除元素:参数(元素在页面中的索引,元素名) deleteElement: function (index, tagName, isrecovery, editorId) { $('.edui-editor-resizer').removeClass('scale').removeClass('hover').removeClass('show'); var editor = UE.getEditor(editorId); var me = editor; var rng = me.selection.getRange(); if (!isrecovery && me.options.cooperation) { var data = {}; data.name = 'deleteElement'; data.elementIndex = index; data.tagName = tagName; me.sendJoinData(data); } // var editor = UE.getEditor(editorId) var ele = $(me.body).find(tagName).eq(index); var isOneImg = false; if (tagName == 'img' || tagName == 'iframe') { if (ele.parents('.drag-image-wrap').length > 0 && ele.parents('.drag-image-wrap').find('.editor-image').length > 0) { isOneImg = true; //兼容图片并排后一行放多个图片 if (ele.parents('.drag-image-wrap')[0].previousSibling && ele.parents('.drag-image-wrap')[0].previousSibling.nodeType == 1 && ele.parents('.drag-image-wrap').find('.editor-image').length == 1 && !ele.parents('.drag-image-wrap')[0].previousSibling.getAttribute('contenteditable') && ele.parents('.drag-image-wrap')[0].previousSibling.lastChild) { //imagewrap有前一个元素时,光标定位到前一个元素 rng.setEndAfter(ele.parents('.drag-image-wrap')[0].previousSibling.lastChild).collapse(); } else if (ele.parents('.drag-image-wrap')[0].nextSibling && ele.parents('.drag-image-wrap')[0].nextSibling.nodeType == 1 && !ele.parents('.drag-image-wrap')[0].nextSibling.getAttribute('contenteditable') && ele.parents('.drag-image-wrap')[0].nextSibling.firstChild) { rng.setStartBefore(ele[0].parentNode.parentNode.nextSibling.firstChild).collapse(true);//防止删除后没有光标 } else { rng.setStartBefore(ele[0].parentNode.parentNode).collapse(true);//防止删除后没有光标 } }else if (ele.parents('.drag-iframe-wrap').length > 0 && ele.parents('.drag-iframe-wrap').find('.editor-iframe').length > 0) { isOneImg = true; //兼容视频并排后一行放多个视频 if (ele.parents('.drag-iframe-wrap')[0].previousSibling && ele.parents('.drag-iframe-wrap')[0].previousSibling.nodeType == 1 && ele.parents('.drag-iframe-wrap').find('.editor-iframe').length == 1 && !ele.parents('.drag-iframe-wrap')[0].previousSibling.getAttribute('contenteditable') && ele.parents('.drag-iframe-wrap')[0].previousSibling.lastChild) { //iframewrap有前一个元素时,光标定位到前一个元素 rng.setEndAfter(ele.parents('.drag-iframe-wrap')[0].previousSibling.lastChild).collapse(); } else if (ele.parents('.drag-iframe-wrap')[0].nextSibling && ele.parents('.drag-iframe-wrap')[0].nextSibling.nodeType == 1 && !ele.parents('.drag-iframe-wrap')[0].nextSibling.getAttribute('contenteditable') && ele.parents('.drag-iframe-wrap')[0].nextSibling.firstChild) { rng.setStartBefore(ele[0].parentNode.parentNode.nextSibling.firstChild).collapse(true);//防止删除后没有光标 } else { rng.setStartBefore(ele[0].parentNode.parentNode).collapse(true);//防止删除后没有光标 } } else if(ele.parent().parent().hasClass('record-iframe')) { //打点附件 rng.setStart(ele.parents('.record-box').prev()[0],ele.parents('.record-box').prev().length).collapse(true);//防止删除后没有光标 }else { rng.setStartBefore(ele[0].parentNode).collapse(true);//防止删除后没有光标 } if (!ele.hasClass('loadingClass') && ele.siblings('.attachprogress').length == 0 && ele.siblings('.imgprogress').length == 0) { if (me.options.statsAttach) { //统计图片附件弹窗删除 var staAtt = [{ 'type': tagName == 'img' ? 'img' : 'iframe', 'resource': tagName == 'img' ? ele.attr('src') : ele.attr('name') }] me.anasycStatsAttach(staAtt, 0); } } } else { rng.setStartBefore(ele[0]); } if (ele.length === 0) { return; } var elePack = ele; if(ele.parent().parent().hasClass('record-iframe')) { //打点附件,删除附件 var start = ele[0].parentNode; startParent = start.parentNode; //record-iframe startParentParent = startParent.parentNode; //record-box // nowstart = start; while (startParent.firstChild) { startParentParent.parentNode.insertBefore(startParent.firstChild, startParentParent); } domUtils.remove(startParent); }else if (ele.parent().length > 0 && ele.parent().attr('contenteditable') == 'false') { elePack = ele.parent(); //兼容图片并排后一行放多个图片 if (elePack.parent().length > 0 && elePack.parent().attr('contenteditable') == 'false' && elePack.parent().hasClass('drag-image-wrap') && elePack.parent().find('.editor-image').length == 1) { elePack = elePack.parent(); }else if (elePack.parent().length > 0 && elePack.parent().attr('contenteditable') == 'false' && elePack.parent().hasClass('drag-iframe-wrap') && elePack.parent().find('.editor-iframe').length == 1) { elePack = elePack.parent(); } } else if (elePack.parent().length > 0 && elePack.parent().attr('class') == 'table') { elePack = elePack.parent(); } elePack.remove(); if (isOneImg) { rng = rng.shrinkBoundary(); } //删除后 顶部悬浮操作栏隐藏 $('.edui-editor-resizer').removeClass('hover'); if (!isrecovery) { rng.select(true); } me.fireEvent('contentchange'); me.fireEvent('saveScene'); }, //删除元素 deleteEle: function (dom, nodeName) { var me = this; $('.edui-editor-resizer').removeClass('scale').removeClass('hover').removeClass('show'); var nodeName; var index = $(dom).parents('.edui-editor-resizer').attr('index'); var delType; if (dom.className.indexOf('img') > -1) { delType = '1'; } else if (dom.className.indexOf('iframe') > -1) { var type = $(dom).parents('.edui-editor-resizer').attr('iframetype'); if (type && type == 'text') { delType = '4'; } else { delType = '2'; } } else if (dom.className.indexOf('table') > -1) { delType = '3'; } else if (dom.className.indexOf('pre') > -1) { //4是a标签 delType = '5'; } if (delType) { me.openDeleteModal(delType, index, me.key); } }, //剪切图片 cutEle: function (dom) { var me = this; var nodeName; if (dom.className.indexOf('img') > -1) { nodeName = 'img'; } else if (dom.className.indexOf('iframe') > -1) { var type = $(dom).parents('.edui-editor-resizer').attr('iframetype'); if (type && type == 'text') { nodeName = 'a'; } else { nodeName = 'iframe'; } } else if (dom.className.indexOf('table') > -1) { nodeName = 'table'; } $('.edui-editor-resizer').removeClass('scale').removeClass('hover').removeClass('show'); var index = $(dom).parents('.edui-editor-resizer').attr('index'); var ele; if (nodeName == 'img') { ele = $(me.document.body).find('img').eq(index)[0]; } else if (nodeName == 'iframe') { ele = $(me.document.body).find('iframe').eq(index)[0]; } else if (nodeName == 'a') { ele = $(me.document.body).find('a').eq(index)[0]; } else if (nodeName == 'table') { ele = $(me.document.body).find('table').eq(index)[0]; } if (!ele) { return; } if (ele.parentNode && ele.parentNode.getAttribute('contenteditable') == 'false') { ele = ele.parentNode; } if (!window.dt) { var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } url = prefix + "third-party/clipboard-polyfill.promise.js"; utils.loadFile(document, { src: url, tag: "script", type: "text/javascript", defer: "defer" }, function () { window.dt = new clipboard.DT(); me.initclipboard('cut', ele, index, nodeName) }); } else { me.initclipboard('cut', ele, index, nodeName) } }, copyEle: function (dom) { var me = this; $('.edui-editor-resizer').removeClass('scale').removeClass('hover').removeClass('show'); var index = $(dom).parents('.edui-editor-resizer').attr('index'); var nodeName; if (dom.className.indexOf('img') > -1) { nodeName = 'img'; } else if (dom.className.indexOf('iframe') > -1) { var type = $(dom).parents('.edui-editor-resizer').attr('iframetype'); if (type && type == 'text') { nodeName = 'a'; } else { nodeName = 'iframe'; } } else if (dom.className.indexOf('table') > -1) { nodeName = 'table'; } else if (dom.className.indexOf('link') > -1) { nodeName = 'a'; } var ele; if (nodeName == 'img') { ele = $(me.document.body).find('img').eq(index)[0]; } else if (nodeName == 'iframe') { ele = $(me.document.body).find('iframe').eq(index)[0]; } else if (nodeName == 'a') { ele = $(me.document.body).find('a').eq(index)[0]; } else if (nodeName == 'table') { ele = $(me.document.body).find('table').eq(index)[0]; } else if (dom.className.indexOf('callout') > -1) { ele = $(me.document.body).find('.callout-block').eq(index)[0]; } if (!ele) { return; } if (ele.parentNode && ele.parentNode.getAttribute('contenteditable') == 'false') { ele.classList.remove('hover'); ele = ele.parentNode; } else if (ele.parentNode && ele.parentNode.className && ele.parentNode.className == 'table') { ele = ele.parentNode; } if (!window.dt) { var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } url = prefix + "third-party/clipboard-polyfill.promise.js"; utils.loadFile(document, { src: url, tag: "script", type: "text/javascript", defer: "defer" }, function () { me.initclipboard('copy', ele, index, nodeName) }); } else { me.initclipboard('copy', ele, index, nodeName) } }, initclipboard: function (type, node, index, nodeName) { var me = this; if (!window.dt) { window.dt = new clipboard.DT(); } var html = '
' + node.outerHTML; dt.setData("text/html", html); clipboard.write(dt).then(function () { if (nodeName == 'img') { $(me.document.body).find('.editor-image').removeClass('scale'); } $('.edui-editor-resizer').removeClass('scale').removeClass('hover').removeClass('show'); if ($('.toolTipBox').length > 0) { $('.toolTipBox').remove() } var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } $(document.body).append('

') if (type == 'cut') { me.deleteElement(index, nodeName, null, me.key); $('.toolTipBox .tipstext').text(me.getLang('tips.cutSuccess')); } else if (type == 'copy') { $('.toolTipBox .tipstext').text(me.getLang('tips.copySuccess')); } $('.toolTipBox').show(); setTimeout(function () { $('.toolTipBox').fadeOut(); }, 1500) }, function (err) { console.log(me.getLang('tips.copyFail')); }); }, //替换公式图片信息 updateMathml: function (imgindex, mathdata, url) { var me = this; var img = me.body.querySelectorAll('img')[imgindex]; var imgObj = new Image() imgObj.src = url imgObj.onload = function(e) { img.style.width = e.target.naturalWidth + 'px' } // img.style.width = ''; img.setAttribute('width', ''); img.setAttribute('mathdata', mathdata); img.setAttribute('src', url); img.setAttribute('_src', url); me.fireEvent('contentchange'); me.fireEvent('saveScene'); }, /* *@Description:增加sign 编辑 *@Date: 2023-04-13 18:58:30 */ editSign:function(){ var me = this; var frames = me.window.frameElement.contentWindow.document var signImg = frames.getElementById('signImg') var signDiv = frames.getElementById('signDiv') var signName = signDiv.querySelector('.nameBox') ? signDiv.querySelector('.nameBox').innerText : 0; var signTime = signDiv.querySelector('.timeBox') ? signDiv.querySelector('.timeBox').innerText : 0; var signLoc = signDiv.querySelector('.signContainer') ? signDiv.querySelector('.signContainer').classList[1] : ''; var nameLoc = signDiv.querySelector('.nameBox') ? signDiv.querySelector('.nameBox').classList[1] : ''; var timeLoc = signDiv.querySelector('.timeBox') ? signDiv.querySelector('.timeBox').classList[1] : ''; me.openEditSignModal(signImg.src,signImg,signName,signTime,signLoc,nameLoc,timeLoc); }, openEditSignModal: function (url,signImgDiv,signName,signTime,signLoc,nameLoc,timeLoc) { var me = this; //新泛雅弹窗覆盖顶部和左侧 if (top) { top.postMessage('{"cmd":1,"toggle":true}', "*"); } if ($(".popUeditorEditSignShowHide").length == 0) { var imgPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ imgPrefix = RichTextUitl.prefix } var div = document.createElement("div"); div.className = "maskDiv popUeditorEditSignShowHide editorMaskDiv"; div.style.cssText = "display: none;"; div.innerHTML = '
' + '
' + '' + '

' + me.getLang('seal.seal') + "

" + "
" + '
' + '
' + '
'+ '
'+ '
'+ '
'+ '
'+ '

'+signName +'

'+ '

'+signTime +'

'+ '
'+ '
'+ '
'+ '
' + // '
' + '
' + '
'+ me.getLang('seal.sealSize') +'
'+ me.getLang('seal.width') +'
' + '' + '
'+ me.getLang('seal.height') +'
' + '' + "
" + '
'+ me.getLang('seal.sealLoc') +'
' + '
'+ me.getLang('seal.sign') +'
' + '
' + '
'+ me.getLang('seal.signLoc') +'
' + '
'+ me.getLang('seal.date') +'
' + '
' + '
'+ me.getLang('seal.date') +'
' + '" + '
' + "
"; document.body.appendChild(div); $("body").on("change",".popUeditorEditSignShowHide #file",function () { if ($(".popUeditorEditSignShowHide #file")[0].files.item(0)) { fileData = $(".popUeditorEditSignShowHide #file")[0].files.item(0); } signAjax("post", me.getActionUrl('uploadimage'), { type: "file" }, function (data) { img = new Image(); img.src = data.data.previewUrl; hasmyImage = true; signImg[0].src = data.data.previewUrl; signImgSrc = data.data.previewUrl; signImg[0].style.display = "block"; signImg[0].style.width = signImgW; signImg[0].style.height = signImgH; $(".popUeditorEditSignShowHide .reloadUpload")[0].style.display = "block"; if (signTime) { $(".popUeditorEditSignShowHide #timeBox")[0] = signTime; } if (signName) { $(".popUeditorEditSignShowHide #nameBox")[0].textContent = signName; } nameLocaChange(); timeLocaChange(); }); }); $("body").on("change",".popUeditorEditSignShowHide #time",function(){ if (!$(".popUeditorEditSignShowHide #time")[0].value) { $(".popUeditorEditSignShowHide #time")[0].className = $(".popUeditorEditSignShowHide #time")[0].className + " timeInputEmpty"; } else { $(".popUeditorEditSignShowHide #time")[0].className = "timeInput"; } }) // 监听input标签 值变化 $("body").on("input",".popUeditorEditSignShowHide #time,.popUeditorEditSignShowHide #name,.popUeditorEditSignShowHide #sign,.popUeditorEditSignShowHide #width,.popUeditorEditSignShowHide #height",function (event) { if (hasmyImage == true) { switch (event.target.id) { case "name": var el = $(".popUeditorEditSignShowHide #nameBox"); el[0].textContent = event.target.value; nameLocaChange(); timeLocaChange(); signName = event.target.value; break; case "time": document.getElementById("time").classList.remove("timeInput"); var el = $(".popUeditorEditSignShowHide #timeBox"); el[0].textContent = event.target.value; nameLocaChange(); timeLocaChange(); signTime = event.target.value; break; case "width": if (event.target.value > 280) { event.target.value = 280; } signImg[0].style.width = event.target.value + "px"; signImgW = event.target.value; nameLocaChange(); timeLocaChange(); break; case "height": if (event.target.value > 280) { event.target.value = 280; } $(".popUeditorEditSignShowHide #signDiv")[0].style.height = event.target.value + "px"; signImg[0].style.height = event.target.value + "px"; signImgH = event.target.value; nameLocaChange(); timeLocaChange(); break; } } }); // 监听select标签 值变化 $("body").on("change",".popUeditorEditSignShowHide #timeSelect,.popUeditorEditSignShowHide #nameSelect,.popUeditorEditSignShowHide #signSelect",function (event) { var index = null; switch (event.target.id) { case "signSelect": index = $(".popUeditorEditSignShowHide #signSelect")[0].selectedIndex; $(".popUeditorEditSignShowHide #signSelect")[0].options[index].value; signLocation = $(".popUeditorEditSignShowHide #signSelect")[0].options[index].value; break; case "timeSelect": index = $(".popUeditorEditSignShowHide #timeSelect")[0].selectedIndex; $(".popUeditorEditSignShowHide #timeSelect")[0].options[index].value; timeLocation = $(".popUeditorEditSignShowHide #timeSelect")[0].options[index].value; nameLocaChange(); timeLocaChange(); break; case "nameSelect": index = $(".popUeditorEditSignShowHide #nameSelect")[0].selectedIndex; $(".popUeditorEditSignShowHide #nameSelect")[0].options[index].value; nameLocation = $(".popUeditorEditSignShowHide #nameSelect")[0].options[index].value; nameLocaChange(); timeLocaChange(); break; } }); //编辑链接弹窗--确认修改 $("body").on("click",".popUeditorEditSignShowHide #confirm",function () { $(".popUeditorEditSignShowHide #signDiv")[0].style.position ="static"; $(".popUeditorEditSignShowHide #signDiv")[0].style.display ="block"; // $(".popUeditorEditSignShowHide #signDiv")[0].style.height = signImgH + "px"; $(".popUeditorEditSignShowHide #drag-image-wrap")[0].style.maxHeight = "none"; $(".popUeditorEditSignShowHide #drag-image-wrap")[0].style.maxWidth = "none"; switch (signLocation) { case "left": $(".popUeditorEditSignShowHide #signDiv")[0].style.textAlign = ""; break; case "right": $(".popUeditorEditSignShowHide #signDiv")[0].style.textAlign = "right"; break; case "center": $(".popUeditorEditSignShowHide #signDiv")[0].style.textAlign = "center"; break; } $(".popUeditorEditSignShowHide #signDiv")[0].style.height = signImg[0].style.height $(".popUeditorEditSignShowHide #signContainer")[0].className = "signContainer " + signLocation; $(".popUeditorEditSignShowHide #timeBox")[0].className = "timeBox " + timeLocation; $(".popUeditorEditSignShowHide #nameBox")[0].className = "nameBox " + nameLocation; divHtml = $(".popUeditorEditSignShowHide #container")[0].innerHTML; if (signImgSrc != null) { var signDiv = me.document.getElementById("signDiv"); var tempNode = document.createElement('div'); tempNode.innerHTML = divHtml; me.body.replaceChild(tempNode.getElementsByClassName('signDiv')[0] , signDiv) $(".popUeditorEditSignShowHide").removeClass("maskFadeOut").hide(); $("body").removeClass("popOverflow"); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } } else { $(".popUeditorEditSignShowHide").removeClass("maskFadeOut").hide(); $("body").removeClass("popOverflow"); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } } me.fireEvent('contentchange'); me.fireEvent('saveScene'); } ); //编辑链接弹窗--关闭按钮 $("body").on("click",".popUeditorEditSignShowHide .popClose,.popUeditorEditSignShowHide #cancel",function () { $(".popUeditorEditSignShowHide").removeClass("maskFadeOut").hide(); $("body").removeClass("popOverflow"); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } } ); } $(".popUeditorEditSignShowHide #signDiv")[0].style.display = "inline-block"; $(".popUeditorEditSignShowHide").addClass("maskFadeOut").show(); var signImg = $(".popUeditorEditSignShowHide #signImg"); // var file = $(".popUeditorEditSignShowHide #file"); var img = null; var divHtml = ""; var signImgSrc = null; var hasmyImage = false; var signImgW = signImgDiv.width var signImgH = signImgDiv.height var signLocation = signLoc; var timeLocation = timeLoc; var nameLocation = nameLoc; var params = {}; var fileData = null; $(".popUeditorEditSignShowHide #signDiv")[0].style.height = signImgH + 'px' $(".popUeditorEditSignShowHide #width").prop('value',signImgW) $(".popUeditorEditSignShowHide #height").prop('value',signImgH) if(signTime){ $(".popUeditorEditSignShowHide #time")[0].className = 'timeInput' } $(".popUeditorEditSignShowHide #name").prop('value',signName) $(".popUeditorEditSignShowHide #time").prop('value',signTime) $(".popUeditorEditSignShowHide #nameBox").text(signName) $(".popUeditorEditSignShowHide #timeBox").text(signTime) // var fileName = null; function nameLocaChange() { switch (nameLocation) { case "center": $(".popUeditorEditSignShowHide #nameBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight / 2 - ($(".popUeditorEditSignShowHide #timeBox")[0].clientHeight + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight) / 2 + "px"; if (timeLocation == "center") { $(".popUeditorEditSignShowHide #timeBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight / 2 - ($(".popUeditorEditSignShowHide #timeBox")[0].clientHeight + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight) / 2 + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight + "px"; } break; case "top": $(".popUeditorEditSignShowHide #nameBox")[0].style.top = "0px"; break; case "bottom": $(".popUeditorEditSignShowHide #nameBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight - $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight + "px"; if (timeLocation == "bottom") { $(".popUeditorEditSignShowHide #timeBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight - ($(".popUeditorEditSignShowHide #timeBox")[0].clientHeight + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight) + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight + "px"; } break; } $(".popUeditorEditSignShowHide #nameBox")[0].style.left = $(".popUeditorEditSignShowHide #signDiv")[0].clientWidth / 2 - $(".popUeditorEditSignShowHide #nameBox")[0].clientWidth / 2 + "px"; } function timeLocaChange() { switch (timeLocation) { case "center": $(".popUeditorEditSignShowHide #timeBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight / 2 - ($(".popUeditorEditSignShowHide #timeBox")[0].clientHeight + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight) / 2 + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight + "px"; if (nameLocation == "center") { $(".popUeditorEditSignShowHide #nameBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight / 2 - ($(".popUeditorEditSignShowHide #timeBox")[0].clientHeight + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight) / 2 + "px"; } break; case "top": $(".popUeditorEditSignShowHide #timeBox")[0].style.top = "0px"; if (nameLocation == "top") { $(".popUeditorEditSignShowHide #timeBox")[0].style.top = $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight + "px"; } break; case "bottom": $(".popUeditorEditSignShowHide #timeBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight - $(".popUeditorEditSignShowHide #timeBox")[0].clientHeight + "px"; if (nameLocation == "bottom") { $(".popUeditorEditSignShowHide #nameBox")[0].style.top = $(".popUeditorEditSignShowHide #signDiv")[0].clientHeight - ($(".popUeditorEditSignShowHide #timeBox")[0].clientHeight + $(".popUeditorEditSignShowHide #nameBox")[0].clientHeight) + "px"; } break; } $(".popUeditorEditSignShowHide #timeBox")[0].style.left = $(".popUeditorEditSignShowHide #signDiv")[0].clientWidth / 2 - $(".popUeditorEditSignShowHide #timeBox")[0].clientWidth / 2 + "px"; } function signAjax(method, url, params, done) { // 统一转换为大写便于后续判断 method = method.toUpperCase(); // 对象形式的参数转换为 urlencoded 格式 var pairs = []; for (var key in params) { pairs.push(key + "=" + params[key]); } var querystring = pairs.join("&"); var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"); xhr.addEventListener("readystatechange", function () { if (this.readyState !== 4) return; // 尝试通过 JSON 格式解析响应体 try { done(JSON.parse(this.responseText)); } catch (e) { done(this.responseText); } }); // 如果是 GET 请求就设置 URL 地址 问号参数 if (method === "GET" && params.type != "file") { url += "?" + querystring; xhr.open(method, url); xhr.send(null); } else if (method === "POST" && params.type == "file") { xhr.open(method, url, true); var fd = new FormData(); fd.append("type", "ajax"); if(RichTextUitl.puid && RichTextUitl.yunToken){ fd.append("puid", RichTextUitl.puid); fd.append("_token", RichTextUitl.yunToken); } fd.append("file", fileData); xhr.send(fd); } } // if (!RichTextUitl.puid || !RichTextUitl.yunToken) { // RichTextUitl.getUploadConfig(true); // } if (url) { img = new Image(); img.src = url; hasmyImage = true; signImg[0].src = url; signImgSrc = url; signImg[0].style.display = "block"; signImg[0].style.width = signImgW + 'px'; signImg[0].style.height = signImgH + 'px'; } if(signTime || signName){ nameLocaChange() timeLocaChange() } switch(signLocation){ case 'left': $(".popUeditorEditSignShowHide #signSelect")[0][0].selected="selected"; break; case 'center': $(".popUeditorEditSignShowHide #signSelect")[0][1].selected="selected"; break; case 'right': $(".popUeditorEditSignShowHide #signSelect")[0][2].selected="selected"; break; } switch(nameLocation){ case 'top': $(".popUeditorEditSignShowHide #nameSelect")[0][0].selected="selected"; break; case 'center': $(".popUeditorEditSignShowHide #nameSelect")[0][1].selected="selected"; break; case 'bottom': $(".popUeditorEditSignShowHide #nameSelect")[0][2].selected="selected"; break; } switch(timeLocation){ case 'top': $(".popUeditorEditSignShowHide #timeSelect")[0][0].selected="selected"; break; case 'center': $(".popUeditorEditSignShowHide #timeSelect")[0][1].selected="selected"; break; case 'bottom': $(".popUeditorEditSignShowHide #timeSelect")[0][2].selected="selected"; break; } $("body").addClass("popOverflow"); $(".popUeditorEditSignShowHide .popDiv").css({ top: function () { return ($(window).height() - $(this).height()) / 2; }, left: function () { return ($(window).width() - $(this).width()) / 2; }, transform: "none", }); }, changeAttachmentModel: function (_this, type) { var me = this; var attachmentData = $(_this).attr('name'); if (!attachmentData) { return; } try { attachmentData = RichTextUitl.b64DecodeUnicode(attachmentData); } catch (e) { } $(_this).attr('preview', 'false'); var module = $(_this).attr('module'); var elementid = $(_this).attr('element-id') || ''; var tagName = _this[0].tagName; var href = ''; var name = ''; var excel = ''; if (tagName == 'IFRAME') { var linkClass = ''; var oldName = RichTextUitl.b64EncodeUnicode(JSON.stringify(attachmentData)); var attachmentContent = RichTextUitl.b64DecodeUnicode(oldName); // 当前是iframe形式,转成 a 标签显示 switch (attachmentData.attachmentType) { case 18: // 云盘文件 href = attachmentData.att_clouddisk.downPath || ('https://d0.cldisk.com/download/' + attachmentData.att_clouddisk.fileId); name = attachmentData.att_clouddisk.name; linkClass = 'iframe'; break; case 25: href = attachmentData.att_web.url; name = attachmentData.att_web.title; linkClass = 'link'; break; } if (!href) { return; } // html = ''; $(_this).parent('.editor-iframe').replaceWith(html); } else if (tagName == 'A') { // 当前是 a 标签形式,转成 iframe 标签显示 var webPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/'; if(RichTextUitl.intranetMode){ webPrefix = RichTextUitl.prefix } var src = webPrefix + 'attachment/' + module + '.html'; var preview = false; if (type == 'preview') { var fileName = $(_this).text(); var att_clouddisk = RichTextUitl.getCloudFileData($(_this).attr('name')); var fileSuffix = att_clouddisk.suffix; if (fileName.indexOf('.' + fileSuffix) > -1) { fileName = fileName.substring(0, fileName.indexOf('.' + fileSuffix)); } src = window.location.protocol + '//previewyd.chaoxing.com/res/view/view.html?objectid=' + att_clouddisk.fileId + '&fileName=' + encodeURIComponent(fileName); if (!RichTextUitl.intranetMode && (fileSuffix == 'xls' || fileSuffix == 'xlsx')) { // excel附件使用在线表格页面 var appDomain = window.location.protocol + '//appswh.chaoxing.com' if(window.obj && window.obj.mirrorDomain){ appDomain = window.location.protocol + window.obj.mirrorDomain.appsWhDomainHttps.replace('https:','').replace('http:',''); } src = appDomain + '/res/Spreadsheets/wpsPC.html?type=attachment&cid=' + $(_this).attr('cid') + '&resid=' + (att_clouddisk.residstr || att_clouddisk.resid) + '&title=' + encodeURIComponent(fileName + '.' + fileSuffix) + '&editorid=' + me.key } preview = true; } else if (type == 'advancedpreview') { var att_clouddisk = RichTextUitl.getCloudFileData($(_this).attr('name')); src = window.location.protocol + '//previewyd.chaoxing.com/res/view/view.html?mode=advancedpreview&objectid=' + att_clouddisk.fileId + '&fileName=' + encodeURIComponent(fileName); preview = true; } src = RichTextUitl.convertUrl(src) // a 标签形式下,可以修改文本内容,从链接形式改回来的,需要修改附件数据 // 笔记有定时保存草稿的逻辑,getRichText里面也会进行处理, // 这里主要是在其他页面没有定时获内容的逻辑时,能正常修改内容 var oldName = $(_this).attr('name') var attachmentContent = RichTextUitl.b64DecodeUnicode(oldName); var hasChange = false; var newText = $(_this).text(); if (module == 'insertCloud' && attachmentContent.att_clouddisk && attachmentContent.att_clouddisk.name != newText) { // 云盘附件 attachmentContent.att_clouddisk.name = newText; attachmentContent.att_clouddisk.infoJsonStr.name = newText; hasChange = true; } else if (module == 'insertWeb' && attachmentContent.att_web) { // 网页附件 if (attachmentContent.att_web.title != newText) { attachmentContent.att_web.title = newText; hasChange = true; } if (attachmentContent.att_web.excel == 1) { // 在线表格转成的excel src = attachmentContent.att_web.url.replace('https:', window.location.protocol) + '&isEditorStatus=1'; excel = 'true'; } } if (hasChange) { oldName = RichTextUitl.b64EncodeUnicode(JSON.stringify(attachmentContent)); } var downloadHtml = ''; if ($(_this).attr('download')) { downloadHtml = ' download=' + '"' + $(_this).attr('download') + '"'; } if ($(_this).attr('allowdownload')) { downloadHtml += ' allowdownload=' + '"' + $(_this).attr('allowdownload') + '"'; } var previewHtml = ''; if ($(_this).attr('allowpreview')) { previewHtml += ' allowpreview=' + '"' + $(_this).attr('allowpreview') + '"'; } if (type == 'advancedpreview') { previewHtml += 'advancedpreview="true"'; } var fileTypehtml = ''; var iframename = RichTextUitl.b64DecodeUnicode(oldName); if (iframename.attachmentType == 18) { var fileSuffix = iframename.att_clouddisk.suffix; if (fileSuffix == 'xls' || fileSuffix == 'xlsx') { fileTypehtml = ' fileType = "excel" '; } else if (fileSuffix == 'pdf') { fileTypehtml = ' fileType = "pdf" '; } else if (fileSuffix == 'doc' || fileSuffix == 'docx') { fileTypehtml = ' fileType = "word" '; } else if (fileSuffix == 'ppt' || fileSuffix == 'pptx') { fileTypehtml = ' fileType = "ppt" '; } else if (fileSuffix == 'zip' || fileSuffix == 'rar') { fileTypehtml = ' fileType = "zip" '; } } html = '
'; $(_this).parent().replaceWith(html); } }, //编辑链接 editLink: function (obj) { var me = this; var iframeType = $(obj).parents('.edui-editor-resizer').attr('iframetype'); var index = $(obj).parents('.edui-editor-resizer').attr('index'); var editorId = me.key; me.openEditLinkModal(iframeType, index, editorId); }, normalList: function () { var me = this; if ($(me.body).find('ul,ol').length == 0) return; var range = me.selection.getRange(); var bk = range.createBookmark(true); //$(me.body).find('p:empty,div:empty,h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty').remove(); utils.each(domUtils.getElementsByTagName(me.document, 'ol ul'), function (list) { if (!list.getAttribute('level')) { list.setAttribute('level', $(list).parents('li').length + 1) } if (list.childNodes.length > 1) { var firstli = list.firstChild; var listnext = list.nextSibling; if (!firstli) { list.remove(); return; } while (firstli.nextSibling) { var nextLi = firstli.nextSibling; var newlist = document.createElement(list.tagName); if (list.tagName.toLowerCase() == 'ol') { //2021.06.01 li后面是文本节点 if (nextLi.nodeType == 3 || (nextLi.nodeType == 1 && !domUtils.isBlockElm(nextLi))) { var newLi = document.createElement('li'); var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()); p.appendChild(nextLi); newLi.appendChild(p); while (nextLi.nextsiblings && (nextLi.nextsiblings.nodeType == 3 || (nextLi.nextsiblings.nodeTpye == 1 && !domUtils.isBlockElm(nextLi.nextsiblings)))) { if (nextLi.nextsiblings.nodeName == 'BR') { nextLi.nextsiblings.remove(); } else { p.appendChild(nextLi.nextsiblings); } } nextLi = newLi; } } newlist.appendChild(nextLi); if (listnext) { list.parentNode.insertBefore(newlist, listnext); } else { list.parentNode.appendChild(newlist) } newlist.setAttribute('level', list.getAttribute('level')); } } }) utils.each(domUtils.getElementsByTagName(me.document, 'ol ul'), function (list) { var firstli = list.firstChild; if (!firstli) { domUtils.remove(list); return; } var firstnode = firstli.firstChild; if (!firstnode) { domUtils.remove(list); return; } //safari浏览器没有文本节点时输入文字会把li和p都移除 if ((browser.safari && firstnode.childNodes.length == 1 && firstnode.firstChild.tagName == 'BR') || (browser.safari && firstnode.childNodes.length == 2 && firstnode.lastChild.tagName == 'BR' && firstnode.firstChild.id && firstnode.firstChild.id == bk.start)) { var text = document.createTextNode(domUtils.fillChar); firstnode.insertBefore(text, firstnode.firstChild); } if (firstnode.nodeName == 'HR') { list.parentNode.insertBefore(firstnode, list); if (!firstli.firstChild) { domUtils.remove(firstli); } if (!list.firstChild) { if (list.nextElementSibling && list.nextElementSibling.nodeName == "OL" && list.nextElementSibling.getAttribute('level') == list.getAttribute('level') && list.nextElementSibling.getAttribute('serialnum') == addSerialNum(list.getAttribute('serialnum'), list.getAttribute('level'))) { list.nextElementSibling.setAttribute('serialnum', list.getAttribute('serialnum')); list.nextElementSibling.firstChild.setAttribute('serialnum', list.getAttribute('serialnum')); } domUtils.remove(list); return; } } else if (firstnode.nodeType == 3 || (firstnode.nodeType == 1 && !domUtils.isBlockElm(firstnode))) { var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()); p.appendChild(firstnode); firstli.prepend(p); while (p.nextsiblings && (p.nextsiblings.nodeType == 3 || (p.nextsiblings.nodeTpye == 1 && !domUtils.isBlockElm(p.nextsiblings)))) { p.appendChild(p.nextsiblings); } } else if (firstnode.nodeType == 1 && domUtils.isBlockElm(firstnode) && !firstnode.firstChild) { domUtils.remove(firstnode); } else if (domUtils.isBlockElm(firstnode) && firstnode.firstChild && domUtils.isBlockElm(firstnode.firstChild)) {//li第一个元素是p套p,预防p套p的问题 if (!firstnode.firstChild.firstChild) { $(firstnode.firstChild).remove(); } if (firstnode.firstChild && domUtils.isBlockElm(firstnode.firstChild)) { firstli.prepend(firstnode.firstChild); } } var listnext = list.nextSibling; var serialnum = 1, serialstr = '1'; var level = parseInt(list.getAttribute('level')) || 1; if (list.tagName.toLowerCase() == 'ol') { if (!firstli.getAttribute('serialnum')) { firstli.setAttribute('serialnum', serialstr); list.setAttribute('serialnum', serialstr); if (!list.getAttribute('level')) { list.setAttribute('data-origin-start', '1'); } } else { serialstr = firstli.getAttribute('serialnum'); list.setAttribute('serialnum', serialstr); } serialnum = domUtils.serialnumToInt(serialstr, level); } if (!list.getAttribute('level') && $(list).parents('li').length == 0) { list.setAttribute('level', 1); } //序号颜色大小根据文字大小改变 var fontweight = $(me.body).hasClass('mac') ? 500 : 600; var firsttag = list.firstChild.firstChild; //去除li下元素的行距,保留li上的行距 if (firsttag && firsttag.style.lineHeight) { firsttag.style.lineHeight = '' } if (list.firstChild && list.firstChild.style.cssText && list.firstChild.style.cssText.indexOf('line-height') > -1) { list.firstChild.style.cssText = 'line-height:' + list.firstChild.style.lineHeight; } else { list.firstChild.style.cssText = ''; } while (firsttag) { if (firsttag.nodeType == 1 && firsttag.nodeName == "SPAN" && firsttag.id.indexOf('bookmark') > -1) { firsttag = firsttag.nextSibling; } else if (firsttag.nodeType == 1 && firsttag.nodeName == "SPAN" && firsttag.style.cssText != "") { firsttag.style.fontFamily != "" ? list.firstChild.style.fontFamily = firsttag.style.fontFamily : ''; firsttag.style.fontSize != "" ? list.firstChild.style.fontSize = firsttag.style.fontSize : ''; firsttag.style.color != "" ? list.firstChild.style.color = firsttag.style.color : ''; firsttag = firsttag.firstChild; } else if (firsttag.nodeType == 1 && firsttag.nodeName == 'H1') { list.firstChild.style.cssText += 'font-size:24px;font-weight:' + fontweight; firsttag = firsttag.firstChild; } else if (firsttag.nodeType == 1 && firsttag.nodeName == 'H2') { list.firstChild.style.cssText += 'font-size:20px;font-weight:' + fontweight; firsttag = firsttag.firstChild; } else if (firsttag.nodeType == 1 && firsttag.nodeName == 'H3') { list.firstChild.style.cssText += 'font-size:18px;font-weight:' + fontweight; firsttag = firsttag.firstChild; } else if (firsttag.nodeType == 1 && firsttag.nodeName == 'H4') { list.firstChild.style.cssText += 'font-size:16px;font-weight:' + fontweight; firsttag = firsttag.firstChild; } else if (firsttag.nodeType == 1 && domUtils.isBlockElm(firsttag)) { list.firstChild.style.fontFamily = ''; list.firstChild.style.fontSize = ''; list.firstChild.style.color = ''; $(list.firstChild).children().css({'font-size': '', 'color': '', 'font-family': ''}); firsttag = firsttag.firstChild; } else if (firsttag.nodeType == 3 && domUtils.isFillChar(firsttag)) { firsttag = firsttag.nextSibling; } else if (firsttag.nodeType == 3 || firsttag.nodeName == 'BR') { break; } else { firsttag = firsttag.firstChild; } } if (list.tagName == 'OL' && domUtils.serialnumToInt(list.getAttribute('serialnum'), level) == 1) { list.setAttribute('data-origin-start', '1') } if (list.tagName == 'OL' && (list.getAttribute('data-start') || list.getAttribute('data-origin-start'))) { var listindex = $(me.body).find('ol').index(list); for (var i = listindex + 1; i < $(me.body).find('ol').length; i++) { var listnext = $(me.body).find('ol')[i]; if (listnext.getAttribute('level')) { if (listnext.getAttribute('level') < list.getAttribute('level')) { break; } else if (listnext.getAttribute('level') == list.getAttribute('level') && (listnext.getAttribute('data-start') || listnext.getAttribute('data-origin-start'))) { break; } else if (listnext && listnext.tagName && listnext.tagName.toLowerCase() == 'ol' && listnext.firstChild && listnext.getAttribute('level') == list.getAttribute('level') && listnext.tagName == list.tagName && listnext.firstChild.nodeType == 1) { ++serialnum; var serialstr = domUtils.serialnumToString(serialnum, level); listnext.removeAttribute('data-origin-start'); listnext.setAttribute('serialnum', serialstr); listnext.firstChild.setAttribute('serialnum', serialstr); } } } } //给有大小颜色的li下的块状子元素添加原始样式,保证后面没有大小颜色的文字样式不被改变 $(list).find('li').children().each(function (index, node) { if (node.parentNode.style.cssText != '' && domUtils.isBlockElm(node) && $(node).text().trim() != '' && node.firstChild) { if (node.tagName.indexOf('H') == -1) { //不是标题 if ($(node).parents('table').length == -1) { $(node).css({'font-size': $(me.body).css('font-size')}); } else { $(node).css({'font-size': $(node).parents('table').css('font-size')}); } } if (node.parentNode.style.cssText.indexOf('color') > -1) { $(node).css({'color': '#333333'}); } } }) }) range.moveToBookmark(bk).select(true); }, //检查添加网址的url是否合法 editLinkCheckUrl: function (obj) { var linkStr = $(obj).val(); var urlReg = new RegExp('((((http[s]{0,1}|ftp)://)([a-zA-Z0-9\\-]+\\.)+[a-zA-Z0-9\\-]+(:\\d+)?)|(((http[s]{0,1}|ftp)://)?(((?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))(:\\d+)?)|(([a-zA-Z0-9\\-]+\\.)+((ac)|(ad)|(ae)|(aero)|(af)|(ag)|(ai)|(al)|(am)|(an)|(ao)|(ar)|(arpa)|(as)|(asia)|(at)|(au)|(aw)|(ax)|(az)|(ba)|(bb)|(bd)|(be)|(bf)|(bg)|(bh)|(bi)|(biz)|(bj)|(bm)|(bn)|(bo)|(br)|(bs)|(bt)|(bv)|(bw)|(by)|(bz)|(ca)|(cat)|(cc)|(cd)|(cf)|(cg)|(ch)|(chintai)|(ci)|(ck)|(cl)|(cm)|(cn)|(co)|(com)|(coop)|(cr)|(cu)|(cv)|(cx)|(cy)|(cz)|(de)|(dj)|(dk)|(dm)|(do)|(dz)|(ec)|(edu)|(ee)|(eg)|(er)|(es)|(et)|(eu)|(fi)|(fj)|(fk)|(fm)|(fo)|(fr)|(ga)|(gb)|(gd)|(ge)|(gf)|(gg)|(gh)|(gi)|(gl)|(global)|(globo)|(gm)|(gmail)|(gn)|(gov)|(gp)|(gq)|(gr)|(gs)|(gt)|(gu)|(gw)|(gy)|(hk)|(hm)|(hn)|(hr)|(ht)|(hu)|(id)|(ie)|(il)|(im)|(in)|(info)|(int)|(iq)|(ir)|(is)|(it)|(je)|(jm)|(jo)|(jobs)|(jp)|(ke)|(kg)|(kh)|(ki)|(km)|(kn)|(kp)|(kr)|(kw)|(ky)|(kz)|(la)|(lb)|(lc)|(li)|(lk)|(lr)|(ls)|(lt)|(lu)|(lv)|(ly)|(ma)|(mc)|(md)|(me)|(mg)|(mh)|(mil)|(mk)|(ml)|(mm)|(mn)|(mo)|(mobi)|(mp)|(mq)|(mr)|(ms)|(mt)|(mu)|(museum)|(mv)|(mw)|(mx)|(my)|(mz)|(na)|(name)|(nc)|(ne)|(net)|(nf)|(ng)|(ni)|(nl)|(no)|(np)|(nr)|(nu)|(nz)|(om)|(org)|(pa)|(pe)|(pf)|(pg)|(ph)|(pk)|(pl)|(pm)|(pn)|(pr)|(pro)|(ps)|(pt)|(pw)|(py)|(qa)|(re)|(ro)|(rs)|(ru)|(rw)|(sa)|(sb)|(sc)|(sd)|(se)|(sg)|(sh)|(si)|(sj)|(sk)|(sl)|(sm)|(smile)|(so)|(sr)|(st)|(su)|(sy)|(sz)|(tc)|(td)|(tel)|(tf)|(tg)|(th)|(tj)|(tl)|(tm)|(tn)|(to)|(tp)|(tr)|(travel)|(tt)|(tv)|(tw)|(tz)|(ua)|(ug)|(uk)|(us)|(uy)|(uz)|(va)|(vc)|(ve)|(vg)|(vi)|(vn)|(vu)|(wf)|(ws)|(ye)|(yt)|(za)|(zm)|(zw))(?![a-zA-Z0-9]))(:\\d+)?)))(/[a-zA-Z0-9\\.\\-~!@#$%^&#$%^&*+?:_/=<>()]*)?', 'gi'); var isLink = urlReg.test(linkStr) if (isLink) { $('.popUeditorEditLinkShowHide #href').removeClass('popBook_cuo'); $(".popUeditorEditLinkShowHide #msg").hide(); } else { $('.popUeditorEditLinkShowHide #href').addClass('popBook_cuo'); $(".popUeditorEditLinkShowHide #msg").show(); } }, //统计业务统计附件和图片 anasycStatsAttach: function (staAtt, staOp) { var me = this; //转成字符串 staAtt = JSON.stringify(staAtt); var json = { staUniId: me.stats.staUniId, //统计的ID staResId1: me.stats.staResId1, //业务ID1(非必须,比如表单id,小组bbsid) staResId2: me.stats.staResId2, //业务ID2(非必须,业务ID1的补充id,比如小组的话题id,回复id等) staResType: me.stats.staResType, //业务类型(非必须,比如表单:form,小组:group等) staAtt: staAtt, //附件json staOp: staOp, // 操作类型:0:删除,1:新增 } // var url = window.location.protocol + '//statisticyd.chaoxing.com/apis/statistic/addAttStatistic'; // try { // $.ajax({ // url: url, // type: "post", // xhrFields: { // withCredentials: true // }, // data: json, // dataType: "json", // success: function (data) { // //console.log(data); // }, // error: function (data) { // //console.log(data); // } // }); // } catch (e) { // console.log(e) // } console.log(json); }, insertCourseVideo:function(pointData, attachment){ var me = this; var html = ''; $(me.body).find('.tempPos').removeClass('tempPos') var webPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/'; if(RichTextUitl.intranetMode){ webPrefix = RichTextUitl.prefix } //第一次插入,需插入附件 if(!me.body.querySelector('#mark_' + attachment.cid)){ html = '
' + '
' + '
'; me.execCommand('inserthtml',html) } html = '' if(pointData instanceof Array){ for(var i=0;i

'+pointData[i].content+'

'; } }else{ html = '
' + me.secondToTime(pointData.time) + '
\u200b


'; } $(me.body).find('#mark_' + attachment.cid).append(html); var range = me.selection.getRange(); range.setStart($(me.body).find('.tempPos')[0],0).collapse(true); range.select(); $(me.body).find('.tempPos').removeClass('tempPos'); me.fireEvent('contentchange'); me.fireEvent('saveScene'); }, secondToTime: function (time) { var newtime; if (null != time) { if (time < 60) { var seconds = parseInt(time) < 10 ? ('0' + parseInt(time)) : parseInt(time); newtime = '00:' + seconds; } else if (time >= 60 && time < 60 * 60) { var minute = parseInt(time / 60.0) < 10 ? ('0' + parseInt(time / 60.0)) : parseInt(time / 60.0); var seconds = (parseInt(time % 60.0) < 10) ? ('0' + parseInt(time % 60.0)) : parseInt(time % 60.0); newtime = minute + ':' + seconds; } else if (time >= 60 * 60 && time < 60 * 60 * 24) { var hour = parseInt(time / 3600.0) < 10 ? ('0' + parseInt(time / 3600.0)) : parseInt(time / 3600.0); var minute = (parseInt(time / 60.0 % 60.0) < 10) ? ('0' + parseInt(time / 60.0 % 60.0)) : parseInt(time / 60.0 % 60.0); var seconds = (parseInt(time % 60.0) < 10) ? ('0' + parseInt(time % 60.0)) : parseInt(time % 60.0); newtime = hour + ':' + minute + ':' + seconds; } } return newtime; }, timeToSecond: function (time) { var s = ''; var lenArr = time.split(':'); if (lenArr.length == 2) { var min = time.split(':')[0]; var sec = time.split(':')[1]; s = Number(min * 60) + Number(sec); } else if (lenArr.length == 3) { var hour = time.split(':')[0]; var min = time.split(':')[1]; var sec = time.split(':')[2]; s = Number(hour * 3600) + Number(min * 60) + Number(sec); } if (s == '') { s = 0; } return s; }, /** * 让编辑器获得焦点,默认focus到编辑器头部 * @method focus * @example * ```javascript * editor.focus() * ``` */ /** * 让编辑器获得焦点,toEnd确定focus位置 * @method focus * @param { Boolean } toEnd 默认focus到编辑器头部,toEnd为true时focus到内容尾部 * @example * ```javascript * editor.focus(true) * ``` */ focus: function (toEnd) { try { var me = this, rng = me.selection.getRange(); if (toEnd) { var node = me.body.lastChild; //20200811 最后一个元素是display:none的时候往上找 if (node && node.nodeType == 1) { if (node.style.display && node.style.display == 'none') { while (!domUtils.isBody(node)) { var prev = node.previousSibling; if (prev) { node = prev; if (prev.nodeType == 1 && !(prev.style.display && prev.style.display == 'none')) { break; } } else { node = node.parentNode; } } } if (!dtd.$empty[node.tagName]) { while (node.lastChild && node.lastChild.nodeType == 1 && !dtd.$empty[node.lastChild.tagName]) { node = node.lastChild; } if (domUtils.isEmptyBlock(node)) { rng.setStartAtFirst(node) } else { rng.setStartAtLast(node) } rng.collapse(true); } } rng.setCursor(true, true); } else { if (!rng.collapsed && domUtils.isBody(rng.startContainer) && rng.startOffset == 0) { var node = me.body.firstChild; if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) { rng.setStartAtFirst(node).collapse(true); } } rng.select(true); } this.fireEvent('focus selectionchange'); } catch (e) { } }, isFocus: function () { return this.selection.isFocus(); }, blur: function () { var sel = this.selection.getNative(); if (sel.empty && browser.ie) { var nativeRng = document.body.createTextRange(); nativeRng.moveToElementText(document.body); nativeRng.collapse(true); nativeRng.select(); sel.empty() } else { sel.removeAllRanges() } //this.fireEvent('blur selectionchange'); }, /** * 初始化UE事件及部分事件代理 * @method _initEvents * @private */ _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(me.body, 'drop', function (e) { //阻止ff下默认的弹出新页面打开图片 // if (browser.gecko && e.stopPropagation) { // e.stopPropagation(); // } me.fireEvent('contentchange') }); 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); }); }, /** * 触发事件代理 * @method _proxyDomEvent * @private * @return { * } fireEvent的返回值 * @see UE.EventBase:fireEvent(String) */ _proxyDomEvent: function (evt) { if (this.fireEvent('before' + evt.type.replace(/^on/, '').toLowerCase()) === false) { return false; } if (this.fireEvent(evt.type.replace(/^on/, ''), evt) === false) { return false; } return this.fireEvent('after' + evt.type.replace(/^on/, '').toLowerCase()) }, /** * 变化选区 * @method _selectionChange * @private */ _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 || !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); }, /** * 执行编辑命令 * @method _callCmdFn * @private * @param { String } fnName 函数名称 * @param { * } args 传给命令函数的参数 * @return { * } 返回命令函数运行的返回值 */ _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,完成富文本编辑效果 * @method execCommand * @param { String } cmdName 需要执行的命令 * @remind 具体命令的使用请参考命令列表 * @return { * } 返回命令函数运行的返回值 * @example * ```javascript * 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.apply(me, arguments) != -1) { me.fireEvent('saveScene'); me.fireEvent.apply(me, ['beforeexeccommand', cmdName].concat(arguments)); result = this._callCmdFn('execCommand', arguments); //保存场景时,做了内容对比,再看是否进行contentchange触发,这里多触发了一次,去掉 // (!cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange'); me.fireEvent.apply(me, ['afterexeccommand', cmdName].concat(arguments)); me.fireEvent('saveScene'); } me.__hasEnterExecCommand = false; } else { result = this._callCmdFn('execCommand', arguments); (!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange') } (!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange) && me._selectionChange(); return result; }, /** * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态 * @method queryCommandState * @param { String } cmdName 需要查询的命令名称 * @remind 具体命令的使用请参考命令列表 * @return { Number } number 返回放前命令的状态,返回值三种情况:(-1|0|1) * @example * ```javascript * editor.queryCommandState(cmdName) => (-1|0|1) * ``` * @see COMMAND.LIST */ queryCommandState: function (cmdName) { return this._callCmdFn('queryCommandState', arguments); }, /** * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值 * @method queryCommandValue * @param { String } cmdName 需要查询的命令名称 * @remind 具体命令的使用请参考命令列表 * @remind 只有部分插件有此方法 * @return { * } 返回每个命令特定的当前状态值 * @grammar editor.queryCommandValue(cmdName) => {*} * @see COMMAND.LIST */ queryCommandValue: function (cmdName) { return this._callCmdFn('queryCommandValue', arguments); }, /** * 检查编辑区域中是否有内容 * @method hasContents * @remind 默认有文本内容,或者有以下节点都不认为是空 * table,ul,ol,dl,iframe,area,base,col,hr,img,embed,input,link,meta,param * @return { Boolean } 检查有内容返回true,否则返回false * @example * ```javascript * editor.hasContents() * ``` */ /** * 检查编辑区域中是否有内容,若包含参数tags中的节点类型,直接返回true * @method hasContents * @param { Array } tags 传入数组判断时用到的节点类型 * @return { Boolean } 若文档中包含tags数组里对应的tag,返回true,否则返回false * @example * ```javascript * 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 = ['table', 'pre', 'code', 'hr', 'img', 'iframe', 'canvas']; 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使用同一个编辑器实例 * @method reset * @remind 此方法会清空编辑器内容,清空回退列表,会触发reset事件 * @example * ```javascript * editor.reset() * ``` */ reset: function () { this.fireEvent('reset'); }, /** * 设置当前编辑区域可以编辑 * @method setEnabled * @example * ```javascript * editor.setEnabled() * ``` */ 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; } if (me.bkqueryCommandValue) { me.queryCommandValue = me.bkqueryCommandValue; delete me.bkqueryCommandValue; } me.fireEvent('selectionchange'); } }, enable: function () { return this.setEnabled(); }, /** 设置当前编辑区域不可编辑 * @method setDisabled */ /** 设置当前编辑区域不可编辑,except中的命令除外 * @method setDisabled * @param { String } except 例外命令的字符串 * @remind 即使设置了disable,此处配置的例外命令仍然可以执行 * @example * ```javascript * editor.setDisabled('bold'); //禁用工具栏中除加粗之外的所有功能 * ``` */ /** 设置当前编辑区域不可编辑,except中的命令除外 * @method setDisabled * @param { Array } except 例外命令的字符串数组,数组中的命令仍然可以执行 * @remind 即使设置了disable,此处配置的例外命令仍然可以执行 * @example * ```javascript * editor.setDisabled(['bold','insertimage']); //禁用工具栏中除加粗和插入图片之外的所有功能 * ``` */ 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.bkqueryCommandValue = me.queryCommandValue; me.queryCommandState = function (type) { if (utils.indexOf(except, type) != -1) { return me.bkqueryCommandState.apply(me, arguments); } return -1; }; me.queryCommandValue = function (type) { if (utils.indexOf(except, type) != -1) { return me.bkqueryCommandValue.apply(me, arguments); } return null; }; me.fireEvent('selectionchange'); } }, disable: function (except) { return this.setDisabled(except); }, /** * 设置默认内容 * @method _setDefaultContent * @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 + '

'; me.addListener('firstBeforeExecCommand focus', clear); } }(), /** * 显示编辑器 * @method setShow * @example * ```javascript * editor.setShow() * ``` */ 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 = ''; } }, show: function () { return this.setShow(); }, /** * 隐藏编辑器 * @method setHide * @example * ```javascript * editor.setHide() * ``` */ setHide: function () { var me = this; if (!me.lastBk) { me.lastBk = me.selection.getRange().createBookmark(true); } me.container.style.display = 'none' }, hide: function () { return this.setHide(); }, /** * 根据指定的路径,获取对应的语言资源 * @method getLang * @param { String } path 路径根据的是lang目录下的语言文件的路径结构 * @return { Object | String } 根据路径返回语言资源的Json格式对象或者语言字符串 * @example * ```javascript * 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; }, /** * 计算编辑器html内容字符串的长度 * @method getContentLength * @return { Number } 返回计算的长度 * @example * ```javascript * //编辑器html内容

132

* editor.getContentLength() //返回27 * ``` */ /** * 计算编辑器当前纯文本内容的长度 * @method getContentLength * @param { Boolean } ingoneHtml 传入true时,只按照纯文本来计算 * @return { Number } 返回计算的长度,内容中有hr/img/iframe标签,长度加1 * @example * ```javascript * //编辑器html内容

132

* editor.getContentLength() //返回3 * ``` */ getContentLength: function (ingoneHtml, tagNames) { var count = this.getContent(false, false, true).length; if (ingoneHtml) { tagNames = (tagNames || []).concat(['hr', 'img', 'iframe']); count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length; for (var i = 0, ci; ci = tagNames[i++];) { count += this.document.getElementsByTagName(ci).length; } } return count; }, /** * PC端 优化计算编辑器当前纯文本内容的长度 不算图片和附件 * @method getWordCountLength * @return { Number } 返回计算的长度,内容中有hr/img/iframe标签 忽略 * @example */ getWordCountLength: function () { var tagNames = (tagNames || []).concat(['hr', 'img', 'iframe']); var count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length; return count; }, /** * 注册输入过滤规则 * @method addInputRule * @param { Function } rule 要添加的过滤规则 * @example * ```javascript * editor.addInputRule(function(root){ * $.each(root.getNodesByTagName('div'),function(i,node){ * node.tagName="p"; * }); * }); * ``` */ addInputRule: function (rule) { this.inputRules.push(rule); }, /** * 执行注册的过滤规则 * @method filterInputRule * @param { UE.uNode } root 要过滤的uNode节点 * @remind 执行editor.setContent方法和执行'inserthtml'命令后,会运行该过滤函数 * @example * ```javascript * editor.filterInputRule(editor.body); * ``` * @see UE.Editor:addInputRule */ filterInputRule: function (root) { for (var i = 0, ci; ci = this.inputRules[i++];) { ci.call(this, root) } }, /** * 注册输出过滤规则 * @method addOutputRule * @param { Function } rule 要添加的过滤规则 * @example * ```javascript * editor.addOutputRule(function(root){ * $.each(root.getNodesByTagName('p'),function(i,node){ * node.tagName="div"; * }); * }); * ``` */ addOutputRule: function (rule) { this.outputRules.push(rule) }, /** * 根据输出过滤规则,过滤编辑器内容 * @method filterOutputRule * @remind 执行editor.getContent方法的时候,会先运行该过滤函数 * @param { UE.uNode } root 要过滤的uNode节点 * @example * ```javascript * editor.filterOutputRule(editor.body); * ``` * @see UE.Editor:addOutputRule */ filterOutputRule: function (root) { for (var i = 0, ci; ci = this.outputRules[i++];) { ci.call(this, root) } }, /** * 根据action名称获取请求的路径 * @method getActionUrl * @remind 假如没有设置serverUrl,会根据imageUrl设置默认的controller路径 * @param { String } action action名称 * @example * ```javascript * editor.getActionUrl('config'); //返回 "/ueditor/php/controller.php?action=config" * editor.getActionUrl('image'); //返回 "/ueditor/php/controller.php?action=uplaodimage" * editor.getActionUrl('scrawl'); //返回 "/ueditor/php/controller.php?action=uplaodscrawl" * editor.getActionUrl('imageManager'); //返回 "/ueditor/php/controller.php?action=listimage" * ``` */ getActionUrl: function (action) { var me = this; // 上传图片和文件的地址单独配置 if (action == 'uploadimage' || action == 'uploadfile' || action == 'uploadvideo') { //如果传了puid和token,还用原接口,兼容微信中获取不到puid和token的情况 if(RichTextUitl.puid && RichTextUitl.yunToken){ if(window.obj && window.obj.mirrorDomain) { if (!RichTextUitl.cloudUrl) { RichTextUitl.uploadUrl = window.location.protocol + window.obj.mirrorDomain.panDomain.replace('https:', '').replace('http:', '') + '/upload'; } } }else{ var from = me.options.from || 'old_note_editor' var url = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/pc/files/getYunPanUploadUrl?from=' + from; if(RichTextUitl.cloudUrl){ url += '&forceUploadToOnline=1' } $.ajax({ url: url, type: 'get', async: false, xhrFields: { withCredentials: true }, success:function(res){ if(res.result){ RichTextUitl.uploadUrl = res.data } } }) } return RichTextUitl.uploadUrl || 'https://pan-yz.chaoxing.com/upload'; } else if (action == "catchimage") { // return 'https://noteyd.chaoxing.com/pc/files/uploadRemoteImage'; // 兼容镜像逻辑 return RichTextUitl.uploadRemoteImageUrl || RichTextUitl.convertUrl('https://noteyd.chaoxing.com/pc/files/uploadRemoteImage'); } else if (action == 'convertfile') { // return 'https://exportyd.chaoxing.com/convert/convertToHtml'; // 兼容镜像逻辑 return RichTextUitl.convertToHtmlUrl || RichTextUitl.convertUrl('https://exportyd.chaoxing.com/convert/convertToHtml'); } else { var actionName = this.getOpt(action) || action, imageUrl = this.getOpt('imageUrl'), serverUrl = this.getOpt('serverUrl'); if (!serverUrl && imageUrl) { serverUrl = imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2'); } if (serverUrl) { serverUrl = serverUrl + (serverUrl.indexOf('?') == -1 ? '?' : '&') + 'action=' + (actionName || ''); return utils.formatUrl(serverUrl); } else { return ''; } } }, /** * 根据上传接口返回的内容向页面加入云盘附件 * @param cloudData */ insertCloudAttachment: function (data) { if (!data) { return; } var me = this; var cloudData = getCloudAttachmentStructure(data); cloudData.cid = RichTextUitl.randomUUID(); var attHtml = '
' + '' + '
' + '
' if (me.options.cooperation) { var data = {}; data.name = 'inserthtml'; var range = me.selection.getRange(); data.address = range.createAddress(false, true); data.html = attHtml; data.value = "insertAttach"; me.sendJoinData(data); } me.execCommand('inserthtml', attHtml); }, insertBase64Img: function (imgdata,divstyle,imgstyle,type) { var me = this; RichTextUitl.editorReplaceTarget = null; var img = document.createElement('img'); /* 创建Ajax并提交 */ var actionUrl = me.getActionUrl(me.getOpt('imageActionName')); var xhr = new XMLHttpRequest(), fd = new FormData(); var file = me.dataURLtoFile(imgdata); fd.append('file', file, file.name); fd.append('type', 'ajax'); if (RichTextUitl.puid && RichTextUitl.yunToken) { fd.append("puid", RichTextUitl.puid); fd.append("_token", RichTextUitl.yunToken); } xhr.open("post", actionUrl, true); xhr.addEventListener('load', function (e) { try { var json = JSON.parse(e.target.response); if (RichTextUitl.intranetMode && typeof RichTextUitl.customUploadDataAnalysis == 'function') { // 镜像版本需要处理下接口返回值 json = RichTextUitl.customUploadDataAnalysis(json); } if (json.result) { var suffix = json.data.suffix || 'jpg'; var imgUrl; if (RichTextUitl.intranetMode) { imgUrl = data.data.imgUrl; } else { imgUrl = json.data.previewUrl; } var img = new Image(); img.src = imgUrl; img.onload = function (argument) { imgUrl = imgUrl + '?rw=' + this.width + '&rh=' + this.height + '&_fileSize=' + json.data.size + '&_orientation=1'; // img.src = imgUrl; // img.setAttribute('_src', imgUrl); me.execCommand('inserthtml', '
'); } } else { RichTextUitl.showTips(json.msg, 0); } } catch (er) { RichTextUitl.showTips('上传图片失败', 0) } }); xhr.send(fd); } }; utils.inherits(Editor, EventBase); })(); // core/Editor.defaultoptions.js //维护编辑器一下默认的不在插件中的配置项 UE.Editor.defaultOptions = function (editor) { var _url = editor.options.UEDITOR_HOME_URL; if (!(typeof (RichTextUitl) == "undefined") && RichTextUitl.prefix && RichTextUitl.intranetMode) { // 镜像版使用本地配置的路径 _url = RichTextUitl.prefix; } return { isShow: true, initialContent: '', initialStyle: '', autoClearinitialContent: false, iframeCssUrl: _url + 'themes/iframe.css', textarea: 'editorValue', focus: false, focusInEnd: true, autoClearEmptyNode: true, fullscreen: false, readonly: false, zIndex: 999, imagePopup: true, enterTag: 'p', customDomain: false, lang: 'zh-cn', langPath: _url + 'lang/', theme: 'default', themePath: _url + 'themes/', allHtmlEnabled: false, scaleEnabled: false, tableNativeEditInFF: false, autoSyncData: true, fileNameFormat: '{time}{rand:6}', allowpaste: true, largePreview: false, } }; // core/loadconfig.js (function () { UE.Editor.prototype.loadServerConfig = function () { var me = this; setTimeout(function () { try { me.options.imageUrl && me.setOpt('serverUrl', me.options.imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2')); var configUrl = me.getActionUrl('config'), isJsonp = utils.isCrossDomainUrl(configUrl); /* 发出ajax请求 */ me._serverConfigLoaded = false; configUrl && UE.ajax.request(configUrl, { 'method': 'GET', 'dataType': isJsonp ? 'jsonp' : '', 'onsuccess': function (r) { try { var config = isJsonp ? r : eval("(" + r.responseText + ")"); utils.extend(me.options, config); me.fireEvent('serverConfigLoaded'); me._serverConfigLoaded = true; } catch (e) { showErrorMsg(me.getLang('loadconfigFormatError')); } }, 'onerror': function () { showErrorMsg(me.getLang('loadconfigHttpError')); } }); } catch (e) { showErrorMsg(me.getLang('loadconfigError')); } }); function showErrorMsg(msg) { console && console.error(msg); //me.fireEvent('showMessage', { // 'title': msg, // 'type': 'error' //}); } }; UE.Editor.prototype.isServerConfigLoaded = function () { var me = this; return me._serverConfigLoaded || false; }; UE.Editor.prototype.afterConfigReady = function (handler) { if (!handler || !utils.isFunction(handler)) return; var me = this; var readyHandler = function () { handler.apply(me, arguments); me.removeListener('serverConfigLoaded', readyHandler); }; if (me.isServerConfigLoaded()) { handler.call(me, 'serverConfigLoaded'); } else { me.addListener('serverConfigLoaded', readyHandler); } }; })(); // core/ajax.js /** * @file * @module UE.ajax * @since 1.2.6.1 */ /** * 提供对ajax请求的支持 * @module UE.ajax */ 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" || i == "dataType" || i == "callback") continue; //忽略控制 if (json[i] == undefined || json[i] == null) continue; //传递过来的对象和函数不在提交之列 if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) { strArr.push(encodeURIComponent(i) + "=" + encodeURIComponent(json[i])); } else if (utils.isArray(json[i])) { //支持传数组内容 for (var j = 0; j < json[i].length; j++) { strArr.push(encodeURIComponent(i) + "[]=" + encodeURIComponent(json[i][j])); } } } return strArr.join("&"); } function doAjax(url, ajaxOptions) { var xhr = 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 (!xhr || !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 (xhr.readyState != 4) { timeIsOut = true; xhr.abort(); clearTimeout(timerID); } }, ajaxOpts.timeout); var method = ajaxOpts.method.toUpperCase(); var str = url + (url.indexOf("?") == -1 ? "?" : "&") + (method == "POST" ? "" : submitStr + "&noCache=" + +new Date); xhr.open(method, str, ajaxOpts.async); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (!timeIsOut && xhr.status == 200) { ajaxOpts.onsuccess(xhr); } else { ajaxOpts.onerror(xhr); } } }; if (method == "POST") { xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(submitStr); } else { xhr.send(null); } } function doJsonp(url, opts) { var successhandler = opts.onsuccess || function () { }, scr = document.createElement('SCRIPT'), options = opts || {}, charset = options['charset'], callbackField = options['jsonp'] || 'callback', callbackFnName, timeOut = options['timeOut'] || 0, timer, reg = new RegExp('(\\?|&)' + callbackField + '=([^&]*)'), matches; if (utils.isFunction(successhandler)) { callbackFnName = 'bd__editor__' + Math.floor(Math.random() * 2147483648).toString(36); window[callbackFnName] = getCallBack(0); } else if (utils.isString(successhandler)) { callbackFnName = successhandler; } else { if (matches = reg.exec(url)) { callbackFnName = matches[2]; } } url = url.replace(reg, '\x241' + callbackField + '=' + callbackFnName); if (url.search(reg) < 0) { url += (url.indexOf('?') < 0 ? '?' : '&') + callbackField + '=' + callbackFnName; } var queryStr = json2str(opts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing" //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串 if (!utils.isEmptyObject(opts.data)) { queryStr += (queryStr ? "&" : "") + json2str(opts.data); } if (queryStr) { url = url.replace(/\?/, '?' + queryStr + '&'); } scr.onerror = getCallBack(1); if (timeOut) { timer = setTimeout(getCallBack(1), timeOut); } createScriptTag(scr, url, charset); function createScriptTag(scr, url, charset) { scr.setAttribute('type', 'text/javascript'); scr.setAttribute('defer', 'defer'); charset && scr.setAttribute('charset', charset); scr.setAttribute('src', url); document.getElementsByTagName('head')[0].appendChild(scr); } function getCallBack(onTimeOut) { return function () { try { if (onTimeOut) { options.onerror && options.onerror(); } else { try { clearTimeout(timer); successhandler.apply(window, arguments); } catch (e) { } } } catch (exception) { options.onerror && options.onerror.call(window, exception); } finally { options.oncomplete && options.oncomplete.apply(window, arguments); scr.parentNode && scr.parentNode.removeChild(scr); window[callbackFnName] = null; try { delete window[callbackFnName]; } catch (e) { } } } } } return { /** * 根据给定的参数项,向指定的url发起一个ajax请求。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求 * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调 * @method request * @param { URLString } url ajax请求的url地址 * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下: * @example * ```javascript * //向sayhello.php发起一个异步的Ajax GET请求, 请求超时时间为10s, 请求完成后执行相应的回调。 * UE.ajax.requeset( 'sayhello.php', { * * //请求方法。可选值: 'GET', 'POST',默认值是'POST' * method: 'GET', * * //超时时间。 默认为5000, 单位是ms * timeout: 10000, * * //是否是异步请求。 true为异步请求, false为同步请求 * async: true, * * //请求携带的数据。如果请求为GET请求, data会经过stringify后附加到请求url之后。 * data: { * name: 'ueditor' * }, * * //请求成功后的回调, 该回调接受当前的XMLHttpRequest对象作为参数。 * onsuccess: function ( xhr ) { * console.log( xhr.responseText ); * }, * * //请求失败或者超时后的回调。 * onerror: function ( xhr ) { * alert( 'Ajax请求失败' ); * } * * } ); * ``` */ /** * 根据给定的参数项发起一个ajax请求, 参数项里必须包含一个url地址。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求 * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调。 * @method request * @warning 如果在参数项里未提供一个key为“url”的地址值,则该请求将直接退出。 * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下: * @example * ```javascript * * //向sayhello.php发起一个异步的Ajax POST请求, 请求超时时间为5s, 请求完成后不执行任何回调。 * UE.ajax.requeset( 'sayhello.php', { * * //请求的地址, 该项是必须的。 * url: 'sayhello.php' * * } ); * ``` */ request: function (url, opts) { if (opts && opts.dataType == 'jsonp') { doJsonp(url, opts); } else { doAjax(url, opts); } }, getJSONP: function (url, data, fn) { var opts = { 'data': data, 'oncomplete': fn }; doJsonp(url, opts); } }; }(); // core/filterword.js /** * UE过滤word的静态方法 * @file */ /** * UEditor公用空间,UEditor所有的功能都挂载在该空间下 * @module UE */ /** * 根据传入html字符串过滤word * @module UE * @since 1.2.6.1 * @method filterWord * @param { String } html html字符串 * @return { String } 已过滤后的结果字符串 * @example * ```javascript * UE.filterWord(html); * ``` */ var filterWord = UE.filterWord = function () { //是否是word过来的内容 function isWordDocument(str) { return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/ig.test(str); } //去掉小数 function transUnit(v) { v = v.replace(/[\d.]+\w+/g, function (m) { return utils.transUnitToPx(m); }); return v; } function filterPasteWord(str) { return str.replace(/[\t\r\n]+/g, ' ') .replace(//ig, "") //转换图片 .replace(/]*>[\s\S]*?.<\/v:shape>/gi, function (str) { //opera能自己解析出image所这里直接返回空 if (browser.opera) { return ''; } try { //有可能是bitmap占为图,无用,直接过滤掉,主要体现在粘贴excel表格中 if (/Bitmap/i.test(str)) { return ''; } 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|\w+:\w+)(?=[\s\/>]))[^>]*>/gi, "") //去除style,解决mac下火狐粘贴word带过来style标签style被去掉只留下css的问题 // .replace( /

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

$1

" ) .replace(/

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

$1

") //去掉多余的属性 .replace(/\s+(lang|align)\s*=\s*(['"]?)([\w-]+)\2/ig, function (str, name, marks, val) { //保留list的标示 return name == 'class' && val == 'MsoListParagraph' ? str : '' }) //清除多余的font/span不能匹配 有可能是空格 .replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi, function (a, b, c) { return c.replace(/[\t\r\n ]+/g, ' ') }) //处理style的问题 .replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function (str, tag, tmp, style) { var n = [], s = style.replace(/^\s+|\s+$/, '') .replace(/'/g, '\'') .replace(/"/gi, "'") .replace(/[\d.]+(cm|pt)/g, function (str) { return utils.transUnitToPx(str) }) .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": continue; //ie下会出现挤到一起的情况 //case "mso-table-layout-alt": case "mso-height": case "mso-width": case "mso-vertical-align-alt": //trace:1819 ff下会解析出padding在table上 if (!/]/.test(html)) { return UE.htmlparser(html).children[0] } else { return new uNode({ type: 'element', children: [], tagName: html }) } }; uNode.createText = function (data, noTrans) { return new UE.uNode({ type: 'text', 'data': noTrans ? data : utils.unhtml(data || '') }) }; function nodeToHtml(node, arr, formatter, current) { switch (node.type) { case 'root': for (var i = 0, ci; ci = node.children[i++];) { //插入新行 if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) { insertLine(arr, current, true); insertIndent(arr, current) } nodeToHtml(ci, arr, formatter, current) } break; case 'text': isText(node, arr); break; case 'element': isElement(node, arr, formatter, current); break; case 'comment': isComment(node, arr, formatter); } return arr; } function isText(node, arr) { if (node.parentNode.tagName == 'pre') { //源码模式下输入html标签,不能做转换处理,直接输出 arr.push(node.data) } else { arr.push(notTransTagName[node.parentNode.tagName] ? utils.html(node.data) : node.data.replace(/[ ]{2}/g, '  ')) } } function isElement(node, arr, formatter, current) { var attrhtml = ''; if (node.attrs) { attrhtml = []; var attrs = node.attrs; for (var a in attrs) { //这里就针对 //

'

//这里边的\"做转换,要不用innerHTML直接被截断了,属性src //有可能做的不够 attrhtml.push(a + (attrs[a] !== undefined ? '="' + (notTransAttrs[a] ? utils.html(attrs[a]).replace(/["]/g, function (a) { return '"' }) : utils.unhtml(attrs[a])) + '"' : '')) } attrhtml = attrhtml.join(' '); } arr.push('<' + node.tagName + (attrhtml ? ' ' + attrhtml : '') + (dtd.$empty[node.tagName] ? '\/' : '') + '>' ); //插入新行 if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') { if (node.children && node.children.length) { current = insertLine(arr, current, true); insertIndent(arr, current) } } if (node.children && node.children.length) { for (var i = 0, ci; ci = node.children[i++];) { if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) { insertLine(arr, current); insertIndent(arr, current) } nodeToHtml(ci, arr, formatter, current) } } if (!dtd.$empty[node.tagName]) { if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') { if (node.children && node.children.length) { current = insertLine(arr, current); insertIndent(arr, current) } } arr.push('<\/' + node.tagName + '>'); } } function isComment(node, arr) { arr.push(''); } function getNodeById(root, id) { var node; if (root.type == 'element' && root.getAttr('id') == id) { return root; } if (root.children && root.children.length) { for (var i = 0, ci; ci = root.children[i++];) { if (node = getNodeById(ci, id)) { return node; } } } } function getNodeByClass(root, classname) { var node; if (root.type == 'element' && root.getAttr('class') && root.getAttr('class').indexOf(classname) > -1) { return root; } if (root.children && root.children.length) { for (var i = 0, ci; ci = root.children[i++];) { if (node = getNodeByClass(ci, classname)) { return node; } } } } function getNodesByTagName(node, tagName, arr) { if (node.type == 'element' && node.tagName == tagName) { arr.push(node); } if (node.children && node.children.length) { for (var i = 0, ci; ci = node.children[i++];) { getNodesByTagName(ci, tagName, arr) } } } function nodeTraversal(root, fn) { if (root.children && root.children.length) { for (var i = 0, ci; ci = root.children[i];) { var pNode = ci.parentNode; nodeTraversal(ci, fn); //ci被替换的情况,这里就不再走 fn了 if (ci.parentNode) { if (ci.children && ci.children.length) { fn(ci) } if (ci.parentNode) i++ } if (pNode.children && pNode.children.length == 0 && pNode.parentNode) { pNode.parentNode.removeChild(pNode); } } } else { fn(root) } } uNode.prototype = { /** * 当前节点对象,转换成html文本 * @method toHtml * @return { String } 返回转换后的html字符串 * @example * ```javascript * node.toHtml(); * ``` */ /** * 当前节点对象,转换成html文本 * @method toHtml * @param { Boolean } formatter 是否格式化返回值 * @return { String } 返回转换后的html字符串 * @example * ```javascript * node.toHtml( true ); * ``` */ toHtml: function (formatter) { var arr = []; nodeToHtml(this, arr, formatter, 0); return arr.join('') }, /** * 获取节点的html内容 * @method innerHTML * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点 * @return { String } 返回节点的html内容 * @example * ```javascript * var htmlstr = node.innerHTML(); * ``` */ /** * 设置节点的html内容 * @method innerHTML * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点 * @param { String } htmlstr 传入要设置的html内容 * @return { UE.uNode } 返回节点本身 * @example * ```javascript * node.innerHTML('text'); * ``` */ innerHTML: function (htmlstr) { if (this.type != 'element' || dtd.$empty[this.tagName]) { return this; } if (utils.isString(htmlstr)) { if (this.children) { for (var i = 0, ci; ci = this.children[i++];) { ci.parentNode = null; } } this.children = []; var tmpRoot = UE.htmlparser(htmlstr); for (var i = 0, ci; ci = tmpRoot.children[i++];) { this.children.push(ci); ci.parentNode = this; } return this; } else { var tmpRoot = new UE.uNode({ type: 'root', children: this.children }); return tmpRoot.toHtml(); } }, /** * 获取节点的纯文本内容 * @method innerText * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点 * @return { String } 返回节点的存文本内容 * @example * ```javascript * var textStr = node.innerText(); * ``` */ /** * 设置节点的纯文本内容 * @method innerText * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点 * @param { String } textStr 传入要设置的文本内容 * @return { UE.uNode } 返回节点本身 * @example * ```javascript * node.innerText('text'); * ``` */ innerText: function (textStr, noTrans) { if (this.type != 'element' || dtd.$empty[this.tagName]) { return this; } if (textStr) { if (this.children) { for (var i = 0, ci; ci = this.children[i++];) { ci.parentNode = null; } } this.children = []; this.appendChild(uNode.createText(textStr, noTrans)); return this; } else { return this.toHtml().replace(/<[^>]+>/g, ''); } }, /** * 获取当前对象的data属性 * @method getData * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性 * @example * ```javascript * node.getData(); * ``` */ getData: function () { if (this.type == 'element') return ''; return this.data }, /** * 获取当前节点下的第一个子节点 * @method firstChild * @return { UE.uNode } 返回第一个子节点 * @example * ```javascript * node.firstChild(); //返回第一个子节点 * ``` */ firstChild: function () { // if (this.type != 'element' || dtd.$empty[this.tagName]) { // return this; // } return this.children ? this.children[0] : null; }, /** * 获取当前节点下的最后一个子节点 * @method lastChild * @return { UE.uNode } 返回最后一个子节点 * @example * ```javascript * node.lastChild(); //返回最后一个子节点 * ``` */ lastChild: function () { // if (this.type != 'element' || dtd.$empty[this.tagName] ) { // return this; // } return this.children ? this.children[this.children.length - 1] : null; }, /** * 获取和当前节点有相同父亲节点的前一个节点 * @method previousSibling * @return { UE.uNode } 返回前一个节点 * @example * ```javascript * node.children[2].previousSibling(); //返回子节点node.children[1] * ``` */ previousSibling: function () { var parent = this.parentNode; for (var i = 0, ci; ci = parent.children[i]; i++) { if (ci === this) { return i == 0 ? null : parent.children[i - 1]; } } }, /** * 获取和当前节点有相同父亲节点的后一个节点 * @method nextSibling * @return { UE.uNode } 返回后一个节点,找不到返回null * @example * ```javascript * node.children[2].nextSibling(); //如果有,返回子节点node.children[3] * ``` */ nextSibling: function () { var parent = this.parentNode; for (var i = 0, ci; ci = parent.children[i++];) { if (ci === this) { return parent.children[i]; } } }, /** * 用新的节点替换当前节点 * @method replaceChild * @param { UE.uNode } target 要替换成该节点参数 * @param { UE.uNode } source 要被替换掉的节点 * @return { UE.uNode } 返回替换之后的节点对象 * @example * ```javascript * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点 * ``` */ replaceChild: function (target, source) { if (this.children) { if (target.parentNode) { target.parentNode.removeChild(target); } for (var i = 0, ci; ci = this.children[i]; i++) { if (ci === source) { this.children.splice(i, 1, target); source.parentNode = null; target.parentNode = this; return target; } } } }, /** * 在节点的子节点列表最后位置插入一个节点 * @method appendChild * @param { UE.uNode } node 要插入的节点 * @return { UE.uNode } 返回刚插入的子节点 * @example * ```javascript * node.appendChild( newNode ); //在node内插入子节点newNode * ``` */ appendChild: function (node) { if (this.type == 'root' || (this.type == 'element' && !dtd.$empty[this.tagName])) { if (!this.children) { this.children = [] } if (node.parentNode) { node.parentNode.removeChild(node); } for (var i = 0, ci; ci = this.children[i]; i++) { if (ci === node) { this.children.splice(i, 1); break; } } this.children.push(node); node.parentNode = this; return node; } }, /** * 在传入节点的前面插入一个节点 * @method insertBefore * @param { UE.uNode } target 要插入的节点 * @param { UE.uNode } source 在该参数节点前面插入 * @return { UE.uNode } 返回刚插入的子节点 * @example * ```javascript * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode * ``` */ insertBefore: function (target, source) { if (this.children) { if (target.parentNode) { target.parentNode.removeChild(target); } for (var i = 0, ci; ci = this.children[i]; i++) { if (ci === source) { this.children.splice(i, 0, target); target.parentNode = this; return target; } } } }, /** * 在传入节点的后面插入一个节点 * @method insertAfter * @param { UE.uNode } target 要插入的节点 * @param { UE.uNode } source 在该参数节点后面插入 * @return { UE.uNode } 返回刚插入的子节点 * @example * ```javascript * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode * ``` */ insertAfter: function (target, source) { if (this.children) { if (target.parentNode) { target.parentNode.removeChild(target); } for (var i = 0, ci; ci = this.children[i]; i++) { if (ci === source) { this.children.splice(i + 1, 0, target); target.parentNode = this; return target; } } } }, /** * 从当前节点的子节点列表中,移除节点 * @method removeChild * @param { UE.uNode } node 要移除的节点引用 * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置 * @return { * } 返回刚移除的子节点 * @example * ```javascript * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置 * ``` */ removeChild: function (node, keepChildren) { if (this.children) { for (var i = 0, ci; ci = this.children[i]; i++) { if (ci === node) { this.children.splice(i, 1); ci.parentNode = null; if (keepChildren && ci.children && ci.children.length) { for (var j = 0, cj; cj = ci.children[j]; j++) { this.children.splice(i + j, 0, cj); cj.parentNode = this; } } return ci; } } } }, /** * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值 * @method getAttr * @param { String } attrName 要获取的属性名称 * @return { * } 返回attrs对象下的属性值 * @example * ```javascript * node.getAttr('title'); * ``` */ getAttr: function (attrName) { return this.attrs && this.attrs[attrName.toLowerCase()] }, /** * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值 * @method setAttr * @param { String } attrName 要设置的属性名称 * @param { * } attrVal 要设置的属性值,类型视设置的属性而定 * @return { * } 返回attrs对象下的属性值 * @example * ```javascript * node.setAttr('title','标题'); * ``` */ setAttr: function (attrName, attrVal) { if (!attrName) { delete this.attrs; return; } if (!this.attrs) { this.attrs = {}; } if (utils.isObject(attrName)) { for (var a in attrName) { if (!attrName[a]) { delete this.attrs[a] } else { this.attrs[a.toLowerCase()] = attrName[a]; } } } else { if (!attrVal) { delete this.attrs[attrName] } else { this.attrs[attrName.toLowerCase()] = attrVal; } } }, /** * 获取当前节点在父节点下的位置索引 * @method getIndex * @return { Number } 返回索引数值,如果没有父节点,返回-1 * @example * ```javascript * node.getIndex(); * ``` */ getIndex: function () { var parent = this.parentNode; for (var i = 0, ci; ci = parent.children[i]; i++) { if (ci === this) { return i; } } return -1; }, /** * 在当前节点下,根据id查找节点 * @method getNodeById * @param { String } id 要查找的id * @return { UE.uNode } 返回找到的节点 * @example * ```javascript * node.getNodeById('textId'); * ``` */ getNodeById: function (id) { var node; if (this.children && this.children.length) { for (var i = 0, ci; ci = this.children[i++];) { if (node = getNodeById(ci, id)) { return node; } } } }, /** * 在当前节点下,根据class查找节点 * @method getNodeByClass * @param { String } class 要查找的class * @return { UE.uNode } 返回找到的节点 * @example * ```javascript * node.getNodeByClass('textclass'); * ``` */ getNodeByClass: function (classname) { var node; if (this.children && this.children.length) { for (var i = 0, ci; ci = this.children[i++];) { if (node = getNodeByClass(ci, classname)) { return node; } } } }, /** * 在当前节点下,根据元素名称查找节点列表 * @method getNodesByTagName * @param { String } tagNames 要查找的元素名称 * @return { Array } 返回找到的节点列表 * @example * ```javascript * node.getNodesByTagName('span'); * ``` */ getNodesByTagName: function (tagNames) { tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, ' ').split(' '); var arr = [], me = this; utils.each(tagNames, function (tagName) { if (me.children && me.children.length) { for (var i = 0, ci; ci = me.children[i++];) { getNodesByTagName(ci, tagName, arr) } } }); return arr; }, /** * 根据样式名称,获取节点的样式值 * @method getStyle * @param { String } name 要获取的样式名称 * @return { String } 返回样式值 * @example * ```javascript * node.getStyle('font-size'); * ``` */ getStyle: function (name) { var cssStyle = this.getAttr('style'); if (!cssStyle) { return '' } //20201012 if (name == "font-family" || cssStyle.indexOf('url') > -1) { cssStyle = cssStyle.replace(/"/gi, " "); } else { cssStyle = cssStyle.replace('/"/g', "'"); } var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+)', 'i'); var match = cssStyle.match(reg); if (match && match[0]) { return match[2].trim() } return ''; }, /** * 给节点设置样式 * @method setStyle * @param { String } name 要设置的的样式名称 * @param { String } val 要设置的的样值 * @example * ```javascript * node.setStyle('font-size', '12px'); * ``` */ setStyle: function (name, val) { function exec(name, val) { var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+;?)', 'gi'); cssStyle = cssStyle.replace(reg, '$1'); if (val) { cssStyle = name + ':' + utils.unhtml(val) + ';' + cssStyle } } var cssStyle = this.getAttr('style'); if (!cssStyle) { cssStyle = ''; } //20201012 if (name == "font-family" || cssStyle.indexOf('url') > -1) { cssStyle = cssStyle.replace(/"/gi, " "); } else { cssStyle = cssStyle.replace('/"/g', "'"); } if (utils.isObject(name)) { for (var a in name) { exec(a, name[a]) } } else { exec(name, val) } this.setAttr('style', utils.trim(cssStyle)) }, /** * 传入一个函数,递归遍历当前节点下的所有节点 * @method traversal * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数 * @example * ```javascript * traversal(node, function(){ * console.log(node.type); * }); * ``` */ traversal: function (fn) { if (this.children && this.children.length) { nodeTraversal(this, fn); } return this; } } })(); // core/htmlparser.js /** * html字符串转换成uNode节点 * @file * @module UE * @since 1.2.6.1 */ /** * UEditor公用空间,UEditor所有的功能都挂载在该空间下 * @unfile * @module UE */ /** * html字符串转换成uNode节点的静态方法 * @method htmlparser * @param { String } htmlstr 要转换的html代码 * @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符 * @return { uNode } 给定的html片段转换形成的uNode对象 * @example * ```javascript * var root = UE.htmlparser('

htmlparser

', true); * ``` */ var htmlparser = UE.htmlparser = function (htmlstr, ignoreBlank) { //todo 原来的方式 [^"'<>\/] 有\/就不能配对上 '); tmpl.push(''); tempIndex === 2 && tmpl.push(''); } return '
' + '
' + '
这样的标签了 //先去掉了,加上的原因忘了,这里先记录 var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g, re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g; //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除 var allowEmptyTags = { b: 1, code: 1, i: 1, u: 1, strike: 1, s: 1, tt: 1, strong: 1, q: 1, samp: 1, em: 1, span: 1, sub: 1, img: 1, sup: 1, font: 1, big: 1, small: 1, iframe: 1, a: 1, br: 1, pre: 1 }; // htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, 'g'), ''); if (!ignoreBlank) { htmlstr = htmlstr.replace(new RegExp('[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*<\/?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*', 'g'), function (a, b) { //br暂时单独处理 if (b && allowEmptyTags[b.toLowerCase()]) { return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, ''); } return a.replace(new RegExp('^[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+'), '').replace(new RegExp('[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+$'), ''); }); } var notTransAttrs = { 'href': 1, 'src': 1 }; var uNode = UE.uNode, needParentNode = { 'td': 'tr', 'tr': ['tbody', 'thead', 'tfoot'], 'tbody': 'table', 'th': 'tr', 'thead': 'table', 'tfoot': 'table', 'caption': 'table', 'li': ['ul', 'ol'], 'dt': 'dl', 'dd': 'dl', 'option': 'select' }, needChild = { 'ol': 'li', 'ul': 'li' }; function text(parent, data) { if (needChild[parent.tagName]) { var tmpNode = uNode.createElement(needChild[parent.tagName]); parent.appendChild(tmpNode); tmpNode.appendChild(uNode.createText(data)); parent = tmpNode; } else { parent.appendChild(uNode.createText(data)); } } function element(parent, tagName, htmlattr) { var needParentTag; if (needParentTag = needParentNode[tagName]) { var tmpParent = parent, hasParent; while (tmpParent.type != 'root') { if (utils.isArray(needParentTag) ? utils.indexOf(needParentTag, tmpParent.tagName) != -1 : needParentTag == tmpParent.tagName) { parent = tmpParent; hasParent = true; break; } tmpParent = tmpParent.parentNode; } if (!hasParent) { parent = element(parent, utils.isArray(needParentTag) ? needParentTag[0] : needParentTag) } } //按dtd处理嵌套 // if(parent.type != 'root' && !dtd[parent.tagName][tagName]) // parent = parent.parentNode; var elm = new uNode({ parentNode: parent, type: 'element', tagName: tagName.toLowerCase(), //是自闭合的处理一下 children: dtd.$empty[tagName] ? null : [] }); //如果属性存在,处理属性 if (htmlattr) { var attrs = {}, match; while (match = re_attr.exec(htmlattr)) { attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()] ? (match[2] || match[3] || match[4]) : utils.unhtml(match[2] || match[3] || match[4]) } elm.attrs = attrs; } //trace:3970 // //如果parent下不能放elm // if(dtd.$inline[parent.tagName] && dtd.$block[elm.tagName] && !dtd[parent.tagName][elm.tagName]){ // parent = parent.parentNode; // elm.parentNode = parent; // } parent.children.push(elm); //如果是自闭合节点返回父亲节点 return dtd.$empty[tagName] ? parent : elm } function comment(parent, data) { parent.children.push(new uNode({ type: 'comment', data: data, parentNode: parent })); } var match, currentIndex = 0, nextIndex = 0; //设置根节点 var root = new uNode({ type: 'root', children: [] }); var currentParent = root; while (match = re_tag.exec(htmlstr)) { currentIndex = match.index; try { if (currentIndex > nextIndex) { //text node text(currentParent, htmlstr.slice(nextIndex, currentIndex)); } if (match[3]) { if (dtd.$cdata[currentParent.tagName]) { text(currentParent, match[0]); } else { //start tag currentParent = element(currentParent, match[3].toLowerCase(), match[4]); } } else if (match[1]) { if (currentParent.type != 'root') { if (dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]) { text(currentParent, match[0]); } else { var tmpParent = currentParent; while (currentParent.type == 'element' && currentParent.tagName != match[1].toLowerCase()) { currentParent = currentParent.parentNode; if (currentParent.type == 'root') { currentParent = tmpParent; throw 'break' } } //end tag currentParent = currentParent.parentNode; } } } else if (match[2]) { //comment comment(currentParent, match[2]) } } catch (e) { } nextIndex = re_tag.lastIndex; } //如果结束是文本,就有可能丢掉,所以这里手动判断一下 //例如
  • sdfsdfsdf
  • sdfsdfsdfsdf if (nextIndex < htmlstr.length) { text(currentParent, htmlstr.slice(nextIndex)); } return root; }; // core/filternode.js /** * UE过滤节点的静态方法 * @file */ /** * UEditor公用空间,UEditor所有的功能都挂载在该空间下 * @module UE */ /** * 根据传入节点和过滤规则过滤相应节点 * @module UE * @since 1.2.6.1 * @method filterNode * @param { Object } root 指定root节点 * @param { Object } rules 过滤规则json对象 * @example * ```javascript * UE.filterNode(root,editor.options.filterRules); * ``` */ var filterNode = UE.filterNode = function () { function filterNode(node, rules) { switch (node.type) { case 'text': break; case 'element': var val; if (val = rules[node.tagName]) { if (val === '-') { node.parentNode.removeChild(node) } else if (utils.isFunction(val)) { var parentNode = node.parentNode, index = node.getIndex(); val(node); if (node.parentNode) { if (node.children) { for (var i = 0, ci; ci = node.children[i];) { filterNode(ci, rules); if (ci.parentNode) { i++; } } } } else { for (var i = index, ci; ci = parentNode.children[i];) { filterNode(ci, rules); if (ci.parentNode) { i++; } } } } else { var attrs = val['$']; if (attrs && node.attrs) { var tmpAttrs = {}, tmpVal; for (var a in attrs) { tmpVal = node.getAttr(a); //todo 只先对style单独处理 if (a == 'style' && utils.isArray(attrs[a])) { var tmpCssStyle = []; utils.each(attrs[a], function (v) { var tmp; if (tmp = node.getStyle(v)) { tmpCssStyle.push(v + ':' + tmp); } }); tmpVal = tmpCssStyle.join(';') } if (tmpVal) { tmpAttrs[a] = tmpVal; } } node.attrs = tmpAttrs; } if (node.children) { for (var i = 0, ci; ci = node.children[i];) { filterNode(ci, rules); if (ci.parentNode) { i++; } } } } } else { //如果不在名单里扣出子节点并删除该节点,cdata除外 if (dtd.$cdata[node.tagName]) { node.parentNode.removeChild(node) } else { var parentNode = node.parentNode, index = node.getIndex(); node.parentNode.removeChild(node, true); for (var i = index, ci; ci = parentNode.children[i];) { filterNode(ci, rules); if (ci.parentNode) { i++; } } } } break; case 'comment': node.parentNode.removeChild(node) } } return function (root, rules) { if (utils.isEmptyObject(rules)) { return root; } var val; if (val = rules['-']) { utils.each(val.split(' '), function (k) { rules[k] = '-' }) } for (var i = 0, ci; ci = root.children[i];) { filterNode(ci, rules); if (ci.parentNode) { i++; } } return root; } }(); // core/plugin.js /** * Created with JetBrains PhpStorm. * User: campaign * Date: 10/8/13 * Time: 6:15 PM * To change this template use File | Settings | File Templates. */ UE.plugin = function () { var _plugins = {}; return { register: function (pluginName, fn, oldOptionName, afterDisabled) { if (oldOptionName && utils.isFunction(oldOptionName)) { afterDisabled = oldOptionName; oldOptionName = null } _plugins[pluginName] = { optionName: oldOptionName || pluginName, execFn: fn, //当插件被禁用时执行 afterDisabled: afterDisabled } }, load: function (editor) { utils.each(_plugins, function (plugin) { var _export = plugin.execFn.call(editor); if (editor.options[plugin.optionName] !== false) { if (_export) { //后边需要再做扩展 utils.each(_export, function (v, k) { switch (k.toLowerCase()) { case 'shortcutkey': editor.addshortcutkey(v); break; case 'bindevents': utils.each(v, function (fn, eventName) { editor.addListener(eventName, fn); }); break; case 'bindmultievents': utils.each(utils.isArray(v) ? v : [v], function (event) { var types = utils.trim(event.type).split(/\s+/); utils.each(types, function (eventName) { editor.addListener(eventName, event.handler); }); }); break; case 'commands': utils.each(v, function (execFn, execName) { editor.commands[execName] = execFn }); break; case 'outputrule': editor.addOutputRule(v); break; case 'inputrule': editor.addInputRule(v); break; case 'defaultoptions': editor.setOpt(v) } }) } } else if (plugin.afterDisabled) { plugin.afterDisabled.call(editor) } }); //向下兼容 utils.each(UE.plugins, function (plugin) { plugin.call(editor); }); }, run: function (pluginName, editor) { var plugin = _plugins[pluginName]; if (plugin) { plugin.exeFn.call(editor) } } } }(); // core/keymap.js var keymap = UE.keymap = { 'Backspace': 8, 'Tab': 9, 'Enter': 13, 'Shift': 16, 'Control': 17, 'Alt': 18, 'CapsLock': 20, 'Esc': 27, 'Spacebar': 32, 'PageUp': 33, 'PageDown': 34, 'End': 35, 'Home': 36, 'Left': 37, 'Up': 38, 'Right': 39, 'Down': 40, 'Insert': 45, 'Del': 46, 'NumLock': 144, 'Cmd': 91, '=': 187, '-': 189, "b": 66, 'i': 73, //回退 'z': 90, 'y': 89, //粘贴 'v': 86, 'x': 88, 's': 83, 'n': 78 }; // core/localstorage.js //存储媒介封装 var LocalStorage = UE.LocalStorage = (function () { var storage = window.localStorage || getUserData() || null, LOCAL_FILE = 'localStorage'; return { saveLocalData: function (key, data) { if (storage && data) { storage.setItem(key, data); return true; } return false; }, getLocalData: function (key) { if (storage) { return storage.getItem(key); } return null; }, removeItem: function (key) { storage && storage.removeItem(key); } }; function getUserData() { var container = document.createElement("div"); container.style.display = "none"; if (!container.addBehavior) { return null; } container.addBehavior("#default#userdata"); return { getItem: function (key) { var result = null; try { document.body.appendChild(container); container.load(LOCAL_FILE); result = container.getAttribute(key); document.body.removeChild(container); } catch (e) { } return result; }, setItem: function (key, value) { document.body.appendChild(container); container.setAttribute(key, value); container.save(LOCAL_FILE); document.body.removeChild(container); }, //// 暂时没有用到 //clear: function () { // // var expiresTime = new Date(); // expiresTime.setFullYear(expiresTime.getFullYear() - 1); // document.body.appendChild(container); // container.expires = expiresTime.toUTCString(); // container.save(LOCAL_FILE); // document.body.removeChild(container); // //}, removeItem: function (key) { document.body.appendChild(container); container.removeAttribute(key); container.save(LOCAL_FILE); document.body.removeChild(container); } }; } })(); (function () { var ROOTKEY = 'ueditor_preference'; UE.Editor.prototype.setPreferences = function (key, value) { var obj = {}; if (utils.isString(key)) { obj[key] = value; } else { obj = key; } var data = LocalStorage.getLocalData(ROOTKEY); if (data && (data = utils.str2json(data))) { utils.extend(data, obj); } else { data = obj; } data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data)); }; UE.Editor.prototype.getPreferences = function (key) { var data = LocalStorage.getLocalData(ROOTKEY); if (data && (data = utils.str2json(data))) { return key ? data[key] : data } return null; }; UE.Editor.prototype.removePreferences = function (key) { var data = LocalStorage.getLocalData(ROOTKEY); if (data && (data = utils.str2json(data))) { data[key] = undefined; delete data[key] } data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data)); }; })(); // plugins/defaultfilter.js ///import core ///plugin 编辑器默认的过滤转换机制 UE.plugins['defaultfilter'] = function () { var me = this; me.setOpt({ 'allowDivTransToP': false, // 去掉 div 转成 p 标签 'disabledTableInTable': true }); //默认的过滤处理 //进入编辑器的内容处理 me.addInputRule(function (root) { var allowDivTransToP = this.options.allowDivTransToP; var val; function tdParent(node) { while (node && node.type == 'element') { if (node.tagName == 'td') { return true; } node = node.parentNode; } return false; } //进行默认的处理 root.traversal(function (node) { if (node.type == 'element') { if (!dtd.$cdata[node.tagName] && me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) { if (!node.firstChild()) node.parentNode.removeChild(node); else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) { node.parentNode.removeChild(node, true) } return; } switch (node.tagName) { case 'style': case 'script': node.setAttr({ cdata_tag: node.tagName, cdata_data: (node.innerHTML() || ''), '_ue_custom_node_': 'true' }); node.tagName = 'div'; node.innerHTML(''); break; // case 'section': // if(!me.options.showXiumi){ // node.tagName = 'div'; // } case 'a': if (val = node.getAttr('href')) { node.setAttr('_href', val) } if (!node.getAttr('target') || node.getAttr('target') == '') { node.setAttr('target', '_blank'); } if (node.getAttr('class') && node.getAttr('class').indexOf('fancybox1') > -1) { var newattr = node.getAttr('class').replace('fancybox1', '') node.setAttr(newattr); } if (node.getAttr('class') && node.getAttr('class').indexOf('iframe') > -1 && node.getAttr('name')) { var jsonOld = RichTextUitl.b64DecodeUnicode(node.getAttr('name')); if (jsonOld.attachmentType == 18) { var fileSuffix = jsonOld.att_clouddisk.suffix; if (fileSuffix == 'xls' || fileSuffix == 'xlsx') { node.setAttr('fileType', 'excel'); } else if (fileSuffix == 'pdf') { node.setAttr('fileType', 'pdf'); } else if (fileSuffix == 'doc' || fileSuffix == 'docx') { node.setAttr('fileType', 'word'); } else if (fileSuffix == 'ppt' || fileSuffix == 'pptx') { node.setAttr('fileType', 'ppt'); } else if (fileSuffix == 'zip' || fileSuffix == 'rar') { node.setAttr('fileType', 'zip'); } } } break; case 'iframe': if(me.options.forbidAttachment){ //不允许有附件 node.parentNode.removeChild(node) break; } //处理从专题粘贴过来的附件TODO if (node.parentNode && node.parentNode.getAttr('class') && node.parentNode.getAttr('class').indexOf('ans-attach-ct') > -1) { node.parentNode.setAttr('contenteditable', 'false'); node.parentNode.setAttr('style', ''); node.parentNode.setAttr('class', 'editor-iframe'); node.setAttr('class', 'attach-module') } if (node.getAttr('class') && node.getAttr('name')) { var jsonOld = RichTextUitl.b64DecodeUnicode(node.getAttr('name')); if (jsonOld.attachmentType == 18) { var fileSuffix = jsonOld.att_clouddisk.suffix; if (fileSuffix == 'xls' || fileSuffix == 'xlsx') { node.setAttr('fileType', 'excel'); } else if (fileSuffix == 'pdf') { node.setAttr('fileType', 'pdf'); } else if (fileSuffix == 'doc' || fileSuffix == 'docx') { node.setAttr('fileType', 'word'); } else if (fileSuffix == 'ppt' || fileSuffix == 'pptx') { node.setAttr('fileType', 'ppt'); } else if (fileSuffix == 'zip' || fileSuffix == 'rar') { node.setAttr('fileType', 'zip'); } } } break; case "mark": node.tagName = 'span'; break; case 'img': if(me.options.forbidImage){ //不允许有图片 node.parentNode.removeChild(node) break; } //没有src,也没有_src,移除 if ((!node.getAttr('src') || node.getAttr('src') == '' || node.getAttr('src') == 'null') && !node.getAttr('_src') && !node.getAttr('name')) { node.parentNode.removeChild(node) break; } //没有套div的图片,套div if (node.parentNode && (!node.parentNode.getAttr('class') || node.parentNode.getAttr('class').indexOf('editor-image') == -1)) { if ((node.parentNode.children.length == 1 || node.parentNode.children.length == 2 && node.nextSibling() && node.nextSibling().tagName == 'br') && (node.parentNode.tagName == 'p' || node.parentNode.tagName == 'h1' || node.parentNode.tagName == 'h2' || node.parentNode.tagName == 'h3' || node.parentNode.tagName == 'h4' || node.parentNode.tagName == 'h5' || node.parentNode.tagName == 'h6' || node.parentNode.tagName == 'div')) { node.parentNode.tagName = 'div'; node.parentNode.setAttr('class', 'editor-image'); node.parentNode.setAttr('contenteditable', 'false'); node.parentNode.setAttr('draggable', 'true'); if (node.nextSibling() && node.nextSibling().tagName == 'br') { node.parentNode.removeChild(node.nextSibling()); } } else { var div = UE.uNode.createElement('div'); div.setAttr('element-id', domUtils.getRandomId()) div.setAttr('class', 'editor-image'); div.setAttr('contenteditable', 'false'); div.setAttr('draggable', 'true'); node.parentNode.insertBefore(div, node); div.appendChild(node); } }else if(node.parentNode && node.parentNode.getAttr('class') && node.parentNode.getAttr('class').indexOf('editor-image') > -1){ node.parentNode.setAttr('contenteditable', 'false'); node.parentNode.setAttr('draggable', 'true'); } //添加drag-image-wrap if (node.parentNode.parentNode && !(node.parentNode.parentNode.getAttr('class') && node.parentNode.parentNode.getAttr('class').indexOf('drag-image-wrap') > -1)) { var div = UE.uNode.createElement('div'); div.setAttr('element-id', domUtils.getRandomId()); div.setAttr('class', 'drag-image-wrap'); div.setAttr('contenteditable', 'false'); node.parentNode.parentNode.insertBefore(div, node.parentNode); div.appendChild(node.parentNode); node.setAttr('draggable', 'true'); } if(node.parentNode.getAttr('class').indexOf('remoteImage') == -1){ node.setAttr('_src', node.getAttr('src')); } /* *@Description: 增加图片无障碍焦点 *@Author:LiChangChang *@Date: 2022-10-21 11:42:23 */ node.setAttr('role', 'img') node.setAttr('tabindex', '0') // 20200525 去掉图片class,只保留加载中动画 if(node.getAttr('class') && node.getAttr('class').indexOf('width-column-img') > -1){ // 处理固定宽高图片排版的老数据图片结构 node.setAttr('class', 'width-column-img') node.setStyle('padding-left',''); node.setStyle('padding-right',''); node.setStyle('padding-bottom',''); }else if (node.getAttr('class') && node.getAttr('class').indexOf('loadingclass') > -1) { node.setAttr('class', 'loadingclass') } else { node.setAttr('class', '') } node.setStyle('display', ''); node.setStyle('font-weight', ''); node.setStyle('font-style', ''); node.setStyle('text-decoration', ''); node.setStyle('font-size',''); node.setStyle('text-indent',''); break; case 'span': if (browser.webkit && (val = node.getStyle('white-space'))) { if (/nowrap|normal/.test(val)) { node.setStyle('white-space', ''); if (me.options.autoClearEmptyNode && utils.isEmptyObject(node.attrs)) { node.parentNode.removeChild(node, true) } } } if (node.getStyle('text-wrap-mode')) { node.setStyle('text-wrap-mode', ''); } if (node.getStyle('text-wrap')) { node.setStyle('text-wrap', ''); } val = node.getAttr('id'); if (val && /^_baidu_bookmark_/i.test(val)) { node.parentNode.removeChild(node) } // 20200813 去除todo-inner里的内容 if (node.getAttr('class') && node.getAttr('class').indexOf('todo-inner') > -1) { node.innerHTML(''); } if (node.getStyle('text-emphasis') || node.getAttr('class') == 'sqp-emphasize-dot') { node.setStyle('text-emphasis', ''); node.tagName = 'em'; node.setAttr('class', 'sqp-emphasize-dot'); if (node.getAttr('style')) { var span = UE.uNode.createElement('span'); span.setAttr('style', node.getAttr('style')); node.setAttr('style', '') node.parentNode.insertBefore(span, node); span.appendChild(node); } } break; case 'p': if (val = node.getAttr('align')) { node.setAttr('align'); node.setStyle('text-align', val) } //去除font-size 14 if (node.getStyle('font-size') == '14px' && node.parentNode.tagName != 'LI') { node.setStyle('font-size', '') } //

    换成


    if (node.children.length == 1 && node.firstChild().data == domUtils.fillChar) { node.removeChild(node.firstChild()); node.appendChild(UE.uNode.createElement('br')) } //去除粘贴列表带出来的display:inline!important if (node.getStyle('display') && (node.getStyle('display') == 'inline !important')) { node.setStyle('display', ''); } //p标签不允许嵌套 utils.each(node.children, function (n) { if (n.type == 'element' && n.tagName == 'p') { var next = n.nextSibling(); node.parentNode.insertAfter(n, node); var last = n; while (next) { var tmp = next.nextSibling(); node.parentNode.insertAfter(next, last); last = next; next = tmp; } return false; } }); if (!node.firstChild()) { var pindex = node.getIndex(); if (node.parentNode && node.parentNode.children.length > 1 && node.parentNode.children[pindex - 1] && node.parentNode.children[pindex - 1].getAttr('contenteditable') == 'false') { node.innerHTML(browser.ie ? ' ' : '
    ') } else { node.parentNode.removeChild(node); } } node.setStyle('float', ''); if (node.getAttr('contenteditable')) { node.tagName = 'div'; } // node.setStyle('font-size', ''); // break; case 'div': if (node.getAttr('cdata_tag')) { break; } if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); node.setStyle('font-size', ''); //针对代码这里不处理插入代码的div val = node.getAttr('class'); if(val && (val.indexOf('noteDetail_main') > -1 || val.indexOf('noteContent') > -1 || val.indexOf('richtext') > -1)){ node.setAttr('class','') } //录音标注后要加文本节点占位 if (val && val.indexOf('record-list-tit') > -1) { if (node.lastChild() && (node.lastChild().type == 'text' || (node.lastChild().type == 'element' && node.lastChild().tagName == 'br'))) { } else { var newTextNode = UE.uNode.createElement('br'); node.appendChild(newTextNode); } } // 2022-6-8 如果div里只有文字,标签改为p if (node.tagName == 'div' && node.firstChild() && node.firstChild() == node.lastChild() && node.firstChild().type == 'text') { node.tagName = 'p'; break; } //20200703 去除图片div添加的背景 if (node.getAttr('class') && node.getAttr('class').indexOf('editor-image') > -1) { node.setStyle('background', ''); node.setStyle('background-color', ''); //解决浮动图片悬浮事件没有触发的问题 if (node.getStyle('float') == 'left' || node.getStyle('float') == 'right') { node.setStyle('z-index', '1'); } else { node.setStyle('z-index', ''); } } else { node.setStyle('float', ''); } if (node.getAttr('class') && node.getAttr('class').indexOf('editor-image') > -1) { //2022-3-24 拖动图片到一排-给图片外层加拖拽容器div if (node.parentNode && !(node.parentNode.getAttr('class') && node.parentNode.getAttr('class').indexOf('drag-image-wrap') > -1)) { var div = UE.uNode.createElement('div'); div.setAttr('element-id', domUtils.getRandomId()); div.setAttr('class', 'drag-image-wrap' + node.getAttr('class').replace('editor-image', '').replace('remoteImage', '')); div.setAttr('contenteditable', 'false'); node.parentNode.insertBefore(div, node); div.appendChild(node); node.setAttr('draggable', 'true'); } } else if (node.getAttr('class') && node.getAttr('class').indexOf('editor-iframe') > -1) { node.setAttr('draggable', 'true'); } if (node.getAttr('class') && node.getAttr('class').indexOf('drag-image-wrap') > -1) { node.setAttr('contenteditable', 'false'); node.setAttr('class', 'drag-image-wrap'); } if (node.getAttr('class') && ((node.getAttr('class').indexOf('editor-iframe') > -1 && node.getNodeByClass('editor-iframe')) || (node.getAttr('class').indexOf('drag-image-wrap') > -1 && node.getNodeByClass('drag-image-wrap')) || (node.getAttr('class').indexOf('editor-image') > -1 && node.getNodeByClass('editor-image')) || (node.getAttr('class').indexOf('table') > -1 && node.getNodeByClass('table')))) { while (node.firstChild()) { node.parentNode.insertBefore(node.firstChild(), node); } node.parentNode.removeChild(node); break; } //将image-wrap里面粘贴的其他元素移出来 2022-6-17 if (node.getAttr('class') && node.getAttr('class').indexOf('drag-image-wrap') > -1) { var firstChild = node.firstChild(), next; var hasImg = false; while (firstChild) { next = firstChild.nextSibling(); if (firstChild.getAttr('contenteditable') && firstChild.getAttr('class').indexOf('editor-image') > -1) { hasImg = true; } else if (firstChild.type == 'text' || !UE.dom.dtd.$block[firstChild.tagName]) { var p = UE.uNode.createElement('p'); p.setAttr('element-id', domUtils.getRandomId()); p.appendChild(firstChild); if (hasImg) { node.parentNode.insertAfter(p, node); } else { node.parentNode.insertBefore(p, node); } } else { if (hasImg) { node.parentNode.insertAfter(firstChild, node); } else { node.parentNode.insertBefore(firstChild, node); } } firstChild = next; } } //20210331 处理文本附件外层的div if (node.tagName == 'div' && node.getAttr('class') == 'editor-textiframe') { node.tagName = 'p'; node.setAttr('contenteditable', ''); node.setAttr('element-id', domUtils.getRandomId()); node.setAttr('class', ''); } if (node.getAttr('class') && node.getAttr('class').indexOf('table') > -1 && node.firstChild()) { node.setStyle('overflow', ''); node.setStyle('margin-left', ''); if (node.firstChild().data == domUtils.fillChar) { node.removeChild(node.firstChild()); } if (node.lastChild().data == domUtils.fillChar) { node.removeChild(node.lastChild()); } } if (val && /^line number\d+/.test(val)) { break; } //如果div没有class和style或者是飞书的图片class,移除外层的div if (node.tagName == 'div' && ((!node.getAttr('style') && !node.getAttr('class') && !(node.parentNode && node.parentNode.getAttr('class') && node.parentNode.getAttr('class').indexOf('classul') > -1)) || (node.getAttr('class') && node.getAttr('class').indexOf('image-uploaded') > -1 && node.getAttr('class').indexOf('gallery') > -1))) { var p = UE.uNode.createElement('p'); p.setAttr('element-id', domUtils.getRandomId()); node.parentNode.insertBefore(p, node); while (node.firstChild()) { if (node.firstChild().type == 'text' || !UE.dom.dtd.$block[node.firstChild().tagName]) { p.appendChild(node.firstChild()); } else if (node.firstChild.tagName == 'br') { p.appendChild(node.firstChild()); p = UE.uNode.createElement('p'); p.setAttr('element-id', domUtils.getRandomId()); } else { node.parentNode.insertBefore(node.firstChild(), node); } } if (!p.firstChild()) { p.parentNode.removeChild(p); } node.parentNode.removeChild(node); break; } //如果不允许div转p,跳出,下面是处理div转p的 if (!allowDivTransToP) { break; } var tmpNode, p = UE.uNode.createElement('p'); p.setAttr('element-id', domUtils.getRandomId()) while (tmpNode = node.firstChild()) { if (tmpNode.type == 'text' || !UE.dom.dtd.$block[tmpNode.tagName]) { p.appendChild(tmpNode); } else { if (p.firstChild()) { node.parentNode.insertBefore(p, node); p = UE.uNode.createElement('p'); p.setAttr('element-id', domUtils.getRandomId()) } else { node.parentNode.insertBefore(tmpNode, node); } } } if (p.firstChild()) { node.parentNode.insertBefore(p, node); } node.parentNode.removeChild(node); break; case 'dl': node.tagName = 'ul'; break; case 'dt': case 'dd': node.tagName = 'li'; break; case 'ul': case 'ol': node.setAttr('style', 'list-style-type: decimal;'); //去除font-size 14 if (node.getStyle('font-size') == '14px') { node.setStyle('font-size', '') } case 'li': var color = node.getStyle('color'); if (color) { node.setStyle('color', color); } if (node.getStyle('caret-color')) { node.setStyle('caret-color', ''); } //去除粘贴列表带出来的display:inline!important if (node.getStyle('display')) { node.setStyle('display', ''); } node.traversal(function (node) { if (node.tagName != 'li' && node.getStyle('line-height') && node.getStyle('line-height') != '') { node.setStyle('line-height', '') } }) break; case 'th': case 'td': var tmpNodes = node.getNodesByTagName('iframe'); if (tmpNodes.length > 0) { node.setAttr('width', '440'); } else if (node.getAttr('width') && node.getAttr('width').indexOf('%') > -1) { var width = parseInt(node.getAttr('width')) * $(me.body).width() / 100; node.setAttr('width', '' + width + ''); } else if (node.getAttr('width') && node.getAttr('width') < 40) { node.setAttr('width', '') } //去除font-size 14 if (node.setStyle('font-size') == '14px' && node.parentNode.tagName != 'LI') { node.setStyle('font-size', '') } node.setStyle('width', ''); // node.setAttr('vAlign', 'middle'); //如果只有一个br或纯文字,给br套一个p标签 if (node.children.length == 1 && (node.firstChild().tagName == 'br' || node.firstChild().type == 'text')) { var p = UE.uNode.createElement('p'); p.appendChild(node.firstChild()); node.appendChild(p); } break; case 'caption': if (!node.children || !node.children.length) { node.appendChild(browser.ie11below ? UE.uNode.createText(' ') : UE.uNode.createElement('br')) } break; case 'table': if (me.options.disabledTableInTable && tdParent(node)) { node.parentNode.insertBefore(UE.uNode.createText(node.innerText()), node); node.parentNode.removeChild(node) } node.setStyle('width', ''); if (node.getAttr('width') && (node.getAttr('width') < 500 || node.getAttr('width') == 'NaN' || node.getAttr('width') == '')) { node.setAttr('width','') } case 'col': if (node.getAttr('width') && (node.getAttr('width') == 'NaN' || node.getAttr('width') == '')) { node.setAttr('width','') } } //标题处理 if (/h\d/i.test(node.tagName)) { //20210317 更新目录--旧笔记没有element-id的加上id if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); //去除font-size 14 if (node.getStyle('font-size') == '14px' && node.parentNode.tagName != 'LI') { node.setStyle('font-size', '') } } //标题折叠:去掉标题折叠的三角 if (node.getAttr('class') && node.getAttr('class').indexOf('foldtitle-tri-wrap') > -1) { node.parentNode.removeChild(node); } //不是表格的外面套了.table,去掉class if (node.tagName != 'table' && node.parentNode && node.parentNode.getAttr('class') && node.parentNode.getAttr('class') == 'table') { node.parentNode.setAttr('class', '') } //去除onclick方法 if (node.getAttr('onclick')) { node.setAttr('onclick', ''); } //white-space 属性改为空 if (node.getStyle('white-space')) { node.setStyle('white-space', ''); } if (node.getStyle('caret-color')) { node.setStyle('caret-color', ''); } //20200422去除translate,防止文字右移超出版心 if (node.getStyle('transform') && node.getStyle('transform').indexOf('translate') > -1) { node.setStyle('transform', ''); } //20201010 浮动后文字不跟过去 if (node.getStyle('clear')) { node.setStyle('clear', ''); } if (node.getStyle('visibility')) { node.setStyle('visibility', ''); } //去除其他地方粘贴过来的contenteditable属性 if (node.getAttr('contenteditable') == 'true') { node.setAttr('contenteditable', ''); } if (node.getStyle('background') && node.getStyle('background').indexOf('url') > -1) { node.setStyle('background', ''); } if (node.getStyle('background-image') && node.getStyle('background-image') == 'url( default/images/callout-icon.png )') { node.setStyle('background-image', ''); } //有 div存在background-image属性 的情况 // node.setStyle('background-image', ''); if (node.getStyle('line-height').trim() == '2em') { node.setStyle('line-height', ''); } //去除img以外标签的宽度 if (node.getStyle('width') && node.tagName.toLocaleLowerCase() != 'img' && node.tagName.toLocaleLowerCase() != 'col' && node.tagName.toLocaleLowerCase() != 'table') { if (node.getStyle('width').indexOf('px') == -1 && node.getStyle('width').indexOf('%') == -1) { if (node.getStyle('width').indexOf('em') != -1) { //em 转换为px var w = node.getStyle('width').slice(0, node.getStyle('width').length - 2) * 16 node.setStyle('width', w + 'px'); } else { node.setStyle('width', 'auto'); } } } if (node.getStyle('position') && node.getStyle('position') == 'fixed') { node.setStyle('position','') } //去除定位相关样式 // if (!me.options.showXiumi && node.tagName && node.tagName.toLowerCase() != 'section') { // node.setStyle('position', ''); // node.setStyle('left', ''); // node.setStyle('top', ''); // node.setStyle('bottom', ''); // node.setStyle('right', ''); // node.setStyle('overflow', ''); // node.setStyle('height', ''); // } if (node.tagName && node.tagName.toLowerCase() != 'table' && node.tagName.toLowerCase() != 'section') { node.setStyle('margin', ''); } // node.setStyle('padding', ''); // node.setStyle('margin-top', ''); // node.setStyle('padding-top', ''); // node.setStyle('margin-bottom', ''); // node.setStyle('padding-bottom', ''); /*if(node.getStyle('margin-left').indexOf('-')){ node.setStyle('margin-left',''); }*/ // node.setStyle('margin-right',''); // if (node.getStyle('display') && (node.getStyle('display').indexOf('box') > -1 || node.getStyle('display').indexOf('flex') > -1)) { // node.setStyle('display', ''); // } node.setStyle('touch-action', ''); node.setStyle('flex', ''); if(node.getStyle('display') && node.getStyle('display').indexOf('flex')){ node.setStyle('display', ''); } node.setStyle('max-width', ''); if (node.getStyle('font-size') && node.getStyle('font-size').indexOf('em') > -1) { node.setStyle('font-size', ''); } else if (node.getStyle('font-size') && node.getStyle('font-size').indexOf('medium') > -1) { node.setStyle('font-size', '16px'); } else if (node.getStyle('font-size') && node.getStyle('font-size').indexOf('large') > -1) { node.setStyle('font-size', '18px'); } else if (node.getStyle('font-size') && node.getStyle('font-size').indexOf('small') > -1) { node.setStyle('font-size', '14px'); } //删除线加下划线 if (dtd.$inline[node.tagName] && node.tagName != 'img' && (node.getStyle('text-decoration-line').indexOf("line-through") > -1 || node.getStyle('text-decoration').indexOf("line-through") > -1) && (node.getStyle('text-decoration-line').indexOf("underline") > -1 || node.getStyle('text-decoration').indexOf("underline") > -1)) { node.setStyle('text-decoration', ''); node.setStyle('text-decoration-line', ''); var strike = UE.uNode.createElement('strike'); strike.appendChild(node.children[0]); node.appendChild(strike); if (node.children.length > 0 && node.attrs.style != '') { var u = UE.uNode.createElement('u'); u.appendChild(strike.children[0]); strike.appendChild(u); } else { node.tagName = 'u'; } } else if (dtd.$inline[node.tagName] && node.tagName != 'img' && node.getStyle('text-decoration-line').indexOf("line-through") > -1 || node.getStyle('text-decoration').indexOf("line-through") > -1) { node.setStyle('text-decoration', ''); node.setStyle('text-decoration-line', ''); if (node.children.length > 0 && node.attrs.style != '') { var span = UE.uNode.createElement('strike'); span.appendChild(node.children[0]); node.appendChild(span); } else { node.tagName = 'strike'; } } else if (dtd.$inline[node.tagName] && node.tagName != 'img' && node.getStyle('text-decoration-line').indexOf("underline") > -1 || node.getStyle('text-decoration').indexOf("underline") > -1) { node.setStyle('text-decoration', ''); node.setStyle('text-decoration-line', ''); if (node.children.length > 0 && node.attrs.style != '') { var span = UE.uNode.createElement('u'); span.appendChild(node.children[0]); node.appendChild(span); } else { node.tagName = 'u'; } } //斜体 if (dtd.$inline[node.tagName] && node.tagName != 'img' && node.getStyle('font-style').indexOf('italic') > -1) { node.setStyle('font-style', ''); if (node.children.length > 0 && node.attrs.style != '') { var span = UE.uNode.createElement('i'); span.appendChild(node.children[0]); node.appendChild(span); } else { node.tagName = 'i'; } } //粗体 if (dtd.$inline[node.tagName] && node.tagName != 'img' && (node.getStyle('font-weight').indexOf('bold') > -1 || node.getStyle('font-weight') >= 600)) { node.setStyle('font-weight', ''); if (node.children.length > 0 && node.attrs.style != '') { var span = UE.uNode.createElement('b'); while (node.children[0]) { span.appendChild(node.children[0]); } node.appendChild(span); } else { node.tagName = 'b'; } } } }) }); //从编辑器出去的内容处理 me.addOutputRule(function (root) { var val; root.traversal(function (node) { if (node.type == 'element') { if (me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) { if (!node.firstChild()) node.parentNode.removeChild(node); else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) { node.parentNode.removeChild(node, true) } return; } //勾选框不删除2019.10.25 if (node.getAttr('class') == 'todo-inner' || node.getAttr('class') == 'todo-mark' || node.getAttr('class') == 'callout-icon' || node.getAttr('class') == 'callout-inner') { return; } else if (node.children && node.children.length == 0 && node.tagName != 'iframe' && node.tagName != 'img' && node.tagName != 'tr' && node.tagName != 'td' && node.tagName != 'br' && node.tagName != 'canvas' && !(node.getAttr('module') && node.getAttr('module') == "chart")) { //去除空标签 node.parentNode.removeChild(node, true); return; } switch (node.tagName) { case 'section': node.tagName = 'div'; case 'div': if (val = node.getAttr('cdata_tag')) { node.tagName = val; node.appendChild(UE.uNode.createText(node.getAttr('cdata_data'))); node.setAttr({ cdata_tag: '', cdata_data: '', '_ue_custom_node_': '' }); } // 20200324 完成笔记时去除原站内信函的签名id if (node.getAttr('id') && node.getAttr('id') == 'signDiv' && node.parentNode.type != 'root') { node.setAttr('id', ''); } node.setAttr('draggable', ''); //20200603 完成时去除编辑图片给div添加的class:scale或hover if (node.getAttr('class') && node.getAttr('class').indexOf('editor-image') > -1 && node.getAttr('class').indexOf('scale') > -1) { node.setAttr('class', node.getAttr('class').replace('scale', '')); } if (node.getAttr('class') && node.getAttr('class').indexOf('drag-image-wrap') > -1) { node.setAttr('contenteditable', 'false'); } //20200731 去除附件拖动把手,去除拖动辅助线 if (node.getAttr('class') && (node.getAttr('class') == 'draghandle' || node.getAttr('class').indexOf('dragGuideLine') > -1)) { node.parentNode.removeChild(node); } //20210323 去除套的多余的 div editor-iframe、editor-image、table if (node.children.length == 1 && node.firstChild().tagName == 'div' && node.getAttr('class') && node.firstChild().getAttr('class') && ((node.getAttr('class').indexOf('editor-iframe') > -1 && node.firstChild().getAttr('class').indexOf('editor-iframe') > -1) || (node.firstChild().getAttr('class').indexOf('editor-image') > -1 && node.getAttr('class').indexOf('editor-image') > -1) || (node.firstChild().getAttr('class').indexOf('table') > -1 && node.getAttr('class').indexOf('table') > -1))) { var firstChild = node.firstChild(); while (firstChild.firstChild()) { node.insertBefore(firstChild.firstChild(), firstChild); } node.removeChild(firstChild); } if (node.getAttr('class') && node.getAttr('class') == 'editor-iframe' && node.getAttr('class') == 'editor-image') { node.setStyle('width', ''); } break; case 'ul': node.setStyle('width', ''); break; case 'ol': node.setStyle('width', ''); break; case 'li': node.setAttr('class', ''); node.traversal(function (node) { if (node.tagName != 'li' && node.getStyle('line-height') && node.getStyle('line-height') != '') { node.setStyle('line-height', '') } }) break; case 'a': if (val = node.getAttr('_href')) { node.setAttr({ 'href': utils.html(val), '_href': '' }) } break; case 'span': val = node.getAttr('id'); if (val && /^_baidu_bookmark_/i.test(val)) { node.parentNode.removeChild(node) } // 20200529 去除图片编辑框的蓝色色块 if (node.getAttr('class') && node.getAttr('class').indexOf('edui-editor-imagescale-hand') > -1) { node.parentNode.removeChild(node); } // 20200609 去除todo-inner里的内容 if (node.getAttr('class') && node.getAttr('class').indexOf('todo-inner') > -1) { node.nodeValue = ''; } break; case 'img': if (val = node.getAttr('_src') && node.parentNode.getAttr('class') && node.parentNode.getAttr('class').indexOf('remoteImage') == -1) { node.setAttr({ 'src': node.getAttr('_src'), '_src': '' }) } if(node.getAttr('src')) node.parentNode.setAttr('class','editor-image') node.setAttr('role', 'img') node.setAttr('tabindex', '0') // 处理固定宽高图片排版的老数据图片结构 if(node.getAttr('class') && node.getAttr('class').indexOf('width-column-img') > -1){ node.setAttr('class', 'width-column-img') }else{ node.setAttr('class', ''); } //20200520 保留图片宽高 // node.setAttr('width','auto'); // node.setAttr('height','auto'); node.setAttr('fileid', ''); //img外层没有div包裹 if (browser.firefox || browser.ie) { if (node.parentNode.tagName == 'div' && !node.parentNode.attrs.class && node.parentNode.children.length == 1) { node.parentNode.setAttr('class', 'editor-image'); node.parentNode.setAttr('contenteditable', 'false'); } else if (node.parentNode.tagName == 'p' && !node.parentNode.attrs.class && node.parentNode.children.length == 1) { node.parentNode.tagName = 'div'; node.parentNode.setAttr('class', 'editor-image'); node.parentNode.setAttr('contenteditable', 'false'); } else { var div = UE.uNode.createElement('div'); div.setAttr('element-id', domUtils.getRandomId()) node.parentNode.insertBefore(div, node); div.appendChild(node); div.setAttr("class", "editor-image"); div.setAttr('contenteditable', 'false'); } } break; case 'iframe': if (browser.firefox || browser.ie) { //iframe外层没有div包裹 if (domUtils.isBlockElm(node.parentNode) && !node.parentNode.attrs.class && node.parentNode.children.length == 1) { node.parentNode.setAttr('class', 'editor-iframe'); node.parentNode.setAttr('contenteditable', 'false'); } else if (node.parentNode.tagName == 'p' && !node.parentNode.attrs.class && node.parentNode.children.length == 1) { node.parentNode.tagName = 'div'; node.parentNode.setAttr('class', 'editor-iframe'); node.parentNode.setAttr('contenteditable', 'false'); } else { var div = UE.uNode.createElement('div'); div.setAttr('element-id', domUtils.getRandomId()) node.parentNode.insertBefore(div, node); div.appendChild(node); div.setAttr("class", "editor-iframe"); div.setAttr('contenteditable', 'false') } } break; case 'table': node.setStyle('width', ''); if (node.getAttr('width') && (node.getAttr('width') == 'NaN' || node.getAttr('width') == '')) { node.setAttr('width','') } break; case 'col': if (node.getAttr('width') && (node.getAttr('width') == 'NaN' || node.getAttr('width') == '')) { node.setAttr('width','') } break; case 'h1': //20210317 更新目录--旧笔记没有element-id的加上id if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); break; case 'h2': if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); break; case 'h3': if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); break; case 'h4': if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); break; case 'h5': if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); break; case 'h6': if (!node.getAttr('element-id') || node.getAttr('element-id') == 'init') node.setAttr('element-id', domUtils.getRandomId()); break; } if (node.getStyle('position') && node.getStyle('position').indexOf('absolute') > 0) { if (!(node.getAttr('id') && node.getAttr('id') == 'ue_tableDragLine')) { node.parentNode.removeChild(node, true) } } if (node.getStyle('position') && node.getStyle('position') == 'fixed') { node.setStyle('position','') } if (node.getStyle('text-align') && node.getStyle('text-align') == 'start') { node.setStyle('text-align', ''); } if (node.getStyle('display') && node.getStyle('display') == 'none') { //标题折叠:完成时需要展开折叠标题 node.setStyle('display', ''); } if (node.getAttr('class') && node.getAttr('class').indexOf('tempShow') > -1) { node.setAttr('class', '') } node.setStyle('touch-action', ''); } }) }); }; // plugins/inserthtml.js /** * 插入html字符串插件 * @file * @since 1.2.6.1 */ /** * 插入html代码 * @command inserthtml * @method execCommand * @param { String } cmd 命令字符串 * @param { String } html 插入的html字符串 * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入 * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。 * @example * ```javascript * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本 * //执行命令,插入CC * //插入后的效果 xxxCCxxx * //

    xx|xxx

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

    CC

    * //结果

    xx

    CC

    xxx

    * //

    xxxx

    |

    xxx

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

    xxxx

    xxxx

    xxx

    * ``` */ UE.commands['inserthtml'] = { execCommand: function (command, html, notNeedFilter, tmpRange) { var me = this, range, div; if (!html) { return; } if (me.fireEvent('beforeinserthtml', html) === true) { return; } range = me.selection.getRange(); //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange } else { // 20211022 如果光标在contenteditable=false 里面,移出 if (range.startContainer.nodeType == 1 && range.startContainer.getAttribute('contenteditable') && range.startContainer.nodeName != 'BODY') { if (range.startOffset == 0 && domUtils.getPreDomNode(range.startContainer, false)) { range.setStart(domUtils.getPreDomNode(range.startContainer, false), domUtils.getPreDomNode(range.startContainer, false).childNodes.length - 1); } else if (range.startOffset == 0) { range.setStartBefore(range.startContainer) } else if (domUtils.getNextDomNode(range.startContainer, false)) { range.setStart(domUtils.getNextDomNode(range.startContainer, false), 0); } else { range.setStartAfter(range.startContainer) } } if (range.endContainer.nodeType == 1 && range.endContainer.getAttribute('contenteditable') && range.endContainer.nodeName != 'BODY') { if (range.endOffset == 0 && domUtils.getPreDomNode(range.endContainer, false)) { range.setEnd(domUtils.getPreDomNode(range.endContainer, false), domUtils.getPreDomNode(range.endContainer, false).childNodes.length - 1); } else if (range.endOffset == 0) { range.setEndBefore(range.endContainer) } else if (domUtils.getNextDomNode(range.endContainer, false)) { range.setEnd(domUtils.getNextDomNode(range.endContainer, false), 0); } else { range.setEndAfter(range.endContainer) } } range.select(true) } if (range.collapsed && range.startContainer.nodeType == 1 && (range.startContainer.className.indexOf('editor-image') > -1 || range.startContainer.className.indexOf('editor-iframe') > -1 || range.startContainer.tagName == 'A')) { range.setStartAfter(range.startContainer); range.setEndAfter(range.startContainer); range.collapse(true); } else if (range.collapsed && $(range.startContainer).parents('a').length > 0 && html.indexOf('<') > -1) { //光标在a标签里,移出//如果插入的内容没有标签,可以直接插入到a标签里 range.setStartAfter($(range.startContainer).parents('a')[0]).collapse(true); } if (html.indexOf(' -1 && ($(range.startContainer).is('td') || $(range.startContainer).parents('td').length > 0)) { if ($(range.startContainer).parents('td').eq(0).attr('width') && $(range.startContainer).parents('td').eq(0).attr('width') < 440) { $(range.startContainer).parents('td').eq(0).attr('width', 440); } } div = range.document.createElement('div'); div.style.display = 'inline'; var root = UE.htmlparser(html); if (!notNeedFilter) { if(html.indexOf('
    ') == 0 || html.indexOf('
    ') == 0){ console.log("插入秀米"); root.traversal(function (node) { if (node.type !== 'element') { return false; } if(node.tagName == 'img'){ if(me.options.forbidImage){ //不允许有图片 node.parentNode.removeChild(node) return } //插入的秀米图片地址换到_src上 if(html.indexOf('
    ') == 0 && node.getAttr('src') && window.obj && window.obj.mirrorDomain && node.getAttr('src').indexOf(window.obj.mirrorDomain.photoDomain.replace('http:','').replace('https:','')) == -1){ node.setAttr('_src',node.getAttr('src')) node.setAttr('src','') } //没有套div的图片,套div if (node.parentNode && (!node.parentNode.getAttr('class') || node.parentNode.getAttr('class').indexOf('editor-image') == -1)) { var div = UE.uNode.createElement('div'); div.setAttr('element-id', domUtils.getRandomId()) div.setAttr('class', 'editor-image'); div.setAttr('contenteditable', 'false'); div.setAttr('draggable', 'true'); node.parentNode.insertBefore(div, node); div.appendChild(node); } //添加drag-image-wrap if (node.parentNode.parentNode && !(node.parentNode.parentNode.getAttr('class') && node.parentNode.parentNode.getAttr('class').indexOf('drag-image-wrap') > -1)) { var div = UE.uNode.createElement('div'); div.setAttr('element-id', domUtils.getRandomId()); div.setAttr('class', 'drag-image-wrap'); div.setAttr('contenteditable', 'false'); node.parentNode.parentNode.insertBefore(div, node.parentNode); div.appendChild(node.parentNode); node.setAttr('draggable', 'true'); } }else if(node.tagName == 'iframe'){ if(me.options.forbidAttachment){ //不允许有附件 node.parentNode.removeChild(node) } } me.filterWhiteList(node); }); }else{ //如果给了过滤规则就先进行过滤 if (me.options.filterRules) { UE.filterNode(root, me.options.filterRules); } //执行默认的处理 me.filterInputRule(root); } } html = root.toHtml() div.innerHTML = utils.trim(html); //插入图片的时候图片地址是base64,不执行savescene操作 var isuploadImg = false; if (div.querySelector('img') && div.querySelector('img').getAttribute('src') && div.querySelector('img').getAttribute('src').indexOf('data:') > -1 && div.querySelector('img').getAttribute('src').indexOf('base64') > -1) { isuploadImg = true; } //统计插入的图片和附件数量,未成功的不统计 if (me.options.statsAttach) { if (!div.querySelector('img.loadingclass') && ($(div).find('img').length > 0 && !div.querySelector('.imgprogress') || $(div).find('iframe').length > 0 && !div.querySelector('.attachprogress'))) { var staAtt = []; for (var i = 0; i < $(div).find('img').length; i++) { var src = $(div).find('img').eq(i).attr('src'); //未上传成功的图片不统计,autouploader处理、非镜像不是chaoxing域名的图片不统计 if (src && src.indexOf('spacer.gif') == -1 && (!RichTextUitl.intranetMode && src.indexOf('chaoxing.com') == -1 && src.indexOf('cldisk.com') == -1)) { continue; } var imgItem = { 'type': 'img', 'resource': src } staAtt.push(imgItem); } for (var i = 0; i < $(div).find('iframe').length; i++) { var name = $(div).find('iframe').eq(i).attr('name'); //未上传成功的name未加密,加密后上传 try { if (JSON.parse(name)) { name = RichTextUitl.b64EncodeUnicode(JSON.stringify(name)); } } catch (e) { } var iframeItem = { 'type': 'iframe', 'resource': name } staAtt.push(iframeItem); } if (staAtt.length > 0) { me.anasycStatsAttach(staAtt, 1); } } } //解决文本链接选中插入附件带了链接图标 if (!range.collapsed && ($(range.startContainer).is('a') || $(range.startContainer).parents('a').length > 0) && div.querySelector('[contenteditable=false]')) { if ($(range.startContainer).is('a')) { range.setStartAfter(range.startContainer).collapse(true); } else if ($(range.startContainer).parents('a').length > 0) { range.setStartAfter($(range.startContainer).parents('a')[0]).collapse(true); } } //新加图片设置显示规则 if (div.querySelector('img')) { var imgs = div.querySelectorAll('img'); for (var i = 0; i < imgs.length; i++) { var addr = imgs[i].getAttribute("src"); if (!addr) { continue; } addr = addr.replace(/&/g, '&'); imgs[i].onload = function () { var imgW1 = this.clientWidth || this.naturalWidth; //原始图片宽度 var imgH1 = this.clientHeight || this.naturalHeight; //原始图片高度 if (imgW1 > 1 && imgH1 > 1) { var imgW2, imgH2; if (imgW1 >= 750) { if (imgW1 / imgH1 <= 9 / 16) { imgW2 = 243; } else { imgW2 = 800; } } else { imgW2 = imgW1; } this.setAttribute('height','') // 20200527 上传阴影和图片宽度一致 if ($(this).siblings('.imgmask').length > 0) { $(this).siblings('.imgmask').css({ 'width': imgW2, 'left': '50%', 'marginLeft': -parseInt(imgW2 / 2) }) } } } } } //光标在baidu_pastebin里面时不处理 if (!range.collapsed && !(range.startContainer.nodeType == 1 && range.startContainer.getAttribute('id') && range.startContainer.getAttribute('id') == 'baidu_pastebin')) { //统计附件和图片的数量,选中插入时需要记录移除的图片附件 if (me.options.statsAttach) { var clonedSelection = range.cloneContents(); var div = document.createElement('div'); div.appendChild(clonedSelection); if ($(div).find('img').length > 0 || $(div).find('iframe').length > 0) { var staAtt = []; for (var i = 0; i < $(div).find('img').length; i++) { var src = $(div).find('img').eq(i).attr('src'); if (src.indexOf('spacer.gif') == -1 && (!RichTextUitl.intranetMode && src.indexOf('chaoxing.com') == -1 && src.indexOf('cldisk.com') == -1)) { continue; } var imgItem = { 'type': 'img', 'resource': $(div).find('img').eq(i).attr('src') } staAtt.push(imgItem); } for (var i = 0; i < $(div).find('iframe').length; i++) { var iframeItem = { 'type': 'iframe', 'resource': $(div).find('iframe').eq(i).attr('name') } staAtt.push(iframeItem); } if (staAtt.length > 0) { me.anasycStatsAttach(staAtt, 0); } } } 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) } } } //解决选中列表粘贴列表序号错乱的问题 if (!range.collapsed && domUtils.findParentByTagName(range.startContainer, 'li', true) && domUtils.isStartInblock(range) && div.querySelector('li')) { range.enlarge(); range.deleteContents(); range.shrinkBoundary(); } else { !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) && !pre.getAttribute('contenteditable')) { range.setEnd(pre, pre.childNodes.length).collapse(); while (child.firstChild) { pre.appendChild(child.firstChild); } domUtils.remove(child); } } } else if (range.startContainer.nodeType == 1 && range.startContainer.firstChild && range.startContainer.getAttribute('id') && range.startContainer.getAttribute('id') == 'baidu_pastebin') { //光标在baidu_pastebin里面插入图片时有空格,会产生空行 range.setStart(range.startContainer.firstChild, 0).collapse(true); } var child, parent, pre, tmp, hadBreak = 0, nextNode; //如果当前位置选中了fillchar要干掉,要不会产生空行 if (range.inFillChar()) { child = range.startContainer; if (domUtils.isFillChar(child)) { range.setStartBefore(child).collapse(true); domUtils.remove(child); } else if (domUtils.isFillChar(child, true)) { child.nodeValue = child.nodeValue.replace(fillCharReg, ''); range.startOffset--; range.collapsed && range.collapse(true) } } if (div.firstChild && domUtils.isBlockElm(div.firstChild) && !div.firstChild.getAttribute('contenteditable') && !div.firstChild) { div.removeChild(div.firstChild); } //如果前一个元素是

    xxx

    ,光标在xxx后面,粘贴的第一个元素又是块状元素,把光标移到br后面,防止粘贴后产生空行 if (range.collapsed && domUtils.isBlockElm(div.firstChild) && div.firstChild.tagName != 'UL' && div.firstChild.tagName != 'OL' && div.firstChild.className.indexOf('todo-view') == -1 && range.startContainer.nodeType == 1 && range.startContainer.childNodes[range.startOffset] && range.startContainer.childNodes[range.startOffset].nodeName == 'BR' ) { if ((range.startContainer.innerText.trim() != '' && range.startContainer.innerText.trim() != domUtils.fillChar) || (div.firstChild.innerText.trim() != '' && div.firstChild.innerText.trim() != domUtils.fillChar)) { range.startContainer.removeChild(range.startContainer.childNodes[range.startOffset]); } else { range.setStartAfter(range.startContainer.childNodes[range.startOffset]).collapse(true); } } //列表单独处理 var li = domUtils.findParentByTagName(range.startContainer, 'li', true); var list = domUtils.findParentByTagName(range.startContainer, ['ul', 'ol'], true); //去除外层的标签 if (range.startContainer.tagName != 'BODY' && domUtils.isBlockElm(div.firstChild) && ['div', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].indexOf(div.firstChild.nodeName.toLowerCase()) > -1 && !(!li && /h\d/i.test(div.firstChild.nodeName)) && div.firstChild.className.indexOf('table') == -1 && !(div.firstChild.getAttribute('contenteditable') && div.firstChild.getAttribute('contenteditable') == 'false') && div.firstChild.className.indexOf('xiumi') == -1 && div.firstChild.className.indexOf('unfilter_css') == -1 && div.firstChild.className.indexOf('todo-view') == -1) { if (div.firstChild.lastChild && div.firstChild.lastChild != div.firstChild.firstChild && div.firstChild.lastChild.nodeType == 1 && div.firstChild.lastChild.nodeName == 'BR') { div.firstChild.removeChild(div.firstChild.lastChild) } //解决导入文档第一个标题居中被去掉的问题 if (div.firstChild.tagName == 'P' && domUtils.getStyle(div.firstChild, 'text-align') == 'center'){ domUtils.setAttributes(range.startContainer, { style: 'text-align:center' }); } domUtils.remove(div.firstChild, true); } if (li) { var level = list.getAttribute('level'); var next, last; //列表下插入表格,表格后加一个空格 if (div.childNodes.length == 1 && div.firstChild.nodeType == 1 && div.firstChild.className.indexOf('table') > -1) { div.appendChild(document.createElement('br')) } // 20190514 处理列表第一行添加图片出现的空行 if (div.firstChild.nodeType == 1 && div.firstChild.tagName == 'BR' && div.lastChild.nodeType == 1 && div.lastChild.getAttribute('contenteditable') == 'false') { var start; if (range.startContainer.nodeType == 3) { start = range.startContainer; if (range.startOffset < 0) { // range.startOffset,endoffset = -1 range.setStart(range.startContainer, 0); range.setEnd(range.endContainer, 0); } if (range.startOffset == 0) { //光标在文字前 if (start.previousSibling && start.previousSibling.nodeType == 1 && !start.previousSibling.getAttribute('contenteditable')) { //
    /

    |xxxx text前存在元素节点 domUtils.remove(div.firstChild); } else if (!start.previousSibling && start.parentNode.previousSibling && start.parentNode.previousSibling.nodeType == 1 && !start.parentNode.previousSibling.getAttribute('contenteditable')) { //

    xxxx

    |xxxx

    domUtils.remove(div.firstChild); } } else if (start.nodeValue.replace(new RegExp(domUtils.fillChar, 'gi'), '').length > range.startOffset) { //文字中间加图片

    xxxx|xxxx

    domUtils.remove(div.firstChild); } else if (range.startOffset > 0) { //光标在文字后 if (start.nextSibling && start.nextSibling.nodeType == 1 && start.nextSibling.nodeName == 'BR') { //xxxx|
    xxxx // domUtils.remove(div.firstChild); // if(start.nextSibling.nextSibling) { // start.parentNode.removeChild(start.nextSibling); // } start.parentNode.removeChild(start.nextSibling); div.appendChild(div.firstChild); } else if (start.nextSibling && start.nextSibling.nodeType == 1 && !start.nextSibling.getAttribute('contenteditable')) { //text后存在元素节点 domUtils.remove(div.firstChild); } else if (!start.nextSibling && start.parentNode.nextSibling && start.parentNode.nextSibling.nodeType == 1 && !start.parentNode.nextSibling.getAttribute('contenteditable')) { //

    xxxxx|

    后存在元素节点 domUtils.remove(div.firstChild); } else { // text后没有元素节点,br和img交换位置 div.appendChild(div.firstChild); } } start = start.parentNode; } else if (range.startContainer.nodeType == 1) { start = range.startContainer; if (range.startOffset > 0 && range.startContainer.nodeName != 'LI') { //列表下多行文字最后加多个图片 //TODO div.appendChild(div.firstChild); } } } else if (/^(ol|ul)$/i.test(div.firstChild.tagName)) { if (!div.firstChild.firstChild) { $(div.firstChild).remove(); } domUtils.remove(div.firstChild, true); if (div.firstChild.tagName == 'LI') { domUtils.remove(div.firstChild, true); } } else if (/^(li)$/i.test(div.firstChild.tagName)) { domUtils.remove(div.firstChild, true); } //如果光标行有br,去除 if (domUtils.isBlockElm(range.startContainer) && range.startContainer.querySelectorAll('br').length == 1 && (range.startContainer.innerText.trim() != '' && range.startContainer.innerText != domUtils.fillChar) && (div.firstChild.nodeType == 1 && div.firstChild.tagName != 'BR' && !div.firstChild.getAttribute('contenteditable')) ) { // if(domUtils.isBlockElm(range.startContainer) && range.startContainer.querySelectorAll('br').length==1 && div.firstChild.tagName!='BR' && !div.firstChild.getAttribute('contenteditable')){ $(range.startContainer).find('br').remove(); } //第一个元素是块状元素,当前行列表不为空,断开列表 if (domUtils.isBlockElm(div.firstChild) && list && !(li.innerText.trim() == domUtils.fillChar || li.innerText.trim() == '') && !li.querySelector('img') && !li.querySelector('iframe')) { var bookmark = range.createBookmark(); var span = document.createElement('span'); range.insertNode(span); domUtils.breakParent(span, li.parentNode); domUtils.clearEmptySibling(span); list = span.previousSibling; nextlist = span.nextSibling; domUtils.remove(span); if (nextlist.firstChild && nextlist.firstChild.nodeName == 'LI' && nextlist.firstChild.children.length == 1 && $(nextlist).text().trim() == '' && $(nextlist).find('img').length == 0 && $(nextlist).find('iframe').length == 0 && $(nextlist).find('hr').length == 0 && $(list).find('canvas').length == 0) { $(nextlist).remove() } if (list.firstChild && list.firstChild.nodeName == 'LI' && list.firstChild.children.length == 1 && $(list).text().trim() == '' && $(list).find('img').length == 0 && $(list).find('iframe').length == 0 && $(list).find('hr').length == 0 && $(list).find('canvas').length == 0) { $(list).remove() } range.moveToBookmark(bookmark); } //如果列表下插入的第一个元素是块状元素,则去除br和块状元素的外标签,只保留文本 if (domUtils.isBlockElm(div.firstChild) && div.firstChild.querySelectorAll('br').length == 1 && ['div', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].indexOf(div.firstChild.nodeName.toLowerCase()) > -1) { $(div.firstChild).find('br').remove(); } if (domUtils.isBlockElm(div.firstChild) && list && !div.firstChild.getAttribute('contenteditable')) { domUtils.remove(div.firstChild, true); } while (child = div.firstChild) { //针对hr单独处理一下先 while (child) { next = child.nextSibling; var list = domUtils.findParentByTagName(range.startContainer, ['ul', 'ol'], true); if (/^(ol|ul)$/i.test(child.tagName)) { //是列表 var list = domUtils.findParentByTagName(range.startContainer, ['ul', 'ol'], true); if (list) { var span = document.createElement('span'); range.setStartAfter(list).collapse(true); range.insertNode(span); if (child.tagName == 'OL') { var level = parseInt(level) || 1; var serialnum = list.getAttribute('serialnum'); var childlevel = parseInt(child.getAttribute('level')) || 1; if (level == childlevel) { child.setAttribute('serialnum', domUtils.addSerialNum(serialnum, childlevel)); child.firstChild.setAttribute('serialnum', child.getAttribute('serialnum')); child.removeAttribute('data-start'); child.removeAttribute('data-origin-start'); } else { child.setAttribute('serialnum', domUtils.serialnumToString('1', childlevel)); child.firstChild.setAttribute('serialnum', child.getAttribute('serialnum')); } } domUtils.insertAfter(span, child); domUtils.remove(span); } else { range.insertNode(child).collapse(); } range.setStartAfter(child.lastChild.lastChild); range.setEndAfter(child.lastChild.lastChild); last = child.lastChild.lastChild; } else { range.insertNode(child).collapse(); last = child; } child = next; } } // li = domUtils.findParentByTagName(range.startContainer, 'li', true); // if(domUtils.isEmptyBlock(li)) { // domUtils.remove(li) // } // 20190514 拆分p套p的情况 if (domUtils.isBlockElm(last.parentNode) && last.parentNode.tagName != 'LI' && (domUtils.isBlockElm(last) || (last.previousSibling && domUtils.isBlockElm(last.previousSibling)))) { var p = last.parentNode; var li = domUtils.findParentByTagName(last, 'li', true); var next = p.nextSibling; var first = p.firstChild; var isstarttext = true; var islilast = (li.lastChild == p ? true : false); if (li.lastChild != p) { pnext = p.nextSibling; } while (first) { //

    aaabbb

    ccc

    ddd eee

    fff

    next = first.nextSibling; if (domUtils.isBlockElm(first)) { //ccc fff部分 isstarttext = false; if (islilast) { li.appendChild(first); } else { li.insertBefore(first, pnext); } var newp = document.createElement('p'); // }else if(first.nodeName=='BR'){ //ddd eee部分 // domUtils.remove(first); } else if (isstarttext == false) { //ddd eee部分 newp.setAttribute('element-id', domUtils.getRandomId()); newp.appendChild(first); if (islilast) { li.appendChild(newp); } else { li.insertBefore(newp, pnext); } } first = next; } } var brs = li.querySelectorAll('br') for (var i = 0; i < brs.length; i++) { if (brs[i].parentNode.querySelectorAll('br').length > 1) { var newp = document.createElement('p'); newp.setAttribute('element-id', domUtils.getRandomId()) brs[i].parentNode.insertBefore(newp, brs[i]); newp.appendChild(brs[i]) } } //解决列表下粘贴文字和视频,视频后面没有空行的问题 if (last && last.nodeType == 1 && last.getAttribute('contenteditable') && !last.nextSibling && !li.parentNode.nextSibling) { var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()); p.innerHTML = '
    '; last.parentNode.appendChild(p); last = p; } else if (last && last.nodeType == 1 && last.getAttribute('contenteditable') && !last.nextSibling && li.parentNode.nextSibling) { last = li.parentNode.nextSibling; } else if (last && last.nodeType == 1 && last.getAttribute('contenteditable') && last.nextSibling) { last = last.nextSibling; } if (last) { if (last.nodeName == 'BR') { range.setStartBefore(last); } else if (last.lastChild) { if ((last.tagName == 'OL' || last.tagName == 'UL') && last.lastChild.lastChild) { range.setStartAfter(last.lastChild.lastChild); } range.setStartAfter(last.lastChild); } else { range.setStartAfter(last); } range = range.shrinkBoundary().collapse(true); if (!tmpRange) { range.select(true) } } //如果当前位置选中了fillchar要干掉,要不会产生空行,再处理一次 if (range.inFillChar()) { child = range.startContainer; if (domUtils.isFillChar(child)) { range.setStartBefore(child).collapse(true); domUtils.remove(child); } else if (domUtils.isFillChar(child, true)) { child.nodeValue = child.nodeValue.replace(fillCharReg, ''); range.startOffset--; range.collapsed && range.collapse(true) } } } else { while (child = div.firstChild) { if (hadBreak) { var p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) { nextNode = child.nextSibling; p.appendChild(child); child = nextNode; } if (p.firstChild) { child = p } } range.insertNode(child); nextNode = child.nextSibling; if (!hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm(child)) { parent = domUtils.findParent(child, function (node) { return domUtils.isBlockElm(node); }); if (parent && parent.tagName.toLowerCase() != 'body' && !(dtd[parent.tagName][child.nodeName] && child.parentNode === parent)) { if (!dtd[parent.tagName][child.nodeName]) { pre = parent; } else { tmp = child.parentNode; while (tmp !== parent) { pre = tmp; tmp = tmp.parentNode; } } domUtils.breakParent(child, pre || tmp); //去掉break后前一个多余的节点

    |<[p> ==>

    |

    var pre = child.previousSibling; domUtils.trimWhiteTextNode(pre); if (!pre.childNodes.length) { domUtils.remove(pre); } //20200619 去除break后右侧的空节点 var next = child.nextSibling; if (next) { domUtils.trimWhiteTextNode(next); if (!next.childNodes.length && next.nextSibling && !(next.nextSibling.nodeType == 1 && next.nextSibling.getAttribute('contenteditable'))) { domUtils.remove(next); } } //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位 if (!browser.ie && (next = child.nextSibling) && domUtils.isBlockElm(next) && next.lastChild && next.tagName != "OL" && next.tagName != 'UL' && !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.isNodeEmpty(child)) { nextNode = child.nextSibling; if (nextNode && !(nextNode.nodeType == 1 && nextNode.getAttribute('contenteditable'))) { // domUtils.remove(child); if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) { var isContainImgOrIframe = nextNode.className && (nextNode.className.indexOf('editor-image') > -1 || nextNode.className.indexOf('editor-iframe') > -1 || (nextNode.className.indexOf('dynacALink') > -1 && nextNode.className.indexOf('iframe') > -1)); if (!isContainImgOrIframe) { range.setStart(nextNode, 0).collapse(true).shrinkBoundary() } } } else { try { child.innerHTML = browser.ie ? domUtils.fillChar : '
    '; } catch (e) { range.setStartBefore(child); domUtils.remove(child) } } } //加上true因为在删除表情等时会删两次,第一次是删的fillData try { if (!tmpRange) { range.select(true) } } catch (e) { } } if (!(typeof (imageViewer) == "undefined") && imageViewer) { imageViewer.update(); } if (!(typeof (RichTextUitl) == "undefined") && !(typeof (RichTextUitl.imageViewer) == "undefined") && RichTextUitl.imageViewer) { RichTextUitl.imageViewer.update(); } if (!isuploadImg ) { me.normalList() } //渲染公式 RichTextUitl.renderLatex(me.body); setTimeout(function () { //20210317 更新目录 if (typeof (updateAllCatalog) == "function") { updateAllCatalog(me.body); } range = me.selection.getRange(); range.scrollToView(me.autoHeightEnabled, me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0); me.fireEvent('afterinserthtml', html); me.fireEvent("catchRemoteImage"); $(me.body).find('animate').each(function (index, node) { if(node.getAttribute("begin")){ node.setAttribute("begin",node.getAttribute("begin")) } }) }, 200); } }; // plugins/autotypeset.js /** * 自动排版 * @file * @since 1.2.6.1 */ /** * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。 * @command autotypeset * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'autotypeset' ); * ``` */ UE.plugins['autotypeset'] = function () { this.setOpt({ 'autotypeset': { mergeEmptyline: false, //合并空行 removeClass: false, //去掉冗余的class removeEmptyline: false, //去掉空行 // textAlign:"left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版 // imageBlockLine: 'center', //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版 pasteFilter: false, //根据规则过滤没事粘贴进来的内容 clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号 clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体 removeEmptyNode: false, // 去掉空节点 //可以去掉的标签 removeTagNames: utils.extend({ div: 1 }, dtd.$removeEmpty), indent: false, // 行首缩进 indentValue: '2em', //行首缩进的大小 bdc2sb: false, tobdc: false } }); var me = this, opt = me.options.autotypeset, remainClass = { 'selectTdClass': 1, 'pagebreak': 1, 'anchorclass': 1 }, remainTag = { 'li': 1 }, tags = { div: 1, p: 1, //trace:2183 这些也认为是行 blockquote: 1, center: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, span: 1 }, highlightCont; //升级了版本,但配置项目里没有autotypeset if (!opt) { return; } readLocalOpts(); function isLine(node, notEmpty) { if (!node || node.nodeType == 3) return 0; if (domUtils.isBr(node)) return 1; if (node && node.parentNode && tags[node.tagName.toLowerCase()]) { if (highlightCont && highlightCont.contains(node) || node.getAttribute('pagebreak') ) { return 0; } return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node, new RegExp('[\\s' + domUtils.fillChar + ']', 'g')); } } function removeNotAttributeSpan(node) { if (!node.style.cssText) { domUtils.removeAttributes(node, ['style']); if (node.tagName.toLowerCase() == 'span' && domUtils.hasNoAttributes(node)) { domUtils.remove(node, true); } } } function autotype(type, html) { var me = this, cont; if (html) { if (!opt.pasteFilter) { return; } cont = me.document.createElement('div'); cont.setAttribute('element-id', domUtils.getRandomId()) cont.innerHTML = html.html; } else { cont = me.document.body; } var nodes = domUtils.getElementsByTagName(cont, '*'); // 行首缩进,段落方向,段间距,段内间距 for (var i = 0, ci; ci = nodes[i++];) { if (me.fireEvent('excludeNodeinautotype', ci) === true) { continue; } //font-size if (opt.clearFontSize && ci.style.fontSize) { domUtils.removeStyle(ci, 'font-size'); removeNotAttributeSpan(ci); } //font-family if (opt.clearFontFamily && ci.style.fontFamily) { domUtils.removeStyle(ci, 'font-family'); removeNotAttributeSpan(ci); } if (isLine(ci)) { //合并空行 if (opt.mergeEmptyline) { var next = ci.nextSibling, tmpNode, isBr = domUtils.isBr(ci); while (isLine(next)) { tmpNode = next; next = tmpNode.nextSibling; if (isBr && (!next || next && !domUtils.isBr(next))) { break; } domUtils.remove(tmpNode); } } //去掉空行,保留占位的空行 if (opt.removeEmptyline && domUtils.inDoc(ci, cont) && $(ci).parents('td,blockquote,code,.todo-view,.callout-block').length == 0 && !$(ci).is('td,blockquote,code,.todo-view,.callout-block')) { if (domUtils.isBr(ci)) { next = ci.nextSibling; if (next && !domUtils.isBr(next)) { continue; } } domUtils.remove(ci); continue; } } if (isLine(ci, true) && (ci.tagName != 'SPAN' && ci.tagName != 'DIV')) { if (opt.indent) { ci.style.textIndent = opt.indentValue; } else { ci.style.textIndent = ''; } if (opt.textAlign) { ci.style.textAlign = opt.textAlign; } else { ci.style.textAlign = ''; } // if(opt.lineHeight) // ci.style.lineHeight = opt.lineHeight + 'cm'; } //去掉class,保留的class不去掉 // if(opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]){ // // if(highlightCont && highlightCont.contains(ci)){ // continue; // } // domUtils.removeAttributes(ci,['class']); // } //表情不处理 if (opt.imageBlockLine && ci.tagName.toLowerCase() == 'img' && !ci.getAttribute('emotion')) { if (html) { var img = ci; switch (opt.imageBlockLine) { case 'left': case 'right': case 'none': var pN = img.parentNode, tmpNode, pre, next; while (dtd.$inline[pN.tagName] || pN.tagName == 'A') { pN = pN.parentNode; } tmpNode = pN; if (tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode, 'text-align') == 'center') { if (!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function (node) { return !domUtils.isBr(node) && !domUtils.isWhitespace(node) }) == 1) { pre = tmpNode.previousSibling; next = tmpNode.nextSibling; if (pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)) { pre.appendChild(tmpNode.firstChild); while (next.firstChild) { pre.appendChild(next.firstChild); } domUtils.remove(tmpNode); domUtils.remove(next); } else { domUtils.setStyle(tmpNode, 'text-align', ''); } } } domUtils.setStyle(img, 'float', opt.imageBlockLine); break; case 'center': if (me.queryCommandValue('imagefloat') != 'center') { pN = img.parentNode; domUtils.setStyle(img, 'float', 'none'); tmpNode = img; while (pN && domUtils.getChildCount(pN, function (node) { return !domUtils.isBr(node) && !domUtils.isWhitespace(node) }) == 1 && (dtd.$inline[pN.tagName] || pN.tagName == 'A')) { tmpNode = pN; pN = pN.parentNode; } var pNode = me.document.createElement('p'); pNode.setAttribute('element-id', domUtils.getRandomId()) domUtils.setAttributes(pNode, { style: 'text-align:center' }); tmpNode.parentNode.insertBefore(pNode, tmpNode); pNode.appendChild(tmpNode); domUtils.setStyle(tmpNode, 'float', ''); } } } else { var range = me.selection.getRange(); range.selectNode(ci).select(); me.execCommand('imagefloat', opt.imageBlockLine); } } else if (opt.imageBlockLine == false) { me.execCommand('imagefloat', 'none'); } //去掉冗余的标签 if (opt.removeEmptyNode) { if (opt.removeTagNames[ci.tagName.toLowerCase()] && domUtils.hasNoAttributes(ci) && domUtils.isEmptyBlock(ci)) { domUtils.remove(ci); } } } if (opt.tobdc) { var root = UE.htmlparser(cont.innerHTML); root.traversal(function (node) { if (node.type == 'text') { node.data = ToDBC(node.data) } }); cont.innerHTML = root.toHtml() } if (opt.bdc2sb) { var root = UE.htmlparser(cont.innerHTML); root.traversal(function (node) { if (node.type == 'text') { node.data = DBC2SB(node.data) } }); cont.innerHTML = root.toHtml() } if (opt.blankTodbc) { var root = UE.htmlparser(cont.innerHTML); root.traversal(function (node) { if (node.type == 'text') { node.data = blankToDBC(node.data) } }); cont.innerHTML = root.toHtml() } if (html) { html.html = cont.innerHTML; } } if (opt.pasteFilter) { me.addListener('beforepaste', autotype); } //转换为半角 function DBC2SB(str) { var result = ''; for (var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); //获取当前字符的unicode编码 if (code >= 65281 && code <= 65373) //在这个unicode编码范围中的是所有的英文字母已经各种字符 { result += String.fromCharCode(str.charCodeAt(i) - 65248); //把全角字符的unicode编码转换为对应半角字符的unicode码 } else if (code == 12288) //空格 { result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32); } else { result += str.charAt(i); } } return result; } //转换为全角 function ToDBC(txtstring) { txtstring = utils.html(txtstring); var tmp = ""; var mark = ""; /*用于判断,如果是html尖括里的标记,则不进行全角的转换*/ for (var i = 0; i < txtstring.length; i++) { if (txtstring.charCodeAt(i) == 32) { tmp = tmp + String.fromCharCode(12288); } else if (txtstring.charCodeAt(i) < 127) { tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248); } else { tmp += txtstring.charAt(i); } } return tmp; } //只把空格转换为全角 function blankToDBC(str) { str = DBC2SB(str); str = str.replace(/ /gi, String.fromCharCode(12288)) return str; } function readLocalOpts() { var cookieOpt = me.getPreferences('autotypeset'); utils.extend(me.options.autotypeset, cookieOpt); } me.commands['autotypeset'] = { execCommand: function () { me.removeListener('beforepaste', autotype); if (opt.pasteFilter) { me.addListener('beforepaste', autotype); } autotype.call(me) } }; }; // plugins/autosubmit.js /** * 快捷键提交 * @file * @since 1.2.6.1 */ /** * 提交表单 * @command autosubmit * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'autosubmit' ); * ``` */ UE.plugin.register('autosubmit', function () { return { shortcutkey: { "autosubmit": "ctrl+13" //手动提交 }, commands: { 'autosubmit': { execCommand: function () { var me = this, form = domUtils.findParentByTagName(me.iframe, "form", false); if (form) { if (me.fireEvent("beforesubmit") === false) { return; } me.sync(); form.submit(); } } } } } }); // plugins/background.js /** * 背景插件,为UEditor提供设置背景功能 * @file * @since 1.2.6.1 */ UE.plugin.register('background', function () { var me = this, cssRuleId = 'editor_background', isSetColored, reg = new RegExp('body[\\s]*\\{(.+)\\}', 'i'); function stringToObj(str) { var obj = {}, styles = str.split(';'); utils.each(styles, function (v) { var index = v.indexOf(':'), key = utils.trim(v.substr(0, index)).toLowerCase(); key && (obj[key] = utils.trim(v.substr(index + 1) || '')); }); return obj; } function setBackground(obj) { if (obj) { var styles = []; for (var name in obj) { if (obj.hasOwnProperty(name)) { styles.push(name + ":" + obj[name] + '; '); } } utils.cssRule(cssRuleId, styles.length ? ('body{' + styles.join("") + '}') : '', me.document); } else { utils.cssRule(cssRuleId, '', me.document) } } //重写editor.hasContent方法 var orgFn = me.hasContents; me.hasContents = function () { if (me.queryCommandValue('background')) { return true } return orgFn.apply(me, arguments); }; return { bindEvents: { 'getAllHtml': function (type, headHtml) { var body = this.body, su = domUtils.getComputedStyle(body, "background-image"), url = ""; if (su.indexOf(me.options.imagePath) > 0) { url = su.substring(su.indexOf(me.options.imagePath), su.length - 1).replace(/"|\(|\)/ig, ""); } else { url = su != "none" ? su.replace(/url\("?|"?\)/ig, "") : ""; } var html = ' '; headHtml.push(html); }, 'aftersetcontent': function () { if (isSetColored == false) setBackground(); } }, inputRule: function (root) { isSetColored = false; utils.each(root.getNodesByTagName('p'), function (p) { var styles = p.getAttr('data-background'); if (styles) { isSetColored = true; setBackground(stringToObj(styles)); p.parentNode.removeChild(p); } }) }, outputRule: function (root) { var me = this, styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg); if (styles) { root.appendChild(UE.uNode.createElement('


    ')); } }, commands: { 'background': { execCommand: function (cmd, obj) { setBackground(obj); }, queryCommandValue: function () { var me = this, styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg); return styles ? stringToObj(styles[1]) : null; }, notNeedUndo: true } } } }); // plugins/image.js /** * 图片插入、排版插件 * @file * @since 1.2.6.1 */ /** * 图片对齐方式 * @command imagefloat * @method execCommand * @remind 值center为独占一行居中 * @param { String } cmd 命令字符串 * @param { String } align 对齐方式,可传left、right、none、center * @remaind center表示图片独占一行 * @example * ```javascript * editor.execCommand( 'imagefloat', 'center' ); * ``` */ /** * 如果选区所在位置是图片区域 * @command imagefloat * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回图片对齐方式 * @example * ```javascript * editor.queryCommandValue( 'imagefloat' ); * ``` */ UE.commands['imagefloat'] = { execCommand: function (cmd, align, imgIndex) { var me = this, range = me.selection.getRange(); if (imgIndex) { img = me.body.querySelectorAll('img')[imgIndex] } else 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(); } if (img.parentNode.className && img.parentNode.className.indexOf('editor-image') > -1) { domUtils.setStyle(img.parentNode, 'float', align == 'none' ? '' : align); domUtils.setStyle(img.parentNode, 'z-index', '1'); if (align == 'left') { domUtils.setStyle(img.parentNode, 'margin-right', '30px'); } else if (align == 'right') { domUtils.setStyle(img.parentNode, 'margin-left', '30px'); } else if (align == 'none') { domUtils.setStyle(img.parentNode, 'margin', ''); domUtils.removeAttributes(img.parentNode, 'align'); domUtils.setStyle(img.parentNode, 'z-index', ''); } } 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.setAttribute('element-id', domUtils.getRandomId()) pN.appendChild(tmpNode); domUtils.setStyle(tmpNode, 'float', ''); me.execCommand('insertHtml', '

    ' + pN.innerHTML + '

    '); tmpNode = me.document.getElementById('_img_parent_tmp'); tmpNode.removeAttribute('id'); tmpNode = tmpNode.firstChild; range.selectNode(tmpNode).select(); //去掉后边多余的元素 next = tmpNode.parentNode.nextSibling; if (next && domUtils.isEmptyNode(next)) { domUtils.remove(next); } } break; } } }, queryCommandValue: function () { var range = this.selection.getRange(), startNode, floatStyle; if (range.collapsed) { return 'none'; } startNode = range.getClosedNode(); if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') { floatStyle = domUtils.getComputedStyle(startNode, 'float') || startNode.getAttribute('align'); if (floatStyle == 'none') { floatStyle = domUtils.getComputedStyle(startNode.parentNode, 'text-align') == 'center' ? 'center' : floatStyle; } return { left: 1, right: 1, center: 1 }[floatStyle] ? floatStyle : 'none'; } return 'none'; }, queryCommandState: function () { var range = this.selection.getRange(), startNode; // if (range.collapsed) return -1; startNode = range.getClosedNode(); if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') { return 0; } return 1; } }; /** * 插入图片 * @command insertimage * @method execCommand * @param { String } cmd 命令字符串 * @param { Object } opt 属性键值对,这些属性都将被复制到当前插入图片 * @remind 该命令第二个参数可接受一个图片配置项对象的数组,可以插入多张图片, * 此时数组的每一个元素都是一个Object类型的图片属性集合。 * @example * ```javascript * editor.execCommand( 'insertimage', { * src:'a/b/c.jpg', * width:'100', * height:'100' * } ); * ``` * @example * ```javascript * editor.execCommand( 'insertimage', [{ * src:'a/b/c.jpg', * width:'100', * height:'100' * },{ * src:'a/b/d.jpg', * width:'100', * height:'100' * }] ); * ``` */ UE.commands['insertimage'] = { execCommand: function (cmd, opt) { opt = utils.isArray(opt) ? opt : [opt]; if (!opt.length) { return; } var me = this, range = me.selection.getRange(), img = range.getClosedNode(); if (me.fireEvent('beforeinsertimage', opt) === true) { return; } function unhtmlData(imgCi) { utils.each('width,height,border,hspace,vspace'.split(','), function (item) { if (imgCi[item]) { imgCi[item] = parseInt(imgCi[item], 10) || 0; } }); utils.each('src,_src'.split(','), function (item) { if (imgCi[item]) { imgCi[item] = utils.unhtmlForUrl(imgCi[item]); } }); utils.each('title,alt'.split(','), function (item) { if (imgCi[item]) { imgCi[item] = utils.unhtml(imgCi[item]); } }); } if (img && /img/i.test(img.tagName) && (img.className != "edui-faked-video" || img.className.indexOf("edui-upload-video") != -1) && !img.getAttribute("word_img")) { var first = opt.shift(); var floatStyle = first['floatStyle']; delete first['floatStyle']; //// img.style.border = (first.border||0) +"px solid #000"; //// img.style.margin = (first.margin||0) +"px"; // img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000"; domUtils.setAttributes(img, first); me.execCommand('imagefloat', floatStyle); if (opt.length > 0) { range.setStartAfter(img).setCursor(false, true); me.execCommand('insertimage', opt); } } else { var html = [], str = '', ci; ci = opt[0]; if (opt.length == 1) { unhtmlData(ci); /* str = '' + ci.alt + ''; if (ci['floatStyle'] == 'center') { str = '

    ' + str + '

    '; }*/ // 修改 if (ci) { str = '
    '; html.push(str); } } else { for (var i = 0; ci = opt[i++];) { unhtmlData(ci); /*str = '

    ';*/ // 修改 if (ci) { str = '
    '; html.push(str); } } } me.execCommand('insertHtml', html.join('')); // 添加图片后需要重置高度 if (me.autoHeightEnabled) { var imgList = me.body.querySelectorAll('img'); for (var i = 0; i < imgList.length; i++) { imgList[i].onload = function () { me.adjustHeight(); } } } } me.fireEvent('afterinsertimage', opt) } }; // plugins/justify.js /** * 段落格式 * @file * @since 1.2.6.1 */ /** * 段落对齐方式 * @command justify * @method execCommand * @param { String } cmd 命令字符串 * @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐 * @example * ```javascript * editor.execCommand( 'justify', 'center' ); * ``` */ /** * 如果选区所在位置是段落区域,返回当前段落对齐方式 * @command justify * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回段落对齐方式 * @example * ```javascript * editor.queryCommandValue( 'justify' ); * ``` */ UE.plugins['justify'] = function () { var me = this, block = domUtils.isBlockElm, defaultValue = { left: 1, right: 1, center: 1, justify: 1 }, doJustify = function (range, style) { var bookmark = range.createBookmark(), filterFn = function (node) { return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); }; //图片点居中时去掉四个角的方块 $('.edui-editor-imagescale').removeClass('scale'); range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode; while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { if (current.nodeType == 3 || !block(current)) { tmpRange.setStartBefore(current); while (current && current !== bookmark2.end && !block(current)) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !block(node); }); } tmpRange.setEndAfter(tmpNode); var common = tmpRange.getCommonAncestor(); if (!domUtils.isBody(common) && block(common)) { //支持图片左右对齐 if (common && common.className && common.className.indexOf('editor-image') > -1 && common.parentNode.className && common.parentNode.className.indexOf('drag-image-wrap') > -1 && common.parentNode.childNodes.length == 1) { common = common.parentNode; } domUtils.setStyles(common, utils.isString(style) ? { 'text-align': style } : style); current = common; } else { var p = range.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) domUtils.setStyles(p, utils.isString(style) ? { 'text-align': style } : style); var frag = tmpRange.extractContents(); p.appendChild(frag); tmpRange.insertNode(p); current = p; } current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } return range.moveToBookmark(bookmark2).moveToBookmark(bookmark); }; UE.commands['justify'] = { execCommand: function (cmdName, align, tmpRange) { var range = this.selection.getRange(), txt; //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange } //闭合时单独处理 if (range.collapsed) { txt = this.document.createTextNode('p'); range.insertNode(txt); } doJustify(range, align); if (txt) { range.setStartBefore(txt).collapse(true); domUtils.remove(txt); } if (!tmpRange) { range.select(); } return true; }, queryCommandValue: function () { var startNode = this.selection.getStart(), value = domUtils.getComputedStyle(startNode, 'text-align'); return defaultValue[value] ? value : 'left'; }, queryCommandState: function () { return 0; // var start = this.selection.getStart(), // cell = start && domUtils.findParentByTagName(start, ["td", "th","caption"], true); // // return cell? -1:0; } }; }; // plugins/font.js /** * 字体颜色,背景色,字号,字体 * @file * @since 1.2.6.1 */ /** * 字体颜色 * @command forecolor * @method execCommand * @param { String } cmd 命令字符串 * @param { String } value 色值(必须十六进制) * @example * ```javascript * editor.execCommand( 'forecolor', '#000' ); * ``` */ /** * 返回选区字体颜色 * @command forecolor * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回字体颜色 * @example * ```javascript * editor.queryCommandValue( 'forecolor' ); * ``` */ /** * 字体背景颜色 * @command backcolor * @method execCommand * @param { String } cmd 命令字符串 * @param { String } value 色值(必须十六进制) * @example * ```javascript * editor.execCommand( 'backcolor', '#000' ); * ``` */ /** * 返回选区字体颜色 * @command backcolor * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回字体背景颜色 * @example * ```javascript * editor.queryCommandValue( 'backcolor' ); * ``` */ /** * 字体大小 * @command fontsize * @method execCommand * @param { String } cmd 命令字符串 * @param { String } value 字体大小 * @example * ```javascript * editor.execCommand( 'fontsize', '14px' ); * ``` */ /** * 返回选区字体大小 * @command fontsize * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回字体大小 * @example * ```javascript * editor.queryCommandValue( 'fontsize' ); * ``` */ /** * 字体样式 * @command fontfamily * @method execCommand * @param { String } cmd 命令字符串 * @param { String } value 字体样式 * @example * ```javascript * editor.execCommand( 'fontfamily', '微软雅黑' ); * ``` */ /** * 返回选区字体样式 * @command fontfamily * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回字体样式 * @example * ```javascript * editor.queryCommandValue( 'fontfamily' ); * ``` */ /** * 字体下划线,与删除线互斥 * @command underline * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'underline' ); * ``` */ UE.plugins['font'] = function () { var me = this, fonts = { 'forecolor': 'color', 'backcolor': 'background-color', 'fontsize': 'font-size', 'fontfamily': 'font-family', // 'underline': 'text-decoration', // 'strikethrough': 'text-decoration', 'fontborder': 'border' }, needCmd = { 'underline': 1, 'strikethrough': 1, 'fontborder': 1, 'forecolor': 1, 'backcolor': 1 }, needSetChild = { 'forecolor': 'color', 'backcolor': 'background-color', 'fontsize': 'font-size', 'fontfamily': 'font-family' }; me.setOpt({ 'fontfamily': [{ name: 'defaultfont', val: 'CXHackSafariFont,CXEmojiFont,CXChineseQuote,-apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Tahoma, Arial, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"' }, { name: 'yahei', val: '微软雅黑,Microsoft YaHei' }, { name: 'songti', val: '宋体,SimSun,STSong' }, { name: 'fangsong', val: '仿宋,FangSong' }, { name: 'kaiti', val: '楷体,楷体_GB2312, SimKai' }, { name: 'heiti', val: '黑体, SimHei' }, { name: 'arial', val: 'arial, helvetica,sans-serif' }, // { name: 'lishu', val: '隶书, SimLi'}, // { name: 'andaleMono', val: 'andale mono'}, // { name: 'arialBlack', val: 'arial black,avant garde'}, // { name: 'comicSansMs', val: 'comic sans ms'}, // { name: 'impact', val: 'impact,chicago'}, { name: 'timesNewRoman', val: 'Times New Roman'}, { name:'symbol', val:'symbol'} ], 'fontsize': [9, 12, 14, 16, 18, 22, 26, 30, 36, 42] }); function mergeWithParent(node) { var parent; while (parent = node.parentNode) { //20200513 classname带todo的不处理 解决多选框设置字体删除框 if (parent.tagName == 'SPAN' && !(node.className && node.className.indexOf('todo') != -1) && domUtils.getChildCount(parent, function (child) { return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child) }) == 1) { parent.id = node.id; parent.style.cssText += node.style.cssText; domUtils.remove(node, true); node = parent; } else { break; } } } function mergeChild(rng, cmdName, value) { if (needSetChild[cmdName]) { rng.adjustmentBoundary(); if (!rng.collapsed && rng.startContainer.nodeType == 1) { var start = rng.startContainer.childNodes[rng.startOffset]; if (start && domUtils.isTagNode(start, 'span')) { var bk = rng.createBookmark(); utils.each(domUtils.getElementsByTagName(start, 'span'), function (span) { if (!span.parentNode || domUtils.isBookmarkNode(span)) return; if (cmdName == 'backcolor' && domUtils.getComputedStyle(span, 'background-color').toLowerCase() === value) { return; } // 注释原因: 设置字体大小删除线后 第一行文字设置颜色失效 https://16q.cn/Linsh9 // domUtils.removeStyle(span, needSetChild[cmdName]); if (span.style.cssText.replace(/^\s+$/, '').length == 0) { domUtils.remove(span, true) } }); rng.moveToBookmark(bk) } } } } function mergesibling(rng, cmdName, value) { var collapsed = rng.collapsed, bk = rng.createBookmark(), common; if (collapsed) { common = bk.start.parentNode; while (dtd.$inline[common.tagName]) { common = common.parentNode; } } else { common = domUtils.getCommonAncestor(bk.start, bk.end); } utils.each(domUtils.getElementsByTagName(common, 'span'), function (span) { if (!span.parentNode || domUtils.isBookmarkNode(span)) return; if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) { if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) { domUtils.remove(span, true); } else { domUtils.removeStyle(span, 'border'); } return } if (/border/i.test(span.style.cssText) && span.parentNode.tagName == 'SPAN' && /border/i.test(span.parentNode.style.cssText)) { span.style.cssText = span.style.cssText.replace(/border[^:]*:[^;]+;?/gi, ''); } if (!(cmdName == 'fontborder' && value == 'none')) { var next = span.nextSibling; while (next && next.nodeType == 1 && next.tagName == 'SPAN') { if (domUtils.isBookmarkNode(next) && cmdName == 'fontborder') { span.appendChild(next); next = span.nextSibling; continue; } if (next.style.cssText == span.style.cssText) { domUtils.moveChild(next, span); domUtils.remove(next); } if (span.nextSibling === next) break; next = span.nextSibling; } } mergeWithParent(span); if (browser.ie && browser.version > 8) { //拷贝父亲们的特别的属性,这里只做背景颜色的处理 var parent = domUtils.findParent(span, function (n) { return n.tagName == 'SPAN' && /background-color/.test(n.style.cssText) }); if (parent && !/background-color/.test(span.style.cssText)) { span.style.backgroundColor = parent.style.backgroundColor; } } }); rng.moveToBookmark(bk); mergeChild(rng, cmdName, value) } me.addInputRule(function (root) { utils.each(root.getNodesByTagName('font'), function (node) { if (node.tagName == 'font') { var cssStyle = []; for (var p in node.attrs) { switch (p) { case 'size': cssStyle.push('font-size:' + ({ '1': '10', '2': '12', '3': '16', '4': '18', '5': '24', '6': '32', '7': '48' }[node.attrs[p]] || node.attrs[p]) + 'px'); break; case 'color': cssStyle.push('color:' + node.attrs[p]); break; case 'face': cssStyle.push('font-family:' + node.attrs[p]); break; case 'style': cssStyle.push(node.attrs[p]); } } node.attrs = { 'style': cssStyle.join(';') }; } else { var val = node.tagName == 'u' ? 'underline' : 'line-through'; node.attrs = { 'style': (node.getAttr('style') || '') + 'text-decoration:' + val + ';' } } node.tagName = 'span'; }); }); for (var p in fonts) { (function (cmd, style) { UE.commands[cmd] = { execCommand: function (cmdName, value, tmpRange) { // value = value || (this.queryCommandState(cmdName) ? 'none' : cmdName == 'underline' ? 'underline' : // cmdName == 'fontborder' ? '1px solid #000' : // 'line-through'); value = value || ''; var me = this, range = this.selection.getRange(), text; //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange } if (value == 'default') { if (range.collapsed) { text = me.document.createTextNode('font'); range.insertNode(text).select(); } else { range.enlarge(); } me.execCommand('removeFormat', 'span,a,strong,em,b,i', style, null, null, range); if (text) { range.setStartBefore(text).collapse(true); domUtils.remove(text); } mergesibling(range, cmdName, value); range.select(); } else { if (!range.collapsed) { // needCmd[cmd] && 注释原因:内层有不同字体大小时,全选改变字体不生效 if (me.queryCommandValue(cmd)) { var sibNode = me.execCommand('removeFormat', 'span,a,strong,em,b,i', style, null, null, range); } range.applyInlineStyle('span', { 'style': style + ':' + value }); if (sibNode) { domUtils.clearEmptySibling(sibNode); } //20201113 设完首行缩进再改变字体大小缩进跟着改变 if (style == 'font-size') { var pN = domUtils.findParentByTagName(range.startContainer, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div'], true); if (pN && pN.style.textIndent) { var nowIndent = pN.style.textIndent; if (nowIndent != '' && parseInt(nowIndent.substr(0, nowIndent.length - 2)) > 0) { var node = pN; var fontsize; if (pN.tagName == "H1") { fontsize = 20; } else if (pN.tagName == "H2") { fontsize = 17; } else { fontsize = 14; } //找到第一个字的fontsize while (node.firstChild) { if (node.firstChild.innerText && node.firstChild.innerText.trim() == '') { if (node.nextSibling) { node = node.nextSibling; } else { break; } } else if (node.firstChild.nodeType == 1) { if (node.firstChild.style.fontSize && node.firstChild.style.fontSize != '') { fontsize = node.firstChild.style.fontSize.replace('px', ''); } node = node.firstChild; } else if (node.firstChild.nodeType == 3) { if (node.firstChild.nodeValue.trim() == '') { node = node.nextSibling; } else { break; } } } pN.style.textIndent = fontsize * 2 + 'px'; } } } // 以列表开头和以列表结尾的,给列表序号加颜色,中间是列表的加不上 if (style != 'background-color') { var li = domUtils.findParentByTagName(range.startContainer, 'li', true); var lastli = domUtils.findParentByTagName(range.endContainer, 'li', true); var cssText = style + ':' + value; //20200312选中一行列表格式前面文字设置颜色后,其他文字颜色也跟着变了 //给li下的元素添加默认颜色和字体 if (sibNode && li) { for (var i = 0; i < li.childNodes.length; i++) { if (li.childNodes[i].nodeType == 1) { switch (style) { case 'color': if (!li.childNodes[i].style.color) { li.childNodes[i].style.cssText += 'color:#333333'; } break; case 'font-size': if (!li.childNodes[i].style.fontSize) { li.childNodes[i].style.cssText += 'font-size:' + $(me.body).css('font-size'); } break; case 'font-family': // if(!li.childNodes[i].style.fontFamily) { // li.childNodes[i].style.cssText += 'font-family:微软雅黑, 黑体, Arial, Helvetica, sans-serif'; // }else{ li.childNodes[i].style.fontFamily = value; // } break; default: break; } } } } if (range.startContainer.nodeType == 1 && range.startContainer.tagName == 'BODY' && range.startContainer == range.endContainer) { //全选点击面板时range区域改变,不能使用下面方法 var list = range.startContainer.getElementsByTagName('li'); for (var i = 0; i < list.length; i++) { list[i].style.cssText += cssText; } } if (li) { if (li.firstChild && li.firstChild.firstChild && li.firstChild.firstChild.nodeType == 1) { while (li.firstChild.firstChild) { if (li.firstChild.firstChild.innerHTML == "​" || li.firstChild.firstChild.innerHTML == "") { domUtils.remove(li.firstChild.firstChild) } else { break; } } li.style.cssText = cssText; li.style.backgroundColor = ''; } if (lastli) { //第一个是li,最后一个是li //是在同一个列表下 while (li != lastli && li.nextSibling) { li = li.nextSibling; li.style.cssText += cssText; li.style.fontFamily = value; } //不同列表下 while (li != lastli && lastli) { lastli.style.cssText += cssText; lastli.style.fontFamily = value; lastli = lastli.previousSibling; } li.style.fontFamily = value; } else { //第一个是li,最后一个不是li // while(li.nextSibling){ // li=li.nextSibling; // li.style.cssText+=cssText; // } } } else if (lastli) { //第一个不是li,最后一个是li while (lastli) { lastli.style.cssText += cssText; lastli.style.fontFamily = value; lastli = lastli.previousSibling; } } } mergesibling(range, cmdName, value); range.select(); me.normalList(); } else { var span = domUtils.findParentByTagName(range.startContainer, 'span', true); text = me.document.createTextNode('font'); if (span && !span.children.length && !span[browser.ie ? 'innerText' : 'textContent'].replace(fillCharReg, '').length) { //for ie hack when enter range.insertNode(text); /*if (needCmd[cmd]) { range.selectNode(text).select(); me.execCommand('removeFormat', 'span,a', style, null); span = domUtils.findParentByTagName(text, 'span', true); range.setStartBefore(text); }*/ span && (span.style.cssText += ';' + style + ':' + value); range.collapse(true).select(); } else { range.insertNode(text); range.selectNode(text).select(); span = range.document.createElement('span'); var sibnode; if (needCmd[cmd]) { //a标签内的不处理跳过 if (domUtils.findParentByTagName(text, 'a', true)) { range.setStartBefore(text).setCursor(); domUtils.remove(text); return; } sibnode = me.execCommand('removeFormat', 'span,a', style, null, null, range); } if (sibnode) { domUtils.clearEmptySibling(sibnode); } span.style.cssText = style + ':' + value; if ((cmd == 'forecolor' || cmd == 'backcolor') && sibnode && sibnode.parentNode) { sibnode.parentNode.insertBefore(span, sibnode); span.appendChild(sibnode); } else { text.parentNode.insertBefore(span, text); } //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; } } while (span.firstChild) { span = span.firstChild; } if (opera) { setTimeout(function () { range.setStart(span, 0).collapse(true); mergesibling(range, cmdName, value); range.select(); }); } else { range.setStart(span, 0).collapse(true); mergesibling(range, cmdName, value); range.select(); } //trace:981 //domUtils.mergeToParent(span) } me.normalList(); var li = domUtils.findParentByTagName(text, 'li', true); if (li) { while (li.firstChild) { while (li.firstChild.firstChild) { if (li.firstChild.firstChild.nodeType == 3 && li.firstChild.firstChild.innerHTML == domUtils.fillChar || li.firstChild.firstChild.innerHTML == "") { domUtils.remove(li.firstChild.firstChild) } else { break; } } if (!li.firstChild.firstChild || li.firstChild.innerHTML == "") { domUtils.remove(li.firstChild); } else { break; } } if (li.firstChild && li.firstChild.firstChild && li.firstChild.firstChild.nodeType == 1 && li.firstChild.firstChild.innerHTML != "​") { li.style.cssText += li.firstChild.firstChild.style.cssText; li.style.backgroundColor = ''; } } domUtils.remove(text); } } return true; }, queryCommandValue: function (cmdName) { var startNode = this.selection.getStart(); if (cmdName == 'underline' || cmdName == 'strikethrough' || cmdName == 'emphasize') { var tmpNode = startNode, value; while (tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(tmpNode)) { if (tmpNode.nodeType == 1) { value = domUtils.getComputedStyle(tmpNode, style); if (value != 'none') { return value; } } tmpNode = tmpNode.parentNode; } return 'none'; } if (cmdName == 'fontborder') { var tmp = startNode, val; while (tmp && dtd.$inline[tmp.tagName]) { if (val = domUtils.getComputedStyle(tmp, 'border')) { if (/1px/.test(val) && /solid/.test(val)) { return val; } } tmp = tmp.parentNode; } return '' } if (cmdName == 'FontSize') { var styleVal = domUtils.getComputedStyle(startNode, style), tmp = /^([\d\.]+)(\w+)$/.exec(styleVal); if (tmp) { return Math.floor(tmp[1]) + tmp[2]; } return styleVal; } return domUtils.getComputedStyle(startNode, style); }, queryCommandState: function (cmdName) { if (!needCmd[cmdName]) return 0; var val = this.queryCommandValue(cmdName); if (cmdName == 'fontborder') { return /1px/.test(val) && /solid/.test(val) } else { return cmdName == 'underline' ? /underline/.test(val) : /line\-through/.test(val); } } }; })(p, fonts[p]); } }; // plugins/link.js /** * 超链接 * @file * @since 1.2.6.1 */ /** * 插入超链接 * @command link * @method execCommand * @param { String } cmd 命令字符串 * @param { Object } options 设置自定义属性,例如:url、title、target * @example * ```javascript * editor.execCommand( 'link', '{ * url:'ueditor.baidu.com', * title:'ueditor', * target:'_blank' * }' ); * ``` */ /** * 返回当前选中的第一个超链接节点 * @command link * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { Element } 超链接节点 * @example * ```javascript * editor.queryCommandValue( 'link' ); * ``` */ /** * 取消超链接 * @command unlink * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'unlink'); * ``` */ UE.plugins['link'] = function () { var me = this; me.options.imagePopup = false; function optimize(range) { var start = range.startContainer, end = range.endContainer; if (start = domUtils.findParentByTagName(start, 'a', true)) { range.setStartBefore(start); } if (end = domUtils.findParentByTagName(end, 'a', true)) { range.setEndAfter(end); } } UE.commands['unlink'] = { execCommand: function () { var range = this.selection.getRange(), bookmark; if (range.collapsed && !domUtils.findParentByTagName(range.startContainer, 'a', true)) { return; } bookmark = range.createBookmark(); optimize(range); range.removeInlineStyle('a').moveToBookmark(bookmark).select(); }, queryCommandState: function () { return !this.highlight && this.queryCommandValue('link') ? 0 : -1; } }; function doLink(range, opt, me) { var rngClone = range.cloneRange(), link = me.queryCommandValue('link'); optimize(range = range.adjustmentBoundary()); var start = range.startContainer; if (start.nodeType == 1 && link) { start = start.childNodes[range.startOffset]; if (start && start.nodeType == 1 && start.tagName == 'A' && /^(?:https?|ftp|file)\s*:\s*\/\//.test(start[browser.ie ? 'innerText' : 'textContent'])) { start[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue || opt.href); } } if (!rngClone.collapsed) { rngClone.collapse(false); } var linktitle = ''; if (opt.textValue) { linktitle = opt.textValue } var logo = ''; if (opt.logo) { logo = opt.logo } var cid; if (!(typeof (RichTextUitl) == "undefined")) { cid = RichTextUitl.randomUUID(); } var json = { "att_web": { "content": "", "logo": logo, "showContent": 0, "title": linktitle, "url": opt.href }, "attachmentType": 25, "cid": cid } var requestUrl = (RichTextUitl.getLinkCoverUrl || RichTextUitl.convertUrl("https://noteyd.chaoxing.com/pc/resource/getLinkCover")) + "?url=" + encodeURIComponent(opt.href); var webPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/'; if(RichTextUitl.intranetMode){ webPrefix = RichTextUitl.prefix } if (RichTextUitl.intranetMode && !RichTextUitl.getLinkCoverUrl) { if (!linktitle) { json.att_web.title = "无标题链接"; } var divelementid = domUtils.getRandomId(); var html = "
    " me.sendhtml(html); me.execCommand('insertHtml', html); return; } $.ajax({ url: requestUrl, type: "get", xhrFields: { withCredentials: true }, success: function (resultData) { if (resultData && resultData.result == 1) { var data = resultData.msg; if (data) { if (!linktitle) { // 没有设置标题,采用抓取的网页的,网页没有标题,则采用 无标题链接 json.att_web.title = data.title || "无标题链接"; } // 如果是默认图标,采用抓取的网页的logo,网页没有logo,则采用默认的logo if (opt.logo.includes('iconLink.png') && data.imgUrl) { json.att_web.logo = data.imgUrl; } } } else { if (!linktitle) { json.att_web.title = "无标题链接"; } } //20200605 插入链接后发送协同数据 var divelementid = domUtils.getRandomId(); var html = "
    " me.sendhtml(html); me.execCommand('insertHtml', html); }, error: function (xhr, textStatus, errorThrown) { //20200605 插入链接后发送协同数据 if (!linktitle) { json.att_web.title = "无标题链接"; } var divelementid = domUtils.getRandomId(); var html = "
    " me.sendhtml(html); me.execCommand('insertHtml', html); } }); } UE.commands['link'] = { execCommand: function (cmdName, opt) { var range; opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g)); opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g)); opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g)); doLink(range = this.selection.getRange(), opt, this); //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题 range.collapse().select(true); }, queryCommandValue: function () { var range = this.selection.getRange(), node; if (range.collapsed) { node = range.startContainer; node = node.nodeType == 1 ? node : node.parentNode; if (node && (node = domUtils.findParentByTagName(node, 'a', true)) && !domUtils.isInNodeEndBoundary(range, node)) { return node; } } else { //trace:1111 如果是

    xx

    startContainer是p就会找不到a range.shrinkBoundary(); var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[range.startOffset] ? range.startContainer : range.startContainer.childNodes[range.startOffset], end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range.endContainer : range.endContainer.childNodes[range.endOffset - 1], common = range.getCommonAncestor(); node = domUtils.findParentByTagName(common, 'a', true); if (!node && common.nodeType == 1) { var as = common.getElementsByTagName('a'), ps, pe; for (var i = 0, ci; ci = as[i++];) { ps = domUtils.getPosition(ci, start), pe = domUtils.getPosition(ci, end); if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS) && (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS) ) { node = ci; break; } } } return node; } }, queryCommandState: function () { //判断如果是视频的话连接不可用 //fix 853 var img = this.selection.getRange().getClosedNode(), flag = img && (img.className == "edui-faked-video" || img.className.indexOf("edui-upload-video") != -1); return flag ? -1 : 0; } }; //20200609 文本超链接 function doTextLink(range, opt, me) { var rngClone = range.cloneRange(), link = me.queryCommandValue('link'); optimize(range = range.adjustmentBoundary()); var start = range.startContainer; if (start.nodeType == 1 && link) { start = start.childNodes[range.startOffset]; if (start && start.nodeType == 1 && start.tagName == 'A' && /^(?:https?|ftp|file)\s*:\s*\/\//.test(start[browser.ie ? 'innerText' : 'textContent'])) { start[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue || opt.href); } } if (!rngClone.collapsed || link) { range.removeInlineStyle('a'); rngClone = range.cloneRange(); } opt.class = 'dynacALink'; if (rngClone.collapsed) { var a = range.document.createElement('a'), text = ''; if (opt.textValue) { text = utils.html(opt.textValue); delete opt.textValue; } else { text = utils.html(opt.href); } domUtils.setAttributes(a, opt); start = domUtils.findParentByTagName(rngClone.startContainer, 'a', true); if (start && domUtils.isInNodeEndBoundary(rngClone, start)) { range.setStartAfter(start).collapse(true); } a[browser.ie ? 'innerText' : 'textContent'] = text; range.insertNode(a).selectNode(a); } else { range.applyInlineStyle('a', opt); } } UE.commands['textlink'] = { execCommand: function (cmdName, opt) { var range; opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g)); opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g)); opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g)); doTextLink(range = this.selection.getRange(), opt, this); //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题 range.collapse().select(true); }, queryCommandValue: function () { var range = this.selection.getRange(), node; if (range.collapsed) { node = range.startContainer; node = node.nodeType == 1 ? node : node.parentNode; if (node && (node = domUtils.findParentByTagName(node, 'a', true)) && !domUtils.isInNodeEndBoundary(range, node)) { return node; } } else { //trace:1111 如果是

    xx

    startContainer是p就会找不到a range.shrinkBoundary(); var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[range.startOffset] ? range.startContainer : range.startContainer.childNodes[range.startOffset], end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range.endContainer : range.endContainer.childNodes[range.endOffset - 1], common = range.getCommonAncestor(); node = domUtils.findParentByTagName(common, 'a', true); if (!node && common.nodeType == 1) { var as = common.getElementsByTagName('a'), ps, pe; for (var i = 0, ci; ci = as[i++];) { ps = domUtils.getPosition(ci, start), pe = domUtils.getPosition(ci, end); if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS) && (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS) ) { node = ci; break; } } } return node; } }, queryCommandState: function () { //判断如果是视频的话连接不可用 //fix 853 var img = this.selection.getRange().getClosedNode(), flag = img && (img.className == "edui-faked-video" || img.className.indexOf("edui-upload-video") != -1); return flag ? -1 : 0; } }; }; // plugins/iframe.js ///import core ///import plugins\inserthtml.js ///commands 插入框架 ///commandsName InsertFrame ///commandsTitle 插入Iframe ///commandsDialog dialogs\insertframe UE.plugins['insertframe'] = function () { var me = this; me.commands['insertframe'] = { execCommand: function (cmdName, data) { var iframesrc = data.iframeUrl, iframeWidth = data.width, iframeHeight = data.height; var cid = RichTextUitl.randomUUID(); var json = { "att_web": { "content": "", "logo": "", "showContent": 0, "title": "网页预览链接", "url": iframesrc }, "attachmentType": 25, "cid": cid } var iframename = RichTextUitl.b64EncodeUnicode(JSON.stringify(json)); me.execCommand('insertHtml', "
    "); } } function deleteIframe() { me._iframe && delete me._iframe; } me.addListener("selectionchange", function () { deleteIframe(); }); }; // plugins/removeformat.js /** * 清除格式 * @file * @since 1.2.6.1 */ /** * 清除文字样式 * @command removeformat * @method execCommand * @param { String } cmd 命令字符串 * @param {String} tags 以逗号隔开的标签。如:strong * @param {String} style 样式如:color * @param {String} attrs 属性如:width * @example * ```javascript * editor.execCommand( 'removeformat', 'strong','color','width' ); * ``` */ UE.plugins['removeformat'] = function () { var me = this; me.setOpt({ 'removeFormatTags': 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var,a', 'removeFormatAttributes': 'style,lang,width,height,align,hspace,valign' }); me.commands['removeformat'] = { execCommand: function (cmdName, tags, style, attrs, notIncludeA, tmpRange) { var tagReg = new RegExp('^(?:' + (tags || this.options.removeFormatTags).replace(/,/g, '|') + ')$', 'i'), removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes).split(','), range = new dom.Range(this.document), bookmark, node, parent, filter = function (node) { return node.nodeType == 1; }; function isRedundantSpan(node) { if (node.nodeType == 3 || node.tagName.toLowerCase() != 'span') { return 0; } if (browser.ie) { //ie 下判断实效,所以只能简单用style来判断 //return node.style.cssText == '' ? 1 : 0; var attrs = node.attributes; if (attrs.length) { for (var i = 0, l = attrs.length; i < l; i++) { if (attrs[i].specified) { return 0; } } return 1; } } return !node.attributes.length; } function doRemove(range) { var bookmark1 = range.createBookmark(); if (range.collapsed) { range.enlarge(true); } //不能把a标签切了 // if (!notIncludeA) { // var aNode = domUtils.findParentByTagName(range.startContainer, 'a', true); // if (aNode) { // range.setStartBefore(aNode); // } // aNode = domUtils.findParentByTagName(range.endContainer, 'a', true); // if (aNode) { // range.setEndAfter(aNode); // } // } bookmark = range.createBookmark(); node = bookmark.start; //切开始 while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) { domUtils.breakParent(node, parent); domUtils.clearEmptySibling(node); } if (bookmark.end) { //切结束 node = bookmark.end; while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) { domUtils.breakParent(node, parent); domUtils.clearEmptySibling(node); } //开始去除样式 var current = domUtils.getNextDomNode(bookmark.start, false, filter), next; while (current) { if (current == bookmark.end) { break; } next = domUtils.getNextDomNode(current, true, filter); if (!dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode(current)) { if (tagReg.test(current.tagName)) { if (style) { domUtils.removeStyle(current, style); if (isRedundantSpan(current) && style != 'text-decoration') { domUtils.remove(current, true); } } else { domUtils.remove(current, true); } } else { //解决格式刷刷链接样式不生效 //清除格式时去除表格上的样式 if (!style && dtd.$tableContent[current.tagName] || current.tagName == 'A') { current.removeAttribute('style'); } //trace:939 不能把list上的样式去掉 //2022-2-18 列表下修改字体为默认字体不成功,去除了& dtd.$list[current.tagName] if (!dtd.$tableContent[current.tagName]) { if (dtd.$listItem[current.tagName] && style) { //删除li上的font-family domUtils.removeStyle(current, style); } var pNodes = ['p','h1','h2','h3','h4','h5','h6'] if (!style && pNodes.indexOf(current.tagName.toLowerCase()) > -1) { var textIndent = current.style.textIndent; var textAlign = current.style.textAlign; domUtils.removeAttributes(current, removeFormatAttributes); current.style.textIndent = textIndent; current.style.textAlign = textAlign; }else{ domUtils.removeAttributes(current, removeFormatAttributes); } if (isRedundantSpan(current)) { domUtils.remove(current, true); } } } } current = next; } } var siblingNode = node.previousSibling; //trace:1035 //trace:1096 不能把td上的样式去掉,比如边框 var pN = bookmark.start.parentNode; if (domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) { domUtils.removeAttributes(pN, removeFormatAttributes); } pN = bookmark.end.parentNode; if (bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) { domUtils.removeAttributes(pN, removeFormatAttributes); } range.moveToBookmark(bookmark).moveToBookmark(bookmark1); //清除冗余的代码 var node = range.startContainer, tmp, collapsed = range.collapsed; while (node.nodeType == 1 && domUtils.isNodeEmpty(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; // if(tmp.children && tmp.children.length > 1 && node.nodeName.toLowerCase() == 'br') { range.setEndBefore(node); domUtils.remove(node); // } node = tmp; } } return siblingNode; } //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange } else { range = this.selection.getRange(); } var siblingNode = doRemove(range); if (!tmpRange) { range.select(); } return siblingNode; } }; }; // plugins/blockquote.js /** * 添加引用 * @file * @since 1.2.6.1 */ /** * 添加引用 * @command blockquote * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'blockquote' ); * ``` */ /** * 添加引用 * @command blockquote * @method execCommand * @param { String } cmd 命令字符串 * @param { Object } attrs 节点属性 * @example * ```javascript * editor.execCommand( 'blockquote',{ * style: "color: red;" * } ); * ``` */ UE.plugins['blockquote'] = function () { var me = this; function getObj(editor) { return domUtils.filterNodeList(editor.selection.getStartElementPath(), 'blockquote'); } me.commands['blockquote'] = { execCommand: function (cmdName, attrs, tempRange) { var range = this.selection.getRange(), obj = getObj(this), blockquote = dtd.blockquote, bookmark = range.createBookmark(); //20200619 tmpRange是协同恢复的时候用的range if (tempRange) { range = tempRange } if (obj) { var start = range.startContainer, startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start, function (node) { return domUtils.isBlockElm(node) }), end = range.endContainer, endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end, function (node) { return domUtils.isBlockElm(node) }); //处理一下li startBlock = domUtils.findParentByTagName(startBlock, 'li', true) || startBlock; endBlock = domUtils.findParentByTagName(endBlock, 'li', true) || endBlock; if (startBlock.tagName == 'LI' || startBlock.tagName == 'TD' || startBlock === obj || domUtils.isBody(startBlock)) { domUtils.remove(obj, true); } else { domUtils.breakParent(startBlock, obj); } if (startBlock !== endBlock) { obj = domUtils.findParentByTagName(endBlock, 'blockquote'); if (obj) { if (endBlock.tagName == 'LI' || endBlock.tagName == 'TD' || domUtils.isBody(endBlock)) { obj.parentNode && domUtils.remove(obj, true); } else { domUtils.breakParent(endBlock, obj); } } } var blockquotes = domUtils.getElementsByTagName(this.document, 'blockquote'); for (var i = 0, bi; bi = blockquotes[i++];) { if (!bi.childNodes.length) { domUtils.remove(bi); } else if (domUtils.getPosition(bi, startBlock) & domUtils.POSITION_FOLLOWING && domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING) { domUtils.remove(bi, true); } } } else { var tmpRange = range.cloneRange(), node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode, preNode = node, doEnd = 1; //调整开始 while (1) { if (domUtils.isBody(node) || $(node).is('.classConBefore') || $(node).is('td') || $(node).is('th') || $(node).is('.callout-text')) { if (preNode !== node) { if (range.collapsed) { tmpRange.selectNode(preNode); doEnd = 0; } else { tmpRange.setStartBefore(preNode); } } else { tmpRange.setStart(node, 0); } break; } if (!blockquote[node.tagName]) { if (range.collapsed) { tmpRange.selectNode(preNode); } else { tmpRange.setStartBefore(preNode); } break; } preNode = node; node = node.parentNode; } //调整结束 if (doEnd) { preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode; while (1) { if (domUtils.isBody(node)) { if (preNode !== node) { tmpRange.setEndAfter(preNode); } else { tmpRange.setEnd(node, node.childNodes.length); } break; } if (!blockquote[node.tagName]) { tmpRange.setEndAfter(preNode); break; } preNode = node; node = node.parentNode; } } node = range.document.createElement('blockquote'); domUtils.setAttributes(node, attrs); node.appendChild(tmpRange.extractContents()); tmpRange.insertNode(node); //去除重复的 var childs = domUtils.getElementsByTagName(node, 'blockquote'); for (var i = 0, ci; ci = childs[i++];) { if (ci.parentNode) { domUtils.remove(ci, true); } } } if (!tempRange) { range.moveToBookmark(bookmark).select(); } else { range.moveToBookmark(bookmark); } }, queryCommandState: function () { return getObj(this) ? 1 : 0; } }; }; //高亮块 callout.js UE.plugins['callout'] = function () { var me = this; function getObj(editor) { return domUtils.filterNodeList(editor.selection.getStartElementPath(), function (n) { return n && n.nodeType == 1 && n.getAttribute('class') && n.getAttribute('class').indexOf('callout-block') > -1 }); } me.commands['callout'] = { execCommand: function (cmdName, attrs, tempRange) { var range = this.selection.getRange(), obj = getObj(this), // blockquote = dtd.blockquote, bookmark = range.createBookmark(); //20200619 tmpRange是协同恢复的时候用的range if (tempRange) { range = tempRange } if (obj) { //取消高亮块 var bookmark = range.createBookmark(); domUtils.remove(obj.querySelector('.callout-icon')); domUtils.remove(obj.querySelector('.callout-text'), true); domUtils.remove(obj, true); range.moveToBookmark(bookmark).select(); me.fireEvent('contentchange'); me.fireEvent('saveScene'); return; } else { var tmpRange = range.cloneRange(), node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode, preNode = node, doEnd = 1; //调整开始 while (1) { if (domUtils.isBody(node) || $(node).is('.classConBefore') || $(node).is('td') || $(node).is('th') || $(node).is('blockquote')) { if (preNode !== node) { if (range.collapsed) { tmpRange.selectNode(preNode); doEnd = 0; } else { tmpRange.setStartBefore(preNode); } } else { tmpRange.setStart(node, 0); } break; } preNode = node; node = node.parentNode; } //调整结束 if (doEnd) { preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode; while (1) { if (domUtils.isBody(node)) { if (preNode !== node) { tmpRange.setEndAfter(preNode); } else { tmpRange.setEnd(node, node.childNodes.length); } break; } preNode = node; node = node.parentNode; } } var calloutText = document.createElement('div'); calloutText.className = 'callout-text'; calloutText.appendChild(tmpRange.extractContents()); if ($(calloutText).find('callout-block').length > 0) { return; } node = range.document.createElement('div'); node.className = 'callout-block'; node.setAttribute('element-id', domUtils.getRandomId()) node.innerHTML = '' domUtils.setAttributes(node, attrs); node.appendChild(calloutText); tmpRange.insertNode(node); var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()); p.innerHTML = '
    ' domUtils.insertAfter(node, p) //去除重复的 var childs = domUtils.getElementsByTagName(node, 'div', function (node) { return node.tagName == 'div' && node.className.indexOf('callout-block') > -1; }); for (var i = 0, ci; ci = childs[i++];) { if (ci.parentNode) { domUtils.remove(ci, true); } } } if (!tempRange) { range.moveToBookmark(bookmark).select(); } else { range.moveToBookmark(bookmark); } }, // queryCommandState: function () { // //表格不允许加高亮块 // var path = this.selection.getStartElementPath(); // for (var i = 0, ci; ci = path[i++];) { // if (ci.nodeName == 'TD' || ci.nodeName == 'TR') { // return -1 // } // } // return getObj(this) ? 1 : 0; // }, }; me.callouthide = { table: 1, } me.queryCommandState = function (cmd) { var me = this; if (!me.callouthide[cmd.toLowerCase()] && me.selection && me.queryCommandValue('callout')) { return -1; } return UE.Editor.prototype.queryCommandState.apply(this, arguments) }; //高亮块显示工具栏 me.callouttool = null; me.addListener('mouseover', function (type, evt) { if ($(evt.target).hasClass('callout-block') && !($(evt.target).parents('.edui-editor-callouttoolbar').length == 0 && $(me.container).find('.callouttoolList').css('display') == 'block')) { $(me.body).find('.callout-block').removeClass('hover'); $(evt.target).addClass('hover'); if (me.callouttool && $(me.container).find('.edui-editor-callouttoolbar').hasClass('hover') && $(me.container).find('.edui-editor-callouttoolbar').attr('index') == $(me.body).find('.callout-block').index(evt.target)) { return; } else if (!me.callouttool) { me.callouttool = new calloutTool(); me.callouttool.init(me); me.ui.getDom().appendChild(me.callouttool.resizer); } me.callouttool.show(evt.target); } else if (me.callouttool && $(me.container).find('.edui-editor-callouttoolbar').hasClass('hover') && ($(evt.target).is('.callout-block') || $(evt.target).parents('.callout-block').length == 0)) { me.callouttool.hide(); } }) //光标移出表情框时,表情框隐藏 $('body').on('mouseleave', '.emojiDivWrap', function (e) { $('.emojiDivWrap').removeClass('active'); }) $('body').on('mouseover', function (e) { if ($(e.target).parents('.edui-editor-callouttoolbar').length == 0 && $(e.target).parents(me.container).length == 0 && !$(e.target).is('.edui-editor-callouttoolbar') && me.callouttool && $(me.container).find('.edui-editor-callouttoolbar').hasClass('hover')) { me.callouttool.hide(); } }) me.addListener('ready', function (type, evt) { $(me.body).on('mouseover', '.callout-icon', function (e) { if (me.callouttool) { $(me.container).find('.edui-editor-callouttoolbar .hoverTips').addClass('active'); } }) $(me.body).on('mouseout', '.callout-icon', function (e) { if (me.callouttool) { $(me.container).find('.edui-editor-callouttoolbar .hoverTips').removeClass('active'); } }) $(me.body).on('click', '.callout-icon', function (e) { if (me.callouttool) { $(me.container).find('.edui-editor-callouttoolbar .hoverTips').removeClass('active'); $(me.container).find('.edui-editor-callouttoolbar .emojiDivWrap').addClass('active'); } }) }) //悬浮列表工具栏 function calloutTool() { this.editor = null; this.resizer = null; this.doc = document; this.target = null; this.bgcolor = ['unset', '#EEEFF0', '#E1EEFF', '#F0ECFC', '#E5F7E7', '#FFFBE6', '#FFE5D9', '#FDE0E0']; this.bordercolor = ['transparent', '#DCDDDE', '#A6CBFF', '#D2C6F6', '#B1E8B6', '#FFF3B5', '#FFB28D', '#FAA2A2']; } (function () { calloutTool.prototype = { init: function (editor) { var _this = this; _this.editor = editor; var resizer = _this.resizer = document.createElement('div'); resizer.innerHTML = '
    ' + '
    ' + '
    ' + _this.editor.getLang('highLight.colorSetting') + '
    ' + '
    ' + _this.editor.getLang('toolbarCmds.copy') + '
    ' + '
    ' + _this.editor.getLang('toolbarCmds.delete') + '
    ' + '
    ' + '
    ' + '
    ' + '

    ' + _this.editor.getLang('highLight.borderColor') + '

    ' + '
    ' + '
    ' + '
    ' + '

    ' + _this.editor.getLang('highLight.bgColor') + '

    ' + '
    ' + '
    ' + '
    ' + _this.editor.getLang('highLight.reset') + '
    ' + '
    ' + '
    ' + _this.editor.getLang('highLight.replaceIcon') + '
    ' + '
    ' + '
    😀
    ' + '
    ' + '

    ' + _this.editor.getLang('highLight.starEmoij') + '

    ' + '
    ' + '
    ' + '
    ' + '
    '; resizer.id = _this.editor.ui.id + '_callouttoolbar'; resizer.className = 'edui-editor-callouttoolbar edui-editor-resizer'; resizer.style.cssText += ';z-index:' + (_this.editor.options.zIndex + 3) + ';'; _this.editor.ui.getDom().appendChild(resizer); var temphtml = ''; for (var i = 0; i < _this.bgcolor.length; i++) { temphtml += '' } $(resizer).find('.bgColorList').html(temphtml); temphtml = ''; for (var i = 0; i < _this.bordercolor.length; i++) { temphtml += '' } $(resizer).find('.borderColorList').html(temphtml); temphtml = '' var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } utils.loadFile(document, { src: prefix + "third-party/cxEmoji/cxEmoji.js", tag: "script", type: "text/javascript", defer: "defer" }, function () { temphtml = cxEmoji.initHtml(prefix + "third-party/cxEmoji/images/"); $(resizer).find('.starList').html(temphtml); }); if (typeof (new Map()).put == 'undefined' && window.location.host == 'noteyd.chaoxing.com') { utils.loadFile(document, { src: prefix + "third-party/emoji-mart/js/browser.js", tag: "script", type: "text/javascript", defer: "defer" }, function () { var picker = new EmojiMart.Picker({ emojiSize: '20', locale: 'zh', perLine: 8, onEmojiSelect: function (e) { // console.log(e.native) $(_this.target).find('.callout-icon').css('backgroundImage', 'unset') $(_this.target).find('.callout-inner').text(e.native); $(_this.resizer).find('.emojiDivWrap').removeClass('active'); }, i18n: { "search": "搜索", "search_no_results_1": "哦不!", "search_no_results_2": "没有找到相关表情", "pick": "选择一个表情…", "add_custom": "添加自定义表情", "categories": { "activity": "活动", "custom": "自定义", "flags": "旗帜", "foods": "食物与饮品", "frequent": "最近使用", "nature": "动物与自然", "objects": "物品", "people": "表情与角色", "places": "旅行与景点", "search": "搜索结果", "symbols": "符号" }, "skins": { "choose": "选择默认肤色", "1": "默认", "2": "白色", "3": "偏白", "4": "中等", "5": "偏黑", "6": "黑色" } }, previewPosition: 'none', navPosition: 'bottom', searchPosition: 'none', }) resizer.querySelector('.emojiDiv').appendChild(picker); }); } else { $(resizer).find('.emojiHead,.emojiDiv').hide(); $(resizer).find('.starDiv').show(); } _this.initEvents(); }, initEvents: function () { var _this = this; //复制 $(_this.resizer).on('click', '.callout-copy', function (e) { _this.editor.copyEle(this) }); //打开颜色设置 $(_this.resizer).on('click', '.setColor', function (e) { $(_this.resizer).find('.colorSettingDiv').addClass('show'); }); //删除 $(_this.resizer).on('click', '.callout-remove', function () { _this.resizer.classList.remove('hover'); var rng = me.selection.getRange(); var index = _this.resizer.getAttribute('index'); var ele = $(me.body).find('.callout-block').eq(index); rng.setStartBefore(ele[0]).collapse(true); ele.remove(); rng.select(true); me.fireEvent('contentchange'); me.fireEvent('saveScene'); }) //选中背景色 $(_this.resizer).on('click', '.bgColorList span', function () { var color = this.style.backgroundColor || 'unset'; _this.target.style.backgroundColor = color; $(this).siblings().removeClass('active'); $(this).addClass('active') me.fireEvent('contentchange'); me.fireEvent('saveScene'); }) //选中边框颜色 $(_this.resizer).on('click', '.borderColorList span', function () { var color = this.style.backgroundColor || 'transparent'; _this.target.style.borderColor = color; $(this).siblings().removeClass('active'); $(this).addClass('active') me.fireEvent('contentchange'); me.fireEvent('saveScene'); }) //恢复默认 $(_this.resizer).on('click', '.resetColor', function () { _this.target.style.borderColor = '' _this.target.style.backgroundColor = '' me.fireEvent('contentchange'); me.fireEvent('saveScene'); }); //选中星宝表情 $(_this.resizer).on('click', '.star-emoji-list span', function () { $(_this.target).find('.callout-icon').css('backgroundImage', 'url(' + $(this).find('img').attr('src') + ')') $(_this.resizer).find('.emojiDivWrap').removeClass('active'); $(_this.target).find('.callout-inner').text(''); me.fireEvent('contentchange'); me.fireEvent('saveScene'); }); // 切换emoji和星宝表情 $(_this.resizer).on('click', '.emojiHead div', function () { $(this).addClass('active'); $(this).siblings().removeClass('active'); if ($(this).hasClass('emojiBtn')) { $(_this.resizer).find('.emojiDiv').show(); $(_this.resizer).find('.starDiv').hide(); } else { $(_this.resizer).find('.emojiDiv').hide(); $(_this.resizer).find('.starDiv').show(); } }) }, show: function (targetObj) { var _this = this; _this.resizer.classList.add('hover'); $(_this.resizer).find('.colorSettingDiv').removeClass('show'); $(_this.resizer).find('.borderColorList span,.bgColorList span').removeClass('active'); $(_this.resizer).find('.emojiDivWrap').removeClass('active'); $(_this.resizer).find('.emojiHead .starBtn').removeClass('active'); $(_this.resizer).find('.emojiHead .emojiBtn').addClass('active'); if (typeof EmojiMart != "undefined") { $(_this.resizer).find('.starDiv').hide(); $(_this.resizer).find('.emojiDiv').show(); } if (targetObj) { _this.attachTo(targetObj); var bgColor = targetObj.style.backgroundColor; var borderColor = targetObj.style.borderColor; if (bgColor) { var bgColorList = $(_this.resizer).find('.bgColorList span'); for (var i = 0; i < bgColorList.length; i++) { if (bgColorList[i].style.backgroundColor == bgColor) { bgColorList.eq(i).addClass('active'); } } } if (borderColor) { var borderColorList = $(_this.resizer).find('.borderColorList span'); for (var i = 0; i < borderColorList.length; i++) { if (borderColorList[i].style.backgroundColor == borderColor) { borderColorList.eq(i).addClass('active'); } } } } }, hide: function () { var _this = this; _this.resizer.classList.remove('hover'); $(_this.resizer).find('.colorSettingDiv').removeClass('show'); $(_this.resizer).find('.borderColorList span,.bgColorList span').removeClass('active'); $(_this.resizer).find('.emojiDivWrap').removeClass('active'); $(_this.resizer).find('.emojiHead .starBtn').removeClass('active'); $(_this.resizer).find('.emojiHead .emojiBtn').addClass('active'); if (typeof EmojiMart != "undefined") { $(_this.resizer).find('.starDiv').hide(); $(_this.resizer).find('.emojiDiv').show(); } }, attachTo: function (targetObj) { var _this = this, target = _this.target = targetObj, resizer = this.resizer, targetPos = domUtils.getXY(target), iframePos = domUtils.getXY(_this.editor.iframe), editorPos = domUtils.getXY(resizer.parentNode); var index = $(me.body).find('.callout-block').index(target); resizer.setAttribute('index', index); domUtils.setStyles(resizer, { 'width': target.clientWidth + 'px', 'height': 0, 'left': iframePos.x + targetPos.x - _this.editor.document.body.scrollLeft - editorPos.x + 'px', 'top': iframePos.y + targetPos.y - _this.editor.document.body.scrollTop - editorPos.y + 'px' }); //底部距离不够时,在上方显示 if (iframePos.y + targetPos.y - document.scrollingElement.scrollTop + 420 > $(window).height()) { domUtils.setStyles(resizer.querySelector('.emojiDivWrap'), { 'top': -420 + 20 + 'px', }); } else { domUtils.setStyles(resizer.querySelector('.emojiDivWrap'), { 'top': '', }); } if (iframePos.y + targetPos.y - document.scrollingElement.scrollTop + 210 + 10 > $(window).height()) { domUtils.setStyles(resizer.querySelector('.colorSettingDiv'), { 'top': -210 + 'px' }); } else { domUtils.setStyles(resizer.querySelector('.colorSettingDiv'), { 'top': '' }); } } } })(); }; //思维导图 mindmap UE.plugins['mindmap'] = function () { var me = this; me.commands['mindmap'] = { execCommand: function () { var cid = RichTextUitl.randomUUID(); var mapId = RichTextUitl.randomUUID() var iframeSrc = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/comp/mindmap/dist/index.html?isedit=true&mapid=' + mapId; var json = { "att_web": { "content": "", "logo": "", "showContent": 0, "title": "思维导图", "url": (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/comp/mindmap/dist/index.html?mapid=' + mapId }, "attachmentType": 25, "cid": cid } var iframename = RichTextUitl.b64EncodeUnicode(JSON.stringify(json)); me.execCommand('insertHtml', "
    "); } } // 删除url中某个参数,并跳转 function delUrlParam(url, name) { url = url.replace(/&/gi, '&') var baseUrl = url.substring(0, url.indexOf('?') + 1); var query = url.substring(url.indexOf('?') + 1, url.length); if (query.indexOf(name) > -1) { var obj = {} var arr = query.split("&"); for (var i = 0; i < arr.length; i++) { arr[i] = arr[i].split("="); obj[arr[i][0]] = arr[i][1]; } ; delete obj[name]; var url = baseUrl + JSON.stringify(obj).replace(/[\"\{\}]/g, "").replace(/\:/g, "=").replace(/\,/g, "&"); return url } return url; } me.addInputRule(function (root) { root.traversal(function (node) { if (node.getAttr('src') && node.getAttr('src').indexOf('mindmap') > -1) { node.setAttr('src', delUrlParam(node.getAttr('src'), 'isedit') + '&isedit=true') } }) }) me.addOutputRule(function (root) { root.traversal(function (node) { if (node.getAttr('src') && node.getAttr('src').indexOf('mindmap') > -1) { node.setAttr('src', delUrlParam(node.getAttr('src'), 'isedit')) } }) }) } // 单词统计 UE.plugins['wordstatistics'] = function () { var me = this; me.addListener('ready', function () { var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } utils.loadFile(document, { src: prefix + "third-party/count.js", tag: "script", type: "text/javascript", defer: "defer" }) $(me.body).on('click',function (e) { wordStatistics.close(); }) $('body').on('click',function (e) { if(!document.querySelector('.word-statistics-wrap')){ return }else if( e.target.nodeType == 1 && e.target.className && e.target.className.indexOf('.edui-for-wordstatistics') > -1 || $(e.target).parents('.edui-for-wordstatistics').length > 0){ return } wordStatistics.close(); }) }) me.commands['wordstatistics'] = { execCommand: function () { var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } var rect = me.container.querySelector('.edui-editor-toolbarbox .edui-for-wordstatistics').getBoundingClientRect() var top = rect.top; var left = rect.left; if(left + 240 > $(window).width()){ left = $(window).width() - 240 - 30 } var content = me.getPlainTxt(); wordStatistics.count(content,top + 40,left,prefix) } } } // plugins/convertcase.js /** * 大小写转换 * @file * @since 1.2.6.1 */ /** * 把选区内文本变大写,与“tolowercase”命令互斥 * @command touppercase * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'touppercase' ); * ``` */ /** * 把选区内文本变小写,与“touppercase”命令互斥 * @command tolowercase * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'tolowercase' ); * ``` */ UE.commands['touppercase'] = UE.commands['tolowercase'] = { execCommand: function (cmd) { var me = this; var rng = me.selection.getRange(); if (rng.collapsed) { return rng; } var bk = rng.createBookmark(), bkEnd = bk.end, filterFn = function (node) { return !domUtils.isBr(node) && !domUtils.isWhitespace(node); }, curNode = domUtils.getNextDomNode(bk.start, false, filterFn); while (curNode && (domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING)) { if (curNode.nodeType == 3) { curNode.nodeValue = curNode.nodeValue[cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase'](); } curNode = domUtils.getNextDomNode(curNode, true, filterFn); if (curNode === bkEnd) { break; } } rng.moveToBookmark(bk).select(); } }; // plugins/indent.js /** * 首行缩进 * @file * @since 1.2.6.1 */ /** * 缩进 * @command indent * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'indent' ); * ``` */ UE.plugins['indent'] = function () { var me = this; me.commands['indent'] = { execCommand: function (cmdName, value, tmpRange) { var me = this; var range = me.selection.getRange(); //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange } range.shrinkBoundary(); var pN = domUtils.findParentByTagName(range.startContainer, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div'], true); if (pN) { switch (value) { case 'pindent': var newIndent = 0; var node = pN; var fontsize; if (pN.tagName == "H1") { fontsize = 24; } else if (pN.tagName == "H2") { fontsize = 20; } else if (pN.tagName == "H3") { fontsize = 18; } else { fontsize = 16; } //找到第一个字的fontsize while (node.firstChild) { if (node.firstChild.innerText && node.firstChild.innerText.trim() == '') { if (node.nextSibling) { node = node.nextSibling; } else { break; } } else if (node.firstChild.nodeType == 1) { if (node.firstChild.style.fontSize && node.firstChild.style.fontSize != '') { fontsize = node.firstChild.style.fontSize.replace('px', '').replace('pt', ''); } node = node.firstChild; } else if (node.firstChild.nodeType == 3) { if (node.firstChild.nodeValue.trim() == '') { node = node.nextSibling; } else { break; } } } var Li = $(node).parents('li'); var nowIndent = pN.style.textIndent; if(Li.length > 0){ nowIndent = Li.parent().css('margin-left'); } if (nowIndent != '' && parseInt(nowIndent.substr(0, nowIndent.length - 2)) > 0) { if (Li.length > 0) { Li.parent().css('margin-left', '0'); me.fireEvent('contentchange'); }else { me.execCommand('Paragraph', 'p', { style: 'text-indent:0' }); } } else { newIndent = 2 * fontsize + 'px'; if (Li.length > 0) { Li.parent().css('margin-left', newIndent); me.fireEvent('contentchange'); }else{ me.execCommand('Paragraph', 'p', { style: 'text-indent:' + newIndent }); } } break; case 'indent': var li = domUtils.findParent(range.startContainer, function (node) { return node.tagName == 'LI' }, true); var list = domUtils.findParent(range.startContainer, function (node) { return node.tagName == 'OL' || node.tagName == 'UL' }, true); if (li && list) { if (range.collapsed) { var level = parseInt(list.getAttribute('level')); if (level < 6) { list.setAttribute('level', ++level); if (list.tagName == 'OL') { indentlist(list); } } } else { bk = range.createBookmark(); if (bk.end) { while (list && domUtils.isTagNode(list, 'ol ul') && !(domUtils.getPosition(list, bk.end) & domUtils.POSITION_FOLLOWING)) { var level = parseInt(list.getAttribute('level')); if (level < 6) { list.setAttribute('level', ++level); if (list.tagName == 'OL') { indentlist(list); } } list = list.nextSibling; } } range.moveToBookmark(bk) } } else { var nowIndent = pN.style.marginLeft; var newIndent = 0; if (nowIndent != '') { newIndent = parseInt(nowIndent.substr(0, nowIndent.length - 2)); if (newIndent < 10) { newIndent += 2; } } var ml = me.queryCommandState("indent") ? (newIndent + 'em') : (me.options.indentValue || '2em'); me.execCommand('Paragraph', 'p', { style: 'margin-left:' + ml }); } break; case 'outdent': var li = domUtils.findParent(range.startContainer, function (node) { return node.tagName == 'LI' }, true); var list = domUtils.findParent(range.startContainer, function (node) { return node.tagName == 'OL' || node.tagName == 'UL' }, true); if (li && list) { if (range.collapsed) { var level = parseInt(list.getAttribute('level')); if (level > 1) { list.setAttribute('level', --level); if (list.tagName == 'OL') { outdentlist(list); } } else { var listnext = list.nextSibling; while (list.firstChild.firstChild) { var p = list.firstChild.firstChild; if (!domUtils.isBlockElm(p)) { p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) p.appendChild(list.firstChild.firstChild); } if (listnext) { list.parentNode.insertBefore(p, listnext); } else { list.parentNode.appendChild(p); } } domUtils.remove(list); } } else { bk = range.createBookmark(); if (bk.end) { while (list && domUtils.isTagNode(list, 'ol ul') && !(domUtils.getPosition(list, bk.end) & domUtils.POSITION_FOLLOWING)) { var level = parseInt(list.getAttribute('level')); if (level > 1) { list.setAttribute('level', --level); if (list.tagName == 'OL') { outdentlist(list); } } list = list.nextSibling; } } range.moveToBookmark(bk) } } else { var nowIndent = pN.style.marginLeft; var newIndent = 0; if (nowIndent != '') { newIndent = parseInt(nowIndent.substr(0, nowIndent.length - 2)); if (newIndent >= 2) { newIndent -= 2; } } var ml = me.queryCommandState("indent") ? (newIndent + 'em') : (me.options.indentValue || '0em'); me.execCommand('Paragraph', 'p', { style: 'margin-left:' + ml }); } break; } me.normalList() } }, queryCommandState: function () { // var pN = domUtils.filterNodeList(this.selection.getStartElementPath(),'p h1 h2 h3 h4 h5 h6'); var range = this.selection.getRange(); var pN = domUtils.findParentByTagName(range.startContainer, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div'], true); return pN && pN.style.marginLeft && parseInt(pN.style.marginLeft) ? 1 : 0; } }; function setNewSerialnum(list, level) { var listprev = list.previousSibling; if (!listprev) {//没有找到前一个 list.setAttribute('data-origin-start', '1'); } var serialnum = 1; //前一个是否有缩进后同级的列表,如果有,序号修改 while (listprev) { if (listprev && listprev.firstChild && listprev.tagName == list.tagName && listprev.getAttribute('level') == list.getAttribute('level')) { if (listprev.getAttribute('serialnum')) { serialnum = domUtils.serialnumToInt(listprev.getAttribute('serialnum'), level); serialnum++; break; } } else if (listprev.getAttribute('level') < list.getAttribute('level')) { break; } listprev = listprev.previousSibling; } var serialstr = domUtils.serialnumToString(serialnum, level); list.setAttribute('serialnum', serialstr); list.firstChild.setAttribute('serialnum', serialstr); if (serialnum == 1) { list.setAttribute('data-origin-start', '1'); } else { list.removeAttribute('data-origin-start'); } } function indentlist(list) { var level = parseInt(list.getAttribute('level')); var startlevel = level - 1; var startserialnum = domUtils.serialnumToInt(list.getAttribute('serialnum'), startlevel); setNewSerialnum(list, level); var listnext = list.nextSibling; while (listnext) { if (listnext.tagName == 'OL' && parseInt(listnext.getAttribute('level'))) { var nextlevel = parseInt(listnext.getAttribute('level')); var nextserialnum = listnext.getAttribute('serialnum'); nextserialnum = domUtils.serialnumToInt(nextserialnum, nextlevel); if (nextlevel == (level - 1) && nextserialnum == startserialnum + 1) { //列表缩进前下面有同级列表 listnext.setAttribute('serialnum', domUtils.minusSerialNum(listnext.getAttribute('serialnum'), nextlevel)); listnext.firstChild.setAttribute('serialnum', listnext.getAttribute('serialnum')); break; } else if (nextlevel == level && listnext.getAttribute('data-origin-start')) { //列表缩进后有同级页面 listnext.removeAttribute('data-origin-start'); listnext.setAttribute('serialnum', domUtils.addSerialNum(listnext.getAttribute('serialnum'), nextlevel)); listnext.firstChild.setAttribute('serialnum', listnext.getAttribute('serialnum')); } else if (nextlevel > level) { break; } } listnext = listnext.nextSibling; } } function outdentlist(list) { var level = parseInt(list.getAttribute('level')); var startlevel = level + 1; var startserialnum = domUtils.serialnumToInt(list.getAttribute('serialnum'), startlevel); setNewSerialnum(list, level); var listnext = list.nextSibling; while (listnext) { if (listnext.tagName == 'OL' && parseInt(listnext.getAttribute('level'))) { var nextlevel = parseInt(listnext.getAttribute('level')); var nextserialnum = listnext.getAttribute('serialnum'); nextserialnum = domUtils.serialnumToInt(nextserialnum, nextlevel); if (nextlevel == (level + 1) && nextserialnum == startserialnum + 1) { //列表缩进前下面有同级列表 listnext.setAttribute('serialnum', domUtils.serialnumToString(1, nextlevel)); listnext.firstChild.setAttribute('serialnum', domUtils.serialnumToString(1, nextlevel)); listnext.setAttribute('data-origin-start', '1'); break; } else if (nextlevel == level && listnext.getAttribute('data-origin-start')) { //列表缩进后有同级页面 listnext.removeAttribute('data-origin-start'); listnext.setAttribute('serialnum', domUtils.addSerialNum(listnext.getAttribute('serialnum'), nextlevel)); listnext.firstChild.setAttribute('serialnum', listnext.getAttribute('serialnum')); break; } else if (nextlevel > level) { break; } } listnext = listnext.nextSibling; } } me.addListener('keydown', function (type, evt) { var me = this, keyCode = evt.keyCode || evt.which; var range = me.selection.getRange(); var temprng = range.shrinkBoundary(); if (range.collapsed) { //首行缩进前删除移除首行缩进 if (keyCode == 8) { var pN = domUtils.findParentByTagName(range.startContainer, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div'], true); if (pN && pN.style) { var nowIndent = pN.style.textIndent ? pN.style.textIndent : '0em'; var newIndent = parseInt(nowIndent.substr(0, nowIndent.length)); if (range.startOffset == 0 && newIndent > 0) { evt.preventDefault(); me.execCommand('indent', 'pindent'); } } } } }) }; UE.commands['checkbox'] = { execCommand: function (cmdName, value, tmpRange, elementId) { var me = this; var range = me.selection.getRange(); //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange } if (!elementId) { elementId = domUtils.getRandomId() } var block = domUtils.isBlockElm; var startContainer = range.startContainer; var start = startContainer; var startOffset = range.startOffset; if (startContainer.nodeType == 3) { start = startContainer.parentNode; } //找到上层的块状元素节点 while (!domUtils.isBlockElm(start) && !domUtils.isBody(start.parentNode)) { start = start.parentNode; } if (!range.collapsed) { //选中区域有列表的不允许设置勾选框 var rangecontent = range.cloneContents(); if (rangecontent.querySelector('.record-list') || rangecontent.querySelector('.record-list-tit') || rangecontent.querySelector('li')) { return; } var startprev = start.previousSibling; var li = domUtils.findParentByTagName(range.startContainer, 'li', true) || $(range.startContainer).find('li')[0]; if (li) { return; } var bookmark = range.createBookmark(), filterFn = function (node) { return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); }, para; range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode; var todoList = range.cloneContents().querySelector('.todo-view'); if (!todoList) { while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { if (current.nodeType == 3 || !block(current)) { tmpRange.setStartBefore(current); while (current && current !== bookmark2.end && !block(current)) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !block(node); }); } tmpRange.setEndAfter(tmpNode); para = range.document.createElement('p'); para.setAttribute('element-id', domUtils.getRandomId()) para.appendChild(tmpRange.extractContents()); var todoview = document.createElement('div'); todoview.setAttribute('class', 'todo-view'); todoview.setAttribute('element-id', elementId); var todoHtml = '' + '' + '' + '
    ' + para.outerHTML + '
    '; todoview.innerHTML = todoHtml; tmpRange.insertNode(todoview); domUtils.remove(todoview.parentNode, true); current = todoview; current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } range.setEndAfter(todoview).select(); range.moveToBookmark(bookmark2).moveToBookmark(bookmark); } else { //取消勾选框 while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { if ($(current).parents('.todo-text').length > 0) { tmpRange.setStartBefore($(current).parents('.todo-text').children().first()[0]); tmpRange.setEndAfter($(current).parents('.todo-text').children().last()[0]); var todoview = $(tmpRange.startContainer).parents('.todo-view')[0]; var todotext = tmpRange.extractContents(); tmpRange.setStartAfter(todoview); tmpRange.setEndAfter(todoview); tmpRange.insertNode(todotext); current = todoview.nextSibling; domUtils.remove(todoview); current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } range.select(); range.moveToBookmark(bookmark2).moveToBookmark(bookmark); } } else { var iframe = me.iframe; if (iframe) { doc = iframe.contentDocument || iframe.document; } if ($(start).is('.todo-view') || $(start).parents('.todo-view').length > 0) { //如果是勾选框 var bk = range.createBookmark(); var todoList = domUtils.findParents(start, false, function (node) { return node.className && node.className.indexOf('todo-view') > -1 }, true); var todo = todoList[0]; var todoText = $(start).parents('.todo-view').find(".todo-text")[0]; var p = document.createElement("p"); p.setAttribute('element-id', domUtils.getRandomId()) while (todoText.firstChild) { if (domUtils.isBlockElm(todoText.firstChild)) { todo.parentNode.insertBefore(todoText.firstChild, todo); var p = document.createElement("p"); } else { div.appendChild(todoText.firstChild); todo.parentNode.insertBefore(div, todo); } } domUtils.remove(todo); if (!tmpRange) { range.moveToBookmark(bk).select(); } else { range.moveToBookmark(bk); } } else if ($(start).is('ol') || $(start).parents('ol').length > 0) { //有序列表下 var bk = range.createBookmark(true); var ol = $(start).parents('ol')[0]; if (start.nodeType == 1 && start.nodeName != 'OL') { //断开列表 while (start.nodeName != 'OL') { if (start.nodeName == 'LI') { break; } else { start = start.parentNode; } } domUtils.breakParent(start, ol); if (start.previousSibling.innerHTML == '') { domUtils.remove(start.previousSibling); } if (start.nextSibling.innerHTML == '') { domUtils.remove(start.nextSibling); } var div = document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()) while (start.firstChild) { if (start.firstChild.nodeType == 3 && start.firstChild.nodeValue != '') { var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) p.appendChild(start.firstChild); div.appendChild(p); } else { div.appendChild(start.firstChild); } } var todoHtml = '
    ' + '' + '' + '' + '
    ' + div.innerHTML + '
    ' + '
    '; start.parentNode.insertBefore($(todoHtml)[0], start); domUtils.remove(start); } if (!tmpRange) { range.moveToBookmark(bk).select(); } else { range.moveToBookmark(bk); } } else if ($(start).is('ul') || $(start).parents('ul').length > 0) { //无序列表下 var bk = range.createBookmark(true); var ul = $(start).parents('ul')[0]; if (start.nodeType == 1 && start.nodeName != 'UL') { //断开列表 while (start.nodeName != 'UL') { if (start.nodeName == 'LI') { break; } else { start = start.parentNode; } } domUtils.breakParent(start, ul); if (start.previousSibling.innerHTML == '') { domUtils.remove(start.previousSibling); } if (start.nextSibling.innerHTML == '') { domUtils.remove(start.nextSibling); } var div = document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()) while (start.firstChild) { if (start.firstChild.nodeType == 3 && start.firstChild.nodeValue != '') { var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) p.appendChild(start.firstChild); div.appendChild(p); } else { div.appendChild(start.firstChild); } } var todoHtml = '
    ' + '' + '' + '' + '
    ' + div.innerHTML + '
    ' + '
    '; start.parentNode.insertBefore($(todoHtml)[0], start); domUtils.remove(start); } if (!tmpRange) { range.moveToBookmark(bk).select(); } else { range.moveToBookmark(bk); } } else { var bk = range.createBookmark(true); // var div = me.document.createElement('p'); // while(start.firstChild){ // div.appendChild(start.firstChild); // } // var todoHtml = '
    '+ // ''+ // ''+ // ''+ // '
    '+div.outerHTML+'
    '+ // '
    '; // start.parentNode.insertBefore($(todoHtml)[0],start); // domUtils.remove(start); //解决颜色丢失 var div, pos; if (start.nextSibling) { pos = start.nextSibling; } var startParent = start.parentNode; if (domUtils.isBlockElm(start)) { div = start; } else { div = me.document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()) div.appendChild(start); } var todoHtml = '
    ' + '' + '' + '' + '
    ' + div.outerHTML + '
    ' + '
    '; if (pos) { startParent.insertBefore($(todoHtml)[0], pos); } else { startParent.appendChild($(todoHtml)[0]) } domUtils.remove(start); if (!tmpRange) { range.moveToBookmark(bk).setCursor(true, true).select(); } else { range.moveToBookmark(bk).setCursor(true, true); } } } }, queryCommandState: function () { var path = this.selection.getStartElementPath(), node; for (var i = 0, ci; ci = path[i++];) { if (ci.nodeName == 'TABLE') { node = null; break; } if ($(ci).hasClass('todo-view')) { node = ci; break; } } return node; } }; UE.commands['radio'] = { execCommand: function () { var me = this; var range = me.selection.getRange(); var startContainer = range.startContainer; //当前已经有录音 if ($('.radiofixed').is(":visible")) { return; } function gettime() { sec++; if (sec == 60) { min++; sec = 0; } if (min == 60) { hor++; min = 0; } var secStr = sec < 10 ? ("0" + sec) : sec; var minStr = min < 10 ? ("0" + min) : min; var horStr = hor; if (hor == 0) { return minStr + ':' + secStr; } else if (hor < 10) { horStr = "0" + hor; return horStr + ':' + minStr + ':' + secStr; } } //初始状态 $('#duration').html('00:00'); var bufer1 = null;//保存录音 var min = sec = hor = 0; var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } //定义为全局的变量: 录音计时和录音object window.recordTimer = null; if (!window.record) { utils.loadFile(document, { src: prefix + "third-party/recorder.mp3.min.js", tag: "script", type: "text/javascript", defer: "defer" }, function () { utils.loadFile(document, { src: prefix + "third-party/wavesurfer.view.js", tag: "script", type: "text/javascript", defer: "defer" }, function () { /*动态加载波形插件*/ window.record = Recorder({ type: "mp3", sampleRate: 16000, //采样率 onProcess: function (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) { //可视化图形绘制 bufer1.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate); } }); openradio(me.key) }); }); } else { //每次进来要把上次录像对象销毁 ,清除显示dom 06-4 lcq window.record = Recorder({ type: "mp3", sampleRate: 16000, //采样率 onProcess: function (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) { //可视化图形绘制 bufer1.input(buffers[buffers.length - 1], powerLevel, bufferSampleRate); } }); // 每次新的录音都先清空波形结构 将样式恢复如初 lcq 06-7 $('.bolb').empty(); $('.bolb').show() $('.bolb-mask').hide() $('.radio-img').removeClass('again') openradio(me.key) } function secondToTime(time) { var newtime; if (null != time) { if (time < 60) { var seconds = parseInt(time) < 10 ? ('0' + parseInt(time)) : parseInt(time); newtime = '00:' + seconds; } else if (time >= 60 && time < 60 * 60) { var minute = parseInt(time / 60.0) < 10 ? ('0' + parseInt(time / 60.0)) : parseInt(time / 60.0); var seconds = (parseInt(time % 60.0) < 10) ? ('0' + parseInt(time % 60.0)) : parseInt(time % 60.0); newtime = minute + ':' + seconds; } else if (time >= 60 * 60 && time < 60 * 60 * 24) { var hour = parseInt(time / 3600.0) < 10 ? ('0' + parseInt(time / 3600.0)) : parseInt(time / 3600.0); var minute = (parseInt(time / 60.0 % 60.0) < 10) ? ('0' + parseInt(time / 60.0 % 60.0)) : parseInt(time / 60.0 % 60.0); var seconds = (parseInt(time % 60.0) < 10) ? ('0' + parseInt(time % 60.0)) : parseInt(time % 60.0); newtime = hour + '小时' + minute + '分' + seconds; } } return newtime; } function openradio(editorId) { $('.radiofixed').show(); window.record.open(function () { //打开麦克风授权获得相关资源 $('.radiocontrol').show(); bufer1 = Recorder.WaveSurferView({elem: '.bolb'}); window.record.start(); //开始录音 clearInterval(window.recordTimer); window.recordTimer = setInterval(function () { var time = gettime(); $('#duration').html(time) }, 1000) $('.radiofixed').attr('editorId', editorId).show(); }, function (msg, isUserNotAllow) { //用户拒绝未授权或不支持 if ($('.toolTipBox').length > 0) { $('.toolTipBox').remove(); } if (msg.indexOf('需https') > -1) { $(document.body).append('
    '+me.getLang('radio.openRadioFailed')+'
    ') } else if (msg.indexOf('NotFoundError') > -1) { $(document.body).append('
    '+me.getLang('radio.noMicroPhone')+'
    '); } else if (msg.indexOf('denied') > -1 || msg.indexOf('拒绝') > -1) { $(document.body).append('
    '+me.getLang('radio.noMicroPhoneRight')+'
    '); } else { $(document.body).append('
    ' + msg + '
    '); } setTimeout(function () { $('.toolTipBox').fadeOut(); }, 1500); console.log((isUserNotAllow ? "UserNotAllow," : "") + "无法录音:" + msg); $('.radiofixed').hide(); }); if ($('.radiofixed').length == 0) { $(document.body).append( '
    ' + '
    ' + me.getLang('radio.pressToDrag') + '
    ' + '
    ' + '
    ' + me.getLang('radio.stop') + '
    ' + '
    00:00
    ' + '
    ' + me.getLang('radio.continue') + '
    ' + '
    ' + '
    ' + '
    ' + '
    '); $('#radiofixed').attr('editorId', editorId); $('.recstop').click(function () { var _this = this; var editor = UE.getEditor($('#radiofixed').attr('editorId')); clearInterval(window.recordTimer); $('.radiofixed').attr('style', 'display:none'); $('.recpause').text(me.getLang('radio.pause')) $(this).parents('.radiocontrol').removeClass('pause'); window.record.stop(function (blob, duration) { //到达指定条件停止录音 $(_this).parents('.radiocontrol').hide(); console.log((window.URL || webkitURL).createObjectURL(blob), "时长:" + duration + "ms"); window.record.close(); //释放录音资源 //已经拿到blob文件对象想干嘛就干嘛:立即播放、上传 //上传云盘获取音频信息 var voiceLength = Math.ceil(duration / 1000); var fileAudio = new File([blob], new Date().valueOf() + '.mp3', { type: blob.type }); fileAudio.duration = duration var data = new FormData() // data.append("id",file.id) data.append("name", (new Date()).getTime()+".mp3") data.append("lastModifiedDate", fileAudio.lastModifiedDate) data.append("size", fileAudio.size) data.append("type", fileAudio.type) if(RichTextUitl.puid && RichTextUitl.yunToken) { data.append("puid", RichTextUitl.puid) data.append("_token", RichTextUitl.yunToken) } data.append("file", fileAudio) //插入页面 var cid = RichTextUitl.randomUUID(); var json = { 'att_voice': { 'fileTitle': secondToTime(voiceLength), 'fileLength': blob.size, 'titleEdited': 1, 'voiceLength': voiceLength }, 'attachmentType': 26, 'cid': cid } var jsonStr = JSON.stringify(json); var divelementid = domUtils.getRandomId(); var webPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/'; if(RichTextUitl.intranetMode){ webPrefix = RichTextUitl.prefix } var voicePrefix = webPrefix + 'attachment/'; if (window.location.host.indexOf('course.ustc.edu.cn') > -1 && !(RichTextUitl.prefix && RichTextUitl.prefix.indexOf('chaoxing.com') > -1)) { // 中科大云盘做了镜像,要使用笔记的定制域名服务端才能请求镜像云盘接口 voicePrefix = 'https://noteyd.course.ustc.edu.cn/attachment/'; } var html = '
    ' + '
    ' + '
    ' + '

    正在上传...

    0/' + parseInt(blob.size / 1024) + 'KB

    ' + '
    ' + '' + '
    '; editor.execCommand('insertHtml', html); //上传云盘后 发送协同数据 var html2 = '
    ' + '' + '
    '; editor.sendhtml(html2); var iframe = editor.iframe; var doc = iframe.contentDocument || iframe.document; var dom = $(editor.body).find('iframe[cid="' + cid + '"]').parent(); var actionUrl = me.getActionUrl(me.getOpt('imageActionName')); //上传录音 $.ajax({ url: actionUrl, //上传接口地址 type: "POST", xhrFields: { withCredentials: true }, contentType: false, //让xhr自动处理Content-Type header,multipart/form-data需要生成随机的boundary processData: false, //不要处理data,让xhr自动处理 data: data, xhr: function () { var xhr = new XMLHttpRequest(); //使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件 xhr.addEventListener('progress', function (e) { //loaded代表上传了多少,total代表总数为多少 var progressRate = (e.loaded / e.total) * 100; $(dom).find(".bar").css('width', progressRate + '%'); $(dom).find(".curSize").text(parseInt(e.loaded / 1024) + 'KB'); }) return xhr; }, success: function (res) { res = JSON.parse(res) //云盘附件 if (res.result && res.data) { json.cid = cid; json.att_voice = { "createTime": (new Date()).getTime(), "fileLength": res.data.size, "fileTitle": res.data.name, "objectId": "", "objectId2": res.data.objectId, "status": 0, "titleEdited": 1, "type": res.data.suffix || file.ext, "url": "", "voiceLength": voiceLength, "isMirror": (res.data.isMirror == null || res.data.isMirror) ? 1 : 0, "fid": getCookie('fid'), "encryptedId": res.data.encryptedId || '' }; var jsonStr = JSON.stringify(json); var iframe = $(dom).find('iframe')[0]; iframe.name = RichTextUitl.b64EncodeUnicode(jsonStr); if (iframe.attachEvent) { iframe.attachEvent("onload", function () { $(this)[0].contentWindow.postMessage({ 'msgType': 'dataChanged', 'cid': iframe.getAttribute('cid'), 'name': iframe.name, 'editorId': editor.key, 'cloudUrl': RichTextUitl.cloudUrl, 'openPreview': RichTextUitl.openPreview || null }, '*'); }); } else { iframe.onload = function () { $(this)[0].contentWindow.postMessage({ 'msgType': 'dataChanged', 'cid': iframe.getAttribute('cid'), 'name': iframe.name, 'editorId': editor.key, 'cloudUrl': RichTextUitl.cloudUrl, 'openPreview': RichTextUitl.openPreview || null }, '*'); }; } $(dom).find(".attachprogress").remove(); $(dom).find('iframe')[0].contentWindow.postMessage({ 'msgType': 'dataChanged', 'cid': iframe.getAttribute('cid'), 'name': iframe.name, 'editorId': editor.key, 'cloudUrl': RichTextUitl.cloudUrl, 'openPreview': RichTextUitl.openPreview || null }, "*"); me.fireEvent('contentchange'); me.fireEvent('saveScene'); } }, error: function (s) { console.error("上传失败", s); } }); }, function (msg) { console.log("录音失败:" + msg); }); }) //暂停 继续 $('.radio-img').click(function () { if (window.record) { //console.log($(this).attr('class')) if ($(this).attr('class') == 'radio-img') { clearInterval(window.recordTimer); $(this).addClass('again') window.record.pause(); //$(this).text('继续') $('.bolb').hide() $('.bolb-mask').show() console.log("已暂停"); } else if ($(this).attr('class') == 'radio-img again') { clearInterval(window.recordTimer); $(this).removeClass('again') window.recordTimer = setInterval(function () { var time = gettime(); $('#duration').html(time) }, 1000); $('.bolb').show() $('.bolb-mask').hide() window.record.resume(); console.log("继续录音中..."); } } ; }); // 中间的继续录制文字也可以点击 $('.bolb-mask').click(function () { clearInterval(window.recordTimer); window.recordTimer = setInterval(function () { var time = gettime(); $('#duration').html(time) }, 1000); window.record.resume(); // console.log("继续录音中..."); $('.radio-img').removeClass('again'); $('.bolb').show() $(this).hide() }); //全屏移动 var radioCtr = document.getElementById('radiofixed'); var leftCha, topCha; //定义鼠标是否按下的标识 var isDown = false; radioCtr.onmousedown = function (e) { var e = e || window.event; leftCha = e.clientX - radioCtr.offsetLeft; topCha = e.clientY - radioCtr.offsetTop; isDown = true; } window.onmousemove = function (e) { var e = e || window.event; if (!isDown) { return; //终止程序执行 } radioCtr.style.left = e.clientX - leftCha + 'px'; radioCtr.style.top = e.clientY - topCha + 'px'; } radioCtr.onmouseup = function (e) { isDown = false; } } var fixedtop = $(me.container).find('.edui-for-radio').offset().top - document.scrollingElement.scrollTop + 50; var fixedleft = $(me.container).find('.edui-for-radio').offset().left - document.scrollingElement.scrollLeft - 65; $('.radiofixed').css({ 'top': fixedtop, 'left': fixedleft }) } }, queryCommandState: function () { } }; // plugins/selectall.js /** * 全选 * @file * @since 1.2.6.1 */ /** * 选中所有内容 * @command selectall * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'selectall' ); * ``` */ UE.plugins['selectall'] = function () { var me = this; me.commands['selectall'] = { execCommand: function () { //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标 var me = this, body = me.body, range = me.selection.getRange(); range.selectNodeContents(body); //20200811 全选不允许选中课堂笔记头部 if (body.querySelector('#ulTab')) { range.setStartAfter(body.querySelector('#ulTab')) } //全选不允许选中收件箱的签名 if (body.querySelector('#signDiv')) { range.setEndBefore(body.querySelector('#signDiv')) } if (domUtils.isEmptyBlock(body)) { //opera不能自动合并到元素的里边,要手动处理一下 if (browser.opera && body.firstChild && body.firstChild.nodeType == 1) { range.setStartAtFirst(body.firstChild); } range.collapse(true); } range.select(true); }, notNeedUndo: 1 }; //快捷键 me.addshortcutkey({ "selectAll": "ctrl+65" }); }; // plugins/paragraph.js /** * 段落样式 * @file * @since 1.2.6.1 */ /** * 段落格式 * @command paragraph * @method execCommand * @param { String } cmd 命令字符串 * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' * @param {Object} attrs 标签的属性 * @example * ```javascript * editor.execCommand( 'Paragraph','h1','{ * class:'test' * }' ); * ``` */ /** * 返回选区内节点标签名 * @command paragraph * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 节点标签名 * @example * ```javascript * editor.queryCommandValue( 'Paragraph' ); * ``` */ UE.plugins['paragraph'] = function () { var me = this, block = domUtils.isBlockElm, notExchange = ['TD', 'LI', 'PRE'], doParagraph = function (range, style, attrs, sourceCmdName) { var bookmark = range.createBookmark(), filterFn = function (node) { return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); }, para; range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode; while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { //设置行距时,行距设置到li上 if (current.nodeType == 1 && current.nodeName == 'LI' && attrs && attrs.style.indexOf('line-height') > -1) { current.style.cssText += attrs.style; current = domUtils.getNextDomNode(current, false, filterFn); } else if (current.nodeType == 3 || !block(current)) { tmpRange.setStartBefore(current); while (current && current !== bookmark2.end && !block(current)) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !block(node); }); } tmpRange.setEndAfter(tmpNode); para = range.document.createElement(style); if (attrs) { domUtils.setAttributes(para, attrs); if (sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) { para.style.cssText = attrs.style; } } para.appendChild(tmpRange.extractContents()); //需要内容占位 if (domUtils.isEmptyNode(para)) { domUtils.fillChar(range.document, para); } tmpRange.insertNode(para); if (style.indexOf('h') > -1) { $(para).find('span').each(function (index, span) { domUtils.removeStyle(span, 'font-size'); }) } var parent = para.parentNode; //20200708 同步时前面有8203会导致多空行 if (domUtils.isFillChar(parent.firstChild)) { domUtils.remove(parent.firstChild) } //如果para上一级是一个block元素且不是body,td就elePack它 if (block(parent) && !domUtils.isBody(para.parentNode) && utils.indexOf(notExchange, parent.tagName) == -1) { //存储dir,style if (!(sourceCmdName && sourceCmdName == 'customstyle')) { parent.getAttribute('dir') && para.setAttribute('dir', parent.getAttribute('dir')); parent.getAttribute('element-id') && para.setAttribute('element-id', parent.getAttribute('element-id')); //trace:1070 parent.style.cssText && (para.style.cssText = parent.style.cssText + ';' + para.style.cssText); //trace:1030 parent.style.textAlign && !para.style.textAlign && (para.style.textAlign = parent.style.textAlign); parent.style.textIndent && !para.style.textIndent && (para.style.textIndent = parent.style.textIndent); parent.style.padding && !para.style.padding && (para.style.padding = parent.style.padding); } //trace:1706 选择的就是h1-6要elePack if (attrs && /h\d/i.test(parent.tagName) && !/h\d/i.test(para.tagName)) { domUtils.setAttributes(parent, attrs); if (sourceCmdName && sourceCmdName == 'customstyle' && attrs.style) { parent.style.cssText = attrs.style; } domUtils.remove(para, true); para = parent; } else { domUtils.remove(para.parentNode, true); } para.style.fontSize = ""; } if (utils.indexOf(notExchange, parent.tagName) != -1) { current = parent; } else { current = para; } current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } return range.moveToBookmark(bookmark2).moveToBookmark(bookmark); }; me.setOpt('paragraph', { 'p': '', 'h1': '', 'h2': '', 'h3': '', 'h4': '' }); me.commands['paragraph'] = { execCommand: function (cmdName, style, attrs, sourceCmdName, tmpRange) { var range = this.selection.getRange(); //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange; } //闭合时单独处理 if (range.collapsed) { var txt = this.document.createTextNode('p'); range.insertNode(txt); //去掉冗余的fillchar if (browser.ie) { var node = txt.previousSibling; if (node && domUtils.isWhitespace(node)) { domUtils.remove(node); } node = txt.nextSibling; if (node && domUtils.isWhitespace(node)) { domUtils.remove(node); } } } var start = range.startContainer; if (start.nodeType == 1 && domUtils.isBlockElm(start) && (!start.getAttribute('element-id') || start.getAttribute('element-id') == 'init')) { start.setAttribute('element-id', domUtils.getRandomId()); } range = doParagraph(range, style, attrs, sourceCmdName); if (txt) { range.setStartBefore(txt).collapse(true); pN = txt.parentNode; domUtils.remove(txt); if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) { domUtils.fillNode(this.document, pN); } } me.normalList(); //20210317 更新目录 if (typeof (updateAllCatalog) == "function") { updateAllCatalog(me.body); } if (browser.gecko && range.collapsed && range.startContainer.nodeType == 1) { var child = range.startContainer.childNodes[range.startOffset]; if (child && child.nodeType == 1 && child.tagName.toLowerCase() == style) { range.setStart(child, 0).collapse(true); } } //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了 if (!tmpRange) { range.select(); } return true; }, queryCommandValue: function () { var node = domUtils.filterNodeList(this.selection.getStartElementPath(), 'p h1 h2 h3 h4 h5 h6'); return node ? node.tagName.toLowerCase() : ''; } }; }; // plugins/directionality.js /** * 设置文字输入的方向的插件 * @file * @since 1.2.6.1 */ (function () { var block = domUtils.isBlockElm, getObj = function (editor) { // var startNode = editor.selection.getStart(), // parents; // if ( startNode ) { // //查找所有的是block的父亲节点 // parents = domUtils.findParents( startNode, true, block, true ); // for ( var i = 0,ci; ci = parents[i++]; ) { // if ( ci.getAttribute( 'dir' ) ) { // return ci; // } // } // } return domUtils.filterNodeList(editor.selection.getStartElementPath(), function (n) { return n && n.nodeType == 1 && n.getAttribute('dir') }); }, doDirectionality = function (range, editor, forward) { var bookmark, filterFn = function (node) { return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node); }, obj = getObj(editor); if (obj && range.collapsed) { obj.setAttribute('dir', forward); return range; } bookmark = range.createBookmark(); range.enlarge(true); var bookmark2 = range.createBookmark(), current = domUtils.getNextDomNode(bookmark2.start, false, filterFn), tmpRange = range.cloneRange(), tmpNode; while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) { if (current.nodeType == 3 || !block(current)) { tmpRange.setStartBefore(current); while (current && current !== bookmark2.end && !block(current)) { tmpNode = current; current = domUtils.getNextDomNode(current, false, null, function (node) { return !block(node); }); } tmpRange.setEndAfter(tmpNode); var common = tmpRange.getCommonAncestor(); if (!domUtils.isBody(common) && block(common)) { //遍历到了block节点 common.setAttribute('dir', forward); current = common; } else { //没有遍历到,添加一个block节点 var p = range.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) p.setAttribute('dir', forward); var frag = tmpRange.extractContents(); p.appendChild(frag); tmpRange.insertNode(p); current = p; } current = domUtils.getNextDomNode(current, false, filterFn); } else { current = domUtils.getNextDomNode(current, true, filterFn); } } return range.moveToBookmark(bookmark2).moveToBookmark(bookmark); }; /** * 文字输入方向 * @command directionality * @method execCommand * @param { String } cmdName 命令字符串 * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入 * @example * ```javascript * editor.execCommand( 'directionality', 'ltr'); * ``` */ /** * 查询当前选区的文字输入方向 * @command directionality * @method queryCommandValue * @param { String } cmdName 命令字符串 * @return { String } 返回'ltr'表示从左向右输入,返回'rtl'表示从右向左输入 * @example * ```javascript * editor.queryCommandValue( 'directionality'); * ``` */ UE.commands['directionality'] = { execCommand: function (cmdName, forward) { var range = this.selection.getRange(); //闭合时单独处理 if (range.collapsed) { var txt = this.document.createTextNode('d'); range.insertNode(txt); } doDirectionality(range, this, forward); if (txt) { range.setStartBefore(txt).collapse(true); domUtils.remove(txt); } range.select(); return true; }, queryCommandValue: function () { var node = getObj(this); return node ? node.getAttribute('dir') : 'ltr'; } }; })(); // plugins/horizontal.js /** * 插入分割线插件 * @file * @since 1.2.6.1 */ /** * 插入分割线 * @command horizontal * @method execCommand * @param { String } cmdName 命令字符串 * @example * ```javascript * editor.execCommand( 'horizontal' ); * ``` */ UE.plugins['horizontal'] = function () { var me = this; //分割线悬浮工具栏 function hrTool() { this.editor = null; this.resizer = null; this.doc = document; this.target = null; } var color0 = ('131B26,474C59,8A8B99,A9AFB8,C4C7CC,DCDDDE,EEEFF0,F2F4F7,FFFFFF').split(','); var COLORS = ( 'F33131,FF5502,FC9208,FFE45B,52CC5C,40DAD4,3A8BFF,9C81EB,EB2F97,' + 'FDE0E0,FFE5D9,FFEFDA,FFFBE6,E5F7E7,E2F9F9,E1EEFF,F0ECFC,FCE0EF,' + 'FAA2A2,FFB28D,FECE90,FFF3B5,B1E8B6,A9EEEC,A6CBFF,D2C6F6,F6A1D0,' + 'F54C4C,FF7735,FDA839,FFE97C,75D67D,66E1DD,61A2FF,B09AEF,EF59AC,' + 'CF1313,D44F0D,D47C08,D5B107,2E9937,079C97,0960D9,7B62C4,C41D79' ).split(','); (function () { hrTool.prototype = { init: function (editor) { var _this = this; _this.editor = editor; var resizer = _this.resizer = document.createElement('div'); resizer.innerHTML = '
    ' + '
    ' + '
    ' + _this.editor.getLang('horizontal.lineSetting') + '
    ' + '
    ' + _this.editor.getLang('highLight.colorSetting') + '
    ' + '
    ' + '
    ' + '
    0.25' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    0.5' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    0.75' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    1' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    1.5' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    2.25' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    3.0' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    4.5' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    6.0' + _this.editor.getLang('horizontal.pound') + '
    ' + '
    ' + '
    ' + '
    ' + _this.editor.getLang('horizontal.defaultColor') + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    '; resizer.id = _this.editor.ui.id + '_hrtoolbar'; resizer.className = 'edui-editor-hrtoolbar edui-editor-resizer'; resizer.style.cssText += ';z-index:' + (_this.editor.options.zIndex) + ';'; _this.editor.ui.getDom().appendChild(resizer); //加载颜色 var html = '' for(var i = 0;i < color0.length; i++){ html += ''; } resizer.querySelector('.color_list_first').innerHTML = html; html = '' for(var i = 0;i < COLORS.length; i++){ html += ''; } resizer.querySelector('.color_list_list').innerHTML = html; _this.initEvents(); }, initEvents: function () { var _this = this; //打开线宽设置 $(_this.resizer).on('click','.hr_set_line',function(){ $(_this.resizer).find('.hr_color_setting_div').removeClass('active'); $(_this.resizer).find('.hr_line_setting_div').addClass('active'); }) //点击线宽 $(_this.resizer).on('click','.line_item',function(){ $(this).siblings().removeClass('active'); $(this).addClass('active'); var index = $(this).index() ; var hr = _this.target.querySelector('hr'); hr.className = ''; hr.classList.add('line'+(index+1)); $(_this.resizer).find('.hr_line_setting_div').removeClass('active'); me.fireEvent('contentchange'); me.fireEvent('saveScene'); }) //打开颜色设置 $(_this.resizer).on('click','.hr_set_color',function(){ $(_this.resizer).find('.hr_line_setting_div').removeClass('active'); $(_this.resizer).find('.hr_color_setting_div').addClass('active'); }) //选择默认颜色 $(_this.resizer).on('click','.reset_color',function(){ var hr = _this.target.querySelector('hr'); hr.style.background = ''; me.fireEvent('contentchange'); me.fireEvent('saveScene'); }); //选择颜色 $(_this.resizer).on('click',':not(.reset_color) .color_item',function(){ var hr = _this.target.querySelector('hr'); hr.style.background = this.style.background; $(_this.resizer).find('.hr_color_setting_div').removeClass('active'); me.fireEvent('contentchange'); me.fireEvent('saveScene'); }); }, show: function (targetObj) { var _this = this; _this.resizer.classList.add('hover'); $(_this.resizer).find('.hr_line_setting_div,.hr_color_setting_div,.color_item,.line_item').removeClass('active'); var hr = targetObj.querySelector('hr'); if(hr.className && hr.className.indexOf('line') > -1){ var hrclass = hr.className.replace('line','').replace(' ',''); if(typeof (hrclass-1) == 'number'){ $(_this.resizer).find('.hr_line_setting_div .line_item').eq(hrclass-1).addClass('active'); } } if(hr.style.background){ $(_this.resizer).find('.color_list .color_item[color="'+utils.fixColor('color',hr.style.background)+'"]').addClass('active'); } if (targetObj) _this.attachTo(targetObj); }, hide: function () { var _this = this; _this.resizer.classList.remove('hover'); $(_this.resizer).find('.hr_line_setting_div,.hr_color_setting_div,.color_item,.line_item').removeClass('active'); $(me.body).find('.horizontal').removeClass('hover'); }, attachTo: function (targetObj) { var _this = this, target = _this.target = targetObj, resizer = this.resizer, targetPos = domUtils.getXY(target), iframePos = domUtils.getXY(_this.editor.iframe), editorPos = domUtils.getXY(resizer.parentNode); var index = $(me.body).find('hr').index(target); resizer.setAttribute('index', index); domUtils.setStyles(resizer, { 'width': target.clientWidth + 'px', 'height': 0, 'left': iframePos.x + targetPos.x - _this.editor.document.body.scrollLeft - editorPos.x + 'px', 'top': iframePos.y + targetPos.y - _this.editor.document.body.scrollTop - editorPos.y - 1 + 'px' }); //底部距离不够时,在上方显示 if (iframePos.y + targetPos.y - document.scrollingElement.scrollTop + 188 > $(window).height()) { domUtils.setStyles(resizer.querySelector('.hr_color_setting_div'), { 'top': -188 + 20 + 'px', }); } else { domUtils.setStyles(resizer.querySelector('.hr_color_setting_div'), { 'top': '', }); } if (iframePos.y + targetPos.y - document.scrollingElement.scrollTop + 352 > $(window).height()) { domUtils.setStyles(resizer.querySelector('.hr_line_setting_div'), { 'top': -352 + 'px' }); } else { domUtils.setStyles(resizer.querySelector('.hr_line_setting_div'), { 'top': '' }); } } } })(); me.hrtool = null; me.addListener('mouseover', function (type, evt) { if (evt.target.nodeName == 'DIV' && evt.target.className.indexOf('horizontal') > -1 && evt.target.firstChild.nodeName == 'HR' && !($(evt.target).parents('.edui-editor-hrtoolbar').length == 0 && $(me.container).find('.hrtoolList').css('display') == 'block')) { $(me.body).find('.horizontal').removeClass('hover'); $(evt.target).addClass('hover'); if (me.hrtool && $(me.container).find('.edui-editor-hrtoolbar').hasClass('hover') && $(me.container).find('.edui-editor-hrtoolbar').attr('index') == $(me.body).find('.horizontal').index(evt.target)) { return; } else if (!me.hrtool) { me.hrtool = new hrTool(); me.hrtool.init(me); me.ui.getDom().appendChild(me.hrtool.resizer); } me.hrtool.show(evt.target); } else if (me.hrtool && $(me.container).find('.edui-editor-hrtoolbar').hasClass('hover') && ($(evt.target).is('.horizontal') || $(evt.target).parents('.horizontal').length == 0)) { me.hrtool.hide(); } }) me.addListener('mouseover', function (type, evt) { if (me.hrtool && evt.target.nodeName == 'DIV' && evt.target.className.indexOf('horizontal') > -1 && evt.target.firstChild.nodeName == 'HR') { $(me.body).find('.horizontal').removeClass('hover'); me.hrtool.hide(); } }) me.addInputRule(function (root) { root.traversal(function (node) { if (node.tagName == 'hr' && !(node.parentNode.getAttr('class') && node.parentNode.getAttr('class').indexOf('horizontal') > -1 )) { var div = UE.uNode.createElement('div'); div.setAttr('class', 'horizontal'); div.setAttr('contenteditable', 'false'); div.setAttr('draggable', 'true'); node.parentNode.insertBefore(div, node); div.appendChild(node); } }) }) me.commands['horizontal'] = { execCommand: function (cmdName, value, tmpRange) { var me = this; if (me.queryCommandState(cmdName) !== -1) { var range = me.selection.getRange(); //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { range = tmpRange } start = range.startContainer; var list = domUtils.findParentByTagName(range.startContainer, ['ol', 'ul'], true); var startnode = domUtils.findParentByTagName(range.startContainer, ['p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], true); //规则:列表最后一行加,就加在列表外,列表里面不是最后一行加,就加在列表里面 if (list && startnode.parentNode.lastChild == startnode) { range.setStartAfter(list).collapse(true); if (!list.nextElementSibling || (list.nextElementSibling && list.nextElementSibling.getAttribute('contenteditable') && list.nextElementSibling.getAttribute('contenteditable') == 'false')) { var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) p.innerHTML = '
    '; range.insertNode(p); range.collapse(true); } range.select(); } //2020605 插入分割线后 发送协同数据 var html = '

    ' me.execCommand('insertHtml', html, null, tmpRange); if (start.nodeType == 1 && !start.childNodes[range.startOffset]) { var tmp; if (tmp = start.childNodes[range.startOffset - 1]) { if (tmp.nodeType == 1 && tmp.tagName == 'HR') { if (me.options.enterTag == 'p') { tmp = me.document.createElement('p'); tmp.setAttribute('element-id', domUtils.getRandomId()) range.insertNode(tmp); range.setStart(tmp, 0).setCursor(); } else { tmp = me.document.createElement('br'); tmp.setAttribute('element-id', domUtils.getRandomId()) range.insertNode(tmp); range.setStartBefore(tmp).setCursor(); } } } } return true; } }, //边界在table里不能加分隔线 queryCommandState: function () { return domUtils.filterNodeList(this.selection.getStartElementPath(), 'table') ? -1 : 0; } }; // me.addListener('delkeyup',function(){ // var rng = this.selection.getRange(); // if(browser.ie && browser.version > 8){ // rng.txtToElmBoundary(true); // if(domUtils.isStartInblock(rng)){ // var tmpNode = rng.startContainer; // var pre = tmpNode.previousSibling; // if(pre && domUtils.isTagNode(pre,'hr')){ // domUtils.remove(pre); // rng.select(); // return; // } // } // } // if(domUtils.isBody(rng.startContainer)){ // var hr = rng.startContainer.childNodes[rng.startOffset -1]; // if(hr && hr.nodeName == 'HR'){ // var next = hr.nextSibling; // if(next){ // rng.setStart(next,0) // }else if(hr.previousSibling){ // rng.setStartAtLast(hr.previousSibling) // }else{ // var p = this.document.createElement('p'); // hr.parentNode.insertBefore(p,hr); // domUtils.fillNode(this.document,p); // rng.setStart(p,0); // } // domUtils.remove(hr); // rng.setCursor(false,true); // } // } // }) me.addListener('delkeydown', function (name, evt) { var rng = this.selection.getRange(); rng.txtToElmBoundary(true); if (domUtils.isStartInblock(rng)) { var tmpNode = rng.startContainer; var pre = tmpNode.previousSibling; if (pre && domUtils.isTagNode(pre, 'hr')) { domUtils.remove(pre); rng.select(); domUtils.preventDefault(evt); return true; } } }) }; // 20210927 在线表格 UE.plugins['onlinetable'] = function () { var me = this; me.commands['onlinetable'] = { execCommand: function (cmdName, value, tmpRange) { var me = this; var appDomain = window.location.protocol + '//appswh.chaoxing.com' if(window.obj && window.obj.mirrorDomain){ appDomain = window.location.protocol + window.obj.mirrorDomain.appsWhDomainHttps.replace('https:','').replace('http:',''); } var cid = RichTextUitl.randomUUID(); var url = appDomain + "/res/Spreadsheets/wpsPC.html?cid=" + cid + '&editorid=' + me.key var json = { "att_web": { "content": "", "logo": RichTextUitl.noteDomain + "/res/images/pc/note/attachIcon/onlineexcel.png", "showContent": 0, "title": "无标题", "url": url, "excel": 1, }, "attachmentType": 25, "cid": cid } var noteCidStr = ''; if (typeof WinInitConfig != 'undefined' && WinInitConfig.noteCid) { // 如果是笔记协作人,也要有表格的编辑权限,在地址上面加上笔记cid,表格那边会根据笔记cid查协作人 noteCidStr = '¬eCid=' + WinInitConfig.noteCid json.att_web.url += noteCidStr } var iframename = RichTextUitl.b64EncodeUnicode(JSON.stringify(json)); var appDomain = window.location.protocol + '//appswh.chaoxing.com' if(window.obj && window.obj.mirrorDomain){ appDomain = window.location.protocol + window.obj.mirrorDomain.appsWhDomainHttps.replace('https:','').replace('http:',''); } var iframesrc = appDomain + "/res/Spreadsheets/wpsPC.html?isEditorStatus=1&cid=" + cid + noteCidStr + '&editorid=' + me.key; me.execCommand('insertHtml', "
    "); return true; }, //边界在table里不能加分隔线 queryCommandState: function () { return domUtils.filterNodeList(this.selection.getStartElementPath(), 'table') ? -1 : 0; } }; }; // plugins/time.js /** * 插入时间和日期 * @file * @since 1.2.6.1 */ /** * 插入时间,默认格式:12:59:59 * @command time * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'time'); * ``` */ /** * 插入日期,默认格式:2013-08-30 * @command date * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'date'); * ``` */ UE.commands['time'] = UE.commands["date"] = { execCommand: function (cmd, format) { var date = new Date; function formatTime(date, format) { var hh = ('0' + date.getHours()).slice(-2), ii = ('0' + date.getMinutes()).slice(-2), ss = ('0' + date.getSeconds()).slice(-2); format = format || 'hh:ii:ss'; return format.replace(/hh/ig, hh).replace(/ii/ig, ii).replace(/ss/ig, ss); } function formatDate(date, format) { var yyyy = ('000' + date.getFullYear()).slice(-4), yy = yyyy.slice(-2), mm = ('0' + (date.getMonth() + 1)).slice(-2), dd = ('0' + date.getDate()).slice(-2); format = format || 'yyyy-mm-dd'; return format.replace(/yyyy/ig, yyyy).replace(/yy/ig, yy).replace(/mm/ig, mm).replace(/dd/ig, dd); } this.execCommand('insertHtml', cmd == "time" ? formatTime(date, format) : formatDate(date, format)); } }; // plugins/rowspacing.js /** * 段前段后间距插件 * @file * @since 1.2.6.1 */ /** * 设置段间距 * @command rowspacing * @method execCommand * @param { String } cmd 命令字符串 * @param { String } value 段间距的值,以px为单位 * @param { String } dir 间距位置,top或bottom,分别表示段前和段后 * @example * ```javascript * editor.execCommand( 'rowspacing', '10', 'top' ); * ``` */ UE.plugins['rowspacing'] = function () { var me = this; me.setOpt({ 'rowspacingtop': ['5', '10', '15', '20', '25'], 'rowspacingbottom': ['5', '10', '15', '20', '25'] }); me.commands['rowspacing'] = { execCommand: function (cmdName, value, dir) { this.execCommand('paragraph', 'p', { style: 'margin-' + dir + ':' + value + 'px' }); return true; }, queryCommandValue: function (cmdName, dir) { var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function (node) { return domUtils.isBlockElm(node) }), value; //trace:1026 if (pN) { value = domUtils.getComputedStyle(pN, 'margin-' + dir).replace(/[^\d]/g, ''); return !value ? 0 : value; } return 0; } }; }; // plugins/lineheight.js /** * 设置行内间距 * @file * @since 1.2.6.1 */ UE.plugins['lineheight'] = function () { var me = this; me.setOpt({ 'lineheight': ['1', '1.25', '1.5', '1.75', '2', '2.5', '3'] }); /** * 行距 * @command lineheight * @method execCommand * @param { String } cmdName 命令字符串 * @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75 * @example * ```javascript * editor.execCommand( 'lineheight', 1.5); * ``` */ /** * 查询当前选区内容的行高大小 * @command lineheight * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回当前行高大小 * @example * ```javascript * editor.queryCommandValue( 'lineheight' ); * ``` */ me.commands['lineheight'] = { execCommand: function (cmdName, value, tmpRange) { var me = this, rng = me.selection.getRange(); //20200619 tmpRange是协同恢复的时候用的range if (tmpRange) { rng = tmpRange; } if (rng.collapsed == false && rng.startContainer == rng.endContainer && rng.startContainer.nodeName == 'DIV' && rng.startContainer.className && rng.startContainer.className == 'editor-image') { } else { this.execCommand('paragraph', 'p', { style: 'line-height:' + value }); // this.execCommand('paragraph','p',{style:'line-height:'+ (value == "1" ? "normal" : value + 'em') }); } return true; }, queryCommandValue: function () { var pN = domUtils.filterNodeList(this.selection.getStartElementPath(), function (node) { return domUtils.isBlockElm(node) }); if (pN) { var value = domUtils.getComputedStyle(pN, 'line-height'); return value == 'normal' ? 1 : value.replace(/[^\d.]*/ig, ""); } } }; }; //加置顶按钮 UE.plugins['toTop'] = function () { var me = this; if(!me.options.showToTop){ return; } me.addListener('ready', function () { var div = document.createElement('div'); div.className = 'ueditor_totop'; div.cssText = 'display:none'; div.innerHTML = '

    返回顶部
    '; me.container.appendChild(div); div.onclick = function () { me.body.firstChild.scrollIntoView(); scrollDiv.scrollBy(0, -200); } var scrollDiv = document.scrollingElement; if (me.options.topOffsetScrollDiv) { scrollDiv = document.querySelector(me.options.topOffsetScrollDiv); var beforeScrollTop = $(scrollDiv).scrollTop(), afterScrollTop; $(scrollDiv).scroll(function () { if (me.selection.isFocus()) { $(me.container).find('.ueditor_totop').show() } else { $(me.container).find('.ueditor_totop').hide() return; } var editorToLeft = me.container.getBoundingClientRect().x + $(me.container).width(); if (editorToLeft + 40 < $(window).width()) { $(me.container).find('.ueditor_totop').css('right', $(scrollDiv).width() - editorToLeft + $(scrollDiv).scrollLeft() + 20) } afterScrollTop = $(scrollDiv).scrollTop(); if (beforeScrollTop != afterScrollTop) { //上下滚动 beforeScrollTop = afterScrollTop; // 编辑器底部距离窗口顶部的距离 var toWinTop = me.container.getBoundingClientRect().y + $(me.container).height(); if (me.container.getBoundingClientRect().y + 100 > $(scrollDiv).height() || toWinTop < 0) { //还未滚动到编辑器位置或已经滚动到看不见的位置 $(me.container).find('.ueditor_totop').hide(); } if (toWinTop > $(scrollDiv).height()) {//底部未完全露出来,还未滚动到底部 //滚动div底部距离窗口顶部的距离 var divToWinTop = $(scrollDiv).offset().top + $(scrollDiv).height(); $(me.container).find('.ueditor_totop').css({'top': divToWinTop - 80}); } else { //底部已露出来 $(me.container).find('.ueditor_totop').css({'top': toWinTop - 80}); } } }) } else { var beforeScrollTop = $(window).scrollTop(), afterScrollTop; function showToTop() { if (me.selection.isFocus()) { $(me.container).find('.ueditor_totop').show() } else { $(me.container).find('.ueditor_totop').hide() return; } var editorToLeft = me.container.getBoundingClientRect().x + $(me.container).width() if (editorToLeft + 40 < $(window).width()) { $(me.container).find('.ueditor_totop').css('right', $(window).width() - editorToLeft + $(window).scrollLeft() + 20) } afterScrollTop = $(window).scrollTop(); if (beforeScrollTop != afterScrollTop) { //上下滚动 beforeScrollTop = afterScrollTop; // 编辑器底部距离窗口顶部的距离 var toWinTop = me.container.getBoundingClientRect().y + $(me.container).height(); if (me.container.getBoundingClientRect().y + 100 > $(window).height() || toWinTop < 0) { //还未滚动到编辑器位置或已经滚动到看不见的位置 $(me.container).find('.ueditor_totop').hide(); } if (toWinTop > $(window).height()) {//底部未完全露出来,还未滚动到底部 $(me.container).find('.ueditor_totop').css({'top': $(scrollDiv).height() - 80}); } else { //底部已露出来 $(me.container).find('.ueditor_totop').css({'top': toWinTop - 80}); } } } domUtils.on(window, 'scroll', showToTop) me.addListener('destroy', function () { domUtils.un(window, ['scroll'], showToTop); }); } }) } //常驻工具栏 UE.plugins['hoverTools'] = function () { var me = this; if (!me.options.showHoverTools) { return; } //悬浮工具栏 function hoverTool() { this.editor = null; this.resizer = null; this.doc = document; this.target = null; } (function () { hoverTool.prototype = { init: function (editor) { var _this = this; _this.editor = editor; var resizer = _this.resizer = document.createElement('div'); resizer.innerHTML = '
    ' + '
    ' + '
    ' + '
    ' + editor.getLang('toolbarCmds.base') + '
    ' + '
    ' + '
    ' + '
    ' + editor.getLang("contextMenu.insert") + '
    ' + '
    ' + '
    ' + editor.getLang("labelMap.checkbox") + '
    ' + '
    ' + editor.getLang("labelMap.insertimage") + '
    ' + '
    ' + editor.getLang("labelMap.attachment") + '
    ' + '
    ' + editor.getLang("labelMap.inserttable") + '' + '
    ' + editor.getLang("contextMenu.inserttable") + '
    ' + '
    ' + '' + '
    ' + editor.getLang("labelMap.insertcode") + '
    ' + '
    ' + editor.getLang("labelMap.horizontal") + '
    ' + '
    ' + '
    ' + editor.getLang("labelMap.mindmap") + '
    ' + '
    ' + '
    ' + editor.getLang("labelMap.onlinetable") + '
    ' + '
    ' + '
    ' + '
    '; resizer.id = _this.editor.ui.id + '_hoverToolbar'; resizer.className = 'edui-editor-hoverToolbar edui-editor-resizer'; resizer.style.cssText += ';z-index:' + (_this.editor.options.zIndex + 3) + ';'; _this.editor.ui.getDom().appendChild(resizer); _this.initEvents(); _this.numRows = 10; _this.numCols = 10; }, initEvents: function () { var _this = this; // $(_this.resizer).on('mouseleave',function(e){ // _this.show(_this.target); // }) $(_this.resizer).on('mouseover', '.add', function (e) { e.preventDefault() if ($(_this.resizer).find('.toolListWrap').css('display') == 'none') { $(_this.resizer).find('.toolListWrap').fadeIn(); } }) //点击基础 $(_this.resizer).on('click', '.cmdList span', function () { var range = me.selection.getRange(); range.setStart(_this.target, 0).collapse(true) var cmd = $(this).removeClass('active').attr('class'); switch (cmd) { case 'h1': if (_this.target.tagName == 'H1') { me.execCommand('paragraph', 'p'); } else { me.execCommand('paragraph', 'h1'); } break; case 'h2': if (_this.target.tagName == 'H2') { me.execCommand('paragraph', 'p'); } else { me.execCommand('paragraph', 'h2'); } break; case 'h3': if (_this.target.tagName == 'H3') { me.execCommand('paragraph', 'p'); } else { me.execCommand('paragraph', 'h3'); } break; case 'h4': if (_this.target.tagName == 'H4') { me.execCommand('paragraph', 'p'); } else { me.execCommand('paragraph', 'h4'); } break; default: me.execCommand(cmd); } _this.hide(); }) //点击插入 $(_this.resizer).on('click', '.iconCmd', function () { var range = me.selection.getRange(); range.setStart(_this.target, 0).collapse(true) var cmd = $(this).attr('class').replace('iconCmd ', ''); switch (cmd) { case 'insertimage': $(me.container).find('.edui-for-insertimage .webuploader-element-invisible').click() break; case 'insertfile': $(me.container).find('.edui-for-attachment .webuploader-element-invisible').click() break; case 'link': $(me.container).find('.edui-for-link .edui-button-body').click() break; case 'inserttable': break; case 'onlinetable': $(me.container).find('.edui-for-onlinetable .edui-button-body').click() break; case 'mindMap': $(me.container).find('.edui-for-mindmap .edui-button-body').click() break; default: me.execCommand(cmd); break; } _this.hide(); }) //表格选择 $(_this.resizer).on('mouseover', '.edui-pickarea', function (evt) { var el = evt.currentTarget; var rel = evt.relatedTarget || evt.fromElement; if ($(rel).parents(el).length == 0 && el !== rel) { _this.resizer.querySelector('.edui-tablepicker .edui-label').innerHTML = me.getLang("contextMenu.inserttable"); _this.resizer.querySelector('.edui-tablepicker .edui-overlay').style.cssText = ''; } }).on('mousemove', '.edui-pickarea', function (evt) { var style = _this.resizer.querySelector('.edui-tablepicker .edui-overlay').style; var sideLen = 19; var numCols = Math.ceil(evt.offsetX / sideLen); var numRows = Math.ceil(evt.offsetY / sideLen); style.width = numCols * sideLen + 'px'; style.height = numRows * sideLen + 'px'; _this.resizer.querySelector('.edui-tablepicker .edui-label').innerHTML = me.getLang("contextMenu.inserttable") + ' ' + numCols + ' x ' + numRows + ''; _this.numCols = numCols; _this.numRows = numRows; }).on('mouseleave', '.edui-pickarea', function (evt) { _this.resizer.querySelector('.edui-tablepicker .edui-label').innerHTML = me.getLang("contextMenu.inserttable"); _this.resizer.querySelector('.edui-tablepicker .edui-overlay').style.cssText = ''; }).on('click', '.edui-pickarea', function () { _this.resizer.querySelector('.edui-tablepicker .edui-label').innerHTML = me.getLang("contextMenu.inserttable"); _this.resizer.querySelector('.edui-tablepicker .edui-overlay').style.cssText = ''; me.execCommand('InsertTable', { numRows: _this.numRows, numCols: _this.numCols, border: 1 }); }) }, show: function (targetObj) { var _this = this; _this.resizer.querySelector('.edui-tablepicker .edui-label').innerHTML = me.getLang("contextMenu.inserttable"); _this.resizer.querySelector('.edui-tablepicker .edui-overlay').style.cssText = ''; $(_this.resizer).find('.cmdList span').removeClass('active'); if (/h\d/i.test(targetObj.tagName)) { switch (targetObj.tagName) { case 'H1': $(_this.resizer).find('.h1').addClass('active'); break; case 'H2': $(_this.resizer).find('.h2').addClass('active'); break; case 'H3': $(_this.resizer).find('.h3').addClass('active'); break; case 'H4': $(_this.resizer).find('.h4').addClass('active'); break; } } _this.resizer.classList.add('hover'); $(_this.resizer).show(); if (targetObj) _this.attachTo(targetObj); }, hide: function () { var _this = this; _this.resizer.classList.remove('hover') $(_this.resizer).hide(); // $(_this.resizer).find('.toolListWrap').fadeOut(); }, attachTo: function (targetObj) { var _this = this, target = _this.target = targetObj, resizer = this.resizer, targetPos = domUtils.getXY(target), iframePos = domUtils.getXY(_this.editor.iframe), editorPos = domUtils.getXY(resizer.parentNode); var index = $(me.body).find('p,div,h1,h2,h3,h4,h5,h6').index(target); resizer.setAttribute('index', index); var lineheight = $(target).height(); domUtils.setStyles(resizer, { 'left': iframePos.x + targetPos.x - _this.editor.document.scrollingElement.scrollLeft - editorPos.x + 'px', 'top': iframePos.y + targetPos.y - _this.editor.document.scrollingElement.scrollTop - editorPos.y + parseInt(lineheight / 2 - 12) + 'px', }); var iframetooltop = iframePos.y + targetPos.y - document.scrollingElement.scrollTop; //距离顶部窗口的距离 resizer.querySelector('.toolListWrap').style.display = "block"; var iframesetHeight = resizer.querySelector('.toolListWrap').offsetHeight; resizer.querySelector('.toolListWrap').style.display = ""; if (iframePos.x + targetPos.x < 246) { //左侧空间不够 if (iframetooltop + iframesetHeight + 20 > $(window).height() && _this.editor.body.clientHeight - targetPos.y - lineheight < iframesetHeight) { //底部空间都不够 domUtils.setStyles(resizer.querySelector('.toolListWrap'), { 'top': _this.editor.body.clientHeight - targetPos.y - iframesetHeight + 'px', 'left': '-6px', }); } else { domUtils.setStyles(resizer.querySelector('.toolListWrap'), { 'top': '24px', 'left': '-28px', }); } } else { //左侧空间足够 if (iframetooltop + iframesetHeight + 10 > $(window).height() && _this.editor.body.clientHeight - targetPos.y - lineheight < iframesetHeight) { //底部空间不够 domUtils.setStyles(resizer.querySelector('.toolListWrap'), { 'top': _this.editor.body.clientHeight - targetPos.y - iframesetHeight + 'px', 'left': '' }); } else { domUtils.setStyles(resizer.querySelector('.toolListWrap'), { 'top': '', 'left': '', }); } } } } })(); //常驻工具栏 me.hovertool = null; me.addListener('mouseover', function (type, evt) { var start = evt.target; if (domUtils.isBody(start)) return; while (!domUtils.isBlockElm(start) && !domUtils.isBody(start.parentNode)) { start = start.parentNode } if (domUtils.isEmptyBlock(start) && $(start).find('img,canvas,hr,iframe').length == 0 && $(start).is('p,div,h1,h2,h3,h4,h5,h6') && $(start).parents('li,blockquote,.callout-block,table,.notice_main,.todo-view,.signDiv,.record-box,.report_main,.editor-iframe,.drag-image-wrap').length == 0 && !$(start).is('li,blockquote,.callout-block,table,.notice_main,.todo-view,.signDiv,.record-box,.report_main,.editor-iframe,.drag-image-wrap,#ue_tableDragLine')) { if (me.hovertool && $(me.container).find('.edui-editor-hoverToolbar').hasClass('hover') && $(me.container).find('.edui-editor-hoverToolbar').attr('index') == $(me.body).find('p,div,h1,h2,h3,h4,h5,h6').index(evt.target)) { return; } else if (!me.hovertool) { me.hovertool = new hoverTool(); me.hovertool.init(me); me.ui.getDom().appendChild(me.hovertool.resizer); } me.hovertool.show(start); } else if (me.hovertool && $(me.container).find('.edui-editor-hoverToolbar').hasClass('hover') && !(domUtils.isEmptyBlock(start) && $(start).find('img,canvas,hr,iframe').length == 0)) { me.hovertool.hide(); } }) me.addListener('ready', function (type, evt) { me.container.classList.add('hover') $(me.body).on('keydown', function (e) { var range = me.selection.getRange(); var start = range.startContainer; if (domUtils.isBody(start)) return; while (!domUtils.isBlockElm(start) && !domUtils.isBody(start.parentNode)) { start = start.parentNode } if (me.hovertool && $(me.container).find('.edui-editor-hoverToolbar').hasClass('hover') && !(domUtils.isEmptyBlock(start) && $(start).find('img,canvas,hr,iframe').length == 0)) { me.hovertool.hide(); } }) $(me.body).on('keyup', function (e) { var range = me.selection.getRange(); var start = range.startContainer; if (domUtils.isBody(start)) return; while (!domUtils.isBlockElm(start) && !domUtils.isBody(start.parentNode)) { start = start.parentNode } if (domUtils.isEmptyBlock(start) && $(start).find('img,canvas,hr,iframe').length == 0 && $(start).parents('li,blockquote,.callout-block,table,.notice_main,.todo-view,.signDiv,.record-box,.report_main,.editor-iframe,.drag-image-wrap').length == 0) { if (!me.hovertool) { me.hovertool = new hoverTool(); me.hovertool.init(me); me.ui.getDom().appendChild(me.hovertool.resizer); } me.hovertool.show(start); } }) }) $('body').on('mouseover', function (e) { if ($(e.target).parents('.edui-editor-hoverToolbar,.edui-editor-iframeholder').length == 0 && !$(e.target).is('.edui-editor-hoverToolbar') && me.hovertool && $(me.container).find('.edui-editor-hoverToolbar').hasClass('hover')) { me.hovertool.hide(); } }) } // 135编辑器 UE.plugins['135editor'] = function(){ var me = this; // if (!me.options.showHoverTools) { // return; // } // 135编辑器 var editor135; function onContentFrom135(event) { if (typeof event.data !== 'string') { if(event.data.ready) { editor135.postMessage(me.getContent(),'*'); } return; }; if(event.data.indexOf('<') !== 0) return; var html = '
    ' + event.data + '
    ' me.setContent(html); window.removeEventListener('message', onContentFrom135); } me.commands['135editor'] = { execCommand: function (cmd, lang) { editor135 = window.open('https://www.135editor.com/beautify_editor.html?callback=true&appkey=','135editor','height='+(window.screen.availHeight-200)+',width='+(window.screen.availWidth-200)+',top=100,left=100,help=no,resizable=no,status=no,scroll=no') window.removeEventListener('message', onContentFrom135); window.addEventListener('message', onContentFrom135, false); } } } // plugins/insertcode.js /** * 插入代码插件 * @file * @since 1.2.6.1 */ UE.plugins['insertcode'] = function () { var me = this; //代码块显示工具栏 me.codetool = null; me.addListener('mouseover', function (type, evt) { if (evt.target.tagName == 'PRE' && !($(evt.target).parents('.edui-editor-codetoolbar').length == 0 && $(me.container).find('.codetoolList').css('display') == 'block')) { $(me.body).find('pre').removeClass('hover'); $(evt.target).addClass('hover'); if (me.codetool && $(me.container).find('.edui-editor-codetoolbar').hasClass('hover') && $(me.container).find('.edui-editor-codetoolbar').attr('index') == $(me.body).find('pre').index(evt.target)) { return; } else if (!me.codetool) { me.codetool = new codeTool(); me.codetool.init(me); me.ui.getDom().appendChild(me.codetool.resizer); } me.codetool.show(evt.target); } else if (me.codetool && $(me.container).find('.edui-editor-codetoolbar').hasClass('hover') && (evt.target.tagName != 'PRE' && $(evt.target).parents('pre').length == 0)) { me.codetool.hide(); } }) me.addListener('ready', function (type, evt) { $(me.body).on('keydown', function (e) { if (e.keyCode == 8) { var range = me.selection.getRange(); //解决鼠标在代码块工具栏上时,删除代码块后工具栏不消失的问题 if (me.codetool && $(me.container).find('.edui-editor-codetoolbar').hasClass('hover') && domUtils.isStartInblock(range) && range.startContainer.nodeType == 1 && (range.startContainer.nodeName == 'CODE' || range.startContainer.nodeName == 'PRE') && range.startContainer.innerText.trim() == '') { me.codetool.hide(); } } }) }) $('body').on('mouseover', function (e) { if ($(e.target).parents('.edui-editor-codetoolbar').length == 0 && !$(e.target).is('.edui-editor-codetoolbar') && me.codetool && $(me.container).find('.edui-editor-codetoolbar').hasClass('hover')) { me.codetool.hide(); } }) //悬浮列表工具栏 function codeTool() { this.editor = null; this.resizer = null; this.doc = document; this.target = null; this.codeList = ['Plain Text', 'Bash', 'C/C++', 'CSS', 'Diff', 'C#', 'Go', 'HTML', 'JSON', 'Java', 'JavaScript', 'Less', 'Objective-C', 'PHP', 'Python', 'SCSS', 'SQl', 'XML'] } (function () { codeTool.prototype = { init: function (editor) { var _this = this; _this.editor = editor; var resizer = _this.resizer = document.createElement('div'); resizer.innerHTML = '
    ' + '
    ' + '

    PlainText

    ' + '
    ' + '
    ' + '' + '' + '' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + editor.getLang('codeBlock.autolineBreak') + '
    ' + '
    ' + editor.getLang('toolbarCmds.copy') + '
    ' + '
    ' + editor.getLang('toolbarCmds.delete') + '
    ' + '
    ' + '
    '; resizer.id = _this.editor.ui.id + '_codetoolbar'; resizer.className = 'edui-editor-codetoolbar edui-editor-resizer'; resizer.style.cssText += ';z-index:' + (_this.editor.options.zIndex) + ';'; _this.editor.ui.getDom().appendChild(resizer); _this.initEvents(); }, initEvents: function () { var _this = this; //打开代码列表 $(_this.resizer).on('click', '.now-lang', function (e) { $(_this.resizer).find('.langList-wrap').addClass('show'); }); //选中代码列表 $(_this.resizer).on('click', '.langList .item', function (e) { $(_this.resizer).find('.now-lang span').text($(this).text()) $(_this.resizer).find('.langList-wrap').removeClass('show'); _this.target.querySelector('code').className = _this.target.querySelector('code').className.replace(/language-[^\s]*/, 'language-' + $(this).text().replace(/\s/g, '')) _this.target.querySelector('code').setAttribute('lang', $(this).text()) }); //搜索 $(_this.resizer).on('keyup', '.dataSearch_input', function () { var val = $(this).val().toLowerCase().trim(); var temphtml = ''; if (val != '') { for (var i = 0; i < _this.codeList.length; i++) { if (_this.codeList[i].toLowerCase().indexOf(val) > -1) { temphtml += '

    ' + _this.codeList[i] + '

    ' } } } else { for (var i = 0; i < _this.codeList.length; i++) { temphtml += '

    ' + _this.codeList[i] + '

    ' } } _this.resizer.querySelector('.langList').innerHTML = '
    ' + temphtml + '
    '; }) //兼容处理360、搜狗浏览器输入中文后按enter没有立即开始搜索的问题 $('body').on('keydown', '.dataSearch_input', function () { var that = this; setTimeout(function () { var val = $(that).val().toLowerCase().trim(); var temphtml = ''; if (val != '') { for (var i = 0; i < _this.codeList.length; i++) { if (_this.codeList[i].toLowerCase().indexOf(val) > -1) { temphtml += '

    ' + _this.codeList[i] + '

    ' } } } else { for (var i = 0; i < _this.codeList.length; i++) { temphtml += '

    ' + _this.codeList[i] + '

    ' } } _this.resizer.querySelector('.langList').innerHTML = '
    ' + temphtml + '
    '; }, 100) }) //自动换行 $(_this.resizer).on('click', '.linebreak', function () { if ($(_this.target).hasClass('autolinebreak')) { $(_this.target).removeClass('autolinebreak') $(this).find('span').text(_this.editor.getLang('codeBlock.autolineBreak')) } else { $(_this.target).addClass('autolinebreak') $(this).find('span').text(_this.editor.getLang('codeBlock.cancleLineBreak')) } }) //复制 $(_this.resizer).on('click', '.copy', function () { if (!window.dt) { var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } url = prefix + "third-party/clipboard-polyfill.promise.js"; utils.loadFile(document, { src: url, tag: "script", type: "text/javascript", defer: "defer" }, function () { copyCode(_this.target) }); } else { copyCode(_this.target) } }) function copyCode(node) { if (!window.dt) { window.dt = new clipboard.DT(); } var html = '
    ' + node.innerHTML + '
    '; dt.setData("text/html", html); dt.setData('text/plain', node.innerText) clipboard.write(dt).then(function () { $('.edui-editor-resizer').removeClass('hover'); if ($('.toolTipBox').length > 0) { $('.toolTipBox').remove() } var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } $('body').append('
    ' + _this.editor.getLang('tips.copySuccess') + '
    ') setTimeout(function () { $('.toolTipBox').fadeOut(); }, 1500) }, function (err) { RichTextUitl.showTips(_this.editor.getLang('tips.copyFail')) }); } //删除 $(_this.resizer).on('click', '.remove', function () { me.deleteEle(this, 'pre') }) }, show: function (targetObj) { var _this = this; var lang = targetObj.querySelector('code').getAttribute('lang') || 'Plain Text'; _this.resizer.querySelector('.now-lang').firstChild.innerText = lang; if (targetObj.className.indexOf('autolinebreak') > -1) { _this.resizer.querySelector('.linebreak').querySelector('span').innerText = _this.editor.getLang('codeBlock.cancleLineBreak') } else { _this.resizer.querySelector('.linebreak').querySelector('span').innerText = _this.editor.getLang('codeBlock.autolineBreak') } var temphtml = ''; for (var i = 0; i < _this.codeList.length; i++) { temphtml += '

    ' + _this.codeList[i] + '

    ' } _this.resizer.querySelector('.langList').innerHTML = '
    ' + temphtml + '
    '; _this.resizer.classList.add('hover'); _this.resizer.querySelector('.dataSearch_input').value = ''; _this.resizer.querySelector('.langList-wrap').classList.remove('show'); if (targetObj) _this.attachTo(targetObj); }, hide: function () { var _this = this; _this.resizer.classList.remove('hover'); _this.resizer.querySelector('.dataSearch_input').value = ''; _this.resizer.querySelector('.langList-wrap').classList.remove('show'); }, attachTo: function (targetObj) { var _this = this, target = _this.target = targetObj, resizer = this.resizer, targetPos = domUtils.getXY(target), iframePos = domUtils.getXY(_this.editor.iframe), editorPos = domUtils.getXY(resizer.parentNode); var index = $(me.body).find('pre').index(target); resizer.setAttribute('index', index); domUtils.setStyles(resizer, { 'width': target.clientWidth - 40 + 'px', 'height': 0, 'left': iframePos.x + targetPos.x - _this.editor.document.body.scrollLeft - editorPos.x + 'px', 'top': iframePos.y + targetPos.y - _this.editor.document.body.scrollTop - editorPos.y + 'px' }); } } })(); /** * 插入代码 * @command insertcode * @method execCommand * @param { String } cmd 命令字符串 * @param { String } lang 插入代码的语言 * @example * ```javascript * editor.execCommand( 'insertcode', 'javascript' ); * ``` */ /** * 如果选区所在位置是插入插入代码区域,返回代码的语言 * @command insertcode * @method queryCommandValue * @param { String } cmd 命令字符串 * @return { String } 返回代码的语言 * @example * ```javascript * editor.queryCommandValue( 'insertcode' ); * ``` */ me.commands['insertcode'] = { execCommand: function (cmd, lang) { var me = this, rng = me.selection.getRange(), pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true); if (pre) { //取消代码块 } else { var code = ''; if (rng.collapsed) { code = browser.ie && browser.ie11below ? (browser.version <= 8 ? ' ' : '') : '
    '; } else { var frag = rng.extractContents(); var div = me.document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()) div.appendChild(frag); utils.each(UE.filterNode(UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, '')), me.options.filterTxtRules).children, function (node) { if (browser.ie && browser.ie11below && browser.version > 8) { if (node.type == 'element') { if (node.tagName == 'br') { code += '\n' } else if (!dtd.$empty[node.tagName]) { utils.each(node.children, function (cn) { if (cn.type == 'element') { if (cn.tagName == 'br') { code += '\n' } else if (!dtd.$empty[node.tagName]) { code += cn.innerText(); } } else { code += cn.data } }) if (!/\n$/.test(code)) { code += '\n'; } } } else { code += node.data + '\n' } if (!node.nextSibling() && /\n$/.test(code)) { code = code.replace(/\n$/, ''); } } else { if (browser.ie && browser.ie11below) { if (node.type == 'element') { if (node.tagName == 'br') { code += '
    ' } else if (!dtd.$empty[node.tagName]) { utils.each(node.children, function (cn) { if (cn.type == 'element') { if (cn.tagName == 'br') { code += '
    ' } else if (!dtd.$empty[node.tagName]) { code += cn.innerText(); } } else { code += cn.data } }); if (!/br>$/.test(code)) { code += '
    '; } } } else { code += node.data + '
    ' } if (!node.nextSibling() && /
    $/.test(code)) { code = code.replace(/
    $/, ''); } } else { code += (node.type == 'element' ? (dtd.$empty[node.tagName] ? '' : node.innerText()) : node.data); if (!/br\/?\s*>$/.test(code)) { if (!node.nextSibling()) return; code += '
    ' } } } }); } //20200605 发送协同数据 // var html = '
    ' + code + '
    ' var html = '
    ' + code + '

    ' me.sendhtml(html); me.execCommand('inserthtml', html, true); // if(typeof me.window.hljs != 'undefined'){ // me.window.hljs.highlightAll() // } code = me.document.getElementById('coder'); domUtils.removeAttributes(code, 'id'); var tmpNode = code.parentNode.previousSibling; if (tmpNode && (tmpNode.nodeType == 3 && tmpNode.nodeValue.length == 1 && browser.ie && browser.version == 6 || domUtils.isEmptyBlock(tmpNode))) { domUtils.remove(tmpNode) } var rng = me.selection.getRange(); if (domUtils.isEmptyBlock(code)) { rng.setStart(code, 0).setCursor(false, true) } else { rng.selectNodeContents(code.parentNode).select() } } }, //光标在table里不能加代码块 queryCommandState: function () { return domUtils.filterNodeList(this.selection.getStartElementPath(), 'table') ? -1 : 0; }, queryCommandValue: function () { var path = this.selection.getStartElementPath(); var lang = ''; utils.each(path, function (node) { if (node.nodeName == 'CODE') { lang = node.getAttribute('lang'); return false; } }); return lang; } }; me.addInputRule(function (root) { root.traversal(function (node) { switch (node.tagName) { case 'code': node.setAttr('style', '') // node.innerHTML(node.toHtml().replace(/]+>/g, '\n').replace(/<[^>]+>/g, '').replace(/\n/g, '
    ')); if (node.parentNode.tagName != 'pre') { var pre = UE.uNode.createElement('pre'); pre.setAttr('element-id', domUtils.getRandomId()) pre.setAttr('class', 'line-numbers'); node.parentNode.insertBefore(pre, node); pre.appendChild(node); } if (node.getAttr('class') && node.getAttr('class').indexOf('language-') > -1 && !node.getAttr('lang')) { var match = node.getAttr('class').match(/language-([^;\s]+)/); var lang = match && match[1] ? match[1] : ''; node.setAttr('lang', lang); } node.innerHTML(node.innerHTML().replace(/]+>/g, ' ').replace(/<[^>]+>/g, '').replace(/ /g, '
    ')); break; case 'pre': if (node.getAttr('class') && node.getAttr('class').indexOf('autolinebreak') > -1) { node.setAttr('class', 'autolinebreak') } else { node.setAttr('class', '') } node.setAttr('style', '') if (node.getNodesByTagName('code').length == 0) { node.innerHTML(node.innerHTML().replace(/]+>/g, ' ').replace(/<[^>]+>/g, '').replace(/ /g, '
    ')); var code = UE.uNode.createElement('code'); code.setAttr('lang', 'Plain Text'); code.setAttr('element-id', domUtils.getRandomId()); while (node.firstChild()) { code.appendChild(node.firstChild()); } node.appendChild(code); } } }) utils.each(root.getNodesByTagName('code'), function (pre) { var brs = pre.getNodesByTagName('br'); if (brs.length) { browser.ie && browser.ie11below && browser.version > 8 && utils.each(brs, function (br) { var txt = UE.uNode.createText('\n'); br.parentNode.insertBefore(txt, br); br.parentNode.removeChild(br); }); return; } if (browser.ie && browser.ie11below && browser.version > 8) return; var code = pre.innerText().split(/\n/); pre.innerHTML(''); utils.each(code, function (c) { if (c.length) { pre.appendChild(UE.uNode.createText(c)); } pre.appendChild(UE.uNode.createElement('br')) }) }) }); //不需要判断highlight的command列表 me.notNeedCodeQuery = { help: 1, undo: 1, redo: 1, source: 1, print: 1, searchreplace: 1, fullscreen: 1, preview: 1, insertparagraph: 1, elementpath: 1, insertcode: 1, inserthtml: 1, selectall: 1 }; //将queyCommamndState重置 var orgQuery = me.queryCommandState; me.queryCommandState = function (cmd) { var me = this; if (!me.notNeedCodeQuery[cmd.toLowerCase()] && me.selection && me.queryCommandValue('insertcode')) { return -1; } return UE.Editor.prototype.queryCommandState.apply(this, arguments) }; me.addListener('beforeenterkeydown', function () { var rng = me.selection.getRange(); var pre = domUtils.findParentByTagName(rng.startContainer, 'code', true); if (pre) { me.fireEvent('saveScene'); if (!rng.collapsed) { rng.deleteContents(); } if (!browser.ie || browser.ie9above) { var tmpNode = me.document.createElement('br'), pre; rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true); var next = tmpNode.nextSibling; if (!next && (!browser.ie || browser.version > 10)) { rng.insertNode(tmpNode.cloneNode(false)); } else { rng.setStartAfter(tmpNode); } pre = tmpNode.previousSibling; var tmp; while (pre) { tmp = pre; pre = pre.previousSibling; if (!pre || pre.nodeName == 'BR') { pre = tmp; break; } } if (pre) { //两次换行退出代码块 if (next && (pre.nodeName == 'BR' || (pre.nodeType == 3 && pre.nodeValue.trim() == ''))) { var preNode = domUtils.findParentByTagName(rng.startContainer, 'pre', true); domUtils.breakParent(next, preNode); var parentNode = next.parentNode; var startblock = document.createElement('p'); startblock.setAttribute('element-id', domUtils.getRandomId()) next.parentNode.insertBefore(startblock, next); startblock.appendChild(next); if ((startblock.nextSibling.innerText.trim() == '' || startblock.nextSibling.innerText.trim() == domUtils.fillChar) && startblock.nextSibling.querySelectorAll('br').length == 0 && startblock.nextSibling.querySelectorAll('hr').length == 0 && startblock.nextSibling.querySelectorAll('img').length == 0 && startblock.nextSibling.querySelectorAll('iframe').length == 0 && startblock.nextSibling.querySelectorAll('canvas').length == 0) { parentNode.removeChild(startblock.nextSibling); } if ((startblock.previousSibling.innerText.trim() == '' || startblock.previousSibling.innerText.trim() == domUtils.fillChar) && startblock.previousSibling.querySelectorAll('br').length == 0 && startblock.previousSibling.querySelectorAll('hr').length == 0 && startblock.previousSibling.querySelectorAll('img').length == 0 && startblock.previousSibling.querySelectorAll('iframe').length == 0 && startblock.previousSibling.querySelectorAll('canvas').length == 0) { parentNode.removeChild(startblock.previousSibling); } rng.setStart(startblock, 0).collapse(true).select(true); me.fireEvent('saveScene'); return; } var str = ''; while (pre && pre.nodeName != 'BR' && new RegExp('^[\\s' + domUtils.fillChar + ']*$').test(pre.nodeValue)) { str += pre.nodeValue; pre = pre.nextSibling; } if (pre.nodeName != 'BR') { var match = pre.nodeValue.match(new RegExp('^([\\s' + domUtils.fillChar + ']+)')); if (match && match[1]) { str += match[1] } } if (str) { str = me.document.createTextNode(str); rng.insertNode(str).setStartAfter(str); } } rng.collapse(true).select(true); } else { if (browser.version > 8) { var txt = me.document.createTextNode('\n'); var start = rng.startContainer; if (rng.startOffset == 0) { var preNode = start.previousSibling; if (preNode) { rng.insertNode(txt); var fillchar = me.document.createTextNode(' '); rng.setStartAfter(txt).insertNode(fillchar).setStart(fillchar, 0).collapse(true).select(true) } } else { rng.insertNode(txt).setStartAfter(txt); var fillchar = me.document.createTextNode(' '); start = rng.startContainer.childNodes[rng.startOffset]; if (start && !/^\n/.test(start.nodeValue)) { rng.setStartBefore(txt) } rng.insertNode(fillchar).setStart(fillchar, 0).collapse(true).select(true) } } else { var tmpNode = me.document.createElement('br'); rng.insertNode(tmpNode); rng.insertNode(me.document.createTextNode(domUtils.fillChar)); rng.setStartAfter(tmpNode); pre = tmpNode.previousSibling; var tmp; while (pre) { tmp = pre; pre = pre.previousSibling; if (!pre || pre.nodeName == 'BR') { pre = tmp; break; } } if (pre) { var str = ''; while (pre && pre.nodeName != 'BR' && new RegExp('^[ ' + domUtils.fillChar + ']*$').test(pre.nodeValue)) { str += pre.nodeValue; pre = pre.nextSibling; } if (pre.nodeName != 'BR') { var match = pre.nodeValue.match(new RegExp('^([ ' + domUtils.fillChar + ']+)')); if (match && match[1]) { str += match[1] } } str = me.document.createTextNode(str); rng.insertNode(str).setStartAfter(str); } rng.collapse(true).select(); } } me.fireEvent('saveScene'); return true; } }); me.addListener('tabkeydown', function (cmd, evt) { var rng = me.selection.getRange(); var pre = domUtils.findParentByTagName(rng.startContainer, 'code', true); if (pre) { me.fireEvent('saveScene'); if (evt.shiftKey) { console.log('取消缩进') if (rng.collapsed) { } else { } } else { if (!rng.collapsed) { var bk = rng.createBookmark(); var start = bk.start.previousSibling; while (start) { if (pre.firstChild === start && !domUtils.isBr(start)) { pre.insertBefore(me.document.createTextNode(' '), start); break; } if (domUtils.isBr(start)) { pre.insertBefore(me.document.createTextNode(' '), start.nextSibling); break; } start = start.previousSibling; } var end = bk.end; start = bk.start.nextSibling; if (pre.firstChild === bk.start) { pre.insertBefore(me.document.createTextNode(' '), start.nextSibling) } while (start && start !== end) { if (domUtils.isBr(start) && start.nextSibling) { if (start.nextSibling === end) { break; } pre.insertBefore(me.document.createTextNode(' '), start.nextSibling) } start = start.nextSibling; } rng.moveToBookmark(bk).select(); } else { var tmpNode = me.document.createTextNode(' '); rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true).select(true); } } me.fireEvent('saveScene'); return true; } }); me.addListener('beforeinserthtml', function (evtName, html) { var me = this, rng = me.selection.getRange(), pre = domUtils.findParentByTagName(rng.startContainer, 'code', true); if (pre) { if (!rng.collapsed) { rng.deleteContents() } var htmlstr = ''; if (browser.ie && browser.version > 8) { utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children, function (node) { if (node.type == 'element') { if (node.tagName == 'br') { htmlstr += '\n' } else if (!dtd.$empty[node.tagName]) { utils.each(node.children, function (cn) { if (cn.type == 'element') { if (cn.tagName == 'br') { htmlstr += '\n' } else if (!dtd.$empty[node.tagName]) { htmlstr += cn.innerText(); } } else { htmlstr += cn.data } }) if (!/\n$/.test(htmlstr)) { htmlstr += '\n'; } } } else { htmlstr += node.data + '\n' } if (!node.nextSibling() && /\n$/.test(htmlstr)) { htmlstr = htmlstr.replace(/\n$/, ''); } }); var tmpNode = me.document.createTextNode(utils.html(htmlstr.replace(/ /g, ' '))); rng.insertNode(tmpNode).selectNode(tmpNode).select(); } else { var frag = me.document.createDocumentFragment(); utils.each(UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules).children, function (node) { if (node.type == 'element') { if (node.tagName == 'br') { frag.appendChild(me.document.createElement('br')) } else if (!dtd.$empty[node.tagName]) { utils.each(node.children, function (cn) { if (cn.type == 'element') { if (cn.tagName == 'br') { frag.appendChild(me.document.createElement('br')) } else if (!dtd.$empty[node.tagName]) { frag.appendChild(me.document.createTextNode(utils.html(cn.innerText().replace(/ /g, ' ')))); } } else { frag.appendChild(me.document.createTextNode(utils.html(cn.data.replace(/ /g, ' ')))); } }) if (frag.lastChild.nodeName != 'BR') { frag.appendChild(me.document.createElement('br')) } } } else { frag.appendChild(me.document.createTextNode(utils.html(node.data.replace(/ /g, ' ')))); } if (!node.nextSibling() && frag.lastChild.nodeName == 'BR') { frag.removeChild(frag.lastChild) } }); if (frag.firstChild) { rng.insertNode(frag).select(); } } return true; } }); me.addListener('mouse', function (cmd, evt) { var me = this; var target = evt.target; var range = me.selection.getRange(); }) me.addListener('click', function (cmd, evt) { var me = this; var target = evt.target; var range = me.selection.getRange(); // 20200609 光标定位到hr后输入文字没有标签 var clonerange = range.cloneRange(); clonerange = clonerange.shrinkBoundary(); var start = clonerange.startContainer; if (start.tagName == 'BODY') { var offset = clonerange.startOffset; if (start.childNodes[offset + 1]) { range.setStart(start.childNodes[offset + 1], 0).collapse(true); range.shrinkBoundary().select() } } //20200716 点击链接跳转页面 if (target.tagName.toLowerCase() == 'a' && target.getAttribute('href')) { var href = target.getAttribute('href'); window.open(href); } //点击录音标注 if (target.className && typeof target.className === 'string' && target.className.indexOf('record-list-tit') > -1) { var last = target.lastChild; while (last) { if (last.nodeType == 3) { //文本 if (last.data == "​" || last.data == " ​") { //为空或​ target.removeChild(last); last = target.lastChild; } else { //其他文本,移出去 lastprev = last.previousSibling; var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) p.appendChild(last); if (target.nextSibling) { target.parentNode.insertBefore(p, target.nextSibling); } else { target.parentNode.appendChild(p); } last = lastprev; } } else if (last.nodeType == 1) { if (last.getAttribute('class') && last.getAttribute('class').indexOf('record-list') > -1) { //不处理,加不可编辑 last.setAttribute('contenteditable', 'false'); last = last.previousSibling; } else if (last.innerText.trim() != '') { //移出去 lastprev = last.previousSibling; if (target.nextSibling) { target.parentNode.insertBefore(last, target.nextSibling); } else { target.parentNode.appendChild(last); } last = lastprev; } else { //空节点elePack target.removeChild(last); last = target.lastChild; } } else { target.removeChild(last); last = target.lastChild; } } var br = document.createElement('br'); target.appendChild(br); range.setStartBefore(br); range.setEndBefore(br); range.select(true); } //点击勾选框 if ($(target).is(".todo-mark") || $(target).parents(".todo-mark").length > 0) { //20200713 TODO var toodomarkdiv; if ($(target).is(".todo-mark")) { toodomarkdiv = $(target).parents(".todo-view")[0]; } else if ($(target).parents(".todo-mark").length > 0) { toodomarkdiv = $(target).parents(".todo-view")[0]; } if (!toodomarkdiv.getAttribute('element-id')) { toodomarkdiv.setAttribute('element-id', domUtils.getRandomId()) } var checkType; if ($(target).parents(".todo-view").is('.checked')) { $(target).parents(".todo-view").removeClass('checked'); checkType = 'remove'; } else { $(target).parents(".todo-view").addClass('checked') checkType = 'add'; } me.fireEvent('contentchange'); me.fireEvent('saveScene'); if (me.options.cooperation) { var data = {}; data.elementId = toodomarkdiv.getAttribute('element-id'); data.name = "todoCheck"; data.checkType = checkType; me.sendJoinData(data); } } }); me.addListener('keydown', function (cmd, evt) { var me = this, keyCode = evt.keyCode || evt.which; var range = me.selection.getRange(); var temprng = range.shrinkBoundary(); if (range.collapsed) { //处理录音打点逻辑 if (keyCode == 8) { //删除 var start = temprng.startContainer; if (start.nodeType == 3) { start = start.parentNode; } //20200811 课程教案--阻止删除课前课中课后 var prev = me.getprevNode(start); if (temprng.startOffset == 0 && prev && $(prev).is('#ulTab')) { evt.preventDefault(); } if ($(start).is('#ulTab') || $(start).parents('#ulTab').length > 0) { evt.preventDefault(); } //录音 if (start.nodeType == 1 && start.getAttribute('class') && start.getAttribute('class').indexOf('record-list-tit') > -1) { //删除标注标签和时间 var startParent = start.parentNode; //record-list var startNext = start.nextSibling; //标注内容 var startParentParent = startParent.parentNode; //record-box var startParentPrev = startParent.previousSibling; if (range.startOffset >= 1) { //删除时间 evt.preventDefault(); if (startParentPrev) { //不是第一个标记 domUtils.remove(start); startParentPrevLast = startParentPrev.lastChild; startParentFirst = startParent.firstChild; var newp = document.createElement('p'); newp.setAttribute('element-id', domUtils.getRandomId()) newp.innerHTML = '
    '; startParentPrev.appendChild(newp); if (startParentFirst) { //有标注内容 while (startParent.firstChild) { startParentPrev.appendChild(startParent.firstChild) } } domUtils.remove(startParent); if(!startParentPrev.parentNode.querySelector('.record-list-tit')){ $(startParentPrev).unwrap(); while (startParentPrev.firstChild) { startParentPrev.parentNode.insertBefore(startParentPrev.firstChild,startParentPrev) } domUtils.remove(startParentPrev); } range.setStart(newp, 0); range.setEnd(newp, 0); } else { //是第一个list startParentNext = startParent.nextSibling; domUtils.remove(start); var startParentFirst = startParent.firstChild; //标注内容 while (startParent.firstChild) { startParentParent.parentNode.insertBefore(startParent.firstChild, startParentParent); } domUtils.remove(startParent); if (startParentFirst) { //有标注内容 range.setStart(startParentFirst, 0); range.setEnd(startParentFirst, 0); } else { if (startParentParent.previousSibling && startParentParent.previousSibling.nodeType == 1) { //record-box前面有元素节点 range.setStartAfter(startParentParent.previousSibling.lastChild); range.setEndAfter(startParentParent.previousSibling.lastChild); } else if (startParentParent.previousSibling && startParentParent.previousSibling.nodeType == 3) { //record-box前面有文本节点 range.setStartAfter(startParentParent.previousSibling); range.setEndAfter(startParentParent.previousSibling); } else {//record-box前面没有内容,新建一行 var p = document.createElement('p'); p.appendChild(document.createElement('br')); startParentParent.parentNode.insertBefore(p, startParentParent); range.setStart(p, 0); range.setEnd(p, 0); } } if (startParentParent.innerText == '') { //如果所有标记为空,删除record-box domUtils.remove(startParentParent); } } range.select(true); me.fireEvent('contentchange'); me.fireEvent('saveScene'); } } else if (start.nodeType == 1 && range.startOffset == 0 && start.previousSibling && start.previousSibling.nodeType == 1 && start.previousSibling.getAttribute('class') && start.previousSibling.getAttribute('class').indexOf('record-list-tit') > -1) { //删除标注内容 evt.preventDefault(); if (start.nodeType == 3) { start = start.parentNode; } var startPrev = start.previousSibling; if (start.innerHTML == '' || start.innerHTML == '
    ') { //标注内容是空 domUtils.remove(start) } range.setStart(startPrev, startPrev.children.length); range.setEnd(startPrev, startPrev.children.length); range.select(true); } else if (start.nodeType == 1 && range.startOffset == 0 && start.previousSibling && start.previousSibling.nodeType == 1 && start.previousSibling.getAttribute('class') && start.previousSibling.getAttribute('class').indexOf('editor-iframe') > -1 && start.parentNode.className && start.parentNode.className.indexOf('record-iframe') > -1) { // if($('.popUeditorDelShowHide')[0].style.display == 'block'){ return; // } // //光标附件后面 删除附件 // evt.preventDefault(); // startParent = start.parentNode; //record-list record-iframe // startParentParent = startParent.parentNode; //record-box // nowstart = start; // domUtils.remove(start.previousSibling); // while (startParent.firstChild) { // startParentParent.parentNode.insertBefore(startParent.firstChild, startParentParent); // } // domUtils.remove(startParent); // range.setStart(nowstart, 0); // range.setEnd(nowstart, 0); // range.select(true); // me.fireEvent('contentchange'); // me.fireEvent('saveScene'); } else if (start.nodeType == 1 && range.startOffset == 0 && start.previousSibling && start.previousSibling.nodeType == 1 && start.previousSibling.getAttribute('class') && start.previousSibling.getAttribute('class').indexOf('record-box') > -1) { //录音record-box后删除不允许删除,否则跳不出去 evt.preventDefault(); } } else if (keyCode == 13) { var start = range.startContainer; if (start.nodeType == 3) { start = start.parentNode; } var listTit = domUtils.findParent(start, function (node) { return node.className == 'record-list-tit'; }); //标记头部换行 if (listTit) { evt.preventDefault(); var newp = document.createElement('p'); newp.setAttribute('element-id', domUtils.getRandomId()) newp.innerHTML = '
    '; if (listTit.nextSibling) { listTit.parentNode.insertBefore(newp, listTit.nextSibling); } else { listTit.parentNode.appendChild(newp); } range.setStart(newp, 0); range.setEnd(newp, 0); range.select() } } } }) //方向键的处理 me.addListener('keydown', function (cmd, evt) { var me = this, keyCode = evt.keyCode || evt.which; if (keyCode == 40) { var rng = me.selection.getRange(), pre, start = rng.startContainer; if (rng.collapsed && (pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true)) && !pre.nextSibling) { var last = pre.lastChild while (last && last.nodeName == 'BR') { last = last.previousSibling; } if (last === start || rng.startContainer === pre && rng.startOffset == pre.childNodes.length) { me.execCommand('insertparagraph'); domUtils.preventDefault(evt) } } } }); //trace:3395 me.addListener('delkeydown', function (type, evt) { var rng = this.selection.getRange(); rng.txtToElmBoundary(true); var start = rng.startContainer; if (domUtils.isTagNode(start, 'pre') && rng.collapsed && domUtils.isStartInblock(rng)) { var p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) domUtils.fillNode(me.document, p); start.parentNode.insertBefore(p, start); domUtils.remove(start); rng.setStart(p, 0).setCursor(false, true); domUtils.preventDefault(evt); return true; } }) }; /* *@Description: 增加sign *@Date: 2023-04-12 19:49:30 */ UE.plugins['inserseal'] = function () { var me = this; if(isNotice) return //代码块显示工具栏 me.signTool = null; me.addListener('mouseover', function (type, evt) { if ( evt.target.tagName == 'DIV' && evt.target.id == "signDiv" && $(evt.target).parents('.edui-editor-signtoolbar').length == 0 ) { // if (evt.target.tagName == 'IMG' && evt.target.id == "signImg" && $(evt.target).parents('.edui-editor-signtoolbar').length == 0 ) { if (me.signTool && $(me.container).find('.edui-editor-signtoolbar').hasClass('hover')) { return; } else if (!me.signTool) { me.signTool = new signTool(); me.signTool.init(me); me.ui.getDom().appendChild(me.signTool.resizer); } me.signTool.show(evt.target); } // else if (me.signTool && $(me.container).find('.edui-editor-signtoolbar').hasClass('hover') && evt.target.tagName != 'IMG') { else if (me.signTool && $(me.container).find('.edui-editor-signtoolbar').hasClass('hover')) { me.signTool.hide(); } }) $('body').on('mouseover', function (e) { if ($(e.target).parents('.edui-editor-signtoolbar').length == 0 && !$(e.target).is('.edui-editor-signtoolbar') && me.codetool && $(me.container).find('.edui-editor-signtoolbar').hasClass('hover')) { if(me.signtool){ me.signtool.hide(); } } }) //悬浮列表工具栏 function signTool() { this.editor = null; this.resizer = null; this.doc = document; this.target = null; } (function () { signTool.prototype = { init: function (editor) { var _this = this; _this.editor = editor; var resizer = _this.resizer = document.createElement('div'); resizer.innerHTML = '
    ' + '
    ' + '
    ' + editor.getLang('toolbarCmds.edit') + '
    ' + '
    ' + editor.getLang('toolbarCmds.delete') + '
    ' + '
    ' + '
    '; resizer.id = _this.editor.ui.id + '_signtoolbar'; resizer.className = 'edui-editor-signtoolbar edui-editor-resizer hover'; resizer.style.cssText += ';z-index:' + (_this.editor.options.zIndex) + ';'; _this.editor.ui.getDom().appendChild(resizer); _this.initEvents(); }, initEvents: function () { var _this = this; //删除 $(_this.resizer).on('click', '.remove', function (e) { _this.editor.document.getElementById('signDiv').remove() _this.resizer.classList.remove('hover'); }) //编辑 $(_this.resizer).on('click', '.signedit', function (e) { _this.editor.editSign(this); }) }, show: function (targetObj) { var _this = this; _this.resizer.classList.add('hover'); $('#edui1_imagescale').removeClass('hover') if (targetObj) _this.attachTo(targetObj); }, hide: function () { var _this = this; _this.resizer.classList.remove('hover'); }, attachTo: function (targetObj) { var _this = this, target = _this.target = targetObj, resizer = this.resizer, targetPos = domUtils.getXY(target), iframePos = domUtils.getXY(_this.editor.iframe), editorPos = domUtils.getXY(resizer.parentNode); var index = $(me.body).find('pre').index(target); resizer.setAttribute('index', index); domUtils.setStyles(resizer, { 'width': target.clientWidth+ 'px', 'height': 0, 'left': iframePos.x + targetPos.x - _this.editor.document.body.scrollLeft - editorPos.x + 'px', 'top': iframePos.y + targetPos.y - _this.editor.document.body.scrollTop - editorPos.y + 'px' }); } } })(); }; // 电子签名 UE.plugins["electronSign"] = function () { var me = this; me.addListener('click', function (cmd, evt){ if($(evt.target).is('.electronSignPlacehoder') || $(evt.target).parents('.electronSignPlacehoder').length > 0){ //点击的是电子签名的占位 RichTextUitl.editorReplaceTarget = $(evt.target).is('.electronSignPlacehoder') ? evt.target : $(evt.target).parents('.electronSignPlacehoder')[0] me.showElectronSignPop() } }) //创建或打开电子签名弹窗 params:url追加的参数 me.showElectronSignPop = function(params){ var div = document.body.querySelector('#electronSignPop') if(!div) { div = document.createElement('div'); div.id = 'electronSignPop'; div.className = 'maskDiv editorMaskDiv maskFadeOut'; div.setAttribute('editorId',me.key) div.innerHTML = '
    ' + '
    ' + '' + '

    电子签名(请在下方区域签名)

    ' + '
    ' + '
    ' + '' '
    '; document.body.appendChild(div); // 关闭弹窗 div.querySelector('.popClose').onclick = function () { document.body.removeChild(div) } }else{ div.querySelector('iframe').setAttribute('src',RichTextUitl.noteDomain + '/comp/draw/html/draw.html?drawType=sign' + params); } } }; // plugins/cleardoc.js /** * 清空文档插件 * @file * @since 1.2.6.1 */ /** * 清空文档 * @command cleardoc * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * //editor 是编辑器实例 * editor.execCommand('cleardoc'); * ``` */ UE.commands['cleardoc'] = { execCommand: function (cmdName) { var me = this, enterTag = me.options.enterTag, range = me.selection.getRange(); if (enterTag == "br") { me.body.innerHTML = "
    "; range.setStart(me.body, 0).setCursor(); } else { me.body.innerHTML = "

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

    "; range.setStart(me.body.firstChild, 0).setCursor(false, true); } setTimeout(function () { me.fireEvent("clearDoc"); }, 0); } }; // plugins/anchor.js /** * 锚点插件,为UEditor提供插入锚点支持 * @file * @since 1.2.6.1 */ UE.plugin.register('anchor', function () { return { bindEvents: { 'ready': function () { utils.cssRule('anchor', '.anchorclass{background: url(\'' + this.options.themePath + this.options.theme + '/images/anchor.gif\') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}', this.document); } }, outputRule: function (root) { utils.each(root.getNodesByTagName('img'), function (a) { var val; if (val = a.getAttr('anchorname')) { a.tagName = 'a'; a.setAttr({ anchorname: '', name: val, 'class': '' }) } }) }, inputRule: function (root) { utils.each(root.getNodesByTagName('a'), function (a) { var val; if ((val = a.getAttr('name')) && !a.getAttr('href')) { a.tagName = 'span'; // a.setAttr({ // anchorname :a.getAttr('name'), // 'class' : 'anchorclass' // }); a.setAttr('name', '') if (a.children.length == 0 || a.innerText() == '') { a.parentNode.removeChild(a) } } }) }, commands: { /** * 插入锚点 * @command anchor * @method execCommand * @param { String } cmd 命令字符串 * @param { String } name 锚点名称字符串 * @example * ```javascript * //editor 是编辑器实例 * editor.execCommand('anchor', 'anchor1'); * ``` */ 'anchor': { execCommand: function (cmd, name) { var range = this.selection.getRange(), img = range.getClosedNode(); if (img && img.getAttribute('anchorname')) { if (name) { img.setAttribute('anchorname', name); } else { range.setStartBefore(img).setCursor(); domUtils.remove(img); } } else { if (name) { //只在选区的开始插入 var anchor = this.document.createElement('img'); range.collapse(true); domUtils.setAttributes(anchor, { 'anchorname': name, 'class': 'anchorclass' }); range.insertNode(anchor).setStartAfter(anchor).setCursor(false, true); } } } } } } }); // plugins/wordcount.js ///import core ///commands 字数统计 ///commandsName WordCount,wordCount ///commandsTitle 字数统计 /* * Created by JetBrains WebStorm. * User: taoqili * Date: 11-9-7 * Time: 下午8:18 * To change this template use File | Settings | File Templates. */ UE.plugins['wordcount'] = function () { var me = this; me.setOpt('wordCount', true); // 内容变化是触发wordcount me.addListener('contentchange', function () { me.fireEvent('wordcount'); }); var timer; me.addListener('ready', function () { var me = this; /* *@Description: 增加数字限制 *@Date: 2023-04-24 17:25:44 */ if(me.options.wordcount == true){ // 初始化调用 wordcount me.fireEvent('wordcount'); } domUtils.on(me.body, "keyup", function (evt) { var code = evt.keyCode || evt.which, //忽略的按键,ctr,alt,shift,方向键 ignores = { "16": 1, "18": 1, "20": 1, "37": 1, "38": 1, "39": 1, "40": 1 }; if (code in ignores) return; // keyup 不再调用 wordcount // clearTimeout(timer); // timer = setTimeout(function () { // me.fireEvent('wordcount'); // }, 200) }) }); }; // plugins/pagebreak.js /** * 分页功能插件 * @file * @since 1.2.6.1 */ UE.plugins['pagebreak'] = function () { var me = this, notBreakTags = ['td']; me.setOpt('pageBreakTag', '_ueditor_page_break_tag_'); function fillNode(node) { if (domUtils.isEmptyBlock(node)) { var firstChild = node.firstChild, tmpNode; while (firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)) { tmpNode = firstChild; firstChild = firstChild.firstChild; } !tmpNode && (tmpNode = node); domUtils.fillNode(me.document, tmpNode); } } //分页符样式添加 me.ready(function () { utils.cssRule('pagebreak', '.pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}', me.document); }); function isHr(node) { return node && node.nodeType == 1 && node.tagName == 'HR' && node.className == 'pagebreak'; } me.addInputRule(function (root) { root.traversal(function (node) { if (node.type == 'text' && node.data == me.options.pageBreakTag) { var hr = UE.uNode.createElement('
    '); node.parentNode.insertBefore(hr, node); node.parentNode.removeChild(node) } }) }); me.addOutputRule(function (node) { utils.each(node.getNodesByTagName('hr'), function (n) { if (n.getAttr('class') == 'pagebreak') { var txt = UE.uNode.createText(me.options.pageBreakTag); n.parentNode.insertBefore(txt, n); n.parentNode.removeChild(n); } }) }); /** * 插入分页符 * @command pagebreak * @method execCommand * @param { String } cmd 命令字符串 * @remind 在表格中插入分页符会把表格切分成两部分 * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串, * 以便于提交数据到服务器端后处理分页。 * @example * ```javascript * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak * ``` */ me.commands['pagebreak'] = { execCommand: function () { var range = me.selection.getRange(), hr = me.document.createElement('hr'); domUtils.setAttributes(hr, { 'class': 'pagebreak', noshade: "noshade", size: "5" }); domUtils.unSelectable(hr); //table单独处理 var node = domUtils.findParentByTagName(range.startContainer, notBreakTags, true), parents = [], pN; if (node) { switch (node.tagName) { case 'TD': pN = node.parentNode; if (!pN.previousSibling) { var table = domUtils.findParentByTagName(pN, 'table'); // var tableWrapDiv = table.parentNode; // if(tableWrapDiv && tableWrapDiv.nodeType == 1 // && tableWrapDiv.tagName == 'DIV' // && tableWrapDiv.getAttribute('dropdrag') // ){ // domUtils.remove(tableWrapDiv,true); // } table.parentNode.insertBefore(hr, table); parents = domUtils.findParents(hr, true); } else { pN.parentNode.insertBefore(hr, pN); parents = domUtils.findParents(hr); } pN = parents[1]; if (hr !== pN) { domUtils.breakParent(hr, pN); } //table要重写绑定一下拖拽 me.fireEvent('afteradjusttable', me.document); } } else { if (!range.collapsed) { range.deleteContents(); var start = range.startContainer; while (!domUtils.isBody(start) && domUtils.isBlockElm(start) && domUtils.isEmptyNode(start)) { range.setStartBefore(start).collapse(true); domUtils.remove(start); start = range.startContainer; } } range.insertNode(hr); var pN = hr.parentNode, nextNode; while (!domUtils.isBody(pN)) { domUtils.breakParent(hr, pN); nextNode = hr.nextSibling; if (nextNode && domUtils.isEmptyBlock(nextNode)) { domUtils.remove(nextNode); } pN = hr.parentNode; } nextNode = hr.nextSibling; var pre = hr.previousSibling; if (isHr(pre)) { domUtils.remove(pre); } else { pre && fillNode(pre); } if (!nextNode) { var p = me.document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) hr.parentNode.appendChild(p); domUtils.fillNode(me.document, p); range.setStart(p, 0).collapse(true); } else { if (isHr(nextNode)) { domUtils.remove(nextNode); } else { fillNode(nextNode); } range.setEndAfter(hr).collapse(false); } range.select(true); } } }; }; // plugins/wordimage.js ///import core ///commands 本地图片引导上传 ///commandsName WordImage ///commandsTitle 本地图片引导上传 ///commandsDialog dialogs\wordimage UE.plugin.register('wordimage', function () { var me = this, images = []; return { commands: { 'wordimage': { execCommand: function () { var images = domUtils.getElementsByTagName(me.body, "img"); var urlList = []; for (var i = 0, ci; ci = images[i++];) { var url = ci.getAttribute("word_img"); url && urlList.push(url); } return urlList; }, queryCommandState: function () { images = domUtils.getElementsByTagName(me.body, "img"); for (var i = 0, ci; ci = images[i++];) { if (ci.getAttribute("word_img")) { return 1; } } return -1; }, notNeedUndo: true } }, inputRule: function (root) { utils.each(root.getNodesByTagName('img'), function (img) { var attrs = img.attrs, flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43, opt = me.options, src = opt.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif'; if (attrs['src'] && /^(?:(file:\/+))/.test(attrs['src'])) { img.setAttr({ width: attrs.width, height: attrs.height, alt: attrs.alt, word_img: attrs.src, src: src, 'style': 'background:url(' + (flag ? opt.themePath + opt.theme + '/images/word.gif' : opt.langPath + opt.lang + '/images/localimage.png') + ') no-repeat center center;border:1px solid #ddd' }) } }) } } }); // plugins/dragdrop.js UE.plugins['dragdrop'] = function () { var me = this; me.ready(function () { domUtils.on(this.body, 'dragend', function () { var rng = me.selection.getRange(); var node = rng.getClosedNode() || me.selection.getStart(); if (node && node.tagName == 'IMG') { var pre = node.previousSibling, next; while (next = node.nextSibling) { if (next.nodeType == 1 && next.tagName == 'SPAN' && !next.firstChild) { domUtils.remove(next) } else { break; } } if ((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre) || !pre) && (!next || next && !domUtils.isEmptyBlock(next))) { if (pre && pre.tagName == 'P' && !domUtils.isEmptyBlock(pre)) { pre.appendChild(node); domUtils.moveChild(next, pre); domUtils.remove(next); } else if (next && next.tagName == 'P' && !domUtils.isEmptyBlock(next)) { next.insertBefore(node, next.firstChild); } if (pre && pre.tagName == 'P' && domUtils.isEmptyBlock(pre)) { domUtils.remove(pre) } if (next && next.tagName == 'P' && domUtils.isEmptyBlock(next)) { domUtils.remove(next) } rng.selectNode(node).select(); me.fireEvent('saveScene'); } } }) }); me.addListener('keyup', function (type, evt) { var keyCode = evt.keyCode || evt.which; var range = me.selection.getRange() if (keyCode == 13) { var rng = me.selection.getRange(), node; // if(node = domUtils.findParentByTagName(rng.startContainer,'p',true)){ // if(domUtils.getComputedStyle(node,'text-align') == 'center'){ // domUtils.removeStyle(node,'text-align') // } // } } //处理录音打点时间后的输入 var range = me.selection.getRange(); var start = range.startContainer; if (start.nodeType == 3) { start = start.parentNode; } if (start && range.startOffset > 0 && start.className && start.className.indexOf('record-list-tit') > -1) { var recordList = start; var p = document.createElement('p'); p.setAttribute('element-id', domUtils.getRandomId()) if ((start.lastChild.nodeType == 3 && start.lastChild.nodeValue != "​") || start.lastChild.nodeType == 1 && start.lastChild.nodeName != 'BR') { p.appendChild(start.lastChild); if (start.nextSibling) { start.parentNode.insertBefore(p, start.nextSibling); } else { start.parentNode.appendChild(p) } recordList.appendChild(document.createElement('br')) range.setStartAfter(p.lastChild); range.setEndAfter(p.lastChild); range.select(true); } } //20210616 在段落最前面换行的,id留在上一行解决:id跟着文字到下一行 if (keyCode == 13) { //20210317 更新目录,优化目录 if (typeof (updateAllCatalog) == "function" && (/h\d/i.test(range.startContainer.tagName) || $(range.startContainer).parents('h1,h2,h3,h4,h5,h6').length > 0) && inputType == false) { updateAllCatalog(me.body); } var li = domUtils.findParentByTagName(rng.startContainer, 'li', true); if (!li && domUtils.isStartInblock(range) && range.startContainer.nodeType == 3 && range.startContainer.nodeValue.trim() != '' && !domUtils.isFillChar(range.startContainer)) { var start = domUtils.findParentByTagName(range.startContainer, ['p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], true); var startprev = start.previousSibling; if (startprev && startprev.nodeType == 1 && start.innerText.trim() != "" && start.innerText.trim() != domUtils.fillChar) { if (startprev.tagName == 'OL' || startprev.tagName == 'UL' || startprev.innerText.trim() != '' || startprev.innerText.trim() != domUtils.fillChar) { return; } var previd = startprev.getAttribute('element-id'); var startid = start.getAttribute('element-id'); if (previd && startid) { startprev.setAttribute('element-id', startid); start.setAttribute('element-id', previd); } } } } }) //20200720 协同编辑同步标题 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 } var noteTitle = document.getElementById('noteTitle'); var titleInputType = false; var saveSceneTimer; if (noteTitle) { //输入法状态下不计算字符数 noteTitle.addEventListener('compositionstart', function () { titleInputType = true; }); noteTitle.addEventListener('compositionend', function () { titleInputType = false; }) noteTitle.addEventListener('keydown', function (evt) { var keyCode = evt.keyCode || evt.which; if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey && me.options.cooperation) { if (titleInputType) return; clearTimeout(saveSceneTimer); function save(cont) { var data = {}; data.name = 'notetitle'; data.text = noteTitle.value; me.sendJoinData(data) } saveSceneTimer = setTimeout(function () { if (titleInputType) { var interalTimer = setInterval(function () { if (!titleInputType) { save(me); clearInterval(interalTimer) } }, 300) return; } save(me); }, 200); } }) } }; // plugins/undo.js /** * undo redo * @file * @since 1.2.6.1 */ /** * 撤销上一次执行的命令 * @command undo * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'undo' ); * ``` */ /** * 重做上一次执行的命令 * @command redo * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand( 'redo' ); * ``` */ UE.plugins['undo'] = function () { var saveSceneTimer; var me = this, maxUndoCount = me.options.maxUndoCount || 20, maxInputCount = me.options.maxInputCount || 20, fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi'); // ie会产生多余的 var noNeedFillCharTags = { ol: 1, ul: 1, table: 1, tbody: 1, tr: 1, body: 1 }; var orgState = me.options.autoClearEmptyNode; function compareAddr(indexA, indexB) { if (indexA.length != indexB.length) return 0; for (var i = 0, l = indexA.length; i < l; i++) { if (indexA[i] != indexB[i]) return 0 } return 1; } function compareRangeAddress(rngAddrA, rngAddrB) { if (rngAddrA.collapsed != rngAddrB.collapsed) { return 0; } if (!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)) { return 0; } return 1; } function UndoManager() { this.list = []; this.index = 0; this.hasUndo = false; this.hasRedo = false; this.undo = function () { if (this.hasUndo) { if (!this.list[this.index - 1] && this.list.length == 1) { this.reset(); return; } while (this.list[this.index].content == this.list[this.index - 1].content) { this.index--; if (this.index == 0) { return this.restore(0); } } this.restore(--this.index); } }; this.redo = function () { if (this.hasRedo) { while (this.list[this.index].content == this.list[this.index + 1].content) { this.index++; if (this.index == this.list.length - 1) { return this.restore(this.index); } } this.restore(++this.index); } }; this.restore = function () { var me = this.editor; var scene = this.list[this.index]; var root = UE.htmlparser(scene.content.replace(fillchar, '')); me.options.autoClearEmptyNode = false; if(scene.content.indexOf('
    ') == -1 && scene.content.indexOf('
    ') == -1){ me.filterInputRule(root); }else{ root.traversal(function (node) { if (node.type !== 'element') { return false; } me.filterWhiteList(node); }); } me.options.autoClearEmptyNode = orgState; //trace:873 //去掉展位符 me.document.body.innerHTML = root.toHtml(); RichTextUitl.renderLatex(me.body) me.fireEvent('afterscencerestore'); if (!$(me.body).find(".record-list-tit").last().is("​")) { $(me.body).find(".record-list-tit").append("​"); } //处理undo后空格不展位的问题 if (browser.ie) { utils.each(domUtils.getElementsByTagName(me.document, 'td th caption p'), function (node) { if (domUtils.isEmptyNode(node)) { domUtils.fillNode(me.document, node); } }) } try { var rng = new dom.Range(me.document).moveToAddress(scene.address); rng.select(noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]); } catch (e) { } this.update(); this.clearKey(); var toolbarBox = me.container.querySelector('.edui-editor-toolbarbox'); if(toolbarBox){ toolbarBox.style.display = ''; } //不能把自己reset了 me.fireEvent('reset', true); }; this.getScene = function () { var me = this.editor; var rng = me.selection.getRange(), rngAddress = rng.createAddress(false, true); me.fireEvent('beforegetscene'); var html = me.body.innerHTML; if($(me.body).find('span[data-latexstr]').length > 0) { //去掉rtf_content中span[data-latexstr]中的内容 var div = document.createElement('div'); div.innerHTML = html; // 去掉rtf_content公式中的内容 $(div).find('span[data-latexstr]').each(function (i, elm) { elm.innerHTML = ' '; }) html = div.innerHTML; //删除div domUtils.remove(div); } var root = UE.htmlparser(html); me.options.autoClearEmptyNode = false; me.filterOutputRule(root); me.options.autoClearEmptyNode = orgState; var cont = root.toHtml(); //trace:3461 //这个会引起回退时导致空格丢失的情况 // browser.ie && (cont = cont.replace(/> <').replace(/\s*\s*/g, '>')); me.fireEvent('aftergetscene'); return { address: rngAddress, content: cont } }; this.save = function (notCompareRange, notSetCursor) { var me = this.editor; var range = me.selection.getRange(); if (!(!range.collapsed && browser.safari)) { //safari浏览器有选区时执行这个方法会去掉选区 //用于协同笔记,连接相邻的文本节点 me.body.normalize(); } if (me.body.querySelector('#baidu_pastebin') || $(me.body).find('img:not([objectid])').attr('src') && $(me.body).find('img:not([objectid])').attr('src').indexOf('spacer.gif') > -1) { return; } clearTimeout(saveSceneTimer); var currentScene = this.getScene(notSetCursor), lastScene = this.list[this.index]; if (lastScene && lastScene.content != currentScene.content) { me.trigger('contentchange') } //内容相同位置相同不存 if (lastScene && lastScene.content == currentScene.content && (notCompareRange ? 1 : compareRangeAddress(lastScene.address, currentScene.address)) ) { return; } //20211020 有未加载成功的图片或附件,不存 20220316有base64的图片不存 if (currentScene.content.indexOf('loadingClass') > -1 || currentScene.content.indexOf('attachprogress') > -1 || currentScene.content.indexOf('imgprogress') > -1 || currentScene.content.indexOf('video_fail') > -1 || (currentScene.content.indexOf('data:image') > -1 && currentScene.content.indexOf('base64') > -1)) { return; } //保存的表格套div table var tables = me.body.querySelectorAll('table'); for (var i = 0; table = tables[i++];) { if (!(table.parentNode.className && table.parentNode.className == 'table')) { var tempdiv = document.createElement('div'); tempdiv.setAttribute('element-id', domUtils.getRandomId()) tempdiv.setAttribute("class", "table"); tempdiv.setAttribute('style', 'width:100%;max-width:100%;overflow-x:auto;'); table.parentNode.insertBefore(tempdiv, table); tempdiv.appendChild(table); } } currentScene = this.getScene(notSetCursor); 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; }; } 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; } //20200602 协同编辑换行 me.addListener('keyup', function (cmd, evt) { var keyCode = evt.keyCode || evt.which; var rng = me.selection.getRange(); if (keyCode == 13) { var start = rng.startContainer, pnode; if (domUtils.isBlockElm(start)) { pnode = start; } else { pnode = domUtils.findParent(start, function (node) { return domUtils.isBlockElm(node); }); } if (!pnode.getAttribute("element-id") || me.getPreBlockNode(pnode) && me.getPreBlockNode(pnode).getAttribute("element-id") == pnode.getAttribute("element-id")) { pnode.setAttribute("element-id", domUtils.getRandomId()); } if (me.options.cooperation) { if (UE.isSendEnter == true) { return } var prenode = me.getPreBlockNode(pnode); var prenodelen = prenode.innerText.replace(new RegExp(domUtils.fillChar, 'g'), '').replace(/^\s+|\s+$/g, '').length; var data = {}; data.name = "enter"; data.address = UE.addressList[0]; data.elementId = pnode.getAttribute("element-id"); data.preId = prenode.getAttribute("element-id"); data.startPos = prenodelen; me.sendJoinData(data) } } }) me.undoManger = new UndoManager(); me.undoManger.editor = me; function saveScene() { this.undoManger.save(); } me.addListener('saveScene', function () { var args = Array.prototype.splice.call(arguments, 1); this.undoManger.save.apply(this.undoManger, args); }); // me.addListener('beforeexeccommand', saveScene); // me.addListener('afterexeccommand', saveScene); me.addListener('keyup', function () { if ((me.body.innerHTML.replace(new RegExp("​", 'g'), '') == '


    ' || me.body.innerHTML.replace(new RegExp("​", 'g'), '') == '


    ' || me.body.innerHTML.replace(new RegExp("​", 'g'), '') == "")) { if(!$('#container .edui-editor-iframeholder').hasClass('empty')){ $('#container .edui-editor-iframeholder').addClass('empty'); } if(typeof MultiEditor != 'undefined'){ $(me.container).parents('.multieditor').find('.templatePop').show(); } } else { if ($('#container .edui-editor-iframeholder').hasClass('empty')){ $('#container .edui-editor-iframeholder').removeClass('empty'); } if(typeof MultiEditor != 'undefined'){ $(me.container).parents('.multieditor').find('.templatePop').hide(); } } }) me.addListener('contentchange', function () { if ( (me.body.innerHTML.replace(new RegExp("​", 'g'), '') == '


    ' || me.body.innerHTML.replace(new RegExp("​", 'g'), '') == '


    ' || me.body.innerHTML.replace(new RegExp("​", 'g'), '') == "")) { if(!$('#container .edui-editor-iframeholder').hasClass('empty')){ $('#container .edui-editor-iframeholder').addClass('empty'); } //为了支持公告用插件空内容placeholder提示 if(!$(me.container).parent().parent().hasClass('empty')){ $(me.container).parent().parent().addClass('empty'); } if(typeof MultiEditor != 'undefined'){ $(me.container).parents('.multieditor').find('.templatePop').show(); } } else { if ($('#container .edui-editor-iframeholder').hasClass('empty')){ $('#container .edui-editor-iframeholder').removeClass('empty'); } if($(me.container).parent().parent().hasClass('empty')){ $(me.container).parent().parent().removeClass('empty'); } if(typeof MultiEditor != 'undefined'){ $(me.container).parents('.multieditor').find('.templatePop').hide(); } } }) me.addListener('reset', function (type, exclude) { if (!exclude) { this.undoManger.reset(); } }); me.commands['redo'] = me.commands['undo'] = { execCommand: function (cmdName) { $('.edui-editor-imagescale').removeClass('hover').removeClass('scale'); //重新统计所有的图片和附件 if (me.options.statsAttach) { if ($(me.body).find('img').length > 0 || $(me.body).find('iframe').length > 0) { var staAtt = []; for (var i = 0; i < $(me.body).find('img').length; i++) { var src = $(me.body).find('img').eq(i).attr('src'); // //未上传成功的图片不统计,autouploader处理、非镜像不是chaoxing域名的图片不统计 // if(src.indexOf('spacer.gif') == -1 && (!RichTextUitl.intranetMode && src.indexOf('chaoxing.com') == -1)) { // continue; // } var imgItem = { 'type': 'img', 'resource': src } staAtt.push(imgItem); } for (var i = 0; i < $(me.body).find('iframe').length; i++) { var iframeItem = { 'type': 'iframe', 'resource': $(me.body).find('iframe').eq(i).attr('name') } staAtt.push(iframeItem); } if (staAtt.length > 0) { me.anasycStatsAttach(staAtt, 0); } } } this.undoManger[cmdName](); if ($('.edui-editor-tabletoolbar').hasClass('show') || $('.edui-editor-tabletoolbar').hasClass('hover')) { $('.rowblock,.colblock,.tableLeftTop').removeClass('active'); $('.oprow,.opcol').hide(); $('.edui-editor-tabletoolbar').removeClass('show').removeClass('hover') } //重新统计所有的图片和附件 if (me.options.statsAttach) { if ($(me.body).find('img').length > 0 || $(me.body).find('iframe').length > 0) { var staAtt = []; for (var i = 0; i < $(me.body).find('img').length; i++) { var src = $(me.body).find('img').eq(i).attr('src'); // 未上传成功的图片不统计,autouploader处理、非镜像不是chaoxing域名的图片不统计 // if(src.indexOf('spacer.gif') == -1 && (!RichTextUitl.intranetMode && src.indexOf('chaoxing.com') == -1)) { // continue; // } var imgItem = { 'type': 'img', 'resource': src } staAtt.push(imgItem); } for (var i = 0; i < $(me.body).find('iframe').length; i++) { var iframeItem = { 'type': 'iframe', 'resource': $(me.body).find('iframe').eq(i).attr('name') } staAtt.push(iframeItem); } if (staAtt.length > 0) { me.anasycStatsAttach(staAtt, 1); } } } me.normalList(); //20210317 更新目录 if (typeof (updateAllCatalog) == "function") { updateAllCatalog(me.body); } }, queryCommandState: function (cmdName) { return this.undoManger['has' + (cmdName.toLowerCase() == 'undo' ? 'Undo' : 'Redo')] ? 0 : -1; }, notNeedUndo: 1 }; var keys = { // /*Backspace*/ 8:1, /*Delete*/ 46:1, /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1, 37: 1, 38: 1, 39: 1, 40: 1 }, keycont = 0, lastKeyCode; //输入法状态下不计算字符数 me.addListener('ready', function () { domUtils.on(this.body, 'compositionstart', function () { inputType = true; }); domUtils.on(this.body, 'compositionend', function () { inputType = false; }) }); //快捷键 me.addshortcutkey({ "Undo": "ctrl+90", //undo "Redo": "ctrl+89" //redo }); function deepEqual(x, y) { // 指向同一内存时 if (x === y) { return true; } else if ((typeof x == "object" && x != null) && (typeof y == "object" && y != null)) { if (Object.keys(x).length != Object.keys(y).length) return false; for (var prop in x) { if (y.hasOwnProperty(prop)) { if (!deepEqual(x[prop], y[prop])) return false; } else return false; } return true; } else return false; } var isCollapsed = true; me.addListener('keydown', function (type, evt) { var me = this; var range = me.selection.getRange().cloneRange(); var keyCode = evt.keyCode || evt.which; var isdelete = false; var selectDelete = false, selectRangeText = 0; var address = range.createAddress(false, true); if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.altKey) { if (inputType) return; if (keyCode == 8 || keyCode == 46) { isdelete = true; } // 20200709 选中内容输入 if (!range.collapsed && me.options.cooperation && (evt.code.indexOf('Key') > -1 || evt.code.indexOf('Digit') > -1 || evt.code == 'Space' || inputkeycodes.indexOf(evt.code) > -1)) { selectDelete = true; selectRangeText = me.selection.getText().replace(new RegExp(domUtils.fillChar, 'g'), '').length; } if (inputkeycodes.indexOf(evt.code) > -1 && me.options.cooperation && evt.keyCode == 299) { //特殊字符插入,startoffset-1【】;’,。、、-=· range.startOffset = range.startOffset - 1; range.startOffset = range.endOffset - 1; UE.addressList.push(address); } else if (!range.collapsed && !selectDelete) { if ((keyCode == 8 || keyCode == 46) && me.options.cooperation && UE.isDeleteAll == false) { var data = {}; data.name = "delete"; data.address = address; data.isCollapsed = "false"; me.sendJoinData(data); } //解决列表下选中删除只删除了前一个字 // me.undoManger.save(false, true); isCollapsed = false; return; } else if (me.options.cooperation) { UE.addressList.push(address); } if (me.undoManger.list.length == 0) { me.undoManger.save(true); } clearTimeout(saveSceneTimer); function save(cont) { cont.undoManger.save(false, true); cont.fireEvent('selectionchange'); //协同编辑插入删除 if (me.options.cooperation) { //计算插入文字 var _this = me.undoManger; //内容相同不存 if (_this.list.length > 1) { var lastList = _this.list[_this.list.length - 2]; } else { var lastList = _this.list[_this.list.length - 1]; } var currentList = _this.list[_this.list.length - 1]; if (lastList && lastList.content == currentList.content) { return; } var currentLen = 0; if (_this.list.length > 1) { var div1 = document.createElement('div'); var div2 = document.createElement('div'); div1.innerHTML = lastList.content.replace(new RegExp(domUtils.fillChar, 'g'), ''); div2.innerHTML = currentList.content.replace(new RegExp(domUtils.fillChar, 'g'), ''); var firstLen = $(div1)[0].innerText.length; var lastLen = $(div2)[0].innerText.length; currentLen = lastLen - firstLen; } else { var div1 = document.createElement('div'); div1.innerHTML = _this.list[0].content.replace(new RegExp(domUtils.fillChar, 'g'), ''); currentLen = $(div1)[0].innerText.length } var range = me.selection.getRange(); var rng = range.cloneRange(); var start = rng.startContainer; var end = rng.endContainer; var tmpStart = start; var prev = start.previousSibling; while (!domUtils.isBlockElm(start)) { start = start.parentNode; } if (start && start.getAttribute("element-id")) { var elementId = start.getAttribute("element-id"); } else { start.setAttribute("element-id", domUtils.getRandomId()); } rng.setStartBefore(start); //获取选取的文本 var rangeText = rng.cloneContents().textContent.replace(new RegExp(domUtils.fillChar, 'g'), ''); var rangeLen = rangeText.length; var startLen = start.innerText.replace(new RegExp(domUtils.fillChar, 'g'), '').replace(/^\s+|\s+$/g, '').length; rng.setCursor(true, true); var insertData = {}; var delData = {}; if (selectDelete == true) { //选中插入文字 var startPos = (rangeLen > 0 ? rangeLen - currentLen : 0) - selectRangeText; var insertText = rangeText.substring(startPos); var data = {}; data.name = 'insert'; data.insertType = 'selectinsert'; data.elementId = 'elementId'; data.startPos = startPos; data.insertText = insertText; if (UE.addressList.length > 0) { data.address = UE.addressList[0]; } me.sendJoinData(data); selectDelete = false; selectRangeText = 0; } else if (currentLen > 0) { var startPos = rangeLen > 0 ? rangeLen - currentLen : 0; var insertText = rangeText.substring(startPos); insertData.name = "insert"; if (UE.addressList.length > 0) { insertData.address = UE.addressList[0]; } insertData.elementId = elementId; insertData.startPos = startPos; insertData.insertText = insertText; var insertDataClone = JSON.parse(JSON.stringify(insertData)); delete insertDataClone.address; if (UE.XTSendData.length >= 1) { var lastData = UE.XTSendData[UE.XTSendData.length - 1]; console.log(deepEqual(lastData, insertDataClone)) if (deepEqual(lastData, insertDataClone) == false) { UE.XTSendData = []; UE.XTSendData.push(JSON.parse(JSON.stringify(insertDataClone))); me.sendJoinData(insertData); } else { UE.XTSendData.push(JSON.parse(JSON.stringify(insertDataClone))); } } else { UE.XTSendData.push(JSON.parse(JSON.stringify(insertDataClone))); me.sendJoinData(insertData); } } else if (currentLen < 0 && UE.isSendDelete == false && UE.isDeleteAll == false && isdelete) { var delLen = Math.abs(currentLen); var startPos = rangeLen + delLen; delData.name = "delete"; delData.address = UE.addressList[0]; delData.addressEnd = range.createAddress(false, true); delData.elementId = elementId; delData.startPos = startPos; delData.delLen = delLen; me.sendJoinData(delData); } //协同编辑行首删除 if (keyCode == 8 && UE.isSendDelete == false && UE.isDeleteAll == false) { if (currentLen == 0) { var data = {}; data.name = "delete"; data.elementId = elementId; data.address = UE.addressList[0]; data.startPos = 0; data.delLen = 0; data.eleLen = startLen - rangeLen; me.sendJoinData(data); } } UE.addressList = []; } } saveSceneTimer = setTimeout(function () { if (inputType) { var interalTimer = setInterval(function () { if (!inputType) { save(me); clearInterval(interalTimer) } }, 300) return; } save(me); }, 200); lastKeyCode = keyCode; keycont++; if (keycont >= maxInputCount) { save(me) } } }); me.addListener('keyup', function (type, evt) { var keyCode = evt.keyCode || evt.which; if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) { if (inputType) return; if (!isCollapsed) { this.undoManger.save(false, true); isCollapsed = true; } else { me.fireEvent('contentchange'); } } }); //扩展实例,添加关闭和开启命令undo me.stopCmdUndo = function () { me.__hasEnterExecCommand = true; }; me.startCmdUndo = function () { me.__hasEnterExecCommand = false; } }; // plugins/copy.js UE.plugin.register('copy', function () { var me = this; return { bindEvents: { 'ready': function () { if (!browser.ie) { if (window.clipboard) { window.dt = new clipboard.DT(); } else { var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } url = prefix + "third-party/clipboard-polyfill.promise.js"; utils.loadFile(document, { src: url, tag: "script", type: "text/javascript", defer: "defer" }, function () { window.dt = new clipboard.DT(); }); } } } }, commands: { 'copy': { queryCommandState: function () { //表格中无内容,且未选中表格时,右键菜单中的复制、剪切按钮隐藏 var range = me.selection.getRange(); return (UE.UETable.getUETableBySelected(me) || !range.collapsed) ? 0 : -1; }, execCommand: function (cmd) { var me = this, rng = me.selection.getRange(); if (!document.getElementById('pasteDiv')) { div = document.createElement('div'); div.id = 'pasteDiv'; div.style.display = 'none'; document.body.appendChild(div); } else { div = document.getElementById('pasteDiv') } div.innerHTML = ''; if ($(rng.startContainer).parents('table').length > 0 && $(rng.startContainer).parents('table').find('td.selectTdClass').length > 0) { tableCopyList = null; var ut = UE.UETable.getUETableBySelected(me); if (ut) { var tds = ut.selectedTds; isFullCol = ut.isFullCol(); isFullRow = ut.isFullRow(); tableCopyList = [ [ut.cloneCell(tds[0], null, true)] ]; for (var i = 1, ci; ci = tds[i]; i++) { if (ci.parentNode !== tds[i - 1].parentNode) { tableCopyList.push([ut.cloneCell(ci, null, true)]); } else { tableCopyList[tableCopyList.length - 1].push(ut.cloneCell(ci, null, true)); } } } var tds = $(rng.startContainer).parents('table').find('td.selectTdClass'); for (var i = 0; i < tds.length; i++) { div.appendChild(tds[i].cloneNode(true)); } } else { div.appendChild(rng.cloneContents()); } dt.setData("text/html", div.innerHTML); clipboard.write(dt).then(function () { if ($('.toolTipBox').length > 0) { $('.toolTipBox').remove() } var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } $(document.body).append('') $('.toolTipBox .tipstext').text(me.getLang('tips.copySuccess')); $('.toolTipBox').show(); setTimeout(function () { $('.toolTipBox').fadeOut(); }, 1500) }, function (err) { console.log(err); }); } }, 'cut': { queryCommandState: function () { //表格中无内容,且未选中表格时,右键菜单中的复制、剪切按钮隐藏 var range = me.selection.getRange(); return (UE.UETable.getUETableBySelected(me) || !range.collapsed) ? 0 : -1; }, execCommand: function (cmd) { var me = this, rng = me.selection.getRange(); if (!document.getElementById('pasteDiv')) { div = document.createElement('div'); div.id = 'pasteDiv'; document.body.appendChild(div); } else { div = document.getElementById('pasteDiv') } var istd = false; if ($(rng.startContainer).parents('table').length > 0 && $(rng.startContainer).parents('table').find('td.selectTdClass').length > 0) { istd = true; tableCopyList = null; var ut = UE.UETable.getUETableBySelected(me); if (ut) { var tds = ut.selectedTds; isFullCol = ut.isFullCol(); isFullRow = ut.isFullRow(); tableCopyList = [ [ut.cloneCell(tds[0], null, true)] ]; for (var i = 1, ci; ci = tds[i]; i++) { if (ci.parentNode !== tds[i - 1].parentNode) { tableCopyList.push([ut.cloneCell(ci, null, true)]); } else { tableCopyList[tableCopyList.length - 1].push(ut.cloneCell(ci, null, true)); } } } var tds = $(rng.startContainer).parents('table').find('td.selectTdClass'); for (var i = 0; i < tds.length; i++) { div.appendChild(tds[i].cloneNode(true)); } } else { div.appendChild(rng.cloneContents()); } dt.setData("text/html", div.innerHTML); clipboard.write(dt).then(function () { if ($('.toolTipBox').length > 0) { $('.toolTipBox').remove() } var prefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/res/plugin/ueditor/'; if(RichTextUitl.intranetMode){ prefix = RichTextUitl.prefix } $(document.body).append('') if (istd) { if (isFullCol && isFullRow) { domUtils.remove(ut.table) } else if (isFullRow) { for (var i = ut.cellsRange.beginRowIndex; i <= ut.cellsRange.endRowIndex; i++) { domUtils.remove(ut.table.lastChild.childNodes[i]) } } else if (isFullCol) { for (var i = 0; i < ut.selectedTds.length; i++) { var colIndex = ut.getCellInfo(ut.selectedTds[i]).colIndex; domUtils.remove(ut.selectedTds[i]); if ($(ut.table).find('col').eq(colIndex).length > 0) { $(ut.table).find('col').eq(colIndex).remove(); $('.colblock').eq(colIndex).remove(); } } ut.update(); } else { me.execCommand('cleartable'); } } else { rng.deleteContents(); } $('.toolTipBox .tipstext').text(me.getLang('tips.cutSuccess')); $('.toolTipBox').show(); setTimeout(function () { $('.toolTipBox').fadeOut(); }, 1500) }, function (err) { console.log(me.getLang('tips.cutFail')); }); } }, } } }); // plugins/paste.js ///import core ///import plugins/inserthtml.js ///import plugins/undo.js ///import plugins/serialize.js ///commands 粘贴 ///commandsName PastePlain ///commandsTitle 纯文本粘贴模式 /** * @description 粘贴 * @author zhanyi */ UE.plugins['paste'] = function () { function getClipboardData(callback) { var doc = this.document; if (doc.getElementById('baidu_pastebin')) { return; } var range = this.selection.getRange(); var rangecollapse = range.collapse; var 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; } } //20200109补全多选框 if (doc.querySelectorAll('#baidu_pastebin .todo-view').length > 0) { var firsttodo = doc.querySelectorAll('#baidu_pastebin .todo-view')[0]; if (firsttodo.querySelectorAll('.todo-mark').length == 0) { var newNode = document.createElement('span'); newNode.className = 'todo-mark'; newNode.contentEditable = false; newNode.innerHTML = ''; firsttodo.insertBefore(newNode, firsttodo.firstChild) } } for (var i = 0, pastebins = doc.querySelectorAll('#baidu_pastebin img'), pi; pi = pastebins[i++];) { if (pi) { //粘贴的图片地址是本地图片时,移除图片 20210907 if (pi.src.indexOf('file://') > -1) { RichTextUitl.showTips('图片粘贴失败,请单独选中图片再复制粘贴,或导入文档', 0) pi.parentNode.removeChild(pi); continue; } if(pi.parentNode && pi.parentNode.className == 'image-wrap'){ $(pi).unwrap() } pi.setAttribute('src',pi.getAttribute('data-original') || pi.getAttribute('_src') || pi.getAttribute('src')) if(pi.getAttribute('data-original')){ pi.setAttribute('_src',pi.getAttribute('data-original')) } pi.removeAttribute('fileid'); if (pi.parentNode && pi.parentNode.className.indexOf('editor-image') > -1) { pi.parentNode.setAttribute('contenteditable', 'false'); if (pi.parentNode.parentNode && pi.parentNode.parentNode.className.indexOf('drag-image-wrap') > -1) { pi = pi.parentNode; } if (pi.parentNode.previousSibling) { var sibling = pi.parentNode.previousSibling; if (sibling.nodeType == 1 && !sibling.firstChild) { // 图片外已经有class 为 editor-image 的 div 标签了,且前一个元素是块状元素,但为空,不占位 ,里面加br占位 sibling.innerHTML = '
    '; } else { //其他情况不处理 } } else { //图片外面已经有class 为 editor-image 的 div 标签了,但前面没有br,图片标签外添加br var ele = document.createElement('div'); ele.setAttribute('element-id', domUtils.getRandomId()) ele.innerHTML = '
    '; var dom = ele.childNodes[0]; pi.parentNode.parentNode.insertBefore(ele.firstChild, pi.parentNode); } } else { // 图片标签外添加div if(pi.parentNode.nodeName == 'A'){ $(pi).unwrap() } var ele = document.createElement('div'); ele.setAttribute('element-id', domUtils.getRandomId()) ele.innerHTML = '
    '; var dom = ele.childNodes[1]; pi.parentNode.insertBefore(ele.firstChild, pi); pi.parentNode.insertBefore(ele.lastChild, pi); dom.appendChild(pi); } // 如果图片域名和当前图片域名一致,或者域名是超星域名,图片是cldisk域名,不置空 if(pi.src && !(pi.src.indexOf(getMainDomain(window.location.host)) > -1 || (window.location.host.indexOf('chaoxing.com') > -1 && pi.src.indexOf('cldisk.com') > -1))){ pi.setAttribute('_src',pi.src); pi.src = ''; pi.parentNode.classList.add('remoteImage'); } } } try { pastebin.parentNode.removeChild(pastebin); } catch (e) { } range.moveToBookmark(bk).select(true); if (rangecollapse) { range.collapse(true); } callback(pastebin); }, 0); } // 获取主域名 function getMainDomain(hostname) { var hostnameParts = hostname.split('.'); if (hostnameParts.length <= 2) { return hostname; } else { return `${hostnameParts[hostnameParts.length - 2]}.${hostnameParts[hostnameParts.length - 1]}`; } } var me = this; me.setOpt({ retainOnlyLabelPasted: false }); var txtContent, htmlContent, address; function matchURL(str) { var urlReg = new RegExp('((((http[s]{0,1}|ftp)://)([a-zA-Z0-9\\-]+\\.)+[a-zA-Z0-9\\-]+(:\\d+)?)|(((http[s]{0,1}|ftp)://)?(((?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))(:\\d+)?)|(([a-zA-Z0-9\\-]+\\.)+((ac)|(ad)|(ae)|(aero)|(af)|(ag)|(ai)|(al)|(am)|(an)|(ao)|(ar)|(arpa)|(as)|(asia)|(at)|(au)|(aw)|(ax)|(az)|(ba)|(bb)|(bd)|(be)|(bf)|(bg)|(bh)|(bi)|(biz)|(bj)|(bm)|(bn)|(bo)|(br)|(bs)|(bt)|(bv)|(bw)|(by)|(bz)|(ca)|(cat)|(cc)|(cd)|(cf)|(cg)|(ch)|(chintai)|(ci)|(ck)|(cl)|(cm)|(cn)|(co)|(com)|(coop)|(cr)|(cu)|(cv)|(cx)|(cy)|(cz)|(de)|(dj)|(dk)|(dm)|(do)|(dz)|(ec)|(edu)|(ee)|(eg)|(er)|(es)|(et)|(eu)|(fi)|(fj)|(fk)|(fm)|(fo)|(fr)|(ga)|(gb)|(gd)|(ge)|(gf)|(gg)|(gh)|(gi)|(gl)|(global)|(globo)|(gm)|(gmail)|(gn)|(gov)|(gp)|(gq)|(gr)|(gs)|(gt)|(gu)|(gw)|(gy)|(hk)|(hm)|(hn)|(hr)|(ht)|(hu)|(id)|(ie)|(il)|(im)|(in)|(info)|(int)|(iq)|(ir)|(is)|(it)|(je)|(jm)|(jo)|(jobs)|(jp)|(ke)|(kg)|(kh)|(ki)|(km)|(kn)|(kp)|(kr)|(kw)|(ky)|(kz)|(la)|(lb)|(lc)|(li)|(lk)|(lr)|(ls)|(lt)|(lu)|(lv)|(ly)|(ma)|(mc)|(md)|(me)|(mg)|(mh)|(mil)|(mk)|(ml)|(mm)|(mn)|(mo)|(mobi)|(mp)|(mq)|(mr)|(ms)|(mt)|(mu)|(museum)|(mv)|(mw)|(mx)|(my)|(mz)|(na)|(name)|(nc)|(ne)|(net)|(nf)|(ng)|(ni)|(nl)|(no)|(np)|(nr)|(nu)|(nz)|(om)|(org)|(pa)|(pe)|(pf)|(pg)|(ph)|(pk)|(pl)|(pm)|(pn)|(pr)|(pro)|(ps)|(pt)|(pw)|(py)|(qa)|(re)|(ro)|(rs)|(ru)|(rw)|(sa)|(sb)|(sc)|(sd)|(se)|(sg)|(sh)|(si)|(sj)|(sk)|(sl)|(sm)|(smile)|(so)|(sr)|(st)|(su)|(sy)|(sz)|(tc)|(td)|(tel)|(tf)|(tg)|(th)|(tj)|(tl)|(tm)|(tn)|(to)|(tp)|(tr)|(travel)|(tt)|(tv)|(tw)|(tz)|(ua)|(ug)|(uk)|(us)|(uy)|(uz)|(va)|(vc)|(ve)|(vg)|(vi)|(vn)|(vu)|(wf)|(ws)|(ye)|(yt)|(za)|(zm)|(zw))(?![a-zA-Z0-9]))(:\\d+)?)))(/[a-zA-Z0-9\\.\\-~!@#$%^&#$%^&*+?:_/=<>()]*)?', 'gi'); str = str.replace(urlReg, function (value, index) { let href = value; if(value.indexOf('http') != 0 && value.indexOf('ftp') != 0){ href = 'https://' + value } return '' + value + '' }) return str; } function getPureHtml(html) { return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function (a, b, tagName, attrs) { tagName = tagName.toLowerCase(); if ({ img: 1 }[tagName]) { return a; } attrs = attrs.replace(/([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi, function (str, atr, val) { if ({ 'src': 1, 'href': 1, 'name': 1 }[atr.toLowerCase()]) { return atr + '=' + val + ' ' } return '' }); if ({ 'span': 1, 'div': 1 }[tagName]) { return '' } else { return '<' + b + tagName + ' ' + utils.trim(attrs) + '>' } }); } function filter(div) { var html; if (div.lastChild && div.lastChild.nodeType == 1 && div.lastChild.nodeName && div.lastChild.nodeName.toLowerCase() == 'br') { div.removeChild(div.lastChild) } //20200909 光标在课前课中课后时不允许粘贴 var range = me.selection.getRange(); var start = range.startContainer; if (start.nodeType == 1 && ($(start).is('#ulTab') || $(start).parents('#ulTab').length > 0)) { return; } //去除飞书粘贴时带的空div if (div.firstChild && div.firstChild.nodeType == 1 && div.firstChild.className == "okr-block-clipboard" && !div.firstChild.firstChild) { domUtils.remove(div.firstChild) } 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); } } //20200811过滤粘贴过来的课堂笔记头部id if (div.querySelector('#ulTab')) { div.querySelector('#ulTab').removeAttribute('id'); } 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'); tmpP.setAttribute('element-id', domUtils.getRandomId()) di.parentNode.insertBefore(tmpP, di); while (di.firstChild) { tmpP.appendChild(di.firstChild); } domUtils.remove(di); } var metas = div.querySelectorAll('meta'); for (var i = 0, ci; ci = metas[i++];) { domUtils.remove(ci); } var brs = div.querySelectorAll('br'); for (i = 0; ci = brs[i++];) { if (/^apple-/i.test(ci.className)) { domUtils.remove(ci); } } } if (browser.gecko) { var dirtyNodes = div.querySelectorAll('[_moz_dirty]'); for (i = 0; ci = dirtyNodes[i++];) { ci.removeAttribute('_moz_dirty'); } } if (!browser.ie) { var spans = div.querySelectorAll('span.Apple-style-span'); for (var i = 0, ci; ci = spans[i++];) { domUtils.remove(ci, true); } } //解决火狐浏览器粘贴时丢失序号属性的问题 $(div).find('ol').eq(0).attr('data-origin-start', 1); $(div).find('ol:not([level])').each(function (index, list) { if (!list.firstChild) { domUtils.remove(list); return } $(this).removeAttr('class').removeAttr('style'); if ($(list).parents('ol,ul').length > 0 && $(list).parents('ol,ul').eq(0).parents(div).length > 0) { var listnext = list.nextSibling; $(list).attr('level', 1 + parseInt($(list).parents('ol,ul').eq(0).attr('level'))); domUtils.breakParent(list, $(list).parents('ol,ul')[0]); if (listnext) { domUtils.remove(list.nextSibling); } if (list.nextSibling && list.nextSibling.firstChild && !list.nextSibling.firstChild.firstChild) { domUtils.remove(list.nextSibling.firstChild); } if (list.nextSibling && !list.nextSibling.firstChild) { domUtils.remove(list.nextSibling); } } if (!$(this).attr('level')) { $(list).attr('level', '1'); if (list.tagName == 'OL') { $(list).attr('serialnum', '1'); } } if ($(this).parents('ol,ul').length > 0 && $(list).parents('ol,ul').eq(0).parents(div).length > 0) { $(list).attr('level', 1 + parseInt($(list).parents('ol,ul').eq(0).attr('level'))); } var level = $(list).attr('level'); $(list).children('li').each(function (index, li) { var serialnum = serialnumToString(index + 1, level); $(li).parent().attr('level', level); if (list.tagName == 'OL') { $(li).attr('serialnum', serialnum); } }); var listnext = list.nextSibling; $(list).children('li').each(function (index, li) { if (index > 0) { var newlist = document.createElement(list.tagName); newlist.setAttribute('element-id', domUtils.getRandomId()) if (list.tagName == 'OL') { $(newlist).attr('serialnum', li.getAttribute('serialnum')); } $(newlist).attr('level', level); if (listnext) { list.parentNode.insertBefore(newlist, listnext); } else { list.parentNode.appendChild(newlist); } newlist.appendChild(li); } else { if (list.tagName == 'OL') { $(list).attr('serialnum', li.getAttribute('serialnum')); } $(list).attr('level', level); } }) }); var tables = div.querySelectorAll('table'); if (tables.length > 0) { for (var i = 0; i < tables.length; i++) { if (tables[i].parentNode == div) { //粘贴的直接就是table的表格 var tempdiv = me.document.createElement('div'); tempdiv.setAttribute('element-id', domUtils.getRandomId()); tempdiv.className = 'table'; tempdiv.style = 'width:100%;max-width:100%;overflow-x:auto;' div.insertBefore(tempdiv, tables[i]); tempdiv.appendChild(tables[i]); } } } //粘贴的附件如果协议头不一样,附件加载不出来,变成空白 $(div).find('iframe').each(function (index, iframe) { var url = iframe.getAttribute('src'); if(!url) return iframe.setAttribute('src', RichTextUitl.convertUrl(url)); }) //粘贴的附件和文本附件更换cid $(div).find('iframe[module],a[module]').each(function (index, item) { var cid = RichTextUitl.randomUUID(); var attachmentContent = RichTextUitl.b64DecodeUnicode($(item).attr('name')); if(attachmentContent.attachmentType == 15 && !(attachmentContent.att_chat_course.type && attachmentContent.att_chat_course.type == 4)){ //课程活动不允许复制 $(item).parent().remove(); return } attachmentContent.cid = cid; var name = RichTextUitl.b64EncodeUnicode(JSON.stringify(attachmentContent)); $(item).attr('cid', cid).attr('name', name); }) $(div).find('h1,h2,h3,h4,h5,h6').attr('element-id', domUtils.getRandomId()); //去掉笔记多余内容(头部信息、目录、点赞、部分评论、评论数量、悬浮工具栏) $(div).find('.noteHead_r,.noteDetail_info,.catalogWrap,.likeWrap,.noteDetail_editContainer,.maskDiv,.attachhover,.cmcount-number,.partCommentWrap,.subNav').remove(); //去除新笔记图片的拖拽按钮和工具栏元素 $(div).find('.cursor-div,.image_tools').remove() //支持粘贴新笔记的附件 $(div).find('.attachment_card').each(function(index,item){ var module = $(item).attr('data-module'); var attachmentName = RichTextUitl.b64DecodeUnicode($(item).attr('data-name')||$(item).attr('name')) var cid = RichTextUitl.randomUUID(); item.setAttribute('cid', cid) attachmentName.cid = cid; var displayMode = $(item).attr('displaymode'); if(displayMode && displayMode == 'previewMode' || $(item).hasClass('web-iframe')){ //预览附件 item.classList = 'editor-iframe'; item.setAttribute('contenteditable','false') if(module == 'insertWeb'){ src = attachmentName.att_web.url }else if(module == 'insertCloud'){ src = window.location.protocol + '//previewyd.chaoxing.com/res/view/view.html?objectid=' + attachmentName.att_clouddisk.fileId + '&fileName=' + encodeURIComponent(attachmentName.att_clouddisk.name); } item.innerHTML = '' }else if(displayMode && displayMode == 'textMode'){ //文本附件 item.className = ''; let src = '', linkClass = '',name = ''; if(module == 'insertWeb'){ src = attachmentName.att_web.url; name = attachmentName.att_web.title; linkClass = 'link'; }else if(module == 'insertCloud'){ src = attachmentName.att_clouddisk.downPath || ('https://d0.cldisk.com/download/' + attachmentName.att_clouddisk.fileId); name = attachmentName.att_clouddisk.name; linkClass = 'iframe'; } item.innerHTML = '' + name + '' }else{ //卡片附件 item.classList = 'editor-iframe'; item.setAttribute('contenteditable','false') item.innerHTML = '' } }); //支持新笔记的列表 $(div).find('ol[level][style]').each(function(index,item){ item.removeAttribute('data-changed') if(item.style.counterReset){ var serialnum = parseInt(item.style.counterReset.replace(/\D/g,'')) + 1; item.style.cssText = ''; item.setAttribute('serialnum',serialnum) $(item).children().each(function(index,li){ li.setAttribute('serialnum',serialnum + index) }) } }) //支持新笔记的勾选框 $(div).find('div.todo_wrap').each(function(index,item){ var checkedClass = '' if(item.className.indexOf('todo-checked') > -1){ checkedClass = ' checked' } item.className = 'todo-view' + checkedClass; $(item).find('.todo-inner')[0].className = 'todo-text'; $(item).find('.todo-inner').attr('contenteditable','false'); if($(item).find('.todo-box')[0]){ $(item).find('.todo-box')[0].innerHTML = ''; $(item).find('.todo-box')[0].className = 'todo-mark'; }else if(!$(item).find('.todo-mark')[0]){ $(item).prepend('') } }) //支持新笔记的代码块 $(div).find('div.cm-editor').each(function(index,item) { item.innerHTML = '
    ' + $(item).find('.cm-content').html().replace(/<\/div>/g,'\n').replace(/<[^>]+>/g,'') + '
    '; $(item.firstChild).unwrap() }) //粘贴笔记内容只保留富文本部分内容 if ($(div).find('.richtext').length == 1) { var noteTitle = $(div).find('.noteDetail_head .title').html() || ''; var titlehtml = noteTitle != '' ? '

    ' + noteTitle + '

    ' : ''; div.innerHTML = titlehtml + $(div).find('.richtext').html(); } if ($(div).find('.ProseMirror').length == 1) { var noteTitle = $(div).find('.noteTitle').val() || ''; var titlehtml = noteTitle != '' ? '

    ' + noteTitle + '

    ' : ''; div.innerHTML = titlehtml + $(div).find('.ProseMirror').html(); } //站内信粘贴的内容去除所有背景色,字体颜色 if(window.location.href.includes('notice.chaoxing.com')){ $(div).find('p,span').each(function(index, item){ if(item.style.color){ item.style.color = null } if(item.style.background){ item.style.background = null } if(item.style.backgroundColor){ item.style.backgroundColor = null } }) } //粘贴的写站内信的原站内信样式去掉 $(div).find('.noticeTitle>*').each(function(index, item){ if($(item).parents('.notice_main').length == 0){ $(item).unwrap(); } }) if ($(div).find('.textA-imgList').length > 0) { $(div).find('.textA-imgList').each(function (index, item) { if (!item.firstChild) $(item).remove(); }) } if ($(div).find('.attachList').length > 0) { $(div).find('.attachList').each(function (index, item) { if (!item.firstChild) $(item).remove(); }) } if ($(div).find('.textA-noteContent').length > 0) { $(div).find('.textA-noteContent').each(function (index, item) { if (!item.firstChild || domUtils.isEmptyBlock(item.firstChild)) $(item).remove(); }) } if ($(div).find('.noteHead.noteDetail_head .title').siblings().length == 0) { $(div).find('.noteHead.noteDetail_head .title').removeAttr('id').removeAttr('style', '').removeClass('title').unwrap(); } if ($(div).find('.noteDetail_main .richtext').siblings().length == 0) { $(div).find('.noteDetail_main .richtext').unwrap(); $(div).find('.richtext>*').unwrap(); } $(div).find('.richtext').removeAttr('id').removeAttr('style', ''); //移除空列表,防止粘贴产生空行 $(div).find('li').each(function () { if ($(this).text() == '' && $(this).find('img').length == 0 && $(this).find('iframe').length == 0 && $(this).find('canvas').length == 0 && $(this).find('br').length == 0 && $(this).find('hr').length == 0) { $(this).remove() } }); $(div).find('ul,ol').each(function (index, item) { if ($(this).html() == '') { $(this).remove() } }); //ie下使用innerHTML会产生多余的\r\n字符,也会产生 这里过滤掉 html = div.innerHTML; //.replace(/>(?:(\s| )*?)<'); //将从QQ粘贴的多行文字 xxx
    xxx
    转成p var hasBlockElm = false, node = div.firstChild; while (node) { if (domUtils.isBlockElm(node)) { hasBlockElm = true; break; } else { node = node.nextSibling; } } if (!hasBlockElm && html.match(/
    /g) && html.match(/
    /g).length > 1) { node = div.firstChild; var p = document.createElement('p'); while (node) { next = node.nextSibling; if (domUtils.isBlockElm(node)) { div.appendChild(p); break; } else if (node.nodeName == 'BR' && node.nextSibling && !domUtils.isBlockElm(node.nextSibling)) { p.appendChild(node); div.appendChild(p); p = document.createElement('p'); } else { p.appendChild(node); } node = next; } html = div.innerHTML; } //粘贴的链接直接标蓝 //取出粘贴内容里的所有文本,并把文本里的url替换为url,再去掉a标签套a标签的问题 let textReg = new RegExp('>(>[^<>]*)*[^<]+(<[^<>]*)*<', 'gi'); html = '>' + html + '<'; html = html.replace(textReg, function () { let str = arguments[0]; str = str.substr(1, str.length - 2); return '>' + matchURL(str) + '<'; }) html = html.substr(1, html.length - 2) div.innerHTML = html; $(div).find('a>object>a').each(function (index, item) { item.parentNode.parentNode.innerHTML = item.parentNode.parentNode.innerText; }) $(div).find('object>a').each(function (index, item) { $(item).unwrap() }) html = div.innerHTML; //粘贴时把pt换成px html = html.replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function (str, tag, quote, style) { var newStyle = style.replace(/[\d.]+(cm|pt)/g, function (str) { return utils.transUnitToPx(str) }); return tag + ' style=' + quote + newStyle + quote; }) //20200917 去除不完整的 html = html.replace(/(<\w+|"\w+\s+")\s+"=""\s*/gi, function () { return (arguments[1] ? arguments[1] : '') + ' '; }); //把英文字母中间的 换成空格 20201104 html = html.replace(/\b( )+\b/gi, function () { html = arguments[0].replace(/ /gi, ' '); return html; }); //粘贴的附件地址处理 html.replace(/' } return { outputRule: function (root) { utils.each(root.getNodesByTagName('img'), function (node) { var html; if (node.getAttr('class') == 'edui-faked-webapp') { html = createInsertStr({ title: node.getAttr('title'), 'width': node.getAttr('width'), 'height': node.getAttr('height'), 'align': node.getAttr('align'), 'cssfloat': node.getStyle('float'), 'url': node.getAttr("_url"), 'logo': node.getAttr('_logo_url') }, true); var embed = UE.uNode.createElement(html); node.parentNode.replaceChild(embed, node); } }) }, inputRule: function (root) { utils.each(root.getNodesByTagName('iframe'), function (node) { if (node.getAttr('class') == 'edui-faked-webapp') { var img = UE.uNode.createElement(createInsertStr({ title: node.getAttr('title'), 'width': node.getAttr('width'), 'height': node.getAttr('height'), 'align': node.getAttr('align'), 'cssfloat': node.getStyle('float'), 'url': node.getAttr("src"), 'logo': node.getAttr('logo_url') })); node.parentNode.replaceChild(img, node); } }) }, commands: { /** * 插入百度应用 * @command webapp * @method execCommand * @remind 需要百度APPKey * @remind 百度应用主页: http://app.baidu.com/ * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度, * height=>应用容器高度,logo=>应用logo,url=>应用地址 * @example * ```javascript * //editor是编辑器实例 * //在编辑器里插入一个“植物大战僵尸”的APP * editor.execCommand( 'webapp' , { * title: '植物大战僵尸', * width: 560, * height: 465, * logo: '应用展示的图片', * url: '百度应用的地址' * } ); * ``` */ 'webapp': { execCommand: function (cmd, obj) { var me = this, str = createInsertStr(utils.extend(obj, { align: 'none' }), false); me.execCommand("inserthtml", str); }, queryCommandState: function () { var me = this, img = me.selection.getRange().getClosedNode(), flag = img && (img.className == "edui-faked-webapp"); return flag ? 1 : 0; } } } } }); // plugins/template.js ///import core ///import plugins\inserthtml.js ///import plugins\cleardoc.js ///commands 模板 ///commandsName template ///commandsTitle 模板 ///commandsDialog dialogs\template UE.plugins['template'] = function () { UE.commands['template'] = { execCommand: function (cmd, obj) { obj.html && this.execCommand("inserthtml", obj.html); } }; this.addListener("click", function (type, evt) { var el = evt.target || evt.srcElement, range = this.selection.getRange(); var tnode = domUtils.findParent(el, function (node) { if (node.className && domUtils.hasClass(node, "ue_t")) { return node; } }, true); tnode && range.selectNode(tnode).shrinkBoundary().select(); }); this.addListener("keydown", function (type, evt) { var range = this.selection.getRange(); if (!range.collapsed) { if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) { var tnode = domUtils.findParent(range.startContainer, function (node) { if (node.className && domUtils.hasClass(node, "ue_t")) { return node; } }, true); if (tnode) { domUtils.removeClasses(tnode, ["ue_t"]); } } } }); }; // plugins/autoupload.js /** * @description * 1.拖放文件到编辑区域,自动上传并插入到选区 * 2.插入粘贴板的图片,自动上传并插入到选区 * @author Jinqn * @date 2013-10-14 */ UE.plugin.register('autoupload', function () { var me = this; var autouploadVideoInfo = new RMap(); if(!RichTextUitl.puid) { RichTextUitl.puid = getCookie('UID') } //获取上传云盘文件夹v2地址 function getFolderUploadUrl(folderId){ var from = me.options.from || 'old_note_editor'; var url = window.location.protocol + window.obj.mirrorDomain.NoteDomainHttps.replace("https:", '').replace('http:','') + '/pc/files/upload/getUploadFileUrl'; var uploadUrl = ''; $.ajax({ url: url, type: 'get', async: false, data:{ from: from, params: JSON.stringify({ type: 'ajax', fldid: folderId, hideFile: true }) }, xhrFields: { withCredentials: true }, success:function(res){ if(res.result){ uploadUrl = res.data } } }) return uploadUrl; } function sendAndInsertFile(file, editor, folderLoadingId, folderName, folderId, folderUploaderUrl) { var me = editor; if (me.options.closeUpload == 1) { // 关闭了上传功能 RichTextUitl.showTips('上传功能暂时关闭,请稍后再试', 0); return; } // 是否启用分片上传 if(chunkedUpload().isEnable(file, editor)) { chunkedUpload().init(file, editor); return false; } //模拟数据 var fieldName, urlPrefix, maxSize, allowFiles, actionUrl, loadingHtml, errorHandler, successHandler, filetype = /image\/\w+/i.test(file.type) ? 'image' : 'file', loadingId = 'loading_' + (+new Date()).toString(36); if(me.options.forbidAttachment && filetype == 'file'){ //不允许有附件 return }else if(me.options.forbidImage && filetype == 'image'){ //不允许有图片 return } fieldName = me.getOpt(filetype + 'FieldName'); urlPrefix = me.getOpt(filetype + 'UrlPrefix'); maxSize = me.getOpt(filetype + 'MaxSize'); allowFiles = me.getOpt(filetype + 'AllowFiles'); actionUrl = me.getActionUrl(me.getOpt(filetype + 'ActionName')); if (folderId) { if(folderUploaderUrl){ actionUrl = folderUploaderUrl }else{ actionUrl = "https://pan-yz.chaoxing.com/upload/uploadfile"; } } errorHandler = function (title) { var loader = me.document.getElementById(loadingId); loader && domUtils.remove(loader.parentNode); // me.fireEvent('showmessage', { // 'id': loadingId, // 'content': title, // 'type': 'error', // 'timeout': 4000 // }); RichTextUitl.showTips(title, 0); //当某个文件上传失败,清空myLoadingId myLoadingId = ''; }; //获取音视频时长 function getDuration2(file) { var video = document.createElement('video'); video.preload = 'metadata' video.src = URL.createObjectURL(file) video.addEventListener("loadedmetadata", function () { window.URL.revokeObjectURL(video.src); autouploadVideoInfo.put(file.name + '_' + file.size + '_duration', parseInt(video.duration)); autouploadVideoInfo.put(file.name + '_' + file.size + '_videoWidth', video.videoWidth); autouploadVideoInfo.put(file.name + '_' + file.size + '_videoHeight', video.videoHeight); } ); } var divelementid = domUtils.getRandomId(); if (folderLoadingId) { // 拖拽文件夹时上传文件夹下的文件 successHandler = function (data) { var folderInfo = RichTextUitl.uploadedFolder[folderLoadingId]; if (data) { folderInfo.objectIds.push(data.data.objectId) folderInfo.resids.push(data.data.residstr) } folderInfo.size = parseInt(folderInfo.size) - 1; if (folderInfo.size == 0) { // 文件都上传完了,向页面中加一个文件夹附件 loader = me.document.getElementById(folderLoadingId); var rng = me.selection.getRange(), bk = rng.createBookmark(); rng.selectNode(loader.parentNode).select(); var fileArray = new Array(); var item = RichTextUitl.yunFolderMap[folderId]; fileArray.push(item); me.execCommand('replacefile', fileArray); //协同编辑 if (me.options.cooperation) { var data = {}; data.name = 'replacefile'; var range = me.selection.getRange(); data.address = range.createAddress(false, true); data.fileArray = fileArray; me.sendJoinData(data); } rng.moveToBookmark(bk).select(); } } } else if (filetype == 'image') { /*loadingHtml = '';*/ loadingHtml = '
    '; successHandler = function (data) { var suffix = data.data.suffix || 'jpg'; var link, loader = me.document.getElementById(loadingId); if (RichTextUitl.intranetMode) { // 镜像版本,使用接口返回的图片地址 link = data.data.imgUrl; } else { link = data.data.previewUrl; } //统计添加的图片 if (me.options.statsAttach) { var staAtt = [{ 'type': 'img', 'resource': link }] me.anasycStatsAttach(staAtt, 1); } if (link && loader) { loader.setAttribute('src', link); loader.setAttribute('_src', link); //loader.setAttribute('title', data.title || ''); //loader.setAttribute('alt', data.original || ''); // 修改 loader.setAttribute('objectid', data.data.objectId || ''); loader.removeAttribute('id'); var hasLoad = false; loader.onload = function () { if (!hasLoad) { domUtils.removeClasses(loader, 'loadingclass'); if (me.autoHeightEnabled) { me.adjustHeight(); } var naturalWidth = this.naturalWidth; var naturalHeight = this.naturalHeight; loader.setAttribute('src', loader.getAttribute('src') + '?rw=' + this.naturalWidth + '&rh=' + this.naturalHeight + '&_fileSize=' + data.data.size + '&_orientation=1'); loader.setAttribute('_src', loader.getAttribute('src')); hasLoad = true; //20200523粘贴的图片加显示规则 var imgW1 = naturalWidth; //原始图片宽度 var imgH1 = naturalHeight; //原始图片高度 var imgW2; if (imgW1 >= 750) { if (imgW1 / imgH1 <= 9 / 16) { imgW2 = 243; } else { imgW2 = 800; } } else { imgW2 = imgW1; } var imgH2 = parseInt(imgW2 * imgH1 / imgW1); if (imgW2 > 0 && imgH2 > 0) { loader.style.width = imgW2 + 'px'; // loader.style.height = imgH2+'px'; } if (me.autoHeightEnabled) { me.adjustHeight(); } //20200616 本地粘贴图片后 发送协同数据 if (me.options.cooperation) { var senddata = {}; senddata.name = 'replace'; senddata.elementId = loader.parentNode.getAttribute('element-id'); senddata.html = loader.outerHTML; me.sendJoinData(senddata); } me.fireEvent('saveScene') } } } }; //20200616 拖拽到编辑器的内容 me.sendhtml(loadingHtml); /* 插入loading的占位符 */ me.execCommand('inserthtml', loadingHtml); } else { loadingHtml = '
    '; //会导致word不能拖拽进编辑器 // if(!file.type){ // if($('.toolTipBox').length > 0) { // $('.toolTipBox').remove() // } // $(document.body).append('') // $('.toolTipBox').show(); // setTimeout(function() { // $('.toolTipBox').fadeOut(); // }, 1500) // return; // } if (file.type && file.type.indexOf('video') > -1) { // 视频 getDuration2(file); } else if (isNotice && !($('.addItem .title').val() && $('.addItem .title').val().trim()) && !myLoadingId && isOneFile) { //发通知那边上传文件填充标题(视频除外) myLoadingId = loadingId; } successHandler = function (data) { //var link = urlPrefix + data.url, loader = me.document.getElementById(loadingId); var rng = me.selection.getRange(), bk = rng.createBookmark(); if (loader.parentNode.parentNode.className && loader.parentNode.parentNode.className.indexOf('drag-image-wrap') > -1) { //loading时是个图片,加了图片的drag-image-wrap,替换时要把它也去掉 rng.selectNode(loader.parentNode.parentNode).select(); } else { rng.selectNode(loader.parentNode).select(); } if (data) { var fileArray = new Array(); var item = getCloudAttachmentStructure(data.data); //当第一个附件上传完成,填充标题 if (isNotice && loadingId == myLoadingId) { //如果上传期间用户手动加标题,上传完成后不再替换标题 if (!($('.addItem .title').val() && $('.addItem .title').val().trim())) { $('.addItem .title').val(data.data.name.substring(0, data.data.name.lastIndexOf("."))); } myLoadingId = ''; } if (",mp4,3gp,avi,rmvb,asf,divx,mpg,mpeg,mpe,mkv,vob,flv,m4v,mov,f4v,wmv,".indexOf(item.att_clouddisk.suffix) > -1) { // 视频 var videoLength = autouploadVideoInfo.get(file.name + '_' + file.size + '_duration') || 1; var videoHeight = autouploadVideoInfo.get(file.name + '_' + file.size + '_videoHeight') || 0; var videoWidth = autouploadVideoInfo.get(file.name + '_' + file.size + '_videoWidth') || 0; var videoJson = { "att_video": { "coverUrl": (data.data.thumbnail || item.att_clouddisk.icon), "createTime": (new Date()).getTime(), "fileLength": item.att_clouddisk.size || file.size, "fileTitle": item.att_clouddisk.name || file.name, "objectId2": item.att_clouddisk.fileId || '', "resid": item.att_clouddisk.residstr || item.att_clouddisk.resid || '', "thumbnails_url": "", "type": item.att_clouddisk.suffix, "videoHeight": videoHeight, "videoLength": videoLength, "videoWidth": videoWidth }, "attachmentType": 29, "cid": RichTextUitl.randomUUID(), } if (RichTextUitl.intranetMode) { videoJson.att_video.playUrl = item.att_clouddisk.playUrl; } item = videoJson; } else if (RichTextUitl.intranetMode) { if (!item.att_clouddisk.size) { item.att_clouddisk.size = file.size || 0; item.att_clouddisk.fileSize = fileSize(file.size || 0); } if (!item.att_clouddisk.name) { item.att_clouddisk.name = file.name || ''; } } fileArray.push(item); me.execCommand('replacefile', fileArray); //协同编辑 if (me.options.cooperation) { var data = {}; data.name = 'replacefile'; var range = me.selection.getRange(); data.address = range.createAddress(false, true); data.fileArray = fileArray; me.sendJoinData(data); } } rng.moveToBookmark(bk).select(); }; /* 插入loading的占位符 */ me.execCommand('inserthtml', loadingHtml); } /* 判断后端配置是否没有加载成功 */ if (!me.getOpt(filetype + 'ActionName')) { errorHandler(me.getLang('autoupload.errorLoadConfig')); return; } /* 判断文件大小是否超出限制 */ if (file.size > maxSize) { errorHandler(me.getLang('autoupload.exceedSizeError')); return; } /* 判断文件格式是否超出允许 */ /*var fileext = file.name ? file.name.substr(file.name.lastIndexOf('.')):''; if ((fileext && filetype != 'image') || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) { errorHandler(me.getLang('autoupload.exceedTypeError')); return; }*/ // if (!RichTextUitl.puid || !RichTextUitl.yunToken) { // RichTextUitl.getUploadConfig(true); // } /* 创建Ajax并提交 */ var xhr = new XMLHttpRequest(), fd = new FormData(), params = utils.serializeParam(me.queryCommandValue('serverparam')) || '', url = utils.formatUrl(actionUrl + (actionUrl.indexOf('?') == -1 ? '?' : '&') + params); fd.append(fieldName, file, file.name || ('blob.' + file.type.substr('image/'.length))); fd.append('type', 'ajax'); fd.append("puid", RichTextUitl.puid); if (folderId) { fd.append("fldid", folderId); fd.append("hideFile ", true); } if(!folderUploaderUrl && RichTextUitl.yunToken) { fd.append("_token", RichTextUitl.yunToken); } xhr.open("post", url, true); // xhr.withCredentials = true; // xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.addEventListener('load', function (e) { try { var json = (new Function("return " + utils.trim(e.target.response)))(); if (RichTextUitl.intranetMode && typeof RichTextUitl.customUploadDataAnalysis == 'function') { // 镜像版本需要处理下接口返回值 json = RichTextUitl.customUploadDataAnalysis(json); } if (json.result) { successHandler(json); } else { errorHandler(json.msg); } } catch (er) { errorHandler(me.getLang('autoupload.loadError')); } }); xhr.send(fd); } function scanFiles(item, loadingId, folderName, folderId,folderUploaderUrl) { if (item && item.isDirectory) { var fileArray = new Array(); var hasSubFolder = false; // 使用目录实体来创建 FileSystemDirectoryReader 实例 var directoryReader = item.createReader(); var folderName = item.name; var fnReadEntries = function (entries) { entries.forEach(function (entry) { if (entry.isDirectory) { hasSubFolder = true; return; } fileArray.push(entry) //scanFiles(entry); }); // directoryReader.readEntries(fnReadEntries); if (hasSubFolder) { RichTextUitl.showTips('文件夹下包含子文件夹,暂不支持上传', 0) return; } if (fileArray.length == 0) { RichTextUitl.showTips('当前文件夹下没有文件', 0) return; } if (fileArray.length > 50) { RichTextUitl.showTips('文件夹下文件数大于50,暂不支持上传', 0); return; } var folderLoadingId = 'loading_' + (+new Date()).toString(36); var folderLoadingHtml = '
    '; // 记录文件夹下的文件数量,所有的文件都上传完后向页面中加一个文件夹附件 RichTextUitl.uploadedFolder[folderLoadingId] = {}; RichTextUitl.uploadedFolder[folderLoadingId].size = fileArray.length; RichTextUitl.uploadedFolder[folderLoadingId].objectIds = []; RichTextUitl.uploadedFolder[folderLoadingId].resids = []; $.ajax({ url: RichTextUitl.convertUrl("https://noteyd.chaoxing.com/pc/resource/createCloudFolder"), type: "get", data: { needShare: 1, name: encodeURI(folderName) }, dataType: "json", async: false, xhrFields: { withCredentials: true }, success: function (data) { var item = data.msg; var folderId = item.att_cloudFolder.resid; if (!RichTextUitl.yunFolderMap) { RichTextUitl.yunFolderMap = {}; } RichTextUitl.yunFolderMap[folderId] = item; var folderUploadUrl = ''; if(!(RichTextUitl.puid && RichTextUitl.yunToken)){ folderUploadUrl = getFolderUploadUrl(folderId) } for (var fileIndex = 0; fileIndex < fileArray.length; fileIndex++) { scanFiles(fileArray[fileIndex], folderLoadingId, folderName, folderId,folderUploadUrl); } } }) me.execCommand('inserthtml', folderLoadingHtml); }; directoryReader.readEntries(fnReadEntries); } else { (function (item) { item.file(function (file) { item['file'] = file; if (item.fullPath[0] == "/") { // 直接拖拽的文件 file.t_webkitRelativePath = item.fullPath.substring(1); } else { // 拖拽的文件夹,处理文件夹下的文件 file.t_webkitRelativePath = item.fullPath; } // files.push(file); // var event = {"target": {"files": files}} sendAndInsertFile(file, me, loadingId, folderName, folderId,folderUploaderUrl); }) })(item) } } function getPasteImage(e) { // return e.clipboardData && e.clipboardData.items && e.clipboardData.items.length >= 1 && (/^image\//.test(e.clipboardData.items[0].type)|| (e.clipboardData.items.length>1 && /^image\//.test(e.clipboardData.items[1].type))) ? e.clipboardData.items : null; // 文件也返回 return e.clipboardData && e.clipboardData.items && e.clipboardData.items.length >= 1 && (e.clipboardData.items[0].kind == 'file' || e.clipboardData.items[1] && e.clipboardData.items[1].kind == 'file') ? e.clipboardData.items : null; //解决部分电脑粘贴飞书图片是裂图,这里第二个图片才是file,返回的是空, 修改后会导致粘贴excel是图片 // return e.clipboardData && e.clipboardData.items && e.clipboardData.items.length >= 1 ? e.clipboardData.items : null; } function getDropImage(e) { // return e.dataTransfer && e.dataTransfer.files ? e.dataTransfer.files : null; return e.dataTransfer && e.dataTransfer.items ? e.dataTransfer.items : null; } return { outputRule: function (root) { utils.each(root.getNodesByTagName('img'), function (n) { if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))) { n.parentNode.removeChild(n); } }); utils.each(root.getNodesByTagName('p'), function (n) { if (/\bloadpara\b/.test(n.getAttr('class'))) { n.parentNode.removeChild(n); } }); }, bindEvents: { //插入粘贴板的图片,拖放插入图片 'ready': function (e) { var me = this; if (window.FormData && window.FileReader) { domUtils.on(me.body, 'paste drop', function (e) { if (me.options.allowPaste != undefined && me.options.allowPaste == false) { e.preventDefault(); if ($('.toolTipBox').length > 0) { $('.toolTipBox').remove(); } $(document.body).append('
    已禁止粘贴操作
    ') setTimeout(function () { $('.toolTipBox').fadeOut(); }, 1500) return false; } var hasImg = false, items; //录音打点标注行禁止粘贴内容 var range = me.selection.getRange(); if (range.collapsed) { start = range.startContainer; if (start.nodeType == 1 && start.parentNode.nodeType == 1 && start.getAttribute('class') && start.getAttribute('class').indexOf('record-list-tit') > -1) { e.preventDefault() return } } //获取粘贴板文件列表或者拖放文件列表 items = e.type == 'paste' ? getPasteImage(e) : getDropImage(e); if (items) { var len = items.length, file; //每次拖拽都记录状态 isOneFile = len > 1 ? false : true; if (e.type == 'paste' && len == 2 && items[0].type.indexOf('image') > -1 && items[1].type.indexOf('image') > -1) { // chrome 里面现在粘贴QQ或微信的图片,或有两个重复的图片,只取第一个 len = 1; } while (len--) { file = items[len]; if (e.type == 'paste') { if (file.getAsFile) file = file.getAsFile(); if (file && file.size > 0) { sendAndInsertFile(file, me); hasImg = true; } } else { // file 对象(按实例拖拽的内容)转换成 FileSystemFileEntry 对象 或 FileSystemDirectoryEntry 对象 var item = items[len].webkitGetAsEntry(); if (item) { hasImg = true; scanFiles(item) } } } hasImg && e.preventDefault(); } }); //取消拖放图片时出现的文字光标位置提示 domUtils.on(me.body, 'dragover', function (e) { if (e.dataTransfer.types[0] == 'Files') { e.preventDefault(); } }); //富文本粘贴到非富文本框,去除多余空行,IE不支持 20211020 // domUtils.on(me.body, 'copy', function(e) { // var clipboardData = e.clipboardData; // if(!clipboardData) return; // var selectedText = me.window.getSelection().toString(); // if (selectedText.trim() == "") return; // var copyText= selectedText.replace(/\r/g, '').replace(/\n\n/g, '\n').replace(/\u200B/gi,''); // clipboardData.setData('text/plain', copyText); // e.preventDefault(); // }); //设置loading的样式 utils.cssRule('loading', '.loadingclass{display:inline-block;cursor:default;background: url(\'' + this.options.themePath + this.options.theme + '/images/loading.gif\') no-repeat center center transparent;border:1px solid #cccccc;margin-left:1px;height: 22px;width: 22px;}\n' + '.loaderrorclass{display:inline-block;cursor:default;background: url(\'' + this.options.themePath + this.options.theme + '/images/loaderror.png\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;' + '}', this.document); } } } } }); // plugins/autosave.js UE.plugin.register('autosave', function () { var me = this, //无限循环保护 lastSaveTime = new Date(), //最小保存间隔时间 MIN_TIME = 20, //auto save key saveKey = null; function save(editor) { var saveData; if (new Date() - lastSaveTime < MIN_TIME) { return; } if (!editor.hasContents()) { //这里不能调用命令来删除, 会造成事件死循环 saveKey && me.removePreferences(saveKey); return; } lastSaveTime = new Date(); editor._saveFlag = null; saveData = me.body.innerHTML; if (editor.fireEvent("beforeautosave", { content: saveData }) === false) { return; } me.setPreferences(saveKey, saveData); editor.fireEvent("afterautosave", { content: saveData }); } return { defaultOptions: { //默认间隔时间 saveInterval: 500 }, bindEvents: { 'ready': function () { var _suffix = "-drafts-data", key = null; if (me.key) { key = me.key + _suffix; } else { key = (me.container.parentNode.id || 'ue-common') + _suffix; } //页面地址+编辑器ID 保持唯一 saveKey = (location.protocol + location.host + location.pathname).replace(/[.:\/]/g, '_') + key; }, 'contentchange': function () { // 去掉本地自动保存逻辑 if (!me.getOpt("enableAutoSave")) { return; } if (!saveKey) { return; } if (me._saveFlag) { window.clearTimeout(me._saveFlag); } if (me.options.saveInterval > 0) { me._saveFlag = window.setTimeout(function () { save(me); }, me.options.saveInterval); } else { save(me); } } }, commands: { 'clearlocaldata': { execCommand: function (cmd, name) { if (saveKey && me.getPreferences(saveKey)) { me.removePreferences(saveKey) } }, notNeedUndo: true, ignoreContentChange: true }, 'getlocaldata': { execCommand: function (cmd, name) { return saveKey ? me.getPreferences(saveKey) || '' : ''; }, notNeedUndo: true, ignoreContentChange: true }, 'drafts': { execCommand: function (cmd, name) { if (saveKey) { me.body.innerHTML = me.getPreferences(saveKey) || '

    ' + domUtils.fillHtml + '

    '; me.focus(true); } }, queryCommandState: function () { return saveKey ? (me.getPreferences(saveKey) === null ? -1 : 0) : -1; }, notNeedUndo: true, ignoreContentChange: true } } } }); // plugins/charts.js UE.plugin.register('charts', function () { var me = this; return { bindEvents: { 'chartserror': function () { } }, commands: { 'charts': { execCommand: function (cmd, data) { var tableNode = domUtils.findParentByTagName(this.selection.getRange().startContainer, 'table', true), flagText = [], config = {}; if (!tableNode) { return false; } if (!validData(tableNode)) { me.fireEvent("chartserror"); return false; } config.title = data.title || ''; config.subTitle = data.subTitle || ''; config.xTitle = data.xTitle || ''; config.yTitle = data.yTitle || ''; config.suffix = data.suffix || ''; config.tip = data.tip || ''; //数据对齐方式 config.dataFormat = data.tableDataFormat || ''; //图表类型 config.chartType = data.chartType || 0; for (var key in config) { if (!config.hasOwnProperty(key)) { continue; } flagText.push(key + ":" + config[key]); } tableNode.setAttribute("data-chart", flagText.join(";")); domUtils.addClass(tableNode, "edui-charts-table"); }, queryCommandState: function (cmd, name) { var tableNode = domUtils.findParentByTagName(this.selection.getRange().startContainer, 'table', true); return tableNode && validData(tableNode) ? 0 : -1; } } }, inputRule: function (root) { utils.each(root.getNodesByTagName('table'), function (tableNode) { if (tableNode.getAttr("data-chart") !== undefined) { tableNode.setAttr("style"); } }) }, outputRule: function (root) { utils.each(root.getNodesByTagName('table'), function (tableNode) { if (tableNode.getAttr("data-chart") !== undefined) { tableNode.setAttr("style", "display: none;"); } }) } } function validData(table) { var firstRows = null, cellCount = 0; //行数不够 if (table.rows.length < 2) { return false; } //列数不够 if (table.rows[0].cells.length < 2) { return false; } //第一行所有cell必须是th firstRows = table.rows[0].cells; cellCount = firstRows.length; for (var i = 0, cell; cell = firstRows[i]; i++) { if (cell.tagName.toLowerCase() !== 'th') { return false; } } for (var i = 1, row; row = table.rows[i]; i++) { //每行单元格数不匹配, 返回false if (row.cells.length != cellCount) { return false; } //第一列不是th也返回false if (row.cells[0].tagName.toLowerCase() !== 'th') { return false; } for (var j = 1, cell; cell = row.cells[j]; j++) { var value = utils.trim((cell.innerText || cell.textContent || '')); value = value.replace(new RegExp(UE.dom.domUtils.fillChar, 'g'), '').replace(/^\s+|\s+$/g, ''); //必须是数字 if (!/^\d*\.?\d+$/.test(value)) { return false; } } } return true; } }); // plugins/section.js /** * 目录大纲支持插件 * @file * @since 1.3.0 */ UE.plugin.register('section', function () { /* 目录节点对象 */ function Section(option) { this.tag = ''; this.level = -1, this.dom = null; this.nextSection = null; this.previousSection = null; this.parentSection = null; this.startAddress = []; this.endAddress = []; this.children = []; } function getSection(option) { var section = new Section(); return utils.extend(section, option); } function getNodeFromAddress(startAddress, root) { var current = root; for (var i = 0; i < startAddress.length; i++) { if (!current.childNodes) return null; current = current.childNodes[startAddress[i]]; } return current; } var me = this; return { bindMultiEvents: { type: 'aftersetcontent afterscencerestore', handler: function () { me.fireEvent('updateSections'); } }, bindEvents: { /* 初始化、拖拽、粘贴、执行setcontent之后 */ 'ready': function () { me.fireEvent('updateSections'); domUtils.on(me.body, 'drop paste', function (e) { me.fireEvent('updateSections'); }); }, /* 执行paragraph命令之后 */ 'afterexeccommand': function (type, cmd) { if (cmd == 'paragraph') { me.fireEvent('updateSections'); } }, /* 部分键盘操作,触发updateSections事件 */ 'keyup': function (type, e) { var me = this, range = me.selection.getRange(); if (range.collapsed != true) { me.fireEvent('updateSections'); } else { var keyCode = e.keyCode || e.which; if (keyCode == 13 || keyCode == 8 || keyCode == 46) { me.fireEvent('updateSections'); } } } }, commands: { 'getsections': { execCommand: function (cmd, levels) { var levelFn = levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; for (var i = 0; i < levelFn.length; i++) { if (typeof levelFn[i] == 'string') { levelFn[i] = function (fn) { return function (node) { return node.tagName == fn.toUpperCase() }; }(levelFn[i]); } else if (typeof levelFn[i] != 'function') { levelFn[i] = function (node) { return null; } } } function getSectionLevel(node) { for (var i = 0; i < levelFn.length; i++) { if (levelFn[i](node)) return i; } return -1; } var me = this, Directory = getSection({ 'level': -1, 'title': 'root' }), previous = Directory; function traversal(node, Directory) { var level, tmpSection = null, parent, child, children = node.childNodes; for (var i = 0, len = children.length; i < len; i++) { child = children[i]; level = getSectionLevel(child); if (level >= 0) { var address = me.selection.getRange().selectNode(child).createAddress(true).startAddress, current = getSection({ 'tag': child.tagName, 'title': child.innerText || child.textContent || '', 'level': level, 'dom': child, 'startAddress': utils.clone(address, []), 'endAddress': utils.clone(address, []), 'children': [] }); previous.nextSection = current; current.previousSection = previous; parent = previous; while (level <= parent.level) { parent = parent.parentSection; } current.parentSection = parent; parent.children.push(current); tmpSection = previous = current; } else { child.nodeType === 1 && traversal(child, Directory); tmpSection && tmpSection.endAddress[tmpSection.endAddress.length - 1]++; } } } traversal(me.body, Directory); return Directory; }, notNeedUndo: true }, 'movesection': { execCommand: function (cmd, sourceSection, targetSection, isAfter) { var me = this, targetAddress, target; if (!sourceSection || !targetSection || targetSection.level == -1) return; targetAddress = isAfter ? targetSection.endAddress : targetSection.startAddress; target = getNodeFromAddress(targetAddress, me.body); /* 判断目标地址是否被源章节包含 */ if (!targetAddress || !target || isContainsAddress(sourceSection.startAddress, sourceSection.endAddress, targetAddress)) return; var startNode = getNodeFromAddress(sourceSection.startAddress, me.body), endNode = getNodeFromAddress(sourceSection.endAddress, me.body), current, nextNode; if (isAfter) { current = endNode; while (current && !(domUtils.getPosition(startNode, current) & domUtils.POSITION_FOLLOWING)) { nextNode = current.previousSibling; domUtils.insertAfter(target, current); if (current == startNode) break; current = nextNode; } } else { current = startNode; while (current && !(domUtils.getPosition(current, endNode) & domUtils.POSITION_FOLLOWING)) { nextNode = current.nextSibling; target.parentNode.insertBefore(current, target); if (current == endNode) break; current = nextNode; } } me.fireEvent('updateSections'); /* 获取地址的包含关系 */ function isContainsAddress(startAddress, endAddress, addressTarget) { var isAfterStartAddress = false, isBeforeEndAddress = false; for (var i = 0; i < startAddress.length; i++) { if (i >= addressTarget.length) break; if (addressTarget[i] > startAddress[i]) { isAfterStartAddress = true; break; } else if (addressTarget[i] < startAddress[i]) { break; } } for (var i = 0; i < endAddress.length; i++) { if (i >= addressTarget.length) break; if (addressTarget[i] < startAddress[i]) { isBeforeEndAddress = true; break; } else if (addressTarget[i] > startAddress[i]) { break; } } return isAfterStartAddress && isBeforeEndAddress; } } }, 'deletesection': { execCommand: function (cmd, section, keepChildren) { var me = this; if (!section) return; function getNodeFromAddress(startAddress) { var current = me.body; for (var i = 0; i < startAddress.length; i++) { if (!current.childNodes) return null; current = current.childNodes[startAddress[i]]; } return current; } var startNode = getNodeFromAddress(section.startAddress), endNode = getNodeFromAddress(section.endAddress), current = startNode, nextNode; if (!keepChildren) { while (current && domUtils.inDoc(endNode, me.document) && !(domUtils.getPosition(current, endNode) & domUtils.POSITION_FOLLOWING)) { nextNode = current.nextSibling; domUtils.remove(current); current = nextNode; } } else { domUtils.remove(current); } me.fireEvent('updateSections'); } }, 'selectsection': { execCommand: function (cmd, section) { if (!section && !section.dom) return false; var me = this, range = me.selection.getRange(), address = { 'startAddress': utils.clone(section.startAddress, []), 'endAddress': utils.clone(section.endAddress, []) }; address.endAddress[address.endAddress.length - 1]++; range.moveToAddress(address).select().scrollToView(); return true; }, notNeedUndo: true }, 'scrolltosection': { execCommand: function (cmd, section) { if (!section && !section.dom) return false; var me = this, range = me.selection.getRange(), address = { 'startAddress': section.startAddress, 'endAddress': section.endAddress }; address.endAddress[address.endAddress.length - 1]++; range.moveToAddress(address).scrollToView(); return true; }, notNeedUndo: true } } } }); // plugins/simpleupload.js /** * @description * 简单上传:点击按钮,直接选择文件上传 * @author Jinqn * @date 2014-03-31 */ UE.plugin.register('simpleupload', function () { var me = this, isLoaded = false, containerBtn; function initUploadBtn() { var w = containerBtn.offsetWidth || 20, h = containerBtn.offsetHeight || 20, btnIframe = document.createElement('iframe'), btnStyle = 'display:block;width:' + w + 'px;height:' + h + 'px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;'; domUtils.on(btnIframe, 'load', function () { var timestrap = (+new Date()).toString(36), wrapper, btnIframeDoc, btnIframeBody; btnIframeDoc = (btnIframe.contentDocument || btnIframe.contentWindow.document); btnIframeBody = btnIframeDoc.body; wrapper = btnIframeDoc.createElement('div'); wrapper.innerHTML = '
    ' + '' + '
    ' + ''; wrapper.className = 'edui-' + me.options.theme; wrapper.id = me.ui.id + '_iframeupload'; btnIframeBody.style.cssText = btnStyle; btnIframeBody.style.width = w + 'px'; btnIframeBody.style.height = h + 'px'; btnIframeBody.appendChild(wrapper); if (btnIframeBody.parentNode) { btnIframeBody.parentNode.style.width = w + 'px'; btnIframeBody.parentNode.style.height = w + 'px'; } var form = btnIframeDoc.getElementById('edui_form_' + timestrap); var input = btnIframeDoc.getElementById('edui_input_' + timestrap); var iframe = btnIframeDoc.getElementById('edui_iframe_' + timestrap); domUtils.on(input, 'change', function () { if (!input.value) return; var loadingId = 'loading_' + (+new Date()).toString(36); var params = utils.serializeParam(me.queryCommandValue('serverparam')) || ''; var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName')); var allowFiles = me.getOpt('imageAllowFiles'); me.focus(); me.execCommand('inserthtml', '
    '); function callback() { try { var link, json, loader, body = (iframe.contentDocument || iframe.contentWindow.document).body, result = body.innerText || body.textContent || ''; json = (new Function("return " + result))(); link = json.url; if (json.state == 'SUCCESS' && json.url) { loader = me.document.getElementById(loadingId); loader.setAttribute('src', link); loader.setAttribute('_src', link); loader.setAttribute('title', json.title || ''); loader.setAttribute('alt', json.original || ''); // 修改 loader.setAttribute('objectid', json.objectid || ''); loader.removeAttribute('id'); domUtils.removeClasses(loader, 'loadingclass'); } else { showErrorLoader && showErrorLoader(json.state); } } catch (er) { showErrorLoader && showErrorLoader(me.getLang('simpleupload.loadError')); } form.reset(); domUtils.un(iframe, 'load', callback); } function showErrorLoader(title) { if (loadingId) { var loader = me.document.getElementById(loadingId); loader && domUtils.remove(loader); me.fireEvent('showmessage', { 'id': loadingId, 'content': title, 'type': 'error', 'timeout': 4000 }); } } /* 判断后端配置是否没有加载成功 */ if (!me.getOpt('imageActionName')) { errorHandler(me.getLang('autoupload.errorLoadConfig')); return; } // 判断文件格式是否错误 var filename = input.value, fileext = filename ? filename.substr(filename.lastIndexOf('.')) : ''; if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) { showErrorLoader(me.getLang('simpleupload.exceedTypeError')); return; } domUtils.on(iframe, 'load', callback); form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?' : '&') + params); form.submit(); }); var stateTimer; me.addListener('selectionchange', function () { clearTimeout(stateTimer); stateTimer = setTimeout(function () { var state = me.queryCommandState('simpleupload'); if (state == -1) { input.disabled = 'disabled'; } else { input.disabled = false; } }, 400); }); isLoaded = true; }); btnIframe.style.cssText = btnStyle; containerBtn.appendChild(btnIframe); } return { bindEvents: { 'ready': function () { //设置loading的样式 utils.cssRule('loading', '.loadingclass{display:inline-block;cursor:default;background: url(\'' + this.options.themePath + this.options.theme + '/images/loading.gif\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n' + '.loaderrorclass{display:inline-block;cursor:default;background: url(\'' + this.options.themePath + this.options.theme + '/images/loaderror.png\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;' + '}', this.document); }, /* 初始化简单上传按钮 */ 'simpleuploadbtnready': function (type, container) { containerBtn = container; me.afterConfigReady(initUploadBtn); } }, outputRule: function (root) { utils.each(root.getNodesByTagName('img'), function (n) { if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))) { n.parentNode.removeChild(n); } }); }, commands: { 'simpleupload': { queryCommandState: function () { return isLoaded ? 0 : -1; } } } } }); // plugins/serverparam.js /** * 服务器提交的额外参数列表设置插件 * @file * @since 1.2.6.1 */ UE.plugin.register('serverparam', function () { var me = this, serverParam = {}; return { commands: { /** * 修改服务器提交的额外参数列表,清除所有项 * @command serverparam * @method execCommand * @param { String } cmd 命令字符串 * @example * ```javascript * editor.execCommand('serverparam'); * editor.queryCommandValue('serverparam'); //返回空 * ``` */ /** * 修改服务器提交的额外参数列表,删除指定项 * @command serverparam * @method execCommand * @param { String } cmd 命令字符串 * @param { String } key 要清除的属性 * @example * ```javascript * editor.execCommand('serverparam', 'name'); //删除属性name * ``` */ /** * 修改服务器提交的额外参数列表,使用键值添加项 * @command serverparam * @method execCommand * @param { String } cmd 命令字符串 * @param { String } key 要添加的属性 * @param { String } value 要添加属性的值 * @example * ```javascript * editor.execCommand('serverparam', 'name', 'hello'); * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'} * ``` */ /** * 修改服务器提交的额外参数列表,传入键值对对象添加多项 * @command serverparam * @method execCommand * @param { String } cmd 命令字符串 * @param { Object } key 传入的键值对对象 * @example * ```javascript * editor.execCommand('serverparam', {'name': 'hello'}); * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'} * ``` */ /** * 修改服务器提交的额外参数列表,使用自定义函数添加多项 * @command serverparam * @method execCommand * @param { String } cmd 命令字符串 * @param { Function } key 自定义获取参数的函数 * @example * ```javascript * editor.execCommand('serverparam', function(editor){ * return {'key': 'value'}; * }); * editor.queryCommandValue('serverparam'); //返回对象 {'key': 'value'} * ``` */ /** * 获取服务器提交的额外参数列表 * @command serverparam * @method queryCommandValue * @param { String } cmd 命令字符串 * @example * ```javascript * editor.queryCommandValue( 'serverparam' ); //返回对象 {'key': 'value'} * ``` */ 'serverparam': { execCommand: function (cmd, key, value) { if (key === undefined || key === null) { //不传参数,清空列表 serverParam = {}; } else if (utils.isString(key)) { //传入键值 if (value === undefined || value === null) { delete serverParam[key]; } else { serverParam[key] = value; } } else if (utils.isObject(key)) { //传入对象,覆盖列表项 utils.extend(serverParam, key, true); } else if (utils.isFunction(key)) { //传入函数,添加列表项 utils.extend(serverParam, key(), true); } }, queryCommandValue: function () { return serverParam || {}; } } } } }); // plugins/insertfile.js /** * 插入附件 */ UE.plugin.register('insertfile', function () { var me = this; function getFileIcon(url) { var ext = url.substr(url.lastIndexOf('.') + 1).toLowerCase(), maps = { "rar": "icon_rar.gif", "zip": "icon_rar.gif", "tar": "icon_rar.gif", "gz": "icon_rar.gif", "bz2": "icon_rar.gif", "doc": "icon_doc.gif", "docx": "icon_doc.gif", "pdf": "icon_pdf.gif", "mp3": "icon_mp3.gif", "xls": "icon_xls.gif", "chm": "icon_chm.gif", "ppt": "icon_ppt.gif", "pptx": "icon_ppt.gif", "avi": "icon_mv.gif", "rmvb": "icon_mv.gif", "wmv": "icon_mv.gif", "flv": "icon_mv.gif", "swf": "icon_mv.gif", "rm": "icon_mv.gif", "exe": "icon_exe.gif", "psd": "icon_psd.gif", "txt": "icon_txt.gif", "jpg": "icon_jpg.gif", "png": "icon_jpg.gif", "jpeg": "icon_jpg.gif", "gif": "icon_jpg.gif", "ico": "icon_jpg.gif", "bmp": "icon_jpg.gif" }; return maps[ext] ? maps[ext] : maps['txt']; } return { commands: { 'insertfile': { execCommand: function (command, filelist) { filelist = utils.isArray(filelist) ? filelist : [filelist]; var i, item, icon, title, html = '', URL = me.getOpt('UEDITOR_HOME_URL'), iconDir = URL + (URL.substr(URL.length - 1) == '/' ? '' : '/') + 'dialogs/attachment/fileTypeImages/'; var containsImg = false; // PPT云盘附件数组,教案那边需要单独处理PPT附件 var pptAttachmentArray = new Array(); for (i = 0; i < filelist.length; i++) { item = filelist[i]; /* icon = iconDir + getFileIcon(item.url); title = item.title || item.url.substr(item.url.lastIndexOf('/') + 1); html += '

    ' + '' + '' + title + '' + '

    '; */ // 修改为自己的页面展示内容 //width = Math.round(width); var divelementid = domUtils.getRandomId(); if (item.attachmentType == 18 && item.att_clouddisk.imgUrl) { // 图片 html += '
    '; containsImg = true; } else { var insertType = ""; var json = ""; var fileType = '' // 其他类型附件 switch (item.attachmentType) { case 18: insertType = "insertCloud"; // 文件,本地上传或从云盘中选择 try { item.att_clouddisk.infoJsonStr = JSON.parse(item.att_clouddisk.infoJsonStr); item.att_clouddisk.parentPath = JSON.parse(item.att_clouddisk.parentPath); } catch (e) { } var fileSuffix = item.att_clouddisk.suffix; if (fileSuffix == 'xls' || fileSuffix == 'xlsx') { fileType = 'excel'; } else if (fileSuffix == 'pdf') { fileType = 'pdf'; } else if (fileSuffix == 'doc' || fileSuffix == 'docx') { fileType = 'word'; } else if (fileSuffix == 'ppt' || fileSuffix == 'pptx') { fileType = 'ppt'; } else if (fileSuffix == 'zip' || fileSuffix == 'rar') { fileType = 'zip'; } if (item.att_clouddisk.suffix && item.att_clouddisk.suffix.toLowerCase().indexOf('ppt') > -1 && typeof createPpt == 'function') { // 教案那边自己处理PPT附件 pptAttachmentArray.push(item); continue; } break; case 38: // 云盘文件夹 insertType = "insertCloudfolder"; break; case 11: // 收藏文件夹 insertType = "insertResource"; json = JSON.stringify(item); json = json.replace('"{', '{'); json = json.replace('}"', '}'); json = json.replace(/\\/g, ""); break; case 3: // 专题 insertType = "insertSubject"; break; case 6: // 期刊 insertType = "insertPeriodical"; break; case 25: // 网页 insertType = "insertWeb"; break; case 1: // 话题 insertType = "insertTopic"; break; case 2: // 笔记 insertType = "insertNote"; break; case 10: // 笔记文件夹 insertType = "insertNotebook"; break; case 29: // 视频 insertType = "insertVideo"; break; case 8: // 通知 insertType = "insertNotice"; break; case 15: // 课程附件 insertType = "insertVote"; break; case 26: // 音频 insertType = "insertVoice"; break; case 17: // 课程章节 insertType = "insertCourse"; break; case 49: // 本地文件夹 insertType = "insertLocalFolder"; break; } if (!insertType) { return; } var cid = RichTextUitl.randomUUID(); item.cid = cid; if (item.attachmentType != 11) { json = JSON.stringify(item); //html += "


    "; } var webPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/'; if(RichTextUitl.intranetMode){ webPrefix = RichTextUitl.prefix } var attachmentHtml = webPrefix + 'attachment/' + insertType + '.html'; //设置默认预览模式或默认文本模式的,修改为预览或文本 if(RichTextUitl.attachMode == 'preview' && fileType && (fileType == 'word' || fileType == 'excel' || fileType == 'pdf' || fileType == 'ppt')){ attachmentHtml = RichTextUitl.convertUrl(window.location.protocol + '//previewyd.chaoxing.com/res/view/view.html?objectid=' + item.att_clouddisk.fileId + '&fileName=' + encodeURIComponent(item.att_clouddisk.name)); html += "
    "; }else if(RichTextUitl.attachMode == 'text' && fileType){ var href = item.att_clouddisk.downPath || ('https://d0.cldisk.com/download/' + item.att_clouddisk.fileId); html += ''; }else{ html += "
    "; } } } me.sendhtml(html) me.execCommand('insertHtml', html); if (containsImg && me.autoHeightEnabled) { // 添加图片后需要重置高度 var imgList = me.body.querySelectorAll('img'); for (var i = 0; i < imgList.length; i++) { imgList[i].onload = function () { me.adjustHeight(); } } } if (pptAttachmentArray.length > 0 && typeof createPpt == 'function') { // 教案那边自己处理PPT附件 createPpt(pptAttachmentArray) } } } } } }); /** * 替换拖拽附件 */ UE.plugin.register('replacefile', function () { var me = this; function getFileIcon(url) { var ext = url.substr(url.lastIndexOf('.') + 1).toLowerCase(), maps = { "rar": "icon_rar.gif", "zip": "icon_rar.gif", "tar": "icon_rar.gif", "gz": "icon_rar.gif", "bz2": "icon_rar.gif", "doc": "icon_doc.gif", "docx": "icon_doc.gif", "pdf": "icon_pdf.gif", "mp3": "icon_mp3.gif", "xls": "icon_xls.gif", "chm": "icon_chm.gif", "ppt": "icon_ppt.gif", "pptx": "icon_ppt.gif", "avi": "icon_mv.gif", "rmvb": "icon_mv.gif", "wmv": "icon_mv.gif", "flv": "icon_mv.gif", "swf": "icon_mv.gif", "rm": "icon_mv.gif", "exe": "icon_exe.gif", "psd": "icon_psd.gif", "txt": "icon_txt.gif", "jpg": "icon_jpg.gif", "png": "icon_jpg.gif", "jpeg": "icon_jpg.gif", "gif": "icon_jpg.gif", "ico": "icon_jpg.gif", "bmp": "icon_jpg.gif" }; return maps[ext] ? maps[ext] : maps['txt']; } return { commands: { 'replacefile': { execCommand: function (command, filelist) { filelist = utils.isArray(filelist) ? filelist : [filelist]; var i, item, icon, title, html = '', URL = me.getOpt('UEDITOR_HOME_URL'), iconDir = URL + (URL.substr(URL.length - 1) == '/' ? '' : '/') + 'dialogs/attachment/fileTypeImages/'; var containsImg = false; // PPT云盘附件数组,教案那边需要单独处理PPT附件 var pptAttachmentArray = new Array(); for (i = 0; i < filelist.length; i++) { item = filelist[i]; // 修改为自己的页面展示内容 //width = Math.round(width); var div = me.document.createElement('div'); div.setAttribute('element-id', domUtils.getRandomId()); div.setAttribute('contenteditable', 'false'); if (item.attachmentType == 18 && item.att_clouddisk.imgUrl) { // 图片 div.setAttribute('class', 'editor-image'); div.innerHTML = ''; containsImg = true; //统计图片附件---拖拽的图片 if (me.options.statsAttach) { var staAtt = [{ 'type': 'img', 'resource': item.att_clouddisk.imgUrl }] me.anasycStatsAttach(staAtt, 1); } } else { var insertType = ""; var json = ""; var fileType = '' // 其他类型附件 switch (item.attachmentType) { case 18: insertType = "insertCloud"; // 文件,本地上传或从云盘中选择 try { item.att_clouddisk.infoJsonStr = JSON.parse(item.att_clouddisk.infoJsonStr); item.att_clouddisk.parentPath = JSON.parse(item.att_clouddisk.parentPath); } catch (e) { } var fileSuffix = item.att_clouddisk.suffix; if (fileSuffix == 'xls' || fileSuffix == 'xlsx') { fileType = 'excel'; } else if (fileSuffix == 'pdf') { fileType = 'pdf'; } else if (fileSuffix == 'doc' || fileSuffix == 'docx') { fileType = 'word'; } else if (fileSuffix == 'ppt' || fileSuffix == 'pptx') { fileType = 'ppt'; } else if (fileSuffix == 'zip' || fileSuffix == 'rar') { fileType = 'zip'; } if (item.att_clouddisk.suffix && item.att_clouddisk.suffix.toLowerCase().indexOf('ppt') > -1 && typeof createPpt == 'function') { // 教案那边自己处理PPT附件 pptAttachmentArray.push(item); continue; } break; case 38: // 云盘文件夹 insertType = "insertCloudfolder"; break; case 11: // 收藏文件夹 insertType = "insertResource"; json = JSON.stringify(item); json = json.replace('"{', '{'); json = json.replace('}"', '}'); json = json.replace(/\\/g, ""); break; case 3: // 专题 insertType = "insertSubject"; break; case 6: // 期刊 insertType = "insertPeriodical"; break; case 25: // 网页 insertType = "insertWeb"; break; case 1: // 话题 insertType = "insertTopic"; break; case 2: // 笔记 insertType = "insertNote"; break; case 10: // 笔记文件夹 insertType = "insertNotebook"; break; case 29: // 视频 insertType = "insertVideo"; break; case 8: // 通知 insertType = "insertNotice"; break; case 15: // 课程附件 insertType = "insertVote"; break; case 26: // 音频 insertType = "insertVoice"; break; case 17: // 课程章节 insertType = "insertCourse"; break; case 49: // 本地文件夹 insertType = "insertLocalFolder"; break; } if (!insertType) { return; } var cid = RichTextUitl.randomUUID(); item.cid = cid; if (item.attachmentType != 11) { json = JSON.stringify(item); //html += "


    "; } var webPrefix = (RichTextUitl.prefix || RichTextUitl.noteDomain) + '/'; if(RichTextUitl.intranetMode){ webPrefix = RichTextUitl.prefix } var attachmentHtml = webPrefix + 'attachment/' + insertType + '.html'; //设置默认预览模式或默认文本模式的,修改为预览或文本 if(RichTextUitl.attachMode == 'preview' && fileType && (fileType == 'word' || fileType == 'excel' || fileType == 'pdf' || fileType == 'ppt')){ attachmentHtml = RichTextUitl.convertUrl(window.location.protocol + '//previewyd.chaoxing.com/res/view/view.html?objectid=' + item.att_clouddisk.fileId + '&fileName=' + encodeURIComponent(item.att_clouddisk.name)); div.setAttribute('class', 'editor-iframe'); div.innerHTML = ""; }else if(RichTextUitl.attachMode == 'text' && fileType){ var href = item.att_clouddisk.downPath || ('https://d0.cldisk.com/download/' + item.att_clouddisk.fileId); div.innerHTML = '' + item.att_clouddisk.name + ''; }else{ div.setAttribute('class', 'editor-iframe'); div.innerHTML = ""; } //统计附件和图片----拖拽的附件 if (me.options.statsAttach) { var staAtt = [{ 'type': 'iframe', 'resource': RichTextUitl.b64EncodeUnicode(json) }] me.anasycStatsAttach(staAtt, 1); } } } var range = me.selection.getRange(); if (!range.collapsed) range.deleteContents(); range.insertNode(div); var $iframe = div.querySelector('iframe'); // 将上传后的内容传到iframe里面去 var data = { 'msgType': 'dataChanged', 'cid': $iframe.getAttribute('cid'), 'name': $iframe.name, 'editorId': me.key, 'cloudUrl': RichTextUitl.cloudUrl, 'openPreview': RichTextUitl.openPreview || null } if($iframe.getAttribute('module') == 'insertVideo'){ data.isGetVideoDataFromCenter = RichTextUitl.isGetVideoDataFromCenter; } $iframe.onload = function () { $iframe.contentWindow.postMessage(data, "*"); } if (containsImg && me.autoHeightEnabled) { // 添加图片后需要重置高度 var imgList = me.body.querySelectorAll('img'); for (var i = 0; i < imgList.length; i++) { imgList[i].onload = function () { me.adjustHeight(); } } } if (pptAttachmentArray.length > 0 && typeof createPpt == 'function') { // 教案那边自己处理PPT附件 createPpt(pptAttachmentArray) } } } } } }); // plugins/xssFilter.js /** * @file xssFilter.js * @desc xss过滤器 * @author robbenmu */ UE.plugins.xssFilter = function () { var config = UEDITOR_CONFIG; var whitList = config.whitList; var me = this; //添加自定义白名单 if(this.options.whiteList){ for (var attr in this.options.whiteList) { whitList[attr] = this.options.whiteList[attr]; } } me.filterWhiteList = function(node) { var tagName = node.tagName; var attrs = node.attrs; //20201106 粘贴自定义标签时内容丢失----把自定义标签改为div if (!whitList.hasOwnProperty(tagName)) { // node.parentNode.removeChild(node); // return false; tagName = node.tagName = 'div'; // if (!node.firstChild()) { // node.parentNode.removeChild(node); // } } UE.utils.each(attrs, function (val, key) { if (whitList[tagName].indexOf(key) === -1) { node.setAttr(key); } }); } // 添加inserthtml\paste等操作用的过滤规则 if (whitList && config.xssFilterRules) { this.options.filterRules = function () { var result = {}; UE.utils.each(whitList, function (val, key) { result[key] = function (node) { return me.filterWhiteList(node); }; }); return result; }(); } var tagList = []; UE.utils.each(whitList, function (val, key) { tagList.push(key); }); // 添加input过滤规则 // if (whitList && config.inputXssFilter) { this.addInputRule(function (root) { root.traversal(function (node) { if (node.type !== 'element') { return false; } me.filterWhiteList(node); }); }); } // 添加output过滤规则 // if (whitList && config.outputXssFilter) { this.addOutputRule(function (root) { root.traversal(function (node) { if (node.type !== 'element') { return false; } me.filterWhiteList(node); }); }); } }; // ui/ui.js var baidu = baidu || {}; baidu.editor = baidu.editor || {}; UE.ui = baidu.editor.ui = {}; // ui/uiutils.js (function () { var browser = baidu.editor.browser, domUtils = baidu.editor.dom.domUtils; var magic = '$EDITORUI'; var root = window[magic] = {}; var uidMagic = 'ID' + magic; var uidCount = 0; var uiUtils = baidu.editor.ui.uiUtils = { uid: function (obj) { return (obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount); }, hook: function (fn, callback) { var dg; if (fn && fn._callbacks) { dg = fn; } else { dg = function () { var q; if (fn) { q = fn.apply(this, arguments); } var callbacks = dg._callbacks; var k = callbacks.length; while (k--) { var r = callbacks[k].apply(this, arguments); if (q === undefined) { q = r; } } return q; }; dg._callbacks = []; } dg._callbacks.push(callback); return dg; }, createElementByHtml: function (html) { var el = document.createElement('div'); el.innerHTML = html; el = el.firstChild; el.parentNode.removeChild(el); return el; }, getViewportElement: function () { return (browser.ie && browser.quirks) ? document.body : document.documentElement; }, getClientRect: function (element) { var bcr; //trace IE6下在控制编辑器显隐时可能会报错,catch一下 try { bcr = element.getBoundingClientRect(); } catch (e) { bcr = { left: 0, top: 0, height: 0, width: 0 } } var rect = { left: Math.round(bcr.left), top: Math.round(bcr.top), height: Math.round(bcr.bottom - bcr.top), width: Math.round(bcr.right - bcr.left) }; var doc; while ((doc = element.ownerDocument) !== document && (element = domUtils.getWindow(doc).frameElement)) { bcr = element.getBoundingClientRect(); rect.left += bcr.left; rect.top += bcr.top; } rect.bottom = rect.top + rect.height; rect.right = rect.left + rect.width; return rect; }, getViewportRect: function () { var viewportEl = uiUtils.getViewportElement(); var width = (window.innerWidth || viewportEl.clientWidth) | 0; var height = (window.innerHeight || viewportEl.clientHeight) | 0; return { left: 0, top: 0, height: height, width: width, bottom: height, right: width }; }, setViewportOffset: function (element, offset) { var rect; var fixedLayer = uiUtils.getFixedLayer(); if (element.parentNode === fixedLayer) { element.style.left = offset.left + 'px'; element.style.top = offset.top + 'px'; } else { domUtils.setViewportOffset(element, offset); } }, getEventOffset: function (evt) { var el = evt.target || evt.srcElement; var rect = uiUtils.getClientRect(el); var offset = uiUtils.getViewportOffsetByEvent(evt); return { left: offset.left - rect.left, top: offset.top - rect.top }; }, getViewportOffsetByEvent: function (evt) { var el = evt.target || evt.srcElement; var frameEl = domUtils.getWindow(el).frameElement; var offset = { left: evt.clientX, top: evt.clientY }; if (frameEl && el.ownerDocument !== document) { var rect = uiUtils.getClientRect(frameEl); offset.left += rect.left; offset.top += rect.top; } return offset; }, setGlobal: function (id, obj) { root[id] = obj; return magic + '["' + id + '"]'; }, unsetGlobal: function (id) { delete root[id]; }, copyAttributes: function (tgt, src) { var attributes = src.attributes; var k = attributes.length; while (k--) { var attrNode = attributes[k]; if (attrNode.nodeName != 'style' && attrNode.nodeName != 'class' && (!browser.ie || attrNode.specified)) { tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue); } } if (src.className) { domUtils.addClass(tgt, src.className); } if (src.style.cssText) { tgt.style.cssText += ';' + src.style.cssText; } }, removeStyle: function (el, styleName) { if (el.style.removeProperty) { el.style.removeProperty(styleName); } else if (el.style.removeAttribute) { el.style.removeAttribute(styleName); } else throw ''; }, contains: function (elA, elB) { return elA && elB && (elA === elB ? false : ( elA.contains ? elA.contains(elB) : elA.compareDocumentPosition(elB) & 16 )); }, startDrag: function (evt, callbacks, doc) { var doc = doc || document; var startX = evt.clientX; var startY = evt.clientY; function handleMouseMove(evt) { var x = evt.clientX - startX; var y = evt.clientY - startY; callbacks.ondragmove(x, y, evt); if (evt.stopPropagation) { evt.stopPropagation(); } else { evt.cancelBubble = true; } } if (doc.addEventListener) { function handleMouseUp(evt) { doc.removeEventListener('mousemove', handleMouseMove, true); doc.removeEventListener('mouseup', handleMouseUp, true); window.removeEventListener('mouseup', handleMouseUp, true); callbacks.ondragstop(); } doc.addEventListener('mousemove', handleMouseMove, true); doc.addEventListener('mouseup', handleMouseUp, true); window.addEventListener('mouseup', handleMouseUp, true); evt.preventDefault(); } else { var elm = evt.srcElement; elm.setCapture(); function releaseCaptrue() { elm.releaseCapture(); elm.detachEvent('onmousemove', handleMouseMove); elm.detachEvent('onmouseup', releaseCaptrue); elm.detachEvent('onlosecaptrue', releaseCaptrue); callbacks.ondragstop(); } elm.attachEvent('onmousemove', handleMouseMove); elm.attachEvent('onmouseup', releaseCaptrue); elm.attachEvent('onlosecaptrue', releaseCaptrue); evt.returnValue = false; } callbacks.ondragstart(); }, getFixedLayer: function () { var layer = document.getElementById('edui_fixedlayer'); if (layer == null) { layer = document.createElement('div'); layer.id = 'edui_fixedlayer'; document.body.appendChild(layer); if (browser.ie && browser.version <= 8) { layer.style.position = 'absolute'; bindFixedLayer(); setTimeout(updateFixedOffset); } else { layer.style.position = 'fixed'; } layer.style.left = '0'; layer.style.top = '0'; layer.style.width = '0'; layer.style.height = '0'; } return layer; }, makeUnselectable: function (element) { if (browser.opera || (browser.ie && browser.version < 9)) { element.unselectable = 'on'; if (element.hasChildNodes()) { for (var i = 0; i < element.childNodes.length; i++) { if (element.childNodes[i].nodeType == 1) { uiUtils.makeUnselectable(element.childNodes[i]); } } } } else { if (element.style.MozUserSelect !== undefined) { element.style.MozUserSelect = 'none'; } else if (element.style.WebkitUserSelect !== undefined) { element.style.WebkitUserSelect = 'none'; } else if (element.style.KhtmlUserSelect !== undefined) { element.style.KhtmlUserSelect = 'none'; } } } }; function updateFixedOffset() { var layer = document.getElementById('edui_fixedlayer'); uiUtils.setViewportOffset(layer, { left: 0, top: 0 }); // layer.style.display = 'none'; // layer.style.display = 'block'; //#trace: 1354 // setTimeout(updateFixedOffset); } function bindFixedLayer(adjOffset) { domUtils.on(window, 'scroll', updateFixedOffset); domUtils.on(window, 'resize', baidu.editor.utils.defer(updateFixedOffset, 0, true)); } })(); // ui/uibase.js (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, EventBase = baidu.editor.EventBase, UIBase = baidu.editor.ui.UIBase = function () { }; UIBase.prototype = { className: '', uiName: '', initOptions: function (options) { var me = this; for (var k in options) { me[k] = options[k]; } this.id = this.id || 'edui' + uiUtils.uid(); }, initUIBase: function () { this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this)); }, render: function (holder) { var html = this.renderHtml(); var el = uiUtils.createElementByHtml(html); //by xuheng 给每个node添加class var list = domUtils.getElementsByTagName(el, "*"); var theme = "edui-" + (this.theme || this.editor.options.theme); var layer = document.getElementById('edui_fixedlayer'); for (var i = 0, node; node = list[i++];) { domUtils.addClass(node, theme); } domUtils.addClass(el, theme); if (layer) { layer.className = ""; domUtils.addClass(layer, theme); } var seatEl = this.getDom(); if (seatEl != null) { seatEl.parentNode.replaceChild(el, seatEl); uiUtils.copyAttributes(el, seatEl); } else { if (typeof holder == 'string') { holder = document.getElementById(holder); } holder = holder || uiUtils.getFixedLayer(); domUtils.addClass(holder, theme); holder.appendChild(el); } this.postRender(); }, getDom: function (name) { if (!name) { return document.getElementById(this.id); } else { return document.getElementById(this.id + '_' + name); } }, postRender: function () { this.fireEvent('postrender'); }, getHtmlTpl: function () { return ''; }, formatHtml: function (tpl) { var prefix = 'edui-' + this.uiName; return (tpl .replace(/##/g, this.id) .replace(/%%-/g, this.uiName ? prefix + '-' : '') .replace(/%%/g, (this.uiName ? prefix : '') + ' ' + this.className) .replace(/\$\$/g, this._globalKey)); }, renderHtml: function () { return this.formatHtml(this.getHtmlTpl()); }, dispose: function () { var box = this.getDom(); if (box) baidu.editor.dom.domUtils.remove(box); uiUtils.unsetGlobal(this.id); } }; utils.inherits(UIBase, EventBase); })(); // ui/separator.js (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase, Separator = baidu.editor.ui.Separator = function (options) { this.initOptions(options); this.initSeparator(); }; Separator.prototype = { uiName: 'separator', initSeparator: function () { this.initUIBase(); }, getHtmlTpl: function () { return '
    '; } }; utils.inherits(Separator, UIBase); })(); // ui/mask.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils, UIBase = baidu.editor.ui.UIBase, uiUtils = baidu.editor.ui.uiUtils; var Mask = baidu.editor.ui.Mask = function (options) { this.initOptions(options); this.initUIBase(); }; Mask.prototype = { getHtmlTpl: function () { return '
    '; }, postRender: function () { var me = this; domUtils.on(window, 'resize', function () { setTimeout(function () { if (!me.isHidden()) { me._fill(); } }); }); }, show: function (zIndex) { this._fill(); this.getDom().style.display = ''; this.getDom().style.zIndex = zIndex; }, hide: function () { this.getDom().style.display = 'none'; this.getDom().style.zIndex = ''; }, isHidden: function () { return this.getDom().style.display == 'none'; }, _onMouseDown: function () { return false; }, _onClick: function (e, target) { this.fireEvent('click', e, target); }, _fill: function () { var el = this.getDom(); var vpRect = uiUtils.getViewportRect(); el.style.width = vpRect.width + 'px'; el.style.height = vpRect.height + 'px'; } }; utils.inherits(Mask, UIBase); })(); // ui/popup.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, domUtils = baidu.editor.dom.domUtils, UIBase = baidu.editor.ui.UIBase, Popup = baidu.editor.ui.Popup = function (options) { this.initOptions(options); this.initPopup(); }; var allPopups = []; function closeAllPopup(evt, el) { var path = evt.path || (evt.composedPath && evt.composedPath()); if (path) { for (var i = 0; i < path.length; i++) { var className = path[i].className; var id = path[i].id; if (id && className && (className.indexOf('edui-combox') > -1 || className.indexOf('edui-splitbutton') > -1)) { id = parseInt(id.substr(4, id.length)); if (className.indexOf('edui-for-forecolor') > -1 || className.indexOf('edui-for-backcolor') > -1) { id = 'edui' + parseInt(id + 2); } else { id = 'edui' + parseInt(id + 1); } if (document.getElementById(id) && document.getElementById(id).style.display != 'none') { return } } } } 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(); } } } if (allPopups.length) pop.editor.fireEvent("afterhidepop"); } Popup.postHide = closeAllPopup; var ANCHOR_CLASSES = ['edui-anchor-topleft', 'edui-anchor-topright', 'edui-anchor-bottomleft', 'edui-anchor-bottomright' ]; Popup.prototype = { SHADOW_RADIUS: 5, content: null, _hidden: false, autoRender: true, canSideLeft: true, canSideUp: true, initPopup: function () { this.initUIBase(); allPopups.push(this); }, getHtmlTpl: function () { return '
    ' + '
    ' + ' ' + '
    ' + '
    ' + this.getContentHtmlTpl() + '
    ' + '
    ' + '
    '; }, getContentHtmlTpl: function () { if (this.content) { if (typeof this.content == 'string') { return this.content; } return this.content.renderHtml(); } else { return '' } }, _UIBase_postRender: UIBase.prototype.postRender, postRender: function () { if (this.content instanceof UIBase) { this.content.postRender(); } //捕获鼠标滚轮 if (this.captureWheel && !this.captured) { this.captured = true; var winHeight = (document.documentElement.clientHeight || document.body.clientHeight) - 80, _height = this.getDom().offsetHeight, _top = uiUtils.getClientRect(this.combox.getDom()).top, content = this.getDom('content'), ifr = this.getDom('body').getElementsByTagName('iframe'), me = this; ifr.length && (ifr = ifr[0]); while (_top + _height > winHeight) { _height -= 30; } content.style.height = _height + 'px'; //同步更改iframe高度 ifr && (ifr.style.height = _height + 'px'); //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解 if (window.XMLHttpRequest) { domUtils.on(content, ('onmousewheel' in document.body) ? 'mousewheel' : 'DOMMouseScroll', function (e) { if (e.preventDefault) { e.preventDefault(); } else { e.returnValue = false; } if (e.wheelDelta) { content.scrollTop -= (e.wheelDelta / 120) * 60; } else { content.scrollTop -= (e.detail / -3) * 60; } }); } else { //ie6 domUtils.on(this.getDom(), 'mousewheel', function (e) { e.returnValue = false; me.getDom('content').scrollTop -= (e.wheelDelta / 120) * 60; }); } } this.fireEvent('postRenderAfter'); this.hide(true); this._UIBase_postRender(); }, _doAutoRender: function () { if (!this.getDom() && this.autoRender) { this.render(); } }, mesureSize: function () { var box = this.getDom('content'); return uiUtils.getClientRect(box); }, fitSize: function () { if (this.captureWheel && this.sized) { return this.__size; } this.sized = true; var popBodyEl = this.getDom('body'); popBodyEl.style.width = ''; popBodyEl.style.height = ''; var size = this.mesureSize(); if (this.captureWheel) { popBodyEl.style.width = -(-20 - size.width) + 'px'; var height = parseInt(this.getDom('content').style.height, 10); !window.isNaN(height) && (size.height = height); } else { popBodyEl.style.width = size.width + 'px'; } popBodyEl.style.height = size.height + 'px'; this.__size = size; this.captureWheel && (this.getDom('content').style.overflow = 'auto'); return size; }, showAnchor: function (element, hoz) { this.showAnchorRect(uiUtils.getClientRect(element), hoz); }, showAnchorRect: function (rect, hoz, adj) { this._doAutoRender(); var vpRect = uiUtils.getViewportRect(); if (this.getDom().style.display == 'none' || this.getDom().style.visibility != 'visible') { this.getDom().style.display = 'block'; this.getDom().style.visibility = 'hidden'; this._show(); var popSize = this.fitSize(); var sideLeft, sideUp, left, top; if (hoz) { sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width); sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height); left = (sideLeft ? rect.left - popSize.width : rect.right); top = (sideUp ? rect.bottom - popSize.height : rect.top); } else { sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width); sideUp = this.canSideUp && rect.top + popSize.height > vpRect.bottom; left = (sideLeft ? rect.right - popSize.width : rect.left); // top = (sideUp ? rect.top - popSize.height : rect.bottom); //20210816 表格右键弹窗如果下面空间不够,从底部开始往上显示 top = (sideUp ? vpRect.bottom - popSize.height - 10 : rect.bottom); } var popEl = this.getDom(); uiUtils.setViewportOffset(popEl, { left: left, top: top }); domUtils.removeClasses(popEl, ANCHOR_CLASSES); popEl.className += ' ' + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)]; if (this.editor) { popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10; baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = popEl.style.zIndex - 1; } this.getDom().style.visibility = 'visible'; } else { this.getDom().style.visibility = 'hidden'; } }, showAt: function (offset) { var left = offset.left; var ttop = offset.top; var rect = { left: left, top: ttop, right: left, bottom: ttop, height: 0, width: 0 }; this.showAnchorRect(rect, false, true); }, _show: function () { if (this._hidden) { var box = this.getDom(); box.style.display = ''; this._hidden = false; // if (box.setActive) { // box.setActive(); // } this.fireEvent('show'); } }, isHidden: function () { return this._hidden; }, show: function () { this._doAutoRender(); this._show(); }, hide: function (notNofity) { if (!this._hidden && this.getDom()) { this.getDom().style.display = 'none'; this._hidden = true; if (!notNofity) { this.fireEvent('hide'); } } }, queryAutoHide: function (el) { return !el || !uiUtils.contains(this.getDom(), el); } }; utils.inherits(Popup, UIBase); domUtils.on(document, 'mousedown', function (evt) { var el = evt.target || evt.srcElement; closeAllPopup(evt, el); }); domUtils.on(window, 'scroll', function (evt, el) { closeAllPopup(evt, el); }); })(); // ui/colorpicker.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase, ColorPicker = baidu.editor.ui.ColorPicker = function (options) { this.initOptions(options); this.noColorText = this.noColorText || this.editor.getLang("clearColor"); this.initUIBase(); }; ColorPicker.prototype = { getHtmlTpl: function () { return genColorPicker(this.noColorText, this.editor); }, activeColor: function (color) { $(this.getDom()).find('.edui-colorpicker-colorcell').removeClass('active'); $(this.getDom()).find('[data-color="' + color + '"]').addClass('active'); }, _onTableClick: function (evt) { var tgt = evt.target || evt.srcElement; var color = tgt.getAttribute('data-color'); if (color) { this.showMoreColorPicker = false; this.fireEvent('pickcolor', color); this._updateRecentUseColor(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'); }, _updateRecentUseColor: function(targetColor) { if(!targetColor) return; var recentColors = new Array(9), targetIndex = -1; var $recentColorElms = $(this.getDom()).find('.edui-recent-color'); $recentColorElms.each((index, item) => { var bgColor = domUtils.getStyle(item, 'background-color').toUpperCase(); // 最近使用颜色含有该颜色 if(bgColor === targetColor.toUpperCase()) { recentColors[index] = bgColor; targetIndex = index; return false; } if(bgColor) { recentColors[index] = bgColor; } else { return false; } }) // 含有该颜色 放到首位 if(targetIndex > -1) { var tempColor = recentColors[targetIndex]; recentColors.splice(targetIndex, 1); recentColors.unshift(tempColor); } else { // 不含改颜色 插入到首位 recentColors.unshift(targetColor); } // 设置最近使用颜色 recentColors.forEach(function(c, i){ $recentColorElms.eq(i).css('background-color', c); $recentColorElms.eq(i).attr({ 'data-color': c, 'title': c }); }) }, _onPickMoreColor: function (evt) { var tgt = evt.target || evt.srcElement, inputElm = tgt.querySelector('input[type="color"]'); if(inputElm) { inputElm.click(); // 显示input颜色选择器 this.showMoreColorPicker = true } }, _onMoreColorChange: function (evt) { var tgt = evt.target || evt.srcElement; this.showMoreColorPicker = false this._updateRecentUseColor(tgt.value); }, _onMoreColorInput: function (evt) { var tgt = evt.target || evt.srcElement; this.fireEvent('pickcolor', tgt.value); }, }; utils.inherits(ColorPicker, UIBase); var COLORS = ( '131B26,474C59,8A8B99,A9AFB8,C4C7CC,DCDDDE,EEEFF0,F2F4F7,FFFFFF,' + 'F33131,FF5502,FC9208,FFE45B,52CC5C,40DAD4,3A8BFF,9C81EB,EB2F97,' + 'FDE0E0,FFE5D9,FFEFDA,FFFBE6,E5F7E7,E2F9F9,E1EEFF,F0ECFC,FCE0EF,' + 'FAA2A2,FFB28D,FECE90,FFF3B5,B1E8B6,A9EEEC,A6CBFF,D2C6F6,F6A1D0,' + 'F54C4C,FF7735,FDA839,FFE97C,75D67D,66E1DD,61A2FF,B09AEF,EF59AC,' + 'CF1313,D44F0D,D47C08,D5B107,2E9937,079C97,0960D9,7B62C4,C41D79' // '131B26,F33131,3A8BFF,00B368,F28C24,acb4bf,f2f2f2' ).split(','); function genColorPicker(noColorText, editor) { var html = '
    ' + '
    ' + '
    ' + '
    ' + noColorText + '
    ' + '
    ' + '' + ''; for (var i = 0; i < COLORS.length; i++) { // if (i && i % 9 === 0) { // html += '' + (i == 54 ? '' : '') + ''; // } // html += i < 63 ? '' : ''; if (i && i % 9 === 0) { html += ''; } html += i < 54 ? '' : ''; } html += '

    ' + editor.getLang("standardColor") + '

    '; // 最近使用颜色 for(var i = 0; i < 9; i++) { if(i === 0) { html+= '

    最近使用

    '; } html+= '
    '; if(i === 8) { html+='
    '; } } html += '
    ' + '自定义颜色' + '
    ' + '
    '; return html; } })(); // ui/tablepicker.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, UIBase = baidu.editor.ui.UIBase; var TablePicker = baidu.editor.ui.TablePicker = function (options) { this.initOptions(options); this.initTablePicker(); }; TablePicker.prototype = { defaultNumRows: 10, defaultNumCols: 10, maxNumRows: 20, maxNumCols: 20, numRows: 10, numCols: 10, lengthOfCellSide: 19, initTablePicker: function () { this.initUIBase(); }, getHtmlTpl: function () { var me = this; return '
    ' + '
    ' + '
    ' + '' + this.editor.getLang('contextMenu.inserttable') + '' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    '; }, _UIBase_render: UIBase.prototype.render, render: function (holder) { this._UIBase_render(holder); this.getDom('label').innerHTML = this.editor.getLang('contextMenu.inserttable'); // 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 = this.editor.getLang('contextMenu.inserttable') + ' ' + numCols + ' x ' + numRows + ''; 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 = this.editor.getLang('contextMenu.inserttable'); 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 = this.editor.getLang('contextMenu.inserttable'); // this.getDom('label').innerHTML = '0'+this.editor.getLang("t_col")+' x 0'+this.editor.getLang("t_row"); this.getDom('overlay').style.visibility = 'hidden'; } }, _onMouseMove: function (evt, el) { var style = this.getDom('overlay').style; var offset = uiUtils.getEventOffset(evt); var sideLen = this.lengthOfCellSide; var numCols = Math.ceil(offset.left / sideLen); var numRows = Math.ceil(offset.top / sideLen); this._track(numCols, numRows); }, _onClick: function () { this.fireEvent('picktable', this.numCols, this.numRows); } }; utils.inherits(TablePicker, UIBase); })(); // ui/stateful.js (function () { var browser = baidu.editor.browser, domUtils = baidu.editor.dom.domUtils, uiUtils = baidu.editor.ui.uiUtils; var TPL_STATEFUL = 'onmousedown="$$.Stateful_onMouseDown(event, this);"' + ' onmouseup="$$.Stateful_onMouseUp(event, this);"' + (browser.ie ? ( ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' + ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"') : ( ' onmouseover="$$.Stateful_onMouseOver(event, this);"' + ' onmouseout="$$.Stateful_onMouseOut(event, this);"')); baidu.editor.ui.Stateful = { alwalysHoverable: false, target: null, //目标元素和this指向dom不一样 Stateful_init: function () { this._Stateful_dGetHtmlTpl = this.getHtmlTpl; this.getHtmlTpl = this.Stateful_getHtmlTpl; }, Stateful_getHtmlTpl: function () { var tpl = this._Stateful_dGetHtmlTpl(); // 使用function避免$转义 return tpl.replace(/stateful/g, function () { return TPL_STATEFUL; }); }, Stateful_onMouseEnter: function (evt, el) { this.target = el; if (!this.isDisabled() || this.alwalysHoverable) { this.addState('hover'); this.fireEvent('over'); } }, Stateful_onMouseLeave: function (evt, el) { if (!this.isDisabled() || this.alwalysHoverable) { this.removeState('hover'); this.removeState('active'); this.fireEvent('out'); } }, Stateful_onMouseOver: function (evt, el) { var rel = evt.relatedTarget; if (!uiUtils.contains(el, rel) && el !== rel) { this.Stateful_onMouseEnter(evt, el); } }, Stateful_onMouseOut: function (evt, el) { var rel = evt.relatedTarget; if (!uiUtils.contains(el, rel) && el !== rel) { this.Stateful_onMouseLeave(evt, el); } }, Stateful_onMouseDown: function (evt, el) { if (!this.isDisabled()) { this.addState('active'); } }, Stateful_onMouseUp: function (evt, el) { if (!this.isDisabled()) { this.removeState('active'); } }, Stateful_postRender: function () { if (this.disabled && !this.hasState('disabled')) { this.addState('disabled'); } }, hasState: function (state) { if (state == 'disabled') { return domUtils.hasClass(this.getStateDom().parentNode, 'edui-state-' + state); } else { return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state); } }, addState: function (state) { if (!this.hasState(state)) { if (state == 'disabled') { this.getStateDom().parentNode.className += ' edui-state-' + state; } else { this.getStateDom().className += ' edui-state-' + state; } } }, removeState: function (state) { if (this.hasState(state)) { if (state == 'disabled') { domUtils.removeClasses(this.getStateDom().parentNode, ['edui-state-' + state]); } else { 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'); return this.hasState('disabled'); }, setDisabled: function (disabled) { if (disabled) { this.removeState('hover'); this.removeState('checked'); this.removeState('active'); this.addState('disabled'); } else { this.removeState('disabled'); } } }; })(); // ui/button.js ///import core ///import uicore ///import ui/stateful.js (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase, Stateful = baidu.editor.ui.Stateful, Button = baidu.editor.ui.Button = function (options) { if (options.name) { var btnName = options.name; var cssRules = options.cssRules; if (!options.className) { options.className = 'edui-for-' + btnName; } options.cssRules = '.edui-default .edui-for-' + btnName + ' .edui-icon {' + cssRules + '}' } this.initOptions(options); this.initButton(); }; Button.prototype = { uiName: 'button', label: '', title: '', showIcon: true, showText: true, cssRules: '', initButton: function () { this.initUIBase(); this.Stateful_init(); if (this.cssRules) { utils.cssRule('edui-customize-' + this.name + '-style', this.cssRules); } }, getHtmlTpl: function () { return '
    ' + '
    ' + '
    ' + (this.showIcon ? '
    ' : '') + (this.showText ? '
    ' + this.label + '
    ' : '') + '
    ' + '
    ' + '
    '; }, postRender: function () { this.Stateful_postRender(); this.setDisabled(this.disabled) }, _onMouseDown: function (e) { var target = e.target || e.srcElement, tagName = target && target.tagName && target.tagName.toLowerCase(); if (tagName == 'input' || tagName == 'object' || tagName == 'object') { return false; } }, _onClick: function () { if (!this.isDisabled()) { this.fireEvent('click'); } }, setTitle: function (text) { var label = this.getDom('label'); label.innerHTML = text; } }; utils.inherits(Button, UIBase); utils.extend(Button.prototype, Stateful); })(); // ui/splitbutton.js ///import core ///import uicore ///import ui/stateful.js (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, domUtils = baidu.editor.dom.domUtils, UIBase = baidu.editor.ui.UIBase, Stateful = baidu.editor.ui.Stateful, SplitButton = baidu.editor.ui.SplitButton = function (options) { this.initOptions(options); this.initSplitButton(); }; SplitButton.prototype = { popup: null, uiName: 'splitbutton', title: '', initSplitButton: function () { this.initUIBase(); this.Stateful_init(); var me = this; if (this.popup != null) { var popup = this.popup; this.popup = null; this.setPopup(popup); } }, _UIBase_postRender: UIBase.prototype.postRender, postRender: function () { this.Stateful_postRender(); this._UIBase_postRender(); }, setPopup: function (popup) { if (this.popup === popup) return; if (this.popup != null) { this.popup.dispose(); } popup.addListener('show', utils.bind(this._onPopupShow, this)); popup.addListener('hide', utils.bind(this._onPopupHide, this)); popup.addListener('postrender', utils.bind(function () { popup.getDom('body').appendChild( uiUtils.createElementByHtml('
    ') ); popup.getDom().className += ' ' + this.className; }, this)); this.popup = popup; }, _onPopupShow: function () { this.addState('opened'); }, _onPopupHide: function () { this.removeState('opened'); }, getHtmlTpl: function () { return '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    '; }, showPopup: function () { // 当popup往上弹出的时候,做特殊处理 var rect = uiUtils.getClientRect(this.getDom()); rect.top -= this.popup.SHADOW_RADIUS; rect.height += this.popup.SHADOW_RADIUS; this.popup.showAnchorRect(rect); }, _onArrowClick: function (event, el) { var range = this.editor.selection.getRange(); range.select(); if (!this.isDisabled()) { this.showPopup(); } }, _onButtonClick: function () { if (!this.isDisabled()) { this.fireEvent('buttonclick'); } } }; utils.inherits(SplitButton, UIBase); utils.extend(SplitButton.prototype, Stateful, true); })(); // ui/colorbutton.js ///import core ///import uicore ///import ui/colorpicker.js ///import ui/popup.js ///import ui/splitbutton.js (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, ColorPicker = baidu.editor.ui.ColorPicker, Popup = baidu.editor.ui.Popup, SplitButton = baidu.editor.ui.SplitButton, ColorButton = baidu.editor.ui.ColorButton = function (options) { this.initOptions(options); this.initColorButton(); }; ColorButton.prototype = { initColorButton: function () { var me = this; var noColorText = ''; if (this.className == 'edui-for-backcolor') { noColorText = me.editor.getLang("clearBackColor") } else { noColorText = me.editor.getLang("clearColor") } this.colorpicker = new ColorPicker({ noColorText: noColorText, editor: me.editor, onpickcolor: function (t, color) { me._onPickColor(color); }, onpicknocolor: function (t, color) { me._onPickNoColor(color); } }) this.popup = new Popup({ content: this.colorpicker, 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) { if (color) { this.getDom('colorlump').style.backgroundColor = color; this.color = color; this.colorpicker.activeColor(color) } }, _onPickColor: function (color) { if (this.fireEvent('pickcolor', color) !== false) { this.setColor(color); // 显示选色器 不进行隐藏 if(!this.colorpicker.showMoreColorPicker) { this.popup.hide(); } } }, _onPickNoColor: function (color) { if (this.fireEvent('picknocolor') !== false) { this.popup.hide(); } } }; utils.inherits(ColorButton, SplitButton); })(); // ui/tablebutton.js ///import core ///import uicore ///import ui/popup.js ///import ui/tablepicker.js ///import ui/splitbutton.js (function () { var utils = baidu.editor.utils, Popup = baidu.editor.ui.Popup, TablePicker = baidu.editor.ui.TablePicker, SplitButton = baidu.editor.ui.SplitButton, TableButton = baidu.editor.ui.TableButton = function (options) { this.initOptions(options); this.initTableButton(); }; TableButton.prototype = { initTableButton: function () { var me = this; this.popup = new Popup({ content: new TablePicker({ editor: me.editor, onpicktable: function (t, numCols, numRows) { me._onPickTable(numCols, numRows); } }), 'editor': me.editor }); this.initSplitButton(); }, _onPickTable: function (numCols, numRows) { if (this.fireEvent('picktable', numCols, numRows) !== false) { this.popup.hide(); } } }; utils.inherits(TableButton, SplitButton); })(); // ui/autotypesetpicker.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase; var AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker = function (options) { this.initOptions(options); this.initAutoTypeSetPicker(); }; AutoTypeSetPicker.prototype = { initAutoTypeSetPicker: function () { this.initUIBase(); }, getHtmlTpl: function () { var me = this.editor, opt = me.options.autotypeset, lang = me.getLang("autoTypeSet"); console.log(opt) var textAlignInputName = 'textAlignValue' + me.uid, imageBlockInputName = 'imageBlockLineValue' + me.uid, symbolConverInputName = 'symbolConverValue' + me.uid; return '
    ' + '
    ' + '' + '' + '' + // '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + // '' + // '' + '' + '' + '' + '' + '' + '' '
    ' + lang.mergeLine + '
    ' + lang.delLine + '
    ' + lang.removeFormat + '
    ' + lang.indent + '
    ' + '
    ' + lang.alignment + '
    ' + '
    ' + '' + me.getLang().labelMap['justifyleft'] + '' + me.getLang().labelMap['justifycenter'] + '' + me.getLang().labelMap['justifyright'] + '' + me.getLang().labelMap['justifyjustify'] + '
    ' + '
    ' + '
    ' + lang.imageFloat + '
    ' + '
    ' + '' + me.getLang("default") + '' + me.getLang("contextMenu.imagejustifyleft") + '' + me.getLang("contextMenu.imagejustifycenter") + '' + me.getLang("contextMenu.imagejustifyright") + '
    ' + '
    ' + lang.removeFontsize + '
    ' + lang.removeFontFamily + '
    ' + lang.removeHtml + '
    ' + lang.pasteFilter + '
    ' + '
    ' + lang.symbol + '
    ' + '
    ' + '' + lang.bdc2sb + '' + lang.tobdc + '' + '' + lang.blankTodbc + '' + '
    ' + '
    ' + '
    ' + '
    '; }, _UIBase_render: UIBase.prototype.render }; utils.inherits(AutoTypeSetPicker, UIBase); })(); // ui/autotypesetbutton.js ///import core ///import uicore ///import ui/popup.js ///import ui/autotypesetpicker.js ///import ui/splitbutton.js (function () { var utils = baidu.editor.utils, Popup = baidu.editor.ui.Popup, AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker, SplitButton = baidu.editor.ui.SplitButton, AutoTypeSetButton = baidu.editor.ui.AutoTypeSetButton = function (options) { this.initOptions(options); this.initAutoTypeSetButton(); }; function getPara(me) { var opt = {}, cont = me.getDom(), editorId = me.editor.uid, inputBoxType = null, attrName = null, ipts = domUtils.getElementsByTagName(cont, "input"); for (var i = ipts.length - 1, ipt; ipt = ipts[i--];) { inputBoxType = ipt.getAttribute("type"); if (inputBoxType == "checkbox") { attrName = ipt.getAttribute("name"); opt[attrName] && delete opt[attrName]; if (ipt.checked) { var attrValue = document.getElementById(attrName + "Value" + editorId); if (attrValue) { if (/input/ig.test(attrValue.tagName)) { opt[attrName] = attrValue.value; } else { var iptChilds = attrValue.getElementsByTagName("input"); for (var j = iptChilds.length - 1, iptchild; iptchild = iptChilds[j--];) { if (iptchild.checked) { opt[attrName] = iptchild.value; break; } } } } else { opt[attrName] = true; } } else { opt[attrName] = false; } } else { opt[ipt.getAttribute("value")] = ipt.checked; } } var selects = domUtils.getElementsByTagName(cont, "select"); for (var i = 0, si; si = selects[i++];) { var attr = si.getAttribute('name'); opt[attr] = opt[attr] ? si.value : ''; } utils.extend(me.editor.options.autotypeset, opt); me.editor.setPreferences('autotypeset', opt); } AutoTypeSetButton.prototype = { initAutoTypeSetButton: function () { var me = this; this.popup = new Popup({ //传入配置参数 content: new AutoTypeSetPicker({ editor: me.editor }), 'editor': me.editor, hide: function () { if (!this._hidden && this.getDom()) { getPara(this); this.getDom().style.display = 'none'; this._hidden = true; this.fireEvent('hide'); } } }); var flag = 0; this.popup.addListener('postRenderAfter', function () { var popupUI = this; if (flag) return; var cont = this.getDom(), btn = cont.getElementsByTagName('button')[0]; btn.onclick = function () { getPara(popupUI); me.editor.execCommand('autotypeset'); popupUI.hide() }; domUtils.on(cont, 'click', function (e) { var target = e.target || e.srcElement, editorId = me.editor.uid; if (target && target.tagName == 'INPUT') { // 点击图片浮动的checkbox,去除对应的radio if (target.name == 'imageBlockLine' || target.name == 'textAlign' || target.name == 'symbolConver') { var checked = target.checked, radioTd = document.getElementById(target.name + 'Value' + editorId), radios = radioTd.getElementsByTagName('input'), defalutSelect = { 'imageBlockLine': 'none', 'textAlign': 'left', 'symbolConver': 'tobdc' }; for (var i = 0; i < radios.length; i++) { if (checked) { if (radios[i].value == defalutSelect[target.name]) { radios[i].checked = 'checked'; } } else { radios[i].checked = false; } } } // 点击radio,选中对应的checkbox if (target.name == ('imageBlockLineValue' + editorId) || target.name == ('textAlignValue' + editorId) || target.name == 'bdc') { var checkboxs = target.parentNode.previousSibling.getElementsByTagName('input'); checkboxs && (checkboxs[0].checked = true); } getPara(popupUI); } }); flag = 1; }); this.initSplitButton(); } }; utils.inherits(AutoTypeSetButton, SplitButton); })(); // ui/cellalignpicker.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, Popup = baidu.editor.ui.Popup, Stateful = baidu.editor.ui.Stateful, UIBase = baidu.editor.ui.UIBase; /** * 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始 * 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom' * @update 2013/4/2 hancong03@baidu.com */ var CellAlignPicker = baidu.editor.ui.CellAlignPicker = function (options) { this.initOptions(options); this.initSelected(); this.initCellAlignPicker(); }; CellAlignPicker.prototype = { //初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引 initSelected: function () { var status = { valign: { top: 0, middle: 1, bottom: 2 }, align: { left: 0, center: 1, right: 2 }, count: 3 }, result = -1; if (this.selected) { this.selectedIndex = status.valign[this.selected.valign] * status.count + status.align[this.selected.align]; } }, initCellAlignPicker: function () { this.initUIBase(); this.Stateful_init(); }, getHtmlTpl: function () { var alignType = ['left', 'center', 'right'], COUNT = 9, tempClassName = null, tempIndex = -1, tmpl = []; for (var i = 0; i < COUNT; i++) { tempClassName = this.selectedIndex === i ? ' class="edui-cellalign-selected" ' : ''; tempIndex = i % 3; tempIndex === 0 && tmpl.push('
  • ' + tmpl.join('') + '
    ' + '
    ' + '
    '; }, getStateDom: function () { return this.target; }, _onClick: function (evt) { var target = evt.target || evt.srcElement; if (/icon/.test(target.className)) { this.items[target.parentNode.getAttribute("index")].onclick(); Popup.postHide(evt); } }, _UIBase_render: UIBase.prototype.render }; utils.inherits(CellAlignPicker, UIBase); utils.extend(CellAlignPicker.prototype, Stateful, true); })(); // ui/pastepicker.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, Stateful = baidu.editor.ui.Stateful, uiUtils = baidu.editor.ui.uiUtils, UIBase = baidu.editor.ui.UIBase; var PastePicker = baidu.editor.ui.PastePicker = function (options) { this.initOptions(options); this.initPastePicker(); }; PastePicker.prototype = { initPastePicker: function () { this.initUIBase(); this.Stateful_init(); }, getHtmlTpl: function () { return '
    ' + '
    ' + '
    ' + this.editor.getLang("pasteOpt") + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' }, getStateDom: function () { return this.target; }, format: function (param) { this.editor.ui._isTransfer = true; this.editor.fireEvent('pasteTransfer', param); }, _onClick: function (cur) { var node = domUtils.getNextDomNode(cur), screenHt = uiUtils.getViewportRect().height, subPop = uiUtils.getClientRect(node); if ((subPop.top + subPop.height) > screenHt) node.style.top = (-subPop.height - cur.offsetHeight) + "px"; else node.style.top = ""; if (/hidden/ig.test(domUtils.getComputedStyle(node, "visibility"))) { node.style.visibility = "visible"; domUtils.addClass(cur, "edui-state-opened"); } else { node.style.visibility = "hidden"; domUtils.removeClasses(cur, "edui-state-opened") } }, _UIBase_render: UIBase.prototype.render }; utils.inherits(PastePicker, UIBase); utils.extend(PastePicker.prototype, Stateful, true); })(); // ui/toolbar.js (function () { var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, UIBase = baidu.editor.ui.UIBase, Toolbar = baidu.editor.ui.Toolbar = function (options) { this.initOptions(options); this.initToolbar(); }; Toolbar.prototype = { items: null, initToolbar: function () { this.items = this.items || []; this.initUIBase(); }, add: function (item, index) { if (index === undefined) { this.items.push(item); } else { this.items.splice(index, 0, item) } }, getHtmlTpl: function () { var buff = []; for (var i = 0; i < this.items.length; i++) { buff[i] = this.items[i].renderHtml(); } return '
    ' + buff.join('') + '
    ' }, postRender: function () { var box = this.getDom(); for (var i = 0; i < this.items.length; i++) { this.items[i].postRender(); } uiUtils.makeUnselectable(box); }, _onMouseDown: function (e) { var target = e.target || e.srcElement, tagName = target && target.tagName && target.tagName.toLowerCase(); if (tagName == 'input' || tagName == 'object' || tagName == 'object') { return false; } } }; utils.inherits(Toolbar, UIBase); })(); // ui/menu.js ///import core ///import uicore ///import ui\popup.js ///import ui\stateful.js (function () { var utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils, uiUtils = baidu.editor.ui.uiUtils, UIBase = baidu.editor.ui.UIBase, Popup = baidu.editor.ui.Popup, Stateful = baidu.editor.ui.Stateful, CellAlignPicker = baidu.editor.ui.CellAlignPicker, Menu = baidu.editor.ui.Menu = function (options) { this.initOptions(options); this.initMenu(); }; var menuSeparator = { renderHtml: function () { return '
    '; }, postRender: function () { }, queryAutoHide: function () { return true; } }; Menu.prototype = { items: null, uiName: 'menu', initMenu: function () { this.items = this.items || []; this.initPopup(); this.initItems(); }, initItems: function () { for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; if (item == '-') { this.items[i] = this.getSeparator(); } else if (!(item instanceof MenuItem)) { item.editor = this.editor; item.theme = this.editor.options.theme; this.items[i] = this.createItem(item); } } }, getSeparator: function () { return menuSeparator; }, createItem: function (item) { //新增一个参数menu, 该参数存储了menuItem所对应的menu引用 item.menu = this; return new MenuItem(item); }, _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl, getContentHtmlTpl: function () { if (this.items.length == 0) { return this._Popup_getContentHtmlTpl(); } var buff = []; for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; buff[i] = item.renderHtml(); } return ('
    ' + buff.join('') + '
    '); }, _Popup_postRender: Popup.prototype.postRender, postRender: function () { var me = this; for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; item.ownerMenu = this; item.postRender(); } domUtils.on(this.getDom(), 'mouseover', function (evt) { evt = evt || event; var rel = evt.relatedTarget || evt.fromElement; var el = me.getDom(); if (!uiUtils.contains(el, rel) && el !== rel) { me.fireEvent('over'); } }); this._Popup_postRender(); }, queryAutoHide: function (el) { if (el) { if (uiUtils.contains(this.getDom(), el)) { return false; } for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; if (item.queryAutoHide(el) === false) { return false; } } } }, clearItems: function () { for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; clearTimeout(item._showingTimer); clearTimeout(item._closingTimer); if (item.subMenu) { item.subMenu.destroy(); } } this.items = []; }, destroy: function () { if (this.getDom()) { domUtils.remove(this.getDom()); } this.clearItems(); }, dispose: function () { this.destroy(); } }; utils.inherits(Menu, Popup); /** * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用 * @type {Function} */ var MenuItem = baidu.editor.ui.MenuItem = function (options) { this.initOptions(options); this.initUIBase(); this.Stateful_init(); if (this.subMenu && !(this.subMenu instanceof Menu)) { if (options.className && options.className.indexOf("aligntd") != -1) { var me = this; //获取单元格对齐初始状态 this.subMenu.selected = this.editor.queryCommandValue('cellalignment'); this.subMenu = new Popup({ content: new CellAlignPicker(this.subMenu), parentMenu: me, editor: me.editor, destroy: function () { if (this.getDom()) { domUtils.remove(this.getDom()); } } }); this.subMenu.addListener("postRenderAfter", function () { domUtils.on(this.getDom(), "mouseover", function () { me.addState('opened'); }); }); } else { this.subMenu = new Menu(this.subMenu); } } }; MenuItem.prototype = { label: '', subMenu: null, ownerMenu: null, uiName: 'menuitem', alwalysHoverable: true, getHtmlTpl: function () { if (!this.title) { this.title = '' } 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) { //20201020 this.getDom() if (this.subMenu && this.getDom() && this.hasState('opened')) { return this.subMenu.queryAutoHide(el); } }, _onClick: function (event, this_) { if (this.hasState('disabled')) return; if (this.fireEvent('click', event, this_) !== false) { if (this.subMenu) { this.showSubMenu(); } else { Popup.postHide(event); } } }, showSubMenu: function () { var rect = uiUtils.getClientRect(this.getDom()); rect.right -= 5; rect.left += 2; rect.width -= 7; rect.top -= 4; rect.bottom += 4; rect.height += 8; this.subMenu.showAnchorRect(rect, true, true); }, hideSubMenu: function () { this.subMenu.hide(); } }; utils.inherits(MenuItem, UIBase); utils.extend(MenuItem.prototype, Stateful, true); })(); // ui/combox.js ///import core ///import uicore ///import ui/menu.js ///import ui/splitbutton.js (function () { // todo: menu和item提成通用list var utils = baidu.editor.utils, uiUtils = baidu.editor.ui.uiUtils, Menu = baidu.editor.ui.Menu, SplitButton = baidu.editor.ui.SplitButton, Combox = baidu.editor.ui.Combox = function (options) { this.initOptions(options); this.initCombox(); }; Combox.prototype = { uiName: 'combox', onbuttonclick: function () { console.log('e') this.showPopup(); }, initCombox: function () { var me = this; this.items = this.items || []; for (var i = 0; i < this.items.length; i++) { var item = this.items[i]; item.uiName = 'listitem'; item.index = i; item.onclick = function () { me.selectByIndex(this.index); }; } this.popup = new Menu({ items: this.items, uiName: 'list', editor: this.editor, captureWheel: true, combox: this }); this.initSplitButton(); }, _SplitButton_postRender: SplitButton.prototype.postRender, postRender: function () { this._SplitButton_postRender(); this.setLabel(this.label || ''); this.setValue(this.initValue || ''); }, openPopup: function () { }, showPopup: function () { var rect = uiUtils.getClientRect(this.getDom()); rect.top += 1; rect.bottom -= 1; rect.height -= 2; this.popup.showAnchorRect(rect); this.openPopup(); }, getValue: function () { return this.value; }, setValue: function (value) { var index = this.indexByValue(value); if (index != -1) { this.selectedIndex = index; this.setLabel(this.items[index].label); this.value = this.items[index].value; } else { this.selectedIndex = -1; this.setLabel(this.getLabelForUnknowValue(value)); this.value = value; } }, setLabel: function (label) { if (label.indexOf('px') > -1) { label = label.substr(0, label.length - 2) } this.getDom('button_body').innerHTML = label; this.label = label; }, getLabelForUnknowValue: function (value) { // 字体不存在 显示默认字体 if(this.className === 'edui-for-fontfamily') { return '默认字体'; } return value; }, indexByValue: function (value) { for (var i = 0; i < this.items.length; i++) { if (value == this.items[i].value) { return i; } } return -1; }, getItem: function (index) { return this.items[index]; }, selectByIndex: function (index) { if (index < this.items.length && this.fireEvent('select', index) !== false) { this.selectedIndex = index; this.value = this.items[index].value; if (this.value && (typeof this.value == 'string') && this.value.indexOf('px') > -1) { this.items[index].label = this.value.substr(0, this.value.length - 2) } if (this.value && (typeof this.value == 'string') && this.value.indexOf('webkit') > -1) { this.items[index].label = "微软雅黑" } this.setLabel(this.items[index].label); } } }; utils.inherits(Combox, SplitButton); })(); // ui/dialog.js ///import core ///import uicore ///import ui/mask.js ///import ui/button.js (function () { var utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils, uiUtils = baidu.editor.ui.uiUtils, Mask = baidu.editor.ui.Mask, UIBase = baidu.editor.ui.UIBase, Button = baidu.editor.ui.Button, Dialog = baidu.editor.ui.Dialog = function (options) { if (options.name) { var name = options.name; var cssRules = options.cssRules; if (!options.className) { options.className = 'edui-for-' + name; } if (cssRules) { options.cssRules = '.edui-default .edui-for-' + name + ' .edui-dialog-content {' + cssRules + '}' } if (options.iframeCssRules) { var height = 'calc(100% - 60px)'; if (options.buttons) { height = 'calc(100% - 130px)' } options.cssRules = '.edui-default .edui-for-' + name + ' .edui-dialog-body {' + options.iframeCssRules + '}' + '.edui-default .edui-for-' + name + ' .edui-dialog-content {height:' + height + '}' } } this.initOptions(utils.extend({ autoReset: true, draggable: true, onok: function () { }, oncancel: function () { }, onclose: function (t, ok) { return ok ? this.onok() : this.oncancel(); }, //是否控制dialog中的scroll事件, 默认为不阻止 holdScroll: false }, options)); this.initDialog(); }; var modalMask; var dragMask; var activeDialog; Dialog.prototype = { draggable: false, uiName: 'dialog', initDialog: function () { var me = this, theme = this.editor.options.theme; if (this.cssRules) { utils.cssRule('edui-customize-' + this.name + '-style', this.cssRules); } this.initUIBase(); this.modalMask = (modalMask || (modalMask = new Mask({ className: 'edui-dialog-modalmask', theme: theme, onclick: function () { // activeDialog && activeDialog.close(false); } }))); this.dragMask = (dragMask || (dragMask = new Mask({ className: 'edui-dialog-dragmask', theme: theme }))); this.closeButton = new Button({ className: 'edui-dialog-closebutton', title: me.closeDialog, theme: theme, onclick: function () { me.close(false); } }); this.fullscreen && this.initResizeEvent(); if (this.buttons) { for (var i = 0; i < this.buttons.length; i++) { if (!(this.buttons[i] instanceof Button)) { this.buttons[i] = new Button(utils.extend(this.buttons[i], { editor: this.editor }, true)); } } } }, initResizeEvent: function () { var me = this; domUtils.on(window, "resize", function () { if (me._hidden || me._hidden === undefined) { return; } if (me.__resizeTimer) { window.clearTimeout(me.__resizeTimer); } me.__resizeTimer = window.setTimeout(function () { me.__resizeTimer = null; var dialogWrapNode = me.getDom(), contentNode = me.getDom('content'), wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode), contentRect = UE.ui.uiUtils.getClientRect(contentNode), vpRect = uiUtils.getViewportRect(); contentNode.style.width = (vpRect.width - wrapRect.width + contentRect.width) + "px"; contentNode.style.height = (vpRect.height - wrapRect.height + contentRect.height) + "px"; dialogWrapNode.style.width = vpRect.width + "px"; dialogWrapNode.style.height = vpRect.height + "px"; me.fireEvent("resize"); }, 100); }); }, fitSize: function () { var popBodyEl = this.getDom('body'); // if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) { // uiUtils.removeStyle(popBodyEl, 'width'); // uiUtils.removeStyle(popBodyEl, 'height'); // } var size = this.mesureSize(); popBodyEl.style.width = size.width + 'px'; popBodyEl.style.height = size.height + 'px'; return size; }, safeSetOffset: function (offset) { var me = this; var el = me.getDom(); var vpRect = uiUtils.getViewportRect(); var rect = uiUtils.getClientRect(el); var left = offset.left; if (left + rect.width > vpRect.right) { left = vpRect.right - rect.width; } var ttop = offset.top; if (ttop + rect.height > vpRect.bottom) { ttop = vpRect.bottom - rect.height; } el.style.left = Math.max(left, 0) + 'px'; el.style.top = Math.max(ttop, 0) + 'px'; }, setTitle: function (title) { this.getDom('titlebar').firstChild.firstChild.innerText = title; }, setDisplay: function (display, type) { document.getElementsByClassName('edui-dialog-modalmask')[0].style.display = display; document.getElementById('edui_fixedlayer').querySelector('.edui-for-' + type).style.display = display; document.getElementById('edui_fixedlayer').querySelector('.edui-for-' + type + ' .edui-for-' + type).style.display = display; }, showAtCenter: function () { var vpRect = uiUtils.getViewportRect(); if (!this.fullscreen) { this.getDom().style.display = ''; var popSize = this.fitSize(); var titleHeight = this.getDom('titlebar').offsetHeight | 0; var left = vpRect.width / 2 - popSize.width / 2; var ttop = vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight; var popEl = this.getDom(); this.safeSetOffset({ left: Math.max(left | 0, 0), top: Math.max(ttop | 0, 0) }); if (!domUtils.hasClass(popEl, 'edui-state-centered')) { popEl.className += ' edui-state-centered'; } } else { var dialogWrapNode = this.getDom(), contentNode = this.getDom('content'); dialogWrapNode.style.display = "block"; var wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode), contentRect = UE.ui.uiUtils.getClientRect(contentNode); dialogWrapNode.style.left = "-100000px"; contentNode.style.width = (vpRect.width - wrapRect.width + contentRect.width) + "px"; contentNode.style.height = (vpRect.height - wrapRect.height + contentRect.height) + "px"; dialogWrapNode.style.width = vpRect.width + "px"; dialogWrapNode.style.height = vpRect.height + "px"; dialogWrapNode.style.left = 0; //保存环境的overflow值 this._originalContext = { html: { overflowX: document.documentElement.style.overflowX, overflowY: document.documentElement.style.overflowY }, body: { overflowX: document.body.style.overflowX, overflowY: document.body.style.overflowY } }; document.documentElement.style.overflowX = 'hidden'; document.documentElement.style.overflowY = 'hidden'; document.body.style.overflowX = 'hidden'; document.body.style.overflowY = 'hidden'; } this._show(); }, getContentHtml: function () { var contentHtml = ''; if (typeof this.content == 'string') { contentHtml = this.content; } else if (this.iframeUrl) { contentHtml = ''; } return contentHtml; }, getHtmlTpl: function () { var footHtml = ''; if (this.buttons) { var buff = []; for (var i = 0; i < this.buttons.length; i++) { buff[i] = this.buttons[i].renderHtml(); } footHtml = '
    ' + '
    ' + buff.join('') + '
    ' + '
    '; } return '
    ' + '
    ' + '
    ' + '
    ' + '' + (this.title || '') + '' + '
    ' + this.closeButton.renderHtml() + '
    ' + '
    ' + (this.autoReset ? '' : this.getContentHtml()) + '
    ' + footHtml + '
    '; }, postRender: function () { // todo: 保持居中/记住上次关闭位置选项 if (!this.modalMask.getDom()) { this.modalMask.render(); this.modalMask.hide(); } if (!this.dragMask.getDom()) { this.dragMask.render(); this.dragMask.hide(); } var me = this; this.addListener('show', function () { me.modalMask.show(this.getDom().style.zIndex - 2); }); this.addListener('hide', function () { me.modalMask.hide(); }); if (this.buttons) { for (var i = 0; i < this.buttons.length; i++) { this.buttons[i].postRender(); } } domUtils.on(window, 'resize', function () { setTimeout(function () { if (!me.isHidden()) { me.safeSetOffset(uiUtils.getClientRect(me.getDom())); } }); }); //hold住scroll事件,防止dialog的滚动影响页面 // if( this.holdScroll ) { // // if( !me.iframeUrl ) { // domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){ // domUtils.preventDefault(e); // } ); // } else { // me.addListener('dialogafterreset', function(){ // window.setTimeout(function(){ // var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow; // // if( browser.ie ) { // // var timer = window.setInterval(function(){ // // if( iframeWindow.document && iframeWindow.document.body ) { // window.clearInterval( timer ); // timer = null; // domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){ // domUtils.preventDefault(e); // } ); // } // // }, 100); // // } else { // domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){ // domUtils.preventDefault(e); // } ); // } // // }, 1); // }); // } // // } this._hide(); }, mesureSize: function () { var body = this.getDom('body'); var width = uiUtils.getClientRect(this.getDom('content')).width; var dialogBodyStyle = body.style; dialogBodyStyle.width = width; return uiUtils.getClientRect(body); }, _onTitlebarMouseDown: function (evt, el) { if (this.draggable) { var rect; var vpRect = uiUtils.getViewportRect(); var me = this; uiUtils.startDrag(evt, { ondragstart: function () { rect = uiUtils.getClientRect(me.getDom()); me.getDom('contmask').style.visibility = 'visible'; me.dragMask.show(me.getDom().style.zIndex - 1); }, ondragmove: function (x, y) { var left = rect.left + x; var ttop = rect.top + y; me.safeSetOffset({ left: left, top: ttop }); }, ondragstop: function () { me.getDom('contmask').style.visibility = 'hidden'; domUtils.removeClasses(me.getDom(), ['edui-state-centered']); me.dragMask.hide(); } }); } }, reset: function () { this.getDom('content').innerHTML = this.getContentHtml(); this.fireEvent('dialogafterreset'); }, _show: function () { if (this._hidden) { this.getDom().style.display = ''; //要高过编辑器的zindxe this.editor.container.style.zIndex && (this.getDom().style.zIndex = this.editor.container.style.zIndex * 1 + 10); this._hidden = false; this.fireEvent('show'); baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = this.getDom().style.zIndex - 4; } }, isHidden: function () { return this._hidden; }, _hide: function () { if (!this._hidden) { var wrapNode = this.getDom(); wrapNode.style.display = 'none'; wrapNode.style.zIndex = ''; wrapNode.style.width = ''; wrapNode.style.height = ''; this._hidden = true; this.fireEvent('hide'); } }, open: function () { if (top && !$('body').hasClass('noticeIframeMode')) { top.postMessage('{"cmd":1,"toggle":true}', "*"); } var _this = this; setTimeout(function () { if (_this.autoReset) { //有可能还没有渲染 try { _this.reset(); } catch (e) { _this.render(); _this.open() } } _this.showAtCenter(); $('body').addClass('popOverflow'); if (_this.iframeUrl) { try { _this.getDom('iframe').focus(); } catch (ex) { } } activeDialog = _this; }) }, _onCloseButtonClick: function (evt, el) { this.close(false); }, close: function (ok) { if (this.fireEvent('close', ok) !== false) { //还原环境 if (this.fullscreen) { document.documentElement.style.overflowX = this._originalContext.html.overflowX; document.documentElement.style.overflowY = this._originalContext.html.overflowY; document.body.style.overflowX = this._originalContext.body.overflowX; document.body.style.overflowY = this._originalContext.body.overflowY; delete this._originalContext; } this._hide(); $('body').removeClass('popOverflow'); if (top) { top.postMessage('{"cmd":1,"toggle":false}', "*"); } //销毁content var content = this.getDom('content'); if (content) { domUtils.remove(content); } var iframe = this.getDom('iframe'); if (iframe) { try { var doc = iframe.contentDocument || iframe.contentWindow.document; doc && (doc.body.innerHTML = ''); } catch (e) { console.log(e); } } } } }; utils.inherits(Dialog, UIBase); })(); // ui/menubutton.js ///import core ///import uicore ///import ui/menu.js ///import ui/splitbutton.js (function () { var utils = baidu.editor.utils, Menu = baidu.editor.ui.Menu, SplitButton = baidu.editor.ui.SplitButton, MenuButton = baidu.editor.ui.MenuButton = function (options) { this.initOptions(options); this.initMenuButton(); }; MenuButton.prototype = { initMenuButton: function () { var me = this; this.uiName = "menubutton"; this.popup = new Menu({ items: me.items, className: me.className, editor: me.editor }); this.popup.addListener('show', function () { var list = this; for (var i = 0; i < list.items.length; i++) { list.items[i].removeState('checked'); if (parseFloat(list.items[i].value).toFixed(2) == parseInt(me._value).toFixed(2)) { //行距 list.items[i].addState('checked'); this.value = me._value; } } }); this.initSplitButton(); }, setValue: function (value) { this._value = value; } }; utils.inherits(MenuButton, SplitButton); })(); // ui/multiMenu.js ///import core ///import uicore ///commands 表情 (function () { var utils = baidu.editor.utils, Popup = baidu.editor.ui.Popup, SplitButton = baidu.editor.ui.SplitButton, MultiMenuPop = baidu.editor.ui.MultiMenuPop = function (options) { this.initOptions(options); this.initMultiMenu(); }; MultiMenuPop.prototype = { initMultiMenu: function () { var me = this; this.popup = new Popup({ content: '', editor: me.editor, iframe_rendered: false, onshow: function () { if (!this.iframe_rendered) { this.iframe_rendered = true; this.getDom('content').innerHTML = ''; me.editor.container.style.zIndex && (this.getDom().style.zIndex = me.editor.container.style.zIndex * 1 + 1); } } // canSideUp:false, // canSideLeft:false }); this.onbuttonclick = function () { this.showPopup(); }; this.initSplitButton(); } }; utils.inherits(MultiMenuPop, SplitButton); })(); // ui/shortcutmenu.js (function () { var UI = baidu.editor.ui, UIBase = UI.UIBase, uiUtils = UI.uiUtils, utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils; var allMenus = [], //存储所有快捷菜单 timeID, isSubMenuShow = false; //是否有子pop显示 var ShortCutMenu = UI.ShortCutMenu = function (options) { this.initOptions(options); this.initShortCutMenu(); }; ShortCutMenu.postHide = hideAllMenu; ShortCutMenu.prototype = { isHidden: true, SPACE: 5, initShortCutMenu: function () { this.items = this.items || []; this.initUIBase(); this.initItems(); this.initEvent(); allMenus.push(this); }, initEvent: function () { var me = this, doc = me.editor.document; domUtils.on(doc, "mousemove", function (e) { if (me.isHidden === false) { //有pop显示就不隐藏快捷菜单 if (me.getSubMenuMark() || me.eventType == "contextmenu") return; var flag = true, el = me.getDom(), wt = el.offsetWidth, ht = el.offsetHeight, distanceX = wt / 2 + me.SPACE, //距离中心X标准 distanceY = ht / 2, //距离中心Y标准 x = Math.abs(e.screenX - me.left), //离中心距离横坐标 y = Math.abs(e.screenY - me.top); //离中心距离纵坐标 clearTimeout(timeID); timeID = setTimeout(function () { if (y > 0 && y < distanceY) { me.setOpacity(el, "1"); } else if (y > distanceY && y < distanceY + 70) { me.setOpacity(el, "0.5"); flag = false; } else if (y > distanceY + 70 && y < distanceY + 140) { me.hide(); } if (flag && x > 0 && x < distanceX) { me.setOpacity(el, "1") } else if (x > distanceX && x < distanceX + 70) { me.setOpacity(el, "0.5") } else if (x > distanceX + 70 && x < distanceX + 140) { me.hide(); } }); } }); //ie\ff下 mouseout不准 if (browser.chrome) { domUtils.on(doc, "mouseout", function (e) { var relatedTgt = e.relatedTarget || e.toElement; if (relatedTgt == null || relatedTgt.tagName == "HTML") { me.hide(); } }); } me.editor.addListener("afterhidepop", function () { if (!me.isHidden) { isSubMenuShow = true; } }); }, initItems: function () { if (utils.isArray(this.items)) { for (var i = 0, len = this.items.length; i < len; i++) { var item = this.items[i].toLowerCase(); if (UI[item]) { this.items[i] = new UI[item](this.editor); this.items[i].className += " edui-shortcutsubmenu "; } } } }, setOpacity: function (el, value) { if (browser.ie && browser.version < 9) { el.style.filter = "alpha(opacity = " + parseFloat(value) * 100 + ");" } else { el.style.opacity = value; } }, getSubMenuMark: function () { isSubMenuShow = false; var layerEle = uiUtils.getFixedLayer(); var list = domUtils.getElementsByTagName(layerEle, "div", function (node) { return domUtils.hasClass(node, "edui-shortcutsubmenu edui-popup") }); for (var i = 0, node; node = list[i++];) { if (node.style.display != "none") { isSubMenuShow = true; } } return isSubMenuShow; }, show: function (e, hasContextmenu) { var me = this, offset = {}, el = this.getDom(), fixedlayer = uiUtils.getFixedLayer(); function setPos(offset) { if (offset.left < 0) { offset.left = 0; } if (offset.top < 0) { offset.top = 0; } el.style.cssText = "position:absolute;left:" + offset.left + "px;top:" + offset.top + "px;"; } function setPosByCxtMenu(menu) { if (!menu.tagName) { menu = menu.getDom(); } offset.left = parseInt(menu.style.left); offset.top = parseInt(menu.style.top); offset.top -= el.offsetHeight + 15; setPos(offset); } me.eventType = e.type; el.style.cssText = "display:block;left:-9999px"; if (e.type == "contextmenu" && hasContextmenu) { var menu = domUtils.getElementsByTagName(fixedlayer, "div", "edui-contextmenu")[0]; if (menu) { setPosByCxtMenu(menu) } else { me.editor.addListener("aftershowcontextmenu", function (type, menu) { setPosByCxtMenu(menu); }); } } else { offset = uiUtils.getViewportOffsetByEvent(e); offset.top -= el.offsetHeight + me.SPACE; offset.left += me.SPACE + 20; setPos(offset); me.setOpacity(el, 0.2); } me.isHidden = false; me.left = e.screenX + el.offsetWidth / 2 - me.SPACE; me.top = e.screenY - (el.offsetHeight / 2) - me.SPACE; if (me.editor) { el.style.zIndex = me.editor.container.style.zIndex * 1 + 10; fixedlayer.style.zIndex = el.style.zIndex - 1; } }, hide: function () { if (this.getDom()) { this.getDom().style.display = "none"; } this.isHidden = true; }, postRender: function () { if (utils.isArray(this.items)) { for (var i = 0, item; item = this.items[i++];) { item.postRender(); } } }, getHtmlTpl: function () { var buff; if (utils.isArray(this.items)) { buff = []; for (var i = 0; i < this.items.length; i++) { buff[i] = this.items[i].renderHtml(); } buff = buff.join(""); } else { buff = this.items; } return '
    ' + buff + '
    '; } }; utils.inherits(ShortCutMenu, UIBase); function hideAllMenu(e) { var tgt = e.target || e.srcElement, cur = domUtils.findParent(tgt, function (node) { return domUtils.hasClass(node, "edui-shortcutmenu") || domUtils.hasClass(node, "edui-popup"); }, true); if (!cur) { for (var i = 0, menu; menu = allMenus[i++];) { menu.hide() } } } domUtils.on(document, 'mousedown', function (e) { hideAllMenu(e); }); domUtils.on(window, 'scroll', function (e) { hideAllMenu(e); }); })(); // ui/breakline.js (function () { var utils = baidu.editor.utils, UIBase = baidu.editor.ui.UIBase, Breakline = baidu.editor.ui.Breakline = function (options) { this.initOptions(options); this.initSeparator(); }; Breakline.prototype = { uiName: 'Breakline', initSeparator: function () { this.initUIBase(); }, getHtmlTpl: function () { return '
    '; } }; utils.inherits(Breakline, UIBase); })(); // ui/message.js ///import core ///import uicore (function () { var utils = baidu.editor.utils, domUtils = baidu.editor.dom.domUtils, UIBase = baidu.editor.ui.UIBase, Message = baidu.editor.ui.Message = function (options) { this.initOptions(options); this.initMessage(); }; Message.prototype = { initMessage: function () { this.initUIBase(); }, getHtmlTpl: function () { return '
    ' + '
    ×
    ' + '
    ' + ' ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    '; }, reset: function (opt) { var me = this; if (!opt.keepshow) { clearTimeout(this.timer); me.timer = setTimeout(function () { me.hide(); }, opt.timeout || 4000); } opt.content !== undefined && me.setContent(opt.content); opt.type !== undefined && me.setType(opt.type); me.show(); }, postRender: function () { var me = this, closer = this.getDom('closer'); closer && domUtils.on(closer, 'click', function () { me.hide(); }); }, setContent: function (content) { this.getDom('content').innerHTML = content; }, setType: function (type) { type = type || 'info'; var body = this.getDom('body'); body.className = body.className.replace(/edui-message-type-[\w-]+/, 'edui-message-type-' + type); }, getContent: function () { return this.getDom('content').innerHTML; }, getType: function () { var arr = this.getDom('body').match(/edui-message-type-([\w-]+)/); return arr ? arr[1] : ''; }, show: function () { this.getDom().style.display = 'block'; }, hide: function () { var dom = this.getDom(); if (dom) { dom.style.display = 'none'; dom.parentNode && dom.parentNode.removeChild(dom); } } }; utils.inherits(Message, UIBase); })(); // adapter/editorui.js //ui跟编辑器的适配層 //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置 //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据ueditor.config中的toolbars找到相应的进行实例化 (function () { var utils = baidu.editor.utils; var editorui = baidu.editor.ui; var _Dialog = editorui.Dialog; editorui.buttons = {}; editorui.Dialog = function (options) { var dialog = new _Dialog(options); dialog.addListener('hide', function () { if (dialog.editor) { var editor = dialog.editor; try { if (browser.gecko) { var y = editor.window.scrollY, x = editor.window.scrollX; editor.body.focus(); editor.window.scrollTo(x, y); } else { editor.focus(); } } catch (ex) { } } }); return dialog; }; let webPrefix = window.location.protocol + '//noteyd.chaoxing.com'; if(window.obj && window.obj.mirrorDomain){ webPrefix = window.location.protocol + window.obj.mirrorDomain.NoteDomainHttps.replace('https:',''); }else if(typeof RichTextUitl != 'undefined' && RichTextUitl.prefix){ webPrefix = RichTextUitl.prefix || RichTextUitl.noteDomain } var iframeUrlMap = { 'anchor': '~/dialogs/anchor/anchor.html', 'insertimage': '~/dialogs/image/image.html', 'link': '~/dialogs/link/link.html', 'textlink': '~/dialogs/link/textlink.html', 'spechars': '~/dialogs/spechars/spechars.html', 'searchreplace': '~/dialogs/searchreplace/searchreplace.html', 'map': '~/dialogs/map/map.html', 'gmap': '~/dialogs/gmap/gmap.html', 'insertvideo': '~/dialogs/video/video.html', 'help': '~/dialogs/help/help.html', 'preview': '~/dialogs/preview/preview.html', 'emotion': '~/dialogs/emotion/emotion.html', 'wordimage': '~/dialogs/wordimage/wordimage.html', 'attachment': '~/dialogs/attachment/attachment.html', 'insertframe': '~/dialogs/insertframe/insertframe.html', 'edittip': '~/dialogs/table/edittip.html', // 'edittable':'~/dialogs/table/edittable.html', 'edittd': '~/dialogs/table/edittd.html', 'webapp': '~/dialogs/webapp/webapp.html', 'snapscreen': '~/dialogs/snapscreen/snapscreen.html', 'scrawl': '~/dialogs/scrawl/scrawl.html', 'music': '~/dialogs/music/music.html', 'template': '~/dialogs/template/template.html', 'background': '~/dialogs/background/background.html', 'charts': '~/dialogs/charts/charts.html', 'notes': '~/dialogs/onlineattach/notes.html', 'cloud': '~/dialogs/onlineattach/cloud.html', 'collection': '~/dialogs/onlineattach/collection.html', 'mathml': '~/dialogs/mathplugin/edrawmath.html#t=' + (new Date).getTime(), // 'draw': '~/dialogs/draw/index.html', 'draw': webPrefix + '/comp/draw/html/draw.html', 'inserseal': '~/dialogs/inserseal/inserseal.html', 'wxurl': window.location.protocol + '//zhypt.chaoxing.com/portal/note/wx', 'xiumi': '~/dialogs/xiumi/xiumi-ue-dialog-v5.html', 'wordscheck': window.location.protocol + '//zhypt.chaoxing.com/portal/note/wordscheck', 'material_library':window.location.protocol + '//all.chaoxing.com/note_editor/views/material.html', 'wordstatistics': '~/dialogs/wordstatistics/wordstatistics.html' }; // 添加第三方自定义的按钮控件 // if (typeof RichTextUitl != 'undefined' && typeof RichTextUitl.customToolbars != 'undefined') { // for (var item in RichTextUitl.customToolbars) { // iframeUrlMap[item] = RichTextUitl.customToolbars[item]; // } // } //iframeUrlMap.test = 'https://noteyd.chaoxing.com/res/plugin/ueditor/dialogs/onlineattach/test.html'; //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起 var btnCmds = ['undo', 'redo', 'formatmatch', 'bold', 'italic', 'underline', 'fontborder', 'touppercase', 'tolowercase', 'strikethrough', 'emphasize', 'subscript', 'superscript', 'source', // 'indent', 'outdent','pindent', 'blockquote', 'pasteplain', 'pagebreak', 'checkbox', 'radio', 'selectall', 'print', 'horizontal', 'removeformat', 'time', 'date', 'unlink', 'insertparagraphbeforetable', 'insertrow', 'insertcol', 'insertrownext', 'insertcolnext', 'mergeright', 'mergedown', 'deleterow', 'edittable', 'settablebackground', 'deletecol', 'splittorows', 'splittocols', 'splittocells', 'mergecells', 'deletetable', 'drafts', 'mathml', 'onlinetable', 'insertcode', 'callout', 'mindmap','wordstatistics' ,'135editor' ]; for (var i = 0, ci; ci = btnCmds[i++];) { ci = ci.toLowerCase(); editorui[ci] = function (cmd) { return function (editor) { var ui = new editorui.Button({ className: 'edui-for-' + cmd, title: editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '', onclick: function () { //20200619 发送协同命令 var elementId = domUtils.getRandomId(); if (editor.options.cooperation && cmd != 'radio' && cmd != 'formatmatch') { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = null; data.elementId = elementId; data.address = range.createAddress(false, true); editor.sendJoinData(data); } if (cmd == 'checkbox') { editor.execCommand(cmd, null, null, elementId); } else { // lichangchang 点击按钮后调用相关方法 editor.execCommand(cmd); } }, theme: editor.options.theme, showText: false }); editorui.buttons[cmd] = ui; editor.addListener('selectionchange', function (type, causeByUi, uiReady) { var state = editor.queryCommandState(cmd); if (state == -1) { ui.setDisabled(true); ui.setChecked(false); } else { if (!uiReady) { ui.setDisabled(false); ui.setChecked(state); } } }); return ui; }; }(ci); } //清除文档 editorui.cleardoc = function (editor) { var ui = new editorui.Button({ className: 'edui-for-cleardoc', title: editor.options.labelMap.cleardoc || editor.getLang("labelMap.cleardoc") || '', theme: editor.options.theme, onclick: function () { if (confirm(editor.getLang("confirmClear"))) { editor.execCommand('cleardoc'); } } }); editorui.buttons["cleardoc"] = ui; editor.addListener('selectionchange', function () { ui.setDisabled(editor.queryCommandState('cleardoc') == -1); }); return ui; }; //文字对齐 editorui['indent'] = function (editor) { var indenttitle = editor.options.labelMap['indent'] || editor.getLang("labelMap.indent") || ''; var objItems = [{ id: 1, name: 'pindent', title: editor.getLang('contextMenu.indent') }, { id: 2, name: 'indent', title: editor.getLang('contextMenu.increaseindent') }, { id: 3, name: 'outdent', title: editor.getLang('contextMenu.decreaseindent') }]; var items = []; for (var i = 0; i < objItems.length; i++) { var item = objItems[i]; items.push({ //显示的条目 label: item['name'], //选中条目后的返回值 value: item['id'], title: item['title'] }); } var ui = new editorui.Combox({ editor: editor, items: items, title: editor.options.labelMap['indent'] || editor.getLang("labelMap." + 'indent') || '', initValue: indenttitle, onselect: function (t, index) { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = 'indent'; data.value = items[index].label; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand('indent', items[index].label); var classList = editor.container.querySelector('.edui-toolbar .edui-for-indent').classList; classList.remove('pindent') classList.remove('indent'); classList.remove('outdent'); classList.add(items[index].label) }, onbuttonclick: function () { //20200312点击左侧不弹框 var justifycombox = editor.container.querySelector('.edui-combox.edui-for-indent') var index = 0; if ($(justifycombox).hasClass('outdent')) { index = 2 } else if ($(justifycombox).hasClass('pindent')) { index = 0 } else if ($(justifycombox).hasClass('indent')) { index = 1 } var range = editor.selection.getRange(); range.select(); //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = 'indent'; data.value = items[index].label; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand('indent', items[index].label); // this.showPopup(); }, className: 'edui-for-indent' }); editorui.buttons['indent'] = ui; editor.addListener('selectionchange', function (type, causeByUi, uiReady) { ui.setDisabled(editor.queryCommandState('indent') == -1); }); return ui; }; //文字对齐 editorui['justify'] = function (editor) { var justifytitle = editor.options.labelMap['justify'] || editor.getLang("labelMap.justify") || ''; var items = [{ value: 'left', // title: 'left', label: editor.options.labelMap['justifyleft'] }, { value: 'center', // title: 'center', label: editor.options.labelMap['justifycenter'] }, { value: 'right', // title: editor.options.labelMap['justifyright'], label: editor.options.labelMap['justifyright'] }, { value: 'justify', // title: 'justify', label: editor.options.labelMap['justifyjustify'] }, { value: 'top', // title: 'top', label: editor.options.labelMap['justifytop'] }, { value: 'middle', // title: 'middle', label: editor.options.labelMap['justifymiddle'] }, { value: 'bottom', // title: 'bottom', label: editor.options.labelMap['justifybottom'] }]; var ui = new editorui.Combox({ editor: editor, items: items, title: editor.options.labelMap['justify'] || editor.getLang("labelMap." + 'justify') || '', initValue: justifytitle, onselect: function (t, index) { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = 'justify'; data.value = items[index].value; data.address = range.createAddress(false, true); editor.sendJoinData(data); } if(index < 4){ editor.execCommand('justify', items[index].value); }else{ editor.execCommand('cellvalign', items[index].value); return } var classList = editor.container.querySelector('.edui-toolbar .edui-for-justify').classList classList.remove('editor-justify-center') classList.remove('editor-justify-right'); classList.remove('editor-justify-left'); classList.remove('editor-justify-justify'); classList.add('editor-justify-'+items[index].value) }, onbuttonclick: function () { //20200312点击左侧不弹框 var justifycombox = editor.container.querySelector('.edui-combox.edui-for-justify') var index = 0; var classNames = justifycombox.className.split(' '); if (classNames.indexOf('editor-justify-left') > -1) { index = 0 } else if (classNames.indexOf('editor-justify-center') > -1) { index = 1 } else if (classNames.indexOf('editor-justify-right') > -1) { index = 2 } else if (classNames.indexOf('editor-justify-justify') > -1) { index = 3 } var range = editor.selection.getRange(); range.select(); //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = 'justify'; data.value = items[index].value; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand('justify', items[index].value); // this.showPopup(); }, openPopup: function () { //点开三角时 if(!document.getElementById(ui.popup.id)) return var justifyValue = editor.queryCommandValue('justify'); var valignValue = editor.queryCommandValue('cellvalign'); var popList = document.getElementById(ui.popup.id).querySelectorAll('.edui-for-justify .edui-popup-content .edui-listitem') for(var i = 0;i3){ //光标在表格里或选中表格 if(editor.queryCommandState('inserttable') == -1 || editor.body.querySelector('.selectTdClass')){ popList[i].style.display = 'block'; }else{ popList[i].style.display = 'none'; continue; } if(valignValue == items[i].value){ ui.items[i].addState('checked'); } } } }, className: 'edui-for-justify' }); editorui.buttons['justify'] = ui; editor.addListener('selectionchange', function (type, causeByUi, uiReady) { var state = editor.queryCommandState('justify'); if (state == -1) { ui.setDisabled(true); } else { ui.setDisabled(false); } }); return ui; }; //排版,图片排版,文字方向 var typeset = { 'imagefloat': ['none', 'left', 'center', 'right'], 'directionality': ['ltr', 'rtl'] }; for (var p in typeset) { (function (cmd, val) { for (var i = 0, ci; ci = val[i++];) { (function (cmd2) { editorui[cmd.replace('float', '') + cmd2] = function (editor) { var ui = new editorui.Button({ className: 'edui-for-' + cmd.replace('float', '') + cmd2, title: editor.options.labelMap[cmd.replace('float', '') + cmd2] || editor.getLang("labelMap." + cmd.replace('float', '') + cmd2) || '', theme: editor.options.theme, onclick: function () { editor.execCommand(cmd, cmd2); } }); editorui.buttons[cmd] = ui; editor.addListener('selectionchange', function (type, causeByUi, uiReady) { ui.setDisabled(editor.queryCommandState(cmd) == -1); ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !uiReady); }); return ui; }; })(ci) } })(p, typeset[p]) } //字体颜色和背景颜色 for (var i = 0, ci; ci = ['backcolor', 'forecolor'][i++];) { editorui[ci] = function (cmd) { var initcolor = '' if (cmd == 'backcolor') { initcolor = '#fff3b5'; } else { initcolor = '#F33131' } return function (editor) { var ui = new editorui.ColorButton({ className: 'edui-for-' + cmd, color: initcolor, title: editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '', editor: editor, onpickcolor: function (t, color) { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = color; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, color); this.setColor(color); }, onpicknocolor: function () { if (this.className == 'edui-for-backcolor') { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = 'default'; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, 'default'); this.setColor('#ffffff'); this.color = '#ffffff'; } else { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = 'default'; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, 'default'); this.setColor('#333333'); this.color = '#333333'; } }, onbuttonclick: function () { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = this.color; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, this.color); } }); editorui.buttons[cmd] = ui; editor.addListener('selectionchange', function () { ui.setDisabled(editor.queryCommandState(cmd) == -1); ui.setColor(editor.queryCommandValue(cmd)); }); return ui; }; }(ci); } //表格边框颜色和背景颜色 20200907 for (var i = 0, ci; ci = ['edittable', 'settablebackground'][i++];) { editorui[ci] = function (cmd) { var initcolor = '' if (cmd == 'settablebackground') { initcolor = '#F2F2F5'; } else { initcolor = '#9CC5FF' } return function (editor) { var ui = new editorui.ColorButton({ className: 'edui-for-' + cmd, color: initcolor, title: editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '', editor: editor, onpickcolor: function (t, color) { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = color; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, color); this.setColor(color); }, onpicknocolor: function () { if (this.className == 'edui-for-settablebackground') { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = '#FFFFFF'; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, '#FFFFFF'); this.setColor('#FFFFFF'); this.color = '#FFFFFF'; } else { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = '#dddddd'; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, '#dddddd'); this.setColor('#dddddd'); this.color = '#dddddd'; } }, onbuttonclick: function () { //20200619 发送协同命令 if (editor.options.cooperation) { var range = editor.selection.getRange(); var data = {}; data.name = 'execCommand'; data.cmdName = cmd; data.value = this.color; data.address = range.createAddress(false, true); editor.sendJoinData(data); } editor.execCommand(cmd, this.color); } }); editorui.buttons[cmd] = ui; editor.addListener('selectionchange', function () { ui.setDisabled(editor.queryCommandState(cmd) == -1); ui.setColor(editor.queryCommandValue(cmd)); }); return ui; }; }(ci); } //20200915 // 导入文档 editorui["insertdoc"] = function (editor) { var name = 'insertdoc', ui = new editorui.Button({ className: 'edui-for-' + name, title: editor.options.labelMap[name] || editor.getLang("labelMap." + name) || '', onclick: function () { }, theme: editor.options.theme, showText: false }); editorui.buttons[name] = ui; editor.addListener('ready', function () { var doc; var iframe = editor.iframe; if (iframe) { doc = iframe.contentDocument || iframe.document; } var acceptExtensions = (editor.getOpt('convertAllowFiles') || []).join('').replace(/\./g, ',').replace(/^[,]/, ''), actionUrl = editor.getActionUrl(editor.getOpt('convertActionName')), fileMaxSize = editor.getOpt('convertMaxSize'), lang = editor.getLang('insertdoc'); var id = '#' + editor.container.querySelector('.edui-for-insertdoc .edui-button-body').getAttribute('id') // 导入文档 var uploader = WebUploader.create({ auto: true, pick: { id: id, multiple: false, }, swf: '../ueditor-1.4.3.3/third-party/webuploader/Uploader.swf', server: actionUrl, fileVal: editor.getOpt('convertFieldName'), duplicate: true, fileSingleSizeLimit: fileMaxSize, compress: false, accept: { extensions: 'doc,docx,pdf', mimeTypes: '.doc,.docx,.pdf' }, withCredentials: true, }); // 点击重传 editor.reupload = function (_this) { if (uploader.getFiles('error').length > 0) { for (i = 0; file = uploader.getFiles('error')[i++];) { if (file.id == $(_this).parent().attr('id')) { uploader.retry(file); } } } } function fileSize(bytes) { if (bytes / 1024 > 1) { if (bytes / (1024 * 1024) > 1) { return "" + (bytes / (1024 * 1024)).toFixed(1) + "MB"; } else { return "" + parseInt(bytes / 1024) + "KB"; } } else { return "" + bytes + "B"; } } function addFile(file) { if (file && file.source && file.source.source) { showError = function (code, fileId) { switch (code) { case 'exceed_size': text = lang.errorExceedSize; break; case 'interrupt': text = lang.errorInterrupt; break; case 'http': text = lang.errorHttp; break; case 'not_allow_type': text = lang.errorFileType; break; default: text = lang.errorUploadRetry; break; } }; if (file.getStatus() === 'invalid') { RichTextUitl.showTips(file.statusText, 0); } else { /* 检查文件格式 */ if (!file.ext || (acceptExtensions && acceptExtensions.indexOf(file.ext.toLowerCase()) == -1)) { RichTextUitl.showTips('not_allow_type', 0); uploader.removeFile(file); } } } } // 当文件被加入队列之前触发,此事件的handler返回值为false,则此文件不会被添加进入队列。 uploader.on('beforeFileQueued', function (file) { if (editor.options.closeUpload == 1 && typeof RichTextUitl.showTips == 'function') { RichTextUitl.showTips('上传功能暂时关闭,请稍后再试', 0); return false; } return true; }); // 当文件被加入队列以后触发。 uploader.on('fileQueued', function (file) { //插入到页面中 addFile(file); if ($('.toolTipBox').length > 0) { $('.toolTipBox').remove(); } $(document.body).append('
    正在导入...
    ') }); uploader.on('uploadBeforeSend', function (file, data, header) { //这里可以通过data对象添加POST参数 header['X-Requested-With'] = 'XMLHttpRequest'; }); //上传进度 uploader.on('uploadProgress', function (file, percentage) { // $(doc.getElementsByClassName("attachprogress_wrap")).show(); // var progresslen = fileSize(file.size * percentage) || 0; // if(doc && doc.getElementById(file.id) && doc.getElementById(file.id).childNodes.length > 0) { // //20200623 // percentage = (Math.round(percentage * 10000) / 100).toFixed(0) + '%'; ; // var radialObj = $(doc.getElementById(file.id)).find('.progressbar .bar').css('width', percentage ); // $(doc.getElementById(file.id)).find('.curSize').text(progresslen) // } // if(file.type && file.type.indexOf("video") > -1) { // $(doc.getElementsByClassName("video_num_progress")).html(progresslen); // var radialObj = $(doc.getElementById(file.id)).find('.attachprogress').data('radialIndicator'); // if(radialObj) { // radialObj.animate(percentage*100); // } // } }); //上传结果 uploader.on('uploadError', function (file) { RichTextUitl.showTips('导入失败', 0); $('.toolTipBox').remove(); $('.tips').hide(); // if(doc && doc.getElementById(file.id)) { // if(file.type && file.type.indexOf("image") > -1) { // // 图片 // $(doc.getElementById(file.id)).find('.imguploaderror').text(lang.errorUploadRetry).show(); // $(doc.getElementById(file.id)).find('.imgprogress').addClass('fail'); // $(doc.getElementById(file.id)).find('.fail').attr("onclick","editor.reupload(this);"); // } else if(file.type && file.type.indexOf("video") > -1){ // $(doc.getElementById(file.id)).find('.attachprogress_wrap').hide(); // $(doc.getElementById(file.id)).find('.video_fail').show(); // $(doc.getElementById(file.id)).find('.video_fail').attr("onclick","editor.reupload(this);"); // }else { // // 其他文件 // $(doc.getElementById(file.id)).find('.uploadinfotext').text(lang.errorUploadRetry).show(); // $(doc.getElementById(file.id)).find('.attachprogress').addClass('fail'); // $(doc.getElementById(file.id)).find('.progressbar .bar').css('width','0'); // $(doc.getElementById(file.id)).find('.attachprogress').attr("onclick","editor.reupload(this);"); // } // } }); uploader.on('error', function (handler, max, file) { if (handler == 'Q_TYPE_DENIED' || handler == 'F_EXCEED_SIZE') { addFile(file); } }); uploader.on('uploadComplete', function (file) { }); var fileRetryTimes = new RMap(); uploader.on('uploadSuccess', function (file, ret) { try { $('.toolTipBox').remove(); var responseText = (ret._raw || ret), json = utils.str2json(responseText); if (json.result || json.code) { // 线上的通过 result 判断,镜像的通过 code 判断 var html = ''; if (json.result && json.msg) { html = json.msg; } if (json.code && json.data) { html = json.data; } if (!html) { RichTextUitl.showTips('导入失败', 0); return; } var processedHtml = html; if ($('body').find('.convertContainer').length == 0) { $('body').append(''); } $('.convertContainer').html(html); if (file.ext && file.ext.toLowerCase().indexOf('doc') > -1) { // doc 或者 docx if ($('.convertContainer').find('p').length > 0) { processedHtml = ''; if (file.ext && file.ext.toLowerCase() == 'doc') { // doc,样式文件单独写在style标签里,解析style标签,将样式追加到标签上 if (document.getElementsByTagName('style').length > 0) { var sheet = document.getElementsByTagName('style')[document.getElementsByTagName('style').length - 1].sheet if (sheet && sheet.cssRules.length > 0) { var cssRules = sheet.cssRules $.each(cssRules, function (idx, val) { var tagClass = val.selectorText; var cssText = val.style.cssText; $('.convertContainer ' + tagClass).attr('style', cssText); }) } } } // $.each($('.convertContainer').children(), function () { // if (this.tagName == 'DIV') { // $.each($(this).children(), function () { // if (this.tagName == 'P') { // processedHtml += ($(this)[0].outerHTML || ''); // } else if (this.tagName == 'TABLE') { // processedHtml += ($(this)[0].outerHTML || ''); // } // }) // } else if (this.tagName == 'P') { // processedHtml += ($(this)[0].outerHTML || ''); // } else if (this.tagName == 'TABLE') { // processedHtml += ($(this)[0].outerHTML || ''); // } // }) processedHtml = $('.convertContainer').html().replace(/\x3C!--[\s\S]*?-->/ig, '').replace(//ig, '').replace(/