@jx3box/jx3box-editor 3.0.3 → 3.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jx3box/jx3box-editor",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "description": "JX3BOX Article & Editor",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/src/Article.vue CHANGED
@@ -66,6 +66,7 @@ import execLazyload from "./assets/js/img";
66
66
  import execFilterIframe from "./assets/js/iframe";
67
67
  import execFilterLink from "./assets/js/a";
68
68
  import execSplitPages from "./assets/js/nextpage";
69
+ import normalizeMarkdownForVditor from "./assets/js/normalizeMarkdownForVditor";
69
70
 
70
71
  // 扩展文本
71
72
  import renderFoldBlock from "./assets/js/fold";
@@ -244,8 +245,9 @@ export default {
244
245
  },
245
246
  renderMarkdownChunk: async function (chunk) {
246
247
  const temp = document.createElement("div");
248
+ const normalizedChunk = normalizeMarkdownForVditor(chunk);
247
249
 
248
- await Vditor.preview(temp, chunk || "", {
250
+ await Vditor.preview(temp, normalizedChunk, {
249
251
  mode: "light",
250
252
  lang: "zh_CN",
251
253
  hljs: {
@@ -254,7 +256,9 @@ export default {
254
256
  style: "github",
255
257
  },
256
258
  markdown: {
259
+ mark: true,
257
260
  sanitize: true,
261
+ toc: true,
258
262
  },
259
263
  icon: "ant",
260
264
  });
package/src/Markdown.vue CHANGED
@@ -35,6 +35,7 @@ import {
35
35
  import Vditor from "vditor";
36
36
  import "vditor/dist/index.css";
37
37
  import "github-markdown-css/github-markdown-light.css";
38
+ import normalizeMarkdownForVditor from "./assets/js/normalizeMarkdownForVditor";
38
39
 
39
40
  const { __cms } = JX3BOX;
40
41
  const UPLOAD_API = `${__cms}api/cms/upload`;
@@ -130,6 +131,7 @@ export default {
130
131
  previewVisible: false,
131
132
  isRebuildingEditor: false,
132
133
  isUploadingImage: false,
134
+ previewRenderVersion: 0,
133
135
  counterElement: null,
134
136
  counterClickListener: null,
135
137
  counterClickTimestamps: [],
@@ -235,7 +237,9 @@ export default {
235
237
  style: "github",
236
238
  },
237
239
  markdown: {
240
+ mark: true,
238
241
  sanitize: true,
242
+ toc: true,
239
243
  },
240
244
  mode: this.getPreviewMode(),
241
245
  },
@@ -300,7 +304,7 @@ export default {
300
304
  if (this.editor.getValue() === nextValue) return;
301
305
  this.editor.setValue(nextValue);
302
306
  if (this.previewVisible) {
303
- this.editor.renderPreview();
307
+ this.renderPreviewContent();
304
308
  }
305
309
  },
306
310
  getToolbarButton(name) {
@@ -356,9 +360,38 @@ export default {
356
360
 
357
361
  this.syncEditorPanels();
358
362
  if (this.previewVisible) {
359
- this.editor.renderPreview();
363
+ this.renderPreviewContent();
360
364
  }
361
365
  },
366
+ renderPreviewContent: async function () {
367
+ if (!this.editorReady || !this.editor) return;
368
+
369
+ const previewRoot = this.$refs.editorHost?.querySelector?.(".vditor-preview");
370
+ const previewBody = previewRoot?.querySelector?.(".vditor-reset") || previewRoot;
371
+ if (!previewBody) return;
372
+
373
+ const version = ++this.previewRenderVersion;
374
+ const normalizedMarkdown = normalizeMarkdownForVditor(this.editor.getValue());
375
+
376
+ await Vditor.preview(previewBody, normalizedMarkdown, {
377
+ mode: "light",
378
+ lang: "zh_CN",
379
+ hljs: {
380
+ enable: true,
381
+ lineNumber: false,
382
+ style: "github",
383
+ },
384
+ markdown: {
385
+ mark: true,
386
+ sanitize: true,
387
+ toc: true,
388
+ },
389
+ icon: "ant",
390
+ });
391
+
392
+ if (version !== this.previewRenderVersion) return;
393
+ previewBody.classList.add("markdown-body");
394
+ },
362
395
  togglePreview() {
363
396
  this.previewVisible = !this.previewVisible;
364
397
 
@@ -528,8 +561,8 @@ export default {
528
561
  }
529
562
 
530
563
  .vditor-toolbar {
531
- display: flex;
532
- align-items: center;
564
+ display: flex;
565
+ align-items: center;
533
566
  padding: 10px 12px;
534
567
  background: #f6f8fa;
535
568
  border-bottom: 1px solid #d8dee4;
@@ -0,0 +1,39 @@
1
+ const PROTECTED_SEGMENT_REGEXP = /(```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`|\$\$[\s\S]*?\$\$|\$[^$\n]+\$)/g;
2
+
3
+ function replaceUnderline(text) {
4
+ return text.replace(/\+\+([^\n+][^\n]*?)\+\+/g, "<u>$1</u>");
5
+ }
6
+
7
+ function replaceSuperscript(text) {
8
+ return text.replace(
9
+ /(^|[^\w\\])([A-Za-z0-9)\]}\u4e00-\u9fa5]+)\^([^^\s][^^]*?)\^/g,
10
+ (match, prefix, base, value) => {
11
+ return `${prefix}${base}<sup>${value}</sup>`;
12
+ }
13
+ );
14
+ }
15
+
16
+ function replaceSubscript(text) {
17
+ return text.replace(/(^|[^\w\\])([A-Za-z0-9)\]}\u4e00-\u9fa5]+)~([^~\s][^~]*?)~/g, (match, prefix, base, value) => {
18
+ return `${prefix}${base}<sub>${value}</sub>`;
19
+ });
20
+ }
21
+
22
+ function normalizePlainMarkdown(text) {
23
+ return [replaceUnderline, replaceSuperscript, replaceSubscript].reduce((result, transform) => {
24
+ return transform(result);
25
+ }, text);
26
+ }
27
+
28
+ export default function normalizeMarkdownForVditor(markdown) {
29
+ const source = String(markdown || "");
30
+ if (!source) return "";
31
+
32
+ const segments = source.split(PROTECTED_SEGMENT_REGEXP);
33
+
34
+ return segments
35
+ .map((segment, index) => {
36
+ return index % 2 === 1 ? segment : normalizePlainMarkdown(segment);
37
+ })
38
+ .join("");
39
+ }