168 lines
5.4 KiB
TypeScript
168 lines
5.4 KiB
TypeScript
import { parse_md_to_html_with_warnings, ParseResult } from './makoto.js';
|
|
import type { Warning } from './endosulfan.js';
|
|
|
|
/*todo:
|
|
- show multiple warnings per line
|
|
- show warnings that do not have line number
|
|
- show warning type, ability to ignore warnings based on type
|
|
- keyboard shortcuts???
|
|
*/
|
|
|
|
let editor: HTMLTextAreaElement = document.getElementById("editor")! as HTMLTextAreaElement;
|
|
let preview: HTMLElement = document.getElementById("rendered-text")!;
|
|
let dark_theme_toggle: HTMLInputElement = document.getElementById("dark-theme-toggle")! as HTMLInputElement;
|
|
let html_toggle: HTMLInputElement = document.getElementById("html-toggle")! as HTMLInputElement;
|
|
|
|
let show_html: boolean = false;
|
|
let unedited: boolean = true;
|
|
|
|
let use_local_storage: boolean = false;
|
|
|
|
let ignore_all_warnings: boolean = false;
|
|
let ignore_warnings: string[] = [];
|
|
|
|
function render_warnings(warnings: Warning[]) {
|
|
document.querySelectorAll(".line-warning").forEach((item: Element) => item.classList.remove("line-warning"));
|
|
warnings.forEach((warning: Warning) => {
|
|
if (ignore_warnings.includes(warning.type)) return;
|
|
if (warning.line_number) {
|
|
let line: HTMLElement = editor.children[warning.line_number-1] as HTMLElement;
|
|
line.classList.add("line-warning");
|
|
line.title = warning.message;
|
|
}
|
|
});
|
|
}
|
|
|
|
const refresh_html = () => {
|
|
//go through the lines and get the editor text
|
|
let editor_text: string = Array.from(editor.children).map((item) => item.textContent).reduce((added, current) => added+"\n"+current);
|
|
if (use_local_storage) {
|
|
localStorage.setItem("markdown", editor_text);
|
|
}
|
|
let parsed: ParseResult = parse_md_to_html_with_warnings(editor_text);
|
|
if (!ignore_all_warnings) {
|
|
render_warnings(parsed.warnings);
|
|
}
|
|
if (show_html) {
|
|
preview.innerText = parsed.html;
|
|
} else {
|
|
preview.innerHTML = parsed.html;
|
|
}
|
|
};
|
|
|
|
editor.addEventListener("keyup", () => {
|
|
if (editor.children.length === 0) {
|
|
//the first <li> was deleted
|
|
let li: HTMLElement = document.createElement("LI");
|
|
unedited = true;
|
|
editor.appendChild(li);
|
|
//reset cursor position
|
|
let range: Range = document.createRange();
|
|
range.setStart(li, 0);
|
|
range.collapse(true);
|
|
let selection: Selection = window.getSelection();
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
}
|
|
refresh_html();
|
|
});
|
|
|
|
document.addEventListener("click", (e: MouseEvent) => {
|
|
if (e.target === editor && unedited) {
|
|
(editor.children[0] as HTMLElement).innerText = "";
|
|
unedited = false;
|
|
refresh_html();
|
|
} else if (e.target !== editor && editor.innerText.trim() === "" && editor.children.length === 1) {
|
|
(editor.children[0] as HTMLElement).innerText = "markdown goes here...";
|
|
unedited = true;
|
|
}
|
|
});
|
|
|
|
const theme_change = () => {
|
|
if (dark_theme_toggle.checked) {
|
|
preview.classList.add("dark");
|
|
} else {
|
|
preview.classList.remove("dark");
|
|
}
|
|
};
|
|
|
|
dark_theme_toggle.addEventListener("change", theme_change);
|
|
|
|
const html_change = () => {
|
|
let changed: boolean = show_html !== html_toggle.checked;
|
|
if (changed) {
|
|
show_html = show_html ? false : true;
|
|
refresh_html();
|
|
}
|
|
}
|
|
|
|
html_toggle.addEventListener("change", html_change);
|
|
|
|
//applies if the browser remembers what the user typed in
|
|
if (editor.innerText.trim() !== "markdown goes here...") {
|
|
unedited = false;
|
|
}
|
|
|
|
let params: URLSearchParams = new URLSearchParams(window.location.search);
|
|
if (params.get("help") === "true") {
|
|
//give a quick intro to markdown
|
|
(editor.children[0] as HTMLElement).innerText = "# Makoto Markdown Parser";
|
|
let extra_lines: string[] = [
|
|
"This markdown parser is powered by spaghetti. You can have **bold text** or *italic text*, and even ^superscripts!^",
|
|
"Of course, you can have [links](https://en.wikipedia.org), and use backslashes to \\*escape\\*. Here's a list:",
|
|
"- uno",
|
|
"- dos",
|
|
"- tres",
|
|
"> ## Wow! A blockquote!",
|
|
"> Reasons why blockquotes are cool:",
|
|
"> 1. They are blocks",
|
|
"> 2. They are also quotes",
|
|
"Now here's some `code`!!!!",
|
|
"```rust",
|
|
"fn main() {",
|
|
" println!('HOLA MUNDO');",
|
|
"}",
|
|
"```",
|
|
"---",
|
|
""
|
|
];
|
|
for (let i=0; i < extra_lines.length; i++) {
|
|
let additional_line: HTMLElement = document.createElement("LI");
|
|
//needs to be .innerHTML so the html space entity can be parsed
|
|
additional_line.innerHTML = extra_lines[i];
|
|
editor.appendChild(additional_line);
|
|
}
|
|
}
|
|
|
|
if (params.get("save") === "true") {
|
|
//save to local storage, and retrieve from it
|
|
if (localStorage) {
|
|
use_local_storage = true;
|
|
}
|
|
let stored_markdown: string = localStorage.getItem("markdown");
|
|
if (stored_markdown) {
|
|
let extra_lines: string[] = stored_markdown.split("\n");
|
|
(editor.children[0] as HTMLElement).innerText = extra_lines.shift();
|
|
for (let i=0; i < extra_lines.length; i++) {
|
|
let additional_line: HTMLElement = document.createElement("LI");
|
|
//needs to be .innerHTML so the html space entity can be parsed
|
|
additional_line.innerHTML = extra_lines[i];
|
|
editor.appendChild(additional_line);
|
|
}
|
|
unedited = false;
|
|
}
|
|
}
|
|
|
|
if (params.get("ignore")) {
|
|
//allow user to specify warnings to ignore
|
|
if (params.get("ignore") === "all") {
|
|
ignore_all_warnings = true;
|
|
} else {
|
|
ignore_warnings = params.get("ignore").split(",");
|
|
}
|
|
}
|
|
|
|
refresh_html();
|
|
theme_change();
|
|
html_change();
|