Zhiqim UI是一套集成Javascript库、Css库、Font库、常用ico图标等,并在其上开发的大量UI组件组成的前端开发套件。

森中灵 最后提交于3月前 整理V8.0.6
zhiqim_text_editor.js66KB
/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_ui.htm
 *
 * Zhiqim UI is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
/************************************************************************/
//富文本编辑器,属性和方法
/************************************************************************/
// 1、配置方式,var editor = new Z.TextEditor();
// 2、属性设置 editor.set***("value");;或者 editor.*** = "value";
// 3、支持的参数值
//     1)id                  表示初始化的编辑器对象,<textarea>的id
//     2)tools               表示工具菜单,定义格式为数组:[];“|”表示分割标签;“allTools”为可用参数值;“defaultTools”为默认值
//     3)fontFamily          表示“字体”可选项,定义格式为数组:[];“allFamilies”为可用参数值;“defaultFamily”为默认值
//     4)fontSize            表示“字号”可选项,定义格式为数组:[];
// 4、举例如下:
// <div>
//     <textarea id="test"></textarea>
// </div>
// Z.onload(function()
// {
//     var editor = new Z.TextEditor();
//     editor.setId("test");
//     editor.setFontSize([12,13,16,18,24,32,48]);
//     editor.execute();
// }
//============待解决的问题:===============【2017-10-26】更新
//        1)精简、排版代码;不需要的功能、方法进行剔除
//        1)自定义上标(superscript)、下标(subscript)的实现:
//        1)字体大小修改时,格式统一
//        1)回车换行,统一换行格式;<pre><code>标签下回车的特殊处理;方法:doNewline
//        2)定位光标;方法:saveHistory、loadHistory
//        3)
//
//============可能存在的问题:===============【2017-10-20】更新
//        1)浏览器兼容:用execcommand实现对齐方式;方法:tool_justify****、doCommandMain
//        2)浏览器兼容:有序列表(insertorderedlist)、无序列表(insertunorderedlist)在换行无内容执行时,执行对象不同
//        3)
// 参考网址
//https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand

+(function(F)
{
/***********************************************************************************************/
//静态参数定义
/***********************************************************************************************/
var defaultFamily = ["宋体","微软雅黑","楷体","黑体","隶体","andale mono","arial","arial black","comic sans ms","impact","times new roman","sans-serif"];
var defaultTools = ["html","|","undo","redo","|","bold","italic","underline","|","superscript","subscript","|",
        "foreColor","backColor","|","removeFormat","|","insertorderedlist","insertunorderedlist","|","selectAll","clearAll",
        "paragraph","fontName","fontSize","|","justifyLeft","justifyCenter","justifyRight","|","createLink","unlink","|","insertImage","symbol"];
var allFamilies = [
    "宋体,SimSun",                      //01
    "微软雅黑,Microsoft YaHei",         //02
    "楷体,楷体_GB2312, SimKai",         //03
    "黑体,SimHei",                      //04
    "隶书,SimLi",                       //05
    "andale mono",                      //06
    "arial, helvetica,sans-serif",      //07
    "arial black,avant garde",          //08
    "comic sans ms",                    //09
    "impact,chicago",                   //10
    "times new roman",                  //11
    "sans-serif",                       //12
];
var allTools = [
    {attr:"html",title:"源码",font:"sourcecode"},                         //01
    {attr:"undo",title:"撤销",font:"undo"},                               //02
    {attr:"redo",title:"重做",font:"redo"},                               //03
    {attr:"bold",title:"加粗",font:"bold"},                               //04
    {attr:"italic",title:"斜体",font:"italic"},                           //05
    {attr:"underline",title:"下划线",font:"underline"},                   //06
    {attr:"strikethrough",title:"删除线",font:"strikethrough"},            //07
    {attr:"superscript",title:"上标",font:"superscript"},                 //08
    {attr:"subscript",title:"下标",font:"subscript"},                     //09
    {attr:"foreColor",title:"字体颜色",font:"fontcolor"},                  //10
    {attr:"backColor",title:"背景颜色",font:"background"},                 //11
    {attr:"removeFormat",title:"清除格式",font:"clearformat"},             //12
    {attr:"insertorderedlist",title:"有序列表",font:"orderedlist"},        //13
    {attr:"insertunorderedlist",title:"无序列表",font:"unorderedlist"},    //14
    {attr:"selectAll",title:"全选",font:"selectall"},                      //15
    {attr:"clearAll",title:"清空",font:"clearall"},                        //16
    {attr:"paragraph",title:"段落格式"},                                   //17
    {attr:"fontName",title:"字体"},                                        //18
    {attr:"fontSize",title:"字号"},                                        //19
    {attr:"justifyLeft",title:"左对齐",font:"alignleft"},                  //20
    {attr:"justifyCenter",title:"居中",font:"aligncenter"},                //21
    {attr:"justifyRight",title:"右对齐",font:"alignright"},                //22
    {attr:"createLink",title:"超链接",font:"hyperlink"},                   //23
    {attr:"unlink",title:"取消超链接",font:"unhyperlink"},                 //24
    {attr:"insertImage",title:"图片",font:"image"},                        //25
    {attr:"symbol",title:"特殊符号",font:"symbol"},                        //26
];
var paragraph = ["p","h1","h2","h3","h4","h5","h6",];
//特殊字符
var symbolObj = {};
symbolObj.math = ["¼","½","¾","⅐","⅑","⅒","⅓","⅔","⅕","⅖","⅗","⅘","⅙","⅚","⅛","⅜","⅝","⅞","﹢","﹣","×","÷","±","=","≡","≠","≤","≦","≥","≧","√","✕","%","‰","‱","⊥","π","∑","℃","℉","㎎","㎏","㎜","㎝","㎞","㎡","㏄","㏎","°"];
symbolObj.index = ["←","↑","→","↓","⇠","⇡","⇢","⇣","↚","↛","⇄","⇆","⇋","⇌","⇎","⇍","⇏","Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ","Ⅸ","Ⅹ","ⅰ","ⅱ","ⅲ","ⅳ","ⅴ","ⅵ","ⅶ","ⅷ","ⅸ","ⅹ","⓪","①","②","③","④","⑤","⑥","⑦","⑧","⑨","⑩","⓿","❶","❷","❸","❹","❺","❻","❼","❽","❾","❿","㊀","㊁","㊂","㊃","㊄","㊅","㊆","㊇","㊈","㊉"];
symbolObj.language = ["α","β","χ","δ","ε","η","γ","ι","κ","λ","μ","ν","ω","ο","φ","π","ψ","ρ","σ","τ","θ","υ","ξ","ζ","á","â","æ","à","å","ã","ä","ç","é","ê","è","ð","ë","í","î","ì","ñ","ó","ô","ò","ø","õ","ö","ß","þ","ú","û","ü","ý","ÿ","㊎","㊍","㊌","㊋","㊏","㊤","㊦","㊧","㊨","㊥","㊚","㊛","㊐","㊰"];
symbolObj.other = ["★","☆","✦","✧","✡","✪","✯","♡","♢","♤","♧","♥","♦","♠","♣","☐","☑","☒","⁂","☸","✱","✿","❀","❃","⌚","☎","☏","✂","✄","✈","✉","✎","☀","☁","☂","☃","☼","☽","☾","♨","❄","☚","☛","☜","☞","☟","♩","♪","♫","♬","♭","♮"];

/***********************************************************************************************/
//编辑器定义开始
/***********************************************************************************************/

Z.TextEditor = Z.Class.newInstance();
Z.TextEditor.AJAX_CLASS = "org.zhiqim.httpd.context.service.UploadService";
Z.TextEditor.AJAX_UPLOAD = "upload";
Z.TextEditor.AJAX_UPLOADWWW = "uploadwww";
Z.TextEditor.prototype = 
{
    defaults:
    {
        id: null,
        contextPath: null,
        origin: true,
        fileDir : "",
        maxSize: 0,
        tools: null,
        fontFamily: null,
        fontSize: [12,13,16,18,24,32,48]
    },
    
    setId: function(id){this.id = id;return this;},
    setContextPath(contextPath){this.contextPath = contextPath;return this;},
    setOriginFalse: function(origin){this.origin = false;return this;},
    setFileDir: function(fileDir){this.fileDir = fileDir;return this;},
    setMaxSize: function(maxSize){this.maxSize = maxSize;return this;},
    setTools: function(tools){this.tools = tools;return this;},
    setFontFamily: function(fontFamily){this.fontFamily = fontFamily;return this},
    setFontSize: function(fontSize){this.fontSize = fontSize;return this;},
    setZUIFix: function(){this.$editor.addClass("ZUI-fix");return this;},
    
    /***********************************************************************************************/
    //初始化函数 & 执行函数
    /***********************************************************************************************/
    
    init: function()
    {
        //dialog用到的插入HTML字符串集合
        this.dialogHtml = {}
        
        //功能按钮对象
        this.$$tools = {};
        
        //定义容器
        this.$container = Z('<div class="zte-container"></div>');
        this.$toolbar = Z('<div class="zte-toolbar"></div>');
        this.$buttonBar = Z('<div class="zte-btn-toolbar"></div>');
        this.$dialogContainer = Z('<div class="zte-dialog-container"></div>');
        this.$editor = Z('<div class="zte-editor" contenteditable="true" spellcheck="false"></div>');
        this.$zoomToolWrap = Z('<div class="zte-zoomTool-wrap"></div>');
        this.$zoomToolCover = Z('<div class="zte-zoomTool-cover"><div class="zte-zoomTool-e"></div><div class="zte-zoomTool-se"></div><div class="zte-zoomTool-s"></div></div>');
        
        //颜色选择器
        this.$$colorPicker = [];
    },
    
    execute: function()
    {
        /******************************************************************/
        //1、检查属性
        /******************************************************************/
        
        /* 上传最大值限制 */
        if (this.maxSize)
            this.maxSize = this.maxSize * 1024 * 1024;
        else
            this.maxSize = Infinity;
        
        /*如果没有自定义菜单,则赋值为默认菜单*/
        if (this.tools == null)
            this.tools = defaultTools;
        
        /*如果没有自定义字体,则赋值为默认字体*/
        if (this.fontFamily == null)
            this.fontFamily = defaultFamily;
        for (var i = 0;i < this.fontFamily.length;i++)
        {//定义字体用的是简称,譬如“微软雅黑,Microsoft YaHei”,只用“微软雅黑”定义,重新赋值 this.fontFamily 为完整定义
            var ff = this.fontFamily[i];
            for (var j = 0;j < allFamilies.length;j++)
            {
                var ffFull = allFamilies[j];
                if (ff == ffFull.split(",")[0])
                {
                    this.fontFamily[i] = ffFull;
                    break;
                }
            }
        }
        
        /******************************************************************/
        //2、替换编辑器
        /******************************************************************/
        
        //原始编辑器
        this.$textarea = Z("#" + this.id);
        
        //编辑器生成唯一ID;格式为“zte_editor、zte_editor1、zte_editor2···”
        this.editorId = function()
        {
            var id = "zte_editor",num = 1;
            while (Z.D.has(id))
                id = "zte_editor" + num++;
            return id;
        }();
        this.$editor.attr("id",this.editorId);
        
        // 插入编辑器,隐藏原来的 <textarea>
        var width = this.$textarea.offsetWidth();
        var height = this.$textarea.offsetHeight();
        
        this.$toolbar.append(this.$buttonBar).append(this.$dialogContainer);
        this.$container.append(this.$toolbar).append(this.$editor).append(this.$zoomToolWrap)
                        .insertAfter(this.$textarea).append(this.$textarea)
                        .css({ width: width});
        this.$zoomToolWrap.append(this.$zoomToolCover);
        // 插入工具栏,定义编辑器高度
        this.initToolBar();
        var editorHeight = height - this.$toolbar.offsetHeight();
        this.$container.css({ height: height,});
        this.$editor.css({ height: editorHeight,});
        this.$zoomToolWrap.css({ height: editorHeight,});

        //把 <textarea> 定位在新的编辑器区域上,用于“源码”显示功能
        this.$textarea.hide().css(
        {
            position: "absolute",left: 0,bottom: 0,
            width: "100%",border: "none",
            paddingLeft: this.$editor.css("paddingLeft"),
            paddingTop: this.$editor.css("paddingTop"),
            paddingRight: this.$editor.css("paddingRight"),
            paddingBottom: this.$editor.css("paddingBottom"),
        })
        
        //所有的功能按钮,列表
        this.$$btnList = this.$buttonBar.find(".zte-btn");
        //下拉菜单dropdown
        this.$$dropdownBtn = this.$buttonBar.find("span.zte-btn-dropdown");
        this.$$dropdown = this.$buttonBar.find("ul.zte-btn-dropdown");
        this.$$dropdownItem = this.$buttonBar.find("ul.zte-btn-dropdown > li");
        
        //定义某些功能按钮样式,如“撤销”、“重做”
        this.$$tools.undo.addClass("zte-btn-disable");
        this.$$tools.redo.addClass("zte-btn-disable");
        
        //定义Z.dialog弹窗时,用到的HTML字符串
        if (Z.AR.contains(this.tools, "createLink"))
        {//添加超连接
            this.dialogHtml.createLink = '<div class="z-h100p z-pd-t20 z-pd-b20"><table class="z-table z-w100p z-h100p">'
                + '<tr><td class="z-w30p zi-pd-l20 z-px14">链接标题:</td><td><input type="text" id="zte-linkCreater-title" class="z-input z-w300" placeholder="输入链接标题..."></td></tr>'
                + '<tr><td class="z-w30p zi-pd-l20 z-px14">链接地址:</td><td><input type="text" id="zte-linkCreater-link" class="z-input z-w300" placeholder="输入完整链接地址..."></td></tr>'
                + '<tr><td class="z-w30p zi-pd-l20 z-px14">是否新窗口打开:</td><td><input type="checkbox" id="zte-linkCreater-blank" class="z-checkbox"></td></tr>'
                + '<tr><td colspan=2 class="z-text-center zi-pd-l20 zi-pd-r20"><button id="zte-linkCreater-confirm" class="z-button z-large zi-pd-t4 zi-pd-b4 z-blue z-mg-r20">确定</button><button class="z-button z-large zi-pd-t4 zi-pd-b4 z-mg-l20" onclick="Z.Dialog.close();">取消</button></td></tr>'
                + '</table></div>';
        }
        if (Z.AR.contains(this.tools, "insertImage"))
        {//插入图片
            this.dialogHtml.insertImage = '<div class="z-h100p z-pd-t20 z-pd-b20"><table class="z-text-center z-table z-w100p z-h100p">'
                + '<tr><td class="z-text-left zi-pd-l20 zi-pd-r20 z-px14"><div class="zte-dialogSwitchBtn"><span data-target="zte-imgInsertor-conLoc" class="zte-active">本地图片</span><span data-target="zte-imgInsertor-conWeb">网络图片</span></div></td></tr>'
                + '<tr><td class="zte-dialogContent z-h300">'
                + '<div class="zte-imgInsertor-conLoc zte-active"><input name="zte-imgInsertor-fileInput" id="zte-imgInsertor-fileInput" type="file" accept="image/png, image/jpeg, image/gif, image/jpg" style="width:0;overflow:hide;"><button id="zte-imgInsertor-btnLoc" class="z-button z-large">+ 添加本地图片</button></div>'
                + '<div class="zte-imgInsertor-conWeb"><input class="z-input z-w300" id="zte-imgInsertor-webUrl" type=text placeholder="输入网络图片地址..."><button id="zte-imgInsertor-btnWeb" class="z-button z-mg-l10">添加</button></div>'
                + '<div class="zte-imgInsertor-conShow"><div class="zte-imgInsertor-imgWrap"><img id="zte-imgInsertor-imgSourse" src=""></div><div class="z-mg-t5"><a id="zte-imgInsertor-Redo" class="z-px12 z-text-red"><u>重新添加</u></a></div></div>'
                + '</td></tr>'
                + '<tr><td class="z-text-center zi-pd-l20 zi-pd-r20"><button id="zte-imgInsertor-confirm" class="z-button z-large zi-pd-t4 zi-pd-b4 z-blue z-mg-r20">确定</button><button class="z-button z-large zi-pd-t4 zi-pd-b4 z-mg-l20" onclick="Z.Dialog.close();">取消</button></td></tr>'
                + '</table></div>';
        }
        if (Z.AR.contains(this.tools, "symbol"))
        {//插入特殊符号
            this.dialogHtml.symbol = '<div class="z-h100p z-pd-t20 z-pd-b20"><table class="z-text-center z-table z-w100p z-h100p">'
                + '<tr><td class="z-text-left zi-pd-l20 zi-pd-r20 z-px14"><div class="zte-dialogSwitchBtn">'
                + '<span data-target="zte-symbolPicker-math" class="zte-active">数学符号</span>'
                + '<span data-target="zte-symbolPicker-index"">索引符号</span>'
                + '<span data-target="zte-symbolPicker-language">语言符号</span>'
                + '<span data-target="zte-symbolPicker-other">其他</span></div></td></tr>'
                + '<tr><td class="zte-dialogContent zte-dialogContent-symbol">'
                + '<div class="zte-symbolPicker-math zte-active">' + this.insertSymbolHtml(symbolObj.math) + '</div>'
                + '<div class="zte-symbolPicker-index">' + this.insertSymbolHtml(symbolObj.index) + '</div>'
                + '<div class="zte-symbolPicker-language">' + this.insertSymbolHtml(symbolObj.language) + '</div>'
                + '<div class="zte-symbolPicker-other">' + this.insertSymbolHtml(symbolObj.other) + '</div>'
                + '</td></tr>'
                + '<tr><td class="z-text-center zi-pd-l20 zi-pd-r20"><button class="z-button z-large zi-pd-t4 zi-pd-b4" onclick="Z.Dialog.close();">取消</button></td></tr>'
                + '</table></div>';
        }
        
        /******************************************************************/
        //3、加入已有内容
        /******************************************************************/

        this.saveEditorHtml(this.$textarea.val());
        
        //编辑选区对象
        this.selection = window.getSelection();
        this.range = document.createRange();
        this.htmlHistory = [{html: this.html,range: this.range}];
        this.historyIndex = 0;
        
        /******************************************************************/
        //4、事件绑定
        /******************************************************************/

        //1:原编辑器修改时,修改zteditor内容
        this.$textarea.on("input",this.editorSynContent,this);
        
        //2:工具栏按钮,标题提示语的显示和隐藏
        this.$$btnList.on("mouseenter",this.btnMouseEnter,this);
        this.$$btnList.on("mouseleave",this.btnMouseLeave,this);
        
        //3.1:功能按钮,统一处理的click事件:(隐藏已显示的提示语)
        this.$$btnList.on("click",this.btnDefaultClick,this);
        //3.2:禁用mousedown默认操作
        this.$$btnList.on("mousedown",function (e){Z.E.forbidden(e)},this)
        //3.3:点击显示dropdown
        this.$$dropdownBtn.on("click",this.showDropdown,this)
        //3.4:dropdown 选项点击事件
        this.$$dropdownItem.on("click",this.dropdownSelect,this)
        
        //4.1:编辑器,键盘操作事件
        this.$editor.on("keydown",this.doKeydown,this);
        //4.2:鼠标滚动事件
        this.$editor.on("scroll",this.locationToolCover,this);
        //4.3:编辑结束的几种触发事件:(blur keyup cut paste drop dragend)
        this.$editor.on("blur keyup cut paste drop dragend",this.editorCheck,this);
        //4.4:编辑器选区判断,标注已实现功能的按钮;几种触发事件:(keyup mouseup)
        this.$editor.on("keyup mouseup",this.setCommandedTool,this);
        //4.5:存储选区的几种触发事件:(keyup mouseup mouseleave);keyup、mouseup 在 this.setCommandedTool 中实现存储
        this.$editor.on("mouseleave",this.saveSelection,this);
        //4.6:编辑器鼠标 mousedown,隐藏图片缩放
        this.$editor.on("mousedown",this.doKeydown,this);
        
        //5:颜色选择器,选中颜色操作
        this.$dialogContainer.find(".zte-colorPicker a").on("mousedown",function (e){Z.E.forbidden(e)},this);
        this.$dialogContainer.find(".zte-colorPicker a").on("click",this.doColorPicker,this);
        
        //6:图片缩放工具事件绑定
        this.$zoomToolCover.children("div").on("mousedown",this.zoomToolMousedown,this);
        Z(document).on("mousemove",this.zoomToolMousemove,this);
        Z(document).on("mouseup",this.zoomToolMouseup,this);
        
        //7:点击页面初始化所有弹窗
        Z(document).on("click",this.initDialogList,this);
    },

    initToolBar: function(e)
    {//初始化工具栏
        var html = "";
        for (var i = 0;i < this.tools.length;i++)
        {
            var attr = this.tools[i];
            if (attr == "|")
            {//值为“|”,插入分隔符
                this.$buttonBar.append(Z('<span class="zte-btn-separator"></span>'));
            }
            else
            {//不是“|”,判断是不是有效工具
                var obj = this.getToolObj(attr);
                if (obj)
                {//有效工具
                    this.$buttonBar.append(this.getToolHtml(obj.attr,obj.title,obj.font));
                }
            }
        }
    },
    
    getToolObj: function(tool)
    {//获取工具对象
        for (var i = 0;i < allTools.length;i++)
        {
            if (allTools[i].attr == tool)
                return allTools[i];
        }
        return null;
    },
    
    getToolHtml: function(attr, title, font)
    {//获取菜单工具的html
        if (attr != "paragraph" && attr != "fontName" && attr != "fontSize")
        {//非下拉列表
            var html = '<span class="zte-btn" data-attr="' + attr + '">'
                    + '<i class="z-font z-f-' + font + ' z-px18"></i>'
                    + '<div class="zte-btn-title"><div class="zte-btn-title-arrow"></div>'
                    + '<div class="zte-btn-title-text">' + title + '</div></div>';
            if (attr == "foreColor" || attr == "backColor")
            {//为颜色选择器,添加弹窗代码
                var bgColor = (attr == "foreColor")?("#000000"):("#FFFFFF");
                html += '<i class="z-px10 z-mg-l5 z-mg-r5 z-font z-arrow-down zte-pickerBtn" style="bottom:2px;"></i></div><div class="zte-pickedColor" style="background-color:' + bgColor + '"></div>';
                this.insertColorPicker(attr);
            }
            html += '</span>';
            this.$$tools[attr] = Z(html);
            return this.$$tools[attr];
        }
        else
        {//三个下拉列表
            var html = '<span class="zte-btn zte-btn-dropdown" data-attr="' + attr + '">';
            switch (attr)
            {//“段落格式”、“字体”、“字号”,dropdown
                case "paragraph":
                    html += '<div class="zte-dropdown-selected z-text-ellipsis"><i class="z-font z-arrowhead-down z-float-right z-px10"></i>' + paragraph[0]
                         + '</div><ul class="zte-btn-dropdown" data-type="' + attr + '">';
                    for (var i = 0;i < paragraph.length;i++)
                        html += '<li data-value="' + paragraph[i] + '"><' + paragraph[i] + '>' + paragraph[i] + '</' + paragraph[i] + '></li>';
                    break;
                case "fontName":
                    html += '<div class="zte-dropdown-selected z-text-ellipsis"><i class="z-font z-arrowhead-down z-float-right z-px10"></i>' + this.fontFamily[0].split(",")[0]
                         + '</div><ul class="zte-btn-dropdown" data-type="' + attr + '">';
                    for (var i = 0;i < this.fontFamily.length;i++)
                        html += '<li style="font-family:' + this.fontFamily[i] + ';" data-value="' + this.fontFamily[i] + '">' + this.fontFamily[i].split(",")[0] + '</li>';
                    break;
                case "fontSize":
                    html += '<div class="zte-dropdown-selected z-text-ellipsis"><i class="z-font z-arrowhead-down z-float-right z-px10"></i>' + this.fontSize[0]
                         + '</div><ul class="zte-btn-dropdown" data-type="' + attr + '">';
                    for (var i = 0;i < this.fontSize.length;i++)
                        html += '<li style="font-size:' + this.fontSize[i] + 'px;" data-value="' + this.fontSize[i] + '">' + this.fontSize[i] + '</li>';
                    break;  
            }
            html += '</ul><div class="zte-btn-title"><div class="zte-btn-title-arrow"></div>'
                + '<div class="zte-btn-title-text">' + title + '</div></div></span>';
            this.$$tools[attr] = Z(html);
            return this.$$tools[attr];
        }
    },
    
    /***********************************************************************************************/
    //一:编辑器功能
    /***********************************************************************************************/

    tool_html: function(command,e)
    {//01源码
        if (this.$textarea.isHide())
        {//显示源码
            //存储当前选区
            this.saveSelection();
            //按钮组样式替换
            this.$$tools.html.addClass("zte-active");
            this.$$tools.html.$$btnListNormal = this.$buttonBar.find(".zte-btn:not(.zte-btn-disable):not([data-attr=html])");
            this.$$tools.html.$$btnListActive = this.$buttonBar.find(".zte-btn.zte-active:not([data-attr=html])");
            this.$$tools.html.$$btnListNormal.addClass("zte-btn-disable");
            this.$$tools.html.$$btnListActive.removeClass("zte-active");
            this.$textarea.css("height",parseInt(this.$editor.css("height"))).show();
            this.$editor.css('visibility', 'hidden');
        }
        else
        {//显示内容
            this.$$tools.html.removeClass("zte-active");
            this.$$tools.html.$$btnListNormal.removeClass("zte-btn-disable");
            this.$$tools.html.$$btnListActive.addClass("zte-active");
            this.$textarea.hide();
            this.$editor.css('visibility', 'visible');
            //存储选区、存储历史
            this.saveHistory();
        }
    },
    
    tool_undo: function(e)
    {//02撤销  
        //读取历史纪录
        this.loadHistory(-1);
        //按钮样式
        if (this.$$tools.redo[0])
        {
            this.$$tools.redo.removeClass("zte-btn-disable");
            if (this.historyIndex == 0)
                this.$$tools.undo.addClass("zte-btn-disable");
        }
        this.setCommandedTool();
    },
    
    tool_redo: function(e)
    {//03重做
        //读取历史纪录
        this.loadHistory(1);
        //按钮样式
        if (this.$$tools.undo[0])
        {
            this.$$tools.undo.removeClass("zte-btn-disable");
            if (this.historyIndex == this.htmlHistory.length - 1)
                this.$$tools.redo.addClass("zte-btn-disable");
        }
        this.setCommandedTool();
    },
    
    tool_bold: function(command)
    {//04加粗
        this.doCommandMain(command);
    },
    
    tool_italic: function(command)
    {//05斜体
        this.doCommandMain(command);
    },
    
    tool_underline: function(command)
    {//06下划线
        this.doCommandMain(command);
    },
    
    tool_strikethrough: function(command)
    {//07删除线
        this.doCommandMain(command);
    },
    
    tool_superscript: function(command)
    {//08上标
        this.doCommandSupSub(command);
    },
    
    tool_subscript: function(command)
    {//09下标
        this.doCommandSupSub(command);
    },
    
    tool_foreColor: function(command,e)
    {//10字体颜色
        this.doCommandPicker(command,e);
    },
    
    tool_backColor: function(command,e)
    {//11背景颜色
        this.doCommandPicker(command,e);
    },
    
    tool_removeFormat: function(command)
    {//12清除格式
        this.doCommandMain(command,null,false);
        this.$$btnList.removeClass("zte-active");
    },
    
    tool_insertorderedlist: function(command)
    {//13有序列表
        this.doCommandInsertlist(command);
    },
    
    tool_insertunorderedlist: function(command)
    {//14无序列表
        this.doCommandInsertlist(command);
    },
    
    tool_selectAll: function(command)
    {//15全选
        this.doCommandMain(command,null,false);
    },
    
    tool_clearAll: function()
    {//16清空
        this.saveEditorHtml();
        this.setCursorEnd();
        //存储选区、存储历史
        this.saveHistory();
    },
    
    tool_paragraph: function(command,value)
    {//17段落格式
        this.doCommandMain("formatBlock",value,false);
    },
    
    tool_fontName: function(command,value)
    {//18字体
        this.doCommandMain(command,value,false);
    },
    
    tool_fontSize: function(command,value)
    {//19字号
        //载入选区
        this.loadSelection();
        var size = 7;
        if (value <= 12) size = 1;
        if (value == 13) size = 2;
        if (value == 16) size = 3;
        if (value == 18) size = 4;
        if (value == 24) size = 5;
        if (value == 32) size = 6;
        //如果选区没内容,则调用insertHTML插入代码;有选区,则直接调用doCommandMain
        if (this.range.collapsed)
        {
            value = '<span style="font-size:' + value + 'px">&#8203;</span>';
            this.doCommandMain("insertHTML", value, false, true);
        }
        else 
        {
            this.doCommandMain(command,size,false,true);
            //获取选区元素<font>
            var $startEle = Z(this.getSelectionEle());
            //不是预选的前6个,则手动修改
            if ($startEle.attr("size") == 7) $startEle.removeAttr("size").css("fontSize",value + "px");
        }
        //存储选区、存储历史
        this.saveHistory();
    },
    
    tool_justifyLeft: function(command)
    {//20左对齐
        this.removeSiblingsActive(command);
        this.doCommandMain(command, null, true);
    },
    
    tool_justifyCenter: function(command)
    {//21居中
        this.removeSiblingsActive(command);
        this.doCommandMain(command, null, true);
        
    },
    
    tool_justifyRight: function(command)
    {//22右对齐
        this.removeSiblingsActive(command);
        this.doCommandMain(command, null, true);
    },
    
    tool_createLink: function(command,e)
    {//23超链接
        var dialog = new Z.Dialog();
        dialog.id = "createLink";
        dialog.title = "添加超链接";
        dialog.text = this.dialogHtml.createLink;
        dialog.width = 500;
        dialog.height = 240;
        dialog.fixed = true;
        dialog.execute();
        Z("#zte-linkCreater-confirm").on("click", this.doLinkCreat,this);
    },
    
    tool_unlink: function(command)
    {//24取消超链接
        this.doCommandMain(command, null, false);
    },
    
    tool_insertImage: function(command)
    {//25插入图片
        var dialog = new Z.Dialog();
        dialog.id = "insertImage";
        dialog.title = "添加图片";
        dialog.text = this.dialogHtml.insertImage;
        dialog.width = 500;
        dialog.height = 450;
        dialog.fixed = true;
        dialog.execute();
        //添加图片方式切换
        Z(".zte-dialogSwitchBtn > span").on("click",this.insertHtmlSwitch,this);
        //按钮触发事件
        Z("#zte-imgInsertor-btnLoc").on("click",this.insertImgLocClick,this);
        Z("#zte-imgInsertor-fileInput").on("change",this.insertImgLoc,this);
        Z("#zte-imgInsertor-btnWeb").on("click",this.insertImgWeb,this);
        Z("#zte-imgInsertor-Redo").on("click",this.insertImgRedo,this);
        //确认插入
        Z("#zte-imgInsertor-confirm").on("click",this.insertImgConfirm,this);
    },
    
    tool_symbol: function(command)
    {//26特殊符号
        var dialog = new Z.Dialog();
        dialog.id = "symbol";
        dialog.title = "插入特殊符号";
        dialog.text = this.dialogHtml.symbol;
        dialog.width = 500;
        dialog.height = 300;
        dialog.fixed = true;
        dialog.execute();
        Z(".zte-dialogSwitchBtn > span").on("click",this.insertHtmlSwitch,this);
        Z(".zte-dialogContent-symbol a").on("click",this.insertSymbolConfirm,this);
    },
    
    /***********************************************************************************************/
    //二:事件处理方法
    /***********************************************************************************************/

    editorSynContent: function()
    {//1:原编辑器内容修改(input事件),实现zteditor内容同步
        this.saveEditorHtml(this.$textarea.val());
    },
    
    btnMouseEnter: function(e)
    {//2.1:按钮提示说明,鼠标进入显示
        var $target = Z(Z.E.current(e));
        if ($target.hasClass("zte-btn"))
        {
            var btnWidth = $target.offsetWidth();
            var btnHeight = $target.offsetHeight();
            var $title = $target.children(".zte-btn-title").show();
            var titleWidth = $title.offsetWidth();
            var setWidth = (btnWidth - titleWidth)/2;
            $title.css({left: setWidth,top:btnHeight});
        }
    },
    
    btnMouseLeave: function(e)
    {//2.2:按钮提示说明,鼠标离开隐藏
        var $target = Z(Z.E.current(e));
        if ($target.hasClass("zte-btn"))
            $target.children(".zte-btn-title").hide();
    },
    
    btnDefaultClick: function(e)
    {//3.1:所有按钮统一的click事件
        var $target = null;
        if (e.nodeType == 1) $target = Z(e);
        else $target = Z(Z.E.current(e));
        
        //隐藏标题提示浮框
        var $btnTitle = $target.children(".zte-btn-title");
        if ($btnTitle.length > 0 && !$btnTitle.isHide())
            $btnTitle.hide();
        
        //隐藏颜色选择器
        this.colorPickerHide();
        
        //非dropdown列表则隐藏所有dropdown,并执行按钮功能
        if (!$target.hasClass("zte-btn-dropdown"))
        {
            this.$$dropdown.hide();
            this["tool_" + $target.attr("data-attr")]($target.attr("data-attr"),e);
        }
    },
    
    showDropdown: function(e)
    {//3.2:特别按钮:展示dropdown列表
        Z.E.forbidden(e);
        var thisBtn = Z.E.current(e);
        //执行按钮默认操作
        this.btnDefaultClick(thisBtn);
        
        //显示dropdown列表
        var dropdown = Z(thisBtn).children("ul.zte-btn-dropdown");
        this.$$dropdown.hide();
        if (Z(dropdown).isHide())
            Z(dropdown).show();
    },
    
    dropdownSelect: function(e)
    {//3.3:dropdown 选项点击事件
        Z.E.forbidden(e);
        var $target = Z(Z.E.current(e));
        var $parent = $target.parent();
        var $show = Z($parent[0].previousElementSibling);
        var showVal = $target.text();
        var dataType =  $target.parent().attr("data-type");
        var dataVal = $target.attr("data-value");
        //填入选中值,显示
        $show.html('<i class="z-font z-arrowhead-down z-float-right z-px10"></i>' + showVal);
        
        //判断是否存在选中,光标位置
        
        //根据类型,执行不同处理
        this["tool_" + dataType](dataType,dataVal);
        //隐藏列表
        $parent.hide();
    },
    
    doKeydown: function(e)
    {//4.1:键盘keydown事件,编辑过程,统一格式
        var keyCode = Z.E.key(e);
        //回车换行
        if (keyCode == 13)
            this.doNewline();
        if (e.ctrlKey)
        {//Ctrl组合键
            if (e.keyCode == 89)
            {// Ctrl + Y
                Z.E.forbidden(e);
                this.tool_redo(e);
            }
            if (e.keyCode == 90)
            {// Ctrl + Z
                Z.E.forbidden(e);
                this.tool_undo(e);
            }
        }
        
        //隐藏图片缩放框
        this.zoomCoverHide();
    },
    
    doNewline: function(e)
    {//4.2:统一“回车”、“换行”格式;针对<pre><code>标签特殊处理;TODO 待处理
        return;
        //等待编辑
        /*
        var startEle = this.getSelectionEle();
        var startEleTag = startEle.tagName;
        if (startEleTag == "PRE" || startEleTag == "NODE")
        {//如果是<pre>、或<code>标签内容
            //禁用默认操作
            //Z.E.forbidden();
            //var insertEle = document.createDocumentFragment();
            //insertEle.appendChild(Z("<p><br></p>")[0]);
            //this.range.insertNode(insertEle);
            //定位光标
        }
        
        //顶级元素
        var topEle = this.getSelectionTopEle(startEle);
        if (topEle)
        {
            var topEleTag = topEle.tagName;
            var closestBlock = this.getClosestBlock(startEle);
            if (closestBlock)
            {//存在最近的块级元素,修改为p标签
                if (topEle != closestBlock && Z(topEle).css("display") == "block" && Z.AR.indexOf(paragraph, topEleTag) == -1)
                {//顶级标签为非p,直接去掉
                    var $newP = Z("<p></p>");
                    $newP.html(Z(topEle).html()).insertBefore(Z(topEle));
                    Z(topEle).remove();
                }
                var $newP2 = Z("<p></p>");
                $newP2.html(Z(closestBlock).html()).insertBefore(Z(closestBlock));
                Z(closestBlock).remove();
            }
            else
            {//没有块级元素的情况
                var $newP = Z("<p></p>");
                $newP.html(Z(closestBlock).html()).insertBefore(Z(closestBlock));
                Z(closestBlock).remove();
            }
        }
        var $newP = Z("<p></p>");
        $newP.html(Z(closestBlock).html()).insertBefore(Z(closestBlock));
        Z(closestBlock).remove();
        */
    },
    
    editorCheck: function(e)
    {//5.1:几种编辑结束判断:(blur keyup cut paste drop dragend),对编辑器进行检查
        var ev = e || window.event;
        if (ev.type == "cut" || ev.type == "paste" || ev.type == "drop")
        {//drop事件处理,用settimeout延时获取编辑器内容
            var _this = this;
            var dropTimeout = setTimeout(function()
            {
                _this.editorCheck_action(_this);
                _this = null;
                clearTimeout(dropTimeout);
            },50);
            return;
        }
        this.editorCheck_action();
    },
    
    editorCheck_action: function(obj)
    {//5.2:操作结束后的处理,编辑器内容对比
        var _this = obj || this;
        var html = _this.$editor.html();
        if (html == "")
            _this.saveEditorHtml();
        _this.html = html;
        _this.saveTextareaValue(_this.$editor.html());
        //存储选取、存储历史记录
        _this.saveHistory();
    },
    
    setCommandedTool: function()
    {//6:选区变换,标注以实现功能的按钮;定时器延时处理
        var _this = this;
        var setTime = setTimeout(function()
        {
            //存储选区
            _this.saveSelection();
            //遍历查找,看有没有已编辑对象
            var tools = _this.tools;
            for (var i = 0;i < tools.length;i++)
            {
                if (tools[i] == "|") continue;
                if (document.queryCommandState(tools[i]))
                    _this.$$tools[tools[i]].addClass("zte-active");
                else
                    _this.$$tools[tools[i]].removeClass("zte-active");
            }
            //释放定时器、对象
            clearTimeout(setTime);
            _this = null;
        },50)
    },
    
    initDialogList: function()
    {//7:隐藏所有弹窗、列表
        this.$$dropdown.hide();
        this.colorPickerHide();
    },
    
    /***********************************************************************************************/
    //三:
    /***********************************************************************************************/
    
    saveEditorHtml: function(html)
    {//3:赋值给编辑器
        if (html && Z.V.isNotEmptyBlank(html))
            this.$editor.html(html);
        else
            this.$editor.html("<p><br></p>");
        this.html = this.$editor.html();
    },
    
    saveTextareaValue: function(html)
    {//3.1:有内容,才赋值textarea
        var html = Z.S.trim(html).replace(/\s/gi,"").replace(/&nbsp;/gi,"").replace(/<p><\/p>/gi,"").replace(/<p><br><\/p>/gi,"");
        if (Z.V.isNotEmptyBlank(html))
            this.$textarea.val(this.html);
        else
            this.$textarea.val("");
    },
    
    setCursorEnd: function()
    {//4:设置光标,到编辑器末尾
        var sel = window.getSelection();  
        var range = document.createRange();
        //找到最后的文本节点对象
        var node = this.getLastTextNode(this.$editor[0]);
        //添加选区为内容末尾
        range.collapse(true);
        range.setStart(node,node.length);
        range.setEnd(node,node.length);
        sel.removeAllRanges();
        sel.addRange(range);
        //存储选区
        this.selection = sel;
        this.range = range;
    },
    
    /***********************************************************************************************/
    //四:自定义get方法/获取
    /***********************************************************************************************/
    
    getClosetParent: function(ele,target)
    {//2:获取最近的祖先元素,从自己开始
        var $parent = Z(ele);
        if (!$parent[0]) return null;
        var allTarget = Z(document).find(target);
        while ($parent[0] && $parent[0].tagName != "BODY")
        {//没找到就继续找,除非找到了根目录
            for (var i = 0;i < allTarget.length;i++)
            {
                if (allTarget[i] == $parent[0])
                    return allTarget[i]
            }
            $parent = $parent.parent();
        }
        return null;
    },
    
    getSelectionEle: function()
    {//3.1:获取编辑区选中对象的元素节点;不存在则返回NULL
        var anchorEle = (this.selection.anchorNode)?
                        ((this.selection.anchorNode.type == 1)?(this.selection.anchorNode):(this.selection.anchorNode.parentNode)):(null);
        if (anchorEle == this.$editor[0])
            return null;
        return anchorEle;
    },
    
    getSelectionTopEle: function(ele)
    {//3.2:获取编辑区选中对象的最高节点,不存在则返回NULL
        var children = this.$editor.children();
        var parent = ele;
        while (parent != this.$editor[0])
        {
            for (var i = 0;i < children.length;i++)
            {
                if (children[i] == parent)
                    return parent;
            }
            parent = parent.parentNode;
        }
        return null;
    },
    
    getCursortPos: function()
    {//3.3:获取选区光标位置
        var CaretPos = 0;
        // IE Support  
        if (document.selection) {   
            ctrl.focus (); // 获取焦点  
            var Sel = document.selection.createRange (); // 创建选定区域  
            Sel.moveStart('character', -ctrl.value.length); // 移动开始点到最左边位置  
            CaretPos = Sel.text.length;                      // 获取当前选定区的文本内容长度  
        }   
        // Firefox support   
        else if (ctrl.selectionStart || ctrl.selectionStart == '0'){  
            CaretPos =ctrl.selectionStart; // 获取选定区的开始点   
        }  
        return CaretPos;   
    },
    
    getClosestBlock: function(ele)
    {//3.4:获取最近的block元素
        while (Z(ele).css("display") != "block" && ele.tagName != "P" && Z(ele) != this.$editor)
            ele = ele.parentNode;
        if (Z(ele) == this.$editor || ele.tagName == "P")
            return null;
        return ele;
    },
    
    getLastTextNode: function(ele)
    {//3.5:内容中最后的文本节点
        var ignoreName = ["BR","IMG","INPUT"];
        var node = ele.lastChild;
        var eleParent = ele.parentElement;
        if (node)
        {
            if (node.nodeType == 1)
            {//元素节点,重复查找
                node = this.getLastTextNode(node);
            }
            if (node.nodeType == 3)
            {//文本节点,直接返回
                return node;
            }
            if (node.nodeType == 8)
            {//注释节点,添加非占位字符
                ele.insertAdjacentHTML("beforeend","&#8203;");
                node = ele.lastChild;
            }
        }
        else if (eleParent)
        {
            var newEle = ele;
            if (Z.AR.contains(ignoreName, ele.nodeName))
                newEle = eleParent;
            ele.insertAdjacentHTML("beforeend","&#8203;");
            node = ele.lastChild;
        }
        return node;
    },

    /***********************************************************************************************/
    //五:自定义方法
    /***********************************************************************************************/
    
    insertColorPicker: function(attr)
    {//1.2:插入颜色选择器
        var colorAlternatived =[
            "EB3D00","EC3A3E","F25F61","FA9D99","F67D6F","C28482","C26A74","976D6B","C16B61","955942",
            "F48000","F47E36","F99F3D","F99F61","D76F4C","F99E7E","FCC78C","FEC7AF","BF6C35","C18557",
            "FDC800","FDFA00","FDFC72","FDFE99","FEFEC6","C1A25F","C0C165","94946A","968064","71624E",
            "009049","1E8F6E","6AC334","AADC7D","8FAE6B","8FAE84","75886C","75887E","95947E","72635B",
            "AADBC7","62C2A1","90AD9F","00AEC4","218E9E","1E8F85","2B726C","567C7E","455F60","4D4A42",
            "340C70","0074C5","0089E1","60BFF3","90ABBD","758792","5C676E","5F6D84","706F61","414548",
            "EF2F72","FD9CB9","C4A0AB","C38296","C371A0","C3538B","A14875","A06186","97576D","824275",
            "653B73","774389","97679F","C18DB8","BBB0D4","9081B6","715D9D","7A6F95","977F87","73545D",
            "9B2575","9E7996","495577","6476B3","624F5D","4F495C","684B6C","7F647A","FFFFFF","000000",
        ];
        //定义列数,计算行数
        var columns = 10;
        var lines = Math.ceil(colorAlternatived.length / columns);
        //计算灰度色值
        var grayNum = 16 / lines;
        //通用颜色变量
        var color = "";
        var html = '<div class="zte-colorPicker" data-target="' + attr + '"><div class="zte-colorPicker-arrow"></div><div class="zte-colorPick-table"><table><tr><td colspan=12 class="zte-colorPicker-title">选择颜色</td></tr>';
        //循环,所有颜色
        for (var i = 0;i < lines;i++) {                             //行 i
            html += '<tr>';
            var hexNum = Math.abs(Math.ceil(16 - (i+1) * grayNum)).toString(16);
            var grayColor = new Array(7).join(hexNum);
            html += '<td><a style="background:#' + grayColor + ';" data-value="#' + grayColor + '" title="#' + grayColor + '"></a></td>';
            html += '<td style="border:none;"></td>';
            for (var j = 0;j < columns;j++) {                       //列 j
                color = colorAlternatived[i*columns + j];
                if (!color) {
                    break;
                }
                html += '<td><a style="background:#' + color + ';" data-value="#' + color + '" title="#' + color + '"></a></td>';
            }
            html += '</tr>';
        }
        html += '</tr></table></div>';
        html += '</div></div>';
        
        var $thisPicker = (this["$colorPicker_" + attr] = Z(html));
        this.$$colorPicker.push($thisPicker)
        this.$dialogContainer.append($thisPicker);
    },
    
    saveSelection: function()
    {//2.1:选区Selection,存储
        var sel = window.getSelection();
        if(sel.rangeCount > 0 && sel.anchorNode.tagName != "BODY")
        {
            var anchorEle = (sel.anchorNode.type == 1)?(sel.anchorNode):(sel.anchorNode.parentNode);
            if (!anchorEle) return;
            var editor = this.getClosetParent(anchorEle,".zte-editor");
            if (editor == this.$editor[0])
            {//选区在编辑器内,赋值 this.selection、this.range
                this.selection = sel;
                this.range = sel.getRangeAt(0);
            }
        }
        else this.setCursorEnd();
    },
    
    loadSelection: function()
    {//2.2:选区Selection,读取
        var container = this.range.endContainer;
        if (container == this.$editor[0] || container == document)
            this.setCursorEnd();
        else
        {
            var sel = window.getSelection();  
            sel.removeAllRanges();
            sel.addRange(this.range);
        }
    },
    
    saveHistory: function()
    {//3.1:添加历史记录
        this.html = this.$editor.html();
        this.saveTextareaValue(this.$editor.html());
        //判断当前是否存在修改
        if (this.html == this.htmlHistory[this.historyIndex].html)
            return;
        this.saveSelection();
        if (this.historyIndex < this.htmlHistory.length - 1)
        {//判断 this.historyIndex 的位置,去掉后面多余的部分
            var num = this.htmlHistory.length - 1 - this.historyIndex;
            while (num > 0)
            {
                this.htmlHistory.pop();
                num--;
            }
        }
        this.htmlHistory.push({html: this.html,range: this.range});
        this.historyIndex = this.htmlHistory.length - 1;
        //按钮样式
        if (this.$buttonBar.find("[data-attr=html]").hasClass("zte-active"))
            return;
        this.$$tools.undo.removeClass("zte-btn-disable");
        this.$$tools.redo.addClass("zte-btn-disable");
        //遍历所有<img>标签,添加缩放功能
        this.addImgZoom();
    },
    
    loadHistory: function(type)
    {//3.2:读取历史记录
        this.historyIndex += type;
        if (this.historyIndex < 0)
            this.historyIndex = 0;
        if (this.historyIndex > this.htmlHistory.length - 1)
            this.historyIndex = this.htmlHistory.length - 1;
        //赋值编辑器
        var html = this.htmlHistory[this.historyIndex].html;
        this.saveEditorHtml(html);
        //载入选区
        var sel = window.getSelection();  
        sel.removeAllRanges();  
        sel.addRange(this.htmlHistory[this.historyIndex].range);
        //遍历所有<img>标签,添加缩放功能
        this.addImgZoom();
    },
    
    //4.1:按钮执行功能
    //command 用于:bold、italic、underline、strikethrough、insertorderedlist、insertrderedlist、justifyLeft、justifyCenter、justifyRight
    //activeOrNot:表示保持激活状态或非激活状态;noSave:不保存选区&历史
    doCommandMain: function(command,value,activeOrNot,noSave)
    {
        //载入选区
        this.loadSelection();
        //判断是否已执行,添加相应样式
        if (typeof activeOrNot === "boolean")
        {
            if (activeOrNot === true) this.$$tools[command].addClass("zte-active");
        }
        else
        {
            var hasDone = document.queryCommandState(command);
            if (hasDone) this.$$tools[command].removeClass("zte-active");
            else this.$$tools[command].addClass("zte-active");
        }
        //执行功能
        document.execCommand(command,false,value);
        //存储选区、存储历史
        if (!noSave)
            this.saveHistory();
    },
    
    doCommandSupSub: function(command)
    {//4.2:按钮执行功能,command 用于:superscript、subscript
        //载入选区
        this.loadSelection();
        //判断是否已执行,添加相应样式
        var hasDone = document.queryCommandState(command);
        //已执行功能的选区
        if (hasDone)
        {
            this.$$tools[command].removeClass("zte-active");
            //去除
            document.execCommand(command,false,null);
        }
        //未执行功能的选区
        else
        {
            this.$$tools[command].addClass("zte-active");
            //执行
            document.execCommand(command,false,null);
        }
        //存储选区、存储历史
        this.saveHistory();
    },
    
    doCommandInsertlist: function(command)
    {//4.3:列表插入功能,添加额外样式,command 用于:insertorderedlist、insertunorderedlist
        this.removeSiblingsActive(command);
        //载入选区
        this.loadSelection();
        //先判断执行状态
        var hasDone = document.queryCommandState(command);
        //再执行功能
        document.execCommand(command,false);
        if (!hasDone)
        {
            this.$$tools[command].addClass("zte-active");
            var startEle = this.getSelectionEle();
            var liEle = this.getClosetParent(startEle,"li");
            var listTag = command.substring("6","7") + "l";
            var listEle = this.getClosetParent(startEle,listTag);
            var liAttr = liEle.getAttribute("style");
            var listAttr = listEle.getAttribute("style");
            var listStyle = (listTag == "ol")?("decimal"):("disc");
            if (!liAttr)
                Z(liEle).css({"list-style":listStyle});
            if (!listAttr)
                Z(listEle).css({"padding":"0 0 0 40px","margin":"15px 0","list-style":listStyle});
        }
        else
            this.$$tools[command].removeClass("zte-active");
        //存储选区、存储历史
        this.saveHistory();
    },
    
    doCommandPicker: function(command,e)
    {//4.4:颜色选择器功能
        var target = Z.E.target(e);
        var $btn = this.$$tools[command]
        if (target == $btn.find(".zte-pickerBtn")[0])
        {//如果点击对象是三角图标,触发显示选则框
            Z.E.forbidden(e);
            var left = $btn.offsetLeft();
            var top = $btn.offsetTop() + $btn.offsetHeight() + 3;
            this["$colorPicker_" + command].show().css({left:left,top:top});
        }
        else
        {//应用当前已选择的颜色
            var color = this.$$tools[command].find(".zte-pickedColor").css("backgroundColor");
            color = this.color2hex(color);
            this.doCommandMain(command,color,false);
        }
    },
    
    doColorPicker: function(e)
    {//5.1:颜色选择器选中颜色
        Z.E.forbidden(e);
        //载入选区
        this.loadSelection();
        var $target = Z(Z.E.target(e));
        var color = $target.attr("data-value");
        var command = Z(this.getClosetParent($target[0],".zte-colorPicker")).attr("data-target");
        this.$$tools[command].find(".zte-pickedColor").css("backgroundColor",color);
        document.execCommand(command,false,color);
        this.colorPickerHide();
        //存储选区、存储历史
        this.saveHistory();
    },
    
    colorPickerHide: function()
    {//5.2:颜色选择器隐藏
        for (var i = 0;i < this.$$colorPicker.length;i++)
            this.$$colorPicker[i].hide();
    },
    
    color2hex: function(str)
    {//5.3:颜色统一转换为 #000000 的格式
        var strHex = "#";
        if (/^(rgba|RGBA|rgb|RGB)/.test(str))
        {
            var colorArr = str.replace(/(?:\(|\)|rgba|RGBA|rgb|RGB)*/g, "").split(",");
            for(var i = 0;i < 3;i++){
                var hex = Number(colorArr[i]).toString(16);
                if (hex === "0") hex += hex;
                strHex += hex;
            }
            return strHex;
        }
        return strHex;
    },
    
    removeSiblingsActive: function(conmand)
    {//6:取消同类型功能其他功能激活样式,去除"zte-active"
        var thisEle = this.$$tools[conmand][0];
        //向上查找
        var $preSibling = Z(thisEle.previousElementSibling);
        while ($preSibling[0] && !$preSibling.hasClass("zte-btn-separator"))
        {
            $preSibling.removeClass("zte-active");
            $preSibling = Z($preSibling[0].previousElementSibling);
        }
        //向下查找
        var $nextSibling = Z(thisEle.nextElementSibling);
        while ($nextSibling[0] && !$nextSibling.hasClass("zte-btn-separator"))
        {
            $nextSibling.removeClass("zte-active");
            $nextSibling = Z($nextSibling[0].nextElementSibling);
        }
    },
    
    
    doLinkCreat: function(e)
    {//7:实现链接添加操作
        var $createrTable = Z(this.getClosetParent(Z.E.target(e),"table"));
        var createrTitle = $createrTable.find("#zte-linkCreater-title").val();
        var createrLink = $createrTable.find("#zte-linkCreater-link").val();
        var createrBlank = $createrTable.find("#zte-linkCreater-blank")[0].checked;
        //去除遮罩
        Z.Dialog.close();
        //插入链接
        this.doCommandMain("createLink",createrLink,true,false);
        //添加title、blank信息
        var $aLinkEle = Z(this.getSelectionEle());
        $aLinkEle.attr("title",createrTitle).attr("target",(createrBlank)?("_blank"):(""));
        //存储选区、存储历史
        this.saveHistory();
    },
    
    /***********************************************************************************************/
    //图片添加功能(1、本地图片上传后保存,2、网络图片通过HTTP下载后保存)
    /***********************************************************************************************/
    
    insertHtmlSwitch: function(e)
    {//8.1:图片添加功能,切换添加方式
        var $thisBtn = Z(Z.E.target(e));
        var $targetEle = Z("." + $thisBtn.attr("data-target"));
        $thisBtn.addClass("zte-active").siblings("span").removeClass("zte-active");
        $targetEle.addClass("zte-active").siblings("div").removeClass("zte-active");
    },
    
    insertImgLocClick: function(e)
    {//8.2:本地图片添加
        Z("#zte-imgInsertor-fileInput")[0].click();
    },
    
    insertImgLoc: function(e)
    {//8.3:图片读取上传
        var file = Z.E.target(e).files[0];
        var fileSize = file.size;
        if (fileSize > this.maxSize) 
            return Z.failure("上传图片超出最大限制,请重新选择图片!");
        
        var _this = this;
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function()
        {
            var ajax = new Z.Ajax();
            ajax.setContextPath(_this.contextPath);
            ajax.setClassName(Z.TextEditor.AJAX_CLASS);
            ajax.setMethodName(Z.TextEditor.AJAX_UPLOAD);
            ajax.addParam("fileData", reader.result);
            ajax.addParam("fileDir", _this.fileDir);
            ajax.addParam("fileName", file.name);
            ajax.setFailureAlert();
            ajax.setCallback(function()
            {
                var src = (_this.origin?location.origin:"") + Z.rootPath(_this.contextPath, this.responseText);
                Z("#zte-imgInsertor-imgSourse").attr("src", src);
                Z(".zte-imgInsertor-conShow").addClass("zte-active").siblings("div").removeClass("zte-active");
                Z(".zte-dialogSwitchBtn > span,.zte-imgInsertor-conUrl").addClass("zte-disable");
            });
            ajax.execute();
        };
    },
    
    insertImgWeb: function(e)
    {//8.4:网络图片添加
        var fileUrl =Z("#zte-imgInsertor-webUrl").val();
        
        //检测是否为有效地址
        var urlReg = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/;
        if (!urlReg.test(fileUrl))
            return Z.failure("请输入正确的图片地址");
            
        //禁用二次点击
        Z(".zte-imgInsertor-conWeb").addClass("zte-disable");
        
        var _this = this;
        var ajax = new Z.Ajax();
        ajax.setContextPath(this.contextPath);
        ajax.setClassName(Z.TextEditor.AJAX_CLASS);
        ajax.setMethodName(Z.TextEditor.AJAX_UPLOADWWW);
        ajax.addParam("fileDir", this.fileDir);
        ajax.addParam("fileUrl", fileUrl);
        ajax.setCallback(function()
        {
            Z(".zte-imgInsertor-conWeb").removeClass("zte-disable");
            if (this.responseStatus != 0)
                return Z.failure(this.responseText);
            
            var src = (_this.origin?location.origin:"") + Z.rootPath(_this.contextPath, this.responseText);
            Z("#zte-imgInsertor-imgSourse").attr("src", src);
            Z(".zte-imgInsertor-conShow").addClass("zte-active").siblings("div").removeClass("zte-active");
            Z(".zte-dialogSwitchBtn > span,.zte-imgInsertor-conUrl").addClass("zte-disable");
        });
        ajax.execute();
    },
    
    insertImgRedo: function(e)
    {//8.5:重新添加图片
        var $targetEle = Z("." + Z(".zte-dialogSwitchBtn > span.zte-active").attr("data-target"));
        Z(".zte-dialogSwitchBtn > span,.zte-imgInsertor-conUrl").removeClass("zte-disable");
        Z(".zte-imgInsertor-conShow").removeClass("zte-active");
        $targetEle.addClass("zte-active");
        //重置input的值
        Z("#zte-imgInsertor-fileInput")[0].value = "";
        Z("#zte-imgInsertor-webUrl").val("");
    },
    
    insertImgConfirm: function(e)
    {//8.6:确定添加到编辑内容,执行添加
        //载入选区
        this.loadSelection();
        var imgSrc = Z("#zte-imgInsertor-imgSourse")[0].getAttribute("src");
        var value = '<img width="" height="" src="' + imgSrc + '">';
        this.doCommandMain("insertHTML",value,false);
        //去除遮罩
        Z.Dialog.close();
        //编辑器检查
        this.editorCheck_action(this);
    },
    
    addImgZoom: function()
    {//9.1:为编辑内容中图片,添加缩放功能
        var $$imgs = this.$editor.find("img");
        for (var i = 0;i < $$imgs.length;i++)
        {
            var $img = Z($$imgs[i]);
            if (!$img.hasOn)
            {
                $img.hasOn = true;
                $img.on("click",this.zoomCoverShow,this);
                $img.on("mousedown mouseup mousemove dragstart click dblclick",function(e){Z.E.forbidden(e)},this);
            }
        }
    },
    
    zoomCoverShow: function(e)
    {//9.2:显示缩放编辑容器 mouseenter
        var thisImg = Z.E.target(e);
        this.$zoomToolCover.show();
        this.locationToolCover(e,thisImg);
    },
    
    zoomCoverHide: function(e)
    {//9.3:隐藏缩放编辑容器 mouseleave
        this.$zoomToolCover.hide();
    },
    
    zoomToolMousedown: function(e)
    {//10.1:编辑器内容图片,缩放操作:mousedown
        //可缩放标识
        this.$zoomToolCover.canZoom = true;
        //存储点击对象、鼠标点下的坐标、原始图片大小
        var $img = Z(this.$zoomToolCover.targetImg);
        this.$zoomToolCover.mouseType = Z.E.target(e).className.substring(13);
        this.$zoomToolCover.mouseLocation = {x: e.pageX, y: e.pageY};
        this.$zoomToolCover.sourseSize = {width: $img.offsetWidth(), height: $img.offsetHeight()};
    },
    
    zoomToolMousemove: function(e)
    {//10.2:编辑器内容图片,缩放操作:mousemove
        if (!this.$zoomToolCover.canZoom)
            return;
        Z.E.forbidden(e);
        //执行缩放操作
        var $img = Z(this.$zoomToolCover.targetImg);
        var oldLoc = this.$zoomToolCover.mouseLocation;
        var oldSize = this.$zoomToolCover.sourseSize;
        var newWidth = oldSize.width + (e.pageX - oldLoc.x);
        var newHeight = oldSize.height + (e.pageY - oldLoc.y);
        switch (this.$zoomToolCover.mouseType)
        {
            case "e": newHeight = oldSize.height;break;
            case "se":
                var oldRadio = oldSize.width/oldSize.height;
                var newRadio = newWidth/newHeight;
                if (oldRadio > newRadio)
                    newWidth = newHeight * oldRadio;
                else
                    newHeight = newWidth / oldRadio;
                break;
            case "s": newWidth = oldSize.width;break;
        }
        $img.css({"width": newWidth,"height": newHeight});
        this.locationToolCover(e,$img[0]);
    },
    
    zoomToolMouseup: function(e)
    {//10.3:编辑器内容图片,缩放操作:mouseup
        if (this.$zoomToolCover.canZoom)
        {//结束图片缩放操作,并存储历史纪录
            this.$zoomToolCover.canZoom = false;
            //存储选区、存储历史
            this.saveHistory();
        }
    },
    
    locationToolCover: function(e,ele)
    {//10.4:编辑图片,更新缩放工具定位,保持和图片重合
        if (this.$zoomToolCover.isHide())
            return;
        var scrollTop, top;
        if (e.type == "scroll")
        {//执行滚动事件时,只修改高度值
            scrollTop = this.$editor[0].scrollTop;
            top = this.$zoomToolCover.sourseTop - scrollTop;
            console.log(scrollTop,this.$zoomToolCover[0].sourseTop,top);
            this.$zoomToolCover.css("top",top);
            return;
        }
        //固定高度:sourseTop,指定对象:targetImg
        this.$zoomToolCover.sourseTop = Z(ele).offsetTop();
        this.$zoomToolCover.targetImg = ele;
        //确定缩放容器的大小和位置
        scrollTop = this.$editor[0].scrollTop;
        var width = Z(ele).offsetWidth();
        var height = Z(ele).offsetHeight();
        var left = Z(ele).offsetLeft();
        top = Z(ele).offsetTop() - scrollTop;
        this.$zoomToolCover.css({"width":width,"height":height,"left":left,"top":top,});
    },
    
    insertSymbolHtml: function(symbolArr)
    {//11.1:插入特殊字符;返回表格字符串
        var symbolNum = symbolArr.length, colNum = 15, rowNum = Math.ceil(symbolNum / colNum);
        var html = '<table class="z-table"><tr>';
        for (var i = 0;i < symbolNum;i++)
        {//colNum 为列数;rowNum 为行数
            if (i != 0 && i % colNum == 0)
                html += '</tr><tr>';
            html += '<td><a>' + symbolArr[i] + '</a></td>';
        }
        html += '</tr></table>';
        return html;
    },
    
    insertSymbolConfirm: function(e)
    {//11.2:插入特殊符号,执行插入功能
        //载入选区
        this.loadSelection();
        var insertSymbol = Z(Z.E.target(e)).text();
        document.execCommand("insertText",false,insertSymbol);
        //去除遮罩
        Z.Dialog.close();
            //存储选区、存储历史
        this.saveHistory();
    },
}

//end
})(zhiqim)