-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
69ff2a5
commit a99c30a
Showing
1 changed file
with
164 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<link rel="stylesheet" href="https://cdn.rawgit.com/Chalarangelo/mini.css/v2.1.0/dist/mini-default.min.css"/> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/> | ||
<title>Parse-MD.js</title> | ||
<meta charset="utf-8"/> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"/> | ||
<meta name="description" content="A regular expression Markdown parser, written in functional Javascript."/> | ||
<meta name="author" content="Angelos Chalaris (chalarangelo)"/> | ||
<meta property="og:title" content="Parse-MD.js"/> | ||
<meta property="og:type" content="website"/> | ||
<meta property="og:description" content="A regular expression Markdown parser, written in functional Javascript."/> | ||
</head> | ||
|
||
<body> | ||
<div class="row"> | ||
<div class="col-sm col-lg-10 col-lg-offset-1"> | ||
<br /> | ||
<h1 style="text-align: center; font-size: 3.5em;">Parse-MD.js<small style="font-size: 33%;">Regex-based Markdown parser in functional JS</small></h1> | ||
<br/> | ||
<p style="text-align: center;"><a href="https://github.com/Chalarangelo/parse-md-js" class="button primary large"><i class="fa fa-github fa-2x"></i><span style="font-size: 150%;"> Github</span></a></p> | ||
<br /> | ||
<div class="card fluid"> | ||
<div class="section double-padded"><h2>Introduction & Usage</h2></div> | ||
<div class="section double-padded"><p><strong>Parse-MD.js</strong> is a really simple tool that converts Markdown to HTML. It's built using regular expressions in combination with functional Javascript. It's really tiny (about 100 lines of code) and can be easily extended by adding more regular expressions. Most major Markdown syntax features are supported (with the exception of tables, that are a little bit tricky to implement using regular expressions). To check the recognized syntax rules, have a look at the <a href="https://github.com/Chalarangelo/parse-md-js/blob/master/README.md">README</a>.</p></div> | ||
<div class="section double-padded"><p>To use the parser, just grab the javascript code from <a href="https://github.com/Chalarangelo/parse-md-js/blob/master/parsemd.js">here</a> and simply call</p><pre>var parsedMD = parseMarkdown(yourMarkdownVar);</pre><p>for the parser to parse the contents of <code>yourMarkdownVar</code> into <code>parsedMD</code> as HTML.</p></div> | ||
</div> | ||
</div> | ||
<div class="col-sm col-lg-10 col-lg-offset-1"> | ||
<div class="card fluid"> | ||
<div class="section double-padded"><h2>Convert some Markdown!</h2></div> | ||
<div class="section double-padded"><p>Actions speak louder than words, right? Well, let's see it at work thne! Enter some valid Markdown text in the input field below, then press the button below it to convert it to HTML instantly!</p></div> | ||
<textarea id="markdownIn" style="height: 200px;" class="section media double-padded" autocomplete="off"># Sample heading | ||
|
||
This is a sample paragraph with a [link](https://github.com/Chalarangelo/parse-md-js) and some `inline code`. | ||
|
||
--- | ||
|
||
Maybe you would like to see some **bold text** or some *italics*, huh?</textarea> | ||
<div class="tabs stacked hidden" id="markdownOutCollapseWrapper"> | ||
<input type="checkbox" id="markdownOutCollapse" aria-hidden="true" checked autocomplete="off"> | ||
<label for="markdownOutCollapse" aria-hidden="true">Show/hide results</label> | ||
<div id="markdownOut"> | ||
</div> | ||
</div> | ||
<button class="section primary large" onClick="document.getElementById('markdownOutCollapseWrapper').className='tabs stacked'; document.getElementById('markdownOut').innerHTML = parseMarkdown(document.getElementById('markdownIn').value);">Convert</button> | ||
</div> | ||
<br/><br/><br /> | ||
</div> | ||
</div> | ||
<footer> | ||
<div class="container"> | ||
<div class="row"> | ||
<div class="col-sm col-lg-10 col-lg-offset-1"> | ||
<p>Made with <i class="fa fa-heart-o" aria-hidden="true"></i> by Angelos Chalaris, licensed under the <a href="https://github.com/Chalarangelo/parse-md-js/blob/master/LICENSE">MIT license</a>.</p> | ||
</div> | ||
</div> | ||
</div> | ||
</footer> | ||
|
||
<script> | ||
/*** Regex Markdown Parser by chalarangelo ***/ | ||
// Replaces 'regex' with 'replacement' in 'str' | ||
// Curry function, usage: replaceRegex(regexVar, replacementVar) (strVar) | ||
const replaceRegex = function(regex, replacement){ | ||
return function(str){ | ||
return str.replace(regex, replacement); | ||
} | ||
} | ||
// Regular expressions for Markdown (a bit strict, but they work) | ||
const codeBlockRegex = /((\n\t)(.*))+/g; | ||
const inlineCodeRegex = /(`)(.*?)\1/g; | ||
const imageRegex = /!\[([^\[]+)\]\(([^\)]+)\)/g; | ||
const linkRegex = /\[([^\[]+)\]\(([^\)]+)\)/g; | ||
const headingRegex = /\n(#+\s*)(.*)/g; | ||
const boldItalicsRegex = /(\*{1,2})(.*?)\1/g; | ||
const strikethroughRegex = /(\~\~)(.*?)\1/g; | ||
const blockquoteRegex = /\n(>|\>)(.*)/g; | ||
const horizontalRuleRegex = /\n((\-{3,})|(={3,}))/g; | ||
const unorderedListRegex = /(\n\s*(\-|\+)\s.*)+/g; | ||
const orderedListRegex = /(\n\s*([0-9]+\.)\s.*)+/g; | ||
const paragraphRegex = /\n+(?!<pre>)(?!<h)(?!<ul>)(?!<blockquote)(?!<hr)(?!\t)([^\n]+)\n/g; | ||
// Replacer functions for Markdown | ||
const codeBlockReplacer = function(fullMatch){ | ||
return '\n<pre>' + fullMatch + '</pre>'; | ||
} | ||
const inlineCodeReplacer = function(fullMatch, tagStart, tagContents){ | ||
return '<code>' + tagContents + '</code>'; | ||
} | ||
const imageReplacer = function(fullMatch, tagTitle, tagURL){ | ||
return '<img src="' + tagURL + '" alt="' + tagTitle + '" />'; | ||
} | ||
const linkReplacer = function(fullMatch, tagTitle, tagURL){ | ||
return '<a href="' + tagURL + '">' + tagTitle + '</a>'; | ||
} | ||
const headingReplacer = function(fullMatch, tagStart, tagContents){ | ||
return '\n<h' + tagStart.trim().length + '>' + tagContents + '</h' + tagStart.trim().length + '>'; | ||
} | ||
const boldItalicsReplacer = function(fullMatch, tagStart, tagContents){ | ||
return '<' + ( (tagStart.trim().length==1)?('em'):('strong') ) + '>'+ tagContents + '</' + ( (tagStart.trim().length==1)?('em'):('strong') ) + '>'; | ||
} | ||
const strikethroughReplacer = function(fullMatch, tagStart, tagContents){ | ||
return '<del>' + tagContents + '</del>'; | ||
} | ||
const blockquoteReplacer = function(fullMatch, tagStart, tagContents){ | ||
return '\n<blockquote>' + tagContents + '</blockquote>'; | ||
} | ||
const horizontalRuleReplacer = function(fullMatch){ | ||
return '\n<hr />'; | ||
} | ||
const unorderedListReplacer = function(fullMatch){ | ||
let items = ''; | ||
fullMatch.trim().split('\n').forEach( item => { items += '<li>' + item.substring(2) + '</li>'; } ); | ||
return '\n<ul>' + items + '</ul>'; | ||
} | ||
const orderedListReplacer = function(fullMatch){ | ||
let items = ''; | ||
fullMatch.trim().split('\n').forEach( item => { items += '<li>' + item.substring(item.indexOf('.')+2) + '</li>'; } ); | ||
return '\n<ol>' + items + '</ol>'; | ||
} | ||
const paragraphReplacer = function(fullMatch, tagContents){ | ||
return '<p>' + tagContents + '</p>'; | ||
} | ||
// Rules for Markdown parsing (use in order of appearance for best results) | ||
const replaceCodeBlocks = replaceRegex(codeBlockRegex, codeBlockReplacer); | ||
const replaceInlineCodes = replaceRegex(inlineCodeRegex, inlineCodeReplacer); | ||
const replaceImages = replaceRegex(imageRegex, imageReplacer); | ||
const replaceLinks = replaceRegex(linkRegex, linkReplacer); | ||
const replaceHeadings = replaceRegex(headingRegex, headingReplacer); | ||
const replaceBoldItalics = replaceRegex(boldItalicsRegex, boldItalicsReplacer); | ||
const replaceceStrikethrough = replaceRegex(strikethroughRegex, strikethroughReplacer); | ||
const replaceBlockquotes = replaceRegex(blockquoteRegex, blockquoteReplacer); | ||
const replaceHorizontalRules = replaceRegex(horizontalRuleRegex, horizontalRuleReplacer); | ||
const replaceUnorderedLists = replaceRegex(unorderedListRegex, unorderedListReplacer); | ||
const replaceOrderedLists = replaceRegex(orderedListRegex, orderedListReplacer); | ||
const replaceParagraphs = replaceRegex(paragraphRegex, paragraphReplacer); | ||
// Fix for tab-indexed code blocks | ||
const codeBlockFixRegex = /\n(<pre>)((\n|.)*)(<\/pre>)/g; | ||
const codeBlockFixer = function(fullMatch, tagStart, tagContents, lastMatch, tagEnd){ | ||
let lines = ''; | ||
tagContents.split('\n').forEach( line => { lines += line.substring(1) + '\n'; } ); | ||
return tagStart + lines + tagEnd; | ||
} | ||
const fixCodeBlocks = replaceRegex(codeBlockFixRegex, codeBlockFixer); | ||
// Replacement rule order function for Markdown | ||
// Do not use as-is, prefer parseMarkdown as seen below | ||
const replaceMarkdown = function(str) { | ||
return replaceParagraphs(replaceOrderedLists(replaceUnorderedLists( | ||
replaceHorizontalRules(replaceBlockquotes(replaceceStrikethrough( | ||
replaceBoldItalics(replaceHeadings(replaceLinks(replaceImages( | ||
replaceInlineCodes(replaceCodeBlocks(str)) | ||
)))) | ||
))) | ||
))); | ||
} | ||
// Parser for Markdown (fixes code, adds empty lines around for parsing) | ||
// Usage: parseMarkdown(strVar) | ||
const parseMarkdown = function(str) { | ||
return fixCodeBlocks(replaceMarkdown('\n' + str + '\n')).trim(); | ||
} | ||
|
||
</script> | ||
</body> |