' + block + '
'
116 | }
117 | ~~~
118 |
119 | #### Extend Parser for enhanced syntax
120 |
121 | to parse every markdown-block, dummy function md.before() and md.after() will be called
122 | (i.e. ``md.after( md.parser( md.before(mdText) ) )``).
123 |
124 | They can be re-defined for enhanced syntax. for example,
125 |
126 | ~~~
127 | // original code in casual-markdown.js
128 | var md = { before: function (str) {return str}, after: function (str) {return str} }
129 |
130 | // re-define for extend syntax. e.g. $text$ => text
131 | md.before = function (str) {
132 | return mdstr = mdstr.replace(/\$(\w.*?[^\\])\$/gm, '$1')
133 | }
134 |
135 | // re-define for extend syntax. e.g. $$text$$ => text
136 | md.after = function (str) {
137 | return mdstr = mdstr.replace(/\$\$(\w.*?[^\\])\$\$/gm, '$1')
138 | }
139 |
140 | document.getElementById('content').innerHTML = md.html()
141 | ~~~
142 |
143 | ### Frontmatter for simple YAML
144 |
145 | Support frontmatter for simple YAML, only support string value (with 2 level ) meanwhile.
146 |
147 | Frontmatter start with `---` (at least three) in first line of markdown document, for example
148 |
149 | ```
150 | -----------------------------------------------------------------------------
151 | title : Markdown-as-Page
152 | style : #header { background: RoyalBlue }
153 | menu :
154 | Home : index.md
155 | Supported Syntax: md-syntax.md
156 | md-as-Doc : md-as-doc.md
157 | md-as-Page : md-as-page.md
158 | md-as-Blog : md-as-blog.md
159 | [DarkMode] : javascript:darkmode()
160 | -----------------------------------------------------------------------------
161 |
162 | ## {{ title }}
163 |
164 | ....
165 | ```
166 |
167 | After called md.html(), js program may refer these values by `md.yaml[name]` (i.e. md.yaml = { title:'Markdown-as-Page', .... })
168 | and html string with ``{{ name }}`` will be replaced with related values
169 |
170 |
171 | ### Applications
172 |
173 | * Markdown-as-Document: https://github.com/casualwriter/casual-markdown-doc
174 | * Markdown-as-WebPage: https://github.com/casualwriter/casual-markdown-page
175 | * Markdown-as-Blog: https://github.com/casualwriter/casual-markdown-blog (not ready yet!)
176 |
177 |
178 | ### Update History
179 |
180 | * 2022/07/19, v0.80, initial release.
181 | * 2022/07/21, v0.82, refine toc/scrollspy, add dummy function for extension
182 | * 2022/07/22, v0.85, frontmatter for simple YAML
183 | * 2022/07/31, v0.90, refine frontmatter. code casual-markdown-doc.js, casual-markdown-page.html
184 | * 2023/04/12, v0.92, add copy feature for code-block. minor fine-tune.
185 |
186 |
--------------------------------------------------------------------------------
/dist/casual-markdown-doc.css:
--------------------------------------------------------------------------------
1 | /* ==== copy from casual-markdown.css ==== */
2 | .markdown code { background:#f0f0f0; color:navy; border-radius:2px; padding:2px; }
3 | .markdown pre { background:#f0f0f0; margin:16px; border:1px solid #ddd; padding:8px; }
4 | .markdown blockquote { background:#f0f0f0; border-left:6px solid grey; padding:8px }
5 | .markdown table { margin:12px; border-collapse: collapse; }
6 | .markdown th { border:1px solid grey; background:lightgrey; padding:6px; }
7 | .markdown td { border:1px solid grey; padding:6px; word-wrap:break-word; }
8 | .markdown tr:nth-child(even) { background:#f6f6f6; }
9 | .markdown ins { color:#890604 }
10 | .markdown rem { color:#198964 }
11 | .toc ul { padding: 0 12px; }
12 | .toc h3 { color:#0057b7; border-bottom:1px dotted grey }
13 | .toc .H1 { list-style-type:none; font-weight:600; margin:4px; background:#eee }
14 | .toc .H2 { list-style-type:none; font-weight:600; margin:4px; }
15 | .toc .H3 { margin-left:2em }
16 | .toc .H4 { margin-left:4em }
17 | .toc .active { color:#0057b7 }
18 | .toc li:hover { background:#ffd700 }
19 |
20 | /* ==== style for casual-markdown-doc.css ==== */
21 | body { font-family:Verdana,sans-serif; font-size:14px; line-height:1.5; margin:0; display:none }
22 | code, xmp { white-space : pre-wrap; font-size:90% }
23 | img { margin:auto; max-width:990px; padding: 2px 10px }
24 | h1, h2 { border-bottom: 1px solid grey; margin:20px 0px; color:#06c; padding:8px 1px; page-break-before:always; }
25 | h3, h4 { margin-top:24px 0px; padding:8px 1px; color:#66e; }
26 | a { text-decoration:none; } a:hover{ background:#ffd700 }
27 |
28 | header { font-size:32px; margin-bottom:24px; padding:16px; background:#0057b7; color:white }
29 | #tocbox { background: rgba(210,210,210,0.8); border:1px solid grey; }
30 | #tocbox { position:fixed; right:8px; top:8px; padding:4px; }
31 |
32 | @media print {
33 | header { margin-top:60px; color:black; border-bottom:2px solid grey;}
34 | #tocbox { position:relative; font-size:18px; margin:12px; line-height:160%; page-break-after: always; }
35 | #tocbox button { display:none }
36 | }
37 |
--------------------------------------------------------------------------------
/dist/casual-markdown-doc.js:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * casual-markdown - a lightweight regexp-base markdown parser with TOC support
3 | * last updated on 2022/07/22, v0.85, code formatter, toc, scrollspy and front matter
4 | *
5 | * Copyright (c) 2022, Casualwriter (MIT Licensed)
6 | * https://github.com/casualwriter/casual-markdown
7 | *****************************************************************************/
8 | ;(function(){
9 |
10 | // define md object, and extent function (which is a dummy function for user extension)
11 | var md = { yaml:{}, before: function (str) {return str}, after: function (str) {return str} }
12 |
13 | // function for REGEXP to convert html tag. ie. ' + block + '
'
39 | }
40 |
41 | //===== parse markdown string into HTML string (exclude code-block)
42 | md.parser = function( mdstr ) {
43 | // apply yaml variables
44 | console.log( 'BEFORE==>', mdstr.substr(0,100) )
45 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
46 | console.log( 'AFTER==>', mdstr.substr(0,100) )
47 | // table syntax
48 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
49 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + thead + '\n | \n' + tbody + '\n
---|
56 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 57 | 58 | // header =>
..
59 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
60 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
61 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
62 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
63 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
64 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
65 |
66 | // inline code-block: `code-block` => code-block
67 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
68 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
69 |
70 | // blockquote, max 2 levels => {text}
71 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
72 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
73 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
74 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
75 |
76 | // image syntax:  =>
77 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
78 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
79 |
80 | // links syntax: [title "title"](url) => text
81 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
82 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
83 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
84 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
85 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
86 |
87 | // unordered/ordered list, max 2 levels => - ..
, - ..
88 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
89 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '- $1
' )
90 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
91 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
92 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
93 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
94 |
95 | // text decoration: bold, italic, underline, strikethrough, highlight
96 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
97 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
98 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
99 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
100 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
101 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
102 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
103 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
104 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
105 |
106 | // line break and paragraph =>
107 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
108 |
109 | // indent as code-block
110 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
111 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
112 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
113 |
114 | // Escaping Characters
115 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
116 | }
117 |
118 | //===== parse markdown string into HTML content (cater code-block)
119 | md.html = function (mdText) {
120 | // replace \r\n to \n, and handle front matter for simple YAML
121 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
122 | // handle code-block.
123 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
124 |
125 | // split by "", skip for code-block and process normal text
126 | var pos1=0, pos2=0, mdHTML = ''
127 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
128 | pos2 = mdText.indexOf('
', pos1 )
129 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
130 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
131 | mdText = mdText.substr( pos2 + 7 )
132 | }
133 |
134 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
135 | }
136 |
137 | //===== TOC support
138 | md.toc = function (srcDiv, tocDiv, options ) {
139 |
140 | // select elements, set title
141 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
142 | var tocTitle = (options&&options.title) || 'Table of Contents'
143 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
144 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
145 |
146 | // loop for each element,add - element with class in TAG name.
147 | for (var i=0; i
'
151 | html += toc[i].textContent + ' ';
152 | }
153 |
154 | document.getElementById(tocDiv).innerHTML = html + "
";
155 |
156 | //===== scrollspy support (ps: add to document if element(scroll) not found)
157 | if ( options && options.scrollspy ) {
158 |
159 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
160 |
161 | // get TOC elements, and viewport position
162 | var list = document.getElementById(tocDiv).querySelectorAll('li')
163 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
164 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
165 |
166 | // loop for each TOC element, add/remove scrollspy class
167 | for (var i=0; i0 && pos tag into HTML document
193 | //=============================================================================
194 | window.onload = function () {
195 |
196 | var html = ''
197 | html += '' + (document.body.title||document.title) + ' '
198 | html += '\n'
200 | html += '\n' + md.html(document.body.innerHTML.replace(/\>/g,'>')) + '';
201 |
202 | // add shortcut for edit current page.
203 | html += ' ';
204 | html += ' ';
205 |
206 | document.body.innerHTML = html
207 | document.body.style.display = 'block';
208 | md.toc( 'content', 'toc', { scrollspy:'body' } )
209 |
210 | }
211 |
212 | // toggle TOC
213 | function tocToggle(show) {
214 | var disp = document.getElementById('tocbox').style.display
215 | document.getElementById('tocbox').style.display = show||(disp=='none')? 'block' : 'none'
216 | }
217 |
218 | // debug: show HTML
219 | function debug() {
220 | var html = document.getElementById('content').innerHTML
221 | if (html.substr(0,5)=='') {
222 | document.getElementById('content').innerHTML = html.substr(5, html.length-11)
223 | } else {
224 | document.getElementById('content').innerHTML = '' + html.replace(/xmp\>/g,'|xmp>') + ' '
225 | }
226 | }
227 |
228 |
--------------------------------------------------------------------------------
/dist/casual-markdown-page.html:
--------------------------------------------------------------------------------
1 |
2 | md-as-Page
3 |
4 |
5 |
6 |
7 |
36 |
37 |
38 |
39 |
40 | casual-markdown
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
135 |
--------------------------------------------------------------------------------
/dist/casual-markdown.css:
--------------------------------------------------------------------------------
1 | .markdown code { background:#f0f0f0; color:navy; border-radius:6px; padding:2px; }
2 | .markdown pre { background:#f0f0f0; margin:12px; border:1px solid #ddd; padding:20px 12px; border-radius:6px; }
3 | .markdown pre:hover button { display:block; }
4 | .markdown pre button { display:none; position:relative; float:right; top:-16px }
5 | .markdown blockquote { background:#f0f0f0; border-left:6px solid grey; padding:8px }
6 | .markdown table { margin:12px; border-collapse: collapse; }
7 | .markdown th { border:1px solid grey; background:lightgrey; padding:6px; }
8 | .markdown td { border:1px solid grey; padding:6px; }
9 | .markdown tr:nth-child(even) { background:#f0f0f0; }
10 | .markdown ins { color:#890604 }
11 | .markdown rem { color:#198964 }
12 | .toc ul { padding: 0 12px; }
13 | .toc h3 { color:#0057b7; border-bottom:1px dotted grey }
14 | .toc .H1 { list-style-type:none; font-weight:600; margin:4px; background:#eee }
15 | .toc .H2 { list-style-type:none; font-weight:600; margin:4px; }
16 | .toc .H3 { margin-left:2em }
17 | .toc .H4 { margin-left:4em }
18 | .toc .active { color:#0057b7 }
19 | .toc li:hover { background:#f0f0f0 }
20 |
--------------------------------------------------------------------------------
/dist/casual-markdown.js:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * casual-markdown - a lightweight regexp-base markdown parser with TOC support
3 | * 2022/07/31, v0.90, refine frontmatter (simple yaml)
4 | * 2023/04/12, v0.92, addCopyButton for code-block
5 | *
6 | * Copyright (c) 2022-2023, Casualwriter (MIT Licensed)
7 | * https://github.com/casualwriter/casual-markdown
8 | *****************************************************************************/
9 | ;(function(){
10 |
11 | // define md object, and extent function (which is a dummy function)
12 | var md = { yaml:{}, before: function (str) {return str}, after: function (str) {return str} }
13 |
14 | // function for REGEXP to convert html tag. ie. => <TAG*gt;
15 | md.formatTag = function (html) { return html.replace(//g,'>'); }
16 |
17 | // frontmatter for simple YAML (support multi-level, but string value only)
18 | md.formatYAML = function (front, matter) {
19 | var level = {}, latest = md.yaml;
20 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) {
21 | level[sp] = level[sp] || latest
22 | latest = level[sp][key.trim()] = val.trim() || {}
23 | for (e in level) if(e>sp) level[e]=null;
24 | } );
25 | return ''
26 | }
27 |
28 | //===== format code-block, highlight remarks/keywords for code/sql
29 | md.formatCode = function (match, title, block) {
30 | // convert tag <> to < > tab to 3 space, support marker using ^^^
31 | block = block.replace(//g,'>')
32 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1')
33 |
34 | // highlight comment and keyword based on title := none | sql | code
35 | if (title.toLowerCase(title) == 'sql') {
36 | block = block.replace(/^\-\-(.*)/gm,'--$1 ').replace(/\s\-\-(.*)/gm,' --$1 ')
37 | block = block.replace(/(\s?)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
38 | block = block.replace(/(\s?)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3')
39 | } else if ((title||'none')!=='none') {
40 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,' //$1 ')
41 | block = block.replace(/(\s?)(function|procedure|return|exit|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
42 | block = block.replace(/(\s?)(var|let|const|=>|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3')
43 | }
44 |
45 | return '' + block + '
'
46 | }
47 |
48 | // copy to clipboard for code-block
49 | md.clipboard = function (e) {
50 | navigator.clipboard.writeText( e.parentNode.innerText.replace('copy\n','') )
51 | e.innerText = 'copied'
52 | }
53 |
54 | //===== parse markdown string into HTML string (exclude code-block)
55 | md.parser = function( mdstr ) {
56 |
57 | // apply yaml variables
58 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
59 |
60 | // table syntax
61 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\s?\|\s?\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
62 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'')
63 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
64 | tbody = tbody.replace(/(.+)/gm,' $1 ').replace(/\|/g,'')
65 | return '\n\n\n' + thead + '\n \n' + tbody + '\n
\n\n'
66 | } )
67 |
68 | // horizontal rule =>
69 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
')
70 |
71 | // header => ..
72 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
73 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
74 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
75 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
76 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
77 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
78 |
79 | // inline code-block: `code-block` => code-block
80 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
81 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
82 |
83 | // blockquote, max 2 levels => {text}
84 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
85 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
86 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
87 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
88 |
89 | // image syntax:  =>
90 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
91 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
92 |
93 | // links syntax: [title "title"](url) => text
94 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
95 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
96 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
97 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
98 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
99 |
100 | // unordered/ordered list, max 2 levels => - ..
, - ..
101 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
102 | mdstr = mdstr.replace(/^\d\d?[ .](.*)/gm, '- $1
' )
103 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
104 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
105 | mdstr = mdstr.replace(/<\/[ou]l\>\n\n?<[ou]l\>/g, '\n' )
106 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
107 |
108 | // text decoration: bold, italic, underline, strikethrough, highlight
109 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
110 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
111 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
112 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
113 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
114 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
115 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
116 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
117 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
118 |
119 | // line break and paragraph =>
120 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
121 |
122 | // indent as code-block
123 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
124 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
125 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
126 |
127 | // Escaping Characters
128 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
129 | }
130 |
131 | //===== parse markdown string into HTML content (cater code-block)
132 | md.html = function (mdText) {
133 | // replace \r\n to \n, and handle front matter for simple YAML
134 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
135 | // handle code-block.
136 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
137 |
138 | // split by "", skip for code-block and process normal text
139 | var pos1=0, pos2=0, mdHTML = ''
140 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
141 | pos2 = mdText.indexOf('
', pos1 )
142 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
143 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
144 | mdText = mdText.substr( pos2 + 7 )
145 | }
146 |
147 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
148 | }
149 |
150 | //===== TOC support
151 | md.toc = function (srcDiv, tocDiv, options ) {
152 |
153 | // select elements, set title
154 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
155 | var tocTitle = (options&&options.title) || 'Table of Contents'
156 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
157 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
158 |
159 | // loop for each element,add - element with class in TAG name.
160 | for (var i=0; i
'
164 | html += toc[i].textContent + ' ';
165 | }
166 |
167 | document.getElementById(tocDiv).innerHTML = html + "
";
168 |
169 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found)
170 | if ( options && options.scrollspy ) {
171 |
172 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
173 |
174 | // get TOC elements, and viewport position
175 | var list = document.getElementById(tocDiv).querySelectorAll('li')
176 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
177 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
178 |
179 | // loop for each TOC element, add/remove scrollspy class
180 | for (var i=0; i0 && pos => <TAG*gt;
14 | md.formatTag = function (html) { return html.replace(//g,'>'); }
15 |
16 | //===== format code-block, highlight remarks/keywords for code/sql
17 | md.formatCode = function (match, title, block) {
18 | // convert tag <> to < > tab to 3 space, support mark code using ^^^
19 | block = block.replace(//g,'>')
20 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1')
21 |
22 | // highlight comment and keyword based on title := none | sql | code
23 | if (title.toLowerCase(title) == 'sql') {
24 | block = block.replace(/^\-\-(.*)/gm,'--$1 ').replace(/\s\-\-(.*)/gm,' --$1 ')
25 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
26 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3')
27 | } else if ((title||'none')!=='none') {
28 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,' //$1 ')
29 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
30 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3')
31 | }
32 | return '' + block + '
'
33 | }
34 |
35 | //===== parse markdown string into HTML string (exclude code-block)
36 | md.parser = function( mdstr ) {
37 | // table syntax
38 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
39 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'')
40 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
41 | tbody = tbody.replace(/(.+)/gm,' $1 ').replace(/\|/g,'')
42 | return '\n\n\n' + thead + '\n \n' + tbody + '\n
\n\n'
43 | } )
44 |
45 | // horizontal rule =>
46 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
')
47 |
48 | // header => ..
49 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
50 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
51 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
52 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
53 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
54 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
55 |
56 | // inline code-block: `code-block` => code-block
57 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
58 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
59 |
60 | // blockquote, max 2 levels => {text}
61 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
62 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
63 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
64 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
65 |
66 | // image syntax:  =>
67 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
68 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
69 |
70 | // links syntax: [title](url) => text
71 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
72 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
73 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
74 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
75 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
76 |
77 | // unordered/ordered list, max 2 levels => - ..
, - ..
78 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
79 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '- $1
' )
80 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
81 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
82 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
83 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
84 |
85 | // text decoration: bold, italic, underline, strikethrough, highlight
86 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
87 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
88 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
89 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
90 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
91 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
92 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
93 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
94 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
95 |
96 | // line break and paragraph =>
97 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
98 |
99 | // indent as code-block
100 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
101 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
102 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
103 |
104 | // Escaping Characters
105 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
106 | }
107 |
108 | //===== parse markdown string into HTML content (cater code-block)
109 | md.html = function (mdText) {
110 | // first, handle syntax for code-block
111 | var pos1=0, pos2=0, mdHTML = ''
112 | mdText = mdText.replace(/\r\n/g, '\n').replace(/\n~~~/g,'\n```')
113 | mdText = mdText.replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
114 |
115 | // split by "", skip for code-block and process normal text
116 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
117 | pos2 = mdText.indexOf('
', pos1 )
118 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
119 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
120 | mdText = mdText.substr( pos2 + 7 )
121 | }
122 |
123 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
124 | }
125 |
126 | //===== TOC support
127 | md.toc = function (srcDiv, tocDiv, options ) {
128 |
129 | // select elements, set title
130 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
131 | var tocTitle = (options&&options.title) || 'Table of Contents'
132 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
133 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
134 |
135 | // loop for each element,add - element with class in TAG name.
136 | for (var i=0; i
'
140 | html += toc[i].textContent + ' ';
141 | }
142 |
143 | document.getElementById(tocDiv).innerHTML = html + "
";
144 |
145 | //===== scrollspy support (ps: add to document if element(scroll) not found)
146 | if ( options && options.scrollspy ) {
147 |
148 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
149 |
150 | // get TOC elements, and viewport position
151 | var list = document.getElementById(tocDiv).querySelectorAll('li')
152 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
153 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
154 |
155 | // loop for each TOC element, add/remove scrollspy class
156 | for (var i=0; i0 && pos => <TAG*gt;
14 | md.formatTag = function (html) { return html.replace(//g,'>'); }
15 |
16 | // frontmatter for simple YAML (only support one level and string value)
17 | md.formatYAML = function (front, matter) {
18 | matter.replace( /^\s*([^:]+):(.*)$/gm, function(m,key,val) { md.yaml[key.trim()] = val.trim() } );
19 | return ''
20 | }
21 |
22 | //===== format code-block, highlight remarks/keywords for code/sql
23 | md.formatCode = function (match, title, block) {
24 | // convert tag <> to < > tab to 3 space, support marker using ^^^
25 | block = block.replace(//g,'>')
26 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1')
27 |
28 | // highlight comment and keyword based on title := none | sql | code
29 | if (title.toLowerCase(title) == 'sql') {
30 | block = block.replace(/^\-\-(.*)/gm,'--$1 ').replace(/\s\-\-(.*)/gm,' --$1 ')
31 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
32 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3')
33 | } else if ((title||'none')!=='none') {
34 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,' //$1 ')
35 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
36 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3')
37 | }
38 | return '' + block + '
'
39 | }
40 |
41 | //===== parse markdown string into HTML string (exclude code-block)
42 | md.parser = function( mdstr ) {
43 |
44 | // apply yaml variables
45 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
46 |
47 | // table syntax
48 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
49 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'')
50 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
51 | tbody = tbody.replace(/(.+)/gm,' $1 ').replace(/\|/g,'')
52 | return '\n\n\n' + thead + '\n \n' + tbody + '\n
\n\n'
53 | } )
54 |
55 | // horizontal rule =>
56 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
')
57 |
58 | // header => ..
59 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
60 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
61 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
62 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
63 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
64 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
65 |
66 | // inline code-block: `code-block` => code-block
67 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
68 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
69 |
70 | // blockquote, max 2 levels => {text}
71 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
72 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
73 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
74 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
75 |
76 | // image syntax:  =>
77 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
78 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
79 |
80 | // links syntax: [title "title"](url) => text
81 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
82 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
83 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
84 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
85 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
86 |
87 | // unordered/ordered list, max 2 levels => - ..
, - ..
88 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
89 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '- $1
' )
90 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
91 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
92 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
93 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
94 |
95 | // text decoration: bold, italic, underline, strikethrough, highlight
96 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
97 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
98 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
99 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
100 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
101 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
102 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
103 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
104 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
105 |
106 | // line break and paragraph =>
107 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
108 |
109 | // indent as code-block
110 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
111 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
112 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
113 |
114 | // Escaping Characters
115 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
116 | }
117 |
118 | //===== parse markdown string into HTML content (cater code-block)
119 | md.html = function (mdText) {
120 | // replace \r\n to \n, and handle front matter for simple YAML
121 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
122 | // handle code-block.
123 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
124 |
125 | // split by "", skip for code-block and process normal text
126 | var pos1=0, pos2=0, mdHTML = ''
127 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
128 | pos2 = mdText.indexOf('
', pos1 )
129 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
130 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
131 | mdText = mdText.substr( pos2 + 7 )
132 | }
133 |
134 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
135 | }
136 |
137 | //===== TOC support
138 | md.toc = function (srcDiv, tocDiv, options ) {
139 |
140 | // select elements, set title
141 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
142 | var tocTitle = (options&&options.title) || 'Table of Contents'
143 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
144 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
145 |
146 | // loop for each element,add - element with class in TAG name.
147 | for (var i=0; i
'
151 | html += toc[i].textContent + ' ';
152 | }
153 |
154 | document.getElementById(tocDiv).innerHTML = html + "
";
155 |
156 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found)
157 | if ( options && options.scrollspy ) {
158 |
159 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
160 |
161 | // get TOC elements, and viewport position
162 | var list = document.getElementById(tocDiv).querySelectorAll('li')
163 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
164 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
165 |
166 | // loop for each TOC element, add/remove scrollspy class
167 | for (var i=0; i0 && pos => <TAG*gt;
14 | md.formatTag = function (html) { return html.replace(//g,'>'); }
15 |
16 | // frontmatter for simple YAML (support multi-level, but string value only)
17 | md.formatYAML = function (front, matter) {
18 | var level = {}, latest = md.yaml;
19 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) {
20 | level[sp] = level[sp] || latest
21 | latest = level[sp][key.trim()] = val.trim() || {}
22 | for (e in level) if(e>sp) level[e]=null;
23 | } );
24 | return ''
25 | }
26 |
27 | //===== format code-block, highlight remarks/keywords for code/sql
28 | md.formatCode = function (match, title, block) {
29 | // convert tag <> to < > tab to 3 space, support marker using ^^^
30 | block = block.replace(//g,'>')
31 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1')
32 |
33 | // highlight comment and keyword based on title := none | sql | code
34 | if (title.toLowerCase(title) == 'sql') {
35 | block = block.replace(/^\-\-(.*)/gm,'--$1 ').replace(/\s\-\-(.*)/gm,' --$1 ')
36 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
37 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3')
38 | } else if ((title||'none')!=='none') {
39 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,' //$1 ')
40 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
41 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3')
42 | }
43 | return '' + block + '
'
44 | }
45 |
46 | //===== parse markdown string into HTML string (exclude code-block)
47 | md.parser = function( mdstr ) {
48 |
49 | // apply yaml variables
50 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
51 |
52 | // table syntax
53 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
54 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'')
55 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
56 | tbody = tbody.replace(/(.+)/gm,' $1 ').replace(/\|/g,'')
57 | return '\n\n\n' + thead + '\n \n' + tbody + '\n
\n\n'
58 | } )
59 |
60 | // horizontal rule =>
61 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
')
62 |
63 | // header => ..
64 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
65 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
66 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
67 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
68 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
69 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
70 |
71 | // inline code-block: `code-block` => code-block
72 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
73 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
74 |
75 | // blockquote, max 2 levels => {text}
76 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
77 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
78 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
79 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
80 |
81 | // image syntax:  =>
82 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
83 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
84 |
85 | // links syntax: [title "title"](url) => text
86 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
87 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
88 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
89 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
90 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
91 |
92 | // unordered/ordered list, max 2 levels => - ..
, - ..
93 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
94 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '- $1
' )
95 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
96 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
97 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
98 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
99 |
100 | // text decoration: bold, italic, underline, strikethrough, highlight
101 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
102 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
103 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
104 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
105 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
106 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
107 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
108 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
109 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
110 |
111 | // line break and paragraph =>
112 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
113 |
114 | // indent as code-block
115 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
116 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
117 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
118 |
119 | // Escaping Characters
120 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
121 | }
122 |
123 | //===== parse markdown string into HTML content (cater code-block)
124 | md.html = function (mdText) {
125 | // replace \r\n to \n, and handle front matter for simple YAML
126 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
127 | // handle code-block.
128 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
129 |
130 | // split by "", skip for code-block and process normal text
131 | var pos1=0, pos2=0, mdHTML = ''
132 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
133 | pos2 = mdText.indexOf('
', pos1 )
134 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
135 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
136 | mdText = mdText.substr( pos2 + 7 )
137 | }
138 |
139 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
140 | }
141 |
142 | //===== TOC support
143 | md.toc = function (srcDiv, tocDiv, options ) {
144 |
145 | // select elements, set title
146 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
147 | var tocTitle = (options&&options.title) || 'Table of Contents'
148 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
149 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
150 |
151 | // loop for each element,add - element with class in TAG name.
152 | for (var i=0; i
'
156 | html += toc[i].textContent + ' ';
157 | }
158 |
159 | document.getElementById(tocDiv).innerHTML = html + "
";
160 |
161 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found)
162 | if ( options && options.scrollspy ) {
163 |
164 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
165 |
166 | // get TOC elements, and viewport position
167 | var list = document.getElementById(tocDiv).querySelectorAll('li')
168 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
169 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
170 |
171 | // loop for each TOC element, add/remove scrollspy class
172 | for (var i=0; i0 && pos => <TAG*gt;
15 | md.formatTag = function (html) { return html.replace(//g,'>'); }
16 |
17 | // frontmatter for simple YAML (support multi-level, but string value only)
18 | md.formatYAML = function (front, matter) {
19 | var level = {}, latest = md.yaml;
20 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) {
21 | level[sp] = level[sp] || latest
22 | latest = level[sp][key.trim()] = val.trim() || {}
23 | for (e in level) if(e>sp) level[e]=null;
24 | } );
25 | return ''
26 | }
27 |
28 | //===== format code-block, highlight remarks/keywords for code/sql
29 | md.formatCode = function (match, title, block) {
30 | // convert tag <> to < > tab to 3 space, support marker using ^^^
31 | block = block.replace(//g,'>')
32 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1')
33 |
34 | // highlight comment and keyword based on title := none | sql | code
35 | if (title.toLowerCase(title) == 'sql') {
36 | block = block.replace(/^\-\-(.*)/gm,'--$1 ').replace(/\s\-\-(.*)/gm,' --$1 ')
37 | block = block.replace(/(\s?)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
38 | block = block.replace(/(\s?)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3')
39 | } else if ((title||'none')!=='none') {
40 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,' //$1 ')
41 | block = block.replace(/(\s?)(function|procedure|return|exit|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
42 | block = block.replace(/(\s?)(var|let|const|=>|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3')
43 | }
44 |
45 | return '' + block + '
'
46 | }
47 |
48 | // copy to clipboard for code-block
49 | md.clipboard = function (e) {
50 | navigator.clipboard.writeText( e.parentNode.innerText.replace('copy\n','') )
51 | e.innerText = 'copied'
52 | }
53 |
54 | //===== parse markdown string into HTML string (exclude code-block)
55 | md.parser = function( mdstr ) {
56 |
57 | // apply yaml variables
58 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
59 |
60 | // table syntax
61 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\s?\|\s?\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
62 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'')
63 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
64 | tbody = tbody.replace(/(.+)/gm,' $1 ').replace(/\|/g,'')
65 | return '\n\n\n' + thead + '\n \n' + tbody + '\n
\n\n'
66 | } )
67 |
68 | // horizontal rule =>
69 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
')
70 |
71 | // header => ..
72 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
73 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
74 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
75 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
76 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
77 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
78 |
79 | // inline code-block: `code-block` => code-block
80 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
81 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
82 |
83 | // blockquote, max 2 levels => {text}
84 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
85 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
86 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
87 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
88 |
89 | // image syntax:  =>
90 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
91 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
92 |
93 | // links syntax: [title "title"](url) => text
94 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
95 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
96 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
97 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
98 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
99 |
100 | // unordered/ordered list, max 2 levels => - ..
, - ..
101 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
102 | mdstr = mdstr.replace(/^\d\d?[ .](.*)/gm, '- $1
' )
103 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
104 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
105 | mdstr = mdstr.replace(/<\/[ou]l\>\n\n?<[ou]l\>/g, '\n' )
106 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
107 |
108 | // text decoration: bold, italic, underline, strikethrough, highlight
109 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
110 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
111 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
112 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
113 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
114 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
115 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
116 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
117 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
118 |
119 | // line break and paragraph =>
120 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
121 |
122 | // indent as code-block
123 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
124 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
125 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
126 |
127 | // Escaping Characters
128 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
129 | }
130 |
131 | //===== parse markdown string into HTML content (cater code-block)
132 | md.html = function (mdText) {
133 | // replace \r\n to \n, and handle front matter for simple YAML
134 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
135 | // handle code-block.
136 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
137 |
138 | // split by "", skip for code-block and process normal text
139 | var pos1=0, pos2=0, mdHTML = ''
140 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
141 | pos2 = mdText.indexOf('
', pos1 )
142 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
143 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
144 | mdText = mdText.substr( pos2 + 7 )
145 | }
146 |
147 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
148 | }
149 |
150 | //===== TOC support
151 | md.toc = function (srcDiv, tocDiv, options ) {
152 |
153 | // select elements, set title
154 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
155 | var tocTitle = (options&&options.title) || 'Table of Contents'
156 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
157 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
158 |
159 | // loop for each element,add - element with class in TAG name.
160 | for (var i=0; i
'
164 | html += toc[i].textContent + ' ';
165 | }
166 |
167 | document.getElementById(tocDiv).innerHTML = html + "
";
168 |
169 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found)
170 | if ( options && options.scrollspy ) {
171 |
172 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
173 |
174 | // get TOC elements, and viewport position
175 | var list = document.getElementById(tocDiv).querySelectorAll('li')
176 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
177 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
178 |
179 | // loop for each TOC element, add/remove scrollspy class
180 | for (var i=0; i0 && pos => <TAG*gt;
14 | md.formatTag = function (html) { return html.replace(//g,'>'); }
15 |
16 | // front matter for simple YAML (support 1 level only)
17 | md.formatYAML = function (front, matter) {
18 | matter.replace( /^\s*([^:]+):(.*)$/gm, function(m,key,val) { md.yaml[key.trim()] = val.trim() } );
19 | return ''
20 | }
21 |
22 | //===== format code-block, highlight remarks/keywords for code/sql
23 | md.formatCode = function (match, title, block) {
24 | // convert tag <> to < > tab to 3 space, support mark code using ^^^
25 | block = block.replace(//g,'>')
26 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1')
27 |
28 | // highlight comment and keyword based on title := none | sql | code
29 | if (title.toLowerCase(title) == 'sql') {
30 | block = block.replace(/^\-\-(.*)/gm,'--$1 ').replace(/\s\-\-(.*)/gm,' --$1 ')
31 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
32 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3')
33 | } else if ((title||'none')!=='none') {
34 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,' //$1 ')
35 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
36 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3')
37 | }
38 | return '' + block + '
'
39 | }
40 |
41 | //===== parse markdown string into HTML string (exclude code-block)
42 | md.parser = function( mdstr ) {
43 | // apply yaml variables
44 | console.log( 'BEFORE==>', mdstr.substr(0,100) )
45 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
46 | console.log( 'AFTER==>', mdstr.substr(0,100) )
47 | // table syntax
48 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
49 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'')
50 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
51 | tbody = tbody.replace(/(.+)/gm,' $1 ').replace(/\|/g,'')
52 | return '\n\n\n' + thead + '\n \n' + tbody + '\n
\n\n'
53 | } )
54 |
55 | // horizontal rule =>
56 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
')
57 |
58 | // header => ..
59 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
60 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
61 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
62 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
63 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
64 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
65 |
66 | // inline code-block: `code-block` => code-block
67 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
68 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
69 |
70 | // blockquote, max 2 levels => {text}
71 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
72 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
73 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
74 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
75 |
76 | // image syntax:  =>
77 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
78 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
79 |
80 | // links syntax: [title "title"](url) => text
81 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
82 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
83 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
84 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
85 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
86 |
87 | // unordered/ordered list, max 2 levels => - ..
, - ..
88 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
89 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '- $1
' )
90 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
91 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
92 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
93 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
94 |
95 | // text decoration: bold, italic, underline, strikethrough, highlight
96 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
97 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
98 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
99 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
100 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
101 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
102 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
103 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
104 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
105 |
106 | // line break and paragraph =>
107 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
108 |
109 | // indent as code-block
110 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
111 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
112 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
113 |
114 | // Escaping Characters
115 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
116 | }
117 |
118 | //===== parse markdown string into HTML content (cater code-block)
119 | md.html = function (mdText) {
120 | // replace \r\n to \n, and handle front matter for simple YAML
121 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
122 | // handle code-block.
123 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
124 |
125 | // split by "", skip for code-block and process normal text
126 | var pos1=0, pos2=0, mdHTML = ''
127 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
128 | pos2 = mdText.indexOf('
', pos1 )
129 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
130 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
131 | mdText = mdText.substr( pos2 + 7 )
132 | }
133 |
134 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
135 | }
136 |
137 | //===== TOC support
138 | md.toc = function (srcDiv, tocDiv, options ) {
139 |
140 | // select elements, set title
141 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
142 | var tocTitle = (options&&options.title) || 'Table of Contents'
143 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
144 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
145 |
146 | // loop for each element,add - element with class in TAG name.
147 | for (var i=0; i
'
151 | html += toc[i].textContent + ' ';
152 | }
153 |
154 | document.getElementById(tocDiv).innerHTML = html + "
";
155 |
156 | //===== scrollspy support (ps: add to document if element(scroll) not found)
157 | if ( options && options.scrollspy ) {
158 |
159 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
160 |
161 | // get TOC elements, and viewport position
162 | var list = document.getElementById(tocDiv).querySelectorAll('li')
163 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
164 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
165 |
166 | // loop for each TOC element, add/remove scrollspy class
167 | for (var i=0; i0 && pos tag into HTML document
193 | //=============================================================================
194 | window.onload = function () {
195 |
196 | var html = ''
197 | html += '' + (document.body.title||document.title) + ' '
198 | html += '\n'
200 | html += '\n' + md.html(document.body.innerHTML.replace(/\>/g,'>')) + '';
201 |
202 | // add shortcut for edit current page.
203 | html += ' ';
204 | html += ' ';
205 |
206 | document.body.innerHTML = html
207 | document.body.style.display = 'block';
208 | md.toc( 'content', 'toc', { scrollspy:'body' } )
209 |
210 | }
211 |
212 | // toggle TOC
213 | function tocToggle(show) {
214 | var disp = document.getElementById('tocbox').style.display
215 | document.getElementById('tocbox').style.display = show||(disp=='none')? 'block' : 'none'
216 | }
217 |
218 | // debug: show HTML
219 | function debug() {
220 | var html = document.getElementById('content').innerHTML
221 | if (html.substr(0,5)=='') {
222 | document.getElementById('content').innerHTML = html.substr(5, html.length-11)
223 | } else {
224 | document.getElementById('content').innerHTML = '' + html.replace(/xmp\>/g,'|xmp>') + ' '
225 | }
226 | }
227 |
228 |
--------------------------------------------------------------------------------
/source/casual-markdown-page.html:
--------------------------------------------------------------------------------
1 |
2 | All-in-One
3 |
4 |
50 |
235 |
236 |
237 |
238 |
239 | casual-markdown
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
317 |
--------------------------------------------------------------------------------
/source/casual-markdown.css:
--------------------------------------------------------------------------------
1 | .markdown code { background:#f0f0f0; color:navy; border-radius:6px; padding:2px; }
2 | .markdown pre { background:#f0f0f0; margin:12px; border:1px solid #ddd; padding:20px 12px; border-radius:6px; }
3 | .markdown pre:hover button { display:block; }
4 | .markdown pre button { display:none; position:relative; float:right; top:-16px }
5 | .markdown blockquote { background:#f0f0f0; border-left:6px solid grey; padding:8px }
6 | .markdown table { margin:12px; border-collapse: collapse; }
7 | .markdown th { border:1px solid grey; background:lightgrey; padding:6px; }
8 | .markdown td { border:1px solid grey; padding:6px; }
9 | .markdown tr:nth-child(even) { background:#f0f0f0; }
10 | .markdown ins { color:#890604 }
11 | .markdown rem { color:#198964 }
12 | .toc ul { padding: 0 12px; }
13 | .toc h3 { color:#0057b7; border-bottom:1px dotted grey }
14 | .toc .H1 { list-style-type:none; font-weight:600; margin:4px; background:#eee }
15 | .toc .H2 { list-style-type:none; font-weight:600; margin:4px; }
16 | .toc .H3 { margin-left:2em }
17 | .toc .H4 { margin-left:4em }
18 | .toc .active { color:#0057b7 }
19 | .toc li:hover { background:#f0f0f0 }
20 |
--------------------------------------------------------------------------------
/source/casual-markdown.js:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 | * casual-markdown - a lightweight regexp-base markdown parser with TOC support
3 | * 2022/07/31, v0.90, refine frontmatter (simple yaml)
4 | * 2023/04/12, v0.92, addCopyButton for code-block
5 | *
6 | * Copyright (c) 2022-2023, Casualwriter (MIT Licensed)
7 | * https://github.com/casualwriter/casual-markdown
8 | *****************************************************************************/
9 | ;(function(){
10 |
11 | // define md object, and extent function (which is a dummy function)
12 | var md = { yaml:{}, before: function (str) {return str}, after: function (str) {return str} }
13 |
14 | // function for REGEXP to convert html tag. ie. => <TAG*gt;
15 | md.formatTag = function (html) { return html.replace(//g,'>'); }
16 |
17 | // frontmatter for simple YAML (support multi-level, but string value only)
18 | md.formatYAML = function (front, matter) {
19 | var level = {}, latest = md.yaml;
20 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) {
21 | level[sp] = level[sp] || latest
22 | latest = level[sp][key.trim()] = val.trim() || {}
23 | for (e in level) if(e>sp) level[e]=null;
24 | } );
25 | return ''
26 | }
27 |
28 | //===== format code-block, highlight remarks/keywords for code/sql
29 | md.formatCode = function (match, title, block) {
30 | // convert tag <> to < > tab to 3 space, support marker using ^^^
31 | block = block.replace(//g,'>')
32 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1')
33 |
34 | // highlight comment and keyword based on title := none | sql | code
35 | if (title.toLowerCase(title) == 'sql') {
36 | block = block.replace(/^\-\-(.*)/gm,'--$1 ').replace(/\s\-\-(.*)/gm,' --$1 ')
37 | block = block.replace(/(\s?)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
38 | block = block.replace(/(\s?)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3')
39 | } else if ((title||'none')!=='none') {
40 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,' //$1 ')
41 | block = block.replace(/(\s?)(function|procedure|return|exit|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3')
42 | block = block.replace(/(\s?)(var|let|const|=>|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3')
43 | }
44 |
45 | return '' + block + '
'
46 | }
47 |
48 | // copy to clipboard for code-block
49 | md.clipboard = function (e) {
50 | navigator.clipboard.writeText( e.parentNode.innerText.replace('copy\n','') )
51 | e.innerText = 'copied'
52 | }
53 |
54 | //===== parse markdown string into HTML string (exclude code-block)
55 | md.parser = function( mdstr ) {
56 |
57 | // apply yaml variables
58 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] )
59 |
60 | // table syntax
61 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\s?\|\s?\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) {
62 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'')
63 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1')
64 | tbody = tbody.replace(/(.+)/gm,' $1 ').replace(/\|/g,'')
65 | return '\n\n\n' + thead + '\n \n' + tbody + '\n
\n\n'
66 | } )
67 |
68 | // horizontal rule =>
69 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
')
70 |
71 | // header => ..
72 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '$1
')
73 | .replace(/^#### (.*?)\s*#*$/gm, '$1
')
74 | .replace(/^### (.*?)\s*#*$/gm, '$1
')
75 | .replace(/^## (.*?)\s*#*$/gm, '$1
')
76 | .replace(/^# (.*?)\s*#*$/gm, '$1
')
77 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, '$2 ')
78 |
79 | // inline code-block: `code-block` => code-block
80 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
81 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
82 |
83 | // blockquote, max 2 levels => {text}
84 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '$1
')
85 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
')
86 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' )
87 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' )
88 |
89 | // image syntax:  =>
90 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
')
91 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
')
92 |
93 | // links syntax: [title "title"](url) => text
94 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1')
95 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1')
96 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3')
97 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1')
98 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1')
99 |
100 | // unordered/ordered list, max 2 levels => - ..
, - ..
101 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '- $1
' )
102 | mdstr = mdstr.replace(/^\d\d?[ .](.*)/gm, '- $1
' )
103 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '- $1
' )
104 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '- $1
' )
105 | mdstr = mdstr.replace(/<\/[ou]l\>\n\n?<[ou]l\>/g, '\n' )
106 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' )
107 |
108 | // text decoration: bold, italic, underline, strikethrough, highlight
109 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1')
110 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1')
111 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1')
112 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1')
113 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1')
114 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!!
115 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1')
116 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1')
117 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '$1')
118 |
119 | // line break and paragraph =>
120 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n
\n')
121 |
122 | // indent as code-block
123 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
' + md.formatTag(p) + '
'} )
124 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} )
125 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n/g, '\n' )
126 |
127 | // Escaping Characters
128 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' )
129 | }
130 |
131 | //===== parse markdown string into HTML content (cater code-block)
132 | md.html = function (mdText) {
133 | // replace \r\n to \n, and handle front matter for simple YAML
134 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML )
135 | // handle code-block.
136 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode)
137 |
138 | // split by "", skip for code-block and process normal text
139 | var pos1=0, pos2=0, mdHTML = ''
140 | while ( (pos1 = mdText.indexOf('')) >= 0 ) {
141 | pos2 = mdText.indexOf('
', pos1 )
142 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) )
143 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) )
144 | mdText = mdText.substr( pos2 + 7 )
145 | }
146 |
147 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + ''
148 | }
149 |
150 | //===== TOC support
151 | md.toc = function (srcDiv, tocDiv, options ) {
152 |
153 | // select elements, set title
154 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4'
155 | var tocTitle = (options&&options.title) || 'Table of Contents'
156 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector )
157 | var html = '' + (tocTitle=='none'? '' : '' + tocTitle + '
');
158 |
159 | // loop for each element,add - element with class in TAG name.
160 | for (var i=0; i
'
164 | html += toc[i].textContent + ' ';
165 | }
166 |
167 | document.getElementById(tocDiv).innerHTML = html + "
";
168 |
169 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found)
170 | if ( options && options.scrollspy ) {
171 |
172 | (document.getElementById(options.scrollspy)||document).onscroll = function () {
173 |
174 | // get TOC elements, and viewport position
175 | var list = document.getElementById(tocDiv).querySelectorAll('li')
176 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement
177 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight
178 |
179 | // loop for each TOC element, add/remove scrollspy class
180 | for (var i=0; i0 && pos
$1
') 60 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 61 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 62 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 63 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 64 | .replace(/^code-block
67 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} )
68 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' )
69 |
70 | // blockquote, max 2 levels => {text}71 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '
') 72 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1
$1') 73 | mdstr = mdstr.replace(/<\/blockquote\>\n
/g, '\n
' ) 74 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 75 | 76 | // image syntax:  =>77 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 78 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 79 | 80 | // links syntax: [title "title"](url) => text 81 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 82 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 83 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 84 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 85 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 86 | 87 | // unordered/ordered list, max 2 levels =>
,
- ..
88 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 89 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '
- $1
' ) 90 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 91 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 92 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 93 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 94 | 95 | // text decoration: bold, italic, underline, strikethrough, highlight 96 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 97 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 98 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 99 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 100 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 101 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 102 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 103 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 104 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 105 | 106 | // line break and paragraph =>
107 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 108 | 109 | // indent as code-block 110 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 111 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 112 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 113 | 114 | // Escaping Characters 115 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 116 | } 117 | 118 | //===== parse markdown string into HTML content (cater code-block) 119 | md.html = function (mdText) { 120 | // replace \r\n to \n, and handle front matter for simple YAML 121 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML ) 122 | // handle code-block. 123 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 124 | 125 | // split by "
", skip for code-block and process normal text 126 | var pos1=0, pos2=0, mdHTML = '' 127 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 128 | pos2 = mdText.indexOf('
', pos1 ) 129 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 130 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 131 | mdText = mdText.substr( pos2 + 7 ) 132 | } 133 | 134 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 135 | } 136 | 137 | //===== TOC support 138 | md.toc = function (srcDiv, tocDiv, options ) { 139 | 140 | // select elements, set title 141 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 142 | var tocTitle = (options&&options.title) || 'Table of Contents' 143 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 144 | var html = '' + (tocTitle=='none'? '' : '
"; 155 | 156 | //===== scrollspy support (ps: add to document if element(scroll) not found) 157 | if ( options && options.scrollspy ) { 158 | 159 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 160 | 161 | // get TOC elements, and viewport position 162 | var list = document.getElementById(tocDiv).querySelectorAll('li') 163 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 164 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 165 | 166 | // loop for each TOC element, add/remove scrollspy class 167 | for (var i=0; i' + tocTitle + '
'); 145 | 146 | // loop for each element,add- element with class in TAG name. 147 | for (var i=0; i
'; 152 | } 153 | 154 | document.getElementById(tocDiv).innerHTML = html + "' 151 | html += toc[i].textContent + ' 0 && pos tag into HTML document 193 | //============================================================================= 194 | window.onload = function () { 195 | 196 | var html = ' ' 197 | html += ''; 201 | 202 | // add shortcut for edit current page. 203 | html += ' '; 204 | html += ' '; 205 | 206 | document.body.innerHTML = html 207 | document.body.style.display = 'block'; 208 | md.toc( 'content', 'toc', { scrollspy:'body' } ) 209 | 210 | } 211 | 212 | // toggle TOC 213 | function tocToggle(show) { 214 | var disp = document.getElementById('tocbox').style.display 215 | document.getElementById('tocbox').style.display = show||(disp=='none')? 'block' : 'none' 216 | } 217 | 218 | // debug: show HTML 219 | function debug() { 220 | var html = document.getElementById('content').innerHTML 221 | if (html.substr(0,5)=='' + (document.body.title||document.title) + ' ' 198 | html += '\n' 200 | html += '\n' + md.html(document.body.innerHTML.replace(/\>/g,'>')) + '') { 222 | document.getElementById('content').innerHTML = html.substr(5, html.length-11) 223 | } else { 224 | document.getElementById('content').innerHTML = ' ' + html.replace(/xmp\>/g,'|xmp>') + ' ' 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- /dist/casual-markdown-page.html: -------------------------------------------------------------------------------- 1 | 2 |md-as-Page 3 | 4 | 5 | 6 | 7 | 36 | 37 | 38 | 39 |40 | casual-markdown 41 | 42 |43 | 44 |45 | 46 | 47 |48 | 49 | 50 | 51 | 52 | 53 | 135 | -------------------------------------------------------------------------------- /dist/casual-markdown.css: -------------------------------------------------------------------------------- 1 | .markdown code { background:#f0f0f0; color:navy; border-radius:6px; padding:2px; } 2 | .markdown pre { background:#f0f0f0; margin:12px; border:1px solid #ddd; padding:20px 12px; border-radius:6px; } 3 | .markdown pre:hover button { display:block; } 4 | .markdown pre button { display:none; position:relative; float:right; top:-16px } 5 | .markdown blockquote { background:#f0f0f0; border-left:6px solid grey; padding:8px } 6 | .markdown table { margin:12px; border-collapse: collapse; } 7 | .markdown th { border:1px solid grey; background:lightgrey; padding:6px; } 8 | .markdown td { border:1px solid grey; padding:6px; } 9 | .markdown tr:nth-child(even) { background:#f0f0f0; } 10 | .markdown ins { color:#890604 } 11 | .markdown rem { color:#198964 } 12 | .toc ul { padding: 0 12px; } 13 | .toc h3 { color:#0057b7; border-bottom:1px dotted grey } 14 | .toc .H1 { list-style-type:none; font-weight:600; margin:4px; background:#eee } 15 | .toc .H2 { list-style-type:none; font-weight:600; margin:4px; } 16 | .toc .H3 { margin-left:2em } 17 | .toc .H4 { margin-left:4em } 18 | .toc .active { color:#0057b7 } 19 | .toc li:hover { background:#f0f0f0 } 20 | -------------------------------------------------------------------------------- /dist/casual-markdown.js: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * casual-markdown - a lightweight regexp-base markdown parser with TOC support 3 | * 2022/07/31, v0.90, refine frontmatter (simple yaml) 4 | * 2023/04/12, v0.92, addCopyButton for code-block 5 | * 6 | * Copyright (c) 2022-2023, Casualwriter (MIT Licensed) 7 | * https://github.com/casualwriter/casual-markdown 8 | *****************************************************************************/ 9 | ;(function(){ 10 | 11 | // define md object, and extent function (which is a dummy function) 12 | var md = { yaml:{}, before: function (str) {return str}, after: function (str) {return str} } 13 | 14 | // function for REGEXP to convert html tag. ie.=> <TAG*gt; 15 | md.formatTag = function (html) { return html.replace(//g,'>'); } 16 | 17 | // frontmatter for simple YAML (support multi-level, but string value only) 18 | md.formatYAML = function (front, matter) { 19 | var level = {}, latest = md.yaml; 20 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) { 21 | level[sp] = level[sp] || latest 22 | latest = level[sp][key.trim()] = val.trim() || {} 23 | for (e in level) if(e>sp) level[e]=null; 24 | } ); 25 | return '' 26 | } 27 | 28 | //===== format code-block, highlight remarks/keywords for code/sql 29 | md.formatCode = function (match, title, block) { 30 | // convert tag <> to < > tab to 3 space, support marker using ^^^ 31 | block = block.replace(//g,'>') 32 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1') 33 | 34 | // highlight comment and keyword based on title := none | sql | code 35 | if (title.toLowerCase(title) == 'sql') { 36 | block = block.replace(/^\-\-(.*)/gm,' --$1 ').replace(/\s\-\-(.*)/gm,'--$1 ') 37 | block = block.replace(/(\s?)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 38 | block = block.replace(/(\s?)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3') 39 | } else if ((title||'none')!=='none') { 40 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,'//$1 ') 41 | block = block.replace(/(\s?)(function|procedure|return|exit|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 42 | block = block.replace(/(\s?)(var|let|const|=>|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3') 43 | } 44 | 45 | return '' 46 | } 47 | 48 | // copy to clipboard for code-block 49 | md.clipboard = function (e) { 50 | navigator.clipboard.writeText( e.parentNode.innerText.replace('copy\n','') ) 51 | e.innerText = 'copied' 52 | } 53 | 54 | //===== parse markdown string into HTML string (exclude code-block) 55 | md.parser = function( mdstr ) { 56 | 57 | // apply yaml variables 58 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] ) 59 | 60 | // table syntax 61 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\s?\|\s?\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) { 62 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + block + '
') 63 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1') 64 | tbody = tbody.replace(/(.+)/gm,' ').replace(/\|/g,' $1 ') 65 | return '\n \n\n
\n\n' 66 | } ) 67 | 68 | // horizontal rule =>' + thead + '\n \n' + tbody + '\n
69 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 70 | 71 | // header =>..
72 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '
$1
') 73 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 74 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 75 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 76 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 77 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, ' $2 ') 78 | 79 | // inline code-block: `code-block` =>code-block
80 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} ) 81 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' ) 82 | 83 | // blockquote, max 2 levels =>{text}84 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '') 85 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1$1') 86 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 87 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 88 | 89 | // image syntax:  =>90 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 91 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 92 | 93 | // links syntax: [title "title"](url) => text 94 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 95 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 96 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 97 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 98 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 99 | 100 | // unordered/ordered list, max 2 levels =>
,
- ..
101 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 102 | mdstr = mdstr.replace(/^\d\d?[ .](.*)/gm, '
- $1
' ) 103 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 104 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 105 | mdstr = mdstr.replace(/<\/[ou]l\>\n\n?<[ou]l\>/g, '\n' ) 106 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 107 | 108 | // text decoration: bold, italic, underline, strikethrough, highlight 109 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 110 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 111 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 112 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 113 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 114 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 115 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 116 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 117 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 118 | 119 | // line break and paragraph =>
120 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 121 | 122 | // indent as code-block 123 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 124 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 125 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 126 | 127 | // Escaping Characters 128 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 129 | } 130 | 131 | //===== parse markdown string into HTML content (cater code-block) 132 | md.html = function (mdText) { 133 | // replace \r\n to \n, and handle front matter for simple YAML 134 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML ) 135 | // handle code-block. 136 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 137 | 138 | // split by "
", skip for code-block and process normal text 139 | var pos1=0, pos2=0, mdHTML = '' 140 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 141 | pos2 = mdText.indexOf('
', pos1 ) 142 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 143 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 144 | mdText = mdText.substr( pos2 + 7 ) 145 | } 146 | 147 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 148 | } 149 | 150 | //===== TOC support 151 | md.toc = function (srcDiv, tocDiv, options ) { 152 | 153 | // select elements, set title 154 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 155 | var tocTitle = (options&&options.title) || 'Table of Contents' 156 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 157 | var html = '' + (tocTitle=='none'? '' : '
"; 168 | 169 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found) 170 | if ( options && options.scrollspy ) { 171 | 172 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 173 | 174 | // get TOC elements, and viewport position 175 | var list = document.getElementById(tocDiv).querySelectorAll('li') 176 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 177 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 178 | 179 | // loop for each TOC element, add/remove scrollspy class 180 | for (var i=0; i' + tocTitle + '
'); 158 | 159 | // loop for each element,add- element with class in TAG name. 160 | for (var i=0; i
'; 165 | } 166 | 167 | document.getElementById(tocDiv).innerHTML = html + "' 164 | html += toc[i].textContent + ' 0 && pos => <TAG*gt; 14 | md.formatTag = function (html) { return html.replace(//g,'>'); } 15 | 16 | //===== format code-block, highlight remarks/keywords for code/sql 17 | md.formatCode = function (match, title, block) { 18 | // convert tag <> to < > tab to 3 space, support mark code using ^^^ 19 | block = block.replace(//g,'>') 20 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1') 21 | 22 | // highlight comment and keyword based on title := none | sql | code 23 | if (title.toLowerCase(title) == 'sql') { 24 | block = block.replace(/^\-\-(.*)/gm,' --$1 ').replace(/\s\-\-(.*)/gm,'--$1 ') 25 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 26 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3') 27 | } else if ((title||'none')!=='none') { 28 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,'//$1 ') 29 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 30 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3') 31 | } 32 | return '' 33 | } 34 | 35 | //===== parse markdown string into HTML string (exclude code-block) 36 | md.parser = function( mdstr ) { 37 | // table syntax 38 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) { 39 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + block + '
') 40 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1') 41 | tbody = tbody.replace(/(.+)/gm,' ').replace(/\|/g,' $1 ') 42 | return '\n \n\n
\n\n' 43 | } ) 44 | 45 | // horizontal rule =>' + thead + '\n \n' + tbody + '\n
46 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 47 | 48 | // header =>..
49 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '
$1
') 50 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 51 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 52 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 53 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 54 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, ' $2 ') 55 | 56 | // inline code-block: `code-block` =>code-block
57 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} ) 58 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' ) 59 | 60 | // blockquote, max 2 levels =>{text}61 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '') 62 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1$1') 63 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 64 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 65 | 66 | // image syntax:  =>67 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 68 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 69 | 70 | // links syntax: [title](url) => text 71 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 72 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 73 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 74 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 75 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 76 | 77 | // unordered/ordered list, max 2 levels =>
,
- ..
78 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 79 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '
- $1
' ) 80 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 81 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 82 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 83 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 84 | 85 | // text decoration: bold, italic, underline, strikethrough, highlight 86 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 87 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 88 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 89 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 90 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 91 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 92 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 93 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 94 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 95 | 96 | // line break and paragraph =>
97 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 98 | 99 | // indent as code-block 100 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 101 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 102 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 103 | 104 | // Escaping Characters 105 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 106 | } 107 | 108 | //===== parse markdown string into HTML content (cater code-block) 109 | md.html = function (mdText) { 110 | // first, handle syntax for code-block 111 | var pos1=0, pos2=0, mdHTML = '' 112 | mdText = mdText.replace(/\r\n/g, '\n').replace(/\n~~~/g,'\n```') 113 | mdText = mdText.replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 114 | 115 | // split by "
", skip for code-block and process normal text 116 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 117 | pos2 = mdText.indexOf('
', pos1 ) 118 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 119 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 120 | mdText = mdText.substr( pos2 + 7 ) 121 | } 122 | 123 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 124 | } 125 | 126 | //===== TOC support 127 | md.toc = function (srcDiv, tocDiv, options ) { 128 | 129 | // select elements, set title 130 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 131 | var tocTitle = (options&&options.title) || 'Table of Contents' 132 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 133 | var html = '' + (tocTitle=='none'? '' : '
"; 144 | 145 | //===== scrollspy support (ps: add to document if element(scroll) not found) 146 | if ( options && options.scrollspy ) { 147 | 148 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 149 | 150 | // get TOC elements, and viewport position 151 | var list = document.getElementById(tocDiv).querySelectorAll('li') 152 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 153 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 154 | 155 | // loop for each TOC element, add/remove scrollspy class 156 | for (var i=0; i' + tocTitle + '
'); 134 | 135 | // loop for each element,add- element with class in TAG name. 136 | for (var i=0; i
'; 141 | } 142 | 143 | document.getElementById(tocDiv).innerHTML = html + "' 140 | html += toc[i].textContent + ' 0 && pos => <TAG*gt; 14 | md.formatTag = function (html) { return html.replace(//g,'>'); } 15 | 16 | // frontmatter for simple YAML (only support one level and string value) 17 | md.formatYAML = function (front, matter) { 18 | matter.replace( /^\s*([^:]+):(.*)$/gm, function(m,key,val) { md.yaml[key.trim()] = val.trim() } ); 19 | return '' 20 | } 21 | 22 | //===== format code-block, highlight remarks/keywords for code/sql 23 | md.formatCode = function (match, title, block) { 24 | // convert tag <> to < > tab to 3 space, support marker using ^^^ 25 | block = block.replace(//g,'>') 26 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1') 27 | 28 | // highlight comment and keyword based on title := none | sql | code 29 | if (title.toLowerCase(title) == 'sql') { 30 | block = block.replace(/^\-\-(.*)/gm,' --$1 ').replace(/\s\-\-(.*)/gm,'--$1 ') 31 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 32 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3') 33 | } else if ((title||'none')!=='none') { 34 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,'//$1 ') 35 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 36 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3') 37 | } 38 | return '' 39 | } 40 | 41 | //===== parse markdown string into HTML string (exclude code-block) 42 | md.parser = function( mdstr ) { 43 | 44 | // apply yaml variables 45 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] ) 46 | 47 | // table syntax 48 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) { 49 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + block + '
') 50 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1') 51 | tbody = tbody.replace(/(.+)/gm,' ').replace(/\|/g,' $1 ') 52 | return '\n \n\n
\n\n' 53 | } ) 54 | 55 | // horizontal rule =>' + thead + '\n \n' + tbody + '\n
56 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 57 | 58 | // header =>..
59 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '
$1
') 60 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 61 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 62 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 63 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 64 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, ' $2 ') 65 | 66 | // inline code-block: `code-block` =>code-block
67 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} ) 68 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' ) 69 | 70 | // blockquote, max 2 levels =>{text}71 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '') 72 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1$1') 73 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 74 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 75 | 76 | // image syntax:  =>77 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 78 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 79 | 80 | // links syntax: [title "title"](url) => text 81 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 82 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 83 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 84 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 85 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 86 | 87 | // unordered/ordered list, max 2 levels =>
,
- ..
88 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 89 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '
- $1
' ) 90 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 91 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 92 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 93 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 94 | 95 | // text decoration: bold, italic, underline, strikethrough, highlight 96 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 97 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 98 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 99 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 100 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 101 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 102 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 103 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 104 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 105 | 106 | // line break and paragraph =>
107 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 108 | 109 | // indent as code-block 110 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 111 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 112 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 113 | 114 | // Escaping Characters 115 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 116 | } 117 | 118 | //===== parse markdown string into HTML content (cater code-block) 119 | md.html = function (mdText) { 120 | // replace \r\n to \n, and handle front matter for simple YAML 121 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML ) 122 | // handle code-block. 123 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 124 | 125 | // split by "
", skip for code-block and process normal text 126 | var pos1=0, pos2=0, mdHTML = '' 127 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 128 | pos2 = mdText.indexOf('
', pos1 ) 129 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 130 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 131 | mdText = mdText.substr( pos2 + 7 ) 132 | } 133 | 134 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 135 | } 136 | 137 | //===== TOC support 138 | md.toc = function (srcDiv, tocDiv, options ) { 139 | 140 | // select elements, set title 141 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 142 | var tocTitle = (options&&options.title) || 'Table of Contents' 143 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 144 | var html = '' + (tocTitle=='none'? '' : '
"; 155 | 156 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found) 157 | if ( options && options.scrollspy ) { 158 | 159 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 160 | 161 | // get TOC elements, and viewport position 162 | var list = document.getElementById(tocDiv).querySelectorAll('li') 163 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 164 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 165 | 166 | // loop for each TOC element, add/remove scrollspy class 167 | for (var i=0; i' + tocTitle + '
'); 145 | 146 | // loop for each element,add- element with class in TAG name. 147 | for (var i=0; i
'; 152 | } 153 | 154 | document.getElementById(tocDiv).innerHTML = html + "' 151 | html += toc[i].textContent + ' 0 && pos => <TAG*gt; 14 | md.formatTag = function (html) { return html.replace(//g,'>'); } 15 | 16 | // frontmatter for simple YAML (support multi-level, but string value only) 17 | md.formatYAML = function (front, matter) { 18 | var level = {}, latest = md.yaml; 19 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) { 20 | level[sp] = level[sp] || latest 21 | latest = level[sp][key.trim()] = val.trim() || {} 22 | for (e in level) if(e>sp) level[e]=null; 23 | } ); 24 | return '' 25 | } 26 | 27 | //===== format code-block, highlight remarks/keywords for code/sql 28 | md.formatCode = function (match, title, block) { 29 | // convert tag <> to < > tab to 3 space, support marker using ^^^ 30 | block = block.replace(//g,'>') 31 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1') 32 | 33 | // highlight comment and keyword based on title := none | sql | code 34 | if (title.toLowerCase(title) == 'sql') { 35 | block = block.replace(/^\-\-(.*)/gm,' --$1 ').replace(/\s\-\-(.*)/gm,'--$1 ') 36 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 37 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3') 38 | } else if ((title||'none')!=='none') { 39 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,'//$1 ') 40 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 41 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3') 42 | } 43 | return '' 44 | } 45 | 46 | //===== parse markdown string into HTML string (exclude code-block) 47 | md.parser = function( mdstr ) { 48 | 49 | // apply yaml variables 50 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] ) 51 | 52 | // table syntax 53 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) { 54 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + block + '
') 55 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1') 56 | tbody = tbody.replace(/(.+)/gm,' ').replace(/\|/g,' $1 ') 57 | return '\n \n\n
\n\n' 58 | } ) 59 | 60 | // horizontal rule =>' + thead + '\n \n' + tbody + '\n
61 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 62 | 63 | // header =>..
64 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '
$1
') 65 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 66 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 67 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 68 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 69 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, ' $2 ') 70 | 71 | // inline code-block: `code-block` =>code-block
72 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} ) 73 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' ) 74 | 75 | // blockquote, max 2 levels =>{text}76 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '') 77 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1$1') 78 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 79 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 80 | 81 | // image syntax:  =>82 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 83 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 84 | 85 | // links syntax: [title "title"](url) => text 86 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 87 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 88 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 89 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 90 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 91 | 92 | // unordered/ordered list, max 2 levels =>
,
- ..
93 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 94 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '
- $1
' ) 95 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 96 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 97 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 98 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 99 | 100 | // text decoration: bold, italic, underline, strikethrough, highlight 101 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 102 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 103 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 104 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 105 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 106 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 107 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 108 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 109 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 110 | 111 | // line break and paragraph =>
112 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 113 | 114 | // indent as code-block 115 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 116 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 117 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 118 | 119 | // Escaping Characters 120 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 121 | } 122 | 123 | //===== parse markdown string into HTML content (cater code-block) 124 | md.html = function (mdText) { 125 | // replace \r\n to \n, and handle front matter for simple YAML 126 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML ) 127 | // handle code-block. 128 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 129 | 130 | // split by "
", skip for code-block and process normal text 131 | var pos1=0, pos2=0, mdHTML = '' 132 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 133 | pos2 = mdText.indexOf('
', pos1 ) 134 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 135 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 136 | mdText = mdText.substr( pos2 + 7 ) 137 | } 138 | 139 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 140 | } 141 | 142 | //===== TOC support 143 | md.toc = function (srcDiv, tocDiv, options ) { 144 | 145 | // select elements, set title 146 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 147 | var tocTitle = (options&&options.title) || 'Table of Contents' 148 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 149 | var html = '' + (tocTitle=='none'? '' : '
"; 160 | 161 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found) 162 | if ( options && options.scrollspy ) { 163 | 164 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 165 | 166 | // get TOC elements, and viewport position 167 | var list = document.getElementById(tocDiv).querySelectorAll('li') 168 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 169 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 170 | 171 | // loop for each TOC element, add/remove scrollspy class 172 | for (var i=0; i' + tocTitle + '
'); 150 | 151 | // loop for each element,add- element with class in TAG name. 152 | for (var i=0; i
'; 157 | } 158 | 159 | document.getElementById(tocDiv).innerHTML = html + "' 156 | html += toc[i].textContent + ' 0 && pos => <TAG*gt; 15 | md.formatTag = function (html) { return html.replace(//g,'>'); } 16 | 17 | // frontmatter for simple YAML (support multi-level, but string value only) 18 | md.formatYAML = function (front, matter) { 19 | var level = {}, latest = md.yaml; 20 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) { 21 | level[sp] = level[sp] || latest 22 | latest = level[sp][key.trim()] = val.trim() || {} 23 | for (e in level) if(e>sp) level[e]=null; 24 | } ); 25 | return '' 26 | } 27 | 28 | //===== format code-block, highlight remarks/keywords for code/sql 29 | md.formatCode = function (match, title, block) { 30 | // convert tag <> to < > tab to 3 space, support marker using ^^^ 31 | block = block.replace(//g,'>') 32 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1') 33 | 34 | // highlight comment and keyword based on title := none | sql | code 35 | if (title.toLowerCase(title) == 'sql') { 36 | block = block.replace(/^\-\-(.*)/gm,' --$1 ').replace(/\s\-\-(.*)/gm,'--$1 ') 37 | block = block.replace(/(\s?)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 38 | block = block.replace(/(\s?)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3') 39 | } else if ((title||'none')!=='none') { 40 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,'//$1 ') 41 | block = block.replace(/(\s?)(function|procedure|return|exit|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 42 | block = block.replace(/(\s?)(var|let|const|=>|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3') 43 | } 44 | 45 | return '' 46 | } 47 | 48 | // copy to clipboard for code-block 49 | md.clipboard = function (e) { 50 | navigator.clipboard.writeText( e.parentNode.innerText.replace('copy\n','') ) 51 | e.innerText = 'copied' 52 | } 53 | 54 | //===== parse markdown string into HTML string (exclude code-block) 55 | md.parser = function( mdstr ) { 56 | 57 | // apply yaml variables 58 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] ) 59 | 60 | // table syntax 61 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\s?\|\s?\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) { 62 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + block + '
') 63 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1') 64 | tbody = tbody.replace(/(.+)/gm,' ').replace(/\|/g,' $1 ') 65 | return '\n \n\n
\n\n' 66 | } ) 67 | 68 | // horizontal rule =>' + thead + '\n \n' + tbody + '\n
69 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 70 | 71 | // header =>..
72 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '
$1
') 73 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 74 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 75 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 76 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 77 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, ' $2 ') 78 | 79 | // inline code-block: `code-block` =>code-block
80 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} ) 81 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' ) 82 | 83 | // blockquote, max 2 levels =>{text}84 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '') 85 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1$1') 86 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 87 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 88 | 89 | // image syntax:  =>90 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 91 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 92 | 93 | // links syntax: [title "title"](url) => text 94 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 95 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 96 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 97 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 98 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 99 | 100 | // unordered/ordered list, max 2 levels =>
,
- ..
101 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 102 | mdstr = mdstr.replace(/^\d\d?[ .](.*)/gm, '
- $1
' ) 103 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 104 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 105 | mdstr = mdstr.replace(/<\/[ou]l\>\n\n?<[ou]l\>/g, '\n' ) 106 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 107 | 108 | // text decoration: bold, italic, underline, strikethrough, highlight 109 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 110 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 111 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 112 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 113 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 114 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 115 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 116 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 117 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 118 | 119 | // line break and paragraph =>
120 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 121 | 122 | // indent as code-block 123 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 124 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 125 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 126 | 127 | // Escaping Characters 128 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 129 | } 130 | 131 | //===== parse markdown string into HTML content (cater code-block) 132 | md.html = function (mdText) { 133 | // replace \r\n to \n, and handle front matter for simple YAML 134 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML ) 135 | // handle code-block. 136 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 137 | 138 | // split by "
", skip for code-block and process normal text 139 | var pos1=0, pos2=0, mdHTML = '' 140 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 141 | pos2 = mdText.indexOf('
', pos1 ) 142 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 143 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 144 | mdText = mdText.substr( pos2 + 7 ) 145 | } 146 | 147 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 148 | } 149 | 150 | //===== TOC support 151 | md.toc = function (srcDiv, tocDiv, options ) { 152 | 153 | // select elements, set title 154 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 155 | var tocTitle = (options&&options.title) || 'Table of Contents' 156 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 157 | var html = '' + (tocTitle=='none'? '' : '
"; 168 | 169 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found) 170 | if ( options && options.scrollspy ) { 171 | 172 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 173 | 174 | // get TOC elements, and viewport position 175 | var list = document.getElementById(tocDiv).querySelectorAll('li') 176 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 177 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 178 | 179 | // loop for each TOC element, add/remove scrollspy class 180 | for (var i=0; i' + tocTitle + '
'); 158 | 159 | // loop for each element,add- element with class in TAG name. 160 | for (var i=0; i
'; 165 | } 166 | 167 | document.getElementById(tocDiv).innerHTML = html + "' 164 | html += toc[i].textContent + ' 0 && pos => <TAG*gt; 14 | md.formatTag = function (html) { return html.replace(//g,'>'); } 15 | 16 | // front matter for simple YAML (support 1 level only) 17 | md.formatYAML = function (front, matter) { 18 | matter.replace( /^\s*([^:]+):(.*)$/gm, function(m,key,val) { md.yaml[key.trim()] = val.trim() } ); 19 | return '' 20 | } 21 | 22 | //===== format code-block, highlight remarks/keywords for code/sql 23 | md.formatCode = function (match, title, block) { 24 | // convert tag <> to < > tab to 3 space, support mark code using ^^^ 25 | block = block.replace(//g,'>') 26 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1') 27 | 28 | // highlight comment and keyword based on title := none | sql | code 29 | if (title.toLowerCase(title) == 'sql') { 30 | block = block.replace(/^\-\-(.*)/gm,' --$1 ').replace(/\s\-\-(.*)/gm,'--$1 ') 31 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 32 | block = block.replace(/(\s)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3') 33 | } else if ((title||'none')!=='none') { 34 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,'//$1 ') 35 | block = block.replace(/(\s)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 36 | block = block.replace(/(\s)(var|let|const|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3') 37 | } 38 | return '' 39 | } 40 | 41 | //===== parse markdown string into HTML string (exclude code-block) 42 | md.parser = function( mdstr ) { 43 | // apply yaml variables 44 | console.log( 'BEFORE==>', mdstr.substr(0,100) ) 45 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] ) 46 | console.log( 'AFTER==>', mdstr.substr(0,100) ) 47 | // table syntax 48 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\|\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) { 49 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + block + '
') 50 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1') 51 | tbody = tbody.replace(/(.+)/gm,' ').replace(/\|/g,' $1 ') 52 | return '\n \n\n
\n\n' 53 | } ) 54 | 55 | // horizontal rule =>' + thead + '\n \n' + tbody + '\n
56 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 57 | 58 | // header =>..
59 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '
$1
') 60 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 61 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 62 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 63 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 64 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, ' $2 ') 65 | 66 | // inline code-block: `code-block` =>code-block
67 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} ) 68 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' ) 69 | 70 | // blockquote, max 2 levels =>{text}71 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '') 72 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1$1') 73 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 74 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 75 | 76 | // image syntax:  =>77 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 78 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 79 | 80 | // links syntax: [title "title"](url) => text 81 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 82 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 83 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 84 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 85 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 86 | 87 | // unordered/ordered list, max 2 levels =>
,
- ..
88 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 89 | mdstr = mdstr.replace(/^\d[ .](.*)/gm, '
- $1
' ) 90 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 91 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 92 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 93 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 94 | 95 | // text decoration: bold, italic, underline, strikethrough, highlight 96 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 97 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 98 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 99 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 100 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 101 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 102 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 103 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 104 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 105 | 106 | // line break and paragraph =>
107 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 108 | 109 | // indent as code-block 110 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 111 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 112 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 113 | 114 | // Escaping Characters 115 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 116 | } 117 | 118 | //===== parse markdown string into HTML content (cater code-block) 119 | md.html = function (mdText) { 120 | // replace \r\n to \n, and handle front matter for simple YAML 121 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML ) 122 | // handle code-block. 123 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 124 | 125 | // split by "
", skip for code-block and process normal text 126 | var pos1=0, pos2=0, mdHTML = '' 127 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 128 | pos2 = mdText.indexOf('
', pos1 ) 129 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 130 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 131 | mdText = mdText.substr( pos2 + 7 ) 132 | } 133 | 134 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 135 | } 136 | 137 | //===== TOC support 138 | md.toc = function (srcDiv, tocDiv, options ) { 139 | 140 | // select elements, set title 141 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 142 | var tocTitle = (options&&options.title) || 'Table of Contents' 143 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 144 | var html = '' + (tocTitle=='none'? '' : '
"; 155 | 156 | //===== scrollspy support (ps: add to document if element(scroll) not found) 157 | if ( options && options.scrollspy ) { 158 | 159 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 160 | 161 | // get TOC elements, and viewport position 162 | var list = document.getElementById(tocDiv).querySelectorAll('li') 163 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 164 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 165 | 166 | // loop for each TOC element, add/remove scrollspy class 167 | for (var i=0; i' + tocTitle + '
'); 145 | 146 | // loop for each element,add- element with class in TAG name. 147 | for (var i=0; i
'; 152 | } 153 | 154 | document.getElementById(tocDiv).innerHTML = html + "' 151 | html += toc[i].textContent + ' 0 && pos tag into HTML document 193 | //============================================================================= 194 | window.onload = function () { 195 | 196 | var html = ' ' 197 | html += ''; 201 | 202 | // add shortcut for edit current page. 203 | html += ' '; 204 | html += ' '; 205 | 206 | document.body.innerHTML = html 207 | document.body.style.display = 'block'; 208 | md.toc( 'content', 'toc', { scrollspy:'body' } ) 209 | 210 | } 211 | 212 | // toggle TOC 213 | function tocToggle(show) { 214 | var disp = document.getElementById('tocbox').style.display 215 | document.getElementById('tocbox').style.display = show||(disp=='none')? 'block' : 'none' 216 | } 217 | 218 | // debug: show HTML 219 | function debug() { 220 | var html = document.getElementById('content').innerHTML 221 | if (html.substr(0,5)=='' + (document.body.title||document.title) + ' ' 198 | html += '\n' 200 | html += '\n' + md.html(document.body.innerHTML.replace(/\>/g,'>')) + '') { 222 | document.getElementById('content').innerHTML = html.substr(5, html.length-11) 223 | } else { 224 | document.getElementById('content').innerHTML = ' ' + html.replace(/xmp\>/g,'|xmp>') + ' ' 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- /source/casual-markdown-page.html: -------------------------------------------------------------------------------- 1 | 2 |All-in-One 3 | 4 | 50 | 235 | 236 | 237 | 238 |239 | casual-markdown 240 | 241 |242 | 243 |244 | 245 | 246 |247 | 248 | 249 | 250 | 251 | 252 | 317 | -------------------------------------------------------------------------------- /source/casual-markdown.css: -------------------------------------------------------------------------------- 1 | .markdown code { background:#f0f0f0; color:navy; border-radius:6px; padding:2px; } 2 | .markdown pre { background:#f0f0f0; margin:12px; border:1px solid #ddd; padding:20px 12px; border-radius:6px; } 3 | .markdown pre:hover button { display:block; } 4 | .markdown pre button { display:none; position:relative; float:right; top:-16px } 5 | .markdown blockquote { background:#f0f0f0; border-left:6px solid grey; padding:8px } 6 | .markdown table { margin:12px; border-collapse: collapse; } 7 | .markdown th { border:1px solid grey; background:lightgrey; padding:6px; } 8 | .markdown td { border:1px solid grey; padding:6px; } 9 | .markdown tr:nth-child(even) { background:#f0f0f0; } 10 | .markdown ins { color:#890604 } 11 | .markdown rem { color:#198964 } 12 | .toc ul { padding: 0 12px; } 13 | .toc h3 { color:#0057b7; border-bottom:1px dotted grey } 14 | .toc .H1 { list-style-type:none; font-weight:600; margin:4px; background:#eee } 15 | .toc .H2 { list-style-type:none; font-weight:600; margin:4px; } 16 | .toc .H3 { margin-left:2em } 17 | .toc .H4 { margin-left:4em } 18 | .toc .active { color:#0057b7 } 19 | .toc li:hover { background:#f0f0f0 } 20 | -------------------------------------------------------------------------------- /source/casual-markdown.js: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * casual-markdown - a lightweight regexp-base markdown parser with TOC support 3 | * 2022/07/31, v0.90, refine frontmatter (simple yaml) 4 | * 2023/04/12, v0.92, addCopyButton for code-block 5 | * 6 | * Copyright (c) 2022-2023, Casualwriter (MIT Licensed) 7 | * https://github.com/casualwriter/casual-markdown 8 | *****************************************************************************/ 9 | ;(function(){ 10 | 11 | // define md object, and extent function (which is a dummy function) 12 | var md = { yaml:{}, before: function (str) {return str}, after: function (str) {return str} } 13 | 14 | // function for REGEXP to convert html tag. ie.=> <TAG*gt; 15 | md.formatTag = function (html) { return html.replace(//g,'>'); } 16 | 17 | // frontmatter for simple YAML (support multi-level, but string value only) 18 | md.formatYAML = function (front, matter) { 19 | var level = {}, latest = md.yaml; 20 | matter.replace( /^\s*#(.*)$/gm, '' ).replace( /^( *)([^:^\n]+):(.*)$/gm, function(m, sp, key,val) { 21 | level[sp] = level[sp] || latest 22 | latest = level[sp][key.trim()] = val.trim() || {} 23 | for (e in level) if(e>sp) level[e]=null; 24 | } ); 25 | return '' 26 | } 27 | 28 | //===== format code-block, highlight remarks/keywords for code/sql 29 | md.formatCode = function (match, title, block) { 30 | // convert tag <> to < > tab to 3 space, support marker using ^^^ 31 | block = block.replace(//g,'>') 32 | block = block.replace(/\t/g,' ').replace(/\^\^\^(.+?)\^\^\^/g, '$1') 33 | 34 | // highlight comment and keyword based on title := none | sql | code 35 | if (title.toLowerCase(title) == 'sql') { 36 | block = block.replace(/^\-\-(.*)/gm,' --$1 ').replace(/\s\-\-(.*)/gm,'--$1 ') 37 | block = block.replace(/(\s?)(function|procedure|return|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 38 | block = block.replace(/(\s?)(select|update|delete|insert|create|from|where|group by|having|set)(\s)/gim,'$1$2$3') 39 | } else if ((title||'none')!=='none') { 40 | block = block.replace(/^\/\/(.*)/gm,'//$1 ').replace(/\s\/\/(.*)/gm,'//$1 ') 41 | block = block.replace(/(\s?)(function|procedure|return|exit|if|then|else|end|loop|while|or|and|case|when)(\s)/gim,'$1$2$3') 42 | block = block.replace(/(\s?)(var|let|const|=>|for|next|do|while|loop|continue|break|switch|try|catch|finally)(\s)/gim,'$1$2$3') 43 | } 44 | 45 | return '' 46 | } 47 | 48 | // copy to clipboard for code-block 49 | md.clipboard = function (e) { 50 | navigator.clipboard.writeText( e.parentNode.innerText.replace('copy\n','') ) 51 | e.innerText = 'copied' 52 | } 53 | 54 | //===== parse markdown string into HTML string (exclude code-block) 55 | md.parser = function( mdstr ) { 56 | 57 | // apply yaml variables 58 | for (var name in this.yaml) mdstr = mdstr.replace( new RegExp('\{\{\\s*'+name+'\\s*\}\}', 'gm'), this.yaml[name] ) 59 | 60 | // table syntax 61 | mdstr = mdstr.replace(/\n(.+?)\n.*?\-\-\s?\|\s?\-\-.*?\n([\s\S]*?)\n\s*?\n/g, function (m,p1,p2) { 62 | var thead = p1.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1').replace(/\|/g,'' + block + '
') 63 | var tbody = p2.replace(/^\|(.+)/gm,'$1').replace(/(.+)\|$/gm,'$1') 64 | tbody = tbody.replace(/(.+)/gm,' ').replace(/\|/g,' $1 ') 65 | return '\n \n\n
\n\n' 66 | } ) 67 | 68 | // horizontal rule =>' + thead + '\n \n' + tbody + '\n
69 | mdstr = mdstr.replace(/^-{3,}|^\_{3,}|^\*{3,}$/gm, '
').replace(/\n\n
/g, '\n
') 70 | 71 | // header =>..
72 | mdstr = mdstr.replace(/^##### (.*?)\s*#*$/gm, '
$1
') 73 | .replace(/^#### (.*?)\s*#*$/gm, '$1
') 74 | .replace(/^### (.*?)\s*#*$/gm, '$1
') 75 | .replace(/^## (.*?)\s*#*$/gm, '$1
') 76 | .replace(/^# (.*?)\s*#*$/gm, '$1
') 77 | .replace(/^(.*?)\s*{(.*)}\s*<\/h\d\>$/gm, ' $2 ') 78 | 79 | // inline code-block: `code-block` =>code-block
80 | mdstr = mdstr.replace(/``(.*?)``/gm, function(m,p){ return '' + md.formatTag(p).replace(/`/g,'`') + '
'} ) 81 | mdstr = mdstr.replace(/`(.*?)`/gm, '$1
' ) 82 | 83 | // blockquote, max 2 levels =>{text}84 | mdstr = mdstr.replace(/^\>\> (.*$)/gm, '') 85 | mdstr = mdstr.replace(/^\> (.*$)/gm, '$1$1') 86 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 87 | mdstr = mdstr.replace(/<\/blockquote\>\n/g, '\n
' ) 88 | 89 | // image syntax:  =>90 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?) "(.*?)"\)/gm, '
') 91 | mdstr = mdstr.replace(/!\[(.*?)\]\((.*?)\)/gm, '
') 92 | 93 | // links syntax: [title "title"](url) => text 94 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "new"\)/gm, '$1') 95 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?) "(.*?)"\)/gm, '$1') 96 | mdstr = mdstr.replace(/([<\s])(https?\:\/\/.*?)([\s\>])/gm, '$1$2$3') 97 | mdstr = mdstr.replace(/\[(.*?)\]\(\)/gm, '$1') 98 | mdstr = mdstr.replace(/\[(.*?)\]\((.*?)\)/gm, '$1') 99 | 100 | // unordered/ordered list, max 2 levels =>
,
- ..
101 | mdstr = mdstr.replace(/^[\*+-][ .](.*)/gm, '
- ..
' ) 102 | mdstr = mdstr.replace(/^\d\d?[ .](.*)/gm, '
- $1
' ) 103 | mdstr = mdstr.replace(/^\s{2,6}[\*+-][ .](.*)/gm, '
- $1
' ) 104 | mdstr = mdstr.replace(/^\s{2,6}\d[ .](.*)/gm, '
- $1
' ) 105 | mdstr = mdstr.replace(/<\/[ou]l\>\n\n?<[ou]l\>/g, '\n' ) 106 | mdstr = mdstr.replace(/<\/[ou]l\>\n<[ou]l\>/g, '\n' ) 107 | 108 | // text decoration: bold, italic, underline, strikethrough, highlight 109 | mdstr = mdstr.replace(/\*\*\*(\w.*?[^\\])\*\*\*/gm, '$1') 110 | mdstr = mdstr.replace(/\*\*(\w.*?[^\\])\*\*/gm, '$1') 111 | mdstr = mdstr.replace(/\*(\w.*?[^\\])\*/gm, '$1') 112 | mdstr = mdstr.replace(/___(\w.*?[^\\])___/gm, '$1') 113 | mdstr = mdstr.replace(/__(\w.*?[^\\])__/gm, '$1') 114 | // mdstr = mdstr.replace(/_(\w.*?[^\\])_/gm, '$1') // NOT support!! 115 | mdstr = mdstr.replace(/\^\^\^(.+?)\^\^\^/gm, '$1') 116 | mdstr = mdstr.replace(/\^\^(\w.*?)\^\^/gm, '$1') 117 | mdstr = mdstr.replace(/~~(\w.*?)~~/gm, '
- $1
$1') 118 | 119 | // line break and paragraph =>
120 | mdstr = mdstr.replace(/ \n/g, '\n
').replace(/\n\s*\n/g, '\n\n') 121 | 122 | // indent as code-block 123 | mdstr = mdstr.replace(/^ {4,10}(.*)/gm, function(m,p) { return '
'} ) 124 | mdstr = mdstr.replace(/^\t(.*)/gm, function(m,p) { return '' + md.formatTag(p) + '
'} ) 125 | mdstr = mdstr.replace(/<\/code\><\/pre\>\n' + md.formatTag(p) + '
/g, '\n' ) 126 | 127 | // Escaping Characters 128 | return mdstr.replace(/\\([`_~\*\+\-\.\^\\\<\>\(\)\[\]])/gm, '$1' ) 129 | } 130 | 131 | //===== parse markdown string into HTML content (cater code-block) 132 | md.html = function (mdText) { 133 | // replace \r\n to \n, and handle front matter for simple YAML 134 | mdText = mdText.replace(/\r\n/g, '\n').replace( /^---+\s*\n([\s\S]*?)\n---+\s*\n/, md.formatYAML ) 135 | // handle code-block. 136 | mdText = mdText.replace(/\n~~~/g,'\n```').replace(/\n``` *(.*?)\n([\s\S]*?)\n``` *\n/g, md.formatCode) 137 | 138 | // split by "
", skip for code-block and process normal text 139 | var pos1=0, pos2=0, mdHTML = '' 140 | while ( (pos1 = mdText.indexOf('
')) >= 0 ) { 141 | pos2 = mdText.indexOf('
', pos1 ) 142 | mdHTML += md.after( md.parser( md.before( mdText.substr(0,pos1) ) ) ) 143 | mdHTML += mdText.substr(pos1, (pos2>0? pos2-pos1+7 : mdtext.length) ) 144 | mdText = mdText.substr( pos2 + 7 ) 145 | } 146 | 147 | return '' + mdHTML + md.after( md.parser( md.before(mdText) ) ) + '' 148 | } 149 | 150 | //===== TOC support 151 | md.toc = function (srcDiv, tocDiv, options ) { 152 | 153 | // select elements, set title 154 | var tocSelector = (options&&options.css) || 'h1,h2,h3,h4' 155 | var tocTitle = (options&&options.title) || 'Table of Contents' 156 | var toc = document.getElementById(srcDiv).querySelectorAll( tocSelector ) 157 | var html = '' + (tocTitle=='none'? '' : '
"; 168 | 169 | //===== scrollspy support (ps: add to document.body if element(scrollspy) not found) 170 | if ( options && options.scrollspy ) { 171 | 172 | (document.getElementById(options.scrollspy)||document).onscroll = function () { 173 | 174 | // get TOC elements, and viewport position 175 | var list = document.getElementById(tocDiv).querySelectorAll('li') 176 | var divScroll = document.getElementById(options.scrollspy) || document.documentElement 177 | var divHeight = divScroll.clientHeight || divScroll.offsetHeight 178 | 179 | // loop for each TOC element, add/remove scrollspy class 180 | for (var i=0; i' + tocTitle + '
'); 158 | 159 | // loop for each element,add- element with class in TAG name. 160 | for (var i=0; i
'; 165 | } 166 | 167 | document.getElementById(tocDiv).innerHTML = html + "' 164 | html += toc[i].textContent + ' 0 && pos