玛氪宕·梦魔(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.
3061 lines
117 KiB
3061 lines
117 KiB
/*
|
|
* Editor.md
|
|
* @file editormd.js
|
|
* @version v1.1.9
|
|
* @description A simple online markdown editor.
|
|
* @license MIT License
|
|
* @author Pandao
|
|
* {@link https://github.com/pandao/editor.md}
|
|
* @updateTime 2015-03-04
|
|
*/
|
|
|
|
/**
|
|
* @fileOverview Editor.md
|
|
* @author pandao
|
|
* @version 1.1.9
|
|
*/
|
|
|
|
;(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
|
|
{
|
|
define(["jquery"], factory);
|
|
}
|
|
else
|
|
{
|
|
window.editormd = factory();
|
|
}
|
|
|
|
}(function() {
|
|
|
|
/**
|
|
* editormd
|
|
*
|
|
* @param {String} id 编辑器的ID
|
|
* @param {Object} options 配置选项 Key/Value
|
|
* @returns {Object} editormd 返回editormd对象
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
var $ = (typeof (jQuery) !== "undefined") ? jQuery : Zepto;
|
|
|
|
if (typeof ($) === "undefined") {
|
|
return ;
|
|
}
|
|
|
|
var editormd = function (id, options) {
|
|
return new editormd.fn.init(id, options);
|
|
};
|
|
|
|
editormd.title = editormd.$name = "Editor.md";
|
|
editormd.version = "1.1.9";
|
|
editormd.homePage = "https://pandao.github.io/editor.md/";
|
|
editormd.classPrefix = "editormd-";
|
|
|
|
editormd.defaults = {
|
|
mode : "gfm", //gfm or markdown
|
|
markdown : "",
|
|
width : "100%",
|
|
height : "100%",
|
|
path : "./lib/",
|
|
watch : true,
|
|
placeholder : "now coding markdown...",
|
|
readOnly : false,
|
|
lineNumbers : true,
|
|
matchWordHighlight : true, // options: true, false, "onselected"
|
|
styleActiveLine : true, // Highlight the current line
|
|
dialogLockScreen : true,
|
|
dialogShowMask : true,
|
|
dialogDraggable : true,
|
|
dialogMaskBgColor : "#fff",
|
|
dialogMaskOpacity : 0.1,
|
|
onload : function() {},
|
|
onchange : function() {},
|
|
onfullscreen : function() {},
|
|
onfullscreenExit : function() {},
|
|
imageUpload : false,
|
|
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
|
|
imageUploadURL : "",
|
|
crossDomainUpload : false,
|
|
uploadCallbackURL : "",
|
|
saveHTMLToTextarea : false,
|
|
toc : true,
|
|
tocStartLevel : 1, // Said from H1 to create ToC
|
|
fontSize : "13px",
|
|
htmlDecode : false, // Open the HTML tag identification
|
|
tex : false,
|
|
flowChart : false, // flowChart.js only support IE9+
|
|
sequenceDiagram : false, // sequenceDiagram.js only support IE9+
|
|
previewCodeHighlight : true,
|
|
inRequirejs : false,
|
|
toolbar : true,
|
|
toolbarIcons : function() {
|
|
return [
|
|
"undo", "redo", "|",
|
|
"bold", "del", "italic", "quote", "|",
|
|
"h1", "h2", "h3", "h4", "h5", "h6", "|",
|
|
"list-ul", "list-ol", "hr", "|",
|
|
"link", "anchor", "image", "code", "code-block-tab", "code-block", "datetime", "|",
|
|
"watch", "preview", "fullscreen", "clear", "|",
|
|
"info"
|
|
]
|
|
},
|
|
toolbarTitles : {},
|
|
toolbarHandlers : {},
|
|
|
|
toolbarIconsClass : {
|
|
undo : "fa-undo",
|
|
redo : "fa-repeat",
|
|
bold : "fa-bold",
|
|
del : "fa-strikethrough",
|
|
italic : "fa-italic",
|
|
quote : "fa-quote-left",
|
|
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",
|
|
anchor : "fa-anchor",
|
|
image : "fa-picture-o",
|
|
code : "fa-code",
|
|
"code-block-tab" : "fa-file-code-o",
|
|
"code-block" : "fa-file-code-o",
|
|
datetime : "fa-clock-o",
|
|
watch : "fa-eye-slash",
|
|
unwatch : "fa-eye",
|
|
preview : "fa-search",
|
|
fullscreen : "fa-arrows-alt",
|
|
clear : "fa-eraser",
|
|
info : "fa-info-circle"
|
|
},
|
|
|
|
toolbarIconTexts : {},
|
|
lang : {
|
|
name : "zh-cn",
|
|
description : "开源在线Markdown编辑器<br/>A simple markdown doucment online editor.",
|
|
toolbar : {
|
|
undo : "撤销(Ctrl+Z)",
|
|
redo : "重做(Ctrl+Y)",
|
|
bold : "粗体",
|
|
del : "删除线",
|
|
italic : "斜体",
|
|
quote : "引用",
|
|
h1 : "标题1",
|
|
h2 : "标题2",
|
|
h3 : "标题3",
|
|
h4 : "标题4",
|
|
h5 : "标题5",
|
|
h6 : "标题6",
|
|
"list-ul" : "无序列表",
|
|
"list-ol" : "有序列表",
|
|
hr : "横线",
|
|
link : "链接",
|
|
anchor : "锚点",
|
|
image : "图片",
|
|
code : "行内代码",
|
|
"code-block-tab" : "预格式文本 / 代码块(缩进风格)",
|
|
"code-block" : "代码块(多语言风格)",
|
|
datetime : "日期时间",
|
|
watch : "关闭实时预览",
|
|
unwatch : "开启实时预览",
|
|
preview : "全窗口预览HTML(可按ESC还原)",
|
|
fullscreen : "全屏(按ESC还原)",
|
|
clear : "清空",
|
|
info : "关于" + editormd.title
|
|
},
|
|
buttons : {
|
|
enter : "确定",
|
|
cancel : "取消"
|
|
},
|
|
dialog : {
|
|
link : {
|
|
title : "添加链接",
|
|
url : "链接地址",
|
|
urlTitle : "链接标题",
|
|
urlEmpty : "错误:请填写链接地址。",
|
|
titleEmpty : "错误:请填写链接标题。"
|
|
},
|
|
anchor : {
|
|
title : "添加锚点链接",
|
|
name : "锚点名称",
|
|
url : "链接地址",
|
|
urlTitle : "链接标题",
|
|
nameEmpty: "错误:锚点名称不能为空。",
|
|
titleEmpty : "错误:请填写锚点链接标题。",
|
|
urlEmpty : "错误:请填写锚点链接地址。"
|
|
},
|
|
image : {
|
|
title : "添加图片",
|
|
url : "图片地址",
|
|
link : "图片链接",
|
|
alt : "图片描述",
|
|
uploadButton : "本地上传",
|
|
imageURLEmpty : "错误:图片地址不能为空。",
|
|
uploadFileEmpty : "错误:上传的图片不能为空。",
|
|
formatNotAllowed : "错误:只允许上传图片文件,允许上传的图片文件格式有:"
|
|
},
|
|
tabCodeBlock : {
|
|
title : "添加预格式文本或代码块",
|
|
codeEmptyAlert : "错误:请填写预格式文本或代码的内容。"
|
|
},
|
|
codeBlock : {
|
|
title : "添加代码块",
|
|
selectLabel : "代码语言:",
|
|
selectDefaultText : "请选择代码语言",
|
|
otherLanguage : "其他语言",
|
|
unselectedLanguageAlert : "错误:请选择代码所属的语言类型。",
|
|
codeEmptyAlert : "错误:请填写代码内容。"
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
editormd.classNames = {
|
|
tex : editormd.classPrefix + "tex"
|
|
};
|
|
|
|
editormd.dialogZindex = 99999;
|
|
|
|
editormd.$katex = null;
|
|
editormd.$marked = null;
|
|
editormd.$CodeMirror = null;
|
|
editormd.$prettyPrint = null;
|
|
|
|
editormd.prototype = editormd.fn = {
|
|
state : {
|
|
watching : false,
|
|
loaded : false,
|
|
preview : false,
|
|
fullscreen : false
|
|
},
|
|
|
|
/**
|
|
* 构造函数/实例初始化
|
|
* @param {String} id 编辑器的ID
|
|
* @param {Object} [options={}] 配置选项 Key/Value
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
init : function (id, options) {
|
|
|
|
options = options || {};
|
|
|
|
var _this = this;
|
|
var classPrefix = this.classPrefix = editormd.classPrefix;
|
|
var editor = this.editor = $("#" + id);
|
|
var settings = this.settings = $.extend(true, editormd.defaults, options);
|
|
|
|
this.id = id;
|
|
this.lang = settings.lang;
|
|
|
|
var classNames = this.classNames = {
|
|
textarea : {
|
|
html : this.classPrefix + "html-textarea",
|
|
markdown : this.classPrefix + "markdown-textarea"
|
|
}
|
|
};
|
|
|
|
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
|
|
});
|
|
|
|
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("name", id + "-markdown-doc").attr("placeholder", settings.placeholder);
|
|
|
|
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");
|
|
|
|
if (settings.markdown !== "")
|
|
{
|
|
markdownTextarea.val(settings.markdown);
|
|
}
|
|
|
|
this.htmlTextarea = editor.find("." + classNames.textarea.html);
|
|
|
|
this.preview = editor.find("." + classPrefix + "preview");
|
|
this.previewContainer = this.preview.children("." + classPrefix + "preview-container");
|
|
this.toolbarIconHandlers = {};
|
|
|
|
if (!settings.inRequirejs)
|
|
{
|
|
this.loadQueues();
|
|
}
|
|
else
|
|
{
|
|
_this.setCodeMirror();
|
|
_this.setToolbar();
|
|
_this.setMarked().loadedDisplay();
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 所需组件加载队列
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
loadQueues : function() {
|
|
var _this = this;
|
|
var settings = this.settings;
|
|
var loadPath = settings.path;
|
|
|
|
var loadFlowChartOrSequenceDiagram = function() {
|
|
|
|
if (editormd.isIE8)
|
|
{
|
|
_this.setMarked().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.setMarked().loadedDisplay();
|
|
});
|
|
}
|
|
else if (settings.flowChart && !settings.sequenceDiagram)
|
|
{
|
|
editormd.loadScript(loadPath + "flowchart.min", function() {
|
|
editormd.loadScript(loadPath + "jquery.flowchart.min", function() {
|
|
_this.setMarked().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.setMarked().loadedDisplay();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
});
|
|
}
|
|
else
|
|
{
|
|
_this.setMarked().loadedDisplay();
|
|
}
|
|
};
|
|
|
|
editormd.loadCSS(loadPath + "codemirror/codemirror.min");
|
|
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();
|
|
_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组件
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
setCodeMirror : function() {
|
|
var settings = this.settings;
|
|
var editor = this.editor;
|
|
var codeMirrorConfig = {
|
|
mode : settings.mode,
|
|
theme : "default",
|
|
tabSize : 4,
|
|
dragDrop : false,
|
|
autofocus : true,
|
|
readOnly : (settings.readOnly) ? "nocursor" : false,
|
|
indentUnit : 4,
|
|
lineNumbers : settings.lineNumbers,
|
|
lineWrapping : true,
|
|
matchBrackets : true,
|
|
indentWithTabs : true,
|
|
styleActiveLine : settings.styleActiveLine,
|
|
styleSelectedText : true,
|
|
autoCloseBrackets : true,
|
|
showTrailingSpace : true,
|
|
highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : {
|
|
showToken: (settings.matchWordHighlight == "onselected") ? false : /\w/
|
|
})
|
|
};
|
|
|
|
this.codeEditor = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig);
|
|
this.codeMirror = editor.find(".CodeMirror");
|
|
|
|
this.codeMirror.css({
|
|
fontSize : settings.fontSize,
|
|
width : (!settings.watch) ? "100%" : "50%"
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 显示工具栏
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
showToolbar : function() {
|
|
var settings = this.settings;
|
|
if(settings.readOnly) return ;
|
|
|
|
settings.toolbar = true;
|
|
this.toolbar.show();
|
|
this.resize();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 隐藏工具栏
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
hideToolbar : function() {
|
|
var settings = this.settings;
|
|
|
|
settings.toolbar = false;
|
|
this.toolbar.hide();
|
|
this.resize();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 配置和初始化工具栏
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
setToolbar : function() {
|
|
var settings = this.settings;
|
|
|
|
if(settings.readOnly) return ;
|
|
|
|
var editor = this.editor;
|
|
var preview = this.preview;
|
|
var classPrefix = this.classPrefix;
|
|
|
|
editor.append('<div class="'+classPrefix+'toolbar"><div class="'+classPrefix+'toolbar-container"><ul class="'+classPrefix+'menu"></ul></div></div>');
|
|
|
|
var toolbar = this.toolbar = editor.find("." + classPrefix + "toolbar");
|
|
|
|
if (!settings.toolbar)
|
|
{
|
|
toolbar.hide();
|
|
|
|
return ;
|
|
}
|
|
else
|
|
{
|
|
toolbar.show();
|
|
}
|
|
|
|
var icons = settings.toolbarIcons();
|
|
var toolbarMenu = toolbar.find("." + this.classPrefix + "menu"), menu = "";
|
|
|
|
for (var i = 0, len = icons.length; i < len; i++)
|
|
{
|
|
var name = icons[i];
|
|
|
|
if (name !== "|")
|
|
{
|
|
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;
|
|
|
|
menu += "<li><a href=\"javascript:;\" title=\"" + title + "\" unselectable=\"on\">" +
|
|
"<i class=\"fa " + iconClass + "\" name=\""+name+"\" unselectable=\"on\">"+((isHeader) ? name : ( (iconClass === "") ? iconTexts : "") ) + "</i></a></li>";
|
|
}
|
|
else
|
|
{
|
|
menu += "<li class=\"divider\" unselectable=\"on\">|</li>";
|
|
}
|
|
}
|
|
|
|
toolbarMenu.html(menu);
|
|
|
|
this.setToolbarHandler();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 工具栏图标事件处理对象序列
|
|
* @param {Object} cm CodeMirror的实例对象
|
|
* @param {String} name 要获取的事件处理器名称
|
|
* @returns {Object} 返回处理对象序列
|
|
*/
|
|
|
|
getToolbarHandles : function(name) {
|
|
var _this = this;
|
|
var settings = this.settings;
|
|
var lang = settings.lang;
|
|
var editor = this.editor;
|
|
var classPrefix = this.classPrefix;
|
|
|
|
var dialogLockScreen = function() {
|
|
if (settings.dialogLockScreen) {
|
|
$("html,body").css("overflow", "hidden");
|
|
}
|
|
};
|
|
|
|
var dialogShowMask = function(dialog) {
|
|
dialog.css({
|
|
top : ($(window).height() - dialog.height()) / 2 + "px",
|
|
left : ($(window).width() - dialog.width()) / 2 + "px"
|
|
});
|
|
|
|
if (settings.dialogShowMask) {
|
|
editor.find("." + classPrefix + "mask").css("z-index", parseInt(dialog.css("z-index")) - 1).show();
|
|
}
|
|
};
|
|
|
|
var toolbarHandlers = this.toolbarHandlers = {
|
|
undo : function(cm) {
|
|
cm.undo();
|
|
},
|
|
redo : function(cm) {
|
|
cm.redo();
|
|
},
|
|
bold : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("**" + selection + "**");
|
|
|
|
if(selection === "") {
|
|
cm.setCursor(cursor.line, cursor.ch + 2);
|
|
}
|
|
},
|
|
del : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("~~" + selection + "~~");
|
|
|
|
if(selection === "") {
|
|
cm.setCursor(cursor.line, cursor.ch + 2);
|
|
}
|
|
},
|
|
|
|
italic : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("*" + selection + "*");
|
|
|
|
if(selection === "") {
|
|
cm.setCursor(cursor.line, cursor.ch + 1);
|
|
}
|
|
},
|
|
|
|
quote : function(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);
|
|
},
|
|
|
|
h1 : function(cm) {
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("# " + selection);
|
|
},
|
|
|
|
h2 : function(cm) {
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("## " + selection);
|
|
},
|
|
|
|
h3 : function(cm) {
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("### " + selection);
|
|
},
|
|
|
|
h4 : function(cm) {
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("#### " + selection);
|
|
},
|
|
|
|
h5 : function(cm) {
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("##### " + selection);
|
|
},
|
|
|
|
h6 : function(cm) {
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("###### " + selection);
|
|
},
|
|
|
|
"list-ul" : function(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(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(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("------------");
|
|
},
|
|
|
|
link : function(cm) {
|
|
var selection = cm.getSelection();
|
|
var linkLang = lang.dialog.link;
|
|
var linkDialogName = classPrefix + "link-dialog", linkDialog;
|
|
|
|
if (editor.find("." + linkDialogName).length > 0)
|
|
{
|
|
linkDialog = editor.find("." + linkDialogName);
|
|
linkDialog.find("[data-url]").val("http://");
|
|
linkDialog.find("[data-title]").val(selection);
|
|
|
|
dialogShowMask(linkDialog);
|
|
dialogLockScreen();
|
|
linkDialog.show();
|
|
}
|
|
else
|
|
{
|
|
var linkDialogHTML = "<div class=\"" + classPrefix + "form\">" +
|
|
"<label>" + linkLang.url + "</label>" +
|
|
"<input type=\"text\" value=\"http://\" data-url />" +
|
|
"<br/>" +
|
|
"<label>" + linkLang.urlTitle + "</label>" +
|
|
"<input type=\"text\" value=\"" + selection + "\" data-title />" +
|
|
"<br/>" +
|
|
"</div>";
|
|
|
|
linkDialog = _this.createDialog({
|
|
title : linkLang.title,
|
|
width : 380,
|
|
height : 210,
|
|
content : linkDialogHTML,
|
|
mask : settings.dialogShowMask,
|
|
drag : settings.dialogDraggable,
|
|
lockScreen : settings.dialogLockScreen,
|
|
maskStyle : {
|
|
opacity : settings.dialogMaskOpacity,
|
|
backgroundColor : settings.dialogMaskBgColor
|
|
},
|
|
buttons : {
|
|
enter : [lang.buttons.enter, function() {
|
|
var url = this.find("[data-url]").val();
|
|
var title = this.find("[data-title]").val();
|
|
|
|
if (url === "http://" || url === "")
|
|
{
|
|
alert(linkLang.urlEmpty);
|
|
return false;
|
|
}
|
|
|
|
if (title === "")
|
|
{
|
|
alert(linkLang.titleEmpty);
|
|
return false;
|
|
}
|
|
|
|
cm.replaceSelection("[" + title + "](" + url + " \""+title+"\")");
|
|
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}],
|
|
cancel : [lang.buttons.cancel, function() {
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}]
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
anchor : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
var anchorLang = lang.dialog.anchor;
|
|
var anchorDialogName = classPrefix + "anchor-dialog", anchorDialog;
|
|
|
|
if (editor.find("." + anchorDialogName).length > 0)
|
|
{
|
|
anchorDialog = editor.find("." + anchorDialogName);
|
|
anchorDialog.find("[data-name]").val("");
|
|
anchorDialog.find("[data-url]").val("http://");
|
|
anchorDialog.find("[data-title]").val(selection);
|
|
|
|
dialogShowMask(anchorDialog);
|
|
dialogLockScreen();
|
|
anchorDialog.show();
|
|
}
|
|
else
|
|
{
|
|
var anchorDialogHTML = "<div class=\"" + classPrefix + "form\">" +
|
|
"<label>" + anchorLang.name + "</label>" +
|
|
"<input type=\"text\" data-name />" +
|
|
"<br/>" +
|
|
"<label>" + anchorLang.url + "</label>" +
|
|
"<input type=\"text\" value=\"http://\" data-url />" +
|
|
"<br/>" +
|
|
"<label>" + anchorLang.urlTitle + "</label>" +
|
|
"<input type=\"text\" value=\"" + selection + "\" data-title />" +
|
|
"<br/>" +
|
|
"</div>";
|
|
|
|
anchorDialog = _this.createDialog({
|
|
name : anchorDialogName,
|
|
title : anchorLang.title,
|
|
width : 380,
|
|
height : 250,
|
|
content : anchorDialogHTML,
|
|
mask : settings.dialogShowMask,
|
|
drag : settings.dialogDraggable,
|
|
lockScreen : settings.dialogLockScreen,
|
|
maskStyle : {
|
|
opacity : settings.dialogMaskOpacity,
|
|
backgroundColor : settings.dialogMaskBgColor
|
|
},
|
|
buttons : {
|
|
enter : [lang.buttons.enter, function() {
|
|
var name = this.find("[data-name]").val();
|
|
var url = this.find("[data-url]").val();
|
|
var title = this.find("[data-title]").val();
|
|
|
|
if (name === "")
|
|
{
|
|
alert(anchorLang.nameEmpty);
|
|
return false;
|
|
}
|
|
|
|
if (url === "http://" || url === "")
|
|
{
|
|
alert(anchorLang.urlEmpty);
|
|
return false;
|
|
}
|
|
|
|
if (title === "")
|
|
{
|
|
alert(anchorLang.titleEmpty);
|
|
return false;
|
|
}
|
|
|
|
cm.replaceSelection("[" + title + "][" + name + "]\n[" + name + "]: " + url + "");
|
|
|
|
if (selection === "") {
|
|
cm.setCursor(cursor.line, cursor.ch + 1);
|
|
}
|
|
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}],
|
|
cancel : [lang.buttons.cancel, function() {
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}]
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
image : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
var imageLang = lang.dialog.image;
|
|
var iframeName = classPrefix + "image-iframe";
|
|
var imageDialogName = classPrefix + "image-dialog", imageDialog;
|
|
|
|
if (editor.find("." + imageDialogName).length > 0)
|
|
{
|
|
imageDialog = editor.find("." + imageDialogName);
|
|
imageDialog.find("[type=\"text\"]").val("");
|
|
imageDialog.find("[type=\"file\"]").val("");
|
|
imageDialog.find("[data-link]").val("http://");
|
|
|
|
dialogShowMask(imageDialog);
|
|
dialogLockScreen();
|
|
imageDialog.show();
|
|
}
|
|
else
|
|
{
|
|
var guid = (new Date).getTime();
|
|
var action = settings.imageUploadURL + "?guid=" + guid;
|
|
|
|
if (settings.crossDomainUpload)
|
|
{
|
|
action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid;
|
|
}
|
|
|
|
var imageDialogHTML = ( (settings.imageUpload) ? "<form action=\"" + action +"\" target=\"" + iframeName + "\" method=\"post\" enctype=\"multipart/form-data\" class=\"" + classPrefix + "form\">" : "<div class=\"" + classPrefix + "form\">" ) +
|
|
( (settings.imageUpload) ? "<iframe name=\"" + iframeName + "\" id=\"" + iframeName + "\" guid=\"" + guid + "\"></iframe>" : "" ) +
|
|
"<label>" + imageLang.url + "</label>" +
|
|
"<input type=\"text\" data-url />" + (function(){
|
|
return (settings.imageUpload) ? "<div class=\"" + classPrefix + "file-input\">" +
|
|
"<input type=\"file\" name=\"" + classPrefix + "image-file\" accept=\"image/*\" />" +
|
|
"<input type=\"submit\" value=\"" + imageLang.uploadButton + "\" />" +
|
|
"</div>" : "";
|
|
})() +
|
|
"<br/>" +
|
|
"<label>" + imageLang.alt + "</label>" +
|
|
"<input type=\"text\" data-alt />" +
|
|
"<br/>" +
|
|
"<label>" + imageLang.link + "</label>" +
|
|
"<input type=\"text\" value=\"http://\" data-link />" +
|
|
"<br/>" +
|
|
( (settings.imageUpload) ? "</form>" : "</div>");
|
|
|
|
//var imageFooterHTML = "<button class=\"" + classPrefix + "btn " + classPrefix + "image-manager-btn\" style=\"float:left;\">" + imageLang.managerButton + "</button>";
|
|
|
|
imageDialog = _this.createDialog({
|
|
title : imageLang.title,
|
|
width : (settings.imageUpload) ? 465 : 380,
|
|
height : 250,
|
|
name : imageDialogName,
|
|
content : imageDialogHTML,
|
|
mask : settings.dialogShowMask,
|
|
drag : settings.dialogDraggable,
|
|
lockScreen : settings.dialogLockScreen,
|
|
maskStyle : {
|
|
opacity : settings.dialogMaskOpacity,
|
|
backgroundColor : settings.dialogMaskBgColor
|
|
},
|
|
buttons : {
|
|
enter : [lang.buttons.enter, function() {
|
|
var url = this.find("[data-url]").val();
|
|
var alt = this.find("[data-alt]").val();
|
|
var link = this.find("[data-link]").val();
|
|
|
|
if (url === "")
|
|
{
|
|
alert(imageLang.imageURLEmpty);
|
|
return false;
|
|
}
|
|
|
|
if (link === "" || link === "http://")
|
|
{
|
|
cm.replaceSelection("![" + alt + "](" + url + " \"" + alt + "\")");
|
|
}
|
|
else
|
|
{
|
|
cm.replaceSelection("[![" + alt + "](" + url + " \"" + alt + "\")](" + link + " \"" + alt + "\")");
|
|
}
|
|
|
|
if (alt === "") {
|
|
cm.setCursor(cursor.line, cursor.ch + 2);
|
|
}
|
|
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}],
|
|
cancel : [lang.buttons.cancel, function() {
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}]
|
|
}
|
|
});
|
|
|
|
imageDialog.attr("id", classPrefix + "image-dialog-" + guid);
|
|
}
|
|
|
|
var fileInput = imageDialog.find("[name=\"" + classPrefix + "image-file\"]");
|
|
|
|
fileInput.bind("change", function() {
|
|
var fileName = fileInput.val();
|
|
var isImage = new RegExp("(\\.(" + settings.imageFormats.join("|") + "))$"); // /(\.(webp|jpg|jpeg|gif|bmp|png))$/
|
|
|
|
if (fileName === "")
|
|
{
|
|
alert(imageLang.uploadFileEmpty);
|
|
}
|
|
else if (!isImage.test(fileName))
|
|
{
|
|
alert(imageLang.formatNotAllowed + settings.imageFormats.join(", "));
|
|
}
|
|
else
|
|
{
|
|
imageDialog.loading(true);
|
|
|
|
var submitHandler = function() {
|
|
|
|
var uploadIframe = document.getElementById(iframeName);
|
|
|
|
uploadIframe.onload = function() {
|
|
imageDialog.loading(false);
|
|
|
|
var json = uploadIframe.contentWindow.document.body.innerHTML;
|
|
json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");
|
|
|
|
if (json.success === 1)
|
|
{
|
|
imageDialog.find("[data-url]").val(json.url);
|
|
}
|
|
else
|
|
{
|
|
alert(json.message);
|
|
}
|
|
|
|
return false;
|
|
};
|
|
};
|
|
|
|
imageDialog.find("[type=\"submit\"]").bind(editormd.mouseOrTouch("click", "touchend"), submitHandler).trigger("click");
|
|
|
|
}
|
|
|
|
return false;
|
|
});
|
|
},
|
|
|
|
code : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
|
|
cm.replaceSelection("`" + selection + "`");
|
|
|
|
if (selection === "") {
|
|
cm.setCursor(cursor.line, cursor.ch + 1);
|
|
}
|
|
|
|
},
|
|
|
|
"code-block-tab" : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
var tabCodeBlockDialogName = classPrefix + "dialog-tab-code-block", tabCodeBlockDialog;
|
|
|
|
if (editor.find("." + tabCodeBlockDialogName).length > 0)
|
|
{
|
|
tabCodeBlockDialog = editor.find("." + tabCodeBlockDialogName);
|
|
tabCodeBlockDialog.find("textarea").val(selection);
|
|
|
|
dialogShowMask(tabCodeBlockDialog);
|
|
dialogLockScreen();
|
|
tabCodeBlockDialog.show();
|
|
}
|
|
else
|
|
{
|
|
var tabCodeBlockDialogHTML = "<textarea placeholder=\"coding now....\" style=\"width: 680px;height: 300px;\">" + selection + "</textarea>";
|
|
|
|
tabCodeBlockDialog = _this.createDialog({
|
|
name : tabCodeBlockDialogName,
|
|
title : lang.dialog.tabCodeBlock.title,
|
|
width : 750,
|
|
height : 470,
|
|
mask : settings.dialogShowMask,
|
|
drag : settings.dialogDraggable,
|
|
content : tabCodeBlockDialogHTML,
|
|
lockScreen : settings.dialogLockScreen,
|
|
maskStyle : {
|
|
opacity : settings.dialogMaskOpacity,
|
|
backgroundColor : settings.dialogMaskBgColor
|
|
},
|
|
buttons : {
|
|
enter : [lang.buttons.enter, function() {
|
|
var codeTexts = this.find("textarea").val();
|
|
|
|
if (codeTexts === "")
|
|
{
|
|
alert(lang.dialog.tabCodeBlock.codeEmptyAlert);
|
|
return false;
|
|
}
|
|
|
|
codeTexts = codeTexts.split("\n");
|
|
|
|
for (var i in codeTexts)
|
|
{
|
|
codeTexts[i] = " " + codeTexts[i];
|
|
}
|
|
|
|
cm.replaceSelection(codeTexts.join("\n"));
|
|
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}],
|
|
cancel : [lang.buttons.cancel, function() {
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}]
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
"code-block" : function(cm) {
|
|
var cursor = cm.getCursor();
|
|
var selection = cm.getSelection();
|
|
var codeBlockDialogName = classPrefix + "dialog-code-block", codeBlockDialog;
|
|
|
|
if (editor.find("." + codeBlockDialogName).length > 0)
|
|
{
|
|
codeBlockDialog = editor.find("." + codeBlockDialogName);
|
|
codeBlockDialog.find("option:first").attr("selected", "selected");
|
|
codeBlockDialog.find("textarea").val(selection);
|
|
|
|
dialogShowMask(codeBlockDialog);
|
|
dialogLockScreen();
|
|
codeBlockDialog.show();
|
|
}
|
|
else
|
|
{
|
|
var codeBlockDialogHTML = "<div class=\"" + classPrefix + "code-toolbar\">" +
|
|
lang.dialog.codeBlock.selectLabel + "<select><option selected=\"selected\" value=\"\">" + lang.dialog.codeBlock.selectDefaultText + "</option></select>" +
|
|
"</div>" +
|
|
"<textarea placeholder=\"coding now....\" style=\"width: 680px;height: 360px;\">" + selection + "</textarea>";
|
|
|
|
codeBlockDialog = _this.createDialog({
|
|
name : codeBlockDialogName,
|
|
title : lang.dialog.codeBlock.title,
|
|
width : 752,
|
|
height : 565,
|
|
mask : settings.dialogShowMask,
|
|
drag : settings.dialogDraggable,
|
|
content : codeBlockDialogHTML,
|
|
lockScreen : settings.dialogLockScreen,
|
|
maskStyle : {
|
|
opacity : settings.dialogMaskOpacity,
|
|
backgroundColor : settings.dialogMaskBgColor
|
|
},
|
|
buttons : {
|
|
enter : [lang.buttons.enter, function() {
|
|
var codeTexts = this.find("textarea").val();
|
|
var langName = this.find("select").val();
|
|
|
|
if (langName === "")
|
|
{
|
|
alert(lang.dialog.codeBlock.unselectedLanguageAlert);
|
|
return false;
|
|
}
|
|
|
|
if (codeTexts === "")
|
|
{
|
|
alert(lang.dialog.codeBlock.codeEmptyAlert);
|
|
return false;
|
|
}
|
|
|
|
langName = (langName === "other") ? "" : langName;
|
|
|
|
cm.replaceSelection(["```" + langName, codeTexts, "```"].join("\n"));
|
|
|
|
if (langName === "") {
|
|
cm.setCursor(cursor.line, cursor.ch + 3);
|
|
}
|
|
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}],
|
|
cancel : [lang.buttons.cancel, function() {
|
|
this.hide().lockScreen(false).hideMask();
|
|
|
|
return false;
|
|
}]
|
|
}
|
|
});
|
|
|
|
var langSelect = codeBlockDialog.find("select");
|
|
|
|
for (var key in editormd.codeLanguages)
|
|
{
|
|
var codeLang = editormd.codeLanguages[key];
|
|
langSelect.append("<option value=\"" + key + "\">" + codeLang + "</option>");
|
|
}
|
|
|
|
langSelect.append("<option value=\"other\">" + lang.dialog.codeBlock.otherLanguage + "</option>");
|
|
}
|
|
},
|
|
|
|
datetime : function(cm) {
|
|
var selection = cm.getSelection();
|
|
var date = new Date();
|
|
var langName = settings.lang.name;
|
|
var datefmt = editormd.dateFormat() + " " + editormd.dateFormat((langName === "zh-cn" || langName === "zh-tw") ? "cn-week-day" : "week-day");
|
|
|
|
cm.replaceSelection(datefmt);
|
|
},
|
|
|
|
watch : function(cm) {
|
|
_this[_this.settings.watch ? "unwatch" : "watch"]();
|
|
},
|
|
|
|
preview : function(cm) {
|
|
|
|
_this.previewing();
|
|
},
|
|
|
|
fullscreen : function(cm) {
|
|
|
|
_this.fullscreen();
|
|
},
|
|
|
|
clear : function(cm) {
|
|
_this.clear();
|
|
},
|
|
|
|
info : function(cm) {
|
|
_this.showInfoDialog();
|
|
}
|
|
};
|
|
|
|
return (name && typeof toolbarIconHandlers[name] !== "undefined") ? toolbarHandlers[name] : toolbarHandlers;
|
|
},
|
|
|
|
/**
|
|
* 工具栏图标事件处理器
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
setToolbarHandler : function() {
|
|
var _this = this;
|
|
var settings = this.settings;
|
|
|
|
if (!settings.toolbar || settings.readOnly) {
|
|
return ;
|
|
}
|
|
|
|
var editor = this.editor;
|
|
var preview = this.preview;
|
|
var toolbar = this.toolbar;
|
|
var codeEditor = this.codeEditor;
|
|
var codeMirror = this.codeMirror;
|
|
var classPrefix = this.classPrefix;
|
|
var previewContainer = this.previewContainer;
|
|
var toolbarIcons = this.toolbarIcons = toolbar.find("." + classPrefix + "menu a");
|
|
|
|
toolbarIcons.bind(editormd.mouseOrTouch("click", "touchend"), function(event) {
|
|
|
|
var icon = $(this).children(".fa");
|
|
var name = icon.attr("name");
|
|
var cursor = codeEditor.getCursor();
|
|
var selection = codeEditor.getSelection();
|
|
var toolbarIconHandlers = _this.getToolbarHandles();
|
|
|
|
if (name === "") {
|
|
return ;
|
|
}
|
|
|
|
_this.activeIcon = icon;
|
|
|
|
if (typeof toolbarIconHandlers[name] !== "undefined")
|
|
{
|
|
toolbarIconHandlers[name](codeEditor);
|
|
}
|
|
else
|
|
{
|
|
if (typeof settings.toolbarHandlers[name] !== "undefined")
|
|
{
|
|
$.proxy(settings.toolbarHandlers[name], _this)(codeEditor, icon, cursor, selection);
|
|
}
|
|
}
|
|
|
|
if (name !== "link" && name !== "anchor" && name !== "image" && name !== "code-block" && name !== "code-block-tab" && name !== "watch" && name !== "preview" && name !== "fullscreen" && name !== "info")
|
|
{
|
|
codeEditor.focus();
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 动态创建对话框
|
|
* @param {Object} options 配置项键值对 Key/Value
|
|
* @returns {dialog} 返回创建的dialog的jQuery实例对象
|
|
*/
|
|
|
|
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 = this.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;
|
|
},
|
|
|
|
/**
|
|
* 创建关于Editor.md的对话框
|
|
* @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>Home page: <a href=\"" + editormd.homePage + "\" traget=\"_blank\">" + editormd.homePage + "</a></p>",
|
|
"<p>License: MIT</p>",
|
|
"</div>",
|
|
"<a href=\"javascript:;\" class=\"fa fa-close " + classPrefix + "dialog-close\"></a>",
|
|
"</div>"
|
|
].join("\n");
|
|
|
|
editor.append(infoDialogHTML);
|
|
|
|
var infoDialog = this.infoDialog = editor.find("." + classPrefix + "dialog-info");
|
|
|
|
infoDialog.find("." + classPrefix + "dialog-close").bind(editormd.mouseOrTouch("click", "touchend"), function() {
|
|
_this.hideInfoDialog();
|
|
});
|
|
|
|
infoDialog.css("border", (editormd.isIE8) ? "1px solid #ddd" : "").show();
|
|
|
|
this.infoDialogPosition();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 关于Editor.md对话居中定位
|
|
* @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
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
showInfoDialog : function() {
|
|
|
|
$("html,body").css("overflow-x", "hidden");
|
|
|
|
var _this = this;
|
|
var editor = this.editor;
|
|
var classPrefix = this.classPrefix;
|
|
var infoDialog = this.infoDialog = editor.find("." + classPrefix + "dialog-info");
|
|
|
|
if (infoDialog.length < 1)
|
|
{
|
|
this.createInfoDialog();
|
|
}
|
|
|
|
infoDialog.show();
|
|
|
|
this.infoDialogPosition();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 隐藏关于Editor.md
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
hideInfoDialog : function() {
|
|
$("html,body").css("overflow-x", "");
|
|
this.infoDialog.hide();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 配置和初始化marked组件
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
setMarked : function() {
|
|
var marked = editormd.$marked;
|
|
var markdownToC = this.markdownToC = [];
|
|
|
|
marked.setOptions({
|
|
renderer : editormd.markedRenderer(markdownToC),
|
|
gfm : true,
|
|
tables : true,
|
|
breaks : true,
|
|
pedantic : false,
|
|
sanitize : (this.settings.htmlDecode) ? false : true, // 关闭忽略HTML标签,即开启识别HTML标签,默认为false
|
|
smartLists : true,
|
|
smartypants : true
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 编辑器界面重建,用于动态语言包或模块加载等
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
recreateEditor : function() {
|
|
var _this = this;
|
|
var editor = this.editor;
|
|
var settings = this.settings;
|
|
var toolbarIcons = settings.toolbarIcons();
|
|
|
|
if (typeof this.infoDialog !== "undefined") {
|
|
this.infoDialog.remove();
|
|
}
|
|
|
|
if (typeof toolbarIcons["info"] !== "undefined") {
|
|
createInfoDialog();
|
|
}
|
|
|
|
if (!settings.readOnly)
|
|
{
|
|
if (editor.find(".editormd-dialog").length > 0) {
|
|
editor.find(".editormd-dialog").remove();
|
|
}
|
|
|
|
this.getToolbarHandles();
|
|
this.setToolbar();
|
|
}
|
|
|
|
this.resize();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 高亮预览HTML的pre代码部分
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
previewCodeHighlight : function() {
|
|
var settings = this.settings;
|
|
var previewContainer = this.previewContainer;
|
|
|
|
if (settings.previewCodeHighlight)
|
|
{
|
|
previewContainer.find("pre").addClass("prettyprint linenums");
|
|
prettyPrint();
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 解析TeX(KaTeX)科学公式
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
katexRender : function() {
|
|
|
|
var previewContainer = this.previewContainer;
|
|
|
|
previewContainer.find("." + editormd.classNames.tex).each(function(){
|
|
var tex = $(this);
|
|
editormd.$katex.render(tex.html(), tex[0]);
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 解析和渲染流程图及时序图
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
flowChartAndSequenceDiagramRender : function() {
|
|
|
|
var settings = this.settings;
|
|
var previewContainer = this.previewContainer;
|
|
|
|
if (editormd.isIE8) return ;
|
|
|
|
if (settings.flowChart) {
|
|
previewContainer.find(".flowchart").flowChart();
|
|
}
|
|
|
|
if (settings.sequenceDiagram) {
|
|
previewContainer.find(".sequence-diagram").sequenceDiagram({theme: "simple"});
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 加载队列完成之后的显示处理
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
loadedDisplay : function() {
|
|
|
|
var _this = this;
|
|
var editor = this.editor;
|
|
var preview = this.preview;
|
|
var settings = this.settings;
|
|
var codeEditor = this.codeEditor;
|
|
var codeMirror = this.codeMirror;
|
|
var previewContainer = this.previewContainer;
|
|
var mouseOrTouch = editormd.mouseOrTouch;
|
|
|
|
editor.find("." + this.classPrefix + "container-mask").hide();
|
|
|
|
this.saveToTextareas();
|
|
|
|
if(settings.watch) {
|
|
preview.show();
|
|
}
|
|
|
|
editor.data("oldWidth", editor.width()).data("oldHeight", editor.height()); // 为了兼容Zepto
|
|
|
|
this.resize();
|
|
|
|
$(window).resize(function(){
|
|
_this.resize();
|
|
});
|
|
|
|
var codeEditorBindScroll = function() {
|
|
codeMirror.find(".CodeMirror-scroll").bind(mouseOrTouch("scroll", "touchmove"), function() {
|
|
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)
|
|
{
|
|
preview.scrollTop(preview[0].scrollHeight);
|
|
}
|
|
else
|
|
{
|
|
preview.scrollTop(preview[0].scrollHeight * percent);
|
|
}
|
|
});
|
|
};
|
|
|
|
var codeEditorUnbindScroll = function() {
|
|
codeMirror.find(".CodeMirror-scroll").unbind(mouseOrTouch("scroll", "touchmove"));
|
|
};
|
|
|
|
var previewBindScroll = function() {
|
|
preview.bind(mouseOrTouch("scroll", "touchmove"), function() {
|
|
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);
|
|
}
|
|
});
|
|
};
|
|
|
|
var previewUnbindScroll = function() {
|
|
preview.unbind(mouseOrTouch("scroll", "touchmove"));
|
|
};
|
|
|
|
codeMirror.bind({
|
|
mouseover : codeEditorBindScroll,
|
|
mouseout : codeEditorUnbindScroll,
|
|
touchstart : codeEditorBindScroll,
|
|
touchend : codeEditorUnbindScroll
|
|
});
|
|
|
|
preview.bind({
|
|
mouseover : previewBindScroll,
|
|
mouseout : previewUnbindScroll,
|
|
touchstart : previewBindScroll,
|
|
touchend : previewUnbindScroll
|
|
});
|
|
|
|
codeEditor.on("change", function(cm, changeObj) {
|
|
_this.saveToTextareas();
|
|
});
|
|
|
|
$.proxy(settings.onload, this)();
|
|
|
|
this.state.loaded = true;
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 设置编辑器的宽度
|
|
* @param {Number|String} width 编辑器宽度值
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
width : function(width) {
|
|
|
|
this.editor.css("width", (typeof width === "number") ? width + "px" : width);
|
|
this.resize();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 设置编辑器的高度
|
|
* @param {Number|String} height 编辑器高度值
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
height : function(height) {
|
|
|
|
this.editor.css("height", (typeof height === "number") ? height + "px" : height);
|
|
this.resize();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 调整编辑器的尺寸和布局
|
|
* @param {Number|String} [width=null] 编辑器宽度值
|
|
* @param {Number|String} [height=null] 编辑器高度值
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
resize : function(width, height) {
|
|
|
|
width = width || null;
|
|
height = height || null;
|
|
|
|
var editor = this.editor;
|
|
var preview = this.preview;
|
|
var toolbar = this.toolbar;
|
|
var settings = this.settings;
|
|
var codeEditor = this.codeEditor;
|
|
var codeMirror = this.codeMirror;
|
|
|
|
if(width && height)
|
|
{
|
|
editor.css({
|
|
width : (typeof width === "number") ? width + "px" : width,
|
|
height : (typeof height === "number") ? height + "px" : 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());
|
|
}
|
|
|
|
codeMirror.find(".CodeMirror-gutters").height(codeMirror.height());
|
|
|
|
if(settings.watch)
|
|
{
|
|
codeMirror.width(editor.width() / 2);
|
|
preview.width((!this.state.preview) ? editor.width() / 2 : editor.width());
|
|
|
|
if (settings.toolbar && !settings.readOnly) {
|
|
preview.css("top", toolbar.height()).height(editor.height() - toolbar.height());
|
|
} else {
|
|
preview.css("top", 0).height(editor.height());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
codeMirror.width(editor.width());
|
|
preview.hide();
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 分别将Markdown源码和解析的HTML源码保存到对应的textarea
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
saveToTextareas : function() {
|
|
var _this = this;
|
|
var state = this.state;
|
|
var settings = this.settings;
|
|
var codeEditor = this.codeEditor;
|
|
var previewContainer = this.previewContainer;
|
|
|
|
var codeMirrorValue = codeEditor.getValue();
|
|
var markdownToC = this.markdownToC = [];
|
|
var newMarkdownDoc = editormd.$marked(codeMirrorValue, {renderer : editormd.markedRenderer(markdownToC)});
|
|
|
|
this.markdownTextarea[0].innerText = codeMirrorValue;
|
|
|
|
codeEditor.save();
|
|
|
|
if (settings.saveHTMLToTextarea) {
|
|
this.htmlTextarea.html(newMarkdownDoc);
|
|
}
|
|
|
|
if(settings.watch || (!settings.watch && state.preview))
|
|
{
|
|
previewContainer.html(newMarkdownDoc);
|
|
|
|
this.previewCodeHighlight();
|
|
|
|
if (settings.toc) {
|
|
editormd.markdownToCRenderer(markdownToC, previewContainer, settings.tocStartLevel);
|
|
}
|
|
|
|
if (!settings.inRequirejs && !editormd.kaTeXLoaded) {
|
|
editormd.loadKaTeX(function(){
|
|
editormd.$katex = katex;
|
|
editormd.kaTeXLoaded = true;
|
|
_this.katexRender();
|
|
});
|
|
} else {
|
|
this.katexRender();
|
|
}
|
|
|
|
var timer = setTimeout(function(){
|
|
clearTimeout(timer);
|
|
_this.flowChartAndSequenceDiagramRender();
|
|
}, 10);
|
|
|
|
if (state.loaded)
|
|
{
|
|
$.proxy(settings.onchange, this)();
|
|
}
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 聚焦光标位置
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
focus : function() {
|
|
this.codeEditor.focus();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 设置光标的位置
|
|
* @param {Object} cursor 要设置的光标位置键值对象,例:{line:1, ch:0}
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
setCursor : function(cursor) {
|
|
this.codeEditor.setCursor(cursor);
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 获取当前光标的位置
|
|
* @returns {Cursor} 返回一个光标Cursor对象
|
|
*/
|
|
|
|
getCursor : function() {
|
|
return this.codeEditor.getCursor();
|
|
},
|
|
|
|
/**
|
|
* 设置光标选中的范围
|
|
* @param {Object} from 开始位置的光标键值对象,例:{line:1, ch:0}
|
|
* @param {Object} to 结束位置的光标键值对象,例:{line:1, ch:0}
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
setSelection : function(from, to) {
|
|
|
|
this.codeEditor.setSelection(from, to);
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 获取光标选中的文本
|
|
* @returns {String} 返回选中文本的字符串形式
|
|
*/
|
|
|
|
getSelection : function() {
|
|
return this.codeEditor.getSelection();
|
|
},
|
|
|
|
/**
|
|
* 替换当前光标选中的文本或在当前光标处插入新字符
|
|
* @param {String} value 要插入的字符值
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
replaceSelection : function(value) {
|
|
this.codeEditor.replaceSelection(value);
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 在当前光标处插入新字符
|
|
*
|
|
* 同replaceSelection()方法
|
|
* @param {String} value 要插入的字符值
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
insertValue : function(value) {
|
|
this.replaceSelection(value);
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 设置和传入编辑器的markdown源文档
|
|
* @param {String} md 要传入的markdown源文档
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
setMarkdown : function(md) {
|
|
var settings = this.settings;
|
|
|
|
this.codeEditor.setValue(md);
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 获取编辑器的markdown源文档
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
getMarkdown : function() {
|
|
return this.codeEditor.getValue();
|
|
},
|
|
|
|
/**
|
|
* 清空编辑器
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
clear : function() {
|
|
this.codeEditor.setValue("");
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 获取解析后存放在Textarea的HTML源码
|
|
* @returns {String} 返回HTML源码
|
|
*/
|
|
|
|
getHTML : function() {
|
|
if (!this.settings.saveHTMLToTextarea)
|
|
{
|
|
alert("Error: settings.saveHTMLToTextarea == false");
|
|
|
|
return false;
|
|
}
|
|
|
|
return this.htmlTextarea.html();
|
|
},
|
|
|
|
/**
|
|
* getHTML()的别名
|
|
* @returns {editormd} 返回HTML源码
|
|
*/
|
|
|
|
getTextareaSavedHTML : function() {
|
|
return this.getHTML();
|
|
},
|
|
|
|
/**
|
|
* 获取预览窗口的HTML源码
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
getPreviewedHTML : function() {
|
|
if (!this.settings.watch)
|
|
{
|
|
alert("Error: settings.watch == false");
|
|
|
|
return false;
|
|
}
|
|
|
|
return this.previewContainer.html();
|
|
},
|
|
|
|
/**
|
|
* 开启实时预览
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
watch : function(callback) {
|
|
callback = callback || function() {};
|
|
|
|
this.state.watching = this.settings.watch = true;
|
|
this.preview.show();
|
|
|
|
var watchIcon = this.settings.toolbarIconsClass.watch;
|
|
var unWatchIcon = this.settings.toolbarIconsClass.unwatch;
|
|
var icon = this.toolbar.find(".fa[name=watch]");
|
|
icon.parent().attr("title", this.settings.lang.toolbar.watch);
|
|
icon.removeClass(unWatchIcon).addClass(watchIcon);
|
|
|
|
this.codeMirror.css("border-right", "1px solid #ddd").width(this.editor.width() / 2);
|
|
|
|
this.saveToTextareas().resize();
|
|
|
|
$.proxy(callback, this)();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 关闭实时预览
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
unwatch : function(callback) {
|
|
callback = callback || function() {};
|
|
|
|
this.state.watching = this.settings.watch = false;
|
|
this.preview.hide();
|
|
|
|
var watchIcon = this.settings.toolbarIconsClass.watch;
|
|
var unWatchIcon = this.settings.toolbarIconsClass.unwatch;
|
|
|
|
var icon = this.toolbar.find(".fa[name=watch]");
|
|
icon.parent().attr("title", this.settings.lang.toolbar.unwatch);
|
|
icon.removeClass(watchIcon).addClass(unWatchIcon);
|
|
|
|
this.codeMirror.css("border-right", "none").width(this.editor.width());
|
|
|
|
this.resize();
|
|
|
|
$.proxy(callback, this)();
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 显示编辑器
|
|
* @param {Function} [callback=function()] 回调函数
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
show : function(callback) {
|
|
callback = callback || function() {};
|
|
|
|
var _this = this;
|
|
this.editor.show(function(){
|
|
$.proxy(callback, _this)();
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 隐藏编辑器
|
|
* @param {Function} [callback=function()] 回调函数
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
hide : function(callback) {
|
|
callback = callback || function() {};
|
|
|
|
var _this = this;
|
|
this.editor.hide(function(){
|
|
$.proxy(callback, _this)();
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 隐藏编辑器部分,只预览HTML
|
|
* @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 (settings.toolbar) {
|
|
toolbar.toggle();
|
|
toolbar.find(".fa[name=preview]").toggleClass("active");
|
|
}
|
|
|
|
codeMirror.toggle();
|
|
|
|
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)
|
|
{
|
|
/*var codeEditor = this.codeEditor;
|
|
var previewContainer = this.previewContainer;
|
|
|
|
codeEditor.save();
|
|
|
|
var markdownToC = this.markdownToC = [];
|
|
var newMarkdownDoc = editormd.$marked(codeEditor.getValue(), {renderer : editormd.markedRenderer(markdownToC)});
|
|
previewContainer.html(newMarkdownDoc);
|
|
|
|
if (settings.toc) {
|
|
editormd.markdownToCRenderer(markdownToC, previewContainer, settings.tocStartLevel);
|
|
}*/
|
|
this.saveToTextareas();
|
|
}
|
|
|
|
preview.show().css({
|
|
position : "static",
|
|
top : 0,
|
|
width : editor.width(),
|
|
height : editor.height()
|
|
});
|
|
}
|
|
else
|
|
{
|
|
this.previewed();
|
|
}
|
|
|
|
$(window).keyup(function(event) {
|
|
if (event.keyCode === 27) {
|
|
_this.previewed();
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* 显示编辑器部分,退出只预览HTML
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
previewed : function() {
|
|
|
|
var editor = this.editor;
|
|
var preview = this.preview;
|
|
var toolbar = this.toolbar;
|
|
var settings = this.settings;
|
|
var codeMirror = this.codeMirror;
|
|
var previewCloseBtn = editor.find("." + this.classPrefix + "preview-close-btn");
|
|
|
|
this.state.preview = false;
|
|
|
|
codeMirror.show();
|
|
|
|
if (settings.toolbar) {
|
|
toolbar.show();
|
|
}
|
|
|
|
if(this.settings.watch) {
|
|
preview.show();
|
|
} else {
|
|
preview.hide();
|
|
}
|
|
|
|
previewCloseBtn.hide().bind(editormd.mouseOrTouch("click", "touchend"));
|
|
|
|
preview.css({
|
|
background : null,
|
|
position : "absolute",
|
|
width : editor.width() / 2,
|
|
height : editor.height() - toolbar.height(),
|
|
top : (settings.toolbar) ? toolbar.height() : 0
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 编辑器全屏显示
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
fullscreen : function() {
|
|
|
|
var _this = this;
|
|
var editor = this.editor;
|
|
var preview = this.preview;
|
|
var toolbar = this.toolbar;
|
|
var fullscreenClass = this.classPrefix + "fullscreen";
|
|
|
|
toolbar.find(".fa[name=fullscreen]").parent().toggleClass("active");
|
|
|
|
if (!editor.hasClass(fullscreenClass))
|
|
{
|
|
this.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(this.settings.onfullscreen, this)();
|
|
}
|
|
else
|
|
{
|
|
this.fullscreenExit();
|
|
}
|
|
|
|
$(window).keyup(function(event) {
|
|
if (_this.state.preview) {
|
|
return ;
|
|
}
|
|
|
|
if (event.keyCode === 27) {
|
|
_this.fullscreenExit();
|
|
}
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 编辑器退出全屏显示
|
|
* @returns {editormd} 返回editormd的实例对象
|
|
*/
|
|
|
|
fullscreenExit : function() {
|
|
|
|
var editor = this.editor;
|
|
var fullscreenClass = this.classPrefix + "fullscreen";
|
|
this.state.fullscreen = false;
|
|
|
|
this.toolbar.find(".fa[name=fullscreen]").parent().removeClass("active");
|
|
|
|
$("html,body").css("overflow", "");
|
|
|
|
editor.css({
|
|
position : "",
|
|
top : "",
|
|
left : "",
|
|
margin : "0 auto",
|
|
width : editor.data("oldWidth"),
|
|
height : editor.data("oldHeight"),
|
|
border : "1px solid #ddd"
|
|
}).removeClass(fullscreenClass);
|
|
|
|
this.resize();
|
|
|
|
|
|
$.proxy(this.settings.onfullscreenExit, this)();
|
|
|
|
return this;
|
|
}
|
|
};
|
|
|
|
editormd.fn.init.prototype = editormd.fn;
|
|
|
|
/**
|
|
* 清除字符串两边的空格
|
|
* @param {String} str string
|
|
* @returns {String} trim string
|
|
*/
|
|
|
|
editormd.trim = function(str) {
|
|
return (!String.prototype.trim) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '') : str.trim();
|
|
};
|
|
|
|
var trim = editormd.trim;
|
|
|
|
/**
|
|
* 自定义marked的解析器
|
|
* @param {Array} markdownToC 传入用于接收TOC的数组
|
|
* @returns {Renderer} markedRenderer 返回marked的Renderer自定义对象
|
|
*/
|
|
|
|
editormd.markedRenderer = function(markdownToC) {
|
|
var marked = editormd.$marked;
|
|
var markedRenderer = new marked.Renderer();
|
|
markdownToC = markdownToC || [];
|
|
|
|
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=\"anchor\"></a>";
|
|
headingHTML += "<span class=\"header-link octicon octicon-link\"></span>";
|
|
headingHTML += (hasLinkReg) ? linkText : text;
|
|
headingHTML += "</h" + level + ">";
|
|
|
|
return headingHTML;
|
|
};
|
|
|
|
markedRenderer.paragraph = function(text) {
|
|
var isTeXInline = /\$\$(.*)\$\$/g.test(text);
|
|
var isTeXLine = /^\$\$(.*)\$\$$/.test(text);
|
|
var isTeXAddClass = (isTeXLine) ? " class=\"" + editormd.classNames.tex + "\"" : "";
|
|
var isToC = /^\[TOC\]$/.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;
|
|
}
|
|
|
|
return (isToC) ? "<div class=\"markdown-toc\"><ul class=\"markdown-toc-list\">" + text + "</ul></div>"
|
|
: "<p" + isTeXAddClass + ">" + 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);
|
|
}
|
|
};
|
|
|
|
return markedRenderer;
|
|
};
|
|
|
|
/**
|
|
* 生成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, startLevel) {
|
|
|
|
var html = "";
|
|
var lastLevel = 0;
|
|
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');
|
|
|
|
tocContainer.children('.markdown-toc-list').html("").html(html);
|
|
|
|
return tocContainer;
|
|
};
|
|
|
|
/**
|
|
* 将Markdown文档解析为HTML用于前台显示
|
|
* @param {String} id 用于显示HTML的对象ID
|
|
* @param {Object} [options={}] 配置选项,可选
|
|
* @returns {Object} div 返回jQuery对象元素
|
|
*/
|
|
|
|
editormd.markdownToHTML = function(id, options) {
|
|
options = options || {};
|
|
|
|
var defaults = {
|
|
toc : true,
|
|
tocStartLevel : 2,
|
|
markdown : "",
|
|
htmlDecode : false,
|
|
inRequirejs : false,
|
|
tex : 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");
|
|
var markdownDoc = (settings.markdown === "") ? saveTo.val() : settings.markdown;
|
|
var markdownToC = [];
|
|
|
|
var markedOptions = {
|
|
renderer : editormd.markedRenderer(markdownToC),
|
|
gfm : true,
|
|
tables : true,
|
|
breaks : true,
|
|
pedantic : false,
|
|
sanitize : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签,即是否开启HTML标签解析,为了安全性,默认不开启
|
|
smartLists : true,
|
|
smartypants : true
|
|
};
|
|
|
|
var markdownParsed = marked(markdownDoc, markedOptions);
|
|
|
|
if (editormd.isIE8)
|
|
{
|
|
saveTo.val(markdownDoc);
|
|
}
|
|
else
|
|
{
|
|
saveTo.html(markdownDoc);
|
|
}
|
|
|
|
div.addClass("markdown-body " + this.classPrefix + "html-preview").append(markdownParsed);
|
|
|
|
if (settings.toc) {
|
|
div.tocContainer = this.markdownToCRenderer(markdownToC, div, settings.tocStartLevel);
|
|
}
|
|
|
|
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);
|
|
editormd.$katex.render(tex.html(), tex[0]);
|
|
});
|
|
};
|
|
|
|
if (!settings.inRequirejs) {
|
|
this.loadKaTeX(function(){
|
|
editormd.$katex = katex;
|
|
katexHandle();
|
|
});
|
|
} else {
|
|
katexHandle();
|
|
}
|
|
}
|
|
|
|
div.getMarkdown = function() {
|
|
return (editormd.isIE8) ? saveTo.val() : saveTo.html();
|
|
};
|
|
|
|
return div;
|
|
};
|
|
|
|
// for CodeBlock dialog select
|
|
editormd.codeLanguages = {
|
|
asp : "ASP",
|
|
actionscript : "ActionScript(3.0)/Flash/Flex",
|
|
bash : "Bash/Bat",
|
|
css : "CSS",
|
|
c : "C",
|
|
cpp : "C++",
|
|
csharp : "C#",
|
|
coffeescript : "CoffeeScript",
|
|
d : "D",
|
|
dart : "Dart",
|
|
delphi : "Delphi/Pascal",
|
|
erlang : "Erlang",
|
|
go : "Golang",
|
|
groovy : "Groovy",
|
|
html : "HTML",
|
|
java : "Java",
|
|
json : "JSON",
|
|
javascript : "Javascript",
|
|
lua : "Lua",
|
|
less : "LESS",
|
|
markdown : "Markdown",
|
|
"objective-c" : "Objective-C",
|
|
php : "PHP",
|
|
perl : "Perl",
|
|
python : "Python",
|
|
r : "R",
|
|
rst : "reStructedText",
|
|
ruby : "Ruby",
|
|
sql : "SQL",
|
|
sass : "SASS/SCSS",
|
|
shell : "Shell",
|
|
scala : "Scala",
|
|
swift : "Swift",
|
|
vb : "VB/VBScript",
|
|
xml : "XML",
|
|
yaml : "YAML"
|
|
};
|
|
|
|
// for Requires.js and Gulpfile.js
|
|
editormd.codeMirrorModules = {
|
|
modes : [
|
|
"css",
|
|
"sass",
|
|
"shell",
|
|
"sql",
|
|
"clike",
|
|
"php",
|
|
"xml",
|
|
"markdown",
|
|
"javascript",
|
|
"htmlmixed",
|
|
"gfm",
|
|
"http",
|
|
"go",
|
|
"dart",
|
|
"coffeescript",
|
|
"nginx",
|
|
"python",
|
|
"perl",
|
|
"lua",
|
|
"r",
|
|
"ruby",
|
|
"rst",
|
|
"smartymixed",
|
|
"vb",
|
|
"vbscript",
|
|
"velocity",
|
|
"xquery",
|
|
"yaml",
|
|
"erlang",
|
|
"jade"
|
|
],
|
|
|
|
addons : [
|
|
"edit/trailingspace",
|
|
"dialog/dialog",
|
|
"search/searchcursor",
|
|
"search/search",
|
|
"scroll/annotatescrollbar",
|
|
"search/matchesonscrollbar",
|
|
"display/placeholder",
|
|
"edit/closetag",
|
|
"fold/xml-fold",
|
|
"mode/overlay",
|
|
"selection/active-line",
|
|
"edit/closebrackets",
|
|
"display/fullscreen",
|
|
"search/searchcursor",
|
|
"search/match-highlighter"
|
|
]
|
|
};
|
|
|
|
/**
|
|
* 用于支持Require.js加载的方法,注入
|
|
* @param {Function} CodeMirror CodeMirror对象
|
|
* @param {Function} marked marked对象
|
|
* @param {Function} prettyPrint prettyPrint函数
|
|
*/
|
|
|
|
editormd.requirejsInit = function(CodeMirror, marked, katex, prettyPrint) {
|
|
editormd.$CodeMirror = CodeMirror;
|
|
editormd.$marked = marked;
|
|
editormd.$katex = katex;
|
|
editormd.$prettyPrint = prettyPrint;
|
|
};
|
|
|
|
/**
|
|
* 用于Require.js加载的模块队列
|
|
* @param {String} [loadPath=""] 基本路径,默认为空
|
|
* @returns {Array} modules 返回队列路径数组
|
|
*/
|
|
|
|
editormd.requireModules = function(loadPath) {
|
|
loadPath = loadPath || "";
|
|
var settings = editormd.defaults;
|
|
var modules = [];
|
|
|
|
modules.push(loadPath + "codemirror/codemirror.min");
|
|
|
|
var codeMirrorModules = editormd.codeMirrorModules;
|
|
|
|
for (var i = 0, len = codeMirrorModules.modes.length; i < len; i++)
|
|
{
|
|
var modeName = codeMirrorModules.modes[i];
|
|
modules.push(loadPath + "codemirror/mode/" + modeName + "/" + modeName);
|
|
}
|
|
|
|
for (var i = 0, len = codeMirrorModules.addons.length; i < len; i++)
|
|
{
|
|
var addonName = codeMirrorModules.addons[i];
|
|
modules.push(loadPath + "codemirror/addon/" + addonName);
|
|
}
|
|
|
|
editormd.loadCSS(editormd.katexURL.css);
|
|
|
|
return modules;
|
|
};
|
|
|
|
/**
|
|
* 动态加载CSS文件的方法
|
|
* @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() {
|
|
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文件的方法
|
|
* @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;
|
|
callback();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
else
|
|
{
|
|
script.onload = function() {
|
|
callback();
|
|
};
|
|
}
|
|
|
|
if (into === "head") {
|
|
document.getElementsByTagName("head")[0].appendChild(script);
|
|
} else {
|
|
document.body.appendChild(script);
|
|
}
|
|
};
|
|
|
|
// 使用国外的CDN,加载速度有时会很慢,或者自定义URL
|
|
editormd.katexURL = {
|
|
css : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.1/katex.min",
|
|
js : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.1/katex.min"
|
|
};
|
|
|
|
editormd.kaTeXLoaded = false;
|
|
|
|
/**
|
|
* 加载KaTex文件
|
|
* @param {Function} [callback=function()] 加载成功后执行的回调函数
|
|
*/
|
|
|
|
editormd.loadKaTeX = function (callback) {
|
|
editormd.loadCSS(editormd.katexURL.css, function(){
|
|
editormd.loadScript(editormd.katexURL.js, callback || function(){});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* 鼠标和触摸事件的判断/选择方法
|
|
* @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;
|
|
};
|
|
|
|
/**
|
|
* 日期时间的格式化方法
|
|
* @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;
|
|
|
|
}));
|