quikdown 1.0.5 → 1.1.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 +37 -23
- package/dist/quikdown.cjs +29 -11
- package/dist/quikdown.d.ts +26 -5
- package/dist/quikdown.dark.css +1 -1
- package/dist/quikdown.esm.js +29 -11
- package/dist/quikdown.esm.min.js +2 -2
- package/dist/quikdown.esm.min.js.map +1 -1
- package/dist/quikdown.light.css +1 -1
- package/dist/quikdown.umd.js +29 -11
- package/dist/quikdown.umd.min.js +2 -2
- package/dist/quikdown.umd.min.js.map +1 -1
- package/dist/quikdown_bd.cjs +102 -14
- package/dist/quikdown_bd.d.ts +10 -8
- package/dist/quikdown_bd.esm.js +102 -14
- package/dist/quikdown_bd.esm.min.js +2 -2
- package/dist/quikdown_bd.esm.min.js.map +1 -1
- package/dist/quikdown_bd.umd.js +102 -14
- package/dist/quikdown_bd.umd.min.js +2 -2
- package/dist/quikdown_bd.umd.min.js.map +1 -1
- package/dist/quikdown_edit.cjs +2100 -160
- package/dist/quikdown_edit.esm.js +2100 -160
- package/dist/quikdown_edit.esm.min.js +3 -4
- package/dist/quikdown_edit.esm.min.js.map +1 -1
- package/dist/quikdown_edit.umd.js +2101 -161
- package/dist/quikdown_edit.umd.min.js +3 -4
- package/dist/quikdown_edit.umd.min.js.map +1 -1
- package/package.json +26 -54
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@ Quikdown is a small, secure markdown parser with bidirectional conversion. Zero
|
|
|
9
9
|
|
|
10
10
|
For small and fast projects quikdown includes built-in inline styles for a "batteries included" rendering experience, but these can be overridden with themed css (see light and dark examples).
|
|
11
11
|
|
|
12
|
-
- **quikdown.js** (
|
|
13
|
-
- **quikdown_bd.js** (
|
|
14
|
-
- **quikdown_edit.js** (
|
|
12
|
+
- **quikdown.js** (9.0KB) - Markdown to HTML Parser with theme support, XSS protection, fence callbacks
|
|
13
|
+
- **quikdown_bd.js** (13.8KB) - Bidirectional (HTML ↔ Markdown) Parser
|
|
14
|
+
- **quikdown_edit.js** (68.0KB) - Drop-in editor component with live preview, copy-as-rich-text, and lazy-loaded fence handlers
|
|
15
15
|
|
|
16
16
|
🚀 **[Live Demo](https://deftio.github.io/quikdown/examples/quikdown-live.html)** | **[Editor Demo](https://deftio.github.io/quikdown/examples/qde/)** | **[Documentation](docs/)**
|
|
17
17
|
|
|
@@ -21,7 +21,7 @@ For small and fast projects quikdown includes built-in inline styles for a "batt
|
|
|
21
21
|
|
|
22
22
|
- 📦 **Zero dependencies** - No external libraries required
|
|
23
23
|
- 🌐 **Universal** - Works in browsers and Node.js
|
|
24
|
-
- 🚀 **Lightweight** -
|
|
24
|
+
- 🚀 **Lightweight** - 9.0KB (core), 13.8KB (bidirectional), 68.0KB (editor)
|
|
25
25
|
- 🔒 **Secure by default** - Built-in XSS protection with URL sanitization
|
|
26
26
|
- 🎨 **Flexible styling** - Inline styles or CSS classes with theme support
|
|
27
27
|
- 🔌 **Plugin system** - Extensible fence block handlers
|
|
@@ -101,6 +101,14 @@ editor.setMarkdown('# Content \nTo be quik or not to be.'); // provide default
|
|
|
101
101
|
const content = editor.getMarkdown(); // get source content, see APIs for getting / setting HTML
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
**Note:** The editor automatically lazy-loads plugin libraries from CDNs when needed:
|
|
105
|
+
- **highlight.js** - Loaded when code blocks are encountered and `highlightjs: true`
|
|
106
|
+
- **mermaid** - Loaded when mermaid diagrams are found and `mermaid: true`
|
|
107
|
+
- **DOMPurify** - Loaded when HTML fence blocks are rendered
|
|
108
|
+
- **KaTeX** - Loaded when math/tex fence blocks are encountered
|
|
109
|
+
|
|
110
|
+
This keeps the initial bundle small while providing rich functionality on-demand.
|
|
111
|
+
|
|
104
112
|
## Other Configuration Options
|
|
105
113
|
quikdown supports built-in styles for a "batteries included" experience or you can bring your own CSS themes. Example css files are provided for basic light and dark themes to get started.
|
|
106
114
|
|
|
@@ -108,7 +116,9 @@ quikdown supports built-in styles for a "batteries included" experience or you c
|
|
|
108
116
|
const html = quikdown(markdown, {
|
|
109
117
|
lazy_linefeeds: true, // Single newlines become <br>
|
|
110
118
|
inline_styles: false, // Use class based CSS instead of inline styles
|
|
111
|
-
fence_plugin:
|
|
119
|
+
fence_plugin: { // Custom code block processor (v1.1.0+ API)
|
|
120
|
+
render: myHandler // Function to render fence blocks
|
|
121
|
+
}
|
|
112
122
|
});
|
|
113
123
|
```
|
|
114
124
|
|
|
@@ -135,18 +145,19 @@ Quikdown provides a callback for all fenced text such as code blocks, math, svg
|
|
|
135
145
|
Handle code blocks with custom languages:
|
|
136
146
|
|
|
137
147
|
```javascript
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
148
|
+
const fencePlugin = {
|
|
149
|
+
render: (code, language) => {
|
|
150
|
+
if (language === 'mermaid') {
|
|
151
|
+
// Process with mermaid library and return rendered diagram
|
|
152
|
+
const id = 'mermaid-' + Math.random().toString(36).substr(2, 9);
|
|
153
|
+
setTimeout(() => mermaid.render(id + '-svg', code).then(result => {
|
|
154
|
+
document.getElementById(id).innerHTML = result.svg;
|
|
155
|
+
}), 0);
|
|
156
|
+
return `<div id="${id}" class="mermaid">Loading diagram...</div>`;
|
|
157
|
+
}
|
|
158
|
+
// Return undefined for default handling
|
|
146
159
|
}
|
|
147
|
-
|
|
148
|
-
// Return undefined for default handling
|
|
149
|
-
}
|
|
160
|
+
};
|
|
150
161
|
|
|
151
162
|
const html = quikdown(markdown, { fence_plugin: fencePlugin });
|
|
152
163
|
```
|
|
@@ -156,18 +167,21 @@ const html = quikdown(markdown, { fence_plugin: fencePlugin });
|
|
|
156
167
|
|
|
157
168
|
quikdown includes TypeScript definitions for better IDE support and type safety:
|
|
158
169
|
|
|
159
|
-
```
|
|
160
|
-
import quikdown, { QuikdownOptions } from 'quikdown';
|
|
170
|
+
```typescript
|
|
171
|
+
import quikdown, { QuikdownOptions, FencePlugin } from 'quikdown';
|
|
172
|
+
|
|
173
|
+
const fencePlugin: FencePlugin = {
|
|
174
|
+
render: (content: string, language: string) => {
|
|
175
|
+
return `<pre class="hljs ${language}">${content}</pre>`;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
161
178
|
|
|
162
179
|
const options: QuikdownOptions = {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return `<pre class="hljs ${language}">${content}</pre>`;
|
|
166
|
-
}
|
|
180
|
+
inline_styles: true,
|
|
181
|
+
fence_plugin: fencePlugin
|
|
167
182
|
};
|
|
168
183
|
|
|
169
184
|
const html: string = quikdown(markdown, options);
|
|
170
|
-
|
|
171
185
|
```
|
|
172
186
|
|
|
173
187
|
## Supported Markdown
|
package/dist/quikdown.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* quikdown - Lightweight Markdown Parser
|
|
3
|
-
* @version 1.
|
|
3
|
+
* @version 1.1.1
|
|
4
4
|
* @license BSD-2-Clause
|
|
5
5
|
* @copyright DeftIO 2025
|
|
6
6
|
*/
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
// Version will be injected at build time
|
|
23
|
-
const quikdownVersion = '1.
|
|
23
|
+
const quikdownVersion = '1.1.1';
|
|
24
24
|
|
|
25
25
|
// Constants for reuse
|
|
26
26
|
const CLASS_PREFIX = 'quikdown-';
|
|
@@ -146,13 +146,14 @@ function quikdown(markdown, options = {}) {
|
|
|
146
146
|
// Trim the language specification
|
|
147
147
|
const langTrimmed = lang ? lang.trim() : '';
|
|
148
148
|
|
|
149
|
-
// If custom fence plugin is provided, use it
|
|
150
|
-
if (fence_plugin && typeof fence_plugin === 'function') {
|
|
149
|
+
// If custom fence plugin is provided, use it (v1.1.0: object format required)
|
|
150
|
+
if (fence_plugin && fence_plugin.render && typeof fence_plugin.render === 'function') {
|
|
151
151
|
codeBlocks.push({
|
|
152
152
|
lang: langTrimmed,
|
|
153
153
|
code: code.trimEnd(),
|
|
154
154
|
custom: true,
|
|
155
|
-
fence: fence
|
|
155
|
+
fence: fence,
|
|
156
|
+
hasReverse: !!fence_plugin.reverse
|
|
156
157
|
});
|
|
157
158
|
} else {
|
|
158
159
|
codeBlocks.push({
|
|
@@ -191,8 +192,8 @@ function quikdown(markdown, options = {}) {
|
|
|
191
192
|
// Merge consecutive blockquotes
|
|
192
193
|
html = html.replace(/<\/blockquote>\n<blockquote>/g, '\n');
|
|
193
194
|
|
|
194
|
-
// Process horizontal rules
|
|
195
|
-
html = html.replace(
|
|
195
|
+
// Process horizontal rules (allow trailing spaces)
|
|
196
|
+
html = html.replace(/^---+\s*$/gm, `<hr${getAttr('hr')}>`);
|
|
196
197
|
|
|
197
198
|
// Process lists
|
|
198
199
|
html = processLists(html, getAttr, inline_styles, bidirectional);
|
|
@@ -272,7 +273,15 @@ function quikdown(markdown, options = {}) {
|
|
|
272
273
|
html = html.replace(/ $/gm, `<br${getAttr('br')}>`);
|
|
273
274
|
|
|
274
275
|
// Paragraphs (double newlines)
|
|
275
|
-
|
|
276
|
+
// Don't add </p> after block elements (they're not in paragraphs)
|
|
277
|
+
html = html.replace(/\n\n+/g, (match, offset) => {
|
|
278
|
+
// Check if we're after a block element closing tag
|
|
279
|
+
const before = html.substring(0, offset);
|
|
280
|
+
if (before.match(/<\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)) {
|
|
281
|
+
return '<p>'; // Just open a new paragraph
|
|
282
|
+
}
|
|
283
|
+
return '</p><p>'; // Normal paragraph break
|
|
284
|
+
});
|
|
276
285
|
html = '<p>' + html + '</p>';
|
|
277
286
|
}
|
|
278
287
|
|
|
@@ -297,15 +306,20 @@ function quikdown(markdown, options = {}) {
|
|
|
297
306
|
html = html.replace(pattern, replacement);
|
|
298
307
|
});
|
|
299
308
|
|
|
309
|
+
// Fix orphaned closing </p> tags after block elements
|
|
310
|
+
// When a paragraph follows a block element, ensure it has opening <p>
|
|
311
|
+
html = html.replace(/(<\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\n([^<])/g, '$1\n<p>$2');
|
|
312
|
+
|
|
300
313
|
// Phase 4: Restore code blocks and inline code
|
|
301
314
|
|
|
302
315
|
// Restore code blocks
|
|
303
316
|
codeBlocks.forEach((block, i) => {
|
|
304
317
|
let replacement;
|
|
305
318
|
|
|
306
|
-
if (block.custom && fence_plugin) {
|
|
307
|
-
// Use custom fence plugin
|
|
308
|
-
replacement = fence_plugin(block.code, block.lang);
|
|
319
|
+
if (block.custom && fence_plugin && fence_plugin.render) {
|
|
320
|
+
// Use custom fence plugin (v1.1.0: object format with render function)
|
|
321
|
+
replacement = fence_plugin.render(block.code, block.lang);
|
|
322
|
+
|
|
309
323
|
// If plugin returns undefined, fall back to default rendering
|
|
310
324
|
if (replacement === undefined) {
|
|
311
325
|
const langClass = !inline_styles && block.lang ? ` class="language-${block.lang}"` : '';
|
|
@@ -313,6 +327,10 @@ function quikdown(markdown, options = {}) {
|
|
|
313
327
|
const langAttr = bidirectional && block.lang ? ` data-qd-lang="${escapeHtml(block.lang)}"` : '';
|
|
314
328
|
const fenceAttr = bidirectional ? ` data-qd-fence="${escapeHtml(block.fence)}"` : '';
|
|
315
329
|
replacement = `<pre${getAttr('pre')}${fenceAttr}${langAttr}><code${codeAttr}>${escapeHtml(block.code)}</code></pre>`;
|
|
330
|
+
} else if (bidirectional) {
|
|
331
|
+
// If bidirectional and plugin provided HTML, add data attributes for roundtrip
|
|
332
|
+
replacement = replacement.replace(/^<(\w+)/,
|
|
333
|
+
`<$1 data-qd-fence="${escapeHtml(block.fence)}" data-qd-lang="${escapeHtml(block.lang)}" data-qd-source="${escapeHtml(block.code)}"`);
|
|
316
334
|
}
|
|
317
335
|
} else {
|
|
318
336
|
// Default rendering
|
package/dist/quikdown.d.ts
CHANGED
|
@@ -5,17 +5,38 @@
|
|
|
5
5
|
|
|
6
6
|
declare module 'quikdown' {
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Fence plugin for custom code block rendering (v1.1.0+)
|
|
9
9
|
*/
|
|
10
|
-
export interface
|
|
10
|
+
export interface FencePlugin {
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
* Return undefined to use default rendering.
|
|
12
|
+
* Render markdown fence to HTML
|
|
14
13
|
* @param content - The code block content (unescaped)
|
|
15
14
|
* @param language - The language identifier (or empty string)
|
|
16
15
|
* @returns HTML string or undefined for default rendering
|
|
17
16
|
*/
|
|
18
|
-
|
|
17
|
+
render: (content: string, language: string) => string | undefined;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Convert HTML element back to markdown fence (optional)
|
|
21
|
+
* @param element - The HTML element to convert
|
|
22
|
+
* @returns Fence details or null to use default
|
|
23
|
+
*/
|
|
24
|
+
reverse?: (element: HTMLElement) => {
|
|
25
|
+
fence: string;
|
|
26
|
+
lang: string;
|
|
27
|
+
content: string;
|
|
28
|
+
} | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Options for configuring the quikdown parser
|
|
33
|
+
*/
|
|
34
|
+
export interface QuikdownOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Custom renderer for fenced code blocks (v1.1.0: object format required)
|
|
37
|
+
* @since 1.1.0 - Must be an object with render function
|
|
38
|
+
*/
|
|
39
|
+
fence_plugin?: FencePlugin;
|
|
19
40
|
|
|
20
41
|
/**
|
|
21
42
|
* If true, uses inline styles instead of CSS classes.
|
package/dist/quikdown.dark.css
CHANGED
package/dist/quikdown.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* quikdown - Lightweight Markdown Parser
|
|
3
|
-
* @version 1.
|
|
3
|
+
* @version 1.1.1
|
|
4
4
|
* @license BSD-2-Clause
|
|
5
5
|
* @copyright DeftIO 2025
|
|
6
6
|
*/
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
// Version will be injected at build time
|
|
21
|
-
const quikdownVersion = '1.
|
|
21
|
+
const quikdownVersion = '1.1.1';
|
|
22
22
|
|
|
23
23
|
// Constants for reuse
|
|
24
24
|
const CLASS_PREFIX = 'quikdown-';
|
|
@@ -144,13 +144,14 @@ function quikdown(markdown, options = {}) {
|
|
|
144
144
|
// Trim the language specification
|
|
145
145
|
const langTrimmed = lang ? lang.trim() : '';
|
|
146
146
|
|
|
147
|
-
// If custom fence plugin is provided, use it
|
|
148
|
-
if (fence_plugin && typeof fence_plugin === 'function') {
|
|
147
|
+
// If custom fence plugin is provided, use it (v1.1.0: object format required)
|
|
148
|
+
if (fence_plugin && fence_plugin.render && typeof fence_plugin.render === 'function') {
|
|
149
149
|
codeBlocks.push({
|
|
150
150
|
lang: langTrimmed,
|
|
151
151
|
code: code.trimEnd(),
|
|
152
152
|
custom: true,
|
|
153
|
-
fence: fence
|
|
153
|
+
fence: fence,
|
|
154
|
+
hasReverse: !!fence_plugin.reverse
|
|
154
155
|
});
|
|
155
156
|
} else {
|
|
156
157
|
codeBlocks.push({
|
|
@@ -189,8 +190,8 @@ function quikdown(markdown, options = {}) {
|
|
|
189
190
|
// Merge consecutive blockquotes
|
|
190
191
|
html = html.replace(/<\/blockquote>\n<blockquote>/g, '\n');
|
|
191
192
|
|
|
192
|
-
// Process horizontal rules
|
|
193
|
-
html = html.replace(
|
|
193
|
+
// Process horizontal rules (allow trailing spaces)
|
|
194
|
+
html = html.replace(/^---+\s*$/gm, `<hr${getAttr('hr')}>`);
|
|
194
195
|
|
|
195
196
|
// Process lists
|
|
196
197
|
html = processLists(html, getAttr, inline_styles, bidirectional);
|
|
@@ -270,7 +271,15 @@ function quikdown(markdown, options = {}) {
|
|
|
270
271
|
html = html.replace(/ $/gm, `<br${getAttr('br')}>`);
|
|
271
272
|
|
|
272
273
|
// Paragraphs (double newlines)
|
|
273
|
-
|
|
274
|
+
// Don't add </p> after block elements (they're not in paragraphs)
|
|
275
|
+
html = html.replace(/\n\n+/g, (match, offset) => {
|
|
276
|
+
// Check if we're after a block element closing tag
|
|
277
|
+
const before = html.substring(0, offset);
|
|
278
|
+
if (before.match(/<\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)) {
|
|
279
|
+
return '<p>'; // Just open a new paragraph
|
|
280
|
+
}
|
|
281
|
+
return '</p><p>'; // Normal paragraph break
|
|
282
|
+
});
|
|
274
283
|
html = '<p>' + html + '</p>';
|
|
275
284
|
}
|
|
276
285
|
|
|
@@ -295,15 +304,20 @@ function quikdown(markdown, options = {}) {
|
|
|
295
304
|
html = html.replace(pattern, replacement);
|
|
296
305
|
});
|
|
297
306
|
|
|
307
|
+
// Fix orphaned closing </p> tags after block elements
|
|
308
|
+
// When a paragraph follows a block element, ensure it has opening <p>
|
|
309
|
+
html = html.replace(/(<\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\n([^<])/g, '$1\n<p>$2');
|
|
310
|
+
|
|
298
311
|
// Phase 4: Restore code blocks and inline code
|
|
299
312
|
|
|
300
313
|
// Restore code blocks
|
|
301
314
|
codeBlocks.forEach((block, i) => {
|
|
302
315
|
let replacement;
|
|
303
316
|
|
|
304
|
-
if (block.custom && fence_plugin) {
|
|
305
|
-
// Use custom fence plugin
|
|
306
|
-
replacement = fence_plugin(block.code, block.lang);
|
|
317
|
+
if (block.custom && fence_plugin && fence_plugin.render) {
|
|
318
|
+
// Use custom fence plugin (v1.1.0: object format with render function)
|
|
319
|
+
replacement = fence_plugin.render(block.code, block.lang);
|
|
320
|
+
|
|
307
321
|
// If plugin returns undefined, fall back to default rendering
|
|
308
322
|
if (replacement === undefined) {
|
|
309
323
|
const langClass = !inline_styles && block.lang ? ` class="language-${block.lang}"` : '';
|
|
@@ -311,6 +325,10 @@ function quikdown(markdown, options = {}) {
|
|
|
311
325
|
const langAttr = bidirectional && block.lang ? ` data-qd-lang="${escapeHtml(block.lang)}"` : '';
|
|
312
326
|
const fenceAttr = bidirectional ? ` data-qd-fence="${escapeHtml(block.fence)}"` : '';
|
|
313
327
|
replacement = `<pre${getAttr('pre')}${fenceAttr}${langAttr}><code${codeAttr}>${escapeHtml(block.code)}</code></pre>`;
|
|
328
|
+
} else if (bidirectional) {
|
|
329
|
+
// If bidirectional and plugin provided HTML, add data attributes for roundtrip
|
|
330
|
+
replacement = replacement.replace(/^<(\w+)/,
|
|
331
|
+
`<$1 data-qd-fence="${escapeHtml(block.fence)}" data-qd-lang="${escapeHtml(block.lang)}" data-qd-source="${escapeHtml(block.code)}"`);
|
|
314
332
|
}
|
|
315
333
|
} else {
|
|
316
334
|
// Default rendering
|
package/dist/quikdown.esm.min.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* quikdown - Lightweight Markdown Parser
|
|
3
|
-
* @version 1.
|
|
3
|
+
* @version 1.1.1
|
|
4
4
|
* @license BSD-2-Clause
|
|
5
5
|
* @copyright DeftIO 2025
|
|
6
6
|
*/
|
|
7
|
-
const e="quikdown-",t="§CB",n={"&":"&","<":"<",">":">",'"':""","'":"'"},r={h1:"font-size:2em;font-weight:600;margin:.67em 0;text-align:left",h2:"font-size:1.5em;font-weight:600;margin:.83em 0",h3:"font-size:1.25em;font-weight:600;margin:1em 0",h4:"font-size:1em;font-weight:600;margin:1.33em 0",h5:"font-size:.875em;font-weight:600;margin:1.67em 0",h6:"font-size:.85em;font-weight:600;margin:2em 0",pre:"background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0",code:"background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace",blockquote:"border-left:4px solid #ddd;margin-left:0;padding-left:1em",table:"border-collapse:collapse;width:100%;margin:1em 0",th:"border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left",td:"border:1px solid #ddd;padding:8px;text-align:left",hr:"border:none;border-top:1px solid #ddd;margin:1em 0",img:"max-width:100%;height:auto",a:"color:#06c;text-decoration:underline",strong:"font-weight:bold",em:"font-style:italic",del:"text-decoration:line-through",ul:"margin:.5em 0;padding-left:2em",ol:"margin:.5em 0;padding-left:2em",li:"margin:.25em 0","task-item":"list-style:none","task-checkbox":"margin-right:.5em"};function o(o,l={}){if(!o||"string"!=typeof o)return"";const{fence_plugin:c,inline_styles:s=!1,bidirectional:i=!1,lazy_linefeeds:p=!1}=l,
|
|
7
|
+
const e="quikdown-",t="§CB",n={"&":"&","<":"<",">":">",'"':""","'":"'"},r={h1:"font-size:2em;font-weight:600;margin:.67em 0;text-align:left",h2:"font-size:1.5em;font-weight:600;margin:.83em 0",h3:"font-size:1.25em;font-weight:600;margin:1em 0",h4:"font-size:1em;font-weight:600;margin:1.33em 0",h5:"font-size:.875em;font-weight:600;margin:1.67em 0",h6:"font-size:.85em;font-weight:600;margin:2em 0",pre:"background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0",code:"background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace",blockquote:"border-left:4px solid #ddd;margin-left:0;padding-left:1em",table:"border-collapse:collapse;width:100%;margin:1em 0",th:"border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left",td:"border:1px solid #ddd;padding:8px;text-align:left",hr:"border:none;border-top:1px solid #ddd;margin:1em 0",img:"max-width:100%;height:auto",a:"color:#06c;text-decoration:underline",strong:"font-weight:bold",em:"font-style:italic",del:"text-decoration:line-through",ul:"margin:.5em 0;padding-left:2em",ol:"margin:.5em 0;padding-left:2em",li:"margin:.25em 0","task-item":"list-style:none","task-checkbox":"margin-right:.5em"};function o(o,l={}){if(!o||"string"!=typeof o)return"";const{fence_plugin:c,inline_styles:s=!1,bidirectional:i=!1,lazy_linefeeds:p=!1}=l,d=function(t,n){return function(r,o=""){if(t){let e=n[r];return e||o?(o&&o.includes("text-align")&&e&&e.includes("text-align")&&(e=e.replace(/text-align:[^;]+;?/,"").trim(),e&&!e.endsWith(";")&&(e+=";")),` style="${o?e?`${e}${o}`:o:e}"`):""}{const t=` class="${e}${r}"`;return o?`${t} style="${o}"`:t}}}(s,r);function g(e){return e.replace(/[&<>"']/g,e=>n[e])}const $=i?e=>` data-qd="${g(e)}"`:()=>"";function f(e,t=!1){if(!e)return"";if(t)return e;const n=e.trim(),r=n.toLowerCase(),o=["javascript:","vbscript:","data:"];for(const e of o)if(r.startsWith(e))return"data:"===e&&r.startsWith("data:image/")?n:"#";return n}let h=o;const u=[],m=[];h=h.replace(/^(```|~~~)([^\n]*)\n([\s\S]*?)^\1$/gm,(e,n,r,o)=>{const l=`${t}${u.length}§`,a=r?r.trim():"";return c&&c.render&&"function"==typeof c.render?u.push({lang:a,code:o.trimEnd(),custom:!0,fence:n,hasReverse:!!c.reverse}):u.push({lang:a,code:g(o.trimEnd()),custom:!1,fence:n}),l}),h=h.replace(/`([^`]+)`/g,(e,t)=>{const n=`§IC${m.length}§`;return m.push(g(t)),n}),h=g(h),h=function(e,t){const n=e.split("\n"),r=[];let o=!1,l=[];for(let e=0;e<n.length;e++){const c=n[e].trim();if(c.includes("|")&&(c.startsWith("|")||/[^\\|]/.test(c)))o||(o=!0,l=[]),l.push(c);else{if(o){const e=a(l,t);e?r.push(e):r.push(...l),o=!1,l=[]}r.push(n[e])}}if(o&&l.length>0){const e=a(l,t);e?r.push(e):r.push(...l)}return r.join("\n")}(h,d),h=h.replace(/^(#{1,6})\s+(.+?)\s*#*$/gm,(e,t,n)=>{const r=t.length;return`<h${r}${d("h"+r)}${$(t)}>${n}</h${r}>`}),h=h.replace(/^>\s+(.+)$/gm,`<blockquote${d("blockquote")}>$1</blockquote>`),h=h.replace(/<\/blockquote>\n<blockquote>/g,"\n"),h=h.replace(/^---+\s*$/gm,`<hr${d("hr")}>`),h=function(t,n,r,o){const l=t.split("\n"),a=[];let c=[];const s=e=>e.replace(/[&<>"']/g,e=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[e])),i=o?e=>` data-qd="${s(e)}"`:()=>"";for(let t=0;t<l.length;t++){const o=l[t],s=o.match(/^(\s*)([*\-+]|\d+\.)\s+(.+)$/);if(s){const[,t,o,l]=s,p=Math.floor(t.length/2),d=/^\d+\./.test(o),g=d?"ol":"ul";let $=l,f="";const h=l.match(/^\[([x ])\]\s+(.*)$/i);if(h&&!d){const[,t,n]=h,o="x"===t.toLowerCase();$=`<input type="checkbox"${r?' style="margin-right:.5em"':` class="${e}task-checkbox"`}${o?" checked":""} disabled> ${n}`,f=r?' style="list-style:none"':` class="${e}task-item"`}for(;c.length>p+1;){const e=c.pop();a.push(`</${e.type}>`)}if(c.length===p)c.push({type:g,level:p}),a.push(`<${g}${n(g)}>`);else if(c.length===p+1){const e=c[c.length-1];e.type!==g&&(a.push(`</${e.type}>`),c.pop(),c.push({type:g,level:p}),a.push(`<${g}${n(g)}>`))}const u=f||n("li");a.push(`<li${u}${i(o)}>${$}</li>`)}else{for(;c.length>0;){const e=c.pop();a.push(`</${e.type}>`)}a.push(o)}}for(;c.length>0;){const e=c.pop();a.push(`</${e.type}>`)}return a.join("\n")}(h,d,s,i),h=h.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(e,t,n)=>{const r=f(n,l.allow_unsafe_urls),o=i&&t?` data-qd-alt="${g(t)}"`:"",a=i?` data-qd-src="${g(n)}"`:"";return`<img${d("img")} src="${r}" alt="${t}"${o}${a}${$("!")}>`}),h=h.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,t,n)=>{const r=f(n,l.allow_unsafe_urls),o=/^https?:\/\//i.test(r)?' rel="noopener noreferrer"':"",a=i?` data-qd-text="${g(t)}"`:"";return`<a${d("a")} href="${r}"${o}${a}${$("[")}>${t}</a>`}),h=h.replace(/(^|\s)(https?:\/\/[^\s<]+)/g,(e,t,n)=>{const r=f(n,l.allow_unsafe_urls);return`${t}<a${d("a")} href="${r}" rel="noopener noreferrer">${n}</a>`});if([[/\*\*(.+?)\*\*/g,"strong","**"],[/__(.+?)__/g,"strong","__"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em","*"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em","_"],[/~~(.+?)~~/g,"del","~~"]].forEach(([e,t,n])=>{h=h.replace(e,`<${t}${d(t)}${$(n)}>$1</${t}>`)}),p){const e=[];let t=0;h=h.replace(/<(table|[uo]l)[^>]*>[\s\S]*?<\/\1>/g,n=>(e[t]=n,`§B${t++}§`)),h=h.replace(/\n\n+/g,"§P§").replace(/(<\/(?:h[1-6]|blockquote|pre)>)\n/g,"$1§N§").replace(/(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)\n/g,"$1§N§").replace(/\n(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)/g,"§N§$1").replace(/\n(§B\d+§)/g,"§N§$1").replace(/(§B\d+§)\n/g,"$1§N§").replace(/\n/g,`<br${d("br")}>`).replace(/§N§/g,"\n").replace(/§P§/g,"</p><p>"),e.forEach((e,t)=>h=h.replace(`§B${t}§`,e)),h="<p>"+h+"</p>"}else h=h.replace(/ $/gm,`<br${d("br")}>`),h=h.replace(/\n\n+/g,(e,t)=>h.substring(0,t).match(/<\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)?"<p>":"</p><p>"),h="<p>"+h+"</p>";return[[/<p><\/p>/g,""],[/<p>(<h[1-6][^>]*>)/g,"$1"],[/(<\/h[1-6]>)<\/p>/g,"$1"],[/<p>(<blockquote[^>]*>)/g,"$1"],[/(<\/blockquote>)<\/p>/g,"$1"],[/<p>(<ul[^>]*>|<ol[^>]*>)/g,"$1"],[/(<\/ul>|<\/ol>)<\/p>/g,"$1"],[/<p>(<hr[^>]*>)<\/p>/g,"$1"],[/<p>(<table[^>]*>)/g,"$1"],[/(<\/table>)<\/p>/g,"$1"],[/<p>(<pre[^>]*>)/g,"$1"],[/(<\/pre>)<\/p>/g,"$1"],[new RegExp(`<p>(${t}\\d+§)</p>`,"g"),"$1"]].forEach(([e,t])=>{h=h.replace(e,t)}),h=h.replace(/(<\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\n([^<])/g,"$1\n<p>$2"),u.forEach((e,n)=>{let r;if(e.custom&&c&&c.render)if(r=c.render(e.code,e.lang),void 0===r){const t=!s&&e.lang?` class="language-${e.lang}"`:"",n=s?d("code"):t,o=i&&e.lang?` data-qd-lang="${g(e.lang)}"`:"",l=i?` data-qd-fence="${g(e.fence)}"`:"";r=`<pre${d("pre")}${l}${o}><code${n}>${g(e.code)}</code></pre>`}else i&&(r=r.replace(/^<(\w+)/,`<$1 data-qd-fence="${g(e.fence)}" data-qd-lang="${g(e.lang)}" data-qd-source="${g(e.code)}"`));else{const t=!s&&e.lang?` class="language-${e.lang}"`:"",n=s?d("code"):t,o=i&&e.lang?` data-qd-lang="${g(e.lang)}"`:"",l=i?` data-qd-fence="${g(e.fence)}"`:"";r=`<pre${d("pre")}${l}${o}><code${n}>${e.code}</code></pre>`}const o=`${t}${n}§`;h=h.replace(o,r)}),m.forEach((e,t)=>{const n=`§IC${t}§`;h=h.replace(n,`<code${d("code")}${$("`")}>${e}</code>`)}),h.trim()}function l(e,t){return[[/\*\*(.+?)\*\*/g,"strong"],[/__(.+?)__/g,"strong"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em"],[/~~(.+?)~~/g,"del"],[/`([^`]+)`/g,"code"]].forEach(([n,r])=>{e=e.replace(n,`<${r}${t(r)}>$1</${r}>`)}),e}function a(e,t){if(e.length<2)return null;let n=-1;for(let t=1;t<e.length;t++)if(/^\|?[\s\-:|]+\|?$/.test(e[t])&&e[t].includes("-")){n=t;break}if(-1===n)return null;const r=e.slice(0,n),o=e.slice(n+1),a=e[n].trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"});let c=`<table${t("table")}>\n`;return c+=`<thead${t("thead")}>\n`,r.forEach(e=>{c+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=a[n]&&"left"!==a[n]?`text-align:${a[n]}`:"",o=l(e.trim(),t);c+=`<th${t("th",r)}>${o}</th>\n`}),c+="</tr>\n"}),c+="</thead>\n",o.length>0&&(c+=`<tbody${t("tbody")}>\n`,o.forEach(e=>{c+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=a[n]&&"left"!==a[n]?`text-align:${a[n]}`:"",o=l(e.trim(),t);c+=`<td${t("td",r)}>${o}</td>\n`}),c+="</tr>\n"}),c+="</tbody>\n"),c+="</table>",c}o.emitStyles=function(e="quikdown-",t="light"){const n=r,o={"#f4f4f4":"#2a2a2a","#f0f0f0":"#2a2a2a","#f2f2f2":"#2a2a2a","#ddd":"#3a3a3a","#06c":"#6db3f2",_textColor:"#e0e0e0"},l={_textColor:"#333"};let a="";for(const[r,c]of Object.entries(n)){let n=c;if("dark"===t&&o){for(const[e,t]of Object.entries(o))e.startsWith("_")||(n=n.replace(new RegExp(e,"g"),t));["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(r)&&(n+=`;color:${o._textColor}`)}else if("light"===t&&l){["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(r)&&(n+=`;color:${l._textColor}`)}a+=`.${e}${r} { ${n} }\n`}return a},o.configure=function(e){return function(t){return o(t,e)}},o.version="1.1.1","undefined"!=typeof module&&module.exports&&(module.exports=o),"undefined"!=typeof window&&(window.quikdown=o);export{o as default};
|
|
8
8
|
//# sourceMappingURL=quikdown.esm.min.js.map
|