Kaynağa Gözat

Markdown playground lets readers be changed on the fly

main
Rocketsoup 1 yıl önce
ebeveyn
işleme
57fde9acc6
6 değiştirilmiş dosya ile 273 ekleme ve 49 silme
  1. 49
    27
      js/markdown.js
  2. 1
    1
      js/markdown.min.js
  3. 2
    2
      js/spreadsheet.js
  4. 1
    1
      js/spreadsheet.min.js
  5. 196
    18
      markdownjs.html
  6. 24
    0
      testjs.html

+ 49
- 27
js/markdown.js Dosyayı Görüntüle

@@ -585,19 +585,19 @@ class MDState {
585 585
 	 * Array of `MDReader`s sorted by block reading priority.
586 586
 	 * @type {MDReader[]}
587 587
 	 */
588
-	#readersByBlockPriority = [];
588
+	readersByBlockPriority = [];
589 589
 
590 590
 	/**
591 591
 	 * Array of `MDReader`s sorted by tokenization priority.
592 592
 	 * @type {MDReader[]}
593 593
 	 */
594
-	#readersByTokenPriority = [];
594
+	readersByTokenPriority = [];
595 595
 
596 596
 	/**
597 597
 	 * Tuples of `pass:number` and `MDReader` sorted substitution priority.
598 598
 	 * @type {Array}
599 599
 	 */
600
-	#readersBySubstitutePriority = [];
600
+	readersBySubstitutePriority = [];
601 601
 
602 602
 	/**
603 603
 	 * Mapping of reference symbols to URLs.
@@ -631,9 +631,9 @@ class MDState {
631 631
 		tagFilter=null) {
632 632
 		this.#lines = lines;
633 633
 		this.config = config;
634
-		this.#readersByBlockPriority = readersByBlockPriority
635
-		this.#readersByTokenPriority = readersByTokenPriority
636
-		this.#readersBySubstitutePriority = readersBySubstitutePriority
634
+		this.readersByBlockPriority = readersByBlockPriority
635
+		this.readersByTokenPriority = readersByTokenPriority
636
+		this.readersBySubstitutePriority = readersBySubstitutePriority
637 637
 		this.tagFilter = tagFilter;
638 638
 	}
639 639
 
@@ -707,7 +707,7 @@ class MDState {
707 707
 			this.p++;
708 708
 		}
709 709
 		if (!this.hasLines(1)) return null;
710
-		for (const reader of this.root.#readersByBlockPriority) {
710
+		for (const reader of this.root.readersByBlockPriority) {
711 711
 			const startP = this.p;
712 712
 			const block = reader.readBlock(this);
713 713
 			if (block) {
@@ -767,7 +767,7 @@ class MDState {
767 767
 				continue;
768 768
 			}
769 769
 			var found = false;
770
-			for (const reader of this.root.#readersByTokenPriority) {
770
+			for (const reader of this.root.readersByTokenPriority) {
771 771
 				const token = reader.readToken(this, remainder);
772 772
 				if (token === null) continue;
773 773
 				if (token === undefined) {
@@ -827,7 +827,7 @@ class MDState {
827 827
 		var anyChanges = false;
828 828
 		do {
829 829
 			anyChanges = false;
830
-			for (const readerTuple of this.root.#readersBySubstitutePriority) {
830
+			for (const readerTuple of this.root.readersBySubstitutePriority) {
831 831
 				/** @type {number} */
832 832
 				const pass = readerTuple[0];
833 833
 				/** @type {MDReader} */
@@ -1154,7 +1154,7 @@ class MDUnderlinedHeadingReader extends MDReader {
1154 1154
 		if (!state.hasLines(2)) return null;
1155 1155
 		var modifier;
1156 1156
 		let contentLine = state.lines[p++].trim();
1157
-		[contentLine, modifier] = MDTagModifier.fromLine(contentLine);
1157
+		[contentLine, modifier] = MDTagModifier.fromLine(contentLine, state);
1158 1158
 		let underLine = state.lines[p++].trim();
1159 1159
 		if (contentLine == '') return null;
1160 1160
 		if (/^=+$/.exec(underLine)) {
@@ -1196,7 +1196,7 @@ class MDHashHeadingReader extends MDReader {
1196 1196
 		var p = state.p;
1197 1197
 		let line = state.lines[p++];
1198 1198
 		var modifier;
1199
-		[line, modifier] = MDTagModifier.fromLine(line);
1199
+		[line, modifier] = MDTagModifier.fromLine(line, state);
1200 1200
 		var groups = MDHashHeadingReader.#hashHeadingRegex.exec(line);
1201 1201
 		if (groups === null) return null;
1202 1202
 		state.p = p;
@@ -1215,7 +1215,7 @@ class MDSubtextReader extends MDReader {
1215 1215
 		var p = state.p;
1216 1216
 		let line = state.lines[p++];
1217 1217
 		var modifier;
1218
-		[line, modifier] = MDTagModifier.fromLine(line);
1218
+		[line, modifier] = MDTagModifier.fromLine(line, state);
1219 1219
 		var groups = MDSubtextReader.#subtextRegex.exec(line);
1220 1220
 		if (groups === null) return null;
1221 1221
 		state.p = p;
@@ -1446,7 +1446,7 @@ class MDFencedCodeBlockReader extends MDReader {
1446 1446
 		var p = state.p;
1447 1447
 		let openFenceLine = state.lines[p++];
1448 1448
 		var modifier;
1449
-		[openFenceLine, modifier] = MDTagModifier.fromLine(openFenceLine);
1449
+		[openFenceLine, modifier] = MDTagModifier.fromLine(openFenceLine, state);
1450 1450
 		const match = /^```\s*([a-z0-9]*)\s*$/.exec(openFenceLine);
1451 1451
 		if (match === null) return null;
1452 1452
 		const language = match[1].length > 0 ? match[1] : null;
@@ -1516,7 +1516,7 @@ class MDHorizontalRuleReader extends MDReader {
1516 1516
 		var p = state.p;
1517 1517
 		let line = state.lines[p++];
1518 1518
 		var modifier;
1519
-		[line, modifier] = MDTagModifier.fromLine(line);
1519
+		[line, modifier] = MDTagModifier.fromLine(line, state);
1520 1520
 		if (MDHorizontalRuleReader.#horizontalRuleRegex.exec(line)) {
1521 1521
 			state.p = p;
1522 1522
 			let block = new MDHorizontalRuleNode();
@@ -1603,7 +1603,7 @@ class MDTableReader extends MDReader {
1603 1603
 		if (!state.hasLines(2)) return null;
1604 1604
 		let startP = state.p;
1605 1605
 		let firstLine = state.lines[startP];
1606
-		var modifier = MDTagModifier.fromLine(firstLine)[1];
1606
+		var modifier = MDTagModifier.fromLine(firstLine, state)[1];
1607 1607
 		let headerRow = this.#readTableRow(state, true);
1608 1608
 		if (headerRow === null) {
1609 1609
 			state.p = startP;
@@ -2210,17 +2210,11 @@ class MDImageReader extends MDLinkReader {
2210 2210
 			tokens.splice(match.index, match.tokens.length, node);
2211 2211
 			return true;
2212 2212
 		}
2213
-		if (match = MDToken.findFirstTokens(tokens, [ MDTokenType.Bang, MDTokenType.Label, MDTokenType.META_OptionalWhitespace, MDTokenType.Label ])) {
2214
-			let alt = match.tokens[1].content;
2215
-			let ref = match.tokens[match.tokens.length - 1].content;
2216
-			tokens.splice(match.index, match.tokens.length, new MDReferencedImageNode(ref, alt));
2217
-			return true;
2218
-		}
2219 2213
 		return false;
2220 2214
 	}
2221 2215
 
2222 2216
 	compareSubstituteOrdering(other, pass) {
2223
-		if (other instanceof MDLinkReader) {
2217
+		if (other.constructor === MDLinkReader || other.constructor === MDReferencedLinkReader) {
2224 2218
 			return -1;
2225 2219
 		}
2226 2220
 		return 0;
@@ -2228,10 +2222,26 @@ class MDImageReader extends MDLinkReader {
2228 2222
 }
2229 2223
 
2230 2224
 class MDReferencedImageReader extends MDReferencedLinkReader {
2231
-	readBlock(state) { return null; }
2225
+	readToken(state, line) {
2226
+		const s = super.readToken(state, line);
2227
+		if (s) return s;
2228
+		if (line.startsWith('!')) return new MDToken('!', MDTokenType.Bang);
2229
+		return null;
2230
+	}
2231
+
2232
+	substituteTokens(state, pass, tokens) {
2233
+		var match;
2234
+		if (match = MDToken.findFirstTokens(tokens, [ MDTokenType.Bang, MDTokenType.Label, MDTokenType.META_OptionalWhitespace, MDTokenType.Label ])) {
2235
+			let alt = match.tokens[1].content;
2236
+			let ref = match.tokens[match.tokens.length - 1].content;
2237
+			tokens.splice(match.index, match.tokens.length, new MDReferencedImageNode(ref, alt));
2238
+			return true;
2239
+		}
2240
+		return false;
2241
+	}
2232 2242
 
2233 2243
 	compareSubstituteOrdering(other, pass) {
2234
-		if (other instanceof MDLinkReader) {
2244
+		if (other.constructor === MDLinkReader || other.constructor === MDReferencedLinkReader) {
2235 2245
 			return -1;
2236 2246
 		}
2237 2247
 		return 0;
@@ -2286,7 +2296,7 @@ class MDSuperscriptReader extends MDSimplePairInlineReader {
2286 2296
 
2287 2297
 class MDHTMLTagReader extends MDReader {
2288 2298
 	readToken(state, line) {
2289
-		const tag = MDHTMLTag.fromLineStart(line)
2299
+		const tag = MDHTMLTag.fromLineStart(line, state);
2290 2300
 		if (tag === null) return null;
2291 2301
 		if (!state.root.tagFilter.isValidTagName(tag.tagName)) return null;
2292 2302
 		state.root.tagFilter.scrubTag(tag);
@@ -2943,7 +2953,8 @@ class MDReferencedLinkNode extends MDLinkNode {
2943 2953
 	 */
2944 2954
 	toHTML(state) {
2945 2955
 		if (this.href === '') {
2946
-			this.href = state.urlForReference(this.reference);
2956
+			const url = state.urlForReference(this.reference);
2957
+			if (url) this.href = url;
2947 2958
 			const title = state.urlTitleForReference(this.reference);
2948 2959
 			if (title) this.attributes['title'] = title;
2949 2960
 		}
@@ -3693,9 +3704,20 @@ class MDTagModifier {
3693 3704
 	/**
3694 3705
 	 * Extracts modifier from line.
3695 3706
 	 * @param {string} line
3707
+	 * @param {MDState} state
3696 3708
 	 * @returns {Array} Tuple with remaining line and MDTagModifier.
3697 3709
 	 */
3698
-	static fromLine(line) {
3710
+	static fromLine(line, state) {
3711
+		if (state) {
3712
+			var found = false;
3713
+			for (const reader of state.root.readersByBlockPriority) {
3714
+				if (reader instanceof MDModifierReader) {
3715
+					found = true;
3716
+					break;
3717
+				}
3718
+			}
3719
+			if (!found) return [ line, null ];
3720
+		}
3699 3721
 		let groups = this.#trailingClassRegex.exec(line);
3700 3722
 		if (groups === null) return [ line, null ];
3701 3723
 		let bareLine = groups[1];

+ 1
- 1
js/markdown.min.js
Dosya farkı çok büyük olduğundan ihmal edildi
Dosyayı Görüntüle


+ 2
- 2
js/spreadsheet.js Dosyayı Görüntüle

@@ -1642,8 +1642,8 @@ class CellExpression {
1642 1642
 		if (tokens[start + 1].type != CellExpressionTokenType.Colon) return null;
1643 1643
 		if (!tokens[end].type.isPotentialAddress()) return null;
1644 1644
 		const last = tokens[end].content.toUpperCase();
1645
-		const firstAddress = new CellAddress(first);
1646
-		const lastAddress = new CellAddress(last);
1645
+		const firstAddress = CellAddress.fromString(first);
1646
+		const lastAddress = CellAddress.fromString(last);
1647 1647
 		const range = new CellAddressRange(firstAddress, lastAddress);
1648 1648
 		return new CellExpression(CellExpressionOperation.Range, [ range ]);
1649 1649
 	}

+ 1
- 1
js/spreadsheet.min.js
Dosya farkı çok büyük olduğundan ihmal edildi
Dosyayı Görüntüle


+ 196
- 18
markdownjs.html Dosyayı Görüntüle

@@ -22,16 +22,6 @@
22 22
 				background-color: var(--color-background);
23 23
 				color: var(--color-text);
24 24
 			}
25
-/* body {
26
-    width: 87.5%;
27
-    margin-left: auto;
28
-    margin-right: auto;
29
-    padding-left: 12.5%;
30
-    background-color: #fffff8;
31
-    color: #111;
32
-    max-width: 1400px;
33
-    counter-reset: sidenote-counter;
34
-} */
35 25
 			.inputhalf {
36 26
 				position: absolute;
37 27
 				width: 50%;
@@ -54,15 +44,44 @@
54 44
 				margin: 0 auto;
55 45
 				max-width: 600px;
56 46
 			}
47
+			.toolbar {
48
+				position: absolute;
49
+				z-index: 1;
50
+				background-color: #eee;
51
+				min-height: 32px;
52
+				/* max-height: 300px; */
53
+				width: 100%;
54
+				color: black;
55
+				border-bottom: 1px solid black;
56
+				box-sizing: border-box;
57
+				padding: 4px 20px;
58
+			}
59
+			#readercontainer {
60
+				overflow-y: scroll;
61
+			}
62
+			.reader-header {
63
+				margin-top: 0.25em;
64
+				font-weight: bold;
65
+			}
66
+			.reader-check {
67
+				display: inline-block;
68
+				padding: 4px 8px;
69
+				border: 1px dotted gray;
70
+				margin: 4px;
71
+			}
57 72
 			#markdowninput {
73
+				position: absolute;
74
+				top: 32px;
75
+				margin-top: 32px;
58 76
 				width: 100%;
59
-				height: 100%;
77
+				height: calc(100% - 32px);
60 78
 				box-sizing: border-box;
61 79
 				margin: 0;
62 80
 				padding: 0.5em;
63 81
 				border: 0;
64 82
 				background-color: var(--color-editor-background);
65 83
 				color: var(--color-editor-text);
84
+				box-sizing: border-box;
66 85
 			}
67 86
 			.calculated {
68 87
 				background-color: var(--color-calculated-background);
@@ -203,6 +222,7 @@
203 222
 			var parser = new Markdown([ ...Markdown.allReaders, new MDSpreadsheetReader() ]);
204 223
 			function onDocumentLoad() {
205 224
 				document.getElementById('markdowninput').addEventListener('input', onMarkdownChange);
225
+				populateReaderCheckboxes();
206 226
 				setTimeout(onMarkdownChange, 0);
207 227
 			}
208 228
 			function onMarkdownChange() {
@@ -210,6 +230,94 @@
210 230
 				let html = parser.toHTML(markdown);
211 231
 				document.getElementById('preview').innerHTML = html;
212 232
 			}
233
+			var blockReaderClasses = {
234
+				'Heading (underline)': MDUnderlinedHeadingReader,
235
+				'Heading (hash)': MDHashHeadingReader,
236
+				'Subtext': MDSubtextReader,
237
+				'Block quote': MDBlockQuoteReader,
238
+				'Unordered list': MDUnorderedListReader,
239
+				'Ordered list': MDOrderedListReader,
240
+				'Code block (fenced)': MDFencedCodeBlockReader,
241
+				'Code block (indented)': MDIndentedCodeBlockReader,
242
+				'Horizontal rule': MDHorizontalRuleReader,
243
+				'Table': MDTableReader,
244
+				'Definition list': MDDefinitionListReader,
245
+				'Paragraph': MDParagraphReader,
246
+				'Spreadsheets': MDSpreadsheetReader,
247
+			};
248
+			var inlineReaderClasses = {
249
+				'Emphasis': MDEmphasisReader,
250
+				'Strong': MDStrongReader,
251
+				'Strikethrough': MDStrikethroughReader,
252
+				'Underline': MDUnderlineReader,
253
+				'Highlight': MDHighlightReader,
254
+				'Links': MDLinkReader,
255
+				'Referenced links': MDReferencedLinkReader,
256
+				'Images': MDImageReader,
257
+				'Referenced images': MDReferencedImageReader,
258
+				'Code span': MDCodeSpanReader,
259
+				'Subscript': MDSubscriptReader,
260
+				'Superscript': MDSuperscriptReader,
261
+				'Footnotes': MDFootnoteReader,
262
+				'Abbrevations': MDAbbreviationReader,
263
+				'HTML tags': MDHTMLTagReader,
264
+				'Modifiers': MDModifierReader,
265
+			};
266
+			var activeReaders = [];
267
+			function populateReaderCheckboxes() {
268
+				const container = document.getElementById('readercontainer');
269
+				var header = document.createElement('div');
270
+				header.classList.add('reader-header');
271
+				header.append(document.createTextNode('Block Readers'));
272
+				container.append(header);
273
+				const blockContainer = document.createElement('div');
274
+				container.append(blockContainer);
275
+				for (const name of Object.keys(blockReaderClasses).sort()) {
276
+					const readerClass = blockReaderClasses[name];
277
+					activeReaders.push(new readerClass());
278
+					const checkbox = makeReaderCheckbox(name, readerClass);
279
+					blockContainer.append(checkbox);
280
+				}
281
+				header = document.createElement('div');
282
+				header.classList.add('reader-header');
283
+				header.append(document.createTextNode('Inline Readers'));
284
+				container.append(header);
285
+				const inlineContainer = document.createElement('div');
286
+				container.append(inlineContainer);
287
+				for (const name of Object.keys(inlineReaderClasses).sort()) {
288
+					const readerClass = inlineReaderClasses[name];
289
+					activeReaders.push(new readerClass());
290
+					const checkbox = makeReaderCheckbox(name, readerClass);
291
+					inlineContainer.append(checkbox);
292
+				}
293
+			}
294
+			function makeReaderCheckbox(name, readerClass) {
295
+				const check = document.createElement('input');
296
+				check.type = 'checkbox';
297
+				check.checked = true;
298
+				check.addEventListener('change', () => {
299
+					handleCheckChanged(readerClass, check);
300
+				});
301
+				check.id = `reader-${readerClass.name}`;
302
+				const label = document.createElement('label');
303
+				label.htmlFor = check.id;
304
+				label.append(document.createTextNode(name));
305
+				const div = document.createElement('div');
306
+				div.classList.add('reader-check');
307
+				div.append(check);
308
+				div.append(label);
309
+				return div;
310
+			}
311
+			function handleCheckChanged(readerClass, check) {
312
+				console.info(`${readerClass.name}: ${check.checked}`);
313
+				if (check.checked) {
314
+					activeReaders.push(new readerClass());
315
+				} else {
316
+					activeReaders = activeReaders.filter((reader) => reader.constructor.name !== readerClass.name);
317
+				}
318
+				parser = new Markdown(activeReaders);
319
+				onMarkdownChange();
320
+			}
213 321
 
214 322
 			document.addEventListener('DOMContentLoaded', onDocumentLoad);
215 323
 		</script>
@@ -217,15 +325,85 @@
217 325
 
218 326
 	<body>
219 327
 		<div class="inputhalf half">
220
-			<textarea id="markdowninput">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut mollis vel metus ut tempor. Morbi dictum, velit quis venenatis consequat, ante leo dignissim magna, quis efficitur ex magna nec ex. In egestas aliquet tortor, vitae posuere dui lobortis ac. Pellentesque quis hendrerit lorem. In maximus ut sapien vel tristique. Pellentesque ut tincidunt orci. Phasellus dignissim massa sit amet tellus placerat finibus. Ut elementum tortor ex, non aliquam libero semper eu.
221
-
222
-Duis gravida convallis nisi ullamcorper tempor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc bibendum varius arcu non molestie. Ut cursus, lorem nec pellentesque interdum, augue risus pellentesque ligula, at vehicula turpis mi vitae nisi. Vivamus pulvinar eget lorem non lacinia. Pellentesque pretium ex at metus elementum semper. Donec tincidunt metus ac ex aliquam, ac iaculis purus facilisis. Phasellus iaculis scelerisque nisl, eu molestie dui sollicitudin sed. Suspendisse ut felis porttitor, sollicitudin urna in, venenatis neque. Donec nec mi ultrices, molestie quam quis, iaculis libero.
223
-
224
-Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut congue consequat vestibulum. Etiam luctus, leo placerat ullamcorper venenatis, nunc metus fringilla sapien, id elementum tellus nulla eu nunc. Integer pulvinar egestas scelerisque. Sed accumsan libero eget pretium sodales. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla pretium egestas elit id cursus. Morbi euismod elementum eros ut eleifend. Praesent velit sem, faucibus sed sapien sit amet, pellentesque fermentum nibh. Nulla consequat turpis nec lacus consequat, sed congue magna consectetur. Nam id urna rhoncus, consectetur eros ac, tempor nisl.
328
+			<div class="toolbar">
329
+				<details>
330
+					<summary>Readers</summary>
225 331
 
226
-Curabitur fermentum nunc sed dapibus feugiat. Etiam volutpat viverra eros sit amet tristique. Suspendisse cursus venenatis accumsan. Suspendisse venenatis vehicula lectus, sed venenatis augue pretium eu. Cras dui eros, iaculis in dictum hendrerit, tincidunt ut sapien. Ut nec nulla ut mauris cursus tincidunt. Suspendisse interdum pulvinar elit sit amet auctor. Donec id lacus tincidunt, varius elit non, tempor felis.
332
+					<div id="readercontainer"></div>
333
+				</details>
334
+			</div>
335
+			<textarea id="markdowninput">## Block Formats {#top}
227 336
 
228
-Quisque posuere, libero ac elementum maximus, lacus nulla lobortis nibh, id aliquam tortor lacus vel quam. Nunc eget dolor non nunc sagittis varius. Proin viverra vestibulum placerat. Fusce placerat interdum diam quis sollicitudin. Praesent sed tincidunt orci. Suspendisse lectus lorem, porta vel quam sit amet, pharetra interdum purus. Suspendisse ac lacus consequat, dapibus nunc in, porttitor purus. Nam dictum elit eget massa tincidunt tempus. Vestibulum blandit, lorem et accumsan tristique, orci dolor vulputate magna, et posuere lorem sapien non sapien. Vivamus nulla justo, eleifend et metus sit amet, gravida iaculis erat. Fusce lacinia cursus accumsan. 
337
+				* Unordered
338
+				* Lists
339
+				  * Sub list
340
+				
341
+				1. Ordered
342
+				2. Lists
343
+				  6. Sub list
344
+				
345
+				&gt; A block quote lorem ipsum dolor sit amet
346
+				
347
+				A regular paragraph
348
+				
349
+				word
350
+				: a unit of meaning in a sentence
351
+				sentence
352
+				: a collection of words
353
+				
354
+				```javascript
355
+				function foo() {
356
+					return 'Fenced code block';
357
+				}
358
+				```
359
+				
360
+					function bar() {
361
+						return 'Indented code';
362
+					}
363
+				
364
+				### Heading, hash style
365
+				
366
+				Heading, underline style
367
+				---
368
+				
369
+				### Modified Heading {style=color:red;}
370
+				
371
+				-# Sub text
372
+				
373
+				| Unit Price | Qty | Subtotal |
374
+				| ---: | ---: | ---: |
375
+				| $1.23 | 2 | =A*B FILL |
376
+				| $4.99 | 6 | |
377
+				| Total | | =SUM(C:C) |
378
+				
379
+				---
380
+				
381
+				## Inline Formats
382
+				
383
+				Normal, **double asterisk,** __double underscore,__ *asterisks,* _underscores,_ ~~double tildes,~~ ~single tildes,~ ^carets,^ ==double equals==, ``double backticks``, `single backticks`.
384
+				
385
+				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
+				
387
+				[^1]: Donec ut felis volutpat, gravida ipsum scelerisque, accumsan est.
388
+				[^abc]: Cras dictum rutrum quam.
389
+				[^foo]: Donec maximus bibendum lorem.
390
+				[^bar]: Praesent consectetur tristique leo. Morbi nec nisi sit amet quam imperdiet vehicula eu feugiat tortor. 
391
+				
392
+				The HTML on the WWW is often full of JS and CSS.
393
+				
394
+				*[HTML]: Hypertext Markup Language
395
+				*[WWW]: World Wide Web
396
+				*[JS]: JavaScript
397
+				*[CSS]: Cascading Style Sheets
398
+				
399
+				Click [here](#top) to return to the top. Referenced link to [Google][google title="I prefer Duck Duck Go"].
400
+				
401
+				![alt text](https://picsum.photos/100/75) ![alt text](https://picsum.photos/101/75 "With a title") ![][testimage]
402
+				
403
+				[testimage]: https://picsum.photos/102/75
404
+				[google]: https://google.com
405
+				
406
+				Some verbatim &lt;span style="color:green;"&gt;HTML&lt;/span&gt;. A script tag will be ignored. &lt;script&gt;&lt;/script&gt;
229 407
 			</textarea>
230 408
 		</div>
231 409
 		<div class="previewhalf half">

+ 24
- 0
testjs.html Dosyayı Görüntüle

@@ -1763,6 +1763,30 @@
1763 1763
 					const result = this.md(markdown);
1764 1764
 					this.assertEqual(result, expected);
1765 1765
 				}
1766
+
1767
+				test_observedError1() {
1768
+					// Saw "Uncaught Error: columnIndex must be number, got string" from this
1769
+					const markdown = '| Unit Price | Qty | Subtotal |\n| ---: | ---: | ---: |\n| $1.23 | 2 | =A*B FILL |\n| $4.99 | 6 | |\n| Total | | =SUM(C:C) |';
1770
+					const expected = '<table> <thead> <tr> ' +
1771
+						'<th style="text-align: right;">Unit Price</th> ' +
1772
+						'<th style="text-align: right;">Qty</th> ' +
1773
+						'<th>Subtotal</th> ' +
1774
+						'</tr> </thead> <tbody> <tr> ' +
1775
+						'<td class="spreadsheet-type-currency" style="text-align: right;" data-numeric-value="1.23" data-string-value="1.23">$1.23</td> ' +
1776
+						'<td class="spreadsheet-type-number" style="text-align: right;" data-numeric-value="2" data-string-value="2">2</td> ' +
1777
+						'<td class="calculated spreadsheet-type-currency" data-numeric-value="2.46" data-string-value="2.46">$2.46</td> ' +
1778
+						'</tr> <tr> ' +
1779
+						'<td class="spreadsheet-type-currency" style="text-align: right;" data-numeric-value="4.99" data-string-value="4.99">$4.99</td> ' +
1780
+						'<td class="spreadsheet-type-number" style="text-align: right;" data-numeric-value="6" data-string-value="6">6</td> ' +
1781
+						'<td class="calculated spreadsheet-type-currency" data-numeric-value="29.94" data-string-value="29.94">$29.94</td> ' +
1782
+						'</tr> <tr> ' +
1783
+						'<td class="spreadsheet-type-string" style="text-align: right;" data-string-value="Total">Total</td> ' +
1784
+						'<td class="spreadsheet-type-blank" style="text-align: right;" data-numeric-value="0" data-string-value=""></td> ' +
1785
+						'<td class="calculated spreadsheet-type-currency" data-numeric-value="32.4" data-string-value="32.4">$32.40</td> ' +
1786
+						'</tr> </tbody> </table>';
1787
+					const result = this.md(markdown);
1788
+					this.assertEqual(result, expected);
1789
+				}
1766 1790
 			}
1767 1791
 		</script>
1768 1792
 	</head>

Loading…
İptal
Kaydet