Pārlūkot izejas kodu

Playground can choose between JS and PHP

main
Rocketsoup 1 gadu atpakaļ
vecāks
revīzija
468486c426
3 mainītis faili ar 179 papildinājumiem un 22 dzēšanām
  1. 42
    20
      php/markdown.php
  2. 81
    2
      playground.html
  3. 56
    0
      playgroundapi.php

+ 42
- 20
php/markdown.php Parādīt failu

2361
 					if ($index === false) continue;
2361
 					if ($index === false) continue;
2362
 					$prefix = substr($text, 0, $index);
2362
 					$prefix = substr($text, 0, $index);
2363
 					$suffix = substr($text, $index + strlen($abbreviation));
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
 					$i = -1; // start over
2367
 					$i = -1; // start over
2366
 					$changed = true;
2368
 					$changed = true;
2367
 					break;
2369
 					break;
2441
 	 *   content string instead of parsed `MDNode`s
2443
 	 *   content string instead of parsed `MDNode`s
2442
 	 * @return bool  `true` if substitution was performed, `false` if not
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
 		// We do four passes. #1: doubles without inner tokens, #2: singles
2449
 		// We do four passes. #1: doubles without inner tokens, #2: singles
2446
 		// without inner tokens, #3: doubles with paired inner tokens,
2450
 		// without inner tokens, #3: doubles with paired inner tokens,
2447
 		// #4: singles with paired inner tokens
2451
 		// #4: singles with paired inner tokens
2449
 		if ($count > 1 && $pass != 1 && $pass != 3) return false;
2453
 		if ($count > 1 && $pass != 1 && $pass != 3) return false;
2450
 		$delimiters = array_fill(0, $count, $delimiter);
2454
 		$delimiters = array_fill(0, $count, $delimiter);
2451
 		$isFirstOfMultiplePasses = $this->substitutionPassCount() > 1 && $pass == 1;
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
 			$firstType = $content[0] instanceof MDToken ? $content[0]->type : null;
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
 			if ($firstType == MDTokenType::Whitespace) return false;
2461
 			if ($firstType == MDTokenType::Whitespace) return false;
2456
 			if ($lastType == MDTokenType::Whitespace) return false;
2462
 			if ($lastType == MDTokenType::Whitespace) return false;
2457
 			foreach ($content as $token) {
2463
 			foreach ($content as $token) {
2470
 		if ($match === null) return false;
2476
 		if ($match === null) return false;
2471
 		$state->checkExecutionTime();
2477
 		$state->checkExecutionTime();
2472
 		if ($plaintext) {
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
 		} else {
2481
 		} else {
2475
 			$content = $state->tokensToNodes($match->contentTokens);
2482
 			$content = $state->tokensToNodes($match->contentTokens);
2476
 		}
2483
 		}
2683
 	}
2690
 	}
2684
 
2691
 
2685
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
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
 			$text = $match->tokens[0]->content;
2695
 			$text = $match->tokens[0]->content;
2688
 			$url = $match->tokens[sizeof($match->tokens) - 1]->content;
2696
 			$url = $match->tokens[sizeof($match->tokens) - 1]->content;
2689
 			$title = $match->tokens[sizeof($match->tokens) - 1]->extra;
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
 			return true;
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
 			$text = $match->tokens[0]->content;
2704
 			$text = $match->tokens[0]->content;
2695
 			$email = $match->tokens[sizeof($match->tokens) - 1]->content;
2705
 			$email = $match->tokens[sizeof($match->tokens) - 1]->content;
2696
 			$url = "mailto:{$email}";
2706
 			$url = "mailto:{$email}";
2697
 			$title = $match->tokens[sizeof($match->tokens) - 1]->extra;
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
 			return true;
2710
 			return true;
2700
 		}
2711
 		}
2701
 		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::SimpleEmail ])) {
2712
 		if ($match = MDToken::findFirstTokens($tokens, [ MDTokenType::SimpleEmail ])) {
2745
 	}
2756
 	}
2746
 
2757
 
2747
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
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
 			$text = $match->tokens[0]->content;
2761
 			$text = $match->tokens[0]->content;
2750
 			$ref = $match->tokens[sizeof($match->tokens) - 1]->content;
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
 			return true;
2765
 			return true;
2753
 		}
2766
 		}
2754
 		return false;
2767
 		return false;
2768
 	}
2781
 	}
2769
 
2782
 
2770
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
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
 			$alt = $match->tokens[1]->content;
2786
 			$alt = $match->tokens[1]->content;
2773
 			$url = $match->tokens[sizeof($match->tokens) - 1]->content;
2787
 			$url = $match->tokens[sizeof($match->tokens) - 1]->content;
2774
 			$title = $match->tokens[sizeof($match->tokens) - 1]->extra;
2788
 			$title = $match->tokens[sizeof($match->tokens) - 1]->extra;
2804
 	}
2818
 	}
2805
 
2819
 
2806
 	public function substituteTokens(MDState $state, int $pass, array &$tokens): bool {
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
 			$alt = $match->tokens[1]->content;
2823
 			$alt = $match->tokens[1]->content;
2809
 			$ref = $match->tokens[sizeof($match->tokens) - 1]->content;
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
 			return true;
2827
 			return true;
2812
 		}
2828
 		}
2813
 		return false;
2829
 		return false;
2933
 				if (!($elem instanceof MDNode)) {
2949
 				if (!($elem instanceof MDNode)) {
2934
 					$thisClassName = MDUtils::typename($this);
2950
 					$thisClassName = MDUtils::typename($this);
2935
 					$elemClassName = MDUtils::typename($elem);
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
 			$this->children = $children;
2956
 			$this->children = $children;
2942
 		} else {
2959
 		} else {
2943
 			$thisClassName = MDUtils::typename($this);
2960
 			$thisClassName = MDUtils::typename($this);
2944
 			$elemClassName = MDUtils::typename($children);
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
 			if (!$content) continue;
3436
 			if (!$content) continue;
3419
 			$footnoteId = $this->footnoteId($state, $symbol);
3437
 			$footnoteId = $this->footnoteId($state, $symbol);
3420
 			$contentHTML = MDNode::arrayToHTML($content, $state);
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
 			$uniques = $footnoteUniques[$symbol] ?? null;
3441
 			$uniques = $footnoteUniques[$symbol] ?? null;
3423
 			if ($uniques) {
3442
 			if ($uniques) {
3424
 				foreach ($uniques as $unique) {
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
 			$html .= "</li>\n";
3448
 			$html .= "</li>\n";
3597
 
3617
 
3598
 	public function toHTML(MDState $state): string {
3618
 	public function toHTML(MDState $state): string {
3599
 		if ($this->footnoteId !== null) {
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
 		return "<!--FNREF:{{$this->symbol}}-->";
3625
 		return "<!--FNREF:{{$this->symbol}}-->";
3604
 	}
3626
 	}

markdownjs.html → playground.html Parādīt failu

60
 				padding: 4px 20px;
60
 				padding: 4px 20px;
61
 				font-family: sans-serif;
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
 			#readercontainer {
74
 			#readercontainer {
64
 				overflow-y: scroll;
75
 				overflow-y: scroll;
65
 			}
76
 			}
298
 				parser = new Markdown(activeReaders);
309
 				parser = new Markdown(activeReaders);
299
 				document.getElementById('markdowninput').addEventListener('input', onMarkdownChange);
310
 				document.getElementById('markdowninput').addEventListener('input', onMarkdownChange);
300
 				populateReaderCheckboxes();
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
 				setTimeout(onMarkdownChange, 0);
317
 				setTimeout(onMarkdownChange, 0);
302
 			}
318
 			}
303
 			function onMarkdownChange() {
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
 				const textarea = document.getElementById('markdowninput');
327
 				const textarea = document.getElementById('markdowninput');
305
 				let markdown = textarea.value;
328
 				let markdown = textarea.value;
306
 				let html = parser.toHTML(markdown, 'foo-');
329
 				let html = parser.toHTML(markdown, 'foo-');
307
 				document.getElementById('preview').innerHTML = html;
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
 			function populateReaderCheckboxes() {
380
 			function populateReaderCheckboxes() {
310
 				const container = document.getElementById('readercontainer');
381
 				const container = document.getElementById('readercontainer');
311
 				var header = document.createElement('div');
382
 				var header = document.createElement('div');
356
 				return div;
427
 				return div;
357
 			}
428
 			}
358
 			function handleCheckChanged(readerClass, check) {
429
 			function handleCheckChanged(readerClass, check) {
359
-				console.info(`${readerClass.name}: ${check.checked}`);
360
 				if (check.checked) {
430
 				if (check.checked) {
361
 					activeReaders.push(new readerClass());
431
 					activeReaders.push(new readerClass());
362
 				} else {
432
 				} else {
365
 				parser = new Markdown(activeReaders);
435
 				parser = new Markdown(activeReaders);
366
 				onMarkdownChange();
436
 				onMarkdownChange();
367
 			}
437
 			}
368
-
438
+			function handleSendClicked() {
439
+				sendPreviewRequest();
440
+			}
369
 			document.addEventListener('DOMContentLoaded', onDocumentLoad);
441
 			document.addEventListener('DOMContentLoaded', onDocumentLoad);
370
 		</script>
442
 		</script>
371
 	</head>
443
 	</head>
379
 					<div id="readercontainer"></div>
451
 					<div id="readercontainer"></div>
380
 				</details>
452
 				</details>
381
 			</div>
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
 			<textarea id="markdowninput">## Block Formats {#top}
461
 			<textarea id="markdowninput">## Block Formats {#top}
383
 
462
 
384
 A regular paragraph.
463
 A regular paragraph.

+ 56
- 0
playgroundapi.php Parādīt failu

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
+?>

Notiek ielāde…
Atcelt
Saglabāt