<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
	<title>parkdown playground</title>
	<script type="module">
		const $ = selector => {
			const elements = document.querySelectorAll(selector);

			return elements.length < 2 ? elements[0] : elements;
		};

		const output  = $("#output");
		const input   = $("#input");
		const numbers = $(".linenumbers");
		let timeout;

		const updateOutput = (event) => {
			const text  = event ? event.target.value : input.value;
			const lines = text.split("\n").length;
			let   html  = "";
			for (let i = 1; i <= lines; i++) {
				html += `${i}<br>`;
			}
			numbers.innerHTML = html;

			timeout = setTimeout(() => {

				fetch("ajax.php", {
					method : "POST",
					headers: {
						"Content-Type" : "application/json"
					},
					body : text
				}).then(response => response.text()).then(text => output.innerHTML = text);
			}, 1000);
		}

		document.addEventListener("DOMContentLoaded", () => {
			updateOutput();

			input.addEventListener("keydown", event => {
				if (event.key !== "Tab")
					return;
				event.preventDefault();
				const start = input.selectionStart;
				const end   = input.selectionEnd;
				const value = input.value;

				input.value = value.substring(0, start) + "\t" + value.substring(end);
				input.selectionStart = input.selectionEnd = (start + 1);
			});

			input.addEventListener("input", event => {
				clearTimeout(timeout);
				updateOutput(event);
			});
		});

		window.highlight = (col, row) => {
			const lines = input.value.split("\n");

			let start = 0;
			let end   = 0;
			let i     = 0;

			for (const line of lines) {
				if (++i === row) {
					end = start + line.length;
					break;
				}
				start += line.length + 1;
			}

			start = start + col - 1 === end ? start : start + col;

			input.focus();
			input.setSelectionRange(start, end);
			const lineHeight       = input.clientHeight / lines.length;
			$(".editor").scrollTop = lineHeight * (row - 10);
			input.scrollLeft       = 0;
		};
	</script>
	<style rel="stylesheet">
		* {
			box-sizing: border-box;
			outline: 0 !important;
		}

		a {
			color: dodgerblue;
			text-decoration: none;
		}
		a:hover {
			text-decoration: underline;
		}
		a.error {
			color: palevioletred;
		}

		body {
			display: grid;
			grid-template-columns: 1fr 1fr;
			font-family: sans-serif;
			margin: 0;
			padding: 0;
			height: 100vh;
			overflow: hidden;
			background: #333;
			color: #eee;
		}

		body > * {
			width: 100%;
			border: solid 1px #111;
			padding: 0;
			margin: 0;
		}

		textarea {
			width: 100%;
			height: 100%;
			font-family: monospace;
			box-sizing: content-box;
			background: transparent;
			tab-size: 4;
			border: none;
			padding-bottom: 4rem;
			font-size: 1.2rem;
			overflow-y: clip;
			overflow-x: scroll;
			white-space: pre;
			resize: none;
			margin: 1rem 0;
			color: #FAF08B;
		}
		textarea::selection {
			background-color: dodgerblue;
			color: white;
		}

		.editor {
			display: grid;
			grid-template-columns: 80px auto;
			gap: 2rem;
			height: 100%;
			border-right: none;
			overflow-y: auto;
			overflow-x: hidden;
		}
		
		.linenumbers {
			font-size: 1.2rem;
			text-align: right;
			padding: 1rem;
			color: #aaa;
			font-family: monospace;
			background: #222;
		}

		#output {
			overflow-y: auto;
			padding: 4rem;
			max-width: 100%;
		}
		#output code {
			word-break: break-word;
			white-space: break-spaces;
		}

		#output img {
			max-width: 100%;
			height: auto;
		}

		::-webkit-scrollbar {
			background-color: transparent;
			width: 16px;
		}
		::-webkit-scrollbar-track {
			background-color: transparent;
		}
		::-webkit-scrollbar-thumb {
			background-color: rgba(255,255,255,0.1);
			border-radius: 16px;
			border: 4px solid #333;
		}
		::-webkit-scrollbar-button {
			display:none;
		}

		@media (max-width: 920px) {
			body {
				grid-template-columns: 1fr !important;
				grid-template-rows: 1fr 1fr;
			}
		
			textarea, .linenumbers {
				font-size: 1rem;
			}

			textarea {
				margin: 0.5rem 0;
			}
			.linenumbers {
				padding: 0.5rem;
			}

			.editor {
				grid-template-columns: 50px auto;
				gap: 1rem;
			}

			#output {
				padding: 1rem;
			}

		}
	</style>
</head>
<body>
	
<section class="editor">
	<section class="linenumbers">1</section>
	<textarea id="input">
# Parkdown
– a simple recursive descent Markdown parser for PHP *(version >= 8.1)*

![Markdown is a simple markup language](https://git.mike-ochmann.de/MassiveDynamic/Parkdown/raw/branch/master/docs/logo_parkdown.svg)

## Specification

### Index
* [Block types](#supported_block_types)
* [Inline types](#supported_inline_types)
* [Examples](#examples)
	* [Paragraphs](#paragraphs)
	* [Images](#images)
	* [Horizontal Rules](#horizontal_rules)
	* [Block quotes](#block_quotes)
	* [Code blocks](#code_blocks)
	* [Tables](#tables)
	* [References](#references)
* [Usage](#usage)
* [Testing](#testing)

### Supported block types
Parkdown currently support the following block types:

* codeblocks *(with the ability to specify a language for the code block)*
* tables *(with alignment specification)*
* paragraphs
* block quotes
* lists *(like this one)*
	* also nested
* horizontal rules `---`

### Supported inline types
Parkdown currently support the following block types:

* bold text (`**bold**`)
* italic text (`*italic*`)
* code snippets
* images (`![alt text](src url)`)
* links (`[link text][url or reference]`)

### Additional functionality

* references (`[marker]: URL`)

## Examples
### Paragraphs
```markdown
A simple paragraph can contain **bold text**, `inline codeblocks` and *italic text*. We can also link [with a direct url][https://google.com] *(i.e. to google)*
or via reference to [a later defined url][massivedynamic], if we so desire.
```

A simple paragraph can contain **bold text**, `inline codeblocks` and *italic text*. We can also link [with a direct url](https://google.com) *(i.e. to google)*
or via reference to [a later defined url][massivedynamic], if we so desire.

Paragraphs can be annotated with `id` and `class` attributes:

```markdown
Paragraphs can be annotated with ids and classes {.thisIsAClass, .anotherClass, #thisIsAnID}
```

results in

Paragraphs can be annotated with ids and classes {.thisIsAClass, .anotherClass, #thisIsAnID}

```html
<p class="thisIsAClass anotherClass" id="thisIsAnID">
	Paragraphs can be annotated with ids and classes
</p>
```

### Images
```markdown
![this is an alt text](https://images.unsplash.com/photo-1571171637578-41bc2dd41cd2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&h=300&w=1740&q=80\)
```

![this is an alt text](https://images.unsplash.com/photo-1571171637578-41bc2dd41cd2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&h=300&w=1740&q=80)

### Horizontal rules
```markdown
---
```

---
### Block quotes
```markdown
> Only two things are infinite,
> the universe and human stupidity,
> i am not totally shure about the universe, though...
>    – Albert Einstein
```


> Only two things are infinite,
> the universe and human stupidity,
> i am not totally shure about the universe, though...
>    – Albert Einstein

### Code blocks
```markdown

\`\`\`php
	function main(int $argc, array $argv) : int {
		echo "Hello World!";

		return 0;
	}
\`\`\`

```

```php
	function main(int $argc, array $argv) : int {
		echo "Hello World!";

		return 0;
	}
```

### Tables
```markdown
| Product name | Amount   | Price  |
|--------------|:--------:|-------:|
| Football     |      7   | $18,00 |
| Golfball     |      122 | $7,00  |
| Fooseball    |      355 | $1,00  |
| Puck         |      58  | $12,00 |
```

| Product name | Amount   | Price  |
|--------------|:--------:|-------:|
| Football     |      7   | $18,00 |
| Golfball     |      122 | $7,00  |
| Fooseball    |      355 | $1,00  |
| Puck         |      58  | $12,00 |

### References

```markdown
[massivedynamic]: https://massivedynamic.eu
```

[massivedynamic]: https://massivedynamic.eu

## Usage
Simply construct an new `parkdown\Parkdown` object and pass the Markdown source code to it's constructor. The parsed `DOMDocument` or it's `HTML` output can then be retrieved through the `::html()` and `::tree()` member functions.

**Example**

```php
	use parkdown\Parkdown;

	$source = "
		This is a **bold** word in a paragraph.
	";

	$parser = new Parkdown($source);
	$tree   = $parser->tree();

	print_r($tree);
	echo $parser->html();
```

## Testing
Unit tests can be run via `composer`:

```
	composer test
```
	</textarea>
</section>
<section id="output"></section>

</body>
</html>