tiny-markdown-editor 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/tiny-mde.js +67 -18
- package/dist/tiny-mde.min.js +1 -1
- package/dist/tiny-mde.tiny.js +1 -1
- package/lib/TinyMDE.d.ts +4 -0
- package/lib/TinyMDE.js +35 -17
- package/lib/grammar.d.ts +7 -0
- package/lib/grammar.js +27 -0
- package/package.json +1 -1
package/lib/TinyMDE.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { GrammarRule } from "./grammar";
|
|
1
2
|
export interface EditorProps {
|
|
2
3
|
element?: string | HTMLElement;
|
|
3
4
|
editor?: string | HTMLElement;
|
|
4
5
|
content?: string;
|
|
5
6
|
textarea?: string | HTMLTextAreaElement;
|
|
7
|
+
customInlineGrammar?: Record<string, GrammarRule>;
|
|
6
8
|
}
|
|
7
9
|
export interface Position {
|
|
8
10
|
row: number;
|
|
@@ -38,6 +40,8 @@ export declare class Editor {
|
|
|
38
40
|
linkLabels: string[];
|
|
39
41
|
lineDirty: boolean[];
|
|
40
42
|
lastCommandState: Record<string, boolean | null> | null;
|
|
43
|
+
private customInlineGrammar;
|
|
44
|
+
private mergedInlineGrammar;
|
|
41
45
|
listeners: {
|
|
42
46
|
change: EventHandler<ChangeEvent>[];
|
|
43
47
|
selection: EventHandler<SelectionEvent>[];
|
package/lib/TinyMDE.js
CHANGED
|
@@ -14,6 +14,8 @@ class Editor {
|
|
|
14
14
|
this.linkLabels = [];
|
|
15
15
|
this.lineDirty = [];
|
|
16
16
|
this.lastCommandState = null;
|
|
17
|
+
this.customInlineGrammar = {};
|
|
18
|
+
this.mergedInlineGrammar = grammar_1.inlineGrammar;
|
|
17
19
|
this.listeners = {
|
|
18
20
|
change: [],
|
|
19
21
|
selection: [],
|
|
@@ -33,6 +35,8 @@ class Editor {
|
|
|
33
35
|
this.linkLabels = [];
|
|
34
36
|
this.lineDirty = [];
|
|
35
37
|
this.lastCommandState = null;
|
|
38
|
+
this.customInlineGrammar = props.customInlineGrammar || {};
|
|
39
|
+
this.mergedInlineGrammar = (0, grammar_1.createMergedInlineGrammar)(this.customInlineGrammar);
|
|
36
40
|
this.listeners = {
|
|
37
41
|
change: [],
|
|
38
42
|
selection: [],
|
|
@@ -555,17 +559,31 @@ class Editor {
|
|
|
555
559
|
outer: while (string) {
|
|
556
560
|
// Process simple rules (non-delimiter)
|
|
557
561
|
for (let rule of ["escape", "code", "autolink", "html"]) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
562
|
+
if (this.mergedInlineGrammar[rule]) {
|
|
563
|
+
let cap = this.mergedInlineGrammar[rule].regexp.exec(string);
|
|
564
|
+
if (cap) {
|
|
565
|
+
string = string.substr(cap[0].length);
|
|
566
|
+
offset += cap[0].length;
|
|
567
|
+
processed += this.mergedInlineGrammar[rule].replacement.replace(/\$([1-9])/g, (str, p1) => (0, grammar_1.htmlescape)(cap[p1]));
|
|
568
|
+
continue outer;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
// Process custom inline grammar rules
|
|
573
|
+
for (let rule in this.customInlineGrammar) {
|
|
574
|
+
if (rule !== "escape" && rule !== "code" && rule !== "autolink" && rule !== "html" && rule !== "linkOpen" && rule !== "imageOpen" && rule !== "linkLabel" && rule !== "default") {
|
|
575
|
+
let cap = this.mergedInlineGrammar[rule].regexp.exec(string);
|
|
576
|
+
if (cap) {
|
|
577
|
+
string = string.substr(cap[0].length);
|
|
578
|
+
offset += cap[0].length;
|
|
579
|
+
processed += this.mergedInlineGrammar[rule].replacement.replace(/\$([1-9])/g, (str, p1) => (0, grammar_1.htmlescape)(cap[p1]));
|
|
580
|
+
continue outer;
|
|
581
|
+
}
|
|
564
582
|
}
|
|
565
583
|
}
|
|
566
584
|
// Check for links / images
|
|
567
|
-
let potentialLink = string.match(
|
|
568
|
-
let potentialImage = string.match(
|
|
585
|
+
let potentialLink = string.match(this.mergedInlineGrammar.linkOpen.regexp);
|
|
586
|
+
let potentialImage = string.match(this.mergedInlineGrammar.imageOpen.regexp);
|
|
569
587
|
if (potentialImage || potentialLink) {
|
|
570
588
|
let result = this.parseLinkOrImage(string, !!potentialImage);
|
|
571
589
|
if (result) {
|
|
@@ -673,11 +691,11 @@ class Editor {
|
|
|
673
691
|
continue outer;
|
|
674
692
|
}
|
|
675
693
|
// Process 'default' rule
|
|
676
|
-
cap =
|
|
694
|
+
cap = this.mergedInlineGrammar.default.regexp.exec(string);
|
|
677
695
|
if (cap) {
|
|
678
696
|
string = string.substr(cap[0].length);
|
|
679
697
|
offset += cap[0].length;
|
|
680
|
-
processed +=
|
|
698
|
+
processed += this.mergedInlineGrammar.default.replacement.replace(/\$([1-9])/g, (str, p1) => (0, grammar_1.htmlescape)(cap[p1]));
|
|
681
699
|
continue outer;
|
|
682
700
|
}
|
|
683
701
|
throw "Infinite loop!";
|
|
@@ -924,20 +942,20 @@ class Editor {
|
|
|
924
942
|
let string = originalString.substr(currentOffset);
|
|
925
943
|
// Capture any escapes and code blocks at current position
|
|
926
944
|
for (let rule of ["escape", "code", "autolink", "html"]) {
|
|
927
|
-
let cap =
|
|
945
|
+
let cap = this.mergedInlineGrammar[rule].regexp.exec(string);
|
|
928
946
|
if (cap) {
|
|
929
947
|
currentOffset += cap[0].length;
|
|
930
948
|
continue textOuter;
|
|
931
949
|
}
|
|
932
950
|
}
|
|
933
951
|
// Check for image
|
|
934
|
-
if (string.match(
|
|
952
|
+
if (string.match(this.mergedInlineGrammar.imageOpen.regexp)) {
|
|
935
953
|
bracketLevel++;
|
|
936
954
|
currentOffset += 2;
|
|
937
955
|
continue textOuter;
|
|
938
956
|
}
|
|
939
957
|
// Check for link
|
|
940
|
-
if (string.match(
|
|
958
|
+
if (string.match(this.mergedInlineGrammar.linkOpen.regexp)) {
|
|
941
959
|
bracketLevel++;
|
|
942
960
|
if (!isImage) {
|
|
943
961
|
if (this.parseLinkOrImage(string, false)) {
|
|
@@ -967,12 +985,12 @@ class Editor {
|
|
|
967
985
|
// REFERENCE LINKS
|
|
968
986
|
if (nextChar === "[") {
|
|
969
987
|
let string = originalString.substr(currentOffset);
|
|
970
|
-
let cap =
|
|
988
|
+
let cap = this.mergedInlineGrammar.linkLabel.regexp.exec(string);
|
|
971
989
|
if (cap) {
|
|
972
990
|
currentOffset += cap[0].length;
|
|
973
991
|
linkLabel.push(cap[1], cap[2], cap[3]);
|
|
974
|
-
if (cap[
|
|
975
|
-
linkRef = cap[
|
|
992
|
+
if (cap[this.mergedInlineGrammar.linkLabel.labelPlaceholder]) {
|
|
993
|
+
linkRef = cap[this.mergedInlineGrammar.linkLabel.labelPlaceholder];
|
|
976
994
|
}
|
|
977
995
|
else {
|
|
978
996
|
linkRef = linkText.trim();
|
|
@@ -1033,7 +1051,7 @@ class Editor {
|
|
|
1033
1051
|
continue inlineOuter;
|
|
1034
1052
|
}
|
|
1035
1053
|
// Process backslash escapes
|
|
1036
|
-
cap =
|
|
1054
|
+
cap = this.mergedInlineGrammar.escape.regexp.exec(string);
|
|
1037
1055
|
if (cap) {
|
|
1038
1056
|
switch (linkDetails.length) {
|
|
1039
1057
|
case 0:
|
package/lib/grammar.d.ts
CHANGED
|
@@ -49,6 +49,13 @@ export declare const htmlBlockGrammar: HTMLBlockRule[];
|
|
|
49
49
|
* In the regular expressions, replacements from the object 'replacements' will be processed before compiling into the property regexp.
|
|
50
50
|
*/
|
|
51
51
|
export declare const inlineGrammar: Record<string, GrammarRule>;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a merged inline grammar by combining the default inline grammar with custom rules.
|
|
54
|
+
* Custom rules are processed and their regexp patterns are expanded with replacements.
|
|
55
|
+
* @param customRules - Object containing custom inline grammar rules
|
|
56
|
+
* @returns Merged inline grammar object
|
|
57
|
+
*/
|
|
58
|
+
export declare function createMergedInlineGrammar(customRules?: Record<string, GrammarRule>): Record<string, GrammarRule>;
|
|
52
59
|
/**
|
|
53
60
|
* Escapes HTML special characters (<, >, and &) in the string.
|
|
54
61
|
* @param {string} string The raw string to be escaped
|
package/lib/grammar.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.commands = exports.inlineGrammar = exports.htmlBlockGrammar = exports.lineGrammar = exports.punctuationTrailing = exports.punctuationLeading = void 0;
|
|
4
|
+
exports.createMergedInlineGrammar = createMergedInlineGrammar;
|
|
4
5
|
exports.htmlescape = htmlescape;
|
|
5
6
|
const replacements = {
|
|
6
7
|
ASCIIPunctuation: /[!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~\\]/,
|
|
@@ -178,6 +179,32 @@ for (let rule of exports.htmlBlockGrammar) {
|
|
|
178
179
|
}
|
|
179
180
|
rule.start = new RegExp(re, rule.start.flags);
|
|
180
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Creates a merged inline grammar by combining the default inline grammar with custom rules.
|
|
184
|
+
* Custom rules are processed and their regexp patterns are expanded with replacements.
|
|
185
|
+
* @param customRules - Object containing custom inline grammar rules
|
|
186
|
+
* @returns Merged inline grammar object
|
|
187
|
+
*/
|
|
188
|
+
function createMergedInlineGrammar(customRules = {}) {
|
|
189
|
+
const merged = { ...exports.inlineGrammar };
|
|
190
|
+
// Process custom rules
|
|
191
|
+
for (const [ruleName, rule] of Object.entries(customRules)) {
|
|
192
|
+
// Copy the rule to avoid modifying the original
|
|
193
|
+
const processedRule = { ...rule };
|
|
194
|
+
// Process replacements in the regexp
|
|
195
|
+
let regexpSource = rule.regexp.source;
|
|
196
|
+
const replacementRegexp = new RegExp(Object.keys(replacements).join('|'));
|
|
197
|
+
// Replace while there is something to replace
|
|
198
|
+
while (regexpSource.match(replacementRegexp)) {
|
|
199
|
+
regexpSource = regexpSource.replace(replacementRegexp, (match) => {
|
|
200
|
+
return replacements[match].source;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
processedRule.regexp = new RegExp(regexpSource, rule.regexp.flags);
|
|
204
|
+
merged[ruleName] = processedRule;
|
|
205
|
+
}
|
|
206
|
+
return merged;
|
|
207
|
+
}
|
|
181
208
|
/**
|
|
182
209
|
* Escapes HTML special characters (<, >, and &) in the string.
|
|
183
210
|
* @param {string} string The raw string to be escaped
|