Explorar el Código

Id differentiator added. CSS improvements to playground. Fixes to footnote links.

main
Rocketsoup hace 1 año
padre
commit
3c35853b49
Se han modificado 3 ficheros con 154 adiciones y 112 borrados
  1. 48
    50
      js/markdown.js
  2. 1
    1
      js/markdown.min.js
  3. 105
    61
      markdownjs.html

+ 48
- 50
js/markdown.js Ver fichero

@@ -578,9 +578,6 @@ class MDState {
578 578
 	/** @type {MDState|null} */
579 579
 	#parent = null;
580 580
 
581
-	/** @type {MDConfig} */
582
-	config;
583
-
584 581
 	/**
585 582
 	 * Array of `MDReader`s sorted by block reading priority.
586 583
 	 * @type {MDReader[]}
@@ -600,6 +597,15 @@ class MDState {
600 597
 	readersBySubstitutePriority = [];
601 598
 
602 599
 	/**
600
+	 * Prefix to include in any generated `id` attributes on HTML elements.
601
+	 * Useful for keeping elements unique in multiple parsed documents in the
602
+	 * same HTML page.
603
+	 *
604
+	 * @type {string}
605
+	 */
606
+	elementIdPrefix = '';
607
+
608
+	/**
603 609
 	 * Mapping of reference symbols to URLs.
604 610
 	 * @type {object}
605 611
 	 */
@@ -618,23 +624,9 @@ class MDState {
618 624
 
619 625
 	/**
620 626
 	 * @param {string[]} lines - lines of markdown text
621
-	 * @param {MDConfig} config
622
-	 * @param {MDReader[]} readersByBlockPriority
623
-	 * @param {MDReader[]} readersByTokenPriority
624
-	 * @param {Array} readersBySubstitutePriority - tuple arrays of priority and MDReader
625
-	 */
626
-	constructor(lines,
627
-		config=null,
628
-		readersByBlockPriority=null,
629
-		readersByTokenPriority=null,
630
-		readersBySubstitutePriority=null,
631
-		tagFilter=null) {
627
+	 */
628
+	constructor(lines) {
632 629
 		this.#lines = lines;
633
-		this.config = config;
634
-		this.readersByBlockPriority = readersByBlockPriority
635
-		this.readersByTokenPriority = readersByTokenPriority
636
-		this.readersBySubstitutePriority = readersBySubstitutePriority
637
-		this.tagFilter = tagFilter;
638 630
 	}
639 631
 
640 632
 	/**
@@ -647,7 +639,6 @@ class MDState {
647 639
 	copy(lines) {
648 640
 		let cp = new MDState(lines);
649 641
 		cp.#parent = this;
650
-		cp.config = this.config;
651 642
 		return cp;
652 643
 	}
653 644
 
@@ -2034,14 +2025,21 @@ class MDStrongReader extends MDSimplePairInlineReader {
2034 2025
 }
2035 2026
 
2036 2027
 class MDStrikethroughReader extends MDSimplePairInlineReader {
2028
+	/** @type {boolean} */
2029
+	singleTildeEnabled = true;
2030
+	/** @type {boolean} */
2031
+	doubleTildeEnabled = true;
2032
+
2037 2033
 	readToken(state, line) {
2038 2034
 		if (line.startsWith('~')) return new MDToken('~', MDTokenType.Tilde);
2039 2035
 		return null;
2040 2036
 	}
2041 2037
 
2042 2038
 	substituteTokens(state, pass, tokens) {
2043
-		if (this.attemptPair(state, pass, tokens, MDStrikethroughNode, MDTokenType.Tilde, 2)) return true;
2044
-		if (state.config.strikethroughSingleTildeEnabled) {
2039
+		if (this.singleTildeEnabled) {
2040
+			if (this.attemptPair(state, pass, tokens, MDStrikethroughNode, MDTokenType.Tilde, 2)) return true;
2041
+		}
2042
+		if (this.doubleTildeEnabled) {
2045 2043
 			if (this.attemptPair(state, pass, tokens, MDStrikethroughNode, MDTokenType.Tilde)) return true;
2046 2044
 		}
2047 2045
 		return false;
@@ -2266,11 +2264,6 @@ class MDSubscriptReader extends MDSimplePairInlineReader {
2266 2264
 		return null;
2267 2265
 	}
2268 2266
 
2269
-	preProcess(state) {
2270
-		// Causes a conflict
2271
-		state.config.strikethroughSingleTildeEnabled = false;
2272
-	}
2273
-
2274 2267
 	substituteTokens(state, pass, tokens) {
2275 2268
 		return this.attemptPair(state, pass, tokens, MDSubscriptNode, MDTokenType.Tilde);
2276 2269
 	}
@@ -2747,6 +2740,17 @@ class MDDefinitionListDefinitionNode extends MDBlockNode {
2747 2740
 }
2748 2741
 
2749 2742
 class MDFootnoteListNode extends MDBlockNode {
2743
+	/**
2744
+	 * @param {MDState} state
2745
+	 * @param {string} symbol
2746
+	 * @return {number}
2747
+	 */
2748
+	#footnoteId(state, symbol) {
2749
+		const lookup = state.root['footnoteIds'];
2750
+		if (!lookup) return null;
2751
+		return lookup[symbol] ?? null;
2752
+	}
2753
+
2750 2754
 	toHTML(state) {
2751 2755
 		const footnotes = state.footnotes;
2752 2756
 		var symbolOrder = Object.keys(footnotes);
@@ -2759,12 +2763,13 @@ class MDFootnoteListNode extends MDBlockNode {
2759 2763
 			/** @type {MDNode[]} */
2760 2764
 			let content = footnotes[symbol];
2761 2765
 			if (!content) continue;
2766
+			let footnoteId = this.#footnoteId(state, symbol);
2762 2767
 			const contentHTML = MDNode.toHTML(content, state);
2763
-			html += `<li value="${symbol}" id="footnote_${symbol}">${contentHTML}`;
2768
+			html += `<li value="${symbol}" id="${state.root.elementIdPrefix}footnote_${footnoteId}">${contentHTML}`;
2764 2769
 			const uniques = footnoteUniques[symbol];
2765 2770
 			if (uniques) {
2766 2771
 				for (const unique of uniques) {
2767
-					html += ` <a href="#footnoteref_${unique}" class="footnote-backref">↩︎</a>`;
2772
+					html += ` <a href="#${state.root.elementIdPrefix}footnoteref_${unique}" class="footnote-backref">↩︎</a>`;
2768 2773
 				}
2769 2774
 			}
2770 2775
 			html += `</li>\n`;
@@ -2908,7 +2913,8 @@ class MDFootnoteNode extends MDInlineNode {
2908 2913
 
2909 2914
 	toHTML(state) {
2910 2915
 		if (this.differentiator !== null) {
2911
-			return `<sup id="footnoteref_${this.occurrenceId}"${this._htmlAttributes()}><a href="#footnote_${this.footnoteId}">${MDUtils.escapeHTML(this.displaySymbol ?? this.symbol)}</a></sup>`;
2916
+			return `<sup id="${state.root.elementIdPrefix}footnoteref_${this.occurrenceId}"${this._htmlAttributes()}>` +
2917
+				`<a href="#${state.root.elementIdPrefix}footnote_${this.footnoteId}">${MDUtils.escapeHTML(this.displaySymbol ?? this.symbol)}</a></sup>`;
2912 2918
 		}
2913 2919
 		return `<!--FNREF:{${this.symbol}}-->`;
2914 2920
 	}
@@ -3747,10 +3753,6 @@ class MDTagModifier {
3747 3753
 	}
3748 3754
 }
3749 3755
 
3750
-class MDConfig {
3751
-	strikethroughSingleTildeEnabled = true;
3752
-}
3753
-
3754 3756
 class Markdown {
3755 3757
 	/**
3756 3758
 	 * Set of standard readers.
@@ -3808,11 +3810,6 @@ class Markdown {
3808 3810
 	static completeParser = new Markdown(this.allReaders);
3809 3811
 
3810 3812
 	/**
3811
-	 * @type {MDConfig}
3812
-	 */
3813
-	config;
3814
-
3815
-	/**
3816 3813
 	 * Filter for what non-markdown HTML is permitted. HTML generated as a
3817 3814
 	 * result of markdown is unaffected.
3818 3815
 	 */
@@ -3831,11 +3828,9 @@ class Markdown {
3831 3828
 	 * Creates a Markdown parser with the given syntax readers.
3832 3829
 	 *
3833 3830
 	 * @param {MDReader[]} readers
3834
-	 * @param {MDConfig} config
3835 3831
 	 */
3836
-	constructor(readers=Markdown.allReaders, config=new MDConfig()) {
3832
+	constructor(readers=Markdown.allReaders) {
3837 3833
 		this.#readers = readers;
3838
-		this.config = config;
3839 3834
 		this.#readersByBlockPriority = MDReader.sortReaderForBlocks(readers);
3840 3835
 		this.#readersByTokenPriority = MDReader.sortReadersForTokenizing(readers);
3841 3836
 		this.#readersBySubstitutePriority = MDReader.sortReadersForSubstitution(readers);
@@ -3844,17 +3839,20 @@ class Markdown {
3844 3839
 	/**
3845 3840
 	 * Converts a markdown string to an HTML string.
3846 3841
 	 *
3847
-	 * @param  {string} markdown
3842
+	 * @param {string} markdown
3843
+	 * @param {string} elementIdPrefix - Optional prefix for generated element
3844
+	 *   `id`s and links to them. For differentiating multiple markdown docs in
3845
+	 *   the same HTML page.
3848 3846
 	 * @returns {string} HTML
3849 3847
 	 */
3850
-	toHTML(markdown) {
3848
+	toHTML(markdown, elementIdPrefix='') {
3851 3849
 		const lines = markdown.split(/(?:\n|\r|\r\n)/);
3852
-		const state = new MDState(lines,
3853
-			this.config,
3854
-			this.#readersByBlockPriority,
3855
-			this.#readersByTokenPriority,
3856
-			this.#readersBySubstitutePriority,
3857
-			this.tagFilter);
3850
+		const state = new MDState(lines);
3851
+		state.readersByBlockPriority = this.#readersByBlockPriority;
3852
+		state.readersByTokenPriority = this.#readersByTokenPriority
3853
+		state.readersBySubstitutePriority = this.#readersBySubstitutePriority
3854
+		state.tagFilter = this.tagFilter;
3855
+		state.elementIdPrefix = elementIdPrefix;
3858 3856
 		for (const reader of this.#readers) {
3859 3857
 			reader.preProcess(state);
3860 3858
 		}

+ 1
- 1
js/markdown.min.js
La diferencia del archivo ha sido suprimido porque es demasiado grande
Ver fichero


+ 105
- 61
markdownjs.html Ver fichero

@@ -5,14 +5,17 @@
5 5
 		<title>Markdown Test</title>
6 6
 		<link rel="icon" href="data:;base64,iVBORw0KGgo=">
7 7
 		<style type="text/css">
8
+			/* Structural style */
8 9
 			:root {
9
-				--color-background: #fffff8;
10
-				--color-text: #111;
11
-				--color-editor-background: #0000aa;
10
+				--color-editor-background: #00a;
12 11
 				--color-editor-text: white;
13
-				--color-table-header: #ddd;
14
-				--color-table-border: black;
15
-				--color-calculated-background: #eee;
12
+				--toolbar-background: #ccc;
13
+				--toolbar-text: #000;
14
+			}
15
+			@media (prefers-color-scheme: dark) {
16
+				:root {
17
+					--toolbar-background: #aaa;
18
+				}
16 19
 			}
17 20
 			:root, body {
18 21
 				width: 100%;
@@ -47,14 +50,15 @@
47 50
 			.toolbar {
48 51
 				position: absolute;
49 52
 				z-index: 1;
50
-				background-color: #eee;
53
+				background-color: var(--toolbar-background);
54
+				color: var(--toolbar-text);
51 55
 				min-height: 32px;
52 56
 				/* max-height: 300px; */
53 57
 				width: 100%;
54
-				color: black;
55 58
 				border-bottom: 1px solid black;
56 59
 				box-sizing: border-box;
57 60
 				padding: 4px 20px;
61
+				font-family: sans-serif;
58 62
 			}
59 63
 			#readercontainer {
60 64
 				overflow-y: scroll;
@@ -71,17 +75,15 @@
71 75
 			}
72 76
 			#markdowninput {
73 77
 				position: absolute;
78
+				box-sizing: border-box;
74 79
 				top: 32px;
75
-				margin-top: 32px;
76 80
 				width: 100%;
77 81
 				height: calc(100% - 32px);
78
-				box-sizing: border-box;
79 82
 				margin: 0;
80
-				padding: 0.5em;
83
+				padding: 1em 2em;
81 84
 				border: 0;
82 85
 				background-color: var(--color-editor-background);
83 86
 				color: var(--color-editor-text);
84
-				box-sizing: border-box;
85 87
 			}
86 88
 			.calculated {
87 89
 				background-color: var(--color-calculated-background);
@@ -92,15 +94,18 @@
92 94
 			.spreadsheet-type-percent {
93 95
 				text-align: right;
94 96
 			}
95
-			table {
96
-				border-collapse: collapse;
97
-			}
98
-			table th {
99
-				background-color: var(--color-table-header);
100
-			}
101
-			table td, table th {
102
-				border: 1px solid var(--color-table-border);
103
-				padding: 0.2em 0.5em;
97
+		</style>
98
+		<style type="text/css">
99
+			/* Document styling */
100
+			/* From https://github.com/edwardtufte/tufte-css/blob/gh-pages/tufte.css */
101
+			:root {
102
+				--color-background: #fffff8;
103
+				--color-text: #111;
104
+				--color-table-header: #ddd;
105
+				--color-table-border: black;
106
+				--color-calculated-background: #eee;
107
+				--color-highlight: #ff0;
108
+				--color-highlight-text: #111;
104 109
 			}
105 110
 			@media (prefers-color-scheme: dark) {
106 111
 				:root {
@@ -109,11 +114,10 @@
109 114
 					--color-table-header: #333;
110 115
 					--color-table-border: #ccc;
111 116
 					--color-calculated-background: #444;
117
+					--color-highlight: #88f;
118
+					--color-highlight-text: #ddd;
112 119
 				}
113 120
 			}
114
-		</style>
115
-		<style type="text/css">
116
-			/* From https://github.com/edwardtufte/tufte-css/blob/gh-pages/tufte.css */
117 121
 			html {
118 122
 				font-size: 15px;
119 123
 			}
@@ -124,19 +128,12 @@
124 128
 				margin-right: auto;
125 129
 				padding-left: 12.5%; */
126 130
 				font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
127
-				background-color: #fffff8;
128
-				color: #111;
131
+				background-color: var(--color-background);
132
+				color: var(--color-text);
129 133
 				/* max-width: 1400px; */
130 134
 				counter-reset: sidenote-counter;
131 135
 			}
132 136
 
133
-			/* Adds dark mode */
134
-			@media (prefers-color-scheme: dark) {
135
-				body {
136
-					background-color: #151515;
137
-					color: #ddd;
138
-				}
139
-			}
140 137
 			h1 {
141 138
 				font-weight: 400;
142 139
 				margin-top: 4rem;
@@ -160,6 +157,35 @@
160 157
 				margin-bottom: 1.4rem;
161 158
 				line-height: 1;
162 159
 			}
160
+			.subtext {
161
+				font-size: 1rem;
162
+				color: #888;
163
+				margin-top: 0.25em;
164
+				margin-bottom: 0.5em;
165
+			}
166
+			mark {
167
+				background-color: var(--color-highlight);
168
+				color: var(--color-highlight-text);
169
+			}
170
+			table {
171
+				margin-top: 1em;
172
+				margin-bottom: 1em;
173
+				border-collapse: collapse;
174
+			}
175
+			td, th {
176
+				padding: 0.4em 0.8em;
177
+				font-size: 1rem;
178
+			}
179
+			th {
180
+				background-color: var(--color-table-header);
181
+				border-bottom: 2px solid var(--color-text);
182
+			}
183
+			tr:not(:last-child) td {
184
+				border-bottom: 1px solid var(--color-text);
185
+			}
186
+			tr td:not(:last-child) {
187
+				border-right: 1px solid var(--color-table-header);
188
+			}
163 189
 			hr {
164 190
 				display: block;
165 191
 				height: 1px;
@@ -177,7 +203,6 @@
177 203
 				padding-bottom: 1rem;
178 204
 			}
179 205
 			p,
180
-			dl,
181 206
 			ol,
182 207
 			ul {
183 208
 				font-size: 1.4rem;
@@ -214,6 +239,19 @@
214 239
 			li:not(:first-child) {
215 240
 				margin-top: 0.25rem;
216 241
 			}
242
+			dt, dd {
243
+				font-size: 1.2rem;
244
+			}
245
+			dt {
246
+				font-weight: bold;
247
+			}
248
+			.footnotes, .footnotes li {
249
+				font-size: 80%;
250
+			}
251
+			.footnotes li:target, sup:target a {
252
+				background-color: var(--color-highlight);
253
+				color: var(--color-highlight-text);
254
+			}
217 255
 
218 256
 		</style>
219 257
 		<script src="js/markdown.js"></script>
@@ -227,7 +265,7 @@
227 265
 			}
228 266
 			function onMarkdownChange() {
229 267
 				let markdown = document.getElementById('markdowninput').value;
230
-				let html = parser.toHTML(markdown);
268
+				let html = parser.toHTML(markdown, 'foo-');
231 269
 				document.getElementById('preview').innerHTML = html;
232 270
 			}
233 271
 			var blockReaderClasses = {
@@ -334,75 +372,81 @@
334 372
 			</div>
335 373
 			<textarea id="markdowninput">## Block Formats {#top}
336 374
 
375
+				A regular paragraph.
376
+
377
+				-# Sub text
378
+
337 379
 				* Unordered
338 380
 				* Lists
339 381
 				  * Sub list
340
-				
382
+
341 383
 				1. Ordered
342 384
 				2. Lists
343 385
 				  6. Sub list
344
-				
345
-				&gt; A block quote lorem ipsum dolor sit amet
346
-				
347
-				A regular paragraph
348
-				
386
+
387
+				A blockquote:
388
+
389
+				&gt; "The only thing we have to fear is fear itself—nameless, unreasoning, unjustified terror which paralyzes needed efforts to convert retreat into advance." - Franklin D. Roosevelt's First Inaugural Address
390
+
391
+				Some definitions:
392
+
349 393
 				word
350 394
 				: a unit of meaning in a sentence
351 395
 				sentence
352 396
 				: a collection of words
353
-				
397
+
398
+				Code:
399
+
354 400
 				```javascript
355 401
 				function foo() {
356
-					return 'Fenced code block';
402
+					return 'Hello world';
357 403
 				}
358 404
 				```
359
-				
405
+
360 406
 					function bar() {
361 407
 						return 'Indented code';
362 408
 					}
363
-				
409
+
364 410
 				### Heading, hash style
365
-				
411
+
366 412
 				Heading, underline style
367 413
 				---
368
-				
414
+
369 415
 				### Modified Heading {style=color:red;}
370
-				
371
-				-# Sub text
372
-				
416
+
373 417
 				| Unit Price | Qty | Subtotal |
374 418
 				| ---: | ---: | ---: |
375 419
 				| $1.23 | 2 | =A*B FILL |
376 420
 				| $4.99 | 6 | |
377 421
 				| Total | | =SUM(C:C) |
378
-				
422
+
379 423
 				---
380
-				
424
+
381 425
 				## Inline Formats
382
-				
426
+
383 427
 				Normal, **double asterisk,** __double underscore,__ *asterisks,* _underscores,_ ~~double tildes,~~ ~single tildes,~ ^carets,^ ==double equals==, ``double backticks``, `single backticks`.
384
-				
428
+
385 429
 				Lorem ipsum dolor sit amet,[^1] consectetur adipiscing elit.[^abc] Sed sodales in odio eget porta. Proin et erat sit amet erat semper mollis vitae ut turpis.[^foo] Ut ipsum dui, maximus sit amet suscipit at, dictum id nulla.[^bar] Aenean efficitur rhoncus nulla non fermentum.
386
-				
430
+
387 431
 				[^1]: Donec ut felis volutpat, gravida ipsum scelerisque, accumsan est.
388 432
 				[^abc]: Cras dictum rutrum quam.
389 433
 				[^foo]: Donec maximus bibendum lorem.
390 434
 				[^bar]: Praesent consectetur tristique leo. Morbi nec nisi sit amet quam imperdiet vehicula eu feugiat tortor. 
391
-				
435
+
392 436
 				The HTML on the WWW is often full of JS and CSS.
393
-				
437
+
394 438
 				*[HTML]: Hypertext Markup Language
395 439
 				*[WWW]: World Wide Web
396 440
 				*[JS]: JavaScript
397 441
 				*[CSS]: Cascading Style Sheets
398
-				
442
+
399 443
 				Click [here](#top) to return to the top. Referenced link to [Google][google title="I prefer Duck Duck Go"].
400
-				
444
+
401 445
 				![alt text](https://picsum.photos/100/75) ![alt text](https://picsum.photos/101/75 "With a title") ![][testimage]
402
-				
446
+
403 447
 				[testimage]: https://picsum.photos/102/75
404 448
 				[google]: https://google.com
405
-				
449
+
406 450
 				Some verbatim &lt;span style="color:green;"&gt;HTML&lt;/span&gt;. A script tag will be ignored. &lt;script&gt;&lt;/script&gt;
407 451
 			</textarea>
408 452
 		</div>

Loading…
Cancelar
Guardar