@coding01/docsjs 0.1.5 → 0.1.6

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/dist/react.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { Ref } from 'react';
2
- import { D as DocsWordEditorChangeDetail, b as DocsWordEditorErrorDetail, c as DocsWordEditorReadyDetail, a as DocsWordEditorElementApi } from './types-DF14w1ol.cjs';
2
+ import { D as DocsWordEditorChangeDetail, b as DocsWordEditorErrorDetail, c as DocsWordEditorReadyDetail, a as DocsWordEditorElementApi } from './types-VvdwVF0_.cjs';
3
3
 
4
4
  interface WordFidelityEditorReactProps {
5
5
  lang?: "zh" | "en";
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { Ref } from 'react';
2
- import { D as DocsWordEditorChangeDetail, b as DocsWordEditorErrorDetail, c as DocsWordEditorReadyDetail, a as DocsWordEditorElementApi } from './types-DF14w1ol.js';
2
+ import { D as DocsWordEditorChangeDetail, b as DocsWordEditorErrorDetail, c as DocsWordEditorReadyDetail, a as DocsWordEditorElementApi } from './types-VvdwVF0_.js';
3
3
 
4
4
  interface WordFidelityEditorReactProps {
5
5
  lang?: "zh" | "en";
package/dist/react.js CHANGED
@@ -1,11 +1,17 @@
1
1
  import {
2
2
  defineDocsWordElement
3
- } from "./chunk-IBVWD4UO.js";
3
+ } from "./chunk-632UOG2B.js";
4
4
 
5
5
  // src/react/WordFidelityEditorReact.tsx
6
6
  import React, { useEffect, useRef } from "react";
7
7
  defineDocsWordElement();
8
- function WordFidelityEditorReact({ lang, onChange, onError, onReady, editorRef }) {
8
+ function WordFidelityEditorReact({
9
+ lang,
10
+ onChange,
11
+ onError,
12
+ onReady,
13
+ editorRef
14
+ }) {
9
15
  const ref = useRef(null);
10
16
  useEffect(() => {
11
17
  const node = ref.current;
@@ -33,7 +39,10 @@ function WordFidelityEditorReact({ lang, onChange, onError, onReady, editorRef }
33
39
  editorRef?.(null);
34
40
  };
35
41
  }, [editorRef, onChange, onError, onReady]);
36
- return React.createElement("docs-word-editor", { ref, lang });
42
+ return React.createElement("docs-word-editor", {
43
+ ref,
44
+ lang
45
+ });
37
46
  }
38
47
  export {
39
48
  WordFidelityEditorReact
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react/WordFidelityEditorReact.tsx"],"sourcesContent":["import React, { useEffect, useRef } from \"react\";\nimport type { Ref } from \"react\";\nimport { defineDocsWordElement } from \"../core/DocsWordElement\";\nimport type {\n DocsWordEditorChangeDetail,\n DocsWordEditorElementApi,\n DocsWordEditorErrorDetail,\n DocsWordEditorReadyDetail\n} from \"../core/types\";\n\ndefineDocsWordElement();\n\nexport interface WordFidelityEditorReactProps {\n lang?: \"zh\" | \"en\";\n onChange?: (payload: DocsWordEditorChangeDetail) => void;\n onError?: (payload: DocsWordEditorErrorDetail) => void;\n onReady?: (payload: DocsWordEditorReadyDetail) => void;\n editorRef?: (el: DocsWordEditorElementApi | null) => void;\n}\n\nexport function WordFidelityEditorReact({ lang, onChange, onError, onReady, editorRef }: WordFidelityEditorReactProps) {\n const ref = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n const node = ref.current;\n if (!node) return;\n\n const onChangeEvent = (event: Event) => {\n const detail = (event as CustomEvent<DocsWordEditorChangeDetail>).detail;\n onChange?.(detail);\n };\n const onErrorEvent = (event: Event) => {\n const detail = (event as CustomEvent<DocsWordEditorErrorDetail>).detail;\n onError?.(detail);\n };\n const onReadyEvent = (event: Event) => {\n const detail = (event as CustomEvent<DocsWordEditorReadyDetail>).detail;\n onReady?.(detail);\n };\n\n node.addEventListener(\"docsjs-change\", onChangeEvent);\n node.addEventListener(\"docsjs-error\", onErrorEvent);\n node.addEventListener(\"docsjs-ready\", onReadyEvent);\n editorRef?.(node as DocsWordEditorElementApi);\n return () => {\n node.removeEventListener(\"docsjs-change\", onChangeEvent);\n node.removeEventListener(\"docsjs-error\", onErrorEvent);\n node.removeEventListener(\"docsjs-ready\", onReadyEvent);\n editorRef?.(null);\n };\n }, [editorRef, onChange, onError, onReady]);\n\n return React.createElement(\"docs-word-editor\", { ref: ref as unknown as Ref<HTMLElement>, lang });\n}\n"],"mappings":";;;;;AAAA,OAAO,SAAS,WAAW,cAAc;AAUzC,sBAAsB;AAUf,SAAS,wBAAwB,EAAE,MAAM,UAAU,SAAS,SAAS,UAAU,GAAiC;AACrH,QAAM,MAAM,OAA2B,IAAI;AAE3C,YAAU,MAAM;AACd,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,KAAM;AAEX,UAAM,gBAAgB,CAAC,UAAiB;AACtC,YAAM,SAAU,MAAkD;AAClE,iBAAW,MAAM;AAAA,IACnB;AACA,UAAM,eAAe,CAAC,UAAiB;AACrC,YAAM,SAAU,MAAiD;AACjE,gBAAU,MAAM;AAAA,IAClB;AACA,UAAM,eAAe,CAAC,UAAiB;AACrC,YAAM,SAAU,MAAiD;AACjE,gBAAU,MAAM;AAAA,IAClB;AAEA,SAAK,iBAAiB,iBAAiB,aAAa;AACpD,SAAK,iBAAiB,gBAAgB,YAAY;AAClD,SAAK,iBAAiB,gBAAgB,YAAY;AAClD,gBAAY,IAAgC;AAC5C,WAAO,MAAM;AACX,WAAK,oBAAoB,iBAAiB,aAAa;AACvD,WAAK,oBAAoB,gBAAgB,YAAY;AACrD,WAAK,oBAAoB,gBAAgB,YAAY;AACrD,kBAAY,IAAI;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,WAAW,UAAU,SAAS,OAAO,CAAC;AAE1C,SAAO,MAAM,cAAc,oBAAoB,EAAE,KAAyC,KAAK,CAAC;AAClG;","names":[]}
1
+ {"version":3,"sources":["../src/react/WordFidelityEditorReact.tsx"],"sourcesContent":["import React, { useEffect, useRef } from \"react\";\nimport type { Ref } from \"react\";\nimport { defineDocsWordElement } from \"../core/DocsWordElement\";\nimport type {\n DocsWordEditorChangeDetail,\n DocsWordEditorElementApi,\n DocsWordEditorErrorDetail,\n DocsWordEditorReadyDetail\n} from \"../core/types\";\n\ndefineDocsWordElement();\n\nexport interface WordFidelityEditorReactProps {\n lang?: \"zh\" | \"en\";\n onChange?: (payload: DocsWordEditorChangeDetail) => void;\n onError?: (payload: DocsWordEditorErrorDetail) => void;\n onReady?: (payload: DocsWordEditorReadyDetail) => void;\n editorRef?: (el: DocsWordEditorElementApi | null) => void;\n}\n\nexport function WordFidelityEditorReact({\n lang,\n onChange,\n onError,\n onReady,\n editorRef\n}: WordFidelityEditorReactProps) {\n const ref = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n const node = ref.current;\n if (!node) return;\n\n const onChangeEvent = (event: Event) => {\n const detail = (event as CustomEvent<DocsWordEditorChangeDetail>).detail;\n onChange?.(detail);\n };\n const onErrorEvent = (event: Event) => {\n const detail = (event as CustomEvent<DocsWordEditorErrorDetail>).detail;\n onError?.(detail);\n };\n const onReadyEvent = (event: Event) => {\n const detail = (event as CustomEvent<DocsWordEditorReadyDetail>).detail;\n onReady?.(detail);\n };\n\n node.addEventListener(\"docsjs-change\", onChangeEvent);\n node.addEventListener(\"docsjs-error\", onErrorEvent);\n node.addEventListener(\"docsjs-ready\", onReadyEvent);\n editorRef?.(node as DocsWordEditorElementApi);\n return () => {\n node.removeEventListener(\"docsjs-change\", onChangeEvent);\n node.removeEventListener(\"docsjs-error\", onErrorEvent);\n node.removeEventListener(\"docsjs-ready\", onReadyEvent);\n editorRef?.(null);\n };\n }, [editorRef, onChange, onError, onReady]);\n\n return React.createElement(\"docs-word-editor\", {\n ref: ref as unknown as Ref<HTMLElement>,\n lang\n });\n}\n"],"mappings":";;;;;AAAA,OAAO,SAAS,WAAW,cAAc;AAUzC,sBAAsB;AAUf,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,MAAM,OAA2B,IAAI;AAE3C,YAAU,MAAM;AACd,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,KAAM;AAEX,UAAM,gBAAgB,CAAC,UAAiB;AACtC,YAAM,SAAU,MAAkD;AAClE,iBAAW,MAAM;AAAA,IACnB;AACA,UAAM,eAAe,CAAC,UAAiB;AACrC,YAAM,SAAU,MAAiD;AACjE,gBAAU,MAAM;AAAA,IAClB;AACA,UAAM,eAAe,CAAC,UAAiB;AACrC,YAAM,SAAU,MAAiD;AACjE,gBAAU,MAAM;AAAA,IAClB;AAEA,SAAK,iBAAiB,iBAAiB,aAAa;AACpD,SAAK,iBAAiB,gBAAgB,YAAY;AAClD,SAAK,iBAAiB,gBAAgB,YAAY;AAClD,gBAAY,IAAgC;AAC5C,WAAO,MAAM;AACX,WAAK,oBAAoB,iBAAiB,aAAa;AACvD,WAAK,oBAAoB,gBAAgB,YAAY;AACrD,WAAK,oBAAoB,gBAAgB,YAAY;AACrD,kBAAY,IAAI;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,WAAW,UAAU,SAAS,OAAO,CAAC;AAE1C,SAAO,MAAM,cAAc,oBAAoB;AAAA,IAC7C;AAAA,IACA;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -0,0 +1,44 @@
1
+ interface DocxParseFeatureCounts {
2
+ hyperlinkCount: number;
3
+ anchorImageCount: number;
4
+ chartCount: number;
5
+ smartArtCount: number;
6
+ ommlCount: number;
7
+ tableCount: number;
8
+ footnoteRefCount: number;
9
+ endnoteRefCount: number;
10
+ commentRefCount: number;
11
+ revisionCount: number;
12
+ pageBreakCount: number;
13
+ }
14
+ interface DocxParseReport {
15
+ elapsedMs: number;
16
+ features: DocxParseFeatureCounts;
17
+ }
18
+ declare function parseDocxToHtmlSnapshotWithReport(file: File): Promise<{
19
+ htmlSnapshot: string;
20
+ report: DocxParseReport;
21
+ }>;
22
+ declare function parseDocxToHtmlSnapshot(file: File): Promise<string>;
23
+
24
+ interface DocsWordEditorChangeDetail {
25
+ htmlSnapshot: string;
26
+ source: "paste" | "upload" | "api" | "clear";
27
+ fileName?: string;
28
+ parseReport?: DocxParseReport;
29
+ }
30
+ interface DocsWordEditorErrorDetail {
31
+ message: string;
32
+ }
33
+ interface DocsWordEditorReadyDetail {
34
+ version: string;
35
+ }
36
+ interface DocsWordEditorElementApi extends HTMLElement {
37
+ loadDocx(file: File): Promise<void>;
38
+ loadHtml(rawHtml: string): void;
39
+ loadClipboard(): Promise<void>;
40
+ clear(): void;
41
+ getSnapshot(): string;
42
+ }
43
+
44
+ export { type DocsWordEditorChangeDetail as D, type DocsWordEditorElementApi as a, type DocsWordEditorErrorDetail as b, type DocsWordEditorReadyDetail as c, type DocxParseFeatureCounts as d, type DocxParseReport as e, parseDocxToHtmlSnapshotWithReport as f, parseDocxToHtmlSnapshot as p };
@@ -0,0 +1,44 @@
1
+ interface DocxParseFeatureCounts {
2
+ hyperlinkCount: number;
3
+ anchorImageCount: number;
4
+ chartCount: number;
5
+ smartArtCount: number;
6
+ ommlCount: number;
7
+ tableCount: number;
8
+ footnoteRefCount: number;
9
+ endnoteRefCount: number;
10
+ commentRefCount: number;
11
+ revisionCount: number;
12
+ pageBreakCount: number;
13
+ }
14
+ interface DocxParseReport {
15
+ elapsedMs: number;
16
+ features: DocxParseFeatureCounts;
17
+ }
18
+ declare function parseDocxToHtmlSnapshotWithReport(file: File): Promise<{
19
+ htmlSnapshot: string;
20
+ report: DocxParseReport;
21
+ }>;
22
+ declare function parseDocxToHtmlSnapshot(file: File): Promise<string>;
23
+
24
+ interface DocsWordEditorChangeDetail {
25
+ htmlSnapshot: string;
26
+ source: "paste" | "upload" | "api" | "clear";
27
+ fileName?: string;
28
+ parseReport?: DocxParseReport;
29
+ }
30
+ interface DocsWordEditorErrorDetail {
31
+ message: string;
32
+ }
33
+ interface DocsWordEditorReadyDetail {
34
+ version: string;
35
+ }
36
+ interface DocsWordEditorElementApi extends HTMLElement {
37
+ loadDocx(file: File): Promise<void>;
38
+ loadHtml(rawHtml: string): void;
39
+ loadClipboard(): Promise<void>;
40
+ clear(): void;
41
+ getSnapshot(): string;
42
+ }
43
+
44
+ export { type DocsWordEditorChangeDetail as D, type DocsWordEditorElementApi as a, type DocsWordEditorErrorDetail as b, type DocsWordEditorReadyDetail as c, type DocxParseFeatureCounts as d, type DocxParseReport as e, parseDocxToHtmlSnapshotWithReport as f, parseDocxToHtmlSnapshot as p };
package/dist/vue.cjs CHANGED
@@ -56,6 +56,21 @@ function buildHtmlSnapshot(rawHtml) {
56
56
 
57
57
  // src/lib/docxHtml.ts
58
58
  var import_jszip = __toESM(require("jszip"), 1);
59
+ function createEmptyFeatureCounts() {
60
+ return {
61
+ hyperlinkCount: 0,
62
+ anchorImageCount: 0,
63
+ chartCount: 0,
64
+ smartArtCount: 0,
65
+ ommlCount: 0,
66
+ tableCount: 0,
67
+ footnoteRefCount: 0,
68
+ endnoteRefCount: 0,
69
+ commentRefCount: 0,
70
+ revisionCount: 0,
71
+ pageBreakCount: 0
72
+ };
73
+ }
59
74
  function escapeHtml(text) {
60
75
  return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
61
76
  }
@@ -230,6 +245,19 @@ function normalizeWordPath(relTarget) {
230
245
  if (normalized.startsWith("../")) return `word/${normalized.replace(/^(\.\.\/)+/, "")}`;
231
246
  return `word/${normalized}`;
232
247
  }
248
+ function resolveHyperlinkHref(relMap, rid, anchor) {
249
+ if (anchor && anchor.trim()) return `#${encodeURIComponent(anchor.trim())}`;
250
+ if (!rid) return null;
251
+ const relTarget = relMap[rid];
252
+ if (!relTarget) return null;
253
+ const trimmed = relTarget.trim();
254
+ if (!trimmed) return null;
255
+ const lower = trimmed.toLowerCase();
256
+ if (lower.startsWith("http://") || lower.startsWith("https://") || lower.startsWith("mailto:") || lower.startsWith("tel:")) {
257
+ return trimmed;
258
+ }
259
+ return trimmed.startsWith("#") ? trimmed : `#${encodeURIComponent(trimmed)}`;
260
+ }
233
261
  async function imageRidToDataUrl(zip, relMap, rid) {
234
262
  const relTarget = relMap[rid];
235
263
  if (!relTarget) return null;
@@ -404,7 +432,7 @@ function renderEndnotesSection(usedIds, endnotesMap) {
404
432
  const items = uniq.map((id) => `<li id="word-endnote-${id}" data-word-endnote-id="${id}">${endnotesMap[id]}</li>`).join("");
405
433
  return `<section data-word-endnotes="1"><hr/><ol>${items}</ol></section>`;
406
434
  }
407
- async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotesMap, usedFootnoteIds, endnotesMap, usedEndnoteIds, commentsMap, usedCommentIds) {
435
+ async function paragraphToHtml(zip, relMap, context, paragraph, paragraphIndex, footnotesMap, usedFootnoteIds, endnotesMap, usedEndnoteIds, commentsMap, usedCommentIds) {
408
436
  const tag = paragraphTag(paragraph);
409
437
  const alignStyle = paragraphAlignStyle(paragraph);
410
438
  const dataAttr = paragraphDataAttr(paragraphIndex);
@@ -445,6 +473,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
445
473
  const footnoteRef = queryByLocalName(run, "footnoteReference");
446
474
  const footnoteId = getAttr(footnoteRef, "w:id") ?? getAttr(footnoteRef, "id");
447
475
  if (footnoteId && footnotesMap[footnoteId]) {
476
+ context.features.footnoteRefCount += 1;
448
477
  usedFootnoteIds.push(footnoteId);
449
478
  result.push(
450
479
  `<sup data-word-footnote-ref="${footnoteId}"><a href="#word-footnote-${footnoteId}">[${footnoteId}]</a></sup>`
@@ -454,6 +483,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
454
483
  const endnoteRef = queryByLocalName(run, "endnoteReference");
455
484
  const endnoteId = getAttr(endnoteRef, "w:id") ?? getAttr(endnoteRef, "id");
456
485
  if (endnoteId && endnotesMap[endnoteId]) {
486
+ context.features.endnoteRefCount += 1;
457
487
  usedEndnoteIds.push(endnoteId);
458
488
  result.push(
459
489
  `<sup data-word-endnote-ref="${endnoteId}"><a href="#word-endnote-${endnoteId}">[${endnoteId}]</a></sup>`
@@ -463,6 +493,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
463
493
  const commentRef = queryByLocalName(run, "commentReference");
464
494
  const commentId = getAttr(commentRef, "w:id") ?? getAttr(commentRef, "id");
465
495
  if (commentId && commentsMap[commentId]) {
496
+ context.features.commentRefCount += 1;
466
497
  usedCommentIds.push(commentId);
467
498
  result.push(
468
499
  `<sup data-word-comment-ref="${commentId}"><a href="#word-comment-${commentId}">[c${commentId}]</a></sup>`
@@ -480,6 +511,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
480
511
  const dimensionAttrs = imageDimensionAttributes(imageSize);
481
512
  const anchorMeta = parseAnchorMeta(drawing);
482
513
  const attrs = mergeImageStyle(dimensionAttrs, anchorMeta);
514
+ if (anchorMeta) context.features.anchorImageCount += 1;
483
515
  result.push(`<img src="${src}" alt="word-image"${attrs}/>`);
484
516
  return result;
485
517
  }
@@ -490,6 +522,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
490
522
  const chartXmlText = await readXmlByRid(zip, relMap, chartRid);
491
523
  if (chartXmlText) {
492
524
  const summary = parseChartSummary(chartXmlText);
525
+ context.features.chartCount += 1;
493
526
  result.push(
494
527
  `<figure data-word-chart="1" data-word-chart-type="${summary.type}" data-word-chart-series="${summary.seriesCount}" data-word-chart-points="${summary.pointCount}"><figcaption>${escapeHtml(summary.title)}</figcaption><div>Chart(${escapeHtml(summary.type)}): series=${summary.seriesCount}, points=${summary.pointCount}</div></figure>`
495
528
  );
@@ -501,6 +534,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
501
534
  if (smartArtRid) {
502
535
  const diagramXmlText = await readXmlByRid(zip, relMap, smartArtRid);
503
536
  const textItems = diagramXmlText ? extractSmartArtText(diagramXmlText) : [];
537
+ context.features.smartArtCount += 1;
504
538
  const preview = textItems.length > 0 ? `: ${escapeHtml(textItems.join(" / "))}` : "";
505
539
  result.push(
506
540
  `<figure data-word-smartart="1" data-word-smartart-items="${textItems.length}"><figcaption>SmartArt fallback${preview}</figcaption></figure>`
@@ -522,12 +556,14 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
522
556
  if (css) {
523
557
  const span = `<span style="${css}">${runText2}</span>`;
524
558
  if (revisionMeta) {
559
+ context.features.revisionCount += 1;
525
560
  const tagName = revisionMeta.type === "ins" ? "ins" : "del";
526
561
  result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${span}</${tagName}>`);
527
562
  } else {
528
563
  result.push(span);
529
564
  }
530
565
  } else if (revisionMeta) {
566
+ context.features.revisionCount += 1;
531
567
  const tagName = revisionMeta.type === "ins" ? "ins" : "del";
532
568
  result.push(`<${tagName} ${revisionMetaAttrs(revisionMeta)}>${runText2}</${tagName}>`);
533
569
  } else {
@@ -535,6 +571,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
535
571
  }
536
572
  }
537
573
  for (let i = 0; i < pageBreakCount; i += 1) {
574
+ context.features.pageBreakCount += 1;
538
575
  result.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
539
576
  }
540
577
  return result;
@@ -551,9 +588,25 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
551
588
  if (node.localName === "r") {
552
589
  return runToHtml(node, revisionFallback);
553
590
  }
591
+ if (node.localName === "hyperlink") {
592
+ const rid = getAttr(node, "r:id") ?? getAttr(node, "id");
593
+ const anchor = getAttr(node, "w:anchor") ?? getAttr(node, "anchor");
594
+ const href = resolveHyperlinkHref(relMap, rid, anchor);
595
+ const nested2 = [];
596
+ for (const child of Array.from(node.children)) {
597
+ nested2.push(...await nodeToHtml(child, revisionFallback));
598
+ }
599
+ const content2 = nested2.join("") || escapeHtml(node.textContent ?? "");
600
+ if (!href) return content2 ? [content2] : [];
601
+ context.features.hyperlinkCount += 1;
602
+ return [
603
+ `<a data-word-hyperlink="1" href="${escapeHtml(href)}" rel="noreferrer noopener" target="_blank">${content2}</a>`
604
+ ];
605
+ }
554
606
  if (node.localName === "oMath" || node.localName === "oMathPara") {
555
607
  const linear = ommlNodeToText(node).trim();
556
608
  if (!linear) return [];
609
+ context.features.ommlCount += 1;
557
610
  return [`<span data-word-omml="1">${escapeHtml(linear)}</span>`];
558
611
  }
559
612
  if (node.localName === "ins" || node.localName === "del") {
@@ -573,6 +626,7 @@ async function paragraphToHtml(zip, relMap, paragraph, paragraphIndex, footnotes
573
626
  const parts = [];
574
627
  const renderedPageBreakCount = queryAllByLocalName(paragraph, "lastRenderedPageBreak").length;
575
628
  for (let i = 0; i < renderedPageBreakCount; i += 1) {
629
+ context.features.pageBreakCount += 1;
576
630
  parts.push(`<span data-word-page-break="1" style="display:block;break-before:page"></span>`);
577
631
  }
578
632
  for (const child of Array.from(paragraph.children)) {
@@ -701,7 +755,7 @@ function parseCellBorderStyle(cell, tableStyle) {
701
755
  const left = parseBorderCss(directChildrenByLocalName(tcBorders, "left")[0] ?? null) ?? tableStyle.insideVCss ?? tableStyle.borderCss;
702
756
  return `border-top:${top};border-right:${right};border-bottom:${bottom};border-left:${left}`;
703
757
  }
704
- function tableCellHtml(cell, paragraphIndexMap) {
758
+ function tableCellHtml(cell, paragraphIndexMap, context) {
705
759
  const blocks = [];
706
760
  for (const child of Array.from(cell.children)) {
707
761
  if (child.localName === "tcPr") continue;
@@ -711,7 +765,7 @@ function tableCellHtml(cell, paragraphIndexMap) {
711
765
  continue;
712
766
  }
713
767
  if (child.localName === "tbl") {
714
- blocks.push(tableToHtml(child, paragraphIndexMap));
768
+ blocks.push(tableToHtml(child, paragraphIndexMap, context));
715
769
  continue;
716
770
  }
717
771
  }
@@ -719,7 +773,8 @@ function tableCellHtml(cell, paragraphIndexMap) {
719
773
  const text = queryAllByLocalName(cell, "t").map((t) => t.textContent ?? "").join("").trim();
720
774
  return escapeHtml(text) || "<br/>";
721
775
  }
722
- function tableToHtml(table, paragraphIndexMap) {
776
+ function tableToHtml(table, paragraphIndexMap, context) {
777
+ context.features.tableCount += 1;
723
778
  const rows = directChildrenByLocalName(table, "tr");
724
779
  const gridWidthsPx = parseTblGridWidthsPx(table);
725
780
  const tableStyle = parseTableStyleProfile(table);
@@ -747,7 +802,7 @@ function tableToHtml(table, paragraphIndexMap) {
747
802
  while (activeByCol.has(colCursor)) {
748
803
  colCursor += 1;
749
804
  }
750
- const html = tableCellHtml(cell, paragraphIndexMap);
805
+ const html = tableCellHtml(cell, paragraphIndexMap, context);
751
806
  const attrs = [];
752
807
  const widthStyle = parseCellWidthStyle(cell, colCursor, colSpan, gridWidthsPx);
753
808
  const borderStyle = parseCellBorderStyle(cell, tableStyle);
@@ -791,7 +846,9 @@ function tableToHtml(table, paragraphIndexMap) {
791
846
  const spacing = tableStyle.borderSpacingPx > 0 ? `border-spacing:${tableStyle.borderSpacingPx.toFixed(2)}px;` : "";
792
847
  return `<table style="border-collapse:${tableStyle.borderCollapse};${spacing}table-layout:${tableStyle.tableLayout};${tableWidthStyle};border:${tableStyle.borderCss};">${merged}</table>`;
793
848
  }
794
- async function parseDocxToHtmlSnapshot(file) {
849
+ async function parseDocxToHtmlSnapshotWithReport(file) {
850
+ const startedAt = Date.now();
851
+ const context = { features: createEmptyFeatureCounts() };
795
852
  const maybeArrayBuffer = file.arrayBuffer;
796
853
  const buffer = maybeArrayBuffer ? await maybeArrayBuffer.call(file) : await new Response(file).arrayBuffer();
797
854
  const zip = await import_jszip.default.loadAsync(buffer);
@@ -828,6 +885,7 @@ async function parseDocxToHtmlSnapshot(file) {
828
885
  await paragraphToHtml(
829
886
  zip,
830
887
  relMap,
888
+ context,
831
889
  child,
832
890
  paragraphIndex,
833
891
  footnotesMap,
@@ -841,14 +899,20 @@ async function parseDocxToHtmlSnapshot(file) {
841
899
  continue;
842
900
  }
843
901
  if (child.localName === "tbl") {
844
- blockHtml.push(tableToHtml(child, paragraphIndexMap));
902
+ blockHtml.push(tableToHtml(child, paragraphIndexMap, context));
845
903
  continue;
846
904
  }
847
905
  }
848
906
  blockHtml.push(renderFootnotesSection(usedFootnoteIds, footnotesMap));
849
907
  blockHtml.push(renderEndnotesSection(usedEndnoteIds, endnotesMap));
850
908
  blockHtml.push(renderCommentsSection(usedCommentIds, commentsMap));
851
- return buildHtmlSnapshot(blockHtml.join("\n"));
909
+ return {
910
+ htmlSnapshot: buildHtmlSnapshot(blockHtml.join("\n")),
911
+ report: {
912
+ elapsedMs: Date.now() - startedAt,
913
+ features: context.features
914
+ }
915
+ };
852
916
  }
853
917
 
854
918
  // src/lib/pastePipeline.ts
@@ -1979,7 +2043,7 @@ function applyWordRenderModel({ doc, styleProfile, showFormattingMarks }) {
1979
2043
  }
1980
2044
 
1981
2045
  // src/core/DocsWordElement.ts
1982
- var VERSION = "0.1.2";
2046
+ var VERSION = "0.1.5";
1983
2047
  var MESSAGES = {
1984
2048
  zh: {
1985
2049
  readClipboard: "\u4ECE\u7CFB\u7EDF\u526A\u8D34\u677F\u8BFB\u53D6",
@@ -2122,15 +2186,15 @@ var DocsWordElement = class extends HTMLElement {
2122
2186
  }
2123
2187
  async applyDocx(file) {
2124
2188
  try {
2125
- const [snapshot, profile] = await Promise.all([
2126
- parseDocxToHtmlSnapshot(file),
2189
+ const [parseResult, profile] = await Promise.all([
2190
+ parseDocxToHtmlSnapshotWithReport(file),
2127
2191
  parseDocxStyleProfile(file)
2128
2192
  ]);
2129
2193
  this.styleProfile = profile;
2130
- this.htmlSnapshot = snapshot;
2194
+ this.htmlSnapshot = parseResult.htmlSnapshot;
2131
2195
  this.renderSnapshot();
2132
2196
  this.setHint(MESSAGES[this.locale].loadedWord(profile.sourceFileName));
2133
- this.emitChange("upload", profile.sourceFileName);
2197
+ this.emitChange("upload", profile.sourceFileName, parseResult.report);
2134
2198
  } catch (error) {
2135
2199
  this.emitError(error instanceof Error ? error.message : MESSAGES[this.locale].parseFailed);
2136
2200
  }
@@ -2190,8 +2254,10 @@ var DocsWordElement = class extends HTMLElement {
2190
2254
  renderSnapshot() {
2191
2255
  this.frame.srcdoc = this.htmlSnapshot;
2192
2256
  }
2193
- emitChange(source, fileName) {
2194
- this.dispatchEvent(new CustomEvent("docsjs-change", { detail: { htmlSnapshot: this.htmlSnapshot, source, fileName } }));
2257
+ emitChange(source, fileName, parseReport) {
2258
+ this.dispatchEvent(
2259
+ new CustomEvent("docsjs-change", { detail: { htmlSnapshot: this.htmlSnapshot, source, fileName, parseReport } })
2260
+ );
2195
2261
  }
2196
2262
  emitError(message) {
2197
2263
  this.dispatchEvent(new CustomEvent("docsjs-error", { detail: { message } }));