Merge pull request #9 from NextStepWebs/development

Autosaving, More options, Split out Font Awesome, Fix bugs
pull/22/head 1.2.0
Wes Cossick 9 years ago
commit 47132fc20a

1
.gitignore vendored

@ -0,0 +1 @@
localtesting/*

@ -6,58 +6,100 @@ A drop-in JavaScript textarea replacement for writing beautiful and understandab
[![Preview](http://i.imgur.com/b9hFHFT.png)](http://nextstepwebs.github.io/simplemde-markdown-editor)
## Quick start
Available on [jsDelivr](http://www.jsdelivr.com/about.php)
SimpleMDE is available on [jsDelivr](http://www.jsdelivr.com/#!simplemde). Font Awesome is available on MaxCDN.
```
```HTML
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">
<script src="//cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
```
And then load SimpleMDE on the first textarea on a page
```
```HTML
<script>
var simplemde = new SimpleMDE();
simplemde.render();
</script>
```
#### Use a specific textarea
Pure JavaScript method
```
```HTML
<script>
var simplemde = new SimpleMDE(document.getElementById("MyID"));
simplemde.render();
</script>
```
jQuery method
```
```HTML
<script>
var simplemde = new SimpleMDE($("#MyID")[0]);
simplemde.render();
</script>
```
## Get the content
```
simplemde.codemirror.getValue();
```JavaScript
simplemde.value();
```
## Configuration
- **element**: The DOM element for the textarea to use. Defaults to the first textarea on the page.
- **status**: If set false, hide the status bar. Defaults to true.
- **tools**: If set false, hide the toolbar. Defaults to true.
- **status**: If set to `false`, hide the status bar. Defaults to `true`.
- Optionally, you can set an array of status bar elements to include, and in what order.
- **toolbar**: If set to `false`, hide the toolbar. Defaults to `true`.
- **autofocus**: If set to `true`, autofocuses the editor. Defaults to `false`.
- **lineWrapping**: If set to `false`, disable line wrapping. Defaults to `true`.
- **indentWithTabs**: If set to `false`, indent using spaces instead of tabs. Defaults to `true`.
- **tabSize**: If set, customize the tab size. Defaults to `2`.
- **autosave**: *Saves the text that's being written. It will forget the text when the form is submitted.*
- **enabled**: If set to `true`, autosave the text. Defaults to `false`.
- **unique_id**: You must set a unique identifier so that SimpleMDE can autosave. Something that separates this from other textareas.
- **delay**: Delay between saves, in milliseconds. Defaults to `10000` (10s).
```JavaScript
var simplemde = new SimpleMDE({
element: document.getElementById("MyID"),
status: false,
status: ['autosave', 'lines', 'words', 'cursor'], // Optional usage
toolbar: false,
autofocus: true,
lineWrapping: false,
indentWithTabs: false,
tabSize: 4,
autosave: {
enabled: true,
unique_id: "MyUniqueID",
delay: 1000,
},
});
```
To change the minimum height (before it starts auto-growing):
```CSS
.CodeMirror {
min-height: 300px;
}
```
new SimpleMDE({
element: document.getElementById("MyID"),
status: false,
tools: false,
});
Or, you can keep the height static:
```CSS
.CodeMirror {
height: 300px;
}
```
## How it works
SimpleMDE is an improvement of [lepture's Editor project](https://github.com/lepture/editor) and includes a great many number of changes. It is bundled with [CodeMirror](https://github.com/codemirror/codemirror) and [Font Awesome](http://fortawesome.github.io/Font-Awesome/).
SimpleMDE is an improvement of [lepture's Editor project](https://github.com/lepture/editor) and includes a great many number of changes. It is bundled with [CodeMirror](https://github.com/codemirror/codemirror) and depends on [Font Awesome](http://fortawesome.github.io/Font-Awesome/).
CodeMirror is the backbone of the project and parses much of the markdown syntax as it's being written. This allows us to add styles to the markdown that's being written. Additionally, a toolbar and status bar has been added to the top and bottom, respectively. Previews are rendered by [Marked](https://github.com/chjj/marked).
@ -74,3 +116,4 @@ As mentioned earlier, SimpleMDE is an improvement of [lepture's Editor project](
- Improved preview rendering in many ways
- Improved as-you-type appearance of headers and code blocks
- Simplified the toolbar
- Many new options during instantiation

7
simplemde.min.css vendored

File diff suppressed because one or more lines are too long

15
simplemde.min.js vendored

File diff suppressed because one or more lines are too long

@ -10,5 +10,4 @@ Minify the JS in this order:
Minify the CSS in this order:
1. `theme.css`
1. `font-awesome.css`
1. `theme.css`

@ -6791,7 +6791,7 @@
// is needed on Webkit to be able to get line-level bounding
// rectangles for it (in measureChar).
var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
var builder = {pre: elt("pre", [content]), content: content,
var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
col: 0, pos: 0, cm: cm,
splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
lineView.measure = {};
@ -8729,7 +8729,7 @@
// THE END
CodeMirror.version = "5.3.1";
CodeMirror.version = "5.4.1";
return CodeMirror;
});

@ -1,51 +1,93 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))(\s*)/,
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)[.)])(\s*)$/,
unorderedListRE = /[*+-]\s/;
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = [];
for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].head;
var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false;
var inQuote = eolState.quote !== 0;
var line = cm.getLine(pos.line), match = listRE.exec(line);
if (!ranges[i].empty() || (!inList && !inQuote) || !match) {
cm.execCommand("newlineAndIndent");
return;
}
if (emptyListRE.test(line)) {
cm.replaceRange("", {
line: pos.line, ch: 0
}, {
line: pos.line, ch: pos.ch + 1
});
replacements[i] = "\n";
} else {
var indent = match[1], after = match[5];
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
? match[2]
: (parseInt(match[3], 10) + 1) + match[4];
replacements[i] = "\n" + indent + bullet + after;
}
}
cm.replaceSelections(replacements);
};
"use strict";
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))(\s*)/,
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)[.)])(\s*)$/,
unorderedListRE = /[*+-]\s/;
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(),
replacements = [];
for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].head;
var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false;
var inQuote = eolState.quote !== 0;
var line = cm.getLine(pos.line),
match = listRE.exec(line);
if (!ranges[i].empty() || (!inList && !inQuote) || !match) {
cm.execCommand("newlineAndIndent");
return;
}
if (emptyListRE.test(line)) {
cm.replaceRange("", {
line: pos.line,
ch: 0
}, {
line: pos.line,
ch: pos.ch + 1
});
replacements[i] = "\n";
} else {
var indent = match[1],
after = match[5];
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 ? match[2] : (parseInt(match[3], 10) + 1) + match[4];
replacements[i] = "\n" + indent + bullet + after;
}
}
cm.replaceSelections(replacements);
};
CodeMirror.commands.shiftTabAndIndentContinueMarkdownList = function(cm) {
var ranges = cm.listSelections();
var pos = ranges[0].head;
var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false;
if (inList) {
cm.execCommand('indentLess');
return;
}
if(cm.options.indentWithTabs){
cm.execCommand('insertTab');
}
else{
var spaces = Array(cm.options.tabSize + 1).join(" ");
cm.replaceSelection(spaces);
}
};
CodeMirror.commands.tabAndIndentContinueMarkdownList = function(cm) {
var ranges = cm.listSelections();
var pos = ranges[0].head;
var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false;
if (inList) {
cm.execCommand('indentMore');
return;
}
if(cm.options.indentWithTabs){
cm.execCommand('insertTab');
}
else{
var spaces = Array(cm.options.tabSize + 1).join(" ");
cm.replaceSelection(spaces);
}
};
});

File diff suppressed because it is too large Load Diff

@ -189,7 +189,7 @@ function drawLink(editor) {
function drawImage(editor) {
var cm = editor.codemirror;
var stat = getState(cm);
_replaceSelection(cm, stat.image, '![Short description of image](http://', ')');
_replaceSelection(cm, stat.image, '![](http://', ')');
}
@ -443,21 +443,22 @@ function SimpleMDE(options) {
if (options.element) {
this.element = options.element;
}
options.toolbar = options.toolbar || SimpleMDE.toolbar;
// you can customize toolbar with object
// [{name: 'bold', shortcut: 'Ctrl-B', className: 'icon-bold'}]
if(options.toolbar === false)
options.toolbar = false;
else
options.toolbar = options.toolbar || SimpleMDE.toolbar;
// you can customize toolbar with object
// [{name: 'bold', shortcut: 'Ctrl-B', className: 'icon-bold'}]
if (!options.hasOwnProperty('status')) {
options.status = ['lines', 'words', 'cursor'];
options.status = ['autosave', 'lines', 'words', 'cursor'];
}
this.options = options;
// If user has passed an element, it should auto rendered
if (this.element) {
this.render();
}
this.render();
}
/**
@ -509,12 +510,12 @@ SimpleMDE.prototype.render = function(el) {
this.codemirror = CodeMirror.fromTextArea(el, {
mode: 'markdown',
theme: 'paper',
tabSize: '2',
indentWithTabs: true,
tabSize: (options.tabSize != undefined) ? options.tabSize : 2,
indentWithTabs: (options.indentWithTabs === false) ? false : true,
lineNumbers: false,
autofocus: false,
autofocus: (options.autofocus === true) ? true : false,
extraKeys: keyMaps,
lineWrapping: true
lineWrapping: (options.lineWrapping === false) ? false : true
});
if (options.toolbar !== false) {
@ -523,10 +524,61 @@ SimpleMDE.prototype.render = function(el) {
if (options.status !== false) {
this.createStatusbar();
}
if (options.autosave != undefined && options.autosave.enabled === true) {
this.autosave();
}
this._rendered = this.element;
};
SimpleMDE.prototype.autosave = function() {
var content = this.value();
var simplemde = this;
if(this.options.autosave.unique_id == undefined || this.options.autosave.unique_id == ""){
console.log("SimpleMDE: You must set a unique_id to use the autosave feature");
return;
}
if(simplemde.element.form != null && simplemde.element.form != undefined){
simplemde.element.form.addEventListener("submit", function(){
localStorage.setItem(simplemde.options.autosave.unique_id, "");
});
}
if(this.options.autosave.loaded !== true){
this.codemirror.setValue(localStorage.getItem(this.options.autosave.unique_id));
this.options.autosave.loaded = true;
}
if(localStorage) {
localStorage.setItem(this.options.autosave.unique_id, content);
}
var el = document.getElementById("autosaved");
if(el != null && el != undefined && el != ""){
var d = new Date();
var hh = d.getHours();
var m = d.getMinutes();
var dd = "am";
var h = hh;
if (h >= 12) {
h = hh-12;
dd = "pm";
}
if (h == 0) {
h = 12;
}
m = m<10?"0"+m:m;
el.innerHTML = "Autosaved: "+h+":"+m+" "+dd;
}
setTimeout(function() {
simplemde.autosave();
}, this.options.autosave.delay || 10000);
};
SimpleMDE.prototype.createToolbar = function(items) {
items = items || this.options.toolbar;
@ -592,6 +644,7 @@ SimpleMDE.prototype.createToolbar = function(items) {
SimpleMDE.prototype.createStatusbar = function(status) {
status = status || this.options.status;
options = this.options;
if (!status || status.length === 0) return;
@ -619,10 +672,15 @@ SimpleMDE.prototype.createStatusbar = function(status) {
pos = cm.getCursor();
el.innerHTML = pos.line + ':' + pos.ch;
});
} else if (name === 'autosave') {
if (options.autosave != undefined && options.autosave.enabled === true) {
el.setAttribute("id", "autosaved");
}
}
bar.appendChild(el);
})(status[i]);
}
var cmWrapper = this.codemirror.getWrapperElement();
cmWrapper.parentNode.insertBefore(bar, cmWrapper.nextSibling);
return bar;

@ -1,6 +1,6 @@
/**
* marked - a markdown parser
* Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
* marked - a markdown parser - v0.3.3
* Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
* https://github.com/chjj/marked
*/
@ -18,9 +18,9 @@ var block = {
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
nptable: noop,
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
table: noop,
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
@ -35,13 +35,18 @@ block.item = replace(block.item, 'gm')
block.list = replace(block.list)
(/bull/g, block.bullet)
('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
('def', '\\n+(?=' + block.def.source + ')')
();
block.blockquote = replace(block.blockquote)
('def', block.def)
();
block._tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
block.html = replace(block.html)
('comment', /<!--[\s\S]*?-->/)
@ -70,8 +75,9 @@ block.normal = merge({}, block);
*/
block.gfm = merge({}, block.normal, {
fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
paragraph: /^/
fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
paragraph: /^/,
heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
});
block.gfm.paragraph = replace(block.paragraph)
@ -141,7 +147,7 @@ Lexer.prototype.lex = function(src) {
* Lexing
*/
Lexer.prototype.token = function(src, top) {
Lexer.prototype.token = function(src, top, bq) {
var src = src.replace(/^ +$/gm, '')
, next
, loose
@ -264,7 +270,7 @@ Lexer.prototype.token = function(src, top) {
// Pass `top` to keep the current
// "toplevel" state. This is exactly
// how markdown.pl works.
this.token(cap, top);
this.token(cap, top, true);
this.tokens.push({
type: 'blockquote_end'
@ -333,7 +339,7 @@ Lexer.prototype.token = function(src, top) {
});
// Recurse.
this.token(item, false);
this.token(item, false, bq);
this.tokens.push({
type: 'list_item_end'
@ -354,14 +360,15 @@ Lexer.prototype.token = function(src, top) {
type: this.options.sanitize
? 'paragraph'
: 'html',
pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
pre: !this.options.sanitizer
&& (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
text: cap[0]
});
continue;
}
// def
if (top && (cap = this.rules.def.exec(src))) {
if ((!bq && top) && (cap = this.rules.def.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.links[cap[1].toLowerCase()] = {
href: cap[2],
@ -514,6 +521,8 @@ function InlineLexer(links, options) {
this.options = options || marked.defaults;
this.links = links;
this.rules = inline.normal;
this.renderer = this.options.renderer || new Renderer;
this.renderer.options = this.options;
if (!this.links) {
throw new
@ -577,43 +586,44 @@ InlineLexer.prototype.output = function(src) {
text = escape(cap[1]);
href = text;
}
out += '<a href="'
+ href
+ '">'
+ text
+ '</a>';
out += this.renderer.link(href, null, text);
continue;
}
// url (gfm)
if (cap = this.rules.url.exec(src)) {
if (!this.inLink && (cap = this.rules.url.exec(src))) {
src = src.substring(cap[0].length);
text = escape(cap[1]);
href = text;
out += '<a href="'
+ href
+ '">'
+ text
+ '</a>';
out += this.renderer.link(href, null, text);
continue;
}
// tag
if (cap = this.rules.tag.exec(src)) {
if (!this.inLink && /^<a /i.test(cap[0])) {
this.inLink = true;
} else if (this.inLink && /^<\/a>/i.test(cap[0])) {
this.inLink = false;
}
src = src.substring(cap[0].length);
out += this.options.sanitize
? escape(cap[0])
: cap[0];
? this.options.sanitizer
? this.options.sanitizer(cap[0])
: escape(cap[0])
: cap[0]
continue;
}
// link
if (cap = this.rules.link.exec(src)) {
src = src.substring(cap[0].length);
this.inLink = true;
out += this.outputLink(cap, {
href: cap[2],
title: cap[3]
});
this.inLink = false;
continue;
}
@ -628,57 +638,51 @@ InlineLexer.prototype.output = function(src) {
src = cap[0].substring(1) + src;
continue;
}
this.inLink = true;
out += this.outputLink(cap, link);
this.inLink = false;
continue;
}
// strong
if (cap = this.rules.strong.exec(src)) {
src = src.substring(cap[0].length);
out += '<strong>'
+ this.output(cap[2] || cap[1])
+ '</strong>';
out += this.renderer.strong(this.output(cap[2] || cap[1]));
continue;
}
// em
if (cap = this.rules.em.exec(src)) {
src = src.substring(cap[0].length);
out += '<em>'
+ this.output(cap[2] || cap[1])
+ '</em>';
out += this.renderer.em(this.output(cap[2] || cap[1]));
continue;
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
out += '<code>'
+ escape(cap[2], true)
+ '</code>';
out += this.renderer.codespan(escape(cap[2], true));
continue;
}
// br
if (cap = this.rules.br.exec(src)) {
src = src.substring(cap[0].length);
out += '<br>';
out += this.renderer.br();
continue;
}
// del (gfm)
if (cap = this.rules.del.exec(src)) {
src = src.substring(cap[0].length);
out += '<del>'
+ this.output(cap[1])
+ '</del>';
out += this.renderer.del(this.output(cap[1]));
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
src = src.substring(cap[0].length);
out += escape(this.smartypants(cap[0]));
out += this.renderer.text(escape(this.smartypants(cap[0])));
continue;
}
@ -696,31 +700,12 @@ InlineLexer.prototype.output = function(src) {
*/
InlineLexer.prototype.outputLink = function(cap, link) {
if (cap[0].charAt(0) !== '!') {
return '<a href="'
+ escape(link.href)
+ '"'
+ (link.title
? ' title="'
+ escape(link.title)
+ '"'
: '')
+ '>'
+ this.output(cap[1])
+ '</a>';
} else {
return '<img src="'
+ escape(link.href)
+ '" alt="'
+ escape(cap[1])
+ '"'
+ (link.title
? ' title="'
+ escape(link.title)
+ '"'
: '')
+ '>';
}
var href = escape(link.href)
, title = link.title ? escape(link.title) : null;
return cap[0].charAt(0) !== '!'
? this.renderer.link(href, title, this.output(cap[1]))
: this.renderer.image(href, title, escape(cap[1]));
};
/**
@ -731,7 +716,9 @@ InlineLexer.prototype.smartypants = function(text) {
if (!this.options.smartypants) return text;
return text
// em-dashes
.replace(/--/g, '\u2014')
.replace(/---/g, '\u2014')
// en-dashes
.replace(/--/g, '\u2013')
// opening singles
.replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
// closing singles & apostrophes
@ -749,6 +736,7 @@ InlineLexer.prototype.smartypants = function(text) {
*/
InlineLexer.prototype.mangle = function(text) {
if (!this.options.mangle) return text;
var out = ''
, l = text.length
, i = 0
@ -765,6 +753,153 @@ InlineLexer.prototype.mangle = function(text) {
return out;
};
/**
* Renderer
*/
function Renderer(options) {
this.options = options || {};
}
Renderer.prototype.code = function(code, lang, escaped) {
if (this.options.highlight) {
var out = this.options.highlight(code, lang);
if (out != null && out !== code) {
escaped = true;
code = out;
}
}
if (!lang) {
return '<pre><code>'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>';
}
return '<pre><code class="'
+ this.options.langPrefix
+ escape(lang, true)
+ '">'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>\n';
};
Renderer.prototype.blockquote = function(quote) {
return '<blockquote>\n' + quote + '</blockquote>\n';
};
Renderer.prototype.html = function(html) {
return html;
};
Renderer.prototype.heading = function(text, level, raw) {
return '<h'
+ level
+ ' id="'
+ this.options.headerPrefix
+ raw.toLowerCase().replace(/[^\w]+/g, '-')
+ '">'
+ text
+ '</h'
+ level
+ '>\n';
};
Renderer.prototype.hr = function() {
return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
};
Renderer.prototype.list = function(body, ordered) {
var type = ordered ? 'ol' : 'ul';
return '<' + type + '>\n' + body + '</' + type + '>\n';
};
Renderer.prototype.listitem = function(text) {
return '<li>' + text + '</li>\n';
};
Renderer.prototype.paragraph = function(text) {
return '<p>' + text + '</p>\n';
};
Renderer.prototype.table = function(header, body) {
return '<table>\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ '<tbody>\n'
+ body
+ '</tbody>\n'
+ '</table>\n';
};
Renderer.prototype.tablerow = function(content) {
return '<tr>\n' + content + '</tr>\n';
};
Renderer.prototype.tablecell = function(content, flags) {
var type = flags.header ? 'th' : 'td';
var tag = flags.align
? '<' + type + ' style="text-align:' + flags.align + '">'
: '<' + type + '>';
return tag + content + '</' + type + '>\n';
};
// span level renderer
Renderer.prototype.strong = function(text) {
return '<strong>' + text + '</strong>';
};
Renderer.prototype.em = function(text) {
return '<em>' + text + '</em>';
};
Renderer.prototype.codespan = function(text) {
return '<code>' + text + '</code>';
};
Renderer.prototype.br = function() {
return this.options.xhtml ? '<br/>' : '<br>';
};
Renderer.prototype.del = function(text) {
return '<del>' + text + '</del>';
};
Renderer.prototype.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 || prot.indexOf('vbscript:') === 0) {
return '';
}
}
var out = '<a href="' + href + '"';
if (title) {
out += ' title="' + title + '"';
}
out += '>' + text + '</a>';
return out;
};
Renderer.prototype.image = function(href, title, text) {
var out = '<img src="' + href + '" alt="' + text + '"';
if (title) {
out += ' title="' + title + '"';
}
out += this.options.xhtml ? '/>' : '>';
return out;
};
Renderer.prototype.text = function(text) {
return text;
};
/**
* Parsing & Compiling
*/
@ -773,14 +908,17 @@ function Parser(options) {
this.tokens = [];
this.token = null;
this.options = options || marked.defaults;
this.options.renderer = this.options.renderer || new Renderer;
this.renderer = this.options.renderer;
this.renderer.options = this.options;
}
/**
* Static Parse Method
*/
Parser.parse = function(src, options) {
var parser = new Parser(options);
Parser.parse = function(src, options, renderer) {
var parser = new Parser(options, renderer);
return parser.parse(src);
};
@ -789,7 +927,7 @@ Parser.parse = function(src, options) {
*/
Parser.prototype.parse = function(src) {
this.inline = new InlineLexer(src.links, this.options);
this.inline = new InlineLexer(src.links, this.options, this.renderer);
this.tokens = src.reverse();
var out = '';
@ -840,83 +978,53 @@ Parser.prototype.tok = function() {
return '';
}
case 'hr': {
return '<hr>\n';
return this.renderer.hr();
}
case 'heading': {
return '<h'
+ this.token.depth
+ ' id="'
+ this.token.text.toLowerCase().replace(/[^\w]+/g, '-')
+ '">'
+ this.inline.output(this.token.text)
+ '</h'
+ this.token.depth
+ '>\n';
return this.renderer.heading(
this.inline.output(this.token.text),
this.token.depth,
this.token.text);
}
case 'code': {
if (this.options.highlight) {
var code = this.options.highlight(this.token.text, this.token.lang);
if (code != null && code !== this.token.text) {
this.token.escaped = true;
this.token.text = code;
}
}
if (!this.token.escaped) {
this.token.text = escape(this.token.text, true);
}
return '<pre><code'
+ (this.token.lang
? ' class="'
+ this.options.langPrefix
+ this.token.lang
+ '"'
: '')
+ '>'
+ this.token.text
+ '</code></pre>\n';
return this.renderer.code(this.token.text,
this.token.lang,
this.token.escaped);
}
case 'table': {
var body = ''
, heading
var header = ''
, body = ''
, i
, row
, cell
, flags
, j;
// header
body += '<thead>\n<tr>\n';
cell = '';
for (i = 0; i < this.token.header.length; i++) {
heading = this.inline.output(this.token.header[i]);
body += '<th';
if (this.token.align[i]) {
body += ' style="text-align:' + this.token.align[i] + '"';
}
body += '>' + heading + '</th>\n';
flags = { header: true, align: this.token.align[i] };
cell += this.renderer.tablecell(
this.inline.output(this.token.header[i]),
{ header: true, align: this.token.align[i] }
);
}
body += '</tr>\n</thead>\n';
header += this.renderer.tablerow(cell);
// body
body += '<tbody>\n'
for (i = 0; i < this.token.cells.length; i++) {
row = this.token.cells[i];
body += '<tr>\n';
cell = '';
for (j = 0; j < row.length; j++) {
cell = this.inline.output(row[j]);
body += '<td';
if (this.token.align[j]) {
body += ' style="text-align:' + this.token.align[j] + '"';
}
body += '>' + cell + '</td>\n';
cell += this.renderer.tablecell(
this.inline.output(row[j]),
{ header: false, align: this.token.align[j] }
);
}
body += '</tr>\n';
}
body += '</tbody>\n';
return '<table>\n'
+ body
+ '</table>\n';
body += this.renderer.tablerow(cell);
}
return this.renderer.table(header, body);
}
case 'blockquote_start': {
var body = '';
@ -925,25 +1033,17 @@ Parser.prototype.tok = function() {
body += this.tok();
}
return '<blockquote>\n'
+ body
+ '</blockquote>\n';
return this.renderer.blockquote(body);
}
case 'list_start': {
var type = this.token.ordered ? 'ol' : 'ul'
, body = '';
var body = ''
, ordered = this.token.ordered;
while (this.next().type !== 'list_end') {
body += this.tok();
}
return '<'
+ type
+ '>\n'
+ body
+ '</'
+ type
+ '>\n';
return this.renderer.list(body, ordered);
}
case 'list_item_start': {
var body = '';
@ -954,9 +1054,7 @@ Parser.prototype.tok = function() {
: this.tok();
}
return '<li>'
+ body
+ '</li>\n';
return this.renderer.listitem(body);
}
case 'loose_item_start': {
var body = '';
@ -965,24 +1063,19 @@ Parser.prototype.tok = function() {
body += this.tok();
}
return '<li>'
+ body
+ '</li>\n';
return this.renderer.listitem(body);
}
case 'html': {
return !this.token.pre && !this.options.pedantic
var html = !this.token.pre && !this.options.pedantic
? this.inline.output(this.token.text)
: this.token.text;
return this.renderer.html(html);
}
case 'paragraph': {
return '<p>'
+ this.inline.output(this.token.text)
+ '</p>\n';
return this.renderer.paragraph(this.inline.output(this.token.text));
}
case 'text': {
return '<p>'
+ this.parseText()
+ '</p>\n';
return this.renderer.paragraph(this.parseText());
}
}
};
@ -1000,6 +1093,19 @@ function escape(html, encode) {
.replace(/'/g, '&#39;');
}
function unescape(html) {
return html.replace(/&([#\w]+);/g, function(_, n) {
n = n.toLowerCase();
if (n === 'colon') return ':';
if (n.charAt(0) === '#') {
return n.charAt(1) === 'x'
? String.fromCharCode(parseInt(n.substring(2), 16))
: String.fromCharCode(+n.substring(1));
}
return '';
});
}
function replace(regex, opt) {
regex = regex.source;
opt = opt || '';
@ -1032,6 +1138,7 @@ function merge(obj) {
return obj;
}
/**
* Marked
*/
@ -1058,8 +1165,13 @@ function marked(src, opt, callback) {
pending = tokens.length;
var done = function() {
var out, err;
var done = function(err) {
if (err) {
opt.highlight = highlight;
return callback(err);
}
var out;
try {
out = Parser.parse(tokens, opt);
@ -1088,6 +1200,7 @@ function marked(src, opt, callback) {
return --pending || done();
}
return highlight(token.text, token.lang, function(err, code) {
if (err) return done(err);
if (code == null || code === token.text) {
return --pending || done();
}
@ -1130,11 +1243,16 @@ marked.defaults = {
breaks: false,
pedantic: false,
sanitize: false,
sanitizer: null,
mangle: true,
smartLists: false,
silent: false,
highlight: null,
langPrefix: 'lang-',
smartypants: false
smartypants: false,
headerPrefix: '',
renderer: new Renderer,
xhtml: false
};
/**
@ -1144,6 +1262,8 @@ marked.defaults = {
marked.Parser = Parser;
marked.parser = Parser.parse;
marked.Renderer = Renderer;
marked.Lexer = Lexer;
marked.lexer = Lexer.lex;
@ -1152,7 +1272,7 @@ marked.inlineLexer = InlineLexer.output;
marked.parse = marked;
if (typeof exports === 'object') {
if (typeof module !== 'undefined' && typeof exports === 'object') {
module.exports = marked;
} else if (typeof define === 'function' && define.amd) {
define(function() { return marked; });

@ -4,27 +4,32 @@
border: 1px solid #ddd;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
padding: 10px
padding: 10px;
}
.CodeMirror-scroll {
min-height: 300px;
min-height: 300px
}
:-webkit-full-screen {
background: #f9f9f5;
padding: .5em 1em;
width: 100%;
height: 100%
height: 100%;
}
:-moz-full-screen {
padding: .5em 1em;
background: #f9f9f5;
width: 100%;
height: 100%
height: 100%;
}
.editor-wrapper {
font: 16px/1.62 "Helvetica Neue", "Xin Gothic", "Hiragino Sans GB", "WenQuanYi Micro Hei", "Microsoft YaHei", sans-serif;
color: #2c3e50
color: #2c3e50;
}
.editor-wrapper input.title {
font: 18px "Helvetica Neue", "Xin Gothic", "Hiragino Sans GB", "WenQuanYi Micro Hei", "Microsoft YaHei", sans-serif;
background: 0 0;
@ -32,8 +37,9 @@
width: 100%;
border: none;
outline: 0;
opacity: .6
opacity: .6;
}
.editor-toolbar {
position: relative;
opacity: .6;
@ -47,25 +53,27 @@
border-left: 1px solid #bbb;
border-right: 1px solid #bbb;
border-top-left-radius: 4px;
border-top-right-radius: 4px
border-top-right-radius: 4px;
}
.editor-toolbar:after,
.editor-toolbar:before {
.editor-toolbar:after, .editor-toolbar:before {
display: block;
content: ' ';
height: 1px
height: 1px;
}
.editor-toolbar:before {
margin-bottom: 8px
}
.editor-toolbar:after {
margin-top: 8px
}
.editor-toolbar:hover,
.editor-wrapper input.title:focus,
.editor-wrapper input.title:hover {
.editor-toolbar:hover, .editor-wrapper input.title:focus, .editor-wrapper input.title:hover {
opacity: .8
}
.editor-toolbar a {
display: inline-block;
text-align: center;
@ -76,16 +84,18 @@
margin: 0;
border: 1px solid transparent;
border-radius: 3px;
cursor: pointer
cursor: pointer;
}
.editor-toolbar a.active,
.editor-toolbar a:hover {
.editor-toolbar a.active, .editor-toolbar a:hover {
background: #fcfcfc;
border-color: #95a5a6
border-color: #95a5a6;
}
.editor-toolbar a:before {
line-height: 30px
}
.editor-toolbar i.separator {
display: inline-block;
width: 0;
@ -93,34 +103,41 @@
border-right: 1px solid #fff;
color: transparent;
text-indent: -10px;
margin: 0 6px
margin: 0 6px;
}
.editor-toolbar a.icon-fullscreen {
position: absolute;
right: 10px
right: 10px;
}
.editor-toolbar.disabled-for-preview a:not(.fa-eye){
pointer-events:none;
background:#fff;
border:none;
.editor-toolbar.disabled-for-preview a:not(.fa-eye) {
pointer-events: none;
background: #fff;
border: none;
}
.editor-statusbar {
padding: 8px 10px;
font-size: 12px;
color: #959694;
text-align: right
text-align: right;
}
.editor-statusbar span {
display: inline-block;
min-width: 4em;
margin-left: 1em
margin-left: 1em;
}
.editor-statusbar .lines:before {
content: 'lines: '
}
.editor-statusbar .words:before {
content: 'words: '
}
.editor-preview {
padding: 10px;
position: absolute;
@ -131,133 +148,172 @@
background: #fafafa;
z-index: 9999;
overflow: auto;
display: none
display: none;
}
.editor-preview-active {
display: block
}
.editor-preview>p {
margin-top: 0
}
.editor-preview pre {
background: #eee;
margin-bottom: 10px
margin-bottom: 10px;
}
.editor-preview table td, table th {
border: 1px solid #ddd;
padding: 5px;
}
.CodeMirror-scroll {
overflow: auto
}
.CodeMirror-lines {
padding: 4px 0
}
.CodeMirror pre {
padding: 0 4px
}
.CodeMirror-scrollbar-filler {
background-color: #fff
}
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid #000;
z-index: 3
z-index: 3;
}
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
z-index: 1
z-index: 1;
}
.cm-s-paper .cm-keyword {
color: #555
}
.cm-s-paper .cm-atom,
.cm-s-paper .cm-number {
.cm-s-paper .cm-atom, .cm-s-paper .cm-number {
color: #7f8c8d
}
.cm-s-paper .cm-def {
color: #00f
}
.cm-s-paper .cm-variable {
color: #000
}
.cm-s-paper .cm-variable-2 {
color: #555
}
.cm-s-paper .cm-variable-3 {
color: #085
}
.cm-s-paper .cm-operator,
.cm-s-paper .cm-property {
.cm-s-paper .cm-operator, .cm-s-paper .cm-property {
color: #000
}
.cm-s-paper .cm-comment {
color: #959595
}
.cm-s-paper .cm-string {
color: #7f8c8d
}
.cm-s-paper .cm-string-2 {
color: #f50
}
.cm-s-paper .cm-meta {
color: #555
}
.cm-s-paper .cm-error {
color: red
}
.cm-s-paper .cm-builtin,
.cm-s-paper .cm-qualifier {
.cm-s-paper .cm-builtin, .cm-s-paper .cm-qualifier {
color: #555
}
.cm-s-paper .cm-bracket {
color: #997
}
.cm-s-paper .cm-attribute,
.cm-s-paper .cm-tag {
.cm-s-paper .cm-attribute, .cm-s-paper .cm-tag {
color: #7f8c8d
}
.cm-s-paper .cm-header {
color: #000
}
.cm-s-paper .cm-quote {
color: #888
}
.cm-s-paper .cm-hr {
color: #999
}
.cm-s-paper .cm-link {
color: #7f8c8d
}
.cm-negative {
color: #d44
}
.cm-positive {
color: #292
}
.cm-header,
.cm-strong {
.cm-header, .cm-strong {
font-weight: 700
}
.cm-em {
font-style: italic
}
.cm-link {
text-decoration: underline
}
.cm-invalidchar {
color: red
}
div.CodeMirror span.CodeMirror-matchingbracket {
color: #0f0
}
div.CodeMirror span.CodeMirror-nonmatchingbracket {
color: #f22
}
.CodeMirror {
position: relative;
overflow: hidden
overflow: hidden;
}
.CodeMirror-scroll {
margin-bottom: -30px;
margin-right: -30px;
@ -266,38 +322,43 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {
height: 100%;
min-height: 300px;
outline: 0;
position: relative
position: relative;
}
.CodeMirror-sizer {
position: relative
}
.CodeMirror-hscrollbar,
.CodeMirror-scrollbar-filler,
.CodeMirror-vscrollbar {
.CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar {
position: absolute;
z-index: 6;
display: none
display: none;
}
.CodeMirror-vscrollbar {
right: 0;
top: 0;
overflow-x: hidden;
overflow-y: scroll
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0;
left: 0;
overflow-y: hidden;
overflow-x: scroll
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0;
bottom: 0;
z-index: 6
z-index: 6;
}
.CodeMirror-lines {
cursor: text
}
.CodeMirror pre {
-moz-border-radius: 0;
-webkit-border-radius: 0;
@ -308,89 +369,107 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre-wrap;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 0
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto
overflow: auto;
}
.CodeMirror-widget {
display: inline-block
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden
visibility: hidden;
}
.CodeMirror-measure pre {
position: static
}
.CodeMirror div.CodeMirror-cursor {
position: absolute;
visibility: hidden;
border-right: none;
width: 0
width: 0;
}
.CodeMirror-focused div.CodeMirror-cursor {
visibility: visible
}
.CodeMirror-selected {
background: #d9d9d9
}
.CodeMirror-focused .CodeMirror-selected {
background: #BDC3C7
}
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4)
background: rgba(255, 255, 0, .4);
}
@media print {
.CodeMirror div.CodeMirror-cursor {
visibility: hidden
}
}
.CodeMirror .CodeMirror-code .cm-header-1 {
font-size: 200%;
line-height: 200%
line-height: 200%;
}
.CodeMirror .CodeMirror-code .cm-header-2 {
font-size: 160%;
line-height: 160%
line-height: 160%;
}
.CodeMirror .CodeMirror-code .cm-header-3 {
font-size: 125%;
line-height: 125%
line-height: 125%;
}
.CodeMirror .CodeMirror-code .cm-header-4 {
font-size: 110%;
line-height: 110%
line-height: 110%;
}
.CodeMirror .CodeMirror-code .cm-comment {
background: #eee;
border-radius: 2px
border-radius: 2px;
}
Loading…
Cancel
Save