Przeglądaj źródła

Playground can choose between JS and PHP

main
Rocketsoup 1 rok temu
rodzic
commit
468486c426
3 zmienionych plików z 179 dodań i 22 usunięć
  1. 42
    20
      php/markdown.php
  2. 81
    2
      playground.html
  3. 56
    0
      playgroundapi.php

+ 42
- 20
php/markdown.php Wyświetl plik

@@ -2361,7 +2361,9 @@ class MDAbbreviationReader extends MDReader {
2361 2361
 					if ($index === false) continue;
2362 2362
 					$prefix = substr($text, 0, $index);
2363 2363
 					$suffix = substr($text, $index + strlen($abbreviation));
2364
-					array_splice($elems, $i, 1, [$prefix, new MDAbbreviationNode($abbreviation, $definition), $suffix]);
2364
+					array_splice($elems, $i, 1, [$prefix,
2365
+						new MDAbbreviationNode($abbreviation, $definition),
2366
+						$suffix]);
2365 2367
 					$i = -1; // start over
2366 2368
 					$changed = true;
2367 2369
 					break;
@@ -2441,7 +2443,9 @@ class MDSimplePairInlineReader extends MDReader {
2441 2443
 	 *   content string instead of parsed `MDNode`s
2442 2444
 	 * @return bool  `true` if substitution was performed, `false` if not
2443 2445
 	 */
2444
-	public function attemptPair(MDState $state, int $pass, array &$tokens, string $nodeClass, MDTokenType $delimiter, int $count=1, bool $plaintext=false): bool {
2446
+	public function attemptPair(MDState $state, int $pass, array &$tokens,
2447
+			string $nodeClass, MDTokenType $delimiter, int $count=1,
2448
+			bool $plaintext=false): bool {
2445 2449
 		// We do four passes. #1: doubles without inner tokens, #2: singles
2446 2450
 		// without inner tokens, #3: doubles with paired inner tokens,
2447 2451
 		// #4: singles with paired inner tokens
@@ -2449,9 +2453,11 @@ class MDSimplePairInlineReader extends MDReader {
2449 2453
 		if ($count > 1 && $pass != 1 && $pass != 3) return false;
2450 2454
 		$delimiters = array_fill(0, $count, $delimiter);
2451 2455
 		$isFirstOfMultiplePasses = $this->substitutionPassCount() > 1 && $pass == 1;
2452
-		$match = MDToken::findPairedTokens($tokens, $delimiters, $delimiters, function($content) use ($nodeClass, $isFirstOfMultiplePasses, $delimiter) {
2456
+		$match = MDToken::findPairedTokens($tokens, $delimiters, $delimiters,
2457
+			function($content) use ($nodeClass, $isFirstOfMultiplePasses, $delimiter) {
2453 2458
 			$firstType = $content[0] instanceof MDToken ? $content[0]->type : null;
2454
-			$lastType = $content[sizeof($content) - 1] instanceof MDToken ? $content[sizeof($content) - 1]->type : null;
2459
+			$lastType = $content[sizeof($content) - 1] instanceof MDToken ?
2460
+				$content[sizeof($content) - 1]->type : null;
2455 2461
 			if ($firstType == MDTokenType::Whitespace) return false;
2456 2462
 			if ($lastType == MDTokenType::Whitespace) return false;
2457 2463
 			foreach ($content as $token) {
@@ -2470,7 +2476,8 @@ class MDSimplePairInlineReader extends MDReader {
2470 2476
 		if ($match === null) return false;
2471 2477
 		$state->checkExecutionTime();
2472 2478
 		if ($plaintext) {
2473
-			$content = implode('', array_map(fn($token) => $token instanceof MDToken ? $token->original : $token->toPlaintext($state), $match->contentTokens));
2479
+			$content = implode('', array_map(fn($token) => $token instanceof MDToken ?
2480
+				$token->original : $token->toPlaintext($state), $match->contentTokens));
2474 2481
 		} else {
2475 2482
 			$content = $state->tokensToNodes($match->contentTokens);
2476 2483
 		}
@@ -2683,19 +2690,23 @@ class MDLinkReader extends MDReader {
2683 2690
 	}
2684 2691
 
2685 2692
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
2686
-		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Label, MDTokenType::META_OptionalWhitespace, MDTokenType::URL ])) {
2693
+		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Label,
2694
+				MDTokenType::META_OptionalWhitespace, MDTokenType::URL ])) {
2687 2695
 			$text = $match->tokens[0]->content;
2688 2696
 			$url = $match->tokens[sizeof($match->tokens) - 1]->content;
2689 2697
 			$title = $match->tokens[sizeof($match->tokens) - 1]->extra;
2690
-			array_splice($tokens, $match->index, sizeof($match->tokens), [new MDLinkNode($url, $state->inlineMarkdownToNode($text), $title)]);
2698
+			array_splice($tokens, $match->index, sizeof($match->tokens),
2699
+				[new MDLinkNode($url, $state->inlineMarkdownToNode($text), $title)]);
2691 2700
 			return true;
2692 2701
 		}
2693
-		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Label, MDTokenType::META_OptionalWhitespace, MDTokenType::Email ])) {
2702
+		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Label,
2703
+				MDTokenType::META_OptionalWhitespace, MDTokenType::Email ])) {
2694 2704
 			$text = $match->tokens[0]->content;
2695 2705
 			$email = $match->tokens[sizeof($match->tokens) - 1]->content;
2696 2706
 			$url = "mailto:{$email}";
2697 2707
 			$title = $match->tokens[sizeof($match->tokens) - 1]->extra;
2698
-			array_splice($tokens, $match->index, sizeof($match->tokens), [new MDLinkNode($url, $state->inlineMarkdownToNodes($text), $title)]);
2708
+			array_splice($tokens, $match->index, sizeof($match->tokens),
2709
+				[new MDLinkNode($url, $state->inlineMarkdownToNodes($text), $title)]);
2699 2710
 			return true;
2700 2711
 		}
2701 2712
 		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::SimpleEmail ])) {
@@ -2745,10 +2756,12 @@ class MDReferencedLinkReader extends MDLinkReader {
2745 2756
 	}
2746 2757
 
2747 2758
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
2748
-		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Label, MDTokenType::META_OptionalWhitespace, MDTokenType::Label ])) {
2759
+		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Label,
2760
+				MDTokenType::META_OptionalWhitespace, MDTokenType::Label ])) {
2749 2761
 			$text = $match->tokens[0]->content;
2750 2762
 			$ref = $match->tokens[sizeof($match->tokens) - 1]->content;
2751
-			array_splice($tokens, $match->index, sizeof($match->tokens), [new MDReferencedLinkNode($ref, $state->inlineMarkdownToNodes($text))]);
2763
+			array_splice($tokens, $match->index, sizeof($match->tokens),
2764
+				[new MDReferencedLinkNode($ref, $state->inlineMarkdownToNodes($text))]);
2752 2765
 			return true;
2753 2766
 		}
2754 2767
 		return false;
@@ -2768,7 +2781,8 @@ class MDImageReader extends MDLinkReader {
2768 2781
 	}
2769 2782
 
2770 2783
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
2771
-		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Bang, MDTokenType::Label, MDTokenType::META_OptionalWhitespace, MDTokenType::URL ])) {
2784
+		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Bang,
2785
+				MDTokenType::Label, MDTokenType::META_OptionalWhitespace, MDTokenType::URL ])) {
2772 2786
 			$alt = $match->tokens[1]->content;
2773 2787
 			$url = $match->tokens[sizeof($match->tokens) - 1]->content;
2774 2788
 			$title = $match->tokens[sizeof($match->tokens) - 1]->extra;
@@ -2804,10 +2818,12 @@ class MDReferencedImageReader extends MDReferencedLinkReader {
2804 2818
 	}
2805 2819
 
2806 2820
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
2807
-		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Bang, MDTokenType::Label, MDTokenType::META_OptionalWhitespace, MDTokenType::Label ])) {
2821
+		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::Bang,
2822
+				MDTokenType::Label, MDTokenType::META_OptionalWhitespace, MDTokenType::Label ])) {
2808 2823
 			$alt = $match->tokens[1]->content;
2809 2824
 			$ref = $match->tokens[sizeof($match->tokens) - 1]->content;
2810
-			array_splice($tokens, $match->index, sizeof($match->tokens), [new MDReferencedImageNode($ref, $alt)]);
2825
+			array_splice($tokens, $match->index, sizeof($match->tokens),
2826
+				[new MDReferencedImageNode($ref, $alt)]);
2811 2827
 			return true;
2812 2828
 		}
2813 2829
 		return false;
@@ -2933,7 +2949,8 @@ class MDNode {
2933 2949
 				if (!($elem instanceof MDNode)) {
2934 2950
 					$thisClassName = MDUtils::typename($this);
2935 2951
 					$elemClassName = MDUtils::typename($elem);
2936
-					throw new Error("{$thisClassName} expects children of type MDNode[] or MDNode, got array with {$elemClassName} element");
2952
+					throw new Error("{$thisClassName} expects children of type " .
2953
+						"MDNode[] or MDNode, got array with {$elemClassName} element");
2937 2954
 				}
2938 2955
 			}
2939 2956
 			$this->children = $children;
@@ -2942,7 +2959,8 @@ class MDNode {
2942 2959
 		} else {
2943 2960
 			$thisClassName = MDUtils::typename($this);
2944 2961
 			$elemClassName = MDUtils::typename($children);
2945
-			throw new Error("{$thisClassName} expects children of type MDNode[] or MDNode, got {$elemClassName}");
2962
+			throw new Error("{$thisClassName} expects children of type MDNode[] " .
2963
+				"or MDNode, got {$elemClassName}");
2946 2964
 		}
2947 2965
 	}
2948 2966
 
@@ -3418,11 +3436,13 @@ class MDFootnoteListNode extends MDBlockNode {
3418 3436
 			if (!$content) continue;
3419 3437
 			$footnoteId = $this->footnoteId($state, $symbol);
3420 3438
 			$contentHTML = MDNode::arrayToHTML($content, $state);
3421
-			$html .= "<li value=\"{$footnoteId}\" id=\"{$state->root()->elementIdPrefix}footnote_{$footnoteId}\">{$contentHTML}";
3439
+			$html .= "<li value=\"{$footnoteId}\" id=\"" .
3440
+				"{$state->root()->elementIdPrefix}footnote_{$footnoteId}\">{$contentHTML}";
3422 3441
 			$uniques = $footnoteUniques[$symbol] ?? null;
3423 3442
 			if ($uniques) {
3424 3443
 				foreach ($uniques as $unique) {
3425
-					$html .= " <a href=\"#{$state->root()->elementIdPrefix}footnoteref_{$unique}\" class=\"footnote-backref\">↩︎</a>";
3444
+					$html .= " <a href=\"#{$state->root()->elementIdPrefix}footnoteref_{$unique}\"" .
3445
+						" class=\"footnote-backref\">↩︎</a>";
3426 3446
 				}
3427 3447
 			}
3428 3448
 			$html .= "</li>\n";
@@ -3597,8 +3617,10 @@ class MDFootnoteNode extends MDInlineNode {
3597 3617
 
3598 3618
 	public function toHTML(MDState $state): string {
3599 3619
 		if ($this->footnoteId !== null) {
3600
-			return "<sup class=\"footnote\" id=\"{$state->root()->elementIdPrefix}footnoteref_{$this->occurrenceId}\"" . $this->htmlAttributes() . ">" .
3601
-				"<a href=\"#{$state->root()->elementIdPrefix}footnote_{$this->footnoteId}\">" . htmlentities($this->displaySymbol ?? $this->symbol) . "</a></sup>";
3620
+			return "<sup class=\"footnote\" id=\"{$state->root()->elementIdPrefix}footnoteref_{$this->occurrenceId}\"" .
3621
+				$this->htmlAttributes() . ">" .
3622
+				"<a href=\"#{$state->root()->elementIdPrefix}footnote_{$this->footnoteId}\">" .
3623
+				htmlentities($this->displaySymbol ?? $this->symbol) . "</a></sup>";
3602 3624
 		}
3603 3625
 		return "<!--FNREF:{{$this->symbol}}-->";
3604 3626
 	}

markdownjs.html → playground.html Wyświetl plik

@@ -60,6 +60,17 @@
60 60
 				padding: 4px 20px;
61 61
 				font-family: sans-serif;
62 62
 			}
63
+			.codeswitch-cont {
64
+				position: absolute;
65
+				top: 0;
66
+				right: 0;
67
+				height: 31px;
68
+				z-index: 2;
69
+				background-color: var(--toolbar-background);
70
+				color: var(--toolbar-text);
71
+				padding: 3px 10px;
72
+				box-sizing: border-box;
73
+			}
63 74
 			#readercontainer {
64 75
 				overflow-y: scroll;
65 76
 			}
@@ -298,14 +309,74 @@
298 309
 				parser = new Markdown(activeReaders);
299 310
 				document.getElementById('markdowninput').addEventListener('input', onMarkdownChange);
300 311
 				populateReaderCheckboxes();
312
+				document.getElementById('sendbutton').addEventListener('click', () => {
313
+					handleSendClicked();
314
+				});
315
+				document.getElementById('code-js').addEventListener('change', onMarkdownChange);
316
+				document.getElementById('code-php').addEventListener('change', onMarkdownChange);
301 317
 				setTimeout(onMarkdownChange, 0);
302 318
 			}
303 319
 			function onMarkdownChange() {
320
+				if (document.getElementById('code-php').checked) {
321
+					debouncedSendPreviewRequest();
322
+				} else if (document.getElementById('code-js').checked) {
323
+					updatePreviewLocally();
324
+				}
325
+			}
326
+			function updatePreviewLocally() {
304 327
 				const textarea = document.getElementById('markdowninput');
305 328
 				let markdown = textarea.value;
306 329
 				let html = parser.toHTML(markdown, 'foo-');
307 330
 				document.getElementById('preview').innerHTML = html;
308 331
 			}
332
+			var debounceTimer = null;
333
+			var needsUpdate = false;
334
+			function debouncedSendPreviewRequest() {
335
+				if (debounceTimer) {
336
+					needsUpdate = true;
337
+				} else {
338
+					debounceTimer = setInterval(() => {
339
+						if (needsUpdate) {
340
+							needsUpdate = false;
341
+							sendPreviewRequest();
342
+						} else {
343
+							clearTimeout(debounceTimer);
344
+							debounceTimer = null;
345
+						}
346
+					}, 500);
347
+					sendPreviewRequest();
348
+				}
349
+			}
350
+			function sendPreviewRequest() {
351
+				const markdown = document.getElementById('markdowninput').value;
352
+				const readers = activeReaders.map((r) => r.constructor.name);
353
+				const request = new XMLHttpRequest();
354
+				var formData = encodeForm({
355
+					'markdown': markdown,
356
+					'readers': readers,
357
+				});
358
+				request.open('POST', 'playgroundapi.php', true);
359
+				request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
360
+				request.onreadystatechange = () => {
361
+					if (request.readyState == 4 && request.status == 200) {
362
+						document.getElementById('preview').innerHTML = request.responseText;
363
+					}
364
+				};
365
+				request.send(formData);
366
+			}
367
+			function encodeForm(values) {
368
+				var pairs = [];
369
+				for (const [key, value] of Object.entries(values)) {
370
+					if (value instanceof Array) {
371
+						for (const v of value) {
372
+							pairs.push(`${encodeURIComponent(key + '[]')}=${encodeURIComponent(v)}`);
373
+						}
374
+					} else {
375
+						pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
376
+					}
377
+				}
378
+				return pairs.join('&');
379
+			}
309 380
 			function populateReaderCheckboxes() {
310 381
 				const container = document.getElementById('readercontainer');
311 382
 				var header = document.createElement('div');
@@ -356,7 +427,6 @@
356 427
 				return div;
357 428
 			}
358 429
 			function handleCheckChanged(readerClass, check) {
359
-				console.info(`${readerClass.name}: ${check.checked}`);
360 430
 				if (check.checked) {
361 431
 					activeReaders.push(new readerClass());
362 432
 				} else {
@@ -365,7 +435,9 @@
365 435
 				parser = new Markdown(activeReaders);
366 436
 				onMarkdownChange();
367 437
 			}
368
-
438
+			function handleSendClicked() {
439
+				sendPreviewRequest();
440
+			}
369 441
 			document.addEventListener('DOMContentLoaded', onDocumentLoad);
370 442
 		</script>
371 443
 	</head>
@@ -379,6 +451,13 @@
379 451
 					<div id="readercontainer"></div>
380 452
 				</details>
381 453
 			</div>
454
+			<div class="codeswitch-cont">
455
+				<input type="radio" id="code-js" name="code" value="js" checked>
456
+				<label for="code-js">Javascript</label>
457
+				<input type="radio" id="code-php" name="code" value="php">
458
+				<label for="code-php">PHP</label>
459
+			</div>
460
+			<div id="sendbuttoncont"><button id="sendbutton">Send</button></div>
382 461
 			<textarea id="markdowninput">## Block Formats {#top}
383 462
 
384 463
 A regular paragraph.

+ 56
- 0
playgroundapi.php Wyświetl plik

@@ -0,0 +1,56 @@
1
+<?php
2
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
3
+	http_response_code(405); // method not allowed
4
+	exit();
5
+}
6
+
7
+$readerNames = $_POST['readers'];
8
+$markdown = $_POST['markdown'];
9
+
10
+$permittedReaders = [
11
+	'MDUnderlinedHeadingReader' => true,
12
+	'MDHashHeadingReader' => true,
13
+	'MDSubtextReader' => true,
14
+	'MDBlockQuoteReader' => true,
15
+	'MDUnorderedListReader' => true,
16
+	'MDOrderedListReader' => true,
17
+	'MDFencedCodeBlockReader' => true,
18
+	'MDIndentedCodeBlockReader' => true,
19
+	'MDHorizontalRuleReader' => true,
20
+	'MDTableReader' => true,
21
+	'MDDefinitionListReader' => true,
22
+	'MDFootnoteReader' => true,
23
+	'MDAbbreviationReader' => true,
24
+	'MDParagraphReader' => true,
25
+
26
+	'MDEmphasisReader' => true,
27
+	'MDStrongReader' => true,
28
+	'MDStrikethroughReader' => true,
29
+	'MDUnderlineReader' => true,
30
+	'MDHighlightReader' => true,
31
+	'MDCodeSpanReader' => true,
32
+	'MDSubscriptReader' => true,
33
+	'MDSuperscriptReader' => true,
34
+	'MDLinkReader' => true,
35
+	'MDReferencedLinkReader' => true,
36
+	'MDImageReader' => true,
37
+	'MDReferencedImageReader' => true,
38
+	'MDLineBreakReader' => true,
39
+	'MDHTMLTagReader' => true,
40
+	'MDModifierReader' => true,
41
+];
42
+
43
+include 'php/markdown.php';
44
+$readers = [];
45
+foreach ($readerNames as $readerName) {
46
+	if ($permittedReaders[$readerName] ?? false) {
47
+		$ref = new ReflectionClass($readerName);
48
+		$reader = $ref->newInstanceArgs([]);
49
+		array_push($readers, $reader);
50
+	}
51
+}
52
+$parser = new Markdown($readers);
53
+$html = $parser->toHTML($markdown);
54
+header('Content-Type: text/html');
55
+print($html);
56
+?>

Ładowanie…
Anuluj
Zapisz