/*!
 * neditor
 * version: 2.0.0
 * build: Tue Mar 20 2018 04:23:08 GMT+0000 (UTC)
 */

(function () {

// editor.js
    UEDITOR_CONFIG = window.UEDITOR_CONFIG || {};

    var baidu = window.baidu || {};

    window.baidu = baidu;

    window.UE = baidu.editor = {
        plugins: {},
        commands: {},
        instants: {},
        I18N: {},
        _customizeUI: {},
        version: "1.5.0"
    };
    var dom = (UE.dom = {});


// core/browser.js
    /**
     * 浏览器判断模块
     * @file
     * @module UE.browser
     * @since 1.2.6.1
     */

    /**
     * 提供浏览器检测的模块
     * @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.]+)/i.test(agent),

                /**
                 * @property {boolean} opera 检测当前浏览器是否为Opera
                 * @example
                 * ```javascript
                 * if ( UE.browser.opera ) {
         *     console.log( '当前浏览器是Opera' );
         * }
                 * ```
                 */
                opera: !!opera && opera.version,

                /**
                 * @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
         * <ul>
         *     <li>IE系列返回值为5,6,7,8,9,10等</li>
         *     <li>gecko系列会返回10900,158900等</li>
         *     <li>webkit系列会返回其build号 (如 522等)</li>
         * </ul>
         * @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 = '<body>&</body>';
         *
         * //output: &lt;body&gt;&amp;&lt;/body&gt;
         * console.log( UE.utils.unhtml( html ) );
         *
         * ```
         */
        unhtml: function (str, reg) {
            return str
                ? str.replace(
                    reg || /[&<">'](?:(amp|lt|ldquo|rdquo|quot|gt|#39|nbsp|#\d+);)?/g,
                    function (a, b) {
                        if (b) {
                            return a;
                        } else {
                            return {
                                "<": "&lt;",
                                "&": "&amp;",
                                '"': "&quot;",
                                "“": "&ldquo;",
                                "”": "&rdquo;",
                                ">": "&gt;",
                                "'": "&#39;"
                            }[a];
                        }
                    }
                )
                : "";
        },

        /**
         * 将str中的转义字符还原成html字符
         * @see UE.utils.unhtml(String);
         * @method html
         * @param { String } str 需要逆转义的字符串
         * @return { String } 逆转义后的字符串
         * @example
         * ```javascript
         *
         * var str = '&lt;body&gt;&amp;&lt;/body&gt;';
         *
         * //output: <body>&</body>
         * console.log( UE.utils.html( str ) );
         *
         * ```
         */
        html: function (str) {
            return str
                ? str.replace(/&((g|l|quo|ldquo|rdquo)t|amp|#39|nbsp);/g, function (m) {
                    return {
                        "&lt;": "<",
                        "&amp;": "&",
                        "&quot;": '"',
                        "&ldquo;": "“",
                        "&rdquo;": "”",
                        "&gt;": ">",
                        "&#39;": "'",
                        "&nbsp;": " "
                    }[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(" ") + " ></" + obj.tag + ">"
                    );
                    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 neditor.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(
                _({
                    mark: 1,
                    b: 1,
                    acronym: 1,
                    bdo: 1,
                    var: 1,
                    "#": 1,
                    abbr: 1,
                    code: 1,
                    br: 1,
                    i: 1,
                    cite: 1,
                    kbd: 1,
                    u: 1,
                    strike: 1,
                    s: 1,
                    tt: 1,
                    strong: 1,
                    q: 1,
                    samp: 1,
                    em: 1,
                    dfn: 1,
                    span: 1
                }),
                F
            ),
            H = X(
                _({
                    sub: 1,
                    img: 1,
                    embed: 1,
                    object: 1,
                    sup: 1,
                    basefont: 1,
                    map: 1,
                    applet: 1,
                    font: 1,
                    big: 1,
                    small: 1
                }),
                G
            ),
            I = X(_({p: 1}), H),
            J = X(_({iframe: 1}), H, B),
            K = _({
                img: 1,
                embed: 1,
                noscript: 1,
                br: 1,
                kbd: 1,
                center: 1,
                button: 1,
                basefont: 1,
                h5: 1,
                h4: 1,
                samp: 1,
                h6: 1,
                ol: 1,
                h1: 1,
                h3: 1,
                h2: 1,
                form: 1,
                font: 1,
                "#": 1,
                select: 1,
                menu: 1,
                ins: 1,
                abbr: 1,
                label: 1,
                code: 1,
                table: 1,
                script: 1,
                cite: 1,
                input: 1,
                iframe: 1,
                strong: 1,
                textarea: 1,
                noframes: 1,
                big: 1,
                small: 1,
                span: 1,
                hr: 1,
                sub: 1,
                bdo: 1,
                var: 1,
                div: 1,
                object: 1,
                sup: 1,
                strike: 1,
                dir: 1,
                map: 1,
                dl: 1,
                applet: 1,
                del: 1,
                isindex: 1,
                fieldset: 1,
                ul: 1,
                b: 1,
                acronym: 1,
                a: 1,
                blockquote: 1,
                i: 1,
                u: 1,
                s: 1,
                tt: 1,
                address: 1,
                q: 1,
                pre: 1,
                p: 1,
                em: 1,
                dfn: 1
            }),
            L = X(_({a: 0}), J), //a不能被切开,所以把他
            M = _({tr: 1}),
            N = _({"#": 1}),
            O = X(_({param: 1}), K),
            P = X(_({form: 1}), A, D, E, I),
            Q = _({li: 1, 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,
                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
            });

        return _({
            // $ 表示自定的属性

            // 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,
                textarea: 1,
                link: 1,
                meta: 1,
                param: 1,
                h1: 1,
                h2: 1,
                h3: 1,
                h4: 1,
                h5: 1,
                h6: 1
            }),

            //如果没有子节点就可以删除的元素列表,像span,a
            $removeEmpty: _({
                a: 1,
                abbr: 1,
                acronym: 1,
                address: 1,
                b: 1,
                bdo: 1,
                big: 1,
                cite: 1,
                code: 1,
                del: 1,
                dfn: 1,
                em: 1,
                font: 1,
                i: 1,
                ins: 1,
                label: 1,
                kbd: 1,
                q: 1,
                s: 1,
                samp: 1,
                small: 1,
                span: 1,
                strike: 1,
                strong: 1,
                sub: 1,
                sup: 1,
                tt: 1,
                u: 1,
                var: 1
            }),

            $removeEmptyBlock: _({p: 1, div: 1}),

            //在table元素里的元素列表
            $tableContent: _({
                caption: 1,
                col: 1,
                colgroup: 1,
                tbody: 1,
                td: 1,
                tfoot: 1,
                th: 1,
                thead: 1,
                tr: 1,
                table: 1
            }),
            //不转换的标签
            $notTransContent: _({pre: 1, script: 1, style: 1, textarea: 1}),
            html: U,
            head: T,
            style: N,
            script: N,
            body: P,
            base: {},
            link: {},
            meta: {},
            title: N,
            col: {},
            tr: _({td: 1, th: 1}),
            img: {},
            embed: {},
            colgroup: _({thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1}),
            noscript: P,
            td: P,
            br: {},
            th: P,
            center: P,
            kbd: L,
            button: X(I, E),
            basefont: {},
            h5: L,
            h4: L,
            samp: L,
            h6: L,
            ol: Q,
            h1: L,
            h3: L,
            option: N,
            h2: L,
            form: X(A, D, E, I),
            select: _({optgroup: 1, option: 1}),
            font: L,
            ins: L,
            menu: Q,
            abbr: L,
            label: L,
            table: _({
                thead: 1,
                col: 1,
                tbody: 1,
                tr: 1,
                colgroup: 1,
                caption: 1,
                tfoot: 1
            }),
            code: L,
            tfoot: M,
            cite: L,
            li: P,
            input: {},
            iframe: P,
            strong: L,
            textarea: N,
            noframes: P,
            big: L,
            small: L,
            //trace:
            span: _({
                "#": 1,
                br: 1,
                b: 1,
                strong: 1,
                u: 1,
                i: 1,
                em: 1,
                sub: 1,
                sup: 1,
                strike: 1,
                span: 1
            }),
            hr: L,
            dt: L,
            sub: L,
            optgroup: _({option: 1}),
            param: {},
            bdo: L,
            var: L,
            div: P,
            object: O,
            sup: L,
            dd: P,
            strike: L,
            area: {},
            dir: Q,
            map: X(_({area: 1, form: 1, p: 1}), A, F, E),
            applet: O,
            dl: _({dt: 1, dd: 1}),
            del: L,
            isindex: {},
            fieldset: X(_({legend: 1}), K),
            thead: M,
            ul: Q,
            acronym: L,
            b: L,
            a: X(_({a: 1}), J),
            blockquote: X(_({td: 1, tr: 1, tbody: 1, li: 1}), P),
            caption: L,
            i: L,
            u: L,
            tbody: M,
            s: L,
            address: X(D, I),
            tt: L,
            legend: L,
            q: L,
            pre: X(G, C),
            p: X(_({a: 1}), L),
            em: L,
            dfn: L,
            mark: 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
         * <body>
         *
         *      <div id="test">
         *      </div>
         *
         *      <script type="text/javascript">
         *
         *          //output: DIV, BODY
         *          var filterNode = UE.dom.domUtils.findParent( document.getElementById( "test" ), function ( node ) {
     *
     *              console.log( node.tagName );
     *              return false;
     *
     *          }, true );
         *
         *      </script>
         * </body>
         * ```
         */
        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
         * <div id="test">
         *     <div id="child">你好</div>
         * </div>
         * <script>
         *     UE.dom.domUtils.remove( document.body, false );
         *     //output: false
         *     console.log( document.getElementById( "child" ) !== null );
         * </script>
         * ```
         */

        /**
         * 删除节点node,并根据keepChildren的值决定是否保留子节点
         * @method remove
         * @param { Node } node 需要删除的节点对象
         * @param { Boolean } keepChildren 是否需要保留子节点
         * @return { Node } 返回刚删除的节点对象
         * @example
         * ```html
         * <div id="test">
         *     <div id="child">你好</div>
         * </div>
         * <script>
         *     UE.dom.domUtils.remove( document.body, true );
         *     //output: true
         *     console.log( document.getElementById( "child" ) !== null );
         * </script>
         * ```
         */
        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
         *     <body>
         *      <div id="test">
         *          <span></span>
         *      </div>
         *      <i>xxx</i>
         * </body>
         * <script>
         *
         *     //output: i节点
         *     console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
         *
         * </script>
         * ```
         * @example
         * ```html
         * <body>
         *      <div>
         *          <span></span>
         *          <i id="test">xxx</i>
         *      </div>
         *      <b>xxx</b>
         * </body>
         * <script>
         *
         *     //由于id为test的i节点之后没有兄弟节点, 则查找其父节点(div)后面的兄弟节点
         *     //output: b节点
         *     console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
         *
         * </script>
         * ```
         */

        /**
         * 取得node节点的下一个兄弟节点, 如果startFromChild的值为ture,则先获取其子节点,
         * 如果有子节点则直接返回第一个子节点;如果没有子节点或者startFromChild的值为false,
         * 则执行<a href="#UE.dom.domUtils.getNextDomNode(Node)">getNextDomNode(Node node)</a>的查找过程。
         * @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
         * <span id="_baidu_bookmark_1"></span>
         * <script>
         *      var bookmarkNode = document.getElementById("_baidu_bookmark_1");
         *      //output: true
         *      console.log( UE.dom.domUtils.isBookmarkNode( bookmarkNode ) );
         * </script>
         * ```
         */
        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
         * <body>
         *     <div></div>
         *     <span id="test"></span>
         *     <i></i>
         *     <b></b>
         *     <em>xxx</em>
         *     <span></span>
         * </body>
         * <script>
         *
         *      UE.dom.domUtils.clearEmptySibling( document.getElementById( "test" ) );
         *
         *      //output: <div></div><span id="test"></span><em>xxx</em><span></span>
         *      console.log( document.body.innerHTML );
         *
         * </script>
         * ```
         */

        /**
         * 清除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
         * <div id="test">abcdef</div>
         * <script>
         *      var newNode = UE.dom.domUtils.split( document.getElementById( "test" ).firstChild, 3 );
         *      //output: def
         *      console.log( newNode.nodeValue );
         * </script>
         * ```
         */
        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
         * <div id="test">
         *
         * </div>
         * <script>
         *      //output: true
         *      console.log( UE.dom.domUtils.isWhitespace( document.getElementById("test").firstChild ) );
         * </script>
         * ```
         */
        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
         * <span style="font-size:12px">ssss</span>
         * <span style="font-size:12px">bbbbb</span>
         * <span style="font-size:13px">ssss</span>
         * <span style="font-size:14px">bbbbb</span>
         *
         * <script>
         *
         *     var nodes = document.getElementsByTagName( "span" );
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.isSameElement( nodes[0], nodes[1] ) );
         *
         *     //output: false
         *     console.log( UE.dom.domUtils.isSameElement( nodes[2], nodes[3] ) );
         *
         * </script>
         * ```
         */
        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
         * <span style="font-size:12px">ssss</span>
         * <span style="font-size:12px">bbbbb</span>
         * <span style="font-size:13px">ssss</span>
         * <span style="font-size:14px">bbbbb</span>
         *
         * <script>
         *
         *     var nodes = document.getElementsByTagName( "span" );
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.isSameStyle( nodes[0], nodes[1] ) );
         *
         *     //output: false
         *     console.log( UE.dom.domUtils.isSameStyle( nodes[2], nodes[3] ) );
         *
         * </script>
         * ```
         */
        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
         * <span id="test1" style="display: block"></span>
         * <span id="test2"></span>
         * <div id="test3" style="display: inline"></div>
         *
         * <script>
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test1") ) );
         *
         *     //output: false
         *     console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test2") ) );
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test3") ) );
         *
         * </script>
         * ```
         */
        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";
        },
        /**
         * 以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: <p><span></span></p>
         *      console.log( wrapNode.innerHTML );
         *
         *
         *      UE.dom.domUtils.breakParent( node, parent );
         *      //拆分后
         *      //output: <p></p><span></span><p></p>
         *      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);
            domUtils.remove(parent);
            return node;
        },
        /**
         * 检查节点node是否是空inline节点
         * @method  isEmptyInlineElement
         * @param { Node } node 需要检测的节点对象
         * @return { Number }  如果给定的节点是空的inline节点, 则返回1, 否则返回0。
         * @example
         * ```html
         * <b><i></i></b> => 1
         * <b><i></i><u></u></b> => 1
         * <b></b> => 1
         * <b>xx<i></i></b> => 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
         * <p><span style="font-size:12px;">xx<span style="font-size:12px;">aa</span>xx</span></p>
         * ==> UE.dom.domUtils.mergeChild(node,'span')
         * <p><span style="font-size:12px;">xxaaxx</span></p>
         */
        mergeChild: function (node, tagName, attrs) {
            var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase());
            for (var i = 0, ci; (ci = list[i++]);) {
                if (!ci.parentNode || domUtils.isBookmarkNode(ci)) {
                    continue;
                }
                //span单独处理
                if (ci.tagName.toLowerCase() == "span") {
                    if (node === ci.parentNode) {
                        domUtils.trimWhiteTextNode(node);
                        if (node.childNodes.length == 1) {
                            node.style.cssText = ci.style.cssText + ";" + node.style.cssText;
                            domUtils.remove(ci, true);
                            continue;
                        }
                    }
                    ci.style.cssText = node.style.cssText + ";" + ci.style.cssText;
                    if (attrs) {
                        var style = attrs.style;
                        if (style) {
                            style = style.split(";");
                            for (var j = 0, s; (s = style[j++]);) {
                                ci.style[utils.cssStyleToDomStyle(s.split(":")[0])] = s.split(
                                    ":"
                                )[1];
                            }
                        }
                    }
                    if (domUtils.isSameStyle(ci, node)) {
                        domUtils.remove(ci, true);
                    }
                    continue;
                }
                if (domUtils.isSameElement(node, ci)) {
                    domUtils.remove(ci, true);
                }
            }
        },

        /**
         * 原生方法getElementsByTagName的封装
         * @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
         * <div id="parent">
         *     <div id="sub">
         *         <span id="child"></span>
         *     </div>
         * </div>
         *
         * <script>
         *
         *     var child = document.getElementById( "child" );
         *
         *     //output: sub
         *     console.log( child.parentNode.id );
         *
         *     UE.dom.domUtils.mergeToParent( child );
         *
         *     //output: parent
         *     console.log( child.parentNode.id );
         *
         * </script>
         * ```
         */
        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需要特殊处理  不处理这样的情况 <span stlye="color:#fff">xxx<span style="color:#ccc">xxx</span>xxx</span>
                    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
         * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
         *
         * <script>
         *     var demoNode = document.getElementById("test");
         *     UE.dom.domUtils.mergeSibling( demoNode );
         *     //output: xxxxoooxxxx
         *     console.log( demoNode.innerHTML );
         * </script>
         * ```
         */

        /**
         * 合并节点node的左右兄弟节点, 可以根据给定的条件选择是否忽略合并左节点。
         * @method mergeSibling
         * @param { Element } node 需要合并的目标节点
         * @param { Boolean } ignorePre 是否忽略合并左节点
         * @example
         * ```html
         * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
         *
         * <script>
         *     var demoNode = document.getElementById("test");
         *     UE.dom.domUtils.mergeSibling( demoNode, true );
         *     //output: oooxxxx
         *     console.log( demoNode.innerHTML );
         * </script>
         * ```
         */

        /**
         * 合并节点node的左右兄弟节点,可以根据给定的条件选择是否忽略合并左右节点。
         * @method mergeSibling
         * @param { Element } node 需要合并的目标节点
         * @param { Boolean } ignorePre 是否忽略合并左节点
         * @param { Boolean } ignoreNext 是否忽略合并右节点
         * @remind 如果同时忽略左右节点, 则该操作什么也不会做
         * @example
         * ```html
         * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
         *
         * <script>
         *     var demoNode = document.getElementById("test");
         *     UE.dom.domUtils.mergeSibling( demoNode, false, true );
         *     //output: xxxxooo
         *     console.log( demoNode.innerHTML );
         * </script>
         * ```
         */
        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
         * <div id="wrap">
         *      <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
         * </div>
         *
         * <script>
         *
         *     UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), "id name" );
         *
         *     //output: <span style="font-size:14px;">xxxxx</span>
         *     console.log( document.getElementById("wrap").innerHTML );
         *
         * </script>
         * ```
         */

        /**
         * 删除节点node上的指定属性名称的属性
         * @method  removeAttributes
         * @param { Node } node 需要删除属性的节点对象
         * @param { Array } attrNames 需要删除的属性名数组
         * @example
         * ```html
         * <div id="wrap">
         *      <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
         * </div>
         *
         * <script>
         *
         *     UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), ["id", "name"] );
         *
         *     //output: <span style="font-size:14px;">xxxxx</span>
         *     console.log( document.getElementById("wrap").innerHTML );
         *
         * </script>
         * ```
         */
        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
         * <span id="test"></span>
         *
         * <script>
         *
         *     var testNode = UE.dom.domUtils.setAttributes( document.getElementById( "test" ), {
     *         id: 'demo'
     *     } );
         *
         *     //output: demo
         *     console.log( testNode.id );
         *
         * </script>
         *
         */
        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
         * <style type="text/css">
         *      #test {
     *          font-size: 15px;
     *      }
         * </style>
         *
         * <span id="test"></span>
         *
         * <script>
         *     //output: 15px
         *     console.log( UE.dom.domUtils.getComputedStyle( document.getElementById( "test" ), 'font-size' ) );
         * </script>
         * ```
         */
        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
         * <span id="test" class="test1 test2 test3">xxx</span>
         *
         * <script>
         *
         *     var testNode = document.getElementById( "test" );
         *     UE.dom.domUtils.removeClasses( testNode, "test1 test2" );
         *
         *     //output: test3
         *     console.log( testNode.className );
         *
         * </script>
         * ```
         */

        /**
         * 删除元素element指定的className
         * @method removeClasses
         * @param { Element } ele 需要删除class的元素节点
         * @param { Array } classNames 需要删除的className数组
         * @example
         * ```html
         * <span id="test" class="test1 test2 test3">xxx</span>
         *
         * <script>
         *
         *     var testNode = document.getElementById( "test" );
         *     UE.dom.domUtils.removeClasses( testNode, ["test1", "test2"] );
         *
         *     //output: test3
         *     console.log( testNode.className );
         *
         * </script>
         * ```
         */
        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
         * <span id="test" class="cls1 cls2"></span>
         *
         * <script>
         *     var testNode = document.getElementById("test");
         *
         *     UE.dom.domUtils.addClass( testNode, "cls2 cls3 cls4" );
         *
         *     //output: cl1 cls2 cls3 cls4
         *     console.log( testNode.className );
         *
         * <script>
         * ```
         */

        /**
         * 给元素element添加className
         * @method addClass
         * @param { Node } ele 需要增加className的元素
         * @param { Array } classNames 需要添加的className的数组
         * @remind 相同的类名不会被重复添加
         * @example
         * ```html
         * <span id="test" class="cls1 cls2"></span>
         *
         * <script>
         *     var testNode = document.getElementById("test");
         *
         *     UE.dom.domUtils.addClass( testNode, ["cls2", "cls3", "cls4"] );
         *
         *     //output: cl1 cls2 cls3 cls4
         *     console.log( testNode.className );
         *
         * <script>
         * ```
         */
        addClass: function (elm, classNames) {
            if (!elm) return;
            classNames = utils.trim(classNames).replace(/[ ]{2,}/g, " ").split(" ");
            for (var i = 0, ci, cls = elm.className; (ci = classNames[i++]);) {
                if (!new RegExp("\\b" + ci + "\\b").test(cls)) {
                    cls += " " + ci;
                }
            }
            elm.className = utils.trim(cls);
        },
        /**
         * 判断元素element是否包含给定的样式类名className
         * @method hasClass
         * @param { Node } ele 需要检测的元素
         * @param { String } classNames 需要检测的className, 多个className之间用空格分割
         * @return { Boolean } 元素是否包含所有给定的className
         * @example
         * ```html
         * <span id="test1" class="cls1 cls2"></span>
         *
         * <script>
         *     var test1 = document.getElementById("test1");
         *
         *     //output: false
         *     console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1 cls3" ) );
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1" ) );
         * </script>
         * ```
         */

        /**
         * 判断元素element是否包含给定的样式类名className
         * @method hasClass
         * @param { Node } ele 需要检测的元素
         * @param { Array } classNames 需要检测的className数组
         * @return { Boolean } 元素是否包含所有给定的className
         * @example
         * ```html
         * <span id="test1" class="cls1 cls2"></span>
         *
         * <script>
         *     var test1 = document.getElementById("test1");
         *
         *     //output: false
         *     console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1", "cls3" ] ) );
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1" ]) );
         * </script>
         * ```
         */
        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
         * <span id="test" style="color: red; background: blue;"></span>
         *
         * <script>
         *
         *     var testNode = document.getElementById("test");
         *
         *     UE.dom.domUtils.removeStyle( testNode, 'color' );
         *
         *     //output: background: blue;
         *     console.log( testNode.style.cssText );
         *
         * </script>
         * ```
         */
        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
         * <div id="test" style="color: red;"></div>
         *
         * <script>
         *
         *      var testNode = document.getElementById( "test" );
         *
         *      //output: red
         *      console.log( UE.dom.domUtils.getStyle( testNode, "color" ) );
         *
         *      //output: ""
         *      console.log( UE.dom.domUtils.getStyle( testNode, "background" ) );
         *
         * </script>
         * ```
         */
        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
         * <div id="test"></div>
         *
         * <script>
         *
         *      var testNode = document.getElementById( "test" );
         *
         *      //output: ""
         *      console.log( testNode.style.color );
         *
         *      UE.dom.domUtils.setStyle( testNode, 'color', 'red' );
         *      //output: "red"
         *      console.log( testNode.style.color );
         *
         * </script>
         * ```
         */
        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
         * <div id="test"></div>
         *
         * <script>
         *
         *      var testNode = document.getElementById( "test" );
         *
         *      //output: ""
         *      console.log( testNode.style.color );
         *
         *      UE.dom.domUtils.setStyles( testNode, {
     *          'color': 'red'
     *      } );
         *      //output: "red"
         *      console.log( testNode.style.color );
         *
         * </script>
         * ```
         */
        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
         * <div id="test">
         *      <span></span>
         * </div>
         *
         * <script>
         *
         *     //output: 3
         *     console.log( UE.dom.domUtils.getChildCount( document.getElementById("test") ) );
         *
         * </script>
         * ```
         */

        /**
         * 根据给定的过滤规则, 获取符合条件的子节点的数量
         * @method getChildCount
         * @param { Element } node 需要检测的元素
         * @param { Function } fn 过滤器, 要求对符合条件的子节点返回true, 反之则要求返回false
         * @return { Number } 符合过滤条件的node元素的子节点数量
         * @example
         * ```html
         * <div id="test">
         *      <span></span>
         * </div>
         *
         * <script>
         *
         *     //output: 1
         *     console.log( UE.dom.domUtils.getChildCount( document.getElementById("test"), function ( node ) {
     *
     *         return node.nodeType === 1;
     *
     *     } ) );
         *
         * </script>
         * ```
         */
        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
            );
        },
        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;
            offset += node.offsetHeight || 0;
            var elementPosition = domUtils.getXY(node);
            offset += elementPosition.y;
            var currentScroll = getScrollPosition(win).y;
            // offset += 50;
            if (offset > currentScroll || offset < currentScroll - winHeight) {
                win.scrollTo(0, offset + (offset < 0 ? -20 : 20));
            }
        },
        /**
         * 判断给定节点是否为br
         * @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;
        },
        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
         * <div id="test"></div>
         *
         * <script>
         *     //output: true
         *     console.log( UE.dom.domUtils.isEmptyBlock( document.getElementById("test") ) );
         * </script>
         * ```
         */

        /**
         * 根据指定的判断规则判断给定的元素是否是一个空元素
         * @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
         * <div id="test" style="top: 100px; left: 50px; position: absolute;"></div>
         *
         * <script>
         *
         *     var testNode = document.getElementById("test");
         *
         *     UE.dom.domUtils.setViewportOffset( testNode, {
     *         left: 200,
     *         top: 50
     *     } );
         *
         *     //output: top: 300px; left: 100px; position: absolute;
         *     console.log( testNode.style.cssText );
         *
         * </script>
         * ```
         */
        setViewportOffset: function (element, offset) {
            var left = parseInt(element.style.left) | 0;
            var top = parseInt(element.style.top) | 0;
            var rect = element.getBoundingClientRect();
            var offsetLeft = offset.left - rect.left;
            var offsetTop = offset.top - rect.top;
            if (offsetLeft) {
                element.style.left = left + offsetLeft + "px";
            }
            if (offsetTop) {
                element.style.top = top + offsetTop + "px";
            }
        },

        /**
         * 用“填充字符”填充节点
         * @method fillNode
         * @private
         * @param { DomDocument } doc 填充的节点所在的docment对象
         * @param { Node } node 需要填充的节点对象
         * @example
         * ```html
         * <div id="test"></div>
         *
         * <script>
         *     var testNode = document.getElementById("test");
         *
         *     //output: 0
         *     console.log( testNode.childNodes.length );
         *
         *     UE.dom.domUtils.fillNode( document, testNode );
         *
         *     //output: 1
         *     console.log( testNode.childNodes.length );
         *
         * </script>
         * ```
         */
        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
         * <div id="test1">
         *      <span></span>
         * </div>
         * <div id="test2">
         *     <div></div>
         * </div>
         *
         * <script>
         *
         *     var test1 = document.getElementById("test1"),
         *         test2 = document.getElementById("test2");
         *
         *     UE.dom.domUtils.moveChild( test1, test2 );
         *
         *     //output: ""(空字符串)
         *     console.log( test1.innerHTML );
         *
         *     //output: "<div></div><span></span>"
         *     console.log( test2.innerHTML );
         *
         * </script>
         * ```
         */

        /**
         * 把节点src的所有子节点移动到另一个节点tag上去, 可以通过dir参数控制附加的行为是“追加”还是“插入顶部”
         * @method moveChild
         * @param { Node } src 源节点, 该节点下的所有子节点将被移除
         * @param { Node } tag 目标节点, 从源节点移除的子节点将被附加到该节点下
         * @param { Boolean } dir 附加方式, 如果为true, 则附加进去的节点将被放到目标节点的顶部, 反之,则放到末尾
         * @example
         * ```html
         * <div id="test1">
         *      <span></span>
         * </div>
         * <div id="test2">
         *     <div></div>
         * </div>
         *
         * <script>
         *
         *     var test1 = document.getElementById("test1"),
         *         test2 = document.getElementById("test2");
         *
         *     UE.dom.domUtils.moveChild( test1, test2, true );
         *
         *     //output: ""(空字符串)
         *     console.log( test1.innerHTML );
         *
         *     //output: "<span></span><div></div>"
         *     console.log( test2.innerHTML );
         *
         * </script>
         * ```
         */
        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
         * <div id="test"><span>xxxx</span></div>
         *
         * <script>
         *
         *     //output: false
         *     console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test") ) );
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test").firstChild ) );
         *
         * </script>
         * ```
         */
        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
         * <div id="test"></div>
         *
         * <script>
         *
         *     //output: true
         *     console.log( UE.dom.domUtils.isTagNode( document.getElementById("test"), "div" ) );
         *
         * </script>
         * ```
         */
        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) {
                return 0;
            }
            while (start !== node) {
                if (start.nextSibling) {
                    return 0;
                }
                start = start.parentNode;
            }
            return 1;
        },
        isBoundaryNode: function (node, dir) {
            var tmp;
            while (!domUtils.isBody(node)) {
                tmp = node;
                node = node.parentNode;
                if (tmp !== node[dir]) {
                    return false;
                }
            }
            return true;
        },
        fillHtml: browser.ie11below ? "&nbsp;" : "<br/>"
    });
    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.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
             * <body>
             *      <!-- 中括号表示选区 -->
             *      <b>x<i>x[x</i>xx]x</b>
             *
             *      <script>
             *          //range是已选中的选区
             *          var fragment = range.cloneContents(),
             *              node = document.createElement("div");
             *
             *          node.appendChild( fragment );
             *
             *          //output: <i>x</i>xx
             *          console.log( node.innerHTML );
             *
             *      </script>
             * </body>
             * ```
             */
            cloneContents: function () {
                return this.collapsed ? null : execContentsAction(this, 0);
            },

            /**
             * 删除当前选区范围中的所有内容
             * @method deleteContents
             * @remind 执行完该操作后, 当前Range对象变成了闭合状态
             * @return { UE.dom.Range } 当前操作的Range对象
             * @example
             * ```html
             * <body>
             *      <!-- 中括号表示选区 -->
             *      <b>x<i>x[x</i>xx]x</b>
             *
             *      <script>
             *          //range是已选中的选区
             *          range.deleteContents();
             *
             *          //竖线表示闭合后的选区位置
             *          //output: <b>x<i>x</i>|x</b>
             *          console.log( document.body.innerHTML );
             *
             *          //此时, range的各项属性为
             *          //output: B
             *          console.log( range.startContainer.tagName );
             *          //output: 2
             *          console.log( range.startOffset );
             *          //output: B
             *          console.log( range.endContainer.tagName );
             *          //output: 2
             *          console.log( range.endOffset );
             *          //output: true
             *          console.log( range.collapsed );
             *
             *      </script>
             * </body>
             * ```
             */
            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
             * <body>
             *      <!-- 中括号表示选区 -->
             *      <b>x<i>x[x</i>xx]x</b>
             *
             *      <script>
             *          //range是已选中的选区
             *          var fragment = range.extractContents(),
             *              node = document.createElement( "div" );
             *
             *          node.appendChild( fragment );
             *
             *          //竖线表示闭合后的选区位置
             *
             *          //output: <b>x<i>x</i>|x</b>
             *          console.log( document.body.innerHTML );
             *          //output: <i>x</i>xx
             *          console.log( node.innerHTML );
             *
             *          //此时, range的各项属性为
             *          //output: B
             *          console.log( range.startContainer.tagName );
             *          //output: 2
             *          console.log( range.startOffset );
             *          //output: B
             *          console.log( range.endContainer.tagName );
             *          //output: 2
             *          console.log( range.endOffset );
             *          //output: true
             *          console.log( range.collapsed );
             *
             *      </script>
             * </body>
             */
            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
             * <!-- 选区 -->
             * <b>xxx<i>x<span>xx</span>xx<em>xx</em>xxx</i>[xxx]</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.setStart( document.getElementsByTagName("i")[0], 1 );
             *
             *     //此时, 选区变成了
             *     //<b>xxx<i>x[<span>xx</span>xx<em>xx</em>xxx</i>xxx]</b>
             *
             * </script>
             * ```
             * @example
             * ```html
             * <!-- 选区 -->
             * <b>xxx<img>[xx]x</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.setStart( document.getElementsByTagName("img")[0], 3 );
             *
             *     //此时, 选区变成了
             *     //<b>xxx[<img>xx]x</b>
             *
             * </script>
             * ```
             */
            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
             * <!-- 选区示例 -->
             * <b>xx<i>xxx</i><span>xx[x</span>xxx]</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.setStartAfter( document.getElementsByTagName("i")[0] );
             *
             *     //结果选区
             *     //<b>xx<i>xxx</i>[<span>xxx</span>xxx]</b>
             *
             * </script>
             * ```
             */
            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
             * <!-- 选区示例 -->
             * <b>[xx<i>xxx</i><span>xx]x</span>xxx</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.setStartAfter( document.getElementsByTagName("span")[0] );
             *
             *     //结果选区
             *     //<b>[xx<i>xxx</i><span>xxx</span>]xxx</b>
             *
             * </script>
             * ```
             */
            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
             * <!-- 选区示例 -->
             * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.setStartAtFirst( document.getElementsByTagName("i")[0] );
             *
             *     //结果选区
             *     //<b>xx<i>[xxx</i><span>xx]x</span>xxx</b>
             *
             * </script>
             * ```
             */
            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
             * <!-- 选区示例 -->
             * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.selectNode( document.getElementsByTagName("i")[0] );
             *
             *     //结果选区
             *     //<b>xx[<i>xxx</i>]<span>xxx</span>xxx</b>
             *
             * </script>
             * ```
             */
            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
             * <!-- 选区示例 -->
             * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.selectNode( document.getElementsByTagName("b")[0] );
             *
             *     //结果选区
             *     //<b>[xx<i>xxx</i><span>xxx</span>xxx]</b>
             *
             * </script>
             * ```
             */
            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
             * <!-- 选区示例 -->
             * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.collapse();
             *
             *     //结果选区
             *     //“|”表示选区已闭合
             *     //<b>xx<i>xxx</i><span>xx|x</span>xxx</b>
             *
             * </script>
             * ```
             */

            /**
             * 闭合当前选区,根据给定的toStart参数项决定是向当前选区开始处闭合还是向结束处闭合,
             * 如果toStart的值为true,则向开始位置闭合, 反之,向结束位置闭合。
             * @method  collapse
             * @param { Boolean } toStart 是否向选区开始处闭合
             * @return { UE.dom.Range } 当前range对象,此时range对象处于闭合状态
             * @see UE.dom.Range:collapse()
             * @example
             * ```html
             * <!-- 选区示例 -->
             * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
             *
             * <script>
             *
             *     //执行操作
             *     range.collapse( true );
             *
             *     //结果选区
             *     //“|”表示选区已闭合
             *     //<b>xx<i>xxx</i><span>|xxx</span>xxx</b>
             *
             * </script>
             * ```
             */
            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
             * <span>xx<b>xx[</b>xxxxx]</span> => <span>xx<b>xx</b>[xxxxx]</span>
             * ```
             *
             * @example
             * ```html
             * <!-- 选区示例 -->
             * <b>x[xx</b><i>]xxx</i>
             *
             * <script>
             *
             *     //执行收缩
             *     range.shrinkBoundary();
             *
             *     //结果选区
             *     //<b>x[xx]</b><i>xxx</i>
             * </script>
             * ```
             *
             * @example
             * ```html
             * [<b><i>xxxx</i>xxxxxxx</b>] => <b><i>[xxxx</i>xxxxxxx]</b>
             * ```
             */

            /**
             * 调整range的开始位置和结束位置,使其"收缩"到最小的位置,
             * 如果ignoreEnd的值为true,则忽略对结束位置的调整
             * @method  shrinkBoundary
             * @param { Boolean } ignoreEnd 是否忽略对结束位置的调整
             * @return { UE.dom.Range } 当前range对象
             * @see UE.dom.domUtils.Range:shrinkBoundary()
             */
            shrinkBoundary: function (ignoreEnd) {
                var me = this,
                    child,
                    collapsed = me.collapsed;

                function check(node) {
                    return (
                        node.nodeType == 1 &&
                        !domUtils.isBookmarkNode(node) &&
                        !dtd.$empty[node.tagName] &&
                        !dtd.$nonChild[node.tagName]
                    );
                }

                while (
                    me.startContainer.nodeType == 1 && //是element
                    (child = me.startContainer.childNodes[me.startOffset]) && //子节点也是element
                    check(child)
                    ) {
                    me.setStart(child, 0);
                }
                if (collapsed) {
                    return me.collapse(true);
                }
                if (!ignoreEnd) {
                    while (
                        me.endContainer.nodeType == 1 && //是element
                        me.endOffset > 0 && //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
                        (child = me.endContainer.childNodes[me.endOffset - 1]) && //子节点也是element
                        check(child)
                        ) {
                        me.setEnd(child, child.childNodes.length);
                    }
                }
                return me;
            },

            /**
             * 获取离当前选区内包含的所有节点最近的公共祖先节点,
             * @method  getCommonAncestor
             * @remind 返回的公共祖先节点一定不是range自身的容器节点, 但有可能是一个文本节点
             * @return { Node } 当前range对象内所有节点的公共祖先节点
             * @example
             * ```html
             * //选区示例
             * <span>xxx<b>x[x<em>xx]x</em>xxx</b>xx</span>
             * <script>
             *
             *     var node = range.getCommonAncestor();
             *
             *     //公共祖先节点是: b节点
             *     //输出: B
             *     console.log(node.tagName);
             *
             * </script>
             * ```
             */

            /**
             * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
             * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
             * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点
             * @method  getCommonAncestor
             * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
             * @return { Node } 当前range对象内所有节点的公共祖先节点
             * @see UE.dom.Range:getCommonAncestor()
             * @example
             * ```html
             * <body>
             *
             *     <!-- 选区示例 -->
             *     <b>xxx<i>xxxx<span>xx[x</span>xx]x</i>xxxxxxx</b>
             *
             *     <script>
             *
             *         var node = range.getCommonAncestor( false );
             *
             *         //这里的公共祖先节点是B而不是I, 是因为参数限制了获取到的节点不能是容器节点
             *         //output: B
             *         console.log( node.tagName );
             *
             *     </script>
             *
             * </body>
             * ```
             */

            /**
             * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 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
             * <body>
             *
             *     <!-- 选区示例 -->
             *     <b>xxx<i>xxxx<span>x[x]x</span>xxx</i>xxxxxxx</b>
             *
             *     <script>
             *
             *         var node = range.getCommonAncestor( true, false );
             *
             *         //output: SPAN
             *         console.log( node.tagName );
             *
             *     </script>
             *
             * </body>
             * ```
             */
            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
             *
             * //选区示例
             * <b>xxx<i>[xxxxx]</i>xxx</b>
             *
             * <script>
             *     //未调整前, 选区的开始容器和结束都是文本节点
             *     //执行调整
             *     range.trimBoundary();
             *
             *     //调整之后, 容器节点变成了i节点
             *     //<b>xxx[<i>xxxxx</i>]xxx</b>
             * </script>
             * ```
             */

            /**
             * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上,
             * 可以根据 ignoreEnd 参数的值决定是否调整对结束边界的调整
             * @method trimBoundary
             * @param { Boolean } ignoreEnd 是否忽略对结束边界的调整
             * @return { UE.dom.Range } 当前range对象
             * @example
             * ```html
             *
             * //选区示例
             * <b>xxx<i>[xxxxx]</i>xxx</b>
             *
             * <script>
             *     //未调整前, 选区的开始容器和结束都是文本节点
             *     //执行调整
             *     range.trimBoundary( true );
             *
             *     //调整之后, 开始容器节点变成了i节点
             *     //但是, 结束容器没有发生变化
             *     //<b>xxx[<i>xxxxx]</i>xxx</b>
             * </script>
             * ```
             */
            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
             * <p>xxxx[xxxx]x</p>  ==>  range.applyInlineStyle("strong")  ==>  <p>xxxx[<strong>xxxx</strong>]x</p>
             * ```
             */

            /**
             * 给range选区中的内容添加给定的inline标签, 并且为标签附加上一些初始化属性。
             * @method applyInlineStyle
             * @param { String } tagName 需要添加的标签名
             * @param { Object } attrs 跟随新添加的标签的属性
             * @return { UE.dom.Range } 当前选区
             * @example
             * ```html
             * <p>xxxx[xxxx]x</p>
             *
             * ==>
             *
             * <!-- 执行操作 -->
             * range.applyInlineStyle("strong",{"style":"font-size:12px"})
             *
             * ==>
             *
             * <p>xxxx[<strong style="font-size:12px">xxxx</strong>]x</p>
             * ```
             */
            applyInlineStyle: function (tagName, attrs, list) {
                if (this.collapsed) return this;
                this.trimBoundary()
                    .enlarge(false, function (node) {
                        return node.nodeType == 1 && domUtils.isBlockElm(node);
                    })
                    .adjustmentBoundary();
                var bookmark = this.createBookmark(),
                    end = bookmark.end,
                    filterFn = function (node) {
                        return node.nodeType == 1
                            ? node.tagName.toLowerCase() != "br"
                            : !domUtils.isWhitespace(node);
                    },
                    current = domUtils.getNextDomNode(bookmark.start, false, filterFn),
                    node,
                    pre,
                    range = this.cloneRange();
                while (
                    current &&
                    domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING
                    ) {
                    if (current.nodeType == 3 || dtd[tagName][current.tagName]) {
                        range.setStartBefore(current);
                        node = current;
                        while (
                            node &&
                            (node.nodeType == 3 || dtd[tagName][node.tagName]) &&
                            node !== end
                            ) {
                            pre = node;
                            node = domUtils.getNextDomNode(
                                node,
                                node.nodeType == 1,
                                null,
                                function (parent) {
                                    return dtd[tagName][parent.tagName];
                                }
                            );
                        }
                        var frag = range.setEndAfter(pre).extractContents(),
                            elm;
                        if (list && list.length > 0) {
                            var level, top;
                            top = level = list[0].cloneNode(false);
                            for (var i = 1, ci; (ci = list[i++]);) {
                                level.appendChild(ci.cloneNode(false));
                                level = level.firstChild;
                            }
                            elm = level;
                        } else {
                            elm = range.document.createElement(tagName);
                        }
                        if (attrs) {
                            domUtils.setAttributes(elm, attrs);
                        }
                        elm.appendChild(frag);
                        //针对嵌套span的全局样式指定,做容错处理
                        if (elm.tagName == "SPAN" && attrs && attrs.style) {
                            utils.each(elm.getElementsByTagName("span"), function (s) {
                                s.style.cssText = s.style.cssText + ";" + attrs.style;
                            });
                        }
                        range.insertNode(list ? top : elm);
                        //处理下滑线在a上的情况
                        var aNode;
                        if (
                            tagName == "span" &&
                            attrs.style &&
                            /text\-decoration/.test(attrs.style) &&
                            (aNode = domUtils.findParentByTagName(elm, "a", true))
                        ) {
                            domUtils.setAttributes(aNode, attrs);
                            domUtils.remove(elm, true);
                            elm = aNode;
                        } else {
                            domUtils.mergeSibling(elm);
                            domUtils.clearEmptySibling(elm);
                        }
                        //去除子节点相同的
                        domUtils.mergeChild(elm, attrs);
                        current = domUtils.getNextDomNode(elm, false, filterFn);
                        domUtils.mergeToParent(elm);
                        if (node === end) {
                            break;
                        }
                    } else {
                        current = domUtils.getNextDomNode(current, true, filterFn);
                    }
                }
                return this.moveToBookmark(bookmark);
            },

            /**
             * 移除当前选区内指定的inline标签,但保留其中的内容
             * @method removeInlineStyle
             * @param { String } tagName 需要移除的标签名
             * @return { UE.dom.Range } 当前的range对象
             * @example
             * ```html
             * xx[x<span>xxx<em>yyy</em>zz]z</span>  => range.removeInlineStyle(["em"])  => xx[x<span>xxxyyyzz]z</span>
             * ```
             */

            /**
             * 移除当前选区内指定的一组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;
                }
                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) {
                            //使用<span>|x<span>固定住光标
                            var tmpText = this.document.createTextNode(fillChar),
                                tmp = this.document.createElement("span");
                            tmp.appendChild(this.document.createTextNode(fillChar));
                            start.parentNode.insertBefore(tmp, start);
                            start.parentNode.insertBefore(tmpText, start);
                            //当点b,i,u时,不能清除i上边的b
                            removeFillData(this.document, tmpText);
                            fillData = tmpText;
                            mergeSibling(tmp, "previousSibling");
                            mergeSibling(start, "nextSibling");
                            nativeRange.moveStart("character", -1);
                            nativeRange.collapse(true);
                        }
                    }
                    this.moveToBookmark(bookmark);
                    tmp && domUtils.remove(tmp);
                    //IE在隐藏状态下不支持range操作,catch一下
                    try {
                        nativeRange.select();
                    } catch (e) {
                    }
                    return this;
                }
                : function (notInsertFillData) {
                    function checkOffset(rng) {
                        function check(node, offset, dir) {
                            if (node.nodeType == 3 && node.nodeValue.length < offset) {
                                rng[dir + "Offset"] = node.nodeValue.length;
                            }
                        }

                        check(rng.startContainer, rng.startOffset, "start");
                        check(rng.endContainer, rng.endOffset, "end");
                    }

                    var win = domUtils.getWindow(this.document),
                        sel = win.getSelection(),
                        txtNode;
                    //FF下关闭自动长高时滚动条在关闭dialog时会跳
                    //ff下如果不body.focus将不能定位闭合光标到编辑器内
                    browser.gecko ? this.document.body.focus() : win.focus();
                    if (sel) {
                        sel.removeAllRanges();
                        // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
                        // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
                        if (this.collapsed && !notInsertFillData) {
                            //                    //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
                            //                    if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) {
                            //                        var tmp = this.document.createTextNode('');
                            //                        this.insertNode(tmp).setStart(tmp, 0).collapse(true);
                            //                    }
                            //
                            //处理光标落在文本节点的情况
                            //处理以下的情况
                            //<b>|xxxx</b>
                            //<b>xxxx</b>|xxxx
                            //xxxx<b>|</b>
                            var start = this.startContainer,
                                child = start;
                            if (start.nodeType == 1) {
                                child = start.childNodes[this.startOffset];
                            }
                            if (
                                !(start.nodeType == 3 && this.startOffset) &&
                                (child
                                    ? !child.previousSibling ||
                                    child.previousSibling.nodeType != 3
                                    : !start.lastChild || start.lastChild.nodeType != 3)
                            ) {
                                txtNode = this.document.createTextNode(fillChar);
                                //跟着前边走
                                this.insertNode(txtNode);
                                removeFillData(this.document, txtNode);
                                mergeSibling(txtNode, "previousSibling");
                                mergeSibling(txtNode, "nextSibling");
                                fillData = txtNode;
                                this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true);
                            }
                        }
                        var nativeRange = this.document.createRange();
                        if (
                            this.collapsed &&
                            browser.opera &&
                            this.startContainer.nodeType == 1
                        ) {
                            var child = this.startContainer.childNodes[this.startOffset];
                            if (!child) {
                                //往前靠拢
                                child = this.startContainer.lastChild;
                                if (child && domUtils.isBr(child)) {
                                    this.setStartBefore(child).collapse(true);
                                }
                            } else {
                                //向后靠拢
                                while (child && domUtils.isBlockElm(child)) {
                                    if (child.nodeType == 1 && child.childNodes[0]) {
                                        child = child.childNodes[0];
                                    } else {
                                        break;
                                    }
                                }
                                child && this.setStartBefore(child).collapse(true);
                            }
                        }
                        //是createAddress最后一位算的不准,现在这里进行微调
                        checkOffset(this);
                        nativeRange.setStart(this.startContainer, this.startOffset);
                        nativeRange.setEnd(this.endContainer, this.endOffset);
                        sel.addRange(nativeRange);
                    }
                    return this;
                },

            /**
             * 滚动到当前range开始的位置
             * @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 = "&nbsp;";
                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
             * <body>
             *     <p>
             *         aaaa
             *         <em>
             *             <!-- 选区开始 -->
             *             bbbb
             *             <!-- 选区结束 -->
             *         </em>
             *     </p>
             *
             *     <script>
             *         //output: {startAddress:[0,1,0,0],endAddress:[0,1,0,4]}
             *         console.log( range.createAddress() );
             *     </script>
             * </body>
             * ```
             */
            createAddress: function (ignoreEnd, ignoreTxt) {
                var addr = {},
                    me = this;

                function getAddress(isStart) {
                    var node = isStart ? me.startContainer : me.endContainer;
                    var parents = domUtils.findParents(node, true, function (node) {
                            return !domUtils.isBody(node);
                        }),
                        addrs = [];
                    for (var i = 0, ci; (ci = parents[i++]);) {
                        addrs.push(domUtils.getNodeIndex(ci, ignoreTxt));
                    }
                    var firstIndex = 0;

                    if (ignoreTxt) {
                        if (node.nodeType == 3) {
                            var tmpNode = node.previousSibling;
                            while (tmpNode && tmpNode.nodeType == 3) {
                                firstIndex += tmpNode.nodeValue.replace(fillCharReg, "").length;
                                tmpNode = tmpNode.previousSibling;
                            }
                            firstIndex += isStart ? me.startOffset : me.endOffset; // - (fillCharReg.test(node.nodeValue) ? 1 : 0 )
                        } else {
                            node = node.childNodes[isStart ? me.startOffset : me.endOffset];
                            if (node) {
                                firstIndex = domUtils.getNodeIndex(node, ignoreTxt);
                            } else {
                                node = isStart ? me.startContainer : me.endContainer;
                                var first = node.firstChild;
                                while (first) {
                                    if (domUtils.isFillChar(first)) {
                                        first = first.nextSibling;
                                        continue;
                                    }
                                    firstIndex++;
                                    if (first.nodeType == 3) {
                                        while (first && first.nodeType == 3) {
                                            first = first.nextSibling;
                                        }
                                    } else {
                                        first = first.nextSibling;
                                    }
                                }
                            }
                        }
                    } else {
                        firstIndex = isStart
                            ? 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();
                }
                return addr;
            },

            /**
             * 保存
             * @method createAddress
             * @private
             * @return { Boolean } 返回开始和结束的位置
             * @example
             * ```html
             * <body>
             *     <p>
             *         aaaa
             *         <em>
             *             <!-- 选区开始 -->
             *             bbbb
             *             <!-- 选区结束 -->
             *         </em>
             *     </p>
             *
             *     <script>
             *         var range = editor.selection.getRange();
             *         range.moveToAddress({startAddress:[0,1,0,0],endAddress:[0,1,0,4]});
             *         range.select();
             *         //output: 'bbbb'
             *         console.log(editor.selection.getText());
             *     </script>
             * </body>
             * ```
             */
            moveToAddress: function (addr, ignoreEnd) {
                var me = this;

                function getNode(address, isStart) {
                    var tmpNode = me.document.body,
                        parentNode,
                        offset;
                    for (var i = 0, ci, l = address.length; i < l; i++) {
                        ci = address[i];
                        parentNode = tmpNode;
                        tmpNode = tmpNode.childNodes[ci];
                        if (!tmpNode) {
                            offset = ci;
                            break;
                        }
                    }
                    if (isStart) {
                        if (tmpNode) {
                            me.setStartBefore(tmpNode);
                        } else {
                            me.setStart(parentNode, offset);
                        }
                    } else {
                        if (tmpNode) {
                            me.setEndBefore(tmpNode);
                        } else {
                            me.setEnd(parentNode, offset);
                        }
                    }
                }

                getNode(addr.startAddress, true);
                !ignoreEnd && addr.endAddress && getNode(addr.endAddress);
                return me;
            },

            /**
             * 判断给定的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
             *
             * <body>
             *
             *     <!-- 选区开始 -->
             *     <span></span>
             *     <a></a>
             *     <!-- 选区结束 -->
             * </body>
             *
             * <script>
             *
             *     //output: <span></span><a></a>
             *     console.log( range.cloneContents() );
             *
             *     range.traversal( function ( node ) {
         *
         *         if ( node.nodeType === 1 ) {
         *             node.className = "test";
         *         }
         *
         *     } );
             *
             *     //output: <span class="test"></span><a class="test"></a>
             *     console.log( range.cloneContents() );
             *
             * </script>
             * ```
             */

            /**
             * 遍历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
             *
             * <body>
             *
             *     <!-- 选区开始 -->
             *     <span></span>
             *     <a></a>
             *     <!-- 选区结束 -->
             * </body>
             *
             * <script>
             *
             *     //output: <span></span><a></a>
             *     console.log( range.cloneContents() );
             *
             *     range.traversal( function ( node ) {
         *
         *         node.className = "test";
         *
         *     }, function ( node ) {
         *          return node.nodeType === 1;
         *     } );
             *
             *     //output: <span class="test"></span><a class="test"></a>
             *     console.log( range.cloneContents() );
             *
             * </script>
             * ```
             */
            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下<b>x</b>[xx] 闭合后 <b>x|</b>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.options.textarea) {
                if (utils.isString(editor.options.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;
            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();

            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 () {
                        UE.plugin.load(me);
                        langReadied(me);
                    }
                );
            }

            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);
                }
            },
            /**
             * 该方法用于设置placeholder
             * @method setPlaceholder
             * @param { String } placeholder 编辑器的placeholder文案
             * @example
             * ```javascript
             * editor.setPlaceholder('请输入内容');
             * ```
             */
            setPlaceholder: function () {

                function contentChange() {
                    var localHtml = this.getPlainTxt();
                    if (!localHtml.trim()) {
                        UE.dom.domUtils.addClass(this.body, 'empty');
                    } else {
                        UE.dom.domUtils.removeClasses(this.body, 'empty');
                    }
                }

                return function (placeholder) {
                    var _editor = this;

                    _editor.ready(function () {
                        contentChange.call(_editor);
                        _editor.body.setAttribute('placeholder', placeholder);
                    });
                    _editor.removeListener('keyup contentchange', contentChange);
                    _editor.addListener('keyup contentchange', contentChange);
                }
            }(),

            /**
             * 该方法是提供给插件里面使用,设置配置项默认值
             * @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 html =
                        (ie && browser.version < 9 ? "" : "<!DOCTYPE html>") +
                        "<html xmlns='http://www.w3.org/1999/xhtml' class='view' >" +
                        "<head>" +
                        "<style type='text/css'>" +
                        //设置四周的留边
                        ".view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n" +
                        //设置默认字体和字号
                        //font-family不能呢随便改,在safari下fillchar会有解析问题
                        "body{margin:8px;font-family:sans-serif;font-size:16px;}" +
                        //设置placeholder
                        "body.empty:before{content:attr(placeholder);position:absolute;color:#999;}" +
                        //设置段落间距
                        "p{margin:5px 0;}</style>" +
                        (options.iframeCssUrl
                            ? "<link rel='stylesheet' type='text/css' href='" +
                            utils.unhtml(options.iframeCssUrl) +
                            "'/>"
                            : "") +
                        (options.initialStyle
                            ? "<style>" + options.initialStyle + "</style>"
                            : "") +
                        "</head>" +
                        "<body class='view' ></body>" +
                        "<script type='text/javascript' " +
                        (ie ? "defer='defer'" : "") +
                        " id='_initialScript'>" +
                        "setTimeout(function(){editor = window.parent.UE.instants['ueditorInstant" +
                        me.uid +
                        "'];editor._setup(document);},0);" +
                        "var _tmpScript = document.getElementById('_initialScript');_tmpScript.parentNode.removeChild(_tmpScript);" +
                        "</script>" +
                        (options.iframeJsUrl
                            ? "<script type='text/javascript' src='" +
                            utils.unhtml(options.iframeJsUrl) +
                            "'></script>"
                            : "") +
                        "</html>";

                    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";
                        }
                    });
                }
            },

            /**
             * 编辑器初始化
             * @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 = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
                }
                //如果要求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();
                            } 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)
                                        me.execCommand(i, param);
                                    domUtils.preventDefault(e);
                                }
                            }
                        }
                    }
                });
            },

            /**
             * 获取编辑器的内容
             * @method getContent
             * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
             * @return { String } 编辑器的内容字符串, 如果编辑器的内容为空,或者是空的标签内容(如:”&lt;p&gt;&lt;br/&gt;&lt;/p&gt;“), 则返回空字符串
             * @example
             * ```javascript
             * //编辑器html内容:<p>1<strong>2<em>34</em>5</strong>6</p>
             * var content = editor.getContent(); //返回值:<p>1<strong>2<em>34</em>5</strong>6</p>
             * ```
             */

            /**
             * 获取编辑器的内容。 可以通过参数定义编辑器内置的判空规则
             * @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 "";
                }
                me.fireEvent("beforegetcontent");
                var root = UE.htmlparser(me.body.innerHTML, ignoreBlank);
                me.filterOutputRule(root);
                me.fireEvent("aftergetcontent", cmd, root);
                return root.toHtml(formatter);
            },

            /**
             * 取得完整的html代码,可以直接显示成完整的html文档
             * @method getAllHtml
             * @return { String } 编辑器的内容html文档字符串
             * @eaxmple
             * ```javascript
             * editor.getAllHtml(); //返回格式大致是: <html><head>...</head><body>...</body></html>
             * ```
             */
            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
                            ? '<link rel="stylesheet" type="text/css" href="' + si.href + '" />'
                            : "<style>" + si.cssText + "</style>";
                    });
                    utils.each(me.document.getElementsByTagName("script"), function (si) {
                        headHtmlForIE9 += si.outerHTML;
                    });
                }
                return (
                    "<html><head>" +
                    (me.options.charset
                        ? '<meta http-equiv="Content-Type" content="text/html; charset=' +
                        me.options.charset +
                        '"/>'
                        : "") +
                    (headHtmlForIE9 ||
                        me.document.getElementsByTagName("head")[0].innerHTML) +
                    headHtml.join("\n") +
                    "</head>" +
                    "<body " +
                    (ie && browser.version < 9 ? 'class="view"' : "") +
                    ">" +
                    me.getContent(null, null, true) +
                    "</body></html>"
                );
            },

            /**
             * 得到编辑器的纯文本内容,但会保留段落格式
             * @method getPlainTxt
             * @return { String } 编辑器带段落格式的纯文本内容字符串
             * @example
             * ```javascript
             * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
             * console.log(editor.getPlainTxt()); //输出:"1\n2\n
             * ```
             */
            getPlainTxt: function () {
                var reg = new RegExp(domUtils.fillChar, "g"),
                    html = this.body.innerHTML.replace(/[\n\r]/g, ""); //ie要先去了\n在处理
                html = html
                    .replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, "\n")
                    .replace(/<br\/?>/gi, "\n")
                    .replace(/<[^>/]+>/g, "")
                    .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) {
                        return dtd.$block[c] ? "\n" : b ? b : "";
                    });
                //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
                return html
                    .replace(reg, "")
                    .replace(/\u00a0/g, " ")
                    .replace(/&nbsp;/g, " ");
            },

            /**
             * 获取编辑器中的纯文本内容,没有段落格式
             * @method getContentTxt
             * @return { String } 编辑器不带段落格式的纯文本内容字符串
             * @example
             * ```javascript
             * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
             * 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, " ");
            },

            /**
             * 设置编辑器的内容,可修改编辑器当前的html内容
             * @method setContent
             * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
             * @warning 该方法会触发selectionchange事件
             * @param { String } html 要插入的html内容
             * @example
             * ```javascript
             * editor.getContent('<p>test</p>');
             * ```
             */

            /**
             * 设置编辑器的内容,可修改编辑器当前的html内容
             * @method setContent
             * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
             * @warning 该方法会触发selectionchange事件
             * @param { String } html 要插入的html内容
             * @param { Boolean } isAppendTo 若传入true,不清空原来的内容,在最后插入内容,否则,清空内容再插入
             * @example
             * ```javascript
             * //假设设置前的编辑器内容是 <p>old text</p>
             * editor.setContent('<p>new text</p>', true); //插入的结果是<p>old text</p><p>new text</p>
             * ```
             */
            setContent: function (html, isAppendTo, notFireSelectionchange) {
                var me = this;

                me.fireEvent("beforesetcontent", html);
                var root = UE.htmlparser(html);
                me.filterInputRule(root);
                html = root.toHtml();

                me.body.innerHTML = (isAppendTo ? me.body.innerHTML : "") + html;

                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 =
                            "<p>" +
                            (browser.ie ? "&nbsp;" : "<br/>") +
                            "</p>" +
                            this.body.innerHTML;
                    } else {
                        var p = me.document.createElement("p");
                        while (child) {
                            while (
                                child &&
                                (child.nodeType == 3 ||
                                    (child.nodeType == 1 &&
                                        dtd.p[child.tagName] &&
                                        !dtd.$cdata[child.tagName]))
                                ) {
                                tmpNode = child.nextSibling;
                                p.appendChild(child);
                                child = tmpNode;
                            }
                            if (p.firstChild) {
                                if (!child) {
                                    me.body.appendChild(p);
                                    break;
                                } else {
                                    child.parentNode.insertBefore(p, child);
                                    p = me.document.createElement("p");
                                }
                            }
                            child = child.nextSibling;
                        }
                    }
                }
                me.fireEvent("aftersetcontent");
                me.fireEvent("contentchange");

                !notFireSelectionchange && me._selectionChange();
                //清除保存的选区
                me._bakRange = me._bakIERange = 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);
                }
            },

            /**
             * 让编辑器获得焦点,默认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;
                        if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
                            if (domUtils.isEmptyBlock(node)) {
                                rng.setStartAtFirst(node);
                            } else {
                                rng.setStartAtLast(node);
                            }
                            rng.collapse(true);
                        }
                        rng.setCursor(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 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
             * @return { * } 返回命令函数运行的返回值
             * @example
             * ```javascript
             * editor.execCommand(cmdName);
             * ```
             */
            execCommand: function (cmdName) {
                cmdName = cmdName.toLowerCase();
                var me = this;
                var result;
                var 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 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
             * @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 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
             * @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 = ["div"];
                for (i = 0; (ci = tags[i++]);) {
                    var nodes = domUtils.getElementsByTagName(this.document, ci);
                    for (var n = 0, cn; (cn = nodes[n++]);) {
                        if (domUtils.isCustomeNode(cn)) {
                            return true;
                        }
                    }
                }
                return false;
            },

            /**
             * 重置编辑器,可用来做多个tab使用同一个编辑器实例
             * @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 = "<p>" + (ie ? "" : "<br/>") + "</p>";
                        me.removeListener("firstBeforeExecCommand focus", clear);
                        setTimeout(function () {
                            me.focus();
                            me._selectionChange();
                        }, 0);
                    }
                }

                return function (cont) {
                    var me = this;
                    me.body.innerHTML = '<p id="initContent">' + cont + "</p>";

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

            /**
             * 注册输入过滤规则
             * @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 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 "";
                }
            }
        };
        utils.inherits(Editor, EventBase);
    })();


// core/Editor.defaultoptions.js
//维护编辑器一下默认的不在插件中的配置项
    UE.Editor.defaultOptions = function (editor) {
        var _url = editor.options.UEDITOR_HOME_URL;
        return {
            isShow: true,
            initialContent: "",
            initialStyle: "",
            autoClearinitialContent: false,
            iframeCssUrl: _url + "themes/iframe.css",
            textarea: "editorValue",
            focus: false,
            focusInEnd: true,
            autoClearEmptyNode: true,
            fullscreen: false,
            readonly: false,
            zIndex: 999,
            imagePopup: true,
            enterTag: "p",
            customDomain: false,
            lang: "zh-cn",
            langPath: _url + "i18n/",
            theme: "default",
            themePath: _url + "themes/",
            allHtmlEnabled: false,
            scaleEnabled: false,
            tableNativeEditInFF: false,
            autoSyncData: true,
            fileNameFormat: "{time}{rand:6}"
        };
    };


// core/loadconfig.js
    ;(function () {
        UE.Editor.prototype.loadServerConfig = function () {
            var me = this;
            setTimeout(function () {
                try {
                    me.options.imageUrl &&
                    me.setOpt(
                        "serverUrl",
                        me.options.imageUrl.replace(
                            /^(.*[\/]).+([\.].+)$/,
                            "$1controller$2"
                        )
                    );

                    var configUrl = me.getActionUrl("config"),
                        isJsonp = utils.isCrossDomainUrl(configUrl);

                    /* 发出ajax请求 */
                    me._serverConfigLoaded = false;

                    configUrl &&
                    UE.ajax.request(configUrl, {
                        method: "GET",
                        dataType: isJsonp ? "jsonp" : "",
                        onsuccess: function (r) {
                            try {
                                var config = isJsonp ? r : eval("(" + r.responseText + ")");
                                utils.extend(me.options, config);
                                me.fireEvent("serverConfigLoaded");
                                me._serverConfigLoaded = true;
                            } catch (e) {
                                showErrorMsg(me.getLang("loadconfigFormatError"));
                            }
                        },
                        onerror: function () {
                            showErrorMsg(me.getLang("loadconfigHttpError"));
                        }
                    });
                } catch (e) {
                    showErrorMsg(me.getLang("loadconfigError"));
                }
            });

            function showErrorMsg(msg) {
                console && 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: 'neditor'
         *     },
         *
         *     //请求成功后的回调, 该回调接受当前的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=)/gi.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(/<!--[\s\S]*?-->/gi, "")
                    //转换图片
                    .replace(/<v:shape [^>]*>[\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 (
                                '<img width="' +
                                transUnit(width) +
                                '" height="' +
                                transUnit(height) +
                                '" src="' +
                                src +
                                '" />'
                            );
                        } catch (e) {
                            return "";
                        }
                    })
                    //针对wps添加的多余标签处理
                    .replace(/<\/?div[^>]*>/g, "")
                    //去掉多余的属性
                    .replace(/v:\w+=(["']?)[^'"]+\1/g, "")
                    .replace(
                        /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi,
                        ""
                    )
                    .replace(
                        /<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi,
                        "<p><strong>$1</strong></p>"
                    )
                    //去掉多余的属性
                    .replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/gi, function (
                        str,
                        name,
                        marks,
                        val
                    ) {
                        //保留list的标示
                        return name == "class" && val == "MsoListParagraph" ? str : "";
                    })
                    //清除多余的font/span不能匹配&nbsp;有可能是空格
                    .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(/&#39;/g, "'")
                                .replace(/&quot;/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":
                                    //ie下会出现挤到一起的情况
                                    //case "mso-table-layout-alt":
                                    case "mso-height":
                                    case "mso-width":
                                    case "mso-vertical-align-alt":
                                        //trace:1819 ff下会解析出padding在table上
                                        if (!/<table/.test(tag))
                                            n[i] =
                                                name.replace(/^mso-|-alt$/g, "") + ":" + transUnit(value);
                                        continue;
                                    case "horiz-align":
                                        n[i] = "text-align:" + value;
                                        continue;

                                    case "vert-align":
                                        n[i] = "vertical-align:" + value;
                                        continue;

                                    case "font-color":
                                    case "mso-foreground":
                                        n[i] = "color:" + value;
                                        continue;

                                    case "mso-background":
                                    case "mso-highlight":
                                        n[i] = "background:" + value;
                                        continue;

                                    case "mso-default-height":
                                        n[i] = "min-height:" + transUnit(value);
                                        continue;

                                    case "mso-default-width":
                                        n[i] = "min-width:" + transUnit(value);
                                        continue;

                                    case "mso-padding-between-alt":
                                        n[i] =
                                            "border-collapse:separate;border-spacing:" +
                                            transUnit(value);
                                        continue;

                                    case "text-line-through":
                                        if (value == "single" || value == "double") {
                                            n[i] = "text-decoration:line-through";
                                        }
                                        continue;
                                    case "mso-zero-height":
                                        if (value == "yes") {
                                            n[i] = "display:none";
                                        }
                                        continue;
                                    //                                case 'background':
                                    //                                    break;
                                    case "margin":
                                        if (!/[1-9]/.test(value)) {
                                            continue;
                                        }
                                }

                                if (
                                    /^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?:decor|trans)|top-bar|version|vnd|word-break)/.test(
                                        name
                                    ) ||
                                    (/text\-indent|padding|margin/.test(name) &&
                                        /\-[\d.]+/.test(value))
                                ) {
                                    continue;
                                }

                                n[i] = name + ":" + parts[1];
                            }
                        }
                        return (
                            tag +
                            (n.length
                                ? ' style="' + n.join(";").replace(/;{2,}/g, ";") + '"'
                                : "")
                        );
                    })
            );
        }

        return function (html) {
            return isWordDocument(html) ? filterPasteWord(html) : html;
        };
    })());


// core/node.js
    /**
     * 编辑器模拟的节点类
     * @file
     * @module UE
     * @class uNode
     * @since 1.2.6.1
     */

    /**
     * UEditor公用空间,UEditor所有的功能都挂载在该空间下
     * @unfile
     * @module UE
     */

    ;(function () {
        /**
         * 编辑器模拟的节点类
         * @unfile
         * @module UE
         * @class uNode
         */

        /**
         * 通过一个键值对,创建一个uNode对象
         * @constructor
         * @param { Object } attr 传入要创建的uNode的初始属性
         * @example
         * ```javascript
         * var node = new uNode({
     *     type:'element',
     *     tagName:'span',
     *     attrs:{style:'font-size:14px;'}
     * })
         * ```
         */
        var uNode = (UE.uNode = function (obj) {
            this.type = obj.type;
            this.data = obj.data;
            this.tagName = obj.tagName;
            this.parentNode = obj.parentNode;
            this.attrs = obj.attrs || {};
            this.children = obj.children;
        });

        var notTransAttrs = {
            href: 1,
            src: 1,
            _src: 1,
            _href: 1,
            cdata_data: 1
        };

        var notTransTagName = {
            style: 1,
            script: 1
        };

        var indentChar = "    ",
            breakChar = "\n";

        function insertLine(arr, current, begin) {
            arr.push(breakChar);
            return current + (begin ? 1 : -1);
        }

        function insertIndent(arr, current) {
            //插入缩进
            for (var i = 0; i < current; i++) {
                arr.push(indentChar);
            }
        }

        //创建uNode的静态方法
        //支持标签和html
        uNode.createElement = function (html) {
            if (/[<>]/.test(html)) {
                return UE.htmlparser(html).children[0];
            } else {
                return new uNode({
                    type: "element",
                    children: [],
                    tagName: html
                });
            }
        };
        uNode.createText = function (data, noTrans) {
            return new UE.uNode({
                type: "text",
                data: noTrans ? data : utils.unhtml(data || "")
            });
        };

        function nodeToHtml(node, arr, formatter, current) {
            switch (node.type) {
                case "root":
                    for (var i = 0, ci; (ci = node.children[i++]);) {
                        //插入新行
                        if (
                            formatter &&
                            ci.type == "element" &&
                            !dtd.$inlineWithA[ci.tagName] &&
                            i > 1
                        ) {
                            insertLine(arr, current, true);
                            insertIndent(arr, current);
                        }
                        nodeToHtml(ci, arr, formatter, current);
                    }
                    break;
                case "text":
                    isText(node, arr);
                    break;
                case "element":
                    isElement(node, arr, formatter, current);
                    break;
                case "comment":
                    isComment(node, arr, formatter);
            }
            return arr;
        }

        function isText(node, arr) {
            if (node.parentNode.tagName == "pre") {
                //源码模式下输入html标签,不能做转换处理,直接输出
                arr.push(node.data);
            } else {
                arr.push(
                    notTransTagName[node.parentNode.tagName]
                        ? utils.html(node.data)
                        : node.data.replace(/[ ]{2}/g, " &nbsp;")
                );
            }
        }

        function isElement(node, arr, formatter, current) {
            var attrhtml = "";
            if (node.attrs) {
                attrhtml = [];
                var attrs = node.attrs;
                for (var a in attrs) {
                    //这里就针对
                    //<p>'<img src='http://nsclick.baidu.com/u.gif?&asdf=\"sdf&asdfasdfs;asdf'></p>
                    //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
                    //有可能做的不够
                    attrhtml.push(
                        a +
                        (attrs[a] !== undefined
                            ? '="' +
                            (notTransAttrs[a]
                                ? utils.html(attrs[a]).replace(/["]/g, function (a) {
                                    return "&quot;";
                                })
                                : 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("<!--" + node.data + "-->");
        }

        function getNodeById(root, id) {
            var node;
            if (root.type == "element" && root.getAttr("id") == id) {
                return root;
            }
            if (root.children && root.children.length) {
                for (var i = 0, ci; (ci = root.children[i++]);) {
                    if ((node = getNodeById(ci, id))) {
                        return node;
                    }
                }
            }
        }

        function getNodesByTagName(node, tagName, arr) {
            if (node.type == "element" && node.tagName == tagName) {
                arr.push(node);
            }
            if (node.children && node.children.length) {
                for (var i = 0, ci; (ci = node.children[i++]);) {
                    getNodesByTagName(ci, tagName, arr);
                }
            }
        }

        function nodeTraversal(root, fn) {
            if (root.children && root.children.length) {
                for (var i = 0, ci; (ci = root.children[i]);) {
                    nodeTraversal(ci, fn);
                    //ci被替换的情况,这里就不再走 fn了
                    if (ci.parentNode) {
                        if (ci.children && ci.children.length) {
                            fn(ci);
                        }
                        if (ci.parentNode) i++;
                    }
                }
            } else {
                fn(root);
            }
        }

        uNode.prototype = {
            /**
             * 当前节点对象,转换成html文本
             * @method toHtml
             * @return { String } 返回转换后的html字符串
             * @example
             * ```javascript
             * node.toHtml();
             * ```
             */

            /**
             * 当前节点对象,转换成html文本
             * @method toHtml
             * @param { Boolean } formatter 是否格式化返回值
             * @return { String } 返回转换后的html字符串
             * @example
             * ```javascript
             * node.toHtml( true );
             * ```
             */
            toHtml: function (formatter) {
                var arr = [];
                nodeToHtml(this, arr, formatter, 0);
                return arr.join("");
            },

            /**
             * 获取节点的html内容
             * @method innerHTML
             * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
             * @return { String } 返回节点的html内容
             * @example
             * ```javascript
             * var htmlstr = node.innerHTML();
             * ```
             */

            /**
             * 设置节点的html内容
             * @method innerHTML
             * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
             * @param { String } htmlstr 传入要设置的html内容
             * @return { UE.uNode } 返回节点本身
             * @example
             * ```javascript
             * node.innerHTML('<span>text</span>');
             * ```
             */
            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('<span>text</span>');
             * ```
             */
            innerText: function (textStr, noTrans) {
                if (this.type != "element" || dtd.$empty[this.tagName]) {
                    return this;
                }
                if (textStr) {
                    if (this.children) {
                        for (var i = 0, ci; (ci = this.children[i++]);) {
                            ci.parentNode = null;
                        }
                    }
                    this.children = [];
                    this.appendChild(uNode.createText(textStr, noTrans));
                    return this;
                } else {
                    return this.toHtml().replace(/<[^>]+>/g, "");
                }
            },

            /**
             * 获取当前对象的data属性
             * @method getData
             * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
             * @example
             * ```javascript
             * node.getData();
             * ```
             */
            getData: function () {
                if (this.type == "element") return "";
                return this.data;
            },

            /**
             * 获取当前节点下的第一个子节点
             * @method firstChild
             * @return { UE.uNode } 返回第一个子节点
             * @example
             * ```javascript
             * node.firstChild(); //返回第一个子节点
             * ```
             */
            firstChild: function () {
                //            if (this.type != 'element' || dtd.$empty[this.tagName]) {
                //                return this;
                //            }
                return this.children ? this.children[0] : null;
            },

            /**
             * 获取当前节点下的最后一个子节点
             * @method lastChild
             * @return { UE.uNode } 返回最后一个子节点
             * @example
             * ```javascript
             * node.lastChild(); //返回最后一个子节点
             * ```
             */
            lastChild: function () {
                //            if (this.type != 'element' || dtd.$empty[this.tagName] ) {
                //                return this;
                //            }
                return this.children ? this.children[this.children.length - 1] : null;
            },

            /**
             * 获取和当前节点有相同父亲节点的前一个节点
             * @method previousSibling
             * @return { UE.uNode } 返回前一个节点
             * @example
             * ```javascript
             * node.children[2].previousSibling(); //返回子节点node.children[1]
             * ```
             */
            previousSibling: function () {
                var parent = this.parentNode;
                for (var i = 0, ci; (ci = parent.children[i]); i++) {
                    if (ci === this) {
                        return i == 0 ? null : parent.children[i - 1];
                    }
                }
            },

            /**
             * 获取和当前节点有相同父亲节点的后一个节点
             * @method nextSibling
             * @return { UE.uNode } 返回后一个节点,找不到返回null
             * @example
             * ```javascript
             * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
             * ```
             */
            nextSibling: function () {
                var parent = this.parentNode;
                for (var i = 0, ci; (ci = parent.children[i++]);) {
                    if (ci === this) {
                        return parent.children[i];
                    }
                }
            },

            /**
             * 用新的节点替换当前节点
             * @method replaceChild
             * @param { UE.uNode } target 要替换成该节点参数
             * @param { UE.uNode } source 要被替换掉的节点
             * @return { UE.uNode } 返回替换之后的节点对象
             * @example
             * ```javascript
             * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
             * ```
             */
            replaceChild: function (target, source) {
                if (this.children) {
                    if (target.parentNode) {
                        target.parentNode.removeChild(target);
                    }
                    for (var i = 0, ci; (ci = this.children[i]); i++) {
                        if (ci === source) {
                            this.children.splice(i, 1, target);
                            source.parentNode = null;
                            target.parentNode = this;
                            return target;
                        }
                    }
                }
            },

            /**
             * 在节点的子节点列表最后位置插入一个节点
             * @method appendChild
             * @param { UE.uNode } node 要插入的节点
             * @return { UE.uNode } 返回刚插入的子节点
             * @example
             * ```javascript
             * node.appendChild( newNode ); //在node内插入子节点newNode
             * ```
             */
            appendChild: function (node) {
                if (
                    this.type == "root" ||
                    (this.type == "element" && !dtd.$empty[this.tagName])
                ) {
                    if (!this.children) {
                        this.children = [];
                    }
                    if (node.parentNode) {
                        node.parentNode.removeChild(node);
                    }
                    for (var i = 0, ci; (ci = this.children[i]); i++) {
                        if (ci === node) {
                            this.children.splice(i, 1);
                            break;
                        }
                    }
                    this.children.push(node);
                    node.parentNode = this;
                    return node;
                }
            },

            /**
             * 在传入节点的前面插入一个节点
             * @method insertBefore
             * @param { UE.uNode } target 要插入的节点
             * @param { UE.uNode } source 在该参数节点前面插入
             * @return { UE.uNode } 返回刚插入的子节点
             * @example
             * ```javascript
             * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
             * ```
             */
            insertBefore: function (target, source) {
                if (this.children) {
                    if (target.parentNode) {
                        target.parentNode.removeChild(target);
                    }
                    for (var i = 0, ci; (ci = this.children[i]); i++) {
                        if (ci === source) {
                            this.children.splice(i, 0, target);
                            target.parentNode = this;
                            return target;
                        }
                    }
                }
            },

            /**
             * 在传入节点的后面插入一个节点
             * @method insertAfter
             * @param { UE.uNode } target 要插入的节点
             * @param { UE.uNode } source 在该参数节点后面插入
             * @return { UE.uNode } 返回刚插入的子节点
             * @example
             * ```javascript
             * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
             * ```
             */
            insertAfter: function (target, source) {
                if (this.children) {
                    if (target.parentNode) {
                        target.parentNode.removeChild(target);
                    }
                    for (var i = 0, ci; (ci = this.children[i]); i++) {
                        if (ci === source) {
                            this.children.splice(i + 1, 0, target);
                            target.parentNode = this;
                            return target;
                        }
                    }
                }
            },

            /**
             * 从当前节点的子节点列表中,移除节点
             * @method removeChild
             * @param { UE.uNode } node 要移除的节点引用
             * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
             * @return { * } 返回刚移除的子节点
             * @example
             * ```javascript
             * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
             * ```
             */
            removeChild: function (node, keepChildren) {
                if (this.children) {
                    for (var i = 0, ci; (ci = this.children[i]); i++) {
                        if (ci === node) {
                            this.children.splice(i, 1);
                            ci.parentNode = null;
                            if (keepChildren && ci.children && ci.children.length) {
                                for (var j = 0, cj; (cj = ci.children[j]); j++) {
                                    this.children.splice(i + j, 0, cj);
                                    cj.parentNode = this;
                                }
                            }
                            return ci;
                        }
                    }
                }
            },

            /**
             * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
             * @method getAttr
             * @param { String } attrName 要获取的属性名称
             * @return { * } 返回attrs对象下的属性值
             * @example
             * ```javascript
             * node.getAttr('title');
             * ```
             */
            getAttr: function (attrName) {
                return this.attrs && this.attrs[attrName.toLowerCase()];
            },

            /**
             * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
             * @method setAttr
             * @param { String } attrName 要设置的属性名称
             * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
             * @return { * } 返回attrs对象下的属性值
             * @example
             * ```javascript
             * node.setAttr('title','标题');
             * ```
             */
            setAttr: function (attrName, attrVal) {
                if (!attrName) {
                    delete this.attrs;
                    return;
                }
                if (!this.attrs) {
                    this.attrs = {};
                }
                if (utils.isObject(attrName)) {
                    for (var a in attrName) {
                        if (!attrName[a]) {
                            delete this.attrs[a];
                        } else {
                            this.attrs[a.toLowerCase()] = attrName[a];
                        }
                    }
                } else {
                    if (!attrVal) {
                        delete this.attrs[attrName];
                    } else {
                        this.attrs[attrName.toLowerCase()] = attrVal;
                    }
                }
            },

            /**
             * 获取当前节点在父节点下的位置索引
             * @method getIndex
             * @return { Number } 返回索引数值,如果没有父节点,返回-1
             * @example
             * ```javascript
             * node.getIndex();
             * ```
             */
            getIndex: function () {
                var parent = this.parentNode;
                for (var i = 0, ci; (ci = parent.children[i]); i++) {
                    if (ci === this) {
                        return i;
                    }
                }
                return -1;
            },

            /**
             * 在当前节点下,根据id查找节点
             * @method getNodeById
             * @param { String } id 要查找的id
             * @return { UE.uNode } 返回找到的节点
             * @example
             * ```javascript
             * node.getNodeById('textId');
             * ```
             */
            getNodeById: function (id) {
                var node;
                if (this.children && this.children.length) {
                    for (var i = 0, ci; (ci = this.children[i++]);) {
                        if ((node = getNodeById(ci, id))) {
                            return node;
                        }
                    }
                }
            },

            /**
             * 在当前节点下,根据元素名称查找节点列表
             * @method getNodesByTagName
             * @param { String } tagNames 要查找的元素名称
             * @return { Array } 返回找到的节点列表
             * @example
             * ```javascript
             * node.getNodesByTagName('span');
             * ```
             */
            getNodesByTagName: function (tagNames) {
                tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, " ").split(" ");
                var arr = [],
                    me = this;
                utils.each(tagNames, function (tagName) {
                    if (me.children && me.children.length) {
                        for (var i = 0, ci; (ci = me.children[i++]);) {
                            getNodesByTagName(ci, tagName, arr);
                        }
                    }
                });
                return arr;
            },

            /**
             * 根据样式名称,获取节点的样式值
             * @method getStyle
             * @param { String } name 要获取的样式名称
             * @return { String } 返回样式值
             * @example
             * ```javascript
             * node.getStyle('font-size');
             * ```
             */
            getStyle: function (name) {
                var cssStyle = this.getAttr("style");
                if (!cssStyle) {
                    return "";
                }
                var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+)", "i");
                var match = cssStyle.match(reg);
                if (match && match[0]) {
                    return match[2];
                }
                return "";
            },

            /**
             * 给节点设置样式
             * @method setStyle
             * @param { String } name 要设置的的样式名称
             * @param { String } val 要设置的的样值
             * @example
             * ```javascript
             * node.setStyle('font-size', '12px');
             * ```
             */
            setStyle: function (name, val) {
                function exec(name, val) {
                    var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+;?)", "gi");
                    cssStyle = cssStyle.replace(reg, "$1");
                    if (val) {
                        cssStyle = name + ":" + utils.unhtml(val) + ";" + cssStyle;
                    }
                }

                var cssStyle = this.getAttr("style");
                if (!cssStyle) {
                    cssStyle = "";
                }
                if (utils.isObject(name)) {
                    for (var a in name) {
                        exec(a, name[a]);
                    }
                } else {
                    exec(name, val);
                }
                this.setAttr("style", utils.trim(cssStyle));
            },

            /**
             * 传入一个函数,递归遍历当前节点下的所有节点
             * @method traversal
             * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
             * @example
             * ```javascript
             * traversal(node, function(){
         *     console.log(node.type);
         * });
             * ```
             */
            traversal: function (fn) {
                if (this.children && this.children.length) {
                    nodeTraversal(this, fn);
                }
                return this;
            }
        };
    })();


// core/htmlparser.js
    /**
     * html字符串转换成uNode节点
     * @file
     * @module UE
     * @since 1.2.6.1
     */

    /**
     * UEditor公用空间,UEditor所有的功能都挂载在该空间下
     * @unfile
     * @module UE
     */

    /**
     * html字符串转换成uNode节点的静态方法
     * @method htmlparser
     * @param { String } htmlstr 要转换的html代码
     * @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符
     * @return { uNode } 给定的html片段转换形成的uNode对象
     * @example
     * ```javascript
     * var root = UE.htmlparser('<p><b>htmlparser</b></p>', true);
     * ```
     */

    var htmlparser = (UE.htmlparser = function (htmlstr, ignoreBlank) {
        //todo 原来的方式  [^"'<>\/] 有\/就不能配对上 <TD vAlign=top background=../AAA.JPG> 这样的标签了
        //先去掉了,加上的原因忘了,这里先记录
        //var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
        //以上的正则表达式无法匹配:<div style="text-align:center;font-family:" font-size:14px;"=""><img src="http://hs-album.oss.aliyuncs.com/static/27/78/35/image/20161206/20161206174331_41105.gif" alt="" /><br /></div>
        //修改为如下正则表达式:
        var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\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;
        }
        //如果结束是文本,就有可能丢掉,所以这里手动判断一下
        //例如 <li>sdfsdfsdf<li>sdfsdfsdfsdf
        if (nextIndex < htmlstr.length) {
            text(currentParent, htmlstr.slice(nextIndex));
        }
        return root;
    });


// core/filternode.js
    /**
     * UE过滤节点的静态方法
     * @file
     */

    /**
     * UEditor公用空间,UEditor所有的功能都挂载在该空间下
     * @module UE
     */

    /**
     * 根据传入节点和过滤规则过滤相应节点
     * @module UE
     * @since 1.2.6.1
     * @method filterNode
     * @param { Object } root 指定root节点
     * @param { Object } rules 过滤规则json对象
     * @example
     * ```javascript
     * UE.filterNode(root,editor.options.filterRules);
     * ```
     */
    var filterNode = (UE.filterNode = (function () {
        function filterNode(node, rules) {
            switch (node.type) {
                case "text":
                    break;
                case "element":
                    var val;
                    if ((val = rules[node.tagName])) {
                        if (val === "-") {
                            node.parentNode.removeChild(node);
                        } else if (utils.isFunction(val)) {
                            var parentNode = node.parentNode,
                                index = node.getIndex();
                            val(node);
                            if (node.parentNode) {
                                if (node.children) {
                                    for (var i = 0, ci; (ci = node.children[i]);) {
                                        filterNode(ci, rules);
                                        if (ci.parentNode) {
                                            i++;
                                        }
                                    }
                                }
                            } else {
                                for (var i = index, ci; (ci = parentNode.children[i]);) {
                                    filterNode(ci, rules);
                                    if (ci.parentNode) {
                                        i++;
                                    }
                                }
                            }
                        } else {
                            var attrs = val["$"];
                            if (attrs && node.attrs) {
                                var tmpAttrs = {},
                                    tmpVal;
                                for (var a in attrs) {
                                    tmpVal = node.getAttr(a);
                                    //todo 只先对style单独处理
                                    if (a == "style" && utils.isArray(attrs[a])) {
                                        var tmpCssStyle = [];
                                        utils.each(attrs[a], function (v) {
                                            var tmp;
                                            if ((tmp = node.getStyle(v))) {
                                                tmpCssStyle.push(v + ":" + tmp);
                                            }
                                        });
                                        tmpVal = tmpCssStyle.join(";");
                                    }
                                    if (tmpVal) {
                                        tmpAttrs[a] = tmpVal;
                                    }
                                }
                                node.attrs = tmpAttrs;
                            }
                            if (node.children) {
                                for (var i = 0, ci; (ci = node.children[i]);) {
                                    filterNode(ci, rules);
                                    if (ci.parentNode) {
                                        i++;
                                    }
                                }
                            }
                        }
                    } else {
                        //如果不在名单里扣出子节点并删除该节点,cdata除外
                        if (dtd.$cdata[node.tagName]) {
                            node.parentNode.removeChild(node);
                        } else {
                            var parentNode = node.parentNode,
                                index = node.getIndex();
                            node.parentNode.removeChild(node, true);
                            for (var i = index, ci; (ci = parentNode.children[i]);) {
                                filterNode(ci, rules);
                                if (ci.parentNode) {
                                    i++;
                                }
                            }
                        }
                    }
                    break;
                case "comment":
                    node.parentNode.removeChild(node);
            }
        }

        return function (root, rules) {
            if (utils.isEmptyObject(rules)) {
                return root;
            }
            var val;
            if ((val = rules["-"])) {
                utils.each(val.split(" "), function (k) {
                    rules[k] = "-";
                });
            }
            for (var i = 0, ci; (ci = root.children[i]);) {
                filterNode(ci, rules);
                if (ci.parentNode) {
                    i++;
                }
            }
            return root;
        };
    })());


// core/plugin.js
    /**
     * Created with JetBrains PhpStorm.
     * User: campaign
     * Date: 10/8/13
     * Time: 6:15 PM
     * To change this template use File | Settings | File Templates.
     */
    UE.plugin = (function () {
        var _plugins = {};
        return {
            register: function (pluginName, fn, oldOptionName, afterDisabled) {
                if (oldOptionName && utils.isFunction(oldOptionName)) {
                    afterDisabled = oldOptionName;
                    oldOptionName = null;
                }
                _plugins[pluginName] = {
                    optionName: oldOptionName || pluginName,
                    execFn: fn,
                    //当插件被禁用时执行
                    afterDisabled: afterDisabled
                };
            },
            load: function (editor) {
                utils.each(_plugins, function (plugin) {
                    var _export = plugin.execFn.call(editor);
                    if (editor.options[plugin.optionName] !== false) {
                        if (_export) {
                            //后边需要再做扩展
                            utils.each(_export, function (v, k) {
                                switch (k.toLowerCase()) {
                                    case "shortcutkey":
                                        editor.addshortcutkey(v);
                                        break;
                                    case "bindevents":
                                        utils.each(v, function (fn, eventName) {
                                            editor.addListener(eventName, fn);
                                        });
                                        break;
                                    case "bindmultievents":
                                        utils.each(utils.isArray(v) ? v : [v], function (event) {
                                            var types = utils.trim(event.type).split(/\s+/);
                                            utils.each(types, function (eventName) {
                                                editor.addListener(eventName, event.handler);
                                            });
                                        });
                                        break;
                                    case "commands":
                                        utils.each(v, function (execFn, execName) {
                                            editor.commands[execName] = execFn;
                                        });
                                        break;
                                    case "outputrule":
                                        editor.addOutputRule(v);
                                        break;
                                    case "inputrule":
                                        editor.addInputRule(v);
                                        break;
                                    case "defaultoptions":
                                        editor.setOpt(v);
                                }
                            });
                        }
                    } else if (plugin.afterDisabled) {
                        plugin.afterDisabled.call(editor);
                    }
                });
                //向下兼容
                utils.each(UE.plugins, function (plugin) {
                    plugin.call(editor);
                });
            },
            run: function (pluginName, editor) {
                var plugin = _plugins[pluginName];
                if (plugin) {
                    plugin.exeFn.call(editor);
                }
            }
        };
    })();


// core/keymap.js
    var keymap = (UE.keymap = {
        Backspace: 8,
        Tab: 9,
        Enter: 13,

        Shift: 16,
        Control: 17,
        Alt: 18,
        CapsLock: 20,

        Esc: 27,

        Spacebar: 32,

        PageUp: 33,
        PageDown: 34,
        End: 35,
        Home: 36,

        Left: 37,
        Up: 38,
        Right: 39,
        Down: 40,

        Insert: 45,

        Del: 46,

        NumLock: 144,

        Cmd: 91,

        "=": 187,
        "-": 189,

        b: 66,
        i: 73,
        //回退
        z: 90,
        y: 89,
        //粘贴
        v: 86,
        x: 88,

        s: 83,

        n: 78
    });


// core/localstorage.js
//存储媒介封装
    var LocalStorage = (UE.LocalStorage = (function () {
        var storage = window.localStorage || getUserData() || null,
            LOCAL_FILE = "localStorage";

        return {
            saveLocalData: function (key, data) {
                if (storage && data) {
                    storage.setItem(key, data);
                    return true;
                }

                return false;
            },

            getLocalData: function (key) {
                if (storage) {
                    return storage.getItem(key);
                }

                return null;
            },

            removeItem: function (key) {
                storage && storage.removeItem(key);
            }
        };

        function getUserData() {
            var container = document.createElement("div");
            container.style.display = "none";

            if (!container.addBehavior) {
                return null;
            }

            container.addBehavior("#default#userdata");

            return {
                getItem: function (key) {
                    var result = null;

                    try {
                        document.body.appendChild(container);
                        container.load(LOCAL_FILE);
                        result = container.getAttribute(key);
                        document.body.removeChild(container);
                    } catch (e) {
                    }

                    return result;
                },

                setItem: function (key, value) {
                    document.body.appendChild(container);
                    container.setAttribute(key, value);
                    container.save(LOCAL_FILE);
                    document.body.removeChild(container);
                },

                //// 暂时没有用到
                //clear: function () {
                //
                //    var expiresTime = new Date();
                //    expiresTime.setFullYear(expiresTime.getFullYear() - 1);
                //    document.body.appendChild(container);
                //    container.expires = expiresTime.toUTCString();
                //    container.save(LOCAL_FILE);
                //    document.body.removeChild(container);
                //
                //},

                removeItem: function (key) {
                    document.body.appendChild(container);
                    container.removeAttribute(key);
                    container.save(LOCAL_FILE);
                    document.body.removeChild(container);
                }
            };
        }
    })());

    ;(function () {
        var ROOTKEY = "ueditor_preference";

        UE.Editor.prototype.setPreferences = function (key, value) {
            var obj = {};
            if (utils.isString(key)) {
                obj[key] = value;
            } else {
                obj = key;
            }
            var data = LocalStorage.getLocalData(ROOTKEY);
            if (data && (data = utils.str2json(data))) {
                utils.extend(data, obj);
            } else {
                data = obj;
            }
            data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
        };

        UE.Editor.prototype.getPreferences = function (key) {
            var data = LocalStorage.getLocalData(ROOTKEY);
            if (data && (data = utils.str2json(data))) {
                return key ? data[key] : data;
            }
            return null;
        };

        UE.Editor.prototype.removePreferences = function (key) {
            var data = LocalStorage.getLocalData(ROOTKEY);
            if (data && (data = utils.str2json(data))) {
                data[key] = undefined;
                delete data[key];
            }
            data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
        };
    })();


// plugins/defaultfilter.js
///import core
///plugin 编辑器默认的过滤转换机制

    UE.plugins["defaultfilter"] = function () {
        var me = this;
        me.setOpt({
            allowDivTransToP: true,
            disabledTableInTable: true,
            rgb2Hex: true
        });
        //默认的过滤处理
        //进入编辑器的内容处理
        me.addInputRule(function (root) {
            var allowDivTransToP = this.options.allowDivTransToP;
            var val;

            function tdParent(node) {
                while (node && node.type == "element") {
                    if (node.tagName == "td") {
                        return true;
                    }
                    node = node.parentNode;
                }
                return false;
            }

            //进行默认的处理
            root.traversal(function (node) {
                if (node.type == "element") {
                    if (
                        !dtd.$cdata[node.tagName] &&
                        me.options.autoClearEmptyNode &&
                        dtd.$inline[node.tagName] &&
                        !dtd.$empty[node.tagName] &&
                        (!node.attrs || utils.isEmptyObject(node.attrs))
                    ) {
                        if (!node.firstChild()) node.parentNode.removeChild(node);
                        else if (
                            node.tagName == "span" &&
                            (!node.attrs || utils.isEmptyObject(node.attrs))
                        ) {
                            node.parentNode.removeChild(node, true);
                        }
                        return;
                    }
                    switch (node.tagName) {
                        case "style":
                        case "script":
                            node.setAttr({
                                cdata_tag: node.tagName,
                                cdata_data: node.innerHTML() || "",
                                _ue_custom_node_: "true"
                            });
                            node.tagName = "div";
                            node.innerHTML("");
                            break;
                        case "a":
                            if ((val = node.getAttr("href"))) {
                                node.setAttr("_href", val);
                            }
                            break;
                        case "img":
                            //todo base64暂时去掉,后边做远程图片上传后,干掉这个
                            if ((val = node.getAttr("src"))) {
                                if (/^data:/.test(val)) {
                                    node.parentNode.removeChild(node);
                                    break;
                                }
                            }
                            node.setAttr("_src", node.getAttr("src"));
                            break;
                        case "span":
                            if (browser.webkit && (val = node.getStyle("white-space"))) {
                                if (/nowrap|normal/.test(val)) {
                                    node.setStyle("white-space", "");
                                    if (
                                        me.options.autoClearEmptyNode &&
                                        utils.isEmptyObject(node.attrs)
                                    ) {
                                        node.parentNode.removeChild(node, true);
                                    }
                                }
                            }
                            val = node.getAttr("id");
                            if (val && /^_baidu_bookmark_/i.test(val)) {
                                node.parentNode.removeChild(node);
                            }
                            break;
                        case "p":
                            if ((val = node.getAttr("align"))) {
                                node.setAttr("align");
                                node.setStyle("text-align", val);
                            }
                            //trace:3431
                            //                        var cssStyle = node.getAttr('style');
                            //                        if (cssStyle) {
                            //                            cssStyle = cssStyle.replace(/(margin|padding)[^;]+/g, '');
                            //                            node.setAttr('style', cssStyle)
                            //
                            //                        }
                            //p标签不允许嵌套
                            utils.each(node.children, function (n) {
                                if (n.type == "element" && n.tagName == "p") {
                                    var next = n.nextSibling();
                                    node.parentNode.insertAfter(n, node);
                                    var last = n;
                                    while (next) {
                                        var tmp = next.nextSibling();
                                        node.parentNode.insertAfter(next, last);
                                        last = next;
                                        next = tmp;
                                    }
                                    return false;
                                }
                            });
                            if (!node.firstChild()) {
                                node.innerHTML(browser.ie ? "&nbsp;" : "<br/>");
                            }
                            break;
                        case "div":
                            if (node.getAttr("cdata_tag")) {
                                break;
                            }
                            //针对代码这里不处理插入代码的div
                            val = node.getAttr("class");
                            if (val && /^line number\d+/.test(val)) {
                                break;
                            }
                            if (!allowDivTransToP) {
                                break;
                            }
                            var tmpNode,
                                p = UE.uNode.createElement("p");
                            while ((tmpNode = node.firstChild())) {
                                if (
                                    tmpNode.type == "text" ||
                                    !UE.dom.dtd.$block[tmpNode.tagName]
                                ) {
                                    p.appendChild(tmpNode);
                                } else {
                                    if (p.firstChild()) {
                                        node.parentNode.insertBefore(p, node);
                                        p = UE.uNode.createElement("p");
                                    } else {
                                        node.parentNode.insertBefore(tmpNode, node);
                                    }
                                }
                            }
                            if (p.firstChild()) {
                                node.parentNode.insertBefore(p, node);
                            }
                            node.parentNode.removeChild(node);
                            break;
                        case "dl":
                            node.tagName = "ul";
                            break;
                        case "dt":
                        case "dd":
                            node.tagName = "li";
                            break;
                        case "li":
                            var className = node.getAttr("class");
                            if (!className || !/list\-/.test(className)) {
                                node.setAttr();
                            }
                            var tmpNodes = node.getNodesByTagName("ol ul");
                            UE.utils.each(tmpNodes, function (n) {
                                node.parentNode.insertAfter(n, node);
                            });
                            break;
                        case "td":
                        case "th":
                        case "caption":
                            if (!node.children || !node.children.length) {
                                node.appendChild(
                                    browser.ie11below
                                        ? UE.uNode.createText(" ")
                                        : UE.uNode.createElement("br")
                                );
                            }
                            break;
                        case "table":
                            if (me.options.disabledTableInTable && tdParent(node)) {
                                node.parentNode.insertBefore(
                                    UE.uNode.createText(node.innerText()),
                                    node
                                );
                                node.parentNode.removeChild(node);
                            }
                    }
                }
                //            if(node.type == 'comment'){
                //                node.parentNode.removeChild(node);
                //            }
            });
        });

        //从编辑器出去的内容处理
        me.addOutputRule(function (root) {
            var val;
            root.traversal(function (node) {
                if (node.type == "element") {
                    if (
                        me.options.autoClearEmptyNode &&
                        dtd.$inline[node.tagName] &&
                        !dtd.$empty[node.tagName] &&
                        (!node.attrs || utils.isEmptyObject(node.attrs))
                    ) {
                        if (!node.firstChild()) node.parentNode.removeChild(node);
                        else if (
                            node.tagName == "span" &&
                            (!node.attrs || utils.isEmptyObject(node.attrs))
                        ) {
                            node.parentNode.removeChild(node, true);
                        }
                        return;
                    }
                    switch (node.tagName) {
                        case "div":
                            if ((val = node.getAttr("cdata_tag"))) {
                                node.tagName = val;
                                node.appendChild(UE.uNode.createText(node.getAttr("cdata_data")));
                                node.setAttr({
                                    cdata_tag: "",
                                    cdata_data: "",
                                    _ue_custom_node_: ""
                                });
                            }
                            break;
                        case "a":
                            if ((val = node.getAttr("_href"))) {
                                node.setAttr({
                                    href: utils.html(val),
                                    _href: ""
                                });
                            }
                            break;
                            break;
                        case "span":
                            val = node.getAttr("id");
                            if (val && /^_baidu_bookmark_/i.test(val)) {
                                node.parentNode.removeChild(node);
                            }
                            //将color的rgb格式转换为#16进制格式
                            if (me.getOpt("rgb2Hex")) {
                                var cssStyle = node.getAttr("style");
                                if (cssStyle) {
                                    node.setAttr(
                                        "style",
                                        cssStyle.replace(/rgba?\(([\d,\s]+)\)/g, function (a, 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;
                                            }
                                            return value.toUpperCase();
                                        })
                                    );
                                }
                            }
                            break;
                        case "img":
                            if ((val = node.getAttr("_src"))) {
                                node.setAttr({
                                    src: node.getAttr("_src"),
                                    _src: ""
                                });
                            }
                    }
                }
            });
        });
    };


// plugins/inserthtml.js
    /**
     * 插入html字符串插件
     * @file
     * @since 1.2.6.1
     */

    /**
     * 插入html代码
     * @command inserthtml
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { String } html 插入的html字符串
     * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入
     * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。
     * @example
     * ```javascript
     * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本
     * //执行命令,插入<b>CC</b>
     * //插入后的效果 xxx<b>CC</b>xxx
     * //<p>xx|xxx</p> 当前选区为闭合状态
     * //插入<p>CC</p>
     * //结果 <p>xx</p><p>CC</p><p>xxx</p>
     * //<p>xxxx</p>|</p>xxx</p> 当前选区在两个p标签之间
     * //插入 xxxx
     * //结果 <p>xxxx</p><p>xxxx</p></p>xxx</p>
     * ```
     */

    UE.commands["inserthtml"] = {
        execCommand: function (command, html, notNeedFilter) {
            var me = this,
                range,
                div;
            if (!html) {
                return;
            }
            if (me.fireEvent("beforeinserthtml", html) === true) {
                return;
            }
            range = me.selection.getRange();
            div = range.document.createElement("div");
            div.style.display = "inline";

            if (!notNeedFilter) {
                var root = UE.htmlparser(html);
                //如果给了过滤规则就先进行过滤
                if (me.options.filterRules) {
                    UE.filterNode(root, me.options.filterRules);
                }
                //执行默认的处理
                me.filterInputRule(root);
                html = root.toHtml();
            }
            div.innerHTML = utils.trim(html);

            if (!range.collapsed) {
                var tmpNode = range.startContainer;
                if (domUtils.isFillChar(tmpNode)) {
                    range.setStartBefore(tmpNode);
                }
                tmpNode = range.endContainer;
                if (domUtils.isFillChar(tmpNode)) {
                    range.setEndAfter(tmpNode);
                }
                range.txtToElmBoundary();
                //结束边界可能放到了br的前边,要把br包含进来
                // x[xxx]<br/>
                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 = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
                            range.setStart(me.body.firstChild, 0).collapse(true);
                        }
                    }
                }
                !range.collapsed && range.deleteContents();
                if (range.startContainer.nodeType == 1) {
                    var child = range.startContainer.childNodes[range.startOffset],
                        pre;
                    if (
                        child &&
                        domUtils.isBlockElm(child) &&
                        (pre = child.previousSibling) &&
                        domUtils.isBlockElm(pre)
                    ) {
                        range.setEnd(pre, pre.childNodes.length).collapse();
                        while (child.firstChild) {
                            pre.appendChild(child.firstChild);
                        }
                        domUtils.remove(child);
                    }
                }
            }

            var child,
                parent,
                pre,
                tmp,
                hadBreak = 0,
                nextNode;
            //如果当前位置选中了fillchar要干掉,要不会产生空行
            if (range.inFillChar()) {
                child = range.startContainer;
                if (domUtils.isFillChar(child)) {
                    range.setStartBefore(child).collapse(true);
                    domUtils.remove(child);
                } else if (domUtils.isFillChar(child, true)) {
                    child.nodeValue = child.nodeValue.replace(fillCharReg, "");
                    range.startOffset--;
                    range.collapsed && range.collapse(true);
                }
            }
            //列表单独处理
            var li = domUtils.findParentByTagName(range.startContainer, "li", true);
            if (li) {
                var next, last;
                while ((child = div.firstChild)) {
                    //针对hr单独处理一下先
                    while (
                        child &&
                        (child.nodeType == 3 ||
                            !domUtils.isBlockElm(child) ||
                            child.tagName == "HR")
                        ) {
                        next = child.nextSibling;
                        range.insertNode(child).collapse();
                        last = child;
                        child = next;
                    }
                    if (child) {
                        if (/^(ol|ul)$/i.test(child.tagName)) {
                            while (child.firstChild) {
                                last = child.firstChild;
                                domUtils.insertAfter(li, child.firstChild);
                                li = li.nextSibling;
                            }
                            domUtils.remove(child);
                        } else {
                            var tmpLi;
                            next = child.nextSibling;
                            tmpLi = me.document.createElement("li");
                            domUtils.insertAfter(li, tmpLi);
                            tmpLi.appendChild(child);
                            last = child;
                            child = next;
                            li = tmpLi;
                        }
                    }
                }
                li = domUtils.findParentByTagName(range.startContainer, "li", true);
                if (domUtils.isEmptyBlock(li)) {
                    domUtils.remove(li);
                }
                if (last) {
                    range.setStartAfter(last).collapse(true).select(true);
                }
            } else {
                while ((child = div.firstChild)) {
                    if (hadBreak) {
                        var p = me.document.createElement("p");
                        while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
                            nextNode = child.nextSibling;
                            p.appendChild(child);
                            child = nextNode;
                        }
                        if (p.firstChild) {
                            child = p;
                        }
                    }
                    range.insertNode(child);
                    nextNode = child.nextSibling;
                    if (
                        !hadBreak &&
                        child.nodeType == domUtils.NODE_ELEMENT &&
                        domUtils.isBlockElm(child)
                    ) {
                        parent = domUtils.findParent(child, function (node) {
                            return domUtils.isBlockElm(node);
                        });
                        if (
                            parent &&
                            parent.tagName.toLowerCase() != "body" &&
                            !(
                                dtd[parent.tagName][child.nodeName] && child.parentNode === parent
                            )
                        ) {
                            if (!dtd[parent.tagName][child.nodeName]) {
                                pre = parent;
                            } else {
                                tmp = child.parentNode;
                                while (tmp !== parent) {
                                    pre = tmp;
                                    tmp = tmp.parentNode;
                                }
                            }

                            domUtils.breakParent(child, pre || tmp);
                            //去掉break后前一个多余的节点  <p>|<[p> ==> <p></p><div></div><p>|</p>
                            var pre = child.previousSibling;
                            domUtils.trimWhiteTextNode(pre);
                            if (!pre.childNodes.length) {
                                domUtils.remove(pre);
                            }
                            //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位

                            if (
                                !browser.ie &&
                                (next = child.nextSibling) &&
                                domUtils.isBlockElm(next) &&
                                next.lastChild &&
                                !domUtils.isBr(next.lastChild)
                            ) {
                                next.appendChild(me.document.createElement("br"));
                            }
                            hadBreak = 1;
                        }
                    }
                    var next = child.nextSibling;
                    if (!div.firstChild && next && domUtils.isBlockElm(next)) {
                        range.setStart(next, 0).collapse(true);
                        break;
                    }
                    range.setEndAfter(child).collapse();
                }

                child = range.startContainer;

                if (nextNode && domUtils.isBr(nextNode)) {
                    domUtils.remove(nextNode);
                }
                //用chrome可能有空白展位符
                if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
                    if ((nextNode = child.nextSibling)) {
                        domUtils.remove(child);
                        if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
                            range.setStart(nextNode, 0).collapse(true).shrinkBoundary();
                        }
                    } else {
                        try {
                            child.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
                        } catch (e) {
                            range.setStartBefore(child);
                            domUtils.remove(child);
                        }
                    }
                }
                //加上true因为在删除表情等时会删两次,第一次是删的fillData
                try {
                    range.select(true);
                } catch (e) {
                }
            }

            setTimeout(function () {
                range = me.selection.getRange();
                range.scrollToView(
                    me.autoHeightEnabled,
                    me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0
                );
                me.fireEvent("afterinserthtml", html);
            }, 200);
        }
    };


// plugins/autotypeset.js
    /**
     * 自动排版
     * @file
     * @since 1.2.6.1
     */

    /**
     * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。
     * @command autotypeset
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'autotypeset' );
     * ```
     */

    UE.plugins["autotypeset"] = function () {
        this.setOpt({
            autotypeset: {
                mergeEmptyline: true, //合并空行
                removeClass: true, //去掉冗余的class
                removeEmptyline: false, //去掉空行
                textAlign: "left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
                imageBlockLine: "center", //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
                pasteFilter: false, //根据规则过滤没事粘贴进来的内容
                clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
                clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
                removeEmptyNode: false, // 去掉空节点
                //可以去掉的标签
                removeTagNames: utils.extend({div: 1}, dtd.$removeEmpty),
                indent: false, // 行首缩进
                indentValue: "2em", //行首缩进的大小
                bdc2sb: false,
                tobdc: false
            }
        });

        var me = this,
            opt = me.options.autotypeset,
            remainClass = {
                selectTdClass: 1,
                pagebreak: 1,
                anchorclass: 1
            },
            remainTag = {
                li: 1
            },
            tags = {
                div: 1,
                p: 1,
                //trace:2183 这些也认为是行
                blockquote: 1,
                center: 1,
                h1: 1,
                h2: 1,
                h3: 1,
                h4: 1,
                h5: 1,
                h6: 1,
                span: 1
            },
            highlightCont;
        //升级了版本,但配置项目里没有autotypeset
        if (!opt) {
            return;
        }

        readLocalOpts();

        function isLine(node, notEmpty) {
            if (!node || node.nodeType == 3) return 0;
            if (domUtils.isBr(node)) return 1;
            if (node && node.parentNode && tags[node.tagName.toLowerCase()]) {
                if (
                    (highlightCont && highlightCont.contains(node)) ||
                    node.getAttribute("pagebreak")
                ) {
                    return 0;
                }

                return notEmpty
                    ? !domUtils.isEmptyBlock(node)
                    : domUtils.isEmptyBlock(
                        node,
                        new RegExp("[\\s" + domUtils.fillChar + "]", "g")
                    );
            }
        }

        function removeNotAttributeSpan(node) {
            if (!node.style.cssText) {
                domUtils.removeAttributes(node, ["style"]);
                if (
                    node.tagName.toLowerCase() == "span" &&
                    domUtils.hasNoAttributes(node)
                ) {
                    domUtils.remove(node, true);
                }
            }
        }

        function autotype(type, html) {
            var me = this,
                cont;
            if (html) {
                if (!opt.pasteFilter) {
                    return;
                }
                cont = me.document.createElement("div");
                cont.innerHTML = html.html;
            } else {
                cont = me.document.body;
            }
            var nodes = domUtils.getElementsByTagName(cont, "*");

            // 行首缩进,段落方向,段间距,段内间距
            for (var i = 0, ci; (ci = nodes[i++]);) {
                if (me.fireEvent("excludeNodeinautotype", ci) === true) {
                    continue;
                }
                //font-size
                if (opt.clearFontSize && ci.style.fontSize) {
                    domUtils.removeStyle(ci, "font-size");

                    removeNotAttributeSpan(ci);
                }
                //font-family
                if (opt.clearFontFamily && ci.style.fontFamily) {
                    domUtils.removeStyle(ci, "font-family");
                    removeNotAttributeSpan(ci);
                }

                if (isLine(ci)) {
                    //合并空行
                    if (opt.mergeEmptyline) {
                        var next = ci.nextSibling,
                            tmpNode,
                            isBr = domUtils.isBr(ci);
                        while (isLine(next)) {
                            tmpNode = next;
                            next = tmpNode.nextSibling;
                            if (isBr && (!next || (next && !domUtils.isBr(next)))) {
                                break;
                            }
                            domUtils.remove(tmpNode);
                        }
                    }
                    //去掉空行,保留占位的空行
                    if (
                        opt.removeEmptyline &&
                        domUtils.inDoc(ci, cont) &&
                        !remainTag[ci.parentNode.tagName.toLowerCase()]
                    ) {
                        if (domUtils.isBr(ci)) {
                            next = ci.nextSibling;
                            if (next && !domUtils.isBr(next)) {
                                continue;
                            }
                        }
                        domUtils.remove(ci);
                        continue;
                    }
                }
                if (isLine(ci, true) && ci.tagName != "SPAN") {
                    if (opt.indent) {
                        ci.style.textIndent = opt.indentValue;
                    }
                    if (opt.textAlign) {
                        ci.style.textAlign = opt.textAlign;
                    }
                    // if(opt.lineHeight)
                    //     ci.style.lineHeight = opt.lineHeight + 'cm';
                }

                //去掉class,保留的class不去掉
                if (
                    opt.removeClass &&
                    ci.className &&
                    !remainClass[ci.className.toLowerCase()]
                ) {
                    if (highlightCont && highlightCont.contains(ci)) {
                        continue;
                    }
                    domUtils.removeAttributes(ci, ["class"]);
                }

                //表情不处理
                if (
                    opt.imageBlockLine &&
                    ci.tagName.toLowerCase() == "img" &&
                    !ci.getAttribute("emotion")
                ) {
                    if (html) {
                        var img = ci;
                        switch (opt.imageBlockLine) {
                            case "left":
                            case "right":
                            case "none":
                                var pN = img.parentNode,
                                    tmpNode,
                                    pre,
                                    next;
                                while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
                                    pN = pN.parentNode;
                                }
                                tmpNode = pN;
                                if (
                                    tmpNode.tagName == "P" &&
                                    domUtils.getStyle(tmpNode, "text-align") == "center"
                                ) {
                                    if (
                                        !domUtils.isBody(tmpNode) &&
                                        domUtils.getChildCount(tmpNode, function (node) {
                                            return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
                                        }) == 1
                                    ) {
                                        pre = tmpNode.previousSibling;
                                        next = tmpNode.nextSibling;
                                        if (
                                            pre &&
                                            next &&
                                            pre.nodeType == 1 &&
                                            next.nodeType == 1 &&
                                            pre.tagName == next.tagName &&
                                            domUtils.isBlockElm(pre)
                                        ) {
                                            pre.appendChild(tmpNode.firstChild);
                                            while (next.firstChild) {
                                                pre.appendChild(next.firstChild);
                                            }
                                            domUtils.remove(tmpNode);
                                            domUtils.remove(next);
                                        } else {
                                            domUtils.setStyle(tmpNode, "text-align", "");
                                        }
                                    }
                                }
                                domUtils.setStyle(img, "float", opt.imageBlockLine);
                                break;
                            case "center":
                                if (me.queryCommandValue("imagefloat") != "center") {
                                    pN = img.parentNode;
                                    domUtils.setStyle(img, "float", "none");
                                    tmpNode = img;
                                    while (
                                        pN &&
                                        domUtils.getChildCount(pN, function (node) {
                                            return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
                                        }) == 1 &&
                                        (dtd.$inline[pN.tagName] || pN.tagName == "A")
                                        ) {
                                        tmpNode = pN;
                                        pN = pN.parentNode;
                                    }
                                    var pNode = me.document.createElement("p");
                                    domUtils.setAttributes(pNode, {
                                        style: "text-align:center"
                                    });
                                    tmpNode.parentNode.insertBefore(pNode, tmpNode);
                                    pNode.appendChild(tmpNode);
                                    domUtils.setStyle(tmpNode, "float", "");
                                }
                        }
                    } else {
                        var range = me.selection.getRange();
                        range.selectNode(ci).select();
                        me.execCommand("imagefloat", opt.imageBlockLine);
                    }
                }

                //去掉冗余的标签
                if (opt.removeEmptyNode) {
                    if (
                        opt.removeTagNames[ci.tagName.toLowerCase()] &&
                        domUtils.hasNoAttributes(ci) &&
                        domUtils.isEmptyBlock(ci)
                    ) {
                        domUtils.remove(ci);
                    }
                }
            }
            if (opt.tobdc) {
                var root = UE.htmlparser(cont.innerHTML);
                root.traversal(function (node) {
                    if (node.type == "text") {
                        node.data = ToDBC(node.data);
                    }
                });
                cont.innerHTML = root.toHtml();
            }
            if (opt.bdc2sb) {
                var root = UE.htmlparser(cont.innerHTML);
                root.traversal(function (node) {
                    if (node.type == "text") {
                        node.data = DBC2SB(node.data);
                    }
                });
                cont.innerHTML = root.toHtml();
            }
            if (html) {
                html.html = cont.innerHTML;
            }
        }

        if (opt.pasteFilter) {
            me.addListener("beforepaste", autotype);
        }

        function DBC2SB(str) {
            var result = "";
            for (var i = 0; i < str.length; i++) {
                var code = str.charCodeAt(i); //获取当前字符的unicode编码
                if (code >= 65281 && code <= 65373) {
                    //在这个unicode编码范围中的是所有的英文字母已经各种字符
                    result += String.fromCharCode(str.charCodeAt(i) - 65248); //把全角字符的unicode编码转换为对应半角字符的unicode码
                } else if (code == 12288) {
                    //空格
                    result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
                } else {
                    result += str.charAt(i);
                }
            }
            return result;
        }

        function ToDBC(txtstring) {
            txtstring = utils.html(txtstring);
            var tmp = "";
            var mark = "";
            /*用于判断,如果是html尖括里的标记,则不进行全角的转换*/
            for (var i = 0; i < txtstring.length; i++) {
                if (txtstring.charCodeAt(i) == 32) {
                    tmp = tmp + String.fromCharCode(12288);
                } else if (txtstring.charCodeAt(i) < 127) {
                    tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248);
                } else {
                    tmp += txtstring.charAt(i);
                }
            }
            return tmp;
        }

        function readLocalOpts() {
            var cookieOpt = me.getPreferences("autotypeset");
            utils.extend(me.options.autotypeset, cookieOpt);
        }

        me.commands["autotypeset"] = {
            execCommand: function () {
                me.removeListener("beforepaste", autotype);
                if (opt.pasteFilter) {
                    me.addListener("beforepaste", autotype);
                }
                autotype.call(me);
            }
        };
    };


// plugins/autosubmit.js
    /**
     * 快捷键提交
     * @file
     * @since 1.2.6.1
     */

    /**
     * 提交表单
     * @command autosubmit
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'autosubmit' );
     * ```
     */

    UE.plugin.register("autosubmit", function () {
        return {
            shortcutkey: {
                autosubmit: "ctrl+13" //手动提交
            },
            commands: {
                autosubmit: {
                    execCommand: function () {
                        var me = this,
                            form = domUtils.findParentByTagName(me.iframe, "form", false);
                        if (form) {
                            if (me.fireEvent("beforesubmit") === false) {
                                return;
                            }
                            me.sync();
                            form.submit();
                        }
                    }
                }
            }
        };
    });


// plugins/background.js
    /**
     * 背景插件,为UEditor提供设置背景功能
     * @file
     * @since 1.2.6.1
     */
    UE.plugin.register("background", function () {
        var me = this,
            cssRuleId = "editor_background",
            isSetColored,
            reg = new RegExp("body[\\s]*\\{(.+)\\}", "i");

        function stringToObj(str) {
            var obj = {},
                styles = str.split(";");
            utils.each(styles, function (v) {
                var index = v.indexOf(":"),
                    key = utils.trim(v.substr(0, index)).toLowerCase();
                key && (obj[key] = utils.trim(v.substr(index + 1) || ""));
            });
            return obj;
        }

        function setBackground(obj) {
            if (obj) {
                var styles = [];
                for (var name in obj) {
                    if (obj.hasOwnProperty(name)) {
                        styles.push(name + ":" + obj[name] + "; ");
                    }
                }
                utils.cssRule(
                    cssRuleId,
                    styles.length ? "body{" + styles.join("") + "}" : "",
                    me.document
                );
            } else {
                utils.cssRule(cssRuleId, "", me.document);
            }
        }

        //重写editor.hasContent方法

        var orgFn = me.hasContents;
        me.hasContents = function () {
            if (me.queryCommandValue("background")) {
                return true;
            }
            return orgFn.apply(me, arguments);
        };
        return {
            bindEvents: {
                getAllHtml: function (type, headHtml) {
                    var body = this.body,
                        su = domUtils.getComputedStyle(body, "background-image"),
                        url = "";
                    if (su.indexOf(me.options.imagePath) > 0) {
                        url = su
                            .substring(su.indexOf(me.options.imagePath), su.length - 1)
                            .replace(/"|\(|\)/gi, "");
                    } else {
                        url = su != "none" ? su.replace(/url\("?|"?\)/gi, "") : "";
                    }
                    var html = '<style type="text/css">body{';
                    var bgObj = {
                        "background-color":
                        domUtils.getComputedStyle(body, "background-color") || "#ffffff",
                        "background-image": url ? "url(" + url + ")" : "",
                        "background-repeat":
                        domUtils.getComputedStyle(body, "background-repeat") || "",
                        "background-position": browser.ie
                            ? domUtils.getComputedStyle(body, "background-position-x") +
                            " " +
                            domUtils.getComputedStyle(body, "background-position-y")
                            : domUtils.getComputedStyle(body, "background-position"),
                        height: domUtils.getComputedStyle(body, "height")
                    };
                    for (var name in bgObj) {
                        if (bgObj.hasOwnProperty(name)) {
                            html += name + ":" + bgObj[name] + "; ";
                        }
                    }
                    html += "}</style> ";
                    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(
                            '<p style="display:none;" data-background="' +
                            utils.trim(styles[1].replace(/"/g, "").replace(/[\s]+/g, " ")) +
                            '"><br/></p>'
                        )
                    );
                }
            },
            commands: {
                background: {
                    execCommand: function (cmd, obj) {
                        setBackground(obj);
                    },
                    queryCommandValue: function () {
                        var me = this,
                            styles = (utils.cssRule(cssRuleId, me.document) || "")
                                .replace(/[\n\r]+/g, "")
                                .match(reg);
                        return styles ? stringToObj(styles[1]) : null;
                    },
                    notNeedUndo: true
                }
            }
        };
    });


// plugins/image.js
    /**
     * 图片插入、排版插件
     * @file
     * @since 1.2.6.1
     */

    /**
     * 图片对齐方式
     * @command imagefloat
     * @method execCommand
     * @remind 值center为独占一行居中
     * @param { String } cmd 命令字符串
     * @param { String } align 对齐方式,可传left、right、none、center
     * @remaind center表示图片独占一行
     * @example
     * ```javascript
     * editor.execCommand( 'imagefloat', 'center' );
     * ```
     */

    /**
     * 如果选区所在位置是图片区域
     * @command imagefloat
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { String } 返回图片对齐方式
     * @example
     * ```javascript
     * editor.queryCommandValue( 'imagefloat' );
     * ```
     */

    UE.commands["imagefloat"] = {
        execCommand: function (cmd, align) {
            var me = this,
                range = me.selection.getRange();
            if (!range.collapsed) {
                var img = range.getClosedNode();
                if (img && img.tagName == "IMG") {
                    switch (align) {
                        case "left":
                        case "right":
                        case "none":
                            var pN = img.parentNode,
                                tmpNode,
                                pre,
                                next;
                            while (dtd.$inline[pN.tagName] || pN.tagName == "A") {
                                pN = pN.parentNode;
                            }
                            tmpNode = pN;
                            if (
                                tmpNode.tagName == "P" &&
                                domUtils.getStyle(tmpNode, "text-align") == "center"
                            ) {
                                if (
                                    !domUtils.isBody(tmpNode) &&
                                    domUtils.getChildCount(tmpNode, function (node) {
                                        return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
                                    }) == 1
                                ) {
                                    pre = tmpNode.previousSibling;
                                    next = tmpNode.nextSibling;
                                    if (
                                        pre &&
                                        next &&
                                        pre.nodeType == 1 &&
                                        next.nodeType == 1 &&
                                        pre.tagName == next.tagName &&
                                        domUtils.isBlockElm(pre)
                                    ) {
                                        pre.appendChild(tmpNode.firstChild);
                                        while (next.firstChild) {
                                            pre.appendChild(next.firstChild);
                                        }
                                        domUtils.remove(tmpNode);
                                        domUtils.remove(next);
                                    } else {
                                        domUtils.setStyle(tmpNode, "text-align", "");
                                    }
                                }

                                range.selectNode(img).select();
                            }
                            domUtils.setStyle(img, "float", align == "none" ? "" : align);
                            if (align == "none") {
                                domUtils.removeAttributes(img, "align");
                            }

                            break;
                        case "center":
                            if (me.queryCommandValue("imagefloat") != "center") {
                                var pN = img.parentNode;
                                domUtils.setStyle(img, "float", "");
                                domUtils.removeAttributes(img, "align");
                                tmpNode = img;
                                while (
                                    pN &&
                                    domUtils.getChildCount(pN, function (node) {
                                        return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
                                    }) == 1 &&
                                    (dtd.$inline[pN.tagName] || pN.tagName == "A")
                                    ) {
                                    tmpNode = pN;
                                    pN = pN.parentNode;
                                }
                                range.setStartBefore(tmpNode).setCursor(false);
                                pN = me.document.createElement("div");
                                pN.appendChild(tmpNode);
                                domUtils.setStyle(tmpNode, "float", "");

                                me.execCommand(
                                    "insertHtml",
                                    '<p class="_img_parent_tmp" style="text-align:center">' +
                                    pN.innerHTML +
                                    "</p>"
                                );

                                tmpNode = me.document.getElementsByClassName("_img_parent_tmp")[0];
                                tmpNode.removeAttribute("class");
                                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;
            }

            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) {
                    str =
                        '<img src="' +
                        ci.src +
                        '" ' +
                        (ci._src ? ' _src="' + ci._src + '" ' : "") +
                        (ci.width ? 'width="' + ci.width + '" ' : "") +
                        (ci.height ? ' height="' + ci.height + '" ' : "") +
                        (ci["floatStyle"] == "left" || ci["floatStyle"] == "right"
                            ? ' style="float:' + ci["floatStyle"] + ';"'
                            : "") +
                        (ci.title && ci.title != "" ? ' title="' + ci.title + '"' : "") +
                        (ci.border && ci.border != "0" ? ' border="' + ci.border + '"' : "") +
                        (ci.alt && ci.alt != "" ? ' alt="' + ci.alt + '"' : "") +
                        (ci.hspace && ci.hspace != "0"
                            ? ' hspace = "' + ci.hspace + '"'
                            : "") +
                        (ci.vspace && ci.vspace != "0"
                            ? ' vspace = "' + ci.vspace + '"'
                            : "") +
                        "/>";
                    if (ci["floatStyle"] == "center") {
                        str = '<p style="text-align: center">' + str + "</p>";
                    }
                    html.push(str);
                } else {
                    for (var i = 0; (ci = opt[i++]);) {
                        str =
                            "<p " +
                            (ci["floatStyle"] == "center"
                                ? 'style="text-align: center" '
                                : "") +
                            '><img src="' +
                            ci.src +
                            '" ' +
                            (ci.width ? 'width="' + ci.width + '" ' : "") +
                            (ci._src ? ' _src="' + ci._src + '" ' : "") +
                            (ci.height ? ' height="' + ci.height + '" ' : "") +
                            ' style="' +
                            (ci["floatStyle"] && ci["floatStyle"] != "center"
                                ? "float:" + ci["floatStyle"] + ";"
                                : "") +
                            (ci.border || "") +
                            '" ' +
                            (ci.title ? ' title="' + ci.title + '"' : "") +
                            " /></p>";
                        html.push(str);
                    }
                }

                me.execCommand("insertHtml", html.join(""));
            }

            me.fireEvent("afterinsertimage", opt);
        }
    };


// plugins/justify.js
    /**
     * 段落格式
     * @file
     * @since 1.2.6.1
     */

    /**
     * 段落对齐方式
     * @command justify
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐
     * @example
     * ```javascript
     * editor.execCommand( 'justify', 'center' );
     * ```
     */
    /**
     * 如果选区所在位置是段落区域,返回当前段落对齐方式
     * @command justify
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { String } 返回段落对齐方式
     * @example
     * ```javascript
     * editor.queryCommandValue( 'justify' );
     * ```
     */

    UE.plugins["justify"] = function () {
        var me = this,
            block = domUtils.isBlockElm,
            defaultValue = {
                left: 1,
                right: 1,
                center: 1,
                justify: 1
            },
            doJustify = function (range, style) {
                var bookmark = range.createBookmark(),
                    filterFn = function (node) {
                        return node.nodeType == 1
                            ? node.tagName.toLowerCase() != "br" &&
                            !domUtils.isBookmarkNode(node)
                            : !domUtils.isWhitespace(node);
                    };

                range.enlarge(true);
                var bookmark2 = range.createBookmark(),
                    current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
                    tmpRange = range.cloneRange(),
                    tmpNode;
                while (
                    current &&
                    !(
                        domUtils.getPosition(current, bookmark2.end) &
                        domUtils.POSITION_FOLLOWING
                    )
                    ) {
                    if (current.nodeType == 3 || !block(current)) {
                        tmpRange.setStartBefore(current);
                        while (current && current !== bookmark2.end && !block(current)) {
                            tmpNode = current;
                            current = domUtils.getNextDomNode(current, false, null, function (
                                node
                            ) {
                                return !block(node);
                            });
                        }
                        tmpRange.setEndAfter(tmpNode);
                        var common = tmpRange.getCommonAncestor();
                        if (!domUtils.isBody(common) && block(common)) {
                            domUtils.setStyles(
                                common,
                                utils.isString(style) ? {"text-align": style} : style
                            );
                            current = common;
                        } else {
                            var p = range.document.createElement("p");
                            domUtils.setStyles(
                                p,
                                utils.isString(style) ? {"text-align": style} : style
                            );
                            var frag = tmpRange.extractContents();
                            p.appendChild(frag);
                            tmpRange.insertNode(p);
                            current = p;
                        }
                        current = domUtils.getNextDomNode(current, false, filterFn);
                    } else {
                        current = domUtils.getNextDomNode(current, true, filterFn);
                    }
                }
                return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
            };

        UE.commands["justify"] = {
            execCommand: function (cmdName, align) {
                var range = this.selection.getRange(),
                    txt;

                //闭合时单独处理
                if (range.collapsed) {
                    txt = this.document.createTextNode("p");
                    range.insertNode(txt);
                }
                doJustify(range, align);
                if (txt) {
                    range.setStartBefore(txt).collapse(true);
                    domUtils.remove(txt);
                }

                range.select();

                return true;
            },
            queryCommandValue: function () {
                var startNode = this.selection.getStart(),
                    value = domUtils.getComputedStyle(startNode, "text-align");
                return defaultValue[value] ? value : "left";
            },
            queryCommandState: function () {
                var start = this.selection.getStart(),
                    cell =
                        start &&
                        domUtils.findParentByTagName(start, ["td", "th", "caption"], true);

                return cell ? -1 : 0;
            }
        };
    };


// plugins/font.js
    /**
     * 字体颜色,背景色,字号,字体,下划线,删除线
     * @file
     * @since 1.2.6.1
     */

    /**
     * 字体颜色
     * @command forecolor
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { String } value 色值(必须十六进制)
     * @example
     * ```javascript
     * editor.execCommand( 'forecolor', '#000' );
     * ```
     */
    /**
     * 返回选区字体颜色
     * @command forecolor
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { String } 返回字体颜色
     * @example
     * ```javascript
     * editor.queryCommandValue( 'forecolor' );
     * ```
     */

    /**
     * 字体背景颜色
     * @command backcolor
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { String } value 色值(必须十六进制)
     * @example
     * ```javascript
     * editor.execCommand( 'backcolor', '#000' );
     * ```
     */
    /**
     * 返回选区字体颜色
     * @command backcolor
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { String } 返回字体背景颜色
     * @example
     * ```javascript
     * editor.queryCommandValue( 'backcolor' );
     * ```
     */

    /**
     * 字体大小
     * @command fontsize
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { String } value 字体大小
     * @example
     * ```javascript
     * editor.execCommand( 'fontsize', '14px' );
     * ```
     */
    /**
     * 返回选区字体大小
     * @command fontsize
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { String } 返回字体大小
     * @example
     * ```javascript
     * editor.queryCommandValue( 'fontsize' );
     * ```
     */

    /**
     * 字体样式
     * @command fontfamily
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { String } value 字体样式
     * @example
     * ```javascript
     * editor.execCommand( 'fontfamily', '微软雅黑' );
     * ```
     */
    /**
     * 返回选区字体样式
     * @command fontfamily
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { String } 返回字体样式
     * @example
     * ```javascript
     * editor.queryCommandValue( 'fontfamily' );
     * ```
     */

    /**
     * 字体下划线,与删除线互斥
     * @command underline
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'underline' );
     * ```
     */

    /**
     * 字体删除线,与下划线互斥
     * @command strikethrough
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'strikethrough' );
     * ```
     */

    /**
     * 字体边框
     * @command fontborder
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'fontborder' );
     * ```
     */

    UE.plugins["font"] = function () {
        var me = this,
            fonts = {
                forecolor: "color",
                backcolor: "background-color",
                fontsize: "font-size",
                fontfamily: "font-family",
                underline: "text-decoration",
                strikethrough: "text-decoration",
                fontborder: "border"
            },
            needCmd = {underline: 1, strikethrough: 1, fontborder: 1},
            needSetChild = {
                forecolor: "color",
                backcolor: "background-color",
                fontsize: "font-size",
                fontfamily: "font-family"
            };
        me.setOpt({
            fontfamily: [
                {name: "songti", val: "宋体,SimSun"},
                {name: "yahei", val: "微软雅黑,Microsoft YaHei"},
                {name: "kaiti", val: "楷体,楷体_GB2312, SimKai"},
                {name: "heiti", val: "黑体, SimHei"},
                {name: "lishu", val: "隶书, SimLi"},
                {name: "andaleMono", val: "andale mono"},
                {name: "arial", val: "arial, helvetica,sans-serif"},
                {name: "arialBlack", val: "arial black,avant garde"},
                {name: "comicSansMs", val: "comic sans ms"},
                {name: "impact", val: "impact,chicago"},
                {name: "timesNewRoman", val: "times new roman"}
            ],
            fontsize: [10, 11, 12, 14, 16, 18, 20, 24, 36]
        });

        function mergeWithParent(node) {
            var parent;
            while ((parent = node.parentNode)) {
                if (
                    parent.tagName == "SPAN" &&
                    domUtils.getChildCount(parent, function (child) {
                        return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child);
                    }) == 1
                ) {
                    parent.style.cssText += node.style.cssText;
                    domUtils.remove(node, true);
                    node = parent;
                } else {
                    break;
                }
            }
        }

        function mergeChild(rng, cmdName, value) {
            if (needSetChild[cmdName]) {
                rng.adjustmentBoundary();
                if (!rng.collapsed && rng.startContainer.nodeType == 1) {
                    rng.traversal(function (node) {
                        var start;
                        if (domUtils.isTagNode(node, 'span')) {
                            start = node;
                        } else {
                            start = domUtils.getElementsByTagName(node, 'span')[0];
                        }
                        if (start && domUtils.isTagNode(start, "span")) {
                            var bk = rng.createBookmark();
                            utils.each(domUtils.getElementsByTagName(start, "span"), function (
                                span
                            ) {
                                if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
                                if (
                                    cmdName == "backcolor" &&
                                    domUtils
                                        .getComputedStyle(span, "background-color")
                                        .toLowerCase() === value
                                ) {
                                    return;
                                }
                                domUtils.removeStyle(span, needSetChild[cmdName]);
                                if (span.style.cssText.replace(/^\s+$/, "").length == 0) {
                                    domUtils.remove(span, true);
                                }
                            });
                            rng.moveToBookmark(bk);
                        }
                    });
                }
            }
        }

        function mergesibling(rng, cmdName, value) {
            var collapsed = rng.collapsed,
                bk = rng.createBookmark(),
                common;
            if (collapsed) {
                common = bk.start.parentNode;
                while (dtd.$inline[common.tagName]) {
                    common = common.parentNode;
                }
            } else {
                common = domUtils.getCommonAncestor(bk.start, bk.end);
            }
            utils.each(domUtils.getElementsByTagName(common, "span"), function (span) {
                if (!span.parentNode || domUtils.isBookmarkNode(span)) return;
                if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
                    if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
                        domUtils.remove(span, true);
                    } else {
                        domUtils.removeStyle(span, "border");
                    }
                    return;
                }
                if (
                    /border/i.test(span.style.cssText) &&
                    span.parentNode.tagName == "SPAN" &&
                    /border/i.test(span.parentNode.style.cssText)
                ) {
                    span.style.cssText = span.style.cssText.replace(
                        /border[^:]*:[^;]+;?/gi,
                        ""
                    );
                }
                if (!(cmdName == "fontborder" && value == "none")) {
                    var next = span.nextSibling;
                    while (next && next.nodeType == 1 && next.tagName == "SPAN") {
                        if (domUtils.isBookmarkNode(next) && cmdName == "fontborder") {
                            span.appendChild(next);
                            next = span.nextSibling;
                            continue;
                        }
                        if (next.style.cssText == span.style.cssText) {
                            domUtils.moveChild(next, span);
                            domUtils.remove(next);
                        }
                        if (span.nextSibling === next) break;
                        next = span.nextSibling;
                    }
                }

                mergeWithParent(span);
                if (browser.ie && browser.version > 8) {
                    //拷贝父亲们的特别的属性,这里只做背景颜色的处理
                    var parent = domUtils.findParent(span, function (n) {
                        return (
                            n.tagName == "SPAN" && /background-color/.test(n.style.cssText)
                        );
                    });
                    if (parent && !/background-color/.test(span.style.cssText)) {
                        span.style.backgroundColor = parent.style.backgroundColor;
                    }
                }
            });
            rng.moveToBookmark(bk);
            mergeChild(rng, cmdName, value);
        }

        me.addInputRule(function (root) {
            utils.each(root.getNodesByTagName("u s del font strike"), function (node) {
                if (node.tagName == "font") {
                    var cssStyle = [];
                    for (var p in node.attrs) {
                        switch (p) {
                            case "size":
                                cssStyle.push(
                                    "font-size:" +
                                    ({
                                        "1": "10",
                                        "2": "12",
                                        "3": "16",
                                        "4": "18",
                                        "5": "24",
                                        "6": "32",
                                        "7": "48"
                                    }[node.attrs[p]] || node.attrs[p]) +
                                    "px"
                                );
                                break;
                            case "color":
                                cssStyle.push("color:" + node.attrs[p]);
                                break;
                            case "face":
                                cssStyle.push("font-family:" + node.attrs[p]);
                                break;
                            case "style":
                                cssStyle.push(node.attrs[p]);
                        }
                    }
                    node.attrs = {
                        style: cssStyle.join(";")
                    };
                } else {
                    var val = node.tagName == "u" ? "underline" : "line-through";
                    node.attrs = {
                        style: (node.getAttr("style") || "") + "text-decoration:" + val + ";"
                    };
                }
                node.tagName = "span";
            });
            //        utils.each(root.getNodesByTagName('span'), function (node) {
            //            var val;
            //            if(val = node.getAttr('class')){
            //                if(/fontstrikethrough/.test(val)){
            //                    node.setStyle('text-decoration','line-through');
            //                    if(node.attrs['class']){
            //                        node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
            //                    }else{
            //                        node.setAttr('class')
            //                    }
            //                }
            //                if(/fontborder/.test(val)){
            //                    node.setStyle('border','1px solid #000');
            //                    if(node.attrs['class']){
            //                        node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
            //                    }else{
            //                        node.setAttr('class')
            //                    }
            //                }
            //            }
            //        });
        });
        //    me.addOutputRule(function(root){
        //        utils.each(root.getNodesByTagName('span'), function (node) {
        //            var val;
        //            if(val = node.getStyle('text-decoration')){
        //                if(/line-through/.test(val)){
        //                    if(node.attrs['class']){
        //                        node.attrs['class'] += ' fontstrikethrough';
        //                    }else{
        //                        node.setAttr('class','fontstrikethrough')
        //                    }
        //                }
        //
        //                node.setStyle('text-decoration')
        //            }
        //            if(val = node.getStyle('border')){
        //                if(/1px/.test(val) && /solid/.test(val)){
        //                    if(node.attrs['class']){
        //                        node.attrs['class'] += ' fontborder';
        //
        //                    }else{
        //                        node.setAttr('class','fontborder')
        //                    }
        //                }
        //                node.setStyle('border')
        //
        //            }
        //        });
        //    });
        for (var p in fonts) {
            (function (cmd, style) {
                UE.commands[cmd] = {
                    execCommand: function (cmdName, value) {
                        value =
                            value ||
                            (this.queryCommandState(cmdName)
                                ? "none"
                                : cmdName == "underline"
                                    ? "underline"
                                    : cmdName == "fontborder" ? "1px solid #000" : "line-through");
                        var me = this,
                            range = this.selection.getRange(),
                            text;

                        if (value == "default") {
                            if (range.collapsed) {
                                text = me.document.createTextNode("font");
                                range.insertNode(text).select();
                            }
                            me.execCommand("removeFormat", "span,a", style);
                            if (text) {
                                range.setStartBefore(text).collapse(true);
                                domUtils.remove(text);
                            }
                            mergesibling(range, cmdName, value);
                            range.select();
                        } else {
                            if (!range.collapsed) {
                                if (needCmd[cmd] && me.queryCommandValue(cmd)) {
                                    me.execCommand("removeFormat", "span,a", style);
                                }
                                range = me.selection.getRange();

                                range.applyInlineStyle("span", {style: style + ":" + value});
                                mergesibling(range, cmdName, value);
                                range.select();
                            } else {
                                var span = domUtils.findParentByTagName(
                                    range.startContainer,
                                    "span",
                                    true
                                );
                                text = me.document.createTextNode("font");
                                if (
                                    span &&
                                    !span.children.length &&
                                    !span[browser.ie ? "innerText" : "textContent"].replace(
                                        fillCharReg,
                                        ""
                                    ).length
                                ) {
                                    //for ie hack when enter
                                    range.insertNode(text);
                                    if (needCmd[cmd]) {
                                        range.selectNode(text).select();
                                        me.execCommand("removeFormat", "span,a", style, null);

                                        span = domUtils.findParentByTagName(text, "span", true);
                                        range.setStartBefore(text);
                                    }
                                    span && (span.style.cssText += ";" + style + ":" + value);
                                    range.collapse(true).select();
                                } else {
                                    range.insertNode(text);
                                    range.selectNode(text).select();
                                    span = range.document.createElement("span");

                                    if (needCmd[cmd]) {
                                        //a标签内的不处理跳过
                                        if (domUtils.findParentByTagName(text, "a", true)) {
                                            range.setStartBefore(text).setCursor();
                                            domUtils.remove(text);
                                            return;
                                        }
                                        me.execCommand("removeFormat", "span,a", style);
                                    }

                                    span.style.cssText = style + ":" + value;

                                    text.parentNode.insertBefore(span, text);
                                    //修复,span套span 但样式不继承的问题
                                    if (!browser.ie || (browser.ie && browser.version == 9)) {
                                        var spanParent = span.parentNode;
                                        while (!domUtils.isBlockElm(spanParent)) {
                                            if (spanParent.tagName == "SPAN") {
                                                //opera合并style不会加入";"
                                                span.style.cssText =
                                                    spanParent.style.cssText + ";" + span.style.cssText;
                                            }
                                            spanParent = spanParent.parentNode;
                                        }
                                    }

                                    if (opera) {
                                        setTimeout(function () {
                                            range.setStart(span, 0).collapse(true);
                                            mergesibling(range, cmdName, value);
                                            range.select();
                                        });
                                    } else {
                                        range.setStart(span, 0).collapse(true);
                                        mergesibling(range, cmdName, value);
                                        range.select();
                                    }

                                    //trace:981
                                    //domUtils.mergeToParent(span)
                                }
                                domUtils.remove(text);
                            }
                        }
                        return true;
                    },
                    queryCommandValue: function (cmdName) {
                        var startNode = this.selection.getStart();

                        //trace:946
                        if (cmdName == "underline" || cmdName == "strikethrough") {
                            var tmpNode = startNode,
                                value;
                            while (
                                tmpNode &&
                                !domUtils.isBlockElm(tmpNode) &&
                                !domUtils.isBody(tmpNode)
                                ) {
                                if (tmpNode.nodeType == 1) {
                                    value = domUtils.getComputedStyle(tmpNode, style);
                                    if (value != "none") {
                                        return value;
                                    }
                                }

                                tmpNode = tmpNode.parentNode;
                            }
                            return "none";
                        }
                        if (cmdName == "fontborder") {
                            var tmp = startNode,
                                val;
                            while (tmp && dtd.$inline[tmp.tagName]) {
                                if ((val = domUtils.getComputedStyle(tmp, "border"))) {
                                    if (/1px/.test(val) && /solid/.test(val)) {
                                        return val;
                                    }
                                }
                                tmp = tmp.parentNode;
                            }
                            return "";
                        }

                        if (cmdName == "FontSize") {
                            var styleVal = domUtils.getComputedStyle(startNode, style),
                                tmp = /^([\d\.]+)(\w+)$/.exec(styleVal);

                            if (tmp) {
                                return Math.floor(tmp[1]) + tmp[2];
                            }

                            return styleVal;
                        }

                        return domUtils.getComputedStyle(startNode, style);
                    },
                    queryCommandState: function (cmdName) {
                        if (!needCmd[cmdName]) return 0;
                        var val = this.queryCommandValue(cmdName);
                        if (cmdName == "fontborder") {
                            return /1px/.test(val) && /solid/.test(val);
                        } else {
                            return cmdName == "underline"
                                ? /underline/.test(val)
                                : /line\-through/.test(val);
                        }
                    }
                };
            })(p, fonts[p]);
        }
    };


// plugins/link.js
    /**
     * 超链接
     * @file
     * @since 1.2.6.1
     */

    /**
     * 插入超链接
     * @command link
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { Object } options   设置自定义属性,例如:url、title、target
     * @example
     * ```javascript
     * editor.execCommand( 'link', '{
 *     url:'neditor.baidu.com',
 *     title:'neditor',
 *     target:'_blank'
 * }' );
     * ```
     */
    /**
     * 返回当前选中的第一个超链接节点
     * @command link
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { Element } 超链接节点
     * @example
     * ```javascript
     * editor.queryCommandValue( 'link' );
     * ```
     */

    /**
     * 取消超链接
     * @command unlink
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'unlink');
     * ```
     */

    UE.plugins["link"] = function () {
        function optimize(range) {
            var start = range.startContainer,
                end = range.endContainer;

            if ((start = domUtils.findParentByTagName(start, "a", true))) {
                range.setStartBefore(start);
            }
            if ((end = domUtils.findParentByTagName(end, "a", true))) {
                range.setEndAfter(end);
            }
        }

        UE.commands["unlink"] = {
            execCommand: function () {
                var range = this.selection.getRange(),
                    bookmark;
                if (
                    range.collapsed &&
                    !domUtils.findParentByTagName(range.startContainer, "a", true)
                ) {
                    return;
                }
                bookmark = range.createBookmark();
                optimize(range);
                range.removeInlineStyle("a").moveToBookmark(bookmark).select();
            },
            queryCommandState: function () {
                return !this.highlight && this.queryCommandValue("link") ? 0 : -1;
            }
        };

        function doLink(range, opt, me) {
            var rngClone = range.cloneRange(),
                link = me.queryCommandValue("link");
            optimize((range = range.adjustmentBoundary()));
            var start = range.startContainer;
            if (start.nodeType == 1 && link) {
                start = start.childNodes[range.startOffset];
                if (
                    start &&
                    start.nodeType == 1 &&
                    start.tagName == "A" &&
                    /^(?:https?|ftp|file)\s*:\s*\/\//.test(
                        start[browser.ie ? "innerText" : "textContent"]
                    )
                ) {
                    start[browser.ie ? "innerText" : "textContent"] = utils.html(
                        opt.textValue || opt.href
                    );
                }
            }
            if (!rngClone.collapsed || link) {
                range.removeInlineStyle("a");
                rngClone = range.cloneRange();
            }

            if (rngClone.collapsed) {
                var a = range.document.createElement("a"),
                    text = "";
                if (opt.textValue) {
                    text = utils.html(opt.textValue);
                    delete opt.textValue;
                } else {
                    text = utils.html(opt.href);
                }
                domUtils.setAttributes(a, opt);
                start = domUtils.findParentByTagName(rngClone.startContainer, "a", true);
                if (start && domUtils.isInNodeEndBoundary(rngClone, start)) {
                    range.setStartAfter(start).collapse(true);
                }
                a[browser.ie ? "innerText" : "textContent"] = text;
                range.insertNode(a).selectNode(a);
            } else {
                range.applyInlineStyle("a", opt);
            }
        }

        UE.commands["link"] = {
            execCommand: function (cmdName, opt) {
                var range;
                opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g));
                opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g));
                opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g));
                doLink((range = this.selection.getRange()), opt, this);
                //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
                range.collapse().select(true);
            },
            queryCommandValue: function () {
                var range = this.selection.getRange(),
                    node;
                if (range.collapsed) {
                    //                    node = this.selection.getStart();
                    //在ie下getstart()取值偏上了
                    node = range.startContainer;
                    node = node.nodeType == 1 ? node : node.parentNode;

                    if (
                        node &&
                        (node = domUtils.findParentByTagName(node, "a", true)) &&
                        !domUtils.isInNodeEndBoundary(range, node)
                    ) {
                        return node;
                    }
                } else {
                    //trace:1111  如果是<p><a>xx</a></p> startContainer是p就会找不到a
                    range.shrinkBoundary();
                    var start = range.startContainer.nodeType == 3 ||
                        !range.startContainer.childNodes[range.startOffset]
                        ? range.startContainer
                        : range.startContainer.childNodes[range.startOffset],
                        end = range.endContainer.nodeType == 3 || range.endOffset == 0
                            ? range.endContainer
                            : range.endContainer.childNodes[range.endOffset - 1],
                        common = range.getCommonAncestor();
                    node = domUtils.findParentByTagName(common, "a", true);
                    if (!node && common.nodeType == 1) {
                        var as = common.getElementsByTagName("a"),
                            ps,
                            pe;

                        for (var i = 0, ci; (ci = as[i++]);) {
                            (ps = domUtils.getPosition(ci, start)), (pe = domUtils.getPosition(
                                ci,
                                end
                            ));
                            if (
                                (ps & domUtils.POSITION_FOLLOWING ||
                                    ps & domUtils.POSITION_CONTAINS) &&
                                (pe & domUtils.POSITION_PRECEDING ||
                                    pe & domUtils.POSITION_CONTAINS)
                            ) {
                                node = ci;
                                break;
                            }
                        }
                    }
                    return node;
                }
            },
            queryCommandState: function () {
                //判断如果是视频的话连接不可用
                //fix 853
                var img = this.selection.getRange().getClosedNode(),
                    flag =
                        img &&
                        (img.className == "edui-faked-video" ||
                            img.className.indexOf("edui-upload-video") != -1);
                return flag ? -1 : 0;
            }
        };
    };


// plugins/iframe.js
///import core
///import plugins\inserthtml.js
///commands 插入框架
///commandsName  InsertFrame
///commandsTitle  插入Iframe
///commandsDialog  dialogs\insertframe

    UE.plugins["insertframe"] = function () {
        var me = this;

        function deleteIframe() {
            me._iframe && delete me._iframe;
        }

        me.addListener("selectionchange", function () {
            deleteIframe();
        });
    };


// plugins/scrawl.js
///import core
///commands 涂鸦
///commandsName  Scrawl
///commandsTitle  涂鸦
///commandsDialog  dialogs\scrawl
    UE.commands["scrawl"] = {
        queryCommandState: function () {
            return browser.ie && browser.version <= 8 ? -1 : 0;
        }
    };


// plugins/removeformat.js
    /**
     * 清除格式
     * @file
     * @since 1.2.6.1
     */

    /**
     * 清除文字样式
     * @command removeformat
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param   {String}   tags     以逗号隔开的标签。如:strong
     * @param   {String}   style    样式如:color
     * @param   {String}   attrs    属性如:width
     * @example
     * ```javascript
     * editor.execCommand( 'removeformat', 'strong','color','width' );
     * ```
     */

    UE.plugins["removeformat"] = function () {
        var me = this;
        me.setOpt({
            removeFormatTags:
                "b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var",
            removeFormatAttributes: "class,style,lang,width,height,align,hspace,valign"
        });
        me.commands["removeformat"] = {
            execCommand: function (cmdName, tags, style, attrs, notIncludeA) {
                var tagReg = new RegExp(
                    "^(?:" +
                    (tags || this.options.removeFormatTags).replace(/,/g, "|") +
                    ")$",
                    "i"
                    ),
                    removeFormatAttributes = style
                        ? []
                        : (attrs || this.options.removeFormatAttributes).split(","),
                    range = new dom.Range(this.document),
                    bookmark,
                    node,
                    parent,
                    filter = function (node) {
                        return node.nodeType == 1;
                    };

                function isRedundantSpan(node) {
                    if (node.nodeType == 3 || node.tagName.toLowerCase() != "span") {
                        return 0;
                    }
                    if (browser.ie) {
                        //ie 下判断实效,所以只能简单用style来判断
                        //return node.style.cssText == '' ? 1 : 0;
                        var attrs = node.attributes;
                        if (attrs.length) {
                            for (var i = 0, l = attrs.length; i < l; i++) {
                                if (attrs[i].specified) {
                                    return 0;
                                }
                            }
                            return 1;
                        }
                    }
                    return !node.attributes.length;
                }

                function doRemove(range) {
                    var bookmark1 = range.createBookmark();
                    if (range.collapsed) {
                        range.enlarge(true);
                    }

                    //不能把a标签切了
                    if (!notIncludeA) {
                        var aNode = domUtils.findParentByTagName(
                            range.startContainer,
                            "a",
                            true
                        );
                        if (aNode) {
                            range.setStartBefore(aNode);
                        }

                        aNode = domUtils.findParentByTagName(range.endContainer, "a", true);
                        if (aNode) {
                            range.setEndAfter(aNode);
                        }
                    }

                    bookmark = range.createBookmark();

                    node = bookmark.start;

                    //切开始
                    while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
                        domUtils.breakParent(node, parent);

                        domUtils.clearEmptySibling(node);
                    }
                    if (bookmark.end) {
                        //切结束
                        node = bookmark.end;
                        while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
                            domUtils.breakParent(node, parent);
                            domUtils.clearEmptySibling(node);
                        }

                        //开始去除样式
                        var current = domUtils.getNextDomNode(bookmark.start, false, filter),
                            next;
                        while (current) {
                            if (current == bookmark.end) {
                                break;
                            }

                            next = domUtils.getNextDomNode(current, true, filter);

                            if (
                                !dtd.$empty[current.tagName.toLowerCase()] &&
                                !domUtils.isBookmarkNode(current)
                            ) {
                                if (tagReg.test(current.tagName)) {
                                    if (style) {
                                        domUtils.removeStyle(current, style);
                                        if (isRedundantSpan(current) && style != "text-decoration") {
                                            domUtils.remove(current, true);
                                        }
                                    } else {
                                        domUtils.remove(current, true);
                                    }
                                } else {
                                    //trace:939  不能把list上的样式去掉
                                    if (
                                        !dtd.$tableContent[current.tagName] &&
                                        !dtd.$list[current.tagName]
                                    ) {
                                        domUtils.removeAttributes(current, removeFormatAttributes);
                                        if (isRedundantSpan(current)) {
                                            domUtils.remove(current, true);
                                        }
                                    }
                                }
                            }
                            current = next;
                        }
                    }
                    //trace:1035
                    //trace:1096 不能把td上的样式去掉,比如边框
                    var pN = bookmark.start.parentNode;
                    if (
                        domUtils.isBlockElm(pN) &&
                        !dtd.$tableContent[pN.tagName] &&
                        !dtd.$list[pN.tagName]
                    ) {
                        domUtils.removeAttributes(pN, removeFormatAttributes);
                    }
                    pN = bookmark.end.parentNode;
                    if (
                        bookmark.end &&
                        domUtils.isBlockElm(pN) &&
                        !dtd.$tableContent[pN.tagName] &&
                        !dtd.$list[pN.tagName]
                    ) {
                        domUtils.removeAttributes(pN, removeFormatAttributes);
                    }
                    range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
                    //清除冗余的代码 <b><bookmark></b>
                    var node = range.startContainer,
                        tmp,
                        collapsed = range.collapsed;
                    while (
                        node.nodeType == 1 &&
                        domUtils.isEmptyNode(node) &&
                        dtd.$removeEmpty[node.tagName]
                        ) {
                        tmp = node.parentNode;
                        range.setStartBefore(node);
                        //trace:937
                        //更新结束边界
                        if (range.startContainer === range.endContainer) {
                            range.endOffset--;
                        }
                        domUtils.remove(node);
                        node = tmp;
                    }

                    if (!collapsed) {
                        node = range.endContainer;
                        while (
                            node.nodeType == 1 &&
                            domUtils.isEmptyNode(node) &&
                            dtd.$removeEmpty[node.tagName]
                            ) {
                            tmp = node.parentNode;
                            range.setEndBefore(node);
                            domUtils.remove(node);

                            node = tmp;
                        }
                    }
                }

                range = this.selection.getRange();
                doRemove(range);
                range.select();
            }
        };
    };


// plugins/blockquote.js
    /**
     * 添加引用
     * @file
     * @since 1.2.6.1
     */

    /**
     * 添加引用
     * @command blockquote
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'blockquote' );
     * ```
     */

    /**
     * 添加引用
     * @command blockquote
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { Object } attrs 节点属性
     * @example
     * ```javascript
     * editor.execCommand( 'blockquote',{
 *     style: "color: red;"
 * } );
     * ```
     */

    UE.plugins["blockquote"] = function () {
        var me = this;

        function getObj(editor) {
            return domUtils.filterNodeList(
                editor.selection.getStartElementPath(),
                "blockquote"
            );
        }

        me.commands["blockquote"] = {
            execCommand: function (cmdName, attrs) {
                var range = this.selection.getRange(),
                    obj = getObj(this),
                    blockquote = dtd.blockquote,
                    bookmark = range.createBookmark();

                if (obj) {
                    var start = range.startContainer,
                        startBlock = domUtils.isBlockElm(start)
                            ? start
                            : domUtils.findParent(start, function (node) {
                                return domUtils.isBlockElm(node);
                            }),
                        end = range.endContainer,
                        endBlock = domUtils.isBlockElm(end)
                            ? end
                            : domUtils.findParent(end, function (node) {
                                return domUtils.isBlockElm(node);
                            });

                    //处理一下li
                    startBlock =
                        domUtils.findParentByTagName(startBlock, "li", true) || startBlock;
                    endBlock =
                        domUtils.findParentByTagName(endBlock, "li", true) || endBlock;

                    if (
                        startBlock.tagName == "LI" ||
                        startBlock.tagName == "TD" ||
                        startBlock === obj ||
                        domUtils.isBody(startBlock)
                    ) {
                        domUtils.remove(obj, true);
                    } else {
                        domUtils.breakParent(startBlock, obj);
                    }

                    if (startBlock !== endBlock) {
                        obj = domUtils.findParentByTagName(endBlock, "blockquote");
                        if (obj) {
                            if (
                                endBlock.tagName == "LI" ||
                                endBlock.tagName == "TD" ||
                                domUtils.isBody(endBlock)
                            ) {
                                obj.parentNode && domUtils.remove(obj, true);
                            } else {
                                domUtils.breakParent(endBlock, obj);
                            }
                        }
                    }

                    var blockquotes = domUtils.getElementsByTagName(
                        this.document,
                        "blockquote"
                    );
                    for (var i = 0, bi; (bi = blockquotes[i++]);) {
                        if (!bi.childNodes.length) {
                            domUtils.remove(bi);
                        } else if (
                            domUtils.getPosition(bi, startBlock) &
                            domUtils.POSITION_FOLLOWING &&
                            domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING
                        ) {
                            domUtils.remove(bi, true);
                        }
                    }
                } else {
                    var tmpRange = range.cloneRange(),
                        node = tmpRange.startContainer.nodeType == 1
                            ? tmpRange.startContainer
                            : tmpRange.startContainer.parentNode,
                        preNode = node,
                        doEnd = 1;

                    //调整开始
                    while (1) {
                        if (domUtils.isBody(node)) {
                            if (preNode !== node) {
                                if (range.collapsed) {
                                    tmpRange.selectNode(preNode);
                                    doEnd = 0;
                                } else {
                                    tmpRange.setStartBefore(preNode);
                                }
                            } else {
                                tmpRange.setStart(node, 0);
                            }

                            break;
                        }
                        if (!blockquote[node.tagName]) {
                            if (range.collapsed) {
                                tmpRange.selectNode(preNode);
                            } else {
                                tmpRange.setStartBefore(preNode);
                            }
                            break;
                        }

                        preNode = node;
                        node = node.parentNode;
                    }

                    //调整结束
                    if (doEnd) {
                        preNode = node = node = tmpRange.endContainer.nodeType == 1
                            ? tmpRange.endContainer
                            : tmpRange.endContainer.parentNode;
                        while (1) {
                            if (domUtils.isBody(node)) {
                                if (preNode !== node) {
                                    tmpRange.setEndAfter(preNode);
                                } else {
                                    tmpRange.setEnd(node, node.childNodes.length);
                                }

                                break;
                            }
                            if (!blockquote[node.tagName]) {
                                tmpRange.setEndAfter(preNode);
                                break;
                            }

                            preNode = node;
                            node = node.parentNode;
                        }
                    }

                    node = range.document.createElement("blockquote");
                    domUtils.setAttributes(node, attrs);
                    node.appendChild(tmpRange.extractContents());
                    tmpRange.insertNode(node);
                    //去除重复的
                    var childs = domUtils.getElementsByTagName(node, "blockquote");
                    for (var i = 0, ci; (ci = childs[i++]);) {
                        if (ci.parentNode) {
                            domUtils.remove(ci, true);
                        }
                    }
                }
                range.moveToBookmark(bookmark).select();
            },
            queryCommandState: function () {
                return getObj(this) ? 1 : 0;
            }
        };
    };


// plugins/convertcase.js
    /**
     * 大小写转换
     * @file
     * @since 1.2.6.1
     */

    /**
     * 把选区内文本变大写,与“tolowercase”命令互斥
     * @command touppercase
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'touppercase' );
     * ```
     */

    /**
     * 把选区内文本变小写,与“touppercase”命令互斥
     * @command tolowercase
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'tolowercase' );
     * ```
     */
    UE.commands["touppercase"] = UE.commands["tolowercase"] = {
        execCommand: function (cmd) {
            var me = this;
            var rng = me.selection.getRange();
            if (rng.collapsed) {
                return rng;
            }
            var bk = rng.createBookmark(),
                bkEnd = bk.end,
                filterFn = function (node) {
                    return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
                },
                curNode = domUtils.getNextDomNode(bk.start, false, filterFn);
            while (
                curNode &&
                domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING
                ) {
                if (curNode.nodeType == 3) {
                    curNode.nodeValue = curNode.nodeValue[
                        cmd == "touppercase" ? "toUpperCase" : "toLowerCase"
                        ]();
                }
                curNode = domUtils.getNextDomNode(curNode, true, filterFn);
                if (curNode === bkEnd) {
                    break;
                }
            }
            rng.moveToBookmark(bk).select();
        }
    };


// plugins/indent.js
    /**
     * 首行缩进
     * @file
     * @since 1.2.6.1
     */

    /**
     * 缩进
     * @command indent
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'indent' );
     * ```
     */
    UE.commands["indent"] = {
        execCommand: function () {
            var me = this,
                value = me.queryCommandState("indent")
                    ? "0em"
                    : me.options.indentValue || "2em";
            me.execCommand("Paragraph", "p", {style: "text-indent:" + value});
        },
        queryCommandState: function () {
            var pN = domUtils.filterNodeList(
                this.selection.getStartElementPath(),
                "p h1 h2 h3 h4 h5 h6"
            );
            return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0;
        }
    };


// plugins/print.js
    /**
     * 打印
     * @file
     * @since 1.2.6.1
     */

    /**
     * 打印
     * @command print
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'print' );
     * ```
     */
    UE.commands["print"] = {
        execCommand: function () {
            this.window.print();
        },
        notNeedUndo: 1
    };


// plugins/preview.js
    /**
     * 预览
     * @file
     * @since 1.2.6.1
     */

    /**
     * 预览
     * @command preview
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'preview' );
     * ```
     */
    UE.commands["preview"] = {
        execCommand: function () {
            var w = window.open("", "_blank", ""),
                d = w.document;
            d.open();
            d.write(
                '<!DOCTYPE html><html><head><meta charset="utf-8"/><script src="' +
                this.options.UEDITOR_HOME_URL +
                'neditor.parse.js"></script><script>' +
                "setTimeout(function(){uParse('div',{rootPath: '" +
                this.options.UEDITOR_HOME_URL +
                "'})},300)" +
                "</script></head><body><div>" +
                this.getContent(null, null, true) +
                "</div></body></html>"
            );
            d.close();
        },
        notNeedUndo: 1
    };


// plugins/selectall.js
    /**
     * 全选
     * @file
     * @since 1.2.6.1
     */

    /**
     * 选中所有内容
     * @command selectall
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'selectall' );
     * ```
     */
    UE.plugins["selectall"] = function () {
        var me = this;
        me.commands["selectall"] = {
            execCommand: function () {
                //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
                var me = this,
                    body = me.body,
                    range = me.selection.getRange();
                range.selectNodeContents(body);
                if (domUtils.isEmptyBlock(body)) {
                    //opera不能自动合并到元素的里边,要手动处理一下
                    if (browser.opera && body.firstChild && body.firstChild.nodeType == 1) {
                        range.setStartAtFirst(body.firstChild);
                    }
                    range.collapse(true);
                }
                range.select(true);
            },
            notNeedUndo: 1
        };

        //快捷键
        me.addshortcutkey({
            selectAll: "ctrl+65"
        });
    };


// plugins/paragraph.js
    /**
     * 段落样式
     * @file
     * @since 1.2.6.1
     */

    /**
     * 段落格式
     * @command paragraph
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param {String}   style               标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
     * @param {Object}   attrs               标签的属性
     * @example
     * ```javascript
     * editor.execCommand( 'Paragraph','h1','{
 *     class:'test'
 * }' );
     * ```
     */

    /**
     * 返回选区内节点标签名
     * @command paragraph
     * @method queryCommandValue
     * @param { String } cmd 命令字符串
     * @return { String } 节点标签名
     * @example
     * ```javascript
     * editor.queryCommandValue( 'Paragraph' );
     * ```
     */

    UE.plugins["paragraph"] = function () {
        var me = this,
            block = domUtils.isBlockElm,
            notExchange = ["TD", "LI", "PRE"],
            doParagraph = function (range, style, attrs, sourceCmdName) {
                var bookmark = range.createBookmark(),
                    filterFn = function (node) {
                        return node.nodeType == 1
                            ? node.tagName.toLowerCase() != "br" &&
                            !domUtils.isBookmarkNode(node)
                            : !domUtils.isWhitespace(node);
                    },
                    para;

                range.enlarge(true);
                var bookmark2 = range.createBookmark(),
                    current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
                    tmpRange = range.cloneRange(),
                    tmpNode;
                while (
                    current &&
                    !(
                        domUtils.getPosition(current, bookmark2.end) &
                        domUtils.POSITION_FOLLOWING
                    )
                    ) {
                    if (current.nodeType == 3 || !block(current)) {
                        tmpRange.setStartBefore(current);
                        while (current && current !== bookmark2.end && !block(current)) {
                            tmpNode = current;
                            current = domUtils.getNextDomNode(current, false, null, function (
                                node
                            ) {
                                return !block(node);
                            });
                        }
                        tmpRange.setEndAfter(tmpNode);

                        para = range.document.createElement(style);
                        if (attrs) {
                            domUtils.setAttributes(para, attrs);
                            if (
                                sourceCmdName &&
                                sourceCmdName == "customstyle" &&
                                attrs.style
                            ) {
                                para.style.cssText = attrs.style;
                            }
                        }
                        para.appendChild(tmpRange.extractContents());
                        //需要内容占位
                        if (domUtils.isEmptyNode(para)) {
                            domUtils.fillChar(range.document, para);
                        }

                        tmpRange.insertNode(para);

                        var parent = para.parentNode;
                        //如果para上一级是一个block元素且不是body,td就删除它
                        if (
                            block(parent) &&
                            !domUtils.isBody(para.parentNode) &&
                            utils.indexOf(notExchange, parent.tagName) == -1
                        ) {
                            //存储dir,style
                            if (!(sourceCmdName && sourceCmdName == "customstyle")) {
                                parent.getAttribute("dir") &&
                                para.setAttribute("dir", parent.getAttribute("dir"));
                                //trace:1070
                                parent.style.cssText &&
                                (para.style.cssText =
                                    parent.style.cssText + ";" + para.style.cssText);
                                //trace:1030
                                parent.style.textAlign &&
                                !para.style.textAlign &&
                                (para.style.textAlign = parent.style.textAlign);
                                parent.style.textIndent &&
                                !para.style.textIndent &&
                                (para.style.textIndent = parent.style.textIndent);
                                parent.style.padding &&
                                !para.style.padding &&
                                (para.style.padding = parent.style.padding);
                            }

                            //trace:1706 选择的就是h1-6要删除
                            if (
                                attrs &&
                                /h\d/i.test(parent.tagName) &&
                                !/h\d/i.test(para.tagName)
                            ) {
                                domUtils.setAttributes(parent, attrs);
                                if (
                                    sourceCmdName &&
                                    sourceCmdName == "customstyle" &&
                                    attrs.style
                                ) {
                                    parent.style.cssText = attrs.style;
                                }
                                domUtils.remove(para.parentNode, true);
                                para = parent;
                            } else {
                                domUtils.remove(para.parentNode, true);
                            }
                        }
                        if (utils.indexOf(notExchange, parent.tagName) != -1) {
                            current = parent;
                        } else {
                            current = para;
                        }

                        current = domUtils.getNextDomNode(current, false, filterFn);
                    } else {
                        current = domUtils.getNextDomNode(current, true, filterFn);
                    }
                }
                return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
            };
        me.setOpt("paragraph", {
            p: "",
            h1: "",
            h2: "",
            h3: "",
            h4: "",
            h5: "",
            h6: ""
        });
        me.commands["paragraph"] = {
            execCommand: function (cmdName, style, attrs, sourceCmdName) {
                var range = this.selection.getRange();
                //闭合时单独处理
                if (range.collapsed) {
                    var txt = this.document.createTextNode("p");
                    range.insertNode(txt);
                    //去掉冗余的fillchar
                    if (browser.ie) {
                        var node = txt.previousSibling;
                        if (node && domUtils.isWhitespace(node)) {
                            domUtils.remove(node);
                        }
                        node = txt.nextSibling;
                        if (node && domUtils.isWhitespace(node)) {
                            domUtils.remove(node);
                        }
                    }
                }
                range = doParagraph(range, style, attrs, sourceCmdName);
                if (txt) {
                    range.setStartBefore(txt).collapse(true);
                    pN = txt.parentNode;

                    domUtils.remove(txt);

                    if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) {
                        domUtils.fillNode(this.document, pN);
                    }
                }

                if (
                    browser.gecko &&
                    range.collapsed &&
                    range.startContainer.nodeType == 1
                ) {
                    var child = range.startContainer.childNodes[range.startOffset];
                    if (
                        child &&
                        child.nodeType == 1 &&
                        child.tagName.toLowerCase() == style
                    ) {
                        range.setStart(child, 0).collapse(true);
                    }
                }
                //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
                range.select();

                return true;
            },
            queryCommandValue: function () {
                var node = domUtils.filterNodeList(
                    this.selection.getStartElementPath(),
                    "p h1 h2 h3 h4 h5 h6"
                );
                return node ? node.tagName.toLowerCase() : "";
            }
        };
    };


// plugins/directionality.js
    /**
     * 设置文字输入的方向的插件
     * @file
     * @since 1.2.6.1
     */
    ;(function () {
        var block = domUtils.isBlockElm,
            getObj = function (editor) {
                //            var startNode = editor.selection.getStart(),
                //                parents;
                //            if ( startNode ) {
                //                //查找所有的是block的父亲节点
                //                parents = domUtils.findParents( startNode, true, block, true );
                //                for ( var i = 0,ci; ci = parents[i++]; ) {
                //                    if ( ci.getAttribute( 'dir' ) ) {
                //                        return ci;
                //                    }
                //                }
                //            }
                return domUtils.filterNodeList(
                    editor.selection.getStartElementPath(),
                    function (n) {
                        return n && n.nodeType == 1 && n.getAttribute("dir");
                    }
                );
            },
            doDirectionality = function (range, editor, forward) {
                var bookmark,
                    filterFn = function (node) {
                        return node.nodeType == 1
                            ? !domUtils.isBookmarkNode(node)
                            : !domUtils.isWhitespace(node);
                    },
                    obj = getObj(editor);

                if (obj && range.collapsed) {
                    obj.setAttribute("dir", forward);
                    return range;
                }
                bookmark = range.createBookmark();
                range.enlarge(true);
                var bookmark2 = range.createBookmark(),
                    current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
                    tmpRange = range.cloneRange(),
                    tmpNode;
                while (
                    current &&
                    !(
                        domUtils.getPosition(current, bookmark2.end) &
                        domUtils.POSITION_FOLLOWING
                    )
                    ) {
                    if (current.nodeType == 3 || !block(current)) {
                        tmpRange.setStartBefore(current);
                        while (current && current !== bookmark2.end && !block(current)) {
                            tmpNode = current;
                            current = domUtils.getNextDomNode(current, false, null, function (
                                node
                            ) {
                                return !block(node);
                            });
                        }
                        tmpRange.setEndAfter(tmpNode);
                        var common = tmpRange.getCommonAncestor();
                        if (!domUtils.isBody(common) && block(common)) {
                            //遍历到了block节点
                            common.setAttribute("dir", forward);
                            current = common;
                        } else {
                            //没有遍历到,添加一个block节点
                            var p = range.document.createElement("p");
                            p.setAttribute("dir", forward);
                            var frag = tmpRange.extractContents();
                            p.appendChild(frag);
                            tmpRange.insertNode(p);
                            current = p;
                        }

                        current = domUtils.getNextDomNode(current, false, filterFn);
                    } else {
                        current = domUtils.getNextDomNode(current, true, filterFn);
                    }
                }
                return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
            };

        /**
         * 文字输入方向
         * @command directionality
         * @method execCommand
         * @param { String } cmdName 命令字符串
         * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入
         * @example
         * ```javascript
         * editor.execCommand( 'directionality', 'ltr');
         * ```
         */

        /**
         * 查询当前选区的文字输入方向
         * @command directionality
         * @method queryCommandValue
         * @param { String } cmdName 命令字符串
         * @return { String } 返回'ltr'表示从左向右输入,返回'rtl'表示从右向左输入
         * @example
         * ```javascript
         * editor.queryCommandValue( 'directionality');
         * ```
         */
        UE.commands["directionality"] = {
            execCommand: function (cmdName, forward) {
                var range = this.selection.getRange();
                //闭合时单独处理
                if (range.collapsed) {
                    var txt = this.document.createTextNode("d");
                    range.insertNode(txt);
                }
                doDirectionality(range, this, forward);
                if (txt) {
                    range.setStartBefore(txt).collapse(true);
                    domUtils.remove(txt);
                }

                range.select();
                return true;
            },
            queryCommandValue: function () {
                var node = getObj(this);
                return node ? node.getAttribute("dir") : "ltr";
            }
        };
    })();


// plugins/horizontal.js
    /**
     * 插入分割线插件
     * @file
     * @since 1.2.6.1
     */

    /**
     * 插入分割线
     * @command horizontal
     * @method execCommand
     * @param { String } cmdName 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'horizontal' );
     * ```
     */
    UE.plugins["horizontal"] = function () {
        var me = this;
        me.commands["horizontal"] = {
            execCommand: function (cmdName) {
                var me = this;
                if (me.queryCommandState(cmdName) !== -1) {
                    me.execCommand("insertHtml", "<hr>");
                    var range = me.selection.getRange(),
                        start = range.startContainer;
                    if (start.nodeType == 1 && !start.childNodes[range.startOffset]) {
                        var tmp;
                        if ((tmp = start.childNodes[range.startOffset - 1])) {
                            if (tmp.nodeType == 1 && tmp.tagName == "HR") {
                                if (me.options.enterTag == "p") {
                                    tmp = me.document.createElement("p");
                                    range.insertNode(tmp);
                                    range.setStart(tmp, 0).setCursor();
                                } else {
                                    tmp = me.document.createElement("br");
                                    range.insertNode(tmp);
                                    range.setStartBefore(tmp).setCursor();
                                }
                            }
                        }
                    }
                    return true;
                }
            },
            //边界在table里不能加分隔线
            queryCommandState: function () {
                return domUtils.filterNodeList(
                    this.selection.getStartElementPath(),
                    "table"
                )
                    ? -1
                    : 0;
            }
        };
        //    me.addListener('delkeyup',function(){
        //        var rng = this.selection.getRange();
        //        if(browser.ie && browser.version > 8){
        //            rng.txtToElmBoundary(true);
        //            if(domUtils.isStartInblock(rng)){
        //                var tmpNode = rng.startContainer;
        //                var pre = tmpNode.previousSibling;
        //                if(pre && domUtils.isTagNode(pre,'hr')){
        //                    domUtils.remove(pre);
        //                    rng.select();
        //                    return;
        //                }
        //            }
        //        }
        //        if(domUtils.isBody(rng.startContainer)){
        //            var hr = rng.startContainer.childNodes[rng.startOffset -1];
        //            if(hr && hr.nodeName == 'HR'){
        //                var next = hr.nextSibling;
        //                if(next){
        //                    rng.setStart(next,0)
        //                }else if(hr.previousSibling){
        //                    rng.setStartAtLast(hr.previousSibling)
        //                }else{
        //                    var p = this.document.createElement('p');
        //                    hr.parentNode.insertBefore(p,hr);
        //                    domUtils.fillNode(this.document,p);
        //                    rng.setStart(p,0);
        //                }
        //                domUtils.remove(hr);
        //                rng.setCursor(false,true);
        //            }
        //        }
        //    })
        me.addListener("delkeydown", function (name, evt) {
            var rng = this.selection.getRange();
            rng.txtToElmBoundary(true);
            if (domUtils.isStartInblock(rng)) {
                var tmpNode = rng.startContainer;
                var pre = tmpNode.previousSibling;
                if (pre && domUtils.isTagNode(pre, "hr")) {
                    domUtils.remove(pre);
                    rng.select();
                    domUtils.preventDefault(evt);
                    return true;
                }
            }
        });
    };


// plugins/time.js
    /**
     * 插入时间和日期
     * @file
     * @since 1.2.6.1
     */

    /**
     * 插入时间,默认格式:12:59:59
     * @command time
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'time');
     * ```
     */

    /**
     * 插入日期,默认格式:2013-08-30
     * @command date
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'date');
     * ```
     */
    UE.commands["time"] = UE.commands["date"] = {
        execCommand: function (cmd, format) {
            var date = new Date();

            function formatTime(date, format) {
                var hh = ("0" + date.getHours()).slice(-2),
                    ii = ("0" + date.getMinutes()).slice(-2),
                    ss = ("0" + date.getSeconds()).slice(-2);
                format = format || "hh:ii:ss";
                return format.replace(/hh/gi, hh).replace(/ii/gi, ii).replace(/ss/gi, ss);
            }

            function formatDate(date, format) {
                var yyyy = ("000" + date.getFullYear()).slice(-4),
                    yy = yyyy.slice(-2),
                    mm = ("0" + (date.getMonth() + 1)).slice(-2),
                    dd = ("0" + date.getDate()).slice(-2);
                format = format || "yyyy-mm-dd";
                return format
                    .replace(/yyyy/gi, yyyy)
                    .replace(/yy/gi, yy)
                    .replace(/mm/gi, mm)
                    .replace(/dd/gi, dd);
            }

            this.execCommand(
                "insertHtml",
                cmd == "time" ? formatTime(date, format) : formatDate(date, format)
            );
        }
    };


// plugins/rowspacing.js
    /**
     * 段前段后间距插件
     * @file
     * @since 1.2.6.1
     */

    /**
     * 设置段间距
     * @command rowspacing
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @param { String } value 段间距的值,以px为单位
     * @param { String } dir 间距位置,top或bottom,分别表示段前和段后
     * @example
     * ```javascript
     * editor.execCommand( 'rowspacing', '10', 'top' );
     * ```
     */

    UE.plugins["rowspacing"] = function () {
        var me = this;
        me.setOpt({
            rowspacingtop: ["5", "10", "15", "20", "25"],
            rowspacingbottom: ["5", "10", "15", "20", "25"]
        });
        me.commands["rowspacing"] = {
            execCommand: function (cmdName, value, dir) {
                this.execCommand("paragraph", "p", {
                    style: "margin-" + dir + ":" + value + "px"
                });
                return true;
            },
            queryCommandValue: function (cmdName, dir) {
                var pN = domUtils.filterNodeList(
                    this.selection.getStartElementPath(),
                    function (node) {
                        return domUtils.isBlockElm(node);
                    }
                    ),
                    value;
                //trace:1026
                if (pN) {
                    value = domUtils
                        .getComputedStyle(pN, "margin-" + dir)
                        .replace(/[^\d]/g, "");
                    return !value ? 0 : value;
                }
                return 0;
            }
        };
    };


// plugins/lineheight.js
    /**
     * 设置行内间距
     * @file
     * @since 1.2.6.1
     */
    UE.plugins["lineheight"] = function () {
        var me = this;
        me.setOpt({lineheight: ["1", "1.5", "1.75", "2", "3", "4", "5"]});

        /**
         * 行距
         * @command lineheight
         * @method execCommand
         * @param { String } cmdName 命令字符串
         * @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75
         * @example
         * ```javascript
         * editor.execCommand( 'lineheight', 1.5);
         * ```
         */
        /**
         * 查询当前选区内容的行高大小
         * @command lineheight
         * @method queryCommandValue
         * @param { String } cmd 命令字符串
         * @return { String } 返回当前行高大小
         * @example
         * ```javascript
         * editor.queryCommandValue( 'lineheight' );
         * ```
         */

        me.commands["lineheight"] = {
            execCommand: function (cmdName, value) {
                this.execCommand("paragraph", "p", {
                    style: "line-height:" + (value == "1" ? "normal" : value + "em")
                });
                return true;
            },
            queryCommandValue: function () {
                var pN = domUtils.filterNodeList(
                    this.selection.getStartElementPath(),
                    function (node) {
                        return domUtils.isBlockElm(node);
                    }
                );
                if (pN) {
                    var value = domUtils.getComputedStyle(pN, "line-height");
                    return value == "normal" ? 1 : value.replace(/[^\d.]*/gi, "");
                }
            }
        };
    };


// plugins/insertcode.js
    /**
     * 插入代码插件
     * @file
     * @since 1.2.6.1
     */

    UE.plugins["insertcode"] = function () {
        var me = this;
        me.ready(function () {
            utils.cssRule(
                "pre",
                "pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}",
                me.document
            );
        });
        me.setOpt("insertcode", {
            as3: "ActionScript3",
            bash: "Bash/Shell",
            cpp: "C/C++",
            css: "Css",
            cf: "CodeFunction",
            "c#": "C#",
            delphi: "Delphi",
            diff: "Diff",
            erlang: "Erlang",
            groovy: "Groovy",
            html: "Html",
            java: "Java",
            jfx: "JavaFx",
            js: "Javascript",
            pl: "Perl",
            php: "Php",
            plain: "Plain Text",
            ps: "PowerShell",
            python: "Python",
            ruby: "Ruby",
            scala: "Scala",
            sql: "Sql",
            vb: "Vb",
            xml: "Xml"
        });

        /**
         * 插入代码
         * @command insertcode
         * @method execCommand
         * @param { String } cmd 命令字符串
         * @param { String } lang 插入代码的语言
         * @example
         * ```javascript
         * editor.execCommand( 'insertcode', 'javascript' );
         * ```
         */

        /**
         * 如果选区所在位置是插入插入代码区域,返回代码的语言
         * @command insertcode
         * @method queryCommandValue
         * @param { String } cmd 命令字符串
         * @return { String } 返回代码的语言
         * @example
         * ```javascript
         * editor.queryCommandValue( 'insertcode' );
         * ```
         */

        me.commands["insertcode"] = {
            execCommand: function (cmd, lang) {
                var me = this,
                    rng = me.selection.getRange(),
                    pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
                if (pre) {
                    pre.className = "brush:" + lang + ";toolbar:false;";
                } else {
                    var code = "";
                    if (rng.collapsed) {
                        code = browser.ie && browser.ie11below
                            ? browser.version <= 8 ? "&nbsp;" : ""
                            : "<br/>";
                    } else {
                        var frag = rng.extractContents();
                        var div = me.document.createElement("div");
                        div.appendChild(frag);

                        utils.each(
                            UE.filterNode(
                                UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, "")),
                                me.options.filterTxtRules
                            ).children,
                            function (node) {
                                if (browser.ie && browser.ie11below && browser.version > 8) {
                                    if (node.type == "element") {
                                        if (node.tagName == "br") {
                                            code += "\n";
                                        } else if (!dtd.$empty[node.tagName]) {
                                            utils.each(node.children, function (cn) {
                                                if (cn.type == "element") {
                                                    if (cn.tagName == "br") {
                                                        code += "\n";
                                                    } else if (!dtd.$empty[node.tagName]) {
                                                        code += cn.innerText();
                                                    }
                                                } else {
                                                    code += cn.data;
                                                }
                                            });
                                            if (!/\n$/.test(code)) {
                                                code += "\n";
                                            }
                                        }
                                    } else {
                                        code += node.data + "\n";
                                    }
                                    if (!node.nextSibling() && /\n$/.test(code)) {
                                        code = code.replace(/\n$/, "");
                                    }
                                } else {
                                    if (browser.ie && browser.ie11below) {
                                        if (node.type == "element") {
                                            if (node.tagName == "br") {
                                                code += "<br>";
                                            } else if (!dtd.$empty[node.tagName]) {
                                                utils.each(node.children, function (cn) {
                                                    if (cn.type == "element") {
                                                        if (cn.tagName == "br") {
                                                            code += "<br>";
                                                        } else if (!dtd.$empty[node.tagName]) {
                                                            code += cn.innerText();
                                                        }
                                                    } else {
                                                        code += cn.data;
                                                    }
                                                });
                                                if (!/br>$/.test(code)) {
                                                    code += "<br>";
                                                }
                                            }
                                        } else {
                                            code += node.data + "<br>";
                                        }
                                        if (!node.nextSibling() && /<br>$/.test(code)) {
                                            code = code.replace(/<br>$/, "");
                                        }
                                    } else {
                                        code += node.type == "element"
                                            ? dtd.$empty[node.tagName] ? "" : node.innerText()
                                            : node.data;
                                        if (!/br\/?\s*>$/.test(code)) {
                                            if (!node.nextSibling()) return;
                                            code += "<br>";
                                        }
                                    }
                                }
                            }
                        );
                    }
                    me.execCommand(
                        "inserthtml",
                        '<pre id="coder"class="brush:' +
                        lang +
                        ';toolbar:false">' +
                        code +
                        "</pre>",
                        true
                    );

                    pre = me.document.getElementById("coder");
                    domUtils.removeAttributes(pre, "id");
                    var tmpNode = pre.previousSibling;

                    if (
                        tmpNode &&
                        ((tmpNode.nodeType == 3 &&
                            tmpNode.nodeValue.length == 1 &&
                            browser.ie &&
                            browser.version == 6) ||
                            domUtils.isEmptyBlock(tmpNode))
                    ) {
                        domUtils.remove(tmpNode);
                    }
                    var rng = me.selection.getRange();
                    if (domUtils.isEmptyBlock(pre)) {
                        rng.setStart(pre, 0).setCursor(false, true);
                    } else {
                        rng.selectNodeContents(pre).select();
                    }
                }
            },
            queryCommandValue: function () {
                var path = this.selection.getStartElementPath();
                var lang = "";
                utils.each(path, function (node) {
                    if (node.nodeName == "PRE") {
                        var match = node.className.match(/brush:([^;]+)/);
                        lang = match && match[1] ? match[1] : "";
                        return false;
                    }
                });
                return lang;
            }
        };

        me.addInputRule(function (root) {
            utils.each(root.getNodesByTagName("pre"), function (pre) {
                var brs = pre.getNodesByTagName("br");
                if (brs.length) {
                    browser.ie &&
                    browser.ie11below &&
                    browser.version > 8 &&
                    utils.each(brs, function (br) {
                        var txt = UE.uNode.createText("\n");
                        br.parentNode.insertBefore(txt, br);
                        br.parentNode.removeChild(br);
                    });
                    return;
                }
                if (browser.ie && browser.ie11below && browser.version > 8) return;
                var code = pre.innerText().split(/\n/);
                pre.innerHTML("");
                utils.each(code, function (c) {
                    if (c.length) {
                        pre.appendChild(UE.uNode.createText(c));
                    }
                    pre.appendChild(UE.uNode.createElement("br"));
                });
            });
        });
        me.addOutputRule(function (root) {
            utils.each(root.getNodesByTagName("pre"), function (pre) {
                var code = "";
                utils.each(pre.children, function (n) {
                    if (n.type == "text") {
                        //在ie下文本内容有可能末尾带有\n要去掉
                        //trace:3396
                        code += n.data.replace(/[ ]/g, "&nbsp;").replace(/\n$/, "");
                    } else {
                        if (n.tagName == "br") {
                            code += "\n";
                        } else {
                            code += !dtd.$empty[n.tagName] ? "" : n.innerText();
                        }
                    }
                });

                pre.innerText(code.replace(/(&nbsp;|\n)+$/, ""));
            });
        });
        //不需要判断highlight的command列表
        me.notNeedCodeQuery = {
            help: 1,
            undo: 1,
            redo: 1,
            source: 1,
            print: 1,
            searchreplace: 1,
            fullscreen: 1,
            preview: 1,
            insertparagraph: 1,
            elementpath: 1,
            insertcode: 1,
            inserthtml: 1,
            selectall: 1
        };
        //将queyCommamndState重置
        var orgQuery = me.queryCommandState;
        me.queryCommandState = function (cmd) {
            var me = this;

            if (
                !me.notNeedCodeQuery[cmd.toLowerCase()] &&
                me.selection &&
                me.queryCommandValue("insertcode")
            ) {
                return -1;
            }
            return UE.Editor.prototype.queryCommandState.apply(this, arguments);
        };
        me.addListener("beforeenterkeydown", function () {
            var rng = me.selection.getRange();
            var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
            if (pre) {
                me.fireEvent("saveScene");
                if (!rng.collapsed) {
                    rng.deleteContents();
                }
                if (!browser.ie || browser.ie9above) {
                    var tmpNode = me.document.createElement("br"),
                        pre;
                    rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
                    var next = tmpNode.nextSibling;
                    if (!next && (!browser.ie || browser.version > 10)) {
                        rng.insertNode(tmpNode.cloneNode(false));
                    } else {
                        rng.setStartAfter(tmpNode);
                    }
                    pre = tmpNode.previousSibling;
                    var tmp;
                    while (pre) {
                        tmp = pre;
                        pre = pre.previousSibling;
                        if (!pre || pre.nodeName == "BR") {
                            pre = tmp;
                            break;
                        }
                    }
                    if (pre) {
                        var str = "";
                        while (
                            pre &&
                            pre.nodeName != "BR" &&
                            new RegExp("^[\\s" + domUtils.fillChar + "]*$").test(pre.nodeValue)
                            ) {
                            str += pre.nodeValue;
                            pre = pre.nextSibling;
                        }
                        if (pre.nodeName != "BR") {
                            var match = pre.nodeValue.match(
                                new RegExp("^([\\s" + domUtils.fillChar + "]+)")
                            );
                            if (match && match[1]) {
                                str += match[1];
                            }
                        }
                        if (str) {
                            str = me.document.createTextNode(str);
                            rng.insertNode(str).setStartAfter(str);
                        }
                    }
                    rng.collapse(true).select(true);
                } else {
                    if (browser.version > 8) {
                        var txt = me.document.createTextNode("\n");
                        var start = rng.startContainer;
                        if (rng.startOffset == 0) {
                            var preNode = start.previousSibling;
                            if (preNode) {
                                rng.insertNode(txt);
                                var fillchar = me.document.createTextNode(" ");
                                rng
                                    .setStartAfter(txt)
                                    .insertNode(fillchar)
                                    .setStart(fillchar, 0)
                                    .collapse(true)
                                    .select(true);
                            }
                        } else {
                            rng.insertNode(txt).setStartAfter(txt);
                            var fillchar = me.document.createTextNode(" ");
                            start = rng.startContainer.childNodes[rng.startOffset];
                            if (start && !/^\n/.test(start.nodeValue)) {
                                rng.setStartBefore(txt);
                            }
                            rng
                                .insertNode(fillchar)
                                .setStart(fillchar, 0)
                                .collapse(true)
                                .select(true);
                        }
                    } else {
                        var tmpNode = me.document.createElement("br");
                        rng.insertNode(tmpNode);
                        rng.insertNode(me.document.createTextNode(domUtils.fillChar));
                        rng.setStartAfter(tmpNode);
                        pre = tmpNode.previousSibling;
                        var tmp;
                        while (pre) {
                            tmp = pre;
                            pre = pre.previousSibling;
                            if (!pre || pre.nodeName == "BR") {
                                pre = tmp;
                                break;
                            }
                        }
                        if (pre) {
                            var str = "";
                            while (
                                pre &&
                                pre.nodeName != "BR" &&
                                new RegExp("^[ " + domUtils.fillChar + "]*$").test(pre.nodeValue)
                                ) {
                                str += pre.nodeValue;
                                pre = pre.nextSibling;
                            }
                            if (pre.nodeName != "BR") {
                                var match = pre.nodeValue.match(
                                    new RegExp("^([ " + domUtils.fillChar + "]+)")
                                );
                                if (match && match[1]) {
                                    str += match[1];
                                }
                            }

                            str = me.document.createTextNode(str);
                            rng.insertNode(str).setStartAfter(str);
                        }
                        rng.collapse(true).select();
                    }
                }
                me.fireEvent("saveScene");
                return true;
            }
        });

        me.addListener("tabkeydown", function (cmd, evt) {
            var rng = me.selection.getRange();
            var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
            if (pre) {
                me.fireEvent("saveScene");
                if (evt.shiftKey) {
                } else {
                    if (!rng.collapsed) {
                        var bk = rng.createBookmark();
                        var start = bk.start.previousSibling;

                        while (start) {
                            if (pre.firstChild === start && !domUtils.isBr(start)) {
                                pre.insertBefore(me.document.createTextNode("    "), start);

                                break;
                            }
                            if (domUtils.isBr(start)) {
                                pre.insertBefore(
                                    me.document.createTextNode("    "),
                                    start.nextSibling
                                );

                                break;
                            }
                            start = start.previousSibling;
                        }
                        var end = bk.end;
                        start = bk.start.nextSibling;
                        if (pre.firstChild === bk.start) {
                            pre.insertBefore(
                                me.document.createTextNode("    "),
                                start.nextSibling
                            );
                        }
                        while (start && start !== end) {
                            if (domUtils.isBr(start) && start.nextSibling) {
                                if (start.nextSibling === end) {
                                    break;
                                }
                                pre.insertBefore(
                                    me.document.createTextNode("    "),
                                    start.nextSibling
                                );
                            }

                            start = start.nextSibling;
                        }
                        rng.moveToBookmark(bk).select();
                    } else {
                        var tmpNode = me.document.createTextNode("    ");
                        rng
                            .insertNode(tmpNode)
                            .setStartAfter(tmpNode)
                            .collapse(true)
                            .select(true);
                    }
                }

                me.fireEvent("saveScene");
                return true;
            }
        });

        me.addListener("beforeinserthtml", function (evtName, html) {
            var me = this,
                rng = me.selection.getRange(),
                pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
            if (pre) {
                if (!rng.collapsed) {
                    rng.deleteContents();
                }
                var htmlstr = "";
                if (browser.ie && browser.version > 8) {
                    utils.each(
                        UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
                            .children,
                        function (node) {
                            if (node.type == "element") {
                                if (node.tagName == "br") {
                                    htmlstr += "\n";
                                } else if (!dtd.$empty[node.tagName]) {
                                    utils.each(node.children, function (cn) {
                                        if (cn.type == "element") {
                                            if (cn.tagName == "br") {
                                                htmlstr += "\n";
                                            } else if (!dtd.$empty[node.tagName]) {
                                                htmlstr += cn.innerText();
                                            }
                                        } else {
                                            htmlstr += cn.data;
                                        }
                                    });
                                    if (!/\n$/.test(htmlstr)) {
                                        htmlstr += "\n";
                                    }
                                }
                            } else {
                                htmlstr += node.data + "\n";
                            }
                            if (!node.nextSibling() && /\n$/.test(htmlstr)) {
                                htmlstr = htmlstr.replace(/\n$/, "");
                            }
                        }
                    );
                    var tmpNode = me.document.createTextNode(
                        utils.html(htmlstr.replace(/&nbsp;/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(/&nbsp;/g, " "))
                                                    )
                                                );
                                            }
                                        } else {
                                            frag.appendChild(
                                                me.document.createTextNode(
                                                    utils.html(cn.data.replace(/&nbsp;/g, " "))
                                                )
                                            );
                                        }
                                    });
                                    if (frag.lastChild.nodeName != "BR") {
                                        frag.appendChild(me.document.createElement("br"));
                                    }
                                }
                            } else {
                                frag.appendChild(
                                    me.document.createTextNode(
                                        utils.html(node.data.replace(/&nbsp;/g, " "))
                                    )
                                );
                            }
                            if (!node.nextSibling() && frag.lastChild.nodeName == "BR") {
                                frag.removeChild(frag.lastChild);
                            }
                        }
                    );
                    rng.insertNode(frag).select();
                }

                return true;
            }
        });
        //方向键的处理
        me.addListener("keydown", function (cmd, evt) {
            var me = this,
                keyCode = evt.keyCode || evt.which;
            if (keyCode == 40) {
                var rng = me.selection.getRange(),
                    pre,
                    start = rng.startContainer;
                if (
                    rng.collapsed &&
                    (pre = domUtils.findParentByTagName(rng.startContainer, "pre", true)) &&
                    !pre.nextSibling
                ) {
                    var last = pre.lastChild;
                    while (last && last.nodeName == "BR") {
                        last = last.previousSibling;
                    }
                    if (
                        last === start ||
                        (rng.startContainer === pre &&
                            rng.startOffset == pre.childNodes.length)
                    ) {
                        me.execCommand("insertparagraph");
                        domUtils.preventDefault(evt);
                    }
                }
            }
        });
        //trace:3395
        me.addListener("delkeydown", function (type, evt) {
            var rng = this.selection.getRange();
            rng.txtToElmBoundary(true);
            var start = rng.startContainer;
            if (
                domUtils.isTagNode(start, "pre") &&
                rng.collapsed &&
                domUtils.isStartInblock(rng)
            ) {
                var p = me.document.createElement("p");
                domUtils.fillNode(me.document, p);
                start.parentNode.insertBefore(p, start);
                domUtils.remove(start);
                rng.setStart(p, 0).setCursor(false, true);
                domUtils.preventDefault(evt);
                return true;
            }
        });
    };


// plugins/cleardoc.js
    /**
     * 清空文档插件
     * @file
     * @since 1.2.6.1
     */

    /**
     * 清空文档
     * @command cleardoc
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * //editor 是编辑器实例
     * editor.execCommand('cleardoc');
     * ```
     */

    UE.commands["cleardoc"] = {
        execCommand: function (cmdName) {
            var me = this,
                enterTag = me.options.enterTag,
                range = me.selection.getRange();
            if (enterTag == "br") {
                me.body.innerHTML = "<br/>";
                range.setStart(me.body, 0).setCursor();
            } else {
                me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
                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")) {
                        //过滤掉word冗余标签
                        //_Toc\d+有可能勿命中
                        if (/^\_Toc\d+$/.test(val)) {
                            a.parentNode.removeChild(a);
                            return;
                        }
                        a.tagName = "img";
                        a.setAttr({
                            anchorname: a.getAttr("name"),
                            class: "anchorclass"
                        });
                        a.setAttr("name");
                    }
                });
            },
            commands: {
                /**
                 * 插入锚点
                 * @command anchor
                 * @method execCommand
                 * @param { String } cmd 命令字符串
                 * @param { String } name 锚点名称字符串
                 * @example
                 * ```javascript
                 * //editor 是编辑器实例
                 * editor.execCommand('anchor', 'anchor1');
                 * ```
                 */
                anchor: {
                    execCommand: function (cmd, name) {
                        var range = this.selection.getRange(),
                            img = range.getClosedNode();
                        if (img && img.getAttribute("anchorname")) {
                            if (name) {
                                img.setAttribute("anchorname", name);
                            } else {
                                range.setStartBefore(img).setCursor();
                                domUtils.remove(img);
                            }
                        } else {
                            if (name) {
                                //只在选区的开始插入
                                var anchor = this.document.createElement("img");
                                range.collapse(true);
                                domUtils.setAttributes(anchor, {
                                    anchorname: name,
                                    class: "anchorclass"
                                });
                                range
                                    .insertNode(anchor)
                                    .setStartAfter(anchor)
                                    .setCursor(false, true);
                            }
                        }
                    }
                }
            }
        };
    });


// plugins/wordcount.js
///import core
///commands 字数统计
///commandsName  WordCount,wordCount
///commandsTitle  字数统计
    /*
 * Created by JetBrains WebStorm.
 * User: taoqili
 * Date: 11-9-7
 * Time: 下午8:18
 * To change this template use File | Settings | File Templates.
 */

    UE.plugins["wordcount"] = function () {
        var me = this;
        me.setOpt("wordCount", true);
        me.addListener("contentchange", function () {
            me.fireEvent("wordcount");
        });
        var timer;
        me.addListener("ready", function () {
            var me = this;
            domUtils.on(me.body, "keyup", function (evt) {
                var code = evt.keyCode || evt.which,
                    //忽略的按键,ctr,alt,shift,方向键
                    ignores = {
                        "16": 1,
                        "18": 1,
                        "20": 1,
                        "37": 1,
                        "38": 1,
                        "39": 1,
                        "40": 1
                    };
                if (code in ignores) return;
                clearTimeout(timer);
                timer = setTimeout(function () {
                    me.fireEvent("wordcount");
                }, 200);
            });
        });
    };


// plugins/pagebreak.js
    /**
     * 分页功能插件
     * @file
     * @since 1.2.6.1
     */
    UE.plugins["pagebreak"] = function () {
        var me = this,
            notBreakTags = ["td"];
        me.setOpt("pageBreakTag", "_ueditor_page_break_tag_");

        function fillNode(node) {
            if (domUtils.isEmptyBlock(node)) {
                var firstChild = node.firstChild,
                    tmpNode;

                while (
                    firstChild &&
                    firstChild.nodeType == 1 &&
                    domUtils.isEmptyBlock(firstChild)
                    ) {
                    tmpNode = firstChild;
                    firstChild = firstChild.firstChild;
                }
                !tmpNode && (tmpNode = node);
                domUtils.fillNode(me.document, tmpNode);
            }
        }

        //分页符样式添加

        me.ready(function () {
            utils.cssRule(
                "pagebreak",
                ".pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}",
                me.document
            );
        });

        function isHr(node) {
            return (
                node &&
                node.nodeType == 1 &&
                node.tagName == "HR" &&
                node.className == "pagebreak"
            );
        }

        me.addInputRule(function (root) {
            root.traversal(function (node) {
                if (node.type == "text" && node.data == me.options.pageBreakTag) {
                    var hr = UE.uNode.createElement(
                        '<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;">'
                    );
                    node.parentNode.insertBefore(hr, node);
                    node.parentNode.removeChild(node);
                }
            });
        });
        me.addOutputRule(function (node) {
            utils.each(node.getNodesByTagName("hr"), function (n) {
                if (n.getAttr("class") == "pagebreak") {
                    var txt = UE.uNode.createText(me.options.pageBreakTag);
                    n.parentNode.insertBefore(txt, n);
                    n.parentNode.removeChild(n);
                }
            });
        });

        /**
         * 插入分页符
         * @command pagebreak
         * @method execCommand
         * @param { String } cmd 命令字符串
         * @remind 在表格中插入分页符会把表格切分成两部分
         * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串,
         *          以便于提交数据到服务器端后处理分页。
         * @example
         * ```javascript
         * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak
         * ```
         */

        me.commands["pagebreak"] = {
            execCommand: function () {
                var range = me.selection.getRange(),
                    hr = me.document.createElement("hr");
                domUtils.setAttributes(hr, {
                    class: "pagebreak",
                    noshade: "noshade",
                    size: "5"
                });
                domUtils.unSelectable(hr);
                //table单独处理
                var node = domUtils.findParentByTagName(
                    range.startContainer,
                    notBreakTags,
                    true
                    ),
                    parents = [],
                    pN;
                if (node) {
                    switch (node.tagName) {
                        case "TD":
                            pN = node.parentNode;
                            if (!pN.previousSibling) {
                                var table = domUtils.findParentByTagName(pN, "table");
                                //                            var tableWrapDiv = table.parentNode;
                                //                            if(tableWrapDiv && tableWrapDiv.nodeType == 1
                                //                                && tableWrapDiv.tagName == 'DIV'
                                //                                && tableWrapDiv.getAttribute('dropdrag')
                                //                                ){
                                //                                domUtils.remove(tableWrapDiv,true);
                                //                            }
                                table.parentNode.insertBefore(hr, table);
                                parents = domUtils.findParents(hr, true);
                            } else {
                                pN.parentNode.insertBefore(hr, pN);
                                parents = domUtils.findParents(hr);
                            }
                            pN = parents[1];
                            if (hr !== pN) {
                                domUtils.breakParent(hr, pN);
                            }
                            //table要重写绑定一下拖拽
                            me.fireEvent("afteradjusttable", me.document);
                    }
                } else {
                    if (!range.collapsed) {
                        range.deleteContents();
                        var start = range.startContainer;
                        while (
                            !domUtils.isBody(start) &&
                            domUtils.isBlockElm(start) &&
                            domUtils.isEmptyNode(start)
                            ) {
                            range.setStartBefore(start).collapse(true);
                            domUtils.remove(start);
                            start = range.startContainer;
                        }
                    }
                    range.insertNode(hr);

                    var pN = hr.parentNode,
                        nextNode;
                    while (!domUtils.isBody(pN)) {
                        domUtils.breakParent(hr, pN);
                        nextNode = hr.nextSibling;
                        if (nextNode && domUtils.isEmptyBlock(nextNode)) {
                            domUtils.remove(nextNode);
                        }
                        pN = hr.parentNode;
                    }
                    nextNode = hr.nextSibling;
                    var pre = hr.previousSibling;
                    if (isHr(pre)) {
                        domUtils.remove(pre);
                    } else {
                        pre && fillNode(pre);
                    }

                    if (!nextNode) {
                        var p = me.document.createElement("p");

                        hr.parentNode.appendChild(p);
                        domUtils.fillNode(me.document, p);
                        range.setStart(p, 0).collapse(true);
                    } else {
                        if (isHr(nextNode)) {
                            domUtils.remove(nextNode);
                        } else {
                            fillNode(nextNode);
                        }
                        range.setEndAfter(hr).collapse(false);
                    }

                    range.select(true);
                }
            }
        };
    };


// plugins/wordimage.js
///import core
///commands 本地图片引导上传
///commandsName  WordImage
///commandsTitle  本地图片引导上传
///commandsDialog  dialogs\wordimage

    UE.plugin.register("wordimage", function () {
        var me = this,
            images = [];
        return {
            commands: {
                wordimage: {
                    execCommand: function () {
                        var images = domUtils.getElementsByTagName(me.body, "img");
                        var urlList = [];
                        for (var i = 0, ci; (ci = images[i++]);) {
                            var url = ci.getAttribute("word_img");
                            url && urlList.push(url);
                        }
                        return urlList;
                    },
                    queryCommandState: function () {
                        images = domUtils.getElementsByTagName(me.body, "img");
                        for (var i = 0, ci; (ci = images[i++]);) {
                            if (ci.getAttribute("word_img")) {
                                return 1;
                            }
                        }
                        return -1;
                    },
                    notNeedUndo: true
                }
            },
            inputRule: function (root) {
                utils.each(root.getNodesByTagName("img"), function (img) {
                    var attrs = img.attrs,
                        flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
                        opt = me.options,
                        src = opt.UEDITOR_HOME_URL + "themes/notadd/images/spacer.gif";
                    if (attrs["src"] && /^(?:(file:\/+))/.test(attrs["src"])) {
                        img.setAttr({
                            width: attrs.width,
                            height: attrs.height,
                            alt: attrs.alt,
                            word_img: attrs.src,
                            src: src,
                            style:
                            "background:url(" +
                            (flag
                                ? opt.themePath + opt.theme + "/images/word.gif"
                                : opt.langPath + opt.lang + "/images/localimage.png") +
                            ") no-repeat center center;border:1px solid #ddd"
                        });
                    }
                });
            }
        };
    });


// plugins/dragdrop.js
    UE.plugins["dragdrop"] = function () {
        var me = this;
        me.ready(function () {
            domUtils.on(this.body, "dragend", function () {
                var rng = me.selection.getRange();
                var node = rng.getClosedNode() || me.selection.getStart();

                if (node && node.tagName == "IMG") {
                    var pre = node.previousSibling,
                        next;
                    while ((next = node.nextSibling)) {
                        if (
                            next.nodeType == 1 &&
                            next.tagName == "SPAN" &&
                            !next.firstChild
                        ) {
                            domUtils.remove(next);
                        } else {
                            break;
                        }
                    }

                    if (
                        ((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre)) || !pre) &&
                        (!next || (next && !domUtils.isEmptyBlock(next)))
                    ) {
                        if (pre && pre.tagName == "P" && !domUtils.isEmptyBlock(pre)) {
                            pre.appendChild(node);
                            domUtils.moveChild(next, pre);
                            domUtils.remove(next);
                        } else if (
                            next &&
                            next.tagName == "P" &&
                            !domUtils.isEmptyBlock(next)
                        ) {
                            next.insertBefore(node, next.firstChild);
                        }

                        if (pre && pre.tagName == "P" && domUtils.isEmptyBlock(pre)) {
                            domUtils.remove(pre);
                        }
                        if (next && next.tagName == "P" && domUtils.isEmptyBlock(next)) {
                            domUtils.remove(next);
                        }
                        rng.selectNode(node).select();
                        me.fireEvent("saveScene");
                    }
                }
            });
        });
        me.addListener("keyup", function (type, evt) {
            var keyCode = evt.keyCode || evt.which;
            if (keyCode == 13) {
                var rng = me.selection.getRange(),
                    node;
                if (
                    (node = domUtils.findParentByTagName(rng.startContainer, "p", true))
                ) {
                    if (domUtils.getComputedStyle(node, "text-align") == "center") {
                        domUtils.removeStyle(node, "text-align");
                    }
                }
            }
        });
    };


// plugins/undo.js
    /**
     * undo redo
     * @file
     * @since 1.2.6.1
     */

    /**
     * 撤销上一次执行的命令
     * @command undo
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'undo' );
     * ```
     */

    /**
     * 重做上一次执行的命令
     * @command redo
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'redo' );
     * ```
     */

    UE.plugins["undo"] = function () {
        var saveSceneTimer;
        var me = this,
            maxUndoCount = me.options.maxUndoCount || 20,
            maxInputCount = me.options.maxInputCount || 20,
            fillchar = new RegExp(domUtils.fillChar + "|</hr>", "gi"); // ie会产生多余的</hr>
        var noNeedFillCharTags = {
            ol: 1,
            ul: 1,
            table: 1,
            tbody: 1,
            tr: 1,
            body: 1
        };
        var orgState = me.options.autoClearEmptyNode;

        function compareAddr(indexA, indexB) {
            if (indexA.length != indexB.length) return 0;
            for (var i = 0, l = indexA.length; i < l; i++) {
                if (indexA[i] != indexB[i]) return 0;
            }
            return 1;
        }

        function compareRangeAddress(rngAddrA, rngAddrB) {
            if (rngAddrA.collapsed != rngAddrB.collapsed) {
                return 0;
            }
            if (
                !compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) ||
                !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)
            ) {
                return 0;
            }
            return 1;
        }

        function UndoManager() {
            this.list = [];
            this.index = 0;
            this.hasUndo = false;
            this.hasRedo = false;
            this.undo = function () {
                if (this.hasUndo) {
                    if (!this.list[this.index - 1] && this.list.length == 1) {
                        this.reset();
                        return;
                    }
                    while (
                        this.list[this.index].content == this.list[this.index - 1].content
                        ) {
                        this.index--;
                        if (this.index == 0) {
                            return this.restore(0);
                        }
                    }
                    this.restore(--this.index);
                }
            };
            this.redo = function () {
                if (this.hasRedo) {
                    while (
                        this.list[this.index].content == this.list[this.index + 1].content
                        ) {
                        this.index++;
                        if (this.index == this.list.length - 1) {
                            return this.restore(this.index);
                        }
                    }
                    this.restore(++this.index);
                }
            };

            this.restore = function () {
                var me = this.editor;
                var scene = this.list[this.index];
                var root = UE.htmlparser(scene.content.replace(fillchar, ""));
                me.options.autoClearEmptyNode = false;
                me.filterInputRule(root);
                me.options.autoClearEmptyNode = orgState;
                //trace:873
                //去掉展位符
                me.document.body.innerHTML = root.toHtml();
                me.fireEvent("afterscencerestore");
                //处理undo后空格不展位的问题
                if (browser.ie) {
                    utils.each(
                        domUtils.getElementsByTagName(me.document, "td th caption p"),
                        function (node) {
                            if (domUtils.isEmptyNode(node)) {
                                domUtils.fillNode(me.document, node);
                            }
                        }
                    );
                }

                try {
                    var rng = new dom.Range(me.document).moveToAddress(scene.address);
                    rng.select(
                        noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]
                    );
                } catch (e) {
                }

                this.update();
                this.clearKey();
                //不能把自己reset了
                me.fireEvent("reset", true);
            };

            this.getScene = function () {
                var me = this.editor;
                var rng = me.selection.getRange(),
                    rngAddress = rng.createAddress(false, true);
                me.fireEvent("beforegetscene");
                var root = UE.htmlparser(me.body.innerHTML);
                me.options.autoClearEmptyNode = false;
                me.filterOutputRule(root);
                me.options.autoClearEmptyNode = orgState;
                var cont = root.toHtml();
                //trace:3461
                //这个会引起回退时导致空格丢失的情况
                //            browser.ie && (cont = cont.replace(/>&nbsp;</g, '><').replace(/\s*</g, '<').replace(/>\s*/g, '>'));
                me.fireEvent("aftergetscene");

                return {
                    address: rngAddress,
                    content: cont
                };
            };
            this.save = function (notCompareRange, notSetCursor) {
                clearTimeout(saveSceneTimer);
                var currentScene = this.getScene(notSetCursor),
                    lastScene = this.list[this.index];

                if (lastScene && lastScene.content != currentScene.content) {
                    me.trigger("contentchange");
                }
                //内容相同位置相同不存
                if (
                    lastScene &&
                    lastScene.content == currentScene.content &&
                    (notCompareRange
                        ? 1
                        : compareRangeAddress(lastScene.address, currentScene.address))
                ) {
                    return;
                }
                this.list = this.list.slice(0, this.index + 1);
                this.list.push(currentScene);
                //如果大于最大数量了,就把最前的剔除
                if (this.list.length > maxUndoCount) {
                    this.list.shift();
                }
                this.index = this.list.length - 1;
                this.clearKey();
                //跟新undo/redo状态
                this.update();
            };
            this.update = function () {
                this.hasRedo = !!this.list[this.index + 1];
                this.hasUndo = !!this.list[this.index - 1];
            };
            this.reset = function () {
                this.list = [];
                this.index = 0;
                this.hasUndo = false;
                this.hasRedo = false;
                this.clearKey();
            };
            this.clearKey = function () {
                keycont = 0;
                lastKeyCode = null;
            };
        }

        me.undoManger = new UndoManager();
        me.undoManger.editor = me;

        function saveScene() {
            this.undoManger.save();
        }

        me.addListener("saveScene", function () {
            var args = Array.prototype.splice.call(arguments, 1);
            this.undoManger.save.apply(this.undoManger, args);
        });

        //    me.addListener('beforeexeccommand', saveScene);
        //    me.addListener('afterexeccommand', saveScene);

        me.addListener("reset", function (type, exclude) {
            if (!exclude) {
                this.undoManger.reset();
            }
        });
        me.commands["redo"] = me.commands["undo"] = {
            execCommand: function (cmdName) {
                this.undoManger[cmdName]();
            },
            queryCommandState: function (cmdName) {
                return this.undoManger[
                "has" + (cmdName.toLowerCase() == "undo" ? "Undo" : "Redo")
                    ]
                    ? 0
                    : -1;
            },
            notNeedUndo: 1
        };

        var keys = {
                //  /*Backspace*/ 8:1, /*Delete*/ 46:1,
                /*Shift*/ 16: 1,
                /*Ctrl*/ 17: 1,
                /*Alt*/ 18: 1,
                37: 1,
                38: 1,
                39: 1,
                40: 1
            },
            keycont = 0,
            lastKeyCode;
        //输入法状态下不计算字符数
        var inputType = false;
        me.addListener("ready", function () {
            domUtils.on(this.body, "compositionstart", function () {
                inputType = true;
            });
            domUtils.on(this.body, "compositionend", function () {
                inputType = false;
            });
        });
        //快捷键
        me.addshortcutkey({
            Undo: "ctrl+90", //undo
            Redo: "ctrl+89" //redo
        });
        var isCollapsed = true;
        me.addListener("keydown", function (type, evt) {
            var me = this;
            var keyCode = evt.keyCode || evt.which;
            if (
                !keys[keyCode] &&
                !evt.ctrlKey &&
                !evt.metaKey &&
                !evt.shiftKey &&
                !evt.altKey
            ) {
                if (inputType) return;

                if (!me.selection.getRange().collapsed) {
                    me.undoManger.save(false, true);
                    isCollapsed = false;
                    return;
                }
                if (me.undoManger.list.length == 0) {
                    me.undoManger.save(true);
                }
                clearTimeout(saveSceneTimer);

                function save(cont) {
                    cont.undoManger.save(false, true);
                    cont.fireEvent("selectionchange");
                }

                saveSceneTimer = setTimeout(function () {
                    if (inputType) {
                        var interalTimer = setInterval(function () {
                            if (!inputType) {
                                save(me);
                                clearInterval(interalTimer);
                            }
                        }, 300);
                        return;
                    }
                    save(me);
                }, 200);

                lastKeyCode = keyCode;
                keycont++;
                if (keycont >= maxInputCount) {
                    save(me);
                }
            }
        });
        me.addListener("keyup", function (type, evt) {
            var keyCode = evt.keyCode || evt.which;
            if (
                !keys[keyCode] &&
                !evt.ctrlKey &&
                !evt.metaKey &&
                !evt.shiftKey &&
                !evt.altKey
            ) {
                if (inputType) return;
                if (!isCollapsed) {
                    this.undoManger.save(false, true);
                    isCollapsed = true;
                }
            }
        });
        //扩展实例,添加关闭和开启命令undo
        me.stopCmdUndo = function () {
            me.__hasEnterExecCommand = true;
        };
        me.startCmdUndo = function () {
            me.__hasEnterExecCommand = false;
        };
    };


// plugins/copy.js
    UE.plugin.register("copy", function () {
        var me = this;

        function initZeroClipboard() {
            ZeroClipboard.config({
                debug: false,
                swfPath:
                me.options.UEDITOR_HOME_URL +
                "third-party/zeroclipboard/ZeroClipboard.swf"
            });

            var client = (me.zeroclipboard = new ZeroClipboard());

            // 复制内容
            client.on("copy", function (e) {
                var client = e.client,
                    rng = me.selection.getRange(),
                    div = document.createElement("div");

                div.appendChild(rng.cloneContents());
                client.setText(div.innerText || div.textContent);
                client.setHtml(div.innerHTML);
                rng.select();
            });
            // hover事件传递到target
            client.on("mouseover mouseout", function (e) {
                var target = e.target;
                if (target) {
                    if (e.type == "mouseover") {
                        domUtils.addClass(target, "edui-state-hover");
                    } else if (e.type == "mouseout") {
                        domUtils.removeClasses(target, "edui-state-hover");
                    }
                }
            });
            // flash加载不成功
            client.on("wrongflash noflash", function () {
                ZeroClipboard.destroy();
            });

            // 触发事件
            me.fireEvent("zeroclipboardready", client);
        }

        return {
            bindEvents: {
                ready: function () {
                    if (!browser.ie) {
                        if (window.ZeroClipboard) {
                            initZeroClipboard();
                        } else {
                            utils.loadFile(
                                document,
                                {
                                    src:
                                    me.options.UEDITOR_HOME_URL +
                                    "third-party/zeroclipboard/ZeroClipboard.js",
                                    tag: "script",
                                    type: "text/javascript",
                                    defer: "defer"
                                },
                                function () {
                                    initZeroClipboard();
                                }
                            );
                        }
                    }
                }
            },
            commands: {
                copy: {
                    execCommand: function (cmd) {
                        if (!me.document.execCommand("copy")) {
                            alert(me.getLang("copymsg"));
                        }
                    }
                }
            }
        };
    });


// plugins/paste.js
///import core
///import plugins/inserthtml.js
///import plugins/undo.js
///import plugins/serialize.js
///commands 粘贴
///commandsName  PastePlain
///commandsTitle  纯文本粘贴模式
    /**
     * @description 粘贴
     * @author zhanyi
     */
    UE.plugins["paste"] = function () {
        function getClipboardData(callback) {
            var doc = this.document;
            if (doc.getElementById("baidu_pastebin")) {
                return;
            }
            var range = this.selection.getRange(),
                bk = range.createBookmark(),
                //创建剪贴的容器div
                pastebin = doc.createElement("div");
            pastebin.id = "baidu_pastebin";
            // Safari 要求div必须有内容,才能粘贴内容进来
            browser.webkit &&
            pastebin.appendChild(
                doc.createTextNode(domUtils.fillChar + domUtils.fillChar)
            );
            doc.body.appendChild(pastebin);
            //trace:717 隐藏的span不能得到top
            //bk.start.innerHTML = '&nbsp;';
            bk.start.style.display = "";
            pastebin.style.cssText =
                "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
                //要在现在光标平行的位置加入,否则会出现跳动的问题
                domUtils.getXY(bk.start).y +
                "px";

            range.selectNodeContents(pastebin).select(true);

            setTimeout(function () {
                if (browser.webkit) {
                    for (
                        var i = 0, pastebins = doc.querySelectorAll("#baidu_pastebin"), pi;
                        (pi = pastebins[i++]);
                    ) {
                        if (domUtils.isEmptyNode(pi)) {
                            domUtils.remove(pi);
                        } else {
                            pastebin = pi;
                            break;
                        }
                    }
                }
                try {
                    pastebin.parentNode.removeChild(pastebin);
                } catch (e) {
                }
                range.moveToBookmark(bk).select(true);
                callback(pastebin);
            }, 0);
        }

        var me = this;

        me.setOpt({
            retainOnlyLabelPasted: false
        });

        var txtContent, htmlContent, address;

        function getPureHtml(html) {
            return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function (
                a,
                b,
                tagName,
                attrs
            ) {
                tagName = tagName.toLowerCase();
                if ({img: 1}[tagName]) {
                    return a;
                }
                attrs = attrs.replace(
                    /([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi,
                    function (str, atr, val) {
                        if (
                            {
                                src: 1,
                                href: 1,
                                name: 1
                            }[atr.toLowerCase()]
                        ) {
                            return atr + "=" + val + " ";
                        }
                        return "";
                    }
                );
                if (
                    {
                        span: 1,
                        div: 1
                    }[tagName]
                ) {
                    return "";
                } else {
                    return "<" + b + tagName + " " + utils.trim(attrs) + ">";
                }
            });
        }

        function filter(div) {
            var html;
            if (div.firstChild) {
                //去掉cut中添加的边界值
                var nodes = domUtils.getElementsByTagName(div, "span");
                for (var i = 0, ni; (ni = nodes[i++]);) {
                    if (ni.id == "_baidu_cut_start" || ni.id == "_baidu_cut_end") {
                        domUtils.remove(ni);
                    }
                }

                if (browser.webkit) {
                    var brs = div.querySelectorAll("div br");
                    for (var i = 0, bi; (bi = brs[i++]);) {
                        var pN = bi.parentNode;
                        if (pN.tagName == "DIV" && pN.childNodes.length == 1) {
                            pN.innerHTML = "<p><br/></p>";
                            domUtils.remove(pN);
                        }
                    }
                    var divs = div.querySelectorAll("#baidu_pastebin");
                    for (var i = 0, di; (di = divs[i++]);) {
                        var tmpP = me.document.createElement("p");
                        di.parentNode.insertBefore(tmpP, di);
                        while (di.firstChild) {
                            tmpP.appendChild(di.firstChild);
                        }
                        domUtils.remove(di);
                    }

                    var metas = div.querySelectorAll("meta");
                    for (var i = 0, ci; (ci = metas[i++]);) {
                        domUtils.remove(ci);
                    }

                    var brs = div.querySelectorAll("br");
                    for (i = 0; (ci = brs[i++]);) {
                        if (/^apple-/i.test(ci.className)) {
                            domUtils.remove(ci);
                        }
                    }
                }
                if (browser.gecko) {
                    var dirtyNodes = div.querySelectorAll("[_moz_dirty]");
                    for (i = 0; (ci = dirtyNodes[i++]);) {
                        ci.removeAttribute("_moz_dirty");
                    }
                }
                if (!browser.ie) {
                    var spans = div.querySelectorAll("span.Apple-style-span");
                    for (var i = 0, ci; (ci = spans[i++]);) {
                        domUtils.remove(ci, true);
                    }
                }

                //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
                html = div.innerHTML; //.replace(/>(?:(\s|&nbsp;)*?)</g,'><');

                //过滤word粘贴过来的冗余属性
                html = UE.filterWord(html);
                //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
                var root = UE.htmlparser(html);
                //如果给了过滤规则就先进行过滤
                if (me.options.filterRules) {
                    UE.filterNode(root, me.options.filterRules);
                }
                //执行默认的处理
                me.filterInputRule(root);
                //针对chrome的处理
                if (browser.webkit) {
                    var br = root.lastChild();
                    if (br && br.type == "element" && br.tagName == "br") {
                        root.removeChild(br);
                    }
                    utils.each(me.body.querySelectorAll("div"), function (node) {
                        if (domUtils.isEmptyBlock(node)) {
                            domUtils.remove(node, true);
                        }
                    });
                }
                html = {html: root.toHtml()};
                me.fireEvent("beforepaste", html, root);
                //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
                if (!html.html) {
                    return;
                }
                root = UE.htmlparser(html.html, true);
                //如果开启了纯文本模式
                if (me.queryCommandState("pasteplain") === 1) {
                    me.execCommand(
                        "insertHtml",
                        UE.filterNode(root, me.options.filterTxtRules).toHtml(),
                        true
                    );
                } else {
                    //文本模式
                    UE.filterNode(root, me.options.filterTxtRules);
                    txtContent = root.toHtml();
                    //完全模式
                    htmlContent = html.html;

                    address = me.selection.getRange().createAddress(true);
                    me.execCommand(
                        "insertHtml",
                        me.getOpt("retainOnlyLabelPasted") === true
                            ? getPureHtml(htmlContent)
                            : htmlContent,
                        true
                    );
                }
                me.fireEvent("afterpaste", html);
            }
        }

        me.addListener("pasteTransfer", function (cmd, plainType) {
            if (address && txtContent && htmlContent && txtContent != htmlContent) {
                var range = me.selection.getRange();
                range.moveToAddress(address, true);

                if (!range.collapsed) {
                    while (!domUtils.isBody(range.startContainer)) {
                        var start = range.startContainer;
                        if (start.nodeType == 1) {
                            start = start.childNodes[range.startOffset];
                            if (!start) {
                                range.setStartBefore(range.startContainer);
                                continue;
                            }
                            var pre = start.previousSibling;

                            if (
                                pre &&
                                pre.nodeType == 3 &&
                                new RegExp("^[\n\r\t " + domUtils.fillChar + "]*$").test(
                                    pre.nodeValue
                                )
                            ) {
                                range.setStartBefore(pre);
                            }
                        }
                        if (range.startOffset == 0) {
                            range.setStartBefore(range.startContainer);
                        } else {
                            break;
                        }
                    }
                    while (!domUtils.isBody(range.endContainer)) {
                        var end = range.endContainer;
                        if (end.nodeType == 1) {
                            end = end.childNodes[range.endOffset];
                            if (!end) {
                                range.setEndAfter(range.endContainer);
                                continue;
                            }
                            var next = end.nextSibling;
                            if (
                                next &&
                                next.nodeType == 3 &&
                                new RegExp("^[\n\r\t" + domUtils.fillChar + "]*$").test(
                                    next.nodeValue
                                )
                            ) {
                                range.setEndAfter(next);
                            }
                        }
                        if (
                            range.endOffset ==
                            range.endContainer[
                                range.endContainer.nodeType == 3 ? "nodeValue" : "childNodes"
                                ].length
                        ) {
                            range.setEndAfter(range.endContainer);
                        } else {
                            break;
                        }
                    }
                }

                range.deleteContents();
                range.select(true);
                me.__hasEnterExecCommand = true;
                var html = htmlContent;
                if (plainType === 2) {
                    html = getPureHtml(html);
                } else if (plainType) {
                    html = txtContent;
                }
                me.execCommand("inserthtml", html, true);
                me.__hasEnterExecCommand = false;
                var rng = me.selection.getRange();
                while (
                    !domUtils.isBody(rng.startContainer) &&
                    !rng.startOffset &&
                    rng.startContainer[
                        rng.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
                        ].length
                    ) {
                    rng.setStartBefore(rng.startContainer);
                }
                var tmpAddress = rng.createAddress(true);
                address.endAddress = tmpAddress.startAddress;
            }
        });

        me.addListener("ready", function () {
            domUtils.on(me.body, "cut", function () {
                var range = me.selection.getRange();
                if (!range.collapsed && me.undoManger) {
                    me.undoManger.save();
                }
            });

            //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
            domUtils.on(
                me.body,
                browser.ie || browser.opera ? "keydown" : "paste",
                function (e) {
                    if (
                        (browser.ie || browser.opera) &&
                        ((!e.ctrlKey && !e.metaKey) || e.keyCode != "86")
                    ) {
                        return;
                    }
                    getClipboardData.call(me, function (div) {
                        filter(div);
                    });
                }
            );
        });

        me.commands["paste"] = {
            execCommand: function (cmd) {
                if (browser.ie) {
                    getClipboardData.call(me, function (div) {
                        filter(div);
                    });
                    me.document.execCommand("paste");
                } else {
                    alert(me.getLang("pastemsg"));
                }
            }
        };
    };


// plugins/puretxtpaste.js
    /**
     * 纯文本粘贴插件
     * @file
     * @since 1.2.6.1
     */

    UE.plugins["pasteplain"] = function () {
        var me = this;
        me.setOpt({
            pasteplain: false,
            filterTxtRules: (function () {
                function transP(node) {
                    node.tagName = "p";
                    node.setStyle();
                }

                function removeNode(node) {
                    node.parentNode.removeChild(node, true);
                }

                return {
                    //直接删除及其字节点内容
                    "-": "script style object iframe embed input select",
                    p: {$: {}},
                    br: {$: {}},
                    div: function (node) {
                        var tmpNode,
                            p = UE.uNode.createElement("p");
                        while ((tmpNode = node.firstChild())) {
                            if (tmpNode.type == "text" || !UE.dom.dtd.$block[tmpNode.tagName]) {
                                p.appendChild(tmpNode);
                            } else {
                                if (p.firstChild()) {
                                    node.parentNode.insertBefore(p, node);
                                    p = UE.uNode.createElement("p");
                                } else {
                                    node.parentNode.insertBefore(tmpNode, node);
                                }
                            }
                        }
                        if (p.firstChild()) {
                            node.parentNode.insertBefore(p, node);
                        }
                        node.parentNode.removeChild(node);
                    },
                    ol: removeNode,
                    ul: removeNode,
                    dl: removeNode,
                    dt: removeNode,
                    dd: removeNode,
                    li: removeNode,
                    caption: transP,
                    th: transP,
                    tr: transP,
                    h1: transP,
                    h2: transP,
                    h3: transP,
                    h4: transP,
                    h5: transP,
                    h6: transP,
                    td: function (node) {
                        //没有内容的td直接删掉
                        var txt = !!node.innerText();
                        if (txt) {
                            node.parentNode.insertAfter(
                                UE.uNode.createText(" &nbsp; &nbsp;"),
                                node
                            );
                        }
                        node.parentNode.removeChild(node, node.innerText());
                    }
                };
            })()
        });
        //暂时这里支持一下老版本的属性
        var pasteplain = me.options.pasteplain;

        /**
         * 启用或取消纯文本粘贴模式
         * @command pasteplain
         * @method execCommand
         * @param { String } cmd 命令字符串
         * @example
         * ```javascript
         * editor.queryCommandState( 'pasteplain' );
         * ```
         */

        /**
         * 查询当前是否处于纯文本粘贴模式
         * @command pasteplain
         * @method queryCommandState
         * @param { String } cmd 命令字符串
         * @return { int } 如果处于纯文本模式,返回1,否则,返回0
         * @example
         * ```javascript
         * editor.queryCommandState( 'pasteplain' );
         * ```
         */
        me.commands["pasteplain"] = {
            queryCommandState: function () {
                return pasteplain ? 1 : 0;
            },
            execCommand: function () {
                pasteplain = !pasteplain | 0;
            },
            notNeedUndo: 1
        };
    };


// plugins/list.js
    /**
     * 有序列表,无序列表插件
     * @file
     * @since 1.2.6.1
     */

    UE.plugins["list"] = function () {
        var me = this,
            notExchange = {
                TD: 1,
                PRE: 1,
                BLOCKQUOTE: 1
            };
        var customStyle = {
            cn: "cn-1-",
            cn1: "cn-2-",
            cn2: "cn-3-",
            num: "num-1-",
            num1: "num-2-",
            num2: "num-3-",
            dash: "dash",
            dot: "dot"
        };

        me.setOpt({
            autoTransWordToList: false,
            insertorderedlist: {
                num: "",
                num1: "",
                num2: "",
                cn: "",
                cn1: "",
                cn2: "",
                decimal: "",
                "lower-alpha": "",
                "lower-roman": "",
                "upper-alpha": "",
                "upper-roman": ""
            },
            insertunorderedlist: {
                circle: "",
                disc: "",
                square: "",
                dash: "",
                dot: ""
            },
            listDefaultPaddingLeft: "30",
            listiconpath: "http://bs.baidu.com/listicon/",
            maxListLevel: -1, //-1不限制
            disablePInList: false
        });

        function listToArray(list) {
            var arr = [];
            for (var p in list) {
                arr.push(p);
            }
            return arr;
        }

        var listStyle = {
            OL: listToArray(me.options.insertorderedlist),
            UL: listToArray(me.options.insertunorderedlist)
        };
        var liiconpath = me.options.listiconpath;

        //根据用户配置,调整customStyle
        for (var s in customStyle) {
            if (
                !me.options.insertorderedlist.hasOwnProperty(s) &&
                !me.options.insertunorderedlist.hasOwnProperty(s)
            ) {
                delete customStyle[s];
            }
        }

        me.ready(function () {
            var customCss = [];
            for (var p in customStyle) {
                if (p == "dash" || p == "dot") {
                    customCss.push(
                        "li.list-" +
                        customStyle[p] +
                        "{background-image:url(" +
                        liiconpath +
                        customStyle[p] +
                        ".gif)}"
                    );
                    customCss.push(
                        "ul.custom_" +
                        p +
                        "{list-style:none;}ul.custom_" +
                        p +
                        " li{background-position:0 3px;background-repeat:no-repeat}"
                    );
                } else {
                    for (var i = 0; i < 99; i++) {
                        customCss.push(
                            "li.list-" +
                            customStyle[p] +
                            i +
                            "{background-image:url(" +
                            liiconpath +
                            "list-" +
                            customStyle[p] +
                            i +
                            ".gif)}"
                        );
                    }
                    customCss.push(
                        "ol.custom_" +
                        p +
                        "{list-style:none;}ol.custom_" +
                        p +
                        " li{background-position:0 3px;background-repeat:no-repeat}"
                    );
                }
                switch (p) {
                    case "cn":
                        customCss.push("li.list-" + p + "-paddingleft-1{padding-left:25px}");
                        customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
                        customCss.push("li.list-" + p + "-paddingleft-3{padding-left:55px}");
                        break;
                    case "cn1":
                        customCss.push("li.list-" + p + "-paddingleft-1{padding-left:30px}");
                        customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
                        customCss.push("li.list-" + p + "-paddingleft-3{padding-left:55px}");
                        break;
                    case "cn2":
                        customCss.push("li.list-" + p + "-paddingleft-1{padding-left:40px}");
                        customCss.push("li.list-" + p + "-paddingleft-2{padding-left:55px}");
                        customCss.push("li.list-" + p + "-paddingleft-3{padding-left:68px}");
                        break;
                    case "num":
                    case "num1":
                        customCss.push("li.list-" + p + "-paddingleft-1{padding-left:25px}");
                        break;
                    case "num2":
                        customCss.push("li.list-" + p + "-paddingleft-1{padding-left:35px}");
                        customCss.push("li.list-" + p + "-paddingleft-2{padding-left:40px}");
                        break;
                    case "dash":
                        customCss.push("li.list-" + p + "-paddingleft{padding-left:35px}");
                        break;
                    case "dot":
                        customCss.push("li.list-" + p + "-paddingleft{padding-left:20px}");
                }
            }
            customCss.push(".list-paddingleft-1{padding-left:0}");
            customCss.push(
                ".list-paddingleft-2{padding-left:" +
                me.options.listDefaultPaddingLeft +
                "px}"
            );
            customCss.push(
                ".list-paddingleft-3{padding-left:" +
                me.options.listDefaultPaddingLeft * 2 +
                "px}"
            );
            //如果不给宽度会在自定应样式里出现滚动条
            utils.cssRule(
                "list",
                "ol,ul{margin:0;pading:0;" +
                (browser.ie ? "" : "width:95%") +
                "}li{clear:both;}" +
                customCss.join("\n"),
                me.document
            );
        });
        //单独处理剪切的问题
        me.ready(function () {
            domUtils.on(me.body, "cut", function () {
                setTimeout(function () {
                    var rng = me.selection.getRange(),
                        li;
                    //trace:3416
                    if (!rng.collapsed) {
                        if (
                            (li = domUtils.findParentByTagName(rng.startContainer, "li", true))
                        ) {
                            if (!li.nextSibling && domUtils.isEmptyBlock(li)) {
                                var pn = li.parentNode,
                                    node;
                                if ((node = pn.previousSibling)) {
                                    domUtils.remove(pn);
                                    rng.setStartAtLast(node).collapse(true);
                                    rng.select(true);
                                } else if ((node = pn.nextSibling)) {
                                    domUtils.remove(pn);
                                    rng.setStartAtFirst(node).collapse(true);
                                    rng.select(true);
                                } else {
                                    var tmpNode = me.document.createElement("p");
                                    domUtils.fillNode(me.document, tmpNode);
                                    pn.parentNode.insertBefore(tmpNode, pn);
                                    domUtils.remove(pn);
                                    rng.setStart(tmpNode, 0).collapse(true);
                                    rng.select(true);
                                }
                            }
                        }
                    }
                });
            });
        });

        function getStyle(node) {
            var cls = node.className;
            if (domUtils.hasClass(node, /custom_/)) {
                return cls.match(/custom_(\w+)/)[1];
            }
            return domUtils.getStyle(node, "list-style-type");
        }

        me.addListener("beforepaste", function (type, html) {
            var me = this,
                rng = me.selection.getRange(),
                li;
            var root = UE.htmlparser(html.html, true);
            if ((li = domUtils.findParentByTagName(rng.startContainer, "li", true))) {
                var list = li.parentNode,
                    tagName = list.tagName == "OL" ? "ul" : "ol";
                utils.each(root.getNodesByTagName(tagName), function (n) {
                    n.tagName = list.tagName;
                    n.setAttr();
                    if (n.parentNode === root) {
                        type = getStyle(list) || (list.tagName == "OL" ? "decimal" : "disc");
                    } else {
                        var className = n.parentNode.getAttr("class");
                        if (className && /custom_/.test(className)) {
                            type = className.match(/custom_(\w+)/)[1];
                        } else {
                            type = n.parentNode.getStyle("list-style-type");
                        }
                        if (!type) {
                            type = list.tagName == "OL" ? "decimal" : "disc";
                        }
                    }
                    var index = utils.indexOf(listStyle[list.tagName], type);
                    if (n.parentNode !== root)
                        index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
                    var currentStyle = listStyle[list.tagName][index];
                    if (customStyle[currentStyle]) {
                        n.setAttr("class", "custom_" + currentStyle);
                    } else {
                        n.setStyle("list-style-type", currentStyle);
                    }
                });
            }

            html.html = root.toHtml();
        });
        //导出时,去掉p标签
        me.getOpt("disablePInList") === true &&
        me.addOutputRule(function (root) {
            utils.each(root.getNodesByTagName("li"), function (li) {
                var newChildrens = [],
                    index = 0;
                utils.each(li.children, function (n) {
                    if (n.tagName == "p") {
                        var tmpNode;
                        while ((tmpNode = n.children.pop())) {
                            newChildrens.splice(index, 0, tmpNode);
                            tmpNode.parentNode = li;
                            lastNode = tmpNode;
                        }
                        tmpNode = newChildrens[newChildrens.length - 1];
                        if (
                            !tmpNode ||
                            tmpNode.type != "element" ||
                            tmpNode.tagName != "br"
                        ) {
                            var br = UE.uNode.createElement("br");
                            br.parentNode = li;
                            newChildrens.push(br);
                        }

                        index = newChildrens.length;
                    }
                });
                if (newChildrens.length) {
                    li.children = newChildrens;
                }
            });
        });
        //进入编辑器的li要套p标签
        me.addInputRule(function (root) {
            utils.each(root.getNodesByTagName("li"), function (li) {
                var tmpP = UE.uNode.createElement("p");
                for (var i = 0, ci; (ci = li.children[i]);) {
                    if (ci.type == "text" || dtd.p[ci.tagName]) {
                        tmpP.appendChild(ci);
                    } else {
                        if (tmpP.firstChild()) {
                            li.insertBefore(tmpP, ci);
                            tmpP = UE.uNode.createElement("p");
                            i = i + 2;
                        } else {
                            i++;
                        }
                    }
                }
                if ((tmpP.firstChild() && !tmpP.parentNode) || !li.firstChild()) {
                    li.appendChild(tmpP);
                }
                //trace:3357
                //p不能为空
                if (!tmpP.firstChild()) {
                    tmpP.innerHTML(browser.ie ? "&nbsp;" : "<br/>");
                }
                //去掉末尾的空白
                var p = li.firstChild();
                var lastChild = p.lastChild();
                if (
                    lastChild &&
                    lastChild.type == "text" &&
                    /^\s*$/.test(lastChild.data)
                ) {
                    p.removeChild(lastChild);
                }
            });
            if (me.options.autoTransWordToList) {
                var orderlisttype = {
                        num1: /^\d+\)/,
                        decimal: /^\d+\./,
                        "lower-alpha": /^[a-z]+\)/,
                        "upper-alpha": /^[A-Z]+\./,
                        cn: /^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
                        cn2: /^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/
                    },
                    unorderlisttype = {
                        square: "n"
                    };

                function checkListType(content, container) {
                    var span = container.firstChild();
                    if (
                        span &&
                        span.type == "element" &&
                        span.tagName == "span" &&
                        /Wingdings|Symbol/.test(span.getStyle("font-family"))
                    ) {
                        for (var p in unorderlisttype) {
                            if (unorderlisttype[p] == span.data) {
                                return p;
                            }
                        }
                        return "disc";
                    }
                    for (var p in orderlisttype) {
                        if (orderlisttype[p].test(content)) {
                            return p;
                        }
                    }
                }

                utils.each(root.getNodesByTagName("p"), function (node) {
                    if (node.getAttr("class") != "MsoListParagraph") {
                        return;
                    }

                    //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视
                    node.setStyle("margin", "");
                    node.setStyle("margin-left", "");
                    node.setAttr("class", "");

                    function appendLi(list, p, type) {
                        if (list.tagName == "ol") {
                            if (browser.ie) {
                                var first = p.firstChild();
                                if (
                                    first.type == "element" &&
                                    first.tagName == "span" &&
                                    orderlisttype[type].test(first.innerText())
                                ) {
                                    p.removeChild(first);
                                }
                            } else {
                                p.innerHTML(p.innerHTML().replace(orderlisttype[type], ""));
                            }
                        } else {
                            p.removeChild(p.firstChild());
                        }

                        var li = UE.uNode.createElement("li");
                        li.appendChild(p);
                        list.appendChild(li);
                    }

                    var tmp = node,
                        type,
                        cacheNode = node;

                    if (
                        node.parentNode.tagName != "li" &&
                        (type = checkListType(node.innerText(), node))
                    ) {
                        var list = UE.uNode.createElement(
                            me.options.insertorderedlist.hasOwnProperty(type) ? "ol" : "ul"
                        );
                        if (customStyle[type]) {
                            list.setAttr("class", "custom_" + type);
                        } else {
                            list.setStyle("list-style-type", type);
                        }
                        while (
                            node &&
                            node.parentNode.tagName != "li" &&
                            checkListType(node.innerText(), node)
                            ) {
                            tmp = node.nextSibling();
                            if (!tmp) {
                                node.parentNode.insertBefore(list, node);
                            }
                            appendLi(list, node, type);
                            node = tmp;
                        }
                        if (!list.parentNode && node && node.parentNode) {
                            node.parentNode.insertBefore(list, node);
                        }
                    }
                    var span = cacheNode.firstChild();
                    if (
                        span &&
                        span.type == "element" &&
                        span.tagName == "span" &&
                        /^\s*(&nbsp;)+\s*$/.test(span.innerText())
                    ) {
                        span.parentNode.removeChild(span);
                    }
                });
            }
        });

        //调整索引标签
        me.addListener("contentchange", function () {
            adjustListStyle(me.document);
        });

        function adjustListStyle(doc, ignore) {
            utils.each(domUtils.getElementsByTagName(doc, "ol ul"), function (node) {
                if (!domUtils.inDoc(node, doc)) return;

                var parent = node.parentNode;
                if (parent.tagName == node.tagName) {
                    var nodeStyleType =
                        getStyle(node) || (node.tagName == "OL" ? "decimal" : "disc"),
                        parentStyleType =
                            getStyle(parent) || (parent.tagName == "OL" ? "decimal" : "disc");
                    if (nodeStyleType == parentStyleType) {
                        var styleIndex = utils.indexOf(
                            listStyle[node.tagName],
                            nodeStyleType
                        );
                        styleIndex = styleIndex + 1 == listStyle[node.tagName].length
                            ? 0
                            : styleIndex + 1;
                        setListStyle(node, listStyle[node.tagName][styleIndex]);
                    }
                }
                var index = 0,
                    type = 2;
                if (domUtils.hasClass(node, /custom_/)) {
                    if (
                        !(
                            /[ou]l/i.test(parent.tagName) &&
                            domUtils.hasClass(parent, /custom_/)
                        )
                    ) {
                        type = 1;
                    }
                } else {
                    if (
                        /[ou]l/i.test(parent.tagName) &&
                        domUtils.hasClass(parent, /custom_/)
                    ) {
                        type = 3;
                    }
                }

                var style = domUtils.getStyle(node, "list-style-type");
                style && (node.style.cssText = "list-style-type:" + style);
                node.className =
                    utils.trim(node.className.replace(/list-paddingleft-\w+/, "")) +
                    " list-paddingleft-" +
                    type;
                utils.each(domUtils.getElementsByTagName(node, "li"), function (li) {
                    li.style.cssText && (li.style.cssText = "");
                    if (!li.firstChild) {
                        domUtils.remove(li);
                        return;
                    }
                    if (li.parentNode !== node) {
                        return;
                    }
                    index++;
                    if (domUtils.hasClass(node, /custom_/)) {
                        var paddingLeft = 1,
                            currentStyle = getStyle(node);
                        if (node.tagName == "OL") {
                            if (currentStyle) {
                                switch (currentStyle) {
                                    case "cn":
                                    case "cn1":
                                    case "cn2":
                                        if (
                                            index > 10 &&
                                            (index % 10 == 0 || (index > 10 && index < 20))
                                        ) {
                                            paddingLeft = 2;
                                        } else if (index > 20) {
                                            paddingLeft = 3;
                                        }
                                        break;
                                    case "num2":
                                        if (index > 9) {
                                            paddingLeft = 2;
                                        }
                                }
                            }
                            li.className =
                                "list-" +
                                customStyle[currentStyle] +
                                index +
                                " " +
                                "list-" +
                                currentStyle +
                                "-paddingleft-" +
                                paddingLeft;
                        } else {
                            li.className =
                                "list-" +
                                customStyle[currentStyle] +
                                " " +
                                "list-" +
                                currentStyle +
                                "-paddingleft";
                        }
                    } else {
                        li.className = li.className.replace(/list-[\w\-]+/gi, "");
                    }
                    var className = li.getAttribute("class");
                    if (className !== null && !className.replace(/\s/g, "")) {
                        domUtils.removeAttributes(li, "class");
                    }
                });
                !ignore &&
                adjustList(
                    node,
                    node.tagName.toLowerCase(),
                    getStyle(node) || domUtils.getStyle(node, "list-style-type"),
                    true
                );
            });
        }

        function adjustList(list, tag, style, ignoreEmpty) {
            var nextList = list.nextSibling;
            if (
                nextList &&
                nextList.nodeType == 1 &&
                nextList.tagName.toLowerCase() == tag &&
                (getStyle(nextList) ||
                    domUtils.getStyle(nextList, "list-style-type") ||
                    (tag == "ol" ? "decimal" : "disc")) == style
            ) {
                domUtils.moveChild(nextList, list);
                if (nextList.childNodes.length == 0) {
                    domUtils.remove(nextList);
                }
            }
            if (nextList && domUtils.isFillChar(nextList)) {
                domUtils.remove(nextList);
            }
            var preList = list.previousSibling;
            if (
                preList &&
                preList.nodeType == 1 &&
                preList.tagName.toLowerCase() == tag &&
                (getStyle(preList) ||
                    domUtils.getStyle(preList, "list-style-type") ||
                    (tag == "ol" ? "decimal" : "disc")) == style
            ) {
                domUtils.moveChild(list, preList);
            }
            if (preList && domUtils.isFillChar(preList)) {
                domUtils.remove(preList);
            }
            !ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list);
            if (getStyle(list)) {
                adjustListStyle(list.ownerDocument, true);
            }
        }

        function setListStyle(list, style) {
            if (customStyle[style]) {
                list.className = "custom_" + style;
            }
            try {
                domUtils.setStyle(list, "list-style-type", style);
            } catch (e) {
            }
        }

        function clearEmptySibling(node) {
            var tmpNode = node.previousSibling;
            if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
                domUtils.remove(tmpNode);
            }
            tmpNode = node.nextSibling;
            if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
                domUtils.remove(tmpNode);
            }
        }

        me.addListener("keydown", function (type, evt) {
            function preventAndSave() {
                evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
                me.fireEvent("contentchange");
                me.undoManger && me.undoManger.save();
            }

            function findList(node, filterFn) {
                while (node && !domUtils.isBody(node)) {
                    if (filterFn(node)) {
                        return null;
                    }
                    if (node.nodeType == 1 && /[ou]l/i.test(node.tagName)) {
                        return node;
                    }
                    node = node.parentNode;
                }
                return null;
            }

            var keyCode = evt.keyCode || evt.which;
            if (keyCode == 13 && !evt.shiftKey) {
                //回车
                var rng = me.selection.getRange(),
                    parent = domUtils.findParent(
                        rng.startContainer,
                        function (node) {
                            return domUtils.isBlockElm(node);
                        },
                        true
                    ),
                    li = domUtils.findParentByTagName(rng.startContainer, "li", true);
                if (parent && parent.tagName != "PRE" && !li) {
                    var html = parent.innerHTML.replace(
                        new RegExp(domUtils.fillChar, "g"),
                        ""
                    );
                    if (/^\s*1\s*\.[^\d]/.test(html)) {
                        parent.innerHTML = html.replace(/^\s*1\s*\./, "");
                        rng.setStartAtLast(parent).collapse(true).select();
                        me.__hasEnterExecCommand = true;
                        me.execCommand("insertorderedlist");
                        me.__hasEnterExecCommand = false;
                    }
                }
                var range = me.selection.getRange(),
                    start = findList(range.startContainer, function (node) {
                        return node.tagName == "TABLE";
                    }),
                    end = range.collapsed
                        ? start
                        : findList(range.endContainer, function (node) {
                            return node.tagName == "TABLE";
                        });

                if (start && end && start === end) {
                    if (!range.collapsed) {
                        start = domUtils.findParentByTagName(
                            range.startContainer,
                            "li",
                            true
                        );
                        end = domUtils.findParentByTagName(range.endContainer, "li", true);
                        if (start && end && start === end) {
                            range.deleteContents();
                            li = domUtils.findParentByTagName(range.startContainer, "li", true);
                            if (li && domUtils.isEmptyBlock(li)) {
                                pre = li.previousSibling;
                                next = li.nextSibling;
                                p = me.document.createElement("p");

                                domUtils.fillNode(me.document, p);
                                parentList = li.parentNode;
                                if (pre && next) {
                                    range.setStart(next, 0).collapse(true).select(true);
                                    domUtils.remove(li);
                                } else {
                                    if ((!pre && !next) || !pre) {
                                        parentList.parentNode.insertBefore(p, parentList);
                                    } else {
                                        li.parentNode.parentNode.insertBefore(
                                            p,
                                            parentList.nextSibling
                                        );
                                    }
                                    domUtils.remove(li);
                                    if (!parentList.firstChild) {
                                        domUtils.remove(parentList);
                                    }
                                    range.setStart(p, 0).setCursor();
                                }
                                preventAndSave();
                                return;
                            }
                        } else {
                            var tmpRange = range.cloneRange(),
                                bk = tmpRange.collapse(false).createBookmark();

                            range.deleteContents();
                            tmpRange.moveToBookmark(bk);
                            var li = domUtils.findParentByTagName(
                                tmpRange.startContainer,
                                "li",
                                true
                            );

                            clearEmptySibling(li);
                            tmpRange.select();
                            preventAndSave();
                            return;
                        }
                    }

                    li = domUtils.findParentByTagName(range.startContainer, "li", true);

                    if (li) {
                        if (domUtils.isEmptyBlock(li)) {
                            bk = range.createBookmark();
                            var parentList = li.parentNode;
                            if (li !== parentList.lastChild) {
                                domUtils.breakParent(li, parentList);
                                clearEmptySibling(li);
                            } else {
                                parentList.parentNode.insertBefore(li, parentList.nextSibling);
                                if (domUtils.isEmptyNode(parentList)) {
                                    domUtils.remove(parentList);
                                }
                            }
                            //嵌套不处理
                            if (!dtd.$list[li.parentNode.tagName]) {
                                if (!domUtils.isBlockElm(li.firstChild)) {
                                    p = me.document.createElement("p");
                                    li.parentNode.insertBefore(p, li);
                                    while (li.firstChild) {
                                        p.appendChild(li.firstChild);
                                    }
                                    domUtils.remove(li);
                                } else {
                                    domUtils.remove(li, true);
                                }
                            }
                            range.moveToBookmark(bk).select();
                        } else {
                            var first = li.firstChild;
                            if (!first || !domUtils.isBlockElm(first)) {
                                var p = me.document.createElement("p");

                                !li.firstChild && domUtils.fillNode(me.document, p);
                                while (li.firstChild) {
                                    p.appendChild(li.firstChild);
                                }
                                li.appendChild(p);
                                first = p;
                            }

                            var span = me.document.createElement("span");

                            range.insertNode(span);
                            domUtils.breakParent(span, li);

                            var nextLi = span.nextSibling;
                            first = nextLi.firstChild;

                            if (!first) {
                                p = me.document.createElement("p");

                                domUtils.fillNode(me.document, p);
                                nextLi.appendChild(p);
                                first = p;
                            }
                            if (domUtils.isEmptyNode(first)) {
                                first.innerHTML = "";
                                domUtils.fillNode(me.document, first);
                            }

                            range.setStart(first, 0).collapse(true).shrinkBoundary().select();
                            domUtils.remove(span);
                            var pre = nextLi.previousSibling;
                            if (pre && domUtils.isEmptyBlock(pre)) {
                                pre.innerHTML = "<p></p>";
                                domUtils.fillNode(me.document, pre.firstChild);
                            }
                        }
                        //                        }
                        preventAndSave();
                    }
                }
            }
            if (keyCode == 8) {
                //修中ie中li下的问题
                range = me.selection.getRange();
                if (range.collapsed && domUtils.isStartInblock(range)) {
                    tmpRange = range.cloneRange().trimBoundary();
                    li = domUtils.findParentByTagName(range.startContainer, "li", true);
                    //要在li的最左边,才能处理
                    if (li && domUtils.isStartInblock(tmpRange)) {
                        start = domUtils.findParentByTagName(range.startContainer, "p", true);
                        if (start && start !== li.firstChild) {
                            var parentList = domUtils.findParentByTagName(start, ["ol", "ul"]);
                            domUtils.breakParent(start, parentList);
                            clearEmptySibling(start);
                            me.fireEvent("contentchange");
                            range.setStart(start, 0).setCursor(false, true);
                            me.fireEvent("saveScene");
                            domUtils.preventDefault(evt);
                            return;
                        }

                        if (li && (pre = li.previousSibling)) {
                            if (keyCode == 46 && li.childNodes.length) {
                                return;
                            }
                            //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
                            if (dtd.$list[pre.tagName]) {
                                pre = pre.lastChild;
                            }
                            me.undoManger && me.undoManger.save();
                            first = li.firstChild;
                            if (domUtils.isBlockElm(first)) {
                                if (domUtils.isEmptyNode(first)) {
                                    //                                    range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
                                    pre.appendChild(first);
                                    range.setStart(first, 0).setCursor(false, true);
                                    //first不是唯一的节点
                                    while (li.firstChild) {
                                        pre.appendChild(li.firstChild);
                                    }
                                } else {
                                    span = me.document.createElement("span");
                                    range.insertNode(span);
                                    //判断pre是否是空的节点,如果是<p><br/></p>类型的空节点,干掉p标签防止它占位
                                    if (domUtils.isEmptyBlock(pre)) {
                                        pre.innerHTML = "";
                                    }
                                    domUtils.moveChild(li, pre);
                                    range.setStartBefore(span).collapse(true).select(true);

                                    domUtils.remove(span);
                                }
                            } else {
                                if (domUtils.isEmptyNode(li)) {
                                    var p = me.document.createElement("p");
                                    pre.appendChild(p);
                                    range.setStart(p, 0).setCursor();
                                    //                                    range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
                                } else {
                                    range
                                        .setEnd(pre, pre.childNodes.length)
                                        .collapse()
                                        .select(true);
                                    while (li.firstChild) {
                                        pre.appendChild(li.firstChild);
                                    }
                                }
                            }
                            domUtils.remove(li);
                            me.fireEvent("contentchange");
                            me.fireEvent("saveScene");
                            domUtils.preventDefault(evt);
                            return;
                        }
                        //trace:980

                        if (li && !li.previousSibling) {
                            var parentList = li.parentNode;
                            var bk = range.createBookmark();
                            if (domUtils.isTagNode(parentList.parentNode, "ol ul")) {
                                parentList.parentNode.insertBefore(li, parentList);
                                if (domUtils.isEmptyNode(parentList)) {
                                    domUtils.remove(parentList);
                                }
                            } else {
                                while (li.firstChild) {
                                    parentList.parentNode.insertBefore(li.firstChild, parentList);
                                }

                                domUtils.remove(li);
                                if (domUtils.isEmptyNode(parentList)) {
                                    domUtils.remove(parentList);
                                }
                            }
                            range.moveToBookmark(bk).setCursor(false, true);
                            me.fireEvent("contentchange");
                            me.fireEvent("saveScene");
                            domUtils.preventDefault(evt);
                            return;
                        }
                    }
                }
            }
        });

        me.addListener("keyup", function (type, evt) {
            var keyCode = evt.keyCode || evt.which;
            if (keyCode == 8) {
                var rng = me.selection.getRange(),
                    list;
                if (
                    (list = domUtils.findParentByTagName(
                        rng.startContainer,
                        ["ol", "ul"],
                        true
                    ))
                ) {
                    adjustList(
                        list,
                        list.tagName.toLowerCase(),
                        getStyle(list) || domUtils.getComputedStyle(list, "list-style-type"),
                        true
                    );
                }
            }
        });
        //处理tab键
        me.addListener("tabkeydown", function () {
            var range = me.selection.getRange();

            //控制级数
            function checkLevel(li) {
                if (me.options.maxListLevel != -1) {
                    var level = li.parentNode,
                        levelNum = 0;
                    while (/[ou]l/i.test(level.tagName)) {
                        levelNum++;
                        level = level.parentNode;
                    }
                    if (levelNum >= me.options.maxListLevel) {
                        return true;
                    }
                }
            }

            //只以开始为准
            //todo 后续改进
            var li = domUtils.findParentByTagName(range.startContainer, "li", true);
            if (li) {
                var bk;
                if (range.collapsed) {
                    if (checkLevel(li)) return true;
                    var parentLi = li.parentNode,
                        list = me.document.createElement(parentLi.tagName),
                        index = utils.indexOf(
                            listStyle[list.tagName],
                            getStyle(parentLi) ||
                            domUtils.getComputedStyle(parentLi, "list-style-type")
                        );
                    index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
                    var currentStyle = listStyle[list.tagName][index];
                    setListStyle(list, currentStyle);
                    if (domUtils.isStartInblock(range)) {
                        me.fireEvent("saveScene");
                        bk = range.createBookmark();
                        parentLi.insertBefore(list, li);
                        list.appendChild(li);
                        adjustList(list, list.tagName.toLowerCase(), currentStyle);
                        me.fireEvent("contentchange");
                        range.moveToBookmark(bk).select(true);
                        return true;
                    }
                } else {
                    me.fireEvent("saveScene");
                    bk = range.createBookmark();
                    for (
                        var i = 0, closeList, parents = domUtils.findParents(li), ci;
                        (ci = parents[i++]);
                    ) {
                        if (domUtils.isTagNode(ci, "ol ul")) {
                            closeList = ci;
                            break;
                        }
                    }
                    var current = li;
                    if (bk.end) {
                        while (
                            current &&
                            !(
                                domUtils.getPosition(current, bk.end) &
                                domUtils.POSITION_FOLLOWING
                            )
                            ) {
                            if (checkLevel(current)) {
                                current = domUtils.getNextDomNode(current, false, null, function (
                                    node
                                ) {
                                    return node !== closeList;
                                });
                                continue;
                            }
                            var parentLi = current.parentNode,
                                list = me.document.createElement(parentLi.tagName),
                                index = utils.indexOf(
                                    listStyle[list.tagName],
                                    getStyle(parentLi) ||
                                    domUtils.getComputedStyle(parentLi, "list-style-type")
                                );
                            var currentIndex = index + 1 == listStyle[list.tagName].length
                                ? 0
                                : index + 1;
                            var currentStyle = listStyle[list.tagName][currentIndex];
                            setListStyle(list, currentStyle);
                            parentLi.insertBefore(list, current);
                            while (
                                current &&
                                !(
                                    domUtils.getPosition(current, bk.end) &
                                    domUtils.POSITION_FOLLOWING
                                )
                                ) {
                                li = current.nextSibling;
                                list.appendChild(current);
                                if (!li || domUtils.isTagNode(li, "ol ul")) {
                                    if (li) {
                                        while ((li = li.firstChild)) {
                                            if (li.tagName == "LI") {
                                                break;
                                            }
                                        }
                                    } else {
                                        li = domUtils.getNextDomNode(current, false, null, function (
                                            node
                                        ) {
                                            return node !== closeList;
                                        });
                                    }
                                    break;
                                }
                                current = li;
                            }
                            adjustList(list, list.tagName.toLowerCase(), currentStyle);
                            current = li;
                        }
                    }
                    me.fireEvent("contentchange");
                    range.moveToBookmark(bk).select();
                    return true;
                }
            }
        });

        function getLi(start) {
            while (start && !domUtils.isBody(start)) {
                if (start.nodeName == "TABLE") {
                    return null;
                }
                if (start.nodeName == "LI") {
                    return start;
                }
                start = start.parentNode;
            }
        }

        /**
         * 有序列表,与“insertunorderedlist”命令互斥
         * @command insertorderedlist
         * @method execCommand
         * @param { String } command 命令字符串
         * @param { String } style 插入的有序列表类型,值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
         * @example
         * ```javascript
         * editor.execCommand( 'insertorderedlist','decimal');
         * ```
         */
        /**
         * 查询当前选区内容是否有序列表
         * @command insertorderedlist
         * @method queryCommandState
         * @param { String } cmd 命令字符串
         * @return { int } 如果当前选区是有序列表返回1,否则返回0
         * @example
         * ```javascript
         * editor.queryCommandState( 'insertorderedlist' );
         * ```
         */
        /**
         * 查询当前选区内容是否有序列表
         * @command insertorderedlist
         * @method queryCommandValue
         * @param { String } cmd 命令字符串
         * @return { String } 返回当前有序列表的类型,值为null或decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
         * @example
         * ```javascript
         * editor.queryCommandValue( 'insertorderedlist' );
         * ```
         */

        /**
         * 无序列表,与“insertorderedlist”命令互斥
         * @command insertunorderedlist
         * @method execCommand
         * @param { String } command 命令字符串
         * @param { String } style 插入的无序列表类型,值为:circle,disc,square,dash,dot
         * @example
         * ```javascript
         * editor.execCommand( 'insertunorderedlist','circle');
         * ```
         */
        /**
         * 查询当前是否有word文档粘贴进来的图片
         * @command insertunorderedlist
         * @method insertunorderedlist
         * @param { String } command 命令字符串
         * @return { int } 如果当前选区是无序列表返回1,否则返回0
         * @example
         * ```javascript
         * editor.queryCommandState( 'insertunorderedlist' );
         * ```
         */
        /**
         * 查询当前选区内容是否有序列表
         * @command insertunorderedlist
         * @method queryCommandValue
         * @param { String } command 命令字符串
         * @return { String } 返回当前无序列表的类型,值为null或circle,disc,square,dash,dot
         * @example
         * ```javascript
         * editor.queryCommandValue( 'insertunorderedlist' );
         * ```
         */

        me.commands["insertorderedlist"] = me.commands["insertunorderedlist"] = {
            execCommand: function (command, style) {
                if (!style) {
                    style = command.toLowerCase() == "insertorderedlist"
                        ? "decimal"
                        : "disc";
                }
                var me = this,
                    range = this.selection.getRange(),
                    filterFn = function (node) {
                        return node.nodeType == 1
                            ? node.tagName.toLowerCase() != "br"
                            : !domUtils.isWhitespace(node);
                    },
                    tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul",
                    frag = me.document.createDocumentFragment();
                //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
                //range.shrinkBoundary();//.adjustmentBoundary();
                range.adjustmentBoundary().shrinkBoundary();
                var bko = range.createBookmark(true),
                    start = getLi(me.document.getElementById(bko.start)),
                    modifyStart = 0,
                    end = getLi(me.document.getElementById(bko.end)),
                    modifyEnd = 0,
                    startParent,
                    endParent,
                    list,
                    tmp;

                if (start || end) {
                    start && (startParent = start.parentNode);
                    if (!bko.end) {
                        end = start;
                    }
                    end && (endParent = end.parentNode);

                    if (startParent === endParent) {
                        while (start !== end) {
                            tmp = start;
                            start = start.nextSibling;
                            if (!domUtils.isBlockElm(tmp.firstChild)) {
                                var p = me.document.createElement("p");
                                while (tmp.firstChild) {
                                    p.appendChild(tmp.firstChild);
                                }
                                tmp.appendChild(p);
                            }
                            frag.appendChild(tmp);
                        }
                        tmp = me.document.createElement("span");
                        startParent.insertBefore(tmp, end);
                        if (!domUtils.isBlockElm(end.firstChild)) {
                            p = me.document.createElement("p");
                            while (end.firstChild) {
                                p.appendChild(end.firstChild);
                            }
                            end.appendChild(p);
                        }
                        frag.appendChild(end);
                        domUtils.breakParent(tmp, startParent);
                        if (domUtils.isEmptyNode(tmp.previousSibling)) {
                            domUtils.remove(tmp.previousSibling);
                        }
                        if (domUtils.isEmptyNode(tmp.nextSibling)) {
                            domUtils.remove(tmp.nextSibling);
                        }
                        var nodeStyle =
                            getStyle(startParent) ||
                            domUtils.getComputedStyle(startParent, "list-style-type") ||
                            (command.toLowerCase() == "insertorderedlist" ? "decimal" : "disc");
                        if (startParent.tagName.toLowerCase() == tag && nodeStyle == style) {
                            for (
                                var i = 0, ci, tmpFrag = me.document.createDocumentFragment();
                                (ci = frag.firstChild);
                            ) {
                                if (domUtils.isTagNode(ci, "ol ul")) {
                                    //                                  删除时,子列表不处理
                                    //                                  utils.each(domUtils.getElementsByTagName(ci,'li'),function(li){
                                    //                                        while(li.firstChild){
                                    //                                            tmpFrag.appendChild(li.firstChild);
                                    //                                        }
                                    //
                                    //                                    });
                                    tmpFrag.appendChild(ci);
                                } else {
                                    while (ci.firstChild) {
                                        tmpFrag.appendChild(ci.firstChild);
                                        domUtils.remove(ci);
                                    }
                                }
                            }
                            tmp.parentNode.insertBefore(tmpFrag, tmp);
                        } else {
                            list = me.document.createElement(tag);
                            setListStyle(list, style);
                            list.appendChild(frag);
                            tmp.parentNode.insertBefore(list, tmp);
                        }

                        domUtils.remove(tmp);
                        list && adjustList(list, tag, style);
                        range.moveToBookmark(bko).select();
                        return;
                    }
                    //开始
                    if (start) {
                        while (start) {
                            tmp = start.nextSibling;
                            if (domUtils.isTagNode(start, "ol ul")) {
                                frag.appendChild(start);
                            } else {
                                var tmpfrag = me.document.createDocumentFragment(),
                                    hasBlock = 0;
                                while (start.firstChild) {
                                    if (domUtils.isBlockElm(start.firstChild)) {
                                        hasBlock = 1;
                                    }
                                    tmpfrag.appendChild(start.firstChild);
                                }
                                if (!hasBlock) {
                                    var tmpP = me.document.createElement("p");
                                    tmpP.appendChild(tmpfrag);
                                    frag.appendChild(tmpP);
                                } else {
                                    frag.appendChild(tmpfrag);
                                }
                                domUtils.remove(start);
                            }

                            start = tmp;
                        }
                        startParent.parentNode.insertBefore(frag, startParent.nextSibling);
                        if (domUtils.isEmptyNode(startParent)) {
                            range.setStartBefore(startParent);
                            domUtils.remove(startParent);
                        } else {
                            range.setStartAfter(startParent);
                        }
                        modifyStart = 1;
                    }

                    if (end && domUtils.inDoc(endParent, me.document)) {
                        //结束
                        start = endParent.firstChild;
                        while (start && start !== end) {
                            tmp = start.nextSibling;
                            if (domUtils.isTagNode(start, "ol ul")) {
                                frag.appendChild(start);
                            } else {
                                tmpfrag = me.document.createDocumentFragment();
                                hasBlock = 0;
                                while (start.firstChild) {
                                    if (domUtils.isBlockElm(start.firstChild)) {
                                        hasBlock = 1;
                                    }
                                    tmpfrag.appendChild(start.firstChild);
                                }
                                if (!hasBlock) {
                                    tmpP = me.document.createElement("p");
                                    tmpP.appendChild(tmpfrag);
                                    frag.appendChild(tmpP);
                                } else {
                                    frag.appendChild(tmpfrag);
                                }
                                domUtils.remove(start);
                            }
                            start = tmp;
                        }
                        var tmpDiv = domUtils.createElement(me.document, "div", {
                            tmpDiv: 1
                        });
                        domUtils.moveChild(end, tmpDiv);

                        frag.appendChild(tmpDiv);
                        domUtils.remove(end);
                        endParent.parentNode.insertBefore(frag, endParent);
                        range.setEndBefore(endParent);
                        if (domUtils.isEmptyNode(endParent)) {
                            domUtils.remove(endParent);
                        }

                        modifyEnd = 1;
                    }
                }

                if (!modifyStart) {
                    range.setStartBefore(me.document.getElementById(bko.start));
                }
                if (bko.end && !modifyEnd) {
                    range.setEndAfter(me.document.getElementById(bko.end));
                }
                range.enlarge(true, function (node) {
                    return notExchange[node.tagName];
                });

                frag = me.document.createDocumentFragment();

                var bk = range.createBookmark(),
                    current = domUtils.getNextDomNode(bk.start, false, filterFn),
                    tmpRange = range.cloneRange(),
                    tmpNode,
                    block = domUtils.isBlockElm;

                while (
                    current &&
                    current !== bk.end &&
                    domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING
                    ) {
                    if (current.nodeType == 3 || dtd.li[current.tagName]) {
                        if (current.nodeType == 1 && dtd.$list[current.tagName]) {
                            while (current.firstChild) {
                                frag.appendChild(current.firstChild);
                            }
                            tmpNode = domUtils.getNextDomNode(current, false, filterFn);
                            domUtils.remove(current);
                            current = tmpNode;
                            continue;
                        }
                        tmpNode = current;
                        tmpRange.setStartBefore(current);

                        while (
                            current &&
                            current !== bk.end &&
                            (!block(current) || domUtils.isBookmarkNode(current))
                            ) {
                            tmpNode = current;
                            current = domUtils.getNextDomNode(current, false, null, function (
                                node
                            ) {
                                return !notExchange[node.tagName];
                            });
                        }

                        if (current && block(current)) {
                            tmp = domUtils.getNextDomNode(tmpNode, false, filterFn);
                            if (tmp && domUtils.isBookmarkNode(tmp)) {
                                current = domUtils.getNextDomNode(tmp, false, filterFn);
                                tmpNode = tmp;
                            }
                        }
                        tmpRange.setEndAfter(tmpNode);

                        current = domUtils.getNextDomNode(tmpNode, false, filterFn);

                        var li = range.document.createElement("li");

                        li.appendChild(tmpRange.extractContents());
                        if (domUtils.isEmptyNode(li)) {
                            var tmpNode = range.document.createElement("p");
                            while (li.firstChild) {
                                tmpNode.appendChild(li.firstChild);
                            }
                            li.appendChild(tmpNode);
                        }
                        frag.appendChild(li);
                    } else {
                        current = domUtils.getNextDomNode(current, true, filterFn);
                    }
                }
                range.moveToBookmark(bk).collapse(true);
                list = me.document.createElement(tag);
                setListStyle(list, style);
                list.appendChild(frag);
                range.insertNode(list);
                //当前list上下看能否合并
                adjustList(list, tag, style);
                //去掉冗余的tmpDiv
                for (
                    var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, "div");
                    (ci = tmpDivs[i++]);
                ) {
                    if (ci.getAttribute("tmpDiv")) {
                        domUtils.remove(ci, true);
                    }
                }
                range.moveToBookmark(bko).select();
            },
            queryCommandState: function (command) {
                var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
                var path = this.selection.getStartElementPath();
                for (var i = 0, ci; (ci = path[i++]);) {
                    if (ci.nodeName == "TABLE") {
                        return 0;
                    }
                    if (tag == ci.nodeName.toLowerCase()) {
                        return 1;
                    }
                }
                return 0;
            },
            queryCommandValue: function (command) {
                var tag = command.toLowerCase() == "insertorderedlist" ? "ol" : "ul";
                var path = this.selection.getStartElementPath(),
                    node;
                for (var i = 0, ci; (ci = path[i++]);) {
                    if (ci.nodeName == "TABLE") {
                        node = null;
                        break;
                    }
                    if (tag == ci.nodeName.toLowerCase()) {
                        node = ci;
                        break;
                    }
                }
                return node
                    ? getStyle(node) || domUtils.getComputedStyle(node, "list-style-type")
                    : null;
            }
        };
    };


// plugins/source.js
    /**
     * 源码编辑插件
     * @file
     * @since 1.2.6.1
     */

    ;(function () {
        var sourceEditors = {
            textarea: function (editor, holder) {
                var textarea = holder.ownerDocument.createElement("textarea");
                textarea.style.cssText =
                    "position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;";
                // todo: IE下只有onresize属性可用... 很纠结
                if (browser.ie && browser.version < 8) {
                    textarea.style.width = holder.offsetWidth + "px";
                    textarea.style.height = holder.offsetHeight + "px";
                    holder.onresize = function () {
                        textarea.style.width = holder.offsetWidth + "px";
                        textarea.style.height = holder.offsetHeight + "px";
                    };
                }
                holder.appendChild(textarea);
                return {
                    setContent: function (content) {
                        textarea.value = content;
                    },
                    getContent: function () {
                        return textarea.value;
                    },
                    select: function () {
                        var range;
                        if (browser.ie) {
                            range = textarea.createTextRange();
                            range.collapse(true);
                            range.select();
                        } else {
                            //todo: chrome下无法设置焦点
                            textarea.setSelectionRange(0, 0);
                            textarea.focus();
                        }
                    },
                    dispose: function () {
                        holder.removeChild(textarea);
                        // todo
                        holder.onresize = null;
                        textarea = null;
                        holder = null;
                    },
                    focus: function () {
                        textarea.focus();
                    },
                    blur: function () {
                        textarea.blur();
                    }
                };
            },
            codemirror: function (editor, holder) {
                var codeEditor = window.CodeMirror(holder, {
                    mode: "text/html",
                    tabMode: "indent",
                    lineNumbers: true,
                    lineWrapping: true
                });
                var dom = codeEditor.getWrapperElement();
                dom.style.cssText =
                    'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
                codeEditor.getScrollerElement().style.cssText =
                    "position:absolute;left:0;top:0;width:100%;height:100%;";
                codeEditor.refresh();
                return {
                    getCodeMirror: function () {
                        return codeEditor;
                    },
                    setContent: function (content) {
                        codeEditor.setValue(content);
                    },
                    getContent: function () {
                        return codeEditor.getValue();
                    },
                    select: function () {
                        codeEditor.focus();
                    },
                    dispose: function () {
                        holder.removeChild(dom);
                        dom = null;
                        codeEditor = null;
                    },
                    focus: function () {
                        codeEditor.focus();
                    },
                    blur: function () {
                        // codeEditor.blur();
                        // since codemirror not support blur()
                        codeEditor.setOption('readOnly', true);
                        codeEditor.setOption('readOnly', false);
                    }
                };
            }
        };

        UE.plugins["source"] = function () {
            var me = this;
            var opt = this.options;
            var sourceMode = false;
            var sourceEditor;
            var orgSetContent;
            var orgFocus;
            var orgBlur;
            opt.sourceEditor = browser.ie
                ? "textarea"
                : opt.sourceEditor || "codemirror";

            me.setOpt({
                sourceEditorFirst: false
            });

            function createSourceEditor(holder) {
                return sourceEditors[
                    opt.sourceEditor == "codemirror" && window.CodeMirror
                        ? "codemirror"
                        : "textarea"
                    ](me, holder);
            }

            var bakCssText;
            //解决在源码模式下getContent不能得到最新的内容问题
            var oldGetContent, bakAddress;

            /**
             * 切换源码模式和编辑模式
             * @command source
             * @method execCommand
             * @param { String } cmd 命令字符串
             * @example
             * ```javascript
             * editor.execCommand( 'source');
             * ```
             */

            /**
             * 查询当前编辑区域的状态是源码模式还是可视化模式
             * @command source
             * @method queryCommandState
             * @param { String } cmd 命令字符串
             * @return { int } 如果当前是源码编辑模式,返回1,否则返回0
             * @example
             * ```javascript
             * editor.queryCommandState( 'source' );
             * ```
             */

            me.commands["source"] = {
                execCommand: function () {
                    sourceMode = !sourceMode;
                    if (sourceMode) {
                        bakAddress = me.selection.getRange().createAddress(false, true);
                        me.undoManger && me.undoManger.save(true);
                        if (browser.gecko) {
                            me.body.contentEditable = false;
                        }

                        bakCssText = me.iframe.style.cssText;
                        me.iframe.style.cssText +=
                            "position:absolute;left:-32768px;top:-32768px;";

                        me.fireEvent("beforegetcontent");
                        var root = UE.htmlparser(me.body.innerHTML);
                        me.filterOutputRule(root);
                        root.traversal(function (node) {
                            if (node.type == "element") {
                                switch (node.tagName) {
                                    case "td":
                                    case "th":
                                    case "caption":
                                        if (node.children && node.children.length == 1) {
                                            if (node.firstChild().tagName == "br") {
                                                node.removeChild(node.firstChild());
                                            }
                                        }
                                        break;
                                    case "pre":
                                        node.innerText(node.innerText().replace(/&nbsp;/g, " "));
                                }
                            }
                        });

                        me.fireEvent("aftergetcontent");

                        var content = root.toHtml(true);

                        sourceEditor = createSourceEditor(me.iframe.parentNode);

                        sourceEditor.setContent(content);

                        orgSetContent = me.setContent;

                        me.setContent = function (html) {
                            //这里暂时不触发事件,防止报错
                            var root = UE.htmlparser(html);
                            me.filterInputRule(root);
                            html = root.toHtml();
                            sourceEditor.setContent(html);
                        };

                        setTimeout(function () {
                            sourceEditor.select();
                            me.addListener("fullscreenchanged", function () {
                                try {
                                    sourceEditor.getCodeMirror().refresh();
                                } catch (e) {
                                }
                            });
                        });

                        //重置getContent,源码模式下取值也能是最新的数据
                        oldGetContent = me.getContent;
                        me.getContent = function () {
                            return (
                                sourceEditor.getContent() ||
                                "<p>" + (browser.ie ? "" : "<br/>") + "</p>"
                            );
                        };

                        orgFocus = me.focus;
                        orgBlur = me.blur;

                        me.focus = function () {
                            sourceEditor.focus();
                        };

                        me.blur = function () {
                            orgBlur.call(me);
                            sourceEditor.blur();
                        };
                    } else {
                        me.iframe.style.cssText = bakCssText;
                        var cont =
                            sourceEditor.getContent() ||
                            "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
                        //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
                        cont = cont.replace(
                            new RegExp("[\\r\\t\\n ]*</?(\\w+)\\s*(?:[^>]*)>", "g"),
                            function (a, b) {
                                if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
                                    return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, "");
                                }
                                return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, "");
                            }
                        );

                        me.setContent = orgSetContent;

                        me.setContent(cont);
                        sourceEditor.dispose();
                        sourceEditor = null;
                        //还原getContent方法
                        me.getContent = oldGetContent;
                        me.focus = orgFocus;
                        me.blur = orgBlur;
                        var first = me.body.firstChild;
                        //trace:1106 都删除空了,下边会报错,所以补充一个p占位
                        if (!first) {
                            me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
                            first = me.body.firstChild;
                        }

                        //要在ifm为显示时ff才能取到selection,否则报错
                        //这里不能比较位置了
                        me.undoManger && me.undoManger.save(true);

                        if (browser.gecko) {
                            var input = document.createElement("input");
                            input.style.cssText = "position:absolute;left:0;top:-32768px";

                            document.body.appendChild(input);

                            me.body.contentEditable = false;
                            setTimeout(function () {
                                domUtils.setViewportOffset(input, {left: -32768, top: 0});
                                input.focus();
                                setTimeout(function () {
                                    me.body.contentEditable = true;
                                    me.selection.getRange().moveToAddress(bakAddress).select(true);
                                    domUtils.remove(input);
                                });
                            });
                        } else {
                            //ie下有可能报错,比如在代码顶头的情况
                            try {
                                me.selection.getRange().moveToAddress(bakAddress).select(true);
                            } catch (e) {
                            }
                        }
                    }
                    this.fireEvent("sourcemodechanged", sourceMode);
                },
                queryCommandState: function () {
                    return sourceMode | 0;
                },
                notNeedUndo: 1
            };
            var oldQueryCommandState = me.queryCommandState;

            me.queryCommandState = function (cmdName) {
                cmdName = cmdName.toLowerCase();
                if (sourceMode) {
                    //源码模式下可以开启的命令
                    return cmdName in
                    {
                        source: 1,
                        fullscreen: 1
                    }
                        ? 1
                        : -1;
                }
                return oldQueryCommandState.apply(this, arguments);
            };

            if (opt.sourceEditor == "codemirror") {
                me.addListener("ready", function () {
                    utils.loadFile(
                        document,
                        {
                            src:
                            opt.codeMirrorJsUrl ||
                            opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.js",
                            tag: "script",
                            type: "text/javascript",
                            defer: "defer"
                        },
                        function () {
                            if (opt.sourceEditorFirst) {
                                setTimeout(function () {
                                    me.execCommand("source");
                                }, 0);
                            }
                        }
                    );
                    utils.loadFile(document, {
                        tag: "link",
                        rel: "stylesheet",
                        type: "text/css",
                        href:
                        opt.codeMirrorCssUrl ||
                        opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.css"
                    });
                });
            }
        };
    })();


// plugins/enterkey.js
///import core
///import plugins/undo.js
///commands 设置回车标签p或br
///commandsName  EnterKey
///commandsTitle  设置回车标签p或br
    /**
     * @description 处理回车
     * @author zhanyi
     */
    UE.plugins["enterkey"] = function () {
        var hTag,
            me = this,
            tag = me.options.enterTag;
        me.addListener("keyup", function (type, evt) {
            var keyCode = evt.keyCode || evt.which;
            if (keyCode == 13) {
                var range = me.selection.getRange(),
                    start = range.startContainer,
                    doSave;

                //修正在h1-h6里边回车后不能嵌套p的问题
                if (!browser.ie) {
                    if (/h\d/i.test(hTag)) {
                        if (browser.gecko) {
                            var h = domUtils.findParentByTagName(
                                start,
                                [
                                    "h1",
                                    "h2",
                                    "h3",
                                    "h4",
                                    "h5",
                                    "h6",
                                    "blockquote",
                                    "caption",
                                    "table"
                                ],
                                true
                            );
                            if (!h) {
                                me.document.execCommand("formatBlock", false, "<p>");
                                doSave = 1;
                            }
                        } else {
                            //chrome remove div
                            if (start.nodeType == 1) {
                                var tmp = me.document.createTextNode(""),
                                    div;
                                range.insertNode(tmp);
                                div = domUtils.findParentByTagName(tmp, "div", true);
                                if (div) {
                                    var p = me.document.createElement("p");
                                    while (div.firstChild) {
                                        p.appendChild(div.firstChild);
                                    }
                                    div.parentNode.insertBefore(p, div);
                                    domUtils.remove(div);
                                    range.setStartBefore(tmp).setCursor();
                                    doSave = 1;
                                }
                                domUtils.remove(tmp);
                            }
                        }

                        if (me.undoManger && doSave) {
                            me.undoManger.save();
                        }
                    }
                    //没有站位符,会出现多行的问题
                    browser.opera && range.select();
                } else {
                    me.fireEvent("saveScene", true, true);
                }
            }
        });

        me.addListener("keydown", function (type, evt) {
            var keyCode = evt.keyCode || evt.which;
            if (keyCode == 13) {
                //回车
                if (me.fireEvent("beforeenterkeydown")) {
                    domUtils.preventDefault(evt);
                    return;
                }
                me.fireEvent("saveScene", true, true);
                hTag = "";

                var range = me.selection.getRange();

                if (!range.collapsed) {
                    //跨td不能删
                    var start = range.startContainer,
                        end = range.endContainer,
                        startTd = domUtils.findParentByTagName(start, "td", true),
                        endTd = domUtils.findParentByTagName(end, "td", true);
                    if (
                        (startTd && endTd && startTd !== endTd) ||
                        (!startTd && endTd) ||
                        (startTd && !endTd)
                    ) {
                        evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
                        return;
                    }
                }
                if (tag == "p") {
                    if (!browser.ie) {
                        start = domUtils.findParentByTagName(
                            range.startContainer,
                            [
                                "ol",
                                "ul",
                                "p",
                                "h1",
                                "h2",
                                "h3",
                                "h4",
                                "h5",
                                "h6",
                                "blockquote",
                                "caption"
                            ],
                            true
                        );

                        //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
                        //trace:2431
                        if (!start && !browser.opera) {
                            me.document.execCommand("formatBlock", false, "<p>");

                            if (browser.gecko) {
                                range = me.selection.getRange();
                                start = domUtils.findParentByTagName(
                                    range.startContainer,
                                    "p",
                                    true
                                );
                                start && domUtils.removeDirtyAttr(start);
                            }
                        } else {
                            hTag = start.tagName;
                            start.tagName.toLowerCase() == "p" &&
                            browser.gecko &&
                            domUtils.removeDirtyAttr(start);
                        }
                    }
                } else {
                    evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);

                    if (!range.collapsed) {
                        range.deleteContents();
                        start = range.startContainer;
                        if (
                            start.nodeType == 1 &&
                            (start = start.childNodes[range.startOffset])
                        ) {
                            while (start.nodeType == 1) {
                                if (dtd.$empty[start.tagName]) {
                                    range.setStartBefore(start).setCursor();
                                    if (me.undoManger) {
                                        me.undoManger.save();
                                    }
                                    return false;
                                }
                                if (!start.firstChild) {
                                    var br = range.document.createElement("br");
                                    start.appendChild(br);
                                    range.setStart(start, 0).setCursor();
                                    if (me.undoManger) {
                                        me.undoManger.save();
                                    }
                                    return false;
                                }
                                start = start.firstChild;
                            }
                            if (start === range.startContainer.childNodes[range.startOffset]) {
                                br = range.document.createElement("br");
                                range.insertNode(br).setCursor();
                            } else {
                                range.setStart(start, 0).setCursor();
                            }
                        } else {
                            br = range.document.createElement("br");
                            range.insertNode(br).setStartAfter(br).setCursor();
                        }
                    } else {
                        br = range.document.createElement("br");
                        range.insertNode(br);
                        var parent = br.parentNode;
                        if (parent.lastChild === br) {
                            br.parentNode.insertBefore(br.cloneNode(true), br);
                            range.setStartBefore(br);
                        } else {
                            range.setStartAfter(br);
                        }
                        range.setCursor();
                    }
                }
            }
        });
    };


// plugins/keystrokes.js
    /* 处理特殊键的兼容性问题 */
    UE.plugins["keystrokes"] = function () {
        var me = this;
        var collapsed = true;
        me.addListener("keydown", function (type, evt) {
            var keyCode = evt.keyCode || evt.which,
                rng = me.selection.getRange();

            //处理全选的情况
            if (
                !rng.collapsed &&
                !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) &&
                ((keyCode >= 65 && keyCode <= 90) ||
                    (keyCode >= 48 && keyCode <= 57) ||
                    (keyCode >= 96 && keyCode <= 111) ||
                    {
                        13: 1,
                        8: 1,
                        46: 1
                    }[keyCode])
            ) {
                var tmpNode = rng.startContainer;
                if (domUtils.isFillChar(tmpNode)) {
                    rng.setStartBefore(tmpNode);
                }
                tmpNode = rng.endContainer;
                if (domUtils.isFillChar(tmpNode)) {
                    rng.setEndAfter(tmpNode);
                }
                rng.txtToElmBoundary();
                //结束边界可能放到了br的前边,要把br包含进来
                // x[xxx]<br/>
                if (rng.endContainer && rng.endContainer.nodeType == 1) {
                    tmpNode = rng.endContainer.childNodes[rng.endOffset];
                    if (tmpNode && domUtils.isBr(tmpNode)) {
                        rng.setEndAfter(tmpNode);
                    }
                }
                if (rng.startOffset == 0) {
                    tmpNode = rng.startContainer;
                    if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
                        tmpNode = rng.endContainer;
                        if (
                            rng.endOffset ==
                            (tmpNode.nodeType == 3
                                ? tmpNode.nodeValue.length
                                : tmpNode.childNodes.length) &&
                            domUtils.isBoundaryNode(tmpNode, "lastChild")
                        ) {
                            me.fireEvent("saveScene");
                            me.body.innerHTML = "<p>" + (browser.ie ? "" : "<br/>") + "</p>";
                            rng.setStart(me.body.firstChild, 0).setCursor(false, true);
                            me._selectionChange();
                            return;
                        }
                    }
                }
            }

            //处理backspace
            if (keyCode == keymap.Backspace) {
                rng = me.selection.getRange();
                collapsed = rng.collapsed;
                if (me.fireEvent("delkeydown", evt)) {
                    return;
                }
                var start, end;
                //避免按两次删除才能生效的问题
                if (rng.collapsed && rng.inFillChar()) {
                    start = rng.startContainer;

                    if (domUtils.isFillChar(start)) {
                        rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
                        domUtils.remove(start);
                    } else {
                        start.nodeValue = start.nodeValue.replace(
                            new RegExp("^" + domUtils.fillChar),
                            ""
                        );
                        rng.startOffset--;
                        rng.collapse(true).select(true);
                    }
                }

                //解决选中control元素不能删除的问题
                if ((start = rng.getClosedNode())) {
                    me.fireEvent("saveScene");
                    rng.setStartBefore(start);
                    domUtils.remove(start);
                    rng.setCursor();
                    me.fireEvent("saveScene");
                    domUtils.preventDefault(evt);
                    return;
                }
                //阻止在table上的删除
                if (!browser.ie) {
                    start = domUtils.findParentByTagName(rng.startContainer, "table", true);
                    end = domUtils.findParentByTagName(rng.endContainer, "table", true);
                    if ((start && !end) || (!start && end) || start !== end) {
                        evt.preventDefault();
                        return;
                    }
                }
            }
            //处理tab键的逻辑
            if (keyCode == keymap.Tab) {
                //不处理以下标签
                var excludeTagNameForTabKey = {
                    ol: 1,
                    ul: 1,
                    table: 1
                };
                //处理组件里的tab按下事件
                if (me.fireEvent("tabkeydown", evt)) {
                    domUtils.preventDefault(evt);
                    return;
                }
                var range = me.selection.getRange();
                me.fireEvent("saveScene");
                for (
                    var i = 0,
                        txt = "",
                        tabSize = me.options.tabSize || 4,
                        tabNode = me.options.tabNode || "&nbsp;";
                    i < tabSize;
                    i++
                ) {
                    txt += tabNode;
                }
                var span = me.document.createElement("span");
                span.innerHTML = txt + domUtils.fillChar;
                if (range.collapsed) {
                    range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
                } else {
                    var filterFn = function (node) {
                        return (
                            domUtils.isBlockElm(node) &&
                            !excludeTagNameForTabKey[node.tagName.toLowerCase()]
                        );
                    };
                    //普通的情况
                    start = domUtils.findParent(range.startContainer, filterFn, true);
                    end = domUtils.findParent(range.endContainer, filterFn, true);
                    if (start && end && start === end) {
                        range.deleteContents();
                        range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
                    } else {
                        var bookmark = range.createBookmark();
                        range.enlarge(true);
                        var bookmark2 = range.createBookmark(),
                            current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
                        while (
                            current &&
                            !(
                                domUtils.getPosition(current, bookmark2.end) &
                                domUtils.POSITION_FOLLOWING
                            )
                            ) {
                            current.insertBefore(
                                span.cloneNode(true).firstChild,
                                current.firstChild
                            );
                            current = domUtils.getNextDomNode(current, false, filterFn);
                        }
                        range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select();
                    }
                }
                domUtils.preventDefault(evt);
            }
            //trace:1634
            //ff的del键在容器空的时候,也会删除
            if (browser.gecko && keyCode == 46) {
                range = me.selection.getRange();
                if (range.collapsed) {
                    start = range.startContainer;
                    if (domUtils.isEmptyBlock(start)) {
                        var parent = start.parentNode;
                        while (
                            domUtils.getChildCount(parent) == 1 &&
                            !domUtils.isBody(parent)
                            ) {
                            start = parent;
                            parent = parent.parentNode;
                        }
                        if (start === parent.lastChild) evt.preventDefault();
                        return;
                    }
                }
            }

            /* 修复在编辑区域快捷键 (Mac:meta+alt+I; Win:ctrl+shift+I) 打不开 chrome 控制台的问题 */
            browser.chrome &&
            me.on("keydown", function (type, e) {
                var keyCode = e.keyCode || e.which;
                if (
                    ((e.metaKey && e.altKey) || (e.ctrlKey && e.shiftKey)) &&
                    keyCode == 73
                ) {
                    return true;
                }
            });
        });
        me.addListener("keyup", function (type, evt) {
            var keyCode = evt.keyCode || evt.which,
                rng,
                me = this;
            if (keyCode == keymap.Backspace) {
                if (me.fireEvent("delkeyup")) {
                    return;
                }
                rng = me.selection.getRange();
                if (rng.collapsed) {
                    var tmpNode,
                        autoClearTagName = ["h1", "h2", "h3", "h4", "h5", "h6"];
                    if (
                        (tmpNode = domUtils.findParentByTagName(
                            rng.startContainer,
                            autoClearTagName,
                            true
                        ))
                    ) {
                        if (domUtils.isEmptyBlock(tmpNode)) {
                            var pre = tmpNode.previousSibling;
                            if (pre && pre.nodeName != "TABLE") {
                                domUtils.remove(tmpNode);
                                rng.setStartAtLast(pre).setCursor(false, true);
                                return;
                            } else {
                                var next = tmpNode.nextSibling;
                                if (next && next.nodeName != "TABLE") {
                                    domUtils.remove(tmpNode);
                                    rng.setStartAtFirst(next).setCursor(false, true);
                                    return;
                                }
                            }
                        }
                    }
                    //处理当删除到body时,要重新给p标签展位
                    if (domUtils.isBody(rng.startContainer)) {
                        var tmpNode = domUtils.createElement(me.document, "p", {
                            innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
                        });
                        rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true);
                    }
                }

                //chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
                if (
                    !collapsed &&
                    (rng.startContainer.nodeType == 3 ||
                        (rng.startContainer.nodeType == 1 &&
                            domUtils.isEmptyBlock(rng.startContainer)))
                ) {
                    if (browser.ie) {
                        var span = rng.document.createElement("span");
                        rng.insertNode(span).setStartBefore(span).collapse(true);
                        rng.select();
                        domUtils.remove(span);
                    } else {
                        rng.select();
                    }
                }
            }
        });
    };


// plugins/fiximgclick.js
///import core
///commands 修复chrome下图片不能点击的问题,出现八个角可改变大小
///commandsName  FixImgClick
///commandsTitle  修复chrome下图片不能点击的问题,出现八个角可改变大小
//修复chrome下图片不能点击的问题,出现八个角可改变大小

    UE.plugins["fiximgclick"] = (function () {
        var elementUpdated = false;

        function Scale() {
            this.editor = null;
            this.resizer = null;
            this.cover = null;
            this.doc = document;
            this.prePos = {x: 0, y: 0};
            this.startPos = {x: 0, y: 0};
        }

        (function () {
            var rect = [
                //[left, top, width, height]
                [0, 0, -1, -1],
                [0, 0, 0, -1],
                [0, 0, 1, -1],
                [0, 0, -1, 0],
                [0, 0, 1, 0],
                [0, 0, -1, 1],
                [0, 0, 0, 1],
                [0, 0, 1, 1]
            ];

            Scale.prototype = {
                init: function (editor) {
                    var me = this;
                    me.editor = editor;
                    me.startPos = this.prePos = {x: 0, y: 0};
                    me.dragId = -1;

                    var hands = [],
                        cover = (me.cover = document.createElement("div")),
                        resizer = (me.resizer = document.createElement("div"));

                    cover.id = me.editor.ui.id + "_imagescale_cover";
                    cover.style.cssText =
                        "position:absolute;display:none;z-index:" +
                        me.editor.options.zIndex +
                        ";filter:alpha(opacity=0); opacity:0;background:#CCC;";
                    domUtils.on(cover, "mousedown click", function () {
                        me.hide();
                    });

                    for (i = 0; i < 8; i++) {
                        hands.push(
                            '<span class="edui-editor-imagescale-hand' + i + '"></span>'
                        );
                    }
                    resizer.id = me.editor.ui.id + "_imagescale";
                    resizer.className = "edui-editor-imagescale";
                    resizer.innerHTML = hands.join("");
                    resizer.style.cssText +=
                        ";display:none;border:1px solid #3b77ff;z-index:" +
                        me.editor.options.zIndex +
                        ";";

                    me.editor.ui.getDom().appendChild(cover);
                    me.editor.ui.getDom().appendChild(resizer);

                    me.initStyle();
                    me.initEvents();
                },
                initStyle: function () {
                    utils.cssRule(
                        "imagescale",
                        ".edui-editor-imagescale{display:none;position:absolute;border:1px solid #38B2CE;cursor:hand;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;}" +
                        ".edui-editor-imagescale span{position:absolute;width:6px;height:6px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}" +
                        ".edui-editor-imagescale .edui-editor-imagescale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}"
                    );
                },
                initEvents: function () {
                    var me = this;

                    me.startPos.x = me.startPos.y = 0;
                    me.isDraging = false;
                },
                _eventHandler: function (e) {
                    var me = this;
                    switch (e.type) {
                        case "mousedown":
                            var hand = e.target || e.srcElement,
                                hand;
                            if (
                                hand.className.indexOf("edui-editor-imagescale-hand") != -1 &&
                                me.dragId == -1
                            ) {
                                me.dragId = hand.className.slice(-1);
                                me.startPos.x = me.prePos.x = e.clientX;
                                me.startPos.y = me.prePos.y = e.clientY;
                                domUtils.on(me.doc, "mousemove", me.proxy(me._eventHandler, me));
                            }
                            break;
                        case "mousemove":
                            if (me.dragId != -1) {
                                me.updateContainerStyle(me.dragId, {
                                    x: e.clientX - me.prePos.x,
                                    y: e.clientY - me.prePos.y
                                });
                                me.prePos.x = e.clientX;
                                me.prePos.y = e.clientY;
                                elementUpdated = true;
                                me.updateTargetElement();
                            }
                            break;
                        case "mouseup":
                            if (me.dragId != -1) {
                                me.updateContainerStyle(me.dragId, {
                                    x: e.clientX - me.prePos.x,
                                    y: e.clientY - me.prePos.y
                                });
                                me.updateTargetElement();
                                if (me.target.parentNode) me.attachTo(me.target);
                                me.dragId = -1;
                            }
                            domUtils.un(me.doc, "mousemove", me.proxy(me._eventHandler, me));
                            //修复只是点击挪动点,但没有改变大小,不应该触发contentchange
                            if (elementUpdated) {
                                elementUpdated = false;
                                me.editor.fireEvent("contentchange");
                            }

                            break;
                        default:
                            break;
                    }
                },
                updateTargetElement: function () {
                    var me = this;
                    domUtils.setStyles(me.target, {
                        width: me.resizer.style.width,
                        height: me.resizer.style.height
                    });
                    me.target.width = parseInt(me.resizer.style.width);
                    me.target.height = parseInt(me.resizer.style.height);
                    me.attachTo(me.target);
                },
                updateContainerStyle: function (dir, offset) {
                    var me = this,
                        dom = me.resizer,
                        tmp;

                    if (rect[dir][0] != 0) {
                        tmp = parseInt(dom.style.left) + offset.x;
                        dom.style.left = me._validScaledProp("left", tmp) + "px";
                    }
                    if (rect[dir][1] != 0) {
                        tmp = parseInt(dom.style.top) + offset.y;
                        dom.style.top = me._validScaledProp("top", tmp) + "px";
                    }
                    if (rect[dir][2] != 0) {
                        tmp = dom.clientWidth + rect[dir][2] * offset.x;
                        dom.style.width = me._validScaledProp("width", tmp) + "px";
                    }
                    if (rect[dir][3] != 0) {
                        tmp = dom.clientHeight + rect[dir][3] * offset.y;
                        dom.style.height = me._validScaledProp("height", tmp) + "px";
                    }
                },
                _validScaledProp: function (prop, value) {
                    var ele = this.resizer,
                        wrap = document;

                    value = isNaN(value) ? 0 : value;
                    switch (prop) {
                        case "left":
                            return value < 0
                                ? 0
                                : value + ele.clientWidth > wrap.clientWidth
                                    ? wrap.clientWidth - ele.clientWidth
                                    : value;
                        case "top":
                            return value < 0
                                ? 0
                                : value + ele.clientHeight > wrap.clientHeight
                                    ? wrap.clientHeight - ele.clientHeight
                                    : value;
                        case "width":
                            return value <= 0
                                ? 1
                                : value + ele.offsetLeft > wrap.clientWidth
                                    ? wrap.clientWidth - ele.offsetLeft
                                    : value;
                        case "height":
                            return value <= 0
                                ? 1
                                : value + ele.offsetTop > wrap.clientHeight
                                    ? wrap.clientHeight - ele.offsetTop
                                    : value;
                    }
                },
                hideCover: function () {
                    this.cover.style.display = "none";
                },
                showCover: function () {
                    var me = this,
                        editorPos = domUtils.getXY(me.editor.ui.getDom()),
                        iframePos = domUtils.getXY(me.editor.iframe);

                    domUtils.setStyles(me.cover, {
                        width: me.editor.iframe.offsetWidth + "px",
                        height: me.editor.iframe.offsetHeight + "px",
                        top: iframePos.y - editorPos.y + "px",
                        left: iframePos.x - editorPos.x + "px",
                        position: "absolute",
                        display: ""
                    });
                },
                show: function (targetObj) {
                    var me = this;
                    me.resizer.style.display = "block";
                    if (targetObj) me.attachTo(targetObj);

                    domUtils.on(this.resizer, "mousedown", me.proxy(me._eventHandler, me));
                    domUtils.on(me.doc, "mouseup", me.proxy(me._eventHandler, me));

                    me.showCover();
                    me.editor.fireEvent("afterscaleshow", me);
                    me.editor.fireEvent("saveScene");
                },
                hide: function () {
                    var me = this;
                    me.hideCover();
                    me.resizer.style.display = "none";

                    domUtils.un(me.resizer, "mousedown", me.proxy(me._eventHandler, me));
                    domUtils.un(me.doc, "mouseup", me.proxy(me._eventHandler, me));
                    me.editor.fireEvent("afterscalehide", me);
                },
                proxy: function (fn, context) {
                    return function (e) {
                        return fn.apply(context || this, arguments);
                    };
                },
                attachTo: function (targetObj) {
                    var me = this,
                        target = (me.target = targetObj),
                        resizer = this.resizer,
                        imgPos = domUtils.getXY(target),
                        iframePos = domUtils.getXY(me.editor.iframe),
                        editorPos = domUtils.getXY(resizer.parentNode);

                    var doc = me.editor.document;
                    domUtils.setStyles(resizer, {
                        width: target.width + "px",
                        height: target.height + "px",
                        left:
                        iframePos.x +
                        imgPos.x -
                        (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0) -
                        editorPos.x -
                        parseInt(resizer.style.borderLeftWidth) +
                        "px",
                        top:
                        iframePos.y +
                        imgPos.y -
                        (doc.documentElement.scrollTop || doc.body.scrollTop || 0) -
                        editorPos.y -
                        parseInt(resizer.style.borderTopWidth) +
                        "px"
                    });
                }
            };
        })();

        return function () {
            var me = this,
                imageScale;

            me.setOpt("imageScaleEnabled", true);

            if (!browser.ie && me.options.imageScaleEnabled) {
                me.addListener("click", function (type, e) {
                    var range = me.selection.getRange(),
                        img = range.getClosedNode();

                    if (img && img.tagName == "IMG" && me.body.contentEditable != "false") {
                        if (
                            img.className.indexOf("edui-faked-music") != -1 ||
                            img.getAttribute("anchorname") ||
                            domUtils.hasClass(img, "loadingclass") ||
                            domUtils.hasClass(img, "loaderrorclass")
                        ) {
                            return;
                        }

                        if (!imageScale) {
                            imageScale = new Scale();
                            imageScale.init(me);
                            me.ui.getDom().appendChild(imageScale.resizer);

                            var _keyDownHandler = function (e) {
                                    imageScale.hide();
                                    if (imageScale.target)
                                        me.selection.getRange().selectNode(imageScale.target).select();
                                },
                                _mouseDownHandler = function (e) {
                                    var ele = e.target || e.srcElement;
                                    if (
                                        ele &&
                                        (ele.className === undefined ||
                                            ele.className.indexOf("edui-editor-imagescale") == -1)
                                    ) {
                                        _keyDownHandler(e);
                                    }
                                },
                                timer;

                            me.addListener("afterscaleshow", function (e) {
                                me.addListener("beforekeydown", _keyDownHandler);
                                me.addListener("beforemousedown", _mouseDownHandler);
                                domUtils.on(document, "keydown", _keyDownHandler);
                                domUtils.on(document, "mousedown", _mouseDownHandler);
                                me.selection.getNative().removeAllRanges();
                            });
                            me.addListener("afterscalehide", function (e) {
                                me.removeListener("beforekeydown", _keyDownHandler);
                                me.removeListener("beforemousedown", _mouseDownHandler);
                                domUtils.un(document, "keydown", _keyDownHandler);
                                domUtils.un(document, "mousedown", _mouseDownHandler);
                                var target = imageScale.target;
                                if (target.parentNode) {
                                    me.selection.getRange().selectNode(target).select();
                                }
                            });
                            //TODO 有iframe的情况,mousedown不能往下传。。
                            domUtils.on(imageScale.resizer, "mousedown", function (e) {
                                me.selection.getNative().removeAllRanges();
                                var ele = e.target || e.srcElement;
                                if (
                                    ele &&
                                    ele.className.indexOf("edui-editor-imagescale-hand") == -1
                                ) {
                                    timer = setTimeout(function () {
                                        imageScale.hide();
                                        if (imageScale.target)
                                            me.selection.getRange().selectNode(ele).select();
                                    }, 200);
                                }
                            });
                            domUtils.on(imageScale.resizer, "mouseup", function (e) {
                                var ele = e.target || e.srcElement;
                                if (
                                    ele &&
                                    ele.className.indexOf("edui-editor-imagescale-hand") == -1
                                ) {
                                    clearTimeout(timer);
                                }
                            });
                        }
                        imageScale.show(img);
                    } else {
                        if (imageScale && imageScale.resizer.style.display != "none")
                            imageScale.hide();
                    }
                });
            }

            if (browser.webkit) {
                me.addListener("click", function (type, e) {
                    if (e.target.tagName == "IMG" && me.body.contentEditable != "false") {
                        var range = new dom.Range(me.document);
                        range.selectNode(e.target).select();
                    }
                });
            }
        };
    })();


// plugins/autolink.js
///import core
///commands 为非ie浏览器自动添加a标签
///commandsName  AutoLink
///commandsTitle  自动增加链接
    /**
     * @description 为非ie浏览器自动添加a标签
     * @author zhanyi
     */

    UE.plugin.register(
        "autolink",
        function () {
            var cont = 0;

            return !browser.ie
                ? {
                    bindEvents: {
                        reset: function () {
                            cont = 0;
                        },
                        keydown: function (type, evt) {
                            var me = this;
                            var keyCode = evt.keyCode || evt.which;

                            if (keyCode == 32 || keyCode == 13) {
                                var sel = me.selection.getNative(),
                                    range = sel.getRangeAt(0).cloneRange(),
                                    offset,
                                    charCode;

                                var start = range.startContainer;
                                while (start.nodeType == 1 && range.startOffset > 0) {
                                    start =
                                        range.startContainer.childNodes[range.startOffset - 1];
                                    if (!start) {
                                        break;
                                    }
                                    range.setStart(
                                        start,
                                        start.nodeType == 1
                                            ? start.childNodes.length
                                            : start.nodeValue.length
                                    );
                                    range.collapse(true);
                                    start = range.startContainer;
                                }

                                do {
                                    if (range.startOffset == 0) {
                                        start = range.startContainer.previousSibling;

                                        while (start && start.nodeType == 1) {
                                            start = start.lastChild;
                                        }
                                        if (!start || domUtils.isFillChar(start)) {
                                            break;
                                        }
                                        offset = start.nodeValue.length;
                                    } else {
                                        start = range.startContainer;
                                        offset = range.startOffset;
                                    }
                                    range.setStart(start, offset - 1);
                                    charCode = range.toString().charCodeAt(0);
                                } while (charCode != 160 && charCode != 32);

                                if (
                                    range
                                        .toString()
                                        .replace(new RegExp(domUtils.fillChar, "g"), "")
                                        .match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)
                                ) {
                                    while (range.toString().length) {
                                        if (
                                            /^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(
                                                range.toString()
                                            )
                                        ) {
                                            break;
                                        }
                                        try {
                                            range.setStart(
                                                range.startContainer,
                                                range.startOffset + 1
                                            );
                                        } catch (e) {
                                            //trace:2121
                                            var start = range.startContainer;
                                            while (!(next = start.nextSibling)) {
                                                if (domUtils.isBody(start)) {
                                                    return;
                                                }
                                                start = start.parentNode;
                                            }
                                            range.setStart(next, 0);
                                        }
                                    }
                                    //range的开始边界已经在a标签里的不再处理
                                    if (
                                        domUtils.findParentByTagName(
                                            range.startContainer,
                                            "a",
                                            true
                                        )
                                    ) {
                                        return;
                                    }
                                    var a = me.document.createElement("a"),
                                        text = me.document.createTextNode(" "),
                                        href;

                                    me.undoManger && me.undoManger.save();
                                    a.appendChild(range.extractContents());
                                    a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, "");
                                    href = a
                                        .getAttribute("href")
                                        .replace(new RegExp(domUtils.fillChar, "g"), "");
                                    href = /^(?:https?:\/\/)/gi.test(href)
                                        ? href
                                        : "http://" + href;
                                    a.setAttribute("_src", utils.html(href));
                                    a.href = utils.html(href);

                                    range.insertNode(a);
                                    a.parentNode.insertBefore(text, a.nextSibling);
                                    range.setStart(text, 0);
                                    range.collapse(true);
                                    sel.removeAllRanges();
                                    sel.addRange(range);
                                    me.undoManger && me.undoManger.save();
                                }
                            }
                        }
                    }
                }
                : {};
        },
        function () {
            var keyCodes = {
                37: 1,
                38: 1,
                39: 1,
                40: 1,
                13: 1,
                32: 1
            };

            function checkIsCludeLink(node) {
                if (node.nodeType == 3) {
                    return null;
                }
                if (node.nodeName == "A") {
                    return node;
                }
                var lastChild = node.lastChild;

                while (lastChild) {
                    if (lastChild.nodeName == "A") {
                        return lastChild;
                    }
                    if (lastChild.nodeType == 3) {
                        if (domUtils.isWhitespace(lastChild)) {
                            lastChild = lastChild.previousSibling;
                            continue;
                        }
                        return null;
                    }
                    lastChild = lastChild.lastChild;
                }
            }

            browser.ie &&
            this.addListener("keyup", function (cmd, evt) {
                var me = this,
                    keyCode = evt.keyCode;
                if (keyCodes[keyCode]) {
                    var rng = me.selection.getRange();
                    var start = rng.startContainer;

                    if (keyCode == 13) {
                        while (
                            start &&
                            !domUtils.isBody(start) &&
                            !domUtils.isBlockElm(start)
                            ) {
                            start = start.parentNode;
                        }
                        if (start && !domUtils.isBody(start) && start.nodeName == "P") {
                            var pre = start.previousSibling;
                            if (pre && pre.nodeType == 1) {
                                var pre = checkIsCludeLink(pre);
                                if (pre && !pre.getAttribute("_href")) {
                                    domUtils.remove(pre, true);
                                }
                            }
                        }
                    } else if (keyCode == 32) {
                        if (start.nodeType == 3 && /^\s$/.test(start.nodeValue)) {
                            start = start.previousSibling;
                            if (
                                start &&
                                start.nodeName == "A" &&
                                !start.getAttribute("_href")
                            ) {
                                domUtils.remove(start, true);
                            }
                        }
                    } else {
                        start = domUtils.findParentByTagName(start, "a", true);
                        if (start && !start.getAttribute("_href")) {
                            var bk = rng.createBookmark();

                            domUtils.remove(start, true);
                            rng.moveToBookmark(bk).select(true);
                        }
                    }
                }
            });
        }
    );


// plugins/autoheight.js
///import core
///commands 当输入内容超过编辑器高度时,编辑器自动增高
///commandsName  AutoHeight,autoHeightEnabled
///commandsTitle  自动增高
    /**
     * @description 自动伸展
     * @author zhanyi
     */
    UE.plugins["autoheight"] = function () {
        var me = this;
        //提供开关,就算加载也可以关闭
        me.autoHeightEnabled = me.options.autoHeightEnabled !== false;
        if (!me.autoHeightEnabled) {
            return;
        }

        var bakOverflow,
            lastHeight = 0,
            options = me.options,
            currentHeight,
            timer;

        function adjustHeight() {
            var me = this;
            clearTimeout(timer);
            if (isFullscreen) return;
            if (
                !me.queryCommandState ||
                (me.queryCommandState && me.queryCommandState("source") != 1)
            ) {
                timer = setTimeout(function () {
                    var node = me.body.lastChild;
                    while (node && node.nodeType != 1) {
                        node = node.previousSibling;
                    }
                    if (node && node.nodeType == 1) {
                        node.style.clear = "both";
                        currentHeight = Math.max(
                            domUtils.getXY(node).y + node.offsetHeight + 25,
                            Math.max(options.minFrameHeight, options.initialFrameHeight)
                        );
                        if (currentHeight != lastHeight) {
                            if (currentHeight !== parseInt(me.iframe.parentNode.style.height)) {
                                me.iframe.parentNode.style.height = currentHeight + "px";
                            }
                            me.body.style.height = currentHeight + "px";
                            lastHeight = currentHeight;
                        }
                        domUtils.removeStyle(node, "clear");
                    }
                }, 50);
            }
        }

        var isFullscreen;
        me.addListener("fullscreenchanged", function (cmd, f) {
            isFullscreen = f;
        });
        me.addListener("destroy", function () {
            domUtils.un(me.window, "scroll", fixedScrollTop);
            me.removeListener(
                "contentchange afterinserthtml keyup mouseup",
                adjustHeight
            );
        });
        me.enableAutoHeight = function () {
            var me = this;
            if (!me.autoHeightEnabled) {
                return;
            }
            var doc = me.document;
            me.autoHeightEnabled = true;
            bakOverflow = doc.body.style.overflowY;
            doc.body.style.overflowY = "hidden";
            me.addListener("contentchange afterinserthtml keyup mouseup", adjustHeight);
            //ff不给事件算得不对

            setTimeout(function () {
                adjustHeight.call(me);
            }, browser.gecko ? 100 : 0);
            me.fireEvent("autoheightchanged", me.autoHeightEnabled);
        };
        me.disableAutoHeight = function () {
            me.body.style.overflowY = bakOverflow || "";

            me.removeListener("contentchange", adjustHeight);
            me.removeListener("keyup", adjustHeight);
            me.removeListener("mouseup", adjustHeight);
            me.autoHeightEnabled = false;
            me.fireEvent("autoheightchanged", me.autoHeightEnabled);
        };

        me.on("setHeight", function () {
            me.disableAutoHeight();
        });
        me.addListener("ready", function () {
            me.enableAutoHeight();
            //trace:1764
            var timer;
            domUtils.on(
                browser.ie ? me.body : me.document,
                browser.webkit ? "dragover" : "drop",
                function () {
                    clearTimeout(timer);
                    timer = setTimeout(function () {
                        //trace:3681
                        adjustHeight.call(me);
                    }, 100);
                }
            );
            //修复内容过多时,回到顶部,顶部内容被工具栏遮挡问题
            domUtils.on(me.window, "scroll", fixedScrollTop);
        });

        var lastScrollY;

        function fixedScrollTop() {
            if (!me.window) return;
            if (lastScrollY === null) {
                lastScrollY = me.window.scrollY;
            } else if (me.window.scrollY == 0 && lastScrollY != 0) {
                me.window.scrollTo(0, 0);
                lastScrollY = null;
            }
        }
    };


// plugins/autofloat.js
///import core
///commands 悬浮工具栏
///commandsName  AutoFloat,autoFloatEnabled
///commandsTitle  悬浮工具栏
    /**
     *  modified by chengchao01
     *  注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
     */
    UE.plugins["autofloat"] = function () {
        var me = this,
            lang = me.getLang();
        me.setOpt({
            topOffset: 0
        });
        var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
            topOffset = me.options.topOffset;

        //如果不固定toolbar的位置,则直接退出
        if (!optsAutoFloatEnabled) {
            return;
        }
        var uiUtils = UE.ui.uiUtils,
            LteIE6 = browser.ie && browser.version <= 6,
            quirks = browser.quirks;

        function checkHasUI() {
            if (!UE.ui) {
                alert(lang.autofloatMsg);
                return 0;
            }
            return 1;
        }

        function fixIE6FixedPos() {
            var docStyle = document.body.style;
            docStyle.backgroundImage = 'url("about:blank")';
            docStyle.backgroundAttachment = "fixed";
        }

        var bakCssText,
            placeHolder = document.createElement("div"),
            toolbarBox,
            orgTop,
            getPosition,
            flag = true; //ie7模式下需要偏移
        function setFloating() {
            var toobarBoxPos = domUtils.getXY(toolbarBox),
                origalFloat = domUtils.getComputedStyle(toolbarBox, "position"),
                origalLeft = domUtils.getComputedStyle(toolbarBox, "left");
            toolbarBox.style.width = toolbarBox.offsetWidth + "px";
            toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
            toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
            if (LteIE6 || (quirks && browser.ie)) {
                if (toolbarBox.style.position != "absolute") {
                    toolbarBox.style.position = "absolute";
                }
                toolbarBox.style.top =
                    (document.body.scrollTop || document.documentElement.scrollTop) -
                    orgTop +
                    topOffset +
                    "px";
            } else {
                if (browser.ie7Compat && flag) {
                    flag = false;
                    toolbarBox.style.left =
                        domUtils.getXY(toolbarBox).x -
                        document.documentElement.getBoundingClientRect().left +
                        2 +
                        "px";
                }
                if (toolbarBox.style.position != "fixed") {
                    toolbarBox.style.position = "fixed";
                    toolbarBox.style.top = topOffset + "px";
                    (origalFloat == "absolute" || origalFloat == "relative") &&
                    parseFloat(origalLeft) &&
                    (toolbarBox.style.left = toobarBoxPos.x + "px");
                }
            }
        }

        function unsetFloating() {
            flag = true;
            if (placeHolder.parentNode) {
                placeHolder.parentNode.removeChild(placeHolder);
            }

            toolbarBox.style.cssText = bakCssText;
        }

        function updateFloating() {
            var rect3 = getPosition(me.container);
            var offset = me.options.toolbarTopOffset || 0;
            if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
                setFloating();
            } else {
                unsetFloating();
            }
        }

        var defer_updateFloating = utils.defer(
            function () {
                updateFloating();
            },
            browser.ie ? 200 : 100,
            true
        );

        me.addListener("destroy", function () {
            domUtils.un(window, ["scroll", "resize"], updateFloating);
            me.removeListener("keydown", defer_updateFloating);
            //适用于在DIV scrollbox中滚动,但页面不滚动的浮动toolbar
            var scrollBox = document.getElementById("scrollBox");
            if (scrollBox) {
                domUtils.un(scrollBox, ['scroll', 'resize'], updateFloating);
            }
        });

        me.addListener("ready", function () {
            if (checkHasUI(me)) {
                //加载了ui组件,但在new时,没有加载ui,导致编辑器实例上没有ui类,所以这里做判断
                if (!me.ui) {
                    return;
                }
                getPosition = uiUtils.getClientRect;
                toolbarBox = me.ui.getDom("toolbarbox");
                orgTop = getPosition(toolbarBox).top;
                bakCssText = toolbarBox.style.cssText;
                placeHolder.style.height = toolbarBox.offsetHeight + "px";
                if (LteIE6) {
                    fixIE6FixedPos();
                }
                domUtils.on(window, ["scroll", "resize"], updateFloating);
                me.addListener("keydown", defer_updateFloating);
                //适用于在DIV scrollbox中滚动,但页面不滚动的浮动toolbar
                var scrollBox = document.getElementById("scrollBox");
                if (scrollBox) {
                    domUtils.on(scrollBox, ['scroll', 'resize'], updateFloating);
                }
                me.addListener("beforefullscreenchange", function (t, enabled) {
                    if (enabled) {
                        unsetFloating();
                    }
                });
                me.addListener("fullscreenchanged", function (t, enabled) {
                    if (!enabled) {
                        updateFloating();
                    }
                });
                me.addListener("sourcemodechanged", function (t, enabled) {
                    setTimeout(function () {
                        updateFloating();
                    }, 0);
                });
                me.addListener("clearDoc", function () {
                    setTimeout(function () {
                        updateFloating();
                    }, 0);
                });
            }
        });
    };


// plugins/video.js
    /**
     * video插件, 为UEditor提供视频插入支持
     * @file
     * @since 1.2.6.1
     */

    UE.plugins["video"] = function () {
        var me = this;

        /**
         * 创建插入视频字符窜
         * @param url 视频地址
         * @param width 视频宽度
         * @param height 视频高度
         * @param align 视频对齐
         * @param toEmbed 是否以flash代替显示
         * @param addParagraph  是否需要添加P 标签
         */
        function creatInsertStr(url, width, height, id, align, classname, type) {
            var str;
            switch (type) {
                case "image":
                    str =
                        "<img " +
                        (id ? 'id="' + id + '"' : "") +
                        ' width="' +
                        width +
                        '" height="' +
                        height +
                        '" _url="' +
                        url +
                        '" class="' +
                        classname.replace(/\bvideo-js\b/, "") +
                        '"' +
                        ' src="' +
                        me.options.UEDITOR_HOME_URL +
                        'themes/notadd/images/spacer.gif" style="background:url(' +
                        me.options.UEDITOR_HOME_URL +
                        "themes/notadd/images/videologo.gif) no-repeat center center; border:1px solid gray;" +
                        (align ? "float:" + align + ";" : "") +
                        '" />';
                    break;
                case "embed":
                    str =
                        '<embed type="application/x-shockwave-flash" class="' +
                        classname +
                        '" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
                        ' src="' +
                        utils.html(url) +
                        '" width="' +
                        width +
                        '" height="' +
                        height +
                        '"' +
                        (align ? ' style="float:' + align + '"' : "") +
                        ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
                    break;
                case "video":
                    var ext = url.substr(url.lastIndexOf(".") + 1);
                    if (ext == "ogv") ext = "ogg";
                    str =
                        "<video" +
                        (id ? ' id="' + id + '"' : "") +
                        ' class="' +
                        classname +
                        ' video-js" ' +
                        (align ? ' style="float:' + align + '"' : "") +
                        ' controls preload="none" width="' +
                        width +
                        '" height="' +
                        height +
                        '" src="' +
                        url +
                        '" data-setup="{}">' +
                        '<source src="' +
                        url +
                        '" type="video/' +
                        ext +
                        '" /></video>';
                    break;
            }
            return str;
        }

        function switchImgAndVideo(root, img2video) {
            utils.each(
                root.getNodesByTagName(img2video ? "img" : "embed video"),
                function (node) {
                    var className = node.getAttr("class");
                    if (className && className.indexOf("edui-faked-video") != -1) {
                        var html = creatInsertStr(
                            img2video ? node.getAttr("_url") : node.getAttr("src"),
                            node.getAttr("width"),
                            node.getAttr("height"),
                            null,
                            node.getStyle("float") || "",
                            className,
                            img2video ? "embed" : "image"
                        );
                        node.parentNode.replaceChild(UE.uNode.createElement(html), node);
                    }
                    if (className && className.indexOf("edui-upload-video") != -1) {
                        var html = creatInsertStr(
                            img2video ? node.getAttr("_url") : node.getAttr("src"),
                            node.getAttr("width"),
                            node.getAttr("height"),
                            null,
                            node.getStyle("float") || "",
                            className,
                            img2video ? "video" : "image"
                        );
                        node.parentNode.replaceChild(UE.uNode.createElement(html), node);
                    }
                }
            );
        }

        me.addOutputRule(function (root) {
            switchImgAndVideo(root, true);
        });
        me.addInputRule(function (root) {
            switchImgAndVideo(root);
        });

        /**
         * 插入视频
         * @command insertvideo
         * @method execCommand
         * @param { String } cmd 命令字符串
         * @param { Object } videoAttr 键值对对象, 描述一个视频的所有属性
         * @example
         * ```javascript
         *
         * var videoAttr = {
     *      //视频地址
     *      url: 'http://www.youku.com/xxx',
     *      //视频宽高值, 单位px
     *      width: 200,
     *      height: 100
     * };
         *
         * //editor 是编辑器实例
         * //向编辑器插入单个视频
         * editor.execCommand( 'insertvideo', videoAttr );
         * ```
         */

        /**
         * 插入视频
         * @command insertvideo
         * @method execCommand
         * @param { String } cmd 命令字符串
         * @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性
         * @example
         * ```javascript
         *
         * var videoAttr1 = {
     *      //视频地址
     *      url: 'http://www.youku.com/xxx',
     *      //视频宽高值, 单位px
     *      width: 200,
     *      height: 100
     * },
         * videoAttr2 = {
     *      //视频地址
     *      url: 'http://www.youku.com/xxx',
     *      //视频宽高值, 单位px
     *      width: 200,
     *      height: 100
     * }
         *
         * //editor 是编辑器实例
         * //该方法将会向编辑器内插入两个视频
         * editor.execCommand( 'insertvideo', [ videoAttr1, videoAttr2 ] );
         * ```
         */

        /**
         * 查询当前光标所在处是否是一个视频
         * @command insertvideo
         * @method queryCommandState
         * @param { String } cmd 需要查询的命令字符串
         * @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0
         * @example
         * ```javascript
         *
         * //editor 是编辑器实例
         * editor.queryCommandState( 'insertvideo' );
         * ```
         */
        me.commands["insertvideo"] = {
            execCommand: function (cmd, videoObjs, type) {
                videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs];

                if (me.fireEvent("beforeinsertvideo", videoObjs) === true) {
                    return;
                }

                var html = [],
                    id = "tmpVedio",
                    cl;
                for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
                    vi = videoObjs[i];
                    cl = type == "upload"
                        ? "edui-upload-video video-js vjs-default-skin"
                        : "edui-faked-video";
                    html.push(
                        creatInsertStr(
                            vi.url,
                            vi.width || 420,
                            vi.height || 280,
                            id + i,
                            null,
                            cl,
                            "image"
                        )
                    );
                }
                me.execCommand("inserthtml", html.join(""), true);
                var rng = this.selection.getRange();
                for (var i = 0, len = videoObjs.length; i < len; i++) {
                    var img = this.document.getElementById("tmpVedio" + i);
                    domUtils.removeAttributes(img, "id");
                    rng.selectNode(img).select();
                    me.execCommand("imagefloat", videoObjs[i].align);
                }

                me.fireEvent("afterinsertvideo", videoObjs);
            },
            queryCommandState: function () {
                var img = me.selection.getRange().getClosedNode(),
                    flag =
                        img &&
                        (img.className == "edui-faked-video" ||
                            img.className.indexOf("edui-upload-video") != -1);
                return flag ? 1 : 0;
            }
        };
    };


// plugins/table.core.js
    /**
     * Created with JetBrains WebStorm.
     * User: taoqili
     * Date: 13-1-18
     * Time: 上午11:09
     * To change this template use File | Settings | File Templates.
     */
    /**
     * UE表格操作类
     * @param table
     * @constructor
     */
    ;(function () {
        var UETable = (UE.UETable = function (table) {
            this.table = table;
            this.indexTable = [];
            this.selectedTds = [];
            this.cellsRange = {};
            this.update(table);
        });

        //===以下为静态工具方法===
        UETable.removeSelectedClass = function (cells) {
            utils.each(cells, function (cell) {
                domUtils.removeClasses(cell, "selectTdClass");
            });
        };
        UETable.addSelectedClass = function (cells) {
            utils.each(cells, function (cell) {
                domUtils.addClass(cell, "selectTdClass");
            });
        };
        UETable.isEmptyBlock = function (node) {
            var reg = new RegExp(domUtils.fillChar, "g");
            if (
                node[browser.ie ? "innerText" : "textContent"]
                    .replace(/^\s*$/, "")
                    .replace(reg, "").length > 0
            ) {
                return 0;
            }
            for (var i in dtd.$isNotEmpty)
                if (dtd.$isNotEmpty.hasOwnProperty(i)) {
                    if (node.getElementsByTagName(i).length) {
                        return 0;
                    }
                }
            return 1;
        };
        UETable.getWidth = function (cell) {
            if (!cell) return 0;
            return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
        };

        /**
         * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
         * 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态;
         * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
         * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
         */
        UETable.getTableCellAlignState = function (cells) {
            !utils.isArray(cells) && (cells = [cells]);

            var result = {},
                status = ["align", "valign"],
                tempStatus = null,
                isSame = true; //状态是否相同

            utils.each(cells, function (cellNode) {
                utils.each(status, function (currentState) {
                    tempStatus = cellNode.getAttribute(currentState);

                    if (!result[currentState] && tempStatus) {
                        result[currentState] = tempStatus;
                    } else if (
                        !result[currentState] ||
                        tempStatus !== result[currentState]
                    ) {
                        isSame = false;
                        return false;
                    }
                });

                return isSame;
            });

            return isSame ? result : null;
        };

        /**
         * 根据当前选区获取相关的table信息
         * @return {Object}
         */
        UETable.getTableItemsByRange = function (editor) {
            var start = editor.selection.getStart();

            //ff下会选中bookmark
            if (
                start &&
                start.id &&
                start.id.indexOf("_baidu_bookmark_start_") === 0 &&
                start.nextSibling
            ) {
                start = start.nextSibling;
            }

            //在table或者td边缘有可能存在选中tr的情况
            var cell = start && domUtils.findParentByTagName(start, ["td", "th"], true),
                tr = cell && cell.parentNode,
                table = tr && domUtils.findParentByTagName(tr, ["table"]),
                caption = table && table.getElementsByTagName("caption")[0];

            return {
                cell: cell,
                tr: tr,
                table: table,
                caption: caption
            };
        };
        UETable.getUETableBySelected = function (editor) {
            var table = UETable.getTableItemsByRange(editor).table;
            if (table && table.ueTable && table.ueTable.selectedTds.length) {
                return table.ueTable;
            }
            return null;
        };

        UETable.getDefaultValue = function (editor, table) {
            var borderMap = {
                    thin: "0px",
                    medium: "1px",
                    thick: "2px"
                },
                tableBorder,
                tdPadding,
                tdBorder,
                tmpValue;
            if (!table) {
                table = editor.document.createElement("table");
                table.insertRow(0).insertCell(0).innerHTML = "xxx";
                editor.body.appendChild(table);
                var td = table.getElementsByTagName("td")[0];
                tmpValue = domUtils.getComputedStyle(table, "border-left-width");
                tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
                tmpValue = domUtils.getComputedStyle(td, "padding-left");
                tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
                tmpValue = domUtils.getComputedStyle(td, "border-left-width");
                tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
                domUtils.remove(table);
                return {
                    tableBorder: tableBorder,
                    tdPadding: tdPadding,
                    tdBorder: tdBorder
                };
            } else {
                td = table.getElementsByTagName("td")[0];
                tmpValue = domUtils.getComputedStyle(table, "border-left-width");
                tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
                tmpValue = domUtils.getComputedStyle(td, "padding-left");
                tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
                tmpValue = domUtils.getComputedStyle(td, "border-left-width");
                tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
                return {
                    tableBorder: tableBorder,
                    tdPadding: tdPadding,
                    tdBorder: tdBorder
                };
            }
        };
        /**
         * 根据当前点击的td或者table获取索引对象
         * @param tdOrTable
         */
        UETable.getUETable = function (tdOrTable) {
            var tag = tdOrTable.tagName.toLowerCase();
            tdOrTable = tag == "td" || tag == "th" || tag == "caption"
                ? domUtils.findParentByTagName(tdOrTable, "table", true)
                : tdOrTable;
            if (!tdOrTable.ueTable) {
                tdOrTable.ueTable = new UETable(tdOrTable);
            }
            return tdOrTable.ueTable;
        };

        UETable.cloneCell = function (cell, ignoreMerge, keepPro) {
            if (!cell || utils.isString(cell)) {
                return this.table.ownerDocument.createElement(cell || "td");
            }
            var flag = domUtils.hasClass(cell, "selectTdClass");
            flag && domUtils.removeClasses(cell, "selectTdClass");
            var tmpCell = cell.cloneNode(true);
            if (ignoreMerge) {
                tmpCell.rowSpan = tmpCell.colSpan = 1;
            }
            //去掉宽高
            !keepPro && domUtils.removeAttributes(tmpCell, "width height");
            !keepPro && domUtils.removeAttributes(tmpCell, "style");

            tmpCell.style.borderLeftStyle = "";
            tmpCell.style.borderTopStyle = "";
            tmpCell.style.borderLeftColor = cell.style.borderRightColor;
            tmpCell.style.borderLeftWidth = cell.style.borderRightWidth;
            tmpCell.style.borderTopColor = cell.style.borderBottomColor;
            tmpCell.style.borderTopWidth = cell.style.borderBottomWidth;
            flag && domUtils.addClass(cell, "selectTdClass");
            return tmpCell;
        };

        UETable.prototype = {
            getMaxRows: function () {
                var rows = this.table.rows,
                    maxLen = 1;
                for (var i = 0, row; (row = rows[i]); i++) {
                    var currentMax = 1;
                    for (var j = 0, cj; (cj = row.cells[j++]);) {
                        currentMax = Math.max(cj.rowSpan || 1, currentMax);
                    }
                    maxLen = Math.max(currentMax + i, maxLen);
                }
                return maxLen;
            },
            /**
             * 获取当前表格的最大列数
             */
            getMaxCols: function () {
                var rows = this.table.rows,
                    maxLen = 0,
                    cellRows = {};
                for (var i = 0, row; (row = rows[i]); i++) {
                    var cellsNum = 0;
                    for (var j = 0, cj; (cj = row.cells[j++]);) {
                        cellsNum += cj.colSpan || 1;
                        if (cj.rowSpan && cj.rowSpan > 1) {
                            for (var k = 1; k < cj.rowSpan; k++) {
                                if (!cellRows["row_" + (i + k)]) {
                                    cellRows["row_" + (i + k)] = cj.colSpan || 1;
                                } else {
                                    cellRows["row_" + (i + k)]++;
                                }
                            }
                        }
                    }
                    cellsNum += cellRows["row_" + i] || 0;
                    maxLen = Math.max(cellsNum, maxLen);
                }
                return maxLen;
            },
            getCellColIndex: function (cell) {
            },
            /**
             * 获取当前cell旁边的单元格,
             * @param cell
             * @param right
             */
            getHSideCell: function (cell, right) {
                try {
                    var cellInfo = this.getCellInfo(cell),
                        previewRowIndex,
                        previewColIndex;
                    var len = this.selectedTds.length,
                        range = this.cellsRange;
                    //首行或者首列没有前置单元格
                    if (
                        (!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
                        (right &&
                            (!len
                                ? cellInfo.colIndex == this.colsNum - 1
                                : range.endColIndex == this.colsNum - 1))
                    )
                        return null;

                    previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex;
                    previewColIndex = !right
                        ? !len
                            ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
                            : range.beginColIndex - 1
                        : !len ? cellInfo.colIndex + 1 : range.endColIndex + 1;
                    return this.getCell(
                        this.indexTable[previewRowIndex][previewColIndex].rowIndex,
                        this.indexTable[previewRowIndex][previewColIndex].cellIndex
                    );
                } catch (e) {
                    showError(e);
                }
            },
            getTabNextCell: function (cell, preRowIndex) {
                var cellInfo = this.getCellInfo(cell),
                    rowIndex = preRowIndex || cellInfo.rowIndex,
                    colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
                    nextCell;
                try {
                    nextCell = this.getCell(
                        this.indexTable[rowIndex][colIndex].rowIndex,
                        this.indexTable[rowIndex][colIndex].cellIndex
                    );
                } catch (e) {
                    try {
                        rowIndex = rowIndex * 1 + 1;
                        colIndex = 0;
                        nextCell = this.getCell(
                            this.indexTable[rowIndex][colIndex].rowIndex,
                            this.indexTable[rowIndex][colIndex].cellIndex
                        );
                    } catch (e) {
                    }
                }
                return nextCell;
            },
            /**
             * 获取视觉上的后置单元格
             * @param cell
             * @param bottom
             */
            getVSideCell: function (cell, bottom, ignoreRange) {
                try {
                    var cellInfo = this.getCellInfo(cell),
                        nextRowIndex,
                        nextColIndex;
                    var len = this.selectedTds.length && !ignoreRange,
                        range = this.cellsRange;
                    //末行或者末列没有后置单元格
                    if (
                        (!bottom && cellInfo.rowIndex == 0) ||
                        (bottom &&
                            (!len
                                ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
                                : range.endRowIndex == this.rowsNum - 1))
                    )
                        return null;

                    nextRowIndex = !bottom
                        ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
                        : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
                    nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
                    return this.getCell(
                        this.indexTable[nextRowIndex][nextColIndex].rowIndex,
                        this.indexTable[nextRowIndex][nextColIndex].cellIndex
                    );
                } catch (e) {
                    showError(e);
                }
            },
            /**
             * 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同
             */
            getSameEndPosCells: function (cell, xOrY) {
                try {
                    var flag = xOrY.toLowerCase() === "x",
                        end =
                            domUtils.getXY(cell)[flag ? "x" : "y"] +
                            cell["offset" + (flag ? "Width" : "Height")],
                        rows = this.table.rows,
                        cells = null,
                        returns = [];
                    for (var i = 0; i < this.rowsNum; i++) {
                        cells = rows[i].cells;
                        for (var j = 0, tmpCell; (tmpCell = cells[j++]);) {
                            var tmpEnd =
                                domUtils.getXY(tmpCell)[flag ? "x" : "y"] +
                                tmpCell["offset" + (flag ? "Width" : "Height")];
                            //对应行的td已经被上面行rowSpan了
                            if (tmpEnd > end && flag) break;
                            if (cell == tmpCell || end == tmpEnd) {
                                //只获取单一的单元格
                                //todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能
                                if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) {
                                    returns.push(tmpCell);
                                }
                                if (flag) break;
                            }
                        }
                    }
                    return returns;
                } catch (e) {
                    showError(e);
                }
            },
            setCellContent: function (cell, content) {
                cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "<br />");
            },
            cloneCell: UETable.cloneCell,
            /**
             * 获取跟当前单元格的右边竖线为左边的所有未合并单元格
             */
            getSameStartPosXCells: function (cell) {
                try {
                    var start = domUtils.getXY(cell).x + cell.offsetWidth,
                        rows = this.table.rows,
                        cells,
                        returns = [];
                    for (var i = 0; i < this.rowsNum; i++) {
                        cells = rows[i].cells;
                        for (var j = 0, tmpCell; (tmpCell = cells[j++]);) {
                            var tmpStart = domUtils.getXY(tmpCell).x;
                            if (tmpStart > start) break;
                            if (tmpStart == start && tmpCell.colSpan == 1) {
                                returns.push(tmpCell);
                                break;
                            }
                        }
                    }
                    return returns;
                } catch (e) {
                    showError(e);
                }
            },
            /**
             * 更新table对应的索引表
             */
            update: function (table) {
                this.table = table || this.table;
                this.selectedTds = [];
                this.cellsRange = {};
                this.indexTable = [];
                var rows = this.table.rows,
                    rowsNum = this.getMaxRows(),
                    dNum = rowsNum - rows.length,
                    colsNum = this.getMaxCols();
                while (dNum--) {
                    this.table.insertRow(rows.length);
                }
                this.rowsNum = rowsNum;
                this.colsNum = colsNum;
                for (var i = 0, len = rows.length; i < len; i++) {
                    this.indexTable[i] = new Array(colsNum);
                }
                //填充索引表
                for (var rowIndex = 0, row; (row = rows[rowIndex]); rowIndex++) {
                    for (
                        var cellIndex = 0, cell, cells = row.cells;
                        (cell = cells[cellIndex]);
                        cellIndex++
                    ) {
                        //修正整行被rowSpan时导致的行数计算错误
                        if (cell.rowSpan > rowsNum) {
                            cell.rowSpan = rowsNum;
                        }
                        var colIndex = cellIndex,
                            rowSpan = cell.rowSpan || 1,
                            colSpan = cell.colSpan || 1;
                        //当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行
                        while (this.indexTable[rowIndex][colIndex]) colIndex++;
                        for (var j = 0; j < rowSpan; j++) {
                            for (var k = 0; k < colSpan; k++) {
                                this.indexTable[rowIndex + j][colIndex + k] = {
                                    rowIndex: rowIndex,
                                    cellIndex: cellIndex,
                                    colIndex: colIndex,
                                    rowSpan: rowSpan,
                                    colSpan: colSpan
                                };
                            }
                        }
                    }
                }
                //修复残缺td
                for (j = 0; j < rowsNum; j++) {
                    for (k = 0; k < colsNum; k++) {
                        if (this.indexTable[j][k] === undefined) {
                            row = rows[j];
                            cell = row.cells[row.cells.length - 1];
                            cell = cell
                                ? cell.cloneNode(true)
                                : this.table.ownerDocument.createElement("td");
                            this.setCellContent(cell);
                            if (cell.colSpan !== 1) cell.colSpan = 1;
                            if (cell.rowSpan !== 1) cell.rowSpan = 1;
                            row.appendChild(cell);
                            this.indexTable[j][k] = {
                                rowIndex: j,
                                cellIndex: cell.cellIndex,
                                colIndex: k,
                                rowSpan: 1,
                                colSpan: 1
                            };
                        }
                    }
                }
                //当框选后删除行或者列后撤销,需要重建选区。
                var tds = domUtils.getElementsByTagName(this.table, "td"),
                    selectTds = [];
                utils.each(tds, function (td) {
                    if (domUtils.hasClass(td, "selectTdClass")) {
                        selectTds.push(td);
                    }
                });
                if (selectTds.length) {
                    var start = selectTds[0],
                        end = selectTds[selectTds.length - 1],
                        startInfo = this.getCellInfo(start),
                        endInfo = this.getCellInfo(end);
                    this.selectedTds = selectTds;
                    this.cellsRange = {
                        beginRowIndex: startInfo.rowIndex,
                        beginColIndex: startInfo.colIndex,
                        endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
                        endColIndex: endInfo.colIndex + endInfo.colSpan - 1
                    };
                }
                //给第一行设置firstRow的样式名称,在排序图标的样式上使用到
                if (!domUtils.hasClass(this.table.rows[0], "firstRow")) {
                    domUtils.addClass(this.table.rows[0], "firstRow");
                    for (var i = 1; i < this.table.rows.length; i++) {
                        domUtils.removeClasses(this.table.rows[i], "firstRow");
                    }
                }
            },
            /**
             * 获取单元格的索引信息
             */
            getCellInfo: function (cell) {
                if (!cell) return;
                var cellIndex = cell.cellIndex,
                    rowIndex = cell.parentNode.rowIndex,
                    rowInfo = this.indexTable[rowIndex],
                    numCols = this.colsNum;
                for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
                    var cellInfo = rowInfo[colIndex];
                    if (
                        cellInfo.rowIndex === rowIndex &&
                        cellInfo.cellIndex === cellIndex
                    ) {
                        return cellInfo;
                    }
                }
            },
            /**
             * 根据行列号获取单元格
             */
            getCell: function (rowIndex, cellIndex) {
                return (
                    (rowIndex < this.rowsNum &&
                        this.table.rows[rowIndex].cells[cellIndex]) ||
                    null
                );
            },
            /**
             * 删除单元格
             */
            deleteCell: function (cell, rowIndex) {
                rowIndex = typeof rowIndex == "number"
                    ? rowIndex
                    : cell.parentNode.rowIndex;
                var row = this.table.rows[rowIndex];
                row.deleteCell(cell.cellIndex);
            },
            /**
             * 根据始末两个单元格获取被框选的所有单元格范围
             */
            getCellsRange: function (cellA, cellB) {
                function checkRange(
                    beginRowIndex,
                    beginColIndex,
                    endRowIndex,
                    endColIndex
                ) {
                    var tmpBeginRowIndex = beginRowIndex,
                        tmpBeginColIndex = beginColIndex,
                        tmpEndRowIndex = endRowIndex,
                        tmpEndColIndex = endColIndex,
                        cellInfo,
                        colIndex,
                        rowIndex;
                    // 通过indexTable检查是否存在超出TableRange上边界的情况
                    if (beginRowIndex > 0) {
                        for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
                            cellInfo = me.indexTable[beginRowIndex][colIndex];
                            rowIndex = cellInfo.rowIndex;
                            if (rowIndex < beginRowIndex) {
                                tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex);
                            }
                        }
                    }
                    // 通过indexTable检查是否存在超出TableRange右边界的情况
                    if (endColIndex < me.colsNum) {
                        for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
                            cellInfo = me.indexTable[rowIndex][endColIndex];
                            colIndex = cellInfo.colIndex + cellInfo.colSpan - 1;
                            if (colIndex > endColIndex) {
                                tmpEndColIndex = Math.max(colIndex, tmpEndColIndex);
                            }
                        }
                    }
                    // 检查是否有超出TableRange下边界的情况
                    if (endRowIndex < me.rowsNum) {
                        for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
                            cellInfo = me.indexTable[endRowIndex][colIndex];
                            rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1;
                            if (rowIndex > endRowIndex) {
                                tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex);
                            }
                        }
                    }
                    // 检查是否有超出TableRange左边界的情况
                    if (beginColIndex > 0) {
                        for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
                            cellInfo = me.indexTable[rowIndex][beginColIndex];
                            colIndex = cellInfo.colIndex;
                            if (colIndex < beginColIndex) {
                                tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex);
                            }
                        }
                    }
                    //递归调用直至所有完成所有框选单元格的扩展
                    if (
                        tmpBeginRowIndex != beginRowIndex ||
                        tmpBeginColIndex != beginColIndex ||
                        tmpEndRowIndex != endRowIndex ||
                        tmpEndColIndex != endColIndex
                    ) {
                        return checkRange(
                            tmpBeginRowIndex,
                            tmpBeginColIndex,
                            tmpEndRowIndex,
                            tmpEndColIndex
                        );
                    } else {
                        // 不需要扩展TableRange的情况
                        return {
                            beginRowIndex: beginRowIndex,
                            beginColIndex: beginColIndex,
                            endRowIndex: endRowIndex,
                            endColIndex: endColIndex
                        };
                    }
                }

                try {
                    var me = this,
                        cellAInfo = me.getCellInfo(cellA);
                    if (cellA === cellB) {
                        return {
                            beginRowIndex: cellAInfo.rowIndex,
                            beginColIndex: cellAInfo.colIndex,
                            endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
                            endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1
                        };
                    }
                    var cellBInfo = me.getCellInfo(cellB);
                    // 计算TableRange的四个边
                    var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
                        beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
                        endRowIndex = Math.max(
                            cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
                            cellBInfo.rowIndex + cellBInfo.rowSpan - 1
                        ),
                        endColIndex = Math.max(
                            cellAInfo.colIndex + cellAInfo.colSpan - 1,
                            cellBInfo.colIndex + cellBInfo.colSpan - 1
                        );

                    return checkRange(
                        beginRowIndex,
                        beginColIndex,
                        endRowIndex,
                        endColIndex
                    );
                } catch (e) {
                    //throw e;
                }
            },
            /**
             * 依据cellsRange获取对应的单元格集合
             */
            getCells: function (range) {
                //每次获取cells之前必须先清除上次的选择,否则会对后续获取操作造成影响
                this.clearSelected();
                var beginRowIndex = range.beginRowIndex,
                    beginColIndex = range.beginColIndex,
                    endRowIndex = range.endRowIndex,
                    endColIndex = range.endColIndex,
                    cellInfo,
                    rowIndex,
                    colIndex,
                    tdHash = {},
                    returnTds = [];
                for (var i = beginRowIndex; i <= endRowIndex; i++) {
                    for (var j = beginColIndex; j <= endColIndex; j++) {
                        cellInfo = this.indexTable[i][j];
                        rowIndex = cellInfo.rowIndex;
                        colIndex = cellInfo.colIndex;
                        // 如果Cells里已经包含了此Cell则跳过
                        var key = rowIndex + "|" + colIndex;
                        if (tdHash[key]) continue;
                        tdHash[key] = 1;
                        if (
                            rowIndex < i ||
                            colIndex < j ||
                            rowIndex + cellInfo.rowSpan - 1 > endRowIndex ||
                            colIndex + cellInfo.colSpan - 1 > endColIndex
                        ) {
                            return null;
                        }
                        returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex));
                    }
                }
                return returnTds;
            },
            /**
             * 清理已经选中的单元格
             */
            clearSelected: function () {
                UETable.removeSelectedClass(this.selectedTds);
                this.selectedTds = [];
                this.cellsRange = {};
            },
            /**
             * 根据range设置已经选中的单元格
             */
            setSelected: function (range) {
                var cells = this.getCells(range);
                UETable.addSelectedClass(cells);
                this.selectedTds = cells;
                this.cellsRange = range;
            },
            isFullRow: function () {
                var range = this.cellsRange;
                return range.endColIndex - range.beginColIndex + 1 == this.colsNum;
            },
            isFullCol: function () {
                var range = this.cellsRange,
                    table = this.table,
                    ths = table.getElementsByTagName("th"),
                    rows = range.endRowIndex - range.beginRowIndex + 1;
                return !ths.length
                    ? rows == this.rowsNum
                    : rows == this.rowsNum || rows == this.rowsNum - 1;
            },
            /**
             * 获取视觉上的前置单元格,默认是左边,top传入时
             * @param cell
             * @param top
             */
            getNextCell: function (cell, bottom, ignoreRange) {
                try {
                    var cellInfo = this.getCellInfo(cell),
                        nextRowIndex,
                        nextColIndex;
                    var len = this.selectedTds.length && !ignoreRange,
                        range = this.cellsRange;
                    //末行或者末列没有后置单元格
                    if (
                        (!bottom && cellInfo.rowIndex == 0) ||
                        (bottom &&
                            (!len
                                ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
                                : range.endRowIndex == this.rowsNum - 1))
                    )
                        return null;

                    nextRowIndex = !bottom
                        ? !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1
                        : !len ? cellInfo.rowIndex + cellInfo.rowSpan : range.endRowIndex + 1;
                    nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
                    return this.getCell(
                        this.indexTable[nextRowIndex][nextColIndex].rowIndex,
                        this.indexTable[nextRowIndex][nextColIndex].cellIndex
                    );
                } catch (e) {
                    showError(e);
                }
            },
            getPreviewCell: function (cell, top) {
                try {
                    var cellInfo = this.getCellInfo(cell),
                        previewRowIndex,
                        previewColIndex;
                    var len = this.selectedTds.length,
                        range = this.cellsRange;
                    //首行或者首列没有前置单元格
                    if (
                        (!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
                        (top &&
                            (!len
                                ? cellInfo.rowIndex > this.colsNum - 1
                                : range.endColIndex == this.colsNum - 1))
                    )
                        return null;

                    previewRowIndex = !top
                        ? !len ? cellInfo.rowIndex : range.beginRowIndex
                        : !len
                            ? cellInfo.rowIndex < 1 ? 0 : cellInfo.rowIndex - 1
                            : range.beginRowIndex;
                    previewColIndex = !top
                        ? !len
                            ? cellInfo.colIndex < 1 ? 0 : cellInfo.colIndex - 1
                            : range.beginColIndex - 1
                        : !len ? cellInfo.colIndex : range.endColIndex + 1;
                    return this.getCell(
                        this.indexTable[previewRowIndex][previewColIndex].rowIndex,
                        this.indexTable[previewRowIndex][previewColIndex].cellIndex
                    );
                } catch (e) {
                    showError(e);
                }
            },
            /**
             * 移动单元格中的内容
             */
            moveContent: function (cellTo, cellFrom) {
                if (UETable.isEmptyBlock(cellFrom)) return;
                if (UETable.isEmptyBlock(cellTo)) {
                    cellTo.innerHTML = cellFrom.innerHTML;
                    return;
                }
                var child = cellTo.lastChild;
                if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
                    cellTo.appendChild(cellTo.ownerDocument.createElement("br"));
                }
                while ((child = cellFrom.firstChild)) {
                    cellTo.appendChild(child);
                }
            },
            /**
             * 向右合并单元格
             */
            mergeRight: function (cell) {
                var cellInfo = this.getCellInfo(cell),
                    rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
                    rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
                    rightCell = this.getCell(
                        rightCellInfo.rowIndex,
                        rightCellInfo.cellIndex
                    );
                //合并
                cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan;
                //被合并的单元格不应存在宽度属性
                cell.removeAttribute("width");
                //移动内容
                this.moveContent(cell, rightCell);
                //删掉被合并的Cell
                this.deleteCell(rightCell, rightCellInfo.rowIndex);
                this.update();
            },
            /**
             * 向下合并单元格
             */
            mergeDown: function (cell) {
                var cellInfo = this.getCellInfo(cell),
                    downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
                    downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
                    downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex);
                cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan;
                cell.removeAttribute("height");
                this.moveContent(cell, downCell);
                this.deleteCell(downCell, downCellInfo.rowIndex);
                this.update();
            },
            /**
             * 合并整个range中的内容
             */
            mergeRange: function () {
                //由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问
                var range = this.cellsRange,
                    leftTopCell = this.getCell(
                        range.beginRowIndex,
                        this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex
                    );

                // 这段关于行表头或者列表头的特殊处理会导致表头合并范围错误
                // 为什么有这段代码的原因未明,暂且注释掉,希望原作者看到后出面说明下
                // if (
                //   leftTopCell.tagName == "TH" &&
                //   range.endRowIndex !== range.beginRowIndex
                // ) {
                //   var index = this.indexTable,
                //     info = this.getCellInfo(leftTopCell);
                //   leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex);
                //   range = this.getCellsRange(
                //     leftTopCell,
                //     this.getCell(
                //       index[this.rowsNum - 1][info.colIndex].rowIndex,
                //       index[this.rowsNum - 1][info.colIndex].cellIndex
                //     )
                //   );
                // }

                // 删除剩余的Cells
                var cells = this.getCells(range);
                for (var i = 0, ci; (ci = cells[i++]);) {
                    if (ci !== leftTopCell) {
                        this.moveContent(leftTopCell, ci);
                        this.deleteCell(ci);
                    }
                }
                // 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置
                leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
                leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
                leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
                leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
                if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
                    leftTopCell.colSpan = 1;
                }

                if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
                    var rowIndex = leftTopCell.parentNode.rowIndex;
                    //解决IE下的表格操作问题
                    if (this.table.deleteRow) {
                        for (
                            var i = rowIndex + 1,
                                curIndex = rowIndex + 1,
                                len = leftTopCell.rowSpan;
                            i < len;
                            i++
                        ) {
                            this.table.deleteRow(curIndex);
                        }
                    } else {
                        for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
                            var row = this.table.rows[rowIndex + 1];
                            row.parentNode.removeChild(row);
                        }
                    }
                    leftTopCell.rowSpan = 1;
                }
                this.update();
            },
            /**
             * 插入一行单元格
             */
            insertRow: function (rowIndex, sourceCell) {
                var numCols = this.colsNum,
                    table = this.table,
                    row = table.insertRow(rowIndex),
                    cell,
                    thead = null,
                    isInsertTitle =
                        typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";

                function replaceTdToTh(colIndex, cell, tableRow) {
                    if (colIndex == 0) {
                        var tr = tableRow.nextSibling || tableRow.previousSibling,
                            th = tr.cells[colIndex];
                        if (th.tagName == "TH") {
                            th = cell.ownerDocument.createElement("th");
                            th.appendChild(cell.firstChild);
                            tableRow.insertBefore(th, cell);
                            domUtils.remove(cell);
                        }
                    } else {
                        if (cell.tagName == "TH") {
                            var td = cell.ownerDocument.createElement("td");
                            td.appendChild(cell.firstChild);
                            tableRow.insertBefore(td, cell);
                            domUtils.remove(cell);
                        }
                    }
                }

                //首行直接插入,无需考虑部分单元格被rowspan的情况
                if (rowIndex == 0 || rowIndex == this.rowsNum) {
                    for (var colIndex = 0; colIndex < numCols; colIndex++) {
                        cell = this.cloneCell(sourceCell, true);
                        this.setCellContent(cell);
                        cell.getAttribute("vAlign") &&
                        cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
                        row.appendChild(cell);
                        if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
                    }

                    if (isInsertTitle) {
                        thead = table.createTHead();
                        thead.insertBefore(row, thead.firstChild);
                    }
                } else {
                    var infoRow = this.indexTable[rowIndex],
                        cellIndex = 0;
                    for (colIndex = 0; colIndex < numCols; colIndex++) {
                        var cellInfo = infoRow[colIndex];
                        //如果存在某个单元格的rowspan穿过待插入行的位置,则修改该单元格的rowspan即可,无需插入单元格
                        if (cellInfo.rowIndex < rowIndex) {
                            cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
                            cell.rowSpan = cellInfo.rowSpan + 1;
                        } else {
                            cell = this.cloneCell(sourceCell, true);
                            this.setCellContent(cell);
                            row.appendChild(cell);
                        }
                        if (!isInsertTitle) replaceTdToTh(colIndex, cell, row);
                    }
                }
                //框选时插入不触发contentchange,需要手动更新索引。
                this.update();
                return row;
            },
            /**
             * 删除一行单元格
             * @param rowIndex
             */
            deleteRow: function (rowIndex) {
                var row = this.table.rows[rowIndex],
                    infoRow = this.indexTable[rowIndex],
                    colsNum = this.colsNum,
                    count = 0; //处理计数
                for (var colIndex = 0; colIndex < colsNum;) {
                    var cellInfo = infoRow[colIndex],
                        cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
                    if (cell.rowSpan > 1) {
                        if (cellInfo.rowIndex == rowIndex) {
                            var clone = cell.cloneNode(true);
                            clone.rowSpan = cell.rowSpan - 1;
                            clone.innerHTML = "";
                            cell.rowSpan = 1;
                            var nextRowIndex = rowIndex + 1,
                                nextRow = this.table.rows[nextRowIndex],
                                insertCellIndex,
                                preMerged =
                                    this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count;
                            if (preMerged < colIndex) {
                                insertCellIndex = colIndex - preMerged - 1;
                                //nextRow.insertCell(insertCellIndex);
                                domUtils.insertAfter(nextRow.cells[insertCellIndex], clone);
                            } else {
                                if (nextRow.cells.length)
                                    nextRow.insertBefore(clone, nextRow.cells[0]);
                            }
                            count += 1;
                            //cell.parentNode.removeChild(cell);
                        }
                    }
                    colIndex += cell.colSpan || 1;
                }
                var deleteTds = [],
                    cacheMap = {};
                for (colIndex = 0; colIndex < colsNum; colIndex++) {
                    var tmpRowIndex = infoRow[colIndex].rowIndex,
                        tmpCellIndex = infoRow[colIndex].cellIndex,
                        key = tmpRowIndex + "_" + tmpCellIndex;
                    if (cacheMap[key]) continue;
                    cacheMap[key] = 1;
                    cell = this.getCell(tmpRowIndex, tmpCellIndex);
                    deleteTds.push(cell);
                }
                var mergeTds = [];
                utils.each(deleteTds, function (td) {
                    if (td.rowSpan == 1) {
                        td.parentNode.removeChild(td);
                    } else {
                        mergeTds.push(td);
                    }
                });
                utils.each(mergeTds, function (td) {
                    td.rowSpan--;
                });
                row.parentNode.removeChild(row);
                //浏览器方法本身存在bug,采用自定义方法删除
                //this.table.deleteRow(rowIndex);
                this.update();
            },
            insertCol: function (colIndex, sourceCell, defaultValue) {
                var rowsNum = this.rowsNum,
                    rowIndex = 0,
                    tableRow,
                    cell,
                    backWidth = parseInt(
                        (this.table.offsetWidth -
                            (this.colsNum + 1) * 20 -
                            (this.colsNum + 1)) /
                        (this.colsNum + 1),
                        10
                    ),
                    isInsertTitleCol =
                        typeof sourceCell == "string" && sourceCell.toUpperCase() == "TH";

                function replaceTdToTh(rowIndex, cell, tableRow) {
                    if (rowIndex == 0) {
                        var th = cell.nextSibling || cell.previousSibling;
                        if (th.tagName == "TH") {
                            th = cell.ownerDocument.createElement("th");
                            th.appendChild(cell.firstChild);
                            tableRow.insertBefore(th, cell);
                            domUtils.remove(cell);
                        }
                    } else {
                        if (cell.tagName == "TH") {
                            var td = cell.ownerDocument.createElement("td");
                            td.appendChild(cell.firstChild);
                            tableRow.insertBefore(td, cell);
                            domUtils.remove(cell);
                        }
                    }
                }

                var preCell;
                if (colIndex == 0 || colIndex == this.colsNum) {
                    for (; rowIndex < rowsNum; rowIndex++) {
                        tableRow = this.table.rows[rowIndex];
                        preCell =
                            tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length];
                        cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
                        this.setCellContent(cell);
                        cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
                        preCell && cell.setAttribute("width", preCell.getAttribute("width"));
                        if (!colIndex) {
                            tableRow.insertBefore(cell, tableRow.cells[0]);
                        } else {
                            domUtils.insertAfter(
                                tableRow.cells[tableRow.cells.length - 1],
                                cell
                            );
                        }
                        if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
                    }
                } else {
                    for (; rowIndex < rowsNum; rowIndex++) {
                        var cellInfo = this.indexTable[rowIndex][colIndex];
                        if (cellInfo.colIndex < colIndex) {
                            cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
                            cell.colSpan = cellInfo.colSpan + 1;
                        } else {
                            tableRow = this.table.rows[rowIndex];
                            preCell = tableRow.cells[cellInfo.cellIndex];

                            cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(cellInfo.cellIndex);
                            this.setCellContent(cell);
                            cell.setAttribute("vAlign", cell.getAttribute("vAlign"));
                            preCell &&
                            cell.setAttribute("width", preCell.getAttribute("width"));
                            //防止IE下报错
                            preCell
                                ? tableRow.insertBefore(cell, preCell)
                                : tableRow.appendChild(cell);
                        }
                        if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
                    }
                }
                //框选时插入不触发contentchange,需要手动更新索引
                this.update();
                this.updateWidth(
                    backWidth,
                    defaultValue || {tdPadding: 10, tdBorder: 1}
                );
            },
            updateWidth: function (width, defaultValue) {
                var table = this.table,
                    tmpWidth =
                        UETable.getWidth(table) -
                        defaultValue.tdPadding * 2 -
                        defaultValue.tdBorder +
                        width;
                if (tmpWidth < table.ownerDocument.body.offsetWidth) {
                    table.setAttribute("width", tmpWidth);
                    return;
                }
                var tds = domUtils.getElementsByTagName(this.table, "td th");
                utils.each(tds, function (td) {
                    td.setAttribute("width", width);
                });
            },
            deleteCol: function (colIndex) {
                var indexTable = this.indexTable,
                    tableRows = this.table.rows,
                    backTableWidth = this.table.getAttribute("width"),
                    backTdWidth = 0,
                    rowsNum = this.rowsNum,
                    cacheMap = {};
                for (var rowIndex = 0; rowIndex < rowsNum;) {
                    var infoRow = indexTable[rowIndex],
                        cellInfo = infoRow[colIndex],
                        key = cellInfo.rowIndex + "_" + cellInfo.colIndex;
                    // 跳过已经处理过的Cell
                    if (cacheMap[key]) continue;
                    cacheMap[key] = 1;
                    var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
                    if (!backTdWidth)
                        backTdWidth =
                            cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0);
                    // 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
                    if (cell.colSpan > 1) {
                        cell.colSpan--;
                    } else {
                        tableRows[rowIndex].deleteCell(cellInfo.cellIndex);
                    }
                    rowIndex += cellInfo.rowSpan || 1;
                }
                this.table.setAttribute("width", backTableWidth - backTdWidth);
                this.update();
            },
            splitToCells: function (cell) {
                var me = this,
                    cells = this.splitToRows(cell);
                utils.each(cells, function (cell) {
                    me.splitToCols(cell);
                });
            },
            splitToRows: function (cell) {
                var cellInfo = this.getCellInfo(cell),
                    rowIndex = cellInfo.rowIndex,
                    colIndex = cellInfo.colIndex,
                    results = [];
                // 修改Cell的rowSpan
                cell.rowSpan = 1;
                results.push(cell);
                // 补齐单元格
                for (
                    var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan;
                    i < endRow;
                    i++
                ) {
                    if (i == rowIndex) continue;
                    var tableRow = this.table.rows[i],
                        tmpCell = tableRow.insertCell(
                            colIndex - this.getPreviewMergedCellsNum(i, colIndex)
                        );
                    tmpCell.colSpan = cellInfo.colSpan;
                    this.setCellContent(tmpCell);
                    tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
                    tmpCell.setAttribute("align", cell.getAttribute("align"));
                    if (cell.style.cssText) {
                        tmpCell.style.cssText = cell.style.cssText;
                    }
                    results.push(tmpCell);
                }
                this.update();
                return results;
            },
            getPreviewMergedCellsNum: function (rowIndex, colIndex) {
                var indexRow = this.indexTable[rowIndex],
                    num = 0;
                for (var i = 0; i < colIndex;) {
                    var colSpan = indexRow[i].colSpan,
                        tmpRowIndex = indexRow[i].rowIndex;
                    num += colSpan - (tmpRowIndex == rowIndex ? 1 : 0);
                    i += colSpan;
                }
                return num;
            },
            splitToCols: function (cell) {
                var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
                    cellInfo = this.getCellInfo(cell),
                    rowIndex = cellInfo.rowIndex,
                    colIndex = cellInfo.colIndex,
                    results = [];
                // 修改Cell的rowSpan
                cell.colSpan = 1;
                cell.setAttribute("width", backWidth);
                results.push(cell);
                // 补齐单元格
                for (
                    var j = colIndex, endCol = colIndex + cellInfo.colSpan;
                    j < endCol;
                    j++
                ) {
                    if (j == colIndex) continue;
                    var tableRow = this.table.rows[rowIndex],
                        tmpCell = tableRow.insertCell(
                            this.indexTable[rowIndex][j].cellIndex + 1
                        );
                    tmpCell.rowSpan = cellInfo.rowSpan;
                    this.setCellContent(tmpCell);
                    tmpCell.setAttribute("vAlign", cell.getAttribute("vAlign"));
                    tmpCell.setAttribute("align", cell.getAttribute("align"));
                    tmpCell.setAttribute("width", backWidth);
                    if (cell.style.cssText) {
                        tmpCell.style.cssText = cell.style.cssText;
                    }
                    //处理th的情况
                    if (cell.tagName == "TH") {
                        var th = cell.ownerDocument.createElement("th");
                        th.appendChild(tmpCell.firstChild);
                        th.setAttribute("vAlign", cell.getAttribute("vAlign"));
                        th.rowSpan = tmpCell.rowSpan;
                        tableRow.insertBefore(th, tmpCell);
                        domUtils.remove(tmpCell);
                    }
                    results.push(tmpCell);
                }
                this.update();
                return results;
            },
            isLastCell: function (cell, rowsNum, colsNum) {
                rowsNum = rowsNum || this.rowsNum;
                colsNum = colsNum || this.colsNum;
                var cellInfo = this.getCellInfo(cell);
                return (
                    cellInfo.rowIndex + cellInfo.rowSpan == rowsNum &&
                    cellInfo.colIndex + cellInfo.colSpan == colsNum
                );
            },
            getLastCell: function (cells) {
                cells = cells || this.table.getElementsByTagName("td");
                var firstInfo = this.getCellInfo(cells[0]);
                var me = this,
                    last = cells[0],
                    tr = last.parentNode,
                    cellsNum = 0,
                    cols = 0,
                    rows;
                utils.each(cells, function (cell) {
                    if (cell.parentNode == tr) cols += cell.colSpan || 1;
                    cellsNum += cell.rowSpan * cell.colSpan || 1;
                });
                rows = cellsNum / cols;
                utils.each(cells, function (cell) {
                    if (me.isLastCell(cell, rows, cols)) {
                        last = cell;
                        return false;
                    }
                });
                return last;
            },
            selectRow: function (rowIndex) {
                var indexRow = this.indexTable[rowIndex],
                    start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
                    end = this.getCell(
                        indexRow[this.colsNum - 1].rowIndex,
                        indexRow[this.colsNum - 1].cellIndex
                    ),
                    range = this.getCellsRange(start, end);
                this.setSelected(range);
            },
            selectTable: function () {
                var tds = this.table.getElementsByTagName("td"),
                    range = this.getCellsRange(tds[0], tds[tds.length - 1]);
                this.setSelected(range);
            },
            setBackground: function (cells, value) {
                if (typeof value === "string") {
                    utils.each(cells, function (cell) {
                        cell.style.backgroundColor = value;
                    });
                } else if (typeof value === "object") {
                    value = utils.extend(
                        {
                            repeat: true,
                            colorList: ["#ddd", "#fff"]
                        },
                        value
                    );
                    var rowIndex = this.getCellInfo(cells[0]).rowIndex,
                        count = 0,
                        colors = value.colorList,
                        getColor = function (list, index, repeat) {
                            return list[index]
                                ? list[index]
                                : repeat ? list[index % list.length] : "";
                        };
                    for (var i = 0, cell; (cell = cells[i++]);) {
                        var cellInfo = this.getCellInfo(cell);
                        cell.style.backgroundColor = getColor(
                            colors,
                            rowIndex + count == cellInfo.rowIndex ? count : ++count,
                            value.repeat
                        );
                    }
                }
            },
            removeBackground: function (cells) {
                utils.each(cells, function (cell) {
                    cell.style.backgroundColor = "";
                });
            }
        };

        function showError(e) {
        }
    })();


// plugins/table.cmds.js
    /**
     * Created with JetBrains PhpStorm.
     * User: taoqili
     * Date: 13-2-20
     * Time: 下午6:25
     * To change this template use File | Settings | File Templates.
     */
    ;(function () {
        var UT = UE.UETable,
            getTableItemsByRange = function (editor) {
                return UT.getTableItemsByRange(editor);
            },
            getUETableBySelected = function (editor) {
                return UT.getUETableBySelected(editor);
            },
            getDefaultValue = function (editor, table) {
                return UT.getDefaultValue(editor, table);
            },
            getUETable = function (tdOrTable) {
                return UT.getUETable(tdOrTable);
            };

        UE.commands["inserttable"] = {
            queryCommandState: function () {
                return getTableItemsByRange(this).table ? -1 : 0;
            },
            execCommand: function (cmd, opt) {
                function createTable(opt, tdWidth) {
                    var html = [],
                        rowsNum = opt.numRows,
                        colsNum = opt.numCols;
                    for (var r = 0; r < rowsNum; r++) {
                        html.push("<tr" + (r == 0 ? ' class="firstRow"' : "") + ">");
                        for (var c = 0; c < colsNum; c++) {
                            html.push(
                                '<td style="border:1px solid windowtext;" width="' +
                                tdWidth +
                                '"  vAlign="' +
                                opt.tdvalign +
                                '" >' +
                                (browser.ie && browser.version < 11
                                    ? domUtils.fillChar
                                    : "<br/>") +
                                "</td>"
                            );
                        }
                        html.push("</tr>");
                    }
                    //禁止指定table-width
                    return "<table style=\"border-collapse:collapse;\" ><tbody>" + html.join("") + "</tbody></table>";
                }

                if (!opt) {
                    opt = utils.extend(
                        {},
                        {
                            numCols: this.options.defaultCols,
                            numRows: this.options.defaultRows,
                            tdvalign: this.options.tdvalign
                        }
                    );
                }
                var me = this;
                var range = this.selection.getRange(),
                    start = range.startContainer,
                    firstParentBlock =
                        domUtils.findParent(
                            start,
                            function (node) {
                                return domUtils.isBlockElm(node);
                            },
                            true
                        ) || me.body;

                var defaultValue = getDefaultValue(me),
                    tableWidth = firstParentBlock.offsetWidth,
                    tdWidth = Math.floor(
                        tableWidth / opt.numCols -
                        defaultValue.tdPadding * 2 -
                        defaultValue.tdBorder
                    );

                //todo其他属性
                !opt.tdvalign && (opt.tdvalign = me.options.tdvalign);
                me.execCommand("inserthtml", createTable(opt, tdWidth));
            }
        };

        UE.commands["insertparagraphbeforetable"] = {
            queryCommandState: function () {
                return getTableItemsByRange(this).cell ? 0 : -1;
            },
            execCommand: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    var p = this.document.createElement("p");
                    p.innerHTML = browser.ie ? "&nbsp;" : "<br />";
                    table.parentNode.insertBefore(p, table);
                    this.selection.getRange().setStart(p, 0).setCursor();
                }
            }
        };

        UE.commands["deletetable"] = {
            queryCommandState: function () {
                var rng = this.selection.getRange();
                return domUtils.findParentByTagName(rng.startContainer, "table", true)
                    ? 0
                    : -1;
            },
            execCommand: function (cmd, table) {
                var rng = this.selection.getRange();
                table =
                    table ||
                    domUtils.findParentByTagName(rng.startContainer, "table", true);
                if (table) {
                    var next = table.nextSibling;
                    if (!next) {
                        next = domUtils.createElement(this.document, "p", {
                            innerHTML: browser.ie ? domUtils.fillChar : "<br/>"
                        });
                        table.parentNode.insertBefore(next, table);
                    }
                    domUtils.remove(table);
                    rng = this.selection.getRange();
                    if (next.nodeType == 3) {
                        rng.setStartBefore(next);
                    } else {
                        rng.setStart(next, 0);
                    }
                    rng.setCursor(false, true);
                    this.fireEvent("tablehasdeleted");
                }
            }
        };
        UE.commands["cellalign"] = {
            queryCommandState: function () {
                return getSelectedArr(this).length ? 0 : -1;
            },
            execCommand: function (cmd, align) {
                var selectedTds = getSelectedArr(this);
                if (selectedTds.length) {
                    for (var i = 0, ci; (ci = selectedTds[i++]);) {
                        ci.setAttribute("align", align);
                    }
                }
            }
        };
        UE.commands["cellvalign"] = {
            queryCommandState: function () {
                return getSelectedArr(this).length ? 0 : -1;
            },
            execCommand: function (cmd, valign) {
                var selectedTds = getSelectedArr(this);
                if (selectedTds.length) {
                    for (var i = 0, ci; (ci = selectedTds[i++]);) {
                        ci.setAttribute("vAlign", valign);
                    }
                }
            }
        };
        UE.commands["insertcaption"] = {
            queryCommandState: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    return table.getElementsByTagName("caption").length == 0 ? 1 : -1;
                }
                return -1;
            },
            execCommand: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    var caption = this.document.createElement("caption");
                    caption.innerHTML = browser.ie ? domUtils.fillChar : "<br/>";
                    table.insertBefore(caption, table.firstChild);
                    var range = this.selection.getRange();
                    range.setStart(caption, 0).setCursor();
                }
            }
        };
        UE.commands["deletecaption"] = {
            queryCommandState: function () {
                var rng = this.selection.getRange(),
                    table = domUtils.findParentByTagName(rng.startContainer, "table");
                if (table) {
                    return table.getElementsByTagName("caption").length == 0 ? -1 : 1;
                }
                return -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    table = domUtils.findParentByTagName(rng.startContainer, "table");
                if (table) {
                    domUtils.remove(table.getElementsByTagName("caption")[0]);
                    var range = this.selection.getRange();
                    range.setStart(table.rows[0].cells[0], 0).setCursor();
                }
            }
        };
        UE.commands["inserttitle"] = {
            queryCommandState: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    var firstRow = table.rows[0];
                    return firstRow.cells[
                    firstRow.cells.length - 1
                        ].tagName.toLowerCase() != "th"
                        ? 0
                        : -1;
                }
                return -1;
            },
            execCommand: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    getUETable(table).insertRow(0, "th");
                }
                var th = table.getElementsByTagName("th")[0];
                this.selection.getRange().setStart(th, 0).setCursor(false, true);
            }
        };
        UE.commands["deletetitle"] = {
            queryCommandState: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    var firstRow = table.rows[0];
                    return firstRow.cells[
                    firstRow.cells.length - 1
                        ].tagName.toLowerCase() == "th"
                        ? 0
                        : -1;
                }
                return -1;
            },
            execCommand: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    domUtils.remove(table.rows[0]);
                }
                var td = table.getElementsByTagName("td")[0];
                this.selection.getRange().setStart(td, 0).setCursor(false, true);
            }
        };
        UE.commands["inserttitlecol"] = {
            queryCommandState: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    var lastRow = table.rows[table.rows.length - 1];
                    return lastRow.getElementsByTagName("th").length ? -1 : 0;
                }
                return -1;
            },
            execCommand: function (cmd) {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    getUETable(table).insertCol(0, "th");
                }
                resetTdWidth(table, this);
                var th = table.getElementsByTagName("th")[0];
                this.selection.getRange().setStart(th, 0).setCursor(false, true);
            }
        };
        UE.commands["deletetitlecol"] = {
            queryCommandState: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    var lastRow = table.rows[table.rows.length - 1];
                    return lastRow.getElementsByTagName("th").length ? 0 : -1;
                }
                return -1;
            },
            execCommand: function () {
                var table = getTableItemsByRange(this).table;
                if (table) {
                    for (var i = 0; i < table.rows.length; i++) {
                        domUtils.remove(table.rows[i].children[0]);
                    }
                }
                resetTdWidth(table, this);
                var td = table.getElementsByTagName("td")[0];
                this.selection.getRange().setStart(td, 0).setCursor(false, true);
            }
        };

        UE.commands["mergeright"] = {
            queryCommandState: function (cmd) {
                var tableItems = getTableItemsByRange(this),
                    table = tableItems.table,
                    cell = tableItems.cell;

                if (!table || !cell) return -1;
                var ut = getUETable(table);
                if (ut.selectedTds.length) return -1;

                var cellInfo = ut.getCellInfo(cell),
                    rightColIndex = cellInfo.colIndex + cellInfo.colSpan;
                if (rightColIndex >= ut.colsNum) return -1; // 如果处于最右边则不能向右合并

                var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
                    rightCell =
                        table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex];
                if (!rightCell || cell.tagName != rightCell.tagName) return -1; // TH和TD不能相互合并

                // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
                return rightCellInfo.rowIndex == cellInfo.rowIndex &&
                rightCellInfo.rowSpan == cellInfo.rowSpan
                    ? 0
                    : -1;
            },
            execCommand: function (cmd) {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell);
                ut.mergeRight(cell);
                rng.moveToBookmark(bk).select();
            }
        };
        UE.commands["mergedown"] = {
            queryCommandState: function (cmd) {
                var tableItems = getTableItemsByRange(this),
                    table = tableItems.table,
                    cell = tableItems.cell;

                if (!table || !cell) return -1;
                var ut = getUETable(table);
                if (ut.selectedTds.length) return -1;

                var cellInfo = ut.getCellInfo(cell),
                    downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan;
                if (downRowIndex >= ut.rowsNum) return -1; // 如果处于最下边则不能向下合并

                var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
                    downCell =
                        table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex];
                if (!downCell || cell.tagName != downCell.tagName) return -1; // TH和TD不能相互合并

                // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
                return downCellInfo.colIndex == cellInfo.colIndex &&
                downCellInfo.colSpan == cellInfo.colSpan
                    ? 0
                    : -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell);
                ut.mergeDown(cell);
                rng.moveToBookmark(bk).select();
            }
        };
        UE.commands["mergecells"] = {
            queryCommandState: function () {
                return getUETableBySelected(this) ? 0 : -1;
            },
            execCommand: function () {
                var ut = getUETableBySelected(this);
                if (ut && ut.selectedTds.length) {
                    var cell = ut.selectedTds[0];
                    ut.mergeRange();
                    var rng = this.selection.getRange();
                    if (domUtils.isEmptyBlock(cell)) {
                        rng.setStart(cell, 0).collapse(true);
                    } else {
                        rng.selectNodeContents(cell);
                    }
                    rng.select();
                }
            }
        };
        UE.commands["insertrow"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell;
                return cell &&
                (cell.tagName == "TD" ||
                    (cell.tagName == "TH" &&
                        tableItems.tr !== tableItems.table.rows[0])) &&
                getUETable(tableItems.table).rowsNum < this.options.maxRowNum
                    ? 0
                    : -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell,
                    table = tableItems.table,
                    ut = getUETable(table),
                    cellInfo = ut.getCellInfo(cell);
                //ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
                if (!ut.selectedTds.length) {
                    ut.insertRow(cellInfo.rowIndex, cell);
                } else {
                    var range = ut.cellsRange;
                    for (
                        var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
                        i < len;
                        i++
                    ) {
                        ut.insertRow(range.beginRowIndex, cell);
                    }
                }
                rng.moveToBookmark(bk).select();
                if (table.getAttribute("interlaced") === "enabled")
                    this.fireEvent("interlacetable", table);
            }
        };
        //后插入行
        UE.commands["insertrownext"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell;
                return cell &&
                cell.tagName == "TD" &&
                getUETable(tableItems.table).rowsNum < this.options.maxRowNum
                    ? 0
                    : -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell,
                    table = tableItems.table,
                    ut = getUETable(table),
                    cellInfo = ut.getCellInfo(cell);
                //ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
                if (!ut.selectedTds.length) {
                    ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell);
                } else {
                    var range = ut.cellsRange;
                    for (
                        var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
                        i < len;
                        i++
                    ) {
                        ut.insertRow(range.endRowIndex + 1, cell);
                    }
                }
                rng.moveToBookmark(bk).select();
                if (table.getAttribute("interlaced") === "enabled")
                    this.fireEvent("interlacetable", table);
            }
        };
        UE.commands["deleterow"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this);
                return tableItems.cell ? 0 : -1;
            },
            execCommand: function () {
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell),
                    cellsRange = ut.cellsRange,
                    cellInfo = ut.getCellInfo(cell),
                    preCell = ut.getVSideCell(cell),
                    nextCell = ut.getVSideCell(cell, true),
                    rng = this.selection.getRange();
                if (utils.isEmptyObject(cellsRange)) {
                    ut.deleteRow(cellInfo.rowIndex);
                } else {
                    for (
                        var i = cellsRange.beginRowIndex;
                        i < cellsRange.endRowIndex + 1;
                        i++
                    ) {
                        ut.deleteRow(cellsRange.beginRowIndex);
                    }
                }
                var table = ut.table;
                if (!table.getElementsByTagName("td").length) {
                    var nextSibling = table.nextSibling;
                    domUtils.remove(table);
                    if (nextSibling) {
                        rng.setStart(nextSibling, 0).setCursor(false, true);
                    }
                } else {
                    if (
                        cellInfo.rowSpan == 1 ||
                        cellInfo.rowSpan ==
                        cellsRange.endRowIndex - cellsRange.beginRowIndex + 1
                    ) {
                        if (nextCell || preCell)
                            rng.selectNodeContents(nextCell || preCell).setCursor(false, true);
                    } else {
                        var newCell = ut.getCell(
                            cellInfo.rowIndex,
                            ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex
                        );
                        if (newCell) rng.selectNodeContents(newCell).setCursor(false, true);
                    }
                }
                if (table.getAttribute("interlaced") === "enabled")
                    this.fireEvent("interlacetable", table);
            }
        };
        UE.commands["insertcol"] = {
            queryCommandState: function (cmd) {
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell;
                return cell &&
                (cell.tagName == "TD" ||
                    (cell.tagName == "TH" && cell !== tableItems.tr.cells[0])) &&
                getUETable(tableItems.table).colsNum < this.options.maxColNum
                    ? 0
                    : -1;
            },
            execCommand: function (cmd) {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                if (this.queryCommandState(cmd) == -1) return;
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell),
                    cellInfo = ut.getCellInfo(cell);

                //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
                if (!ut.selectedTds.length) {
                    ut.insertCol(cellInfo.colIndex, cell);
                } else {
                    var range = ut.cellsRange;
                    for (
                        var i = 0, len = range.endColIndex - range.beginColIndex + 1;
                        i < len;
                        i++
                    ) {
                        ut.insertCol(range.beginColIndex, cell);
                    }
                }
                rng.moveToBookmark(bk).select(true);
            }
        };
        UE.commands["insertcolnext"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell;
                return cell &&
                getUETable(tableItems.table).colsNum < this.options.maxColNum
                    ? 0
                    : -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell),
                    cellInfo = ut.getCellInfo(cell);
                //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
                if (!ut.selectedTds.length) {
                    ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell);
                } else {
                    var range = ut.cellsRange;
                    for (
                        var i = 0, len = range.endColIndex - range.beginColIndex + 1;
                        i < len;
                        i++
                    ) {
                        ut.insertCol(range.endColIndex + 1, cell);
                    }
                }
                rng.moveToBookmark(bk).select();
            }
        };

        UE.commands["deletecol"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this);
                return tableItems.cell ? 0 : -1;
            },
            execCommand: function () {
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell),
                    range = ut.cellsRange,
                    cellInfo = ut.getCellInfo(cell),
                    preCell = ut.getHSideCell(cell),
                    nextCell = ut.getHSideCell(cell, true);
                if (utils.isEmptyObject(range)) {
                    ut.deleteCol(cellInfo.colIndex);
                } else {
                    for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
                        ut.deleteCol(range.beginColIndex);
                    }
                }
                var table = ut.table,
                    rng = this.selection.getRange();

                if (!table.getElementsByTagName("td").length) {
                    var nextSibling = table.nextSibling;
                    domUtils.remove(table);
                    if (nextSibling) {
                        rng.setStart(nextSibling, 0).setCursor(false, true);
                    }
                } else {
                    if (domUtils.inDoc(cell, this.document)) {
                        rng.setStart(cell, 0).setCursor(false, true);
                    } else {
                        if (nextCell && domUtils.inDoc(nextCell, this.document)) {
                            rng.selectNodeContents(nextCell).setCursor(false, true);
                        } else {
                            if (preCell && domUtils.inDoc(preCell, this.document)) {
                                rng.selectNodeContents(preCell).setCursor(true, true);
                            }
                        }
                    }
                }
            }
        };
        UE.commands["splittocells"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell;
                if (!cell) return -1;
                var ut = getUETable(tableItems.table);
                if (ut.selectedTds.length > 0) return -1;
                return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell);
                ut.splitToCells(cell);
                rng.moveToBookmark(bk).select();
            }
        };
        UE.commands["splittorows"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell;
                if (!cell) return -1;
                var ut = getUETable(tableItems.table);
                if (ut.selectedTds.length > 0) return -1;
                return cell && cell.rowSpan > 1 ? 0 : -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell);
                ut.splitToRows(cell);
                rng.moveToBookmark(bk).select();
            }
        };
        UE.commands["splittocols"] = {
            queryCommandState: function () {
                var tableItems = getTableItemsByRange(this),
                    cell = tableItems.cell;
                if (!cell) return -1;
                var ut = getUETable(tableItems.table);
                if (ut.selectedTds.length > 0) return -1;
                return cell && cell.colSpan > 1 ? 0 : -1;
            },
            execCommand: function () {
                var rng = this.selection.getRange(),
                    bk = rng.createBookmark(true);
                var cell = getTableItemsByRange(this).cell,
                    ut = getUETable(cell);
                ut.splitToCols(cell);
                rng.moveToBookmark(bk).select();
            }
        };

        UE.commands["adaptbytext"] = UE.commands["adaptbywindow"] = {
            queryCommandState: function () {
                return getTableItemsByRange(this).table ? 0 : -1;
            },
            execCommand: function (cmd) {
                var tableItems = getTableItemsByRange(this),
                    table = tableItems.table;
                if (table) {
                    if (cmd == "adaptbywindow") {
                        resetTdWidth(table, this);
                    } else {
                        var cells = domUtils.getElementsByTagName(table, "td th");
                        utils.each(cells, function (cell) {
                            cell.removeAttribute("width");
                        });
                        table.removeAttribute("width");
                    }
                }
            }
        };

        //平均分配各列
        UE.commands["averagedistributecol"] = {
            queryCommandState: function () {
                var ut = getUETableBySelected(this);
                if (!ut) return -1;
                return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
            },
            execCommand: function (cmd) {
                var me = this,
                    ut = getUETableBySelected(me);

                function getAverageWidth() {
                    var tb = ut.table,
                        averageWidth,
                        sumWidth = 0,
                        colsNum = 0,
                        tbAttr = getDefaultValue(me, tb);

                    if (ut.isFullRow()) {
                        sumWidth = tb.offsetWidth;
                        colsNum = ut.colsNum;
                    } else {
                        var begin = ut.cellsRange.beginColIndex,
                            end = ut.cellsRange.endColIndex,
                            node;
                        for (var i = begin; i <= end;) {
                            node = ut.selectedTds[i];
                            sumWidth += node.offsetWidth;
                            i += node.colSpan;
                            colsNum += 1;
                        }
                    }
                    averageWidth =
                        Math.ceil(sumWidth / colsNum) -
                        tbAttr.tdBorder * 2 -
                        tbAttr.tdPadding * 2;
                    return averageWidth;
                }

                function setAverageWidth(averageWidth) {
                    utils.each(domUtils.getElementsByTagName(ut.table, "th"), function (
                        node
                    ) {
                        node.setAttribute("width", "");
                    });
                    var cells = ut.isFullRow()
                        ? domUtils.getElementsByTagName(ut.table, "td")
                        : ut.selectedTds;

                    utils.each(cells, function (node) {
                        if (node.colSpan == 1) {
                            node.setAttribute("width", averageWidth);
                        }
                    });
                }

                if (ut && ut.selectedTds.length) {
                    setAverageWidth(getAverageWidth());
                }
            }
        };
        //平均分配各行
        UE.commands["averagedistributerow"] = {
            queryCommandState: function () {
                var ut = getUETableBySelected(this);
                if (!ut) return -1;
                if (ut.selectedTds && /th/gi.test(ut.selectedTds[0].tagName)) return -1;
                return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
            },
            execCommand: function (cmd) {
                var me = this,
                    ut = getUETableBySelected(me);

                function getAverageHeight() {
                    var averageHeight,
                        rowNum,
                        sumHeight = 0,
                        tb = ut.table,
                        tbAttr = getDefaultValue(me, tb),
                        tdpadding = parseInt(
                            domUtils.getComputedStyle(
                                tb.getElementsByTagName("td")[0],
                                "padding-top"
                            )
                        );

                    if (ut.isFullCol()) {
                        var captionArr = domUtils.getElementsByTagName(tb, "caption"),
                            thArr = domUtils.getElementsByTagName(tb, "th"),
                            captionHeight,
                            thHeight;

                        if (captionArr.length > 0) {
                            captionHeight = captionArr[0].offsetHeight;
                        }
                        if (thArr.length > 0) {
                            thHeight = thArr[0].offsetHeight;
                        }

                        sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0);
                        rowNum = thArr.length == 0 ? ut.rowsNum : ut.rowsNum - 1;
                    } else {
                        var begin = ut.cellsRange.beginRowIndex,
                            end = ut.cellsRange.endRowIndex,
                            count = 0,
                            trs = domUtils.getElementsByTagName(tb, "tr");
                        for (var i = begin; i <= end; i++) {
                            sumHeight += trs[i].offsetHeight;
                            count += 1;
                        }
                        rowNum = count;
                    }
                    //ie8下是混杂模式
                    if (browser.ie && browser.version < 9) {
                        averageHeight = Math.ceil(sumHeight / rowNum);
                    } else {
                        averageHeight =
                            Math.ceil(sumHeight / rowNum) - tbAttr.tdBorder * 2 - tdpadding * 2;
                    }
                    return averageHeight;
                }

                function setAverageHeight(averageHeight) {
                    var cells = ut.isFullCol()
                        ? domUtils.getElementsByTagName(ut.table, "td")
                        : ut.selectedTds;
                    utils.each(cells, function (node) {
                        if (node.rowSpan == 1) {
                            node.setAttribute("height", averageHeight);
                        }
                    });
                }

                if (ut && ut.selectedTds.length) {
                    setAverageHeight(getAverageHeight());
                }
            }
        };

        //单元格对齐方式
        UE.commands["cellalignment"] = {
            queryCommandState: function () {
                return getTableItemsByRange(this).table ? 0 : -1;
            },
            execCommand: function (cmd, data) {
                var me = this,
                    ut = getUETableBySelected(me);

                if (!ut) {
                    var start = me.selection.getStart(),
                        cell =
                            start &&
                            domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
                    if (!/caption/gi.test(cell.tagName)) {
                        domUtils.setAttributes(cell, data);
                    } else {
                        cell.style.textAlign = data.align;
                        cell.style.verticalAlign = data.vAlign;
                    }
                    me.selection.getRange().setCursor(true);
                } else {
                    utils.each(ut.selectedTds, function (cell) {
                        domUtils.setAttributes(cell, data);
                    });
                }
            },
            /**
             * 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态
             * @see UE.UETable.getTableCellAlignState
             */
            queryCommandValue: function (cmd) {
                var activeMenuCell = getTableItemsByRange(this).cell;

                if (!activeMenuCell) {
                    activeMenuCell = getSelectedArr(this)[0];
                }

                if (!activeMenuCell) {
                    return null;
                } else {
                    //获取同时选中的其他单元格
                    var cells = UE.UETable.getUETable(activeMenuCell).selectedTds;

                    !cells.length && (cells = activeMenuCell);

                    return UE.UETable.getTableCellAlignState(cells);
                }
            }
        };
        //表格对齐方式
        UE.commands["tablealignment"] = {
            queryCommandState: function () {
                if (browser.ie && browser.version < 8) {
                    return -1;
                }
                return getTableItemsByRange(this).table ? 0 : -1;
            },
            execCommand: function (cmd, value) {
                var me = this,
                    start = me.selection.getStart(),
                    table = start && domUtils.findParentByTagName(start, ["table"], true);

                if (table) {
                    table.setAttribute("align", value);
                }
            }
        };

        //表格属性
        UE.commands["edittable"] = {
            queryCommandState: function () {
                return getTableItemsByRange(this).table ? 0 : -1;
            },
            execCommand: function (cmd, color) {
                var rng = this.selection.getRange(),
                    table = domUtils.findParentByTagName(rng.startContainer, "table");
                if (table) {
                    var arr = domUtils
                        .getElementsByTagName(table, "td")
                        .concat(
                            domUtils.getElementsByTagName(table, "th"),
                            domUtils.getElementsByTagName(table, "caption")
                        );
                    utils.each(arr, function (node) {
                        node.style.borderColor = color;
                    });
                }
            }
        };
        //单元格属性
        UE.commands["edittd"] = {
            queryCommandState: function () {
                return getTableItemsByRange(this).table ? 0 : -1;
            },
            execCommand: function (cmd, bkColor) {
                var me = this,
                    ut = getUETableBySelected(me);

                if (!ut) {
                    var start = me.selection.getStart(),
                        cell =
                            start &&
                            domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
                    if (cell) {
                        cell.style.backgroundColor = bkColor;
                    }
                } else {
                    utils.each(ut.selectedTds, function (cell) {
                        cell.style.backgroundColor = bkColor;
                    });
                }
            }
        };

        UE.commands["settablebackground"] = {
            queryCommandState: function () {
                return getSelectedArr(this).length > 1 ? 0 : -1;
            },
            execCommand: function (cmd, value) {
                var cells, ut;
                cells = getSelectedArr(this);
                ut = getUETable(cells[0]);
                ut.setBackground(cells, value);
            }
        };

        UE.commands["cleartablebackground"] = {
            queryCommandState: function () {
                var cells = getSelectedArr(this);
                if (!cells.length) return -1;
                for (var i = 0, cell; (cell = cells[i++]);) {
                    if (cell.style.backgroundColor !== "") return 0;
                }
                return -1;
            },
            execCommand: function () {
                var cells = getSelectedArr(this),
                    ut = getUETable(cells[0]);
                ut.removeBackground(cells);
            }
        };

        UE.commands["interlacetable"] = UE.commands["uninterlacetable"] = {
            queryCommandState: function (cmd) {
                var table = getTableItemsByRange(this).table;
                if (!table) return -1;
                var interlaced = table.getAttribute("interlaced");
                if (cmd == "interlacetable") {
                    //TODO 待定
                    //是否需要待定,如果设置,则命令只能单次执行成功,但反射具备toggle效果;否则可以覆盖前次命令,但反射将不存在toggle效果
                    return interlaced === "enabled" ? -1 : 0;
                } else {
                    return !interlaced || interlaced === "disabled" ? -1 : 0;
                }
            },
            execCommand: function (cmd, classList) {
                var table = getTableItemsByRange(this).table;
                if (cmd == "interlacetable") {
                    table.setAttribute("interlaced", "enabled");
                    this.fireEvent("interlacetable", table, classList);
                } else {
                    table.setAttribute("interlaced", "disabled");
                    this.fireEvent("uninterlacetable", table);
                }
            }
        };
        UE.commands["setbordervisible"] = {
            queryCommandState: function (cmd) {
                var table = getTableItemsByRange(this).table;
                if (!table) return -1;
                return 0;
            },
            execCommand: function () {
                var table = getTableItemsByRange(this).table;
                utils.each(domUtils.getElementsByTagName(table, "td"), function (td) {
                    td.style.borderWidth = "1px";
                    td.style.borderStyle = "solid";
                    td.style.borderColor = 'windowtext';
                });
                utils.each(domUtils.getElementsByTagName(table, "th"), function (th) {
                    th.style.borderWidth = "1px";
                    th.style.borderStyle = "solid";
                    th.style.borderColor = 'windowtext';
                });
            }
        };

        function resetTdWidth(table, editor) {
            var tds = domUtils.getElementsByTagName(table, "td th");
            utils.each(tds, function (td) {
                td.removeAttribute("width");
            });
            table.setAttribute(
                "width",
                getTableWidth(editor, true, getDefaultValue(editor, table))
            );
            var tdsWidths = [];
            setTimeout(function () {
                utils.each(tds, function (td) {
                    td.colSpan == 1 && tdsWidths.push(td.offsetWidth);
                });
                utils.each(tds, function (td, i) {
                    td.colSpan == 1 && td.setAttribute("width", tdsWidths[i] + "");
                });
            }, 0);
        }

        function getTableWidth(editor, needIEHack, defaultValue) {
            var body = editor.body;
            return (
                body.offsetWidth -
                (needIEHack
                    ? parseInt(domUtils.getComputedStyle(body, "margin-left"), 10) * 2
                    : 0) -
                defaultValue.tableBorder * 2 -
                (editor.options.offsetWidth || 0)
            );
        }

        function getSelectedArr(editor) {
            var cell = getTableItemsByRange(editor).cell;
            if (cell) {
                var ut = getUETable(cell);
                return ut.selectedTds.length ? ut.selectedTds : [cell];
            } else {
                return [];
            }
        }
    })();


// plugins/table.action.js
    /**
     * Created with JetBrains PhpStorm.
     * User: taoqili
     * Date: 12-10-12
     * Time: 上午10:05
     * To change this template use File | Settings | File Templates.
     */
    UE.plugins["table"] = function () {
        var me = this,
            tabTimer = null,
            //拖动计时器
            tableDragTimer = null,
            //双击计时器
            tableResizeTimer = null,
            //单元格最小宽度
            cellMinWidth = 5,
            isInResizeBuffer = false,
            //单元格边框大小
            cellBorderWidth = 5,
            //鼠标偏移距离
            offsetOfTableCell = 10,
            //记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
            singleClickState = 0,
            userActionStatus = null,
            //双击允许的时间范围
            dblclickTime = 360,
            UT = UE.UETable,
            getUETable = function (tdOrTable) {
                return UT.getUETable(tdOrTable);
            },
            getUETableBySelected = function (editor) {
                return UT.getUETableBySelected(editor);
            },
            getDefaultValue = function (editor, table) {
                return UT.getDefaultValue(editor, table);
            },
            removeSelectedClass = function (cells) {
                return UT.removeSelectedClass(cells);
            };

        function showError(e) {
            //        throw e;
        }

        me.ready(function () {
            var me = this;
            var orgGetText = me.selection.getText;
            me.selection.getText = function () {
                var table = getUETableBySelected(me);
                if (table) {
                    var str = "";
                    utils.each(table.selectedTds, function (td) {
                        str += td[browser.ie ? "innerText" : "textContent"];
                    });
                    return str;
                } else {
                    return orgGetText.call(me.selection);
                }
            };
        });

        //处理拖动及框选相关方法
        var startTd = null, //鼠标按下时的锚点td
            currentTd = null, //当前鼠标经过时的td
            onDrag = "", //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
            onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
            dragButton = null,
            dragOver = false,
            dragLine = null, //模拟的拖动线
            dragTd = null; //发生拖动的目标td

        var mousedown = false,
            //todo 判断混乱模式
            needIEHack = true;

        me.setOpt({
            maxColNum: 20,
            maxRowNum: 100,
            defaultCols: 5,
            defaultRows: 5,
            tdvalign: "top",
            cursorpath: me.options.UEDITOR_HOME_URL + "themes/default/images/cursor_",
            tableDragable: false,
            classList: [
                "ue-table-interlace-color-single",
                "ue-table-interlace-color-double"
            ]
        });
        me.getUETable = getUETable;
        var commands = {
            deletetable: 1,
            inserttable: 1,
            cellvalign: 1,
            insertcaption: 1,
            deletecaption: 1,
            inserttitle: 1,
            deletetitle: 1,
            mergeright: 1,
            mergedown: 1,
            mergecells: 1,
            insertrow: 1,
            insertrownext: 1,
            deleterow: 1,
            insertcol: 1,
            insertcolnext: 1,
            deletecol: 1,
            splittocells: 1,
            splittorows: 1,
            splittocols: 1,
            adaptbytext: 1,
            adaptbywindow: 1,
            adaptbycustomer: 1,
            insertparagraph: 1,
            insertparagraphbeforetable: 1,
            averagedistributecol: 1,
            averagedistributerow: 1
        };
        me.ready(function () {
            utils.cssRule(
                "table",
                //选中的td上的样式
                ".selectTdClass{background-color:#edf5fa !important}" +
                "table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}" +
                //插入的表格的默认样式
                "table{margin-bottom:10px;border-collapse:collapse;display:table;}" +
                "td,th{padding: 5px 10px;border: 1px dashed #DDD;}" +
                "caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}" +
                "th{border-top:1px dashed #BBB;background-color:#F7F7F7;}" +
                "table tr.firstRow th{border-top-width:2px;}" +
                ".ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }" +
                "td p{margin:0;padding:0;}",
                me.document
            );

            var tableCopyList, isFullCol, isFullRow;
            //注册del/backspace事件
            me.addListener("keydown", function (cmd, evt) {
                var me = this;
                var keyCode = evt.keyCode || evt.which;

                if (keyCode == 8) {
                    var ut = getUETableBySelected(me);
                    if (ut && ut.selectedTds.length) {
                        if (ut.isFullCol()) {
                            me.execCommand("deletecol");
                        } else if (ut.isFullRow()) {
                            me.execCommand("deleterow");
                        } else {
                            me.fireEvent("delcells");
                        }
                        domUtils.preventDefault(evt);
                    }

                    var caption = domUtils.findParentByTagName(
                        me.selection.getStart(),
                        "caption",
                        true
                        ),
                        range = me.selection.getRange();
                    if (range.collapsed && caption && isEmptyBlock(caption)) {
                        me.fireEvent("saveScene");
                        var table = caption.parentNode;
                        domUtils.remove(caption);
                        if (table) {
                            range.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
                        }
                        me.fireEvent("saveScene");
                    }
                }

                if (keyCode == 46) {
                    ut = getUETableBySelected(me);
                    if (ut) {
                        me.fireEvent("saveScene");
                        for (var i = 0, ci; (ci = ut.selectedTds[i++]);) {
                            domUtils.fillNode(me.document, ci);
                        }
                        me.fireEvent("saveScene");
                        domUtils.preventDefault(evt);
                    }
                }
                if (keyCode == 13) {
                    var rng = me.selection.getRange(),
                        caption = domUtils.findParentByTagName(
                            rng.startContainer,
                            "caption",
                            true
                        );
                    if (caption) {
                        var table = domUtils.findParentByTagName(caption, "table");
                        if (!rng.collapsed) {
                            rng.deleteContents();
                            me.fireEvent("saveScene");
                        } else {
                            if (caption) {
                                rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
                            }
                        }
                        domUtils.preventDefault(evt);
                        return;
                    }
                    if (rng.collapsed) {
                        var table = domUtils.findParentByTagName(rng.startContainer, "table");
                        if (table) {
                            var cell = table.rows[0].cells[0],
                                start = domUtils.findParentByTagName(
                                    me.selection.getStart(),
                                    ["td", "th"],
                                    true
                                ),
                                preNode = table.previousSibling;
                            if (
                                cell === start &&
                                (!preNode ||
                                    (preNode.nodeType == 1 && preNode.tagName == "TABLE")) &&
                                domUtils.isStartInblock(rng)
                            ) {
                                var first = domUtils.findParent(
                                    me.selection.getStart(),
                                    function (n) {
                                        return domUtils.isBlockElm(n);
                                    },
                                    true
                                );
                                if (
                                    first &&
                                    (/t(h|d)/i.test(first.tagName) || first === start.firstChild)
                                ) {
                                    me.execCommand("insertparagraphbeforetable");
                                    domUtils.preventDefault(evt);
                                }
                            }
                        }
                    }
                }

                if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == "67") {
                    tableCopyList = null;
                    var ut = getUETableBySelected(me);
                    if (ut) {
                        var tds = ut.selectedTds;
                        isFullCol = ut.isFullCol();
                        isFullRow = ut.isFullRow();
                        tableCopyList = [[ut.cloneCell(tds[0], null, true)]];
                        for (var i = 1, ci; (ci = tds[i]); i++) {
                            if (ci.parentNode !== tds[i - 1].parentNode) {
                                tableCopyList.push([ut.cloneCell(ci, null, true)]);
                            } else {
                                tableCopyList[tableCopyList.length - 1].push(
                                    ut.cloneCell(ci, null, true)
                                );
                            }
                        }
                    }
                }
            });
            me.addListener("tablehasdeleted", function () {
                toggleDraggableState(this, false, "", null);
                if (dragButton) domUtils.remove(dragButton);
            });

            me.addListener("beforepaste", function (cmd, html) {
                var me = this;
                var rng = me.selection.getRange();
                if (domUtils.findParentByTagName(rng.startContainer, "caption", true)) {
                    var div = me.document.createElement("div");
                    div.innerHTML = html.html;
                    //trace:3729
                    html.html = div[browser.ie9below ? "innerText" : "textContent"];
                    return;
                }
                var table = getUETableBySelected(me);
                if (tableCopyList) {
                    me.fireEvent("saveScene");
                    var rng = me.selection.getRange();
                    var td = domUtils.findParentByTagName(
                        rng.startContainer,
                        ["td", "th"],
                        true
                        ),
                        tmpNode,
                        preNode;
                    if (td) {
                        var ut = getUETable(td);
                        if (isFullRow) {
                            var rowIndex = ut.getCellInfo(td).rowIndex;
                            if (td.tagName == "TH") {
                                rowIndex++;
                            }
                            for (var i = 0, ci; (ci = tableCopyList[i++]);) {
                                var tr = ut.insertRow(rowIndex++, "td");
                                for (var j = 0, cj; (cj = ci[j]); j++) {
                                    var cell = tr.cells[j];
                                    if (!cell) {
                                        cell = tr.insertCell(j);
                                    }
                                    cell.innerHTML = cj.innerHTML;
                                    cj.getAttribute("width") &&
                                    cell.setAttribute("width", cj.getAttribute("width"));
                                    cj.getAttribute("vAlign") &&
                                    cell.setAttribute("vAlign", cj.getAttribute("vAlign"));
                                    cj.getAttribute("align") &&
                                    cell.setAttribute("align", cj.getAttribute("align"));
                                    cj.style.cssText && (cell.style.cssText = cj.style.cssText);
                                }
                                for (var j = 0, cj; (cj = tr.cells[j]); j++) {
                                    if (!ci[j]) break;
                                    cj.innerHTML = ci[j].innerHTML;
                                    ci[j].getAttribute("width") &&
                                    cj.setAttribute("width", ci[j].getAttribute("width"));
                                    ci[j].getAttribute("vAlign") &&
                                    cj.setAttribute("vAlign", ci[j].getAttribute("vAlign"));
                                    ci[j].getAttribute("align") &&
                                    cj.setAttribute("align", ci[j].getAttribute("align"));
                                    ci[j].style.cssText && (cj.style.cssText = ci[j].style.cssText);
                                }
                            }
                        } else {
                            if (isFullCol) {
                                cellInfo = ut.getCellInfo(td);
                                var maxColNum = 0;
                                for (var j = 0, ci = tableCopyList[0], cj; (cj = ci[j++]);) {
                                    maxColNum += cj.colSpan || 1;
                                }
                                me.__hasEnterExecCommand = true;
                                for (i = 0; i < maxColNum; i++) {
                                    me.execCommand("insertcol");
                                }
                                me.__hasEnterExecCommand = false;
                                td = ut.table.rows[0].cells[cellInfo.cellIndex];
                                if (td.tagName == "TH") {
                                    td = ut.table.rows[1].cells[cellInfo.cellIndex];
                                }
                            }
                            for (var i = 0, ci; (ci = tableCopyList[i++]);) {
                                tmpNode = td;
                                for (var j = 0, cj; (cj = ci[j++]);) {
                                    if (td) {
                                        td.innerHTML = cj.innerHTML;
                                        //todo 定制处理
                                        cj.getAttribute("width") &&
                                        td.setAttribute("width", cj.getAttribute("width"));
                                        cj.getAttribute("vAlign") &&
                                        td.setAttribute("vAlign", cj.getAttribute("vAlign"));
                                        cj.getAttribute("align") &&
                                        td.setAttribute("align", cj.getAttribute("align"));
                                        cj.style.cssText && (td.style.cssText = cj.style.cssText);
                                        preNode = td;
                                        td = td.nextSibling;
                                    } else {
                                        var cloneTd = cj.cloneNode(true);
                                        domUtils.removeAttributes(cloneTd, [
                                            "class",
                                            "rowSpan",
                                            "colSpan"
                                        ]);

                                        preNode.parentNode.appendChild(cloneTd);
                                    }
                                }
                                td = ut.getNextCell(tmpNode, true, true);
                                if (!tableCopyList[i]) break;
                                if (!td) {
                                    var cellInfo = ut.getCellInfo(tmpNode);
                                    ut.table.insertRow(ut.table.rows.length);
                                    ut.update();
                                    td = ut.getVSideCell(tmpNode, true);
                                }
                            }
                        }
                        ut.update();
                    } else {
                        table = me.document.createElement("table");
                        for (var i = 0, ci; (ci = tableCopyList[i++]);) {
                            var tr = table.insertRow(table.rows.length);
                            for (var j = 0, cj; (cj = ci[j++]);) {
                                cloneTd = UT.cloneCell(cj, null, true);
                                domUtils.removeAttributes(cloneTd, ["class"]);
                                tr.appendChild(cloneTd);
                            }
                            if (j == 2 && cloneTd.rowSpan > 1) {
                                cloneTd.rowSpan = 1;
                            }
                        }

                        var defaultValue = getDefaultValue(me),
                            width =
                                me.body.offsetWidth -
                                (needIEHack
                                    ? parseInt(
                                    domUtils.getComputedStyle(me.body, "margin-left"),
                                    10
                                ) * 2
                                    : 0) -
                                defaultValue.tableBorder * 2 -
                                (me.options.offsetWidth || 0);
                        me.execCommand(
                            "insertHTML",
                            "<table  " +
                            (isFullCol && isFullRow ? 'width="' + width + '"' : "") +
                            ">" +
                            table.innerHTML
                                .replace(/>\s*</g, "><")
                                .replace(/\bth\b/gi, "td") +
                            "</table>"
                        );
                    }
                    me.fireEvent("contentchange");
                    me.fireEvent("saveScene");
                    html.html = "";
                    return true;
                } else {
                    var div = me.document.createElement("div"),
                        tables;
                    div.innerHTML = html.html;
                    tables = div.getElementsByTagName("table");
                    if (domUtils.findParentByTagName(me.selection.getStart(), "table")) {
                        utils.each(tables, function (t) {
                            domUtils.remove(t);
                        });
                        if (
                            domUtils.findParentByTagName(
                                me.selection.getStart(),
                                "caption",
                                true
                            )
                        ) {
                            div.innerHTML = div[browser.ie ? "innerText" : "textContent"];
                        }
                    } else {
                        utils.each(tables, function (table) {
                            removeStyleSize(table, true);
                            domUtils.removeAttributes(table, ["style"]);
                            utils.each(domUtils.getElementsByTagName(table, "td"), function (
                                td
                            ) {
                                if (isEmptyBlock(td)) {
                                    domUtils.fillNode(me.document, td);
                                }
                                removeStyleSize(td, true);
                                //                            domUtils.removeAttributes(td, ['style'])
                            });
                        });
                    }
                    html.html = div.innerHTML;
                }
            });

            me.addListener("afterpaste", function () {
                utils.each(domUtils.getElementsByTagName(me.body, "table"), function (
                    table
                ) {
                    if (table.offsetWidth > me.body.offsetWidth) {
                        var defaultValue = getDefaultValue(me, table);
                        table.style.width =
                            me.body.offsetWidth -
                            (needIEHack
                                ? parseInt(
                                domUtils.getComputedStyle(me.body, "margin-left"),
                                10
                            ) * 2
                                : 0) -
                            defaultValue.tableBorder * 2 -
                            (me.options.offsetWidth || 0) +
                            "px";
                    }
                });
            });
            me.addListener("blur", function () {
                tableCopyList = null;
            });
            var timer;
            me.addListener("keydown", function () {
                clearTimeout(timer);
                timer = setTimeout(function () {
                    var rng = me.selection.getRange(),
                        cell = domUtils.findParentByTagName(
                            rng.startContainer,
                            ["th", "td"],
                            true
                        );
                    if (cell) {
                        var table = cell.parentNode.parentNode.parentNode;
                        if (table.offsetWidth > table.getAttribute("width")) {
                            cell.style.wordBreak = "break-all";
                        }
                    }
                }, 100);
            });
            me.addListener("selectionchange", function () {
                toggleDraggableState(me, false, "", null);
            });

            //内容变化时触发索引更新
            //todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
            me.addListener("contentchange", function () {
                var me = this;
                //尽可能排除一些不需要更新的状况
                hideDragLine(me);
                if (getUETableBySelected(me)) return;
                var rng = me.selection.getRange();
                var start = rng.startContainer;
                start = domUtils.findParentByTagName(start, ["td", "th"], true);
                utils.each(domUtils.getElementsByTagName(me.document, "table"), function (
                    table
                ) {
                    if (me.fireEvent("excludetable", table) === true) return;
                    table.ueTable = new UT(table);
                    //trace:3742
                    //                utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
                    //
                    //                    if (domUtils.isEmptyBlock(td) && td !== start) {
                    //                        domUtils.fillNode(me.document, td);
                    //                        if (browser.ie && browser.version == 6) {
                    //                            td.innerHTML = '&nbsp;'
                    //                        }
                    //                    }
                    //                });
                    //                utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
                    //                    if (domUtils.isEmptyBlock(th) && th !== start) {
                    //                        domUtils.fillNode(me.document, th);
                    //                        if (browser.ie && browser.version == 6) {
                    //                            th.innerHTML = '&nbsp;'
                    //                        }
                    //                    }
                    //                });
                    table.onmouseover = function () {
                        me.fireEvent("tablemouseover", table);
                    };
                    table.onmousemove = function () {
                        me.fireEvent("tablemousemove", table);
                        me.options.tableDragable && toggleDragButton(true, this, me);
                        utils.defer(function () {
                            me.fireEvent("contentchange", 50);
                        }, true);
                    };
                    table.onmouseout = function () {
                        me.fireEvent("tablemouseout", table);
                        toggleDraggableState(me, false, "", null);
                        hideDragLine(me);
                    };
                    table.onclick = function (evt) {
                        evt = me.window.event || evt;
                        var target = getParentTdOrTh(evt.target || evt.srcElement);
                        if (!target) return;
                        var ut = getUETable(target),
                            table = ut.table,
                            cellInfo = ut.getCellInfo(target),
                            cellsRange,
                            rng = me.selection.getRange();
                        //                    if ("topLeft" == inPosition(table, mouseCoords(evt))) {
                        //                        cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
                        //                        ut.setSelected(cellsRange);
                        //                        return;
                        //                    }
                        //                    if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
                        //
                        //                        return;
                        //                    }
                        if (inTableSide(table, target, evt, true)) {
                            var endTdCol = ut.getCell(
                                ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex,
                                ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex
                            );
                            if (evt.shiftKey && ut.selectedTds.length) {
                                if (ut.selectedTds[0] !== endTdCol) {
                                    cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol);
                                    ut.setSelected(cellsRange);
                                } else {
                                    rng && rng.selectNodeContents(endTdCol).select();
                                }
                            } else {
                                if (target !== endTdCol) {
                                    cellsRange = ut.getCellsRange(target, endTdCol);
                                    ut.setSelected(cellsRange);
                                } else {
                                    rng && rng.selectNodeContents(endTdCol).select();
                                }
                            }
                            return;
                        }
                        if (inTableSide(table, target, evt)) {
                            var endTdRow = ut.getCell(
                                ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex,
                                ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex
                            );
                            if (evt.shiftKey && ut.selectedTds.length) {
                                if (ut.selectedTds[0] !== endTdRow) {
                                    cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow);
                                    ut.setSelected(cellsRange);
                                } else {
                                    rng && rng.selectNodeContents(endTdRow).select();
                                }
                            } else {
                                if (target !== endTdRow) {
                                    cellsRange = ut.getCellsRange(target, endTdRow);
                                    ut.setSelected(cellsRange);
                                } else {
                                    rng && rng.selectNodeContents(endTdRow).select();
                                }
                            }
                        }
                    };
                });

                switchBorderColor(me, true);
            });

            domUtils.on(me.document, "mousemove", mouseMoveEvent);

            domUtils.on(me.document, "mouseout", function (evt) {
                var target = evt.target || evt.srcElement;
                if (target.tagName == "TABLE") {
                    toggleDraggableState(me, false, "", null);
                }
            });
            /**
             * 表格隔行变色
             */
            me.addListener("interlacetable", function (type, table, classList) {
                if (!table) return;
                var me = this,
                    rows = table.rows,
                    len = rows.length,
                    getClass = function (list, index, repeat) {
                        return list[index]
                            ? list[index]
                            : repeat ? list[index % list.length] : "";
                    };
                for (var i = 0; i < len; i++) {
                    rows[i].className = getClass(
                        classList || me.options.classList,
                        i,
                        true
                    );
                }
            });
            me.addListener("uninterlacetable", function (type, table) {
                if (!table) return;
                var me = this,
                    rows = table.rows,
                    classList = me.options.classList,
                    len = rows.length;
                for (var i = 0; i < len; i++) {
                    domUtils.removeClasses(rows[i], classList);
                }
            });

            me.addListener("mousedown", mouseDownEvent);
            me.addListener("mouseup", mouseUpEvent);
            //拖动的时候触发mouseup
            domUtils.on(me.body, "dragstart", function (evt) {
                mouseUpEvent.call(me, "dragstart", evt);
            });
            me.addOutputRule(function (root) {
                utils.each(root.getNodesByTagName("div"), function (n) {
                    if (n.getAttr("id") == "ue_tableDragLine") {
                        n.parentNode.removeChild(n);
                    }
                });
            });

            var currentRowIndex = 0;
            me.addListener("mousedown", function () {
                currentRowIndex = 0;
            });
            me.addListener("tabkeydown", function () {
                var range = this.selection.getRange(),
                    common = range.getCommonAncestor(true, true),
                    table = domUtils.findParentByTagName(common, "table");
                if (table) {
                    if (domUtils.findParentByTagName(common, "caption", true)) {
                        var cell = domUtils.getElementsByTagName(table, "th td");
                        if (cell && cell.length) {
                            range.setStart(cell[0], 0).setCursor(false, true);
                        }
                    } else {
                        var cell = domUtils.findParentByTagName(common, ["td", "th"], true),
                            ua = getUETable(cell);
                        currentRowIndex = cell.rowSpan > 1
                            ? currentRowIndex
                            : ua.getCellInfo(cell).rowIndex;
                        var nextCell = ua.getTabNextCell(cell, currentRowIndex);
                        if (nextCell) {
                            if (isEmptyBlock(nextCell)) {
                                range.setStart(nextCell, 0).setCursor(false, true);
                            } else {
                                range.selectNodeContents(nextCell).select();
                            }
                        } else {
                            me.fireEvent("saveScene");
                            me.__hasEnterExecCommand = true;
                            this.execCommand("insertrownext");
                            me.__hasEnterExecCommand = false;
                            range = this.selection.getRange();
                            range
                                .setStart(table.rows[table.rows.length - 1].cells[0], 0)
                                .setCursor();
                            me.fireEvent("saveScene");
                        }
                    }
                    return true;
                }
            });
            browser.ie &&
            me.addListener("selectionchange", function () {
                toggleDraggableState(this, false, "", null);
            });
            me.addListener("keydown", function (type, evt) {
                var me = this;
                //处理在表格的最后一个输入tab产生新的表格
                var keyCode = evt.keyCode || evt.which;
                if (keyCode == 8 || keyCode == 46) {
                    return;
                }
                var notCtrlKey =
                    !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey;
                notCtrlKey &&
                removeSelectedClass(domUtils.getElementsByTagName(me.body, "td"));
                var ut = getUETableBySelected(me);
                if (!ut) return;
                notCtrlKey && ut.clearSelected();
            });

            me.addListener("beforegetcontent", function () {
                switchBorderColor(this, false);
                browser.ie &&
                utils.each(this.document.getElementsByTagName("caption"), function (ci) {
                    if (domUtils.isEmptyNode(ci)) {
                        ci.innerHTML = "&nbsp;";
                    }
                });
            });
            me.addListener("aftergetcontent", function () {
                switchBorderColor(this, true);
            });
            me.addListener("getAllHtml", function () {
                removeSelectedClass(me.document.getElementsByTagName("td"));
            });
            //修正全屏状态下插入的表格宽度在非全屏状态下撑开编辑器的情况
            me.addListener("fullscreenchanged", function (type, fullscreen) {
                if (!fullscreen) {
                    var ratio = this.body.offsetWidth / document.body.offsetWidth,
                        tables = domUtils.getElementsByTagName(this.body, "table");
                    utils.each(tables, function (table) {
                        if (table.offsetWidth < me.body.offsetWidth) return false;
                        var tds = domUtils.getElementsByTagName(table, "td"),
                            backWidths = [];
                        utils.each(tds, function (td) {
                            backWidths.push(td.offsetWidth);
                        });
                        for (var i = 0, td; (td = tds[i]); i++) {
                            td.setAttribute("width", Math.floor(backWidths[i] * ratio));
                        }
                        table.setAttribute(
                            "width",
                            Math.floor(getTableWidth(me, needIEHack, getDefaultValue(me)))
                        );
                    });
                }
            });

            //重写execCommand命令,用于处理框选时的处理
            var oldExecCommand = me.execCommand;
            me.execCommand = function (cmd, datatat) {
                var me = this,
                    args = arguments;

                cmd = cmd.toLowerCase();
                var ut = getUETableBySelected(me),
                    tds,
                    range = new dom.Range(me.document),
                    cmdFun = me.commands[cmd] || UE.commands[cmd],
                    result;
                if (!cmdFun) return;
                if (
                    ut &&
                    !commands[cmd] &&
                    !cmdFun.notNeedUndo &&
                    !me.__hasEnterExecCommand
                ) {
                    me.__hasEnterExecCommand = true;
                    me.fireEvent("beforeexeccommand", cmd);
                    tds = ut.selectedTds;
                    var lastState = -2,
                        lastValue = -2,
                        value,
                        state;
                    for (var i = 0, td; (td = tds[i]); i++) {
                        if (isEmptyBlock(td)) {
                            range.setStart(td, 0).setCursor(false, true);
                        } else {
                            range.selectNode(td).select(true);
                        }
                        state = me.queryCommandState(cmd);
                        value = me.queryCommandValue(cmd);
                        if (state != -1) {
                            if (lastState !== state || lastValue !== value) {
                                me._ignoreContentChange = true;
                                result = oldExecCommand.apply(me, arguments);
                                me._ignoreContentChange = false;
                            }
                            lastState = me.queryCommandState(cmd);
                            lastValue = me.queryCommandValue(cmd);
                            if (domUtils.isEmptyBlock(td)) {
                                domUtils.fillNode(me.document, td);
                            }
                        }
                    }
                    range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true);
                    me.fireEvent("contentchange");
                    me.fireEvent("afterexeccommand", cmd);
                    me.__hasEnterExecCommand = false;
                    me._selectionChange();
                } else {
                    result = oldExecCommand.apply(me, arguments);
                }
                return result;
            };
        });

        /**
         * 删除obj的宽高style,改成属性宽高
         * @param obj
         * @param replaceToProperty
         */
        function removeStyleSize(obj, replaceToProperty) {
            removeStyle(obj, "width", true);
            removeStyle(obj, "height", true);
        }

        function removeStyle(obj, styleName, replaceToProperty) {
            if (obj.style[styleName]) {
                replaceToProperty &&
                obj.setAttribute(styleName, parseInt(obj.style[styleName], 10));
                obj.style[styleName] = "";
            }
        }

        function getParentTdOrTh(ele) {
            if (ele.tagName == "TD" || ele.tagName == "TH") return ele;
            var td;
            if (
                (td =
                    domUtils.findParentByTagName(ele, "td", true) ||
                    domUtils.findParentByTagName(ele, "th", true))
            )
                return td;
            return null;
        }

        function isEmptyBlock(node) {
            var reg = new RegExp(domUtils.fillChar, "g");
            if (
                node[browser.ie ? "innerText" : "textContent"]
                    .replace(/^\s*$/, "")
                    .replace(reg, "").length > 0
            ) {
                return 0;
            }
            for (var n in dtd.$isNotEmpty) {
                if (node.getElementsByTagName(n).length) {
                    return 0;
                }
            }
            return 1;
        }

        function mouseCoords(evt) {
            if (evt.pageX || evt.pageY) {
                return {x: evt.pageX, y: evt.pageY};
            }
            return {
                x:
                evt.clientX + me.document.body.scrollLeft - me.document.body.clientLeft,
                y: evt.clientY + me.document.body.scrollTop - me.document.body.clientTop
            };
        }

        function mouseMoveEvent(evt) {
            if (isEditorDisabled()) {
                return;
            }

            try {
                //普通状态下鼠标移动
                var target = getParentTdOrTh(evt.target || evt.srcElement),
                    pos;

                //区分用户的行为是拖动还是双击
                if (isInResizeBuffer) {
                    me.body.style.webkitUserSelect = "none";

                    if (
                        Math.abs(userActionStatus.x - evt.clientX) > offsetOfTableCell ||
                        Math.abs(userActionStatus.y - evt.clientY) > offsetOfTableCell
                    ) {
                        clearTableDragTimer();
                        isInResizeBuffer = false;
                        singleClickState = 0;
                        //drag action
                        tableBorderDrag(evt);
                    }
                }

                //修改单元格大小时的鼠标移动
                if (onDrag && dragTd) {
                    singleClickState = 0;
                    me.body.style.webkitUserSelect = "none";
                    me.selection.getNative()[
                        browser.ie9below ? "empty" : "removeAllRanges"
                        ]();
                    pos = mouseCoords(evt);
                    toggleDraggableState(me, true, onDrag, pos, target);
                    if (onDrag == "h") {
                        dragLine.style.left = getPermissionX(dragTd, evt) + "px";
                    } else if (onDrag == "v") {
                        dragLine.style.top = getPermissionY(dragTd, evt) + "px";
                    }
                    return;
                }
                //当鼠标处于table上时,修改移动过程中的光标状态
                if (target) {
                    //针对使用table作为容器的组件不触发拖拽效果
                    if (me.fireEvent("excludetable", target) === true) return;
                    pos = mouseCoords(evt);
                    var state = getRelation(target, pos),
                        table = domUtils.findParentByTagName(target, "table", true);

                    if (inTableSide(table, target, evt, true)) {
                        if (me.fireEvent("excludetable", table) === true) return;
                        me.body.style.cursor =
                            "url(" + me.options.cursorpath + "h.png),pointer";
                    } else if (inTableSide(table, target, evt)) {
                        if (me.fireEvent("excludetable", table) === true) return;
                        me.body.style.cursor =
                            "url(" + me.options.cursorpath + "v.png),pointer";
                    } else {
                        me.body.style.cursor = "text";
                        var curCell = target;
                        if (/\d/.test(state)) {
                            state = state.replace(/\d/, "");
                            target = getUETable(target).getPreviewCell(target, state == "v");
                        }
                        //位于第一行的顶部或者第一列的左边时不可拖动
                        toggleDraggableState(
                            me,
                            target ? !!state : false,
                            target ? state : "",
                            pos,
                            target
                        );
                    }
                } else {
                    toggleDragButton(false, table, me);
                }
            } catch (e) {
                showError(e);
            }
        }

        var dragButtonTimer;

        function toggleDragButton(show, table, editor) {
            if (!show) {
                if (dragOver) return;
                dragButtonTimer = setTimeout(function () {
                    !dragOver &&
                    dragButton &&
                    dragButton.parentNode &&
                    dragButton.parentNode.removeChild(dragButton);
                }, 2000);
            } else {
                createDragButton(table, editor);
            }
        }

        function createDragButton(table, editor) {
            var pos = domUtils.getXY(table),
                doc = table.ownerDocument;
            if (dragButton && dragButton.parentNode) return dragButton;
            dragButton = doc.createElement("div");
            dragButton.contentEditable = false;
            dragButton.innerHTML = "";
            dragButton.style.cssText =
                "width:15px;height:15px;background-image:url(" +
                editor.options.UEDITOR_HOME_URL +
                "dialogs/table/dragicon.png);position: absolute;cursor:move;top:" +
                (pos.y - 15) +
                "px;left:" +
                pos.x +
                "px;";
            domUtils.unSelectable(dragButton);
            dragButton.onmouseover = function (evt) {
                dragOver = true;
            };
            dragButton.onmouseout = function (evt) {
                dragOver = false;
            };
            domUtils.on(dragButton, "click", function (type, evt) {
                doClick(evt, this);
            });
            domUtils.on(dragButton, "dblclick", function (type, evt) {
                doDblClick(evt);
            });
            domUtils.on(dragButton, "dragstart", function (type, evt) {
                domUtils.preventDefault(evt);
            });
            var timer;

            function doClick(evt, button) {
                // 部分浏览器下需要清理
                clearTimeout(timer);
                timer = setTimeout(function () {
                    editor.fireEvent("tableClicked", table, button);
                }, 300);
            }

            function doDblClick(evt) {
                clearTimeout(timer);
                var ut = getUETable(table),
                    start = table.rows[0].cells[0],
                    end = ut.getLastCell(),
                    range = ut.getCellsRange(start, end);
                editor.selection.getRange().setStart(start, 0).setCursor(false, true);
                ut.setSelected(range);
            }

            doc.body.appendChild(dragButton);
        }

        //    function inPosition(table, pos) {
        //        var tablePos = domUtils.getXY(table),
        //            width = table.offsetWidth,
        //            height = table.offsetHeight;
        //        if (pos.x - tablePos.x < 5 && pos.y - tablePos.y < 5) {
        //            return "topLeft";
        //        } else if (tablePos.x + width - pos.x < 5 && tablePos.y + height - pos.y < 5) {
        //            return "bottomRight";
        //        }
        //    }

        function inTableSide(table, cell, evt, top) {
            var pos = mouseCoords(evt),
                state = getRelation(cell, pos);

            if (top) {
                var caption = table.getElementsByTagName("caption")[0],
                    capHeight = caption ? caption.offsetHeight : 0;
                return state == "v1" && pos.y - domUtils.getXY(table).y - capHeight < 8;
            } else {
                return state == "h1" && pos.x - domUtils.getXY(table).x < 8;
            }
        }

        /**
         * 获取拖动时允许的X轴坐标
         * @param dragTd
         * @param evt
         */
        function getPermissionX(dragTd, evt) {
            var ut = getUETable(dragTd);
            if (ut) {
                var preTd = ut.getSameEndPosCells(dragTd, "x")[0],
                    nextTd = ut.getSameStartPosXCells(dragTd)[0],
                    mouseX = mouseCoords(evt).x,
                    left =
                        (preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20,
                    right = nextTd
                        ? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20
                        : me.body.offsetWidth + 5 ||
                        parseInt(domUtils.getComputedStyle(me.body, "width"), 10);

                left += cellMinWidth;
                right -= cellMinWidth;

                return mouseX < left ? left : mouseX > right ? right : mouseX;
            }
        }

        /**
         * 获取拖动时允许的Y轴坐标
         */
        function getPermissionY(dragTd, evt) {
            try {
                var top = domUtils.getXY(dragTd).y,
                    mousePosY = mouseCoords(evt).y;
                return mousePosY < top ? top : mousePosY;
            } catch (e) {
                showError(e);
            }
        }

        /**
         * 移动状态切换
         */
        function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
            try {
                editor.body.style.cursor = dir == "h"
                    ? "col-resize"
                    : dir == "v" ? "row-resize" : "text";
                if (browser.ie) {
                    if (dir && !mousedown && !getUETableBySelected(editor)) {
                        getDragLine(editor, editor.document);
                        showDragLineAt(dir, cell);
                    } else {
                        hideDragLine(editor);
                    }
                }
                onBorder = draggable;
            } catch (e) {
                showError(e);
            }
        }

        /**
         * 获取与UETable相关的resize line
         * @param uetable UETable对象
         */
        function getResizeLineByUETable() {
            var lineId = "_UETableResizeLine",
                line = this.document.getElementById(lineId);

            if (!line) {
                line = this.document.createElement("div");
                line.id = lineId;
                line.contnetEditable = false;
                line.setAttribute("unselectable", "on");

                var styles = {
                    width: 2 * cellBorderWidth + 1 + "px",
                    position: "absolute",
                    "z-index": 100000,
                    cursor: "col-resize",
                    background: "red",
                    display: "none"
                };

                //切换状态
                line.onmouseout = function () {
                    this.style.display = "none";
                };

                utils.extend(line.style, styles);

                this.document.body.appendChild(line);
            }

            return line;
        }

        /**
         * 更新resize-line
         */
        function updateResizeLine(cell, uetable) {
            var line = getResizeLineByUETable.call(this),
                table = uetable.table,
                styles = {
                    top: domUtils.getXY(table).y + "px",
                    left:
                    domUtils.getXY(cell).x + cell.offsetWidth - cellBorderWidth + "px",
                    display: "block",
                    height: table.offsetHeight + "px"
                };

            utils.extend(line.style, styles);
        }

        /**
         * 显示resize-line
         */
        function showResizeLine(cell) {
            var uetable = getUETable(cell);

            updateResizeLine.call(this, cell, uetable);
        }

        /**
         * 获取鼠标与当前单元格的相对位置
         * @param ele
         * @param mousePos
         */
        function getRelation(ele, mousePos) {
            var elePos = domUtils.getXY(ele);

            if (!elePos) {
                return "";
            }

            if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
                return "h";
            }
            if (mousePos.x - elePos.x < cellBorderWidth) {
                return "h1";
            }
            if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
                return "v";
            }
            if (mousePos.y - elePos.y < cellBorderWidth) {
                return "v1";
            }
            return "";
        }

        function mouseDownEvent(type, evt) {
            if (isEditorDisabled()) {
                return;
            }

            userActionStatus = {
                x: evt.clientX,
                y: evt.clientY
            };

            //右键菜单单独处理
            if (evt.button == 2) {
                var ut = getUETableBySelected(me),
                    flag = false;

                if (ut) {
                    var td = getTargetTd(me, evt);
                    utils.each(ut.selectedTds, function (ti) {
                        if (ti === td) {
                            flag = true;
                        }
                    });
                    if (!flag) {
                        removeSelectedClass(domUtils.getElementsByTagName(me.body, "th td"));
                        ut.clearSelected();
                    } else {
                        td = ut.selectedTds[0];
                        setTimeout(function () {
                            me.selection.getRange().setStart(td, 0).setCursor(false, true);
                        }, 0);
                    }
                }
            } else {
                tableClickHander(evt);
            }
        }

        //清除表格的计时器
        function clearTableTimer() {
            tabTimer && clearTimeout(tabTimer);
            tabTimer = null;
        }

        //双击收缩
        function tableDbclickHandler(evt) {
            singleClickState = 0;
            evt = evt || me.window.event;
            var target = getParentTdOrTh(evt.target || evt.srcElement);
            if (target) {
                var h;
                if ((h = getRelation(target, mouseCoords(evt)))) {
                    hideDragLine(me);

                    if (h == "h1") {
                        h = "h";
                        if (
                            inTableSide(
                                domUtils.findParentByTagName(target, "table"),
                                target,
                                evt
                            )
                        ) {
                            me.execCommand("adaptbywindow");
                        } else {
                            target = getUETable(target).getPreviewCell(target);
                            if (target) {
                                var rng = me.selection.getRange();
                                rng.selectNodeContents(target).setCursor(true, true);
                            }
                        }
                    }
                    if (h == "h") {
                        var ut = getUETable(target),
                            table = ut.table,
                            cells = getCellsByMoveBorder(target, table, true);

                        cells = extractArray(cells, "left");

                        ut.width = ut.offsetWidth;

                        var oldWidth = [],
                            newWidth = [];

                        utils.each(cells, function (cell) {
                            oldWidth.push(cell.offsetWidth);
                        });

                        utils.each(cells, function (cell) {
                            cell.removeAttribute("width");
                        });

                        window.setTimeout(function () {
                            //是否允许改变
                            var changeable = true;

                            utils.each(cells, function (cell, index) {
                                var width = cell.offsetWidth;

                                if (width > oldWidth[index]) {
                                    changeable = false;
                                    return false;
                                }

                                newWidth.push(width);
                            });

                            var change = changeable ? newWidth : oldWidth;

                            utils.each(cells, function (cell, index) {
                                cell.width = change[index] - getTabcellSpace();
                            });
                        }, 0);

                        //                    minWidth -= cellMinWidth;
                        //
                        //                    table.removeAttribute("width");
                        //                    utils.each(cells, function (cell) {
                        //                        cell.style.width = "";
                        //                        cell.width -= minWidth;
                        //                    });
                    }
                }
            }
        }

        function tableClickHander(evt) {
            removeSelectedClass(domUtils.getElementsByTagName(me.body, "td th"));
            //trace:3113
            //选中单元格,点击table外部,不会清掉table上挂的ueTable,会引起getUETableBySelected方法返回值
            utils.each(me.document.getElementsByTagName("table"), function (t) {
                t.ueTable = null;
            });
            startTd = getTargetTd(me, evt);
            if (!startTd) return;
            var table = domUtils.findParentByTagName(startTd, "table", true);
            ut = getUETable(table);
            ut && ut.clearSelected();

            //判断当前鼠标状态
            if (!onBorder) {
                me.document.body.style.webkitUserSelect = "";
                mousedown = true;
                me.addListener("mouseover", mouseOverEvent);
            } else {
                //边框上的动作处理
                borderActionHandler(evt);
            }
        }

        //处理表格边框上的动作, 这里做延时处理,避免两种动作互相影响
        function borderActionHandler(evt) {
            if (browser.ie) {
                evt = reconstruct(evt);
            }

            clearTableDragTimer();

            //是否正在等待resize的缓冲中
            isInResizeBuffer = true;

            tableDragTimer = setTimeout(function () {
                tableBorderDrag(evt);
            }, dblclickTime);
        }

        function extractArray(originArr, key) {
            var result = [],
                tmp = null;

            for (var i = 0, len = originArr.length; i < len; i++) {
                tmp = originArr[i][key];

                if (tmp) {
                    result.push(tmp);
                }
            }

            return result;
        }

        function clearTableDragTimer() {
            tableDragTimer && clearTimeout(tableDragTimer);
            tableDragTimer = null;
        }

        function reconstruct(obj) {
            var attrs = [
                    "pageX",
                    "pageY",
                    "clientX",
                    "clientY",
                    "srcElement",
                    "target"
                ],
                newObj = {};

            if (obj) {
                for (var i = 0, key, val; (key = attrs[i]); i++) {
                    val = obj[key];
                    val && (newObj[key] = val);
                }
            }

            return newObj;
        }

        //边框拖动
        function tableBorderDrag(evt) {
            isInResizeBuffer = false;

            startTd = evt.target || evt.srcElement;
            if (!startTd) return;
            var state = getRelation(startTd, mouseCoords(evt));
            if (/\d/.test(state)) {
                state = state.replace(/\d/, "");
                startTd = getUETable(startTd).getPreviewCell(startTd, state == "v");
            }
            hideDragLine(me);
            getDragLine(me, me.document);
            me.fireEvent("saveScene");
            showDragLineAt(state, startTd);
            mousedown = true;
            //拖动开始
            onDrag = state;
            dragTd = startTd;
        }

        function mouseUpEvent(type, evt) {
            if (isEditorDisabled()) {
                return;
            }

            clearTableDragTimer();

            isInResizeBuffer = false;

            if (onBorder) {
                singleClickState = ++singleClickState % 3;

                userActionStatus = {
                    x: evt.clientX,
                    y: evt.clientY
                };

                tableResizeTimer = setTimeout(function () {
                    singleClickState > 0 && singleClickState--;
                }, dblclickTime);

                if (singleClickState === 2) {
                    singleClickState = 0;
                    tableDbclickHandler(evt);
                    return;
                }
            }

            if (evt.button == 2) return;
            var me = this;
            //清除表格上原生跨选问题
            var range = me.selection.getRange(),
                start = domUtils.findParentByTagName(range.startContainer, "table", true),
                end = domUtils.findParentByTagName(range.endContainer, "table", true);

            if (start || end) {
                if (start === end) {
                    start = domUtils.findParentByTagName(
                        range.startContainer,
                        ["td", "th", "caption"],
                        true
                    );
                    end = domUtils.findParentByTagName(
                        range.endContainer,
                        ["td", "th", "caption"],
                        true
                    );
                    if (start !== end) {
                        me.selection.clearRange();
                    }
                } else {
                    me.selection.clearRange();
                }
            }
            mousedown = false;
            me.document.body.style.webkitUserSelect = "";
            //拖拽状态下的mouseUP
            if (onDrag && dragTd) {
                me.selection.getNative()[
                    browser.ie9below ? "empty" : "removeAllRanges"
                    ]();

                singleClickState = 0;
                dragLine = me.document.getElementById("ue_tableDragLine");

                // trace 3973
                if (dragLine) {
                    var dragTdPos = domUtils.getXY(dragTd),
                        dragLinePos = domUtils.getXY(dragLine);

                    switch (onDrag) {
                        case "h":
                            changeColWidth(dragTd, dragLinePos.x - dragTdPos.x);
                            break;
                        case "v":
                            changeRowHeight(
                                dragTd,
                                dragLinePos.y - dragTdPos.y - dragTd.offsetHeight
                            );
                            break;
                        default:
                    }
                    onDrag = "";
                    dragTd = null;

                    hideDragLine(me);
                    me.fireEvent("saveScene");
                    return;
                }
            }
            //正常状态下的mouseup
            if (!startTd) {
                var target = domUtils.findParentByTagName(
                    evt.target || evt.srcElement,
                    "td",
                    true
                );
                if (!target)
                    target = domUtils.findParentByTagName(
                        evt.target || evt.srcElement,
                        "th",
                        true
                    );
                if (target && (target.tagName == "TD" || target.tagName == "TH")) {
                    if (me.fireEvent("excludetable", target) === true) return;
                    range = new dom.Range(me.document);
                    range.setStart(target, 0).setCursor(false, true);
                }
            } else {
                var ut = getUETable(startTd),
                    cell = ut ? ut.selectedTds[0] : null;
                if (cell) {
                    range = new dom.Range(me.document);
                    if (domUtils.isEmptyBlock(cell)) {
                        range.setStart(cell, 0).setCursor(false, true);
                    } else {
                        range
                            .selectNodeContents(cell)
                            .shrinkBoundary()
                            .setCursor(false, true);
                    }
                } else {
                    range = me.selection.getRange().shrinkBoundary();
                    if (!range.collapsed) {
                        var start = domUtils.findParentByTagName(
                            range.startContainer,
                            ["td", "th"],
                            true
                            ),
                            end = domUtils.findParentByTagName(
                                range.endContainer,
                                ["td", "th"],
                                true
                            );
                        //在table里边的不能清除
                        if (
                            (start && !end) ||
                            (!start && end) ||
                            (start && end && start !== end)
                        ) {
                            range.setCursor(false, true);
                        }
                    }
                }
                startTd = null;
                me.removeListener("mouseover", mouseOverEvent);
            }
            me._selectionChange(250, evt);
        }

        function mouseOverEvent(type, evt) {
            if (isEditorDisabled()) {
                return;
            }

            var me = this,
                tar = evt.target || evt.srcElement;
            currentTd =
                domUtils.findParentByTagName(tar, "td", true) ||
                domUtils.findParentByTagName(tar, "th", true);
            //需要判断两个TD是否位于同一个表格内
            if (
                startTd &&
                currentTd &&
                ((startTd.tagName == "TD" && currentTd.tagName == "TD") ||
                    (startTd.tagName == "TH" && currentTd.tagName == "TH")) &&
                domUtils.findParentByTagName(startTd, "table") ==
                domUtils.findParentByTagName(currentTd, "table")
            ) {
                var ut = getUETable(currentTd);
                if (startTd != currentTd) {
                    me.document.body.style.webkitUserSelect = "none";
                    me.selection.getNative()[
                        browser.ie9below ? "empty" : "removeAllRanges"
                        ]();
                    var range = ut.getCellsRange(startTd, currentTd);
                    ut.setSelected(range);
                } else {
                    me.document.body.style.webkitUserSelect = "";
                    ut.clearSelected();
                }
            }
            evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
        }

        function setCellHeight(cell, height, backHeight) {
            var lineHight = parseInt(
                domUtils.getComputedStyle(cell, "line-height"),
                10
                ),
                tmpHeight = backHeight + height;
            height = tmpHeight < lineHight ? lineHight : tmpHeight;
            if (cell.style.height) cell.style.height = "";
            cell.rowSpan == 1
                ? cell.setAttribute("height", height)
                : cell.removeAttribute && cell.removeAttribute("height");
        }

        function getWidth(cell) {
            if (!cell) return 0;
            return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
        }

        function changeColWidth(cell, changeValue) {
            var ut = getUETable(cell);
            if (ut) {
                //根据当前移动的边框获取相关的单元格
                var table = ut.table,
                    cells = getCellsByMoveBorder(cell, table);

                table.style.width = "";
                table.removeAttribute("width");

                //修正改变量
                changeValue = correctChangeValue(changeValue, cell, cells);

                if (cell.nextSibling) {
                    var i = 0;

                    utils.each(cells, function (cellGroup) {
                        cellGroup.left.width = +cellGroup.left.width + changeValue;
                        cellGroup.right &&
                        (cellGroup.right.width = +cellGroup.right.width - changeValue);
                    });
                } else {
                    utils.each(cells, function (cellGroup) {
                        cellGroup.left.width -= -changeValue;
                    });
                }
            }
        }

        function isEditorDisabled() {
            return me.body.contentEditable === "false";
        }

        function changeRowHeight(td, changeValue) {
            if (Math.abs(changeValue) < 10) return;
            var ut = getUETable(td);
            if (ut) {
                var cells = ut.getSameEndPosCells(td, "y"),
                    //备份需要连带变化的td的原始高度,否则后期无法获取正确的值
                    backHeight = cells[0] ? cells[0].offsetHeight : 0;
                for (var i = 0, cell; (cell = cells[i++]);) {
                    setCellHeight(cell, changeValue, backHeight);
                }
            }
        }

        /**
         * 获取调整单元格大小的相关单元格
         * @isContainMergeCell 返回的结果中是否包含发生合并后的单元格
         */
        function getCellsByMoveBorder(cell, table, isContainMergeCell) {
            if (!table) {
                table = domUtils.findParentByTagName(cell, "table");
            }

            if (!table) {
                return null;
            }

            //获取到该单元格所在行的序列号
            var index = domUtils.getNodeIndex(cell),
                temp = cell,
                rows = table.rows,
                colIndex = 0;

            while (temp) {
                //获取到当前单元格在未发生单元格合并时的序列
                if (temp.nodeType === 1) {
                    colIndex += temp.colSpan || 1;
                }
                temp = temp.previousSibling;
            }

            temp = null;

            //记录想关的单元格
            var borderCells = [];

            utils.each(rows, function (tabRow) {
                var cells = tabRow.cells,
                    currIndex = 0;

                utils.each(cells, function (tabCell) {
                    currIndex += tabCell.colSpan || 1;

                    if (currIndex === colIndex) {
                        borderCells.push({
                            left: tabCell,
                            right: tabCell.nextSibling || null
                        });

                        return false;
                    } else if (currIndex > colIndex) {
                        if (isContainMergeCell) {
                            borderCells.push({
                                left: tabCell
                            });
                        }

                        return false;
                    }
                });
            });

            return borderCells;
        }

        /**
         * 通过给定的单元格集合获取最小的单元格width
         */
        function getMinWidthByTableCells(cells) {
            var minWidth = Number.MAX_VALUE;

            for (var i = 0, curCell; (curCell = cells[i]); i++) {
                minWidth = Math.min(
                    minWidth,
                    curCell.width || getTableCellWidth(curCell)
                );
            }

            return minWidth;
        }

        function correctChangeValue(changeValue, relatedCell, cells) {
            //为单元格的paading预留空间
            changeValue -= getTabcellSpace();

            if (changeValue < 0) {
                return 0;
            }

            changeValue -= getTableCellWidth(relatedCell);

            //确定方向
            var direction = changeValue < 0 ? "left" : "right";

            changeValue = Math.abs(changeValue);

            //只关心非最后一个单元格就可以
            utils.each(cells, function (cellGroup) {
                var curCell = cellGroup[direction];

                //为单元格保留最小空间
                if (curCell) {
                    changeValue = Math.min(
                        changeValue,
                        getTableCellWidth(curCell) - cellMinWidth
                    );
                }
            });

            //修正越界
            changeValue = changeValue < 0 ? 0 : changeValue;

            return direction === "left" ? -changeValue : changeValue;
        }

        function getTableCellWidth(cell) {
            var width = 0,
                //偏移纠正量
                offset = 0,
                width = cell.offsetWidth - getTabcellSpace();

            //最后一个节点纠正一下
            if (!cell.nextSibling) {
                width -= getTableCellOffset(cell);
            }

            width = width < 0 ? 0 : width;

            try {
                cell.width = width;
            } catch (e) {
            }

            return width;
        }

        /**
         * 获取单元格所在表格的最末单元格的偏移量
         */
        function getTableCellOffset(cell) {
            tab = domUtils.findParentByTagName(cell, "table", false);

            if (tab.offsetVal === undefined) {
                var prev = cell.previousSibling;

                if (prev) {
                    //最后一个单元格和前一个单元格的width diff结果 如果恰好为一个border width, 则条件成立
                    tab.offsetVal = cell.offsetWidth - prev.offsetWidth === UT.borderWidth
                        ? UT.borderWidth
                        : 0;
                } else {
                    tab.offsetVal = 0;
                }
            }

            return tab.offsetVal;
        }

        function getTabcellSpace() {
            if (UT.tabcellSpace === undefined) {
                var cell = null,
                    tab = me.document.createElement("table"),
                    tbody = me.document.createElement("tbody"),
                    trow = me.document.createElement("tr"),
                    tabcell = me.document.createElement("td"),
                    mirror = null;

                tabcell.style.cssText = "border: 0;";
                tabcell.width = 1;

                trow.appendChild(tabcell);
                trow.appendChild((mirror = tabcell.cloneNode(false)));

                tbody.appendChild(trow);

                tab.appendChild(tbody);

                tab.style.cssText = "visibility: hidden;";

                me.body.appendChild(tab);

                UT.paddingSpace = tabcell.offsetWidth - 1;

                var tmpTabWidth = tab.offsetWidth;

                tabcell.style.cssText = "";
                mirror.style.cssText = "";

                UT.borderWidth = (tab.offsetWidth - tmpTabWidth) / 3;

                UT.tabcellSpace = UT.paddingSpace + UT.borderWidth;

                me.body.removeChild(tab);
            }

            getTabcellSpace = function () {
                return UT.tabcellSpace;
            };

            return UT.tabcellSpace;
        }

        function getDragLine(editor, doc) {
            if (mousedown) return;
            dragLine = editor.document.createElement("div");
            domUtils.setAttributes(dragLine, {
                id: "ue_tableDragLine",
                unselectable: "on",
                contenteditable: false,
                onresizestart: "return false",
                ondragstart: "return false",
                onselectstart: "return false",
                style:
                    "background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)"
            });
            editor.body.appendChild(dragLine);
        }

        function hideDragLine(editor) {
            if (mousedown) return;
            var line;
            while ((line = editor.document.getElementById("ue_tableDragLine"))) {
                domUtils.remove(line);
            }
        }

        /**
         * 依据state(v|h)在cell位置显示横线
         * @param state
         * @param cell
         */
        function showDragLineAt(state, cell) {
            if (!cell) return;
            var table = domUtils.findParentByTagName(cell, "table"),
                caption = table.getElementsByTagName("caption"),
                width = table.offsetWidth,
                height =
                    table.offsetHeight - (caption.length > 0 ? caption[0].offsetHeight : 0),
                tablePos = domUtils.getXY(table),
                cellPos = domUtils.getXY(cell),
                css;
            switch (state) {
                case "h":
                    css =
                        "height:" +
                        height +
                        "px;top:" +
                        (tablePos.y + (caption.length > 0 ? caption[0].offsetHeight : 0)) +
                        "px;left:" +
                        (cellPos.x + cell.offsetWidth);
                    dragLine.style.cssText =
                        css +
                        "px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)";
                    break;
                case "v":
                    css =
                        "width:" +
                        width +
                        "px;left:" +
                        tablePos.x +
                        "px;top:" +
                        (cellPos.y + cell.offsetHeight);
                    //必须加上border:0和color:blue,否则低版ie不支持背景色显示
                    dragLine.style.cssText =
                        css +
                        "px;overflow:hidden;position: absolute;display:block;background-color:blue;height:1px;border:0;color:blue;opacity:.2;filter:alpha(opacity=20)";
                    break;
                default:
            }
        }

        /**
         * 当表格边框颜色为白色时设置为虚线,true为添加虚线
         * @param editor
         * @param flag
         */
        function switchBorderColor(editor, flag) {
            var tableArr = domUtils.getElementsByTagName(editor.body, "table"),
                color;
            for (var i = 0, node; (node = tableArr[i++]);) {
                var td = domUtils.getElementsByTagName(node, "td");
                if (td[0]) {
                    if (flag) {
                        color = td[0].style.borderColor.replace(/\s/g, "");
                        if (/(#ffffff)|(rgb\(255,255,255\))/gi.test(color))
                            domUtils.addClass(node, "noBorderTable");
                    } else {
                        domUtils.removeClasses(node, "noBorderTable");
                    }
                }
            }
        }

        function getTableWidth(editor, needIEHack, defaultValue) {
            var body = editor.body;
            return (
                body.offsetWidth -
                (needIEHack
                    ? parseInt(domUtils.getComputedStyle(body, "margin-left"), 10) * 2
                    : 0) -
                defaultValue.tableBorder * 2 -
                (editor.options.offsetWidth || 0)
            );
        }

        /**
         * 获取当前拖动的单元格
         */
        function getTargetTd(editor, evt) {
            var target = domUtils.findParentByTagName(
                evt.target || evt.srcElement,
                ["td", "th"],
                true
                ),
                dir = null;

            if (!target) {
                return null;
            }

            dir = getRelation(target, mouseCoords(evt));

            //如果有前一个节点, 需要做一个修正, 否则可能会得到一个错误的td

            if (!target) {
                return null;
            }

            if (dir === "h1" && target.previousSibling) {
                var position = domUtils.getXY(target),
                    cellWidth = target.offsetWidth;

                if (Math.abs(position.x + cellWidth - evt.clientX) > cellWidth / 3) {
                    target = target.previousSibling;
                }
            } else if (dir === "v1" && target.parentNode.previousSibling) {
                var position = domUtils.getXY(target),
                    cellHeight = target.offsetHeight;

                if (Math.abs(position.y + cellHeight - evt.clientY) > cellHeight / 3) {
                    target = target.parentNode.previousSibling.firstChild;
                }
            }

            //排除了非td内部以及用于代码高亮部分的td
            return target && !(editor.fireEvent("excludetable", target) === true)
                ? target
                : null;
        }
    };


// plugins/table.sort.js
    /**
     * Created with JetBrains PhpStorm.
     * User: Jinqn
     * Date: 13-10-12
     * Time: 上午10:20
     * To change this template use File | Settings | File Templates.
     */

    UE.UETable.prototype.sortTable = function (sortByCellIndex, compareFn) {
        var table = this.table,
            rows = table.rows,
            trArray = [],
            flag = rows[0].cells[0].tagName === "TH",
            lastRowIndex = 0;
        if (this.selectedTds.length) {
            var range = this.cellsRange,
                len = range.endRowIndex + 1;
            for (var i = range.beginRowIndex; i < len; i++) {
                trArray[i] = rows[i];
            }
            trArray.splice(0, range.beginRowIndex);
            lastRowIndex = range.endRowIndex + 1 === this.rowsNum
                ? 0
                : range.endRowIndex + 1;
        } else {
            for (var i = 0, len = rows.length; i < len; i++) {
                trArray[i] = rows[i];
            }
        }

        var Fn = {
            reversecurrent: function (td1, td2) {
                return 1;
            },
            orderbyasc: function (td1, td2) {
                var value1 = td1.innerText || td1.textContent,
                    value2 = td2.innerText || td2.textContent;
                return value1.localeCompare(value2);
            },
            reversebyasc: function (td1, td2) {
                var value1 = td1.innerHTML,
                    value2 = td2.innerHTML;
                return value2.localeCompare(value1);
            },
            orderbynum: function (td1, td2) {
                var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
                    value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
                if (value1) value1 = +value1[0];
                if (value2) value2 = +value2[0];
                return (value1 || 0) - (value2 || 0);
            },
            reversebynum: function (td1, td2) {
                var value1 = td1[browser.ie ? "innerText" : "textContent"].match(/\d+/),
                    value2 = td2[browser.ie ? "innerText" : "textContent"].match(/\d+/);
                if (value1) value1 = +value1[0];
                if (value2) value2 = +value2[0];
                return (value2 || 0) - (value1 || 0);
            }
        };

        //对表格设置排序的标记data-sort-type
        table.setAttribute(
            "data-sort-type",
            compareFn && typeof compareFn === "string" && Fn[compareFn] ? compareFn : ""
        );

        //th不参与排序
        flag && trArray.splice(0, 1);
        trArray = utils.sort(trArray, function (tr1, tr2) {
            var result;
            if (compareFn && typeof compareFn === "function") {
                result = compareFn.call(
                    this,
                    tr1.cells[sortByCellIndex],
                    tr2.cells[sortByCellIndex]
                );
            } else if (compareFn && typeof compareFn === "number") {
                result = 1;
            } else if (compareFn && typeof compareFn === "string" && Fn[compareFn]) {
                result = Fn[compareFn].call(
                    this,
                    tr1.cells[sortByCellIndex],
                    tr2.cells[sortByCellIndex]
                );
            } else {
                result = Fn["orderbyasc"].call(
                    this,
                    tr1.cells[sortByCellIndex],
                    tr2.cells[sortByCellIndex]
                );
            }
            return result;
        });
        var fragment = table.ownerDocument.createDocumentFragment();
        for (var j = 0, len = trArray.length; j < len; j++) {
            fragment.appendChild(trArray[j]);
        }
        var tbody = table.getElementsByTagName("tbody")[0];
        if (!lastRowIndex) {
            tbody.appendChild(fragment);
        } else {
            tbody.insertBefore(
                fragment,
                rows[lastRowIndex - range.endRowIndex + range.beginRowIndex - 1]
            );
        }
    };

    UE.plugins["tablesort"] = function () {
        var me = this,
            UT = UE.UETable,
            getUETable = function (tdOrTable) {
                return UT.getUETable(tdOrTable);
            },
            getTableItemsByRange = function (editor) {
                return UT.getTableItemsByRange(editor);
            };

        me.ready(function () {
            //添加表格可排序的样式
            utils.cssRule(
                "tablesort",
                "table.sortEnabled tr.firstRow th,table.sortEnabled tr.firstRow td{padding-right:20px;background-repeat: no-repeat;background-position: center right;" +
                "   background-image:url(" +
                me.options.themePath +
                me.options.theme +
                "/images/sortable.png);}",
                me.document
            );

            //做单元格合并操作时,清除可排序标识
            me.addListener("afterexeccommand", function (type, cmd) {
                if (cmd == "mergeright" || cmd == "mergedown" || cmd == "mergecells") {
                    this.execCommand("disablesort");
                }
            });
        });

        //表格排序
        UE.commands["sorttable"] = {
            queryCommandState: function () {
                var me = this,
                    tableItems = getTableItemsByRange(me);
                if (!tableItems.cell) return -1;
                var table = tableItems.table,
                    cells = table.getElementsByTagName("td");
                for (var i = 0, cell; (cell = cells[i++]);) {
                    if (cell.rowSpan != 1 || cell.colSpan != 1) return -1;
                }
                return 0;
            },
            execCommand: function (cmd, fn) {
                var me = this,
                    range = me.selection.getRange(),
                    bk = range.createBookmark(true),
                    tableItems = getTableItemsByRange(me),
                    cell = tableItems.cell,
                    ut = getUETable(tableItems.table),
                    cellInfo = ut.getCellInfo(cell);
                ut.sortTable(cellInfo.cellIndex, fn);
                range.moveToBookmark(bk);
                try {
                    range.select();
                } catch (e) {
                }
            }
        };

        //设置表格可排序,清除表格可排序
        UE.commands["enablesort"] = UE.commands["disablesort"] = {
            queryCommandState: function (cmd) {
                var table = getTableItemsByRange(this).table;
                if (table && cmd == "enablesort") {
                    var cells = domUtils.getElementsByTagName(table, "th td");
                    for (var i = 0; i < cells.length; i++) {
                        if (
                            cells[i].getAttribute("colspan") > 1 ||
                            cells[i].getAttribute("rowspan") > 1
                        )
                            return -1;
                    }
                }

                return !table
                    ? -1
                    : (cmd == "enablesort") ^
                    (table.getAttribute("data-sort") != "sortEnabled")
                        ? -1
                        : 0;
            },
            execCommand: function (cmd) {
                var table = getTableItemsByRange(this).table;
                table.setAttribute(
                    "data-sort",
                    cmd == "enablesort" ? "sortEnabled" : "sortDisabled"
                );
                table.setAttribute("style", "border-collapse:collapse;");
                cmd == "enablesort"
                    ? domUtils.addClass(table, "sortEnabled")
                    : domUtils.removeClasses(table, "sortEnabled");
            }
        };
    };


// plugins/contextmenu.js
///import core
///commands 右键菜单
///commandsName  ContextMenu
///commandsTitle  右键菜单
    /**
     * 右键菜单
     * @function
     * @name baidu.editor.plugins.contextmenu
     * @author zhanyi
     */

    UE.plugins["contextmenu"] = function () {
        var me = this;

        me.setOpt("enableContextMenu", me.getOpt("enableContextMenu") || true);

        if (me.getOpt("enableContextMenu") === false) {
            return;
        }
        var lang = me.getLang("contextMenu"),
            menu,
            items = me.options.contextMenu || [
                {label: lang["selectall"], cmdName: "selectall"},
                {
                    label: lang.cleardoc,
                    cmdName: "cleardoc",
                    exec: function () {
                        if (confirm(lang.confirmclear)) {
                            this.execCommand("cleardoc");
                        }
                    }
                },
                "-",
                {
                    label: lang.unlink,
                    cmdName: "unlink"
                },
                "-",
                {
                    group: lang.paragraph,
                    icon: "justifyjustify",
                    subMenu: [
                        {
                            label: lang.justifyleft,
                            cmdName: "justify",
                            value: "left"
                        },
                        {
                            label: lang.justifyright,
                            cmdName: "justify",
                            value: "right"
                        },
                        {
                            label: lang.justifycenter,
                            cmdName: "justify",
                            value: "center"
                        },
                        {
                            label: lang.justifyjustify,
                            cmdName: "justify",
                            value: "justify"
                        }
                    ]
                },
                "-",
                {
                    group: lang.table,
                    icon: "table",
                    subMenu: [
                        {
                            label: lang.inserttable,
                            cmdName: "inserttable"
                        },
                        {
                            label: lang.deletetable,
                            cmdName: "deletetable"
                        },
                        "-",
                        {
                            label: lang.deleterow,
                            cmdName: "deleterow"
                        },
                        {
                            label: lang.deletecol,
                            cmdName: "deletecol"
                        },
                        {
                            label: lang.insertcol,
                            cmdName: "insertcol"
                        },
                        {
                            label: lang.insertcolnext,
                            cmdName: "insertcolnext"
                        },
                        {
                            label: lang.insertrow,
                            cmdName: "insertrow"
                        },
                        {
                            label: lang.insertrownext,
                            cmdName: "insertrownext"
                        },
                        "-",
                        {
                            label: lang.insertcaption,
                            cmdName: "insertcaption"
                        },
                        {
                            label: lang.deletecaption,
                            cmdName: "deletecaption"
                        },
                        {
                            label: lang.inserttitle,
                            cmdName: "inserttitle"
                        },
                        {
                            label: lang.deletetitle,
                            cmdName: "deletetitle"
                        },
                        {
                            label: lang.inserttitlecol,
                            cmdName: "inserttitlecol"
                        },
                        {
                            label: lang.deletetitlecol,
                            cmdName: "deletetitlecol"
                        },
                        "-",
                        {
                            label: lang.mergecells,
                            cmdName: "mergecells"
                        },
                        {
                            label: lang.mergeright,
                            cmdName: "mergeright"
                        },
                        {
                            label: lang.mergedown,
                            cmdName: "mergedown"
                        },
                        "-",
                        {
                            label: lang.splittorows,
                            cmdName: "splittorows"
                        },
                        {
                            label: lang.splittocols,
                            cmdName: "splittocols"
                        },
                        {
                            label: lang.splittocells,
                            cmdName: "splittocells"
                        },
                        "-",
                        {
                            label: lang.averageDiseRow,
                            cmdName: "averagedistributerow"
                        },
                        {
                            label: lang.averageDisCol,
                            cmdName: "averagedistributecol"
                        },
                        "-",
                        {
                            label: lang.edittd,
                            cmdName: "edittd",
                            exec: function () {
                                if (UE.ui["edittd"]) {
                                    new UE.ui["edittd"](this);
                                }
                                this.getDialog("edittd").open();
                            }
                        },
                        {
                            label: lang.edittable,
                            cmdName: "edittable",
                            exec: function () {
                                if (UE.ui["edittable"]) {
                                    new UE.ui["edittable"](this);
                                }
                                this.getDialog("edittable").open();
                            }
                        },
                        {
                            label: lang.setbordervisible,
                            cmdName: "setbordervisible"
                        }
                    ]
                },
                {
                    group: lang.tablesort,
                    icon: "tablesort",
                    subMenu: [
                        {
                            label: lang.enablesort,
                            cmdName: "enablesort"
                        },
                        {
                            label: lang.disablesort,
                            cmdName: "disablesort"
                        },
                        "-",
                        {
                            label: lang.reversecurrent,
                            cmdName: "sorttable",
                            value: "reversecurrent"
                        },
                        {
                            label: lang.orderbyasc,
                            cmdName: "sorttable",
                            value: "orderbyasc"
                        },
                        {
                            label: lang.reversebyasc,
                            cmdName: "sorttable",
                            value: "reversebyasc"
                        },
                        {
                            label: lang.orderbynum,
                            cmdName: "sorttable",
                            value: "orderbynum"
                        },
                        {
                            label: lang.reversebynum,
                            cmdName: "sorttable",
                            value: "reversebynum"
                        }
                    ]
                },
                {
                    group: lang.borderbk,
                    icon: "borderBack",
                    subMenu: [
                        {
                            label: lang.setcolor,
                            cmdName: "interlacetable",
                            exec: function () {
                                this.execCommand("interlacetable");
                            }
                        },
                        {
                            label: lang.unsetcolor,
                            cmdName: "uninterlacetable",
                            exec: function () {
                                this.execCommand("uninterlacetable");
                            }
                        },
                        {
                            label: lang.setbackground,
                            cmdName: "settablebackground",
                            exec: function () {
                                this.execCommand("settablebackground", {
                                    repeat: true,
                                    colorList: ["#bbb", "#ccc"]
                                });
                            }
                        },
                        {
                            label: lang.unsetbackground,
                            cmdName: "cleartablebackground",
                            exec: function () {
                                this.execCommand("cleartablebackground");
                            }
                        },
                        {
                            label: lang.redandblue,
                            cmdName: "settablebackground",
                            exec: function () {
                                this.execCommand("settablebackground", {
                                    repeat: true,
                                    colorList: ["red", "blue"]
                                });
                            }
                        },
                        {
                            label: lang.threecolorgradient,
                            cmdName: "settablebackground",
                            exec: function () {
                                this.execCommand("settablebackground", {
                                    repeat: true,
                                    colorList: ["#aaa", "#bbb", "#ccc"]
                                });
                            }
                        }
                    ]
                },
                {
                    group: lang.aligntd,
                    icon: "aligntd",
                    subMenu: [
                        {
                            cmdName: "cellalignment",
                            value: {align: "left", vAlign: "top"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "center", vAlign: "top"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "right", vAlign: "top"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "left", vAlign: "middle"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "center", vAlign: "middle"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "right", vAlign: "middle"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "left", vAlign: "bottom"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "center", vAlign: "bottom"}
                        },
                        {
                            cmdName: "cellalignment",
                            value: {align: "right", vAlign: "bottom"}
                        }
                    ]
                },
                {
                    group: lang.aligntable,
                    icon: "aligntable",
                    subMenu: [
                        {
                            cmdName: "tablealignment",
                            className: "left",
                            label: lang.tableleft,
                            value: "left"
                        },
                        {
                            cmdName: "tablealignment",
                            className: "center",
                            label: lang.tablecenter,
                            value: "center"
                        },
                        {
                            cmdName: "tablealignment",
                            className: "right",
                            label: lang.tableright,
                            value: "right"
                        }
                    ]
                },
                "-",
                {
                    label: lang.insertparagraphbefore,
                    cmdName: "insertparagraph",
                    value: true
                },
                {
                    label: lang.insertparagraphafter,
                    cmdName: "insertparagraph"
                },
                {
                    label: lang["copy"],
                    cmdName: "copy"
                },
                {
                    label: lang["paste"],
                    cmdName: "paste"
                }
            ];
        if (!items.length) {
            return;
        }
        var uiUtils = UE.ui.uiUtils;

        me.addListener("contextmenu", function (type, evt) {
            var offset = uiUtils.getViewportOffsetByEvent(evt);
            me.fireEvent("beforeselectionchange");
            if (menu) {
                menu.destroy();
            }
            for (var i = 0, ti, contextItems = []; (ti = items[i]); i++) {
                var last;
                (function (item) {
                    if (item == "-") {
                        if ((last = contextItems[contextItems.length - 1]) && last !== "-") {
                            contextItems.push("-");
                        }
                    } else if (item.hasOwnProperty("group")) {
                        for (var j = 0, cj, subMenu = []; (cj = item.subMenu[j]); j++) {
                            (function (subItem) {
                                if (subItem == "-") {
                                    if ((last = subMenu[subMenu.length - 1]) && last !== "-") {
                                        subMenu.push("-");
                                    } else {
                                        subMenu.splice(subMenu.length - 1);
                                    }
                                } else {
                                    if (
                                        (me.commands[subItem.cmdName] ||
                                            UE.commands[subItem.cmdName] ||
                                            subItem.query) &&
                                        (subItem.query
                                            ? subItem.query()
                                            : me.queryCommandState(subItem.cmdName)) > -1
                                    ) {
                                        subMenu.push({
                                            label:
                                            subItem.label ||
                                            me.getLang(
                                                "contextMenu." +
                                                subItem.cmdName +
                                                (subItem.value || "")
                                            ) ||
                                            "",
                                            className:
                                            "edui-for-" +
                                            subItem.cmdName +
                                            (subItem.className
                                                ? " edui-for-" +
                                                subItem.cmdName +
                                                "-" +
                                                subItem.className
                                                : ""),
                                            onclick: subItem.exec
                                                ? function () {
                                                    subItem.exec.call(me);
                                                }
                                                : function () {
                                                    me.execCommand(subItem.cmdName, subItem.value);
                                                }
                                        });
                                    }
                                }
                            })(cj);
                        }
                        if (subMenu.length) {
                            function getLabel() {
                                switch (item.icon) {
                                    case "table":
                                        return me.getLang("contextMenu.table");
                                    case "justifyjustify":
                                        return me.getLang("contextMenu.paragraph");
                                    case "aligntd":
                                        return me.getLang("contextMenu.aligntd");
                                    case "aligntable":
                                        return me.getLang("contextMenu.aligntable");
                                    case "tablesort":
                                        return lang.tablesort;
                                    case "borderBack":
                                        return lang.borderbk;
                                    default:
                                        return "";
                                }
                            }

                            contextItems.push({
                                //todo 修正成自动获取方式
                                label: getLabel(),
                                className: "edui-for-" + item.icon,
                                subMenu: {
                                    items: subMenu,
                                    editor: me
                                }
                            });
                        }
                    } else {
                        //有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
                        if (
                            (me.commands[item.cmdName] ||
                                UE.commands[item.cmdName] ||
                                item.query) &&
                            (item.query
                                ? item.query.call(me)
                                : me.queryCommandState(item.cmdName)) > -1
                        ) {
                            contextItems.push({
                                label: item.label || me.getLang("contextMenu." + item.cmdName),
                                className:
                                "edui-for-" +
                                (item.icon ? item.icon : item.cmdName + (item.value || "")),
                                onclick: item.exec
                                    ? function () {
                                        item.exec.call(me);
                                    }
                                    : function () {
                                        me.execCommand(item.cmdName, item.value);
                                    }
                            });
                        }
                    }
                })(ti);
            }
            if (contextItems[contextItems.length - 1] == "-") {
                contextItems.pop();
            }

            menu = new UE.ui.Menu({
                items: contextItems,
                className: "edui-contextmenu",
                editor: me
            });
            menu.render();
            menu.showAt(offset);

            me.fireEvent("aftershowcontextmenu", menu);

            domUtils.preventDefault(evt);
            if (browser.ie) {
                var ieRange;
                try {
                    ieRange = me.selection.getNative().createRange();
                } catch (e) {
                    return;
                }
                if (ieRange.item) {
                    var range = new dom.Range(me.document);
                    range.selectNode(ieRange.item(0)).select(true, true);
                }
            }
        });

        // 添加复制的flash按钮
        me.addListener("aftershowcontextmenu", function (type, menu) {
            if (me.zeroclipboard) {
                var items = menu.items;
                for (var key in items) {
                    if (items[key].className == "edui-for-copy") {
                        me.zeroclipboard.clip(items[key].getDom());
                    }
                }
            }
        });
    };


// plugins/shortcutmenu.js
///import core
///commands       弹出菜单
// commandsName  popupmenu
///commandsTitle  弹出菜单
    /**
     * 弹出菜单
     * @function
     * @name baidu.editor.plugins.popupmenu
     * @author xuheng
     */

    UE.plugins["shortcutmenu"] = function () {
        var me = this,
            menu,
            items = me.options.shortcutMenu || [];

        if (!items.length) {
            return;
        }

        me.addListener("contextmenu mouseup", function (type, e) {
            var me = this,
                customEvt = {
                    type: type,
                    target: e.target || e.srcElement,
                    screenX: e.screenX,
                    screenY: e.screenY,
                    clientX: e.clientX,
                    clientY: e.clientY
                };

            setTimeout(function () {
                var rng = me.selection.getRange();
                if (rng.collapsed === false || type == "contextmenu") {
                    if (!menu) {
                        menu = new baidu.editor.ui.ShortCutMenu({
                            editor: me,
                            items: items,
                            theme: me.options.theme,
                            className: "edui-shortcutmenu"
                        });

                        menu.render();
                        me.fireEvent("afterrendershortcutmenu", menu);
                    }

                    menu.show(customEvt, !!UE.plugins["contextmenu"]);
                }
            });

            if (type == "contextmenu") {
                domUtils.preventDefault(e);
                if (browser.ie9below) {
                    var ieRange;
                    try {
                        ieRange = me.selection.getNative().createRange();
                    } catch (e) {
                        return;
                    }
                    if (ieRange.item) {
                        var range = new dom.Range(me.document);
                        range.selectNode(ieRange.item(0)).select(true, true);
                    }
                }
            }
        });

        me.addListener("keydown", function (type) {
            if (type == "keydown") {
                menu && !menu.isHidden && menu.hide();
            }
        });
    };


// plugins/basestyle.js
    /**
     * B、I、sub、super命令支持
     * @file
     * @since 1.2.6.1
     */

    UE.plugins["basestyle"] = function () {
        /**
         * 字体加粗
         * @command bold
         * @param { String } cmd 命令字符串
         * @remind 对已加粗的文本内容执行该命令, 将取消加粗
         * @method execCommand
         * @example
         * ```javascript
         * //editor是编辑器实例
         * //对当前选中的文本内容执行加粗操作
         * //第一次执行, 文本内容加粗
         * editor.execCommand( 'bold' );
         *
         * //第二次执行, 文本内容取消加粗
         * editor.execCommand( 'bold' );
         * ```
         */

        /**
         * 字体倾斜
         * @command italic
         * @method execCommand
         * @param { String } cmd 命令字符串
         * @remind 对已倾斜的文本内容执行该命令, 将取消倾斜
         * @example
         * ```javascript
         * //editor是编辑器实例
         * //对当前选中的文本内容执行斜体操作
         * //第一次操作, 文本内容将变成斜体
         * editor.execCommand( 'italic' );
         *
         * //再次对同一文本内容执行, 则文本内容将恢复正常
         * editor.execCommand( 'italic' );
         * ```
         */

        /**
         * 下标文本,与“superscript”命令互斥
         * @command subscript
         * @method execCommand
         * @remind  把选中的文本内容切换成下标文本, 如果当前选中的文本已经是下标, 则该操作会把文本内容还原成正常文本
         * @param { String } cmd 命令字符串
         * @example
         * ```javascript
         * //editor是编辑器实例
         * //对当前选中的文本内容执行下标操作
         * //第一次操作, 文本内容将变成下标文本
         * editor.execCommand( 'subscript' );
         *
         * //再次对同一文本内容执行, 则文本内容将恢复正常
         * editor.execCommand( 'subscript' );
         * ```
         */

        /**
         * 上标文本,与“subscript”命令互斥
         * @command superscript
         * @method execCommand
         * @remind 把选中的文本内容切换成上标文本, 如果当前选中的文本已经是上标, 则该操作会把文本内容还原成正常文本
         * @param { String } cmd 命令字符串
         * @example
         * ```javascript
         * //editor是编辑器实例
         * //对当前选中的文本内容执行上标操作
         * //第一次操作, 文本内容将变成上标文本
         * editor.execCommand( 'superscript' );
         *
         * //再次对同一文本内容执行, 则文本内容将恢复正常
         * editor.execCommand( 'superscript' );
         * ```
         */
        var basestyles = {
                bold: ["strong", "b"],
                italic: ["em", "i"],
                subscript: ["sub"],
                superscript: ["sup"]
            },
            getObj = function (editor, tagNames) {
                return domUtils.filterNodeList(
                    editor.selection.getStartElementPath(),
                    tagNames
                );
            },
            me = this;
        //添加快捷键
        me.addshortcutkey({
            Bold: "ctrl+66", //^B
            Italic: "ctrl+73", //^I
            Underline: "ctrl+85" //^U
        });
        me.addInputRule(function (root) {
            utils.each(root.getNodesByTagName("b i"), function (node) {
                switch (node.tagName) {
                    case "b":
                        node.tagName = "strong";
                        break;
                    case "i":
                        node.tagName = "em";
                }
            });
        });
        for (var style in basestyles) {
            (function (cmd, tagNames) {
                me.commands[cmd] = {
                    execCommand: function (cmdName) {
                        var range = me.selection.getRange(),
                            obj = getObj(this, tagNames);
                        if (range.collapsed) {
                            if (obj) {
                                var tmpText = me.document.createTextNode("");
                                range.insertNode(tmpText).removeInlineStyle(tagNames);
                                range.setStartBefore(tmpText);
                                domUtils.remove(tmpText);
                            } else {
                                var tmpNode = range.document.createElement(tagNames[0]);
                                if (cmdName == "superscript" || cmdName == "subscript") {
                                    tmpText = me.document.createTextNode("");
                                    range
                                        .insertNode(tmpText)
                                        .removeInlineStyle(["sub", "sup"])
                                        .setStartBefore(tmpText)
                                        .collapse(true);
                                }
                                range.insertNode(tmpNode).setStart(tmpNode, 0);
                            }
                            range.collapse(true);
                        } else {
                            if (cmdName == "superscript" || cmdName == "subscript") {
                                if (!obj || obj.tagName.toLowerCase() != cmdName) {
                                    range.removeInlineStyle(["sub", "sup"]);
                                }
                            }
                            obj
                                ? range.removeInlineStyle(tagNames)
                                : range.applyInlineStyle(tagNames[0]);
                        }
                        range.select();
                    },
                    queryCommandState: function () {
                        return getObj(this, tagNames) ? 1 : 0;
                    }
                };
            })(style, basestyles[style]);
        }
    };


// plugins/elementpath.js
    /**
     * 选取路径命令
     * @file
     */
    UE.plugins["elementpath"] = function () {
        var currentLevel,
            tagNames,
            me = this;
        me.setOpt("elementPathEnabled", true);
        if (!me.options.elementPathEnabled) {
            return;
        }
        me.commands["elementpath"] = {
            execCommand: function (cmdName, level) {
                var start = tagNames[level],
                    range = me.selection.getRange();
                currentLevel = level * 1;
                range.selectNode(start).select();
            },
            queryCommandValue: function () {
                //产生一个副本,不能修改原来的startElementPath;
                var parents = [].concat(this.selection.getStartElementPath()).reverse(),
                    names = [];
                tagNames = parents;
                for (var i = 0, ci; (ci = parents[i]); i++) {
                    if (ci.nodeType == 3) {
                        continue;
                    }
                    var name = ci.tagName.toLowerCase();
                    if (name == "img" && ci.getAttribute("anchorname")) {
                        name = "anchor";
                    }
                    names[i] = name;
                    if (currentLevel == i) {
                        currentLevel = -1;
                        break;
                    }
                }
                return names;
            }
        };
    };


// plugins/formatmatch.js
    /**
     * 格式刷,只格式inline的
     * @file
     * @since 1.2.6.1
     */

    /**
     * 格式刷
     * @command formatmatch
     * @method execCommand
     * @remind 该操作不能复制段落格式
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * //editor是编辑器实例
     * //获取格式刷
     * editor.execCommand( 'formatmatch' );
     * ```
     */
    UE.plugins["formatmatch"] = function () {
        var me = this,
            list = [],
            img,
            flag = 0;

        me.addListener("reset", function () {
            list = [];
            flag = 0;
        });

        function addList(type, evt) {
            if (browser.webkit) {
                var target = evt.target.tagName == "IMG" ? evt.target : null;
            }

            function addFormat(range) {
                if (text) {
                    range.selectNode(text);
                }
                return range.applyInlineStyle(list[list.length - 1].tagName, null, list);
            }

            me.undoManger && me.undoManger.save();

            var range = me.selection.getRange(),
                imgT = target || range.getClosedNode();
            if (img && imgT && imgT.tagName == "IMG") {
                //trace:964

                imgT.style.cssText +=
                    ";float:" +
                    (img.style.cssFloat || img.style.styleFloat || "none") +
                    ";display:" +
                    (img.style.display || "inline");

                img = null;
            } else {
                if (!img) {
                    var collapsed = range.collapsed;
                    if (collapsed) {
                        var text = me.document.createTextNode("match");
                        range.insertNode(text).select();
                    }
                    me.__hasEnterExecCommand = true;
                    //不能把block上的属性干掉
                    //trace:1553
                    var removeFormatAttributes = me.options.removeFormatAttributes;
                    me.options.removeFormatAttributes = "";
                    me.execCommand("removeformat");
                    me.options.removeFormatAttributes = removeFormatAttributes;
                    me.__hasEnterExecCommand = false;
                    //trace:969
                    range = me.selection.getRange();
                    if (list.length) {
                        addFormat(range);
                    }
                    if (text) {
                        range.setStartBefore(text).collapse(true);
                    }
                    range.select();
                    text && domUtils.remove(text);
                }
            }

            me.undoManger && me.undoManger.save();
            me.removeListener("mouseup", addList);
            flag = 0;
        }

        me.commands["formatmatch"] = {
            execCommand: function (cmdName) {
                if (flag) {
                    flag = 0;
                    list = [];
                    me.removeListener("mouseup", addList);
                    return;
                }

                var range = me.selection.getRange();
                img = range.getClosedNode();
                if (!img || img.tagName != "IMG") {
                    range.collapse(true).shrinkBoundary();
                    var start = range.startContainer;
                    list = domUtils.findParents(start, true, function (node) {
                        return !domUtils.isBlockElm(node) && node.nodeType == 1;
                    });
                    //a不能加入格式刷, 并且克隆节点
                    for (var i = 0, ci; (ci = list[i]); i++) {
                        if (ci.tagName == "A") {
                            list.splice(i, 1);
                            break;
                        }
                    }
                }

                me.addListener("mouseup", addList);
                flag = 1;
            },
            queryCommandState: function () {
                return flag;
            },
            notNeedUndo: 1
        };
    };


// plugins/searchreplace.js
///import core
///commands 查找替换
///commandsName  SearchReplace
///commandsTitle  查询替换
///commandsDialog  dialogs\searchreplace
    /**
     * @description 查找替换
     * @author zhanyi
     */

    UE.plugin.register("searchreplace", function () {
        var me = this;

        var _blockElm = {table: 1, tbody: 1, tr: 1, ol: 1, ul: 1};

        var lastRng = null;

        function getText(node) {
            var text = node.nodeType == 3
                ? node.nodeValue
                : node[browser.ie ? "innerText" : "textContent"];
            return text.replace(domUtils.fillChar, "");
        }

        function findTextInString(textContent, opt, currentIndex) {
            var str = opt.searchStr;

            var reg = new RegExp(str, "g" + (opt.casesensitive ? "" : "i")),
                match;

            if (opt.dir == -1) {
                textContent = textContent.substr(0, currentIndex);
                textContent = textContent.split("").reverse().join("");
                str = str.split("").reverse().join("");
                match = reg.exec(textContent);
                if (match) {
                    return currentIndex - match.index - str.length;
                }
            } else {
                textContent = textContent.substr(currentIndex);
                match = reg.exec(textContent);
                if (match) {
                    return match.index + currentIndex;
                }
            }

            return -1;
        }

        function findTextBlockElm(node, currentIndex, opt) {
            var textContent,
                index,
                methodName = opt.all || opt.dir == 1 ? "getNextDomNode" : "getPreDomNode";
            if (domUtils.isBody(node)) {
                node = node.firstChild;
            }
            var first = 1;
            while (node) {
                textContent = getText(node);
                index = findTextInString(textContent, opt, currentIndex);
                first = 0;
                if (index != -1) {
                    return {
                        node: node,
                        index: index
                    };
                }
                node = domUtils[methodName](node);
                while (node && _blockElm[node.nodeName.toLowerCase()]) {
                    node = domUtils[methodName](node, true);
                }
                if (node) {
                    currentIndex = opt.dir == -1 ? getText(node).length : 0;
                }
            }
        }

        function findNTextInBlockElm(node, index, str) {
            var currentIndex = 0,
                currentNode = node.firstChild,
                currentNodeLength = 0,
                result;
            while (currentNode) {
                if (currentNode.nodeType == 3) {
                    currentNodeLength = getText(currentNode).replace(
                        /(^[\t\r\n]+)|([\t\r\n]+$)/,
                        ""
                    ).length;
                    currentIndex += currentNodeLength;
                    if (currentIndex >= index) {
                        return {
                            node: currentNode,
                            index: currentNodeLength - (currentIndex - index)
                        };
                    }
                } else if (!dtd.$empty[currentNode.tagName]) {
                    currentNodeLength = getText(currentNode).replace(
                        /(^[\t\r\n]+)|([\t\r\n]+$)/,
                        ""
                    ).length;
                    currentIndex += currentNodeLength;
                    if (currentIndex >= index) {
                        result = findNTextInBlockElm(
                            currentNode,
                            currentNodeLength - (currentIndex - index),
                            str
                        );
                        if (result) {
                            return result;
                        }
                    }
                }
                currentNode = domUtils.getNextDomNode(currentNode);
            }
        }

        function searchReplace(me, opt) {
            var rng = lastRng || me.selection.getRange(),
                startBlockNode,
                searchStr = opt.searchStr,
                span = me.document.createElement("span");
            span.innerHTML = "$$ueditor_searchreplace_key$$";

            rng.shrinkBoundary(true);

            //判断是不是第一次选中
            if (!rng.collapsed) {
                rng.select();
                var rngText = me.selection.getText();
                if (
                    new RegExp(
                        "^" + opt.searchStr + "$",
                        opt.casesensitive ? "" : "i"
                    ).test(rngText)
                ) {
                    if (opt.replaceStr != undefined) {
                        replaceText(rng, opt.replaceStr);
                        rng.select();
                        return true;
                    } else {
                        rng.collapse(opt.dir == -1);
                    }
                }
            }

            rng.insertNode(span);
            rng.enlargeToBlockElm(true);
            startBlockNode = rng.startContainer;
            var currentIndex = getText(startBlockNode).indexOf(
                "$$ueditor_searchreplace_key$$"
            );
            rng.setStartBefore(span);
            domUtils.remove(span);
            var result = findTextBlockElm(startBlockNode, currentIndex, opt);
            if (result) {
                var rngStart = findNTextInBlockElm(result.node, result.index, searchStr);
                var rngEnd = findNTextInBlockElm(
                    result.node,
                    result.index + searchStr.length,
                    searchStr
                );
                rng
                    .setStart(rngStart.node, rngStart.index)
                    .setEnd(rngEnd.node, rngEnd.index);

                if (opt.replaceStr !== undefined) {
                    replaceText(rng, opt.replaceStr);
                }
                rng.select();
                return true;
            } else {
                rng.setCursor();
            }
        }

        function replaceText(rng, str) {
            str = me.document.createTextNode(str);
            rng.deleteContents().insertNode(str);
        }

        return {
            commands: {
                searchreplace: {
                    execCommand: function (cmdName, opt) {
                        utils.extend(
                            opt,
                            {
                                all: false,
                                casesensitive: false,
                                dir: 1
                            },
                            true
                        );
                        var num = 0;
                        if (opt.all) {
                            lastRng = null;
                            var rng = me.selection.getRange(),
                                first = me.body.firstChild;
                            if (first && first.nodeType == 1) {
                                rng.setStart(first, 0);
                                rng.shrinkBoundary(true);
                            } else if (first.nodeType == 3) {
                                rng.setStartBefore(first);
                            }
                            rng.collapse(true).select(true);
                            if (opt.replaceStr !== undefined) {
                                me.fireEvent("saveScene");
                            }
                            while (searchReplace(this, opt)) {
                                num++;
                                lastRng = me.selection.getRange();
                                lastRng.collapse(opt.dir == -1);
                            }
                            if (num) {
                                me.fireEvent("saveScene");
                            }
                        } else {
                            if (opt.replaceStr !== undefined) {
                                me.fireEvent("saveScene");
                            }
                            if (searchReplace(this, opt)) {
                                num++;
                                lastRng = me.selection.getRange();
                                lastRng.collapse(opt.dir == -1);
                            }
                            if (num) {
                                me.fireEvent("saveScene");
                            }
                        }

                        return num;
                    },
                    notNeedUndo: 1
                }
            },
            bindEvents: {
                clearlastSearchResult: function () {
                    lastRng = null;
                }
            }
        };
    });


// plugins/customstyle.js
    /**
     * 自定义样式
     * @file
     * @since 1.2.6.1
     */

    /**
     * 根据config配置文件里“customstyle”选项的值对匹配的标签执行样式替换。
     * @command customstyle
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * editor.execCommand( 'customstyle' );
     * ```
     */
    UE.plugins["customstyle"] = function () {
        var me = this;
        me.setOpt({
            customstyle: [
                {
                    tag: "h1",
                    name: "tc",
                    style:
                        "font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;margin:0 0 20px 0;"
                },
                {
                    tag: "h1",
                    name: "tl",
                    style:
                        "font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:left;margin:0 0 10px 0;"
                },
                {
                    tag: "span",
                    name: "im",
                    style:
                        "font-size:16px;font-style:italic;font-weight:bold;line-height:18px;"
                },
                {
                    tag: "span",
                    name: "hi",
                    style:
                        "font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;"
                }
            ]
        });
        me.commands["customstyle"] = {
            execCommand: function (cmdName, obj) {
                var me = this,
                    tagName = obj.tag,
                    node = domUtils.findParent(
                        me.selection.getStart(),
                        function (node) {
                            return node.getAttribute("label");
                        },
                        true
                    ),
                    range,
                    bk,
                    tmpObj = {};
                for (var p in obj) {
                    if (obj[p] !== undefined) tmpObj[p] = obj[p];
                }
                delete tmpObj.tag;
                if (node && node.getAttribute("label") == obj.label) {
                    range = this.selection.getRange();
                    bk = range.createBookmark();
                    if (range.collapsed) {
                        //trace:1732 删掉自定义标签,要有p来回填站位
                        if (dtd.$block[node.tagName]) {
                            var fillNode = me.document.createElement("p");
                            domUtils.moveChild(node, fillNode);
                            node.parentNode.insertBefore(fillNode, node);
                            domUtils.remove(node);
                        } else {
                            domUtils.remove(node, true);
                        }
                    } else {
                        var common = domUtils.getCommonAncestor(bk.start, bk.end),
                            nodes = domUtils.getElementsByTagName(common, tagName);
                        if (new RegExp(tagName, "i").test(common.tagName)) {
                            nodes.push(common);
                        }
                        for (var i = 0, ni; (ni = nodes[i++]);) {
                            if (ni.getAttribute("label") == obj.label) {
                                var ps = domUtils.getPosition(ni, bk.start),
                                    pe = domUtils.getPosition(ni, bk.end);
                                if (
                                    (ps & domUtils.POSITION_FOLLOWING ||
                                        ps & domUtils.POSITION_CONTAINS) &&
                                    (pe & domUtils.POSITION_PRECEDING ||
                                        pe & domUtils.POSITION_CONTAINS)
                                )
                                    if (dtd.$block[tagName]) {
                                        var fillNode = me.document.createElement("p");
                                        domUtils.moveChild(ni, fillNode);
                                        ni.parentNode.insertBefore(fillNode, ni);
                                    }
                                domUtils.remove(ni, true);
                            }
                        }
                        node = domUtils.findParent(
                            common,
                            function (node) {
                                return node.getAttribute("label") == obj.label;
                            },
                            true
                        );
                        if (node) {
                            domUtils.remove(node, true);
                        }
                    }
                    range.moveToBookmark(bk).select();
                } else {
                    if (dtd.$block[tagName]) {
                        this.execCommand("paragraph", tagName, tmpObj, "customstyle");
                        range = me.selection.getRange();
                        if (!range.collapsed) {
                            range.collapse();
                            node = domUtils.findParent(
                                me.selection.getStart(),
                                function (node) {
                                    return node.getAttribute("label") == obj.label;
                                },
                                true
                            );
                            var pNode = me.document.createElement("p");
                            domUtils.insertAfter(node, pNode);
                            domUtils.fillNode(me.document, pNode);
                            range.setStart(pNode, 0).setCursor();
                        }
                    } else {
                        range = me.selection.getRange();
                        if (range.collapsed) {
                            node = me.document.createElement(tagName);
                            domUtils.setAttributes(node, tmpObj);
                            range.insertNode(node).setStart(node, 0).setCursor();

                            return;
                        }

                        bk = range.createBookmark();
                        range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select();
                    }
                }
            },
            queryCommandValue: function () {
                var parent = domUtils.filterNodeList(
                    this.selection.getStartElementPath(),
                    function (node) {
                        return node.getAttribute("label");
                    }
                );
                return parent ? parent.getAttribute("label") : "";
            }
        };
        //当去掉customstyle是,如果是块元素,用p代替
        me.addListener("keyup", function (type, evt) {
            var keyCode = evt.keyCode || evt.which;

            if (keyCode == 32 || keyCode == 13) {
                var range = me.selection.getRange();
                if (range.collapsed) {
                    var node = domUtils.findParent(
                        me.selection.getStart(),
                        function (node) {
                            return node.getAttribute("label");
                        },
                        true
                    );
                    if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
                        var p = me.document.createElement("p");
                        domUtils.insertAfter(node, p);
                        domUtils.fillNode(me.document, p);
                        domUtils.remove(node);
                        range.setStart(p, 0).setCursor();
                    }
                }
            }
        });
    };


// plugins/catchremoteimage.js
///import core
///commands 远程图片抓取
///commandsName  catchRemoteImage,catchremoteimageenable
///commandsTitle  远程图片抓取
    /**
     * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
     */
    UE.plugins["catchremoteimage"] = function () {
        var me = this,
            ajax = UE.ajax;

        /* 设置默认值 */
        if (me.options.catchRemoteImageEnable === false) return;
        me.setOpt({
            catchRemoteImageEnable: false
        });

        me.addListener("afterpaste", function () {
            me.fireEvent("catchRemoteImage");
        });

        me.addListener("catchRemoteImage", function () {
            var catcherLocalDomain = me.getOpt("catcherLocalDomain"),
                catcherActionUrl = me.getActionUrl(me.getOpt("catcherActionName")),
                catcherUrlPrefix = me.getOpt("catcherUrlPrefix"),
                catcherFieldName = me.getOpt("catcherFieldName");

            var remoteImages = [],
                loadingIMG = me.options.themePath + me.options.theme + '/images/spacer.gif',
                imgs = me.document.querySelectorAll('[style*="url"],img'),
                test = function (src, urls) {
                    if (src.indexOf(location.host) != -1 || /(^\.)|(^\/)/.test(src)) {
                        return true;
                    }
                    if (urls) {
                        for (var j = 0, url; (url = urls[j++]);) {
                            if (src.indexOf(url) !== -1) {
                                return true;
                            }
                        }
                    }
                    return false;
                };

            for (var i = 0, ci; (ci = imgs[i++]);) {
                if (ci.getAttribute("word_img")) {
                    continue;
                }
                if (ci.nodeName == "IMG") {
                    var src = ci.getAttribute("_src") || ci.src || "";
                    if (/^(https?|ftp):/i.test(src) && !test(src, catcherLocalDomain)) {
                        remoteImages.push(src);
                        // 添加上传时的uploading动画
                        domUtils.setAttributes(ci, {
                            class: "loadingclass",
                            _src: src,
                            src: loadingIMG
                        })
                    }
                } else {
                    // 获取背景图片url
                    var backgroundImageurl = ci.style.cssText.replace(/.*\s?url\([\'\"]?/, '').replace(/[\'\"]?\).*/, '');
                    if (/^(https?|ftp):/i.test(backgroundImageurl) && !test(backgroundImageurl, catcherLocalDomain)) {
                        remoteImages.push(backgroundImageurl);
                        ci.style.cssText = ci.style.cssText.replace(backgroundImageurl, loadingIMG);
                        domUtils.setAttributes(ci, {
                            "data-background": backgroundImageurl
                        })
                    }
                }
            }

            if (remoteImages.length) {
                catchremoteimage(remoteImages, {
                    //成功抓取
                    success: function (r) {
                        try {
                            var info = r.state !== undefined
                                ? r
                                : eval("(" + r.responseText + ")");
                        } catch (e) {
                            return;
                        }

                        /* 获取源路径和新路径 */
                        var i,
                            j,
                            ci,
                            cj,
                            oldSrc,
                            newSrc,
                            list = info.list;

                        /* 抓取失败统计 */
                        var catchFailList = [];
                        /* 抓取成功统计 */
                        var catchSuccessList = [];
                        /* 抓取失败时显示的图片 */
                        var failIMG = me.options.themePath + me.options.theme + '/images/img-cracked.png';

                        for (i = 0; ci = imgs[i++];) {
                            oldSrc = ci.getAttribute("_src") || ci.src || "";
                            oldBgIMG = ci.getAttribute("data-background") || "";
                            for (j = 0; cj = list[j++];) {
                                if (oldSrc == cj.source && cj.state == "SUCCESS") {
                                    newSrc = catcherUrlPrefix + cj.url;
                                    // 上传成功是删除uploading动画
                                    domUtils.removeClasses(ci, "loadingclass");
                                    domUtils.setAttributes(ci, {
                                        "src": newSrc,
                                        "_src": newSrc,
                                        "data-catchResult": "img_catchSuccess"   // 添加catch成功标记
                                    });
                                    catchSuccessList.push(ci);
                                    break;
                                } else if (oldSrc == cj.source && cj.state == "FAIL") {
                                    // 替换成统一的失败图片
                                    domUtils.removeClasses(ci, "loadingclass");
                                    domUtils.setAttributes(ci, {
                                        "src": failIMG,
                                        "_src": failIMG,
                                        "data-catchResult": "img_catchFail" // 添加catch失败标记
                                    });
                                    catchFailList.push(ci);
                                    break;
                                } else if (oldBgIMG == cj.source && cj.state == "SUCCESS") {
                                    newBgIMG = catcherUrlPrefix + cj.url;
                                    ci.style.cssText = ci.style.cssText.replace(loadingIMG, newBgIMG);
                                    domUtils.removeAttributes(ci, "data-background");
                                    domUtils.setAttributes(ci, {
                                        "data-catchResult": "img_catchSuccess"   // 添加catch成功标记
                                    });
                                    catchSuccessList.push(ci);
                                    break;
                                } else if (oldBgIMG == cj.source && cj.state == "FAIL") {
                                    ci.style.cssText = ci.style.cssText.replace(loadingIMG, failIMG);
                                    domUtils.removeAttributes(ci, "data-background");
                                    domUtils.setAttributes(ci, {
                                        "data-catchResult": "img_catchFail"   // 添加catch失败标记
                                    });
                                    catchFailList.push(ci);
                                    break;
                                }
                            }

                        }
                        // 监听事件添加成功抓取和抓取失败的dom列表参数
                        me.fireEvent('catchremotesuccess', catchSuccessList, catchFailList);
                    },
                    //回调失败,本次请求超时
                    error: function () {
                        me.fireEvent("catchremoteerror");
                    }
                });
            }

            function catchremoteimage(imgs, callbacks) {
                var params =
                    utils.serializeParam(me.queryCommandValue("serverparam")) || "",
                    url = utils.formatUrl(
                        catcherActionUrl +
                        (catcherActionUrl.indexOf("?") == -1 ? "?" : "&") +
                        params
                    ),
                    isJsonp = utils.isCrossDomainUrl(url),
                    opt = {
                        method: "POST",
                        dataType: isJsonp ? "jsonp" : "",
                        timeout: 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
                        onsuccess: callbacks["success"],
                        onerror: callbacks["error"]
                    };
                opt[catcherFieldName] = imgs;
                ajax.request(url, opt);
            }
        });
    };


// plugins/snapscreen.js
    /**
     * 截屏插件,为UEditor提供插入支持
     * @file
     * @since 1.4.2
     */
    UE.plugin.register("snapscreen", function () {
        var me = this;
        var snapplugin;

        function getLocation(url) {
            var search,
                a = document.createElement("a"),
                params = utils.serializeParam(me.queryCommandValue("serverparam")) || "";

            a.href = url;
            if (browser.ie) {
                a.href = a.href;
            }

            search = a.search;
            if (params) {
                search = search + (search.indexOf("?") == -1 ? "?" : "&") + params;
                search = search.replace(/[&]+/gi, "&");
            }
            return {
                port: a.port,
                hostname: a.hostname,
                path: a.pathname + search || +a.hash
            };
        }

        return {
            commands: {
                /**
                 * 字体背景颜色
                 * @command snapscreen
                 * @method execCommand
                 * @param { String } cmd 命令字符串
                 * @example
                 * ```javascript
                 * editor.execCommand('snapscreen');
                 * ```
                 */
                snapscreen: {
                    execCommand: function (cmd) {
                        var url, local, res;
                        var lang = me.getLang("snapScreen_plugin");

                        if (!snapplugin) {
                            var container = me.container;
                            var doc = me.container.ownerDocument || me.container.document;
                            snapplugin = doc.createElement("object");
                            try {
                                snapplugin.type = "application/x-pluginbaidusnap";
                            } catch (e) {
                                return;
                            }
                            snapplugin.style.cssText =
                                "position:absolute;left:-9999px;width:0;height:0;";
                            snapplugin.setAttribute("width", "0");
                            snapplugin.setAttribute("height", "0");
                            container.appendChild(snapplugin);
                        }

                        function onSuccess(rs) {
                            try {
                                rs = eval("(" + rs + ")");
                                if (rs.state == "SUCCESS") {
                                    var opt = me.options;
                                    me.execCommand("insertimage", {
                                        src: opt.snapscreenUrlPrefix + rs.url,
                                        _src: opt.snapscreenUrlPrefix + rs.url,
                                        alt: rs.title || "",
                                        floatStyle: opt.snapscreenImgAlign
                                    });
                                } else {
                                    alert(rs.state);
                                }
                            } catch (e) {
                                alert(lang.callBackErrorMsg);
                            }
                        }

                        url = me.getActionUrl(me.getOpt("snapscreenActionName"));
                        local = getLocation(url);
                        setTimeout(function () {
                            try {
                                res = snapplugin.saveSnapshot(
                                    local.hostname,
                                    local.path,
                                    local.port
                                );
                            } catch (e) {
                                me.ui._dialogs["snapscreenDialog"].open();
                                return;
                            }

                            onSuccess(res);
                        }, 50);
                    },
                    queryCommandState: function () {
                        return navigator.userAgent.indexOf("Windows", 0) != -1 ? 0 : -1;
                    }
                }
            }
        };
    });


// plugins/insertparagraph.js
    /**
     * 插入段落
     * @file
     * @since 1.2.6.1
     */

    /**
     * 插入段落
     * @command insertparagraph
     * @method execCommand
     * @param { String } cmd 命令字符串
     * @example
     * ```javascript
     * //editor是编辑器实例
     * editor.execCommand( 'insertparagraph' );
     * ```
     */

    UE.commands["insertparagraph"] = {
        execCommand: function (cmdName, front) {
            var me = this,
                range = me.selection.getRange(),
                start = range.startContainer,
                tmpNode;
            while (start) {
                if (domUtils.isBody(start)) {
                    break;
                }
                tmpNode = start;
                start = start.parentNode;
            }
            if (tmpNode) {
                var p = me.document.createElement("p");
                if (front) {
                    tmpNode.parentNode.insertBefore(p, tmpNode);
                } else {
                    tmpNode.parentNode.insertBefore(p, tmpNode.nextSibling);
                }
                domUtils.fillNode(me.document, p);
                range.setStart(p, 0).setCursor(false, true);
            }
        }
    };


// plugins/webapp.js
    /**
     * 百度应用
     * @file
     * @since 1.2.6.1
     */

    /**
     * 插入百度应用
     * @command webapp
     * @method execCommand
     * @remind 需要百度APPKey
     * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
     * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
     * height=>应用容器高度,logo=>应用logo,url=>应用地址
     * @example
     * ```javascript
     * //editor是编辑器实例
     * //在编辑器里插入一个“植物大战僵尸”的APP
     * editor.execCommand( 'webapp' , {
 *     title: '植物大战僵尸',
 *     width: 560,
 *     height: 465,
 *     logo: '应用展示的图片',
 *     url: '百度应用的地址'
 * } );
     * ```
     */

//UE.plugins['webapp'] = function () {
//    var me = this;
//    function createInsertStr( obj, toIframe, addParagraph ) {
//        return !toIframe ?
//                (addParagraph ? '<p>' : '') + '<img title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"' +
//                        ' src="' + me.options.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif" style="background:url(' + obj.logo+') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' + obj.url + '" />' +
//                        (addParagraph ? '</p>' : '')
//                :
//                '<iframe class="edui-faked-webapp" title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"  scrolling="no" frameborder="0" src="' + obj.url + '" logo_url = '+obj.logo+'></iframe>';
//    }
//
//    function switchImgAndIframe( img2frame ) {
//        var tmpdiv,
//                nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
//        for ( var i = 0, node; node = nodes[i++]; ) {
//            if ( node.className != "edui-faked-webapp" ){
//                continue;
//            }
//            tmpdiv = me.document.createElement( "div" );
//            tmpdiv.innerHTML = createInsertStr( img2frame ? {url:node.getAttribute( "_url" ), width:node.width, height:node.height,title:node.title,logo:node.style.backgroundImage.replace("url(","").replace(")","")} : {url:node.getAttribute( "src", 2 ),title:node.title, width:node.width, height:node.height,logo:node.getAttribute("logo_url")}, img2frame ? true : false,false );
//            node.parentNode.replaceChild( tmpdiv.firstChild, node );
//        }
//    }
//
//    me.addListener( "beforegetcontent", function () {
//        switchImgAndIframe( true );
//    } );
//    me.addListener( 'aftersetcontent', function () {
//        switchImgAndIframe( false );
//    } );
//    me.addListener( 'aftergetcontent', function ( cmdName ) {
//        if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
//            return;
//        }
//        switchImgAndIframe( false );
//    } );
//
//    me.commands['webapp'] = {
//        execCommand:function ( cmd, obj ) {
//            me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
//        }
//    };
//};

    UE.plugin.register("webapp", function () {
        var me = this;

        function createInsertStr(obj, toEmbed) {
            return !toEmbed
                ? '<img title="' +
                obj.title +
                '" width="' +
                obj.width +
                '" height="' +
                obj.height +
                '"' +
                ' src="' +
                me.options.UEDITOR_HOME_URL +
                'themes/notadd/images/spacer.gif" _logo_url="' +
                obj.logo +
                '" style="background:url(' +
                obj.logo +
                ') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' +
                obj.url +
                '" ' +
                (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : "") +
                (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : "") +
                "/>"
                : '<iframe class="edui-faked-webapp" title="' +
                obj.title +
                '" ' +
                (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : "") +
                (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : "") +
                'width="' +
                obj.width +
                '" height="' +
                obj.height +
                '"  scrolling="no" frameborder="0" src="' +
                obj.url +
                '" logo_url = "' +
                obj.logo +
                '"></iframe>';
        }

        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 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
                 * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
                 * height=>应用容器高度,logo=>应用logo,url=>应用地址
                 * @example
                 * ```javascript
                 * //editor是编辑器实例
                 * //在编辑器里插入一个“植物大战僵尸”的APP
                 * editor.execCommand( 'webapp' , {
             *     title: '植物大战僵尸',
             *     width: 560,
             *     height: 465,
             *     logo: '应用展示的图片',
             *     url: '百度应用的地址'
             * } );
                 * ```
                 */
                webapp: {
                    execCommand: function (cmd, obj) {
                        var me = this,
                            str = createInsertStr(
                                utils.extend(obj, {
                                    align: "none"
                                }),
                                false
                            );
                        me.execCommand("inserthtml", str);
                    },
                    queryCommandState: function () {
                        var me = this,
                            img = me.selection.getRange().getClosedNode(),
                            flag = img && img.className == "edui-faked-webapp";
                        return flag ? 1 : 0;
                    }
                }
            }
        };
    });


// plugins/template.js
///import core
///import plugins\inserthtml.js
///import plugins\cleardoc.js
///commands 模板
///commandsName  template
///commandsTitle  模板
///commandsDialog  dialogs\template
    UE.plugins["template"] = function () {
        UE.commands["template"] = {
            execCommand: function (cmd, obj) {
                obj.html && this.execCommand("inserthtml", obj.html);
            }
        };
        this.addListener("click", function (type, evt) {
            var el = evt.target || evt.srcElement,
                range = this.selection.getRange();
            var tnode = domUtils.findParent(
                el,
                function (node) {
                    if (node.className && domUtils.hasClass(node, "ue_t")) {
                        return node;
                    }
                },
                true
            );
            tnode && range.selectNode(tnode).shrinkBoundary().select();
        });
        this.addListener("keydown", function (type, evt) {
            var range = this.selection.getRange();
            if (!range.collapsed) {
                if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
                    var tnode = domUtils.findParent(
                        range.startContainer,
                        function (node) {
                            if (node.className && domUtils.hasClass(node, "ue_t")) {
                                return node;
                            }
                        },
                        true
                    );
                    if (tnode) {
                        domUtils.removeClasses(tnode, ["ue_t"]);
                    }
                }
            }
        });
    };


// plugins/music.js
    /**
     * 插入音乐命令
     * @file
     */
    UE.plugin.register("music", function () {
        var me = this;

        function creatInsertStr(url, width, height, align, cssfloat, toEmbed) {
            return !toEmbed
                ? "<img " +
                (align && !cssfloat ? 'align="' + align + '"' : "") +
                (cssfloat ? 'style="float:' + cssfloat + '"' : "") +
                ' width="' +
                width +
                '" height="' +
                height +
                '" _url="' +
                url +
                '" class="edui-faked-music"' +
                ' src="' +
                me.options.langPath +
                me.options.lang +
                '/images/music.png" />'
                : '<embed type="application/x-shockwave-flash" class="edui-faked-music" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
                ' src="' +
                url +
                '" width="' +
                width +
                '" height="' +
                height +
                '" ' +
                (align && !cssfloat ? 'align="' + align + '"' : "") +
                (cssfloat ? 'style="float:' + cssfloat + '"' : "") +
                ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
        }

        return {
            outputRule: function (root) {
                utils.each(root.getNodesByTagName("img"), function (node) {
                    var html;
                    if (node.getAttr("class") == "edui-faked-music") {
                        var cssfloat = node.getStyle("float");
                        var align = node.getAttr("align");
                        html = creatInsertStr(
                            node.getAttr("_url"),
                            node.getAttr("width"),
                            node.getAttr("height"),
                            align,
                            cssfloat,
                            true
                        );
                        var embed = UE.uNode.createElement(html);
                        node.parentNode.replaceChild(embed, node);
                    }
                });
            },
            inputRule: function (root) {
                utils.each(root.getNodesByTagName("embed"), function (node) {
                    if (node.getAttr("class") == "edui-faked-music") {
                        var cssfloat = node.getStyle("float");
                        var align = node.getAttr("align");
                        html = creatInsertStr(
                            node.getAttr("src"),
                            node.getAttr("width"),
                            node.getAttr("height"),
                            align,
                            cssfloat,
                            false
                        );
                        var img = UE.uNode.createElement(html);
                        node.parentNode.replaceChild(img, node);
                    }
                });
            },
            commands: {
                /**
                 * 插入音乐
                 * @command music
                 * @method execCommand
                 * @param { Object } musicOptions 插入音乐的参数项, 支持的key有: url=>音乐地址;
                 * width=>音乐容器宽度;height=>音乐容器高度;align=>音乐文件的对齐方式, 可选值有: left, center, right, none
                 * @example
                 * ```javascript
                 * //editor是编辑器实例
                 * //在编辑器里插入一个“植物大战僵尸”的APP
                 * editor.execCommand( 'music' , {
             *     width: 400,
             *     height: 95,
             *     align: "center",
             *     url: "音乐地址"
             * } );
                 * ```
                 */
                music: {
                    execCommand: function (cmd, musicObj) {
                        var me = this,
                            str = creatInsertStr(
                                musicObj.url,
                                musicObj.width || 400,
                                musicObj.height || 95,
                                "none",
                                false
                            );
                        me.execCommand("inserthtml", str);
                    },
                    queryCommandState: function () {
                        var me = this,
                            img = me.selection.getRange().getClosedNode(),
                            flag = img && img.className == "edui-faked-music";
                        return flag ? 1 : 0;
                    }
                }
            }
        };
    });


// plugins/autoupload.js
    /**
     * @description
     * 1.拖放文件到编辑区域,自动上传并插入到选区
     * 2.插入粘贴板的图片,自动上传并插入到选区
     * @author Jinqn
     * @date 2013-10-14
     */
    UE.plugin.register("autoupload", function () {
        function sendAndInsertFile(file, editor) {
            var me = editor;
            //模拟数据
            var fieldName,
                urlPrefix,
                maxSize,
                allowFiles,
                actionUrl,
                loadingHtml,
                errorHandler,
                successHandler,
                filetype = /image\/\w+/i.test(file.type) ? "image" : "file",
                loadingId = "loading_" + (+new Date()).toString(36);

            fieldName = me.getOpt(filetype + "FieldName");
            urlPrefix = me.getOpt(filetype + "UrlPrefix");
            maxSize = me.getOpt(filetype + "MaxSize");
            allowFiles = me.getOpt(filetype + "AllowFiles");
            actionUrl = me.getActionUrl(me.getOpt(filetype + "ActionName"));
            errorHandler = function (title) {
                var loader = me.document.getElementById(loadingId);
                loader && domUtils.remove(loader);
                me.fireEvent("showmessage", {
                    id: loadingId,
                    content: title,
                    type: "error",
                    timeout: 4000
                });
            };

            if (filetype == "image") {
                loadingHtml =
                    '<img class="loadingclass" id="' +
                    loadingId +
                    '" src="' +
                    me.options.themePath +
                    me.options.theme +
                    '/images/spacer.gif">';
                successHandler = function (data) {
                    var link = urlPrefix + data.url,
                        loader = me.document.getElementById(loadingId);
                    if (loader) {
                        domUtils.removeClasses(loader, "loadingclass");
                        loader.setAttribute("src", link);
                        loader.setAttribute("_src", link);
                        loader.setAttribute("alt", data.original || "");
                        loader.removeAttribute("id");
                        me.trigger("contentchange", loader);
                    }
                };
            } else {
                loadingHtml =
                    "<p>" +
                    '<img class="loadingclass" id="' +
                    loadingId +
                    '" src="' +
                    me.options.themePath +
                    me.options.theme +
                    '/images/spacer.gif">' +
                    "</p>";
                successHandler = function (data) {
                    var link = urlPrefix + data.url,
                        loader = me.document.getElementById(loadingId);

                    var rng = me.selection.getRange(),
                        bk = rng.createBookmark();
                    rng.selectNode(loader).select();
                    me.execCommand("insertfile", {url: link});
                    rng.moveToBookmark(bk).select();
                };
            }

            /* 插入loading的占位符 */
            me.execCommand("inserthtml", loadingHtml);
            /* 判断后端配置是否没有加载成功 */
            if (!me.getOpt(filetype + "ActionName")) {
                errorHandler(me.getLang("autoupload.errorLoadConfig"));
                return;
            }
            /* 判断文件大小是否超出限制 */
            if (file.size > maxSize) {
                errorHandler(me.getLang("autoupload.exceedSizeError"));
                return;
            }
            /* 判断文件格式是否超出允许 */
            var fileext = file.name ? file.name.substr(file.name.lastIndexOf(".")) : "";
            if (
                (fileext && filetype != "image") ||
                (allowFiles &&
                    (allowFiles.join("") + ".").indexOf(fileext.toLowerCase() + ".") == -1)
            ) {
                errorHandler(me.getLang("autoupload.exceedTypeError"));
                return;
            }

            /* 创建Ajax并提交 */
            var xhr = new XMLHttpRequest(),
                fd = new FormData(),
                params = utils.serializeParam(me.queryCommandValue("serverparam")) || "",
                url = utils.formatUrl(
                    actionUrl + (actionUrl.indexOf("?") == -1 ? "?" : "&") + params
                );

            fd.append(
                fieldName,
                file,
                file.name || "blob." + file.type.substr("image/".length)
            );
            fd.append("type", "ajax");
            xhr.open("post", url, true);
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhr.addEventListener("load", function (e) {
                try {
                    var json = new Function("return " + utils.trim(e.target.response))();
                    if (json.state == "SUCCESS" && json.url) {
                        successHandler(json);
                    } else {
                        errorHandler(json.state);
                    }
                } catch (er) {
                    errorHandler(me.getLang("autoupload.loadError"));
                }
            });
            xhr.send(fd);
        }

        function getPasteImage(e) {
            return e.clipboardData &&
            e.clipboardData.items &&
            e.clipboardData.items.length == 1 &&
            /^image\//.test(e.clipboardData.items[0].type)
                ? e.clipboardData.items
                : null;
        }

        function getDropImage(e) {
            return e.dataTransfer && e.dataTransfer.files ? e.dataTransfer.files : null;
        }

        return {
            outputRule: function (root) {
                utils.each(root.getNodesByTagName("img"), function (n) {
                    if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr("class"))) {
                        n.parentNode.removeChild(n);
                    }
                });
                utils.each(root.getNodesByTagName("p"), function (n) {
                    if (/\bloadpara\b/.test(n.getAttr("class"))) {
                        n.parentNode.removeChild(n);
                    }
                });
            },
            bindEvents: {
                defaultOptions: {
                    //默认间隔时间
                    enableDragUpload: true,
                    enablePasteUpload: true
                },
                //插入粘贴板的图片,拖放插入图片
                ready: function (e) {
                    var me = this;
                    if (window.FormData && window.FileReader) {
                        var handler = function (e) {
                            var hasImg = false,
                                items;
                            //获取粘贴板文件列表或者拖放文件列表
                            items = e.type == "paste" ? getPasteImage(e) : getDropImage(e);
                            if (items) {
                                var len = items.length,
                                    file;
                                while (len--) {
                                    file = items[len];
                                    if (file.getAsFile) file = file.getAsFile();
                                    if (file && file.size > 0) {
                                        sendAndInsertFile(file, me);
                                        hasImg = true;
                                    }
                                }
                                hasImg && e.preventDefault();
                            }
                        };

                        if (me.getOpt("enablePasteUpload") !== false) {
                            domUtils.on(me.body, "paste ", handler);
                        }
                        if (me.getOpt("enableDragUpload") !== false) {
                            domUtils.on(me.body, "drop", handler);
                            //取消拖放图片时出现的文字光标位置提示
                            domUtils.on(me.body, "dragover", function (e) {
                                if (e.dataTransfer.types[0] == "Files") {
                                    e.preventDefault();
                                }
                            });
                        } else {
                            if (browser.gecko) {
                                domUtils.on(me.body, "drop", function (e) {
                                    if (getDropImage(e)) {
                                        e.preventDefault();
                                    }
                                });
                            }
                        }

                        //设置loading的样式
                        utils.cssRule(
                            "loading",
                            ".loadingclass{display:inline-block;cursor:default;background: url('" +
                            this.options.themePath +
                            this.options.theme +
                            "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-left:1px;height: 22px;width: 22px;}\n" +
                            ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
                            this.options.themePath +
                            this.options.theme +
                            "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
                            "}",
                            this.document
                        );
                    }
                }
            }
        };
    });


// plugins/autosave.js
    UE.plugin.register("autosave", function () {
        var me = this,
            //无限循环保护
            lastSaveTime = new Date(),
            //最小保存间隔时间
            MIN_TIME = 20,
            //auto save key
            saveKey = null;

        function save(editor) {
            var saveData;

            if (new Date() - lastSaveTime < MIN_TIME) {
                return;
            }

            if (!editor.hasContents()) {
                //这里不能调用命令来删除, 会造成事件死循环
                saveKey && me.removePreferences(saveKey);
                return;
            }

            lastSaveTime = new Date();

            editor._saveFlag = null;

            saveData = me.body.innerHTML;

            if (
                editor.fireEvent("beforeautosave", {
                    content: saveData
                }) === false
            ) {
                return;
            }

            me.setPreferences(saveKey, saveData);

            editor.fireEvent("afterautosave", {
                content: saveData
            });
        }

        return {
            defaultOptions: {
                //默认间隔时间
                saveInterval: 500,
                enableAutoSave: true
            },
            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) || "<p>" + domUtils.fillHtml + "</p>";
                            me.focus(true);
                        }
                    },
                    queryCommandState: function () {
                        return saveKey ? (me.getPreferences(saveKey) === null ? -1 : 0) : -1;
                    },
                    notNeedUndo: true,
                    ignoreContentChange: true
                }
            }
        };
    });


// plugins/charts.js
    UE.plugin.register("charts", function () {
        var me = this;

        return {
            bindEvents: {
                chartserror: function () {
                }
            },
            commands: {
                charts: {
                    execCommand: function (cmd, data) {
                        var tableNode = domUtils.findParentByTagName(
                            this.selection.getRange().startContainer,
                            "table",
                            true
                            ),
                            flagText = [],
                            config = {};

                        if (!tableNode) {
                            return false;
                        }

                        if (!validData(tableNode)) {
                            me.fireEvent("chartserror");
                            return false;
                        }

                        config.title = data.title || "";
                        config.subTitle = data.subTitle || "";
                        config.xTitle = data.xTitle || "";
                        config.yTitle = data.yTitle || "";
                        config.suffix = data.suffix || "";
                        config.tip = data.tip || "";
                        //数据对齐方式
                        config.dataFormat = data.tableDataFormat || "";
                        //图表类型
                        config.chartType = data.chartType || 0;

                        for (var key in config) {
                            if (!config.hasOwnProperty(key)) {
                                continue;
                            }

                            flagText.push(key + ":" + config[key]);
                        }

                        tableNode.setAttribute("data-chart", flagText.join(";"));
                        domUtils.addClass(tableNode, "edui-charts-table");
                    },
                    queryCommandState: function (cmd, name) {
                        var tableNode = domUtils.findParentByTagName(
                            this.selection.getRange().startContainer,
                            "table",
                            true
                        );
                        return tableNode && validData(tableNode) ? 0 : -1;
                    }
                }
            },
            inputRule: function (root) {
                utils.each(root.getNodesByTagName("table"), function (tableNode) {
                    if (tableNode.getAttr("data-chart") !== undefined) {
                        tableNode.setAttr("style");
                    }
                });
            },
            outputRule: function (root) {
                utils.each(root.getNodesByTagName("table"), function (tableNode) {
                    if (tableNode.getAttr("data-chart") !== undefined) {
                        tableNode.setAttr("style", "display: none;");
                    }
                });
            }
        };

        function validData(table) {
            var firstRows = null,
                cellCount = 0;

            //行数不够
            if (table.rows.length < 2) {
                return false;
            }

            //列数不够
            if (table.rows[0].cells.length < 2) {
                return false;
            }

            //第一行所有cell必须是th
            firstRows = table.rows[0].cells;
            cellCount = firstRows.length;

            for (var i = 0, cell; (cell = firstRows[i]); i++) {
                if (cell.tagName.toLowerCase() !== "th") {
                    return false;
                }
            }

            for (var i = 1, row; (row = table.rows[i]); i++) {
                //每行单元格数不匹配, 返回false
                if (row.cells.length != cellCount) {
                    return false;
                }

                //第一列不是th也返回false
                if (row.cells[0].tagName.toLowerCase() !== "th") {
                    return false;
                }

                for (var j = 1, cell; (cell = row.cells[j]); j++) {
                    var value = utils.trim(cell.innerText || cell.textContent || "");

                    value = value
                        .replace(new RegExp(UE.dom.domUtils.fillChar, "g"), "")
                        .replace(/^\s+|\s+$/g, "");

                    //必须是数字
                    if (!/^\d*\.?\d+$/.test(value)) {
                        return false;
                    }
                }
            }

            return true;
        }
    });


// plugins/section.js
    /**
     * 目录大纲支持插件
     * @file
     * @since 1.3.0
     */
    UE.plugin.register("section", function () {
        /* 目录节点对象 */
        function Section(option) {
            this.tag = "";
            (this.level = -1), (this.dom = null);
            this.nextSection = null;
            this.previousSection = null;
            this.parentSection = null;
            this.startAddress = [];
            this.endAddress = [];
            this.children = [];
        }

        function getSection(option) {
            var section = new Section();
            return utils.extend(section, option);
        }

        function getNodeFromAddress(startAddress, root) {
            var current = root;
            for (var i = 0; i < startAddress.length; i++) {
                if (!current.childNodes) return null;
                current = current.childNodes[startAddress[i]];
            }
            return current;
        }

        var me = this;

        return {
            bindMultiEvents: {
                type: "aftersetcontent afterscencerestore",
                handler: function () {
                    me.fireEvent("updateSections");
                }
            },
            bindEvents: {
                /* 初始化、拖拽、粘贴、执行setcontent之后 */
                ready: function () {
                    me.fireEvent("updateSections");
                    domUtils.on(me.body, "drop paste", function () {
                        me.fireEvent("updateSections");
                    });
                },
                /* 执行paragraph命令之后 */
                afterexeccommand: function (type, cmd) {
                    if (cmd == "paragraph") {
                        me.fireEvent("updateSections");
                    }
                },
                /* 部分键盘操作,触发updateSections事件 */
                keyup: function (type, e) {
                    var me = this,
                        range = me.selection.getRange();
                    if (range.collapsed != true) {
                        me.fireEvent("updateSections");
                    } else {
                        var keyCode = e.keyCode || e.which;
                        if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
                            me.fireEvent("updateSections");
                        }
                    }
                }
            },
            commands: {
                getsections: {
                    execCommand: function (cmd, levels) {
                        var levelFn = levels || ["h1", "h2", "h3", "h4", "h5", "h6"];

                        for (var i = 0; i < levelFn.length; i++) {
                            if (typeof levelFn[i] == "string") {
                                levelFn[i] = (function (fn) {
                                    return function (node) {
                                        return node.tagName == fn.toUpperCase();
                                    };
                                })(levelFn[i]);
                            } else if (typeof levelFn[i] != "function") {
                                levelFn[i] = function (node) {
                                    return null;
                                };
                            }
                        }

                        function getSectionLevel(node) {
                            for (var i = 0; i < levelFn.length; i++) {
                                if (levelFn[i](node)) return i;
                            }
                            return -1;
                        }

                        var me = this,
                            Directory = getSection({level: -1, title: "root"}),
                            previous = Directory;

                        function traversal(node, Directory) {
                            var level,
                                tmpSection = null,
                                parent,
                                child,
                                children = node.childNodes;
                            for (var i = 0, len = children.length; i < len; i++) {
                                child = children[i];
                                level = getSectionLevel(child);
                                if (level >= 0) {
                                    var address = me.selection
                                            .getRange()
                                            .selectNode(child)
                                            .createAddress(true).startAddress,
                                        current = getSection({
                                            tag: child.tagName,
                                            title: child.innerText || child.textContent || "",
                                            level: level,
                                            dom: child,
                                            startAddress: utils.clone(address, []),
                                            endAddress: utils.clone(address, []),
                                            children: []
                                        });
                                    previous.nextSection = current;
                                    current.previousSection = previous;
                                    parent = previous;
                                    while (level <= parent.level) {
                                        parent = parent.parentSection;
                                    }
                                    current.parentSection = parent;
                                    parent.children.push(current);
                                    tmpSection = previous = current;
                                } else {
                                    child.nodeType === 1 && traversal(child, Directory);
                                    tmpSection &&
                                    tmpSection.endAddress[tmpSection.endAddress.length - 1]++;
                                }
                            }
                        }

                        traversal(me.body, Directory);
                        return Directory;
                    },
                    notNeedUndo: true
                },
                movesection: {
                    execCommand: function (cmd, sourceSection, targetSection, isAfter) {
                        var me = this,
                            targetAddress,
                            target;

                        if (!sourceSection || !targetSection || targetSection.level == -1)
                            return;

                        targetAddress = isAfter
                            ? targetSection.endAddress
                            : targetSection.startAddress;
                        target = getNodeFromAddress(targetAddress, me.body);

                        /* 判断目标地址是否被源章节包含 */
                        if (
                            !targetAddress ||
                            !target ||
                            isContainsAddress(
                                sourceSection.startAddress,
                                sourceSection.endAddress,
                                targetAddress
                            )
                        )
                            return;

                        var startNode = getNodeFromAddress(
                            sourceSection.startAddress,
                            me.body
                            ),
                            endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
                            current,
                            nextNode;

                        if (isAfter) {
                            current = endNode;
                            while (
                                current &&
                                !(
                                    domUtils.getPosition(startNode, current) &
                                    domUtils.POSITION_FOLLOWING
                                )
                                ) {
                                nextNode = current.previousSibling;
                                domUtils.insertAfter(target, current);
                                if (current == startNode) break;
                                current = nextNode;
                            }
                        } else {
                            current = startNode;
                            while (
                                current &&
                                !(
                                    domUtils.getPosition(current, endNode) &
                                    domUtils.POSITION_FOLLOWING
                                )
                                ) {
                                nextNode = current.nextSibling;
                                target.parentNode.insertBefore(current, target);
                                if (current == endNode) break;
                                current = nextNode;
                            }
                        }

                        me.fireEvent("updateSections");

                        /* 获取地址的包含关系 */
                        function isContainsAddress(startAddress, endAddress, addressTarget) {
                            var isAfterStartAddress = false,
                                isBeforeEndAddress = false;
                            for (var i = 0; i < startAddress.length; i++) {
                                if (i >= addressTarget.length) break;
                                if (addressTarget[i] > startAddress[i]) {
                                    isAfterStartAddress = true;
                                    break;
                                } else if (addressTarget[i] < startAddress[i]) {
                                    break;
                                }
                            }
                            for (var i = 0; i < endAddress.length; i++) {
                                if (i >= addressTarget.length) break;
                                if (addressTarget[i] < startAddress[i]) {
                                    isBeforeEndAddress = true;
                                    break;
                                } else if (addressTarget[i] > startAddress[i]) {
                                    break;
                                }
                            }
                            return isAfterStartAddress && isBeforeEndAddress;
                        }
                    }
                },
                deletesection: {
                    execCommand: function (cmd, section, keepChildren) {
                        var me = this;

                        if (!section) return;

                        function getNodeFromAddress(startAddress) {
                            var current = me.body;
                            for (var i = 0; i < startAddress.length; i++) {
                                if (!current.childNodes) return null;
                                current = current.childNodes[startAddress[i]];
                            }
                            return current;
                        }

                        var startNode = getNodeFromAddress(section.startAddress),
                            endNode = getNodeFromAddress(section.endAddress),
                            current = startNode,
                            nextNode;

                        if (!keepChildren) {
                            while (
                                current &&
                                domUtils.inDoc(endNode, me.document) &&
                                !(
                                    domUtils.getPosition(current, endNode) &
                                    domUtils.POSITION_FOLLOWING
                                )
                                ) {
                                nextNode = current.nextSibling;
                                domUtils.remove(current);
                                current = nextNode;
                            }
                        } else {
                            domUtils.remove(current);
                        }

                        me.fireEvent("updateSections");
                    }
                },
                selectsection: {
                    execCommand: function (cmd, section) {
                        if (!section && !section.dom) return false;
                        var me = this,
                            range = me.selection.getRange(),
                            address = {
                                startAddress: utils.clone(section.startAddress, []),
                                endAddress: utils.clone(section.endAddress, [])
                            };
                        address.endAddress[address.endAddress.length - 1]++;
                        range.moveToAddress(address).select().scrollToView();
                        return true;
                    },
                    notNeedUndo: true
                },
                scrolltosection: {
                    execCommand: function (cmd, section) {
                        if (!section && !section.dom) return false;
                        var me = this,
                            range = me.selection.getRange(),
                            address = {
                                startAddress: section.startAddress,
                                endAddress: section.endAddress
                            };
                        address.endAddress[address.endAddress.length - 1]++;
                        range.moveToAddress(address).scrollToView();
                        return true;
                    },
                    notNeedUndo: true
                }
            }
        };
    });


// plugins/simpleupload.js
    /**
     * @description
     * 简单上传:点击按钮,直接选择文件上传
     * @author Jinqn
     * @date 2014-03-31
     */
    UE.plugin.register("simpleupload", function () {
        var me = this,
            isLoaded = false,
            containerBtn;

        function initUploadBtn() {
            var w = containerBtn.offsetWidth || 20,
                h = containerBtn.offsetHeight || 20,
                btnIframe = document.createElement("iframe"),
                btnStyle =
                    "display:block;width:" +
                    w +
                    "px;height:" +
                    h +
                    "px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;";

            domUtils.on(btnIframe, "load", function () {
                var timestrap = (+new Date()).toString(36),
                    wrapper,
                    btnIframeDoc,
                    btnIframeBody;

                btnIframeDoc =
                    btnIframe.contentDocument || btnIframe.contentWindow.document;
                btnIframeBody = btnIframeDoc.body;
                wrapper = btnIframeDoc.createElement("div");

                wrapper.innerHTML =
                    '<form id="edui_form_' +
                    timestrap +
                    '" target="edui_iframe_' +
                    timestrap +
                    '" method="POST" enctype="multipart/form-data" action="' +
                    me.getOpt("serverUrl") +
                    '" ' +
                    'style="' +
                    btnStyle +
                    '">' +
                    '<input id="edui_input_' +
                    timestrap +
                    '" type="file" accept="image/*" name="' +
                    me.options.imageFieldName +
                    '" ' +
                    'style="' +
                    btnStyle +
                    '">' +
                    "</form>" +
                    '<iframe id="edui_iframe_' +
                    timestrap +
                    '" name="edui_iframe_' +
                    timestrap +
                    '" style="display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;"></iframe>';

                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",
                        '<img class="loadingclass" id="' +
                        loadingId +
                        '" src="' +
                        me.options.themePath +
                        me.options.theme +
                        '/images/spacer.gif">'
                    );

                    function callback() {
                        try {
                            var link,
                                json,
                                loader,
                                body = (iframe.contentDocument || iframe.contentWindow.document)
                                    .body,
                                result = body.innerText || body.textContent || "";
                            json = new Function("return " + result)();
                            link = me.options.imageUrlPrefix + json.url;
                            if (json.state == "SUCCESS" && json.url) {
                                loader = me.document.getElementById(loadingId);
                                domUtils.removeClasses(loader, "loadingclass");
                                domUtils.on(loader, 'load', function () {
                                    me.fireEvent('contentchange');
                                });
                                loader.setAttribute("src", link);
                                loader.setAttribute("_src", link);
                                loader.setAttribute("alt", json.original || "");
                                loader.removeAttribute("id");
                            } 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, false);
                        } else if (utils.isFunction(key)) {
                            //传入函数,添加列表项
                            utils.extend(serverParam, key(), false);
                        }
                    },
                    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];

                        if (me.fireEvent("beforeinsertfile", filelist) === true) {
                            return;
                        }

                        var i,
                            item,
                            icon,
                            title,
                            html = "",
                            URL = me.getOpt("UEDITOR_HOME_URL"),
                            iconDir =
                                URL +
                                (URL.substr(URL.length - 1) == "/" ? "" : "/") +
                                "dialogs/attachment/fileTypeImages/";
                        for (i = 0; i < filelist.length; i++) {
                            item = filelist[i];
                            icon = iconDir + getFileIcon(item.url);
                            title =
                                item.title || item.url.substr(item.url.lastIndexOf("/") + 1);
                            html +=
                                '<p style="line-height: 16px;">' +
                                '<img style="vertical-align: middle; margin-right: 2px;" src="' +
                                icon +
                                '" _src="' +
                                icon +
                                '" />' +
                                '<a style="font-size:12px; color:#0066cc;" href="' +
                                item.url +
                                '" title="' +
                                title +
                                '">' +
                                title +
                                "</a>" +
                                "</p>";
                        }
                        me.execCommand("insertHtml", html);

                        me.fireEvent("afterinsertfile", filelist);
                    }
                }
            }
        };
    });


// plugins/xssFilter.js
    /**
     * @file xssFilter.js
     * @desc xss过滤器
     * @author robbenmu
     */

    UE.plugins.xssFilter = function () {

        var config = UEDITOR_CONFIG;
        var whitList = config.whitList;

        function filter(node) {

            var tagName = node.tagName;
            var attrs = node.attrs;

            if (!whitList.hasOwnProperty(tagName)) {
                node.parentNode.removeChild(node);
                return false;
            }

            UE.utils.each(attrs, function (val, key) {

                if (whitList[tagName].indexOf(key) === -1) {
                    node.setAttr(key);
                }
            });
        }

        // 添加inserthtml\paste等操作用的过滤规则
        if (whitList && config.xssFilterRules) {
            this.options.filterRules = function () {

                var result = {};

                UE.utils.each(whitList, function (val, key) {
                    result[key] = function (node) {
                        return filter(node);
                    };
                });

                return result;
            }();
        }

        var tagList = [];

        UE.utils.each(whitList, function (val, key) {
            tagList.push(key);
        });

        // 添加input过滤规则
        //
        if (whitList && config.inputXssFilter) {
            this.addInputRule(function (root) {

                root.traversal(function (node) {
                    if (node.type !== 'element') {
                        return false;
                    }
                    filter(node);
                });
            });
        }
        // 添加output过滤规则
        //
        if (whitList && config.outputXssFilter) {
            this.addOutputRule(function (root) {

                root.traversal(function (node) {
                    if (node.type !== 'element') {
                        return false;
                    }
                    filter(node);
                });
            });
        }

    };


// ui/ui.js
    var baidu = baidu || {};
    baidu.editor = baidu.editor || {};
    UE.ui = baidu.editor.ui = {};


// ui/uiutils.js
    ;(function () {
        var browser = baidu.editor.browser,
            domUtils = baidu.editor.dom.domUtils;

        var magic = "$EDITORUI";
        var root = (window[magic] = {});
        var uidMagic = "ID" + magic;
        var uidCount = 0;

        var uiUtils = (baidu.editor.ui.uiUtils = {
            uid: function (obj) {
                return obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount;
            },
            hook: function (fn, callback) {
                var dg;
                if (fn && fn._callbacks) {
                    dg = fn;
                } else {
                    dg = function () {
                        var q;
                        if (fn) {
                            q = fn.apply(this, arguments);
                        }
                        var callbacks = dg._callbacks;
                        var k = callbacks.length;
                        while (k--) {
                            var r = callbacks[k].apply(this, arguments);
                            if (q === undefined) {
                                q = r;
                            }
                        }
                        return q;
                    };
                    dg._callbacks = [];
                }
                dg._callbacks.push(callback);
                return dg;
            },
            createElementByHtml: function (html) {
                var el = document.createElement("div");
                el.innerHTML = html;
                el = el.firstChild;
                el.parentNode.removeChild(el);
                return el;
            },
            getViewportElement: function () {
                return browser.ie && browser.quirks
                    ? document.body
                    : document.documentElement;
            },
            getClientRect: function (element) {
                var bcr;
                //trace  IE6下在控制编辑器显隐时可能会报错,catch一下
                try {
                    bcr = element.getBoundingClientRect();
                } catch (e) {
                    bcr = {left: 0, top: 0, height: 0, width: 0};
                }
                var rect = {
                    left: Math.round(bcr.left),
                    top: Math.round(bcr.top),
                    height: Math.round(bcr.bottom - bcr.top),
                    width: Math.round(bcr.right - bcr.left)
                };
                var doc;
                while (
                    (doc = element.ownerDocument) !== document &&
                    (element = domUtils.getWindow(doc).frameElement)
                    ) {
                    bcr = element.getBoundingClientRect();
                    rect.left += bcr.left;
                    rect.top += bcr.top;
                }
                rect.bottom = rect.top + rect.height;
                rect.right = rect.left + rect.width;
                return rect;
            },
            getViewportRect: function () {
                var viewportEl = uiUtils.getViewportElement();
                var width = (window.innerWidth || viewportEl.clientWidth) | 0;
                var height = (window.innerHeight || viewportEl.clientHeight) | 0;
                return {
                    left: 0,
                    top: 0,
                    height: height,
                    width: width,
                    bottom: height,
                    right: width
                };
            },
            setViewportOffset: function (element, offset) {
                var rect;
                var fixedLayer = uiUtils.getFixedLayer();
                if (element.parentNode === fixedLayer) {
                    element.style.left = offset.left + "px";
                    element.style.top = offset.top + "px";
                } else {
                    domUtils.setViewportOffset(element, offset);
                }
            },
            getEventOffset: function (evt) {
                var el = evt.target || evt.srcElement;
                var rect = uiUtils.getClientRect(el);
                var offset = uiUtils.getViewportOffsetByEvent(evt);
                return {
                    left: offset.left - rect.left,
                    top: offset.top - rect.top
                };
            },
            getViewportOffsetByEvent: function (evt) {
                var el = evt.target || evt.srcElement;
                var frameEl = domUtils.getWindow(el).frameElement;
                var offset = {
                    left: evt.clientX,
                    top: evt.clientY
                };
                if (frameEl && el.ownerDocument !== document) {
                    var rect = uiUtils.getClientRect(frameEl);
                    offset.left += rect.left;
                    offset.top += rect.top;
                }
                return offset;
            },
            setGlobal: function (id, obj) {
                root[id] = obj;
                return magic + '["' + id + '"]';
            },
            unsetGlobal: function (id) {
                delete root[id];
            },
            copyAttributes: function (tgt, src) {
                var attributes = src.attributes;
                var k = attributes.length;
                while (k--) {
                    var attrNode = attributes[k];
                    if (
                        attrNode.nodeName != "style" &&
                        attrNode.nodeName != "class" &&
                        (!browser.ie || attrNode.specified)
                    ) {
                        tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue);
                    }
                }
                if (src.className) {
                    domUtils.addClass(tgt, src.className);
                }
                if (src.style.cssText) {
                    tgt.style.cssText += ";" + src.style.cssText;
                }
            },
            removeStyle: function (el, styleName) {
                if (el.style.removeProperty) {
                    el.style.removeProperty(styleName);
                } else if (el.style.removeAttribute) {
                    el.style.removeAttribute(styleName);
                } else throw "";
            },
            contains: function (elA, elB) {
                return (
                    elA &&
                    elB &&
                    (elA === elB
                        ? false
                        : elA.contains
                            ? elA.contains(elB)
                            : elA.compareDocumentPosition(elB) & 16)
                );
            },
            startDrag: function (evt, callbacks, doc) {
                var doc = doc || document;
                var startX = evt.clientX;
                var startY = evt.clientY;

                function handleMouseMove(evt) {
                    var x = evt.clientX - startX;
                    var y = evt.clientY - startY;
                    callbacks.ondragmove(x, y, evt);
                    if (evt.stopPropagation) {
                        evt.stopPropagation();
                    } else {
                        evt.cancelBubble = true;
                    }
                }

                if (doc.addEventListener) {
                    function handleMouseUp(evt) {
                        doc.removeEventListener("mousemove", handleMouseMove, true);
                        doc.removeEventListener("mouseup", handleMouseUp, true);
                        window.removeEventListener("mouseup", handleMouseUp, true);
                        callbacks.ondragstop();
                    }

                    doc.addEventListener("mousemove", handleMouseMove, true);
                    doc.addEventListener("mouseup", handleMouseUp, true);
                    window.addEventListener("mouseup", handleMouseUp, true);

                    evt.preventDefault();
                } else {
                    var elm = evt.srcElement;
                    elm.setCapture();

                    function releaseCaptrue() {
                        elm.releaseCapture();
                        elm.detachEvent("onmousemove", handleMouseMove);
                        elm.detachEvent("onmouseup", releaseCaptrue);
                        elm.detachEvent("onlosecaptrue", releaseCaptrue);
                        callbacks.ondragstop();
                    }

                    elm.attachEvent("onmousemove", handleMouseMove);
                    elm.attachEvent("onmouseup", releaseCaptrue);
                    elm.attachEvent("onlosecaptrue", releaseCaptrue);
                    evt.returnValue = false;
                }
                callbacks.ondragstart();
            },
            getFixedLayer: function () {
                var layer = document.getElementById("edui_fixedlayer");
                if (layer == null) {
                    layer = document.createElement("div");
                    layer.id = "edui_fixedlayer";
                    document.body.appendChild(layer);
                    if (browser.ie && browser.version <= 8) {
                        layer.style.position = "absolute";
                        bindFixedLayer();
                        setTimeout(updateFixedOffset);
                    } else {
                        layer.style.position = "fixed";
                    }
                    layer.style.left = "0";
                    layer.style.top = "0";
                    layer.style.width = "0";
                    layer.style.height = "0";
                }
                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 '<div id="##" class="edui-box %%"></div>';
            }
        };
        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 '<div id="##" class="edui-mask %%" onclick="return $$._onClick(event, this);" onmousedown="return $$._onMouseDown(event, this);"></div>';
            },
            postRender: function () {
                var me = this;
                domUtils.on(window, "resize", function () {
                    setTimeout(function () {
                        if (!me.isHidden()) {
                            me._fill();
                        }
                    });
                });
            },
            show: function (zIndex) {
                this._fill();
                this.getDom().style.display = "";
                this.getDom().style.zIndex = zIndex;
            },
            hide: function () {
                this.getDom().style.display = "none";
                this.getDom().style.zIndex = "";
            },
            isHidden: function () {
                return this.getDom().style.display == "none";
            },
            _onMouseDown: function () {
                return false;
            },
            _onClick: function (e, target) {
                this.fireEvent("click", e, target);
            },
            _fill: function () {
                var el = this.getDom();
                var vpRect = uiUtils.getViewportRect();
                el.style.width = vpRect.width + "px";
                el.style.height = vpRect.height + "px";
            }
        };
        utils.inherits(Mask, UIBase);
    })();


// ui/popup.js
///import core
///import uicore
    ;(function () {
        var utils = baidu.editor.utils,
            uiUtils = baidu.editor.ui.uiUtils,
            domUtils = baidu.editor.dom.domUtils,
            UIBase = baidu.editor.ui.UIBase,
            Popup = (baidu.editor.ui.Popup = function (options) {
                this.initOptions(options);
                this.initPopup();
            });

        var allPopups = [];

        function closeAllPopup(evt, el) {
            for (var i = 0; i < allPopups.length; i++) {
                var pop = allPopups[i];
                if (!pop.isHidden()) {
                    if (pop.queryAutoHide(el) !== false) {
                        if (
                            evt &&
                            /scroll/gi.test(evt.type) &&
                            pop.className == "edui-wordpastepop"
                        )
                            return;
                        pop.hide();
                    }
                }
            }

            if (allPopups.length) pop.editor.fireEvent("afterhidepop");
        }

        Popup.postHide = closeAllPopup;

        var ANCHOR_CLASSES = [
            "edui-anchor-topleft",
            "edui-anchor-topright",
            "edui-anchor-bottomleft",
            "edui-anchor-bottomright"
        ];
        Popup.prototype = {
            SHADOW_RADIUS: 5,
            content: null,
            _hidden: false,
            autoRender: true,
            canSideLeft: true,
            canSideUp: true,
            initPopup: function () {
                this.initUIBase();
                allPopups.push(this);
            },
            getHtmlTpl: function () {
                return (
                    '<div id="##" class="edui-popup %%" onmousedown="return false;">' +
                    ' <div id="##_body" class="edui-popup-body">' +
                    ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
                    ' <div class="edui-shadow"></div>' +
                    ' <div id="##_content" class="edui-popup-content">' +
                    this.getContentHtmlTpl() +
                    "  </div>" +
                    " </div>" +
                    "</div>"
                );
            },
            getContentHtmlTpl: function () {
                if (this.content) {
                    if (typeof this.content == "string") {
                        return this.content;
                    }
                    return this.content.renderHtml();
                } else {
                    return "";
                }
            },
            _UIBase_postRender: UIBase.prototype.postRender,
            postRender: function () {
                if (this.content instanceof UIBase) {
                    this.content.postRender();
                }

                //捕获鼠标滚轮
                if (this.captureWheel && !this.captured) {
                    this.captured = true;

                    var winHeight =
                        (document.documentElement.clientHeight ||
                            document.body.clientHeight) - 80,
                        _height = this.getDom().offsetHeight,
                        _top = uiUtils.getClientRect(this.combox.getDom()).top,
                        content = this.getDom("content"),
                        ifr = this.getDom("body").getElementsByTagName("iframe"),
                        me = this;

                    ifr.length && (ifr = ifr[0]);

                    while (_top + _height > winHeight) {
                        _height -= 30;
                    }
                    content.style.height = _height + "px";
                    //同步更改iframe高度
                    ifr && (ifr.style.height = _height + "px");

                    //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解
                    if (window.XMLHttpRequest) {
                        domUtils.on(
                            content,
                            "onmousewheel" in document.body ? "mousewheel" : "DOMMouseScroll",
                            function (e) {
                                if (e.preventDefault) {
                                    e.preventDefault();
                                } else {
                                    e.returnValue = false;
                                }

                                if (e.wheelDelta) {
                                    content.scrollTop -= e.wheelDelta / 120 * 60;
                                } else {
                                    content.scrollTop -= e.detail / -3 * 60;
                                }
                            }
                        );
                    } else {
                        //ie6
                        domUtils.on(this.getDom(), "mousewheel", function (e) {
                            e.returnValue = false;

                            me.getDom("content").scrollTop -= e.wheelDelta / 120 * 60;
                        });
                    }
                }
                this.fireEvent("postRenderAfter");
                this.hide(true);
                this._UIBase_postRender();
            },
            _doAutoRender: function () {
                if (!this.getDom() && this.autoRender) {
                    this.render();
                }
            },
            mesureSize: function () {
                var box = this.getDom("content");
                return uiUtils.getClientRect(box);
            },
            fitSize: function () {
                if (this.captureWheel && this.sized) {
                    return this.__size;
                }
                this.sized = true;
                var popBodyEl = this.getDom("body");
                popBodyEl.style.width = "";
                popBodyEl.style.height = "";
                var size = this.mesureSize();
                if (this.captureWheel) {
                    popBodyEl.style.width = -(-20 - size.width) + "px";
                    var height = parseInt(this.getDom("content").style.height, 10);
                    !window.isNaN(height) && (size.height = height);
                } else {
                    popBodyEl.style.width = size.width + "px";
                }
                popBodyEl.style.height = size.height + "px";
                this.__size = size;
                this.captureWheel && (this.getDom("content").style.overflow = "auto");
                return size;
            },
            showAnchor: function (element, hoz) {
                this.showAnchorRect(uiUtils.getClientRect(element), hoz);
            },
            showAnchorRect: function (rect, hoz, adj) {
                this._doAutoRender();
                var vpRect = uiUtils.getViewportRect();
                this.getDom().style.visibility = "hidden";
                this._show();
                var popSize = this.fitSize();

                var sideLeft, sideUp, left, top;
                if (hoz) {
                    sideLeft =
                        this.canSideLeft &&
                        (rect.right + popSize.width > vpRect.right &&
                            rect.left > popSize.width);
                    sideUp =
                        this.canSideUp &&
                        (rect.top + popSize.height > vpRect.bottom &&
                            rect.bottom > popSize.height);
                    left = sideLeft ? rect.left - popSize.width : rect.right;
                    top = sideUp ? rect.bottom - popSize.height : rect.top;
                } else {
                    sideLeft =
                        this.canSideLeft &&
                        (rect.right + popSize.width > vpRect.right &&
                            rect.left > popSize.width);
                    sideUp =
                        this.canSideUp &&
                        (rect.top + popSize.height > vpRect.bottom &&
                            rect.bottom > popSize.height);
                    left = sideLeft ? rect.right - popSize.width : rect.left;
                    top = sideUp ? rect.top - popSize.height : rect.bottom;
                }

                var popEl = this.getDom();
                uiUtils.setViewportOffset(popEl, {
                    left: left,
                    top: top
                });
                domUtils.removeClasses(popEl, ANCHOR_CLASSES);
                popEl.className +=
                    " " + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)];
                if (this.editor) {
                    popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10;
                    baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
                        popEl.style.zIndex - 1;
                }
                this.getDom().style.visibility = "visible";
            },
            showAt: function (offset) {
                var left = offset.left;
                var top = offset.top;
                var rect = {
                    left: left,
                    top: top,
                    right: left,
                    bottom: top,
                    height: 0,
                    width: 0
                };
                this.showAnchorRect(rect, false, true);
            },
            _show: function () {
                if (this._hidden) {
                    var box = this.getDom();
                    box.style.display = "";
                    this._hidden = false;
                    //                if (box.setActive) {
                    //                    box.setActive();
                    //                }
                    this.fireEvent("show");
                }
            },
            isHidden: function () {
                return this._hidden;
            },
            show: function () {
                this._doAutoRender();
                this._show();
            },
            hide: function (notNofity) {
                if (!this._hidden && this.getDom()) {
                    this.getDom().style.display = "none";
                    this._hidden = true;
                    if (!notNofity) {
                        this.fireEvent("hide");
                    }
                }
            },
            queryAutoHide: function (el) {
                return !el || !uiUtils.contains(this.getDom(), el);
            }
        };
        utils.inherits(Popup, UIBase);

        domUtils.on(document, "mousedown", function (evt) {
            var el = evt.target || evt.srcElement;
            closeAllPopup(evt, el);
        });
        domUtils.on(window, "scroll", function (evt, el) {
            closeAllPopup(evt, el);
        });
    })();


// ui/colorpicker.js
///import core
///import uicore
    ;(function () {
        var utils = baidu.editor.utils,
            UIBase = baidu.editor.ui.UIBase,
            ColorPicker = (baidu.editor.ui.ColorPicker = function (options) {
                this.initOptions(options);
                this.noColorText = this.noColorText || this.editor.getLang("clearColor");
                this.initUIBase();
            });

        ColorPicker.prototype = {
            getHtmlTpl: function () {
                return genColorPicker(this.noColorText, this.editor);
            },
            _onTableClick: function (evt) {
                var tgt = evt.target || evt.srcElement;
                var color = tgt.getAttribute("data-color");
                if (color) {
                    this.fireEvent("pickcolor", color);
                }
            },
            _onTableOver: function (evt) {
                var tgt = evt.target || evt.srcElement;
                var color = tgt.getAttribute("data-color");
                if (color) {
                    this.getDom("preview").style.backgroundColor = color;
                }
            },
            _onTableOut: function () {
                this.getDom("preview").style.backgroundColor = "";
            },
            _onPickNoColor: function () {
                this.fireEvent("picknocolor");
            }
        };
        utils.inherits(ColorPicker, UIBase);

        var COLORS = ("ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646," +
            "f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada," +
            "d8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5," +
            "bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f," +
            "a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09," +
            "7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806," +
            "c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,").split(
            ","
        );

        function genColorPicker(noColorText, editor) {
            var html =
                '<div id="##" class="edui-colorpicker %%">' +
                '<div class="edui-colorpicker-topbar edui-clearfix">' +
                '<div unselectable="on" id="##_preview" class="edui-colorpicker-preview"></div>' +
                '<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">' +
                noColorText +
                "</div>" +
                "</div>" +
                '<table  class="edui-box" style="border-collapse: collapse;" onmouseover="$$._onTableOver(event, this);" onmouseout="$$._onTableOut(event, this);" onclick="return $$._onTableClick(event, this);" cellspacing="0" cellpadding="0">' +
                '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;padding-top: 2px"><td colspan="10">' +
                editor.getLang("themeColor") +
                "</td> </tr>" +
                '<tr class="edui-colorpicker-tablefirstrow" >';
            for (var i = 0; i < COLORS.length; i++) {
                if (i && i % 10 === 0) {
                    html +=
                        "</tr>" +
                        (i == 60
                            ? '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;"><td colspan="10">' +
                            editor.getLang("standardColor") +
                            "</td></tr>"
                            : "") +
                        "<tr" +
                        (i == 60 ? ' class="edui-colorpicker-tablefirstrow"' : "") +
                        ">";
                }
                html += i < 70
                    ? '<td style="padding: 0 2px;"><a hidefocus title="' +
                    COLORS[i] +
                    '" onclick="return false;" href="javascript:" unselectable="on" class="edui-box edui-colorpicker-colorcell"' +
                    ' data-color="#' +
                    COLORS[i] +
                    '"' +
                    ' style="background-color:#' +
                    COLORS[i] +
                    ";border:solid #ccc;" +
                    (i < 10 || i >= 60
                        ? "border-width:1px;"
                        : i >= 10 && i < 20
                            ? "border-width:1px 1px 0 1px;"
                            : "border-width:0 1px 0 1px;") +
                    '"' +
                    "></a></td>"
                    : "";
            }
            html += "</tr></table></div>";
            return html;
        }
    })();


// ui/tablepicker.js
///import core
///import uicore
    ;(function () {
        var utils = baidu.editor.utils,
            uiUtils = baidu.editor.ui.uiUtils,
            UIBase = baidu.editor.ui.UIBase;

        var TablePicker = (baidu.editor.ui.TablePicker = function (options) {
            this.initOptions(options);
            this.initTablePicker();
        });
        TablePicker.prototype = {
            defaultNumRows: 10,
            defaultNumCols: 10,
            maxNumRows: 20,
            maxNumCols: 20,
            numRows: 10,
            numCols: 10,
            lengthOfCellSide: 22,
            initTablePicker: function () {
                this.initUIBase();
            },
            getHtmlTpl: function () {
                var me = this;
                return (
                    '<div id="##" class="edui-tablepicker %%">' +
                    '<div class="edui-tablepicker-body">' +
                    '<div class="edui-infoarea">' +
                    '<span id="##_label" class="edui-label"></span>' +
                    "</div>" +
                    '<div class="edui-pickarea"' +
                    ' onmousemove="$$._onMouseMove(event, this);"' +
                    ' onmouseover="$$._onMouseOver(event, this);"' +
                    ' onmouseout="$$._onMouseOut(event, this);"' +
                    ' onclick="$$._onClick(event, this);"' +
                    ">" +
                    '<div id="##_overlay" class="edui-overlay"></div>' +
                    "</div>" +
                    "</div>" +
                    "</div>"
                );
            },
            _UIBase_render: UIBase.prototype.render,
            render: function (holder) {
                this._UIBase_render(holder);
                this.getDom("label").innerHTML =
                    "0" +
                    this.editor.getLang("t_row") +
                    " x 0" +
                    this.editor.getLang("t_col");
            },
            _track: function (numCols, numRows) {
                var style = this.getDom("overlay").style;
                var sideLen = this.lengthOfCellSide;
                style.width = numCols * sideLen + "px";
                style.height = numRows * sideLen + "px";
                var label = this.getDom("label");
                label.innerHTML =
                    numCols +
                    this.editor.getLang("t_col") +
                    " x " +
                    numRows +
                    this.editor.getLang("t_row");
                this.numCols = numCols;
                this.numRows = numRows;
            },
            _onMouseOver: function (evt, el) {
                var rel = evt.relatedTarget || evt.fromElement;
                if (!uiUtils.contains(el, rel) && el !== rel) {
                    this.getDom("label").innerHTML =
                        "0" +
                        this.editor.getLang("t_col") +
                        " x 0" +
                        this.editor.getLang("t_row");
                    this.getDom("overlay").style.visibility = "";
                }
            },
            _onMouseOut: function (evt, el) {
                var rel = evt.relatedTarget || evt.toElement;
                if (!uiUtils.contains(el, rel) && el !== rel) {
                    this.getDom("label").innerHTML =
                        "0" +
                        this.editor.getLang("t_col") +
                        " x 0" +
                        this.editor.getLang("t_row");
                    this.getDom("overlay").style.visibility = "hidden";
                }
            },
            _onMouseMove: function (evt, el) {
                var style = this.getDom("overlay").style;
                var offset = uiUtils.getEventOffset(evt);
                var sideLen = this.lengthOfCellSide;
                var numCols = Math.ceil(offset.left / sideLen);
                var numRows = Math.ceil(offset.top / sideLen);
                this._track(numCols, numRows);
            },
            _onClick: function () {
                this.fireEvent("picktable", this.numCols, this.numRows);
            }
        };
        utils.inherits(TablePicker, UIBase);
    })();


// ui/stateful.js
    ;(function () {
        var browser = baidu.editor.browser,
            domUtils = baidu.editor.dom.domUtils,
            uiUtils = baidu.editor.ui.uiUtils;

        var TPL_STATEFUL =
            'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
            ' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
            (browser.ie
                ? ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
                ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"'
                : ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
                ' onmouseout="$$.Stateful_onMouseOut(event, this);"');

        baidu.editor.ui.Stateful = {
            alwalysHoverable: false,
            target: null, //目标元素和this指向dom不一样
            Stateful_init: function () {
                this._Stateful_dGetHtmlTpl = this.getHtmlTpl;
                this.getHtmlTpl = this.Stateful_getHtmlTpl;
            },
            Stateful_getHtmlTpl: function () {
                var tpl = this._Stateful_dGetHtmlTpl();
                // 使用function避免$转义
                return tpl.replace(/stateful/g, function () {
                    return TPL_STATEFUL;
                });
            },
            Stateful_onMouseEnter: function (evt, el) {
                this.target = el;
                if (!this.isDisabled() || this.alwalysHoverable) {
                    this.addState("hover");
                    this.fireEvent("over");
                }
            },
            Stateful_onMouseLeave: function (evt, el) {
                if (!this.isDisabled() || this.alwalysHoverable) {
                    this.removeState("hover");
                    this.removeState("active");
                    this.fireEvent("out");
                }
            },
            Stateful_onMouseOver: function (evt, el) {
                var rel = evt.relatedTarget;
                if (!uiUtils.contains(el, rel) && el !== rel) {
                    this.Stateful_onMouseEnter(evt, el);
                }
            },
            Stateful_onMouseOut: function (evt, el) {
                var rel = evt.relatedTarget;
                if (!uiUtils.contains(el, rel) && el !== rel) {
                    this.Stateful_onMouseLeave(evt, el);
                }
            },
            Stateful_onMouseDown: function (evt, el) {
                if (!this.isDisabled()) {
                    this.addState("active");
                }
            },
            Stateful_onMouseUp: function (evt, el) {
                if (!this.isDisabled()) {
                    this.removeState("active");
                }
            },
            Stateful_postRender: function () {
                if (this.disabled && !this.hasState("disabled")) {
                    this.addState("disabled");
                }
            },
            hasState: function (state) {
                return domUtils.hasClass(this.getStateDom(), "edui-state-" + state);
            },
            addState: function (state) {
                if (!this.hasState(state)) {
                    this.getStateDom().className += " edui-state-" + state;
                }
            },
            removeState: function (state) {
                if (this.hasState(state)) {
                    domUtils.removeClasses(this.getStateDom(), ["edui-state-" + state]);
                }
            },
            getStateDom: function () {
                return this.getDom("state");
            },
            isChecked: function () {
                return this.hasState("checked");
            },
            setChecked: function (checked) {
                if (!this.isDisabled() && checked) {
                    this.addState("checked");
                } else {
                    this.removeState("checked");
                }
            },
            isDisabled: function () {
                return this.hasState("disabled");
            },
            setDisabled: function (disabled) {
                if (disabled) {
                    this.removeState("hover");
                    this.removeState("checked");
                    this.removeState("active");
                    this.addState("disabled");
                } else {
                    this.removeState("disabled");
                }
            }
        };
    })();


// ui/button.js
///import core
///import uicore
///import ui/stateful.js
    ;(function () {
        var utils = baidu.editor.utils,
            UIBase = baidu.editor.ui.UIBase,
            Stateful = baidu.editor.ui.Stateful,
            Button = (baidu.editor.ui.Button = function (options) {
                if (options.name) {
                    var btnName = options.name;
                    var cssRules = options.cssRules;
                    if (!options.className) {
                        options.className = "edui-for-" + btnName;
                    }
                    options.cssRules =
                        ".edui-" +
                        (options.theme || "default") +
                        " .edui-toolbar .edui-button.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 (
                    '<div id="##" class="edui-box %%">' +
                    '<div id="##_state" stateful>' +
                    '<div class="%%-wrap"><div id="##_body" unselectable="on" ' +
                    (this.title ? 'title="' + this.title + '"' : "") +
                    ' class="%%-body" onmousedown="return $$._onMouseDown(event, this);" onclick="return $$._onClick(event, this);">' +
                    (this.showIcon ? '<div class="edui-box edui-icon"><svg class="edui-iconfont"><use xlink:href="#' + this.className + '"></use></svg></div>' : "") +
                    (this.showText
                        ? '<div class="edui-box edui-label">' + this.label + "</div>"
                        : "") +
                    "</div>" +
                    "</div>" +
                    "</div></div>"
                );
            },
            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(
                                    '<div id="' +
                                    this.popup.id +
                                    '_bordereraser" class="edui-bordereraser edui-background" style="width:' +
                                    (uiUtils.getClientRect(this.getDom()).width + 20) +
                                    'px"></div>'
                                )
                            );
                        popup.getDom().className += " " + this.className;
                    }, this)
                );
                this.popup = popup;
            },
            _onPopupShow: function () {
                this.addState("opened");
            },
            _onPopupHide: function () {
                this.removeState("opened");
            },
            getHtmlTpl: function () {
                return (
                    '<div id="##" class="edui-box %%">' +
                    "<div " +
                    (this.title ? 'title="' + this.title + '"' : "") +
                    ' id="##_state" stateful><div class="%%-body">' +
                    '<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
                    '<div class="edui-box edui-icon"><svg class="edui-iconfont"><use xlink:href="#' + this.className + '"></use></svg></div>' +
                    "</div>" +
                    '<div class="edui-box edui-splitborder"></div>' +
                    '<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
                    "</div></div></div>"
                );
            },
            showPopup: function () {
                // 当popup往上弹出的时候,做特殊处理
                var rect = uiUtils.getClientRect(this.getDom());
                rect.top -= this.popup.SHADOW_RADIUS;
                rect.height += this.popup.SHADOW_RADIUS;
                this.popup.showAnchorRect(rect);
            },
            _onArrowClick: function (event, el) {
                if (!this.isDisabled()) {
                    this.showPopup();
                }
            },
            _onButtonClick: function () {
                if (!this.isDisabled()) {
                    this.fireEvent("buttonclick");
                }
            }
        };
        utils.inherits(SplitButton, UIBase);
        utils.extend(SplitButton.prototype, Stateful, true);
    })();


// ui/colorbutton.js
///import core
///import uicore
///import ui/colorpicker.js
///import ui/popup.js
///import ui/splitbutton.js
    ;(function () {
        var utils = baidu.editor.utils,
            uiUtils = baidu.editor.ui.uiUtils,
            ColorPicker = baidu.editor.ui.ColorPicker,
            Popup = baidu.editor.ui.Popup,
            SplitButton = baidu.editor.ui.SplitButton,
            ColorButton = (baidu.editor.ui.ColorButton = function (options) {
                this.initOptions(options);
                this.initColorButton();
            });
        ColorButton.prototype = {
            initColorButton: function () {
                var me = this;
                this.popup = new Popup({
                    content: new ColorPicker({
                        noColorText: me.editor.getLang("clearColor"),
                        editor: me.editor,
                        onpickcolor: function (t, color) {
                            me._onPickColor(color);
                        },
                        onpicknocolor: function (t, color) {
                            me._onPickNoColor(color);
                        }
                    }),
                    editor: me.editor
                });
                this.initSplitButton();
            },
            _SplitButton_postRender: SplitButton.prototype.postRender,
            postRender: function () {
                this._SplitButton_postRender();
                this.getDom("button_body").appendChild(
                    uiUtils.createElementByHtml(
                        '<div id="' + this.id + '_colorlump" class="edui-colorlump"></div>'
                    )
                );
                this.getDom().className += " edui-colorbutton";
            },
            setColor: function (color) {
                this.getDom("colorlump").style.backgroundColor = color;
                this.color = color;
            },
            _onPickColor: function (color) {
                if (this.fireEvent("pickcolor", color) !== false) {
                    this.setColor(color);
                    this.popup.hide();
                }
            },
            _onPickNoColor: function (color) {
                if (this.fireEvent("picknocolor") !== false) {
                    this.popup.hide();
                }
            }
        };
        utils.inherits(ColorButton, SplitButton);
    })();


// ui/tablebutton.js
///import core
///import uicore
///import ui/popup.js
///import ui/tablepicker.js
///import ui/splitbutton.js
    ;(function () {
        var utils = baidu.editor.utils,
            Popup = baidu.editor.ui.Popup,
            TablePicker = baidu.editor.ui.TablePicker,
            SplitButton = baidu.editor.ui.SplitButton,
            TableButton = (baidu.editor.ui.TableButton = function (options) {
                this.initOptions(options);
                this.initTableButton();
            });
        TableButton.prototype = {
            initTableButton: function () {
                var me = this;
                this.popup = new Popup({
                    content: new TablePicker({
                        editor: me.editor,
                        onpicktable: function (t, numCols, numRows) {
                            me._onPickTable(numCols, numRows);
                        }
                    }),
                    editor: me.editor
                });
                this.initSplitButton();
            },
            _onPickTable: function (numCols, numRows) {
                if (this.fireEvent("picktable", numCols, numRows) !== false) {
                    this.popup.hide();
                }
            }
        };
        utils.inherits(TableButton, SplitButton);
    })();


// ui/autotypesetpicker.js
///import core
///import uicore
    ;(function () {
        var utils = baidu.editor.utils,
            UIBase = baidu.editor.ui.UIBase;

        var AutoTypeSetPicker = (baidu.editor.ui.AutoTypeSetPicker = function (
            options
        ) {
            this.initOptions(options);
            this.initAutoTypeSetPicker();
        });
        AutoTypeSetPicker.prototype = {
            initAutoTypeSetPicker: function () {
                this.initUIBase();
            },
            getHtmlTpl: function () {
                var me = this.editor,
                    opt = me.options.autotypeset,
                    lang = me.getLang("autoTypeSet");

                var textAlignInputName = "textAlignValue" + me.uid,
                    imageBlockInputName = "imageBlockLineValue" + me.uid,
                    symbolConverInputName = "symbolConverValue" + me.uid;

                return (
                    '<div id="##" class="edui-autotypesetpicker %%">' +
                    '<div class="edui-autotypesetpicker-body">' +
                    "<table >" +
                    '<tr><td nowrap><input type="checkbox" name="mergeEmptyline" ' +
                    (opt["mergeEmptyline"] ? "checked" : "") +
                    ">" +
                    lang.mergeLine +
                    '</td><td colspan="2"><input type="checkbox" name="removeEmptyline" ' +
                    (opt["removeEmptyline"] ? "checked" : "") +
                    ">" +
                    lang.delLine +
                    "</td></tr>" +
                    '<tr><td nowrap><input type="checkbox" name="removeClass" ' +
                    (opt["removeClass"] ? "checked" : "") +
                    ">" +
                    lang.removeFormat +
                    '</td><td colspan="2"><input type="checkbox" name="indent" ' +
                    (opt["indent"] ? "checked" : "") +
                    ">" +
                    lang.indent +
                    "</td></tr>" +
                    "<tr>" +
                    '<td nowrap><input type="checkbox" name="textAlign" ' +
                    (opt["textAlign"] ? "checked" : "") +
                    ">" +
                    lang.alignment +
                    "</td>" +
                    '<td colspan="2" id="' +
                    textAlignInputName +
                    '">' +
                    '<input type="radio" name="' +
                    textAlignInputName +
                    '" value="left" ' +
                    (opt["textAlign"] && opt["textAlign"] == "left" ? "checked" : "") +
                    ">" +
                    me.getLang("justifyleft") +
                    '<input type="radio" name="' +
                    textAlignInputName +
                    '" value="center" ' +
                    (opt["textAlign"] && opt["textAlign"] == "center" ? "checked" : "") +
                    ">" +
                    me.getLang("justifycenter") +
                    '<input type="radio" name="' +
                    textAlignInputName +
                    '" value="right" ' +
                    (opt["textAlign"] && opt["textAlign"] == "right" ? "checked" : "") +
                    ">" +
                    me.getLang("justifyright") +
                    "</td>" +
                    "</tr>" +
                    "<tr>" +
                    '<td nowrap><input type="checkbox" name="imageBlockLine" ' +
                    (opt["imageBlockLine"] ? "checked" : "") +
                    ">" +
                    lang.imageFloat +
                    "</td>" +
                    '<td nowrap id="' +
                    imageBlockInputName +
                    '">' +
                    '<input type="radio" name="' +
                    imageBlockInputName +
                    '" value="none" ' +
                    (opt["imageBlockLine"] && opt["imageBlockLine"] == "none"
                        ? "checked"
                        : "") +
                    ">" +
                    me.getLang("default") +
                    '<input type="radio" name="' +
                    imageBlockInputName +
                    '" value="left" ' +
                    (opt["imageBlockLine"] && opt["imageBlockLine"] == "left"
                        ? "checked"
                        : "") +
                    ">" +
                    me.getLang("justifyleft") +
                    '<input type="radio" name="' +
                    imageBlockInputName +
                    '" value="center" ' +
                    (opt["imageBlockLine"] && opt["imageBlockLine"] == "center"
                        ? "checked"
                        : "") +
                    ">" +
                    me.getLang("justifycenter") +
                    '<input type="radio" name="' +
                    imageBlockInputName +
                    '" value="right" ' +
                    (opt["imageBlockLine"] && opt["imageBlockLine"] == "right"
                        ? "checked"
                        : "") +
                    ">" +
                    me.getLang("justifyright") +
                    "</td>" +
                    "</tr>" +
                    '<tr><td nowrap><input type="checkbox" name="clearFontSize" ' +
                    (opt["clearFontSize"] ? "checked" : "") +
                    ">" +
                    lang.removeFontsize +
                    '</td><td colspan="2"><input type="checkbox" name="clearFontFamily" ' +
                    (opt["clearFontFamily"] ? "checked" : "") +
                    ">" +
                    lang.removeFontFamily +
                    "</td></tr>" +
                    '<tr><td nowrap colspan="3"><input type="checkbox" name="removeEmptyNode" ' +
                    (opt["removeEmptyNode"] ? "checked" : "") +
                    ">" +
                    lang.removeHtml +
                    "</td></tr>" +
                    '<tr><td nowrap colspan="3"><input type="checkbox" name="pasteFilter" ' +
                    (opt["pasteFilter"] ? "checked" : "") +
                    ">" +
                    lang.pasteFilter +
                    "</td></tr>" +
                    "<tr>" +
                    '<td nowrap><input type="checkbox" name="symbolConver" ' +
                    (opt["bdc2sb"] || opt["tobdc"] ? "checked" : "") +
                    ">" +
                    lang.symbol +
                    "</td>" +
                    '<td id="' +
                    symbolConverInputName +
                    '">' +
                    '<input type="radio" name="bdc" value="bdc2sb" ' +
                    (opt["bdc2sb"] ? "checked" : "") +
                    ">" +
                    lang.bdc2sb +
                    '<input type="radio" name="bdc" value="tobdc" ' +
                    (opt["tobdc"] ? "checked" : "") +
                    ">" +
                    lang.tobdc +
                    "" +
                    "</td>" +
                    '<td nowrap align="right"><button >' +
                    lang.run +
                    "</button></td>" +
                    "</tr>" +
                    "</table>" +
                    "</div>" +
                    "</div>"
                );
            },
            _UIBase_render: UIBase.prototype.render
        };
        utils.inherits(AutoTypeSetPicker, UIBase);
    })();


// ui/autotypesetbutton.js
///import core
///import uicore
///import ui/popup.js
///import ui/autotypesetpicker.js
///import ui/splitbutton.js
    ;(function () {
        var utils = baidu.editor.utils,
            Popup = baidu.editor.ui.Popup,
            AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
            SplitButton = baidu.editor.ui.SplitButton,
            AutoTypeSetButton = (baidu.editor.ui.AutoTypeSetButton = function (options) {
                this.initOptions(options);
                this.initAutoTypeSetButton();
            });

        function getPara(me) {
            var opt = {},
                cont = me.getDom(),
                editorId = me.editor.uid,
                inputType = null,
                attrName = null,
                ipts = domUtils.getElementsByTagName(cont, "input");
            for (var i = ipts.length - 1, ipt; (ipt = ipts[i--]);) {
                inputType = ipt.getAttribute("type");
                if (inputType == "checkbox") {
                    attrName = ipt.getAttribute("name");
                    opt[attrName] && delete opt[attrName];
                    if (ipt.checked) {
                        var attrValue = document.getElementById(
                            attrName + "Value" + editorId
                        );
                        if (attrValue) {
                            if (/input/gi.test(attrValue.tagName)) {
                                opt[attrName] = attrValue.value;
                            } else {
                                var iptChilds = attrValue.getElementsByTagName("input");
                                for (
                                    var j = iptChilds.length - 1, iptchild;
                                    (iptchild = iptChilds[j--]);
                                ) {
                                    if (iptchild.checked) {
                                        opt[attrName] = iptchild.value;
                                        break;
                                    }
                                }
                            }
                        } else {
                            opt[attrName] = true;
                        }
                    } else {
                        opt[attrName] = false;
                    }
                } else {
                    opt[ipt.getAttribute("value")] = ipt.checked;
                }
            }

            var selects = domUtils.getElementsByTagName(cont, "select");
            for (var i = 0, si; (si = selects[i++]);) {
                var attr = si.getAttribute("name");
                opt[attr] = opt[attr] ? si.value : "";
            }

            utils.extend(me.editor.options.autotypeset, opt);

            me.editor.setPreferences("autotypeset", opt);
        }

        AutoTypeSetButton.prototype = {
            initAutoTypeSetButton: function () {
                var me = this;
                this.popup = new Popup({
                    //传入配置参数
                    content: new AutoTypeSetPicker({editor: me.editor}),
                    editor: me.editor,
                    hide: function () {
                        if (!this._hidden && this.getDom()) {
                            getPara(this);
                            this.getDom().style.display = "none";
                            this._hidden = true;
                            this.fireEvent("hide");
                        }
                    }
                });
                var flag = 0;
                this.popup.addListener("postRenderAfter", function () {
                    var popupUI = this;
                    if (flag) return;
                    var cont = this.getDom(),
                        btn = cont.getElementsByTagName("button")[0];

                    btn.onclick = function () {
                        getPara(popupUI);
                        me.editor.execCommand("autotypeset");
                        popupUI.hide();
                    };

                    domUtils.on(cont, "click", function (e) {
                        var target = e.target || e.srcElement,
                            editorId = me.editor.uid;
                        if (target && target.tagName == "INPUT") {
                            // 点击图片浮动的checkbox,去除对应的radio
                            if (
                                target.name == "imageBlockLine" ||
                                target.name == "textAlign" ||
                                target.name == "symbolConver"
                            ) {
                                var checked = target.checked,
                                    radioTd = document.getElementById(
                                        target.name + "Value" + editorId
                                    ),
                                    radios = radioTd.getElementsByTagName("input"),
                                    defalutSelect = {
                                        imageBlockLine: "none",
                                        textAlign: "left",
                                        symbolConver: "tobdc"
                                    };

                                for (var i = 0; i < radios.length; i++) {
                                    if (checked) {
                                        if (radios[i].value == defalutSelect[target.name]) {
                                            radios[i].checked = "checked";
                                        }
                                    } else {
                                        radios[i].checked = false;
                                    }
                                }
                            }
                            // 点击radio,选中对应的checkbox
                            if (
                                target.name == "imageBlockLineValue" + editorId ||
                                target.name == "textAlignValue" + editorId ||
                                target.name == "bdc"
                            ) {
                                var checkboxs = target.parentNode.previousSibling.getElementsByTagName(
                                    "input"
                                );
                                checkboxs && (checkboxs[0].checked = true);
                            }

                            getPara(popupUI);
                        }
                    });

                    flag = 1;
                });
                this.initSplitButton();
            }
        };
        utils.inherits(AutoTypeSetButton, SplitButton);
    })();


// ui/cellalignpicker.js
///import core
///import uicore
    ;(function () {
        var utils = baidu.editor.utils,
            Popup = baidu.editor.ui.Popup,
            Stateful = baidu.editor.ui.Stateful,
            UIBase = baidu.editor.ui.UIBase;

        /**
         * 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始
         * 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom'
         * @update 2013/4/2 hancong03@baidu.com
         */
        var CellAlignPicker = (baidu.editor.ui.CellAlignPicker = function (options) {
            this.initOptions(options);
            this.initSelected();
            this.initCellAlignPicker();
        });
        CellAlignPicker.prototype = {
            //初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引
            initSelected: function () {
                var status = {
                        valign: {
                            top: 0,
                            middle: 1,
                            bottom: 2
                        },
                        align: {
                            left: 0,
                            center: 1,
                            right: 2
                        },
                        count: 3
                    },
                    result = -1;

                if (this.selected) {
                    this.selectedIndex =
                        status.valign[this.selected.valign] * status.count +
                        status.align[this.selected.align];
                }
            },
            initCellAlignPicker: function () {
                this.initUIBase();
                this.Stateful_init();
            },
            getHtmlTpl: function () {
                var alignType = ["left", "center", "right"],
                    COUNT = 9,
                    tempClassName = null,
                    tempIndex = -1,
                    tmpl = [];

                for (var i = 0; i < COUNT; i++) {
                    tempClassName = this.selectedIndex === i
                        ? ' class="edui-cellalign-selected" '
                        : "";
                    tempIndex = i % 3;

                    tempIndex === 0 && tmpl.push("<tr>");

                    tmpl.push(
                        '<td index="' +
                        i +
                        '" ' +
                        tempClassName +
                        ' stateful><div class="edui-icon edui-' +
                        alignType[tempIndex] +
                        '"></div></td>'
                    );

                    tempIndex === 2 && tmpl.push("</tr>");
                }

                return (
                    '<div id="##" class="edui-cellalignpicker %%">' +
                    '<div class="edui-cellalignpicker-body">' +
                    '<table onclick="$$._onClick(event);">' +
                    tmpl.join("") +
                    "</table>" +
                    "</div>" +
                    "</div>"
                );
            },
            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 (
                    '<div class="edui-pasteicon" onclick="$$._onClick(this)"></div>' +
                    '<div class="edui-pastecontainer">' +
                    '<div class="edui-title">' +
                    this.editor.getLang("pasteOpt") +
                    "</div>" +
                    '<div class="edui-button">' +
                    '<div title="' +
                    this.editor.getLang("pasteSourceFormat") +
                    '" onclick="$$.format(false)" stateful>' +
                    '<div class="edui-richtxticon"></div></div>' +
                    '<div title="' +
                    this.editor.getLang("tagFormat") +
                    '" onclick="$$.format(2)" stateful>' +
                    '<div class="edui-tagicon"></div></div>' +
                    '<div title="' +
                    this.editor.getLang("pasteTextFormat") +
                    '" onclick="$$.format(true)" stateful>' +
                    '<div class="edui-plaintxticon"></div></div>' +
                    "</div>" +
                    "</div>" +
                    "</div>"
                );
            },
            getStateDom: function () {
                return this.target;
            },
            format: function (param) {
                this.editor.ui._isTransfer = true;
                this.editor.fireEvent("pasteTransfer", param);
            },
            _onClick: function (cur) {
                var node = domUtils.getNextDomNode(cur),
                    screenHt = uiUtils.getViewportRect().height,
                    subPop = uiUtils.getClientRect(node);

                if (subPop.top + subPop.height > screenHt)
                    node.style.top = -subPop.height - cur.offsetHeight + "px";
                else node.style.top = "";

                if (/hidden/gi.test(domUtils.getComputedStyle(node, "visibility"))) {
                    node.style.visibility = "visible";
                    domUtils.addClass(cur, "edui-state-opened");
                } else {
                    node.style.visibility = "hidden";
                    domUtils.removeClasses(cur, "edui-state-opened");
                }
            },
            _UIBase_render: UIBase.prototype.render
        };
        utils.inherits(PastePicker, UIBase);
        utils.extend(PastePicker.prototype, Stateful, true);
    })();


// ui/toolbar.js
    ;(function () {
        var utils = baidu.editor.utils,
            uiUtils = baidu.editor.ui.uiUtils,
            UIBase = baidu.editor.ui.UIBase,
            Toolbar = (baidu.editor.ui.Toolbar = function (options) {
                this.initOptions(options);
                this.initToolbar();
            });
        Toolbar.prototype = {
            items: null,
            initToolbar: function () {
                this.items = this.items || [];
                this.initUIBase();
            },
            add: function (item, index) {
                if (index === undefined) {
                    this.items.push(item);
                } else {
                    this.items.splice(index, 0, item);
                }
            },
            getHtmlTpl: function () {
                var buff = [];
                for (var i = 0; i < this.items.length; i++) {
                    buff[i] = this.items[i].renderHtml();
                }
                return (
                    '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
                    buff.join("") +
                    "</div>"
                );
            },
            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 '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>';
            },
            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 '<div class="%%-body">' + buff.join("") + "</div>";
            },
            _Popup_postRender: Popup.prototype.postRender,
            postRender: function () {
                var me = this;
                for (var i = 0; i < this.items.length; i++) {
                    var item = this.items[i];
                    item.ownerMenu = this;
                    item.postRender();
                }
                domUtils.on(this.getDom(), "mouseover", function (evt) {
                    evt = evt || event;
                    var rel = evt.relatedTarget || evt.fromElement;
                    var el = me.getDom();
                    if (!uiUtils.contains(el, rel) && el !== rel) {
                        me.fireEvent("over");
                    }
                });
                this._Popup_postRender();
            },
            queryAutoHide: function (el) {
                if (el) {
                    if (uiUtils.contains(this.getDom(), el)) {
                        return false;
                    }
                    for (var i = 0; i < this.items.length; i++) {
                        var item = this.items[i];
                        if (item.queryAutoHide(el) === false) {
                            return false;
                        }
                    }
                }
            },
            clearItems: function () {
                for (var i = 0; i < this.items.length; i++) {
                    var item = this.items[i];
                    clearTimeout(item._showingTimer);
                    clearTimeout(item._closingTimer);
                    if (item.subMenu) {
                        item.subMenu.destroy();
                    }
                }
                this.items = [];
            },
            destroy: function () {
                if (this.getDom()) {
                    domUtils.remove(this.getDom());
                }
                this.clearItems();
            },
            dispose: function () {
                this.destroy();
            }
        };
        utils.inherits(Menu, Popup);

        /**
         * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
         * @type {Function}
         */
        var MenuItem = (baidu.editor.ui.MenuItem = function (options) {
            this.initOptions(options);
            this.initUIBase();
            this.Stateful_init();
            if (this.subMenu && !(this.subMenu instanceof Menu)) {
                if (options.className && options.className.indexOf("aligntd") != -1) {
                    var me = this;

                    //获取单元格对齐初始状态
                    this.subMenu.selected = this.editor.queryCommandValue("cellalignment");

                    this.subMenu = new Popup({
                        content: new CellAlignPicker(this.subMenu),
                        parentMenu: me,
                        editor: me.editor,
                        destroy: function () {
                            if (this.getDom()) {
                                domUtils.remove(this.getDom());
                            }
                        }
                    });
                    this.subMenu.addListener("postRenderAfter", function () {
                        domUtils.on(this.getDom(), "mouseover", function () {
                            me.addState("opened");
                        });
                    });
                } else {
                    this.subMenu = new Menu(this.subMenu);
                }
            }
        });
        MenuItem.prototype = {
            label: "",
            subMenu: null,
            ownerMenu: null,
            uiName: "menuitem",
            alwalysHoverable: true,
            getHtmlTpl: function () {
                return (
                    '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
                    '<div class="%%-body">' +
                    this.renderLabelHtml() +
                    "</div>" +
                    "</div>"
                );
            },
            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 (
                    '<div class="edui-arrow"></div>' +
                    '<div class="edui-box edui-icon"></div>' +
                    '<div class="edui-box edui-label %%-label">' +
                    (this.label || "") +
                    "</div>"
                );
            },
            getStateDom: function () {
                return this.getDom();
            },
            queryAutoHide: function (el) {
                if (this.subMenu && this.hasState("opened")) {
                    return this.subMenu.queryAutoHide(el);
                }
            },
            _onClick: function (event, this_) {
                if (this.hasState("disabled")) return;
                if (this.fireEvent("click", event, this_) !== false) {
                    if (this.subMenu) {
                        this.showSubMenu();
                    } else {
                        Popup.postHide(event);
                    }
                }
            },
            showSubMenu: function () {
                var rect = uiUtils.getClientRect(this.getDom());
                rect.right -= 5;
                rect.left += 2;
                rect.width -= 7;
                rect.top -= 4;
                rect.bottom += 4;
                rect.height += 8;
                this.subMenu.showAnchorRect(rect, true, true);
            },
            hideSubMenu: function () {
                this.subMenu.hide();
            }
        };
        utils.inherits(MenuItem, UIBase);
        utils.extend(MenuItem.prototype, Stateful, true);
    })();


// ui/combox.js
///import core
///import uicore
///import ui/menu.js
///import ui/splitbutton.js
    ;(function () {
        // todo: menu和item提成通用list
        var utils = baidu.editor.utils,
            uiUtils = baidu.editor.ui.uiUtils,
            Menu = baidu.editor.ui.Menu,
            SplitButton = baidu.editor.ui.SplitButton,
            Combox = (baidu.editor.ui.Combox = function (options) {
                this.initOptions(options);
                this.initCombox();
            });
        Combox.prototype = {
            uiName: "combox",
            onbuttonclick: function () {
                this.showPopup();
            },
            initCombox: function () {
                var me = this;
                this.items = this.items || [];
                for (var i = 0; i < this.items.length; i++) {
                    var item = this.items[i];
                    item.uiName = "listitem";
                    item.index = i;
                    item.onclick = function () {
                        me.selectByIndex(this.index);
                    };
                }
                this.popup = new Menu({
                    items: this.items,
                    uiName: "list",
                    editor: this.editor,
                    captureWheel: true,
                    combox: this
                });

                this.initSplitButton();
            },
            _SplitButton_postRender: SplitButton.prototype.postRender,
            postRender: function () {
                this._SplitButton_postRender();
                this.setLabel(this.label || "");
                this.setValue(this.initValue || "");
            },
            showPopup: function () {
                var rect = uiUtils.getClientRect(this.getDom());
                rect.top += 1;
                rect.bottom -= 1;
                rect.height -= 2;
                this.popup.showAnchorRect(rect);
            },
            getValue: function () {
                return this.value;
            },
            setValue: function (value) {
                var index = this.indexByValue(value);
                if (index != -1) {
                    this.selectedIndex = index;
                    this.setLabel(this.items[index].label);
                    this.value = this.items[index].value;
                } else {
                    this.selectedIndex = -1;
                    this.setLabel(this.getLabelForUnknowValue(value));
                    this.value = value;
                }
            },
            setLabel: function (label) {
                this.getDom("button_body").innerHTML = label;
                this.label = label;
            },
            getLabelForUnknowValue: function (value) {
                return value;
            },
            indexByValue: function (value) {
                for (var i = 0; i < this.items.length; i++) {
                    if (value == this.items[i].value) {
                        return i;
                    }
                }
                return -1;
            },
            getItem: function (index) {
                return this.items[index];
            },
            selectByIndex: function (index) {
                if (
                    index < this.items.length &&
                    this.fireEvent("select", index) !== false
                ) {
                    this.selectedIndex = index;
                    this.value = this.items[index].value;
                    this.setLabel(this.items[index].label);
                }
            }
        };
        utils.inherits(Combox, SplitButton);
    })();


// ui/dialog.js
///import core
///import uicore
///import ui/mask.js
///import ui/button.js
    ;(function () {
        var utils = baidu.editor.utils,
            domUtils = baidu.editor.dom.domUtils,
            uiUtils = baidu.editor.ui.uiUtils,
            Mask = baidu.editor.ui.Mask,
            UIBase = baidu.editor.ui.UIBase,
            Button = baidu.editor.ui.Button,
            Dialog = (baidu.editor.ui.Dialog = function (options) {
                if (options.name) {
                    var name = options.name;
                    var cssRules = options.cssRules;
                    if (!options.className) {
                        options.className = "edui-for-" + name;
                    }
                    if (cssRules) {
                        options.cssRules =
                            ".edui-for-" + name + " .edui-dialog-content  {" + cssRules + "}";
                    }
                }
                this.initOptions(
                    utils.extend(
                        {
                            autoReset: true,
                            draggable: true,
                            onok: function () {
                            },
                            oncancel: function () {
                            },
                            onclose: function (t, ok) {
                                return ok ? this.onok() : this.oncancel();
                            },
                            //是否控制dialog中的scroll事件, 默认为不阻止
                            holdScroll: false
                        },
                        options
                    )
                );
                this.initDialog();
            });
        var modalMask;
        var dragMask;
        var activeDialog;
        Dialog.prototype = {
            draggable: false,
            uiName: "dialog",
            initDialog: function () {
                var me = this,
                    theme = this.editor.options.theme;
                if (this.cssRules) {
                    this.cssRules = ".edui-" + theme + " " + this.cssRules;
                    utils.cssRule("edui-customize-" + this.name + "-style", this.cssRules);
                }
                this.initUIBase();
                this.modalMask =
                    modalMask ||
                    (modalMask = new Mask({
                        className: "edui-dialog-modalmask",
                        theme: theme,
                        onclick: function () {
                            activeDialog && activeDialog.close(false);
                        }
                    }));
                this.dragMask =
                    dragMask ||
                    (dragMask = new Mask({
                        className: "edui-dialog-dragmask",
                        theme: theme
                    }));
                this.closeButton = new Button({
                    className: "edui-dialog-closebutton",
                    title: me.closeDialog,
                    theme: theme,
                    onclick: function () {
                        me.close(false);
                    }
                });

                this.fullscreen && this.initResizeEvent();

                if (this.buttons) {
                    for (var i = 0; i < this.buttons.length; i++) {
                        if (!(this.buttons[i] instanceof Button)) {
                            this.buttons[i] = new Button(
                                utils.extend(
                                    this.buttons[i],
                                    {
                                        editor: this.editor
                                    },
                                    true
                                )
                            );
                        }
                    }
                }
            },
            initResizeEvent: function () {
                var me = this;

                domUtils.on(window, "resize", function () {
                    if (me._hidden || me._hidden === undefined) {
                        return;
                    }

                    if (me.__resizeTimer) {
                        window.clearTimeout(me.__resizeTimer);
                    }

                    me.__resizeTimer = window.setTimeout(function () {
                        me.__resizeTimer = null;

                        var dialogWrapNode = me.getDom(),
                            contentNode = me.getDom("content"),
                            wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
                            contentRect = UE.ui.uiUtils.getClientRect(contentNode),
                            vpRect = uiUtils.getViewportRect();

                        contentNode.style.width =
                            vpRect.width - wrapRect.width + contentRect.width + "px";
                        contentNode.style.height =
                            vpRect.height - wrapRect.height + contentRect.height + "px";

                        dialogWrapNode.style.width = vpRect.width + "px";
                        dialogWrapNode.style.height = vpRect.height + "px";

                        me.fireEvent("resize");
                    }, 100);
                });
            },
            fitSize: function () {
                var popBodyEl = this.getDom("body");
                //            if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
                //                uiUtils.removeStyle(popBodyEl, 'width');
                //                uiUtils.removeStyle(popBodyEl, 'height');
                //            }
                var size = this.mesureSize();
                popBodyEl.style.width = size.width + "px";
                popBodyEl.style.height = size.height + "px";
                return size;
            },
            safeSetOffset: function (offset) {
                var me = this;
                var el = me.getDom();
                var vpRect = uiUtils.getViewportRect();
                var rect = uiUtils.getClientRect(el);
                var left = offset.left;
                if (left + rect.width > vpRect.right) {
                    left = vpRect.right - rect.width;
                }
                var top = offset.top;
                if (top + rect.height > vpRect.bottom) {
                    top = vpRect.bottom - rect.height;
                }
                el.style.left = Math.max(left, 0) + "px";
                el.style.top = Math.max(top, 0) + "px";
            },
            showAtCenter: function () {
                var vpRect = uiUtils.getViewportRect();

                if (!this.fullscreen) {
                    this.getDom().style.display = "";
                    var popSize = this.fitSize();
                    var titleHeight = this.getDom("titlebar").offsetHeight | 0;
                    var left = vpRect.width / 2 - popSize.width / 2;
                    var top =
                        vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight;
                    var popEl = this.getDom();
                    this.safeSetOffset({
                        left: Math.max(left | 0, 0),
                        top: Math.max(top | 0, 0)
                    });
                    if (!domUtils.hasClass(popEl, "edui-state-centered")) {
                        popEl.className += " edui-state-centered";
                    }
                } else {
                    var dialogWrapNode = this.getDom(),
                        contentNode = this.getDom("content");

                    dialogWrapNode.style.display = "block";

                    var wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
                        contentRect = UE.ui.uiUtils.getClientRect(contentNode);
                    dialogWrapNode.style.left = "-100000px";

                    contentNode.style.width =
                        vpRect.width - wrapRect.width + contentRect.width + "px";
                    contentNode.style.height =
                        vpRect.height - wrapRect.height + contentRect.height + "px";

                    dialogWrapNode.style.width = vpRect.width + "px";
                    dialogWrapNode.style.height = vpRect.height + "px";
                    dialogWrapNode.style.left = 0;

                    //保存环境的overflow值
                    this._originalContext = {
                        html: {
                            overflowX: document.documentElement.style.overflowX,
                            overflowY: document.documentElement.style.overflowY
                        },
                        body: {
                            overflowX: document.body.style.overflowX,
                            overflowY: document.body.style.overflowY
                        }
                    };

                    document.documentElement.style.overflowX = "hidden";
                    document.documentElement.style.overflowY = "hidden";
                    document.body.style.overflowX = "hidden";
                    document.body.style.overflowY = "hidden";
                }

                this._show();
            },
            getContentHtml: function () {
                var contentHtml = "";
                if (typeof this.content == "string") {
                    contentHtml = this.content;
                } else if (this.iframeUrl) {
                    contentHtml =
                        '<span id="' +
                        this.id +
                        '_contmask" class="dialogcontmask"></span><iframe id="' +
                        this.id +
                        '_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="' +
                        this.iframeUrl +
                        '"></iframe>';
                }
                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 =
                        '<div class="%%-foot">' +
                        '<div id="##_buttons" class="%%-buttons">' +
                        buff.join("") +
                        "</div>" +
                        "</div>";
                }

                return (
                    '<div id="##" class="%%"><div ' +
                    (!this.fullscreen
                        ? 'class="%%"'
                        : 'class="%%-wrap edui-dialog-fullscreen-flag"') +
                    '><div id="##_body" class="%%-body">' +
                    '<div class="%%-shadow"></div>' +
                    '<div id="##_titlebar" class="%%-titlebar">' +
                    '<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
                    '<span class="%%-caption">' +
                    (this.title || "") +
                    "</span>" +
                    "</div>" +
                    this.closeButton.renderHtml() +
                    "</div>" +
                    '<div id="##_content" class="%%-content">' +
                    (this.autoReset ? "" : this.getContentHtml()) +
                    "</div>" +
                    footHtml +
                    "</div></div></div>"
                );
            },
            postRender: function () {
                // todo: 保持居中/记住上次关闭位置选项
                if (!this.modalMask.getDom()) {
                    this.modalMask.render();
                    this.modalMask.hide();
                }
                if (!this.dragMask.getDom()) {
                    this.dragMask.render();
                    this.dragMask.hide();
                }
                var me = this;
                this.addListener("show", function () {
                    me.modalMask.show(this.getDom().style.zIndex - 2);
                });
                this.addListener("hide", function () {
                    me.modalMask.hide();
                });
                if (this.buttons) {
                    for (var i = 0; i < this.buttons.length; i++) {
                        this.buttons[i].postRender();
                    }
                }
                domUtils.on(window, "resize", function () {
                    setTimeout(function () {
                        if (!me.isHidden()) {
                            me.safeSetOffset(uiUtils.getClientRect(me.getDom()));
                        }
                    });
                });

                //hold住scroll事件,防止dialog的滚动影响页面
                //            if( this.holdScroll ) {
                //
                //                if( !me.iframeUrl ) {
                //                    domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
                //                        domUtils.preventDefault(e);
                //                    } );
                //                } else {
                //                    me.addListener('dialogafterreset', function(){
                //                        window.setTimeout(function(){
                //                            var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow;
                //
                //                            if( browser.ie ) {
                //
                //                                var timer = window.setInterval(function(){
                //
                //                                    if( iframeWindow.document && iframeWindow.document.body ) {
                //                                        window.clearInterval( timer );
                //                                        timer = null;
                //                                        domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
                //                                            domUtils.preventDefault(e);
                //                                        } );
                //                                    }
                //
                //                                }, 100);
                //
                //                            } else {
                //                                domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
                //                                    domUtils.preventDefault(e);
                //                                } );
                //                            }
                //
                //                        }, 1);
                //                    });
                //                }
                //
                //            }
                this._hide();
            },
            mesureSize: function () {
                var body = this.getDom("body");
                var width = uiUtils.getClientRect(this.getDom("content")).width;
                var dialogBodyStyle = body.style;
                dialogBodyStyle.width = width;
                return uiUtils.getClientRect(body);
            },
            _onTitlebarMouseDown: function (evt, el) {
                if (this.draggable) {
                    var rect;
                    var vpRect = uiUtils.getViewportRect();
                    var me = this;
                    uiUtils.startDrag(evt, {
                        ondragstart: function () {
                            rect = uiUtils.getClientRect(me.getDom());
                            me.getDom("contmask").style.visibility = "visible";
                            me.dragMask.show(me.getDom().style.zIndex - 1);
                        },
                        ondragmove: function (x, y) {
                            var left = rect.left + x;
                            var top = rect.top + y;
                            me.safeSetOffset({
                                left: left,
                                top: top
                            });
                        },
                        ondragstop: function () {
                            me.getDom("contmask").style.visibility = "hidden";
                            domUtils.removeClasses(me.getDom(), ["edui-state-centered"]);
                            me.dragMask.hide();
                        }
                    });
                }
            },
            reset: function () {
                this.getDom("content").innerHTML = this.getContentHtml();
                this.fireEvent("dialogafterreset");
            },
            _show: function () {
                if (this._hidden) {
                    this.getDom().style.display = "";

                    //要高过编辑器的zindxe
                    this.editor.container.style.zIndex &&
                    (this.getDom().style.zIndex =
                        this.editor.container.style.zIndex * 1 + 10);
                    this._hidden = false;
                    this.fireEvent("show");
                    baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
                        this.getDom().style.zIndex - 4;
                }
            },
            isHidden: function () {
                return this._hidden;
            },
            _hide: function () {
                if (!this._hidden) {
                    var wrapNode = this.getDom();
                    wrapNode.style.display = "none";
                    wrapNode.style.zIndex = "";
                    wrapNode.style.width = "";
                    wrapNode.style.height = "";
                    this._hidden = true;
                    this.fireEvent("hide");
                }
            },
            open: function () {
                if (this.autoReset) {
                    //有可能还没有渲染
                    try {
                        this.reset();
                    } catch (e) {
                        this.render();
                        this.open();
                    }
                }
                this.showAtCenter();
                if (this.iframeUrl) {
                    try {
                        this.getDom("iframe").focus();
                    } catch (ex) {
                    }
                }
                activeDialog = this;
            },
            _onCloseButtonClick: function (evt, el) {
                this.close(false);
            },
            close: function (ok) {
                if (this.fireEvent("close", ok) !== false) {
                    //还原环境
                    if (this.fullscreen) {
                        document.documentElement.style.overflowX = this._originalContext.html.overflowX;
                        document.documentElement.style.overflowY = this._originalContext.html.overflowY;
                        document.body.style.overflowX = this._originalContext.body.overflowX;
                        document.body.style.overflowY = this._originalContext.body.overflowY;
                        delete this._originalContext;
                    }
                    this._hide();

                    //销毁content
                    var content = this.getDom("content");
                    var iframe = this.getDom("iframe");
                    if (content && iframe) {
                        var doc = iframe.contentDocument || iframe.contentWindow.document;
                        doc && (doc.body.innerHTML = "");
                        domUtils.remove(content);
                    }
                }
            }
        };
        utils.inherits(Dialog, UIBase);
    })();


// ui/menubutton.js
///import core
///import uicore
///import ui/menu.js
///import ui/splitbutton.js
    ;(function () {
        var utils = baidu.editor.utils,
            Menu = baidu.editor.ui.Menu,
            SplitButton = baidu.editor.ui.SplitButton,
            MenuButton = (baidu.editor.ui.MenuButton = function (options) {
                this.initOptions(options);
                this.initMenuButton();
            });
        MenuButton.prototype = {
            initMenuButton: function () {
                var me = this;
                this.uiName = "menubutton";
                this.popup = new Menu({
                    items: me.items,
                    className: me.className,
                    editor: me.editor
                });
                this.popup.addListener("show", function () {
                    var list = this;
                    for (var i = 0; i < list.items.length; i++) {
                        list.items[i].removeState("checked");
                        if (list.items[i].value == me._value) {
                            list.items[i].addState("checked");
                            this.value = me._value;
                        }
                    }
                });
                this.initSplitButton();
            },
            setValue: function (value) {
                this._value = value;
            }
        };
        utils.inherits(MenuButton, SplitButton);
    })();


// ui/multiMenu.js
///import core
///import uicore
///commands 表情
    ;(function () {
        var utils = baidu.editor.utils,
            Popup = baidu.editor.ui.Popup,
            SplitButton = baidu.editor.ui.SplitButton,
            MultiMenuPop = (baidu.editor.ui.MultiMenuPop = function (options) {
                this.initOptions(options);
                this.initMultiMenu();
            });

        MultiMenuPop.prototype = {
            initMultiMenu: function () {
                var me = this;
                this.popup = new Popup({
                    content: "",
                    editor: me.editor,
                    iframe_rendered: false,
                    onshow: function () {
                        if (!this.iframe_rendered) {
                            this.iframe_rendered = true;
                            this.getDom("content").innerHTML =
                                '<iframe id="' +
                                me.id +
                                '_iframe" src="' +
                                me.iframeUrl +
                                '" frameborder="0"></iframe>';
                            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 (
                    '<div id="##" class="%% edui-toolbar" data-src="shortcutmenu" onmousedown="return false;" onselectstart="return false;" >' +
                    buff +
                    "</div>"
                );
            }
        };

        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 "<br/>";
            }
        };
        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 (
                    '<div id="##" class="edui-message %%">' +
                    ' <div id="##_closer" class="edui-message-closer">×</div>' +
                    ' <div id="##_body" class="edui-message-body edui-message-type-info">' +
                    ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
                    ' <div class="edui-shadow"></div>' +
                    ' <div id="##_content" class="edui-message-content">' +
                    "  </div>" +
                    " </div>" +
                    "</div>"
                );
            },
            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);
    })();


// ui/iconfont.js
    ;(function (window) {
        var svgSprite = '<svg><symbol id="edui-for-close" viewBox="0 0 1024 1024"><path d="M960 153.6L870.4 64 512 422.4 153.6 64 64 153.6 422.4 512 64 870.4 153.6 960 512 601.6l358.4 358.4 89.6-89.6L601.6 512 960 153.6z" fill="#666666" ></path></symbol><symbol id="edui-for-italic" viewBox="0 0 1024 1024"><path d="M384 64v64h128L384 896H256v64h384v-64H512l128-768h128V64z" fill="#666666" ></path></symbol><symbol id="edui-for-insertcaption" viewBox="0 0 1024 1024"><path d="M576 0v448h448V0z m384 256h-128v128h-64V256h-128V192h128V64h64v128h128z" fill="#1C7C59" ></path><path d="M997.12 448H0v576h1024V448zM60.16 960v-256H320v256z m481.92 0H384v-256h256v256z m421.76 0H704v-256h259.84zM448 0H0v64h192v384h64V64h192V0z" fill="#666666" ></path></symbol><symbol id="edui-for-insertparagraph" viewBox="0 0 1024 1024"><path d="M997.12 0H0v576h1024V0zM60.16 512V256H320v256z m481.92 0H384V256h256v256z m421.76 0H704V256h259.84zM448 576H0v64h192v384h64v-384h192V576z" fill="#666666" ></path></symbol><symbol id="edui-for-inserttitlecol" viewBox="0 0 1024 1024"><path d="M64 960v-128H0v192h192v-64H64zM448 1024h576V0H448z m512-320v256h-192v-256z m-256 0v256H512v-256z m256-320v256h-192V384z m-256 0v256H512V384z m256-320v256h-192V64z m-256 0v256H512V64zM64 512h128V448H0v192h64V512zM384 512v128h64V448H256v64h128zM384 960H256v64h192v-192H384v128z" fill="#666666" ></path><path d="M64 960v-128H0v192h192v-64H64zM448 1024h576V0H448z m512-320v256h-192v-256z m-256 0v256H512v-256z m256-320v256h-192V384z m-256 0v256H512V384z m256-320v256h-192V64z m-256 0v256H512V64zM64 512h128V448H0v192h64V512zM384 512v128h64V448H256v64h128zM384 960H256v64h192v-192H384v128z" fill="#666666" ></path><path d="M0 448h448V0H0z m256-384v128h128v64H256v128H192V256H64V192h128V64z" fill="#1C7C59" ></path></symbol><symbol id="edui-for-insertimage" viewBox="0 0 1024 1024"><path d="M350.08 535.04l128 192 263.68-430.08 156.16 256V576h64V117.12a53.12 53.12 0 0 0-55.04-53.12H53.12a53.12 53.12 0 0 0-53.12 53.12v727.04a51.84 51.84 0 0 0 51.84 51.84H640v-64H154.88z m-53.12-350.72a119.04 119.04 0 1 1-118.4 118.4 119.04 119.04 0 0 1 118.4-118.4z" fill="#666666" ></path><path d="M1024 704h-192V512h-64v192H576v64h192v192h64v-192h192v-64z" fill="#666666" ></path></symbol><symbol id="edui-for-previousstep" viewBox="0 0 1024 1024"><path d="M483.84 896a53.76 53.76 0 0 1-24.96-6.4h-3.84L87.04 556.8A55.04 55.04 0 0 1 64 517.76a56.96 56.96 0 0 1 22.4-48.64l371.2-328.32a46.08 46.08 0 0 1 30.72-12.8 40.96 40.96 0 0 1 35.84 21.12 60.16 60.16 0 0 1 7.04 28.16v192h29.44a400 400 0 0 1 97.28 12.16 363.52 363.52 0 0 1 120.32 54.4A384 384 0 0 1 889.6 556.8 602.88 602.88 0 0 1 960 768a60.16 60.16 0 0 1-10.24 53.12 39.68 39.68 0 0 1-29.44 13.44 55.04 55.04 0 0 1-42.24-26.24 229.12 229.12 0 0 0-64-68.48 314.24 314.24 0 0 0-89.6-47.36 437.76 437.76 0 0 0-141.44-21.76h-48.64V832a68.48 68.48 0 0 1-12.8 51.2 43.52 43.52 0 0 1-37.76 12.8zM145.28 512l312.96 281.6v-148.48a64 64 0 0 1 68.48-48h53.12a507.52 507.52 0 0 1 167.68 26.88 384 384 0 0 1 110.72 60.16l9.6 7.68a354.56 354.56 0 0 0-128-197.76 312.32 312.32 0 0 0-176-53.12 240 240 0 0 0-33.92 0h-12.8a56.96 56.96 0 0 1-49.28-24.96 55.04 55.04 0 0 1-8.96-26.24V234.88z" fill="#666666" ></path></symbol><symbol id="edui-for-nextstep" viewBox="0 0 1024 1024"><path d="M506.88 880.64a68.48 68.48 0 0 1-12.8-51.2v-160h-48.64a437.76 437.76 0 0 0-141.44 21.76 314.24 314.24 0 0 0-89.6 47.36 229.12 229.12 0 0 0-64 68.48 55.04 55.04 0 0 1-42.24 26.24 39.68 39.68 0 0 1-29.44-13.44A60.16 60.16 0 0 1 64 768a602.88 602.88 0 0 1 70.4-211.2 384 384 0 0 1 111.36-124.16 363.52 363.52 0 0 1 120.32-54.4 400 400 0 0 1 97.28-12.16h29.44v-192a60.16 60.16 0 0 1 7.04-28.16 40.96 40.96 0 0 1 35.84-17.92 46.08 46.08 0 0 1 30.72 12.8l370.56 328.32a56.96 56.96 0 0 1 22.4 48.64 55.04 55.04 0 0 1-22.4 39.68l-368 330.24h-3.84a53.76 53.76 0 0 1-24.96 6.4 43.52 43.52 0 0 1-33.28-13.44z m58.24-645.76v154.24a55.04 55.04 0 0 1-8.96 26.24 56.96 56.96 0 0 1-49.28 24.96h-9.6a240 240 0 0 0-33.92 0 312.32 312.32 0 0 0-176 53.12 354.56 354.56 0 0 0-128 197.76l9.6-7.68a384 384 0 0 1 110.72-60.16 507.52 507.52 0 0 1 163.84-28.16h53.12a64 64 0 0 1 68.48 48v150.4l313.6-281.6z" fill="#666666" ></path></symbol><symbol id="edui-for-scaleboard" viewBox="0 0 1024 1024"><path d="M374.935252 651.624033a35.190169 35.190169 0 0 0-26.872492-11.516783H39.029096a40.308739 40.308739 0 0 0-39.029096 39.668918V704.089375a41.588381 41.588381 0 0 0 43.507845 37.749454h163.154419L19.834459 932.505561a53.105164 53.105164 0 0 0 0 74.859087 51.825521 51.825521 0 0 0 73.579443 0l186.827805-188.107448v165.073883a37.749454 37.749454 0 0 0 37.109633 39.029096h26.872492a36.469811 36.469811 0 0 0 39.668918-33.910526v-309.673485a36.469811 36.469811 0 0 0-8.957498-26.872493zM383.89275 325.955016V34.196526A35.82999 35.82999 0 0 0 343.584011 0.286h-28.152135a37.109632 37.109632 0 0 0-37.109632 39.029096v166.353525L94.053724 21.400101a51.1857 51.1857 0 0 0-72.939623 0 52.465342 52.465342 0 0 0 0 73.579444l184.26852 184.26852H43.507845A42.228202 42.228202 0 0 0 0 320.196625v26.872493A40.308739 40.308739 0 0 0 38.389275 384.17875h310.313306a35.190169 35.190169 0 0 0 26.232671-10.876961A35.82999 35.82999 0 0 0 383.89275 345.789475v-19.194637zM648.778747 372.661968a35.190169 35.190169 0 0 0 26.872493 10.876961H984.684904a40.308739 40.308739 0 0 0 39.029096-39.029096V320.196625a41.588381 41.588381 0 0 0-43.507845-37.749454h-163.154419l186.827805-187.467626a53.105164 53.105164 0 0 0 0-74.859086 51.825521 51.825521 0 0 0-73.579444 0L743.472292 205.0288V39.954918a37.749454 37.749454 0 0 0-36.469811-39.668918h-26.872492a36.469811 36.469811 0 0 0-40.308739 34.550348v309.673485a36.469811 36.469811 0 0 0 8.957497 26.872492zM639.82125 698.330984v291.118669a35.82999 35.82999 0 0 0 38.389275 33.910526h28.152135a37.109632 37.109632 0 0 0 37.109632-39.029096v-166.353525l185.548163 184.26852a51.1857 51.1857 0 0 0 72.939622 0 52.465342 52.465342 0 0 0 0-73.579444l-183.628698-183.628699h161.874776A42.228202 42.228202 0 0 0 1023.714 704.089375v-26.872492a40.308739 40.308739 0 0 0-38.389275-39.029097h-309.673485a35.190169 35.190169 0 0 0-26.232671 10.876962 35.82999 35.82999 0 0 0-8.957498 26.872492v19.194638z" fill="#666666" ></path></symbol><symbol id="edui-for-brush" viewBox="0 0 1024 1024"><path d="M986.878764 284.789854L739.847564 35.198746a122.875623 122.875623 0 0 0-172.153867 0L92.830614 511.981761a87.676877 87.676877 0 0 0-32.638837 56.317993L0.03392 915.807374a119.675737 119.675737 0 0 0 28.158997 79.99715 94.076649 94.076649 0 0 0 69.757515 28.158997h14.079498l344.307734-63.99772a86.396922 86.396922 0 0 0 55.678017-30.078928l474.863083-475.50306a115.195896 115.195896 0 0 0 0-169.593959zM448.017961 868.449062l-348.787575 63.99772 60.797834-348.147598 347.50762-351.347483 288.629718 287.349763z m474.863083-479.982901l-63.997721 70.397492-291.189626-286.709786 63.99772-63.99772a34.558769 34.558769 0 0 1 41.598518 0l246.391223 249.591108a35.838723 35.838723 0 0 1 9.599658 18.559339c1.919932 2.559909-3.199886 7.679726-7.679727 12.159567z" fill="#666666" ></path></symbol><symbol id="edui-for-background" viewBox="0 0 1024 1024"><path d="M988.16 448H419.84a35.84 35.84 0 0 0-35.84 35.84v504.32a35.84 35.84 0 0 0 35.84 35.84h568.96a35.84 35.84 0 0 0 35.84-35.84V483.84a35.84 35.84 0 0 0-36.48-35.84z m-323.84 164.48a80 80 0 1 1-80-81.92 81.28 81.28 0 0 1 80 81.92zM929.28 960H461.44l131.2-205.44 85.12 133.12 177.28-298.24L960 768v163.2a30.72 30.72 0 0 1-30.72 28.8z" fill="#666666" ></path><path d="M320 832H224a32 32 0 0 0 0 64H320zM320 640H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h640a64 64 0 0 1 64 64v256h64V64a64 64 0 0 0-64-64H64a64 64 0 0 0-64 64v576a64 64 0 0 0 64 64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-strikethrough" viewBox="0 0 1024 1024"><path d="M994.56 672a128 128 0 0 1-98.56 48.64c-74.24 0-122.88-57.6-128-150.4h236.8v-52.48H768c7.68-92.8 58.24-150.4 132.48-150.4a115.84 115.84 0 0 1 87.04 40.96l28.8-35.2A156.8 156.8 0 0 0 896 320c-100.48 0-176.64 74.24-186.88 197.76H608.64a96.64 96.64 0 0 0 44.16-83.84c0-76.16-59.52-105.6-146.56-105.6h-128v192H267.52l-64-192h-58.88l-64 192H22.4v52.48H64l-64 192h54.4l41.6-136.32h155.52l40.32 131.84h56.96l-64-192h95.36v192h135.68c95.36 0 161.28-41.6 161.28-128a103.04 103.04 0 0 0-19.84-64h52.48C719.36 694.4 794.24 768 896 768a163.84 163.84 0 0 0 128-64zM433.92 371.2h64c64 0 100.48 18.56 100.48 69.76S570.24 512 497.28 512h-64z m-261.76 0c14.08 49.92 26.88 96.64 42.88 145.28H128c17.28-47.36 31.36-93.44 44.16-144z m64 212.48h-128l4.48-14.72h120.96z m384 47.36c0 58.24-42.88 85.12-115.84 85.12h-70.4V570.24H588.8a64 64 0 0 1 35.2 61.44z" fill="#666666" ></path></symbol><symbol id="edui-for-spechars" viewBox="0 0 1024 1024"><path d="M954.24 1024l-158.72-160A434.56 434.56 0 0 1 512 965.76a421.12 421.12 0 0 1-283.52-101.76L69.76 1024 0 951.68l160.64-155.52A477.44 477.44 0 0 1 64 512a426.88 426.88 0 0 1 96.64-282.24L0 72.32 69.76 0l158.72 160A464 464 0 0 1 512 60.16a432 432 0 0 1 281.6 99.84L954.24 0 1024 72.32l-161.92 157.44A430.08 430.08 0 0 1 960 512a448 448 0 0 1-99.2 283.52L1024 951.68zM512 160a337.28 337.28 0 0 0-250.24 103.68A342.4 342.4 0 0 0 160.64 512a343.04 343.04 0 0 0 104.96 249.6 339.84 339.84 0 0 0 492.16 0A344.32 344.32 0 0 0 862.08 512a332.8 332.8 0 0 0-105.6-250.24A339.84 339.84 0 0 0 512 160z" fill="#666666" ></path></symbol><symbol id="edui-for-clearboard" viewBox="0 0 1024 1024"><path d="M704 128V0H320v128H0v64h64v832h896V192h64V128zM384 64h256v64H384zM320 960H128V384h192z m320 0H384V384h256z m256 0h-192V384h192z m0-640H128V192h768z" fill="#666666" ></path></symbol><symbol id="edui-for-bold" viewBox="0 0 1024 1024"><path d="M876.8 710.4c-6.4-51.2-25.6-102.4-57.6-140.8-32-38.4-83.2-70.4-128-76.8 44.8-12.8 76.8-38.4 102.4-76.8 32-38.4 38.4-83.2 38.4-134.4 0-57.6-25.6-121.6-70.4-166.4C710.4 76.8 640 64 576 64H192v896h384c76.8 6.4 140.8-12.8 211.2-51.2 57.6-44.8 96-121.6 89.6-198.4zM288 153.6h262.4c44.8 0 96 6.4 134.4 38.4 32 25.6 51.2 57.6 44.8 96 0 44.8-12.8 83.2-44.8 115.2-38.4 32-89.6 44.8-134.4 38.4H288V153.6zM768 704c0 51.2-25.6 102.4-70.4 134.4-44.8 25.6-89.6 38.4-140.8 38.4H288V544h275.2c51.2 0 102.4 6.4 147.2 38.4 44.8 25.6 64 76.8 57.6 121.6z" fill="#666666" ></path></symbol><symbol id="edui-for-fullscreen" viewBox="0 0 1024 1024"><path d="M960 0H64a64 64 0 0 0-64 64v704a64 64 0 0 0 64 64h320v128H288a32 32 0 0 0 0 64h448a32 32 0 0 0 0-64H640v-128h320a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64zM576 960H448v-128h128z m384-256a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-formatmatch" viewBox="0 0 1024 1024"><path d="M128 448v448l108.8-300.8L396.8 896H896V448zM128 256h768v64H128zM384 128h256v128H384z" fill="#666666" ></path></symbol><symbol id="edui-for-underline" viewBox="0 0 1024 1024"><path d="M192 896h640v64H192zM704 64v384c0 102.4-83.2 192-192 192-102.4 0-192-83.2-192-192V64H192v384c0 179.2 147.2 320 320 320s320-147.2 320-320V64h-128z" fill="#666666" ></path></symbol><symbol id="edui-for-removeformat" viewBox="0 0 1024 1024"><path d="M682.88 64L0 768l170.88 192h398.08L1024 448zM528 832h-288L192 775.04l192-227.2 192 227.84z" fill="#666666" ></path></symbol><symbol id="edui-for-blockquote" viewBox="0 0 1024 1024"><path d="M401.92 894.272v-292.48H248.064c-7.36-187.392 65.92-344.96 219.648-472.448L401.856 61.888C218.88 189.44 127.36 384.384 127.36 646.72v247.552h274.56z m428.16 0v-292.48h-153.728c-7.36-187.392 65.92-344.96 219.648-472.448L830.08 61.888c-182.976 127.616-274.432 322.496-274.432 584.832v247.552h274.496z" fill="#666666" ></path></symbol><symbol id="edui-for-anchor" viewBox="0 0 1024 1024"><path d="M722.56 668.16l76.8 72.32A438.4 438.4 0 0 1 576 837.76V436.48a192 192 0 1 0-128 0v400a448 448 0 0 1-231.68-90.88l82.56-77.44L0 625.28l45.44 280.96L124.8 832a618.88 618.88 0 0 0 384 128 597.12 597.12 0 0 0 384-133.12l87.04 81.92 44.16-283.52zM384 256a128 128 0 1 1 128 128 128 128 0 0 1-128-128z" fill="#666666" ></path></symbol><symbol id="edui-for-help" viewBox="0 0 1024 1024"><path d="M512 0a512 512 0 1 0 512 512 512 512 0 0 0-512-512z m0 960a448 448 0 1 1 448-448 448 448 0 0 1-448 448z" fill="#666666" ></path><path d="M512 640H448v-27.52a151.68 151.68 0 0 1 75.52-117.76q64-47.36 64-90.24a64 64 0 0 0-64-57.6q-76.8 0-95.36 87.68L320 414.08A192 192 0 0 1 536.96 256q153.6 7.68 167.04 135.68a156.16 156.16 0 0 1-90.24 140.8A544 544 0 0 0 512 620.16zM448 704h128v128H448z" fill="#666666" ></path></symbol><symbol id="edui-for-horizontal" viewBox="0 0 1024 1024"><path d="M0 448h1024v128H0z" fill="#666666" ></path></symbol><symbol id="edui-for-simpleupload" viewBox="0 0 1024 1024"><path d="M128 832l160-320L448 832H128zM514.56 832l254.72-512L1024 832H514.56z" fill="#666666" ></path><path d="M960 64H64a64 64 0 0 0-64 64v768a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V128a64 64 0 0 0-64-64z m0 768a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V192a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-indent" viewBox="0 0 1024 1024"><path d="M896 416L768 320v384l128-96L1024 512zM32 128h960c19.2 0 32-12.8 32-32s-12.8-32-32-32H32c-19.2 0-32 12.8-32 32s12.8 32 32 32zM32 960h960c19.2 0 32-12.8 32-32s-12.8-32-32-32H32c-19.2 0-32 12.8-32 32s12.8 32 32 32zM64 448h512c32 0 64-25.6 64-64 0-32-25.6-64-64-64H64c-38.4 0-64 25.6-64 64s25.6 64 64 64zM64 704h512c32 0 64-25.6 64-64 0-32-25.6-64-64-64H64c-32 0-64 25.6-64 64s25.6 64 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-justifycenter" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 256h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 640h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 1024h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM800 640h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-justifyleft" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM608 256h-576C12.8 256 0 243.2 0 224S12.8 192 32 192h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM608 1024h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM608 640h-576c-19.2 0-32-12.8-32-32S12.8 576 32 576h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-justifyjustify" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 256H32C12.8 256 0 243.2 0 224S12.8 192 32 192h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 1024H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 640H32c-19.2 0-32-12.8-32-32S12.8 576 32 576h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-justifyright" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 256h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 832H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 1024h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 640h-576c-19.2 0-32-12.8-32-32s12.8-32 32-32h576c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-link" viewBox="0 0 1024 1024"><path d="M759.04 768v-124.16a132.48 132.48 0 1 0 0-264.96H608.64A135.04 135.04 0 0 0 472.32 512h-128a261.12 261.12 0 0 1 264.32-256h150.4A261.12 261.12 0 0 1 1024 512a261.12 261.12 0 0 1-264.96 256z" fill="#666666" ></path><path d="M415.36 768H264.96A261.12 261.12 0 0 1 0 512a261.12 261.12 0 0 1 264.96-256v124.16a132.48 132.48 0 1 0 0 264.96h150.4A135.04 135.04 0 0 0 552.32 512h128a261.12 261.12 0 0 1-264.96 256z" fill="#666666" ></path></symbol><symbol id="edui-for-cleardoc" viewBox="0 0 1024 1024"><path d="M895.909541 256.060626h-191.95477V56.427664A63.984924 63.984924 0 0 0 639.969847 0.120932H137.688197A69.743567 69.743567 0 0 0 64.105535 64.105855v895.78893a69.743567 69.743567 0 0 0 73.582662 63.984923h748.623606A69.743567 69.743567 0 0 0 959.894465 959.894785V313.007208A63.984924 63.984924 0 0 0 895.909541 256.060626z m0 695.516119a8.31804 8.31804 0 0 1-8.31804 8.31804H137.688197a9.597739 9.597739 0 0 1-9.597738-9.597739V72.423895A8.31804 8.31804 0 0 1 136.408499 64.105855h491.404213a11.517286 11.517286 0 0 1 12.157135 10.877437v191.954771A60.145828 60.145828 0 0 0 703.954771 320.045549h180.437484a11.517286 11.517286 0 0 1 12.157136 10.877437v620.653759z" fill="#666666" ></path></symbol><symbol id="edui-for-drafts" viewBox="0 0 1024 1024"><path d="M832 320V160a32 32 0 0 0-32-32H576V64a64 64 0 0 0-64-64H384a64 64 0 0 0-64 64v64H96a32 32 0 0 0-32 32v640a32 32 0 0 0 32 32H384v192h448l192-192V320zM384 64h128v64H384zM192 192h512v64H192z m640 741.76V832h101.76zM960 768h-192v192H448V384h512z" fill="#666666" ></path></symbol><symbol id="edui-for-subscript" viewBox="0 0 1024 1024"><path d="M716.8 819.2v-29.696c0-99.328 160.256-135.68 160.256-179.2 0-16.896-10.752-27.136-32.768-27.136a116.736 116.736 0 0 0-74.24 35.84l-47.104-51.2A170.496 170.496 0 0 1 852.992 512c76.288 0 119.808 40.448 119.808 93.184 0 74.752-95.232 94.72-142.848 141.312H972.8V819.2zM72.192 720.384l494.592-494.592a56.832 56.832 0 0 1 78.848-8.704l7.68 7.68a56.832 56.832 0 0 1-8.704 78.848l-494.592 494.592a56.832 56.832 0 0 1-78.848 8.704l-7.68-7.68a56.832 56.832 0 0 1 8.704-78.848z" fill="#666666" ></path><path d="M566.784 798.208L72.192 303.616a56.832 56.832 0 0 1-8.704-78.848l7.68-7.68a56.832 56.832 0 0 1 78.848 8.704l494.592 494.592a56.832 56.832 0 0 1 8.704 78.848l-7.68 7.68a56.832 56.832 0 0 1-78.848-8.704z" fill="#666666" ></path></symbol><symbol id="edui-for-unlink" viewBox="0 0 1024 1024"><path d="M539.416837 448.012238V320.036713A95.341766 95.341766 0 0 0 639.877623 233.653234v-19.196329A95.341766 95.341766 0 0 0 539.416837 128.073426H228.436312A95.341766 95.341766 0 0 0 127.975525 214.456905v18.556451A95.341766 95.341766 0 0 0 228.436312 320.036713v127.975525A222.037535 222.037535 0 0 1 0 233.653234v-19.196329A222.037535 222.037535 0 0 1 228.436312 0.097901h310.980525A222.037535 222.037535 0 0 1 767.853148 214.456905v18.556451A222.037535 222.037535 0 0 1 539.416837 448.012238zM795.367886 1023.902099H484.387361A222.037535 222.037535 0 0 1 255.951049 809.543095v-18.556451A222.037535 222.037535 0 0 1 484.387361 575.987762v127.975525A95.341766 95.341766 0 0 0 383.926574 790.346766v18.556451A95.341766 95.341766 0 0 0 484.387361 895.926574h311.620403A95.341766 95.341766 0 0 0 895.828673 809.543095v-18.556451A95.341766 95.341766 0 0 0 795.367886 703.963287V575.987762A222.037535 222.037535 0 0 1 1023.804197 790.346766v18.556451A222.037535 222.037535 0 0 1 795.367886 1023.902099z" fill="#666666" ></path></symbol><symbol id="edui-for-superscript" viewBox="0 0 1024 1024"><path d="M716.8 512v-29.696c0-99.328 160.256-135.68 160.256-179.2 0-16.896-10.752-27.136-32.768-27.136a116.736 116.736 0 0 0-74.24 35.84l-47.104-51.2A170.496 170.496 0 0 1 852.992 204.8C929.28 204.8 972.8 245.248 972.8 297.984c0 74.752-95.232 94.72-142.848 141.312H972.8V512zM72.192 720.384l494.592-494.592a56.832 56.832 0 0 1 78.848-8.704l7.68 7.68a56.832 56.832 0 0 1-8.704 78.848l-494.592 494.592a56.832 56.832 0 0 1-78.848 8.704l-7.68-7.68a56.832 56.832 0 0 1 8.704-78.848z" fill="#666666" ></path><path d="M566.784 798.208L72.192 303.616a56.832 56.832 0 0 1-8.704-78.848l7.68-7.68a56.832 56.832 0 0 1 78.848 8.704l494.592 494.592a56.832 56.832 0 0 1 8.704 78.848l-7.68 7.68a56.832 56.832 0 0 1-78.848-8.704z" fill="#666666" ></path></symbol><symbol id="edui-for-forecolor" viewBox="0 0 1024 1024"><path d="M588.8 64H428.8L192 768h108.8l57.6-166.4h275.2l57.6 166.4H832L588.8 64zM390.4 499.2l102.4-313.6 102.4 313.6H390.4zM192 896h640v64H192z" fill="#666666" ></path></symbol><symbol id="edui-for-backcolor" viewBox="0 0 1024 1024"><path d="M910.593777 663.461622s-105.39199 190.467451-105.39199 246.972795a105.39199 105.39199 0 1 0 210.149088 0c0.634892-59.04491-104.757098-246.972795-104.757098-246.972795zM412.838838 100.947749L388.712961 126.978301 266.813792 0 169.675392 100.312858l121.899168 126.978301L0.15936 526.325057 412.838838 952.337256 825.518316 526.325057z m-274.27313 425.377308l275.542913-283.796502 274.908021 283.796502z" fill="#666666" ></path></symbol><symbol id="edui-for-touppercase" viewBox="0 0 1024 1024"><path d="M295.68 128L0 896h113.28l74.24-192h328.96l71.04 192H704L408.32 128z m-53.12 448l92.16-250.88A245.76 245.76 0 0 0 353.28 256a225.92 225.92 0 0 0 16 69.12L461.44 576zM996.48 812.16v-115.84Q998.4 576 865.28 576t-152.32 92.16l67.84 17.92q8.32-55.68 82.56-51.84t64 53.76a224.64 224.64 0 0 1-97.28 19.84q-122.88 12.16-128 101.76T820.48 896a139.52 139.52 0 0 0 114.56-44.16 48.64 48.64 0 0 0 19.2 37.76H1024a102.4 102.4 0 0 1-27.52-77.44zM926.72 768q-6.4 64-95.36 71.68-56.96 0-55.04-32t67.84-44.16a149.76 149.76 0 0 0 82.56-23.68zM949.76 384H1024c-15.36-106.88-232.32-128-311.04-128V128L512 288 712.32 448V327.04a488.96 488.96 0 0 1 237.44 56.96z" fill="#666666" ></path></symbol><symbol id="edui-for-tolowercase" viewBox="0 0 1024 1024"><path d="M295.68 128L0 896h113.28l74.24-192h328.96l71.04 192H704L408.32 128z m-53.12 448l92.16-250.88A245.76 245.76 0 0 0 353.28 256a225.92 225.92 0 0 0 16 69.12L461.44 576zM996.48 812.16v-115.84Q998.4 576 865.28 576t-152.32 92.16l67.84 17.92q8.32-55.68 82.56-51.84t64 53.76a224.64 224.64 0 0 1-97.28 19.84q-122.88 12.16-128 101.76T820.48 896a139.52 139.52 0 0 0 114.56-44.16 48.64 48.64 0 0 0 19.2 37.76H1024a102.4 102.4 0 0 1-27.52-77.44zM926.72 768q-6.4 64-95.36 71.68-56.96 0-55.04-32t67.84-44.16a149.76 149.76 0 0 0 82.56-23.68zM586.24 384H512c15.36-106.88 232.32-128 311.04-128V128L1024 288 823.04 448V327.04a488.96 488.96 0 0 0-236.8 56.96z" fill="#666666" ></path></symbol><symbol id="edui-for-insertvideo" viewBox="0 0 1024 1024"><path d="M384 768l256-256-256-256v512z" fill="#666666" ></path><path d="M960 64H64a64 64 0 0 0-64 64v768a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V128a64 64 0 0 0-64-64z m0 832H64V128h896z" fill="#666666" ></path></symbol><symbol id="edui-for-emotion" viewBox="0 0 1024 1024"><path d="M512 0a512 512 0 1 0 512 512 512 512 0 0 0-512-512z m0 960a448 448 0 1 1 448-448 448 448 0 0 1-448 448z" fill="#666666" ></path><path d="M320 384m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#666666" ></path><path d="M704 384m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#666666" ></path><path d="M512 832a256 256 0 0 0 256-256H256a256 256 0 0 0 256 256z" fill="#666666" ></path></symbol><symbol id="edui-for-pasteplain" viewBox="0 0 1024 1024"><path d="M640 256V128H576V64a64 64 0 0 0-64-64H320a64 64 0 0 0-64 64v64H192v128zM320 64h192v64H320z" fill="#666666" ></path><path d="M832 384V160a33.28 33.28 0 0 0-33.92-32H704v64h64v64h-64v64H128V128H33.92a33.28 33.28 0 0 0-33.92 32V896h384v128h640V384z m-384 576V448h512v512z" fill="#666666" ></path><path d="M576 576h320v64H576zM704 640h64v256h-64zM704 192h64v128h-64z" fill="#666666" ></path></symbol><symbol id="edui-for-preview" viewBox="0 0 1024 1024"><path d="M895.909541 256.060626h-191.95477V56.427664A63.984924 63.984924 0 0 0 639.969847 0.120932H137.688197A69.743567 69.743567 0 0 0 64.105535 64.105855v895.78893a69.743567 69.743567 0 0 0 73.582662 63.984923h748.623606A69.743567 69.743567 0 0 0 959.894465 959.894785V313.007208A63.984924 63.984924 0 0 0 895.909541 256.060626z m0 695.516119a8.31804 8.31804 0 0 1-8.31804 8.31804H137.688197a9.597739 9.597739 0 0 1-9.597738-9.597739V72.423895A8.31804 8.31804 0 0 1 136.408499 64.105855h491.404213a11.517286 11.517286 0 0 1 12.157135 10.877437v191.954771A60.145828 60.145828 0 0 0 703.954771 320.045549h180.437484a11.517286 11.517286 0 0 1 12.157136 10.877437v620.653759z" fill="#666666" ></path><path d="M767.939694 850.480566l-173.399143-172.759294a225.86678 225.86678 0 1 0-45.429295 45.429296l173.399142 172.759293zM256.060306 543.992782A159.962309 159.962309 0 1 1 416.022615 703.955091 159.962309 159.962309 0 0 1 256.060306 543.992782z" fill="#666666" ></path></symbol><symbol id="edui-for-print" viewBox="0 0 1024 1024"><path d="M320.00576 448h384v64H320.00576zM320.00576 576h384v64H320.00576z" fill="#666666" ></path><path d="M988.80576 179.2H832.00576V0H192.00576v179.2H35.20576a35.2 35.2 0 0 0-35.2 35.84v443.52h192V704l256 256h384v-301.44h192V346.88a36.48 36.48 0 0 0 0-3.84v-128a35.2 35.2 0 0 0-35.2-35.84zM256.00576 64h512v115.2H256.00576z m640 512h-56.96V455.68H768.00576V896H471.04576v-199.04H256.00576V455.68H187.52576V576H128.00576V384h768z m32-274.56a32.64 32.64 0 1 1 32-32.64 32 32 0 0 1-32 32.64z" fill="#666666" ></path></symbol><symbol id="edui-for-searchreplace" viewBox="0 0 1024 1024"><path d="M855.04 0H0v1024h1024V343.04zM512 128h128v256H512z m256 832H256v-320h512z m192-512v512h-128V576H192v384H64V64h128v384h512V64h64l192 320z" fill="#666666" ></path></symbol><symbol id="edui-for-selectall" viewBox="0 0 1024 1024"><path d="M184.32 113.92L298.24 0h-40.32L144 113.92h40.32zM113.92 144L0 257.92v40.32l113.92-113.92v-40.32zM144 0L0 144v40.32L184.32 0h-40.32zM30.72 0L0 30.72v40.32L71.04 0H30.72zM527.36 113.92L641.28 0h-40.32L487.68 113.92h39.68zM113.92 487.68L0 600.96v40.32l113.92-113.92v-39.68zM113.92 373.76L0 487.68v39.68l113.92-113.28v-40.32zM414.08 113.92L527.36 0h-39.68L373.76 113.92h40.32zM300.16 113.92L414.08 0h-40.32L259.84 113.92h40.32zM113.92 259.84L0 373.76v40.32l113.92-113.92v-40.32zM113.92 835.2L0 948.48v40.32l113.92-113.28v-40.32zM875.52 113.92L988.8 0h-40.32l-113.28 113.92h40.32zM113.92 721.28L0 835.2v40.32l113.92-113.92v-40.32zM761.6 113.92L875.52 0h-40.32l-113.92 113.92h40.32zM113.92 607.36L0 721.28v40.32l113.92-113.92v-40.32zM647.68 113.92L761.6 0h-40.32L607.36 113.92h40.32zM910.08 419.2L1024 305.28v-40.32l-113.92 113.92v40.32zM378.88 910.08L264.96 1024h40.32l113.92-113.92h-40.32zM910.08 305.28L1024 192v-40.32l-113.92 113.28v40.32zM264.96 910.08L151.68 1024H192l113.28-113.92h-40.32zM151.68 910.08L37.76 1024h40.32L192 910.08h-40.32zM910.08 151.68V192L1024 78.08V37.76l-113.92 113.92zM910.08 759.04L1024 645.12v-40.32l-113.92 113.92v40.32zM718.72 910.08L604.8 1024h40.32l113.92-113.92h-40.32zM910.08 645.12L1024 531.2v-40.32l-113.92 113.92v40.32zM604.8 910.08L490.88 1024h40.32l113.92-113.92h-40.32zM490.88 910.08L376.96 1024h40.32l113.92-113.92h-40.32zM910.08 531.2L1024 417.28v-40.32l-113.92 113.92v40.32zM988.16 1024l35.84-35.84v-40.32L947.84 1024h40.32zM874.24 1024L1024 874.24v-40.32L833.92 1024h40.32zM833.92 910.08L720.64 1024h39.68l113.92-113.92h-40.32zM910.08 874.24L1024 760.32v-39.68l-113.92 113.28v40.32zM256 630.4Q263.04 768 442.24 768a223.36 223.36 0 0 0 183.04-70.4 77.44 77.44 0 0 0 30.72 60.8H768a163.84 163.84 0 0 1-44.16-124.8V448Q727.04 256 512 256T269.44 403.2l108.8 28.8q13.44-89.6 133.76-83.2 112-6.4 101.76 86.4a359.68 359.68 0 0 1-156.16 32Q259.2 486.4 256 630.4zM611.84 518.4v44.8q-10.24 105.6-152.32 115.2-91.52 0-88.32-51.2-6.4-60.8 108.8-70.4a240 240 0 0 0 131.84-38.4z" fill="#666666" ></path></symbol><symbol id="edui-for-mergecells" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m0-320H64V64h256z m64-256h256v256H384z m576 896H384V384h576z m0-640h-256V64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-deletecol" viewBox="0 0 1024 1024"><path d="M1024 307.84V0h-256v576h256zM832 256V64h128v192z m0 256V320h128v192zM448 307.84V0H0v576h448zM64 256V64h128v192z m192 0V64h128v192zM64 512V320h128v192z m192 0V320h128v192zM640 704V635.52L570.24 704H640zM593.28 708.48z" fill="#666666" ></path><path d="M640 512v136.32l64-34.56V256H512v352l64 32V512zM576 448V320h64v128z" fill="#666666" ></path><path d="M734.72 1024l96.64-92.8L704 808.96l128-122.88-96-92.16-32 19.84V768H512V608l-32-14.08L384 686.08l128 122.88-127.36 122.24L480.64 1024l127.36-122.24L734.72 1024z" fill="#666666" ></path><path d="M512 704h76.8L512 629.76V704z" fill="#666666" ></path></symbol><symbol id="edui-for-deleterow" viewBox="0 0 1024 1024"><path d="M307.84 0H0v256h576V0zM256 192H64V64h192z m256 0H320V64h192zM307.84 576H0v448h576V576zM256 960H64v-128h192z m0-192H64v-128h192z m256 192H320v-128h192z m0-192H320v-128h192zM716.8 360.32h-68.48l68.48 70.4v-70.4zM708.48 430.72zM520.96 344.96h128l-34.56-35.84H256v219.52h352l32-35.84H520.96zM448 448H316.16V384H448z" fill="#666666" ></path><path d="M1024 288.64l-92.8-96L808.96 320l-122.88-128-92.16 96 19.84 21.12h137.6V528.64H608l-14.08 15.36 92.16 96 122.88-128 122.24 127.36L1024 542.72 901.76 416 1024 288.64z" fill="#666666" ></path><path d="M716.8 492.8V416l-74.24 76.8h74.24z" fill="#666666" ></path></symbol><symbol id="edui-for-attachment" viewBox="0 0 1024 1024"><path d="M972.16 372.48l-520.32 512a222.72 222.72 0 0 1-312.32 0A216.32 216.32 0 0 1 138.88 576l468.48-460.8a148.48 148.48 0 0 1 208 0 144.64 144.64 0 0 1 0 206.08l-467.84 463.36a74.24 74.24 0 0 1-104.32 0 72.32 72.32 0 0 1 0-103.04l416.64-411.52-51.84-51.2L192 630.4a144.64 144.64 0 0 0 0 206.08 148.48 148.48 0 0 0 208 0l468.48-463.36a216.96 216.96 0 0 0 0-308.48A222.72 222.72 0 0 0 555.52 64L64 552.96a291.2 291.2 0 0 0 26.24 384 296.96 296.96 0 0 0 385.28 23.04L1024 424.32l-51.84-51.2z" fill="#666666" ></path></symbol><symbol id="edui-for-music" viewBox="0 0 1024 1024"><path d="M991.140186 0.88755h-7.673343a36.448381 36.448381 0 0 0-15.986133 0L219.969177 135.810504a31.972264 31.972264 0 0 0-28.135593 30.693374 30.053928 30.053928 0 0 0 0 3.197226v616.425251A127.889056 127.889056 0 0 0 127.889056 768.221888a127.889056 127.889056 0 1 0 127.889056 127.889056V384.554719a36.448381 36.448381 0 0 0 17.904468 0L959.167922 260.502334v457.203376a127.889056 127.889056 0 0 0-63.944528-17.904468A127.889056 127.889056 0 1 0 1023.11245 832.166416V32.859814a31.972264 31.972264 0 0 0-31.972264-31.972264z" fill="#666666" ></path></symbol><symbol id="edui-for-gmap" viewBox="0 0 1024 1024"><path d="M543.36 572.16h128v144.64a170.24 170.24 0 0 1-103.68 30.08c-135.68 0-208-89.6-208-236.8s83.84-233.6 206.08-233.6a183.04 183.04 0 0 1 138.24 55.68l56.32-64A270.72 270.72 0 0 0 562.56 192 298.24 298.24 0 0 0 256 512c0 202.24 128 320 304 320A306.56 306.56 0 0 0 768 759.68V492.16H543.36z" fill="#1C7C59" ></path><path d="M896 0H128a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h768a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H192a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h640a64 64 0 0 1 64 64z" fill="#1C7C59" ></path></symbol><symbol id="edui-for-insertframe" viewBox="0 0 1024 1024"><path d="M448 384a256 256 0 1 0 256 256 256 256 0 0 0-256-256z m195.84 170.88a213.76 213.76 0 0 1 0 170.88H547.2a504.32 504.32 0 0 0 0-170.88zM384 640a527.36 527.36 0 0 1 6.4-85.12h115.2A527.36 527.36 0 0 1 512 640a527.36 527.36 0 0 1-6.4 85.12H390.4A527.36 527.36 0 0 1 384 640z m234.88-128H537.6a218.88 218.88 0 0 0-39.68-79.36A213.76 213.76 0 0 1 618.88 512zM448 448c19.2 0 35.84 24.96 48 64h-96c12.16-39.04 28.8-64 48-64z m-49.92-15.36A218.88 218.88 0 0 0 358.4 512H277.12a213.76 213.76 0 0 1 120.96-79.36zM252.16 554.88h96a504.32 504.32 0 0 0 0 170.88h-96a213.76 213.76 0 0 1 0-170.88zM277.12 768H358.4a218.88 218.88 0 0 0 39.68 79.36A213.76 213.76 0 0 1 277.12 768zM448 832c-19.2 0-35.84-24.96-48-64h96c-12.16 39.04-28.8 64-48 64z m49.92 15.36A218.88 218.88 0 0 0 537.6 768h81.28a213.76 213.76 0 0 1-120.96 79.36z" fill="#666666" ></path><path d="M597.76 0H64v1024h896V330.24zM896 355.84V960H128V64h448v256h320z" fill="#666666" ></path></symbol><symbol id="edui-for-pdfformat" viewBox="0 0 1024 1024"><path d="M597.76 0H64v1024h896V330.24zM896 960H128V64h448v291.2h320z" fill="#EF4848" ></path><path d="M213.76 615.68H166.4v133.12h49.28c58.24 0 85.76-21.76 85.76-69.76s-30.72-63.36-87.68-63.36zM486.4 622.08h-32.64v268.8h32.64c77.44 0 119.04-45.44 119.04-135.68S564.48 622.08 486.4 622.08z" fill="#EF4848" ></path><path d="M64 448v576h874.24V448z m175.36 352.64h-54.4v136.96H128V576h109.44c82.56 0 138.24 27.52 138.24 108.8S320 800.64 239.36 800.64z m256 136.96H396.8V576h93.44a159.36 159.36 0 0 1 174.72 179.2 160.64 160.64 0 0 1-171.52 182.4z m411.52-313.6h-158.72v110.72h133.76v48h-133.76v155.52h-56.96V576h214.4z" fill="#EF4848" ></path></symbol><symbol id="edui-for-word" viewBox="0 0 1024 1024"><path d="M718.08 545.92c-12.16 60.16-21.12 117.76-32 177.28h-3.84c-12.8-58.88-23.68-117.12-36.48-177.28L567.68 208H461.44L384 545.92c-12.8 58.88-23.68 117.76-35.84 177.28H345.6c-9.6-58.88-18.56-117.12-29.44-177.28L243.2 208H128L275.84 832h131.84l64-307.2c14.08-58.88 23.68-117.12 34.56-181.76H512c12.16 64 21.76 121.6 34.56 180.48L618.24 832h136.96L896 208h-106.88z" fill="#4972AD" ></path><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#4972AD" ></path></symbol><symbol id="edui-for-excel" viewBox="0 0 1024 1024"><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#60BF6B" ></path><path d="M816.64 128h-155.52L586.24 282.88c-19.2 41.6-40.32 85.12-59.52 128h-5.12c-23.04-43.52-46.72-86.4-67.2-128L369.28 128H208.64L422.4 495.36 192 896h156.16l82.56-161.92c21.76-47.36 44.16-93.44 64-136.96h6.4c25.6 43.52 50.56 90.88 73.6 136.96l96 161.92H832L602.88 512z" fill="#60BF6B" ></path></symbol><symbol id="edui-for-time" viewBox="0 0 1024 1024"><path d="M839.710352 230.607611l21.719276-21.719277 43.438553 43.438553 54.298191-53.659389-127.760449-127.760449-54.936993 54.298191 43.438552 43.438553-21.719276 21.719276A477.82408 477.82408 0 0 0 556.720957 74.739863a76.656269 76.656269 0 0 0-152.673737 0 472.713662 472.713662 0 0 0-87.515907 23.635683l51.104179 79.211478a383.281347 383.281347 0 0 1 112.429196-17.24766 383.281347 383.281347 0 1 1-383.281348 383.281347 383.281347 383.281347 0 0 1 47.271366-184.613849L64.843228 304.708671a472.07486 472.07486 0 0 0-63.880225 240.189645 479.101684 479.101684 0 0 0 958.203369 0 473.352464 473.352464 0 0 0-119.45602-314.290705z" fill="#666666" ></path><path d="M480.064688 255.520898a46.632564 46.632564 0 0 0-46.632564 45.993762v182.05864a76.017467 76.017467 0 0 0 0 122.650031v63.880225a46.632564 46.632564 0 0 0 92.626325 0v-63.880225a76.017467 76.017467 0 0 0 0-122.650031V298.959451A46.632564 46.632564 0 0 0 480.064688 255.520898zM252.651088 0L143.415904 251.049283l274.684966 5.110418-50.465378-77.933874-51.104179-79.850281-63.880225-98.375546z" fill="#666666" ></path></symbol><symbol id="edui-for-snapscreen" viewBox="0 0 1024 1024"><path d="M665.6 392.96L460.8 548.48 256 314.88V704h512V548.48l-102.4-155.52z" fill="#666666" ></path><path d="M1024 832h-128V128H192V0H128v128H0v64h128v704h704v128h64v-128h128zM192 832V192h640v640z" fill="#666666" ></path></symbol><symbol id="edui-for-wordimage" viewBox="0 0 1024 1024"><path d="M988.16 448H419.84a35.84 35.84 0 0 0-35.84 35.84v504.32a35.84 35.84 0 0 0 35.84 35.84h568.96a35.84 35.84 0 0 0 35.84-35.84V483.84a35.84 35.84 0 0 0-36.48-35.84z m-323.84 164.48a80 80 0 1 1-80-81.92 81.28 81.28 0 0 1 80 81.92zM929.28 960H461.44l131.2-205.44 85.12 133.12 177.28-298.24L960 768v163.2a30.72 30.72 0 0 1-30.72 28.8z" fill="#666666" ></path><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h256v-64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64v256h64V64a64 64 0 0 0-64-64z" fill="#4972AD" ></path><path d="M320 554.24L241.28 192H122.88l151.68 640H320V565.76zM858.88 384l43.52-192h-116.48l-40.32 192h113.28zM501.76 384c0-26.88 4.48-40.32 7.04-64H512c0 23.68 7.68 64 7.68 64h97.28l-44.8-192H456.32l-42.88 192z" fill="#4972AD" ></path></symbol><symbol id="edui-for-edittd" viewBox="0 0 1024 1024"><path d="M768 768m-192 0a192 192 0 1 0 384 0 192 192 0 1 0-384 0Z" fill="#666666" ></path><path d="M448 768a320 320 0 0 1 448-293.12V128H128v768h346.88A320 320 0 0 1 448 768z" fill="#666666" ></path><path d="M0 0v1024h576a320 320 0 0 1-64-64H64V64h896v448a320 320 0 0 1 64 64V0z" fill="#666666" ></path></symbol><symbol id="edui-for-lineheight" viewBox="0 0 1024 1024"><path d="M380.8 768H0l190.72 254.72L380.8 768z" fill="#666666" ></path><path d="M512 768l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M512 576l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M512 384l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M512 192l512 0 0 64-512 0 0-64Z" fill="#666666" ></path><path d="M2.56 256h380.8L193.28 1.28 2.56 256z" fill="#666666" ></path></symbol><symbol id="edui-for-rowspacingbottom" viewBox="0 0 1024 1024"><path d="M704 768H320l192 256zM672 640H32c-19.2 0-32-12.8-32-32S12.8 576 32 576h640c19.2 0 32 12.8 32 32s-12.8 32-32 32zM864 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h832c19.2 0 32 12.8 32 32s-12.8 32-32 32zM480 256h-448C12.8 256 0 243.2 0 224S12.8 192 32 192h448c19.2 0 32 12.8 32 32s-12.8 32-32 32zM992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-rowspacingtop" viewBox="0 0 1024 1024"><path d="M320 256h384L512 0zM352 384h640c19.2 0 32 12.8 32 32s-12.8 32-32 32h-640c-19.2 0-32-12.8-32-32s12.8-32 32-32zM160 576h832c19.2 0 32 12.8 32 32s-12.8 32-32 32h-832c-19.2 0-32-12.8-32-32s12.8-32 32-32zM544 768h448c19.2 0 32 12.8 32 32s-12.8 32-32 32h-448c-19.2 0-32-12.8-32-32s12.8-32 32-32zM32 960h960c19.2 0 32 12.8 32 32s-12.8 32-32 32H32c-19.2 0-32-12.8-32-32s12.8-32 32-32z" fill="#666666" ></path></symbol><symbol id="edui-for-scrawl" viewBox="0 0 1024 1024"><path d="M1018.28352 277.12a20.48 20.48 0 0 0-15.36-6.4 68.48 68.48 0 0 0-40.96 23.68l-390.4 389.12a1234.56 1234.56 0 0 0-69.12 105.6l-8.32 14.08 14.08-8.96c3.84 0 90.24-56.96 104.96-71.04l390.4-389.12c16.64-14.08 29.44-41.6 14.72-56.96z m-243.84 120.96a56.96 56.96 0 1 1-56.96-58.88 58.24 58.24 0 0 1 56.96 58.88zM173.48352 603.52a58.88 58.88 0 1 1 56.96-58.88 58.24 58.24 0 0 1-56.96 58.88zM256.68352 398.08a56.96 56.96 0 1 1 56.96 58.88 58.24 58.24 0 0 1-56.96-58.88z m202.88-58.88a56.96 56.96 0 1 1 56.96 58.88 58.24 58.24 0 0 1-56.96-58.88z m442.88 199.04a415.36 415.36 0 0 1-402.56 352.64 335.36 335.36 0 0 1-122.88-23.68c-38.4-16-55.68-34.56-59.52-46.72s-3.84-13.44-5.12-20.48a250.24 250.24 0 0 0-23.04-64 81.28 81.28 0 0 0-72.96-43.52 114.56 114.56 0 0 0-26.24 0 187.52 187.52 0 0 1-42.24 5.12c-28.8 0-77.44-7.68-78.72-60.16-8.32-266.88 206.08-412.16 421.76-437.76a419.2 419.2 0 0 1 48.64 0 500.48 500.48 0 0 1 174.72 30.72c10.88 4.48 16.64 7.04 44.8 21.12a260.48 260.48 0 0 1 73.6 53.76l34.56-64a314.88 314.88 0 0 0-76.8-55.68c-28.8-14.08-36.48-17.92-49.92-23.68A570.24 570.24 0 0 0 539.56352 128a485.12 485.12 0 0 0-56.32 0 592 592 0 0 0-339.2 151.68A462.08 462.08 0 0 0 0.68352 640a122.88 122.88 0 0 0 46.72 97.28 159.36 159.36 0 0 0 99.84 30.72 256 256 0 0 0 57.6-7.04h10.88c13.44 0 19.2 11.52 30.72 57.6 0 7.68 3.84 15.36 5.76 23.04a154.88 154.88 0 0 0 99.2 91.52A403.84 403.84 0 0 0 499.88352 960a460.16 460.16 0 0 0 177.92-35.2A471.04 471.04 0 0 0 821.80352 832a496 496 0 0 0 100.48-135.04 476.8 476.8 0 0 0 48.64-158.72V519.04z" fill="#666666" ></path></symbol><symbol id="edui-for-redo" viewBox="0 0 1024 1024"><path d="M900.608 474.112c-51.2-51.2-260.608-261.632-291.84-292.352a68.096 68.096 0 0 0-91.648 3.072 73.216 73.216 0 0 0-14.336 76.288c12.288 18.432 187.904 199.68 187.904 199.68H169.984A61.952 61.952 0 0 0 102.4 525.312a71.168 71.168 0 0 0 68.096 67.584h517.632l-173.056 172.032a68.096 68.096 0 0 0 0 93.184 65.536 65.536 0 0 0 90.624 7.168c25.088-23.04 256-252.928 297.984-296.448s-3.072-94.72-3.072-94.72z" fill="#666666" ></path></symbol><symbol id="edui-for-undo" viewBox="0 0 1024 1024"><path d="M128.512 476.16c51.2-51.2 260.608-261.632 291.84-292.352a68.096 68.096 0 0 1 91.648 3.072 73.216 73.216 0 0 1 13.824 76.288C512 281.6 338.432 460.8 338.432 460.8h520.192a61.952 61.952 0 0 1 65.536 66.56 71.168 71.168 0 0 1-68.096 67.584H338.432L512 768a68.096 68.096 0 0 1 0 93.184 65.536 65.536 0 0 1-90.624 7.168c-25.088-23.04-256-252.928-297.984-296.448s5.12-95.744 5.12-95.744z" fill="#666666" ></path></symbol><symbol id="edui-for-inserttitle" viewBox="0 0 1024 1024"><path d="M512 516.096v-153.6H460.8v102.4H358.4v51.2H204.8v-51.2H102.4v-102.4H51.2v614.4h921.6v-460.8z m-173.056 409.6h-240.64V757.76h238.592z m0-219.136h-240.64v-139.264h238.592z m297.472 219.136H388.096V757.76h246.272z m0-219.136H388.096v-139.264h246.272z m283.136 219.136h-233.984V757.76h231.936z m0-219.136h-233.984v-139.264h231.936z" fill="#666666" ></path><path d="M512 465.408v51.2h460.8V51.2h-460.8v307.2z m51.2-204.8h153.6v-153.6h51.2v153.6h153.6v51.2h-153.6v153.6h-51.2v-153.6h-153.6z" fill="#1C7C59" ></path><path d="M99.328 108.032h102.4v-51.2h-153.6v153.6h51.2v-102.4zM512.512 104.96v-51.2h-153.6v51.2h102.4v102.4h51.2v-102.4z" fill="#666666" ></path></symbol><symbol id="edui-for-insertparagraphtrue" viewBox="0 0 1024 1024"><path d="M997.12 448H0v576h1024V448zM60.16 960v-256H320v256z m481.92 0H384v-256h256v256z m421.76 0H704v-256h259.84zM448 0H0v64h192v384h64V64h192V0z" fill="#666666" ></path></symbol><symbol id="edui-for-aligntable" viewBox="0 0 1024 1024"><path d="M992 64H32C12.8 64 0 51.2 0 32S12.8 0 32 0h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32C12.8 256 0 243.2 0 224S12.8 192 32 192h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 384H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32c-19.2 0-32-12.8-32-32s12.8-32 32-32h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path><path d="M992 448H32C12.8 448 0 435.2 0 416S12.8 384 32 384h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z m0 192H32c-19.2 0-32-12.8-32-32S12.8 576 32 576h960c19.2 0 32 12.8 32 32s-12.8 32-32 32z" fill="#666666" ></path></symbol><symbol id="edui-for-table" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m320 320H384v-256h256z m0-320H384V384h256z m320 320h-256v-256h256z m0-320h-256V384h256z m0-320H64V64h896z" fill="#666666" ></path></symbol><symbol id="edui-for-tablealignment-left" viewBox="0 0 1024 1024"><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 256l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 563.2l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 870.4l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-tablealignment-center" viewBox="0 0 1024 1024"><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 256l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 563.2l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 870.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-tablealignment-right" viewBox="0 0 1024 1024"><path d="M51.2 102.4l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M358.4 256l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 409.6l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M358.4 563.2l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path><path d="M51.2 716.8l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M358.4 870.4l614.4 0 0 51.2-614.4 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-paste" viewBox="0 0 1024 1024"><path d="M832 320V160a32 32 0 0 0-32-32H576V64a64 64 0 0 0-64-64H384a64 64 0 0 0-64 64v64H96a32 32 0 0 0-32 32v640a32 32 0 0 0 32 32H384v192h448l192-192V320zM384 64h128v64H384zM192 192h512v64H192z m640 741.76V832h101.76zM960 768h-192v192H448V384h512z" fill="#666666" ></path></symbol><symbol id="edui-for-map" viewBox="0 0 1024 1024"><path d="M375.424 331.824c-2.432 6.96-7.856 24.704-3.152 40.208 9.232 34.672 39.424 36.24 39.424 36.24h43.264V302.368h-46.4c-20.864 6.24-30.944 22.432-33.136 29.456z m129.072 119.072H397.008c-46.448-9.28-64.896-40.992-67.28-46.368-2.288-5.456-15.504-30.944-8.464-74.256 20.032-64.976 77.28-69.616 77.28-69.616h57.248v-70.368l48.704 0.8v259.808z m200.272-0.768H581.04c-47.92-12.368-50.176-46.496-50.176-46.496V266.816L581.04 266v123.024c3.008 13.024 19.376 15.44 19.376 15.44h50.912V266.768h53.456v183.36h-0.016z" fill="" ></path><path d="M512 1021.45c-11.203 0-21.563-6-27.172-15.688L208.375 527.726c-30.803-53.1-47.11-113.662-47.11-175.084 0-193.047 157.35-350.094 350.75-350.094 193.391 0 350.72 157.047 350.72 350.094 0 61.421-16.298 121.975-47.126 175.115l-276.437 478.007c-5.61 9.687-15.953 15.687-27.172 15.687z m0.016-956.138c-158.788 0-287.985 128.907-287.985 287.329 0 50.375 13.375 100.037 38.663 143.615l249.303 431.1 249.297-431.062c25.297-43.616 38.656-93.281 38.656-143.656 0-158.42-129.172-287.325-287.934-287.325z" fill="" ></path></symbol><symbol id="edui-for-directionalityrtl" viewBox="0 0 1024 1024"><path d="M960 833.92l-384-320 384-320.64v640.64zM64 192V128h448v64H320v640h192v64H64v-64h192V192H64z" fill="#666666" ></path></symbol><symbol id="edui-for-imagecenter" viewBox="0 0 1024 1024"><path d="M0 0h1024v64H0z" fill="#666666" ></path><path d="M128 192l768 0 0 448-768 0 0-448Z" fill="#66BBBF" ></path><path d="M0 768h1024v64H0zM0 960h1024v64H0z" fill="#666666" ></path></symbol><symbol id="edui-for-imagenone" viewBox="0 0 1024 1024"><path d="M52.736 107.008l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M52.736 260.608l409.6 0 0 512-409.6 0 0-512Z" fill="#66BBBF" ></path><path d="M564.736 721.408l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M54.784 875.008l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M564.736 567.808l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-fontborder" viewBox="0 0 1024 1024"><path d="M345.6 832l44.8-153.6h224l44.8 153.6H768L576 192H448L256 832h89.6z m153.6-531.2l83.2 288H416l83.2-288z" fill="#666666" ></path><path d="M896 64H64v896h896V64h-64z m0 832H128V128h768v768z" fill="#666666" ></path></symbol><symbol id="edui-for-edittable" viewBox="0 0 1024 1024"><path d="M993.92 848.64L849.92 704a240 240 0 0 0-320-300.8L512 410.24v2.56a12.16 12.16 0 0 0 0 17.28l134.4 134.4-81.92 80.64L432.64 512a14.08 14.08 0 0 0-23.68 5.12l-4.48 10.24a240 240 0 0 0 300.8 320l144 144a102.4 102.4 0 0 0 72.96 30.08 103.04 103.04 0 0 0 72.96-175.36zM960 960a56.96 56.96 0 0 1-40.32 16.64 56.96 56.96 0 0 1-40.32-16.64l-165.12-165.12-14.08 6.4a192 192 0 0 1-265.6-220.8L555.52 704a14.08 14.08 0 0 0 17.28 0l128-128a14.08 14.08 0 0 0 0-18.56L580.48 434.56A192 192 0 0 1 802.56 704l-6.4 14.08L960 880.64A56.96 56.96 0 0 1 960 960z" fill="#666666" ></path><path d="M832 0H0v832h320V320h512zM256 768H64V576h192z m0-256H64V320h192z m0-256H64V64h192z m256 0H320V64h192z m64 0V64h192v192z" fill="#666666" ></path></symbol><symbol id="edui-for-imageleft" viewBox="0 0 1024 1024"><path d="M50.688 101.376l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M50.688 254.976l409.6 0 0 512-409.6 0 0-512Z" fill="#66BBBF" ></path><path d="M562.688 715.776l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M52.736 869.376l921.6 0 0 51.2-921.6 0 0-51.2Z" fill="#666666" ></path><path d="M562.688 562.176l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M562.688 408.576l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path><path d="M562.688 254.976l409.6 0 0 51.2-409.6 0 0-51.2Z" fill="#666666" ></path></symbol><symbol id="edui-for-imageright" viewBox="0 0 1024 1024"><path d="M0 0h1024v64H0z" fill="#666666" ></path><path d="M512 192l512 0 0 640-512 0 0-640Z" fill="#66BBBF" ></path><path d="M0 768h448v64H0zM0 960h1024v64H0zM0 576h448v64H0zM0 384h448v64H0zM0 192h448v64H0z" fill="#666666" ></path></symbol><symbol id="edui-for-insertcol" viewBox="0 0 1024 1024"><path d="M256 256L0 512l256 256V256zM1024 1024V0H384v1024zM768 64h192v256h-192z m0 320h192v256h-192z m0 320h192v256h-192zM448 64h192v256H448z m0 320h192v256H448z m0 320h192v256H448z" fill="#666666" ></path></symbol><symbol id="edui-for-insertcolnext" viewBox="0 0 1024 1024"><path d="M768 768l256-256-256-256v512zM0 0v1024h640V0z m256 960H64v-256h192z m0-320H64V384h192z m0-320H64V64h192z m320 640H384v-256h192z m0-320H384V384h192z m0-320H384V64h192z" fill="#666666" ></path></symbol><symbol id="edui-for-insertorderedlist" viewBox="0 0 1024 1024"><path d="M319.955606 63.991121l703.902334 0 0 127.982243-703.902334 0 0-127.982243Z" fill="#666666" ></path><path d="M319.955606 447.937849l703.902334 0 0 127.982242-703.902334 0 0-127.982242Z" fill="#666666" ></path><path d="M319.955606 831.884576l703.902334 0 0 127.982242-703.902334 0 0-127.982242Z" fill="#666666" ></path><path d="M191.973364 0v255.964485H63.991121V0zM0 639.911212v-30.715738C0 505.529858 159.977803 467.775096 159.977803 422.3414c0-17.917514-10.878491-28.156093-33.275383-28.156093a114.544107 114.544107 0 0 0-74.229701 37.11485l-46.713518-54.392453a167.656738 167.656738 0 0 1 127.982242-56.952098C212.450522 319.955606 255.964485 362.189746 255.964485 417.22211c0 78.069168-95.346771 98.546327-142.7002 147.179579H255.964485V639.911212zM127.982242 1023.85794a165.737004 165.737004 0 0 1-127.982242-52.47272l48.633252-49.273163a106.865172 106.865172 0 0 0 69.750322 30.075827c28.156093 0 41.594229-14.078047 41.594229-33.275383 0-17.277603-12.158313-26.23636-36.474939-26.23636h-24.316626v-52.472719h24.956537c23.036804 0 36.474939-6.399112 36.474939-26.876271 0-19.837248-12.798224-31.355649-38.394672-31.35565a85.748102 85.748102 0 0 0-63.991122 31.35565l-47.993341-48.633252a158.058069 158.058069 0 0 1 127.982243-55.032365C211.1707 703.902334 255.964485 745.496562 255.964485 792.210081v5.11929a63.991121 63.991121 0 0 1-67.830589 63.991121c50.552986 7.039023 70.390233 33.275383 70.390234 67.190677v3.839467C255.964485 985.463267 204.131677 1023.85794 127.982242 1023.85794z" fill="#666666" ></path></symbol><symbol id="edui-for-insertparagraphbeforetable" viewBox="0 0 1024 1024"><path d="M256 384v640h768V384z m256 576H320V448h192z m448 0H576v-128h384z m0-192H576v-128h384z m0-192H576V448h384z" fill="#666666" ></path><path d="M384 576h64v256H384zM0 0v64h128v384h64V64h128V0H0z" fill="#666666" ></path></symbol><symbol id="edui-for-insertrow" viewBox="0 0 1024 1024"><path d="M768 256L512 0 256 256h512zM0 1024h1024V384H0z m960-256v192h-256v-192z m-320 0v192H384v-192z m-320 0v192H64v-192z m640-320v192h-256V448z m-320 0v192H384V448zM320 448v192H64V448z" fill="#666666" ></path></symbol><symbol id="edui-for-insertrownext" viewBox="0 0 1024 1024"><path d="M256 768l256 256 256-256H256zM1024 0H0v640h1024zM64 256V64h256v192z m320 0V64h256v192z m320 0V64h256v192zM64 576V384h256v192z m320 0V384h256v192z m320 0V384h256v192z" fill="#666666" ></path></symbol><symbol id="edui-for-insertunorderedlist" viewBox="0 0 1024 1024"><path d="M960 192H256c-38.4 0-64-25.6-64-64s25.6-64 64-64h704c38.4 0 64 25.6 64 64s-25.6 64-64 64zM64 192c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64zM960 576H256c-38.4 0-64-25.6-64-64s25.6-64 64-64h704c38.4 0 64 25.6 64 64s-25.6 64-64 64zM64 576c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64zM960 960H256c-38.4 0-64-25.6-64-64s25.6-64 64-64h704c38.4 0 64 25.6 64 64s-25.6 64-64 64zM64 960c-38.4 0-64-25.6-64-64s25.6-64 64-64 64 25.6 64 64-25.6 64-64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-mergeright" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m384 64h256v256H384z m0 384h320V384l192 128-192 128V576H384z m-64 512H64v-256h256z m0-320H64V384h256z m0-320H64V64h256z m320 640H384v-256h256z m320 0h-256v-256h256z m0-640h-256V64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-mergedown" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m0-320H64V64h256z m192 576l-128-192h64V384h128v320h64z m128-576H384V64h256z m320 640h-256v-256h256z m0-320h-256V384h256z m0-320h-256V64h256z" fill="#666666" ></path></symbol><symbol id="edui-for-inserttable" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64v-256h256z m0-320H64V384h256z m320 320H384v-256h256z m0-320H384V384h256z m320 320h-256v-256h256z m0-320h-256V384h256z m0-320H64V64h896z" fill="#666666" ></path></symbol><symbol id="edui-for-pagebreak" viewBox="0 0 1024 1024"><path d="M384 960h512v64H384zM0 320v384l256-192-256-192zM320 128h576v64H320zM384 832h256v64H384z" fill="#666666" ></path><path d="M192 704v320h64v-256h704v256h64v-320H192zM1022.72 0H960v256H256V0H192v320h832V0h-1.28z" fill="#666666" ></path></symbol><symbol id="edui-for-source" viewBox="0 0 1024 1024"><path d="M170.88 512H56.96V384H0v320h56.96V576h113.92v128h56.96V384h-56.96v128zM284.16 448h56.96v256h56.96V448h56.96V384H284.16v64zM738.56 385.28l-84.48 250.24L569.6 384l-2.56 1.28H512v316.8h56.96V561.92l47.36 140.8h72.96l2.56 1.28 48-140.8v139.52h56.32V385.92h-55.04l-2.56-0.64zM910.08 640V384h-56.96v320H1024v-64h-113.92z" fill="#666666" ></path></symbol><symbol id="edui-for-splittorows" viewBox="0 0 1024 1024"><path d="M0 0h1024v64H0z" fill="#666666" ></path><path d="M960 0v320h-128V0h-64v320H256V0H192v320H64V0H0v1024h1024V0z m-192 384v256H256V384zM64 384h128v256H64z m0 576v-256h128v256z m192 0v-256h512v256z m704 0h-128v-256h128z m0-320h-128V384h128z" fill="#666666" ></path></symbol><symbol id="edui-for-splittocols" viewBox="0 0 1024 1024"><path d="M1024 0H0v1024h1024z m-64 384v256h-128V384z m0-320v256h-128V64zM64 320V64h128v256z m0 320V384h128v256z m0 320v-256h128v256z m192 0V64h128v896z m192 0V64h128v896z m192 0V64h128v896z m192 0v-256h128v256z" fill="#666666" ></path></symbol><symbol id="edui-for-splittocells" viewBox="0 0 1024 1024"><path d="M0 0v1024h1024V0z m320 960H64V384h256z m320 0H384v-256h256z m0-320H384V384h256z m320 320h-256v-256h256z m0-320h-256V384h256z m0-320H384V64h576z" fill="#666666" ></path></symbol><symbol id="edui-for-arrow" viewBox="0 0 1024 1024"><path d="M513.024 665.6l204.8-204.8h-409.6l204.8 204.8z" fill="" ></path></symbol><symbol id="edui-for-aligntd" viewBox="0 0 1024 1024"><path d="M256.061265 767.939055l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M256.061265 575.985004l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M256.061265 384.030953l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M256.061265 192.076902l511.87747 0 0 63.984683-511.87747 0 0-63.984683Z" fill="#666666" ></path><path d="M863.91576 1023.877789h-703.83152A91.498098 91.498098 0 0 1 64.107214 938.77816V85.22248A91.498098 91.498098 0 0 1 160.08424 0.122851h703.83152A91.498098 91.498098 0 0 1 959.892786 85.22248v853.55568A91.498098 91.498098 0 0 1 863.91576 1023.877789zM160.08424 64.107534a30.072801 30.072801 0 0 0-31.992342 28.153261v839.47905a30.072801 30.072801 0 0 0 31.992342 28.153261h703.83152a30.072801 30.072801 0 0 0 31.992342-28.153261V92.260795a30.072801 30.072801 0 0 0-31.992342-28.153261z" fill="#666666" ></path></symbol><symbol id="edui-for-autotypeset" viewBox="0 0 1024 1024"><path d="M192 192l384 0 0 320-384 0 0-320Z" fill="#66BBBF" ></path><path d="M640 192l192 0 0 64-192 0 0-64Z" fill="#666666" ></path><path d="M640 384l192 0 0 64-192 0 0-64Z" fill="#666666" ></path><path d="M192 576l640 0 0 64-640 0 0-64Z" fill="#666666" ></path><path d="M192 768l640 0 0 64-640 0 0-64Z" fill="#666666" ></path><path d="M960 0H64a64 64 0 0 0-64 64v896a64 64 0 0 0 64 64h896a64 64 0 0 0 64-64V64a64 64 0 0 0-64-64z m0 896a64 64 0 0 1-64 64H128a64 64 0 0 1-64-64V128a64 64 0 0 1 64-64h768a64 64 0 0 1 64 64z" fill="#666666" ></path></symbol><symbol id="edui-for-charts" viewBox="0 0 1024 1024"><path d="M0 64v896h1024V64z m960 832H64V128h896z" fill="#666666" ></path><path d="M704 256h128v512h-128zM448 576h128v192H448zM192 384h128v384H192z" fill="#666666" ></path></symbol><symbol id="edui-for-closeerror" viewBox="0 0 1024 1024"><path d="M512 0a512 512 0 1 0 512 512 512 512 0 0 0-512-512z m284.16 670.08l-128 128L512 640l-158.08 156.16-128-128L384 512 227.84 353.92l128-128L512 384l158.08-158.08 128 128L640 512z" fill="#EF4848" ></path></symbol><symbol id="edui-for-copy" viewBox="0 0 1024 1024"><path d="M256.060306 384.030473l511.879388 0 0 63.984923-511.879388 0 0-63.984923Z" fill="#666666" ></path><path d="M256.060306 575.985243l511.879388 0 0 63.984924-511.879388 0 0-63.984924Z" fill="#666666" ></path><path d="M256.060306 767.940014l511.879388 0 0 63.984924-511.879388 0 0-63.984924Z" fill="#666666" ></path><path d="M256.060306 192.075702l255.939694 0 0 63.984924-255.939694 0 0-63.984924Z" fill="#666666" ></path><path d="M895.909541 256.060626h-191.95477V56.427664A63.984924 63.984924 0 0 0 639.969847 0.120932H137.688197A69.743567 69.743567 0 0 0 64.105535 64.105855v895.78893a69.743567 69.743567 0 0 0 73.582662 63.984923h748.623606A69.743567 69.743567 0 0 0 959.894465 959.894785V313.007208A63.984924 63.984924 0 0 0 895.909541 256.060626z m0 695.516119a8.31804 8.31804 0 0 1-8.31804 8.31804H137.688197a9.597739 9.597739 0 0 1-9.597738-9.597739V72.423895A8.31804 8.31804 0 0 1 136.408499 64.105855h491.404213a11.517286 11.517286 0 0 1 12.157135 10.877437v191.954771A60.145828 60.145828 0 0 0 703.954771 320.045549h180.437484a11.517286 11.517286 0 0 1 12.157136 10.877437v620.653759z" fill="#666666" ></path></symbol><symbol id="edui-for-date" viewBox="0 0 1024 1024"><path d="M896 128v64h64v704H64V192h64V128H0v832h1024V128h-128z" fill="#666666" ></path><path d="M832 64h-192v255.36L832 320V64z" fill="#EF4848" ></path><path d="M576 704h256v64H576zM576 512h256v64H576zM448 128h128v64H448zM192 704h256v64H192zM192 512h256v64H192z" fill="#666666" ></path><path d="M384 64H192v256l192-0.64V64z" fill="#EF4848" ></path></symbol><symbol id="edui-for-deletetable" viewBox="0 0 1024 1024"><path d="M576 0v448h448V0z m427.52 337.28l-90.24 90.24-113.28-113.28-113.28 113.28-90.24-90.24 113.28-113.28-113.28-113.28L686.72 20.48l113.28 113.28L913.28 20.48l90.88 90.88-113.92 112.64z" fill="#EF4848" ></path><path d="M960 640h-256V448h-64v192H384V384h192V320H64V64h512V0H0v1024h1024V448h-64zM320 960H64v-256h256z m0-320H64V384h256z m320 320H384v-256h256z m320 0h-256v-256h256z" fill="#666666" ></path></symbol><symbol id="edui-for-directionalityltr" viewBox="0 0 1024 1024"><path d="M64 832l384-320-384-320v640zM960 192V128H512v64h192v640H512v64h448v-64h-192V192h192z" fill="#666666" ></path></symbol><symbol id="edui-for-arrowright" viewBox="0 0 1024 1024"><path d="M615.424 512l-204.8-204.8v409.6l204.8-204.8z" fill="" ></path></symbol><symbol id="edui-for-tableleft" viewBox="0 0 1024 1024"><path d="M960 64v896H64V64h896m64-64H0v1024h1024V0z" fill="" ></path><path d="M192 192h640v64H192zM192 384h640v64H192zM192 576h256v64H192z" fill="" ></path></symbol><symbol id="edui-for-tableright" viewBox="0 0 1024 1024"><path d="M960 64v896H64V64h896m64-64H0v1024h1024V0z" fill="" ></path><path d="M188.8 191.36h640v64h-640zM188.8 383.36h640v64h-640zM576 575.36h256v64H576z" fill="" ></path></symbol><symbol id="edui-for-tablecenter" viewBox="0 0 1024 1024"><path d="M960 64v896H64V64h896m64-64H0v1024h1024V0z" fill="" ></path><path d="M188.8 192.64h640v64h-640zM188.8 384.64h640v64h-640zM383.36 576.64h256v64h-256z" fill="" ></path></symbol><symbol id="edui-for-videoleft" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 704l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 608l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 512l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 416l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 320l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M256 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M640 320H128a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L544 448l-162.24 208.64L304 563.2 186.56 704H160a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-videocenter" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 704l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 608l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 512l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 416l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 320l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 608l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 704l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 512l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 416l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M832 320l96 0 0 32-96 0 0-32Z" fill="#3FBEE0" ></path><path d="M384 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M768 320H256a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L672 448l-162.24 208.64-77.76-93.44L314.56 704H288a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-videonone" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 704l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M704 608l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M256 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M640 320H128a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L544 448l-162.24 208.64L304 563.2 186.56 704H160a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-videoright" viewBox="0 0 1024 1024"><path d="M96 96l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 192l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 800l832 0 0 32-832 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 896l399.36 0 0 32-399.36 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 704l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 608l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 512l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 416l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M96 320l224 0 0 32-224 0 0-32Z" fill="#3FBEE0" ></path><path d="M512 480m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" fill="#3FBEE0" ></path><path d="M896 320H384a32 32 0 0 0-32 32v352a32 32 0 0 0 32 32h512a32 32 0 0 0 32-32V352a32 32 0 0 0-32-32z m0 251.52L800 448l-162.24 208.64-77.76-93.44-117.44 140.8H416a32 32 0 0 1-32-32v-288a32 32 0 0 1 32-32h448a32 32 0 0 1 32 32z" fill="#3FBEE0" ></path><path d="M992 32v960H32V32h960m0-32H32a32 32 0 0 0-32 32v960a32 32 0 0 0 32 32h960a32 32 0 0 0 32-32V32a32 32 0 0 0-32-32z" fill="#3FBEE0" ></path></symbol><symbol id="edui-for-template" viewBox="0 0 1024 1024"><path d="M0 64v896h1024V64z m960 832H64V128h896z" fill="#666666" ></path><path d="M192 256h320v192H192zM640 256h192v512h-192zM192 576h320v192H192z" fill="#666666" ></path></symbol><symbol id="edui-for-addfile" viewBox="0 0 1024 1024"><path d="M1024 480H544V0h-64v480H0v64h480v480h64V544h480v-64z" fill="#E5E5E5" ></path></symbol><symbol id="edui-for-selected" viewBox="0 0 1024 1024"><path d="M914.24 617.28a32 32 0 0 0-45.12 0l-221.44 221.12-112.96-112.96a32 32 0 1 0-45.12 45.12l135.68 135.68a32 32 0 0 0 45.44 0l243.52-243.52a32 32 0 0 0 0-45.44z" fill="#FFFFFF" ></path><path d="M0 1024h1024V0z m914.24-361.28L672 906.24a32 32 0 0 1-45.44 0l-135.68-135.68a32 32 0 1 1 45.12-45.12l112.96 112.96 221.12-221.12a32 32 0 1 1 45.12 45.12z" fill="#1094FA" ></path></symbol><symbol id="edui-for-pickarea" viewBox="0 0 1024 1024"><path d="M977.454545 93.090909h-46.545454v791.272727a46.545455 46.545455 0 0 1-46.545455 46.545455H93.090909v46.545454a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V139.636364a46.545455 46.545455 0 0 0-46.545455-46.545455z" fill="#E5E5E5" ></path><path d="M46.545455 46.545455l837.818181 0 0 837.818181-837.818181 0 0-837.818181Z" fill="#FFFFFF" ></path><path d="M884.363636 0H46.545455a46.545455 46.545455 0 0 0-46.545455 46.545455v837.818181a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V46.545455a46.545455 46.545455 0 0 0-46.545455-46.545455z m0 837.818182a46.545455 46.545455 0 0 1-46.545454 46.545454H93.090909a46.545455 46.545455 0 0 1-46.545454-46.545454V93.090909a46.545455 46.545455 0 0 1 46.545454-46.545454h744.727273a46.545455 46.545455 0 0 1 46.545454 46.545454z" fill="#CCCCCC" ></path></symbol><symbol id="edui-for-overlay" viewBox="0 0 1024 1024"><path d="M977.454545 93.090909h-46.545454v791.272727a46.545455 46.545455 0 0 1-46.545455 46.545455H93.090909v46.545454a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V139.636364a46.545455 46.545455 0 0 0-46.545455-46.545455z" fill="#E3F6FF" ></path><path d="M46.545455 46.545455l837.818181 0 0 837.818181-837.818181 0 0-837.818181Z" fill="#E3F6FF" ></path><path d="M884.363636 0H46.545455a46.545455 46.545455 0 0 0-46.545455 46.545455v837.818181a46.545455 46.545455 0 0 0 46.545455 46.545455h837.818181a46.545455 46.545455 0 0 0 46.545455-46.545455V46.545455a46.545455 46.545455 0 0 0-46.545455-46.545455z m0 837.818182a46.545455 46.545455 0 0 1-46.545454 46.545454H93.090909a46.545455 46.545455 0 0 1-46.545454-46.545454V93.090909a46.545455 46.545455 0 0 1 46.545454-46.545454h744.727273a46.545455 46.545455 0 0 1 46.545454 46.545454z" fill="#45A7EF" ></path></symbol><symbol id="edui-for-preitem" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M175.542857 131.657143h497.371429v58.514286H175.542857zM175.542857 512h438.857143v29.257143H175.542857zM175.542857 394.971429h906.971429v29.257142H175.542857zM175.542857 277.942857h234.057143v29.257143H175.542857zM175.542857 629.028571h1111.771429v29.257143H175.542857zM175.542857 746.057143h292.571429v29.257143H175.542857zM175.542857 863.085714h760.685714v29.257143H175.542857z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem1" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M117.028571 175.542857h351.085715v29.257143H117.028571z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem2" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M175.542857 117.028571h497.371429v58.514286H175.542857zM848.457143 555.885714h438.857143v29.257143H848.457143zM848.457143 438.857143h438.857143v29.257143H848.457143zM848.457143 321.828571h438.857143v29.257143H848.457143zM175.542857 672.914286h1111.771429v29.257143H175.542857zM175.542857 789.942857h702.171429v29.257143H175.542857zM175.542857 906.971429h702.171429v29.257142H175.542857zM731.428571 351.085714v204.8H204.8V351.085714h526.628571m29.257143-29.257143H175.542857v263.314286h585.142857V321.828571zM1258.057143 789.942857v117.028572H994.742857v-117.028572h263.314286m29.257143-29.257143H965.485714v175.542857h321.828572V760.685714z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem3" viewBox="0 0 1462 1024"><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M482.742857 175.542857h497.371429v58.514286H482.742857zM643.657143 292.571429h175.542857v29.257142H643.657143zM175.542857 468.114286h1111.771429v29.257143H175.542857zM175.542857 585.142857h1111.771429v29.257143H175.542857zM175.542857 702.171429h1111.771429v29.257142H175.542857zM175.542857 819.2h1111.771429v29.257143H175.542857z" fill="#666666" ></path></symbol><symbol id="edui-for-preitem4" viewBox="0 0 1462 1024"><path d="M1258.057143 263.314286v204.8H204.8V263.314286h1053.257143m29.257143-29.257143H175.542857v263.314286h1111.771429V234.057143z" fill="#666666" ></path><path d="M0 0v1024h1462.857143V0z m1433.6 994.742857H29.257143V29.257143h1404.342857z" fill="#CCCCCC" ></path><path d="M175.542857 117.028571h497.371429v58.514286H175.542857zM175.542857 555.885714h351.085714v29.257143H175.542857zM175.542857 672.914286h1111.771429v29.257143H175.542857zM175.542857 789.942857h702.171429v29.257143H175.542857zM175.542857 906.971429h1111.771429v29.257142H175.542857z" fill="#666666" ></path></symbol></svg>';
        var script = function () {
            var scripts = document.getElementsByTagName("script");
            return scripts[scripts.length - 1]
        }();
        var shouldInjectCss = script.getAttribute("data-injectcss");
        var ready = function (fn) {
            if (document.addEventListener) {
                if (~["complete", "loaded", "interactive"].indexOf(document.readyState)) {
                    setTimeout(fn, 0)
                } else {
                    var loadFn = function () {
                        document.removeEventListener("DOMContentLoaded", loadFn, false);
                        fn()
                    };
                    document.addEventListener("DOMContentLoaded", loadFn, false)
                }
            } else if (document.attachEvent) {
                IEContentLoaded(window, fn)
            }

            function IEContentLoaded(w, fn) {
                var d = w.document, done = false, init = function () {
                    if (!done) {
                        done = true;
                        fn()
                    }
                };
                var polling = function () {
                    try {
                        d.documentElement.doScroll("left")
                    } catch (e) {
                        setTimeout(polling, 50);
                        return
                    }
                    init()
                };
                polling();
                d.onreadystatechange = function () {
                    if (d.readyState == "complete") {
                        d.onreadystatechange = null;
                        init()
                    }
                }
            }
        };
        var before = function (el, target) {
            target.parentNode.insertBefore(el, target)
        };
        var prepend = function (el, target) {
            if (target.firstChild) {
                before(el, target.firstChild)
            } else {
                target.appendChild(el)
            }
        };

        function appendSvg() {
            var div, svg;
            div = document.createElement("div");
            div.innerHTML = svgSprite;
            svgSprite = null;
            svg = div.getElementsByTagName("svg")[0];
            if (svg) {
                svg.setAttribute("aria-hidden", "true");
                svg.style.position = "absolute";
                svg.style.width = 0;
                svg.style.height = 0;
                svg.style.overflow = "hidden";
                prepend(svg, document.body)
            }
        }

        if (shouldInjectCss && !window.__iconfont__svg__cssinject__) {
            window.__iconfont__svg__cssinject__ = true;
            try {
                document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")
            } catch (e) {
                console && console.log(e)
            }
        }
        ready(appendSvg)
    })(window)

// adapter/editorui.js
//ui跟编辑器的适配層
//那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
//自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据neditor.config中的toolbars找到相应的进行实例化
    ;(function () {
        var utils = baidu.editor.utils;
        var editorui = baidu.editor.ui;
        var _Dialog = editorui.Dialog;
        editorui.buttons = {};

        editorui.Dialog = function (options) {
            var dialog = new _Dialog(options);
            dialog.addListener("hide", function () {
                if (dialog.editor) {
                    var editor = dialog.editor;
                    try {
                        if (browser.gecko) {
                            var y = editor.window.scrollY,
                                x = editor.window.scrollX;
                            editor.body.focus();
                            editor.window.scrollTo(x, y);
                        } else {
                            editor.focus();
                        }
                    } catch (ex) {
                    }
                }
            });
            return dialog;
        };

        var iframeUrlMap = {
            anchor: "~/dialogs/anchor/anchor.html",
            insertimage: "~/dialogs/image/image.html",
            link: "~/dialogs/link/link.html",
            spechars: "~/dialogs/spechars/spechars.html",
            searchreplace: "~/dialogs/searchreplace/searchreplace.html",
            map: "~/dialogs/map/map.html",
            gmap: "~/dialogs/gmap/gmap.html",
            insertvideo: "~/dialogs/video/video.html",
            help: "~/dialogs/help/help.html",
            preview: "~/dialogs/preview/preview.html",
            emotion: "~/dialogs/emotion/emotion.html",
            wordimage: "~/dialogs/wordimage/wordimage.html",
            attachment: "~/dialogs/attachment/attachment.html",
            insertframe: "~/dialogs/insertframe/insertframe.html",
            edittip: "~/dialogs/table/edittip.html",
            edittable: "~/dialogs/table/edittable.html",
            edittd: "~/dialogs/table/edittd.html",
            webapp: "~/dialogs/webapp/webapp.html",
            snapscreen: "~/dialogs/snapscreen/snapscreen.html",
            scrawl: "~/dialogs/scrawl/scrawl.html",
            music: "~/dialogs/music/music.html",
            template: "~/dialogs/template/template.html",
            background: "~/dialogs/background/background.html",
            charts: "~/dialogs/charts/charts.html"
        };
        //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
        var btnCmds = [
            "undo",
            "redo",
            "formatmatch",
            "bold",
            "italic",
            "underline",
            "fontborder",
            "touppercase",
            "tolowercase",
            "strikethrough",
            "subscript",
            "superscript",
            "source",
            "indent",
            "outdent",
            "blockquote",
            "pasteplain",
            "pagebreak",
            "selectall",
            "print",
            "horizontal",
            "removeformat",
            "time",
            "date",
            "unlink",
            "insertparagraphbeforetable",
            "insertrow",
            "insertcol",
            "mergeright",
            "mergedown",
            "deleterow",
            "deletecol",
            "splittorows",
            "splittocols",
            "splittocells",
            "mergecells",
            "deletetable",
            "drafts"
        ];

        for (var i = 0, ci; (ci = btnCmds[i++]);) {
            ci = ci.toLowerCase();
            editorui[ci] = (function (cmd) {
                return function (editor) {
                    var ui = new editorui.Button({
                        className: "edui-for-" + cmd,
                        title:
                        editor.options.labelMap[cmd] ||
                        editor.getLang("labelMap." + cmd) ||
                        "",
                        onclick: function () {
                            editor.execCommand(cmd);
                        },
                        theme: editor.options.theme,
                        showText: false
                    });
                    editorui.buttons[cmd] = ui;
                    editor.addListener("selectionchange", function (
                        type,
                        causeByUi,
                        uiReady
                    ) {
                        var state = editor.queryCommandState(cmd);
                        if (state == -1) {
                            ui.setDisabled(true);
                            ui.setChecked(false);
                        } else {
                            if (!uiReady) {
                                ui.setDisabled(false);
                                ui.setChecked(state);
                            }
                        }
                    });
                    return ui;
                };
            })(ci);
        }

        //清除文档
        editorui.cleardoc = function (editor) {
            var ui = new editorui.Button({
                className: "edui-for-cleardoc",
                title:
                editor.options.labelMap.cleardoc ||
                editor.getLang("labelMap.cleardoc") ||
                "",
                theme: editor.options.theme,
                onclick: function () {
                    if (confirm(editor.getLang("confirmClear"))) {
                        editor.execCommand("cleardoc");
                    }
                }
            });
            editorui.buttons["cleardoc"] = ui;
            editor.addListener("selectionchange", function () {
                ui.setDisabled(editor.queryCommandState("cleardoc") == -1);
            });
            return ui;
        };

        //排版,图片排版,文字方向
        var typeset = {
            justify: ["left", "right", "center", "justify"],
            imagefloat: ["none", "left", "center", "right"],
            directionality: ["ltr", "rtl"]
        };

        for (var p in typeset) {
            (function (cmd, val) {
                for (var i = 0, ci; (ci = val[i++]);) {
                    (function (cmd2) {
                        editorui[cmd.replace("float", "") + cmd2] = function (editor) {
                            var ui = new editorui.Button({
                                className: "edui-for-" + cmd.replace("float", "") + cmd2,
                                title:
                                editor.options.labelMap[cmd.replace("float", "") + cmd2] ||
                                editor.getLang(
                                    "labelMap." + cmd.replace("float", "") + cmd2
                                ) ||
                                "",
                                theme: editor.options.theme,
                                onclick: function () {
                                    editor.execCommand(cmd, cmd2);
                                }
                            });
                            editorui.buttons[cmd] = ui;
                            editor.addListener("selectionchange", function (
                                type,
                                causeByUi,
                                uiReady
                            ) {
                                ui.setDisabled(editor.queryCommandState(cmd) == -1);
                                ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !uiReady);
                            });
                            return ui;
                        };
                    })(ci);
                }
            })(p, typeset[p]);
        }

        //字体颜色和背景颜色
        for (var i = 0, ci; (ci = ["backcolor", "forecolor"][i++]);) {
            editorui[ci] = (function (cmd) {
                return function (editor) {
                    var ui = new editorui.ColorButton({
                        className: "edui-for-" + cmd,
                        color: "default",
                        title:
                        editor.options.labelMap[cmd] ||
                        editor.getLang("labelMap." + cmd) ||
                        "",
                        editor: editor,
                        onpickcolor: function (t, color) {
                            editor.execCommand(cmd, color);
                        },
                        onpicknocolor: function () {
                            editor.execCommand(cmd, "default");
                            this.setColor("transparent");
                            this.color = "default";
                        },
                        onbuttonclick: function () {
                            editor.execCommand(cmd, this.color);
                        }
                    });
                    editorui.buttons[cmd] = ui;
                    editor.addListener("selectionchange", function () {
                        ui.setDisabled(editor.queryCommandState(cmd) == -1);
                    });
                    return ui;
                };
            })(ci);
        }

        var dialogBtns = {
            noOk: ["searchreplace", "help", "spechars", "webapp", "preview"],
            ok: [
                "attachment",
                "anchor",
                "link",
                "insertimage",
                "map",
                "gmap",
                "insertframe",
                "wordimage",
                "insertvideo",
                "insertframe",
                "edittip",
                "edittable",
                "edittd",
                "scrawl",
                "template",
                "music",
                "background",
                "charts"
            ]
        };

        for (var p in dialogBtns) {
            (function (type, vals) {
                for (var i = 0, ci; (ci = vals[i++]);) {
                    //todo opera下存在问题
                    if (browser.opera && ci === "searchreplace") {
                        continue;
                    }
                    (function (cmd) {
                        editorui[cmd] = function (editor, iframeUrl, title) {
                            iframeUrl =
                                iframeUrl ||
                                (editor.options.iframeUrlMap || {})[cmd] ||
                                iframeUrlMap[cmd];
                            title =
                                editor.options.labelMap[cmd] ||
                                editor.getLang("labelMap." + cmd) ||
                                "";

                            var dialog;
                            //没有iframeUrl不创建dialog
                            if (iframeUrl) {
                                dialog = new editorui.Dialog(
                                    utils.extend(
                                        {
                                            iframeUrl: editor.ui.mapUrl(iframeUrl),
                                            editor: editor,
                                            className: "edui-for-" + cmd,
                                            title: title,
                                            holdScroll: cmd === "insertimage",
                                            fullscreen: /charts|preview/.test(cmd),
                                            closeDialog: editor.getLang("closeDialog")
                                        },
                                        type == "ok"
                                            ? {
                                                buttons: [
                                                    {
                                                        className: "edui-okbutton",
                                                        label: editor.getLang("ok"),
                                                        editor: editor,
                                                        onclick: function () {
                                                            dialog.close(true);
                                                        }
                                                    },
                                                    {
                                                        className: "edui-cancelbutton",
                                                        label: editor.getLang("cancel"),
                                                        editor: editor,
                                                        onclick: function () {
                                                            dialog.close(false);
                                                        }
                                                    }
                                                ]
                                            }
                                            : {}
                                    )
                                );

                                editor.ui._dialogs[cmd + "Dialog"] = dialog;
                            }

                            var ui = new editorui.Button({
                                className: "edui-for-" + cmd,
                                title: title,
                                onclick: function () {
                                    if (dialog) {
                                        switch (cmd) {
                                            case "wordimage":
                                                var images = editor.execCommand("wordimage");
                                                if (images && images.length) {
                                                    dialog.render();
                                                    dialog.open();
                                                }
                                                break;
                                            case "scrawl":
                                                if (editor.queryCommandState("scrawl") != -1) {
                                                    dialog.render();
                                                    dialog.open();
                                                }

                                                break;
                                            default:
                                                dialog.render();
                                                dialog.open();
                                        }
                                    }
                                },
                                theme: editor.options.theme,
                                disabled:
                                (cmd == "scrawl" && editor.queryCommandState("scrawl") == -1) ||
                                cmd == "charts"
                            });
                            editorui.buttons[cmd] = ui;
                            editor.addListener("selectionchange", function () {
                                //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
                                var unNeedCheckState = {edittable: 1};
                                if (cmd in unNeedCheckState) return;

                                var state = editor.queryCommandState(cmd);
                                if (ui.getDom()) {
                                    ui.setDisabled(state == -1);
                                    ui.setChecked(state);
                                }
                            });

                            return ui;
                        };
                    })(ci.toLowerCase());
                }
            })(p, dialogBtns[p]);
        }

        editorui.snapscreen = function (editor, iframeUrl, title) {
            title =
                editor.options.labelMap["snapscreen"] ||
                editor.getLang("labelMap.snapscreen") ||
                "";
            var ui = new editorui.Button({
                className: "edui-for-snapscreen",
                title: title,
                onclick: function () {
                    editor.execCommand("snapscreen");
                },
                theme: editor.options.theme
            });
            editorui.buttons["snapscreen"] = ui;
            iframeUrl =
                iframeUrl ||
                (editor.options.iframeUrlMap || {})["snapscreen"] ||
                iframeUrlMap["snapscreen"];
            if (iframeUrl) {
                var dialog = new editorui.Dialog({
                    iframeUrl: editor.ui.mapUrl(iframeUrl),
                    editor: editor,
                    className: "edui-for-snapscreen",
                    title: title,
                    buttons: [
                        {
                            className: "edui-okbutton",
                            label: editor.getLang("ok"),
                            editor: editor,
                            onclick: function () {
                                dialog.close(true);
                            }
                        },
                        {
                            className: "edui-cancelbutton",
                            label: editor.getLang("cancel"),
                            editor: editor,
                            onclick: function () {
                                dialog.close(false);
                            }
                        }
                    ]
                });
                dialog.render();
                editor.ui._dialogs["snapscreenDialog"] = dialog;
            }
            editor.addListener("selectionchange", function () {
                ui.setDisabled(editor.queryCommandState("snapscreen") == -1);
            });
            return ui;
        };

        editorui.insertcode = function (editor, list, title) {
            list = editor.options["insertcode"] || [];
            title =
                editor.options.labelMap["insertcode"] ||
                editor.getLang("labelMap.insertcode") ||
                "";
            // if (!list.length) return;
            var items = [];
            utils.each(list, function (key, val) {
                items.push({
                    label: key,
                    value: val,
                    theme: editor.options.theme,
                    renderLabelHtml: function () {
                        return (
                            '<div class="edui-label %%-label" >' + (this.label || "") + "</div>"
                        );
                    }
                });
            });

            var ui = new editorui.Combox({
                editor: editor,
                items: items,
                onselect: function (t, index) {
                    editor.execCommand("insertcode", this.items[index].value);
                },
                onbuttonclick: function () {
                    this.showPopup();
                },
                title: title,
                initValue: title,
                className: "edui-for-insertcode",
                indexByValue: function (value) {
                    if (value) {
                        for (var i = 0, ci; (ci = this.items[i]); i++) {
                            if (ci.value.indexOf(value) != -1) return i;
                        }
                    }

                    return -1;
                }
            });
            editorui.buttons["insertcode"] = ui;
            editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
                if (!uiReady) {
                    var state = editor.queryCommandState("insertcode");
                    if (state == -1) {
                        ui.setDisabled(true);
                    } else {
                        ui.setDisabled(false);
                        var value = editor.queryCommandValue("insertcode");
                        if (!value) {
                            ui.setValue(title);
                            return;
                        }
                        //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
                        value && (value = value.replace(/['"]/g, "").split(",")[0]);
                        ui.setValue(value);
                    }
                }
            });
            return ui;
        };
        editorui.fontfamily = function (editor, list, title) {
            list = editor.options["fontfamily"] || [];
            title =
                editor.options.labelMap["fontfamily"] ||
                editor.getLang("labelMap.fontfamily") ||
                "";
            if (!list.length) return;
            for (var i = 0, ci, items = []; (ci = list[i]); i++) {
                var langLabel = editor.getLang("fontfamily")[ci.name] || "";
                (function (key, val) {
                    items.push({
                        label: key,
                        value: val,
                        theme: editor.options.theme,
                        renderLabelHtml: function () {
                            return (
                                '<div class="edui-label %%-label" style="font-family:' +
                                utils.unhtml(this.value) +
                                '">' +
                                (this.label || "") +
                                "</div>"
                            );
                        }
                    });
                })(ci.label || langLabel, ci.val);
            }
            var ui = new editorui.Combox({
                editor: editor,
                items: items,
                onselect: function (t, index) {
                    editor.execCommand("FontFamily", this.items[index].value);
                },
                onbuttonclick: function () {
                    this.showPopup();
                },
                title: title,
                initValue: title,
                className: "edui-for-fontfamily",
                indexByValue: function (value) {
                    if (value) {
                        for (var i = 0, ci; (ci = this.items[i]); i++) {
                            if (ci.value.indexOf(value) != -1) return i;
                        }
                    }

                    return -1;
                }
            });
            editorui.buttons["fontfamily"] = ui;
            editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
                if (!uiReady) {
                    var state = editor.queryCommandState("FontFamily");
                    if (state == -1) {
                        ui.setDisabled(true);
                    } else {
                        ui.setDisabled(false);
                        var value = editor.queryCommandValue("FontFamily");
                        //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
                        value && (value = value.replace(/['"]/g, "").split(",")[0]);
                        ui.setValue(value);
                    }
                }
            });
            return ui;
        };

        editorui.fontsize = function (editor, list, title) {
            title =
                editor.options.labelMap["fontsize"] ||
                editor.getLang("labelMap.fontsize") ||
                "";
            list = list || editor.options["fontsize"] || [];
            if (!list.length) return;
            var items = [];
            for (var i = 0; i < list.length; i++) {
                var size = list[i] + "px";
                items.push({
                    label: size,
                    value: size,
                    theme: editor.options.theme,
                    renderLabelHtml: function () {
                        return (
                            '<div class="edui-label %%-label" style="line-height:1;font-size:' +
                            this.value +
                            '">' +
                            (this.label || "") +
                            "</div>"
                        );
                    }
                });
            }
            var ui = new editorui.Combox({
                editor: editor,
                items: items,
                title: title,
                initValue: title,
                onselect: function (t, index) {
                    editor.execCommand("FontSize", this.items[index].value);
                },
                onbuttonclick: function () {
                    this.showPopup();
                },
                className: "edui-for-fontsize"
            });
            editorui.buttons["fontsize"] = ui;
            editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
                if (!uiReady) {
                    var state = editor.queryCommandState("FontSize");
                    if (state == -1) {
                        ui.setDisabled(true);
                    } else {
                        ui.setDisabled(false);
                        ui.setValue(editor.queryCommandValue("FontSize"));
                    }
                }
            });
            return ui;
        };

        editorui.paragraph = function (editor, list, title) {
            title =
                editor.options.labelMap["paragraph"] ||
                editor.getLang("labelMap.paragraph") ||
                "";
            list = editor.options["paragraph"] || [];
            if (utils.isEmptyObject(list)) return;
            var items = [];
            for (var i in list) {
                items.push({
                    value: i,
                    label: list[i] || editor.getLang("paragraph")[i],
                    theme: editor.options.theme,
                    renderLabelHtml: function () {
                        return (
                            '<div class="edui-label %%-label"><span class="edui-for-' +
                            this.value +
                            '">' +
                            (this.label || "") +
                            "</span></div>"
                        );
                    }
                });
            }
            var ui = new editorui.Combox({
                editor: editor,
                items: items,
                title: title,
                initValue: title,
                className: "edui-for-paragraph",
                onselect: function (t, index) {
                    editor.execCommand("Paragraph", this.items[index].value);
                },
                onbuttonclick: function () {
                    this.showPopup();
                }
            });
            editorui.buttons["paragraph"] = ui;
            editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
                if (!uiReady) {
                    var state = editor.queryCommandState("Paragraph");
                    if (state == -1) {
                        ui.setDisabled(true);
                    } else {
                        ui.setDisabled(false);
                        var value = editor.queryCommandValue("Paragraph");
                        var index = ui.indexByValue(value);
                        if (index != -1) {
                            ui.setValue(value);
                        } else {
                            ui.setValue(ui.initValue);
                        }
                    }
                }
            });
            return ui;
        };

        //自定义标题
        editorui.customstyle = function (editor) {
            var list = editor.options["customstyle"] || [],
                title =
                    editor.options.labelMap["customstyle"] ||
                    editor.getLang("labelMap.customstyle") ||
                    "";
            if (!list.length) return;
            var langCs = editor.getLang("customstyle");
            for (var i = 0, items = [], t; (t = list[i++]);) {
                (function (t) {
                    var ck = {};
                    ck.label = t.label ? t.label : langCs[t.name];
                    ck.style = t.style;
                    ck.className = t.className;
                    ck.tag = t.tag;
                    items.push({
                        label: ck.label,
                        value: ck,
                        theme: editor.options.theme,
                        renderLabelHtml: function () {
                            return (
                                '<div class="edui-label %%-label">' +
                                "<" +
                                ck.tag +
                                " " +
                                (ck.className ? ' class="' + ck.className + '"' : "") +
                                (ck.style ? ' style="' + ck.style + '"' : "") +
                                ">" +
                                ck.label +
                                "</" +
                                ck.tag +
                                ">" +
                                "</div>"
                            );
                        }
                    });
                })(t);
            }

            var ui = new editorui.Combox({
                editor: editor,
                items: items,
                title: title,
                initValue: title,
                className: "edui-for-customstyle",
                onselect: function (t, index) {
                    editor.execCommand("customstyle", this.items[index].value);
                },
                onbuttonclick: function () {
                    this.showPopup();
                },
                indexByValue: function (value) {
                    for (var i = 0, ti; (ti = this.items[i++]);) {
                        if (ti.label == value) {
                            return i - 1;
                        }
                    }
                    return -1;
                }
            });
            editorui.buttons["customstyle"] = ui;
            editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
                if (!uiReady) {
                    var state = editor.queryCommandState("customstyle");
                    if (state == -1) {
                        ui.setDisabled(true);
                    } else {
                        ui.setDisabled(false);
                        var value = editor.queryCommandValue("customstyle");
                        var index = ui.indexByValue(value);
                        if (index != -1) {
                            ui.setValue(value);
                        } else {
                            ui.setValue(ui.initValue);
                        }
                    }
                }
            });
            return ui;
        };
        editorui.inserttable = function (editor, iframeUrl, title) {
            title =
                editor.options.labelMap["inserttable"] ||
                editor.getLang("labelMap.inserttable") ||
                "";
            var ui = new editorui.TableButton({
                editor: editor,
                title: title,
                className: "edui-for-inserttable",
                onpicktable: function (t, numCols, numRows) {
                    editor.execCommand("InsertTable", {
                        numRows: numRows,
                        numCols: numCols,
                        border: 1
                    });
                },
                onbuttonclick: function () {
                    this.showPopup();
                }
            });
            editorui.buttons["inserttable"] = ui;
            editor.addListener("selectionchange", function () {
                ui.setDisabled(editor.queryCommandState("inserttable") == -1);
            });
            return ui;
        };

        editorui.lineheight = function (editor) {
            var val = editor.options.lineheight || [];
            if (!val.length) return;
            for (var i = 0, ci, items = []; (ci = val[i++]);) {
                items.push({
                    //todo:写死了
                    label: ci,
                    value: ci,
                    theme: editor.options.theme,
                    onclick: function () {
                        editor.execCommand("lineheight", this.value);
                    }
                });
            }
            var ui = new editorui.MenuButton({
                editor: editor,
                className: "edui-for-lineheight",
                title:
                editor.options.labelMap["lineheight"] ||
                editor.getLang("labelMap.lineheight") ||
                "",
                items: items,
                onbuttonclick: function () {
                    var value = editor.queryCommandValue("LineHeight") || this.value;
                    editor.execCommand("LineHeight", value);
                }
            });
            editorui.buttons["lineheight"] = ui;
            editor.addListener("selectionchange", function () {
                var state = editor.queryCommandState("LineHeight");
                if (state == -1) {
                    ui.setDisabled(true);
                } else {
                    ui.setDisabled(false);
                    var value = editor.queryCommandValue("LineHeight");
                    value && ui.setValue((value + "").replace(/cm/, ""));
                    ui.setChecked(state);
                }
            });
            return ui;
        };

        var rowspacings = ["top", "bottom"];
        for (var r = 0, ri; (ri = rowspacings[r++]);) {
            (function (cmd) {
                editorui["rowspacing" + cmd] = function (editor) {
                    var val = editor.options["rowspacing" + cmd] || [];
                    if (!val.length) return null;
                    for (var i = 0, ci, items = []; (ci = val[i++]);) {
                        items.push({
                            label: ci,
                            value: ci,
                            theme: editor.options.theme,
                            onclick: function () {
                                editor.execCommand("rowspacing", this.value, cmd);
                            }
                        });
                    }
                    var ui = new editorui.MenuButton({
                        editor: editor,
                        className: "edui-for-rowspacing" + cmd,
                        title:
                        editor.options.labelMap["rowspacing" + cmd] ||
                        editor.getLang("labelMap.rowspacing" + cmd) ||
                        "",
                        items: items,
                        onbuttonclick: function () {
                            var value =
                                editor.queryCommandValue("rowspacing", cmd) || this.value;
                            editor.execCommand("rowspacing", value, cmd);
                        }
                    });
                    editorui.buttons[cmd] = ui;
                    editor.addListener("selectionchange", function () {
                        var state = editor.queryCommandState("rowspacing", cmd);
                        if (state == -1) {
                            ui.setDisabled(true);
                        } else {
                            ui.setDisabled(false);
                            var value = editor.queryCommandValue("rowspacing", cmd);
                            value && ui.setValue((value + "").replace(/%/, ""));
                            ui.setChecked(state);
                        }
                    });
                    return ui;
                };
            })(ri);
        }
        //有序,无序列表
        var lists = ["insertorderedlist", "insertunorderedlist"];
        for (var l = 0, cl; (cl = lists[l++]);) {
            (function (cmd) {
                editorui[cmd] = function (editor) {
                    var vals = editor.options[cmd],
                        _onMenuClick = function () {
                            editor.execCommand(cmd, this.value);
                        },
                        items = [];
                    for (var i in vals) {
                        items.push({
                            label: vals[i] || editor.getLang()[cmd][i] || "",
                            value: i,
                            theme: editor.options.theme,
                            onclick: _onMenuClick
                        });
                    }
                    var ui = new editorui.MenuButton({
                        editor: editor,
                        className: "edui-for-" + cmd,
                        title: editor.getLang("labelMap." + cmd) || "",
                        items: items,
                        onbuttonclick: function () {
                            var value = editor.queryCommandValue(cmd) || this.value;
                            editor.execCommand(cmd, value);
                        }
                    });
                    editorui.buttons[cmd] = ui;
                    editor.addListener("selectionchange", function () {
                        var state = editor.queryCommandState(cmd);
                        if (state == -1) {
                            ui.setDisabled(true);
                        } else {
                            ui.setDisabled(false);
                            var value = editor.queryCommandValue(cmd);
                            ui.setValue(value);
                            ui.setChecked(state);
                        }
                    });
                    return ui;
                };
            })(cl);
        }

        editorui.fullscreen = function (editor, title) {
            title =
                editor.options.labelMap["fullscreen"] ||
                editor.getLang("labelMap.fullscreen") ||
                "";
            var ui = new editorui.Button({
                className: "edui-for-fullscreen",
                title: title,
                theme: editor.options.theme,
                onclick: function () {
                    if (editor.ui) {
                        editor.ui.setFullScreen(!editor.ui.isFullScreen());
                    }
                    this.setChecked(editor.ui.isFullScreen());
                }
            });
            editorui.buttons["fullscreen"] = ui;
            editor.addListener("selectionchange", function () {
                var state = editor.queryCommandState("fullscreen");
                ui.setDisabled(state == -1);
                ui.setChecked(editor.ui.isFullScreen());
            });
            return ui;
        };

        // 表情
        editorui["emotion"] = function (editor, iframeUrl) {
            var cmd = "emotion";
            var ui = new editorui.MultiMenuPop({
                title:
                editor.options.labelMap[cmd] ||
                editor.getLang("labelMap." + cmd + "") ||
                "",
                editor: editor,
                className: "edui-for-" + cmd,
                iframeUrl: editor.ui.mapUrl(
                    iframeUrl ||
                    (editor.options.iframeUrlMap || {})[cmd] ||
                    iframeUrlMap[cmd]
                )
            });
            editorui.buttons[cmd] = ui;

            editor.addListener("selectionchange", function () {
                ui.setDisabled(editor.queryCommandState(cmd) == -1);
            });
            return ui;
        };

        editorui.autotypeset = function (editor) {
            var ui = new editorui.AutoTypeSetButton({
                editor: editor,
                title:
                editor.options.labelMap["autotypeset"] ||
                editor.getLang("labelMap.autotypeset") ||
                "",
                className: "edui-for-autotypeset",
                onbuttonclick: function () {
                    editor.execCommand("autotypeset");
                }
            });
            editorui.buttons["autotypeset"] = ui;
            editor.addListener("selectionchange", function () {
                ui.setDisabled(editor.queryCommandState("autotypeset") == -1);
            });
            return ui;
        };

        /* 简单上传插件 */
        editorui["simpleupload"] = function (editor) {
            var name = "simpleupload",
                ui = new editorui.Button({
                    className: "edui-for-" + name,
                    title:
                    editor.options.labelMap[name] ||
                    editor.getLang("labelMap." + name) ||
                    "",
                    onclick: function () {
                    },
                    theme: editor.options.theme,
                    showText: false
                });
            editorui.buttons[name] = ui;
            editor.addListener("ready", function () {
                var b = ui.getDom("body"),
                    iconSpan = b.children[0];
                editor.fireEvent("simpleuploadbtnready", iconSpan);
            });
            editor.addListener("selectionchange", function (type, causeByUi, uiReady) {
                var state = editor.queryCommandState(name);
                if (state == -1) {
                    ui.setDisabled(true);
                    ui.setChecked(false);
                } else {
                    if (!uiReady) {
                        ui.setDisabled(false);
                        ui.setChecked(state);
                    }
                }
            });
            return ui;
        };
    })();


// adapter/editor.js
///import core
///commands 全屏
///commandsName FullScreen
///commandsTitle  全屏
    ;(function () {
        var utils = baidu.editor.utils,
            uiUtils = baidu.editor.ui.uiUtils,
            UIBase = baidu.editor.ui.UIBase,
            domUtils = baidu.editor.dom.domUtils;
        var nodeStack = [];

        function EditorUI(options) {
            this.initOptions(options);
            this.initEditorUI();
        }

        EditorUI.prototype = {
            uiName: "editor",
            initEditorUI: function () {
                this.editor.ui = this;
                this._dialogs = {};
                this.initUIBase();
                this._initToolbars();
                var editor = this.editor,
                    me = this;

                editor.addListener("ready", function () {
                    //提供getDialog方法
                    editor.getDialog = function (name) {
                        return editor.ui._dialogs[name + "Dialog"];
                    };
                    domUtils.on(editor.window, "scroll", function (evt) {
                        baidu.editor.ui.Popup.postHide(evt);
                    });
                    //提供编辑器实时宽高(全屏时宽高不变化)
                    editor.ui._actualFrameWidth = editor.options.initialFrameWidth;

                    UE.browser.ie &&
                    UE.browser.version === 6 &&
                    editor.container.ownerDocument.execCommand(
                        "BackgroundImageCache",
                        false,
                        true
                    );

                    //display bottom-bar label based on config
                    if (editor.options.elementPathEnabled) {
                        editor.ui.getDom("elementpath").innerHTML =
                            '<div class="edui-editor-breadcrumb">' +
                            editor.getLang("elementPathTip") +
                            ":</div>";
                    }
                    if (editor.options.wordCount) {
                        function countFn() {
                            setCount(editor, me);
                            domUtils.un(editor.document, "click", arguments.callee);
                        }

                        domUtils.on(editor.document, "click", countFn);
                        editor.ui.getDom("wordcount").innerHTML = editor.getLang(
                            "wordCountTip"
                        );
                    }
                    editor.ui._scale();
                    if (editor.options.scaleEnabled) {
                        if (editor.autoHeightEnabled) {
                            editor.disableAutoHeight();
                        }
                        me.enableScale();
                    } else {
                        me.disableScale();
                    }
                    if (
                        !editor.options.elementPathEnabled &&
                        !editor.options.wordCount &&
                        !editor.options.scaleEnabled
                    ) {
                        editor.ui.getDom("elementpath").style.display = "none";
                        editor.ui.getDom("wordcount").style.display = "none";
                        editor.ui.getDom("scale").style.display = "none";
                    }

                    if (!editor.selection.isFocus()) return;
                    editor.fireEvent("selectionchange", false, true);
                });

                editor.addListener("mousedown", function (t, evt) {
                    var el = evt.target || evt.srcElement;
                    baidu.editor.ui.Popup.postHide(evt, el);
                    baidu.editor.ui.ShortCutMenu.postHide(evt);
                });
                editor.addListener("delcells", function () {
                    if (UE.ui["edittip"]) {
                        new UE.ui["edittip"](editor);
                    }
                    editor.getDialog("edittip").open();
                });

                var pastePop,
                    isPaste = false,
                    timer;
                editor.addListener("afterpaste", function () {
                    if (editor.queryCommandState("pasteplain")) return;
                    if (baidu.editor.ui.PastePicker) {
                        pastePop = new baidu.editor.ui.Popup({
                            content: new baidu.editor.ui.PastePicker({editor: editor}),
                            editor: editor,
                            className: "edui-wordpastepop"
                        });
                        pastePop.render();
                    }
                    isPaste = true;
                });

                editor.addListener("afterinserthtml", function () {
                    clearTimeout(timer);
                    timer = setTimeout(function () {
                        if (pastePop && (isPaste || editor.ui._isTransfer)) {
                            if (pastePop.isHidden()) {
                                var span = domUtils.createElement(editor.document, "span", {
                                        style: "line-height:0px;",
                                        innerHTML: "\ufeff"
                                    }),
                                    range = editor.selection.getRange();
                                range.insertNode(span);
                                var tmp = getDomNode(span, "firstChild", "previousSibling");
                                tmp &&
                                pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp);
                                domUtils.remove(span);
                            } else {
                                pastePop.show();
                            }
                            delete editor.ui._isTransfer;
                            isPaste = false;
                        }
                    }, 200);
                });
                editor.addListener("contextmenu", function (t, evt) {
                    baidu.editor.ui.Popup.postHide(evt);
                });
                editor.addListener("keydown", function (t, evt) {
                    if (pastePop) pastePop.dispose(evt);
                    var keyCode = evt.keyCode || evt.which;
                    if (evt.altKey && keyCode == 90) {
                        UE.ui.buttons["fullscreen"].onclick();
                    }
                });
                editor.addListener("wordcount", function (type) {
                    setCount(this, me);
                });

                function setCount(editor, ui) {
                    editor.setOpt({
                        wordCount: true,
                        maximumWords: 10000,
                        wordCountMsg:
                        editor.options.wordCountMsg || editor.getLang("wordCountMsg"),
                        wordOverFlowMsg:
                        editor.options.wordOverFlowMsg || editor.getLang("wordOverFlowMsg")
                    });
                    var opt = editor.options,
                        max = opt.maximumWords,
                        msg = opt.wordCountMsg,
                        errMsg = opt.wordOverFlowMsg,
                        countDom = ui.getDom("wordcount");
                    if (!opt.wordCount) {
                        return;
                    }
                    var count = editor.getContentLength(true);
                    if (count > max) {
                        countDom.innerHTML = errMsg;
                        editor.fireEvent("wordcountoverflow");
                    } else {
                        countDom.innerHTML = msg
                            .replace("{#leave}", max - count)
                            .replace("{#count}", count);
                    }
                }

                editor.addListener("selectionchange", function () {
                    if (editor.options.elementPathEnabled) {
                        me[
                        (editor.queryCommandState("elementpath") == -1 ? "dis" : "en") +
                        "ableElementPath"
                            ]();
                    }
                    if (editor.options.scaleEnabled) {
                        me[
                        (editor.queryCommandState("scale") == -1 ? "dis" : "en") +
                        "ableScale"
                            ]();
                    }
                });
                var popup = new baidu.editor.ui.Popup({
                    editor: editor,
                    content: "",
                    className: "edui-bubble",
                    _onEditButtonClick: function () {
                        this.hide();
                        editor.ui._dialogs.linkDialog.open();
                    },
                    _onImgEditButtonClick: function (name) {
                        this.hide();
                        editor.ui._dialogs[name] && editor.ui._dialogs[name].open();
                    },
                    _onImgSetFloat: function (value) {
                        this.hide();
                        editor.execCommand("imagefloat", value);
                    },
                    _setIframeAlign: function (value) {
                        var frame = popup.anchorEl;
                        var newFrame = frame.cloneNode(true);
                        switch (value) {
                            case -2:
                                newFrame.setAttribute("align", "");
                                break;
                            case -1:
                                newFrame.setAttribute("align", "left");
                                break;
                            case 1:
                                newFrame.setAttribute("align", "right");
                                break;
                        }
                        frame.parentNode.insertBefore(newFrame, frame);
                        domUtils.remove(frame);
                        popup.anchorEl = newFrame;
                        popup.showAnchor(popup.anchorEl);
                    },
                    _updateIframe: function () {
                        var frame = (editor._iframe = popup.anchorEl);
                        if (domUtils.hasClass(frame, "ueditor_baidumap")) {
                            editor.selection.getRange().selectNode(frame).select();
                            editor.ui._dialogs.mapDialog.open();
                            popup.hide();
                        } else {
                            editor.ui._dialogs.insertframeDialog.open();
                            popup.hide();
                        }
                    },
                    _onRemoveButtonClick: function (cmdName) {
                        editor.execCommand(cmdName);
                        this.hide();
                    },
                    queryAutoHide: function (el) {
                        if (el && el.ownerDocument == editor.document) {
                            if (
                                el.tagName.toLowerCase() == "img" ||
                                domUtils.findParentByTagName(el, "a", true)
                            ) {
                                return el !== popup.anchorEl;
                            }
                        }
                        return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el);
                    }
                });
                popup.render();
                if (editor.options.imagePopup) {
                    editor.addListener("mouseover", function (t, evt) {
                        evt = evt || window.event;
                        var el = evt.target || evt.srcElement;
                        if (
                            editor.ui._dialogs.insertframeDialog &&
                            /iframe/gi.test(el.tagName)
                        ) {
                            var html = popup.formatHtml(
                                "<nobr>" +
                                editor.getLang("property") +
                                ': <span onclick=$$._setIframeAlign(-2) class="edui-clickable">' +
                                editor.getLang("default") +
                                '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(-1) class="edui-clickable">' +
                                editor.getLang("justifyleft") +
                                '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(1) class="edui-clickable">' +
                                editor.getLang("justifyright") +
                                "</span>&nbsp;&nbsp;" +
                                ' <span onclick="$$._updateIframe( this);" class="edui-clickable">' +
                                editor.getLang("modify") +
                                "</span></nobr>"
                            );
                            if (html) {
                                popup.getDom("content").innerHTML = html;
                                popup.anchorEl = el;
                                popup.showAnchor(popup.anchorEl);
                            } else {
                                popup.hide();
                            }
                        }
                    });
                    editor.addListener("selectionchange", function (t, causeByUi) {
                        if (!causeByUi) return;
                        var html = "",
                            str = "",
                            img = editor.selection.getRange().getClosedNode(),
                            dialogs = editor.ui._dialogs;
                        if (img && img.tagName == "IMG") {
                            var dialogName = "insertimageDialog";
                            if (
                                img.className.indexOf("edui-faked-video") != -1 ||
                                img.className.indexOf("edui-upload-video") != -1
                            ) {
                                dialogName = "insertvideoDialog";
                            }
                            if (img.className.indexOf("edui-faked-webapp") != -1) {
                                dialogName = "webappDialog";
                            }
                            if (img.src.indexOf("https://api.map.baidu.com") != -1) {
                                dialogName = "mapDialog";
                            }
                            if (img.className.indexOf("edui-faked-music") != -1) {
                                dialogName = "musicDialog";
                            }
                            if (
                                img.src.indexOf("http://maps.google.com/maps/api/staticmap") != -1
                            ) {
                                dialogName = "gmapDialog";
                            }
                            if (img.getAttribute("anchorname")) {
                                dialogName = "anchorDialog";
                                html = popup.formatHtml(
                                    "<nobr>" +
                                    editor.getLang("property") +
                                    ': <span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">' +
                                    editor.getLang("modify") +
                                    "</span>&nbsp;&nbsp;" +
                                    "<span onclick=$$._onRemoveButtonClick('anchor') class=\"edui-clickable\">" +
                                    editor.getLang("delete") +
                                    "</span></nobr>"
                                );
                            }
                            if (img.getAttribute("word_img")) {
                                //todo 放到dialog去做查询
                                editor.word_img = [img.getAttribute("word_img")];
                                dialogName = "wordimageDialog";
                            }
                            if (
                                domUtils.hasClass(img, "loadingclass") ||
                                domUtils.hasClass(img, "loaderrorclass")
                            ) {
                                dialogName = "";
                            }
                            if (!dialogs[dialogName]) {
                                return;
                            }
                            str =
                                "<nobr>" +
                                editor.getLang("property") +
                                ": " +
                                '<span onclick=$$._onImgSetFloat("none") class="edui-clickable">' +
                                editor.getLang("default") +
                                "</span>&nbsp;&nbsp;" +
                                '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">' +
                                editor.getLang("justifyleft") +
                                "</span>&nbsp;&nbsp;" +
                                '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">' +
                                editor.getLang("justifyright") +
                                "</span>&nbsp;&nbsp;" +
                                '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">' +
                                editor.getLang("justifycenter") +
                                "</span>&nbsp;&nbsp;" +
                                "<span onclick=\"$$._onImgEditButtonClick('" +
                                dialogName +
                                '\');" class="edui-clickable">' +
                                editor.getLang("modify") +
                                "</span></nobr>";

                            !html && (html = popup.formatHtml(str));
                        }
                        if (editor.ui._dialogs.linkDialog) {
                            var link = editor.queryCommandValue("link");
                            var url;
                            if (
                                link &&
                                (url = link.getAttribute("_href") || link.getAttribute("href", 2))
                            ) {
                                var txt = url;
                                if (url.length > 30) {
                                    txt = url.substring(0, 20) + "...";
                                }
                                if (html) {
                                    html += '<div style="height:5px;"></div>';
                                }
                                html += popup.formatHtml(
                                    "<nobr>" +
                                    editor.getLang("anthorMsg") +
                                    ': <a target="_blank" href="' +
                                    url +
                                    '" title="' +
                                    url +
                                    '" >' +
                                    txt +
                                    "</a>" +
                                    ' <span class="edui-clickable" onclick="$$._onEditButtonClick();">' +
                                    editor.getLang("modify") +
                                    "</span>" +
                                    ' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> ' +
                                    editor.getLang("clear") +
                                    "</span></nobr>"
                                );
                                popup.showAnchor(link);
                            }
                        }

                        if (html) {
                            popup.getDom("content").innerHTML = html;
                            popup.anchorEl = img || link;
                            popup.showAnchor(popup.anchorEl);
                        } else {
                            popup.hide();
                        }
                    });
                }
            },
            _initToolbars: function () {
                var editor = this.editor;
                var toolbars = this.toolbars || [];
                var toolbarUis = [];
                var extraUIs = [];
                for (var i = 0; i < toolbars.length; i++) {
                    var toolbar = toolbars[i];
                    var toolbarUi = new baidu.editor.ui.Toolbar({
                        theme: editor.options.theme
                    });
                    for (var j = 0; j < toolbar.length; j++) {
                        var toolbarItem = toolbar[j];
                        var toolbarItemUi = null;
                        if (typeof toolbarItem == "string") {
                            toolbarItem = toolbarItem.toLowerCase();
                            if (toolbarItem == "|") {
                                toolbarItem = "Separator";
                            }
                            if (toolbarItem == "||") {
                                toolbarItem = "Breakline";
                            }
                            var ui = baidu.editor.ui[toolbarItem];
                            if (ui) {
                                if (utils.isFunction(ui)) {
                                    toolbarItemUi = new baidu.editor.ui[toolbarItem](editor);
                                } else {
                                    if (ui.id && ui.id != editor.key) {
                                        continue;
                                    }
                                    var itemUI = ui.execFn.call(editor, editor, toolbarItem);
                                    if (itemUI) {
                                        if (ui.index === undefined) {
                                            toolbarUi.add(itemUI);
                                            continue;
                                        } else {
                                            extraUIs.push({
                                                index: ui.index,
                                                itemUI: itemUI
                                            });
                                        }
                                    }
                                }
                            }
                            //fullscreen这里单独处理一下,放到首行去
                            if (toolbarItem == "fullscreen") {
                                if (toolbarUis && toolbarUis[0]) {
                                    toolbarUis[0].items.splice(0, 0, toolbarItemUi);
                                } else {
                                    toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi);
                                }
                                continue;
                            }
                        } else {
                            toolbarItemUi = toolbarItem;
                        }
                        if (toolbarItemUi && toolbarItemUi.id) {
                            toolbarUi.add(toolbarItemUi);
                        }
                    }
                    toolbarUis[i] = toolbarUi;
                }

                //接受外部定制的UI

                utils.each(extraUIs, function (obj) {
                    toolbarUi.add(obj.itemUI, obj.index);
                });
                this.toolbars = toolbarUis;
            },
            getHtmlTpl: function () {
                return (
                    '<div id="##" class="%%">' +
                    '<div id="##_toolbarbox" class="%%-toolbarbox">' +
                    (this.toolbars.length
                        ? '<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
                        this.renderToolbarBoxHtml() +
                        "</div></div>"
                        : "") +
                    '<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
                    '<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">' +
                    this.editor.getLang("clickToUpload") +
                    "</div>" +
                    '<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
                    '<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
                    '<div style="height:0;overflow:hidden;clear:both;"></div>' +
                    "</div>" +
                    '<div id="##_message_holder" class="%%-messageholder"></div>' +
                    "</div>" +
                    '<div id="##_iframeholder" class="%%-iframeholder">' +
                    "</div>" +
                    //modify wdcount by matao
                    '<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
                    '<td id="##_elementpath" class="%%-bottombar"></td>' +
                    '<td id="##_wordcount" class="%%-wordcount"></td>' +
                    '<td id="##_scale" class="%%-scale"><div class="%%-icon"></div></td>' +
                    "</tr></table></div>" +
                    '<div id="##_scalelayer"></div>' +
                    "</div>"
                );
            },
            showWordImageDialog: function () {
                this._dialogs["wordimageDialog"].open();
            },
            renderToolbarBoxHtml: function () {
                var buff = [];
                for (var i = 0; i < this.toolbars.length; i++) {
                    buff.push(this.toolbars[i].renderHtml());
                }
                return buff.join("");
            },
            setFullScreen: function (fullscreen) {
                var editor = this.editor,
                    container = editor.container.parentNode.parentNode;
                if (this._fullscreen != fullscreen) {
                    this._fullscreen = fullscreen;
                    this.editor.fireEvent("beforefullscreenchange", fullscreen);
                    if (baidu.editor.browser.gecko) {
                        var bk = editor.selection.getRange().createBookmark();
                    }
                    if (fullscreen) {
                        while (container.tagName != "BODY") {
                            var position = baidu.editor.dom.domUtils.getComputedStyle(
                                container,
                                "position"
                            );
                            nodeStack.push(position);
                            container.style.position = "static";
                            container = container.parentNode;
                        }
                        this._bakHtmlOverflow = document.documentElement.style.overflow;
                        this._bakBodyOverflow = document.body.style.overflow;
                        this._bakAutoHeight = this.editor.autoHeightEnabled;
                        this._bakScrollTop = Math.max(
                            document.documentElement.scrollTop,
                            document.body.scrollTop
                        );

                        this._bakEditorContaninerWidth = editor.iframe.parentNode.offsetWidth;
                        if (this._bakAutoHeight) {
                            //当全屏时不能执行自动长高
                            editor.autoHeightEnabled = false;
                            this.editor.disableAutoHeight();
                        }

                        document.documentElement.style.overflow = "hidden";
                        //修复,滚动条不收起的问题

                        window.scrollTo(0, window.scrollY);
                        this._bakCssText = this.getDom().style.cssText;
                        this._bakCssText1 = this.getDom("iframeholder").style.cssText;
                        editor.iframe.parentNode.style.width = "";
                        this._updateFullScreen();
                    } else {
                        while (container.tagName != "BODY") {
                            container.style.position = nodeStack.shift();
                            container = container.parentNode;
                        }
                        this.getDom().style.cssText = this._bakCssText;
                        this.getDom("iframeholder").style.cssText = this._bakCssText1;
                        if (this._bakAutoHeight) {
                            editor.autoHeightEnabled = true;
                            this.editor.enableAutoHeight();
                        }

                        document.documentElement.style.overflow = this._bakHtmlOverflow;
                        document.body.style.overflow = this._bakBodyOverflow;
                        editor.iframe.parentNode.style.width =
                            this._bakEditorContaninerWidth + "px";
                        window.scrollTo(0, this._bakScrollTop);
                    }
                    if (browser.gecko && editor.body.contentEditable === "true") {
                        var input = document.createElement("input");
                        document.body.appendChild(input);
                        editor.body.contentEditable = false;
                        setTimeout(function () {
                            input.focus();
                            setTimeout(function () {
                                editor.body.contentEditable = true;
                                editor.fireEvent("fullscreenchanged", fullscreen);
                                editor.selection.getRange().moveToBookmark(bk).select(true);
                                baidu.editor.dom.domUtils.remove(input);
                                fullscreen && window.scroll(0, 0);
                            }, 0);
                        }, 0);
                    }

                    if (editor.body.contentEditable === "true") {
                        this.editor.fireEvent("fullscreenchanged", fullscreen);
                        this.triggerLayout();
                    }
                }
            },
            _updateFullScreen: function () {
                if (this._fullscreen) {
                    var vpRect = uiUtils.getViewportRect();
                    this.getDom().style.cssText =
                        "border:0;position:absolute;left:0;top:" +
                        (this.editor.options.topOffset || 0) +
                        "px;width:" +
                        vpRect.width +
                        "px;height:" +
                        vpRect.height +
                        "px;z-index:" +
                        (this.getDom().style.zIndex * 1 + 100);
                    uiUtils.setViewportOffset(this.getDom(), {
                        left: 0,
                        top: this.editor.options.topOffset || 0
                    });
                    this.editor.setHeight(
                        vpRect.height -
                        this.getDom("toolbarbox").offsetHeight -
                        this.getDom("bottombar").offsetHeight -
                        (this.editor.options.topOffset || 0),
                        true
                    );
                    //不手动调一下,会导致全屏失效
                    if (browser.gecko) {
                        try {
                            window.onresize();
                        } catch (e) {
                        }
                    }
                }
            },
            _updateElementPath: function () {
                var bottom = this.getDom("elementpath"),
                    list;
                if (
                    this.elementPathEnabled &&
                    (list = this.editor.queryCommandValue("elementpath"))
                ) {
                    var buff = [];
                    for (var i = 0, ci; (ci = list[i]); i++) {
                        buff[i] = this.formatHtml(
                            '<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' +
                            i +
                            '&quot;);">' +
                            ci +
                            "</span>"
                        );
                    }
                    bottom.innerHTML =
                        '<div class="edui-editor-breadcrumb" onmousedown="return false;">' +
                        this.editor.getLang("elementPathTip") +
                        ": " +
                        buff.join(" &gt; ") +
                        "</div>";
                } else {
                    bottom.style.display = "none";
                }
            },
            disableElementPath: function () {
                var bottom = this.getDom("elementpath");
                bottom.innerHTML = "";
                bottom.style.display = "none";
                this.elementPathEnabled = false;
            },
            enableElementPath: function () {
                var bottom = this.getDom("elementpath");
                bottom.style.display = "";
                this.elementPathEnabled = true;
                this._updateElementPath();
            },
            _scale: function () {
                var doc = document,
                    editor = this.editor,
                    editorHolder = editor.container,
                    editorDocument = editor.document,
                    toolbarBox = this.getDom("toolbarbox"),
                    bottombar = this.getDom("bottombar"),
                    scale = this.getDom("scale"),
                    scalelayer = this.getDom("scalelayer");

                var isMouseMove = false,
                    position = null,
                    minEditorHeight = 0,
                    minEditorWidth = editor.options.minFrameWidth,
                    pageX = 0,
                    pageY = 0,
                    scaleWidth = 0,
                    scaleHeight = 0;

                function down() {
                    position = domUtils.getXY(editorHolder);

                    if (!minEditorHeight) {
                        minEditorHeight =
                            editor.options.minFrameHeight +
                            toolbarBox.offsetHeight +
                            bottombar.offsetHeight;
                    }

                    scalelayer.style.cssText =
                        "position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:" +
                        editorHolder.offsetWidth +
                        "px;height:" +
                        editorHolder.offsetHeight +
                        "px;z-index:" +
                        (editor.options.zIndex + 1);

                    domUtils.on(doc, "mousemove", move);
                    domUtils.on(editorDocument, "mouseup", up);
                    domUtils.on(doc, "mouseup", up);
                }

                var me = this;
                //by xuheng 全屏时关掉缩放
                this.editor.addListener("fullscreenchanged", function (e, fullScreen) {
                    if (fullScreen) {
                        me.disableScale();
                    } else {
                        if (me.editor.options.scaleEnabled) {
                            me.enableScale();
                            var tmpNode = me.editor.document.createElement("span");
                            me.editor.body.appendChild(tmpNode);
                            me.editor.body.style.height =
                                Math.max(
                                    domUtils.getXY(tmpNode).y,
                                    me.editor.iframe.offsetHeight - 20
                                ) + "px";
                            domUtils.remove(tmpNode);
                        }
                    }
                });

                function move(event) {
                    clearSelection();
                    var e = event || window.event;
                    pageX = e.pageX || doc.documentElement.scrollLeft + e.clientX;
                    pageY = e.pageY || doc.documentElement.scrollTop + e.clientY;
                    scaleWidth = pageX - position.x;
                    scaleHeight = pageY - position.y;

                    if (scaleWidth >= minEditorWidth) {
                        isMouseMove = true;
                        scalelayer.style.width = scaleWidth + "px";
                    }
                    if (scaleHeight >= minEditorHeight) {
                        isMouseMove = true;
                        scalelayer.style.height = scaleHeight + "px";
                    }
                }

                function up() {
                    if (isMouseMove) {
                        isMouseMove = false;
                        editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2;
                        editorHolder.style.width = editor.ui._actualFrameWidth + "px";

                        editor.setHeight(
                            scalelayer.offsetHeight -
                            bottombar.offsetHeight -
                            toolbarBox.offsetHeight -
                            2,
                            true
                        );
                    }
                    if (scalelayer) {
                        scalelayer.style.display = "none";
                    }
                    clearSelection();
                    domUtils.un(doc, "mousemove", move);
                    domUtils.un(editorDocument, "mouseup", up);
                    domUtils.un(doc, "mouseup", up);
                }

                function clearSelection() {
                    if (browser.ie) doc.selection.clear();
                    else window.getSelection().removeAllRanges();
                }

                this.enableScale = function () {
                    //trace:2868
                    if (editor.queryCommandState("source") == 1) return;
                    scale.style.display = "";
                    this.scaleEnabled = true;
                    domUtils.on(scale, "mousedown", down);
                };
                this.disableScale = function () {
                    scale.style.display = "none";
                    this.scaleEnabled = false;
                    domUtils.un(scale, "mousedown", down);
                };
            },
            isFullScreen: function () {
                return this._fullscreen;
            },
            postRender: function () {
                UIBase.prototype.postRender.call(this);
                for (var i = 0; i < this.toolbars.length; i++) {
                    this.toolbars[i].postRender();
                }
                var me = this;
                var timerId,
                    domUtils = baidu.editor.dom.domUtils,
                    updateFullScreenTime = function () {
                        clearTimeout(timerId);
                        timerId = setTimeout(function () {
                            me._updateFullScreen();
                        });
                    };
                domUtils.on(window, "resize", updateFullScreenTime);

                me.addListener("destroy", function () {
                    domUtils.un(window, "resize", updateFullScreenTime);
                    clearTimeout(timerId);
                });
            },
            showToolbarMsg: function (msg, flag) {
                this.getDom("toolbarmsg_label").innerHTML = msg;
                this.getDom("toolbarmsg").style.display = "";
                //
                if (!flag) {
                    var w = this.getDom("upload_dialog");
                    w.style.display = "none";
                }
            },
            hideToolbarMsg: function () {
                this.getDom("toolbarmsg").style.display = "none";
            },
            mapUrl: function (url) {
                return url
                    ? url.replace("~/", this.editor.options.UEDITOR_HOME_URL || "")
                    : "";
            },
            triggerLayout: function () {
                var dom = this.getDom();
                if (dom.style.zoom == "1") {
                    dom.style.zoom = "100%";
                } else {
                    dom.style.zoom = "1";
                }
            }
        };
        utils.inherits(EditorUI, baidu.editor.ui.UIBase);

        var instances = {};

        UE.ui.Editor = function (options) {
            var editor = new UE.Editor(options);
            editor.options.editor = editor;
            utils.loadFile(document, {
                href:
                editor.options.themePath + editor.options.theme + "/css/neditor.css",
                tag: "link",
                type: "text/css",
                rel: "stylesheet"
            });

            var oldRender = editor.render;
            editor.render = function (holder) {
                if (holder.constructor === String) {
                    editor.key = holder;
                    instances[holder] = editor;
                }
                utils.domReady(function () {
                    editor.langIsReady
                        ? renderUI()
                        : editor.addListener("langReady", renderUI);

                    function renderUI() {
                        editor.setOpt({
                            labelMap: editor.options.labelMap || editor.getLang("labelMap")
                        });
                        new EditorUI(editor.options);
                        if (holder) {
                            if (holder.constructor === String) {
                                holder = document.getElementById(holder);
                            }
                            holder &&
                            holder.getAttribute("name") &&
                            (editor.options.textarea = holder.getAttribute("name"));
                            if (holder && /script|textarea/gi.test(holder.tagName)) {
                                var newDiv = document.createElement("div");
                                holder.parentNode.insertBefore(newDiv, holder);
                                var cont = holder.value || holder.innerHTML;
                                editor.options.initialContent = /^[\t\r\n ]*$/.test(cont)
                                    ? editor.options.initialContent
                                    : cont
                                        .replace(/>[\n\r\t]+([ ]{4})+/g, ">")
                                        .replace(/[\n\r\t]+([ ]{4})+</g, "<")
                                        .replace(/>[\n\r\t]+</g, "><");
                                holder.className && (newDiv.className = holder.className);
                                holder.style.cssText &&
                                (newDiv.style.cssText = holder.style.cssText);
                                if (/textarea/i.test(holder.tagName)) {
                                    editor.textarea = holder;
                                    editor.textarea.style.display = "none";
                                } else {
                                    holder.parentNode.removeChild(holder);
                                }
                                if (holder.id) {
                                    newDiv.id = holder.id;
                                    domUtils.removeAttributes(holder, "id");
                                }
                                holder = newDiv;
                                holder.innerHTML = "";
                            }
                        }
                        domUtils.addClass(holder, "edui-" + editor.options.theme);
                        editor.ui.render(holder);
                        var opt = editor.options;
                        //给实例添加一个编辑器的容器引用
                        editor.container = editor.ui.getDom();
                        var parents = domUtils.findParents(holder, true);
                        var displays = [];
                        for (var i = 0, ci; (ci = parents[i]); i++) {
                            displays[i] = ci.style.display;
                            ci.style.display = "block";
                        }
                        if (opt.initialFrameWidth) {
                            opt.minFrameWidth = opt.initialFrameWidth;
                        } else {
                            opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth;
                            var styleWidth = holder.style.width;
                            if (/%$/.test(styleWidth)) {
                                opt.initialFrameWidth = styleWidth;
                            }
                        }
                        if (opt.initialFrameHeight) {
                            opt.minFrameHeight = opt.initialFrameHeight;
                        } else {
                            opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight;
                        }
                        for (var i = 0, ci; (ci = parents[i]); i++) {
                            ci.style.display = displays[i];
                        }
                        //编辑器最外容器设置了高度,会导致,编辑器不占位
                        //todo 先去掉,没有找到原因
                        if (holder.style.height) {
                            holder.style.height = "";
                        }
                        editor.container.style.width =
                            opt.initialFrameWidth +
                            (/%$/.test(opt.initialFrameWidth) ? "" : "px");
                        editor.container.style.zIndex = opt.zIndex;
                        oldRender.call(editor, editor.ui.getDom("iframeholder"));
                        editor.fireEvent("afteruiready");
                    }
                });
            };
            return editor;
        };

        /**
         * @file
         * @name UE
         * @short UE
         * @desc UEditor的顶部命名空间
         */
        /**
         * @name getEditor
         * @since 1.2.4+
         * @grammar UE.getEditor(id,[opt])  =>  Editor实例
         * @desc 提供一个全局的方法得到编辑器实例
         *
         * * ''id''  放置编辑器的容器id, 如果容器下的编辑器已经存在,就直接返回
         * * ''opt'' 编辑器的可选参数
         * @example
         *  UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
     *      this.setContent('hello')
     *  }});
         *  UE.getEditor('containerId'); //返回刚创建的实例
         *
         */
        UE.getEditor = function (id, opt) {
            var editor = instances[id];
            if (!editor) {
                editor = instances[id] = new UE.ui.Editor(opt);
                editor.render(id);
            }
            return editor;
        };

        UE.delEditor = function (id) {
            var editor;
            if ((editor = instances[id])) {
                editor.key && editor.destroy();
                delete instances[id];
            }
        };

        UE.registerUI = function (uiName, fn, index, editorId) {
            utils.each(uiName.split(/\s+/), function (name) {
                baidu.editor.ui[name] = {
                    id: editorId,
                    execFn: fn,
                    index: index
                };
            });
        };
    })();


// adapter/message.js
    UE.registerUI("message", function (editor) {
        var editorui = baidu.editor.ui;
        var Message = editorui.Message;
        var holder;
        var _messageItems = [];
        var me = editor;

        me.setOpt("enableMessageShow", true);
        if (me.getOpt("enableMessageShow") === false) {
            return;
        }

        me.addListener("ready", function () {
            holder = document.getElementById(me.ui.id + "_message_holder");
            updateHolderPos();
            setTimeout(function () {
                updateHolderPos();
            }, 500);
        });

        me.addListener("showmessage", function (type, opt) {
            opt = utils.isString(opt)
                ? {
                    content: opt
                }
                : opt;
            var message = new Message({
                    timeout: opt.timeout,
                    type: opt.type,
                    content: opt.content,
                    keepshow: opt.keepshow,
                    editor: me
                }),
                mid = opt.id || "msg_" + (+new Date()).toString(36);
            message.render(holder);
            _messageItems[mid] = message;
            message.reset(opt);
            updateHolderPos();
            return mid;
        });

        me.addListener("updatemessage", function (type, id, opt) {
            opt = utils.isString(opt)
                ? {
                    content: opt
                }
                : opt;
            var message = _messageItems[id];
            message.render(holder);
            message && message.reset(opt);
        });

        me.addListener("hidemessage", function (type, id) {
            var message = _messageItems[id];
            message && message.hide();
        });

        function updateHolderPos() {
            if (!holder || !me.ui) return;
            var toolbarbox = me.ui.getDom("toolbarbox");
            if (toolbarbox) {
                holder.style.top = toolbarbox.offsetHeight + 3 + "px";
            }
            holder.style.zIndex =
                Math.max(me.options.zIndex, me.iframe.style.zIndex) + 1;
        }
    });


// adapter/autosave.js
    UE.registerUI("autosave", function (editor) {
        var timer = null,
            uid = null;
        editor.on("afterautosave", function () {
            clearTimeout(timer);

            timer = setTimeout(function () {
                if (uid) {
                    editor.trigger("hidemessage", uid);
                }
                uid = editor.trigger("showmessage", {
                    content: editor.getLang("autosave.success"),
                    timeout: 2000
                });
            }, 2000);
        });
    });


})();