玛氪宕·梦魔(Markdown Memo),使用Markdown的云端备忘录,百度IFE的RIA启航班的不合格的作业,才……才没有什么阴谋呢!
源gitee链接https://gitee.com/arathi/MarkdownMemo?_from=gitee_search
				
			
			
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							4407 lines
						
					
					
						
							153 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							4407 lines
						
					
					
						
							153 KiB
						
					
					
				| <!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" && typeof exports === "object" && 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 <a> tag. | |
|             lowercase        : "<a href=\"javascript:;\" title=\"Lowercase\" unselectable=\"on\"><i class=\"fa\" name=\"lowercase\" style=\"font-size:24px;margin-top: -10px;\">a</i></a>", | |
|             "ucwords"        : "<a href=\"javascript:;\" title=\"ucwords\" unselectable=\"on\"><i class=\"fa\" name=\"ucwords\" style=\"font-size:20px;margin-top: -3px;\">Aa</i></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编辑器<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 < 1) | |
|             { | |
|                 editor.append("<textarea></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) ? "<a href=\"javascript:;\" class=\"fa fa-close " + classPrefix + "preview-close-btn\"></a>" : "", | |
|                 ( (settings.saveHTMLToTextarea) ? "<textarea class=\"" + classNames.textarea.html + "\" name=\"" + id + "-html-code\"></textarea>" : "" ), | |
|                 "<div class=\"" + classPrefix + "preview\"><div class=\"markdown-body " + classPrefix + "preview-container\"></div></div>", | |
|                 "<div class=\"" + classPrefix + "container-mask\" style=\"display:block;\"></div>", | |
|                 "<div class=\"" + classPrefix + "mask\"></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" && define.amd) | |
|             { | |
|                 if (typeof katex !== "undefined")  | |
|                 { | |
|                     editormd.$katex = katex; | |
|                 } | |
|                  | |
|                 if (settings.searchReplace && !settings.readOnly)  | |
|                 { | |
|                     editormd.loadCSS(settings.path + "codemirror/addon/dialog/dialog"); | |
|                     editormd.loadCSS(settings.path + "codemirror/addon/search/matchesonscrollbar"); | |
|                 } | |
|             } | |
|              | |
|             if ((typeof define === "function" && 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 && settings.sequenceDiagram)  | |
|                             { | |
|                                 editormd.loadScript(loadPath + "sequence-diagram.min", function() { | |
|                                     _this.loadedDisplay(); | |
|                                 }); | |
|                             } | |
|                             else if (settings.flowChart && !settings.sequenceDiagram)  | |
|                             {       | |
|                                 editormd.loadScript(loadPath + "flowchart.min", function() {   | |
|                                     editormd.loadScript(loadPath + "jquery.flowchart.min", function() { | |
|                                         _this.loadedDisplay(); | |
|                                     }); | |
|                                 }); | |
|                             } | |
|                             else if (settings.flowChart && 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 && !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" && 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" && 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" && 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 && (this.toolbar.length < 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 && top < 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 && !state.preview && settings.toolbar && 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 && toolbar.length < 1) | |
|             {             | |
|                 var toolbarHTML = "<div class=\"" + classPrefix + "toolbar\"><div class=\"" + classPrefix + "toolbar-container\"><ul class=\"" + classPrefix + "menu\"></ul></div></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 < len; i++) | |
|             { | |
|                 var name = icons[i]; | |
| 
 | |
|                 if (name === "||")  | |
|                 {  | |
|                     pullRight = true; | |
|                 }  | |
|                 else if (name === "|") | |
|                 { | |
|                     menu += "<li class=\"divider\" unselectable=\"on\">|</li>"; | |
|                 } | |
|                 else | |
|                 { | |
|                     var isHeader = (/h(\d)/.test(name)); | |
|                     var index    = name; | |
|                      | |
|                     if (name === "watch" && !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 ? "<li class=\"pull-right\">" : "<li>"; | |
|                      | |
|                     if (typeof settings.toolbarCustomIcons[name] !== "undefined" && typeof settings.toolbarCustomIcons[name] !== "function") | |
|                     { | |
|                         menuItem += settings.toolbarCustomIcons[name]; | |
|                     } | |
|                     else  | |
|                     { | |
|                         menuItem += "<a href=\"javascript:;\" title=\"" + title + "\" unselectable=\"on\">"; | |
|                         menuItem += "<i class=\"fa " + iconClass + "\" name=\""+name+"\" unselectable=\"on\">"+((isHeader) ? name.toUpperCase() : ( (iconClass === "") ? iconTexts : "") ) + "</i>"; | |
|                         menuItem += "</a>"; | |
|                     } | |
| 
 | |
|                     menuItem += "</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 && 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" && name !== "reference-link" && name !== "image" && name !== "code-block" &&  | |
|                     name !== "preformatted-text" && name !== "watch" && name !== "preview" && name !== "search" && name !== "fullscreen" && 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 = [ | |
|                 "<div class=\"" + classPrefix + "dialog " + classPrefix + "dialog-info\" style=\"\">", | |
|                 "<div class=\"" + classPrefix + "dialog-container\">", | |
|                 "<h1><i class=\"editormd-logo editormd-logo-lg editormd-logo-color\"></i> " + editormd.title + "<small>v" + editormd.version + "</small></h1>", | |
|                 "<p>" + this.lang.description + "</p>", | |
|                 "<p style=\"margin: 10px 0 20px 0;\"><a href=\"" + editormd.homePage + "\" target=\"_blank\">" + editormd.homePage + " <i class=\"fa fa-external-link\"></i></a></p>", | |
|                 "<p style=\"font-size: 0.85em;\">Copyright &copy; 2015 <a href=\"https://github.com/pandao\" target=\"_blank\" class=\"hover-link\">Pandao</a>, The <a href=\"https://github.com/pandao/editor.md/blob/master/LICENSE\" target=\"_blank\" class=\"hover-link\">MIT</a> License.</p>", | |
|                 "</div>", | |
|                 "<a href=\"javascript:;\" class=\"fa fa-close " + classPrefix + "dialog-close\"></a>", | |
|                 "</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 : function() { | |
|             var infoDialog = this.infoDialog; | |
|              | |
| 			var _infoDialogPosition = function() { | |
| 				infoDialog.css({ | |
| 					top  : ($(window).height() - infoDialog.height()) / 2 + "px", | |
| 					left : ($(window).width()  - infoDialog.width()) / 2  + "px" | |
| 				}); | |
| 			}; | |
| 
 | |
| 			_infoDialogPosition(); | |
| 
 | |
| 			$(window).resize(_infoDialogPosition); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 显示关于Editor.md | |
|          * Display about Editor.md dialog | |
|          *  | |
|          * @returns {editormd}  返回editormd的实例对象 | |
|          */ | |
|          | |
|         showInfoDialog : function() { | |
| 
 | |
|             $("html,body").css("overflow-x", "hidden"); | |
|              | |
|             var _this       = this; | |
| 			var editor      = this.editor; | |
|             var settings    = this.settings;          | |
| 			var infoDialog  = this.infoDialog = editor.children("." + this.classPrefix + "dialog-info"); | |
|              | |
|             if (infoDialog.length < 1) | |
|             { | |
|                 this.createInfoDialog(); | |
|             } | |
|              | |
|             this.lockScreen(true); | |
|              | |
|             this.mask.css({ | |
| 						opacity         : settings.dialogMaskOpacity, | |
| 						backgroundColor : settings.dialogMaskBgColor | |
| 					}).show(); | |
| 
 | |
| 			infoDialog.css("z-index", editormd.dialogZindex).show(); | |
| 
 | |
| 			this.infoDialogPosition(); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 隐藏关于Editor.md | |
|          * Hide about Editor.md dialog | |
|          *  | |
|          * @returns {editormd}  返回editormd的实例对象 | |
|          */ | |
|          | |
|         hideInfoDialog : function() {             | |
|             $("html,body").css("overflow-x", ""); | |
|             this.infoDialog.hide(); | |
|             this.mask.hide(); | |
|             this.lockScreen(false); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 锁屏 | |
|          * lock screen | |
|          *  | |
|          * @param   {Boolean}    lock    Boolean 布尔值,是否锁屏 | |
|          * @returns {editormd}           返回editormd的实例对象 | |
|          */ | |
|          | |
|         lockScreen : function(lock) { | |
|             editormd.lockScreen(lock); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 编辑器界面重建,用于动态语言包或模块加载等 | |
|          * Recreate editor | |
|          *  | |
|          * @returns {editormd}  返回editormd的实例对象 | |
|          */ | |
|          | |
|         recreate : function() { | |
|             var _this            = this; | |
|             var editor           = this.editor; | |
|             var settings         = this.settings; | |
|              | |
|             this.codeMirror.remove(); | |
|              | |
|             this.setCodeMirror(); | |
| 
 | |
|             if (!settings.readOnly)  | |
|             { | |
|                 if (editor.find(".editormd-dialog").length > 0) { | |
|                     editor.find(".editormd-dialog").remove(); | |
|                 } | |
|                  | |
|                 if (settings.toolbar)  | |
|                 {   | |
|                     this.getToolbarHandles();                   | |
|                     this.setToolbar(); | |
|                 } | |
|             } | |
|              | |
|             this.loadedDisplay(true); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 高亮预览HTML的pre代码部分 | |
|          * highlight of preview codes | |
|          *  | |
|          * @returns {editormd}             返回editormd的实例对象 | |
|          */ | |
|          | |
|         previewCodeHighlight : function() {     | |
|             var settings         = this.settings; | |
|             var previewContainer = this.previewContainer; | |
|              | |
|             if (settings.previewCodeHighlight)  | |
|             { | |
|                 previewContainer.find("pre").addClass("prettyprint linenums"); | |
|                  | |
|                 if (typeof prettyPrint !== "undefined") | |
|                 {                     | |
|                     prettyPrint(); | |
|                 } | |
|             } | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 解析TeX(KaTeX)科学公式 | |
|          * TeX(KaTeX) Renderer | |
|          *  | |
|          * @returns {editormd}             返回editormd的实例对象 | |
|          */ | |
|          | |
|         katexRender : function() { | |
|              | |
|             if (timer === null) | |
|             { | |
|                 return this; | |
|             } | |
|              | |
|             this.previewContainer.find("." + editormd.classNames.tex).each(function(){ | |
|                 var tex  = $(this); | |
|                 editormd.$katex.render(tex.text(), tex[0]); | |
|             });    | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 解析和渲染流程图及时序图 | |
|          * FlowChart and SequenceDiagram Renderer | |
|          *  | |
|          * @returns {editormd}             返回editormd的实例对象 | |
|          */ | |
|          | |
|         flowChartAndSequenceDiagramRender : function() { | |
|              | |
|             var settings         = this.settings; | |
|             var previewContainer = this.previewContainer; | |
|              | |
|             if (editormd.isIE8) { | |
|                 return this; | |
|             } | |
| 
 | |
|             if (settings.flowChart) { | |
|                 if (flowchartTimer === null) { | |
|                     return this; | |
|                 } | |
|                  | |
|                 previewContainer.find(".flowchart").flowChart();  | |
|             } | |
| 
 | |
|             if (settings.sequenceDiagram) { | |
|                 previewContainer.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); | |
|             } | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 注册键盘快捷键处理 | |
|          * Register CodeMirror keyMaps (keyboard shortcuts). | |
|          *  | |
|          * @param   {Object}    keyMap      KeyMap key/value {"(Ctrl/Shift/Alt)-Key" : function(){}} | |
|          * @returns {editormd}              return this | |
|          */ | |
|          | |
|         registerKeyMaps : function(keyMap) { | |
|              | |
|             var _this           = this; | |
|             var cm              = this.cm; | |
|             var settings        = this.settings; | |
|             var toolbarHandlers = editormd.toolbarHandlers; | |
|             var disabledKeyMaps = settings.disabledKeyMaps; | |
|              | |
|             keyMap              = keyMap || null; | |
|              | |
|             if (keyMap) | |
|             { | |
|                 for (var i in keyMap) | |
|                 { | |
|                     if ($.inArray(i, disabledKeyMaps) < 0) | |
|                     { | |
|                         var map = {}; | |
|                         map[i]  = keyMap[i]; | |
| 
 | |
|                         cm.addKeyMap(keyMap); | |
|                     } | |
|                 } | |
|             } | |
|             else | |
|             { | |
|                 for (var k in editormd.keyMaps) | |
|                 { | |
|                     var _keyMap = editormd.keyMaps[k]; | |
|                     var handle = (typeof _keyMap === "string") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this); | |
|                      | |
|                     if ($.inArray(k, ["F9", "F10", "F11"]) < 0 && $.inArray(k, disabledKeyMaps) < 0) | |
|                     { | |
|                         var _map = {}; | |
|                         _map[k] = handle; | |
| 
 | |
|                         cm.addKeyMap(_map); | |
|                     } | |
|                 } | |
|                  | |
|                 $(window).keydown(function(event) { | |
|                      | |
|                     var keymaps = { | |
|                         "120" : "F9", | |
|                         "121" : "F10", | |
|                         "122" : "F11" | |
|                     }; | |
|                      | |
|                     if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 ) | |
|                     { | |
|                         switch (event.keyCode) | |
|                         { | |
|                             case 120: | |
|                                     $.proxy(toolbarHandlers["watch"], _this)(); | |
|                                     return false; | |
|                                 break; | |
|                                  | |
|                             case 121: | |
|                                     $.proxy(toolbarHandlers["preview"], _this)(); | |
|                                     return false; | |
|                                 break; | |
|                                  | |
|                             case 122: | |
|                                     $.proxy(toolbarHandlers["fullscreen"], _this)();                         | |
|                                     return false; | |
|                                 break; | |
|                                  | |
|                             default: | |
|                                 break; | |
|                         } | |
|                     } | |
|                 }); | |
|             } | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         bindScrollEvent : function() { | |
|              | |
|             var _this            = this; | |
|             var preview          = this.preview; | |
|             var settings         = this.settings; | |
|             var codeMirror       = this.codeMirror; | |
|             var mouseOrTouch     = editormd.mouseOrTouch; | |
|              | |
|             if (!settings.syncScrolling) { | |
|                 return this; | |
|             } | |
|                  | |
|             var cmBindScroll = function() {     | |
|                 codeMirror.find(".CodeMirror-scroll").bind(mouseOrTouch("scroll", "touchmove"), function(event) { | |
|                     var height    = $(this).height(); | |
|                     var scrollTop = $(this).scrollTop();                     | |
|                     var percent   = (scrollTop / $(this)[0].scrollHeight); | |
| 
 | |
|                     if (scrollTop === 0)  | |
|                     { | |
|                         preview.scrollTop(0); | |
|                     }  | |
|                     else if (scrollTop + height >= $(this)[0].scrollHeight - 16) | |
|                     {  | |
|                         preview.scrollTop(preview[0].scrollHeight);                         | |
|                     }  | |
|                     else | |
|                     {                     | |
|                         preview.scrollTop(preview[0].scrollHeight * percent); | |
|                     } | |
|                      | |
|                     $.proxy(settings.onscroll, _this)(event); | |
|                 }); | |
|             }; | |
| 
 | |
|             var cmUnbindScroll = function() { | |
|                 codeMirror.find(".CodeMirror-scroll").unbind(mouseOrTouch("scroll", "touchmove")); | |
|             }; | |
| 
 | |
|             var previewBindScroll = function() { | |
|                  | |
|                 preview.bind(mouseOrTouch("scroll", "touchmove"), function(event) { | |
|                     var height    = $(this).height(); | |
|                     var scrollTop = $(this).scrollTop();          | |
|                     var percent   = (scrollTop / $(this)[0].scrollHeight); | |
|                     var codeView  = codeMirror.find(".CodeMirror-scroll"); | |
| 
 | |
|                     if(scrollTop === 0)  | |
|                     { | |
|                         codeView.scrollTop(0); | |
|                     } | |
|                     else if (scrollTop + height >= $(this)[0].scrollHeight) | |
|                     { | |
|                         codeView.scrollTop(codeView[0].scrollHeight);                         | |
|                     } | |
|                     else  | |
|                     { | |
|                         codeView.scrollTop(codeView[0].scrollHeight * percent); | |
|                     } | |
|                      | |
|                     $.proxy(settings.onpreviewscroll, _this)(event); | |
|                 }); | |
| 
 | |
|             }; | |
| 
 | |
|             var previewUnbindScroll = function() { | |
|                 preview.unbind(mouseOrTouch("scroll", "touchmove")); | |
|             };  | |
| 
 | |
| 			codeMirror.bind({ | |
| 				mouseover  : cmBindScroll, | |
| 				mouseout   : cmUnbindScroll, | |
| 				touchstart : cmBindScroll, | |
| 				touchend   : cmUnbindScroll | |
| 			}); | |
|              | |
| 			preview.bind({ | |
| 				mouseover  : previewBindScroll, | |
| 				mouseout   : previewUnbindScroll, | |
| 				touchstart : previewBindScroll, | |
| 				touchend   : previewUnbindScroll | |
| 			}); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         bindChangeEvent : function() { | |
|              | |
|             var _this            = this; | |
|             var cm               = this.cm; | |
|             var settings         = this.settings; | |
|              | |
|             if (!settings.syncScrolling) { | |
|                 return this; | |
|             } | |
|              | |
|             cm.on("change", function(_cm, changeObj) { | |
|                  | |
|                 if (settings.watch) | |
|                 {            | |
|                     _this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); | |
|                 } | |
|                  | |
|                 timer = setTimeout(function() { | |
|                     clearTimeout(timer); | |
|                     _this.save(); | |
|                     timer = null; | |
|                 }, settings.delay); | |
|             }); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 加载队列完成之后的显示处理 | |
|          * Display handle of the module queues loaded after. | |
|          *  | |
|          * @param   {Boolean}   recreate   是否为重建编辑器 | |
|          * @returns {editormd}             返回editormd的实例对象 | |
|          */ | |
|          | |
|         loadedDisplay : function(recreate) { | |
|              | |
|             recreate             = recreate || false; | |
|              | |
|             var _this            = this; | |
|             var editor           = this.editor; | |
|             var preview          = this.preview; | |
|             var settings         = this.settings; | |
|              | |
|             this.containerMask.hide(); | |
|              | |
|             this.save(); | |
|              | |
|             if (settings.watch) { | |
|                 preview.show(); | |
|             } | |
|              | |
|             editor.data("oldWidth", editor.width()).data("oldHeight", editor.height()); // 为了兼容Zepto | |
|              | |
|             this.resize(); | |
|             this.registerKeyMaps(); | |
|              | |
|             $(window).resize(function(){ | |
|                 _this.resize(); | |
|             }); | |
|              | |
|             this.bindScrollEvent().bindChangeEvent(); | |
|              | |
|             if (!recreate) | |
|             { | |
|                 $.proxy(settings.onload, this)(); | |
|             } | |
|              | |
|             this.state.loaded = true; | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 设置编辑器的宽度 | |
|          * Set editor width | |
|          *  | |
|          * @param   {Number|String} width  编辑器宽度值 | |
|          * @returns {editormd}             返回editormd的实例对象 | |
|          */ | |
|          | |
|         width : function(width) { | |
|                  | |
|             this.editor.css("width", (typeof width === "number") ? width  + "px" : width);             | |
|             this.resize(); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 设置编辑器的高度 | |
|          * Set editor height | |
|          *  | |
|          * @param   {Number|String} height  编辑器高度值 | |
|          * @returns {editormd}              返回editormd的实例对象 | |
|          */ | |
|          | |
|         height : function(height) { | |
|                  | |
|             this.editor.css("height", (typeof height === "number")  ? height  + "px" : height);             | |
|             this.resize(); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 调整编辑器的尺寸和布局 | |
|          * Resize editor layout | |
|          *  | |
|          * @param   {Number|String} [width=null]  编辑器宽度值 | |
|          * @param   {Number|String} [height=null] 编辑器高度值 | |
|          * @returns {editormd}                    返回editormd的实例对象 | |
|          */ | |
|          | |
|         resize : function(width, height) { | |
|              | |
|             width  = width  || null; | |
|             height = height || null; | |
|              | |
|             var state      = this.state; | |
|             var editor     = this.editor; | |
|             var preview    = this.preview; | |
|             var toolbar    = this.toolbar; | |
|             var settings   = this.settings; | |
|             var codeMirror = this.codeMirror; | |
|              | |
|             if (width) | |
|             { | |
|                 editor.css("width", (typeof width  === "number") ? width  + "px" : width); | |
|             } | |
|              | |
|             if (settings.autoHeight && !state.fullscreen && !state.preview) | |
|             { | |
|                 editor.css("height", "auto"); | |
|                 codeMirror.css("height", "auto"); | |
|             }  | |
|             else  | |
|             { | |
|                 if (height)  | |
|                 { | |
|                     editor.css("height", (typeof height === "number") ? height + "px" : height); | |
|                 } | |
|                  | |
|                 if (state.fullscreen) | |
|                 { | |
|                     editor.height($(window).height()); | |
|                 } | |
| 
 | |
|                 if (settings.toolbar && !settings.readOnly)  | |
|                 { | |
|                     codeMirror.css("margin-top", toolbar.height() + 1).height(editor.height() - toolbar.height()); | |
|                 }  | |
|                 else | |
|                 { | |
|                     codeMirror.css("margin-top", 0).height(editor.height()); | |
|                 } | |
|             } | |
|              | |
|             if(settings.watch)  | |
|             { | |
|                 codeMirror.width(editor.width() / 2); | |
|                 preview.width((!state.preview) ? editor.width() / 2 : editor.width()); | |
|                  | |
|                 this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); | |
|                  | |
|                 if (settings.toolbar && !settings.readOnly)  | |
|                 { | |
|                     preview.css("top", toolbar.height()); | |
|                 }  | |
|                 else  | |
|                 { | |
|                     preview.css("top", 0); | |
|                 } | |
|                  | |
|                 if (settings.autoHeight && !state.fullscreen && !state.preview) | |
|                 { | |
|                     preview.height(""); | |
|                 } | |
|                 else | |
|                 {                 | |
|                     preview.height((settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height()); | |
|                 } | |
|             }  | |
|             else  | |
|             { | |
|                 codeMirror.width(editor.width()); | |
|                 preview.hide(); | |
|             } | |
|              | |
|             if (state.loaded)  | |
|             { | |
|                 $.proxy(settings.onresize, this)(); | |
|             } | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 解析和保存Markdown代码 | |
|          * Parse & Saving Markdown source code | |
|          *  | |
|          * @returns {editormd}     返回editormd的实例对象 | |
|          */ | |
|          | |
|         save : function() { | |
|              | |
|             if (timer === null) | |
|             { | |
|                 return this; | |
|             } | |
|              | |
|             var _this            = this; | |
|             var state            = this.state; | |
|             var settings         = this.settings; | |
|             var cm               = this.cm;             | |
|             var cmValue          = cm.getValue(); | |
|             var previewContainer = this.previewContainer; | |
| 
 | |
|             if (settings.mode !== "gfm" && settings.mode !== "markdown")  | |
|             { | |
|                 this.markdownTextarea.val(cmValue); | |
|                  | |
|                 return this; | |
|             } | |
|              | |
|             var marked          = editormd.$marked; | |
|             var markdownToC     = this.markdownToC = [];             | |
|             var rendererOptions = this.markedRendererOptions = {   | |
|                 toc                  : settings.toc, | |
|                 tocm                 : settings.tocm, | |
|                 tocStartLevel        : settings.tocStartLevel, | |
|                 pageBreak            : settings.pageBreak, | |
|                 taskList             : settings.taskList, | |
|                 emoji                : settings.emoji, | |
|                 tex                  : settings.tex, | |
|                 atLink               : settings.atLink,           // for @link | |
|                 emailLink            : settings.emailLink,        // for mail address auto link | |
|                 flowChart            : settings.flowChart, | |
|                 sequenceDiagram      : settings.sequenceDiagram, | |
|                 previewCodeHighlight : settings.previewCodeHighlight, | |
|             }; | |
|              | |
|             var markedOptions = this.markedOptions = { | |
|                 renderer    : editormd.markedRenderer(markdownToC, rendererOptions), | |
|                 gfm         : true, | |
|                 tables      : true, | |
|                 breaks      : true, | |
|                 pedantic    : false, | |
|                 sanitize    : (settings.htmlDecode) ? false : true,  // 关闭忽略HTML标签,即开启识别HTML标签,默认为false | |
|                 smartLists  : true, | |
|                 smartypants : true | |
|             }; | |
|              | |
|             marked.setOptions(markedOptions); | |
|          | |
|             cmValue            = editormd.filterHTMLTags(cmValue, settings.htmlDecode); | |
|              | |
|             var newMarkdownDoc = editormd.$marked(cmValue, markedOptions); | |
|              | |
|             //console.log("cmValue", cmValue, this.markdownTextarea, this.htmlTextarea); | |
|              | |
|             this.markdownTextarea.text(cmValue); | |
|              | |
|             cm.save(); | |
|              | |
|             if (settings.saveHTMLToTextarea)  | |
|             { | |
|                 this.htmlTextarea.text(newMarkdownDoc); | |
|             } | |
|              | |
|             if(settings.watch || (!settings.watch && state.preview)) | |
|             { | |
|                 previewContainer.html(newMarkdownDoc); | |
| 
 | |
|                 this.previewCodeHighlight(); | |
|                  | |
|                 if (settings.toc)  | |
|                 { | |
|                     var tocContainer = (settings.tocContainer === "") ? previewContainer : $(settings.tocContainer); | |
|                     var tocMenu      = tocContainer.find("." + this.classPrefix + "toc-menu"); | |
|                      | |
|                     tocContainer.attr("previewContainer", (settings.tocContainer === "") ? "true" : "false"); | |
|                      | |
|                     if (settings.tocContainer !== "" && tocMenu.length > 0) | |
|                     { | |
|                         tocMenu.remove(); | |
|                     } | |
|                      | |
|                     editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); | |
|              | |
|                     if (settings.tocDropdown || tocContainer.find("." + this.classPrefix + "toc-menu").length > 0) | |
|                     { | |
|                         editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== "") ? settings.tocTitle : this.lang.tocTitle); | |
|                     } | |
|              | |
|                     if (settings.tocContainer !== "") | |
|                     { | |
|                         previewContainer.find(".markdown-toc").css("border", "none"); | |
|                     } | |
|                 } | |
|                  | |
|                 if (settings.tex) | |
|                 { | |
|                     if (!editormd.kaTeXLoaded && settings.autoLoadModules)  | |
|                     { | |
|                         editormd.loadKaTeX(function() { | |
|                             editormd.$katex = katex; | |
|                             editormd.kaTeXLoaded = true; | |
|                             _this.katexRender(); | |
|                         }); | |
|                     }  | |
|                     else  | |
|                     { | |
|                         editormd.$katex = katex; | |
|                         this.katexRender(); | |
|                     } | |
|                 }                 | |
|                  | |
|                 if (settings.flowChart || settings.sequenceDiagram) | |
|                 { | |
|                     flowchartTimer = setTimeout(function(){ | |
|                         clearTimeout(flowchartTimer); | |
|                         _this.flowChartAndSequenceDiagramRender(); | |
|                         flowchartTimer = null; | |
|                     }, 10); | |
|                 } | |
| 
 | |
|                 if (state.loaded)  | |
|                 { | |
|                     $.proxy(settings.onchange, this)(); | |
|                 } | |
|             } | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 聚焦光标位置 | |
|          * Focusing the cursor position | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         focus : function() { | |
|             this.cm.focus(); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 设置光标的位置 | |
|          * Set cursor position | |
|          *  | |
|          * @param   {Object}    cursor 要设置的光标位置键值对象,例:{line:1, ch:0} | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         setCursor : function(cursor) { | |
|             this.cm.setCursor(cursor); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 获取当前光标的位置 | |
|          * Get the current position of the cursor | |
|          *  | |
|          * @returns {Cursor}         返回一个光标Cursor对象 | |
|          */ | |
|          | |
|         getCursor : function() { | |
|             return this.cm.getCursor(); | |
|         }, | |
|          | |
|         /** | |
|          * 设置光标选中的范围 | |
|          * Set cursor selected ranges | |
|          *  | |
|          * @param   {Object}    from   开始位置的光标键值对象,例:{line:1, ch:0} | |
|          * @param   {Object}    to     结束位置的光标键值对象,例:{line:1, ch:0} | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         setSelection : function(from, to) { | |
|          | |
|             this.cm.setSelection(from, to); | |
|          | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 获取光标选中的文本 | |
|          * Get the texts from cursor selected | |
|          *  | |
|          * @returns {String}         返回选中文本的字符串形式 | |
|          */ | |
|          | |
|         getSelection : function() { | |
|             return this.cm.getSelection(); | |
|         }, | |
|          | |
|         /** | |
|          * 设置光标选中的文本范围 | |
|          * Set the cursor selection ranges | |
|          *  | |
|          * @param   {Array}    ranges  cursor selection ranges array | |
|          * @returns {Array}            return this | |
|          */ | |
|          | |
|         setSelections : function(ranges) { | |
|             this.cm.setSelections(ranges); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 获取光标选中的文本范围 | |
|          * Get the cursor selection ranges | |
|          *  | |
|          * @returns {Array}         return selection ranges array | |
|          */ | |
|          | |
|         getSelections : function() { | |
|             return this.cm.getSelections(); | |
|         }, | |
|          | |
|         /** | |
|          * 替换当前光标选中的文本或在当前光标处插入新字符 | |
|          * Replace the text at the current cursor selected or insert a new character at the current cursor position | |
|          *  | |
|          * @param   {String}    value  要插入的字符值 | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         replaceSelection : function(value) { | |
|             this.cm.replaceSelection(value); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 在当前光标处插入新字符 | |
|          * Insert a new character at the current cursor position | |
|          * | |
|          * 同replaceSelection()方法 | |
|          * With the replaceSelection() method | |
|          *  | |
|          * @param   {String}    value  要插入的字符值 | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         insertValue : function(value) { | |
|             this.replaceSelection(value); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 追加markdown | |
|          * append Markdown to editor | |
|          *  | |
|          * @param   {String}    md     要追加的markdown源文档 | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         appendMarkdown : function(md) { | |
|             var settings = this.settings; | |
|             var cm       = this.cm; | |
|              | |
|             cm.setValue(cm.getValue() + md); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 设置和传入编辑器的markdown源文档 | |
|          * Set Markdown source document | |
|          *  | |
|          * @param   {String}    md     要传入的markdown源文档 | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         setMarkdown : function(md) { | |
|             this.cm.setValue(md || this.settings.markdown); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 获取编辑器的markdown源文档 | |
|          * Set Editor.md markdown/CodeMirror value | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         getMarkdown : function() { | |
|             return this.cm.getValue(); | |
|         }, | |
|          | |
|         /** | |
|          * 获取编辑器的源文档 | |
|          * Get CodeMirror value | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         getValue : function() { | |
|             return this.cm.getValue(); | |
|         }, | |
|          | |
|         /** | |
|          * 设置编辑器的源文档 | |
|          * Set CodeMirror value | |
|          *  | |
|          * @param   {String}     value   set code/value/string/text | |
|          * @returns {editormd}           返回editormd的实例对象 | |
|          */ | |
|          | |
|         setValue : function(value) { | |
|             this.cm.setValue(value); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 清空编辑器 | |
|          * Empty CodeMirror editor container | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         clear : function() { | |
|             this.cm.setValue(""); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 获取解析后存放在Textarea的HTML源码 | |
|          * Get parsed html code from Textarea | |
|          *  | |
|          * @returns {String}               返回HTML源码 | |
|          */ | |
|          | |
|         getHTML : function() { | |
|             if (!this.settings.saveHTMLToTextarea) | |
|             { | |
|                 alert("Error: settings.saveHTMLToTextarea == false"); | |
| 
 | |
|                 return false; | |
|             } | |
|              | |
|             return this.htmlTextarea.val(); | |
|         }, | |
|          | |
|         /** | |
|          * getHTML()的别名 | |
|          * getHTML (alias) | |
|          *  | |
|          * @returns {String}           Return html code 返回HTML源码 | |
|          */ | |
|          | |
|         getTextareaSavedHTML : function() { | |
|             return this.getHTML(); | |
|         }, | |
|          | |
|         /** | |
|          * 获取预览窗口的HTML源码 | |
|          * Get html from preview container | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         getPreviewedHTML : function() { | |
|             if (!this.settings.watch) | |
|             { | |
|                 alert("Error: settings.watch == false"); | |
| 
 | |
|                 return false; | |
|             } | |
|              | |
|             return this.previewContainer.html(); | |
|         }, | |
|          | |
|         /** | |
|          * 开启实时预览 | |
|          * Enable real-time watching | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         watch : function(callback) {      | |
|             var settings        = this.settings; | |
|              | |
|             if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) | |
|             { | |
|                 return this; | |
|             } | |
|              | |
|             this.state.watching = settings.watch = true; | |
|             this.preview.show(); | |
|              | |
|             if (this.toolbar) | |
|             { | |
|                 var watchIcon   = settings.toolbarIconsClass.watch; | |
|                 var unWatchIcon = settings.toolbarIconsClass.unwatch; | |
|                  | |
|                 var icon        = this.toolbar.find(".fa[name=watch]"); | |
|                 icon.parent().attr("title", settings.lang.toolbar.watch); | |
|                 icon.removeClass(unWatchIcon).addClass(watchIcon); | |
|             } | |
|              | |
|             this.codeMirror.css("border-right", "1px solid #ddd").width(this.editor.width() / 2);  | |
|              | |
|             timer = 0; | |
|              | |
|             this.save().resize(); | |
|              | |
|             if (!settings.onwatch) | |
|             { | |
|                 settings.onwatch = callback || function() {}; | |
|             } | |
|              | |
|             $.proxy(settings.onwatch, this)(); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 关闭实时预览 | |
|          * Disable real-time watching | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         unwatch : function(callback) { | |
|             var settings        = this.settings; | |
|             this.state.watching = settings.watch = false; | |
|             this.preview.hide(); | |
|              | |
|             if (this.toolbar)  | |
|             { | |
|                 var watchIcon   = settings.toolbarIconsClass.watch; | |
|                 var unWatchIcon = settings.toolbarIconsClass.unwatch; | |
|                  | |
|                 var icon    = this.toolbar.find(".fa[name=watch]"); | |
|                 icon.parent().attr("title", settings.lang.toolbar.unwatch); | |
|                 icon.removeClass(watchIcon).addClass(unWatchIcon); | |
|             } | |
|              | |
|             this.codeMirror.css("border-right", "none").width(this.editor.width()); | |
|              | |
|             this.resize(); | |
|              | |
|             if (!settings.onunwatch) | |
|             { | |
|                 settings.onunwatch = callback || function() {}; | |
|             } | |
|              | |
|             $.proxy(settings.onunwatch, this)(); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 显示编辑器 | |
|          * Show editor | |
|          *  | |
|          * @param   {Function} [callback=function()] 回调函数 | |
|          * @returns {editormd}                       返回editormd的实例对象 | |
|          */ | |
|          | |
|         show : function(callback) { | |
|             callback  = callback || function() {}; | |
|              | |
|             var _this = this; | |
|             this.editor.show(0, function() { | |
|                 $.proxy(callback, _this)(); | |
|             }); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 隐藏编辑器 | |
|          * Hide editor | |
|          *  | |
|          * @param   {Function} [callback=function()] 回调函数 | |
|          * @returns {editormd}                       返回editormd的实例对象 | |
|          */ | |
|          | |
|         hide : function(callback) { | |
|             callback  = callback || function() {}; | |
|              | |
|             var _this = this; | |
|             this.editor.hide(0, function() { | |
|                 $.proxy(callback, _this)(); | |
|             }); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 隐藏编辑器部分,只预览HTML | |
|          * Enter preview html state | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         previewing : function() { | |
|              | |
|             var _this            = this; | |
|             var editor           = this.editor; | |
|             var preview          = this.preview; | |
|             var toolbar          = this.toolbar; | |
|             var settings         = this.settings; | |
|             var codeMirror       = this.codeMirror; | |
|              | |
|             if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) { | |
|                 return this; | |
|             } | |
|              | |
|             if (settings.toolbar && toolbar) { | |
|                 toolbar.toggle(); | |
|                 toolbar.find(".fa[name=preview]").toggleClass("active"); | |
|             } | |
|              | |
|             codeMirror.toggle(); | |
|              | |
|             var escHandle = function(event) { | |
|                 if (event.shiftKey && event.keyCode === 27) { | |
|                     _this.previewed(); | |
|                 } | |
|             }; | |
| 
 | |
|             if (codeMirror.css("display") === "none") // 为了兼容Zepto,而不使用codeMirror.is(":hidden") | |
|             { | |
|                 this.state.preview = true; | |
| 
 | |
|                 if (this.state.fullscreen) { | |
|                     preview.css("background", "#fff"); | |
|                 } | |
|                  | |
|                 editor.find("." + this.classPrefix + "preview-close-btn").show().bind(editormd.mouseOrTouch("click", "touchend"), function(){ | |
|                     _this.previewed(); | |
|                 }); | |
|              | |
|                 if (!settings.watch) | |
|                 { | |
|                     this.save(); | |
|                 } | |
| 
 | |
|                 preview.show().css({ | |
|                     position  : "static", | |
|                     top       : 0, | |
|                     width     : editor.width(), | |
|                     height    : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() | |
|                 }); | |
|                  | |
|                 if (this.state.loaded) | |
|                 { | |
|                     $.proxy(settings.onpreviewing, this)(); | |
|                 } | |
| 
 | |
|                 $(window).bind("keyup", escHandle); | |
|             }  | |
|             else  | |
|             { | |
|                 $(window).unbind("keyup", escHandle); | |
|                 this.previewed(); | |
|             } | |
|         }, | |
|          | |
|         /** | |
|          * 显示编辑器部分,退出只预览HTML | |
|          * Exit preview html state | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         previewed : function() { | |
|              | |
|             var editor           = this.editor; | |
|             var preview          = this.preview; | |
|             var toolbar          = this.toolbar; | |
|             var settings         = this.settings; | |
|             var previewCloseBtn  = editor.find("." + this.classPrefix + "preview-close-btn"); | |
| 
 | |
|             this.state.preview   = false; | |
|              | |
|             this.codeMirror.show(); | |
|              | |
|             if (settings.toolbar) { | |
|                 toolbar.show(); | |
|             } | |
|              | |
|             preview[(settings.watch) ? "show" : "hide"](); | |
|              | |
|             previewCloseBtn.hide().unbind(editormd.mouseOrTouch("click", "touchend")); | |
|              | |
|             preview.css({  | |
|                 background : null, | |
|                 position   : "absolute", | |
|                 width      : editor.width() / 2, | |
|                 height     : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() - toolbar.height(), | |
|                 top        : (settings.toolbar)    ? toolbar.height() : 0 | |
|             }); | |
| 
 | |
|             if (this.state.loaded) | |
|             { | |
|                 $.proxy(settings.onpreviewed, this)(); | |
|             } | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 编辑器全屏显示 | |
|          * Fullscreen show | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         fullscreen : function() { | |
|              | |
|             var _this            = this; | |
|             var state            = this.state; | |
|             var editor           = this.editor; | |
|             var preview          = this.preview; | |
|             var toolbar          = this.toolbar; | |
|             var settings         = this.settings; | |
|             var fullscreenClass  = this.classPrefix + "fullscreen"; | |
|              | |
|             if (toolbar) { | |
|                 toolbar.find(".fa[name=fullscreen]").parent().toggleClass("active");  | |
|             } | |
|              | |
|             var escHandle = function(event) { | |
|                 if (!event.shiftKey && event.keyCode === 27)  | |
|                 { | |
|                     if (state.fullscreen) | |
|                     { | |
|                         _this.fullscreenExit(); | |
|                     } | |
|                 } | |
|             }; | |
| 
 | |
|             if (!editor.hasClass(fullscreenClass))  | |
|             { | |
|                 state.fullscreen = true; | |
| 
 | |
|                 $("html,body").css("overflow", "hidden"); | |
|                  | |
|                 editor.css({ | |
|                     position : "fixed",  | |
|                     top      : 0,  | |
|                     left     : 0,  | |
|                     margin   : 0,  | |
|                     border   : "none", | |
|                     width    : $(window).width(), | |
|                     height   : $(window).height() | |
|                 }).addClass(fullscreenClass); | |
| 
 | |
|                 this.resize(); | |
|      | |
|                 $.proxy(settings.onfullscreen, this)(); | |
| 
 | |
|                 $(window).bind("keyup", escHandle); | |
|             } | |
|             else | |
|             {            | |
|                 $(window).unbind("keyup", escHandle);  | |
|                 this.fullscreenExit(); | |
|             } | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 编辑器退出全屏显示 | |
|          * Exit fullscreen state | |
|          *  | |
|          * @returns {editormd}         返回editormd的实例对象 | |
|          */ | |
|          | |
|         fullscreenExit : function() { | |
|              | |
|             var editor            = this.editor; | |
|             var settings          = this.settings; | |
|             var toolbar           = this.toolbar; | |
|             var fullscreenClass   = this.classPrefix + "fullscreen";   | |
|              | |
|             this.state.fullscreen = false; | |
|              | |
|             if (toolbar) { | |
|                 toolbar.find(".fa[name=fullscreen]").parent().removeClass("active");  | |
|             } | |
| 
 | |
|             $("html,body").css("overflow", ""); | |
| 
 | |
|             editor.css({ | |
|                 position : "",  | |
|                 top      : "", | |
|                 left     : "",  | |
|                 margin   : "0 auto 15px",  | |
|                 width    : editor.data("oldWidth"), | |
|                 height   : editor.data("oldHeight"), | |
|                 border   : "1px solid #ddd" | |
|             }).removeClass(fullscreenClass); | |
| 
 | |
|             this.resize(); | |
|              | |
|             $.proxy(settings.onfullscreenExit, this)(); | |
| 
 | |
|             return this; | |
|         }, | |
|          | |
|         /** | |
|          * 加载并执行插件 | |
|          * Load and execute the plugin | |
|          *  | |
|          * @param   {String}     name    plugin name / function name | |
|          * @param   {String}     path    plugin load path | |
|          * @returns {editormd}           返回editormd的实例对象 | |
|          */ | |
|          | |
|         executePlugin : function(name, path) { | |
|              | |
|             var _this    = this; | |
|             var cm       = this.cm; | |
|             var settings = this.settings; | |
|              | |
|             path = settings.pluginPath + path; | |
|              | |
|             if (typeof define === "function")  | |
|             {             | |
|                 if (typeof this[name] === "undefined") | |
|                 { | |
|                     alert("Error: " + name + " plugin is not found, you are not load this plugin."); | |
|                      | |
|                     return this; | |
|                 } | |
|                  | |
|                 this[name](cm); | |
|                  | |
|                 return this; | |
|             } | |
|              | |
|             if ($.inArray(path, editormd.loadFiles.plugin) < 0) | |
|             { | |
|                 editormd.loadPlugin(path, function() { | |
|                     editormd.loadPlugins[name] = _this[name]; | |
|                     _this[name](cm); | |
|                 }); | |
|             } | |
|             else | |
|             { | |
|                 $.proxy(editormd.loadPlugins[name], this)(cm); | |
|             } | |
|              | |
|             return this; | |
|         }, | |
|                  | |
|         /** | |
|          * 搜索替换 | |
|          * Search & replace | |
|          *  | |
|          * @param   {String}     command    CodeMirror serach commands, "find, fintNext, fintPrev, clearSearch, replace, replaceAll" | |
|          * @returns {editormd}              return this | |
|          */ | |
|          | |
|         search : function(command) { | |
|             var settings = this.settings; | |
|              | |
|             if (!settings.searchReplace) | |
|             { | |
|                 alert("Error: settings.searchReplace == false"); | |
|                 return this; | |
|             } | |
|              | |
|             if (!settings.readOnly) | |
|             { | |
|                 this.cm.execCommand(command || "find"); | |
|             } | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         searchReplace : function() {             | |
|             this.search("replace"); | |
|              | |
|             return this; | |
|         }, | |
|          | |
|         searchReplaceAll : function() {           | |
|             this.search("replaceAll"); | |
|              | |
|             return this; | |
|         } | |
|     }; | |
|      | |
|     editormd.fn.init.prototype = editormd.fn;  | |
|     | |
|     /** | |
|      * 锁屏 | |
|      * lock screen when dialog opening | |
|      *  | |
|      * @returns {void} | |
|      */ | |
| 
 | |
|     editormd.dialogLockScreen = function() { | |
|         var settings = this.settings || {dialogLockScreen : true}; | |
|          | |
|         if (settings.dialogLockScreen)  | |
|         { | |
|             $("html,body").css("overflow", "hidden"); | |
|         } | |
|     }; | |
|     | |
|     /** | |
|      * 显示透明背景层 | |
|      * Display mask layer when dialog opening | |
|      *  | |
|      * @param   {Object}     dialog    dialog jQuery object | |
|      * @returns {void} | |
|      */ | |
|      | |
|     editormd.dialogShowMask = function(dialog) { | |
|         var editor   = this.editor; | |
|         var settings = this.settings || {dialogShowMask : true}; | |
|          | |
|         dialog.css({ | |
|             top  : ($(window).height() - dialog.height()) / 2 + "px", | |
|             left : ($(window).width()  - dialog.width())  / 2 + "px" | |
|         }); | |
| 
 | |
|         if (settings.dialogShowMask) { | |
|             editor.children("." + this.classPrefix + "mask").css("z-index", parseInt(dialog.css("z-index")) - 1).show(); | |
|         } | |
|     }; | |
| 
 | |
|     editormd.toolbarHandlers = { | |
|         undo : function() { | |
|             this.cm.undo(); | |
|         }, | |
|          | |
|         redo : function() { | |
|             this.cm.redo(); | |
|         }, | |
|          | |
|         bold : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("**" + selection + "**"); | |
| 
 | |
|             if(selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 2); | |
|             } | |
|         }, | |
|          | |
|         del : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("~~" + selection + "~~"); | |
| 
 | |
|             if(selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 2); | |
|             } | |
|         }, | |
| 
 | |
|         italic : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("*" + selection + "*"); | |
| 
 | |
|             if(selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 1); | |
|             } | |
|         }, | |
| 
 | |
|         quote : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("> " + selection); | |
|             cm.setCursor(cursor.line, (selection === "") ? cursor.ch + 2 : cursor.ch + selection.length + 2); | |
|         }, | |
|          | |
|         ucfirst : function() { | |
|             var cm         = this.cm; | |
|             var selection  = cm.getSelection(); | |
|             var selections = cm.listSelections(); | |
| 
 | |
|             cm.replaceSelection(editormd.firstUpperCase(selection)); | |
|             cm.setSelections(selections); | |
|         }, | |
|          | |
|         ucwords : function() { | |
|             var cm         = this.cm; | |
|             var selection  = cm.getSelection(); | |
|             var selections = cm.listSelections(); | |
| 
 | |
|             cm.replaceSelection(editormd.wordsFirstUpperCase(selection)); | |
|             cm.setSelections(selections); | |
|         }, | |
|          | |
|         uppercase : function() { | |
|             var cm         = this.cm; | |
|             var selection  = cm.getSelection(); | |
|             var selections = cm.listSelections(); | |
| 
 | |
|             cm.replaceSelection(selection.toUpperCase()); | |
|             cm.setSelections(selections); | |
|         }, | |
|          | |
|         lowercase : function() { | |
|             var cm         = this.cm; | |
|             var cursor     = cm.getCursor(); | |
|             var selection  = cm.getSelection(); | |
|             var selections = cm.listSelections(); | |
|              | |
|             cm.replaceSelection(selection.toLowerCase()); | |
|             cm.setSelections(selections); | |
|         }, | |
| 
 | |
|         h1 : function() { | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("# " + selection); | |
|         }, | |
| 
 | |
|         h2 : function() { | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("## " + selection); | |
|         }, | |
| 
 | |
|         h3 : function() { | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("### " + selection); | |
|         }, | |
| 
 | |
|         h4 : function() { | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("#### " + selection); | |
|         }, | |
| 
 | |
|         h5 : function() { | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("##### " + selection); | |
|         }, | |
| 
 | |
|         h6 : function() { | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("###### " + selection); | |
|         }, | |
| 
 | |
|         "list-ul" : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             if (selection === "")  | |
|             { | |
|                 cm.replaceSelection("- " + selection); | |
|             }  | |
|             else  | |
|             { | |
|                 var selectionText = selection.split("\n"); | |
| 
 | |
|                 for (var i = 0, len = selectionText.length; i < len; i++)  | |
|                 { | |
|                     selectionText[i] = (selectionText[i] === "") ? "" : "- " + selectionText[i]; | |
|                 } | |
| 
 | |
|                 cm.replaceSelection(selectionText.join("\n")); | |
|             } | |
|         }, | |
| 
 | |
|         "list-ol" : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             if(selection === "")  | |
|             { | |
|                 cm.replaceSelection("1. " + selection); | |
|             } | |
|             else | |
|             { | |
|                 var selectionText = selection.split("\n"); | |
| 
 | |
|                 for (var i = 0, len = selectionText.length; i < len; i++)  | |
|                 { | |
|                     selectionText[i] = (selectionText[i] === "") ? "" : (i+1) + ". " + selectionText[i]; | |
|                 } | |
| 
 | |
|                 cm.replaceSelection(selectionText.join("\n")); | |
|             } | |
|         }, | |
| 
 | |
|         hr : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("------------"); | |
|         }, | |
| 
 | |
|         tex : function() { | |
|             if (!this.settings.tex) | |
|             { | |
|                 alert("settings.tex === false"); | |
|                 return this; | |
|             } | |
|              | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("$$" + selection + "$$"); | |
| 
 | |
|             if(selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 2); | |
|             } | |
|         }, | |
| 
 | |
|         link : function() { | |
|             this.executePlugin("linkDialog", "link-dialog/link-dialog"); | |
|         }, | |
| 
 | |
|         "reference-link" : function() { | |
|             this.executePlugin("referenceLinkDialog", "reference-link-dialog/reference-link-dialog"); | |
|         }, | |
| 
 | |
|         pagebreak : function() { | |
|             if (!this.settings.pageBreak) | |
|             { | |
|                 alert("settings.pageBreak === false"); | |
|                 return this; | |
|             } | |
|              | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("\r\n[========]\r\n"); | |
|         }, | |
| 
 | |
|         image : function() { | |
|             this.executePlugin("imageDialog", "image-dialog/image-dialog"); | |
|         }, | |
|          | |
|         code : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
| 
 | |
|             cm.replaceSelection("`" + selection + "`"); | |
| 
 | |
|             if (selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 1); | |
|             } | |
|         }, | |
| 
 | |
|         "code-block" : function() { | |
|             this.executePlugin("codeBlockDialog", "code-block-dialog/code-block-dialog");             | |
|         }, | |
| 
 | |
|         "preformatted-text" : function() { | |
|             this.executePlugin("preformattedTextDialog", "preformatted-text-dialog/preformatted-text-dialog"); | |
|         }, | |
|          | |
|         table : function() { | |
|             this.executePlugin("tableDialog", "table-dialog/table-dialog");          | |
|         }, | |
|          | |
|         datetime : function() { | |
|             var cm        = this.cm; | |
|             var selection = cm.getSelection(); | |
|             var date      = new Date(); | |
|             var langName  = this.settings.lang.name; | |
|             var datefmt   = editormd.dateFormat() + " " + editormd.dateFormat((langName === "zh-cn" || langName === "zh-tw") ? "cn-week-day" : "week-day"); | |
| 
 | |
|             cm.replaceSelection(datefmt); | |
|         }, | |
|          | |
|         emoji : function() { | |
|             this.executePlugin("emojiDialog", "emoji-dialog/emoji-dialog"); | |
|         }, | |
|                  | |
|         "html-entities" : function() { | |
|             this.executePlugin("htmlEntitiesDialog", "html-entities-dialog/html-entities-dialog"); | |
|         }, | |
|                  | |
|         "goto-line" : function() { | |
|             this.executePlugin("gotoLineDialog", "goto-line-dialog/goto-line-dialog"); | |
|         }, | |
| 
 | |
|         watch : function() {     | |
|             this[this.settings.watch ? "unwatch" : "watch"](); | |
|         }, | |
| 
 | |
|         preview : function() { | |
|             this.previewing(); | |
|         }, | |
| 
 | |
|         fullscreen : function() { | |
|             this.fullscreen(); | |
|         }, | |
| 
 | |
|         clear : function() { | |
|             this.clear(); | |
|         }, | |
|          | |
|         search : function() { | |
|             this.search(); | |
|         }, | |
| 
 | |
|         help : function() { | |
|             this.executePlugin("helpDialog", "help-dialog/help-dialog"); | |
|         }, | |
| 
 | |
|         info : function() { | |
|             this.showInfoDialog(); | |
|         } | |
|     }; | |
|      | |
|     editormd.keyMaps = { | |
|         "Ctrl-1"       : "h1", | |
|         "Ctrl-2"       : "h2", | |
|         "Ctrl-3"       : "h3", | |
|         "Ctrl-4"       : "h4", | |
|         "Ctrl-5"       : "h5", | |
|         "Ctrl-6"       : "h6", | |
|         "Ctrl-B"       : "bold",  // if this is string ==  editormd.toolbarHandlers.xxxx | |
|         "Ctrl-D"       : "datetime", | |
|          | |
|         "Ctrl-E"       : function() { // emoji | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
|              | |
|             if (!this.settings.emoji) | |
|             { | |
|                 alert("Error: settings.emoji == false"); | |
|                 return ; | |
|             } | |
| 
 | |
|             cm.replaceSelection(":" + selection + ":"); | |
| 
 | |
|             if (selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 1); | |
|             } | |
|         }, | |
|         "Ctrl-Alt-G"   : "goto-line", | |
|         "Ctrl-H"       : "hr", | |
|         "Ctrl-I"       : "italic", | |
|         "Ctrl-K"       : "code", | |
|          | |
|         "Ctrl-L"        : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
|              | |
|             var title = (selection === "") ? "" : " \""+selection+"\""; | |
| 
 | |
|             cm.replaceSelection("[" + selection + "]("+title+")"); | |
| 
 | |
|             if (selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 1); | |
|             } | |
|         }, | |
|         "Ctrl-U"         : "list-ul", | |
|          | |
|         "Shift-Ctrl-A"   : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
|              | |
|             if (!this.settings.atLink) | |
|             { | |
|                 alert("Error: settings.atLink == false"); | |
|                 return ; | |
|             } | |
| 
 | |
|             cm.replaceSelection("@" + selection); | |
| 
 | |
|             if (selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 1); | |
|             } | |
|         }, | |
|          | |
|         "Shift-Ctrl-C"     : "code", | |
|         "Shift-Ctrl-Q"     : "quote", | |
|         "Shift-Ctrl-S"     : "del", | |
|         "Shift-Ctrl-K"     : "tex",  // KaTeX | |
|          | |
|         "Shift-Alt-C"      : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
|              | |
|             cm.replaceSelection(["```", selection, "```"].join("\n")); | |
| 
 | |
|             if (selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 3); | |
|             }  | |
|         }, | |
|          | |
|         "Shift-Ctrl-Alt-C" : "code-block", | |
|         "Shift-Ctrl-H"     : "html-entities", | |
|         "Shift-Alt-H"      : "help", | |
|         "Shift-Ctrl-E"     : "emoji", | |
|         "Shift-Ctrl-U"     : "uppercase", | |
|         "Shift-Alt-U"      : "ucwords", | |
|         "Shift-Ctrl-Alt-U" : "ucfirst", | |
|         "Shift-Alt-L"      : "lowercase", | |
|          | |
|         "Shift-Ctrl-I"     : function() { | |
|             var cm        = this.cm; | |
|             var cursor    = cm.getCursor(); | |
|             var selection = cm.getSelection(); | |
|              | |
|             var title = (selection === "") ? "" : " \""+selection+"\""; | |
| 
 | |
|             cm.replaceSelection(""); | |
| 
 | |
|             if (selection === "") { | |
|                 cm.setCursor(cursor.line, cursor.ch + 4); | |
|             } | |
|         }, | |
|          | |
|         "Shift-Ctrl-Alt-I" : "image", | |
|         "Shift-Ctrl-L"     : "link", | |
|         "Shift-Ctrl-O"     : "list-ol", | |
|         "Shift-Ctrl-P"     : "preformatted-text", | |
|         "Shift-Ctrl-T"     : "table", | |
|         "Shift-Alt-P"      : "pagebreak", | |
|         "F9"               : "watch", | |
|         "F10"              : "preview", | |
|         "F11"              : "fullscreen", | |
|     }; | |
|      | |
|     /** | |
|      * 清除字符串两边的空格 | |
|      * Clear the space of strings both sides. | |
|      *  | |
|      * @param   {String}    str            string | |
|      * @returns {String}                   trimed string     | |
|      */ | |
|      | |
|     var trim = function(str) { | |
|         return (!String.prototype.trim) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "") : str.trim(); | |
|     }; | |
|      | |
|     editormd.trim = trim; | |
|      | |
|     /** | |
|      * 所有单词首字母大写 | |
|      * Words first to uppercase | |
|      *  | |
|      * @param   {String}    str            string | |
|      * @returns {String}                   string | |
|      */ | |
|      | |
|     var ucwords = function (str) { | |
|         return str.toLowerCase().replace(/\b(\w)|\s(\w)/g, function($1) {   | |
|             return $1.toUpperCase(); | |
|         }); | |
|     }; | |
|      | |
|     editormd.ucwords = editormd.wordsFirstUpperCase = ucwords; | |
|      | |
|     /** | |
|      * 字符串首字母大写 | |
|      * Only string first char to uppercase | |
|      *  | |
|      * @param   {String}    str            string | |
|      * @returns {String}                   string | |
|      */ | |
|      | |
|     var firstUpperCase = function(str) {         | |
|         return str.toLowerCase().replace(/\b(\w)/, function($1){ | |
|             return $1.toUpperCase(); | |
|         }); | |
|     }; | |
|      | |
|     var ucfirst = firstUpperCase; | |
|      | |
|     editormd.firstUpperCase = editormd.ucfirst = firstUpperCase; | |
|      | |
|     editormd.urls = { | |
|         atLinkBase : "https://github.com/" | |
|     }; | |
|      | |
|     editormd.regexs = { | |
|         atLink        : /@(\w+)/g, | |
|         email         : /(\w+)@(\w+)\.(\w+)\.?(\w+)?/g, | |
|         emailLink     : /(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g, | |
|         emoji         : /:([\w\+-]+):/g, | |
|         emojiDatetime : /(\d{2}:\d{2}:\d{2})/g, | |
|         twemoji       : /:(tw-([\w]+)-?(\w+)?):/g, | |
|         fontAwesome   : /:(fa-([\w]+)(-(\w+)){0,}):/g, | |
|         editormdLogo  : /:(editormd-logo-?(\w+)?):/g, | |
|         pageBreak     : /^\[[=]{8,}\]$/ | |
|     }; | |
| 
 | |
|     // Emoji graphics files url path | |
|     editormd.emoji     = { | |
|         path  : "http://www.emoji-cheat-sheet.com/graphics/emojis/", | |
|         ext   : ".png" | |
|     }; | |
| 
 | |
|     // Twitter Emoji (Twemoji)  graphics files url path     | |
|     editormd.twemoji = { | |
|         path : "http://twemoji.maxcdn.com/36x36/", | |
|         ext  : ".png" | |
|     }; | |
| 
 | |
|     /** | |
|      * 自定义marked的解析器 | |
|      * Custom Marked renderer rules | |
|      *  | |
|      * @param   {Array}    markdownToC     传入用于接收TOC的数组 | |
|      * @returns {Renderer} markedRenderer  返回marked的Renderer自定义对象 | |
|      */ | |
| 
 | |
|     editormd.markedRenderer = function(markdownToC, options) { | |
|         var defaults = { | |
|             toc                  : true,           // Table of contents | |
|             tocm                 : false, | |
|             tocStartLevel        : 1,              // Said from H1 to create ToC   | |
|             pageBreak            : true, | |
|             atLink               : true,           // for @link | |
|             emailLink            : true,           // for mail address auto link | |
|             taskList             : false,          // Enable Github Flavored Markdown task lists | |
|             emoji                : false,          // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis. | |
|             tex                  : false,          // TeX(LaTeX), based on KaTeX | |
|             flowChart            : false,          // flowChart.js only support IE9+ | |
|             sequenceDiagram      : false,          // sequenceDiagram.js only support IE9+ | |
|         }; | |
|          | |
|         var settings        = $.extend(defaults, options || {});     | |
|         var marked          = editormd.$marked; | |
|         var markedRenderer  = new marked.Renderer(); | |
|         markdownToC         = markdownToC || [];         | |
|              | |
|         var regexs          = editormd.regexs; | |
|         var atLinkReg       = regexs.atLink; | |
|         var emojiReg        = regexs.emoji; | |
|         var emailReg        = regexs.email; | |
|         var emailLinkReg    = regexs.emailLink; | |
|         var twemojiReg      = regexs.twemoji; | |
|         var faIconReg       = regexs.fontAwesome; | |
|         var editormdLogoReg = regexs.editormdLogo; | |
|         var pageBreakReg    = regexs.pageBreak; | |
| 
 | |
|         markedRenderer.emoji = function(text) { | |
|              | |
|             text = text.replace(editormd.regexs.emojiDatetime, function($1) {            | |
|                 return $1.replace(/:/g, "&#58;"); | |
|             }); | |
|              | |
|             var matchs = text.match(emojiReg); | |
| 
 | |
|             if (!matchs || !settings.emoji) { | |
|                 return text; | |
|             } | |
| 
 | |
|             for (var i = 0, len = matchs.length; i < len; i++) | |
|             {             | |
|                 if (matchs[i] === ":+1:") { | |
|                     matchs[i] = ":\\+1:"; | |
|                 } | |
| 
 | |
|                 text = text.replace(new RegExp(matchs[i]), function($1, $2){ | |
|                     var faMatchs = $1.match(faIconReg); | |
|                     var name     = $1.replace(/:/g, ""); | |
| 
 | |
|                     if (faMatchs) | |
|                     {                         | |
|                         for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++) | |
|                         { | |
|                             var faName = faMatchs[fa].replace(/:/g, ""); | |
|                              | |
|                             return "<i class=\"fa " + faName + " fa-emoji\" title=\"" + faName.replace("fa-", "") + "\"></i>"; | |
|                         } | |
|                     } | |
|                     else | |
|                     { | |
|                         var emdlogoMathcs = $1.match(editormdLogoReg); | |
|                         var twemojiMatchs = $1.match(twemojiReg); | |
| 
 | |
|                         if (emdlogoMathcs)                                         | |
|                         {                             | |
|                             for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++) | |
|                             { | |
|                                 var logoName = emdlogoMathcs[x].replace(/:/g, ""); | |
|                                 return "<i class=\"" + logoName + "\" title=\"Editor.md logo (" + logoName + ")\"></i>"; | |
|                             } | |
|                         } | |
|                         else if (twemojiMatchs)  | |
|                         { | |
|                             for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++) | |
|                             { | |
|                                 var twe = twemojiMatchs[t].replace(/:/g, "").replace("tw-", ""); | |
|                                 return "<img src=\"" + editormd.twemoji.path + twe + editormd.twemoji.ext + "\" title=\"twemoji-" + twe + "\" alt=\"twemoji-" + twe + "\" class=\"emoji twemoji\" />"; | |
|                             } | |
|                         } | |
|                         else | |
|                         { | |
|                             var src = (name === "+1") ? "plus1" : name; | |
|                             src     = (src === "black_large_square") ? "black_square" : src; | |
| 
 | |
|                             return "<img src=\"" + editormd.emoji.path + src + editormd.emoji.ext + "\" class=\"emoji\" title=\"&#58;" + name + "&#58;\" alt=\"&#58;" + name + "&#58;\" />"; | |
|                         } | |
|                     } | |
|                 }); | |
|             } | |
| 
 | |
|             return text; | |
|         }; | |
| 
 | |
|         markedRenderer.atLink = function(text) { | |
| 
 | |
|             if (atLinkReg.test(text)) | |
|             {  | |
|                 if (settings.atLink)  | |
|                 { | |
|                     text = text.replace(emailReg, function($1, $2, $3, $4) { | |
|                         return $1.replace(/@/g, "_#_&#64;_#_"); | |
|                     }); | |
| 
 | |
|                     text = text.replace(atLinkReg, function($1, $2) { | |
|                         return "<a href=\"" + editormd.urls.atLinkBase + "" + $2 + "\" title=\"&#64;" + $2 + "\" class=\"at-link\">" + $1 + "</a>"; | |
|                     }).replace(/_#_&#64;_#_/g, "@"); | |
|                 } | |
|                  | |
|                 if (settings.emailLink) | |
|                 { | |
|                     text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) { | |
|                         return (!$2 && $.inArray($5, "jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|")) < 0) ? "<a href=\"mailto:" + $1 + "\">"+$1+"</a>" : $1; | |
|                     }); | |
|                 } | |
| 
 | |
|                 return text; | |
|             } | |
| 
 | |
|             return text; | |
|         }; | |
|                  | |
|         markedRenderer.link = function (href, title, text) { | |
| 
 | |
|             if (this.options.sanitize) { | |
|                 try { | |
|                     var prot = decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase(); | |
|                 } catch(e) { | |
|                     return ""; | |
|                 } | |
| 
 | |
|                 if (prot.indexOf("javascript:") === 0) { | |
|                     return ""; | |
|                 } | |
|             } | |
| 
 | |
|             var out = "<a href=\"" + href + "\""; | |
|              | |
|             if (atLinkReg.test(title) || atLinkReg.test(text)) | |
|             { | |
|                 if (title) | |
|                 { | |
|                     out += " title=\"" + title.replace(/@/g, "&#64;"); | |
|                 } | |
|                  | |
|                 return out + "\">" + text.replace(/@/g, "&#64;") + "</a>"; | |
|             } | |
| 
 | |
|             if (title) { | |
|                 out += " title=\"" + title + "\""; | |
|             } | |
| 
 | |
|             out += ">" + text + "</a>"; | |
| 
 | |
|             return out; | |
|         }; | |
|          | |
|         markedRenderer.heading = function(text, level, raw) { | |
|                      | |
|             var linkText       = text; | |
|             var hasLinkReg     = /\s*\<a\s*href\=\"(.*)\"\s*([^\>]*)\>(.*)\<\/a\>\s*/; | |
|             var getLinkTextReg = /\s*\<a\s*([^\>]+)\>([^\>]*)\<\/a\>\s*/g; | |
| 
 | |
|             if (hasLinkReg.test(text))  | |
|             { | |
|                 var tempText = []; | |
|                 text         = text.split(/\<a\s*([^\>]+)\>([^\>]*)\<\/a\>/); | |
| 
 | |
|                 for (var i = 0, len = text.length; i < len; i++) | |
|                 { | |
|                     tempText.push(text[i].replace(/\s*href\=\"(.*)\"\s*/g, "")); | |
|                 } | |
| 
 | |
|                 text = tempText.join(" "); | |
|             } | |
|              | |
|             text = trim(text); | |
|              | |
|             var escapedText    = text.toLowerCase().replace(/[^\w]+/g, "-"); | |
|             var toc = { | |
|                 text  : text, | |
|                 level : level, | |
|                 slug  : escapedText | |
|             }; | |
|              | |
|             var isChinese = /^[\u4e00-\u9fa5]+$/.test(text); | |
|             var id        = (isChinese) ? escape(text).replace(/\%/g, "") : text.toLowerCase().replace(/[^\w]+/g, "-"); | |
| 
 | |
|             markdownToC.push(toc); | |
|              | |
|             var headingHTML = "<h" + level + " id=\"h"+ level + "-" + this.options.headerPrefix + id +"\">"; | |
|              | |
|             headingHTML    += "<a name=\"" + text + "\" class=\"reference-link\"></a>"; | |
|             headingHTML    += "<span class=\"header-link octicon octicon-link\"></span>"; | |
|             headingHTML    += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text)); | |
|             headingHTML    += "</h" + level + ">"; | |
| 
 | |
|             return headingHTML; | |
|         }; | |
|          | |
|         markedRenderer.pageBreak = function(text) { | |
|             if (pageBreakReg.test(text) && settings.pageBreak) | |
|             { | |
|                 text = "<hr style=\"page-break-after:always;\" class=\"page-break editormd-page-break\" />"; | |
|             } | |
|              | |
|             return text; | |
|         }; | |
| 
 | |
|         markedRenderer.paragraph = function(text) { | |
|             var isTeXInline     = /\$\$(.*)\$\$/g.test(text); | |
|             var isTeXLine       = /^\$\$(.*)\$\$$/.test(text); | |
|             var isTeXAddClass   = (isTeXLine)     ? " class=\"" + editormd.classNames.tex + "\"" : ""; | |
|             var isToC           = (settings.tocm) ? /^(\[TOC\]|\[TOCM\])$/.test(text) : /^\[TOC\]$/.test(text); | |
|             var isToCMenu       = /^\[TOCM\]$/.test(text); | |
|              | |
|             if (!isTeXLine && isTeXInline)  | |
|             { | |
|                 text = text.replace(/(\$\$([^\$]*)\$\$)+/g, function($1, $2) { | |
|                     return "<span class=\"" + editormd.classNames.tex + "\">" + $2.replace(/\$/g, "") + "</span>"; | |
|                 }); | |
|             }  | |
|             else  | |
|             { | |
|                 text = (isTeXLine) ? text.replace(/\$/g, "") : text; | |
|             } | |
|              | |
|             var tocHTML = "<div class=\"markdown-toc editormd-markdown-toc\">" + text + "</div>"; | |
|              | |
|             return (isToC) ? ( (isToCMenu) ? "<div class=\"editormd-toc-menu\">" + tocHTML + "</div><br/>" : tocHTML ) | |
|                            : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : "<p" + isTeXAddClass + ">" + this.atLink(this.emoji(text)) + "</p>\n" ); | |
|         }; | |
| 
 | |
|         markedRenderer.code = function (code, lang, escaped) {  | |
| 
 | |
|             if (lang === "seq" || lang === "sequence") | |
|             { | |
|                 return "<div class=\"sequence-diagram\">" + code + "</div>"; | |
|             }  | |
|             else if ( lang === "flow") | |
|             { | |
|                 return "<div class=\"flowchart\">" + code + "</div>"; | |
|             }  | |
|             else  | |
|             { | |
| 
 | |
|                 return marked.Renderer.prototype.code.apply(this, arguments); | |
|             } | |
|         }; | |
| 
 | |
|         markedRenderer.tablecell = function(content, flags) { | |
|             var type = (flags.header) ? "th" : "td"; | |
|             var tag  = (flags.align)  ? "<" + type +" style=\"text-align:" + flags.align + "\">" : "<" + type + ">"; | |
|              | |
|             return tag + this.atLink(this.emoji(content)) + "</" + type + ">\n"; | |
|         }; | |
| 
 | |
|         markedRenderer.listitem = function(text) { | |
|             if (settings.taskList && /^\s*\[[x\s]\]\s*/.test(text))  | |
|             { | |
|                 text = text.replace(/^\s*\[\s\]\s*/, "<input type=\"checkbox\" class=\"task-list-item-checkbox\" /> ") | |
|                            .replace(/^\s*\[x\]\s*/,  "<input type=\"checkbox\" class=\"task-list-item-checkbox\" checked disabled /> "); | |
| 
 | |
|                 return "<li style=\"list-style: none;\">" + this.atLink(this.emoji(text)) + "</li>"; | |
|             } | |
|             else  | |
|             { | |
|                 return "<li>" + this.atLink(this.emoji(text)) + "</li>"; | |
|             } | |
|         }; | |
|          | |
|         return markedRenderer; | |
|     }; | |
|      | |
|     /** | |
|      * | |
|      * 生成TOC(Table of Contents) | |
|      * Creating ToC (Table of Contents) | |
|      *  | |
|      * @param   {Array}    toc             从marked获取的TOC数组列表 | |
|      * @param   {Element}  container       插入TOC的容器元素 | |
|      * @param   {Integer}  startLevel      Hx 起始层级 | |
|      * @returns {Object}   tocContainer    返回ToC列表容器层的jQuery对象元素 | |
|      */ | |
|      | |
|     editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) { | |
|          | |
|         var html        = "";     | |
|         var lastLevel   = 0; | |
|         var classPrefix = this.classPrefix; | |
|          | |
|         startLevel      = startLevel  || 1; | |
|          | |
|         for (var i = 0, len = toc.length; i < len; i++)  | |
|         { | |
|             var text  = toc[i].text; | |
|             var level = toc[i].level; | |
|              | |
|             if (level < startLevel) { | |
|                 continue; | |
|             } | |
|              | |
|             if (level > lastLevel)  | |
|             { | |
|                 html += ""; | |
|             } | |
|             else if (level < lastLevel)  | |
|             { | |
|                 html += (new Array(lastLevel - level + 2)).join("</ul></li>"); | |
|             }  | |
|             else  | |
|             { | |
|                 html += "</ul></li>"; | |
|             } | |
| 
 | |
|             html += "<li><a class=\"toc-level-" + level + "\" href=\"#" + text + "\" level=\"" + level + "\">" + text + "</a><ul>"; | |
|             lastLevel = level; | |
|         } | |
|          | |
|         var tocContainer = container.find(".markdown-toc"); | |
|          | |
|         if (tocContainer.length < 1 && container.attr("previewContainer") === "false") | |
|         { | |
|             var tocHTML = "<div class=\"markdown-toc " + classPrefix + "markdown-toc\"></div>"; | |
|              | |
|             tocHTML = (tocDropdown) ? "<div class=\"" + classPrefix + "toc-menu\">" + tocHTML + "</div>" : tocHTML; | |
|              | |
|             container.html(tocHTML); | |
|              | |
|             tocContainer = container.find(".markdown-toc"); | |
|         } | |
|          | |
|         if (tocDropdown) | |
|         { | |
|             tocContainer.wrap("<div class=\"" + classPrefix + "toc-menu\"></div><br/>"); | |
|         } | |
|          | |
|         tocContainer.html("<ul class=\"markdown-toc-list\"></ul>").children(".markdown-toc-list").html(html.replace(/\r?\n?\<ul\>\<\/ul\>/g, "")); | |
|          | |
|         return tocContainer; | |
|     }; | |
|      | |
|     /** | |
|      * | |
|      * 生成TOC下拉菜单 | |
|      * Creating ToC dropdown menu | |
|      *  | |
|      * @param   {Object}   container       插入TOC的容器jQuery对象元素 | |
|      * @param   {String}   tocTitle        ToC title | |
|      * @returns {Object}                   return toc-menu object | |
|      */ | |
|      | |
|     editormd.tocDropdownMenu = function(container, tocTitle) { | |
|          | |
|         tocTitle      = tocTitle || "Table of Contents"; | |
|          | |
|         var zindex    = 400; | |
|         var tocMenus  = container.find("." + this.classPrefix + "toc-menu"); | |
| 
 | |
|         tocMenus.each(function() { | |
|             var $this  = $(this); | |
|             var toc    = $this.children(".markdown-toc"); | |
|             var icon   = "<i class=\"fa fa-angle-down\"></i>"; | |
|             var btn    = "<a href=\"javascript:;\" class=\"toc-menu-btn\">" + icon + tocTitle + "</a>"; | |
|             var menu   = toc.children("ul");             | |
|             var list   = menu.find("li"); | |
|              | |
|             toc.append(btn); | |
|              | |
|             list.first().before("<li><h1>" + tocTitle + " " + icon + "</h1></li>"); | |
|              | |
|             $this.mouseover(function(){ | |
|                 menu.show(); | |
| 
 | |
|                 list.each(function(){ | |
|                     var li = $(this); | |
|                     var ul = li.children("ul"); | |
| 
 | |
|                     if (ul.html() === "") | |
|                     { | |
|                         ul.remove(); | |
|                     } | |
| 
 | |
|                     if (ul.length > 0 && ul.html() !== "") | |
|                     { | |
|                         var firstA = li.children("a").first(); | |
| 
 | |
|                         if (firstA.children(".fa").length < 1) | |
|                         { | |
|                             firstA.append( $(icon).css({ float:"right", paddingTop:"4px" }) ); | |
|                         } | |
|                     } | |
| 
 | |
|                     li.mouseover(function(){ | |
|                         ul.css("z-index", zindex).show(); | |
|                         zindex += 1; | |
|                     }).mouseleave(function(){ | |
|                         ul.hide(); | |
|                     }); | |
|                 }); | |
|             }).mouseleave(function(){ | |
|                 menu.hide(); | |
|             });  | |
|         });        | |
|          | |
|         return tocMenus; | |
|     }; | |
|      | |
|     /** | |
|      * 简单地过滤指定的HTML标签 | |
|      * Filter custom html tags | |
|      *  | |
|      * @param   {String}   html          要过滤HTML | |
|      * @param   {String}   filters       要过滤的标签 | |
|      * @returns {String}   html          返回过滤的HTML | |
|      */ | |
|      | |
|     editormd.filterHTMLTags = function(html, filters) { | |
|          | |
|         if (typeof html !== "string") { | |
|             html = new String(html); | |
|         } | |
|              | |
|         if (typeof filters !== "string") { | |
|             return html; | |
|         } | |
| 
 | |
|         var expression = filters.split("|"); | |
|         var filterTags = expression[0].split(","); | |
|         var attrs      = expression[1]; | |
| 
 | |
|         for (var i = 0, len = filterTags.length; i < len; i++) | |
|         { | |
|             var tag = filterTags[i]; | |
| 
 | |
|             html = html.replace(new RegExp("\<\s*" + tag + "\s*([^\>]*)\>([^\>]*)\<\s*\/" + tag + "\s*\>", "igm"), ""); | |
|         } | |
| 
 | |
|         if (typeof attrs !== "undefined") | |
|         { | |
|             var htmlTagRegex = /\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/ig; | |
| 
 | |
|             if (attrs === "*") | |
|             { | |
|                 html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { | |
|                     return "<" + $2 + ">" + $4 + "</" + $5 + ">"; | |
|                 });          | |
|             } | |
|             else if (attrs === "on*") | |
|             { | |
|                 html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { | |
|                     var el = $("<" + $2 + ">" + $4 + "</" + $5 + ">"); | |
|                     var _attrs = $($1)[0].attributes; | |
|                     var $attrs = {}; | |
|                      | |
|                     $.each(_attrs, function(i, e) { | |
|                         $attrs[e.nodeName] = e.nodeValue; | |
|                     }); | |
|                      | |
|                     $.each($attrs, function(i) {                 | |
|                         if (i.indexOf("on") === 0) { | |
|                             delete $attrs[i]; | |
|                         } | |
|                     }); | |
|                      | |
|                     el.attr($attrs); | |
| 
 | |
|                     return el[0].outerHTML; | |
|                 }); | |
|             } | |
|             else | |
|             { | |
|                 html = html.replace(htmlTagRegex, function($1, $2, $3, $4) { | |
|                     var filterAttrs = attrs.split(","); | |
|                     var el = $($1); | |
|                     el.html($4); | |
| 
 | |
|                     $.each(filterAttrs, function(i) { | |
|                         el.attr(filterAttrs[i], null); | |
|                     }); | |
| 
 | |
|                     return el[0].outerHTML; | |
|                 }); | |
|             } | |
|         } | |
|          | |
|         return html; | |
|     }; | |
|      | |
|     /** | |
|      * 将Markdown文档解析为HTML用于前台显示 | |
|      * Parse Markdown to HTML for Font-end preview. | |
|      *  | |
|      * @param   {String}   id            用于显示HTML的对象ID | |
|      * @param   {Object}   [options={}]  配置选项,可选 | |
|      * @returns {Object}   div           返回jQuery对象元素 | |
|      */ | |
|      | |
|     editormd.markdownToHTML = function(id, options) { | |
|         var defaults = { | |
|             gfm                  : true, | |
|             toc                  : true, | |
|             tocm                 : false, | |
|             tocStartLevel        : 1, | |
|             tocTitle             : "目录", | |
|             tocDropdown          : false, | |
|             markdown             : "", | |
|             htmlDecode           : false, | |
|             autoLoadKaTeX        : true, | |
|             pageBreak            : true, | |
|             atLink               : true,    // for @link | |
|             emailLink            : true,    // for mail address auto link | |
|             tex                  : false, | |
|             taskList             : false,   // Github Flavored Markdown task lists | |
|             emoji                : false, | |
|             flowChart            : false, | |
|             sequenceDiagram      : false, | |
|             previewCodeHighlight : true | |
|         }; | |
|          | |
|         editormd.$marked  = marked; | |
| 
 | |
|         var div           = $("#" + id); | |
|         var settings      = div.settings = $.extend(true, defaults, options || {}); | |
|         var saveTo        = div.find("textarea"); | |
|          | |
|         if (saveTo.length < 1) | |
|         { | |
|             div.append("<textarea></textarea>"); | |
|             saveTo        = div.find("textarea"); | |
|         }         | |
|          | |
|         var markdownDoc   = (settings.markdown === "") ? saveTo.val() : settings.markdown;  | |
|         var markdownToC   = []; | |
| 
 | |
|         var rendererOptions = {   | |
|             toc                  : settings.toc, | |
|             tocm                 : settings.tocm, | |
|             tocStartLevel        : settings.tocStartLevel, | |
|             taskList             : settings.taskList, | |
|             emoji                : settings.emoji, | |
|             tex                  : settings.tex, | |
|             pageBreak            : settings.pageBreak, | |
|             atLink               : settings.atLink,           // for @link | |
|             emailLink            : settings.emailLink,        // for mail address auto link | |
|             flowChart            : settings.flowChart, | |
|             sequenceDiagram      : settings.sequenceDiagram, | |
|             previewCodeHighlight : settings.previewCodeHighlight, | |
|         }; | |
| 
 | |
|         var markedOptions = { | |
|             renderer    : editormd.markedRenderer(markdownToC, rendererOptions), | |
|             gfm         : settings.gfm, | |
|             tables      : true, | |
|             breaks      : true, | |
|             pedantic    : false, | |
|             sanitize    : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签,即是否开启HTML标签解析,为了安全性,默认不开启 | |
|             smartLists  : true, | |
|             smartypants : true | |
|         }; | |
|          | |
| 		markdownDoc = new String(markdownDoc); | |
|         markdownDoc = editormd.filterHTMLTags(markdownDoc, settings.htmlDecode); | |
|          | |
|         var markdownParsed = marked(markdownDoc, markedOptions); | |
|          | |
|         saveTo.val(markdownDoc); | |
|          | |
|         div.addClass("markdown-body " + this.classPrefix + "html-preview").append(markdownParsed); | |
|           | |
|         if (settings.toc)  | |
|         { | |
|             div.tocContainer = this.markdownToCRenderer(markdownToC, div, settings.tocDropdown, settings.tocStartLevel); | |
|              | |
|             if (settings.tocDropdown || div.find("." + this.classPrefix + "toc-menu").length > 0) | |
|             { | |
|                 this.tocDropdownMenu(div, settings.tocTitle); | |
|             } | |
|         } | |
|              | |
|         if (settings.previewCodeHighlight)  | |
|         { | |
|             div.find("pre").addClass("prettyprint linenums"); | |
|             prettyPrint(); | |
|         } | |
|          | |
|         if (!editormd.isIE8)  | |
|         { | |
|             if (settings.flowChart) { | |
|                 div.find(".flowchart").flowChart();  | |
|             } | |
| 
 | |
|             if (settings.sequenceDiagram) { | |
|                 div.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); | |
|             } | |
|         } | |
| 
 | |
|         if (settings.tex) | |
|         { | |
|             var katexHandle = function() { | |
|                 div.find("." + editormd.classNames.tex).each(function(){ | |
|                     var tex  = $(this); | |
|                     katex.render(tex.html().replace(/&lt;/g, "<").replace(/&gt;/g, ">"), tex[0]); | |
|                 }); | |
|             }; | |
|              | |
|             if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded) | |
|             { | |
|                 this.loadKaTeX(function() { | |
|                     editormd.$katex      = katex; | |
|                     editormd.kaTeXLoaded = true; | |
|                     katexHandle(); | |
|                 }); | |
|             } | |
|             else | |
|             { | |
|                 katexHandle(); | |
|             } | |
|         } | |
|          | |
|         div.getMarkdown = function() {             | |
|             return saveTo.val(); | |
|         }; | |
|          | |
|         return div; | |
|     }; | |
|      | |
|     editormd.themes = [ | |
|         "default", "3024-day", "3024-night", | |
|         "ambiance", "ambiance-mobile", | |
|         "base16-dark", "base16-light", "blackboard", | |
|         "cobalt", | |
|         "eclipse", "elegant", "erlang-dark", | |
|         "lesser-dark", | |
|         "mbo", "mdn-like", "midnight", "monokai", | |
|         "neat", "neo", "night", | |
|         "paraiso-dark", "paraiso-light", "pastel-on-dark", | |
|         "rubyblue", | |
|         "solarized", | |
|         "the-matrix", "tomorrow-night-eighties", "twilight", | |
|         "vibrant-ink", | |
|         "xq-dark", "xq-light" | |
|     ]; | |
| 
 | |
|     editormd.loadPlugins = {}; | |
|      | |
|     editormd.loadFiles = { | |
|         js     : [], | |
|         css    : [], | |
|         plugin : [] | |
|     }; | |
|      | |
|     /** | |
|      * 动态加载Editor.md插件,但不立即执行 | |
|      * Load editor.md plugins | |
|      *  | |
|      * @param {String}   fileName              插件文件路径 | |
|      * @param {Function} [callback=function()] 加载成功后执行的回调函数 | |
|      * @param {String}   [into="head"]         嵌入页面的位置 | |
|      */ | |
|      | |
|     editormd.loadPlugin = function(fileName, callback, into) { | |
|         callback   = callback || function() {}; | |
|          | |
|         this.loadScript(fileName, function() { | |
|             editormd.loadFiles.plugin.push(fileName); | |
|             callback(); | |
|         }, into); | |
|     }; | |
|      | |
|     /** | |
|      * 动态加载CSS文件的方法 | |
|      * Load css file method | |
|      *  | |
|      * @param {String}   fileName              CSS文件名 | |
|      * @param {Function} [callback=function()] 加载成功后执行的回调函数 | |
|      * @param {String}   [into="head"]         嵌入页面的位置 | |
|      */ | |
|      | |
|     editormd.loadCSS   = function(fileName, callback, into) { | |
|         into       = into     || "head";         | |
|         callback   = callback || function() {}; | |
|          | |
|         var css    = document.createElement("link"); | |
|         css.type   = "text/css"; | |
|         css.rel    = "stylesheet"; | |
|         css.onload = css.onreadystatechange = function() { | |
|             editormd.loadFiles.css.push(fileName); | |
|             callback(); | |
|         }; | |
| 
 | |
|         css.href   = fileName + ".css"; | |
| 
 | |
|         if(into === "head") { | |
|             document.getElementsByTagName("head")[0].appendChild(css); | |
|         } else { | |
|             document.body.appendChild(css); | |
|         } | |
|     }; | |
|      | |
|     editormd.isIE    = (navigator.appName == "Microsoft Internet Explorer"); | |
|     editormd.isIE8   = (editormd.isIE && navigator.appVersion.match(/8./i) == "8."); | |
| 
 | |
|     /** | |
|      * 动态加载JS文件的方法 | |
|      * Load javascript file method | |
|      *  | |
|      * @param {String}   fileName              JS文件名 | |
|      * @param {Function} [callback=function()] 加载成功后执行的回调函数 | |
|      * @param {String}   [into="head"]         嵌入页面的位置 | |
|      */ | |
| 
 | |
|     editormd.loadScript = function(fileName, callback, into) { | |
|          | |
|         into          = into     || "head"; | |
|         callback      = callback || function() {}; | |
|          | |
|         var script    = null;  | |
|         script        = document.createElement("script"); | |
|         script.id     = fileName.replace(/[\./]+/g, "-"); | |
|         script.type   = "text/javascript";         | |
|         script.src    = fileName + ".js"; | |
|          | |
|         if (editormd.isIE8)  | |
|         {             | |
|             script.onreadystatechange = function() { | |
|                 if(script.readyState)  | |
|                 { | |
|                     if (script.readyState === "loaded" || script.readyState === "complete")  | |
|                     { | |
|                         script.onreadystatechange = null;  | |
|                         editormd.loadFiles.js.push(fileName); | |
|                         callback(); | |
|                     } | |
|                 }  | |
|             }; | |
|         } | |
|         else | |
|         { | |
|             script.onload = function() { | |
|                 editormd.loadFiles.js.push(fileName); | |
|                 callback(); | |
|             }; | |
|         } | |
| 
 | |
|         if (into === "head") { | |
|             document.getElementsByTagName("head")[0].appendChild(script); | |
|         } else { | |
|             document.body.appendChild(script); | |
|         } | |
|     }; | |
|      | |
|     // 使用国外的CDN,加载速度有时会很慢,或者自定义URL | |
|     // You can custom KaTeX load url. | |
|     editormd.katexURL  = { | |
|         css : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min", | |
|         js  : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min" | |
|     }; | |
|      | |
|     editormd.kaTeXLoaded = false; | |
|      | |
|     /** | |
|      * 加载KaTeX文件 | |
|      * load KaTeX files | |
|      *  | |
|      * @param {Function} [callback=function()]  加载成功后执行的回调函数 | |
|      */ | |
|      | |
|     editormd.loadKaTeX = function (callback) { | |
|         editormd.loadCSS(editormd.katexURL.css, function(){ | |
|             editormd.loadScript(editormd.katexURL.js, callback || function(){}); | |
|         }); | |
|     }; | |
|          | |
|     /** | |
|      * 锁屏 | |
|      * lock screen | |
|      *  | |
|      * @param   {Boolean}   lock   Boolean 布尔值,是否锁屏 | |
|      * @returns {void} | |
|      */ | |
|      | |
|     editormd.lockScreen = function(lock) { | |
|         $("html,body").css("overflow", (lock) ? "hidden" : ""); | |
|     }; | |
|          | |
|     /** | |
|      * 动态创建对话框 | |
|      * Creating custom dialogs | |
|      *  | |
|      * @param   {Object} options 配置项键值对 Key/Value | |
|      * @returns {dialog} 返回创建的dialog的jQuery实例对象 | |
|      */ | |
| 
 | |
|     editormd.createDialog = function(options) { | |
|         var defaults = { | |
|             name : "", | |
|             width : 420, | |
|             height: 240, | |
|             title : "", | |
|             drag  : true, | |
|             closed : true, | |
|             content : "", | |
|             mask : true, | |
|             maskStyle : { | |
|                 backgroundColor : "#fff", | |
|                 opacity : 0.1 | |
|             }, | |
|             lockScreen : true, | |
|             footer : true, | |
|             buttons : false | |
|         }; | |
| 
 | |
|         options          = $.extend(true, defaults, options); | |
| 
 | |
|         var editor       = this.editor; | |
|         var classPrefix  = editormd.classPrefix; | |
|         var guid         = (new Date()).getTime(); | |
|         var dialogName   = ( (options.name === "") ? classPrefix + "dialog-" + guid : options.name); | |
|         var mouseOrTouch = editormd.mouseOrTouch; | |
| 
 | |
|         var html         = "<div class=\"" + classPrefix + "dialog " + dialogName + "\">"; | |
| 
 | |
|         if (options.title !== "") | |
|         { | |
|             html += "<div class=\"" + classPrefix + "dialog-header\"" + ( (options.drag) ? " style=\"cursor: move;\"" : "" ) + ">"; | |
|             html += "<strong class=\"" + classPrefix + "dialog-title\">" + options.title + "</strong>"; | |
|             html += "</div>"; | |
|         } | |
| 
 | |
|         if (options.closed) | |
|         { | |
|             html += "<a href=\"javascript:;\" class=\"fa fa-close " + classPrefix + "dialog-close\"></a>"; | |
|         } | |
| 
 | |
|         html += "<div class=\"" + classPrefix + "dialog-container\">" + options.content;                     | |
| 
 | |
|         if (options.footer || typeof options.footer === "string")  | |
|         { | |
|             html += "<div class=\"" + classPrefix + "dialog-footer\">" + ( (typeof options.footer === "boolean") ? "" : options.footer) + "</div>"; | |
|         } | |
| 
 | |
|         html += "</div>"; | |
| 
 | |
|         html += "<div class=\"" + classPrefix + "dialog-mask " + classPrefix + "dialog-mask-bg\"></div>"; | |
|         html += "<div class=\"" + classPrefix + "dialog-mask " + classPrefix + "dialog-mask-con\"></div>"; | |
|         html += "</div>"; | |
| 
 | |
|         editor.append(html); | |
| 
 | |
|         var dialog = editor.find("." + dialogName); | |
| 
 | |
|         dialog.lockScreen = function(lock) { | |
|             if (options.lockScreen) | |
|             {                 | |
|                 $("html,body").css("overflow", (lock) ? "hidden" : ""); | |
|             } | |
| 
 | |
|             return dialog; | |
|         }; | |
| 
 | |
|         dialog.showMask = function() { | |
|             if (options.mask) | |
|             { | |
|                 editor.find("." + classPrefix + "mask").css(options.maskStyle).css("z-index", editormd.dialogZindex - 1).show(); | |
|             } | |
|             return dialog; | |
|         }; | |
| 
 | |
|         dialog.hideMask = function() { | |
|             if (options.mask) | |
|             { | |
|                 editor.find("." + classPrefix + "mask").hide(); | |
|             } | |
| 
 | |
|             return dialog; | |
|         }; | |
| 
 | |
|         dialog.loading = function(show) {                         | |
|             var loading = dialog.find("." + classPrefix + "dialog-mask"); | |
|             loading[(show) ? "show" : "hide"](); | |
| 
 | |
|             return dialog; | |
|         }; | |
| 
 | |
|         dialog.lockScreen(true).showMask(); | |
| 
 | |
|         dialog.show().css({ | |
|             zIndex : editormd.dialogZindex, | |
|             border : (editormd.isIE8) ? "1px solid #ddd" : "", | |
|             width  : (typeof options.width  === "number") ? options.width + "px"  : options.width, | |
|             height : (typeof options.height === "number") ? options.height + "px" : options.height | |
|         }); | |
| 
 | |
|         var dialogPosition = function(){ | |
|             dialog.css({ | |
|                 top    : ($(window).height() - dialog.height()) / 2 + "px", | |
|                 left   : ($(window).width() - dialog.width()) / 2 + "px" | |
|             }); | |
|         }; | |
| 
 | |
|         dialogPosition(); | |
| 
 | |
|         $(window).resize(dialogPosition); | |
| 
 | |
|         dialog.children("." + classPrefix + "dialog-close").bind(mouseOrTouch("click", "touchend"), function() { | |
|             dialog.hide().lockScreen(false).hideMask(); | |
|         }); | |
| 
 | |
|         if (typeof options.buttons === "object") | |
|         { | |
|             var footer = dialog.footer = dialog.find("." + classPrefix + "dialog-footer"); | |
| 
 | |
|             for (var key in options.buttons) | |
|             { | |
|                 var btn = options.buttons[key]; | |
|                 var btnClassName = classPrefix + key + "-btn"; | |
| 
 | |
|                 footer.append("<button class=\"" + classPrefix + "btn " + btnClassName + "\">" + btn[0] + "</button>"); | |
|                 btn[1] = $.proxy(btn[1], dialog); | |
|                 footer.children("." + btnClassName).bind(mouseOrTouch("click", "touchend"), btn[1]); | |
|             } | |
|         } | |
| 
 | |
|         if (options.title !== "" && options.drag) | |
|         {                         | |
|             var posX, posY; | |
|             var dialogHeader = dialog.children("." + classPrefix + "dialog-header"); | |
| 
 | |
|             if (!options.mask) { | |
|                 dialogHeader.bind(mouseOrTouch("click", "touchend"), function(){ | |
|                     editormd.dialogZindex += 2; | |
|                     dialog.css("z-index", editormd.dialogZindex); | |
|                 }); | |
|             } | |
| 
 | |
|             dialogHeader.mousedown(function(e) { | |
|                 e = e || window.event;  //IE | |
|                 posX = e.clientX - parseInt(dialog[0].style.left); | |
|                 posY = e.clientY - parseInt(dialog[0].style.top); | |
| 
 | |
|                 document.onmousemove = moveAction;                    | |
|             }); | |
| 
 | |
|             var userCanSelect = function (obj) { | |
|                 obj.removeClass(classPrefix + "user-unselect").off("selectstart"); | |
|             }; | |
| 
 | |
|             var userUnselect = function (obj) { | |
|                 obj.addClass(classPrefix + "user-unselect").on("selectstart", function(event) { // selectstart for IE                         | |
|                     return false; | |
|                 }); | |
|             }; | |
| 
 | |
|             var moveAction = function (e) { | |
|                 e = e || window.event;  //IE | |
| 
 | |
|                 var left, top, nowLeft = parseInt(dialog[0].style.left), nowTop = parseInt(dialog[0].style.top); | |
| 
 | |
|                 if( nowLeft >= 0 ) { | |
|                     if( nowLeft + dialog.width() <= $(window).width()) { | |
|                         left = e.clientX - posX; | |
|                     } else {	 | |
|                         left = $(window).width() - dialog.width(); | |
|                         document.onmousemove = null; | |
|                     } | |
|                 } else { | |
|                     left = 0; | |
|                     document.onmousemove = null; | |
|                 } | |
| 
 | |
|                 if( nowTop >= 0 ) { | |
|                     top = e.clientY - posY; | |
|                 } else { | |
|                     top = 0; | |
|                     document.onmousemove = null; | |
|                 } | |
| 
 | |
| 
 | |
|                 document.onselectstart = function() { | |
|                     return false; | |
|                 }; | |
| 
 | |
|                 userUnselect($("body")); | |
|                 userUnselect(dialog); | |
|                 dialog[0].style.left = left + "px"; | |
|                 dialog[0].style.top  = top + "px"; | |
|             }; | |
| 
 | |
|             document.onmouseup = function() {                             | |
|                 userCanSelect($("body")); | |
|                 userCanSelect(dialog); | |
| 
 | |
|                 document.onselectstart = null;          | |
|                 document.onmousemove = null; | |
|             }; | |
| 
 | |
|             dialogHeader.touchDraggable = function() { | |
|                 var offset = null; | |
|                 var start  = function(e) { | |
|                     var orig = e.originalEvent;  | |
|                     var pos  = $(this).parent().position(); | |
| 
 | |
|                     offset = { | |
|                         x : orig.changedTouches[0].pageX - pos.left, | |
|                         y : orig.changedTouches[0].pageY - pos.top | |
|                     }; | |
|                 }; | |
| 
 | |
|                 var move = function(e) { | |
|                     e.preventDefault(); | |
|                     var orig = e.originalEvent; | |
| 
 | |
|                     $(this).parent().css({ | |
|                         top  : orig.changedTouches[0].pageY - offset.y, | |
|                         left : orig.changedTouches[0].pageX - offset.x | |
|                     }); | |
|                 }; | |
| 
 | |
|                 this.bind("touchstart", start).bind("touchmove", move); | |
|             }; | |
| 
 | |
|             dialogHeader.touchDraggable(); | |
|         } | |
| 
 | |
|         editormd.dialogZindex += 2; | |
| 
 | |
|         return dialog; | |
|     }; | |
|      | |
|     /** | |
|      * 鼠标和触摸事件的判断/选择方法 | |
|      * MouseEvent or TouchEvent type switch | |
|      *  | |
|      * @param   {String} [mouseEventType="click"]    供选择的鼠标事件 | |
|      * @param   {String} [touchEventType="touchend"] 供选择的触摸事件 | |
|      * @returns {String} EventType                   返回事件类型名称 | |
|      */ | |
|      | |
|     editormd.mouseOrTouch = function(mouseEventType, touchEventType) { | |
|         mouseEventType = mouseEventType || "click"; | |
|         touchEventType = touchEventType || "touchend"; | |
|          | |
|         var eventType  = mouseEventType; | |
| 
 | |
|         try { | |
|             document.createEvent("TouchEvent"); | |
|             eventType = touchEventType; | |
|         } catch(e) {} | |
| 
 | |
|         return eventType; | |
|     }; | |
|      | |
|     /** | |
|      * 日期时间的格式化方法 | |
|      * Datetime format method | |
|      *  | |
|      * @param   {String}   [format=""]  日期时间的格式,类似PHP的格式 | |
|      * @returns {String}   datefmt      返回格式化后的日期时间字符串 | |
|      */ | |
|      | |
|     editormd.dateFormat = function(format) {                 | |
|         format      = format || ""; | |
| 
 | |
|         var addZero = function(d) { | |
|             return (d < 10) ? "0" + d : d; | |
|         }; | |
| 
 | |
|         var date    = new Date();  | |
|         var year    = date.getFullYear(); | |
|         var year2   = year.toString().slice(2, 4); | |
|         var month   = addZero(date.getMonth() + 1); | |
|         var day     = addZero(date.getDate()); | |
|         var weekDay = date.getDay(); | |
|         var hour    = addZero(date.getHours()); | |
|         var min     = addZero(date.getMinutes()); | |
|         var second  = addZero(date.getSeconds()); | |
|         var ms      = addZero(date.getMilliseconds());  | |
|         var datefmt = ""; | |
| 
 | |
|         var ymd     = year2 + "-" + month + "-" + day; | |
|         var fymd    = year  + "-" + month + "-" + day; | |
|         var hms     = hour  + ":" + min   + ":" + second; | |
| 
 | |
|         switch (format)  | |
|         { | |
|             case "UNIX Time" : | |
|                     datefmt = date.getTime(); | |
|                 break; | |
| 
 | |
|             case "UTC" : | |
|                     datefmt = date.toUTCString(); | |
|                 break;	 | |
| 
 | |
|             case "yy" : | |
|                     datefmt = year2; | |
|                 break;	 | |
| 
 | |
|             case "year" : | |
|             case "yyyy" : | |
|                     datefmt = year; | |
|                 break; | |
| 
 | |
|             case "month" : | |
|             case "mm" : | |
|                     datefmt = month; | |
|                 break;                         | |
| 
 | |
|             case "cn-week-day" : | |
|             case "cn-wd" : | |
|                     var cnWeekDays = ["日", "一", "二", "三", "四", "五", "六"]; | |
|                     datefmt = "星期" + cnWeekDays[weekDay]; | |
|                 break; | |
| 
 | |
|             case "week-day" : | |
|             case "wd" : | |
|                     var weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; | |
|                     datefmt = weekDays[weekDay]; | |
|                 break; | |
| 
 | |
|             case "day" : | |
|             case "dd" : | |
|                     datefmt = day; | |
|                 break; | |
| 
 | |
|             case "hour" : | |
|             case "hh" : | |
|                     datefmt = hour; | |
|                 break; | |
| 
 | |
|             case "min" : | |
|             case "ii" : | |
|                     datefmt = min; | |
|                 break; | |
| 
 | |
|             case "second" : | |
|             case "ss" : | |
|                     datefmt = second; | |
|                 break; | |
| 
 | |
|             case "ms" : | |
|                     datefmt = ms; | |
|                 break; | |
| 
 | |
|             case "yy-mm-dd" : | |
|                     datefmt = ymd; | |
|                 break; | |
| 
 | |
|             case "yyyy-mm-dd" : | |
|                     datefmt = fymd; | |
|                 break; | |
| 
 | |
|             case "yyyy-mm-dd h:i:s ms" : | |
|             case "full + ms" :  | |
|                     datefmt = fymd + " " + hms + " " + ms; | |
|                 break; | |
| 
 | |
|             case "full" : | |
|             case "yyyy-mm-dd h:i:s" : | |
|                 default: | |
|                     datefmt = fymd + " " + hms; | |
|                 break; | |
|         } | |
| 
 | |
|         return datefmt; | |
|     }; | |
| 
 | |
|     return editormd; | |
| 
 | |
| })); | |
| </code></pre> | |
|         </article> | |
|     </section> | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| </div> | |
| 
 | |
| <nav> | |
|     <h2><a href="index.html">Home</a></h2> | |
| </nav> | |
| 
 | |
| <br class="clear"> | |
| 
 | |
| <footer> | |
|     Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0</a> on Mon Jun 08 2015 01:07:40 GMT+0800 (中国标准时间) | |
| </footer> | |
| 
 | |
| <script> prettyPrint(); </script> | |
| <script src="scripts/linenumber.js"> </script> | |
| </body> | |
| </html>
 |