+function($){

/**
 * 定义基础内部全局变量
 */
var
    /**
     * 当前window对象
     * @type {jQuery Object}
     */
    $win = $(window),

    /**
     * 当前document对象
     * @type {jQuery Object}
     */
    $doc = $(document),

    /**
     * ThinkEditor 对象
     * @type {Object}
     */
    ThinkEditor,

    /**
     * 封装过的textarea Range对象
     * @type {Object}
     */
    Range,

    /**
     * 编辑器弹出层对象
     * 主要提供给一些需要复杂功能的插件使用
     * 在插件中使用 this.dialog()方法调用
     * @type {Object}
     */
    Dialog,

    /**
     * ThinkEditor插件对象,所有的操作都是通过该对象实现
     * @type {Object}
     */
    Plugin = {},

    /**
     * ThinkEditor语言包对象
     */
    Language = {},

    /**
     * 键盘按键对应数值表
     * @type {Object}
     */
    KeyCode = {
        "BACKSPACE" : 8,
        "TAB"       : 9,
        "ENTER"     : 13,
        "ESC"       : 27,
        "SPACE"     : 32,
        "F1"        : 112,
        "F2"        : 113,
        "F3"        : 114,
        "F4"        : 115,
        "F5"        : 116,
        "F6"        : 117,
        "F7"        : 118,
        "F8"        : 119,
        "F9"        : 120,
        "F10"       : 121,
        "F11"       : 122,
        "F12"       : 123
    },

    /**
     * 默认配置项,创建Tree时传入的配置项会和该配置合并
     * @type {Object}
     */
    Defaults = {
        /**
         * 显示风格
         * 目前仅支持默认风格,可自己扩展
         */
        "style" : "default",

        /**
         * 编辑器插件按钮配置
         * 没配置到这里的插件不能显示在工具栏
         * 如果设置了快捷键依然生效
         */
        "items" : "h1,h2,h3,h4,h5,h6,-,link,image,-,bold,italic,code,-," +
                  "ul,ol,blockquote,hr,-,fullscreen,save",

        /**
         * 编辑器默认宽度
         * 默认自适应父容器
         */
        "width" : "100%",

        /**
         * 编辑器高度,默认自适应父容器
         * 设置为100%时一定要给父元素设置高度
         */
        "height" : "100%",

        /**
         * 编辑器显示语言
         * 目前仅支持简体中文和英文
         * 可以在调用编辑器之前调用$.thinkeditor.language方法扩展
         */
        "lang" : "zh-cn",

        /**
         * 按TAB键插入的字符
         * 默认为四个空格,一般情况下为空格或制表符
         * 插入制表符请写 \t
         */
        "tab" : "    ",

        /**
         * 图片上传插件上传到的URL
         * 该URL必须返回JSON数据
         * 数据格式:
         * {
         *     "status" : 1,
         *     "info"   : "message",
         *     "files"  : [] //文件信息
         * }
         */
        "uploader" : "",

        /**
         * 图片上传表单名称
         * 即<input type="file" name=""/>name属性默认设置的值
         */
        "dataName" : "images",

        /**
         * 保存按钮点击后调用的回调函数
         */
        "onSave" : $.noop //保存按钮回调接口
    },

    DialogWraper = [
        '<div class="thinkeditor-dialog">',
            '<div class="thinkeditor-dialog-header">',
                '<span class="thinkeditor-dialog-title"></span>',
                '<span class="thinkeditor-dialog-close"></span>',
            '</div>',
            '<div class="thinkeditor-dialog-body"></div>',
            '<div class="thinkeditor-dialog-footer">',
                '<div class="thinkeditor-dialog-status"></div>',
                '<div class="thinkeditor-dialog-tools">',
                    '<button type="button" class="thinkeditor-dialog-btn-ok"></button>',
                    '<button type="button" class="thinkeditor-dialog-btn-cancel"></button>',
                '</div>',
            '</div>',
        '</div>'
    ].join("");

/**
 * Range构造器,用于创建一个新的Range对象
 * @param {Object} textarea 一个textarea对象,用于创建Range
 */
Range = function(textarea){
    /* 绑定Range对象的textarea */
    this.textarea = textarea;
}

/**
 * 扩展Range原型,主要添加了get,set,insert三个方法
 * @type {Object}
 */
Range.prototype = {
    /**
     * 获取当前range
     * @return {Object} 当前range对象
     */
    "get" : function(){
        var textarea = this.textarea,
            data     = {"start" : 0, "end" : 0, "text" : ""},
            range, dupRange, rangeNl, dupRangeNl;

        textarea.focus();
        if (textarea.setSelectionRange) { // W3C
            data.start = textarea.selectionStart;
            data.end   = textarea.selectionEnd;
            data.text  = (data.start != data.end) ?
                         textarea.value.substring(data.start, data.end) : "";
        } else if (document.selection) { // For IE
            range    = document.selection.createRange(),
            dupRange = range.duplicate();
            dupRange.moveToElementText(textarea);
            dupRange.setEndPoint("EndToEnd", range );

            data.text  = range.text; //选中的文本内容
            rangeNl    = range.text.split("\n").length - 1; //选中文本换行数
            dupRangeNl = dupRange.text.split("\n").length - 1; //选中之前换行数
            data.start = dupRange.text.length - range.text.length -
                         dupRangeNl + rangeNl;
            data.end   = data.text.length + data.start - rangeNl;
        }

        return data;
    },

    /**
     * 设置当前range的位置
     * @param  {Integer} start 起始位置
     * @param  {Integer} end   结束位置
     * @return {Object}        当前Range对象
     */
    "set" : function (start, end) {
        var range, textarea = this.textarea;

        textarea.focus();
        if (textarea.setSelectionRange) { // W3C
            textarea.setSelectionRange(start, end);
        } else if (textarea.createTextRange) { // For IE
            range = textarea.createTextRange();
            range.collapse(true);
            range.moveStart("character", start);
            range.moveEnd("character", end - start);
            range.select();
        }

        return this;
    },

    /**
     * 在当前Range处插入文本
     * @param  {String} text 文本内容
     * @return {Object}      当前Range对象
     */
    "insert" : function (text) {
        var textarea = this.textarea, data = this.get(),
            oValue, nValue, range, scroll;

        if (textarea.setSelectionRange) { // W3C
            oValue         = textarea.value;
            nValue         = oValue.substring(0, data.start) + text +
                             oValue.substring(data.end);
            scroll         = textarea.scrollTop;
            data.end       = data.start + text.length;
            textarea.value = nValue;

            /**
             * Fixbug:
             * After textarea.values = nValue, scrollTop value to 0
             */
            if(textarea.scrollTop != scroll) {
                textarea.scrollTop = scroll;
            }

            textarea.setSelectionRange(data.start, data.end);
        } else if (textarea.createTextRange) { //For IE
            range      = document.selection.createRange();
            range.text = text;
            range.setEndPoint("StartToEnd", range);
            range.select();
        }

        return this;
    }
};

/**
 * 简单的弹出层对象,供需要弹出显示的插件调用
 * @param {Object} editor  编辑器对象
 * @param {Object} options 编辑器配置对象
 */
Dialog = function(editor, options){
    var self    = this, $dialog, $modal, defaults,
        $editor = $(editor.range.textarea).closest(".thinkeditor");

    /* 弹出层默认配置 */
    defaults = {
        "title"         : "title",
        "content"       : "<div></div>",
        "onOkClick"     : $.noop,
        "onCancelClick" : $.noop
    }

    //合并配置并创建弹出层
    options = $.extend({}, defaults, options || {});

    /* 创建弹出层内容区 */
    this.dialog = $dialog = $(DialogWraper).appendTo($editor);
    //创建遮罩层
    this.modal  = $modal = $("<div/>").addClass("thinkeditor-dialog-modal")
                           .appendTo($editor);

    /* 弹出层相关容器 */
    this.title   = $dialog.find(".thinkeditor-dialog-title"); //标题
    this.content = $dialog.find(".thinkeditor-dialog-body"); //内容
    this.status  = $dialog.find(".thinkeditor-dialog-status"); //状态信息

    /* 弹出层按钮 */
    this.btn = {
        "close"  : $dialog.find(".thinkeditor-dialog-close"),
        "ok"     : $dialog.find(".thinkeditor-dialog-btn-ok"),
        "cancel" : $dialog.find(".thinkeditor-dialog-btn-cancel")
    }

    /* 绑定关闭事件 */
    this.btn.close.click(function(){
        self.remove();
    });

    /* 绑定确定按钮事件 */
    this.btn.ok.click(function(){
        options.onOkClick.call(self, this);
    });

    /* 绑定取消按钮事件 */
    this.btn.cancel.click(function(){
        options.onCancelClick.call(self, this);
        self.remove();
    });

    //添加弹出层内容并
    this.setTitle(options.title);
    this.setContent(options.content);
    this.btn.ok.text(editor.lang("ok"));
    this.btn.cancel.text(editor.lang("cancel"));

    //显示弹出层
    $dialog.add($modal).fadeIn("fast");
}

/**
 * 弹出层标准接口
 * @type {Object}
 */
Dialog.prototype = {
    /**
     * 查找弹出层内容里的元素
     * @param  {String} expr jQuery支持的所有选择器
     * @return {Object}      jQuery对象
     */
    "find" : function(expr){
        return this.content.find(expr);
    },

    /**
     * 移动弹出层到屏幕中央
     * @return {Object} 弹出层对象
     */
    "moveToCenter" : function(){
        this.dialog.css({
            "top"  : ($win.height() - this.dialog.outerHeight()) / 2,
            "left" : ($win.width() - this.dialog.outerWidth()) / 2
        });
        return this;
    },

    /**
     * 重置弹出层内容
     * @param  {Object} content 弹出层内容对象,可以是html代码
     * @return {Object}         弹出层对象
     */
    "setContent" : function(content){
        this.content.empty().append(content);
        this.moveToCenter();
        return this;
    },

    /**
     * 改变弹出层标题
     * @param  {String} title 弹出层标题文字,可以是html代码
     * @return {Object}       弹出层对象
     */
    "setTitle" : function(title){
        return this.title.html(title);
    },

    /**
     * 设置弹出层状态信息
     * @param  {String}  info   状态信息
     * @param  {String}  status 状态标识,success,error
     * @param  {Boolean} dealy  是否自动关闭
     * @return {Object}         当前弹出层对象
     */
    "setStatus" : function(info, status, dealy){
        var $status = $("<span/>").text(info), timeout;

        /* 清楚原来计时器 */
        timeout = this.status.children("span").data("timeout");
        timeout && clearTimeout(timeout);

        /* 显示状态信息 */
        status && $status.addClass("thinkeditor-dialog-" + status);
        this.status.empty().append($status);

        /* 延时关闭 */
        if(dealy){
            $status.data("timeout", setTimeout(function(){
                $status.fadeOut("fast");
            }, 5000));
        }
        return this;
    },

    /**
     * 卸载当前弹出层
     */
    "remove" : function(){
        this.dialog.add(this.modal).fadeOut("fast", function(){
            this.remove();
        });
    }
};

/**
 * 创建编辑器工具栏
 * @param  {Object} $editor 编辑器对象
 * @param  {Object} options 配置项
 */
function create_editor_tools($editor, options){
    var self = this, items, groups = options.items.split(",-,"), $group,
        $tools = $("<div/>");

    /* 创建按钮组 */
    for(i in groups){
        items  = groups[i].split(",");
        $group = $("<div/>").addClass("thinkeditor-tools-group")
                 .appendTo($tools);
        for(j in items){
            $("<a/>").addClass("thinkeditor-tools-" + items[j])
                .attr({"title" : this.lang(items[j]), "href" : "javascript:;"})
                .data("name", items[j])
                .appendTo($group);
        }
    }

    /* 工具栏放入editor */
    $tools.addClass("thinkeditor-tools clearfix").prependTo($editor);

    /* 绑定操作事件 */
    $tools.on("click", ".thinkeditor-tools-group a", function(event){
        event.stopPropagation();
        self.plugin($(this).data("name"), options);
    });
}

/**
 * 执行快捷键
 * @param  {event} event 事件对象
 */
function keyboard(event){
    var keyboard = Array(4),
        self     = event.data.self,
        options  = event.data.options;

    /* 当前按键 */
    keyboard[0] = event.ctrlKey  ? "ctrl"  : "";
    keyboard[1] = event.shiftKey ? "shift" : "";
    keyboard[2] = event.altKey   ? "alt"   : "";
    keyboard[3] = event.which;
    keyboard    = keyboard.join("");

    /* 执行快捷键 */
    if(self.keyboards[keyboard]){
        if($.isFunction(self.keyboards[keyboard])){
            self.keyboards[keyboard].call(self);
        } else {
            self.plugin(self.keyboards[keyboard], options);
        }
        return false;
    }
}

/**
 * 编辑器构造器,用于创建一个新的编辑器对象
 * @param {Object} textarea 被创建编辑器的textarea对象
 * @param {Object} options  编辑器初始化选项
 */
ThinkEditor = function(textarea, options){
    var options, self = this, $textarea = $(textarea), $editor;

    /* 合并配置项 */
    options = $.extend({}, Defaults, options || {});
    options.width  = options.width  ? options.width  : $textarea.width();
    options.height = options.height ? options.height : $textarea.height();

    /* 创建Range对象 */
    this.range = new Range(textarea);
    this.language = Language[options.lang] ? options.lang : "en-us";

    /* 创建编辑器 */
    $textarea.wrap("<div/>").parent().wrap("<div/>");
    $editor = $textarea.parent().parent();

    $editor.addClass("thinkeditor thinkeditor-" + options.style);
    $editor.children("div").addClass("thinkeditor-textarea");
    //如果是预览创建预览div
    if(options.preview){
        options.width = '50%';
        $textarea.parent().after('<div/>');
        $textarea.css({resize: 'none'});
        $preview = $editor.find('.thinkeditor-textarea').next('div');
    }
    /* 设置editor尺寸 */
    $editor.css({"width" : options.width, "height" : options.height});

    /* 创建工具栏 */
    create_editor_tools.call(this, $editor, options);

    /* 绑定快捷键事件 */
    $textarea.keydown({"self" : this, "options" : options}, keyboard);

    /* 绑定插件的快捷键 */
    for(name in Plugin){
        Plugin[name].keyboard && this.keyboard(Plugin[name].keyboard, name);
    }
    if(options.preview){
        $preview.css({
            "width" : '100%',
            "height" : $textarea.outerHeight(true)+'px',
            left: '100%'
        });
        $preview.addClass('thinkeditor-preview');

        $preview.html(this.preview(this.range.textarea.value));
        _this = this;
        $textarea.keyup(function(){
            $preview.html(_this.preview(this.value));
        });
        $textarea.scroll(function(){
            fix_img_scroll();
        });
        var fix_img_scroll = function(){
            imgs = $preview.find("img") //获取预览下所有图片
            if (imgs.length > 0){
                imgs_height = 0
                for (var i in imgs){
                    tm = new Image()
                    tm.src = this.src
                    tow = tm.width
                    toh = tm.height
                    var limit_width = $preview.width()*0.5 //父容器50%的宽度
                    if (tow > limit_width){ //如果原始图片宽度大于限制宽度,真实rh高度也要缩放比例
                        r = tow / limit_width
                        rh = toh / r
                    }else{
                        rh = toh
                    }
                    imgs_height += rh //这个就是得到所有图片的高度
                }
            }
            caculate_and_scroll($textarea, $preview, imgs_height);
        }

        var caculate_and_scroll = function(editor, preview, imgs_height){ //这里只要再按比例计算一下滚动高度就行
            real_height = preview[0].scrollHeight + imgs_height;

            setTimeout(function(){
                if (real_height > editor[0].scrollHeight){
                    r = real_height / editor[0].scrollHeight;
                    preview.prop('scrollTop', editor.scrollTop() * r);
                }else{
                    r = editor[0].scrollHeight / real_height;
                    preview.prop('scrollTop', editor.scrollTop() / r);
                }
            }, 500);
        }
    }

}

/**
 * 编辑器原型,用于扩展编辑器的外部调用接口
 * @type {Object}
 */
ThinkEditor.prototype = {
    /**
     * 获取语言变量
     * @param  {String} name     变量名
     * @param  {String} language 语言,默认去当前options.lang
     * @return {String}          指定语言的值
     */
    "lang" : function(name, language){
        return Language[language || this.language][name] || name;
    },

    /**
     * 执行某个插件插件
     * @param {String} name    插件名称
     * @param {Object} options 编辑器配置项
     */
    "plugin" : function(name, options){
        var plugin = Plugin[name]
        plugin.markdown.call(this, options, plugin);
        return this;
    },

    /**
     * 插入数据到编辑器光标处
     * @param  {String} text 要插入的数据
     * @return {Object}      ThinkEditor对象
     */
    "insert" : function(text){
        var range = this.range.get(), start, _start, end, length, line = 0;
        if(arguments.length > 1){ //首尾添加文本
            start = arguments[0];
            end   = arguments[1];

            if(arguments[2]){ //按行添加
                text   = range.text.split("\n");
                length = range.text.length;

                /* 逐行添加 */
                for(i in text){
                    if(!length || $.trim(text[i])){
                        _start  = start.replace("{$line}", ++line)
                                       .replace("{$i}", i);
                        text[i] = _start + text[i] + end;
                    }
                }

                /* 插入数据 */
                this.range.insert(text.join("\n"));

                /* 没有选中文本时设置光标位置 */
                if(!length){
                    start = range.start + _start.length;
                    this.range.set(start, start);
                }
            } else {
                this.range.insert(start + range.text + end);
            }
        } else { //插入文本
            this.range.insert(text);
        }
        return this;
    },

    /**
     * 设置或获取编辑器的值
     * @param  {String} text 要设置的值,不传递此参数则获取编辑器的值
     * @return {String}      设置值 - 返回ThinkEditor对象, 获取值 - 返回当前值
     */
    "value" : function(text){
        if(text === undefined){
            return this.range.textarea.value;
        } else {
            this.range.textarea.value = text;
            return this;
        }
    },

    /**
     * 给编辑器绑定快捷键
     * @param  {String}   keys     快捷键名称
     * @param  {Function} callback 触发快捷键时执行额函数或插件名称
     * @return {Object}            当前编辑器对象
     */
    "keyboard" : function(keys, callback){
        var keyboard = Array(4); //[ctrl, shift, alt, code]

        //初始化快捷键
        if(!this.keyboards) {
            this.keyboards = {};
        }

        keys = keys.toUpperCase().split("+");
        for(i in keys){
            switch(keys[i]){
                case "CTRL" :
                    keyboard[0] = "ctrl";
                    break;
                case "SHIFT" :
                    keyboard[1] = "shift";
                    break;
                case "ALT" :
                    keyboard[2] = "alt";
                    break;
                default:
                    keyboard[3] = KeyCode[keys[i]] || keys[i].charCodeAt();
                    break;
            }
        }
        this.keyboards[keyboard.join("")] = callback;
        return this;
    },

    "dialog" : function(options){
        return new Dialog(this, options);
    },
    "preview": function(text){
        var opt = {
            renderer: new marked.Renderer(),
            gfm: true,
            tables: true,
            breaks: false,
            pedantic: false,
            sanitize: true,
            smartLists: true,
            smartypants: false
        }
        return marked(text, opt);
    }
}

/**
 * 通过textarea获取通过当前textarea创建的ThinkEditor对象
 * @param  {elements} textarea textarea对象或jquery textarea选择器
 * @return {Object}            ThinkEditor对象
 */
$.thinkeditor = function(textarea){
    return $(textarea).data("ThinkEditor");
};

/**
 * 添加ThinkEditor全局扩展
 * 提供对编辑器的语言包,插件,全局设置等功能
 */
$.extend($.thinkeditor, {
    /**
     * 扩展语言包
     * @param  {Object} language 语言包
     */
    "language" : function(language){
        $.extend(Language, $.isPlainObject(language) ? language : {});
    },

    /**
     * 扩展插件
     * @param  {Object} plugin 一个或多个插件
     */
    "plugin" : function(plugin){
        $.extend(Plugin, $.isPlainObject(plugin) ? plugin : {});
    },

    /**
     * 全局设置ThinkEditor
     * @param  {Object} options 要改变的编辑器默认设置项
     */
    "defaults" : function(options){
        $.extend(Defaults, $.isPlainObject(options) ? options : {});
    }
});

/**
 * jQuery.fn对象,用于创建ThinkEditor插件
 * @param  {Object} options ThinkEditor初始化参数
 */
$.fn.thinkeditor = function(options){
    return this.each(function(){
        $(this).data("ThinkEditor", new ThinkEditor(this, options));
    });
}

/**
 * ThinkEditor编辑器插件,工具按显示的每一个按钮代表一个插件
 * 一个合法的插件必须包含markdown方法,用于内部调用
 * 如果需要给插件设置快捷键,则可以通过 keyboard 属性来设置
 * 插件的this指针指向当前ThinkEditor对象
 */
$.thinkeditor.plugin({
    /* 标题一插件 */
    "h1" : {
        /* 标题一快捷键 */
        "keyboard" : "ctrl+1",

        /* 执行标题一 */
        "markdown" : function(options){
            this.insert("# ", "", true);
        }
    },

    /* 标题二插件 */
    "h2" : {
        /* 标题二快捷键 */
        "keyboard" : "ctrl+2",

        /* 执行标题二 */
        "markdown" : function(options){
            this.insert("## ", "", true);
        }
    },

    /* 标题三插件 */
    "h3" : {
        /* 标题三快捷键 */
        "keyboard" : "ctrl+3",

        /* 执行标题三 */
        "markdown" : function(options){
            this.insert("### ", "", true);
        }
    },

    /* 标题四插件 */
    "h4" : {
        /* 标题四快捷键 */
        "keyboard" : "ctrl+4",

        /* 执行标题四 */
        "markdown" : function(options){
            this.insert("#### ", "", true);
        }
    },

    /* 标题五插件 */
    "h5" : {
        /* 标题五快捷键 */
        "keyboard" : "ctrl+5",

        /* 执行标题五 */
        "markdown" : function(options){
            this.insert("##### ", "", true);
        }
    },

    /* 标题六插件 */
    "h6" : {
        /* 标题六快捷键 */
        "keyboard" : "ctrl+6",

        /* 执行标题六 */
        "markdown" : function(options){
            this.insert("###### ", "", true);
        }
    },

    /* 添加链接 */
    "link" : {
        /* 连接快捷键 */
        "keyboard" : "ctrl+l",

        /* 插入连接 */
        "markdown" : function(options){
            var range = this.range.get(), start;

            if(range.text.length){
                if(range.text.match(/^http:\/\/.*/i)){
                    this.insert("[" + range.text + "](" + range.text + ")");
                } else {
                    this.insert("[" + range.text + "]()");
                    start = range.start + range.text.length + 3;
                    this.range.set(start, start);
                }
            } else {
                this.insert("[]()");
                start = range.start + 1;
                this.range.set(start, start);
            }
        }
    },

    /* 添加图片 */
    "image" : {
        /* 图片快捷键 */
        "keyboard" : "ctrl+p",

        /* 插入图片 */
        "markdown" : function(options, self){
            var $text, drop, dialog, start,
                editor = this,
                range  = this.range.get();

            /* 当选中文本是远程图片URL时不弹出上传层 */
            if(range.text.length && range.text.match(/^http:\/\/.*/i)){
                this.insert("![ALT](" + range.text + ")");
                start = range.start + 2;
                this.range.set(start, start + 3);
                return;
            }

            //拖动上传容器
            $text     = $("<span/>").text(this.lang("image-text"));
            self.drop = drop = $("<div/>").addClass("thinkeditor-plugin-image")
                               .append($text);

            //弹出图片上传层
            self.dialog = dialog = this.dialog({
                "title"     : this.lang("image-title"),
                "content"   : drop,
                "onOkClick" : function(){ self.upload(editor, options) }
            });

            /* 初始化数据对象 */
            self.data = new FormData();
            //初始化文件数
            self.data.length = 0;

            /* 绑定drag事件,主要是用来设置文件放置框的样式 */
            drop.on("dragenter dragleave", function(event){
                drop.toggleClass("thinkeditor-image-draghover");
                event.stopPropagation();
                return false;
            });

            /* 文件拖动事件,不绑定该事件 drop 事件不生效 */
            drop.on("dragover", function(){ return false });

            /**
             * 文件拖动结束事件
             * 该事件必须用原生方式绑定,拖动结束后浏览器会自动跳转到图片预览页面
             * ?暂不明白是什么原因
             */
            drop[0].addEventListener("drop", function(event) {
                var files = event.target.files || event.dataTransfer.files;

                if(!files) return; //不支持文件拖动

                /* 取消拖动样式,阻止事件冒泡及默认事件 */
                drop.removeClass("thinkeditor-image-draghover");
                event.stopPropagation();
                event.preventDefault();

                //上传文件
                self.show(files, options);
            }, false);
        },

        /**
         * 将上传好的图片插入到编辑器
         * @param  {Array}  imgs   上传的图片数组
         * @param  {Object} editor 图片对象
         */
        "insert" : function(imgs, editor){
            var range = editor.range.get(), img, alt, src, text = [];

            for(name in imgs){
                img = imgs[name];
                alt = range.text.length ? range.text : img.name.split(".")[0];
                src = img.rootpath + img.savepath + img.savename;
                text.push("![" + alt + "](" + src + ")");
            }

            editor.insert(text.join("\n"));
            text = text[0];
            editor.range.set(range.start + 2, range.start + text.indexOf("]"));
        },

        /**
         * 预览选择的图片
         * @param  {Object} files   选择的图片对象
         * @param  {Object} options 编辑器配置对象
         */
        "show" : function(files, options){
            var data = this.data, msg;

            for(var i = 0, file; file = files[i]; i++){
                //禁止上传非图片文件
                if(!file.type.match(/^image\/(?:png|jpeg|jpg|gif)$/)){
                    msg = "忽略非图片文件:" + file.name;
                    this.dialog.setStatus(msg, "error", true);
                } else if(file.size > 1024 * 1024 * 10) {
                    msg = "忽略超过大小限制的图片:" + file.name;
                    this.dialog.setStatus(msg, "error", true);
                } else {
                    if(data.length < 3){
                        data.append(options.dataName + i, file);
                        data.length ++;
                        this.reader(file);
                    } else {
                        msg  = "最多同时上传3张图片,";
                        msg += "已忽略" + (files.length - i) + "张";
                        this.dialog.setStatus(msg, "error", true);
                        break;
                    }
                }
            }
        },

        /**
         * 读取图片数据以提供预览
         * @param  {Object} file 图片对象
         */
        "reader" : function(file){
            var self = this, reader = new FileReader(); //初始化文件对象

            /* 展示选择的图片 */
            reader.onload = function(){
                var html = [
                    "<div>", //用于浮动
                        "<span>", //再添加一层标签主要是为了解决图片垂直居中
                            "<img src=\"" + this.result + "\">",
                        "</span>",
                    "</div>"
                ].join("");
                self.drop.append(html);
            }
            reader.readAsDataURL(file);
        },

        /**
         * AJAX上传图片,只有支持HTML的浏览器才能支持该方法
         * @param  {Object} editor  编辑器对象
         * @param  {Object} options 编辑器配置对象
         */
        "upload" : function(editor, options){
            var self = this, xhr = new XMLHttpRequest(), msg;
            if (!xhr.upload) {
                msg = "您的浏览器不支持ajax上传文件!";
                this.dialog.setStatus(msg, "error", true);
                return;
            }

            // 上传中
            xhr.upload.addEventListener("progress", function(event) {
                var progress = Math.round(event.loaded / event.total);
                msg = "正在上传图片..." + progress + "%";
                self.dialog.setStatus(msg, "success");
            }, false);

            // 文件上传成功或是失败
            xhr.onreadystatechange = function() {
                var data, images = [];
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) {
                        data = $.parseJSON(xhr.responseText);
                        if(data.status){
                            self.insert(data.files, editor);
                            self.dialog.remove();
                        } else {
                            self.dialog.setStatus(data.info, "error", true);
                        }
                    } else {
                        self.dialog.setStatus("图片上传失败!", "error", true);
                    }
                }
            };

            // 开始上传
            this.dialog.setStatus("正在上传图片...0%", "success");
            xhr.open("POST", options.uploader, true);
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhr.send(this.data);
        }

    },

    /* 文本加粗插件 */
    "bold" : {
        /* 文本加粗快捷键 */
        "keyboard" : "ctrl+b",

        /* 执行文本加粗 */
        "markdown" : function(options){
            this.insert("**", "**", true);
        }
    },

    /* 文字倾斜插件 */
    "italic" : {
        /* 文字倾斜快捷键 */
        "keyboard" : "ctrl+i",

        /* 执行文字倾斜 */
        "markdown" : function(options){
            this.insert("_", "_", true);
        }
    },

    /* 插入代码 */
    "code" : {
        /* 代码快捷键 */
        "keyboard" : "ctrl+d",

        /* 插入代码 */
        "markdown" : function(options){
            var range = this.range.get(), start;

            if(range.text.length){
                if(range.text.split("\n").length > 1){
                    this.insert("~~~\n"+ range.text +"\n~~~");
                    start = range.start + 3;
                    this.range.set(start, start);
                } else {
                    this.insert("`"+ range.text +"`");
                }
            } else {
                this.insert("``");
                start = range.start + 1;
                this.range.set(start, start);
            }
        }
    },

    /* 无序列表插件 */
    "ul" : {
        /* 代码快捷键 */
        "keyboard" : "ctrl+u",

        /* 插入代码 */
        "markdown" : function(options){
            this.insert("* ", "", true);
        }
    },

    /* 插入有序列表 */
    "ol" : {
        /* 有序列表捷键 */
        "keyboard" : "ctrl+o",

        /* 插入有序列表 */
        "markdown" : function(options){
            this.insert("{$line}. ", "", true);
        }
    },

    /* 引用文本 */
    "blockquote" : {
        /* 引用快捷键 */
        "keyboard" : "ctrl+q",

        /* 插入代码 */
        "markdown" : function(options){
            this.insert("> ", "", true);
        }
    },

    /* 插入水平分割线 */
    "hr" : {
        /* 分割线快捷键 */
        "keyboard" : "ctrl+h",

        /* 插入分割线 */
        "markdown" : function(options){
            var range = this.range.get(),
                start = range.start + range.text.length + 11;

            this.insert(range.text + "\n* * * * *\n");
            this.range.set(start, start);
        }
    },

    /* 全屏编辑 */
    "fullscreen" : {
        /* 全屏编辑快捷键 */
        "keyboard" : "ctrl+f",

        /* 执行全屏编辑 */
        "markdown" : function(options){
            var $body   = $("body"),
                $editor = $(this.range.textarea).closest(".thinkeditor");

            if($editor.hasClass("thinkeditor-fullscreen")){
                $body.css("overflow", "");
                $editor.removeClass("thinkeditor-fullscreen");
            } else {
                $body.css("overflow", "hidden");
                $editor.addClass("thinkeditor-fullscreen");
            }
        }
    },

    /* 保存数据 */
    "save" : {
        /* 保存数据快捷键 */
        "keyboard" : "ctrl+s",

        /* 执行全屏编辑 */
        "markdown" : function(options){
            if($.isFunction(options.onSave)){
                options.onSave.call(this.range.textarea);
            }
        }
    },

    /* 文本缩进 */
    "indent" : {
        /* 缩进快捷键 */
        "keyboard" : "tab",

        /* 插入缩进 */
        "markdown" : function(options){
            var range = this.range.get(), text, start;
            if(range.start){
                text  = this.range.textarea.value.substring(0, range.start);
                start = text.lastIndexOf("\n") + 1;
                if(range.text.length && start != text.length){
                    this.range.set(start, range.end);
                }
            }
            this.insert(options.tab, "", true);
        }
    },

    /* 减少缩进 */
    "outdent" : {
        /* 减少缩进快捷键 */
        "keyboard" : "shift+tab",

        /* 插入代码 */
        "markdown" : function(options){
            var range = this.range.get(), text, start;
            if(range.start){
                text  = this.range.textarea.value.substring(0, range.start);
                start = text.lastIndexOf("\n") + 1;
                if(start != text.length){
                    range = this.range.set(start, range.end).get();
                }
            }

            if(range.text.length){
                text = range.text.split("\n");
                for(i in text){
                    text[i] = text[i].replace(/^((\t)|( {1,4}))/, "");
                }
                this.insert(text.join("\n"));
            }
        }
    }
});

/**
 * ThinkEditor编辑器默认语言包
 * 默认仅支持英文和简体中文语言包
 * 其他语言包可以通过 $.thinkeditor.laguage() 方法扩展
 */
$.thinkeditor.language({
    /* 英文语言包 */
    "en-us" : {
        /* 工具栏语言 */
        "h1"         : "H1 (Ctrl+1)",
        "h2"         : "H2 (Ctrl+2)",
        "h3"         : "H3 (Ctrl+3)",
        "h4"         : "H4 (Ctrl+4)",
        "h5"         : "H5 (Ctrl+5)",
        "h6"         : "H6 (Ctrl+6)",
        "link"       : "Link (Ctrl+L)",
        "image"      : "Image (Ctrl+P)",
        "bold"       : "Blod (Ctrl+B)",
        "italic"     : "Italic (Ctrl+I)",
        "code"       : "Code (Ctrl+D)",
        "ul"         : "Unordered List (Ctrl+U)",
        "ol"         : "Ordered List (Ctrl+O)",
        "blockquote" : "Blockquote (Ctrl+Q)",
        "hr"         : "Horizontal Rule (Ctrl+H)",
        "fullscreen" : "Full Screen (Ctrl+F)",
        "save"       : "Save (Ctrl+S)",

        /* 弹出层语言 */
        "ok"     : "OK",
        "cancel" : "Cancel",

        /* 图片插件语言 */
        "image-title" : "Insert Image",
        "image-text"  : "Drag the image to here"
    },

    /* 简体中文语言包 */
    "zh-cn" : {
        /* 工具栏语言 */
        "h1"         : "标题一 (Ctrl+1)",
        "h2"         : "标题二 (Ctrl+2)",
        "h3"         : "标题三 (Ctrl+3)",
        "h4"         : "标题四 (Ctrl+4)",
        "h5"         : "标题五 (Ctrl+5)",
        "h6"         : "标题六 (Ctrl+6)",
        "link"       : "链接 (Ctrl+L)",
        "image"      : "图片 (Ctrl+P)",
        "bold"       : "加粗 (Ctrl+B)",
        "italic"     : "斜体 (Ctrl+I)",
        "code"       : "代码 (Ctrl+D)",
        "ul"         : "无序列表 (Ctrl+U)",
        "ol"         : "有序列表 (Ctrl+O)",
        "blockquote" : "引用 (Ctrl+Q)",
        "hr"         : "分割线 (Ctrl+H)",
        "fullscreen" : "全屏编辑 (Ctrl+F)",
        "save"       : "保存 (Ctrl+S)",

        /* 弹出层语言 */
        "ok"     : "确定",
        "cancel" : "取消",

        /* 图片插件语言 */
        "image-title" : "插入图片",
        "image-text"  : "拖动图片到这里上传"
    }
});

}(jQuery);