]/.test(html)) {
      return UE.htmlparser(html).children[0];
    } else {
      return new uNode({
        type: "element",
        children: [],
        tagName: html
      });
    }
  };
  uNode.createText = function(data, noTrans) {
    return new UE.uNode({
      type: "text",
      data: noTrans ? data : utils.unhtml(data || "")
    });
  };
  function nodeToHtml(node, arr, formatter, current) {
    switch (node.type) {
      case "root":
        for (var i = 0, ci; (ci = node.children[i++]); ) {
          //插入新行
          if (
            formatter &&
            ci.type == "element" &&
            !dtd.$inlineWithA[ci.tagName] &&
            i > 1
          ) {
            insertLine(arr, current, true);
            insertIndent(arr, current);
          }
          nodeToHtml(ci, arr, formatter, current);
        }
        break;
      case "text":
        isText(node, arr);
        break;
      case "element":
        isElement(node, arr, formatter, current);
        break;
      case "comment":
        isComment(node, arr, formatter);
    }
    return arr;
  }
  function isText(node, arr) {
    if (node.parentNode.tagName == "pre") {
      //源码模式下输入html标签,不能做转换处理,直接输出
      arr.push(node.data);
    } else {
      arr.push(
        notTransTagName[node.parentNode.tagName]
          ? utils.html(node.data)
          : node.data.replace(/[ ]{2}/g, "  ")
      );
    }
  }
  function isElement(node, arr, formatter, current) {
    var attrhtml = "";
    if (node.attrs) {
      attrhtml = [];
      var attrs = node.attrs;
      for (var a in attrs) {
        //这里就针对
        //'
        //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
        //有可能做的不够
        attrhtml.push(
          a +
            (attrs[a] !== undefined
              ? '="' +
                  (notTransAttrs[a]
                    ? utils.html(attrs[a]).replace(/["]/g, function(a) {
                        return """;
                      })
                    : utils.unhtml(attrs[a])) +
                  '"'
              : "")
        );
      }
      attrhtml = attrhtml.join(" ");
    }
    arr.push(
      "<" +
        node.tagName +
        (attrhtml ? " " + attrhtml : "") +
        (dtd.$empty[node.tagName] ? "/" : "") +
        ">"
    );
    //插入新行
    if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != "pre") {
      if (node.children && node.children.length) {
        current = insertLine(arr, current, true);
        insertIndent(arr, current);
      }
    }
    if (node.children && node.children.length) {
      for (var i = 0, ci; (ci = node.children[i++]); ) {
        if (
          formatter &&
          ci.type == "element" &&
          !dtd.$inlineWithA[ci.tagName] &&
          i > 1
        ) {
          insertLine(arr, current);
          insertIndent(arr, current);
        }
        nodeToHtml(ci, arr, formatter, current);
      }
    }
    if (!dtd.$empty[node.tagName]) {
      if (
        formatter &&
        !dtd.$inlineWithA[node.tagName] &&
        node.tagName != "pre"
      ) {
        if (node.children && node.children.length) {
          current = insertLine(arr, current);
          insertIndent(arr, current);
        }
      }
      arr.push("" + node.tagName + ">");
    }
  }
  function isComment(node, arr) {
    arr.push("");
  }
  function getNodeById(root, id) {
    var node;
    if (root.type == "element" && root.getAttr("id") == id) {
      return root;
    }
    if (root.children && root.children.length) {
      for (var i = 0, ci; (ci = root.children[i++]); ) {
        if ((node = getNodeById(ci, id))) {
          return node;
        }
      }
    }
  }
  function getNodesByTagName(node, tagName, arr) {
    if (node.type == "element" && node.tagName == tagName) {
      arr.push(node);
    }
    if (node.children && node.children.length) {
      for (var i = 0, ci; (ci = node.children[i++]); ) {
        getNodesByTagName(ci, tagName, arr);
      }
    }
  }
  function nodeTraversal(root, fn) {
    if (root.children && root.children.length) {
      for (var i = 0, ci; (ci = root.children[i]); ) {
        nodeTraversal(ci, fn);
        //ci被替换的情况,这里就不再走 fn了
        if (ci.parentNode) {
          if (ci.children && ci.children.length) {
            fn(ci);
          }
          if (ci.parentNode) i++;
        }
      }
    } else {
      fn(root);
    }
  }
  uNode.prototype = {
    /**
         * 当前节点对象,转换成html文本
         * @method toHtml
         * @return { String } 返回转换后的html字符串
         * @example
         * ```javascript
         * node.toHtml();
         * ```
         */
    /**
         * 当前节点对象,转换成html文本
         * @method toHtml
         * @param { Boolean } formatter 是否格式化返回值
         * @return { String } 返回转换后的html字符串
         * @example
         * ```javascript
         * node.toHtml( true );
         * ```
         */
    toHtml: function(formatter) {
      var arr = [];
      nodeToHtml(this, arr, formatter, 0);
      return arr.join("");
    },
    /**
         * 获取节点的html内容
         * @method innerHTML
         * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
         * @return { String } 返回节点的html内容
         * @example
         * ```javascript
         * var htmlstr = node.innerHTML();
         * ```
         */
    /**
         * 设置节点的html内容
         * @method innerHTML
         * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
         * @param { String } htmlstr 传入要设置的html内容
         * @return { UE.uNode } 返回节点本身
         * @example
         * ```javascript
         * node.innerHTML('text ');
         * ```
         */
    innerHTML: function(htmlstr) {
      if (this.type != "element" || dtd.$empty[this.tagName]) {
        return this;
      }
      if (utils.isString(htmlstr)) {
        if (this.children) {
          for (var i = 0, ci; (ci = this.children[i++]); ) {
            ci.parentNode = null;
          }
        }
        this.children = [];
        var tmpRoot = UE.htmlparser(htmlstr);
        for (var i = 0, ci; (ci = tmpRoot.children[i++]); ) {
          this.children.push(ci);
          ci.parentNode = this;
        }
        return this;
      } else {
        var tmpRoot = new UE.uNode({
          type: "root",
          children: this.children
        });
        return tmpRoot.toHtml();
      }
    },
    /**
         * 获取节点的纯文本内容
         * @method innerText
         * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
         * @return { String } 返回节点的存文本内容
         * @example
         * ```javascript
         * var textStr = node.innerText();
         * ```
         */
    /**
         * 设置节点的纯文本内容
         * @method innerText
         * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
         * @param { String } textStr 传入要设置的文本内容
         * @return { UE.uNode } 返回节点本身
         * @example
         * ```javascript
         * node.innerText('text ');
         * ```
         */
    innerText: function(textStr, noTrans) {
      if (this.type != "element" || dtd.$empty[this.tagName]) {
        return this;
      }
      if (textStr) {
        if (this.children) {
          for (var i = 0, ci; (ci = this.children[i++]); ) {
            ci.parentNode = null;
          }
        }
        this.children = [];
        this.appendChild(uNode.createText(textStr, noTrans));
        return this;
      } else {
        return this.toHtml().replace(/<[^>]+>/g, "");
      }
    },
    /**
         * 获取当前对象的data属性
         * @method getData
         * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
         * @example
         * ```javascript
         * node.getData();
         * ```
         */
    getData: function() {
      if (this.type == "element") return "";
      return this.data;
    },
    /**
         * 获取当前节点下的第一个子节点
         * @method firstChild
         * @return { UE.uNode } 返回第一个子节点
         * @example
         * ```javascript
         * node.firstChild(); //返回第一个子节点
         * ```
         */
    firstChild: function() {
      //            if (this.type != 'element' || dtd.$empty[this.tagName]) {
      //                return this;
      //            }
      return this.children ? this.children[0] : null;
    },
    /**
         * 获取当前节点下的最后一个子节点
         * @method lastChild
         * @return { UE.uNode } 返回最后一个子节点
         * @example
         * ```javascript
         * node.lastChild(); //返回最后一个子节点
         * ```
         */
    lastChild: function() {
      //            if (this.type != 'element' || dtd.$empty[this.tagName] ) {
      //                return this;
      //            }
      return this.children ? this.children[this.children.length - 1] : null;
    },
    /**
         * 获取和当前节点有相同父亲节点的前一个节点
         * @method previousSibling
         * @return { UE.uNode } 返回前一个节点
         * @example
         * ```javascript
         * node.children[2].previousSibling(); //返回子节点node.children[1]
         * ```
         */
    previousSibling: function() {
      var parent = this.parentNode;
      for (var i = 0, ci; (ci = parent.children[i]); i++) {
        if (ci === this) {
          return i == 0 ? null : parent.children[i - 1];
        }
      }
    },
    /**
         * 获取和当前节点有相同父亲节点的后一个节点
         * @method nextSibling
         * @return { UE.uNode } 返回后一个节点,找不到返回null
         * @example
         * ```javascript
         * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
         * ```
         */
    nextSibling: function() {
      var parent = this.parentNode;
      for (var i = 0, ci; (ci = parent.children[i++]); ) {
        if (ci === this) {
          return parent.children[i];
        }
      }
    },
    /**
         * 用新的节点替换当前节点
         * @method replaceChild
         * @param { UE.uNode } target 要替换成该节点参数
         * @param { UE.uNode } source 要被替换掉的节点
         * @return { UE.uNode } 返回替换之后的节点对象
         * @example
         * ```javascript
         * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
         * ```
         */
    replaceChild: function(target, source) {
      if (this.children) {
        if (target.parentNode) {
          target.parentNode.removeChild(target);
        }
        for (var i = 0, ci; (ci = this.children[i]); i++) {
          if (ci === source) {
            this.children.splice(i, 1, target);
            source.parentNode = null;
            target.parentNode = this;
            return target;
          }
        }
      }
    },
    /**
         * 在节点的子节点列表最后位置插入一个节点
         * @method appendChild
         * @param { UE.uNode } node 要插入的节点
         * @return { UE.uNode } 返回刚插入的子节点
         * @example
         * ```javascript
         * node.appendChild( newNode ); //在node内插入子节点newNode
         * ```
         */
    appendChild: function(node) {
      if (
        this.type == "root" ||
        (this.type == "element" && !dtd.$empty[this.tagName])
      ) {
        if (!this.children) {
          this.children = [];
        }
        if (node.parentNode) {
          node.parentNode.removeChild(node);
        }
        for (var i = 0, ci; (ci = this.children[i]); i++) {
          if (ci === node) {
            this.children.splice(i, 1);
            break;
          }
        }
        this.children.push(node);
        node.parentNode = this;
        return node;
      }
    },
    /**
         * 在传入节点的前面插入一个节点
         * @method insertBefore
         * @param { UE.uNode } target 要插入的节点
         * @param { UE.uNode } source 在该参数节点前面插入
         * @return { UE.uNode } 返回刚插入的子节点
         * @example
         * ```javascript
         * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
         * ```
         */
    insertBefore: function(target, source) {
      if (this.children) {
        if (target.parentNode) {
          target.parentNode.removeChild(target);
        }
        for (var i = 0, ci; (ci = this.children[i]); i++) {
          if (ci === source) {
            this.children.splice(i, 0, target);
            target.parentNode = this;
            return target;
          }
        }
      }
    },
    /**
         * 在传入节点的后面插入一个节点
         * @method insertAfter
         * @param { UE.uNode } target 要插入的节点
         * @param { UE.uNode } source 在该参数节点后面插入
         * @return { UE.uNode } 返回刚插入的子节点
         * @example
         * ```javascript
         * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
         * ```
         */
    insertAfter: function(target, source) {
      if (this.children) {
        if (target.parentNode) {
          target.parentNode.removeChild(target);
        }
        for (var i = 0, ci; (ci = this.children[i]); i++) {
          if (ci === source) {
            this.children.splice(i + 1, 0, target);
            target.parentNode = this;
            return target;
          }
        }
      }
    },
    /**
         * 从当前节点的子节点列表中,移除节点
         * @method removeChild
         * @param { UE.uNode } node 要移除的节点引用
         * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
         * @return { * } 返回刚移除的子节点
         * @example
         * ```javascript
         * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
         * ```
         */
    removeChild: function(node, keepChildren) {
      if (this.children) {
        for (var i = 0, ci; (ci = this.children[i]); i++) {
          if (ci === node) {
            this.children.splice(i, 1);
            ci.parentNode = null;
            if (keepChildren && ci.children && ci.children.length) {
              for (var j = 0, cj; (cj = ci.children[j]); j++) {
                this.children.splice(i + j, 0, cj);
                cj.parentNode = this;
              }
            }
            return ci;
          }
        }
      }
    },
    /**
         * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
         * @method getAttr
         * @param { String } attrName 要获取的属性名称
         * @return { * } 返回attrs对象下的属性值
         * @example
         * ```javascript
         * node.getAttr('title');
         * ```
         */
    getAttr: function(attrName) {
      return this.attrs && this.attrs[attrName.toLowerCase()];
    },
    /**
         * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
         * @method setAttr
         * @param { String } attrName 要设置的属性名称
         * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
         * @return { * } 返回attrs对象下的属性值
         * @example
         * ```javascript
         * node.setAttr('title','标题');
         * ```
         */
    setAttr: function(attrName, attrVal) {
      if (!attrName) {
        delete this.attrs;
        return;
      }
      if (!this.attrs) {
        this.attrs = {};
      }
      if (utils.isObject(attrName)) {
        for (var a in attrName) {
          if (!attrName[a]) {
            delete this.attrs[a];
          } else {
            this.attrs[a.toLowerCase()] = attrName[a];
          }
        }
      } else {
        if (!attrVal) {
          delete this.attrs[attrName];
        } else {
          this.attrs[attrName.toLowerCase()] = attrVal;
        }
      }
    },
    /**
         * 获取当前节点在父节点下的位置索引
         * @method getIndex
         * @return { Number } 返回索引数值,如果没有父节点,返回-1
         * @example
         * ```javascript
         * node.getIndex();
         * ```
         */
    getIndex: function() {
      var parent = this.parentNode;
      for (var i = 0, ci; (ci = parent.children[i]); i++) {
        if (ci === this) {
          return i;
        }
      }
      return -1;
    },
    /**
         * 在当前节点下,根据id查找节点
         * @method getNodeById
         * @param { String } id 要查找的id
         * @return { UE.uNode } 返回找到的节点
         * @example
         * ```javascript
         * node.getNodeById('textId');
         * ```
         */
    getNodeById: function(id) {
      var node;
      if (this.children && this.children.length) {
        for (var i = 0, ci; (ci = this.children[i++]); ) {
          if ((node = getNodeById(ci, id))) {
            return node;
          }
        }
      }
    },
    /**
         * 在当前节点下,根据元素名称查找节点列表
         * @method getNodesByTagName
         * @param { String } tagNames 要查找的元素名称
         * @return { Array } 返回找到的节点列表
         * @example
         * ```javascript
         * node.getNodesByTagName('span');
         * ```
         */
    getNodesByTagName: function(tagNames) {
      tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, " ").split(" ");
      var arr = [],
        me = this;
      utils.each(tagNames, function(tagName) {
        if (me.children && me.children.length) {
          for (var i = 0, ci; (ci = me.children[i++]); ) {
            getNodesByTagName(ci, tagName, arr);
          }
        }
      });
      return arr;
    },
    /**
         * 根据样式名称,获取节点的样式值
         * @method getStyle
         * @param { String } name 要获取的样式名称
         * @return { String } 返回样式值
         * @example
         * ```javascript
         * node.getStyle('font-size');
         * ```
         */
    getStyle: function(name) {
      var cssStyle = this.getAttr("style");
      if (!cssStyle) {
        return "";
      }
      var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+)", "i");
      var match = cssStyle.match(reg);
      if (match && match[0]) {
        return match[2];
      }
      return "";
    },
    /**
         * 给节点设置样式
         * @method setStyle
         * @param { String } name 要设置的的样式名称
         * @param { String } val 要设置的的样值
         * @example
         * ```javascript
         * node.setStyle('font-size', '12px');
         * ```
         */
    setStyle: function(name, val) {
      function exec(name, val) {
        var reg = new RegExp("(^|;)\\s*" + name + ":([^;]+;?)", "gi");
        cssStyle = cssStyle.replace(reg, "$1");
        if (val) {
          cssStyle = name + ":" + utils.unhtml(val) + ";" + cssStyle;
        }
      }
      var cssStyle = this.getAttr("style");
      if (!cssStyle) {
        cssStyle = "";
      }
      if (utils.isObject(name)) {
        for (var a in name) {
          exec(a, name[a]);
        }
      } else {
        exec(name, val);
      }
      this.setAttr("style", utils.trim(cssStyle));
    },
    /**
         * 传入一个函数,递归遍历当前节点下的所有节点
         * @method traversal
         * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
         * @example
         * ```javascript
         * traversal(node, function(){
         *     console.log(node.type);
         * });
         * ```
         */
    traversal: function(fn) {
      if (this.children && this.children.length) {
        nodeTraversal(this, fn);
      }
      return this;
    }
  };
})();
// core/htmlparser.js
/**
 * html字符串转换成uNode节点
 * @file
 * @module UE
 * @since 1.2.6.1
 */
/**
 * UEditor公用空间,UEditor所有的功能都挂载在该空间下
 * @unfile
 * @module UE
 */
/**
 * html字符串转换成uNode节点的静态方法
 * @method htmlparser
 * @param { String } htmlstr 要转换的html代码
 * @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符
 * @return { uNode } 给定的html片段转换形成的uNode对象
 * @example
 * ```javascript
 * var root = UE.htmlparser('htmlparser 
', true);
 * ```
 */
var htmlparser = (UE.htmlparser = function(htmlstr, ignoreBlank) {
  //todo 原来的方式  [^"'<>\/] 有\/就不能配对上  这样的标签了
  //先去掉了,加上的原因忘了,这里先记录
  //var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  //以上的正则表达式无法匹配:
  //修改为如下正则表达式:
  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;
  }
  //如果结束是文本,就有可能丢掉,所以这里手动判断一下
  //例如 sdfsdfsdf sdfsdfsdfsdf
  if (nextIndex < htmlstr.length) {
    text(currentParent, htmlstr.slice(nextIndex));
  }
  return root;
});
// core/filternode.js
/**
 * UE过滤节点的静态方法
 * @file
 */
/**
 * UEditor公用空间,UEditor所有的功能都挂载在该空间下
 * @module UE
 */
/**
 * 根据传入节点和过滤规则过滤相应节点
 * @module UE
 * @since 1.2.6.1
 * @method filterNode
 * @param { Object } root 指定root节点
 * @param { Object } rules 过滤规则json对象
 * @example
 * ```javascript
 * UE.filterNode(root,editor.options.filterRules);
 * ```
 */
var filterNode = (UE.filterNode = (function() {
  function filterNode(node, rules) {
    switch (node.type) {
      case "text":
        break;
      case "element":
        var val;
        if ((val = rules[node.tagName])) {
          if (val === "-") {
            node.parentNode.removeChild(node);
          } else if (utils.isFunction(val)) {
            var parentNode = node.parentNode,
              index = node.getIndex();
            val(node);
            if (node.parentNode) {
              if (node.children) {
                for (var i = 0, ci; (ci = node.children[i]); ) {
                  filterNode(ci, rules);
                  if (ci.parentNode) {
                    i++;
                  }
                }
              }
            } else {
              for (var i = index, ci; (ci = parentNode.children[i]); ) {
                filterNode(ci, rules);
                if (ci.parentNode) {
                  i++;
                }
              }
            }
          } else {
            var attrs = val["$"];
            if (attrs && node.attrs) {
              var tmpAttrs = {},
                tmpVal;
              for (var a in attrs) {
                tmpVal = node.getAttr(a);
                //todo 只先对style单独处理
                if (a == "style" && utils.isArray(attrs[a])) {
                  var tmpCssStyle = [];
                  utils.each(attrs[a], function(v) {
                    var tmp;
                    if ((tmp = node.getStyle(v))) {
                      tmpCssStyle.push(v + ":" + tmp);
                    }
                  });
                  tmpVal = tmpCssStyle.join(";");
                }
                if (tmpVal) {
                  tmpAttrs[a] = tmpVal;
                }
              }
              node.attrs = tmpAttrs;
            }
            if (node.children) {
              for (var i = 0, ci; (ci = node.children[i]); ) {
                filterNode(ci, rules);
                if (ci.parentNode) {
                  i++;
                }
              }
            }
          }
        } else {
          //如果不在名单里扣出子节点并删除该节点,cdata除外
          if (dtd.$cdata[node.tagName]) {
            node.parentNode.removeChild(node);
          } else {
            var parentNode = node.parentNode,
              index = node.getIndex();
            node.parentNode.removeChild(node, true);
            for (var i = index, ci; (ci = parentNode.children[i]); ) {
              filterNode(ci, rules);
              if (ci.parentNode) {
                i++;
              }
            }
          }
        }
        break;
      case "comment":
        node.parentNode.removeChild(node);
    }
  }
  return function(root, rules) {
    if (utils.isEmptyObject(rules)) {
      return root;
    }
    var val;
    if ((val = rules["-"])) {
      utils.each(val.split(" "), function(k) {
        rules[k] = "-";
      });
    }
    for (var i = 0, ci; (ci = root.children[i]); ) {
      filterNode(ci, rules);
      if (ci.parentNode) {
        i++;
      }
    }
    return root;
  };
})());
// core/plugin.js
/**
 * Created with JetBrains PhpStorm.
 * User: campaign
 * Date: 10/8/13
 * Time: 6:15 PM
 * To change this template use File | Settings | File Templates.
 */
UE.plugin = (function() {
  var _plugins = {};
  return {
    register: function(pluginName, fn, oldOptionName, afterDisabled) {
      if (oldOptionName && utils.isFunction(oldOptionName)) {
        afterDisabled = oldOptionName;
        oldOptionName = null;
      }
      _plugins[pluginName] = {
        optionName: oldOptionName || pluginName,
        execFn: fn,
        //当插件被禁用时执行
        afterDisabled: afterDisabled
      };
    },
    load: function(editor) {
      utils.each(_plugins, function(plugin) {
        var _export = plugin.execFn.call(editor);
        if (editor.options[plugin.optionName] !== false) {
          if (_export) {
            //后边需要再做扩展
            utils.each(_export, function(v, k) {
              switch (k.toLowerCase()) {
                case "shortcutkey":
                  editor.addshortcutkey(v);
                  break;
                case "bindevents":
                  utils.each(v, function(fn, eventName) {
                    editor.addListener(eventName, fn);
                  });
                  break;
                case "bindmultievents":
                  utils.each(utils.isArray(v) ? v : [v], function(event) {
                    var types = utils.trim(event.type).split(/\s+/);
                    utils.each(types, function(eventName) {
                      editor.addListener(eventName, event.handler);
                    });
                  });
                  break;
                case "commands":
                  utils.each(v, function(execFn, execName) {
                    editor.commands[execName] = execFn;
                  });
                  break;
                case "outputrule":
                  editor.addOutputRule(v);
                  break;
                case "inputrule":
                  editor.addInputRule(v);
                  break;
                case "defaultoptions":
                  editor.setOpt(v);
              }
            });
          }
        } else if (plugin.afterDisabled) {
          plugin.afterDisabled.call(editor);
        }
      });
      //向下兼容
      utils.each(UE.plugins, function(plugin) {
        plugin.call(editor);
      });
    },
    run: function(pluginName, editor) {
      var plugin = _plugins[pluginName];
      if (plugin) {
        plugin.exeFn.call(editor);
      }
    }
  };
})();
// core/keymap.js
var keymap = (UE.keymap = {
  Backspace: 8,
  Tab: 9,
  Enter: 13,
  Shift: 16,
  Control: 17,
  Alt: 18,
  CapsLock: 20,
  Esc: 27,
  Spacebar: 32,
  PageUp: 33,
  PageDown: 34,
  End: 35,
  Home: 36,
  Left: 37,
  Up: 38,
  Right: 39,
  Down: 40,
  Insert: 45,
  Del: 46,
  NumLock: 144,
  Cmd: 91,
  "=": 187,
  "-": 189,
  b: 66,
  i: 73,
  //回退
  z: 90,
  y: 89,
  //粘贴
  v: 86,
  x: 88,
  s: 83,
  n: 78
});
// core/localstorage.js
//存储媒介封装
var LocalStorage = (UE.LocalStorage = (function() {
  var storage = window.localStorage || getUserData() || null,
    LOCAL_FILE = "localStorage";
  return {
    saveLocalData: function(key, data) {
      if (storage && data) {
        storage.setItem(key, data);
        return true;
      }
      return false;
    },
    getLocalData: function(key) {
      if (storage) {
        return storage.getItem(key);
      }
      return null;
    },
    removeItem: function(key) {
      storage && storage.removeItem(key);
    }
  };
  function getUserData() {
    var container = document.createElement("div");
    container.style.display = "none";
    if (!container.addBehavior) {
      return null;
    }
    container.addBehavior("#default#userdata");
    return {
      getItem: function(key) {
        var result = null;
        try {
          document.body.appendChild(container);
          container.load(LOCAL_FILE);
          result = container.getAttribute(key);
          document.body.removeChild(container);
        } catch (e) {}
        return result;
      },
      setItem: function(key, value) {
        document.body.appendChild(container);
        container.setAttribute(key, value);
        container.save(LOCAL_FILE);
        document.body.removeChild(container);
      },
      //// 暂时没有用到
      //clear: function () {
      //
      //    var expiresTime = new Date();
      //    expiresTime.setFullYear(expiresTime.getFullYear() - 1);
      //    document.body.appendChild(container);
      //    container.expires = expiresTime.toUTCString();
      //    container.save(LOCAL_FILE);
      //    document.body.removeChild(container);
      //
      //},
      removeItem: function(key) {
        document.body.appendChild(container);
        container.removeAttribute(key);
        container.save(LOCAL_FILE);
        document.body.removeChild(container);
      }
    };
  }
})());
;(function() {
  var ROOTKEY = "ueditor_preference";
  UE.Editor.prototype.setPreferences = function(key, value) {
    var obj = {};
    if (utils.isString(key)) {
      obj[key] = value;
    } else {
      obj = key;
    }
    var data = LocalStorage.getLocalData(ROOTKEY);
    if (data && (data = utils.str2json(data))) {
      utils.extend(data, obj);
    } else {
      data = obj;
    }
    data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  };
  UE.Editor.prototype.getPreferences = function(key) {
    var data = LocalStorage.getLocalData(ROOTKEY);
    if (data && (data = utils.str2json(data))) {
      return key ? data[key] : data;
    }
    return null;
  };
  UE.Editor.prototype.removePreferences = function(key) {
    var data = LocalStorage.getLocalData(ROOTKEY);
    if (data && (data = utils.str2json(data))) {
      data[key] = undefined;
      delete data[key];
    }
    data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  };
})();
// plugins/defaultfilter.js
///import core
///plugin 编辑器默认的过滤转换机制
UE.plugins["defaultfilter"] = function() {
  var me = this;
  me.setOpt({
    allowDivTransToP: 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 ? " " : " ");
            }
            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这两个文本
 * //执行命令,插入CC 
 * //插入后的效果 xxxCC xxx
 * //xx|xxx
 当前选区为闭合状态
 * //插入CC
 * //结果 xx
CC
xxx
 * //xxxx
|xxx 当前选区在两个p标签之间
 * //插入 xxxx
 * //结果 xxxx
xxxx
xxx
 * ```
 */
UE.commands["inserthtml"] = {
  execCommand: function(command, html, notNeedFilter) {
    var me = this,
      range,
      div;
    if (!html) {
      return;
    }
    if (me.fireEvent("beforeinserthtml", html) === true) {
      return;
    }
    range = me.selection.getRange();
    div = range.document.createElement("div");
    div.style.display = "inline";
    if (!notNeedFilter) {
      var root = UE.htmlparser(html);
      //如果给了过滤规则就先进行过滤
      if (me.options.filterRules) {
        UE.filterNode(root, me.options.filterRules);
      }
      //执行默认的处理
      me.filterInputRule(root);
      html = root.toHtml();
    }
    div.innerHTML = utils.trim(html);
    if (!range.collapsed) {
      var tmpNode = range.startContainer;
      if (domUtils.isFillChar(tmpNode)) {
        range.setStartBefore(tmpNode);
      }
      tmpNode = range.endContainer;
      if (domUtils.isFillChar(tmpNode)) {
        range.setEndAfter(tmpNode);
      }
      range.txtToElmBoundary();
      //结束边界可能放到了br的前边,要把br包含进来
      // x[xxx] 
      if (range.endContainer && range.endContainer.nodeType == 1) {
        tmpNode = range.endContainer.childNodes[range.endOffset];
        if (tmpNode && domUtils.isBr(tmpNode)) {
          range.setEndAfter(tmpNode);
        }
      }
      if (range.startOffset == 0) {
        tmpNode = range.startContainer;
        if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
          tmpNode = range.endContainer;
          if (
            range.endOffset ==
              (tmpNode.nodeType == 3
                ? tmpNode.nodeValue.length
                : tmpNode.childNodes.length) &&
            domUtils.isBoundaryNode(tmpNode, "lastChild")
          ) {
            me.body.innerHTML = "" + (browser.ie ? "" : " ") + "
";
            range.setStart(me.body.firstChild, 0).collapse(true);
          }
        }
      }
      !range.collapsed && range.deleteContents();
      if (range.startContainer.nodeType == 1) {
        var child = range.startContainer.childNodes[range.startOffset],
          pre;
        if (
          child &&
          domUtils.isBlockElm(child) &&
          (pre = child.previousSibling) &&
          domUtils.isBlockElm(pre)
        ) {
          range.setEnd(pre, pre.childNodes.length).collapse();
          while (child.firstChild) {
            pre.appendChild(child.firstChild);
          }
          domUtils.remove(child);
        }
      }
    }
    var child,
      parent,
      pre,
      tmp,
      hadBreak = 0,
      nextNode;
    //如果当前位置选中了fillchar要干掉,要不会产生空行
    if (range.inFillChar()) {
      child = range.startContainer;
      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> ==> 
|
            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 : " ";
          } 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 = ' ";
        headHtml.push(html);
      },
      aftersetcontent: function() {
        if (isSetColored == false) setBackground();
      }
    },
    inputRule: function(root) {
      isSetColored = false;
      utils.each(root.getNodesByTagName("p"), function(p) {
        var styles = p.getAttr("data-background");
        if (styles) {
          isSetColored = true;
          setBackground(stringToObj(styles));
          p.parentNode.removeChild(p);
        }
      });
    },
    outputRule: function(root) {
      var me = this,
        styles = (utils.cssRule(cssRuleId, me.document) || "")
          .replace(/[\n\r]+/g, "")
          .match(reg);
      if (styles) {
        root.appendChild(
          UE.uNode.createElement(
            '
'
          )
        );
      }
    },
    commands: {
      background: {
        execCommand: function(cmd, obj) {
          setBackground(obj);
        },
        queryCommandValue: function() {
          var me = this,
            styles = (utils.cssRule(cssRuleId, me.document) || "")
              .replace(/[\n\r]+/g, "")
              .match(reg);
          return styles ? stringToObj(styles[1]) : null;
        },
        notNeedUndo: true
      }
    }
  };
});
// plugins/image.js
/**
 * 图片插入、排版插件
 * @file
 * @since 1.2.6.1
 */
/**
 * 图片对齐方式
 * @command imagefloat
 * @method execCommand
 * @remind 值center为独占一行居中
 * @param { String } cmd 命令字符串
 * @param { String } align 对齐方式,可传left、right、none、center
 * @remaind center表示图片独占一行
 * @example
 * ```javascript
 * editor.execCommand( 'imagefloat', 'center' );
 * ```
 */
/**
 * 如果选区所在位置是图片区域
 * @command imagefloat
 * @method queryCommandValue
 * @param { String } cmd 命令字符串
 * @return { String } 返回图片对齐方式
 * @example
 * ```javascript
 * editor.queryCommandValue( 'imagefloat' );
 * ```
 */
UE.commands["imagefloat"] = {
  execCommand: function(cmd, align) {
    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",
                '' +
                  pN.innerHTML +
                  "
"
              );
              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 =
          ' ";
        if (ci["floatStyle"] == "center") {
          str = '' + str + "
";
        }
        html.push(str);
      } else {
        for (var i = 0; (ci = opt[i++]); ) {
          str =
            "
";
          html.push(str);
        }
      }
      me.execCommand("insertHtml", html.join(""));
    }
    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  如果是xx 
 startContainer是p就会找不到a
        range.shrinkBoundary();
        var start = range.startContainer.nodeType == 3 ||
          !range.startContainer.childNodes[range.startOffset]
          ? range.startContainer
          : range.startContainer.childNodes[range.startOffset],
          end = range.endContainer.nodeType == 3 || range.endOffset == 0
            ? range.endContainer
            : range.endContainer.childNodes[range.endOffset - 1],
          common = range.getCommonAncestor();
        node = domUtils.findParentByTagName(common, "a", true);
        if (!node && common.nodeType == 1) {
          var as = common.getElementsByTagName("a"),
            ps,
            pe;
          for (var i = 0, ci; (ci = as[i++]); ) {
            (ps = domUtils.getPosition(ci, start)), (pe = domUtils.getPosition(
              ci,
              end
            ));
            if (
              (ps & domUtils.POSITION_FOLLOWING ||
                ps & domUtils.POSITION_CONTAINS) &&
              (pe & domUtils.POSITION_PRECEDING ||
                pe & domUtils.POSITION_CONTAINS)
            ) {
              node = ci;
              break;
            }
          }
        }
        return node;
      }
    },
    queryCommandState: function() {
      //判断如果是视频的话连接不可用
      //fix 853
      var img = this.selection.getRange().getClosedNode(),
        flag =
          img &&
          (img.className == "edui-faked-video" ||
            img.className.indexOf("edui-upload-video") != -1);
      return flag ? -1 : 0;
    }
  };
};
// plugins/iframe.js
///import core
///import plugins\inserthtml.js
///commands 插入框架
///commandsName  InsertFrame
///commandsTitle  插入Iframe
///commandsDialog  dialogs\insertframe
UE.plugins["insertframe"] = function() {
  var me = this;
  function deleteIframe() {
    me._iframe && delete me._iframe;
  }
  me.addListener("selectionchange", function() {
    deleteIframe();
  });
};
// plugins/scrawl.js
///import core
///commands 涂鸦
///commandsName  Scrawl
///commandsTitle  涂鸦
///commandsDialog  dialogs\scrawl
UE.commands["scrawl"] = {
  queryCommandState: function() {
    return browser.ie && browser.version <= 8 ? -1 : 0;
  }
};
// plugins/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);
        //清除冗余的代码  
        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(
      '" +
        this.getContent(null, null, true) +
        "
"
    );
    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", " ");
        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 ? " " : ""
            : " ";
        } else {
          var frag = rng.extractContents();
          var div = me.document.createElement("div");
          div.appendChild(frag);
          utils.each(
            UE.filterNode(
              UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, "")),
              me.options.filterTxtRules
            ).children,
            function(node) {
              if (browser.ie && browser.ie11below && browser.version > 8) {
                if (node.type == "element") {
                  if (node.tagName == "br") {
                    code += "\n";
                  } else if (!dtd.$empty[node.tagName]) {
                    utils.each(node.children, function(cn) {
                      if (cn.type == "element") {
                        if (cn.tagName == "br") {
                          code += "\n";
                        } else if (!dtd.$empty[node.tagName]) {
                          code += cn.innerText();
                        }
                      } else {
                        code += cn.data;
                      }
                    });
                    if (!/\n$/.test(code)) {
                      code += "\n";
                    }
                  }
                } else {
                  code += node.data + "\n";
                }
                if (!node.nextSibling() && /\n$/.test(code)) {
                  code = code.replace(/\n$/, "");
                }
              } else {
                if (browser.ie && browser.ie11below) {
                  if (node.type == "element") {
                    if (node.tagName == "br") {
                      code += " ";
                    } else if (!dtd.$empty[node.tagName]) {
                      utils.each(node.children, function(cn) {
                        if (cn.type == "element") {
                          if (cn.tagName == "br") {
                            code += " ";
                          } else if (!dtd.$empty[node.tagName]) {
                            code += cn.innerText();
                          }
                        } else {
                          code += cn.data;
                        }
                      });
                      if (!/br>$/.test(code)) {
                        code += " ";
                      }
                    }
                  } else {
                    code += node.data + " ";
                  }
                  if (!node.nextSibling() && / $/.test(code)) {
                    code = code.replace(/ $/, "");
                  }
                } else {
                  code += node.type == "element"
                    ? dtd.$empty[node.tagName] ? "" : node.innerText()
                    : node.data;
                  if (!/br\/?\s*>$/.test(code)) {
                    if (!node.nextSibling()) return;
                    code += " ";
                  }
                }
              }
            }
          );
        }
        me.execCommand(
          "inserthtml",
          '' +
            code +
            " ",
          true
        );
        pre = me.document.getElementById("coder");
        domUtils.removeAttributes(pre, "id");
        var tmpNode = pre.previousSibling;
        if (
          tmpNode &&
          ((tmpNode.nodeType == 3 &&
            tmpNode.nodeValue.length == 1 &&
            browser.ie &&
            browser.version == 6) ||
            domUtils.isEmptyBlock(tmpNode))
        ) {
          domUtils.remove(tmpNode);
        }
        var rng = me.selection.getRange();
        if (domUtils.isEmptyBlock(pre)) {
          rng.setStart(pre, 0).setCursor(false, true);
        } else {
          rng.selectNodeContents(pre).select();
        }
      }
    },
    queryCommandValue: function() {
      var path = this.selection.getStartElementPath();
      var lang = "";
      utils.each(path, function(node) {
        if (node.nodeName == "PRE") {
          var match = node.className.match(/brush:([^;]+)/);
          lang = match && match[1] ? match[1] : "";
          return false;
        }
      });
      return lang;
    }
  };
  me.addInputRule(function(root) {
    utils.each(root.getNodesByTagName("pre"), function(pre) {
      var brs = pre.getNodesByTagName("br");
      if (brs.length) {
        browser.ie &&
          browser.ie11below &&
          browser.version > 8 &&
          utils.each(brs, function(br) {
            var txt = UE.uNode.createText("\n");
            br.parentNode.insertBefore(txt, br);
            br.parentNode.removeChild(br);
          });
        return;
      }
      if (browser.ie && browser.ie11below && browser.version > 8) return;
      var code = pre.innerText().split(/\n/);
      pre.innerHTML("");
      utils.each(code, function(c) {
        if (c.length) {
          pre.appendChild(UE.uNode.createText(c));
        }
        pre.appendChild(UE.uNode.createElement("br"));
      });
    });
  });
  me.addOutputRule(function(root) {
    utils.each(root.getNodesByTagName("pre"), function(pre) {
      var code = "";
      utils.each(pre.children, function(n) {
        if (n.type == "text") {
          //在ie下文本内容有可能末尾带有\n要去掉
          //trace:3396
          code += n.data.replace(/[ ]/g, " ").replace(/\n$/, "");
        } else {
          if (n.tagName == "br") {
            code += "\n";
          } else {
            code += !dtd.$empty[n.tagName] ? "" : n.innerText();
          }
        }
      });
      pre.innerText(code.replace(/( |\n)+$/, ""));
    });
  });
  //不需要判断highlight的command列表
  me.notNeedCodeQuery = {
    help: 1,
    undo: 1,
    redo: 1,
    source: 1,
    print: 1,
    searchreplace: 1,
    fullscreen: 1,
    preview: 1,
    insertparagraph: 1,
    elementpath: 1,
    insertcode: 1,
    inserthtml: 1,
    selectall: 1
  };
  //将queyCommamndState重置
  var orgQuery = me.queryCommandState;
  me.queryCommandState = function(cmd) {
    var me = this;
    if (
      !me.notNeedCodeQuery[cmd.toLowerCase()] &&
      me.selection &&
      me.queryCommandValue("insertcode")
    ) {
      return -1;
    }
    return UE.Editor.prototype.queryCommandState.apply(this, arguments);
  };
  me.addListener("beforeenterkeydown", function() {
    var rng = me.selection.getRange();
    var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
    if (pre) {
      me.fireEvent("saveScene");
      if (!rng.collapsed) {
        rng.deleteContents();
      }
      if (!browser.ie || browser.ie9above) {
        var tmpNode = me.document.createElement("br"),
          pre;
        rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
        var next = tmpNode.nextSibling;
        if (!next && (!browser.ie || browser.version > 10)) {
          rng.insertNode(tmpNode.cloneNode(false));
        } else {
          rng.setStartAfter(tmpNode);
        }
        pre = tmpNode.previousSibling;
        var tmp;
        while (pre) {
          tmp = pre;
          pre = pre.previousSibling;
          if (!pre || pre.nodeName == "BR") {
            pre = tmp;
            break;
          }
        }
        if (pre) {
          var str = "";
          while (
            pre &&
            pre.nodeName != "BR" &&
            new RegExp("^[\\s" + domUtils.fillChar + "]*$").test(pre.nodeValue)
          ) {
            str += pre.nodeValue;
            pre = pre.nextSibling;
          }
          if (pre.nodeName != "BR") {
            var match = pre.nodeValue.match(
              new RegExp("^([\\s" + domUtils.fillChar + "]+)")
            );
            if (match && match[1]) {
              str += match[1];
            }
          }
          if (str) {
            str = me.document.createTextNode(str);
            rng.insertNode(str).setStartAfter(str);
          }
        }
        rng.collapse(true).select(true);
      } else {
        if (browser.version > 8) {
          var txt = me.document.createTextNode("\n");
          var start = rng.startContainer;
          if (rng.startOffset == 0) {
            var preNode = start.previousSibling;
            if (preNode) {
              rng.insertNode(txt);
              var fillchar = me.document.createTextNode(" ");
              rng
                .setStartAfter(txt)
                .insertNode(fillchar)
                .setStart(fillchar, 0)
                .collapse(true)
                .select(true);
            }
          } else {
            rng.insertNode(txt).setStartAfter(txt);
            var fillchar = me.document.createTextNode(" ");
            start = rng.startContainer.childNodes[rng.startOffset];
            if (start && !/^\n/.test(start.nodeValue)) {
              rng.setStartBefore(txt);
            }
            rng
              .insertNode(fillchar)
              .setStart(fillchar, 0)
              .collapse(true)
              .select(true);
          }
        } else {
          var tmpNode = me.document.createElement("br");
          rng.insertNode(tmpNode);
          rng.insertNode(me.document.createTextNode(domUtils.fillChar));
          rng.setStartAfter(tmpNode);
          pre = tmpNode.previousSibling;
          var tmp;
          while (pre) {
            tmp = pre;
            pre = pre.previousSibling;
            if (!pre || pre.nodeName == "BR") {
              pre = tmp;
              break;
            }
          }
          if (pre) {
            var str = "";
            while (
              pre &&
              pre.nodeName != "BR" &&
              new RegExp("^[ " + domUtils.fillChar + "]*$").test(pre.nodeValue)
            ) {
              str += pre.nodeValue;
              pre = pre.nextSibling;
            }
            if (pre.nodeName != "BR") {
              var match = pre.nodeValue.match(
                new RegExp("^([ " + domUtils.fillChar + "]+)")
              );
              if (match && match[1]) {
                str += match[1];
              }
            }
            str = me.document.createTextNode(str);
            rng.insertNode(str).setStartAfter(str);
          }
          rng.collapse(true).select();
        }
      }
      me.fireEvent("saveScene");
      return true;
    }
  });
  me.addListener("tabkeydown", function(cmd, evt) {
    var rng = me.selection.getRange();
    var pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
    if (pre) {
      me.fireEvent("saveScene");
      if (evt.shiftKey) {
      } else {
        if (!rng.collapsed) {
          var bk = rng.createBookmark();
          var start = bk.start.previousSibling;
          while (start) {
            if (pre.firstChild === start && !domUtils.isBr(start)) {
              pre.insertBefore(me.document.createTextNode("    "), start);
              break;
            }
            if (domUtils.isBr(start)) {
              pre.insertBefore(
                me.document.createTextNode("    "),
                start.nextSibling
              );
              break;
            }
            start = start.previousSibling;
          }
          var end = bk.end;
          start = bk.start.nextSibling;
          if (pre.firstChild === bk.start) {
            pre.insertBefore(
              me.document.createTextNode("    "),
              start.nextSibling
            );
          }
          while (start && start !== end) {
            if (domUtils.isBr(start) && start.nextSibling) {
              if (start.nextSibling === end) {
                break;
              }
              pre.insertBefore(
                me.document.createTextNode("    "),
                start.nextSibling
              );
            }
            start = start.nextSibling;
          }
          rng.moveToBookmark(bk).select();
        } else {
          var tmpNode = me.document.createTextNode("    ");
          rng
            .insertNode(tmpNode)
            .setStartAfter(tmpNode)
            .collapse(true)
            .select(true);
        }
      }
      me.fireEvent("saveScene");
      return true;
    }
  });
  me.addListener("beforeinserthtml", function(evtName, html) {
    var me = this,
      rng = me.selection.getRange(),
      pre = domUtils.findParentByTagName(rng.startContainer, "pre", true);
    if (pre) {
      if (!rng.collapsed) {
        rng.deleteContents();
      }
      var htmlstr = "";
      if (browser.ie && browser.version > 8) {
        utils.each(
          UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
            .children,
          function(node) {
            if (node.type == "element") {
              if (node.tagName == "br") {
                htmlstr += "\n";
              } else if (!dtd.$empty[node.tagName]) {
                utils.each(node.children, function(cn) {
                  if (cn.type == "element") {
                    if (cn.tagName == "br") {
                      htmlstr += "\n";
                    } else if (!dtd.$empty[node.tagName]) {
                      htmlstr += cn.innerText();
                    }
                  } else {
                    htmlstr += cn.data;
                  }
                });
                if (!/\n$/.test(htmlstr)) {
                  htmlstr += "\n";
                }
              }
            } else {
              htmlstr += node.data + "\n";
            }
            if (!node.nextSibling() && /\n$/.test(htmlstr)) {
              htmlstr = htmlstr.replace(/\n$/, "");
            }
          }
        );
        var tmpNode = me.document.createTextNode(
          utils.html(htmlstr.replace(/ /g, " "))
        );
        rng.insertNode(tmpNode).selectNode(tmpNode).select();
      } else {
        var frag = me.document.createDocumentFragment();
        utils.each(
          UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
            .children,
          function(node) {
            if (node.type == "element") {
              if (node.tagName == "br") {
                frag.appendChild(me.document.createElement("br"));
              } else if (!dtd.$empty[node.tagName]) {
                utils.each(node.children, function(cn) {
                  if (cn.type == "element") {
                    if (cn.tagName == "br") {
                      frag.appendChild(me.document.createElement("br"));
                    } else if (!dtd.$empty[node.tagName]) {
                      frag.appendChild(
                        me.document.createTextNode(
                          utils.html(cn.innerText().replace(/ /g, " "))
                        )
                      );
                    }
                  } else {
                    frag.appendChild(
                      me.document.createTextNode(
                        utils.html(cn.data.replace(/ /g, " "))
                      )
                    );
                  }
                });
                if (frag.lastChild.nodeName != "BR") {
                  frag.appendChild(me.document.createElement("br"));
                }
              }
            } else {
              frag.appendChild(
                me.document.createTextNode(
                  utils.html(node.data.replace(/ /g, " "))
                )
              );
            }
            if (!node.nextSibling() && frag.lastChild.nodeName == "BR") {
              frag.removeChild(frag.lastChild);
            }
          }
        );
        rng.insertNode(frag).select();
      }
      return true;
    }
  });
  //方向键的处理
  me.addListener("keydown", function(cmd, evt) {
    var me = this,
      keyCode = evt.keyCode || evt.which;
    if (keyCode == 40) {
      var rng = me.selection.getRange(),
        pre,
        start = rng.startContainer;
      if (
        rng.collapsed &&
        (pre = domUtils.findParentByTagName(rng.startContainer, "pre", true)) &&
        !pre.nextSibling
      ) {
        var last = pre.lastChild;
        while (last && last.nodeName == "BR") {
          last = last.previousSibling;
        }
        if (
          last === start ||
          (rng.startContainer === pre &&
            rng.startOffset == pre.childNodes.length)
        ) {
          me.execCommand("insertparagraph");
          domUtils.preventDefault(evt);
        }
      }
    }
  });
  //trace:3395
  me.addListener("delkeydown", function(type, evt) {
    var rng = this.selection.getRange();
    rng.txtToElmBoundary(true);
    var start = rng.startContainer;
    if (
      domUtils.isTagNode(start, "pre") &&
      rng.collapsed &&
      domUtils.isStartInblock(rng)
    ) {
      var p = me.document.createElement("p");
      domUtils.fillNode(me.document, p);
      start.parentNode.insertBefore(p, start);
      domUtils.remove(start);
      rng.setStart(p, 0).setCursor(false, true);
      domUtils.preventDefault(evt);
      return true;
    }
  });
};
// plugins/cleardoc.js
/**
 * 清空文档插件
 * @file
 * @since 1.2.6.1
 */
/**
 * 清空文档
 * @command cleardoc
 * @method execCommand
 * @param { String } cmd 命令字符串
 * @example
 * ```javascript
 * //editor 是编辑器实例
 * editor.execCommand('cleardoc');
 * ```
 */
UE.commands["cleardoc"] = {
  execCommand: function(cmdName) {
    var me = this,
      enterTag = me.options.enterTag,
      range = me.selection.getRange();
    if (enterTag == "br") {
      me.body.innerHTML = " ";
      range.setStart(me.body, 0).setCursor();
    } else {
      me.body.innerHTML = "" + (ie ? "" : " ") + "
";
      range.setStart(me.body.firstChild, 0).setCursor(false, true);
    }
    setTimeout(function() {
      me.fireEvent("clearDoc");
    }, 0);
  }
};
// plugins/anchor.js
/**
 * 锚点插件,为UEditor提供插入锚点支持
 * @file
 * @since 1.2.6.1
 */
UE.plugin.register("anchor", function() {
  return {
    bindEvents: {
      ready: function() {
        utils.cssRule(
          "anchor",
          ".anchorclass{background: url('" +
            this.options.themePath +
            this.options.theme +
            "/images/anchor.gif') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}",
          this.document
        );
      }
    },
    outputRule: function(root) {
      utils.each(root.getNodesByTagName("img"), function(a) {
        var val;
        if ((val = a.getAttr("anchorname"))) {
          a.tagName = "a";
          a.setAttr({
            anchorname: "",
            name: val,
            class: ""
          });
        }
      });
    },
    inputRule: function(root) {
      utils.each(root.getNodesByTagName("a"), function(a) {
        var val;
        if ((val = a.getAttr("name")) && !a.getAttr("href")) {
          //过滤掉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(
          ' '
        );
        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 + "|", "gi"); // ie会产生多余的
  var noNeedFillCharTags = {
    ol: 1,
    ul: 1,
    table: 1,
    tbody: 1,
    tr: 1,
    body: 1
  };
  var orgState = me.options.autoClearEmptyNode;
  function compareAddr(indexA, indexB) {
    if (indexA.length != indexB.length) return 0;
    for (var i = 0, l = indexA.length; i < l; i++) {
      if (indexA[i] != indexB[i]) return 0;
    }
    return 1;
  }
  function compareRangeAddress(rngAddrA, rngAddrB) {
    if (rngAddrA.collapsed != rngAddrB.collapsed) {
      return 0;
    }
    if (
      !compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) ||
      !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)
    ) {
      return 0;
    }
    return 1;
  }
  function UndoManager() {
    this.list = [];
    this.index = 0;
    this.hasUndo = false;
    this.hasRedo = false;
    this.undo = function() {
      if (this.hasUndo) {
        if (!this.list[this.index - 1] && this.list.length == 1) {
          this.reset();
          return;
        }
        while (
          this.list[this.index].content == this.list[this.index - 1].content
        ) {
          this.index--;
          if (this.index == 0) {
            return this.restore(0);
          }
        }
        this.restore(--this.index);
      }
    };
    this.redo = function() {
      if (this.hasRedo) {
        while (
          this.list[this.index].content == this.list[this.index + 1].content
        ) {
          this.index++;
          if (this.index == this.list.length - 1) {
            return this.restore(this.index);
          }
        }
        this.restore(++this.index);
      }
    };
    this.restore = function() {
      var me = this.editor;
      var scene = this.list[this.index];
      var root = UE.htmlparser(scene.content.replace(fillchar, ""));
      me.options.autoClearEmptyNode = false;
      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(/> <').replace(/\s*\s*/g, '>'));
      me.fireEvent("aftergetscene");
      return {
        address: rngAddress,
        content: cont
      };
    };
    this.save = function(notCompareRange, notSetCursor) {
      clearTimeout(saveSceneTimer);
      var currentScene = this.getScene(notSetCursor),
        lastScene = this.list[this.index];
      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 = ' ';
    bk.start.style.display = "";
    pastebin.style.cssText =
      "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
      //要在现在光标平行的位置加入,否则会出现跳动的问题
      domUtils.getXY(bk.start).y +
      "px";
    range.selectNodeContents(pastebin).select(true);
    setTimeout(function() {
      if (browser.webkit) {
        for (
          var i = 0, pastebins = doc.querySelectorAll("#baidu_pastebin"), pi;
          (pi = pastebins[i++]);
        ) {
          if (domUtils.isEmptyNode(pi)) {
            domUtils.remove(pi);
          } else {
            pastebin = pi;
            break;
          }
        }
      }
      try {
        pastebin.parentNode.removeChild(pastebin);
      } catch (e) {}
      range.moveToBookmark(bk).select(true);
      callback(pastebin);
    }, 0);
  }
  var me = this;
  me.setOpt({
    retainOnlyLabelPasted: false
  });
  var txtContent, htmlContent, address;
  function getPureHtml(html) {
    return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function(
      a,
      b,
      tagName,
      attrs
    ) {
      tagName = tagName.toLowerCase();
      if ({ img: 1 }[tagName]) {
        return a;
      }
      attrs = attrs.replace(
        /([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi,
        function(str, atr, val) {
          if (
            {
              src: 1,
              href: 1,
              name: 1
            }[atr.toLowerCase()]
          ) {
            return atr + "=" + val + " ";
          }
          return "";
        }
      );
      if (
        {
          span: 1,
          div: 1
        }[tagName]
      ) {
        return "";
      } else {
        return "<" + b + tagName + " " + utils.trim(attrs) + ">";
      }
    });
  }
  function filter(div) {
    var html;
    if (div.firstChild) {
      //去掉cut中添加的边界值
      var nodes = domUtils.getElementsByTagName(div, "span");
      for (var i = 0, ni; (ni = nodes[i++]); ) {
        if (ni.id == "_baidu_cut_start" || ni.id == "_baidu_cut_end") {
          domUtils.remove(ni);
        }
      }
      if (browser.webkit) {
        var brs = div.querySelectorAll("div br");
        for (var i = 0, bi; (bi = brs[i++]); ) {
          var pN = bi.parentNode;
          if (pN.tagName == "DIV" && pN.childNodes.length == 1) {
            pN.innerHTML = "
";
            domUtils.remove(pN);
          }
        }
        var divs = div.querySelectorAll("#baidu_pastebin");
        for (var i = 0, di; (di = divs[i++]); ) {
          var tmpP = me.document.createElement("p");
          di.parentNode.insertBefore(tmpP, di);
          while (di.firstChild) {
            tmpP.appendChild(di.firstChild);
          }
          domUtils.remove(di);
        }
        var metas = div.querySelectorAll("meta");
        for (var i = 0, ci; (ci = metas[i++]); ) {
          domUtils.remove(ci);
        }
        var brs = div.querySelectorAll("br");
        for (i = 0; (ci = brs[i++]); ) {
          if (/^apple-/i.test(ci.className)) {
            domUtils.remove(ci);
          }
        }
      }
      if (browser.gecko) {
        var dirtyNodes = div.querySelectorAll("[_moz_dirty]");
        for (i = 0; (ci = dirtyNodes[i++]); ) {
          ci.removeAttribute("_moz_dirty");
        }
      }
      if (!browser.ie) {
        var spans = div.querySelectorAll("span.Apple-style-span");
        for (var i = 0, ci; (ci = spans[i++]); ) {
          domUtils.remove(ci, true);
        }
      }
      //ie下使用innerHTML会产生多余的\r\n字符,也会产生 这里过滤掉
      html = div.innerHTML; //.replace(/>(?:(\s| )*?)<');
      //过滤word粘贴过来的冗余属性
      html = UE.filterWord(html);
      //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
      var root = UE.htmlparser(html);
      //如果给了过滤规则就先进行过滤
      if (me.options.filterRules) {
        UE.filterNode(root, me.options.filterRules);
      }
      //执行默认的处理
      me.filterInputRule(root);
      //针对chrome的处理
      if (browser.webkit) {
        var br = root.lastChild();
        if (br && br.type == "element" && br.tagName == "br") {
          root.removeChild(br);
        }
        utils.each(me.body.querySelectorAll("div"), function(node) {
          if (domUtils.isEmptyBlock(node)) {
            domUtils.remove(node, true);
          }
        });
      }
      html = { html: root.toHtml() };
      me.fireEvent("beforepaste", html, root);
      //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
      if (!html.html) {
        return;
      }
      root = UE.htmlparser(html.html, true);
      //如果开启了纯文本模式
      if (me.queryCommandState("pasteplain") === 1) {
        me.execCommand(
          "insertHtml",
          UE.filterNode(root, me.options.filterTxtRules).toHtml(),
          true
        );
      } else {
        //文本模式
        UE.filterNode(root, me.options.filterTxtRules);
        txtContent = root.toHtml();
        //完全模式
        htmlContent = html.html;
        address = me.selection.getRange().createAddress(true);
        me.execCommand(
          "insertHtml",
          me.getOpt("retainOnlyLabelPasted") === true
            ? getPureHtml(htmlContent)
            : htmlContent,
          true
        );
      }
      me.fireEvent("afterpaste", html);
    }
  }
  me.addListener("pasteTransfer", function(cmd, plainType) {
    if (address && txtContent && htmlContent && txtContent != htmlContent) {
      var range = me.selection.getRange();
      range.moveToAddress(address, true);
      if (!range.collapsed) {
        while (!domUtils.isBody(range.startContainer)) {
          var start = range.startContainer;
          if (start.nodeType == 1) {
            start = start.childNodes[range.startOffset];
            if (!start) {
              range.setStartBefore(range.startContainer);
              continue;
            }
            var pre = start.previousSibling;
            if (
              pre &&
              pre.nodeType == 3 &&
              new RegExp("^[\n\r\t " + domUtils.fillChar + "]*$").test(
                pre.nodeValue
              )
            ) {
              range.setStartBefore(pre);
            }
          }
          if (range.startOffset == 0) {
            range.setStartBefore(range.startContainer);
          } else {
            break;
          }
        }
        while (!domUtils.isBody(range.endContainer)) {
          var end = range.endContainer;
          if (end.nodeType == 1) {
            end = end.childNodes[range.endOffset];
            if (!end) {
              range.setEndAfter(range.endContainer);
              continue;
            }
            var next = end.nextSibling;
            if (
              next &&
              next.nodeType == 3 &&
              new RegExp("^[\n\r\t" + domUtils.fillChar + "]*$").test(
                next.nodeValue
              )
            ) {
              range.setEndAfter(next);
            }
          }
          if (
            range.endOffset ==
            range.endContainer[
              range.endContainer.nodeType == 3 ? "nodeValue" : "childNodes"
            ].length
          ) {
            range.setEndAfter(range.endContainer);
          } else {
            break;
          }
        }
      }
      range.deleteContents();
      range.select(true);
      me.__hasEnterExecCommand = true;
      var html = htmlContent;
      if (plainType === 2) {
        html = getPureHtml(html);
      } else if (plainType) {
        html = txtContent;
      }
      me.execCommand("inserthtml", html, true);
      me.__hasEnterExecCommand = false;
      var rng = me.selection.getRange();
      while (
        !domUtils.isBody(rng.startContainer) &&
        !rng.startOffset &&
        rng.startContainer[
          rng.startContainer.nodeType == 3 ? "nodeValue" : "childNodes"
        ].length
      ) {
        rng.setStartBefore(rng.startContainer);
      }
      var tmpAddress = rng.createAddress(true);
      address.endAddress = tmpAddress.startAddress;
    }
  });
  me.addListener("ready", function() {
    domUtils.on(me.body, "cut", function() {
      var range = me.selection.getRange();
      if (!range.collapsed && me.undoManger) {
        me.undoManger.save();
      }
    });
    //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
    domUtils.on(
      me.body,
      browser.ie || browser.opera ? "keydown" : "paste",
      function(e) {
        if (
          (browser.ie || browser.opera) &&
          ((!e.ctrlKey && !e.metaKey) || e.keyCode != "86")
        ) {
          return;
        }
        getClipboardData.call(me, function(div) {
          filter(div);
        });
      }
    );
  });
  me.commands["paste"] = {
    execCommand: function(cmd) {
      if (browser.ie) {
        getClipboardData.call(me, function(div) {
          filter(div);
        });
        me.document.execCommand("paste");
      } else {
        alert(me.getLang("pastemsg"));
      }
    }
  };
};
// plugins/puretxtpaste.js
/**
 * 纯文本粘贴插件
 * @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("    "),
              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 ? " " : " ");
      }
      //去掉末尾的空白
      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*( )+\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 = "
";
              domUtils.fillNode(me.document, pre.firstChild);
            }
          }
          //                        }
          preventAndSave();
        }
      }
    }
    if (keyCode == 8) {
      //修中ie中li下的问题
      range = me.selection.getRange();
      if (range.collapsed && domUtils.isStartInblock(range)) {
        tmpRange = range.cloneRange().trimBoundary();
        li = domUtils.findParentByTagName(range.startContainer, "li", true);
        //要在li的最左边,才能处理
        if (li && domUtils.isStartInblock(tmpRange)) {
          start = domUtils.findParentByTagName(range.startContainer, "p", true);
          if (start && start !== li.firstChild) {
            var parentList = domUtils.findParentByTagName(start, ["ol", "ul"]);
            domUtils.breakParent(start, parentList);
            clearEmptySibling(start);
            me.fireEvent("contentchange");
            range.setStart(start, 0).setCursor(false, true);
            me.fireEvent("saveScene");
            domUtils.preventDefault(evt);
            return;
          }
          if (li && (pre = li.previousSibling)) {
            if (keyCode == 46 && li.childNodes.length) {
              return;
            }
            //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
            if (dtd.$list[pre.tagName]) {
              pre = pre.lastChild;
            }
            me.undoManger && me.undoManger.save();
            first = li.firstChild;
            if (domUtils.isBlockElm(first)) {
              if (domUtils.isEmptyNode(first)) {
                //                                    range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
                pre.appendChild(first);
                range.setStart(first, 0).setCursor(false, true);
                //first不是唯一的节点
                while (li.firstChild) {
                  pre.appendChild(li.firstChild);
                }
              } else {
                span = me.document.createElement("span");
                range.insertNode(span);
                //判断pre是否是空的节点,如果是
类型的空节点,干掉p标签防止它占位
                if (domUtils.isEmptyBlock(pre)) {
                  pre.innerHTML = "";
                }
                domUtils.moveChild(li, pre);
                range.setStartBefore(span).collapse(true).select(true);
                domUtils.remove(span);
              }
            } else {
              if (domUtils.isEmptyNode(li)) {
                var p = me.document.createElement("p");
                pre.appendChild(p);
                range.setStart(p, 0).setCursor();
                //                                    range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
              } else {
                range
                  .setEnd(pre, pre.childNodes.length)
                  .collapse()
                  .select(true);
                while (li.firstChild) {
                  pre.appendChild(li.firstChild);
                }
              }
            }
            domUtils.remove(li);
            me.fireEvent("contentchange");
            me.fireEvent("saveScene");
            domUtils.preventDefault(evt);
            return;
          }
          //trace:980
          if (li && !li.previousSibling) {
            var parentList = li.parentNode;
            var bk = range.createBookmark();
            if (domUtils.isTagNode(parentList.parentNode, "ol ul")) {
              parentList.parentNode.insertBefore(li, parentList);
              if (domUtils.isEmptyNode(parentList)) {
                domUtils.remove(parentList);
              }
            } else {
              while (li.firstChild) {
                parentList.parentNode.insertBefore(li.firstChild, parentList);
              }
              domUtils.remove(li);
              if (domUtils.isEmptyNode(parentList)) {
                domUtils.remove(parentList);
              }
            }
            range.moveToBookmark(bk).setCursor(false, true);
            me.fireEvent("contentchange");
            me.fireEvent("saveScene");
            domUtils.preventDefault(evt);
            return;
          }
        }
      }
    }
  });
  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(/ /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() ||
              "" + (browser.ie ? "" : " ") + "
"
            );
          };
           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() ||
            "" + (browser.ie ? "" : " ") + "
";
          //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
          cont = cont.replace(
            new RegExp("[\\r\\t\\n ]*?(\\w+)\\s*(?:[^>]*)>", "g"),
            function(a, b) {
              if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
                return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, "");
              }
              return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, "");
            }
          );
          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 = "" + (browser.ie ? "" : " ") + "
";
            first = me.body.firstChild;
          }
          //要在ifm为显示时ff才能取到selection,否则报错
          //这里不能比较位置了
          me.undoManger && me.undoManger.save(true);
          if (browser.gecko) {
            var input = document.createElement("input");
            input.style.cssText = "position:absolute;left:0;top:-32768px";
            document.body.appendChild(input);
            me.body.contentEditable = false;
            setTimeout(function() {
              domUtils.setViewportOffset(input, { left: -32768, top: 0 });
              input.focus();
              setTimeout(function() {
                me.body.contentEditable = true;
                me.selection.getRange().moveToAddress(bakAddress).select(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, "");
              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, "
");
            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] 
      if (rng.endContainer && rng.endContainer.nodeType == 1) {
        tmpNode = rng.endContainer.childNodes[rng.endOffset];
        if (tmpNode && domUtils.isBr(tmpNode)) {
          rng.setEndAfter(tmpNode);
        }
      }
      if (rng.startOffset == 0) {
        tmpNode = rng.startContainer;
        if (domUtils.isBoundaryNode(tmpNode, "firstChild")) {
          tmpNode = rng.endContainer;
          if (
            rng.endOffset ==
              (tmpNode.nodeType == 3
                ? tmpNode.nodeValue.length
                : tmpNode.childNodes.length) &&
            domUtils.isBoundaryNode(tmpNode, "lastChild")
          ) {
            me.fireEvent("saveScene");
            me.body.innerHTML = "
" + (browser.ie ? "" : " ") + "
";
            rng.setStart(me.body.firstChild, 0).setCursor(false, true);
            me._selectionChange();
            return;
          }
        }
      }
    }
    //处理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 || " ";
        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 : " "
          });
          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(
            ' '
          );
        }
        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 =
          " ';
        break;
      case "embed":
        str =
          '';
        break;
      case "video":
        var ext = url.substr(url.lastIndexOf(".") + 1);
        if (ext == "ogv") ext = "ogg";
        str =
          "' +
          ' ';
        break;
    }
    return str;
  }
  function switchImgAndVideo(root, img2video) {
    utils.each(
      root.getNodesByTagName(img2video ? "img" : "embed video"),
      function(node) {
        var className = node.getAttr("class");
        if (className && className.indexOf("edui-faked-video") != -1) {
          var html = creatInsertStr(
            img2video ? node.getAttr("_url") : node.getAttr("src"),
            node.getAttr("width"),
            node.getAttr("height"),
            null,
            node.getStyle("float") || "",
            className,
            img2video ? "embed" : "image"
          );
          node.parentNode.replaceChild(UE.uNode.createElement(html), node);
        }
        if (className && className.indexOf("edui-upload-video") != -1) {
          var html = creatInsertStr(
            img2video ? node.getAttr("_url") : node.getAttr("src"),
            node.getAttr("width"),
            node.getAttr("height"),
            null,
            node.getStyle("float") || "",
            className,
            img2video ? "video" : "image"
          );
          node.parentNode.replaceChild(UE.uNode.createElement(html), node);
        }
      }
    );
  }
  me.addOutputRule(function(root) {
    switchImgAndVideo(root, true);
  });
  me.addInputRule(function(root) {
    switchImgAndVideo(root);
  });
  /**
     * 插入视频
     * @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 : " ");
    },
    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("");
          for (var c = 0; c < colsNum; c++) {
            html.push(
              '' +
                (browser.ie && browser.version < 11
                  ? domUtils.fillChar
                  : " ") +
                " "
            );
          }
          html.push(" ");
        }
        //禁止指定table-width
        return "";
      }
      if (!opt) {
        opt = utils.extend(
          {},
          {
            numCols: this.options.defaultCols,
            numRows: this.options.defaultRows,
            tdvalign: this.options.tdvalign
          }
        );
      }
      var me = this;
      var range = this.selection.getRange(),
        start = range.startContainer,
        firstParentBlock =
          domUtils.findParent(
            start,
            function(node) {
              return domUtils.isBlockElm(node);
            },
            true
          ) || me.body;
      var defaultValue = getDefaultValue(me),
        tableWidth = firstParentBlock.offsetWidth,
        tdWidth = Math.floor(
          tableWidth / opt.numCols -
            defaultValue.tdPadding * 2 -
            defaultValue.tdBorder
        );
      //todo其他属性
      !opt.tdvalign && (opt.tdvalign = me.options.tdvalign);
      me.execCommand("inserthtml", createTable(opt, tdWidth));
    }
  };
  UE.commands["insertparagraphbeforetable"] = {
    queryCommandState: function() {
      return getTableItemsByRange(this).cell ? 0 : -1;
    },
    execCommand: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        var p = this.document.createElement("p");
        p.innerHTML = browser.ie ? " " : " ";
        table.parentNode.insertBefore(p, table);
        this.selection.getRange().setStart(p, 0).setCursor();
      }
    }
  };
  UE.commands["deletetable"] = {
    queryCommandState: function() {
      var rng = this.selection.getRange();
      return domUtils.findParentByTagName(rng.startContainer, "table", true)
        ? 0
        : -1;
    },
    execCommand: function(cmd, table) {
      var rng = this.selection.getRange();
      table =
        table ||
        domUtils.findParentByTagName(rng.startContainer, "table", true);
      if (table) {
        var next = table.nextSibling;
        if (!next) {
          next = domUtils.createElement(this.document, "p", {
            innerHTML: browser.ie ? domUtils.fillChar : " "
          });
          table.parentNode.insertBefore(next, table);
        }
        domUtils.remove(table);
        rng = this.selection.getRange();
        if (next.nodeType == 3) {
          rng.setStartBefore(next);
        } else {
          rng.setStart(next, 0);
        }
        rng.setCursor(false, true);
        this.fireEvent("tablehasdeleted");
      }
    }
  };
  UE.commands["cellalign"] = {
    queryCommandState: function() {
      return getSelectedArr(this).length ? 0 : -1;
    },
    execCommand: function(cmd, align) {
      var selectedTds = getSelectedArr(this);
      if (selectedTds.length) {
        for (var i = 0, ci; (ci = selectedTds[i++]); ) {
          ci.setAttribute("align", align);
        }
      }
    }
  };
  UE.commands["cellvalign"] = {
    queryCommandState: function() {
      return getSelectedArr(this).length ? 0 : -1;
    },
    execCommand: function(cmd, valign) {
      var selectedTds = getSelectedArr(this);
      if (selectedTds.length) {
        for (var i = 0, ci; (ci = selectedTds[i++]); ) {
          ci.setAttribute("vAlign", valign);
        }
      }
    }
  };
  UE.commands["insertcaption"] = {
    queryCommandState: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        return table.getElementsByTagName("caption").length == 0 ? 1 : -1;
      }
      return -1;
    },
    execCommand: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        var caption = this.document.createElement("caption");
        caption.innerHTML = browser.ie ? domUtils.fillChar : " ";
        table.insertBefore(caption, table.firstChild);
        var range = this.selection.getRange();
        range.setStart(caption, 0).setCursor();
      }
    }
  };
  UE.commands["deletecaption"] = {
    queryCommandState: function() {
      var rng = this.selection.getRange(),
        table = domUtils.findParentByTagName(rng.startContainer, "table");
      if (table) {
        return table.getElementsByTagName("caption").length == 0 ? -1 : 1;
      }
      return -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        table = domUtils.findParentByTagName(rng.startContainer, "table");
      if (table) {
        domUtils.remove(table.getElementsByTagName("caption")[0]);
        var range = this.selection.getRange();
        range.setStart(table.rows[0].cells[0], 0).setCursor();
      }
    }
  };
  UE.commands["inserttitle"] = {
    queryCommandState: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        var firstRow = table.rows[0];
        return firstRow.cells[
          firstRow.cells.length - 1
        ].tagName.toLowerCase() != "th"
          ? 0
          : -1;
      }
      return -1;
    },
    execCommand: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        getUETable(table).insertRow(0, "th");
      }
      var th = table.getElementsByTagName("th")[0];
      this.selection.getRange().setStart(th, 0).setCursor(false, true);
    }
  };
  UE.commands["deletetitle"] = {
    queryCommandState: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        var firstRow = table.rows[0];
        return firstRow.cells[
          firstRow.cells.length - 1
        ].tagName.toLowerCase() == "th"
          ? 0
          : -1;
      }
      return -1;
    },
    execCommand: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        domUtils.remove(table.rows[0]);
      }
      var td = table.getElementsByTagName("td")[0];
      this.selection.getRange().setStart(td, 0).setCursor(false, true);
    }
  };
  UE.commands["inserttitlecol"] = {
    queryCommandState: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        var lastRow = table.rows[table.rows.length - 1];
        return lastRow.getElementsByTagName("th").length ? -1 : 0;
      }
      return -1;
    },
    execCommand: function(cmd) {
      var table = getTableItemsByRange(this).table;
      if (table) {
        getUETable(table).insertCol(0, "th");
      }
      resetTdWidth(table, this);
      var th = table.getElementsByTagName("th")[0];
      this.selection.getRange().setStart(th, 0).setCursor(false, true);
    }
  };
  UE.commands["deletetitlecol"] = {
    queryCommandState: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        var lastRow = table.rows[table.rows.length - 1];
        return lastRow.getElementsByTagName("th").length ? 0 : -1;
      }
      return -1;
    },
    execCommand: function() {
      var table = getTableItemsByRange(this).table;
      if (table) {
        for (var i = 0; i < table.rows.length; i++) {
          domUtils.remove(table.rows[i].children[0]);
        }
      }
      resetTdWidth(table, this);
      var td = table.getElementsByTagName("td")[0];
      this.selection.getRange().setStart(td, 0).setCursor(false, true);
    }
  };
  UE.commands["mergeright"] = {
    queryCommandState: function(cmd) {
      var tableItems = getTableItemsByRange(this),
        table = tableItems.table,
        cell = tableItems.cell;
      if (!table || !cell) return -1;
      var ut = getUETable(table);
      if (ut.selectedTds.length) return -1;
      var cellInfo = ut.getCellInfo(cell),
        rightColIndex = cellInfo.colIndex + cellInfo.colSpan;
      if (rightColIndex >= ut.colsNum) return -1; // 如果处于最右边则不能向右合并
      var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
        rightCell =
          table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex];
      if (!rightCell || cell.tagName != rightCell.tagName) return -1; // TH和TD不能相互合并
      // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
      return rightCellInfo.rowIndex == cellInfo.rowIndex &&
        rightCellInfo.rowSpan == cellInfo.rowSpan
        ? 0
        : -1;
    },
    execCommand: function(cmd) {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell);
      ut.mergeRight(cell);
      rng.moveToBookmark(bk).select();
    }
  };
  UE.commands["mergedown"] = {
    queryCommandState: function(cmd) {
      var tableItems = getTableItemsByRange(this),
        table = tableItems.table,
        cell = tableItems.cell;
      if (!table || !cell) return -1;
      var ut = getUETable(table);
      if (ut.selectedTds.length) return -1;
      var cellInfo = ut.getCellInfo(cell),
        downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan;
      if (downRowIndex >= ut.rowsNum) return -1; // 如果处于最下边则不能向下合并
      var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
        downCell =
          table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex];
      if (!downCell || cell.tagName != downCell.tagName) return -1; // TH和TD不能相互合并
      // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
      return downCellInfo.colIndex == cellInfo.colIndex &&
        downCellInfo.colSpan == cellInfo.colSpan
        ? 0
        : -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell);
      ut.mergeDown(cell);
      rng.moveToBookmark(bk).select();
    }
  };
  UE.commands["mergecells"] = {
    queryCommandState: function() {
      return getUETableBySelected(this) ? 0 : -1;
    },
    execCommand: function() {
      var ut = getUETableBySelected(this);
      if (ut && ut.selectedTds.length) {
        var cell = ut.selectedTds[0];
        ut.mergeRange();
        var rng = this.selection.getRange();
        if (domUtils.isEmptyBlock(cell)) {
          rng.setStart(cell, 0).collapse(true);
        } else {
          rng.selectNodeContents(cell);
        }
        rng.select();
      }
    }
  };
  UE.commands["insertrow"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell;
      return cell &&
        (cell.tagName == "TD" ||
          (cell.tagName == "TH" &&
            tableItems.tr !== tableItems.table.rows[0])) &&
        getUETable(tableItems.table).rowsNum < this.options.maxRowNum
        ? 0
        : -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell,
        table = tableItems.table,
        ut = getUETable(table),
        cellInfo = ut.getCellInfo(cell);
      //ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
      if (!ut.selectedTds.length) {
        ut.insertRow(cellInfo.rowIndex, cell);
      } else {
        var range = ut.cellsRange;
        for (
          var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
          i < len;
          i++
        ) {
          ut.insertRow(range.beginRowIndex, cell);
        }
      }
      rng.moveToBookmark(bk).select();
      if (table.getAttribute("interlaced") === "enabled")
        this.fireEvent("interlacetable", table);
    }
  };
  //后插入行
  UE.commands["insertrownext"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell;
      return cell &&
        cell.tagName == "TD" &&
        getUETable(tableItems.table).rowsNum < this.options.maxRowNum
        ? 0
        : -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell,
        table = tableItems.table,
        ut = getUETable(table),
        cellInfo = ut.getCellInfo(cell);
      //ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
      if (!ut.selectedTds.length) {
        ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell);
      } else {
        var range = ut.cellsRange;
        for (
          var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
          i < len;
          i++
        ) {
          ut.insertRow(range.endRowIndex + 1, cell);
        }
      }
      rng.moveToBookmark(bk).select();
      if (table.getAttribute("interlaced") === "enabled")
        this.fireEvent("interlacetable", table);
    }
  };
  UE.commands["deleterow"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this);
      return tableItems.cell ? 0 : -1;
    },
    execCommand: function() {
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell),
        cellsRange = ut.cellsRange,
        cellInfo = ut.getCellInfo(cell),
        preCell = ut.getVSideCell(cell),
        nextCell = ut.getVSideCell(cell, true),
        rng = this.selection.getRange();
      if (utils.isEmptyObject(cellsRange)) {
        ut.deleteRow(cellInfo.rowIndex);
      } else {
        for (
          var i = cellsRange.beginRowIndex;
          i < cellsRange.endRowIndex + 1;
          i++
        ) {
          ut.deleteRow(cellsRange.beginRowIndex);
        }
      }
      var table = ut.table;
      if (!table.getElementsByTagName("td").length) {
        var nextSibling = table.nextSibling;
        domUtils.remove(table);
        if (nextSibling) {
          rng.setStart(nextSibling, 0).setCursor(false, true);
        }
      } else {
        if (
          cellInfo.rowSpan == 1 ||
          cellInfo.rowSpan ==
            cellsRange.endRowIndex - cellsRange.beginRowIndex + 1
        ) {
          if (nextCell || preCell)
            rng.selectNodeContents(nextCell || preCell).setCursor(false, true);
        } else {
          var newCell = ut.getCell(
            cellInfo.rowIndex,
            ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex
          );
          if (newCell) rng.selectNodeContents(newCell).setCursor(false, true);
        }
      }
      if (table.getAttribute("interlaced") === "enabled")
        this.fireEvent("interlacetable", table);
    }
  };
  UE.commands["insertcol"] = {
    queryCommandState: function(cmd) {
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell;
      return cell &&
        (cell.tagName == "TD" ||
          (cell.tagName == "TH" && cell !== tableItems.tr.cells[0])) &&
        getUETable(tableItems.table).colsNum < this.options.maxColNum
        ? 0
        : -1;
    },
    execCommand: function(cmd) {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      if (this.queryCommandState(cmd) == -1) return;
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell),
        cellInfo = ut.getCellInfo(cell);
      //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
      if (!ut.selectedTds.length) {
        ut.insertCol(cellInfo.colIndex, cell);
      } else {
        var range = ut.cellsRange;
        for (
          var i = 0, len = range.endColIndex - range.beginColIndex + 1;
          i < len;
          i++
        ) {
          ut.insertCol(range.beginColIndex, cell);
        }
      }
      rng.moveToBookmark(bk).select(true);
    }
  };
  UE.commands["insertcolnext"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell;
      return cell &&
        getUETable(tableItems.table).colsNum < this.options.maxColNum
        ? 0
        : -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell),
        cellInfo = ut.getCellInfo(cell);
      //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
      if (!ut.selectedTds.length) {
        ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell);
      } else {
        var range = ut.cellsRange;
        for (
          var i = 0, len = range.endColIndex - range.beginColIndex + 1;
          i < len;
          i++
        ) {
          ut.insertCol(range.endColIndex + 1, cell);
        }
      }
      rng.moveToBookmark(bk).select();
    }
  };
  UE.commands["deletecol"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this);
      return tableItems.cell ? 0 : -1;
    },
    execCommand: function() {
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell),
        range = ut.cellsRange,
        cellInfo = ut.getCellInfo(cell),
        preCell = ut.getHSideCell(cell),
        nextCell = ut.getHSideCell(cell, true);
      if (utils.isEmptyObject(range)) {
        ut.deleteCol(cellInfo.colIndex);
      } else {
        for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
          ut.deleteCol(range.beginColIndex);
        }
      }
      var table = ut.table,
        rng = this.selection.getRange();
      if (!table.getElementsByTagName("td").length) {
        var nextSibling = table.nextSibling;
        domUtils.remove(table);
        if (nextSibling) {
          rng.setStart(nextSibling, 0).setCursor(false, true);
        }
      } else {
        if (domUtils.inDoc(cell, this.document)) {
          rng.setStart(cell, 0).setCursor(false, true);
        } else {
          if (nextCell && domUtils.inDoc(nextCell, this.document)) {
            rng.selectNodeContents(nextCell).setCursor(false, true);
          } else {
            if (preCell && domUtils.inDoc(preCell, this.document)) {
              rng.selectNodeContents(preCell).setCursor(true, true);
            }
          }
        }
      }
    }
  };
  UE.commands["splittocells"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell;
      if (!cell) return -1;
      var ut = getUETable(tableItems.table);
      if (ut.selectedTds.length > 0) return -1;
      return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell);
      ut.splitToCells(cell);
      rng.moveToBookmark(bk).select();
    }
  };
  UE.commands["splittorows"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell;
      if (!cell) return -1;
      var ut = getUETable(tableItems.table);
      if (ut.selectedTds.length > 0) return -1;
      return cell && cell.rowSpan > 1 ? 0 : -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell);
      ut.splitToRows(cell);
      rng.moveToBookmark(bk).select();
    }
  };
  UE.commands["splittocols"] = {
    queryCommandState: function() {
      var tableItems = getTableItemsByRange(this),
        cell = tableItems.cell;
      if (!cell) return -1;
      var ut = getUETable(tableItems.table);
      if (ut.selectedTds.length > 0) return -1;
      return cell && cell.colSpan > 1 ? 0 : -1;
    },
    execCommand: function() {
      var rng = this.selection.getRange(),
        bk = rng.createBookmark(true);
      var cell = getTableItemsByRange(this).cell,
        ut = getUETable(cell);
      ut.splitToCols(cell);
      rng.moveToBookmark(bk).select();
    }
  };
  UE.commands["adaptbytext"] = UE.commands["adaptbywindow"] = {
    queryCommandState: function() {
      return getTableItemsByRange(this).table ? 0 : -1;
    },
    execCommand: function(cmd) {
      var tableItems = getTableItemsByRange(this),
        table = tableItems.table;
      if (table) {
        if (cmd == "adaptbywindow") {
          resetTdWidth(table, this);
        } else {
          var cells = domUtils.getElementsByTagName(table, "td th");
          utils.each(cells, function(cell) {
            cell.removeAttribute("width");
          });
          table.removeAttribute("width");
        }
      }
    }
  };
  //平均分配各列
  UE.commands["averagedistributecol"] = {
    queryCommandState: function() {
      var ut = getUETableBySelected(this);
      if (!ut) return -1;
      return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
    },
    execCommand: function(cmd) {
      var me = this,
        ut = getUETableBySelected(me);
      function getAverageWidth() {
        var tb = ut.table,
          averageWidth,
          sumWidth = 0,
          colsNum = 0,
          tbAttr = getDefaultValue(me, tb);
        if (ut.isFullRow()) {
          sumWidth = tb.offsetWidth;
          colsNum = ut.colsNum;
        } else {
          var begin = ut.cellsRange.beginColIndex,
            end = ut.cellsRange.endColIndex,
            node;
          for (var i = begin; i <= end; ) {
            node = ut.selectedTds[i];
            sumWidth += node.offsetWidth;
            i += node.colSpan;
            colsNum += 1;
          }
        }
        averageWidth =
          Math.ceil(sumWidth / colsNum) -
          tbAttr.tdBorder * 2 -
          tbAttr.tdPadding * 2;
        return averageWidth;
      }
      function setAverageWidth(averageWidth) {
        utils.each(domUtils.getElementsByTagName(ut.table, "th"), function(
          node
        ) {
          node.setAttribute("width", "");
        });
        var cells = ut.isFullRow()
          ? domUtils.getElementsByTagName(ut.table, "td")
          : ut.selectedTds;
        utils.each(cells, function(node) {
          if (node.colSpan == 1) {
            node.setAttribute("width", averageWidth);
          }
        });
      }
      if (ut && ut.selectedTds.length) {
        setAverageWidth(getAverageWidth());
      }
    }
  };
  //平均分配各行
  UE.commands["averagedistributerow"] = {
    queryCommandState: function() {
      var ut = getUETableBySelected(this);
      if (!ut) return -1;
      if (ut.selectedTds && /th/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";
      });
    }
  };
  function resetTdWidth(table, editor) {
    var tds = domUtils.getElementsByTagName(table, "td th");
    utils.each(tds, function(td) {
      td.removeAttribute("width");
    });
    table.setAttribute(
      "width",
      getTableWidth(editor, true, getDefaultValue(editor, table))
    );
    var tdsWidths = [];
    setTimeout(function() {
      utils.each(tds, function(td) {
        td.colSpan == 1 && tdsWidths.push(td.offsetWidth);
      });
      utils.each(tds, function(td, i) {
        td.colSpan == 1 && td.setAttribute("width", tdsWidths[i] + "");
      });
    }, 0);
  }
  function getTableWidth(editor, needIEHack, defaultValue) {
    var body = editor.body;
    return (
      body.offsetWidth -
      (needIEHack
        ? parseInt(domUtils.getComputedStyle(body, "margin-left"), 10) * 2
        : 0) -
      defaultValue.tableBorder * 2 -
      (editor.options.offsetWidth || 0)
    );
  }
  function getSelectedArr(editor) {
    var cell = getTableItemsByRange(editor).cell;
    if (cell) {
      var ut = getUETable(cell);
      return ut.selectedTds.length ? ut.selectedTds : [cell];
    } else {
      return [];
    }
  }
})();
// plugins/table.action.js
/**
 * Created with JetBrains PhpStorm.
 * User: taoqili
 * Date: 12-10-12
 * Time: 上午10:05
 * To change this template use File | Settings | File Templates.
 */
UE.plugins["table"] = function() {
  var me = this,
    tabTimer = null,
    //拖动计时器
    tableDragTimer = null,
    //双击计时器
    tableResizeTimer = null,
    //单元格最小宽度
    cellMinWidth = 5,
    isInResizeBuffer = false,
    //单元格边框大小
    cellBorderWidth = 5,
    //鼠标偏移距离
    offsetOfTableCell = 10,
    //记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
    singleClickState = 0,
    userActionStatus = null,
    //双击允许的时间范围
    dblclickTime = 360,
    UT = UE.UETable,
    getUETable = function(tdOrTable) {
      return UT.getUETable(tdOrTable);
    },
    getUETableBySelected = function(editor) {
      return UT.getUETableBySelected(editor);
    },
    getDefaultValue = function(editor, table) {
      return UT.getDefaultValue(editor, table);
    },
    removeSelectedClass = function(cells) {
      return UT.removeSelectedClass(cells);
    };
  function showError(e) {
    //        throw e;
  }
  me.ready(function() {
    var me = this;
    var orgGetText = me.selection.getText;
    me.selection.getText = function() {
      var table = getUETableBySelected(me);
      if (table) {
        var str = "";
        utils.each(table.selectedTds, function(td) {
          str += td[browser.ie ? "innerText" : "textContent"];
        });
        return str;
      } else {
        return orgGetText.call(me.selection);
      }
    };
  });
  //处理拖动及框选相关方法
  var startTd = null, //鼠标按下时的锚点td
    currentTd = null, //当前鼠标经过时的td
    onDrag = "", //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
    onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
    dragButton = null,
    dragOver = false,
    dragLine = null, //模拟的拖动线
    dragTd = null; //发生拖动的目标td
  var mousedown = false,
    //todo 判断混乱模式
    needIEHack = true;
  me.setOpt({
    maxColNum: 20,
    maxRowNum: 100,
    defaultCols: 5,
    defaultRows: 5,
    tdvalign: "top",
    cursorpath: me.options.UEDITOR_HOME_URL + "themes/default/images/cursor_",
    tableDragable: false,
    classList: [
      "ue-table-interlace-color-single",
      "ue-table-interlace-color-double"
    ]
  });
  me.getUETable = getUETable;
  var commands = {
    deletetable: 1,
    inserttable: 1,
    cellvalign: 1,
    insertcaption: 1,
    deletecaption: 1,
    inserttitle: 1,
    deletetitle: 1,
    mergeright: 1,
    mergedown: 1,
    mergecells: 1,
    insertrow: 1,
    insertrownext: 1,
    deleterow: 1,
    insertcol: 1,
    insertcolnext: 1,
    deletecol: 1,
    splittocells: 1,
    splittorows: 1,
    splittocols: 1,
    adaptbytext: 1,
    adaptbywindow: 1,
    adaptbycustomer: 1,
    insertparagraph: 1,
    insertparagraphbeforetable: 1,
    averagedistributecol: 1,
    averagedistributerow: 1
  };
  me.ready(function() {
    utils.cssRule(
      "table",
      //选中的td上的样式
      ".selectTdClass{background-color:#edf5fa !important}" +
        "table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}" +
        //插入的表格的默认样式
        "table{margin-bottom:10px;border-collapse:collapse;display:table;}" +
        "td,th{padding: 5px 10px;border: 1px solid #DDD;}" +
        "caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}" +
        "th{border-top:1px solid #BBB;background-color:#F7F7F7;}" +
        "table tr.firstRow th{border-top-width:2px;}" +
        ".ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }" +
        "td p{margin:0;padding:0;}",
      me.document
    );
    var tableCopyList, isFullCol, isFullRow;
    //注册del/backspace事件
    me.addListener("keydown", function(cmd, evt) {
      var me = this;
      var keyCode = evt.keyCode || evt.which;
      if (keyCode == 8) {
        var ut = getUETableBySelected(me);
        if (ut && ut.selectedTds.length) {
          if (ut.isFullCol()) {
            me.execCommand("deletecol");
          } else if (ut.isFullRow()) {
            me.execCommand("deleterow");
          } else {
            me.fireEvent("delcells");
          }
          domUtils.preventDefault(evt);
        }
        var caption = domUtils.findParentByTagName(
          me.selection.getStart(),
          "caption",
          true
        ),
          range = me.selection.getRange();
        if (range.collapsed && caption && isEmptyBlock(caption)) {
          me.fireEvent("saveScene");
          var table = caption.parentNode;
          domUtils.remove(caption);
          if (table) {
            range.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
          }
          me.fireEvent("saveScene");
        }
      }
      if (keyCode == 46) {
        ut = getUETableBySelected(me);
        if (ut) {
          me.fireEvent("saveScene");
          for (var i = 0, ci; (ci = ut.selectedTds[i++]); ) {
            domUtils.fillNode(me.document, ci);
          }
          me.fireEvent("saveScene");
          domUtils.preventDefault(evt);
        }
      }
      if (keyCode == 13) {
        var rng = me.selection.getRange(),
          caption = domUtils.findParentByTagName(
            rng.startContainer,
            "caption",
            true
          );
        if (caption) {
          var table = domUtils.findParentByTagName(caption, "table");
          if (!rng.collapsed) {
            rng.deleteContents();
            me.fireEvent("saveScene");
          } else {
            if (caption) {
              rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
            }
          }
          domUtils.preventDefault(evt);
          return;
        }
        if (rng.collapsed) {
          var table = domUtils.findParentByTagName(rng.startContainer, "table");
          if (table) {
            var cell = table.rows[0].cells[0],
              start = domUtils.findParentByTagName(
                me.selection.getStart(),
                ["td", "th"],
                true
              ),
              preNode = table.previousSibling;
            if (
              cell === start &&
              (!preNode ||
                (preNode.nodeType == 1 && preNode.tagName == "TABLE")) &&
              domUtils.isStartInblock(rng)
            ) {
              var first = domUtils.findParent(
                me.selection.getStart(),
                function(n) {
                  return domUtils.isBlockElm(n);
                },
                true
              );
              if (
                first &&
                (/t(h|d)/i.test(first.tagName) || first === start.firstChild)
              ) {
                me.execCommand("insertparagraphbeforetable");
                domUtils.preventDefault(evt);
              }
            }
          }
        }
      }
      if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == "67") {
        tableCopyList = null;
        var ut = getUETableBySelected(me);
        if (ut) {
          var tds = ut.selectedTds;
          isFullCol = ut.isFullCol();
          isFullRow = ut.isFullRow();
          tableCopyList = [[ut.cloneCell(tds[0], null, true)]];
          for (var i = 1, ci; (ci = tds[i]); i++) {
            if (ci.parentNode !== tds[i - 1].parentNode) {
              tableCopyList.push([ut.cloneCell(ci, null, true)]);
            } else {
              tableCopyList[tableCopyList.length - 1].push(
                ut.cloneCell(ci, null, true)
              );
            }
          }
        }
      }
    });
    me.addListener("tablehasdeleted", function() {
      toggleDraggableState(this, false, "", null);
      if (dragButton) domUtils.remove(dragButton);
    });
    me.addListener("beforepaste", function(cmd, html) {
      var me = this;
      var rng = me.selection.getRange();
      if (domUtils.findParentByTagName(rng.startContainer, "caption", true)) {
        var div = me.document.createElement("div");
        div.innerHTML = html.html;
        //trace:3729
        html.html = div[browser.ie9below ? "innerText" : "textContent"];
        return;
      }
      var table = getUETableBySelected(me);
      if (tableCopyList) {
        me.fireEvent("saveScene");
        var rng = me.selection.getRange();
        var td = domUtils.findParentByTagName(
          rng.startContainer,
          ["td", "th"],
          true
        ),
          tmpNode,
          preNode;
        if (td) {
          var ut = getUETable(td);
          if (isFullRow) {
            var rowIndex = ut.getCellInfo(td).rowIndex;
            if (td.tagName == "TH") {
              rowIndex++;
            }
            for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
              var tr = ut.insertRow(rowIndex++, "td");
              for (var j = 0, cj; (cj = ci[j]); j++) {
                var cell = tr.cells[j];
                if (!cell) {
                  cell = tr.insertCell(j);
                }
                cell.innerHTML = cj.innerHTML;
                cj.getAttribute("width") &&
                  cell.setAttribute("width", cj.getAttribute("width"));
                cj.getAttribute("vAlign") &&
                  cell.setAttribute("vAlign", cj.getAttribute("vAlign"));
                cj.getAttribute("align") &&
                  cell.setAttribute("align", cj.getAttribute("align"));
                cj.style.cssText && (cell.style.cssText = cj.style.cssText);
              }
              for (var j = 0, cj; (cj = tr.cells[j]); j++) {
                if (!ci[j]) break;
                cj.innerHTML = ci[j].innerHTML;
                ci[j].getAttribute("width") &&
                  cj.setAttribute("width", ci[j].getAttribute("width"));
                ci[j].getAttribute("vAlign") &&
                  cj.setAttribute("vAlign", ci[j].getAttribute("vAlign"));
                ci[j].getAttribute("align") &&
                  cj.setAttribute("align", ci[j].getAttribute("align"));
                ci[j].style.cssText && (cj.style.cssText = ci[j].style.cssText);
              }
            }
          } else {
            if (isFullCol) {
              cellInfo = ut.getCellInfo(td);
              var maxColNum = 0;
              for (var j = 0, ci = tableCopyList[0], cj; (cj = ci[j++]); ) {
                maxColNum += cj.colSpan || 1;
              }
              me.__hasEnterExecCommand = true;
              for (i = 0; i < maxColNum; i++) {
                me.execCommand("insertcol");
              }
              me.__hasEnterExecCommand = false;
              td = ut.table.rows[0].cells[cellInfo.cellIndex];
              if (td.tagName == "TH") {
                td = ut.table.rows[1].cells[cellInfo.cellIndex];
              }
            }
            for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
              tmpNode = td;
              for (var j = 0, cj; (cj = ci[j++]); ) {
                if (td) {
                  td.innerHTML = cj.innerHTML;
                  //todo 定制处理
                  cj.getAttribute("width") &&
                    td.setAttribute("width", cj.getAttribute("width"));
                  cj.getAttribute("vAlign") &&
                    td.setAttribute("vAlign", cj.getAttribute("vAlign"));
                  cj.getAttribute("align") &&
                    td.setAttribute("align", cj.getAttribute("align"));
                  cj.style.cssText && (td.style.cssText = cj.style.cssText);
                  preNode = td;
                  td = td.nextSibling;
                } else {
                  var cloneTd = cj.cloneNode(true);
                  domUtils.removeAttributes(cloneTd, [
                    "class",
                    "rowSpan",
                    "colSpan"
                  ]);
                  preNode.parentNode.appendChild(cloneTd);
                }
              }
              td = ut.getNextCell(tmpNode, true, true);
              if (!tableCopyList[i]) break;
              if (!td) {
                var cellInfo = ut.getCellInfo(tmpNode);
                ut.table.insertRow(ut.table.rows.length);
                ut.update();
                td = ut.getVSideCell(tmpNode, true);
              }
            }
          }
          ut.update();
        } else {
          table = me.document.createElement("table");
          for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
            var tr = table.insertRow(table.rows.length);
            for (var j = 0, cj; (cj = ci[j++]); ) {
              cloneTd = UT.cloneCell(cj, null, true);
              domUtils.removeAttributes(cloneTd, ["class"]);
              tr.appendChild(cloneTd);
            }
            if (j == 2 && cloneTd.rowSpan > 1) {
              cloneTd.rowSpan = 1;
            }
          }
          var defaultValue = getDefaultValue(me),
            width =
              me.body.offsetWidth -
              (needIEHack
                ? parseInt(
                    domUtils.getComputedStyle(me.body, "margin-left"),
                    10
                  ) * 2
                : 0) -
              defaultValue.tableBorder * 2 -
              (me.options.offsetWidth || 0);
          me.execCommand(
            "insertHTML",
            "" +
              table.innerHTML
                .replace(/>\s*<")
                .replace(/\bth\b/gi, "td") +
              "
"
          );
        }
        me.fireEvent("contentchange");
        me.fireEvent("saveScene");
        html.html = "";
        return true;
      } else {
        var div = me.document.createElement("div"),
          tables;
        div.innerHTML = html.html;
        tables = div.getElementsByTagName("table");
        if (domUtils.findParentByTagName(me.selection.getStart(), "table")) {
          utils.each(tables, function(t) {
            domUtils.remove(t);
          });
          if (
            domUtils.findParentByTagName(
              me.selection.getStart(),
              "caption",
              true
            )
          ) {
            div.innerHTML = div[browser.ie ? "innerText" : "textContent"];
          }
        } else {
          utils.each(tables, function(table) {
            removeStyleSize(table, true);
            domUtils.removeAttributes(table, ["style", "border"]);
            utils.each(domUtils.getElementsByTagName(table, "td"), function(
              td
            ) {
              if (isEmptyBlock(td)) {
                domUtils.fillNode(me.document, td);
              }
              removeStyleSize(td, true);
              //                            domUtils.removeAttributes(td, ['style'])
            });
          });
        }
        html.html = div.innerHTML;
      }
    });
    me.addListener("afterpaste", function() {
      utils.each(domUtils.getElementsByTagName(me.body, "table"), function(
        table
      ) {
        if (table.offsetWidth > me.body.offsetWidth) {
          var defaultValue = getDefaultValue(me, table);
          table.style.width =
            me.body.offsetWidth -
            (needIEHack
              ? parseInt(
                  domUtils.getComputedStyle(me.body, "margin-left"),
                  10
                ) * 2
              : 0) -
            defaultValue.tableBorder * 2 -
            (me.options.offsetWidth || 0) +
            "px";
        }
      });
    });
    me.addListener("blur", function() {
      tableCopyList = null;
    });
    var timer;
    me.addListener("keydown", function() {
      clearTimeout(timer);
      timer = setTimeout(function() {
        var rng = me.selection.getRange(),
          cell = domUtils.findParentByTagName(
            rng.startContainer,
            ["th", "td"],
            true
          );
        if (cell) {
          var table = cell.parentNode.parentNode.parentNode;
          if (table.offsetWidth > table.getAttribute("width")) {
            cell.style.wordBreak = "break-all";
          }
        }
      }, 100);
    });
    me.addListener("selectionchange", function() {
      toggleDraggableState(me, false, "", null);
    });
    //内容变化时触发索引更新
    //todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
    me.addListener("contentchange", function() {
      var me = this;
      //尽可能排除一些不需要更新的状况
      hideDragLine(me);
      if (getUETableBySelected(me)) return;
      var rng = me.selection.getRange();
      var start = rng.startContainer;
      start = domUtils.findParentByTagName(start, ["td", "th"], true);
      utils.each(domUtils.getElementsByTagName(me.document, "table"), function(
        table
      ) {
        if (me.fireEvent("excludetable", table) === true) return;
        table.ueTable = new UT(table);
        //trace:3742
        //                utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
        //
        //                    if (domUtils.isEmptyBlock(td) && td !== start) {
        //                        domUtils.fillNode(me.document, td);
        //                        if (browser.ie && browser.version == 6) {
        //                            td.innerHTML = ' '
        //                        }
        //                    }
        //                });
        //                utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
        //                    if (domUtils.isEmptyBlock(th) && th !== start) {
        //                        domUtils.fillNode(me.document, th);
        //                        if (browser.ie && browser.version == 6) {
        //                            th.innerHTML = ' '
        //                        }
        //                    }
        //                });
        table.onmouseover = function() {
          me.fireEvent("tablemouseover", table);
        };
        table.onmousemove = function() {
          me.fireEvent("tablemousemove", table);
          me.options.tableDragable && toggleDragButton(true, this, me);
          utils.defer(function() {
            me.fireEvent("contentchange", 50);
          }, true);
        };
        table.onmouseout = function() {
          me.fireEvent("tablemouseout", table);
          toggleDraggableState(me, false, "", null);
          hideDragLine(me);
        };
        table.onclick = function(evt) {
          evt = me.window.event || evt;
          var target = getParentTdOrTh(evt.target || evt.srcElement);
          if (!target) return;
          var ut = getUETable(target),
            table = ut.table,
            cellInfo = ut.getCellInfo(target),
            cellsRange,
            rng = me.selection.getRange();
          //                    if ("topLeft" == inPosition(table, mouseCoords(evt))) {
          //                        cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
          //                        ut.setSelected(cellsRange);
          //                        return;
          //                    }
          //                    if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
          //
          //                        return;
          //                    }
          if (inTableSide(table, target, evt, true)) {
            var endTdCol = ut.getCell(
              ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex,
              ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex
            );
            if (evt.shiftKey && ut.selectedTds.length) {
              if (ut.selectedTds[0] !== endTdCol) {
                cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol);
                ut.setSelected(cellsRange);
              } else {
                rng && rng.selectNodeContents(endTdCol).select();
              }
            } else {
              if (target !== endTdCol) {
                cellsRange = ut.getCellsRange(target, endTdCol);
                ut.setSelected(cellsRange);
              } else {
                rng && rng.selectNodeContents(endTdCol).select();
              }
            }
            return;
          }
          if (inTableSide(table, target, evt)) {
            var endTdRow = ut.getCell(
              ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex,
              ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex
            );
            if (evt.shiftKey && ut.selectedTds.length) {
              if (ut.selectedTds[0] !== endTdRow) {
                cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow);
                ut.setSelected(cellsRange);
              } else {
                rng && rng.selectNodeContents(endTdRow).select();
              }
            } else {
              if (target !== endTdRow) {
                cellsRange = ut.getCellsRange(target, endTdRow);
                ut.setSelected(cellsRange);
              } else {
                rng && rng.selectNodeContents(endTdRow).select();
              }
            }
          }
        };
      });
      switchBorderColor(me, true);
    });
    domUtils.on(me.document, "mousemove", mouseMoveEvent);
    domUtils.on(me.document, "mouseout", function(evt) {
      var target = evt.target || evt.srcElement;
      if (target.tagName == "TABLE") {
        toggleDraggableState(me, false, "", null);
      }
    });
    /**
         * 表格隔行变色
         */
    me.addListener("interlacetable", function(type, table, classList) {
      if (!table) return;
      var me = this,
        rows = table.rows,
        len = rows.length,
        getClass = function(list, index, repeat) {
          return list[index]
            ? list[index]
            : repeat ? list[index % list.length] : "";
        };
      for (var i = 0; i < 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 = " ";
          }
        });
    });
    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"
      );
      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 百度应用主页: http://app.baidu.com/ 
 * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
 * height=>应用容器高度,logo=>应用logo,url=>应用地址
 * @example
 * ```javascript
 * //editor是编辑器实例
 * //在编辑器里插入一个“植物大战僵尸”的APP
 * editor.execCommand( 'webapp' , {
 *     title: '植物大战僵尸',
 *     width: 560,
 *     height: 465,
 *     logo: '应用展示的图片',
 *     url: '百度应用的地址'
 * } );
 * ```
 */
//UE.plugins['webapp'] = function () {
//    var me = this;
//    function createInsertStr( obj, toIframe, addParagraph ) {
//        return !toIframe ?
//                (addParagraph ? '' : '') + ' ' +
//                        (addParagraph ? '
' : '')
//                :
//                '';
//    }
//
//    function switchImgAndIframe( img2frame ) {
//        var tmpdiv,
//                nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
//        for ( var i = 0, node; node = nodes[i++]; ) {
//            if ( node.className != "edui-faked-webapp" ){
//                continue;
//            }
//            tmpdiv = me.document.createElement( "div" );
//            tmpdiv.innerHTML = createInsertStr( img2frame ? {url:node.getAttribute( "_url" ), width:node.width, height:node.height,title:node.title,logo:node.style.backgroundImage.replace("url(","").replace(")","")} : {url:node.getAttribute( "src", 2 ),title:node.title, width:node.width, height:node.height,logo:node.getAttribute("logo_url")}, img2frame ? true : false,false );
//            node.parentNode.replaceChild( tmpdiv.firstChild, node );
//        }
//    }
//
//    me.addListener( "beforegetcontent", function () {
//        switchImgAndIframe( true );
//    } );
//    me.addListener( 'aftersetcontent', function () {
//        switchImgAndIframe( false );
//    } );
//    me.addListener( 'aftergetcontent', function ( cmdName ) {
//        if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
//            return;
//        }
//        switchImgAndIframe( false );
//    } );
//
//    me.commands['webapp'] = {
//        execCommand:function ( cmd, obj ) {
//            me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
//        }
//    };
//};
UE.plugin.register("webapp", function() {
  var me = this;
  function createInsertStr(obj, toEmbed) {
    return !toEmbed
      ? ' "
      : '';
  }
  return {
    outputRule: function(root) {
      utils.each(root.getNodesByTagName("img"), function(node) {
        var html;
        if (node.getAttr("class") == "edui-faked-webapp") {
          html = createInsertStr(
            {
              title: node.getAttr("title"),
              width: node.getAttr("width"),
              height: node.getAttr("height"),
              align: node.getAttr("align"),
              cssfloat: node.getStyle("float"),
              url: node.getAttr("_url"),
              logo: node.getAttr("_logo_url")
            },
            true
          );
          var embed = UE.uNode.createElement(html);
          node.parentNode.replaceChild(embed, node);
        }
      });
    },
    inputRule: function(root) {
      utils.each(root.getNodesByTagName("iframe"), function(node) {
        if (node.getAttr("class") == "edui-faked-webapp") {
          var img = UE.uNode.createElement(
            createInsertStr({
              title: node.getAttr("title"),
              width: node.getAttr("width"),
              height: node.getAttr("height"),
              align: node.getAttr("align"),
              cssfloat: node.getStyle("float"),
              url: node.getAttr("src"),
              logo: node.getAttr("logo_url")
            })
          );
          node.parentNode.replaceChild(img, node);
        }
      });
    },
    commands: {
      /**
             * 插入百度应用
             * @command webapp
             * @method execCommand
             * @remind 需要百度APPKey
             * @remind 百度应用主页: http://app.baidu.com/ 
             * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
             * height=>应用容器高度,logo=>应用logo,url=>应用地址
             * @example
             * ```javascript
             * //editor是编辑器实例
             * //在编辑器里插入一个“植物大战僵尸”的APP
             * editor.execCommand( 'webapp' , {
             *     title: '植物大战僵尸',
             *     width: 560,
             *     height: 465,
             *     logo: '应用展示的图片',
             *     url: '百度应用的地址'
             * } );
             * ```
             */
      webapp: {
        execCommand: function(cmd, obj) {
          var me = this,
            str = createInsertStr(
              utils.extend(obj, {
                align: "none"
              }),
              false
            );
          me.execCommand("inserthtml", str);
        },
        queryCommandState: function() {
          var me = this,
            img = me.selection.getRange().getClosedNode(),
            flag = img && img.className == "edui-faked-webapp";
          return flag ? 1 : 0;
        }
      }
    }
  };
});
// plugins/template.js
///import core
///import plugins\inserthtml.js
///import plugins\cleardoc.js
///commands 模板
///commandsName  template
///commandsTitle  模板
///commandsDialog  dialogs\template
UE.plugins["template"] = function() {
  UE.commands["template"] = {
    execCommand: function(cmd, obj) {
      obj.html && this.execCommand("inserthtml", obj.html);
    }
  };
  this.addListener("click", function(type, evt) {
    var el = evt.target || evt.srcElement,
      range = this.selection.getRange();
    var tnode = domUtils.findParent(
      el,
      function(node) {
        if (node.className && domUtils.hasClass(node, "ue_t")) {
          return node;
        }
      },
      true
    );
    tnode && range.selectNode(tnode).shrinkBoundary().select();
  });
  this.addListener("keydown", function(type, evt) {
    var range = this.selection.getRange();
    if (!range.collapsed) {
      if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
        var tnode = domUtils.findParent(
          range.startContainer,
          function(node) {
            if (node.className && domUtils.hasClass(node, "ue_t")) {
              return node;
            }
          },
          true
        );
        if (tnode) {
          domUtils.removeClasses(tnode, ["ue_t"]);
        }
      }
    }
  });
};
// plugins/music.js
/**
 * 插入音乐命令
 * @file
 */
UE.plugin.register("music", function() {
  var me = this;
  function creatInsertStr(url, width, height, align, cssfloat, toEmbed) {
    return !toEmbed
      ? " '
      : '';
  }
  return {
    outputRule: function(root) {
      utils.each(root.getNodesByTagName("img"), function(node) {
        var html;
        if (node.getAttr("class") == "edui-faked-music") {
          var cssfloat = node.getStyle("float");
          var align = node.getAttr("align");
          html = creatInsertStr(
            node.getAttr("_url"),
            node.getAttr("width"),
            node.getAttr("height"),
            align,
            cssfloat,
            true
          );
          var embed = UE.uNode.createElement(html);
          node.parentNode.replaceChild(embed, node);
        }
      });
    },
    inputRule: function(root) {
      utils.each(root.getNodesByTagName("embed"), function(node) {
        if (node.getAttr("class") == "edui-faked-music") {
          var cssfloat = node.getStyle("float");
          var align = node.getAttr("align");
          html = creatInsertStr(
            node.getAttr("src"),
            node.getAttr("width"),
            node.getAttr("height"),
            align,
            cssfloat,
            false
          );
          var img = UE.uNode.createElement(html);
          node.parentNode.replaceChild(img, node);
        }
      });
    },
    commands: {
      /**
             * 插入音乐
             * @command music
             * @method execCommand
             * @param { Object } musicOptions 插入音乐的参数项, 支持的key有: url=>音乐地址;
             * width=>音乐容器宽度;height=>音乐容器高度;align=>音乐文件的对齐方式, 可选值有: left, center, right, none
             * @example
             * ```javascript
             * //editor是编辑器实例
             * //在编辑器里插入一个“植物大战僵尸”的APP
             * editor.execCommand( 'music' , {
             *     width: 400,
             *     height: 95,
             *     align: "center",
             *     url: "音乐地址"
             * } );
             * ```
             */
      music: {
        execCommand: function(cmd, musicObj) {
          var me = this,
            str = creatInsertStr(
              musicObj.url,
              musicObj.width || 400,
              musicObj.height || 95,
              "none",
              false
            );
          me.execCommand("inserthtml", str);
        },
        queryCommandState: function() {
          var me = this,
            img = me.selection.getRange().getClosedNode(),
            flag = img && img.className == "edui-faked-music";
          return flag ? 1 : 0;
        }
      }
    }
  };
});
// plugins/autoupload.js
/**
 * @description
 * 1.拖放文件到编辑区域,自动上传并插入到选区
 * 2.插入粘贴板的图片,自动上传并插入到选区
 * @author Jinqn
 * @date 2013-10-14
 */
UE.plugin.register("autoupload", function() {
  function sendAndInsertFile(file, editor) {
    var me = editor;
    //模拟数据
    var fieldName,
      urlPrefix,
      maxSize,
      allowFiles,
      actionUrl,
      loadingHtml,
      errorHandler,
      successHandler,
      filetype = /image\/\w+/i.test(file.type) ? "image" : "file",
      loadingId = "loading_" + (+new Date()).toString(36);
    fieldName = me.getOpt(filetype + "FieldName");
    urlPrefix = me.getOpt(filetype + "UrlPrefix");
    maxSize = me.getOpt(filetype + "MaxSize");
    allowFiles = me.getOpt(filetype + "AllowFiles");
    actionUrl = me.getActionUrl(me.getOpt(filetype + "ActionName"));
    errorHandler = function(title) {
      var loader = me.document.getElementById(loadingId);
      loader && domUtils.remove(loader);
      me.fireEvent("showmessage", {
        id: loadingId,
        content: title,
        type: "error",
        timeout: 4000
      });
    };
    if (filetype == "image") {
      loadingHtml =
        ' ';
      successHandler = function(data) {
        var link = urlPrefix + data.url,
          loader = me.document.getElementById(loadingId);
        if (loader) {
          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 =
        "" +
        ' ' +
        "
";
      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) || "" + domUtils.fillHtml + "
";
            me.focus(true);
          }
        },
        queryCommandState: function() {
          return saveKey ? (me.getPreferences(saveKey) === null ? -1 : 0) : -1;
        },
        notNeedUndo: true,
        ignoreContentChange: true
      }
    }
  };
});
// plugins/charts.js
UE.plugin.register("charts", function() {
  var me = this;
  return {
    bindEvents: {
      chartserror: function() {}
    },
    commands: {
      charts: {
        execCommand: function(cmd, data) {
          var tableNode = domUtils.findParentByTagName(
            this.selection.getRange().startContainer,
            "table",
            true
          ),
            flagText = [],
            config = {};
          if (!tableNode) {
            return false;
          }
          if (!validData(tableNode)) {
            me.fireEvent("chartserror");
            return false;
          }
          config.title = data.title || "";
          config.subTitle = data.subTitle || "";
          config.xTitle = data.xTitle || "";
          config.yTitle = data.yTitle || "";
          config.suffix = data.suffix || "";
          config.tip = data.tip || "";
          //数据对齐方式
          config.dataFormat = data.tableDataFormat || "";
          //图表类型
          config.chartType = data.chartType || 0;
          for (var key in config) {
            if (!config.hasOwnProperty(key)) {
              continue;
            }
            flagText.push(key + ":" + config[key]);
          }
          tableNode.setAttribute("data-chart", flagText.join(";"));
          domUtils.addClass(tableNode, "edui-charts-table");
        },
        queryCommandState: function(cmd, name) {
          var tableNode = domUtils.findParentByTagName(
            this.selection.getRange().startContainer,
            "table",
            true
          );
          return tableNode && validData(tableNode) ? 0 : -1;
        }
      }
    },
    inputRule: function(root) {
      utils.each(root.getNodesByTagName("table"), function(tableNode) {
        if (tableNode.getAttr("data-chart") !== undefined) {
          tableNode.setAttr("style");
        }
      });
    },
    outputRule: function(root) {
      utils.each(root.getNodesByTagName("table"), function(tableNode) {
        if (tableNode.getAttr("data-chart") !== undefined) {
          tableNode.setAttr("style", "display: none;");
        }
      });
    }
  };
  function validData(table) {
    var firstRows = null,
      cellCount = 0;
    //行数不够
    if (table.rows.length < 2) {
      return false;
    }
    //列数不够
    if (table.rows[0].cells.length < 2) {
      return false;
    }
    //第一行所有cell必须是th
    firstRows = table.rows[0].cells;
    cellCount = firstRows.length;
    for (var i = 0, cell; (cell = firstRows[i]); i++) {
      if (cell.tagName.toLowerCase() !== "th") {
        return false;
      }
    }
    for (var i = 1, row; (row = table.rows[i]); i++) {
      //每行单元格数不匹配, 返回false
      if (row.cells.length != cellCount) {
        return false;
      }
      //第一列不是th也返回false
      if (row.cells[0].tagName.toLowerCase() !== "th") {
        return false;
      }
      for (var j = 1, cell; (cell = row.cells[j]); j++) {
        var value = utils.trim(cell.innerText || cell.textContent || "");
        value = value
          .replace(new RegExp(UE.dom.domUtils.fillChar, "g"), "")
          .replace(/^\s+|\s+$/g, "");
        //必须是数字
        if (!/^\d*\.?\d+$/.test(value)) {
          return false;
        }
      }
    }
    return true;
  }
});
// plugins/section.js
/**
 * 目录大纲支持插件
 * @file
 * @since 1.3.0
 */
UE.plugin.register("section", function() {
  /* 目录节点对象 */
  function Section(option) {
    this.tag = "";
    (this.level = -1), (this.dom = null);
    this.nextSection = null;
    this.previousSection = null;
    this.parentSection = null;
    this.startAddress = [];
    this.endAddress = [];
    this.children = [];
  }
  function getSection(option) {
    var section = new Section();
    return utils.extend(section, option);
  }
  function getNodeFromAddress(startAddress, root) {
    var current = root;
    for (var i = 0; i < startAddress.length; i++) {
      if (!current.childNodes) return null;
      current = current.childNodes[startAddress[i]];
    }
    return current;
  }
  var me = this;
  return {
    bindMultiEvents: {
      type: "aftersetcontent afterscencerestore",
      handler: function() {
        me.fireEvent("updateSections");
      }
    },
    bindEvents: {
      /* 初始化、拖拽、粘贴、执行setcontent之后 */
      ready: function() {
        me.fireEvent("updateSections");
        domUtils.on(me.body, "drop paste", function() {
          me.fireEvent("updateSections");
        });
      },
      /* 执行paragraph命令之后 */
      afterexeccommand: function(type, cmd) {
        if (cmd == "paragraph") {
          me.fireEvent("updateSections");
        }
      },
      /* 部分键盘操作,触发updateSections事件 */
      keyup: function(type, e) {
        var me = this,
          range = me.selection.getRange();
        if (range.collapsed != true) {
          me.fireEvent("updateSections");
        } else {
          var keyCode = e.keyCode || e.which;
          if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
            me.fireEvent("updateSections");
          }
        }
      }
    },
    commands: {
      getsections: {
        execCommand: function(cmd, levels) {
          var levelFn = levels || ["h1", "h2", "h3", "h4", "h5", "h6"];
          for (var i = 0; i < levelFn.length; i++) {
            if (typeof levelFn[i] == "string") {
              levelFn[i] = (function(fn) {
                return function(node) {
                  return node.tagName == fn.toUpperCase();
                };
              })(levelFn[i]);
            } else if (typeof levelFn[i] != "function") {
              levelFn[i] = function(node) {
                return null;
              };
            }
          }
          function getSectionLevel(node) {
            for (var i = 0; i < levelFn.length; i++) {
              if (levelFn[i](node)) return i;
            }
            return -1;
          }
          var me = this,
            Directory = getSection({ level: -1, title: "root" }),
            previous = Directory;
          function traversal(node, Directory) {
            var level,
              tmpSection = null,
              parent,
              child,
              children = node.childNodes;
            for (var i = 0, len = children.length; i < len; i++) {
              child = children[i];
              level = getSectionLevel(child);
              if (level >= 0) {
                var address = me.selection
                  .getRange()
                  .selectNode(child)
                  .createAddress(true).startAddress,
                  current = getSection({
                    tag: child.tagName,
                    title: child.innerText || child.textContent || "",
                    level: level,
                    dom: child,
                    startAddress: utils.clone(address, []),
                    endAddress: utils.clone(address, []),
                    children: []
                  });
                previous.nextSection = current;
                current.previousSection = previous;
                parent = previous;
                while (level <= parent.level) {
                  parent = parent.parentSection;
                }
                current.parentSection = parent;
                parent.children.push(current);
                tmpSection = previous = current;
              } else {
                child.nodeType === 1 && traversal(child, Directory);
                tmpSection &&
                  tmpSection.endAddress[tmpSection.endAddress.length - 1]++;
              }
            }
          }
          traversal(me.body, Directory);
          return Directory;
        },
        notNeedUndo: true
      },
      movesection: {
        execCommand: function(cmd, sourceSection, targetSection, isAfter) {
          var me = this,
            targetAddress,
            target;
          if (!sourceSection || !targetSection || targetSection.level == -1)
            return;
          targetAddress = isAfter
            ? targetSection.endAddress
            : targetSection.startAddress;
          target = getNodeFromAddress(targetAddress, me.body);
          /* 判断目标地址是否被源章节包含 */
          if (
            !targetAddress ||
            !target ||
            isContainsAddress(
              sourceSection.startAddress,
              sourceSection.endAddress,
              targetAddress
            )
          )
            return;
          var startNode = getNodeFromAddress(
            sourceSection.startAddress,
            me.body
          ),
            endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
            current,
            nextNode;
          if (isAfter) {
            current = endNode;
            while (
              current &&
              !(
                domUtils.getPosition(startNode, current) &
                domUtils.POSITION_FOLLOWING
              )
            ) {
              nextNode = current.previousSibling;
              domUtils.insertAfter(target, current);
              if (current == startNode) break;
              current = nextNode;
            }
          } else {
            current = startNode;
            while (
              current &&
              !(
                domUtils.getPosition(current, endNode) &
                domUtils.POSITION_FOLLOWING
              )
            ) {
              nextNode = current.nextSibling;
              target.parentNode.insertBefore(current, target);
              if (current == endNode) break;
              current = nextNode;
            }
          }
          me.fireEvent("updateSections");
          /* 获取地址的包含关系 */
          function isContainsAddress(startAddress, endAddress, addressTarget) {
            var isAfterStartAddress = false,
              isBeforeEndAddress = false;
            for (var i = 0; i < startAddress.length; i++) {
              if (i >= addressTarget.length) break;
              if (addressTarget[i] > startAddress[i]) {
                isAfterStartAddress = true;
                break;
              } else if (addressTarget[i] < startAddress[i]) {
                break;
              }
            }
            for (var i = 0; i < endAddress.length; i++) {
              if (i >= addressTarget.length) break;
              if (addressTarget[i] < startAddress[i]) {
                isBeforeEndAddress = true;
                break;
              } else if (addressTarget[i] > startAddress[i]) {
                break;
              }
            }
            return isAfterStartAddress && isBeforeEndAddress;
          }
        }
      },
      deletesection: {
        execCommand: function(cmd, section, keepChildren) {
          var me = this;
          if (!section) return;
          function getNodeFromAddress(startAddress) {
            var current = me.body;
            for (var i = 0; i < startAddress.length; i++) {
              if (!current.childNodes) return null;
              current = current.childNodes[startAddress[i]];
            }
            return current;
          }
          var startNode = getNodeFromAddress(section.startAddress),
            endNode = getNodeFromAddress(section.endAddress),
            current = startNode,
            nextNode;
          if (!keepChildren) {
            while (
              current &&
              domUtils.inDoc(endNode, me.document) &&
              !(
                domUtils.getPosition(current, endNode) &
                domUtils.POSITION_FOLLOWING
              )
            ) {
              nextNode = current.nextSibling;
              domUtils.remove(current);
              current = nextNode;
            }
          } else {
            domUtils.remove(current);
          }
          me.fireEvent("updateSections");
        }
      },
      selectsection: {
        execCommand: function(cmd, section) {
          if (!section && !section.dom) return false;
          var me = this,
            range = me.selection.getRange(),
            address = {
              startAddress: utils.clone(section.startAddress, []),
              endAddress: utils.clone(section.endAddress, [])
            };
          address.endAddress[address.endAddress.length - 1]++;
          range.moveToAddress(address).select().scrollToView();
          return true;
        },
        notNeedUndo: true
      },
      scrolltosection: {
        execCommand: function(cmd, section) {
          if (!section && !section.dom) return false;
          var me = this,
            range = me.selection.getRange(),
            address = {
              startAddress: section.startAddress,
              endAddress: section.endAddress
            };
          address.endAddress[address.endAddress.length - 1]++;
          range.moveToAddress(address).scrollToView();
          return true;
        },
        notNeedUndo: true
      }
    }
  };
});
// plugins/simpleupload.js
/**
 * @description
 * 简单上传:点击按钮,直接选择文件上传
 * @author Jinqn
 * @date 2014-03-31
 */
UE.plugin.register("simpleupload", function() {
  var me = this,
    isLoaded = false,
    containerBtn;
  function initUploadBtn() {
    var w = containerBtn.offsetWidth || 20,
      h = containerBtn.offsetHeight || 20,
      btnIframe = document.createElement("iframe"),
      btnStyle =
        "display:block;width:" +
        w +
        "px;height:" +
        h +
        "px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;";
    domUtils.on(btnIframe, "load", function() {
      var timestrap = (+new Date()).toString(36),
        wrapper,
        btnIframeDoc,
        btnIframeBody;
      btnIframeDoc =
        btnIframe.contentDocument || btnIframe.contentWindow.document;
      btnIframeBody = btnIframeDoc.body;
      wrapper = btnIframeDoc.createElement("div");
      wrapper.innerHTML =
        '" +
        '';
      wrapper.className = "edui-" + me.options.theme;
      wrapper.id = me.ui.id + "_iframeupload";
      btnIframeBody.style.cssText = btnStyle;
      btnIframeBody.style.width = w + "px";
      btnIframeBody.style.height = h + "px";
      btnIframeBody.appendChild(wrapper);
      if (btnIframeBody.parentNode) {
        btnIframeBody.parentNode.style.width = w + "px";
        btnIframeBody.parentNode.style.height = w + "px";
      }
      var form = btnIframeDoc.getElementById("edui_form_" + timestrap);
      var input = btnIframeDoc.getElementById("edui_input_" + timestrap);
      var iframe = btnIframeDoc.getElementById("edui_iframe_" + timestrap);
      domUtils.on(input, "change", function() {
        if (!input.value) return;
        var loadingId = "loading_" + (+new Date()).toString(36);
        var params =
          utils.serializeParam(me.queryCommandValue("serverparam")) || "";
        var imageActionUrl = me.getActionUrl(me.getOpt("imageActionName"));
        var allowFiles = me.getOpt("imageAllowFiles");
        me.focus();
        me.execCommand(
          "inserthtml",
          ' '
        );
        function callback() {
          try {
            var link,
              json,
              loader,
              body = (iframe.contentDocument || iframe.contentWindow.document)
                .body,
              result = body.innerText || body.textContent || "";
            json = new Function("return " + result)();
            link = me.options.imageUrlPrefix + json.url;
            if (json.state == "SUCCESS" && json.url) {
              loader = me.document.getElementById(loadingId);
              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 +=
              '' +
              ' ' +
              '' +
              title +
              " " +
              "
";
          }
          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 '
';
    }
  };
  utils.inherits(Separator, UIBase);
})();
// ui/mask.js
///import core
///import uicore
;(function() {
  var utils = baidu.editor.utils,
    domUtils = baidu.editor.dom.domUtils,
    UIBase = baidu.editor.ui.UIBase,
    uiUtils = baidu.editor.ui.uiUtils;
  var Mask = (baidu.editor.ui.Mask = function(options) {
    this.initOptions(options);
    this.initUIBase();
  });
  Mask.prototype = {
    getHtmlTpl: function() {
      return '
';
    },
    postRender: function() {
      var me = this;
      domUtils.on(window, "resize", function() {
        setTimeout(function() {
          if (!me.isHidden()) {
            me._fill();
          }
        });
      });
    },
    show: function(zIndex) {
      this._fill();
      this.getDom().style.display = "";
      this.getDom().style.zIndex = zIndex;
    },
    hide: function() {
      this.getDom().style.display = "none";
      this.getDom().style.zIndex = "";
    },
    isHidden: function() {
      return this.getDom().style.display == "none";
    },
    _onMouseDown: function() {
      return false;
    },
    _onClick: function(e, target) {
      this.fireEvent("click", e, target);
    },
    _fill: function() {
      var el = this.getDom();
      var vpRect = uiUtils.getViewportRect();
      el.style.width = vpRect.width + "px";
      el.style.height = vpRect.height + "px";
    }
  };
  utils.inherits(Mask, UIBase);
})();
// ui/popup.js
///import core
///import uicore
;(function() {
  var utils = baidu.editor.utils,
    uiUtils = baidu.editor.ui.uiUtils,
    domUtils = baidu.editor.dom.domUtils,
    UIBase = baidu.editor.ui.UIBase,
    Popup = (baidu.editor.ui.Popup = function(options) {
      this.initOptions(options);
      this.initPopup();
    });
  var allPopups = [];
  function closeAllPopup(evt, el) {
    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 (
        '"
      );
    },
    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 =
      '' +
      '
' +
      '
' +
      '
' +
      noColorText +
      "
" +
      "
" +
      '
 ";
    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 (
        '' +
        '
' +
        '
' +
        ' ' +
        "
" +
        '
" +
        "
" +
        "
 "
      );
    },
    _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 (
        '' +
        '
' +
        '
' +
        (this.showIcon ? '
' : "") +
        (this.showText
          ? '
' + this.label + "
"
          : "") +
        "
" +
        "
" +
        "
 "
      );
    },
    postRender: function() {
      this.Stateful_postRender();
      this.setDisabled(this.disabled);
    },
    _onMouseDown: function(e) {
      var target = e.target || e.srcElement,
        tagName = target && target.tagName && target.tagName.toLowerCase();
      if (tagName == "input" || tagName == "object" || tagName == "object") {
        return false;
      }
    },
    _onClick: function() {
      if (!this.isDisabled()) {
        this.fireEvent("click");
      }
    },
    setTitle: function(text) {
      var label = this.getDom("label");
      label.innerHTML = text;
    }
  };
  utils.inherits(Button, UIBase);
  utils.extend(Button.prototype, Stateful);
})();
// ui/splitbutton.js
///import core
///import uicore
///import ui/stateful.js
;(function() {
  var utils = baidu.editor.utils,
    uiUtils = baidu.editor.ui.uiUtils,
    domUtils = baidu.editor.dom.domUtils,
    UIBase = baidu.editor.ui.UIBase,
    Stateful = baidu.editor.ui.Stateful,
    SplitButton = (baidu.editor.ui.SplitButton = function(options) {
      this.initOptions(options);
      this.initSplitButton();
    });
  SplitButton.prototype = {
    popup: null,
    uiName: "splitbutton",
    title: "",
    initSplitButton: function() {
      this.initUIBase();
      this.Stateful_init();
      var me = this;
      if (this.popup != null) {
        var popup = this.popup;
        this.popup = null;
        this.setPopup(popup);
      }
    },
    _UIBase_postRender: UIBase.prototype.postRender,
    postRender: function() {
      this.Stateful_postRender();
      this._UIBase_postRender();
    },
    setPopup: function(popup) {
      if (this.popup === popup) return;
      if (this.popup != null) {
        this.popup.dispose();
      }
      popup.addListener("show", utils.bind(this._onPopupShow, this));
      popup.addListener("hide", utils.bind(this._onPopupHide, this));
      popup.addListener(
        "postrender",
        utils.bind(function() {
          popup
            .getDom("body")
            .appendChild(
              uiUtils.createElementByHtml(
                ''
              )
            );
          popup.getDom().className += " " + this.className;
        }, this)
      );
      this.popup = popup;
    },
    _onPopupShow: function() {
      this.addState("opened");
    },
    _onPopupHide: function() {
      this.removeState("opened");
    },
    getHtmlTpl: function() {
      return (
        '"
      );
    },
    showPopup: function() {
      // 当popup往上弹出的时候,做特殊处理
      var rect = uiUtils.getClientRect(this.getDom());
      rect.top -= this.popup.SHADOW_RADIUS;
      rect.height += this.popup.SHADOW_RADIUS;
      this.popup.showAnchorRect(rect);
    },
    _onArrowClick: function(event, el) {
      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(
          '
'
        )
      );
      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 (
        '"
      );
    },
    _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("");
        tmpl.push(
          '
 '
        );
        tempIndex === 2 && tmpl.push(" ");
      }
      return (
        '"
      );
    },
    getStateDom: function() {
      return this.target;
    },
    _onClick: function(evt) {
      var target = evt.target || evt.srcElement;
      if (/icon/.test(target.className)) {
        this.items[target.parentNode.getAttribute("index")].onclick();
        Popup.postHide(evt);
      }
    },
    _UIBase_render: UIBase.prototype.render
  };
  utils.inherits(CellAlignPicker, UIBase);
  utils.extend(CellAlignPicker.prototype, Stateful, true);
})();
// ui/pastepicker.js
///import core
///import uicore
;(function() {
  var utils = baidu.editor.utils,
    Stateful = baidu.editor.ui.Stateful,
    uiUtils = baidu.editor.ui.uiUtils,
    UIBase = baidu.editor.ui.UIBase;
  var PastePicker = (baidu.editor.ui.PastePicker = function(options) {
    this.initOptions(options);
    this.initPastePicker();
  });
  PastePicker.prototype = {
    initPastePicker: function() {
      this.initUIBase();
      this.Stateful_init();
    },
    getHtmlTpl: function() {
      return (
        '
' +
        '' +
        '
' +
        this.editor.getLang("pasteOpt") +
        "
" +
        '
" +
        "
 " +
        ""
      );
    },
    getStateDom: function() {
      return this.target;
    },
    format: function(param) {
      this.editor.ui._isTransfer = true;
      this.editor.fireEvent("pasteTransfer", param);
    },
    _onClick: function(cur) {
      var node = domUtils.getNextDomNode(cur),
        screenHt = uiUtils.getViewportRect().height,
        subPop = uiUtils.getClientRect(node);
      if (subPop.top + subPop.height > screenHt)
        node.style.top = -subPop.height - cur.offsetHeight + "px";
      else node.style.top = "";
      if (/hidden/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 (
        '' +
        buff.join("") +
        "
"
      );
    },
    postRender: function() {
      var box = this.getDom();
      for (var i = 0; i < this.items.length; i++) {
        this.items[i].postRender();
      }
      uiUtils.makeUnselectable(box);
    },
    _onMouseDown: function(e) {
      var target = e.target || e.srcElement,
        tagName = target && target.tagName && target.tagName.toLowerCase();
      if (tagName == "input" || tagName == "object" || tagName == "object") {
        return false;
      }
    }
  };
  utils.inherits(Toolbar, UIBase);
})();
// ui/menu.js
///import core
///import uicore
///import ui\popup.js
///import ui\stateful.js
;(function() {
  var utils = baidu.editor.utils,
    domUtils = baidu.editor.dom.domUtils,
    uiUtils = baidu.editor.ui.uiUtils,
    UIBase = baidu.editor.ui.UIBase,
    Popup = baidu.editor.ui.Popup,
    Stateful = baidu.editor.ui.Stateful,
    CellAlignPicker = baidu.editor.ui.CellAlignPicker,
    Menu = (baidu.editor.ui.Menu = function(options) {
      this.initOptions(options);
      this.initMenu();
    });
  var menuSeparator = {
    renderHtml: function() {
      return '';
    },
    postRender: function() {},
    queryAutoHide: function() {
      return true;
    }
  };
  Menu.prototype = {
    items: null,
    uiName: "menu",
    initMenu: function() {
      this.items = this.items || [];
      this.initPopup();
      this.initItems();
    },
    initItems: function() {
      for (var i = 0; i < this.items.length; i++) {
        var item = this.items[i];
        if (item == "-") {
          this.items[i] = this.getSeparator();
        } else if (!(item instanceof MenuItem)) {
          item.editor = this.editor;
          item.theme = this.editor.options.theme;
          this.items[i] = this.createItem(item);
        }
      }
    },
    getSeparator: function() {
      return menuSeparator;
    },
    createItem: function(item) {
      //新增一个参数menu, 该参数存储了menuItem所对应的menu引用
      item.menu = this;
      return new MenuItem(item);
    },
    _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
    getContentHtmlTpl: function() {
      if (this.items.length == 0) {
        return this._Popup_getContentHtmlTpl();
      }
      var buff = [];
      for (var i = 0; i < this.items.length; i++) {
        var item = this.items[i];
        buff[i] = item.renderHtml();
      }
      return '' + buff.join("") + "
";
    },
    _Popup_postRender: Popup.prototype.postRender,
    postRender: function() {
      var me = this;
      for (var i = 0; i < this.items.length; i++) {
        var item = this.items[i];
        item.ownerMenu = this;
        item.postRender();
      }
      domUtils.on(this.getDom(), "mouseover", function(evt) {
        evt = evt || event;
        var rel = evt.relatedTarget || evt.fromElement;
        var el = me.getDom();
        if (!uiUtils.contains(el, rel) && el !== rel) {
          me.fireEvent("over");
        }
      });
      this._Popup_postRender();
    },
    queryAutoHide: function(el) {
      if (el) {
        if (uiUtils.contains(this.getDom(), el)) {
          return false;
        }
        for (var i = 0; i < this.items.length; i++) {
          var item = this.items[i];
          if (item.queryAutoHide(el) === false) {
            return false;
          }
        }
      }
    },
    clearItems: function() {
      for (var i = 0; i < this.items.length; i++) {
        var item = this.items[i];
        clearTimeout(item._showingTimer);
        clearTimeout(item._closingTimer);
        if (item.subMenu) {
          item.subMenu.destroy();
        }
      }
      this.items = [];
    },
    destroy: function() {
      if (this.getDom()) {
        domUtils.remove(this.getDom());
      }
      this.clearItems();
    },
    dispose: function() {
      this.destroy();
    }
  };
  utils.inherits(Menu, Popup);
  /**
     * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
     * @type {Function}
     */
  var MenuItem = (baidu.editor.ui.MenuItem = function(options) {
    this.initOptions(options);
    this.initUIBase();
    this.Stateful_init();
    if (this.subMenu && !(this.subMenu instanceof Menu)) {
      if (options.className && options.className.indexOf("aligntd") != -1) {
        var me = this;
        //获取单元格对齐初始状态
        this.subMenu.selected = this.editor.queryCommandValue("cellalignment");
        this.subMenu = new Popup({
          content: new CellAlignPicker(this.subMenu),
          parentMenu: me,
          editor: me.editor,
          destroy: function() {
            if (this.getDom()) {
              domUtils.remove(this.getDom());
            }
          }
        });
        this.subMenu.addListener("postRenderAfter", function() {
          domUtils.on(this.getDom(), "mouseover", function() {
            me.addState("opened");
          });
        });
      } else {
        this.subMenu = new Menu(this.subMenu);
      }
    }
  });
  MenuItem.prototype = {
    label: "",
    subMenu: null,
    ownerMenu: null,
    uiName: "menuitem",
    alwalysHoverable: true,
    getHtmlTpl: function() {
      return (
        '' +
        '
' +
        this.renderLabelHtml() +
        "
" +
        "
 "
      );
    },
    postRender: function() {
      var me = this;
      this.addListener("over", function() {
        me.ownerMenu.fireEvent("submenuover", me);
        if (me.subMenu) {
          me.delayShowSubMenu();
        }
      });
      if (this.subMenu) {
        this.getDom().className += " edui-hassubmenu";
        this.subMenu.render();
        this.addListener("out", function() {
          me.delayHideSubMenu();
        });
        this.subMenu.addListener("over", function() {
          clearTimeout(me._closingTimer);
          me._closingTimer = null;
          me.addState("opened");
        });
        this.ownerMenu.addListener("hide", function() {
          me.hideSubMenu();
        });
        this.ownerMenu.addListener("submenuover", function(t, subMenu) {
          if (subMenu !== me) {
            me.delayHideSubMenu();
          }
        });
        this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide;
        this.subMenu.queryAutoHide = function(el) {
          if (el && uiUtils.contains(me.getDom(), el)) {
            return false;
          }
          return this._bakQueryAutoHide(el);
        };
      }
      this.getDom().style.tabIndex = "-1";
      uiUtils.makeUnselectable(this.getDom());
      this.Stateful_postRender();
    },
    delayShowSubMenu: function() {
      var me = this;
      if (!me.isDisabled()) {
        me.addState("opened");
        clearTimeout(me._showingTimer);
        clearTimeout(me._closingTimer);
        me._closingTimer = null;
        me._showingTimer = setTimeout(function() {
          me.showSubMenu();
        }, 250);
      }
    },
    delayHideSubMenu: function() {
      var me = this;
      if (!me.isDisabled()) {
        me.removeState("opened");
        clearTimeout(me._showingTimer);
        if (!me._closingTimer) {
          me._closingTimer = setTimeout(function() {
            if (!me.hasState("opened")) {
              me.hideSubMenu();
            }
            me._closingTimer = null;
          }, 400);
        }
      }
    },
    renderLabelHtml: function() {
      return (
        '
' +
        '
' +
        '' +
        (this.label || "") +
        "
"
      );
    },
    getStateDom: function() {
      return this.getDom();
    },
    queryAutoHide: function(el) {
      if (this.subMenu && this.hasState("opened")) {
        return this.subMenu.queryAutoHide(el);
      }
    },
    _onClick: function(event, this_) {
      if (this.hasState("disabled")) return;
      if (this.fireEvent("click", event, this_) !== false) {
        if (this.subMenu) {
          this.showSubMenu();
        } else {
          Popup.postHide(event);
        }
      }
    },
    showSubMenu: function() {
      var rect = uiUtils.getClientRect(this.getDom());
      rect.right -= 5;
      rect.left += 2;
      rect.width -= 7;
      rect.top -= 4;
      rect.bottom += 4;
      rect.height += 8;
      this.subMenu.showAnchorRect(rect, true, true);
    },
    hideSubMenu: function() {
      this.subMenu.hide();
    }
  };
  utils.inherits(MenuItem, UIBase);
  utils.extend(MenuItem.prototype, Stateful, true);
})();
// 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 =
          ' ';
      }
      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 =
          '";
      }
      return (
        '' +
        '
' +
        '
' +
        '
' +
        '' +
        (this.title || "") +
        " " +
        "
" +
        this.closeButton.renderHtml() +
        "
" +
        '
' +
        (this.autoReset ? "" : this.getContentHtml()) +
        "
" +
        footHtml +
        "
 "
      );
    },
    postRender: function() {
      // todo: 保持居中/记住上次关闭位置选项
      if (!this.modalMask.getDom()) {
        this.modalMask.render();
        this.modalMask.hide();
      }
      if (!this.dragMask.getDom()) {
        this.dragMask.render();
        this.dragMask.hide();
      }
      var me = this;
      this.addListener("show", function() {
        me.modalMask.show(this.getDom().style.zIndex - 2);
      });
      this.addListener("hide", function() {
        me.modalMask.hide();
      });
      if (this.buttons) {
        for (var i = 0; i < this.buttons.length; i++) {
          this.buttons[i].postRender();
        }
      }
      domUtils.on(window, "resize", function() {
        setTimeout(function() {
          if (!me.isHidden()) {
            me.safeSetOffset(uiUtils.getClientRect(me.getDom()));
          }
        });
      });
      //hold住scroll事件,防止dialog的滚动影响页面
      //            if( this.holdScroll ) {
      //
      //                if( !me.iframeUrl ) {
      //                    domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
      //                        domUtils.preventDefault(e);
      //                    } );
      //                } else {
      //                    me.addListener('dialogafterreset', function(){
      //                        window.setTimeout(function(){
      //                            var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow;
      //
      //                            if( browser.ie ) {
      //
      //                                var timer = window.setInterval(function(){
      //
      //                                    if( iframeWindow.document && iframeWindow.document.body ) {
      //                                        window.clearInterval( timer );
      //                                        timer = null;
      //                                        domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
      //                                            domUtils.preventDefault(e);
      //                                        } );
      //                                    }
      //
      //                                }, 100);
      //
      //                            } else {
      //                                domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
      //                                    domUtils.preventDefault(e);
      //                                } );
      //                            }
      //
      //                        }, 1);
      //                    });
      //                }
      //
      //            }
      this._hide();
    },
    mesureSize: function() {
      var body = this.getDom("body");
      var width = uiUtils.getClientRect(this.getDom("content")).width;
      var dialogBodyStyle = body.style;
      dialogBodyStyle.width = width;
      return uiUtils.getClientRect(body);
    },
    _onTitlebarMouseDown: function(evt, el) {
      if (this.draggable) {
        var rect;
        var vpRect = uiUtils.getViewportRect();
        var me = this;
        uiUtils.startDrag(evt, {
          ondragstart: function() {
            rect = uiUtils.getClientRect(me.getDom());
            me.getDom("contmask").style.visibility = "visible";
            me.dragMask.show(me.getDom().style.zIndex - 1);
          },
          ondragmove: function(x, y) {
            var left = rect.left + x;
            var 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 =
              '';
            me.editor.container.style.zIndex &&
              (this.getDom().style.zIndex =
                me.editor.container.style.zIndex * 1 + 1);
          }
        }
        // canSideUp:false,
        // canSideLeft:false
      });
      this.onbuttonclick = function() {
        this.showPopup();
      };
      this.initSplitButton();
    }
  };
  utils.inherits(MultiMenuPop, SplitButton);
})();
// ui/shortcutmenu.js
;(function() {
  var UI = baidu.editor.ui,
    UIBase = UI.UIBase,
    uiUtils = UI.uiUtils,
    utils = baidu.editor.utils,
    domUtils = baidu.editor.dom.domUtils;
  var allMenus = [], //存储所有快捷菜单
    timeID,
    isSubMenuShow = false; //是否有子pop显示
  var ShortCutMenu = (UI.ShortCutMenu = function(options) {
    this.initOptions(options);
    this.initShortCutMenu();
  });
  ShortCutMenu.postHide = hideAllMenu;
  ShortCutMenu.prototype = {
    isHidden: true,
    SPACE: 5,
    initShortCutMenu: function() {
      this.items = this.items || [];
      this.initUIBase();
      this.initItems();
      this.initEvent();
      allMenus.push(this);
    },
    initEvent: function() {
      var me = this,
        doc = me.editor.document;
      domUtils.on(doc, "mousemove", function(e) {
        if (me.isHidden === false) {
          //有pop显示就不隐藏快捷菜单
          if (me.getSubMenuMark() || me.eventType == "contextmenu") return;
          var flag = true,
            el = me.getDom(),
            wt = el.offsetWidth,
            ht = el.offsetHeight,
            distanceX = wt / 2 + me.SPACE, //距离中心X标准
            distanceY = ht / 2, //距离中心Y标准
            x = Math.abs(e.screenX - me.left), //离中心距离横坐标
            y = Math.abs(e.screenY - me.top); //离中心距离纵坐标
          clearTimeout(timeID);
          timeID = setTimeout(function() {
            if (y > 0 && y < distanceY) {
              me.setOpacity(el, "1");
            } else if (y > distanceY && y < distanceY + 70) {
              me.setOpacity(el, "0.5");
              flag = false;
            } else if (y > distanceY + 70 && y < distanceY + 140) {
              me.hide();
            }
            if (flag && x > 0 && x < distanceX) {
              me.setOpacity(el, "1");
            } else if (x > distanceX && x < distanceX + 70) {
              me.setOpacity(el, "0.5");
            } else if (x > distanceX + 70 && x < distanceX + 140) {
              me.hide();
            }
          });
        }
      });
      //ie\ff下 mouseout不准
      if (browser.chrome) {
        domUtils.on(doc, "mouseout", function(e) {
          var relatedTgt = e.relatedTarget || e.toElement;
          if (relatedTgt == null || relatedTgt.tagName == "HTML") {
            me.hide();
          }
        });
      }
      me.editor.addListener("afterhidepop", function() {
        if (!me.isHidden) {
          isSubMenuShow = true;
        }
      });
    },
    initItems: function() {
      if (utils.isArray(this.items)) {
        for (var i = 0, len = this.items.length; i < len; i++) {
          var item = this.items[i].toLowerCase();
          if (UI[item]) {
            this.items[i] = new UI[item](this.editor);
            this.items[i].className += " edui-shortcutsubmenu ";
          }
        }
      }
    },
    setOpacity: function(el, value) {
      if (browser.ie && browser.version < 9) {
        el.style.filter = "alpha(opacity = " + parseFloat(value) * 100 + ");";
      } else {
        el.style.opacity = value;
      }
    },
    getSubMenuMark: function() {
      isSubMenuShow = false;
      var layerEle = uiUtils.getFixedLayer();
      var list = domUtils.getElementsByTagName(layerEle, "div", function(node) {
        return domUtils.hasClass(node, "edui-shortcutsubmenu edui-popup");
      });
      for (var i = 0, node; (node = list[i++]); ) {
        if (node.style.display != "none") {
          isSubMenuShow = true;
        }
      }
      return isSubMenuShow;
    },
    show: function(e, hasContextmenu) {
      var me = this,
        offset = {},
        el = this.getDom(),
        fixedlayer = uiUtils.getFixedLayer();
      function setPos(offset) {
        if (offset.left < 0) {
          offset.left = 0;
        }
        if (offset.top < 0) {
          offset.top = 0;
        }
        el.style.cssText =
          "position:absolute;left:" +
          offset.left +
          "px;top:" +
          offset.top +
          "px;";
      }
      function setPosByCxtMenu(menu) {
        if (!menu.tagName) {
          menu = menu.getDom();
        }
        offset.left = parseInt(menu.style.left);
        offset.top = parseInt(menu.style.top);
        offset.top -= el.offsetHeight + 15;
        setPos(offset);
      }
      me.eventType = e.type;
      el.style.cssText = "display:block;left:-9999px";
      if (e.type == "contextmenu" && hasContextmenu) {
        var menu = domUtils.getElementsByTagName(
          fixedlayer,
          "div",
          "edui-contextmenu"
        )[0];
        if (menu) {
          setPosByCxtMenu(menu);
        } else {
          me.editor.addListener("aftershowcontextmenu", function(type, menu) {
            setPosByCxtMenu(menu);
          });
        }
      } else {
        offset = uiUtils.getViewportOffsetByEvent(e);
        offset.top -= el.offsetHeight + me.SPACE;
        offset.left += me.SPACE + 20;
        setPos(offset);
        me.setOpacity(el, 0.2);
      }
      me.isHidden = false;
      me.left = e.screenX + el.offsetWidth / 2 - me.SPACE;
      me.top = e.screenY - el.offsetHeight / 2 - me.SPACE;
      if (me.editor) {
        el.style.zIndex = me.editor.container.style.zIndex * 1 + 10;
        fixedlayer.style.zIndex = el.style.zIndex - 1;
      }
    },
    hide: function() {
      if (this.getDom()) {
        this.getDom().style.display = "none";
      }
      this.isHidden = true;
    },
    postRender: function() {
      if (utils.isArray(this.items)) {
        for (var i = 0, item; (item = this.items[i++]); ) {
          item.postRender();
        }
      }
    },
    getHtmlTpl: function() {
      var buff;
      if (utils.isArray(this.items)) {
        buff = [];
        for (var i = 0; i < this.items.length; i++) {
          buff[i] = this.items[i].renderHtml();
        }
        buff = buff.join("");
      } else {
        buff = this.items;
      }
      return (
        '' +
        buff +
        "
"
      );
    }
  };
  utils.inherits(ShortCutMenu, UIBase);
  function hideAllMenu(e) {
    var tgt = e.target || e.srcElement,
      cur = domUtils.findParent(
        tgt,
        function(node) {
          return (
            domUtils.hasClass(node, "edui-shortcutmenu") ||
            domUtils.hasClass(node, "edui-popup")
          );
        },
        true
      );
    if (!cur) {
      for (var i = 0, menu; (menu = allMenus[i++]); ) {
        menu.hide();
      }
    }
  }
  domUtils.on(document, "mousedown", function(e) {
    hideAllMenu(e);
  });
  domUtils.on(window, "scroll", function(e) {
    hideAllMenu(e);
  });
})();
// ui/breakline.js
;(function() {
  var utils = baidu.editor.utils,
    UIBase = baidu.editor.ui.UIBase,
    Breakline = (baidu.editor.ui.Breakline = function(options) {
      this.initOptions(options);
      this.initSeparator();
    });
  Breakline.prototype = {
    uiName: "Breakline",
    initSeparator: function() {
      this.initUIBase();
    },
    getHtmlTpl: function() {
      return " ";
    }
  };
  utils.inherits(Breakline, UIBase);
})();
// ui/message.js
///import core
///import uicore
;(function() {
  var utils = baidu.editor.utils,
    domUtils = baidu.editor.dom.domUtils,
    UIBase = baidu.editor.ui.UIBase,
    Message = (baidu.editor.ui.Message = function(options) {
      this.initOptions(options);
      this.initMessage();
    });
  Message.prototype = {
    initMessage: function() {
      this.initUIBase();
    },
    getHtmlTpl: function() {
      return (
        '' +
        ' 
×
' +
        ' 
' +
        ' 
' +
        ' 
' +
        ' 
' +
        "  
" +
        " 
" +
        "
 "
      );
    },
    reset: function(opt) {
      var me = this;
      if (!opt.keepshow) {
        clearTimeout(this.timer);
        me.timer = setTimeout(function() {
          me.hide();
        }, opt.timeout || 4000);
      }
      opt.content !== undefined && me.setContent(opt.content);
      opt.type !== undefined && me.setType(opt.type);
      me.show();
    },
    postRender: function() {
      var me = this,
        closer = this.getDom("closer");
      closer &&
        domUtils.on(closer, "click", function() {
          me.hide();
        });
    },
    setContent: function(content) {
      this.getDom("content").innerHTML = content;
    },
    setType: function(type) {
      type = type || "info";
      var body = this.getDom("body");
      body.className = body.className.replace(
        /edui-message-type-[\w-]+/,
        "edui-message-type-" + type
      );
    },
    getContent: function() {
      return this.getDom("content").innerHTML;
    },
    getType: function() {
      var arr = this.getDom("body").match(/edui-message-type-([\w-]+)/);
      return arr ? arr[1] : "";
    },
    show: function() {
      this.getDom().style.display = "block";
    },
    hide: function() {
      var dom = this.getDom();
      if (dom) {
        dom.style.display = "none";
        dom.parentNode && dom.parentNode.removeChild(dom);
      }
    }
  };
  utils.inherits(Message, UIBase);
})();
// ui/iconfont.js
;(function(window){var svgSprite=' ';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("")}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: "/admin/Base/Photos/index",
    link: "~/dialogs/link/link.html",
    spechars: "~/dialogs/spechars/spechars.html",
    searchreplace: "~/dialogs/searchreplace/searchreplace.html",
    map: "~/dialogs/map/map.html",
    gmap: "~/dialogs/gmap/gmap.html",
    insertvideo: "~/dialogs/video/video.html",
    help: "~/dialogs/help/help.html",
    preview: "~/dialogs/preview/preview.html",
    emotion: "~/dialogs/emotion/emotion.html",
    wordimage: "~/dialogs/wordimage/wordimage.html",
    attachment: "~/dialogs/attachment/attachment.html",
    insertframe: "~/dialogs/insertframe/insertframe.html",
    edittip: "~/dialogs/table/edittip.html",
    edittable: "~/dialogs/table/edittable.html",
    edittd: "~/dialogs/table/edittd.html",
    webapp: "~/dialogs/webapp/webapp.html",
    snapscreen: "~/dialogs/snapscreen/snapscreen.html",
    scrawl: "~/dialogs/scrawl/scrawl.html",
    music: "~/dialogs/music/music.html",
    template: "~/dialogs/template/template.html",
    background: "~/dialogs/background/background.html",
    charts: "~/dialogs/charts/charts.html"
  };
  //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
  var btnCmds = [
    "undo",
    "redo",
    "formatmatch",
    "bold",
    "italic",
    "underline",
    "fontborder",
    "touppercase",
    "tolowercase",
    "strikethrough",
    "subscript",
    "superscript",
    "source",
    "indent",
    "outdent",
    "blockquote",
    "pasteplain",
    "pagebreak",
    "selectall",
    "print",
    "horizontal",
    "removeformat",
    "time",
    "date",
    "unlink",
    "insertparagraphbeforetable",
    "insertrow",
    "insertcol",
    "mergeright",
    "mergedown",
    "deleterow",
    "deletecol",
    "splittorows",
    "splittocols",
    "splittocells",
    "mergecells",
    "deletetable",
    "drafts"
  ];
  for (var i = 0, ci; (ci = btnCmds[i++]); ) {
    ci = ci.toLowerCase();
    editorui[ci] = (function(cmd) {
      return function(editor) {
        var ui = new editorui.Button({
          className: "edui-for-" + cmd,
          title:
            editor.options.labelMap[cmd] ||
              editor.getLang("labelMap." + cmd) ||
              "",
          onclick: function() {
            editor.execCommand(cmd);
          },
          theme: editor.options.theme,
          showText: false
        });
        editorui.buttons[cmd] = ui;
        editor.addListener("selectionchange", function(
          type,
          causeByUi,
          uiReady
        ) {
          var state = editor.queryCommandState(cmd);
          if (state == -1) {
            ui.setDisabled(true);
            ui.setChecked(false);
          } else {
            if (!uiReady) {
              ui.setDisabled(false);
              ui.setChecked(state);
            }
          }
        });
        return ui;
      };
    })(ci);
  }
  //清除文档
  editorui.cleardoc = function(editor) {
    var ui = new editorui.Button({
      className: "edui-for-cleardoc",
      title:
        editor.options.labelMap.cleardoc ||
          editor.getLang("labelMap.cleardoc") ||
          "",
      theme: editor.options.theme,
      onclick: function() {
        if (confirm(editor.getLang("confirmClear"))) {
          editor.execCommand("cleardoc");
        }
      }
    });
    editorui.buttons["cleardoc"] = ui;
    editor.addListener("selectionchange", function() {
      ui.setDisabled(editor.queryCommandState("cleardoc") == -1);
    });
    return ui;
  };
  //排版,图片排版,文字方向
  var typeset = {
    justify: ["left", "right", "center", "justify"],
    imagefloat: ["none", "left", "center", "right"],
    directionality: ["ltr", "rtl"]
  };
  for (var p in typeset) {
    (function(cmd, val) {
      for (var i = 0, ci; (ci = val[i++]); ) {
        (function(cmd2) {
          editorui[cmd.replace("float", "") + cmd2] = function(editor) {
            var ui = new editorui.Button({
              className: "edui-for-" + cmd.replace("float", "") + cmd2,
              title:
                editor.options.labelMap[cmd.replace("float", "") + cmd2] ||
                  editor.getLang(
                    "labelMap." + cmd.replace("float", "") + cmd2
                  ) ||
                  "",
              theme: editor.options.theme,
              onclick: function() {
                editor.execCommand(cmd, cmd2);
              }
            });
            editorui.buttons[cmd] = ui;
            editor.addListener("selectionchange", function(
              type,
              causeByUi,
              uiReady
            ) {
              ui.setDisabled(editor.queryCommandState(cmd) == -1);
              ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !uiReady);
            });
            return ui;
          };
        })(ci);
      }
    })(p, typeset[p]);
  }
  //字体颜色和背景颜色
  for (var i = 0, ci; (ci = ["backcolor", "forecolor"][i++]); ) {
    editorui[ci] = (function(cmd) {
      return function(editor) {
        var ui = new editorui.ColorButton({
          className: "edui-for-" + cmd,
          color: "default",
          title:
            editor.options.labelMap[cmd] ||
              editor.getLang("labelMap." + cmd) ||
              "",
          editor: editor,
          onpickcolor: function(t, color) {
            editor.execCommand(cmd, color);
          },
          onpicknocolor: function() {
            editor.execCommand(cmd, "default");
            this.setColor("transparent");
            this.color = "default";
          },
          onbuttonclick: function() {
            editor.execCommand(cmd, this.color);
          }
        });
        editorui.buttons[cmd] = ui;
        editor.addListener("selectionchange", function() {
          ui.setDisabled(editor.queryCommandState(cmd) == -1);
        });
        return ui;
      };
    })(ci);
  }
  var dialogBtns = {
    noOk: ["searchreplace", "help", "spechars", "webapp", "preview"],
    ok: [
      "attachment",
      "anchor",
      "link",
      "insertimage",
      "map",
      "gmap",
      "insertframe",
      "wordimage",
      "insertvideo",
      "insertframe",
      "edittip",
      "edittable",
      "edittd",
      "scrawl",
      "template",
      "music",
      "background",
      "charts"
    ]
  };
  for (var p in dialogBtns) {
    (function(type, vals) {
      for (var i = 0, ci; (ci = vals[i++]); ) {
        //todo opera下存在问题
        if (browser.opera && ci === "searchreplace") {
          continue;
        }
        (function(cmd) {
          editorui[cmd] = function(editor, iframeUrl, title) {
            iframeUrl =
              iframeUrl ||
              (editor.options.iframeUrlMap || {})[cmd] ||
              iframeUrlMap[cmd];
            title =
              editor.options.labelMap[cmd] ||
              editor.getLang("labelMap." + cmd) ||
              "";
            var dialog;
            //没有iframeUrl不创建dialog
            if (iframeUrl) {
              dialog = new editorui.Dialog(
                utils.extend(
                  {
                    iframeUrl: editor.ui.mapUrl(iframeUrl),
                    editor: editor,
                    className: "edui-for-" + cmd,
                    title: title,
                    holdScroll: cmd === "insertimage",
                    fullscreen: /charts|preview/.test(cmd),
                    closeDialog: editor.getLang("closeDialog")
                  },
                  type == "ok"
                    ? {
                        buttons: [
                          {
                            className: "edui-okbutton",
                            label: editor.getLang("ok"),
                            editor: editor,
                            onclick: function() {
                              dialog.close(true);
                            }
                          },
                          {
                            className: "edui-cancelbutton",
                            label: editor.getLang("cancel"),
                            editor: editor,
                            onclick: function() {
                              dialog.close(false);
                            }
                          }
                        ]
                      }
                    : {}
                )
              );
              editor.ui._dialogs[cmd + "Dialog"] = dialog;
            }
            var ui = new editorui.Button({
              className: "edui-for-" + cmd,
              title: title,
              onclick: function() {
                if (dialog) {
                  switch (cmd) {
                    case "wordimage":
                      var images = editor.execCommand("wordimage");
                      if (images && images.length) {
                        dialog.render();
                        dialog.open();
                      }
                      break;
                    case "scrawl":
                      if (editor.queryCommandState("scrawl") != -1) {
                        dialog.render();
                        dialog.open();
                      }
                      break;
                    default:
                      dialog.render();
                      dialog.open();
                  }
                }
              },
              theme: editor.options.theme,
              disabled:
                (cmd == "scrawl" && editor.queryCommandState("scrawl") == -1) ||
                  cmd == "charts"
            });
            editorui.buttons[cmd] = ui;
            editor.addListener("selectionchange", function() {
              //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
              var unNeedCheckState = { edittable: 1 };
              if (cmd in unNeedCheckState) return;
              var state = editor.queryCommandState(cmd);
              if (ui.getDom()) {
                ui.setDisabled(state == -1);
                ui.setChecked(state);
              }
            });
            return ui;
          };
        })(ci.toLowerCase());
      }
    })(p, dialogBtns[p]);
  }
  editorui.snapscreen = function(editor, iframeUrl, title) {
    title =
      editor.options.labelMap["snapscreen"] ||
      editor.getLang("labelMap.snapscreen") ||
      "";
    var ui = new editorui.Button({
      className: "edui-for-snapscreen",
      title: title,
      onclick: function() {
        editor.execCommand("snapscreen");
      },
      theme: editor.options.theme
    });
    editorui.buttons["snapscreen"] = ui;
    iframeUrl =
      iframeUrl ||
      (editor.options.iframeUrlMap || {})["snapscreen"] ||
      iframeUrlMap["snapscreen"];
    if (iframeUrl) {
      var dialog = new editorui.Dialog({
        iframeUrl: editor.ui.mapUrl(iframeUrl),
        editor: editor,
        className: "edui-for-snapscreen",
        title: title,
        buttons: [
          {
            className: "edui-okbutton",
            label: editor.getLang("ok"),
            editor: editor,
            onclick: function() {
              dialog.close(true);
            }
          },
          {
            className: "edui-cancelbutton",
            label: editor.getLang("cancel"),
            editor: editor,
            onclick: function() {
              dialog.close(false);
            }
          }
        ]
      });
      dialog.render();
      editor.ui._dialogs["snapscreenDialog"] = dialog;
    }
    editor.addListener("selectionchange", function() {
      ui.setDisabled(editor.queryCommandState("snapscreen") == -1);
    });
    return ui;
  };
  editorui.insertcode = function(editor, list, title) {
    list = editor.options["insertcode"] || [];
    title =
      editor.options.labelMap["insertcode"] ||
      editor.getLang("labelMap.insertcode") ||
      "";
    // if (!list.length) return;
    var items = [];
    utils.each(list, function(key, val) {
      items.push({
        label: key,
        value: val,
        theme: editor.options.theme,
        renderLabelHtml: function() {
          return (
            '' + (this.label || "") + "
"
          );
        }
      });
    });
    var ui = new editorui.Combox({
      editor: editor,
      items: items,
      onselect: function(t, index) {
        editor.execCommand("insertcode", this.items[index].value);
      },
      onbuttonclick: function() {
        this.showPopup();
      },
      title: title,
      initValue: title,
      className: "edui-for-insertcode",
      indexByValue: function(value) {
        if (value) {
          for (var i = 0, ci; (ci = this.items[i]); i++) {
            if (ci.value.indexOf(value) != -1) return i;
          }
        }
        return -1;
      }
    });
    editorui.buttons["insertcode"] = ui;
    editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
      if (!uiReady) {
        var state = editor.queryCommandState("insertcode");
        if (state == -1) {
          ui.setDisabled(true);
        } else {
          ui.setDisabled(false);
          var value = editor.queryCommandValue("insertcode");
          if (!value) {
            ui.setValue(title);
            return;
          }
          //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
          value && (value = value.replace(/['"]/g, "").split(",")[0]);
          ui.setValue(value);
        }
      }
    });
    return ui;
  };
  editorui.fontfamily = function(editor, list, title) {
    list = editor.options["fontfamily"] || [];
    title =
      editor.options.labelMap["fontfamily"] ||
      editor.getLang("labelMap.fontfamily") ||
      "";
    if (!list.length) return;
    for (var i = 0, ci, items = []; (ci = list[i]); i++) {
      var langLabel = editor.getLang("fontfamily")[ci.name] || "";
      (function(key, val) {
        items.push({
          label: key,
          value: val,
          theme: editor.options.theme,
          renderLabelHtml: function() {
            return (
              '' +
              (this.label || "") +
              "
"
            );
          }
        });
      })(ci.label || langLabel, ci.val);
    }
    var ui = new editorui.Combox({
      editor: editor,
      items: items,
      onselect: function(t, index) {
        editor.execCommand("FontFamily", this.items[index].value);
      },
      onbuttonclick: function() {
        this.showPopup();
      },
      title: title,
      initValue: title,
      className: "edui-for-fontfamily",
      indexByValue: function(value) {
        if (value) {
          for (var i = 0, ci; (ci = this.items[i]); i++) {
            if (ci.value.indexOf(value) != -1) return i;
          }
        }
        return -1;
      }
    });
    editorui.buttons["fontfamily"] = ui;
    editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
      if (!uiReady) {
        var state = editor.queryCommandState("FontFamily");
        if (state == -1) {
          ui.setDisabled(true);
        } else {
          ui.setDisabled(false);
          var value = editor.queryCommandValue("FontFamily");
          //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
          value && (value = value.replace(/['"]/g, "").split(",")[0]);
          ui.setValue(value);
        }
      }
    });
    return ui;
  };
  editorui.fontsize = function(editor, list, title) {
    title =
      editor.options.labelMap["fontsize"] ||
      editor.getLang("labelMap.fontsize") ||
      "";
    list = list || editor.options["fontsize"] || [];
    if (!list.length) return;
    var items = [];
    for (var i = 0; i < list.length; i++) {
      var size = list[i] + "px";
      items.push({
        label: size,
        value: size,
        theme: editor.options.theme,
        renderLabelHtml: function() {
          return (
            '' +
            (this.label || "") +
            "
"
          );
        }
      });
    }
    var ui = new editorui.Combox({
      editor: editor,
      items: items,
      title: title,
      initValue: title,
      onselect: function(t, index) {
        editor.execCommand("FontSize", this.items[index].value);
      },
      onbuttonclick: function() {
        this.showPopup();
      },
      className: "edui-for-fontsize"
    });
    editorui.buttons["fontsize"] = ui;
    editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
      if (!uiReady) {
        var state = editor.queryCommandState("FontSize");
        if (state == -1) {
          ui.setDisabled(true);
        } else {
          ui.setDisabled(false);
          ui.setValue(editor.queryCommandValue("FontSize"));
        }
      }
    });
    return ui;
  };
  editorui.paragraph = function(editor, list, title) {
    title =
      editor.options.labelMap["paragraph"] ||
      editor.getLang("labelMap.paragraph") ||
      "";
    list = editor.options["paragraph"] || [];
    if (utils.isEmptyObject(list)) return;
    var items = [];
    for (var i in list) {
      items.push({
        value: i,
        label: list[i] || editor.getLang("paragraph")[i],
        theme: editor.options.theme,
        renderLabelHtml: function() {
          return (
            '' +
            (this.label || "") +
            " 
"
          );
        }
      });
    }
    var ui = new editorui.Combox({
      editor: editor,
      items: items,
      title: title,
      initValue: title,
      className: "edui-for-paragraph",
      onselect: function(t, index) {
        editor.execCommand("Paragraph", this.items[index].value);
      },
      onbuttonclick: function() {
        this.showPopup();
      }
    });
    editorui.buttons["paragraph"] = ui;
    editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
      if (!uiReady) {
        var state = editor.queryCommandState("Paragraph");
        if (state == -1) {
          ui.setDisabled(true);
        } else {
          ui.setDisabled(false);
          var value = editor.queryCommandValue("Paragraph");
          var index = ui.indexByValue(value);
          if (index != -1) {
            ui.setValue(value);
          } else {
            ui.setValue(ui.initValue);
          }
        }
      }
    });
    return ui;
  };
  //自定义标题
  editorui.customstyle = function(editor) {
    var list = editor.options["customstyle"] || [],
      title =
        editor.options.labelMap["customstyle"] ||
        editor.getLang("labelMap.customstyle") ||
        "";
    if (!list.length) return;
    var langCs = editor.getLang("customstyle");
    for (var i = 0, items = [], t; (t = list[i++]); ) {
      (function(t) {
        var ck = {};
        ck.label = t.label ? t.label : langCs[t.name];
        ck.style = t.style;
        ck.className = t.className;
        ck.tag = t.tag;
        items.push({
          label: ck.label,
          value: ck,
          theme: editor.options.theme,
          renderLabelHtml: function() {
            return (
              '' +
              "<" +
              ck.tag +
              " " +
              (ck.className ? ' class="' + ck.className + '"' : "") +
              (ck.style ? ' style="' + ck.style + '"' : "") +
              ">" +
              ck.label +
              "" +
              ck.tag +
              ">" +
              "
"
            );
          }
        });
      })(t);
    }
    var ui = new editorui.Combox({
      editor: editor,
      items: items,
      title: title,
      initValue: title,
      className: "edui-for-customstyle",
      onselect: function(t, index) {
        editor.execCommand("customstyle", this.items[index].value);
      },
      onbuttonclick: function() {
        this.showPopup();
      },
      indexByValue: function(value) {
        for (var i = 0, ti; (ti = this.items[i++]); ) {
          if (ti.label == value) {
            return i - 1;
          }
        }
        return -1;
      }
    });
    editorui.buttons["customstyle"] = ui;
    editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
      if (!uiReady) {
        var state = editor.queryCommandState("customstyle");
        if (state == -1) {
          ui.setDisabled(true);
        } else {
          ui.setDisabled(false);
          var value = editor.queryCommandValue("customstyle");
          var index = ui.indexByValue(value);
          if (index != -1) {
            ui.setValue(value);
          } else {
            ui.setValue(ui.initValue);
          }
        }
      }
    });
    return ui;
  };
  editorui.inserttable = function(editor, iframeUrl, title) {
    title =
      editor.options.labelMap["inserttable"] ||
      editor.getLang("labelMap.inserttable") ||
      "";
    var ui = new editorui.TableButton({
      editor: editor,
      title: title,
      className: "edui-for-inserttable",
      onpicktable: function(t, numCols, numRows) {
        editor.execCommand("InsertTable", {
          numRows: numRows,
          numCols: numCols,
          border: 1
        });
      },
      onbuttonclick: function() {
        this.showPopup();
      }
    });
    editorui.buttons["inserttable"] = ui;
    editor.addListener("selectionchange", function() {
      ui.setDisabled(editor.queryCommandState("inserttable") == -1);
    });
    return ui;
  };
  editorui.lineheight = function(editor) {
    var val = editor.options.lineheight || [];
    if (!val.length) return;
    for (var i = 0, ci, items = []; (ci = val[i++]); ) {
      items.push({
        //todo:写死了
        label: ci,
        value: ci,
        theme: editor.options.theme,
        onclick: function() {
          editor.execCommand("lineheight", this.value);
        }
      });
    }
    var ui = new editorui.MenuButton({
      editor: editor,
      className: "edui-for-lineheight",
      title:
        editor.options.labelMap["lineheight"] ||
          editor.getLang("labelMap.lineheight") ||
          "",
      items: items,
      onbuttonclick: function() {
        var value = editor.queryCommandValue("LineHeight") || this.value;
        editor.execCommand("LineHeight", value);
      }
    });
    editorui.buttons["lineheight"] = ui;
    editor.addListener("selectionchange", function() {
      var state = editor.queryCommandState("LineHeight");
      if (state == -1) {
        ui.setDisabled(true);
      } else {
        ui.setDisabled(false);
        var value = editor.queryCommandValue("LineHeight");
        value && ui.setValue((value + "").replace(/cm/, ""));
        ui.setChecked(state);
      }
    });
    return ui;
  };
  var rowspacings = ["top", "bottom"];
  for (var r = 0, ri; (ri = rowspacings[r++]); ) {
    (function(cmd) {
      editorui["rowspacing" + cmd] = function(editor) {
        var val = editor.options["rowspacing" + cmd] || [];
        if (!val.length) return null;
        for (var i = 0, ci, items = []; (ci = val[i++]); ) {
          items.push({
            label: ci,
            value: ci,
            theme: editor.options.theme,
            onclick: function() {
              editor.execCommand("rowspacing", this.value, cmd);
            }
          });
        }
        var ui = new editorui.MenuButton({
          editor: editor,
          className: "edui-for-rowspacing" + cmd,
          title:
            editor.options.labelMap["rowspacing" + cmd] ||
              editor.getLang("labelMap.rowspacing" + cmd) ||
              "",
          items: items,
          onbuttonclick: function() {
            var value =
              editor.queryCommandValue("rowspacing", cmd) || this.value;
            editor.execCommand("rowspacing", value, cmd);
          }
        });
        editorui.buttons[cmd] = ui;
        editor.addListener("selectionchange", function() {
          var state = editor.queryCommandState("rowspacing", cmd);
          if (state == -1) {
            ui.setDisabled(true);
          } else {
            ui.setDisabled(false);
            var value = editor.queryCommandValue("rowspacing", cmd);
            value && ui.setValue((value + "").replace(/%/, ""));
            ui.setChecked(state);
          }
        });
        return ui;
      };
    })(ri);
  }
  //有序,无序列表
  var lists = ["insertorderedlist", "insertunorderedlist"];
  for (var l = 0, cl; (cl = lists[l++]); ) {
    (function(cmd) {
      editorui[cmd] = function(editor) {
        var vals = editor.options[cmd],
          _onMenuClick = function() {
            editor.execCommand(cmd, this.value);
          },
          items = [];
        for (var i in vals) {
          items.push({
            label: vals[i] || editor.getLang()[cmd][i] || "",
            value: i,
            theme: editor.options.theme,
            onclick: _onMenuClick
          });
        }
        var ui = new editorui.MenuButton({
          editor: editor,
          className: "edui-for-" + cmd,
          title: editor.getLang("labelMap." + cmd) || "",
          items: items,
          onbuttonclick: function() {
            var value = editor.queryCommandValue(cmd) || this.value;
            editor.execCommand(cmd, value);
          }
        });
        editorui.buttons[cmd] = ui;
        editor.addListener("selectionchange", function() {
          var state = editor.queryCommandState(cmd);
          if (state == -1) {
            ui.setDisabled(true);
          } else {
            ui.setDisabled(false);
            var value = editor.queryCommandValue(cmd);
            ui.setValue(value);
            ui.setChecked(state);
          }
        });
        return ui;
      };
    })(cl);
  }
  editorui.fullscreen = function(editor, title) {
    title =
      editor.options.labelMap["fullscreen"] ||
      editor.getLang("labelMap.fullscreen") ||
      "";
    var ui = new editorui.Button({
      className: "edui-for-fullscreen",
      title: title,
      theme: editor.options.theme,
      onclick: function() {
        if (editor.ui) {
          editor.ui.setFullScreen(!editor.ui.isFullScreen());
        }
        this.setChecked(editor.ui.isFullScreen());
      }
    });
    editorui.buttons["fullscreen"] = ui;
    editor.addListener("selectionchange", function() {
      var state = editor.queryCommandState("fullscreen");
      ui.setDisabled(state == -1);
      ui.setChecked(editor.ui.isFullScreen());
    });
    return ui;
  };
  // 表情
  editorui["emotion"] = function(editor, iframeUrl) {
    var cmd = "emotion";
    var ui = new editorui.MultiMenuPop({
      title:
        editor.options.labelMap[cmd] ||
          editor.getLang("labelMap." + cmd + "") ||
          "",
      editor: editor,
      className: "edui-for-" + cmd,
      iframeUrl: editor.ui.mapUrl(
        iframeUrl ||
          (editor.options.iframeUrlMap || {})[cmd] ||
          iframeUrlMap[cmd]
      )
    });
    editorui.buttons[cmd] = ui;
    editor.addListener("selectionchange", function() {
      ui.setDisabled(editor.queryCommandState(cmd) == -1);
    });
    return ui;
  };
  editorui.autotypeset = function(editor) {
    var ui = new editorui.AutoTypeSetButton({
      editor: editor,
      title:
        editor.options.labelMap["autotypeset"] ||
          editor.getLang("labelMap.autotypeset") ||
          "",
      className: "edui-for-autotypeset",
      onbuttonclick: function() {
        editor.execCommand("autotypeset");
      }
    });
    editorui.buttons["autotypeset"] = ui;
    editor.addListener("selectionchange", function() {
      ui.setDisabled(editor.queryCommandState("autotypeset") == -1);
    });
    return ui;
  };
  /* 简单上传插件 */
  editorui["simpleupload"] = function(editor) {
    var name = "simpleupload",
      ui = new editorui.Button({
        className: "edui-for-" + name,
        title:
          editor.options.labelMap[name] ||
            editor.getLang("labelMap." + name) ||
            "",
        onclick: function() {},
        theme: editor.options.theme,
        showText: false
      });
    editorui.buttons[name] = ui;
    editor.addListener("ready", function() {
      var b = ui.getDom("body"),
        iconSpan = b.children[0];
      editor.fireEvent("simpleuploadbtnready", iconSpan);
    });
    editor.addListener("selectionchange", function(type, causeByUi, uiReady) {
      var state = editor.queryCommandState(name);
      if (state == -1) {
        ui.setDisabled(true);
        ui.setChecked(false);
      } else {
        if (!uiReady) {
          ui.setDisabled(false);
          ui.setChecked(state);
        }
      }
    });
    return ui;
  };
})();
// adapter/editor.js
///import core
///commands 全屏
///commandsName FullScreen
///commandsTitle  全屏
;(function() {
  var utils = baidu.editor.utils,
    uiUtils = baidu.editor.ui.uiUtils,
    UIBase = baidu.editor.ui.UIBase,
    domUtils = baidu.editor.dom.domUtils;
  var nodeStack = [];
  function EditorUI(options) {
    this.initOptions(options);
    this.initEditorUI();
  }
  EditorUI.prototype = {
    uiName: "editor",
    initEditorUI: function() {
      this.editor.ui = this;
      this._dialogs = {};
      this.initUIBase();
      this._initToolbars();
      var editor = this.editor,
        me = this;
      editor.addListener("ready", function() {
        //提供getDialog方法
        editor.getDialog = function(name) {
          return editor.ui._dialogs[name + "Dialog"];
        };
        domUtils.on(editor.window, "scroll", function(evt) {
          baidu.editor.ui.Popup.postHide(evt);
        });
        //提供编辑器实时宽高(全屏时宽高不变化)
        editor.ui._actualFrameWidth = editor.options.initialFrameWidth;
        UE.browser.ie &&
          UE.browser.version === 6 &&
          editor.container.ownerDocument.execCommand(
            "BackgroundImageCache",
            false,
            true
          );
        //display bottom-bar label based on config
        if (editor.options.elementPathEnabled) {
          editor.ui.getDom("elementpath").innerHTML =
            '' +
            editor.getLang("elementPathTip") +
            ":
";
        }
        if (editor.options.wordCount) {
          function countFn() {
            setCount(editor, me);
            domUtils.un(editor.document, "click", arguments.callee);
          }
          domUtils.on(editor.document, "click", countFn);
          editor.ui.getDom("wordcount").innerHTML = editor.getLang(
            "wordCountTip"
          );
        }
        editor.ui._scale();
        if (editor.options.scaleEnabled) {
          if (editor.autoHeightEnabled) {
            editor.disableAutoHeight();
          }
          me.enableScale();
        } else {
          me.disableScale();
        }
        if (
          !editor.options.elementPathEnabled &&
          !editor.options.wordCount &&
          !editor.options.scaleEnabled
        ) {
          editor.ui.getDom("elementpath").style.display = "none";
          editor.ui.getDom("wordcount").style.display = "none";
          editor.ui.getDom("scale").style.display = "none";
        }
        if (!editor.selection.isFocus()) return;
        editor.fireEvent("selectionchange", false, true);
      });
      editor.addListener("mousedown", function(t, evt) {
        var el = evt.target || evt.srcElement;
        baidu.editor.ui.Popup.postHide(evt, el);
        baidu.editor.ui.ShortCutMenu.postHide(evt);
      });
      editor.addListener("delcells", function() {
        if (UE.ui["edittip"]) {
          new UE.ui["edittip"](editor);
        }
        editor.getDialog("edittip").open();
      });
      var pastePop,
        isPaste = false,
        timer;
      editor.addListener("afterpaste", function() {
        if (editor.queryCommandState("pasteplain")) return;
        if (baidu.editor.ui.PastePicker) {
          pastePop = new baidu.editor.ui.Popup({
            content: new baidu.editor.ui.PastePicker({ editor: editor }),
            editor: editor,
            className: "edui-wordpastepop"
          });
          pastePop.render();
        }
        isPaste = true;
      });
      editor.addListener("afterinserthtml", function() {
        clearTimeout(timer);
        timer = setTimeout(function() {
          if (pastePop && (isPaste || editor.ui._isTransfer)) {
            if (pastePop.isHidden()) {
              var span = domUtils.createElement(editor.document, "span", {
                style: "line-height:0px;",
                innerHTML: "\ufeff"
              }),
                range = editor.selection.getRange();
              range.insertNode(span);
              var tmp = getDomNode(span, "firstChild", "previousSibling");
              tmp &&
                pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp);
              domUtils.remove(span);
            } else {
              pastePop.show();
            }
            delete editor.ui._isTransfer;
            isPaste = false;
          }
        }, 200);
      });
      editor.addListener("contextmenu", function(t, evt) {
        baidu.editor.ui.Popup.postHide(evt);
      });
      editor.addListener("keydown", function(t, evt) {
        if (pastePop) pastePop.dispose(evt);
        var keyCode = evt.keyCode || evt.which;
        if (evt.altKey && keyCode == 90) {
          UE.ui.buttons["fullscreen"].onclick();
        }
      });
      editor.addListener("wordcount", function(type) {
        setCount(this, me);
      });
      function setCount(editor, ui) {
        editor.setOpt({
          wordCount: true,
          maximumWords: 10000,
          wordCountMsg:
            editor.options.wordCountMsg || editor.getLang("wordCountMsg"),
          wordOverFlowMsg:
            editor.options.wordOverFlowMsg || editor.getLang("wordOverFlowMsg")
        });
        var opt = editor.options,
          max = opt.maximumWords,
          msg = opt.wordCountMsg,
          errMsg = opt.wordOverFlowMsg,
          countDom = ui.getDom("wordcount");
        if (!opt.wordCount) {
          return;
        }
        var count = editor.getContentLength(true);
        if (count > max) {
          countDom.innerHTML = errMsg;
          editor.fireEvent("wordcountoverflow");
        } else {
          countDom.innerHTML = msg
            .replace("{#leave}", max - count)
            .replace("{#count}", count);
        }
      }
      editor.addListener("selectionchange", function() {
        if (editor.options.elementPathEnabled) {
          me[
            (editor.queryCommandState("elementpath") == -1 ? "dis" : "en") +
              "ableElementPath"
          ]();
        }
        if (editor.options.scaleEnabled) {
          me[
            (editor.queryCommandState("scale") == -1 ? "dis" : "en") +
              "ableScale"
          ]();
        }
      });
      var popup = new baidu.editor.ui.Popup({
        editor: editor,
        content: "",
        className: "edui-bubble",
        _onEditButtonClick: function() {
          this.hide();
          editor.ui._dialogs.linkDialog.open();
        },
        _onImgEditButtonClick: function(name) {
          this.hide();
          editor.ui._dialogs[name] && editor.ui._dialogs[name].open();
        },
        _onImgSetFloat: function(value) {
          this.hide();
          editor.execCommand("imagefloat", value);
        },
        _setIframeAlign: function(value) {
          var frame = popup.anchorEl;
          var newFrame = frame.cloneNode(true);
          switch (value) {
            case -2:
              newFrame.setAttribute("align", "");
              break;
            case -1:
              newFrame.setAttribute("align", "left");
              break;
            case 1:
              newFrame.setAttribute("align", "right");
              break;
          }
          frame.parentNode.insertBefore(newFrame, frame);
          domUtils.remove(frame);
          popup.anchorEl = newFrame;
          popup.showAnchor(popup.anchorEl);
        },
        _updateIframe: function() {
          var frame = (editor._iframe = popup.anchorEl);
          if (domUtils.hasClass(frame, "ueditor_baidumap")) {
            editor.selection.getRange().selectNode(frame).select();
            editor.ui._dialogs.mapDialog.open();
            popup.hide();
          } else {
            editor.ui._dialogs.insertframeDialog.open();
            popup.hide();
          }
        },
        _onRemoveButtonClick: function(cmdName) {
          editor.execCommand(cmdName);
          this.hide();
        },
        queryAutoHide: function(el) {
          if (el && el.ownerDocument == editor.document) {
            if (
              el.tagName.toLowerCase() == "img" ||
              domUtils.findParentByTagName(el, "a", true)
            ) {
              return el !== popup.anchorEl;
            }
          }
          return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el);
        }
      });
      popup.render();
      if (editor.options.imagePopup) {
        editor.addListener("mouseover", function(t, evt) {
          evt = evt || window.event;
          var el = evt.target || evt.srcElement;
          if (
            editor.ui._dialogs.insertframeDialog &&
            /iframe/gi.test(el.tagName)
          ) {
            var html = popup.formatHtml(
              "" +
                editor.getLang("property") +
                ': ' +
                editor.getLang("default") +
                '   ' +
                editor.getLang("justifyleft") +
                '   ' +
                editor.getLang("justifyright") +
                "   " +
                ' ' +
                editor.getLang("modify") +
                "  "
            );
            if (html) {
              popup.getDom("content").innerHTML = html;
              popup.anchorEl = el;
              popup.showAnchor(popup.anchorEl);
            } else {
              popup.hide();
            }
          }
        });
        editor.addListener("selectionchange", function(t, causeByUi) {
          if (!causeByUi) return;
          var html = "",
            str = "",
            img = editor.selection.getRange().getClosedNode(),
            dialogs = editor.ui._dialogs;
          if (img && img.tagName == "IMG") {
            var dialogName = "insertimageDialog";
            if (
              img.className.indexOf("edui-faked-video") != -1 ||
              img.className.indexOf("edui-upload-video") != -1
            ) {
              dialogName = "insertvideoDialog";
            }
            if (img.className.indexOf("edui-faked-webapp") != -1) {
              dialogName = "webappDialog";
            }
            if (img.src.indexOf("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(
                "" +
                  editor.getLang("property") +
                  ': ' +
                  editor.getLang("modify") +
                  "   " +
                  "" +
                  editor.getLang("delete") +
                  "  "
              );
            }
            if (img.getAttribute("word_img")) {
              //todo 放到dialog去做查询
              editor.word_img = [img.getAttribute("word_img")];
              dialogName = "wordimageDialog";
            }
            if (
              domUtils.hasClass(img, "loadingclass") ||
              domUtils.hasClass(img, "loaderrorclass")
            ) {
              dialogName = "";
            }
            if (!dialogs[dialogName]) {
              return;
            }
            str =
              "" +
              editor.getLang("property") +
              ": " +
              '' +
              editor.getLang("default") +
              "   " +
              '' +
              editor.getLang("justifyleft") +
              "   " +
              '' +
              editor.getLang("justifyright") +
              "   " +
              '' +
              editor.getLang("justifycenter") +
              "   " +
              "' +
              editor.getLang("modify") +
              "  ";
            !html && (html = popup.formatHtml(str));
          }
          if (editor.ui._dialogs.linkDialog) {
            var link = editor.queryCommandValue("link");
            var url;
            if (
              link &&
              (url = link.getAttribute("_href") || link.getAttribute("href", 2))
            ) {
              var txt = url;
              if (url.length > 30) {
                txt = url.substring(0, 20) + "...";
              }
              if (html) {
                html += '
';
              }
              html += popup.formatHtml(
                "" +
                  editor.getLang("anthorMsg") +
                  ': ' +
                  txt +
                  " " +
                  ' ' +
                  editor.getLang("modify") +
                  " " +
                  '  ' +
                  editor.getLang("clear") +
                  "  "
              );
              popup.showAnchor(link);
            }
          }
          if (html) {
            popup.getDom("content").innerHTML = html;
            popup.anchorEl = img || link;
            popup.showAnchor(popup.anchorEl);
          } else {
            popup.hide();
          }
        });
      }
    },
    _initToolbars: function() {
      var editor = this.editor;
      var toolbars = this.toolbars || [];
      var toolbarUis = [];
      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 (
        '' +
        '
" +
        '
' +
        "
" +
        //modify wdcount by matao
        '
" +
        '
' +
        "
 "
      );
    },
    showWordImageDialog: function() {
      this._dialogs["wordimageDialog"].open();
    },
    renderToolbarBoxHtml: function() {
      var buff = [];
      for (var i = 0; i < this.toolbars.length; i++) {
        buff.push(this.toolbars[i].renderHtml());
      }
      return buff.join("");
    },
    setFullScreen: function(fullscreen) {
      var editor = this.editor,
        container = editor.container.parentNode.parentNode;
      if (this._fullscreen != fullscreen) {
        this._fullscreen = fullscreen;
        this.editor.fireEvent("beforefullscreenchange", fullscreen);
        if (baidu.editor.browser.gecko) {
          var bk = editor.selection.getRange().createBookmark();
        }
        if (fullscreen) {
          while (container.tagName != "BODY") {
            var position = baidu.editor.dom.domUtils.getComputedStyle(
              container,
              "position"
            );
            nodeStack.push(position);
            container.style.position = "static";
            container = container.parentNode;
          }
          this._bakHtmlOverflow = document.documentElement.style.overflow;
          this._bakBodyOverflow = document.body.style.overflow;
          this._bakAutoHeight = this.editor.autoHeightEnabled;
          this._bakScrollTop = Math.max(
            document.documentElement.scrollTop,
            document.body.scrollTop
          );
          this._bakEditorContaninerWidth = editor.iframe.parentNode.offsetWidth;
          if (this._bakAutoHeight) {
            //当全屏时不能执行自动长高
            editor.autoHeightEnabled = false;
            this.editor.disableAutoHeight();
          }
          document.documentElement.style.overflow = "hidden";
          //修复,滚动条不收起的问题
          window.scrollTo(0, window.scrollY);
          this._bakCssText = this.getDom().style.cssText;
          this._bakCssText1 = this.getDom("iframeholder").style.cssText;
          editor.iframe.parentNode.style.width = "";
          this._updateFullScreen();
        } else {
          while (container.tagName != "BODY") {
            container.style.position = nodeStack.shift();
            container = container.parentNode;
          }
          this.getDom().style.cssText = this._bakCssText;
          this.getDom("iframeholder").style.cssText = this._bakCssText1;
          if (this._bakAutoHeight) {
            editor.autoHeightEnabled = true;
            this.editor.enableAutoHeight();
          }
          document.documentElement.style.overflow = this._bakHtmlOverflow;
          document.body.style.overflow = this._bakBodyOverflow;
          editor.iframe.parentNode.style.width =
            this._bakEditorContaninerWidth + "px";
          window.scrollTo(0, this._bakScrollTop);
        }
        if (browser.gecko && editor.body.contentEditable === "true") {
          var input = document.createElement("input");
          document.body.appendChild(input);
          editor.body.contentEditable = false;
          setTimeout(function() {
            input.focus();
            setTimeout(function() {
              editor.body.contentEditable = true;
              editor.fireEvent("fullscreenchanged", fullscreen);
              editor.selection.getRange().moveToBookmark(bk).select(true);
              baidu.editor.dom.domUtils.remove(input);
              fullscreen && window.scroll(0, 0);
            }, 0);
          }, 0);
        }
        if (editor.body.contentEditable === "true") {
          this.editor.fireEvent("fullscreenchanged", fullscreen);
          this.triggerLayout();
        }
      }
    },
    _updateFullScreen: function() {
      if (this._fullscreen) {
        var vpRect = uiUtils.getViewportRect();
        this.getDom().style.cssText =
          "border:0;position:absolute;left:0;top:" +
          (this.editor.options.topOffset || 0) +
          "px;width:" +
          vpRect.width +
          "px;height:" +
          vpRect.height +
          "px;z-index:" +
          (this.getDom().style.zIndex * 1 + 100);
        uiUtils.setViewportOffset(this.getDom(), {
          left: 0,
          top: this.editor.options.topOffset || 0
        });
        this.editor.setHeight(
          vpRect.height -
            this.getDom("toolbarbox").offsetHeight -
            this.getDom("bottombar").offsetHeight -
            (this.editor.options.topOffset || 0),
          true
        );
        //不手动调一下,会导致全屏失效
        if (browser.gecko) {
          try {
            window.onresize();
          } catch (e) {}
        }
      }
    },
    _updateElementPath: function() {
      var bottom = this.getDom("elementpath"),
        list;
      if (
        this.elementPathEnabled &&
        (list = this.editor.queryCommandValue("elementpath"))
      ) {
        var buff = [];
        for (var i = 0, ci; (ci = list[i]); i++) {
          buff[i] = this.formatHtml(
            '' +
              ci +
              " "
          );
        }
        bottom.innerHTML =
          '' +
          this.editor.getLang("elementPathTip") +
          ": " +
          buff.join(" > ") +
          "
";
      } else {
        bottom.style.display = "none";
      }
    },
    disableElementPath: function() {
      var bottom = this.getDom("elementpath");
      bottom.innerHTML = "";
      bottom.style.display = "none";
      this.elementPathEnabled = false;
    },
    enableElementPath: function() {
      var bottom = this.getDom("elementpath");
      bottom.style.display = "";
      this.elementPathEnabled = true;
      this._updateElementPath();
    },
    _scale: function() {
      var doc = document,
        editor = this.editor,
        editorHolder = editor.container,
        editorDocument = editor.document,
        toolbarBox = this.getDom("toolbarbox"),
        bottombar = this.getDom("bottombar"),
        scale = this.getDom("scale"),
        scalelayer = this.getDom("scalelayer");
      var isMouseMove = false,
        position = null,
        minEditorHeight = 0,
        minEditorWidth = editor.options.minFrameWidth,
        pageX = 0,
        pageY = 0,
        scaleWidth = 0,
        scaleHeight = 0;
      function down() {
        position = domUtils.getXY(editorHolder);
        if (!minEditorHeight) {
          minEditorHeight =
            editor.options.minFrameHeight +
            toolbarBox.offsetHeight +
            bottombar.offsetHeight;
        }
        scalelayer.style.cssText =
          "position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:" +
          editorHolder.offsetWidth +
          "px;height:" +
          editorHolder.offsetHeight +
          "px;z-index:" +
          (editor.options.zIndex + 1);
        domUtils.on(doc, "mousemove", move);
        domUtils.on(editorDocument, "mouseup", up);
        domUtils.on(doc, "mouseup", up);
      }
      var me = this;
      //by xuheng 全屏时关掉缩放
      this.editor.addListener("fullscreenchanged", function(e, fullScreen) {
        if (fullScreen) {
          me.disableScale();
        } else {
          if (me.editor.options.scaleEnabled) {
            me.enableScale();
            var tmpNode = me.editor.document.createElement("span");
            me.editor.body.appendChild(tmpNode);
            me.editor.body.style.height =
              Math.max(
                domUtils.getXY(tmpNode).y,
                me.editor.iframe.offsetHeight - 20
              ) + "px";
            domUtils.remove(tmpNode);
          }
        }
      });
      function move(event) {
        clearSelection();
        var e = event || window.event;
        pageX = e.pageX || doc.documentElement.scrollLeft + e.clientX;
        pageY = e.pageY || doc.documentElement.scrollTop + e.clientY;
        scaleWidth = pageX - position.x;
        scaleHeight = pageY - position.y;
        if (scaleWidth >= minEditorWidth) {
          isMouseMove = true;
          scalelayer.style.width = scaleWidth + "px";
        }
        if (scaleHeight >= minEditorHeight) {
          isMouseMove = true;
          scalelayer.style.height = scaleHeight + "px";
        }
      }
      function up() {
        if (isMouseMove) {
          isMouseMove = false;
          editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2;
          editorHolder.style.width = editor.ui._actualFrameWidth + "px";
          editor.setHeight(
            scalelayer.offsetHeight -
              bottombar.offsetHeight -
              toolbarBox.offsetHeight -
              2,
            true
          );
        }
        if (scalelayer) {
          scalelayer.style.display = "none";
        }
        clearSelection();
        domUtils.un(doc, "mousemove", move);
        domUtils.un(editorDocument, "mouseup", up);
        domUtils.un(doc, "mouseup", up);
      }
      function clearSelection() {
        if (browser.ie) doc.selection.clear();
        else window.getSelection().removeAllRanges();
      }
      this.enableScale = function() {
        //trace:2868
        if (editor.queryCommandState("source") == 1) return;
        scale.style.display = "";
        this.scaleEnabled = true;
        domUtils.on(scale, "mousedown", down);
      };
      this.disableScale = function() {
        scale.style.display = "none";
        this.scaleEnabled = false;
        domUtils.un(scale, "mousedown", down);
      };
    },
    isFullScreen: function() {
      return this._fullscreen;
    },
    postRender: function() {
      UIBase.prototype.postRender.call(this);
      for (var i = 0; i < this.toolbars.length; i++) {
        this.toolbars[i].postRender();
      }
      var me = this;
      var timerId,
        domUtils = baidu.editor.dom.domUtils,
        updateFullScreenTime = function() {
          clearTimeout(timerId);
          timerId = setTimeout(function() {
            me._updateFullScreen();
          });
        };
      domUtils.on(window, "resize", updateFullScreenTime);
      me.addListener("destroy", function() {
        domUtils.un(window, "resize", updateFullScreenTime);
        clearTimeout(timerId);
      });
    },
    showToolbarMsg: function(msg, flag) {
      this.getDom("toolbarmsg_label").innerHTML = msg;
      this.getDom("toolbarmsg").style.display = "";
      //
      if (!flag) {
        var w = this.getDom("upload_dialog");
        w.style.display = "none";
      }
    },
    hideToolbarMsg: function() {
      this.getDom("toolbarmsg").style.display = "none";
    },
    mapUrl: function(url) {
      return url
        ? url.replace("~/", this.editor.options.UEDITOR_HOME_URL || "")
        : "";
    },
    triggerLayout: function() {
      var dom = this.getDom();
      if (dom.style.zoom == "1") {
        dom.style.zoom = "100%";
      } else {
        dom.style.zoom = "1";
      }
    }
  };
  utils.inherits(EditorUI, baidu.editor.ui.UIBase);
  var instances = {};
  UE.ui.Editor = function(options) {
    var editor = new UE.Editor(options);
    editor.options.editor = editor;
    utils.loadFile(document, {
      href:
        editor.options.themePath + editor.options.theme + "/css/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})+[\n\r\t]+<");
              holder.className && (newDiv.className = holder.className);
              holder.style.cssText &&
                (newDiv.style.cssText = holder.style.cssText);
              if (/textarea/i.test(holder.tagName)) {
                editor.textarea = holder;
                editor.textarea.style.display = "none";
              } else {
                holder.parentNode.removeChild(holder);
              }
              if (holder.id) {
                newDiv.id = holder.id;
                domUtils.removeAttributes(holder, "id");
              }
              holder = newDiv;
              holder.innerHTML = "";
            }
          }
          domUtils.addClass(holder, "edui-" + editor.options.theme);
          editor.ui.render(holder);
          var opt = editor.options;
          //给实例添加一个编辑器的容器引用
          editor.container = editor.ui.getDom();
          var parents = domUtils.findParents(holder, true);
          var displays = [];
          for (var i = 0, ci; (ci = parents[i]); i++) {
            displays[i] = ci.style.display;
            ci.style.display = "block";
          }
          if (opt.initialFrameWidth) {
            opt.minFrameWidth = opt.initialFrameWidth;
          } else {
            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);
  });
});
})();