UNPKG

hdjs

Version:
1,306 lines (1,070 loc) 157 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: editormd.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: editormd.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/* * Editor.md * * @file editormd.js * @version v1.4.5 * @description Open source online markdown editor. * @license MIT License * @author Pandao * {@link https://github.com/pandao/editor.md} * @updateTime 2015-06-02 */ ;(function(factory) { "use strict"; // CommonJS/Node.js if (typeof require === "function" &amp;&amp; typeof exports === "object" &amp;&amp; typeof module === "object") { module.exports = factory; } else if (typeof define === "function") // AMD/CMD/Sea.js { if (define.amd) // for Require.js { /* Require.js define replace */ } else { define(["jquery"], factory); // for Sea.js } } else { window.editormd = factory(); } }(function() { /* Require.js assignment replace */ "use strict"; var $ = (typeof (jQuery) !== "undefined") ? jQuery : Zepto; if (typeof ($) === "undefined") { return ; } /** * editormd * * @param {String} id 编辑器的ID * @param {Object} options 配置选项 Key/Value * @returns {Object} editormd 返回editormd对象 */ var editormd = function (id, options) { return new editormd.fn.init(id, options); }; editormd.title = editormd.$name = "Editor.md"; editormd.version = "1.4.5"; editormd.homePage = "https://pandao.github.io/editor.md/"; editormd.classPrefix = "editormd-"; editormd.toolbarModes = { full : [ "undo", "redo", "|", "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "list-ul", "list-ol", "hr", "|", "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", "help", "info" ], simple : [ "undo", "redo", "|", "bold", "del", "italic", "quote", "uppercase", "lowercase", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "list-ul", "list-ol", "hr", "|", "watch", "preview", "fullscreen", "|", "help", "info" ], mini : [ "undo", "redo", "|", "watch", "preview", "|", "help", "info" ] }; editormd.defaults = { mode : "gfm", //gfm or markdown theme : "default", name : "", value : "", // value for CodeMirror, if mode not gfm/markdown markdown : "", appendMarkdown : "", // if in init textarea value not empty, append markdown to textarea width : "100%", height : "100%", path : "./lib/", // Dependents module file directory pluginPath : "", // If this empty, default use settings.path + "../plugins/" delay : 300, // Delay parse markdown to html, Uint : ms autoLoadModules : true, // Automatic load dependent module files watch : true, placeholder : "Enjoy Markdown! coding now...", gotoLine : true, codeFold : false, autoHeight : false, autoFocus : true, autoCloseTags : true, searchReplace : true, syncScrolling : true, readOnly : false, tabSize : 4, indentUnit : 4, lineNumbers : true, lineWrapping : true, autoCloseBrackets : true, showTrailingSpace : true, matchBrackets : true, indentWithTabs : true, styleSelectedText : true, matchWordHighlight : true, // options: true, false, "onselected" styleActiveLine : true, // Highlight the current line dialogLockScreen : true, dialogShowMask : true, dialogDraggable : true, dialogMaskBgColor : "#fff", dialogMaskOpacity : 0.1, fontSize : "13px", saveHTMLToTextarea : false, disabledKeyMaps : [], onload : function() {}, onresize : function() {}, onchange : function() {}, onwatch : null, onunwatch : null, onpreviewing : function() {}, onpreviewed : function() {}, onfullscreen : function() {}, onfullscreenExit : function() {}, onscroll : function() {}, onpreviewscroll : function() {}, imageUpload : false, imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"], imageUploadURL : "", crossDomainUpload : false, uploadCallbackURL : "", toc : true, // Table of contents tocm : false, // Using [TOCM], auto create ToC dropdown menu tocTitle : "", // for ToC dropdown menu btn tocDropdown : false, tocContainer : "", tocStartLevel : 1, // Said from H1 to create ToC htmlDecode : false, // Open the HTML tag identification pageBreak : true, // Enable parse page break [========] atLink : true, // for @link emailLink : true, // for email address auto link taskList : false, // Enable Github Flavored Markdown task lists emoji : false, // :emoji: , Support Github emoji, Twitter Emoji (Twemoji); // Support FontAwesome icon emoji :fa-xxx: > Using fontAwesome icon web fonts; // Support Editor.md logo icon emoji :editormd-logo: :editormd-logo-1x: > 1~8x; tex : false, // TeX(LaTeX), based on KaTeX flowChart : false, // flowChart.js only support IE9+ sequenceDiagram : false, // sequenceDiagram.js only support IE9+ previewCodeHighlight : true, toolbar : true, // show/hide toolbar toolbarAutoFixed : true, // on window scroll auto fixed position toolbarIcons : "full", toolbarTitles : {}, toolbarHandlers : { ucwords : function() { return editormd.toolbarHandlers.ucwords; }, lowercase : function() { return editormd.toolbarHandlers.lowercase; } }, toolbarCustomIcons : { // using html tag create toolbar icon, unused default &lt;a> tag. lowercase : "&lt;a href=\"javascript:;\" title=\"Lowercase\" unselectable=\"on\">&lt;i class=\"fa\" name=\"lowercase\" style=\"font-size:24px;margin-top: -10px;\">a&lt;/i>&lt;/a>", "ucwords" : "&lt;a href=\"javascript:;\" title=\"ucwords\" unselectable=\"on\">&lt;i class=\"fa\" name=\"ucwords\" style=\"font-size:20px;margin-top: -3px;\">Aa&lt;/i>&lt;/a>" }, toolbarIconsClass : { undo : "fa-undo", redo : "fa-repeat", bold : "fa-bold", del : "fa-strikethrough", italic : "fa-italic", quote : "fa-quote-left", uppercase : "fa-font", h1 : editormd.classPrefix + "bold", h2 : editormd.classPrefix + "bold", h3 : editormd.classPrefix + "bold", h4 : editormd.classPrefix + "bold", h5 : editormd.classPrefix + "bold", h6 : editormd.classPrefix + "bold", "list-ul" : "fa-list-ul", "list-ol" : "fa-list-ol", hr : "fa-minus", link : "fa-link", "reference-link" : "fa-anchor", image : "fa-picture-o", code : "fa-code", "preformatted-text" : "fa-file-code-o", "code-block" : "fa-file-code-o", table : "fa-table", datetime : "fa-clock-o", emoji : "fa-smile-o", "html-entities" : "fa-copyright", pagebreak : "fa-newspaper-o", "goto-line" : "fa-terminal", // fa-crosshairs watch : "fa-eye-slash", unwatch : "fa-eye", preview : "fa-desktop", search : "fa-search", fullscreen : "fa-arrows-alt", clear : "fa-eraser", help : "fa-question-circle", info : "fa-info-circle" }, toolbarIconTexts : {}, lang : { name : "zh-cn", description : "开源在线Markdown编辑器&lt;br/>Open source online Markdown editor.", tocTitle : "目录", toolbar : { undo : "撤销(Ctrl+Z)", redo : "重做(Ctrl+Y)", bold : "粗体", del : "删除线", italic : "斜体", quote : "引用", ucwords : "将每个单词首字母转成大写", uppercase : "将所选转换成大写", lowercase : "将所选转换成小写", h1 : "标题1", h2 : "标题2", h3 : "标题3", h4 : "标题4", h5 : "标题5", h6 : "标题6", "list-ul" : "无序列表", "list-ol" : "有序列表", hr : "横线", link : "链接", "reference-link" : "引用链接", image : "添加图片", code : "行内代码", "preformatted-text" : "预格式文本 / 代码块(缩进风格)", "code-block" : "代码块(多语言风格)", table : "添加表格", datetime : "日期时间", emoji : "Emoji表情", "html-entities" : "HTML实体字符", pagebreak : "插入分页符", "goto-line" : "跳转到行", watch : "关闭实时预览", unwatch : "开启实时预览", preview : "全窗口预览HTML(按 Shift + ESC还原)", fullscreen : "全屏(按ESC还原)", clear : "清空", search : "搜索", help : "使用帮助", info : "关于" + editormd.title }, buttons : { enter : "确定", cancel : "取消", close : "关闭" }, dialog : { link : { title : "添加链接", url : "链接地址", urlTitle : "链接标题", urlEmpty : "错误:请填写链接地址。" }, referenceLink : { title : "添加引用链接", name : "引用名称", url : "链接地址", urlId : "链接ID", urlTitle : "链接标题", nameEmpty: "错误:引用链接的名称不能为空。", idEmpty : "错误:请填写引用链接的ID。", urlEmpty : "错误:请填写引用链接的URL地址。" }, image : { title : "添加图片", url : "图片地址", link : "图片链接", alt : "图片描述", uploadButton : "本地上传", imageURLEmpty : "错误:图片地址不能为空。", uploadFileEmpty : "错误:上传的图片不能为空。", formatNotAllowed : "错误:只允许上传图片文件,允许上传的图片文件格式有:" }, preformattedText : { title : "添加预格式文本或代码块", emptyAlert : "错误:请填写预格式文本或代码的内容。" }, codeBlock : { title : "添加代码块", selectLabel : "代码语言:", selectDefaultText : "请选择代码语言", otherLanguage : "其他语言", unselectedLanguageAlert : "错误:请选择代码所属的语言类型。", codeEmptyAlert : "错误:请填写代码内容。" }, htmlEntities : { title : "HTML 实体字符" }, help : { title : "使用帮助" } } } }; editormd.classNames = { tex : editormd.classPrefix + "tex" }; editormd.dialogZindex = 99999; editormd.$katex = null; editormd.$marked = null; editormd.$CodeMirror = null; editormd.$prettyPrint = null; var timer, flowchartTimer; editormd.prototype = editormd.fn = { state : { watching : false, loaded : false, preview : false, fullscreen : false }, /** * 构造函数/实例初始化 * Constructor / instance initialization * * @param {String} id 编辑器的ID * @param {Object} [options={}] 配置选项 Key/Value * @returns {editormd} 返回editormd的实例对象 */ init : function (id, options) { options = options || {}; if (typeof id === "object") { options = id; } var _this = this; var classPrefix = this.classPrefix = editormd.classPrefix; var settings = this.settings = $.extend(true, editormd.defaults, options); id = (typeof id === "object") ? settings.id : id; var editor = this.editor = $("#" + id); this.id = id; this.lang = settings.lang; var classNames = this.classNames = { textarea : { html : classPrefix + "html-textarea", markdown : classPrefix + "markdown-textarea" } }; settings.pluginPath = (settings.pluginPath === "") ? settings.path + "../plugins/" : settings.pluginPath; this.state.watching = (settings.watch) ? true : false; if ( !editor.hasClass("editormd") ) { editor.addClass("editormd"); } editor.css({ width : (typeof settings.width === "number") ? settings.width + "px" : settings.width, height : (typeof settings.height === "number") ? settings.height + "px" : settings.height }); if (settings.autoHeight) { editor.css("height", "auto"); } var markdownTextarea = this.markdownTextarea = editor.children("textarea"); if (markdownTextarea.length &lt; 1) { editor.append("&lt;textarea>&lt;/textarea>"); markdownTextarea = this.markdownTextarea = editor.children("textarea"); } markdownTextarea.addClass(classNames.textarea.markdown).attr("placeholder", settings.placeholder); if (typeof markdownTextarea.attr("name") === "undefined" || markdownTextarea.attr("name") === "") { markdownTextarea.attr("name", (settings.name !== "") ? settings.name : id + "-markdown-doc"); } var appendElements = [ (!settings.readOnly) ? "&lt;a href=\"javascript:;\" class=\"fa fa-close " + classPrefix + "preview-close-btn\">&lt;/a>" : "", ( (settings.saveHTMLToTextarea) ? "&lt;textarea class=\"" + classNames.textarea.html + "\" name=\"" + id + "-html-code\">&lt;/textarea>" : "" ), "&lt;div class=\"" + classPrefix + "preview\">&lt;div class=\"markdown-body " + classPrefix + "preview-container\">&lt;/div>&lt;/div>", "&lt;div class=\"" + classPrefix + "container-mask\" style=\"display:block;\">&lt;/div>", "&lt;div class=\"" + classPrefix + "mask\">&lt;/div>" ].join("\n"); editor.append(appendElements).addClass(classPrefix + "vertical"); this.mask = editor.children("." + classPrefix + "mask"); this.containerMask = editor.children("." + classPrefix + "container-mask"); if (settings.markdown !== "") { markdownTextarea.val(settings.markdown); } if (settings.appendMarkdown !== "") { markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown); } this.htmlTextarea = editor.children("." + classNames.textarea.html); this.preview = editor.children("." + classPrefix + "preview"); this.previewContainer = this.preview.children("." + classPrefix + "preview-container"); if (typeof define === "function" &amp;&amp; define.amd) { if (typeof katex !== "undefined") { editormd.$katex = katex; } if (settings.searchReplace &amp;&amp; !settings.readOnly) { editormd.loadCSS(settings.path + "codemirror/addon/dialog/dialog"); editormd.loadCSS(settings.path + "codemirror/addon/search/matchesonscrollbar"); } } if ((typeof define === "function" &amp;&amp; define.amd) || !settings.autoLoadModules) { if (typeof CodeMirror !== "undefined") { editormd.$CodeMirror = CodeMirror; } if (typeof marked !== "undefined") { editormd.$marked = marked; } this.setCodeMirror().setToolbar().loadedDisplay(); } else { this.loadQueues(); } return this; }, /** * 所需组件加载队列 * Required components loading queue * * @returns {editormd} 返回editormd的实例对象 */ loadQueues : function() { var _this = this; var settings = this.settings; var loadPath = settings.path; var loadFlowChartOrSequenceDiagram = function() { if (editormd.isIE8) { _this.loadedDisplay(); return ; } if (settings.flowChart || settings.sequenceDiagram) { editormd.loadScript(loadPath + "raphael.min", function() { editormd.loadScript(loadPath + "underscore.min", function() { if (!settings.flowChart &amp;&amp; settings.sequenceDiagram) { editormd.loadScript(loadPath + "sequence-diagram.min", function() { _this.loadedDisplay(); }); } else if (settings.flowChart &amp;&amp; !settings.sequenceDiagram) { editormd.loadScript(loadPath + "flowchart.min", function() { editormd.loadScript(loadPath + "jquery.flowchart.min", function() { _this.loadedDisplay(); }); }); } else if (settings.flowChart &amp;&amp; settings.sequenceDiagram) { editormd.loadScript(loadPath + "flowchart.min", function() { editormd.loadScript(loadPath + "jquery.flowchart.min", function() { editormd.loadScript(loadPath + "sequence-diagram.min", function() { _this.loadedDisplay(); }); }); }); } }); }); } else { _this.loadedDisplay(); } }; editormd.loadCSS(loadPath + "codemirror/codemirror.min"); if (settings.searchReplace &amp;&amp; !settings.readOnly) { editormd.loadCSS(loadPath + "codemirror/addon/dialog/dialog"); editormd.loadCSS(loadPath + "codemirror/addon/search/matchesonscrollbar"); } if (settings.codeFold) { editormd.loadCSS(loadPath + "codemirror/addon/fold/foldgutter"); } editormd.loadScript(loadPath + "codemirror/codemirror.min", function() { editormd.$CodeMirror = CodeMirror; editormd.loadScript(loadPath + "codemirror/modes.min", function() { editormd.loadScript(loadPath + "codemirror/addons.min", function() { _this.setCodeMirror(); if (settings.mode !== "gfm" &amp;&amp; settings.mode !== "markdown") { _this.loadedDisplay(); return false; } _this.setToolbar(); editormd.loadScript(loadPath + "marked.min", function() { editormd.$marked = marked; if (settings.previewCodeHighlight) { editormd.loadScript(loadPath + "prettify.min", function() { loadFlowChartOrSequenceDiagram(); }); } else { loadFlowChartOrSequenceDiagram(); } }); }); }); }); return this; }, /** * 设置CodeMirror的主题 * Setting CodeMirror theme * * @returns {editormd} 返回editormd的实例对象 */ setTheme : function(theme) { var settings = this.settings; settings.theme = theme; if (theme !== "default") { editormd.loadCSS(settings.path + "codemirror/theme/" + settings.theme); } this.cm.setOption("theme", theme); return this; }, /** * 配置和初始化CodeMirror组件 * CodeMirror initialization * * @returns {editormd} 返回editormd的实例对象 */ setCodeMirror : function() { var settings = this.settings; var editor = this.editor; if (settings.theme !== "default") { editormd.loadCSS(settings.path + "codemirror/theme/" + settings.theme); } var codeMirrorConfig = { mode : settings.mode, theme : settings.theme, tabSize : settings.tabSize, dragDrop : false, autofocus : settings.autoFocus, autoCloseTags : settings.autoCloseTags, readOnly : (settings.readOnly) ? "nocursor" : false, indentUnit : settings.indentUnit, lineNumbers : settings.lineNumbers, lineWrapping : settings.lineWrapping, extraKeys : { "Ctrl-Q": function(cm) { cm.foldCode(cm.getCursor()); } }, foldGutter : settings.codeFold, gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], matchBrackets : settings.matchBrackets, indentWithTabs : settings.indentWithTabs, styleActiveLine : settings.styleActiveLine, styleSelectedText : settings.styleSelectedText, autoCloseBrackets : settings.autoCloseBrackets, showTrailingSpace : settings.showTrailingSpace, highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === "onselected") ? false : /\w/ } ) }; this.codeEditor = this.cm = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig); this.codeMirror = this.cmElement = editor.children(".CodeMirror"); if (settings.value !== "") { this.cm.setValue(settings.value); } this.codeMirror.css({ fontSize : settings.fontSize, width : (!settings.watch) ? "100%" : "50%" }); if (settings.autoHeight) { this.codeMirror.css("height", "auto"); this.cm.setOption("viewportMargin", Infinity); } return this; }, /** * 获取CodeMirror的配置选项 * Get CodeMirror setting options * * @returns {Mixed} return CodeMirror setting option value */ getCodeMirrorOption : function(key) { return this.cm.getOption(key); }, /** * 配置和重配置CodeMirror的选项 * CodeMirror setting options / resettings * * @returns {editormd} 返回editormd的实例对象 */ setCodeMirrorOption : function(key, value) { this.cm.setOption(key, value); return this; }, /** * 添加 CodeMirror 键盘快捷键 * Add CodeMirror keyboard shortcuts key map * * @returns {editormd} 返回editormd的实例对象 */ addKeyMap : function(map, bottom) { this.cm.addKeyMap(map, bottom); return this; }, /** * 移除 CodeMirror 键盘快捷键 * Remove CodeMirror keyboard shortcuts key map * * @returns {editormd} 返回editormd的实例对象 */ removeKeyMap : function(map) { this.cm.removeKeyMap(map); return this; }, /** * 跳转到指定的行 * Goto CodeMirror line * * @param {String|Intiger} line line number or "first"|"last" * @returns {editormd} 返回editormd的实例对象 */ gotoLine : function (line) { var settings = this.settings; if (!settings.gotoLine) { return this; } var cm = this.cm; var editor = this.editor; var count = cm.lineCount(); var preview = this.preview; if (typeof line === "string") { if(line === "last") { line = count; } if (line === "first") { line = 1; } } if (typeof line !== "number") { alert("Error: The line number must be an integer."); return this; } line = parseInt(line) - 1; if (line > count) { alert("Error: The line number range 1-" + count); return this; } cm.setCursor( {line : line, ch : 0} ); var scrollInfo = cm.getScrollInfo(); var clientHeight = scrollInfo.clientHeight; var coords = cm.charCoords({line : line, ch : 0}, "local"); cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2); if (settings.watch) { var cmScroll = this.codeMirror.find(".CodeMirror-scroll")[0]; var height = $(cmScroll).height(); var scrollTop = cmScroll.scrollTop; var percent = (scrollTop / cmScroll.scrollHeight); if (scrollTop === 0) { preview.scrollTop(0); } else if (scrollTop + height >= cmScroll.scrollHeight - 16) { preview.scrollTop(preview[0].scrollHeight); } else { preview.scrollTop(preview[0].scrollHeight * percent); } } cm.focus(); return this; }, /** * 扩展当前实例对象,可同时设置多个或者只设置一个 * Extend editormd instance object, can mutil setting. * * @returns {editormd} this(editormd instance object.) */ extend : function() { if (typeof arguments[1] !== "undefined") { if (typeof arguments[1] === "function") { arguments[1] = $.proxy(arguments[1], this); } this[arguments[0]] = arguments[1]; } if (typeof arguments[0] === "object" &amp;&amp; typeof arguments[0].length === "undefined") { $.extend(true, this, arguments[0]); } return this; }, /** * 设置或扩展当前实例对象,单个设置 * Extend editormd instance object, one by one * * @param {String|Object} key option key * @param {String|Object} value option value * @returns {editormd} this(editormd instance object.) */ set : function (key, value) { if (typeof value !== "undefined" &amp;&amp; typeof value === "function") { value = $.proxy(value, this); } this[key] = value; return this; }, /** * 重新配置 * Resetting editor options * * @param {String|Object} key option key * @param {String|Object} value option value * @returns {editormd} this(editormd instance object.) */ config : function(key, value) { var settings = this.settings; if (typeof key === "object") { settings = $.extend(true, settings, key); } if (typeof key === "string") { settings[key] = value; } this.settings = settings; this.recreate(); return this; }, /** * 注册事件处理方法 * Bind editor event handle * * @param {String} eventType event type * @param {Function} callback 回调函数 * @returns {editormd} this(editormd instance object.) */ on : function(eventType, callback) { var settings = this.settings; if (typeof settings["on" + eventType] !== "undefined") { settings["on" + eventType] = $.proxy(callback, this); } return this; }, /** * 解除事件处理方法 * Unbind editor event handle * * @param {String} eventType event type * @returns {editormd} this(editormd instance object.) */ off : function(eventType) { var settings = this.settings; if (typeof settings["on" + eventType] !== "undefined") { settings["on" + eventType] = function(){}; } return this; }, /** * 显示工具栏 * Display toolbar * * @param {Function} [callback=function(){}] 回调函数 * @returns {editormd} 返回editormd的实例对象 */ showToolbar : function(callback) { var settings = this.settings; if(settings.readOnly) { return this; } if (settings.toolbar &amp;&amp; (this.toolbar.length &lt; 1 || this.toolbar.find("." + this.classPrefix + "menu").html() === "") ) { this.setToolbar(); } settings.toolbar = true; this.toolbar.show(); this.resize(); $.proxy(callback || function(){}, this)(); return this; }, /** * 隐藏工具栏 * Hide toolbar * * @param {Function} [callback=function(){}] 回调函数 * @returns {editormd} this(editormd instance object.) */ hideToolbar : function(callback) { var settings = this.settings; settings.toolbar = false; this.toolbar.hide(); this.resize(); $.proxy(callback || function(){}, this)(); return this; }, /** * 页面滚动时工具栏的固定定位 * Set toolbar in window scroll auto fixed position * * @returns {editormd} 返回editormd的实例对象 */ setToolbarAutoFixed : function(fixed) { var state = this.state; var editor = this.editor; var toolbar = this.toolbar; var settings = this.settings; if (typeof fixed !== "undefined") { settings.toolbarAutoFixed = fixed; } var autoFixedHandle = function(){ var $window = $(window); var top = $window.scrollTop(); if (!settings.toolbarAutoFixed) { return false; } if (top - editor.offset().top > 10 &amp;&amp; top &lt; editor.height()) { toolbar.css({ position : "fixed", width : editor.width() + "px", left : ($window.width() - editor.width()) / 2 + "px" }); } else { toolbar.css({ position : "absolute", width : "100%", left : 0 }); } }; if (!state.fullscreen &amp;&amp; !state.preview &amp;&amp; settings.toolbar &amp;&amp; settings.toolbarAutoFixed) { $(window).bind("scroll", autoFixedHandle); } return this; }, /** * 配置和初始化工具栏 * Set toolbar and Initialization * * @returns {editormd} 返回editormd的实例对象 */ setToolbar : function() { var settings = this.settings; if(settings.readOnly) { return this; } var editor = this.editor; var preview = this.preview; var classPrefix = this.classPrefix; var toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); if (settings.toolbar &amp;&amp; toolbar.length &lt; 1) { var toolbarHTML = "&lt;div class=\"" + classPrefix + "toolbar\">&lt;div class=\"" + classPrefix + "toolbar-container\">&lt;ul class=\"" + classPrefix + "menu\">&lt;/ul>&lt;/div>&lt;/div>"; editor.append(toolbarHTML); toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); } if (!settings.toolbar) { toolbar.hide(); return this; } toolbar.show(); var icons = (typeof settings.toolbarIcons === "function") ? settings.toolbarIcons() : ((typeof settings.toolbarIcons === "string") ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons); var toolbarMenu = toolbar.find("." + this.classPrefix + "menu"), menu = ""; var pullRight = false; for (var i = 0, len = icons.length; i &lt; len; i++) { var name = icons[i]; if (name === "||") { pullRight = true; } else if (name === "|") { menu += "&lt;li class=\"divider\" unselectable=\"on\">|&lt;/li>"; } else { var isHeader = (/h(\d)/.test(name)); var index = name; if (name === "watch" &amp;&amp; !settings.watch) { index = "unwatch"; } var title = settings.lang.toolbar[index]; var iconTexts = settings.toolbarIconTexts[index]; var iconClass = settings.toolbarIconsClass[index]; title = (typeof title === "undefined") ? "" : title; iconTexts = (typeof iconTexts === "undefined") ? "" : iconTexts; iconClass = (typeof iconClass === "undefined") ? "" : iconClass; var menuItem = pullRight ? "&lt;li class=\"pull-right\">" : "&lt;li>"; if (typeof settings.toolbarCustomIcons[name] !== "undefined" &amp;&amp; typeof settings.toolbarCustomIcons[name] !== "function") { menuItem += settings.toolbarCustomIcons[name]; } else { menuItem += "&lt;a href=\"javascript:;\" title=\"" + title + "\" unselectable=\"on\">"; menuItem += "&lt;i class=\"fa " + iconClass + "\" name=\""+name+"\" unselectable=\"on\">"+((isHeader) ? name.toUpperCase() : ( (iconClass === "") ? iconTexts : "") ) + "&lt;/i>"; menuItem += "&lt;/a>"; } menuItem += "&lt;/li>"; menu = pullRight ? menuItem + menu : menu + menuItem; } } toolbarMenu.html(menu); toolbarMenu.find("[title=\"Lowercase\"]").attr("title", settings.lang.toolbar.lowercase); toolbarMenu.find("[title=\"ucwords\"]").attr("title", settings.lang.toolbar.ucwords); this.setToolbarHandler(); this.setToolbarAutoFixed(); return this; }, /** * 工具栏图标事件处理对象序列 * Get toolbar icons event handlers * * @param {Object} cm CodeMirror的实例对象 * @param {String} name 要获取的事件处理器名称 * @returns {Object} 返回处理对象序列 */ dialogLockScreen : function() { $.proxy(editormd.dialogLockScreen, this)(); return this; }, dialogShowMask : function(dialog) { $.proxy(editormd.dialogShowMask, this)(dialog); return this; }, getToolbarHandles : function(name) { var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers; return (name &amp;&amp; typeof toolbarIconHandlers[name] !== "undefined") ? toolbarHandlers[name] : toolbarHandlers; }, /** * 工具栏图标事件处理器 * Bind toolbar icons event handle * * @returns {editormd} 返回editormd的实例对象 */ setToolbarHandler : function() { var _this = this; var settings = this.settings; if (!settings.toolbar || settings.readOnly) { return this; } var toolbar = this.toolbar; var cm = this.cm; var classPrefix = this.classPrefix; var toolbarIcons = this.toolbarIcons = toolbar.find("." + classPrefix + "menu > li > a"); var toolbarIconHandlers = this.getToolbarHandles(); toolbarIcons.bind(editormd.mouseOrTouch("click", "touchend"), function(event) { var icon = $(this).children(".fa"); var name = icon.attr("name"); var cursor = cm.getCursor(); var selection = cm.getSelection(); if (name === "") { return ; } _this.activeIcon = icon; if (typeof toolbarIconHandlers[name] !== "undefined") { $.proxy(toolbarIconHandlers[name], _this)(cm); } else { if (typeof settings.toolbarHandlers[name] !== "undefined") { $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection); } } if (name !== "link" &amp;&amp; name !== "reference-link" &amp;&amp; name !== "image" &amp;&amp; name !== "code-block" &amp;&amp; name !== "preformatted-text" &amp;&amp; name !== "watch" &amp;&amp; name !== "preview" &amp;&amp; name !== "search" &amp;&amp; name !== "fullscreen" &amp;&amp; name !== "info") { cm.focus(); } return false; }); return this; }, /** * 动态创建对话框 * Creating custom dialogs * * @param {Object} options 配置项键值对 Key/Value * @returns {dialog} 返回创建的dialog的jQuery实例对象 */ createDialog : function(options) { return $.proxy(editormd.createDialog, this)(options); }, /** * 创建关于Editor.md的对话框 * Create about Editor.md dialog * * @returns {editormd} 返回editormd的实例对象 */ createInfoDialog : function() { var _this = this; var editor = this.editor; var classPrefix = this.classPrefix; var infoDialogHTML = [ "&lt;div class=\"" + classPrefix + "dialog " + classPrefix + "dialog-info\" style=\"\">", "&lt;div class=\"" + classPrefix + "dialog-container\">", "&lt;h1>&lt;i class=\"editormd-logo editormd-logo-lg editormd-logo-color\">&lt;/i> " + editormd.title + "&lt;small>v" + editormd.version + "&lt;/small>&lt;/h1>", "&lt;p>" + this.lang.description + "&lt;/p>", "&lt;p style=\"margin: 10px 0 20px 0;\">&lt;a href=\"" + editormd.homePage + "\" target=\"_blank\">" + editormd.homePage + " &lt;i class=\"fa fa-external-link\">&lt;/i>&lt;/a>&lt;/p>", "&lt;p style=\"font-size: 0.85em;\">Copyright &amp;copy; 2015 &lt;a href=\"https://github.com/pandao\" target=\"_blank\" class=\"hover-link\">Pandao&lt;/a>, The &lt;a href=\"https://github.com/pandao/editor.md/blob/master/LICENSE\" target=\"_blank\" class=\"hover-link\">MIT&lt;/a> License.&lt;/p>", "&lt;/div>", "&lt;a href=\"javascript:;\" class=\"fa fa-close " + classPrefix + "dialog-close\">&lt;/a>", "&lt;/div>" ].join("\n"); editor.append(infoDialogHTML); var infoDialog = this.infoDialog = editor.children("." + classPrefix + "dialog-info"); infoDialog.find("." + classPrefix + "dialog-close").bind(editormd.mouseOrTouch("click", "touchend"), function() { _this.hideInfoDialog(); }); infoDialog.css("border", (editormd.isIE8) ? "1px solid #ddd" : "").css("z-index", editormd.dialogZindex).show(); this.infoDialogPosition(); return this; }, /** * 关于Editor.md对话居中定位 * Editor.md dialog position handle * * @returns {editormd} 返回editormd的实例对象 */ infoDialogPosition : fun