浏览代码

CSS modifiers work for inline tags now

main
Rocketsoup 1年前
父节点
当前提交
859a8172df
共有 1 个文件被更改,包括 69 次插入11 次删除
  1. 69
    11
      js/markdown.js

+ 69
- 11
js/markdown.js 查看文件

@@ -50,7 +50,7 @@ class _MDTokenType {
50 50
 	static SimpleLink = new _MDTokenType('SimpleLink'); // content=URL
51 51
 	static SimpleEmail = new _MDTokenType('SimpleEmail'); // content=email address
52 52
 	static Footnote = new _MDTokenType('Footnote'); // content=symbol
53
-	static Class = new _MDTokenType('Class'); // content
53
+	static Modifier = new _MDTokenType('Modifier'); // content
54 54
 
55 55
 	static HTMLTag = new _MDTokenType('HTMLTag'); // content=tag string, tag=_MDHTMLTag
56 56
 
@@ -82,18 +82,26 @@ class _MDToken {
82 82
 	extra;
83 83
 	/** @var {_MDHTMLTag|null} */
84 84
 	tag;
85
+	/** @var {_MDTagModifier|null} */
86
+	modifier;
85 87
 
86 88
 	/**
87 89
 	 * @param {String} original
88 90
 	 * @param {_MDTokenType} type
89
-	 * @param {String|null} content
91
+	 * @param {String|_MDTagModifier|null} content
90 92
 	 * @param {String|null} extra
91 93
 	 * @param {_MDHTMLTag|null} tag
92 94
 	 */
93 95
 	constructor(original, type, content=null, extra=null, tag=null) {
94 96
 		this.original = original;
95 97
 		this.type = type;
96
-		this.content = content;
98
+		if (content instanceof _MDTagModifier) {
99
+			this.content = null;
100
+			this.modifier = content;
101
+		} else {
102
+			this.content = content;
103
+			this.modifier = null;
104
+		}
97 105
 		this.extra = extra;
98 106
 		this.tag = tag;
99 107
 	}
@@ -925,12 +933,10 @@ class _MDTagModifier {
925 933
 	/** @var {Object} */
926 934
 	attributes = {};
927 935
 
928
-	static #baseClassRegex = /\.([a-z_\-][a-z0-9_\-]*)/i;
929
-	static #baseIdRegex = /#([a-z_\-][a-z0-9_\-]*)/i;
930
-	static #baseAttributeRegex = /([a-z0-9]+)=([^\s\}]+)/i;
931
-	static #modifierRegex = new RegExp('(?:' + this.#baseClassRegex.source + '|' + this.#baseIdRegex.source + '|' + this.#baseAttributeRegex.source + ')', 'i');
932
-	// static #baseRegex = new RegExp('\\{(' + this.#modifierRegex.source + '(?:\\s+' + this.#modifierRegex.source + '))\\}', 'i'); //  /\{((?:||)(?:\s+(?:\.[a-z_\-][a-z0-9_\-]*|#[a-z_\-][a-z0-9_\-]*|[a-z0-9]+=\S+)))\}/i; // 1=content
933
-	static #baseRegex = /\{([^}]+)}/i;
936
+	static #baseClassRegex = /\.([a-z_\-][a-z0-9_\-]*?)/i;
937
+	static #baseIdRegex = /#([a-z_\-][a-z0-9_\-]*?)/i;
938
+	static #baseAttributeRegex = /([a-z0-9]+?)=([^\s\}]+?)/i;
939
+	static #baseRegex = /\{([^}]+?)}/i;
934 940
 	static #leadingClassRegex = new RegExp('^' + this.#baseRegex.source, 'i');
935 941
 	static #trailingClassRegex = new RegExp('^(.*?)\\s*' + this.#baseRegex.source + '\\s*$', 'i');
936 942
 	static #classRegex = new RegExp('^' + this.#baseClassRegex.source + '$', 'i');  // 1=classname
@@ -984,6 +990,17 @@ class _MDTagModifier {
984 990
 	}
985 991
 
986 992
 	/**
993
+	 * Extracts modifier from head of string.
994
+	 * @param {String} line
995
+	 * @returns {_MDTagModifier}
996
+	 */
997
+	static fromStart(line) {
998
+		let groups = this.#leadingClassRegex.exec(line);
999
+		if (groups === null) return null;
1000
+		return this.#fromContents(groups[1]);
1001
+	}
1002
+
1003
+	/**
987 1004
 	 * @param {String} line
988 1005
 	 * @returns {String}
989 1006
 	 */
@@ -1243,7 +1260,7 @@ class Markdown {
1243 1260
 	static #footnoteWithTitleRegex = /^\[\^(\d+?)\s+"(.*?)"\]/;  // 1=symbol, 2=title
1244 1261
 	static #footnoteRegex = /^\[\^(\d+?)\]/;  // 1=symbol
1245 1262
 	// Note: label contents have to have matching pairs of [] and (). Handles images inside links.
1246
-	static #labelRegex = /^\[((?:[^\[\]]*\[[^\[\]]*\][^\[\]]*|[^\(\)]*\([^\(\)]*?\)[^\(\)]*|[^\[\]\(\)]*?)*)\]/;  // 1=content
1263
+	static #labelRegex = /^\[((?:[^\[\]]*?\[[^\[\]]*?\][^\[\]]*?|[^\(\)]*?\([^\(\)]*?\)[^\(\)]*?|[^\[\]\(\)]*?)*?)\]/;  // 1=content
1247 1264
 	static #urlWithTitleRegex = /^\((\S+?)\s+"(.*?)"\)/i;  // 1=URL, 2=title
1248 1265
 	static #urlRegex = /^\((\S+?)\)/i;  // 1=URL
1249 1266
 	static #emailWithTitleRegex = new RegExp("^\\(\\s*(" + this.#baseEmailRegex.source + ")\\s+\"(.*?)\"\\s*\\)", "i");  // 1=email, 2=title
@@ -1253,6 +1270,34 @@ class Markdown {
1253 1270
 
1254 1271
 	/**
1255 1272
 	 * @param {String} line
1273
+	 * @returns {String[]}
1274
+	 */
1275
+	static #matchLabel(line) {
1276
+		if (!line.startsWith('[')) return null;
1277
+		var parenCount = 0;
1278
+		var bracketCount = 0;
1279
+		for (var p = 1; p < line.length; p++) {
1280
+			let ch = line.substring(p, p + 1);
1281
+			if (ch == '(') {
1282
+				parenCount++;
1283
+			} else if (ch == ')') {
1284
+				parenCount--;
1285
+				if (parenCount < 0) return null;
1286
+			} else if (ch == '[') {
1287
+				bracketCount++;
1288
+			} else if (ch == ']') {
1289
+				if (bracketCount > 0) {
1290
+					bracketCount--;
1291
+				} else {
1292
+					return [ line.substring(0, p + 1), line.substring(1, p) ];
1293
+				}
1294
+			}
1295
+		}
1296
+		return null;
1297
+	}
1298
+
1299
+	/**
1300
+	 * @param {String} line
1256 1301
 	 * @returns {_MDToken[]} tokens
1257 1302
 	 */
1258 1303
 	static #tokenize(line) {
@@ -1261,6 +1306,7 @@ class Markdown {
1261 1306
 		var expectLiteral = false;
1262 1307
 		var groups = null;
1263 1308
 		var tag = null;
1309
+		var modifier = null;
1264 1310
 		const endText = function() {
1265 1311
 			if (text.length == 0) return;
1266 1312
 			let textGroups = Markdown.#textWhitespaceRegex.exec(text);
@@ -1315,7 +1361,7 @@ class Markdown {
1315 1361
 				endText();
1316 1362
 				tokens.push(new _MDToken(groups[0], _MDTokenType.Footnote, groups[1]));
1317 1363
 				p += groups[0].length - 1;
1318
-			} else if (groups = this.#labelRegex.exec(remainder)) {
1364
+			} else if (groups = this.#matchLabel(remainder)) {
1319 1365
 				// Label/ref for link/image   [Foo]
1320 1366
 				endText();
1321 1367
 				tokens.push(new _MDToken(groups[0], _MDTokenType.Label, groups[1]));
@@ -1354,6 +1400,10 @@ class Markdown {
1354 1400
 				endText();
1355 1401
 				tokens.push(new _MDToken(tag.fullTag, _MDTokenType.HTMLTag, tag.fullTag, null, tag));
1356 1402
 				p += tag.fullTag.length - 1;
1403
+			} else if (modifier = _MDTagModifier.fromStart(remainder)) {
1404
+				endText();
1405
+				tokens.push(new _MDToken(modifier.original, _MDTokenType.Modifier, modifier));
1406
+				p += modifier.original.length - 1;
1357 1407
 			} else {
1358 1408
 				text += ch;
1359 1409
 			}
@@ -1551,10 +1601,18 @@ class Markdown {
1551 1601
 				}
1552 1602
 			} while (anyChanges);
1553 1603
 		}
1604
+		var lastSpan = null;
1554 1605
 		spans = spans.map(function(span) {
1555 1606
 			if (span instanceof _MDToken) {
1607
+				if (span.type == _MDTokenType.Modifier && lastSpan) {
1608
+					span.modifier.applyTo(lastSpan);
1609
+					lastSpan = null;
1610
+					return new _MDTextSpan('');
1611
+				}
1612
+				lastSpan = null;
1556 1613
 				return new _MDTextSpan(span.original);
1557 1614
 			} else if (span instanceof _MDSpan) {
1615
+				lastSpan = (span instanceof _MDTextSpan) ? null : span;
1558 1616
 				return span;
1559 1617
 			} else {
1560 1618
 				throw new Error(`Unexpected span type ${span.constructor.name}`);

正在加载...
取消
保存