AnP/Public/ecma/Utils/MarkDown.ecma.js
2026-06-20 10:04:54 +02:00

127 lines
4.6 KiB
JavaScript

"use strict";
export const MarkDown = (function(){
const MarkDown = function(anp){};
MarkDown.Item = function(pattern, replace, block = false){
this.pattern = pattern;
this.replace = replace;
this.block = block;
this.match = null;
this.length = 0;
this.more = true;
this.index = -1;
};
MarkDown.Header = () => new MarkDown.Item(/^(#{1,6})\s*(.+)$/m, (match, hashes, content) => `<h${hashes.length}>${MarkDown.to_html(content, false)}</h${hashes.length}>`, true);
MarkDown.Block = () => new MarkDown.Item(/^```([a-z]*)\r?\n([\s\S]*?)\r?\n```/, (match, lang, content) => `<fieldset><legend>${lang}</legend><pre><code class="${lang}">${content}</code></pre></fieldset>`, true);
MarkDown.BlockQuote = () => new MarkDown.Item(/^>\s?(.+)$/m, (match, content) => `<blockquote>${MarkDown.to_html(content, false)}</blockquote>`, true);
MarkDown.Paragraph = () => new MarkDown.Item(/^((?:[^\r\n]+(?:\r\n|[\r\n])?)+)/m, (match, content) => `<p>${MarkDown.to_html(content, false)}</p>\n\n`, true);
MarkDown.Link = () => new MarkDown.Item(/\[([^\]]+)\]\(([^)]+)\)|([a-z]{2,12}:\/{2}[^ "']+)/, (match, text, url, link) => `<a href="${url || link}" target="_blank" title="${text || link}">${text || link}</a>`);
MarkDown.Bold = () => new MarkDown.Item(/\*{2}((?:(?!(?:\*{2})).)+)\*{2}/, (match, content) => `<b>${MarkDown.to_html(content, false)}</b>`);
MarkDown.Italic = () => new MarkDown.Item(/\*((?:(?!(?:\*)).|\*{2})+)\*(?!\*)/, (match, content) => `<i>${MarkDown.to_html(content, false)}</i>`);
// MarkDown.UnorderedList = () => new MarkDown.Item(/^\s*[-+*]\s+(.+)$/m, (match, content) => `<ul><li>${MarkDown.to_html(content, false)}</li></ul>`, true);
// MarkDown.OrderedList = () => new MarkDown.Item(/^(\s*\d+\.\s+.+(?:\r\n|[\r\n])?)$/m, (match, content) => `<ol><li>${MarkDown.to_html(content, false)}</li></ol>`, true);
// MarkDown.Table = () => new MarkDown.Item(/^\s*\|(.+)\|\s*$/m, (match, content) => {
// const rows = content.split(/\r?\n/).map(row => row.trim().split("|").map(cell => cell.trim()));
// if(rows.length < 2)
// return content;
// const header = rows[0],
// alignments = rows[1].map(cell => {
// if(/^:-+:$/.test(cell))
// return "center";
// else if(/^-+:$/.test(cell))
// return "right";
// else if(/^:-+$/.test(cell))
// return "left";
// return null;
// }),
// body = rows.slice(2);
// return `<table><thead><tr>${header.map((cell, i) => `<th${alignments[i] ? ` style="text-align:${alignments[i]}"` : ""}>${MarkDown.to_html(cell, false)}</th>`).join("")}</tr></thead><tbody>${body.map(row => `<tr>${row.map((cell, i) => `<td${alignments[i] ? ` style="text-align:${alignments[i]}"` : ""}>${MarkDown.to_html(cell, false)}</td>`).join("")}</tr>`).join("")}</tbody></table>`;
// }, true);
MarkDown.to_html = (string, blocks = true) => {
let html = ``;
const matches = [
MarkDown.Header(),
MarkDown.Block(),
MarkDown.BlockQuote(),
MarkDown.Paragraph(),
MarkDown.Link(),
MarkDown.Bold(),
MarkDown.Italic()
];
do{
let index = 1 << 28,
i = null;
[...matches].forEach((item, j) => {
if(!item.more)
return;
if(item.block && !blocks){
item.more = false;
return;
};
if(item.index < 0){
const submatches = string.match(item.pattern);
if(!submatches){
item.more = false;
return;
};
item.match = submatches;
item.length = submatches[0].length;
item.index = submatches.index;
};
if(index > item.index){
index = item.index;
i = j;
};
});
if(i === null)
break;
const item = matches[i],
total = index + item.length;
html += string.substring(0, index) + item.replace(...item.match);
string = string.substring(total);
matches.forEach(item => {
item.index -= total;
});
}while(matches.length)
html += string;
return html;
}
return MarkDown;
})();