-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathscript.js
More file actions
122 lines (110 loc) · 6.15 KB
/
script.js
File metadata and controls
122 lines (110 loc) · 6.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
const params = new URLSearchParams(window.location.search);
var markdownFile = "";
if (params.get('page') == "CV") {
markdownFile = "src/CV.md";
} else if(params.get('page') == null){
markdownFile = "src/profile.md";
} else {
markdownFile = "posts/" + params.get('page') + ".md"
}
// 使用 fetch API 讀取 Markdown 文件內容
fetch(markdownFile)
.then(response => response.text())
.then(markdownText => {
// 將 Markdown 轉換為 HTML
const htmlText = markdownToHtml(markdownText);
// 顯示轉換後的 HTML
document.getElementById('html-output').innerHTML = htmlText;
})
.catch(error => console.error('Error fetching the Markdown file:', error));
// 將 Markdown 轉換為 HTML 的函式
function markdownToHtml(markdown) {
// 定義正則表達式模式和標誌
const patterns = {
heading6: { pattern: "^###### (.*)$", flags: "gm", replacement: "<h6>$1</h6>" },
heading5: { pattern: "^##### (.*)$", flags: "gm", replacement: "<h5>$1</h5>" },
heading4: { pattern: "^#### (.*)$", flags: "gm", replacement: "<h4>$1</h4>" },
heading3: { pattern: "^### (.*)$", flags: "gm", replacement: "<h3>$1</h3>" },
heading2: { pattern: "^## (.*)$", flags: "gm", replacement: "<h2>$1</h2>" },
heading1: { pattern: "^# (.*)$", flags: "gm", replacement: "<h1>$1</h1>" },
bold: { pattern: "\\*\\*(.*?)\\*\\*", flags: "gm", replacement: "<b>$1</b>" },
italic: { pattern: "\\*(.*?)\\*", flags: "gm", replacement: "<i>$1</i>" },
strikethrough: { pattern: "~~(.*?)~~", flags: "gm", replacement: "<del>$1</del>" },
codeBlock: { pattern: "```([a-z]*)\\n([\\s\\S]*?)```", flags: "gm", replacement: function(match, lang, code) {
return `<pre><code class="language-${lang}">${code.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>')}</code></pre>`;
}},
inlineCode: { pattern: "`([^`]+)`", flags: "gm", replacement: "<code>$1</code>" },
// 使用前瞻確保不是圖片
link: { pattern: "(?<!\\!)\\\[([^\\\]]+)\\\]\\\(([^)]+)\\\)", flags: "gm", replacement: "<a href=\"$2\" target=\"_blank\">$1</a>" }, image: { pattern: "!\\\[([^\\\]]*)\\\]\\\(([^)]+)\\\)", flags: "gm", replacement: "<img src=\"$2\" alt=\"$1\" />" },
horizontalRule: { pattern: "^---$", flags: "gm", replacement: "<hr />" },
// 處理檢核方塊,先於無序列表
checkboxUnchecked: { pattern: "^\\s*\\- \\\[ \\\] (.*)$", flags: "gm", replacement: "<ul class=\"checkbox\"><li><input type=\"radio\" class=\"checkbox-off\" disabled/> $1</li></ul>" },
checkboxChecked: { pattern: "^\\s*\\- \\\[x\\\] (.*)$", flags: "gm", replacement: "<ul class=\"checkbox\"><li><input type=\"radio\" class=\"checkbox-on\" disabled checked/> $1</li></ul>" },// 處理無序列表,匹配星號、連字號和加號,允許前面有空格
unorderedList: { pattern: "^(?!\\s*\\- \\[ \\])(?!\\s*\\- \\[x\\])\\s*[\\*\\-\\+] (.*)$", flags: "gm", replacement: "<ul><li>$1</li></ul>" },
orderedList: { pattern: "^\\s*(\\d+)\\. (.*)$", flags: "gm", replacement: "<ol start=\"$1\"><li>$2</li></ol>" },
blockquote: { pattern: "^> (.*)$", flags: "gm", replacement: "<blockquote>$1</blockquote>" },
// 處理兩個或更多換行符號
paragraphBreak: { pattern: "\n{2,}", flags: "gm", replacement: "</p><p>" },
// 處理行尾有兩個或更多空格的換行符號
lineBreakWithSpaces: { pattern: " {2,}\n", flags: "gm", replacement: "<br>" },
// 處理單個換行符號
lineBreak: { pattern: "(?<!<br>)\n", flags: "gm", replacement: " <br>" },
table: {
pattern: "^\\|(.+)\\|\n\\|(?:-+\\|)+\n((?:\\|.*\\|\\n)*)",
flags: "gm",
replacement: function(match, header, body) {
const headers = header.split('|').map(h => `<th>${h.trim()}</th>`).join('');
const rows = body.trim().split('\n').map(row => {
const cells = row.split('|').filter(c => c.trim() !== '').map(c => `<td>${c.trim()}</td>`).join('');
return `<tr>${cells}</tr>`;
}).join('');
return `<table><thead><tr>${headers}</tr></thead><tbody>${rows}</tbody></table>`;
}
}
};
for (const key of ["heading6", "heading5", "heading4", "heading3", "heading2", "heading1", "horizontalRule", "blockquote", "codeBlock", "unorderedList", "orderedList", "checkboxUnchecked", "checkboxChecked", "table"]) {
const { pattern, flags, replacement } = patterns[key];
const regex = new RegExp(pattern, flags);
markdown = markdown.replace(regex, replacement);
}
// 處理段落和換行
const lines = markdown.split('\n');
let inParagraph = false;
let result = '';
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (line === '') {
if (inParagraph) {
result += '</p>';
inParagraph = false;
}
} else if (!line.match(/^(<h[1-6]>|<hr>|<blockquote>|<pre>|<ul>|<ol>|<li>|<table>|<\/table>|<tr>|<\/tr>|<th>|<\/th>|<td>|<\/td>)/)) {
if (!inParagraph) {
result += '<p>';
inParagraph = true;
}
result += line + ' ';
} else {
if (inParagraph) {
result += '</p>';
inParagraph = false;
}
result += line;
}
}
if (inParagraph) {
result += '</p>';
}
// 再處理其他元素
for (const key of ["bold", "italic", "strikethrough", "inlineCode", "link", "image", "paragraphBreak", "lineBreakWithSpaces", "lineBreak"]) {
const { pattern, flags, replacement } = patterns[key];
const regex = new RegExp(pattern, flags);
result = result.replace(regex, replacement);
}
// 合併連續的 <ul> 和 <ol> 列表項
result = result.replace(/<\/ul>\s*<ul>/gim, '');
result = result.replace(/<\/ol>\s*<ol start="\d+">/gim, '');
// 移除多餘的 <p> 標籤,包括那些包含空白字符的情況
result = result.replace(/<p>\s*<\/p>/gim, '');
return result.trim();
}