fixes, add web warnings

This commit is contained in:
Jon Dough
2023-06-13 22:31:42 +08:00
parent d454a1f8ea
commit a5cfb04510
5 changed files with 144 additions and 31 deletions

View File

@@ -79,7 +79,7 @@ test_assert_equal(parse_md_to_html("> ```\n> alert('e')\n> ```"), "<blockquote>\
test_assert_equal(parse_md_to_html("> a\n\n> b"), "<blockquote>\n<p>a</p>\n</blockquote>\n<blockquote>\n<p>b</p>\n</blockquote>", "block quote test 3");
test_assert_equal(parse_md_to_html("> - burger\n> -winter melons\n> abcdefg\n> - fries\n- p**i**zza\nabacus"), "<blockquote>\n<ul>\n<li>burger</li>\n</ul>\n<p>-winter melons</p>\n<p>abcdefg</p>\n<ul>\n<li>fries</li>\n</ul>\n</blockquote>\n<ul>\n<li>p<b>i</b>zza</li>\n</ul>\n<p>abacus</p>", "unordered lists test");
test_assert_equal(parse_md_to_html("> - burger\n> -winter melons\n> abcdefg\n> - fries\n- p**i**zza\na"), "<blockquote>\n<ul>\n<li>burger</li>\n</ul>\n<p>-winter melons</p>\n<p>abcdefg</p>\n<ul>\n<li>fries</li>\n</ul>\n</blockquote>\n<ul>\n<li>p<b>i</b>zza</li>\n</ul>\n<p>a</p>", "unordered lists test");
test_assert_equal(parse_md_to_html("1. a\n2. b\n3. c\n5. should *fail*\n> 1. d\n> 2. e\n3. should fail too"), "<ol>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n</ol>\n<p>5. should <i>fail</i></p>\n<blockquote>\n<ol>\n<li>d</li>\n<li>e</li>\n</ol>\n</blockquote>\n<p>3. should fail too</p>", "ordered lists test 1")

View File

@@ -225,6 +225,11 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
}
}
}
warnings.push({
type: "italic-not-closed",
message: "Italic not closed, may be missing closing '*'? Backslash the '*' if this is intentional",
line_number,
});
} else if (asterisk_num === 2) {
//remove the last <b> and replace it with a **
let split: string[] = html_line.split("<b>");
@@ -239,6 +244,11 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
}
}
}
warnings.push({
type: "bold-not-closed",
message: "Bold not closed, may be missing closing '**'? Backslash the '**' if this is intentional",
line_number,
});
}
asterisk_num = 0;
asterisk_out_num = 0;
@@ -260,6 +270,11 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
}
}
in_superscript = false;
warnings.push({
type: "superscript-not-closed",
message: "Superscript not closed, may be missing closing '^'? Backslash the '^' if this is intentional",
line_number,
});
}
//ending table row
if (in_table) {
@@ -286,7 +301,23 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
}
html_line = "";
horizontal_num = 0;
if (char === "\n") {
line_number++;
}
//check to see if unordered list is ending
if (in_unordered_list && char === "\n" && ((chars.slice(i+1, i+3) !== "- " && !blockquote_list) || (chars.slice(i+1, i+5) !== "> - " && blockquote_list))) {
html += "</ul>\n";
in_unordered_list = false;
blockquote_list = false;
}
//check to see if ordered list is ending
let ol_num_length: number = String(ordered_list_num+1).length;
if (in_ordered_list && char === "\n" && ((chars.slice(i+1, i+ol_num_length+3) !== `${ordered_list_num+1}. ` && !blockquote_list) || (chars.slice(i+1, i+ol_num_length+5) !== `> ${ordered_list_num+1}. ` && blockquote_list))) {
html += "</ol>\n";
ordered_list_num = 0;
in_ordered_list = false;
blockquote_list = false;
}
if (horizontal_rule || was_image || was_link) {
if (i !== chars.length - 1 && html[html.length-1] !== "\n") {
//only add new line if there isn't already one, and isn't last character
@@ -434,10 +465,6 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
blockquote_list = true;
}
continue;
} else if (in_unordered_list && ((((chars[i-1] === "\n" && char !== "-") || (chars[i-2] === "\n" && char !== " ")) && !blockquote_list) || (((chars[i-3] === "\n" && char !== "-") || (chars[i-4] === "\n" && char !== " ")) && blockquote_list))) {
html += "</ul>\n";
in_unordered_list = false;
blockquote_list = false;
}
//handle ordered lists
let ol_num_length: number = String(ordered_list_num+1).length;
@@ -452,11 +479,6 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
blockquote_list = true;
}
continue;
} else if (in_ordered_list && ((chars[i-ol_num_length-2] === "\n" && chars.slice(i-ol_num_length-1, i+1) !== `${ordered_list_num+1}. ` && !in_blockquote) || (in_blockquote && chars[i-ol_num_length-4] === "\n" && chars.slice(i-ol_num_length-3, i+1) !== `> ${ordered_list_num+1}. `))) {
html += "</ol>\n";
ordered_list_num = 0;
in_ordered_list = false;
blockquote_list = false;
}
//handle code
if (char === "`" && !in_code) {
@@ -534,7 +556,7 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
//ensure headings are continuous and have after it ("#a##" or "##abc" are not a valid headings), and are at the beginning of the line
//ensure headings are possible in block quotes
if (chars.slice(i-heading_level-1, i) === "\n"+"#".repeat(heading_level) || (is_first_line && chars.slice(0, i) === "#".repeat(heading_level)) || (chars.slice(i-heading_level-3, i) === "\n> "+"#".repeat(heading_level) && in_blockquote) || (is_first_line && chars.slice(0, i) === "> "+"#".repeat(heading_level) && in_blockquote)) {
if (char === "#" && !in_heading && heading_level <= 6) {
if (char === "#" && !in_heading && heading_level < 6) {
heading_level++;
continue;
} else if (heading_level > 0 && char === " " && !in_heading) {
@@ -542,6 +564,12 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
html_line = `<h${heading_level} id="header-${header_num}">`;
header_num++;
continue;
} else if (char === "#" && heading_level === 6) {
warnings.push({
type: "too-much-header",
message: "Header cannot be more than 6 levels",
line_number,
})
} else if (heading_level > 0) {
//not a heading
html_line = "<p>"+"#".repeat(heading_level);
@@ -569,6 +597,7 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
} else if (horizontal_num > 0) {
//no longer a horizontal line
html_line = "<p>"+"-".repeat(horizontal_num);
if (horizontal_num > 2) {
warnings.push({
type: "horizontal-rule-broken",
message: "Horizontal rule broken",
@@ -576,6 +605,7 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
});
}
}
}
//handle images
if (char === "!" && chars[i+1] === "[") {
continue;
@@ -591,6 +621,13 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
if (chars[i+1] === ")" && i+1 === chars.length-1) {
image_src += char;
}
if (image_alt === "") {
warnings.push({
type: "missing-image-alt",
message: "Image is missing alt text, this is bad for accessibility",
line_number,
});
}
html_line += `<img src="${image_src}" alt="${image_alt}">`;
was_image = true;
image_alt = undefined;
@@ -625,6 +662,13 @@ export function parse_md_to_html_with_warnings(md: string): ParseResult {
if (chars[before_link] === "\n" || before_link === -1) {
html_line = "<p>";
}
if (link_content === "") {
warnings.push({
type: "empty-link",
message: "Link missing text",
line_number,
});
}
html_line += `<a href="${link_href}">${link_content}</a>`;
was_link = true;
link_content = undefined;

View File

@@ -7,7 +7,7 @@ blockquote {
}
p {
margin: 4px 0px;
margin: 7px 0px;
}
h1, h2, h3, h4, h5, h6 {
@@ -18,6 +18,8 @@ h1, h2, h3, h4, h5, h6 {
.code-block {
font-family: 'Courier New', Courier, monospace;
background-color: #d8d8d8;
padding: 2px 4px;
word-break: break-all;
}
img {

View File

@@ -26,15 +26,14 @@ html, body {
#editor {
box-sizing: border-box;
width: 95%;
width: calc(100% - 15px);
width: calc(100% - 58px);
height: 95%;
margin: 0;
word-break: break-all;
font-family: 'Courier New', Courier, monospace;
font-size: 0.9em;
padding: 3px;
padding-left: 35px;
margin-left: 15px;
padding-left: 58px;
overflow-y: auto;
}
@@ -44,7 +43,7 @@ html, body {
#rendered-text {
padding: 5px;
word-break: break-all;
word-break: break-word;
font-family: Arial, sans-serif;
}
@@ -56,3 +55,16 @@ html, body {
#rendered-text.dark .code-block {
color: #2d2d2d;
}
.line-warning {
position: relative;
display: inline-block;
width: 0;
left: -58px;
margin-top: -1px;
font-size: 0.9em;
}
.line-warning::after {
content: "⚠️";
}

73
web.ts
View File

@@ -8,27 +8,49 @@ let dark_theme_toggle: HTMLInputElement = document.getElementById("dark-theme-to
let unedited: boolean = true;
function render_warnings(warnings: Warning[]) {
console.log(warnings)
document.querySelectorAll(".line-warning").forEach((item: Element) => item.remove());
warnings.forEach((warning: Warning) => {
if (warning.line_number) {
//
let line: Element = editor.children[warning.line_number-1];
let warning_span: HTMLElement = document.createElement("SPAN");
warning_span.classList.add("line-warning");
warning_span.title = warning.message;
line.insertBefore(warning_span, line.childNodes[0]);
}
});
}
const refresh_html = () => {
let parsed: ParseResult = parse_md_to_html_with_warnings(editor.innerText);
//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);
let parsed: ParseResult = parse_md_to_html_with_warnings(editor_text);
render_warnings(parsed.warnings);
preview.innerHTML = parsed.html;
};
editor.addEventListener("keyup", refresh_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() === "") {
} else if (e.target !== editor && editor.innerText.trim() === "" && editor.children.length === 1) {
(editor.children[0] as HTMLElement).innerText = "markdown goes here...";
unedited = true;
}
@@ -44,9 +66,42 @@ const theme_change = () => {
dark_theme_toggle.addEventListener("change", theme_change);
refresh_html();
theme_change();
if (editor.innerText !== "markdown goes here...") {
//applies if the browser remembers what the user typed in
if (editor.innerText.trim() !== "markdown goes here...") {
unedited = false;
}
//give a quick intro to markdown
let params: URLSearchParams = new URLSearchParams(window.location.search);
if (params.get("help") === "true") {
(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() {",
"&nbsp;&nbsp;println!('HOLA MUNDO');",
"}",
"```",
"---",
"![Not a bass!](https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Gibson_Les_Paul_54_Custom.jpg/86px-Gibson_Les_Paul_54_Custom.jpg)"
];
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);
}
//
}
refresh_html();
theme_change();