@a3s-lab/office 0.9.2 → 0.10.0
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/COLLABORATION_ROADMAP.md +19 -5
- package/README.md +16 -6
- package/dist/{0~7754.js → 0~4705.js} +500 -3
- package/dist/0~document-editor.js +7 -1
- package/dist/0~work-docx-export.js +260 -13
- package/dist/0~work-docx-import.js +9 -391
- package/dist/0~work-office-diagnostics.js +6 -4
- package/dist/8928.js +325 -22
- package/dist/internal/features/work/work-document-format-change-tracking.d.ts +9 -0
- package/dist/internal/features/work/work-document-format-changes.d.ts +28 -0
- package/dist/internal/features/work/work-docx-format-change-export.d.ts +17 -0
- package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +10 -0
- package/dist/internal/features/work/work-types.d.ts +1 -1
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +20 -0
- package/package.json +5 -3
package/COLLABORATION_ROADMAP.md
CHANGED
|
@@ -110,15 +110,17 @@ Redis/NATS fan-out plus a distributed writer/lock policy.
|
|
|
110
110
|
|
|
111
111
|
Status: browser collaboration foundation, participant roster, remote
|
|
112
112
|
selection/caret projection, participant navigation, durable review-only
|
|
113
|
-
comment and suggestion modes,
|
|
114
|
-
text/options/bounded structural
|
|
115
|
-
implemented; rich native mutation
|
|
113
|
+
comment and suggestion modes, character-formatting revisions, immutable
|
|
114
|
+
decision audit, and native text/options/bounded structural
|
|
115
|
+
paragraph/comment/suggestion mutations implemented; rich native mutation
|
|
116
|
+
parity remains pending.
|
|
116
117
|
|
|
117
118
|
- TipTap is bound to `document.content` through
|
|
118
119
|
`@tiptap/extension-collaboration`; StarterKit undo/redo is disabled and the
|
|
119
120
|
collaboration binding owns local history.
|
|
120
|
-
- Section/page OOXML state, comment anchors, and
|
|
121
|
-
in the ProseMirror fragment. Document-level
|
|
121
|
+
- Section/page OOXML state, comment anchors, and text or character-formatting
|
|
122
|
+
tracked-change marks converge in the ProseMirror fragment. Document-level
|
|
123
|
+
page color, tracking mode,
|
|
122
124
|
comment threads/replies, and bibliography sources use conflict-local typed
|
|
123
125
|
roots instead of a serialized document blob.
|
|
124
126
|
- React, Vue, and Web Component adapters accept the same initialized session.
|
|
@@ -166,6 +168,12 @@ implemented; rich native mutation parity remains pending.
|
|
|
166
168
|
converge, a second conflicting final decision fails closed, old Documents
|
|
167
169
|
without the additive roots remain readable, and a final decision clears
|
|
168
170
|
local history that could otherwise resurrect the decided mark.
|
|
171
|
+
- Character-formatting commands over existing text create one `formatting`
|
|
172
|
+
change mark with a bounded prior-direct-mark snapshot. Accept removes only
|
|
173
|
+
the revision wrapper and keeps the new formatting; reject restores the prior
|
|
174
|
+
bold, italic, underline, strike, sub/superscript, font, size, color,
|
|
175
|
+
highlight, and grid marks without changing text. Supported DOCX
|
|
176
|
+
`w:rPrChange` records import into the same model and export natively.
|
|
169
177
|
- Rust, CLI, MCP, and A3S Code expose `document-comment-create`,
|
|
170
178
|
`document-comment-reply`, `document-comment-set-resolved`,
|
|
171
179
|
`document-comment-delete`, `document-suggestion-create`, and
|
|
@@ -183,6 +191,12 @@ implemented; rich native mutation parity remains pending.
|
|
|
183
191
|
content, structure, options, non-suggestion formatting, authorship, order,
|
|
184
192
|
claims, anchors, foreign deletion, or foreign suggestion changes fail before
|
|
185
193
|
the durable store changes.
|
|
194
|
+
- Native Yrs validation admits only the bounded formatting-change schema,
|
|
195
|
+
preserves it across restart and duplicate/reordered delivery, exposes
|
|
196
|
+
`formatting` in immutable decision projections, and makes `suggest` updates
|
|
197
|
+
retain existing formatting revisions byte-semantically. Formatting is a
|
|
198
|
+
Document change kind, not a native insertion/deletion suggestion kind; the
|
|
199
|
+
current closed `document-suggestion-*` mutations remain text-only.
|
|
186
200
|
|
|
187
201
|
Remaining:
|
|
188
202
|
|
package/README.md
CHANGED
|
@@ -47,8 +47,10 @@ workflows, and a separate Rust automation plane.
|
|
|
47
47
|
- **Collaborate across every editor** with shared Yjs/Yrs content, Awareness
|
|
48
48
|
participants and remote locations, plus browser, CLI, MCP, and A3S Code peers.
|
|
49
49
|
Document reviewers can submit attributed insertions, deletions, and
|
|
50
|
-
replacements without directly changing canonical text
|
|
51
|
-
|
|
50
|
+
replacements without directly changing canonical text. Editors can also
|
|
51
|
+
track character-formatting revisions, accept the new formatting or restore
|
|
52
|
+
the exact prior marks, and retain either result in the immutable shared
|
|
53
|
+
decision audit.
|
|
52
54
|
- **Automate deterministically** through the native CLI, standard MCP server,
|
|
53
55
|
or packaged Office Skill.
|
|
54
56
|
|
|
@@ -148,7 +150,8 @@ The images below are committed visual-regression baselines from the real
|
|
|
148
150
|
Presentation scene-element and z-order, and PDF annotation, form-value, and
|
|
149
151
|
review changes, including attributable Document selection comments, replies,
|
|
150
152
|
text suggestions, and atomic final decisions, retain browser/native actor
|
|
151
|
-
attribution,
|
|
153
|
+
attribution, validate browser-created formatting revisions and their audit
|
|
154
|
+
records, and checkpoint without replacing a whole Office file.
|
|
152
155
|
|
|
153
156
|
## Real-time collaboration
|
|
154
157
|
|
|
@@ -171,9 +174,13 @@ deletions, and replacements while canonical text, structure, formatting,
|
|
|
171
174
|
options, comments, and other actors' suggestions remain protected. An `edit`
|
|
172
175
|
participant accepts or rejects a proposal and appends the final actor-attributed
|
|
173
176
|
decision to the immutable `document.change-decisions` audit trail. The A3S Boot
|
|
174
|
-
service
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
service also persists `edit`-mode character-formatting revisions and validates
|
|
178
|
+
their bounded prior-format snapshot before broadcast. Accept keeps the new
|
|
179
|
+
bold, italic, underline, strike, vertical position, font, size, color, or
|
|
180
|
+
highlight; reject restores the prior direct marks without deleting the text.
|
|
181
|
+
Authenticated `suggest` updates must preserve those formatting revisions and
|
|
182
|
+
cannot rewrite their identity or snapshot. `suggest` on non-Document formats
|
|
183
|
+
remains receive-only.
|
|
177
184
|
See the bilingual [real-time collaboration guide](https://a3s-lab.github.io/Office/docs/components/collaboration.html)
|
|
178
185
|
for React, Vue, Web Component, reconnect, security, and native-agent setup.
|
|
179
186
|
The repository also ships a runnable
|
|
@@ -196,6 +203,8 @@ bun run playground
|
|
|
196
203
|
|
|
197
204
|
Then open the local URL printed by the development server. For a zero-install
|
|
198
205
|
tour, use the [live Playground](https://a3s-lab.github.io/Office/).
|
|
206
|
+
Choose **体验格式修订**, open **审阅**, then **查看修订(1)** to inspect the
|
|
207
|
+
Formatting card and exercise accept or reject semantics.
|
|
199
208
|
|
|
200
209
|
### Embed a controlled React editor
|
|
201
210
|
|
|
@@ -1327,6 +1336,7 @@ without hard-coded return URLs.
|
|
|
1327
1336
|
|
|
1328
1337
|
- [Live Playground](https://a3s-lab.github.io/Office/)
|
|
1329
1338
|
- [Documentation center](https://a3s-lab.github.io/Office/docs/)
|
|
1339
|
+
- [A3S Office 0.10.0 documentation](https://a3s-lab.github.io/Office/docs/0.10.0/)
|
|
1330
1340
|
- [A3S Office 0.9.2 documentation](https://a3s-lab.github.io/Office/docs/0.9.2/)
|
|
1331
1341
|
- [A3S Office 0.9.1 documentation](https://a3s-lab.github.io/Office/docs/0.9.1/)
|
|
1332
1342
|
- [A3S Office 0.9.0 documentation](https://a3s-lab.github.io/Office/docs/0.9.0/)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { descendants, directChildren as work_ooxml_package_directChildren, xmlNamespacePrefix, directChild, attribute as work_ooxml_package_attribute, childPath } from "./5184.js";
|
|
2
|
-
import { xmlAttributeLocalName,
|
|
3
|
-
import { DOCUMENT_PARAGRAPH_BORDER_STYLES, normalizeDocumentParagraphBorders as work_document_paragraph_borders_normalizeDocumentParagraphBorders, DOCUMENT_PARAGRAPH_BORDER_EDGES, normalizeDocumentPageBorders, normalizeDocumentParagraphBorder, normalizeDocumentEquation, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_PARAGRAPH_SHADING_PATTERNS, documentParagraphShadingDomAttributes, documentParagraphBordersDomAttributes, createDocumentEquationElement, normalizeDocumentPageGeometry, normalizeDocumentPageMargins, documentEquationText, normalizeDocumentPaperSource } from "./8928.js";
|
|
2
|
+
import { xmlAttributeLocalName, docxThemeFont, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, docxThemeColor, resolveDocxThemeResolver as work_docx_theme_resolveDocxThemeResolver, DOCX_WORDPROCESSING_NAMESPACES, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, xmlAttributeNamespace } from "./0~2805.js";
|
|
3
|
+
import { DOCUMENT_PARAGRAPH_BORDER_STYLES, normalizeDocumentParagraphBorders as work_document_paragraph_borders_normalizeDocumentParagraphBorders, DOCUMENT_PARAGRAPH_BORDER_EDGES, normalizeDocumentPageBorders, normalizeDocumentParagraphBorder, normalizeDocumentEquation, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_PARAGRAPH_SHADING_PATTERNS, serializeDocxThemeReference, documentParagraphShadingDomAttributes, importedDocumentCharacterFormatting, documentParagraphBordersDomAttributes, createDocumentEquationElement, normalizeDocumentPageGeometry, normalizeDocumentPageMargins, documentEquationText, normalizeDocumentPaperSource, documentWordLineHeightFactor } from "./8928.js";
|
|
4
4
|
function docxFieldInstructions(root) {
|
|
5
5
|
return docxFieldOccurrences(root).map((field)=>field.instruction);
|
|
6
6
|
}
|
|
@@ -5650,4 +5650,501 @@ function work_docx_paragraph_shading_import_textNodes(root) {
|
|
|
5650
5650
|
while(walker.nextNode())nodes.push(walker.currentNode);
|
|
5651
5651
|
return nodes;
|
|
5652
5652
|
}
|
|
5653
|
-
|
|
5653
|
+
const work_docx_run_formatting_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
|
|
5654
|
+
const work_docx_run_formatting_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
|
|
5655
|
+
const RUN_FORMATTING_MARKER_PATTERN = /__A3S_WORK_RUN_(?:START|END)_\d+__/g;
|
|
5656
|
+
const SUPPORTED_RUN_PROPERTY_CHANGE_CHILDREN = new Set([
|
|
5657
|
+
'b',
|
|
5658
|
+
'bCs',
|
|
5659
|
+
'i',
|
|
5660
|
+
'iCs',
|
|
5661
|
+
'u',
|
|
5662
|
+
'strike',
|
|
5663
|
+
'dstrike',
|
|
5664
|
+
'rFonts',
|
|
5665
|
+
'sz',
|
|
5666
|
+
'szCs',
|
|
5667
|
+
'color',
|
|
5668
|
+
'highlight',
|
|
5669
|
+
'shd',
|
|
5670
|
+
'snapToGrid',
|
|
5671
|
+
'cs',
|
|
5672
|
+
'rtl',
|
|
5673
|
+
'vertAlign'
|
|
5674
|
+
]);
|
|
5675
|
+
function markDocxRunFormatting(document, styleSource, themeSource, tableStyleSource) {
|
|
5676
|
+
const runs = [];
|
|
5677
|
+
const styles = resolveDocxParagraphStyleResolver(styleSource);
|
|
5678
|
+
const theme = work_docx_theme_resolveDocxThemeResolver(themeSource);
|
|
5679
|
+
const tableStyles = resolveDocxTableStyleResolver(tableStyleSource);
|
|
5680
|
+
for (const run of descendants(document, 'r')){
|
|
5681
|
+
const runText = directRunText(run);
|
|
5682
|
+
if (!runText || runText.includes('__A3S_')) continue;
|
|
5683
|
+
const paragraph = work_docx_run_formatting_import_closestAncestor(run, 'p');
|
|
5684
|
+
if (!paragraph) continue;
|
|
5685
|
+
const paragraphProperties = directChild(paragraph, 'pPr');
|
|
5686
|
+
const runProperties = directChild(run, 'rPr');
|
|
5687
|
+
const formatting = resolvedRunFormatting(docxRunPropertySources(paragraphProperties, runProperties, styles, docxTableRunPropertySources(run, tableStyles)), theme, runText);
|
|
5688
|
+
const change = importedRunFormattingChange(runProperties, paragraphProperties, styles, docxTableRunPropertySources(run, tableStyles), theme, runText);
|
|
5689
|
+
if (!Object.keys(formatting).length && !change) continue;
|
|
5690
|
+
const index = runs.length + 1;
|
|
5691
|
+
const startMarker = `__A3S_WORK_RUN_START_${index}__`;
|
|
5692
|
+
const endMarker = `__A3S_WORK_RUN_END_${index}__`;
|
|
5693
|
+
insertRunMarkers(document, run, runProperties, startMarker, endMarker);
|
|
5694
|
+
runs.push({
|
|
5695
|
+
startMarker,
|
|
5696
|
+
endMarker,
|
|
5697
|
+
formatting,
|
|
5698
|
+
...change ? {
|
|
5699
|
+
change
|
|
5700
|
+
} : {}
|
|
5701
|
+
});
|
|
5702
|
+
}
|
|
5703
|
+
return {
|
|
5704
|
+
runs
|
|
5705
|
+
};
|
|
5706
|
+
}
|
|
5707
|
+
function applyImportedDocxRunFormattingMarkers(document, markers) {
|
|
5708
|
+
const replacements = new Map();
|
|
5709
|
+
for (const marker of markers.runs){
|
|
5710
|
+
const markup = formattingMarkup(document, marker.formatting);
|
|
5711
|
+
const change = marker.change ? formattingChangeMarkup(document, marker.change) : {
|
|
5712
|
+
start: '',
|
|
5713
|
+
end: ''
|
|
5714
|
+
};
|
|
5715
|
+
replacements.set(marker.startMarker, `${change.start}${markup.start}`);
|
|
5716
|
+
replacements.set(marker.endMarker, `${markup.end}${change.end}`);
|
|
5717
|
+
}
|
|
5718
|
+
document.body.innerHTML = document.body.innerHTML.replace(RUN_FORMATTING_MARKER_PATTERN, (marker)=>replacements.get(marker) ?? '');
|
|
5719
|
+
}
|
|
5720
|
+
function hasImportedDocxRunFormattingMarkers(markers) {
|
|
5721
|
+
return markers.runs.length > 0;
|
|
5722
|
+
}
|
|
5723
|
+
function resolvedRunFormatting(propertySources, theme, runText) {
|
|
5724
|
+
const fonts = {};
|
|
5725
|
+
let fontSize;
|
|
5726
|
+
let complexFontSize;
|
|
5727
|
+
let color;
|
|
5728
|
+
let backgroundColor;
|
|
5729
|
+
let themeColor;
|
|
5730
|
+
let themeFill;
|
|
5731
|
+
let bold;
|
|
5732
|
+
let complexBold;
|
|
5733
|
+
let italic;
|
|
5734
|
+
let complexItalic;
|
|
5735
|
+
let underline;
|
|
5736
|
+
let strike;
|
|
5737
|
+
let subscript;
|
|
5738
|
+
let superscript;
|
|
5739
|
+
let snapToGrid;
|
|
5740
|
+
let complexScriptFormatting;
|
|
5741
|
+
let rightToLeft;
|
|
5742
|
+
let fontHint;
|
|
5743
|
+
for (const properties of propertySources){
|
|
5744
|
+
bold = overriddenBoolean(bold, onOffProperty(properties, 'b'));
|
|
5745
|
+
complexBold = overriddenBoolean(complexBold, onOffProperty(properties, 'bCs'));
|
|
5746
|
+
italic = overriddenBoolean(italic, onOffProperty(properties, 'i'));
|
|
5747
|
+
complexItalic = overriddenBoolean(complexItalic, onOffProperty(properties, 'iCs'));
|
|
5748
|
+
underline = overriddenBoolean(underline, underlineProperty(properties));
|
|
5749
|
+
strike = overriddenBoolean(strike, onOffProperty(properties, 'strike'));
|
|
5750
|
+
strike = overriddenBoolean(strike, onOffProperty(properties, 'dstrike'));
|
|
5751
|
+
const verticalAlign = directChild(properties, 'vertAlign');
|
|
5752
|
+
if (verticalAlign) {
|
|
5753
|
+
const value = work_docx_run_formatting_import_wordAttribute(verticalAlign, 'val')?.trim().toLowerCase();
|
|
5754
|
+
subscript = "subscript" === value;
|
|
5755
|
+
superscript = "superscript" === value;
|
|
5756
|
+
if ('baseline' === value) {
|
|
5757
|
+
subscript = false;
|
|
5758
|
+
superscript = false;
|
|
5759
|
+
}
|
|
5760
|
+
}
|
|
5761
|
+
snapToGrid = overriddenBoolean(snapToGrid, onOffProperty(properties, 'snapToGrid'));
|
|
5762
|
+
complexScriptFormatting = overriddenBoolean(complexScriptFormatting, onOffProperty(properties, 'cs'));
|
|
5763
|
+
rightToLeft = overriddenBoolean(rightToLeft, onOffProperty(properties, 'rtl'));
|
|
5764
|
+
const runFonts = directChild(properties, 'rFonts');
|
|
5765
|
+
if (runFonts) {
|
|
5766
|
+
fontHint = resolvedFontHint(runFonts) ?? fontHint;
|
|
5767
|
+
assignFont(fonts, 'ascii', resolvedFont(runFonts, 'ascii', 'asciiTheme', theme));
|
|
5768
|
+
assignFont(fonts, 'hAnsi', resolvedFont(runFonts, 'hAnsi', 'hAnsiTheme', theme));
|
|
5769
|
+
assignFont(fonts, 'eastAsia', resolvedFont(runFonts, 'eastAsia', 'eastAsiaTheme', theme));
|
|
5770
|
+
assignFont(fonts, 'complex', resolvedFont(runFonts, 'cs', 'cstheme', theme));
|
|
5771
|
+
}
|
|
5772
|
+
const size = numericAttribute(directChild(properties, 'sz'), 'val');
|
|
5773
|
+
if (void 0 !== size && size > 0) fontSize = Math.min(512, size / 2);
|
|
5774
|
+
const complexSize = numericAttribute(directChild(properties, 'szCs'), 'val');
|
|
5775
|
+
if (void 0 !== complexSize && complexSize > 0) complexFontSize = Math.min(512, complexSize / 2);
|
|
5776
|
+
const colorElement = directChild(properties, 'color');
|
|
5777
|
+
if (colorElement) {
|
|
5778
|
+
const value = work_docx_run_formatting_import_wordAttribute(colorElement, 'val')?.trim();
|
|
5779
|
+
const themed = docxThemeColor(theme, work_docx_run_formatting_import_wordAttribute(colorElement, 'themeColor'), work_docx_run_formatting_import_wordAttribute(colorElement, 'themeTint'), work_docx_run_formatting_import_wordAttribute(colorElement, 'themeShade'));
|
|
5780
|
+
if (themed) {
|
|
5781
|
+
color = `#${themed}`;
|
|
5782
|
+
themeColor = work_docx_run_formatting_import_themeReference(colorElement, 'themeColor', 'themeTint', 'themeShade', color);
|
|
5783
|
+
} else if (value?.toLowerCase() === 'auto') {
|
|
5784
|
+
color = 'inherit';
|
|
5785
|
+
themeColor = void 0;
|
|
5786
|
+
} else if (value && /^[0-9a-f]{6}$/i.test(value)) {
|
|
5787
|
+
color = `#${value.toLowerCase()}`;
|
|
5788
|
+
themeColor = void 0;
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
const highlight = directChild(properties, 'highlight');
|
|
5792
|
+
if (highlight) {
|
|
5793
|
+
const value = work_docx_run_formatting_import_wordAttribute(highlight, 'val')?.trim().toLowerCase();
|
|
5794
|
+
if (value) {
|
|
5795
|
+
backgroundColor = wordHighlightColor(value);
|
|
5796
|
+
themeFill = void 0;
|
|
5797
|
+
}
|
|
5798
|
+
} else {
|
|
5799
|
+
const shading = directChild(properties, 'shd');
|
|
5800
|
+
const fill = shading ? work_docx_run_formatting_import_wordAttribute(shading, 'fill')?.trim() : void 0;
|
|
5801
|
+
const themed = shading ? docxThemeColor(theme, work_docx_run_formatting_import_wordAttribute(shading, 'themeFill'), work_docx_run_formatting_import_wordAttribute(shading, 'themeFillTint'), work_docx_run_formatting_import_wordAttribute(shading, 'themeFillShade')) : void 0;
|
|
5802
|
+
if (themed) {
|
|
5803
|
+
backgroundColor = `#${themed}`;
|
|
5804
|
+
themeFill = work_docx_run_formatting_import_themeReference(shading, 'themeFill', 'themeFillTint', 'themeFillShade', backgroundColor);
|
|
5805
|
+
} else if (fill?.toLowerCase() === 'auto') {
|
|
5806
|
+
backgroundColor = 'transparent';
|
|
5807
|
+
themeFill = void 0;
|
|
5808
|
+
} else if (fill && /^[0-9a-f]{6}$/i.test(fill)) {
|
|
5809
|
+
backgroundColor = `#${fill.toLowerCase()}`;
|
|
5810
|
+
themeFill = void 0;
|
|
5811
|
+
}
|
|
5812
|
+
}
|
|
5813
|
+
}
|
|
5814
|
+
const fontSlot = true === complexScriptFormatting || true === rightToLeft ? 'complex' : docxFontSlotForText(runText, fontHint);
|
|
5815
|
+
const usesComplexFormatting = 'complex' === fontSlot;
|
|
5816
|
+
const resolvedBold = usesComplexFormatting ? complexBold ?? bold : bold;
|
|
5817
|
+
const resolvedItalic = usesComplexFormatting ? complexItalic ?? italic : italic;
|
|
5818
|
+
const resolvedFontSize = usesComplexFormatting ? complexFontSize ?? fontSize : fontSize;
|
|
5819
|
+
let fontFamily = uniqueFonts(orderedFonts(fonts, fontSlot));
|
|
5820
|
+
if (!fontFamily) fontFamily = uniqueFonts(orderedFonts({
|
|
5821
|
+
ascii: docxThemeFont(theme, 'minorAscii'),
|
|
5822
|
+
hAnsi: docxThemeFont(theme, 'minorHAnsi'),
|
|
5823
|
+
eastAsia: docxThemeFont(theme, 'minorEastAsia'),
|
|
5824
|
+
complex: docxThemeFont(theme, 'minorBidi')
|
|
5825
|
+
}, fontSlot));
|
|
5826
|
+
const hasRunPropertySource = propertySources.length > 0;
|
|
5827
|
+
return {
|
|
5828
|
+
...void 0 !== resolvedBold || hasRunPropertySource ? {
|
|
5829
|
+
bold: resolvedBold ?? false
|
|
5830
|
+
} : {},
|
|
5831
|
+
...void 0 !== resolvedItalic || hasRunPropertySource ? {
|
|
5832
|
+
italic: resolvedItalic ?? false
|
|
5833
|
+
} : {},
|
|
5834
|
+
...void 0 !== underline || hasRunPropertySource ? {
|
|
5835
|
+
underline: underline ?? false
|
|
5836
|
+
} : {},
|
|
5837
|
+
...void 0 !== strike || hasRunPropertySource ? {
|
|
5838
|
+
strike: strike ?? false
|
|
5839
|
+
} : {},
|
|
5840
|
+
...void 0 !== subscript ? {
|
|
5841
|
+
subscript
|
|
5842
|
+
} : {},
|
|
5843
|
+
...void 0 !== superscript ? {
|
|
5844
|
+
superscript
|
|
5845
|
+
} : {},
|
|
5846
|
+
...fontFamily ? {
|
|
5847
|
+
fontFamily,
|
|
5848
|
+
wordLineHeightFactor: documentWordLineHeightFactor(fontFamily)
|
|
5849
|
+
} : {},
|
|
5850
|
+
...void 0 !== resolvedFontSize ? {
|
|
5851
|
+
fontSize: resolvedFontSize
|
|
5852
|
+
} : {},
|
|
5853
|
+
...void 0 !== snapToGrid ? {
|
|
5854
|
+
wordSnapToGrid: snapToGrid
|
|
5855
|
+
} : {},
|
|
5856
|
+
...color ? {
|
|
5857
|
+
color
|
|
5858
|
+
} : {},
|
|
5859
|
+
...backgroundColor ? {
|
|
5860
|
+
backgroundColor
|
|
5861
|
+
} : {},
|
|
5862
|
+
...themeColor ? {
|
|
5863
|
+
themeColor
|
|
5864
|
+
} : {},
|
|
5865
|
+
...themeFill ? {
|
|
5866
|
+
themeFill
|
|
5867
|
+
} : {}
|
|
5868
|
+
};
|
|
5869
|
+
}
|
|
5870
|
+
function insertRunMarkers(document, run, properties, startMarker, endMarker) {
|
|
5871
|
+
const start = markerText(document, startMarker);
|
|
5872
|
+
const end = markerText(document, endMarker);
|
|
5873
|
+
run.insertBefore(start, properties?.nextSibling ?? run.firstChild);
|
|
5874
|
+
run.append(end);
|
|
5875
|
+
}
|
|
5876
|
+
function markerText(document, marker) {
|
|
5877
|
+
const text = document.createElementNS(work_docx_run_formatting_import_WORD_NAMESPACE, 'w:t');
|
|
5878
|
+
text.setAttributeNS(work_docx_run_formatting_import_XML_NAMESPACE, 'xml:space', 'preserve');
|
|
5879
|
+
text.textContent = marker;
|
|
5880
|
+
return text;
|
|
5881
|
+
}
|
|
5882
|
+
function formattingMarkup(document, formatting) {
|
|
5883
|
+
const span = document.createElement('span');
|
|
5884
|
+
if (false === formatting.bold) span.style.fontWeight = 'normal';
|
|
5885
|
+
if (false === formatting.italic) span.style.fontStyle = 'normal';
|
|
5886
|
+
if ((false === formatting.underline || false === formatting.strike) && !formatting.underline && !formatting.strike) span.style.textDecorationLine = 'none';
|
|
5887
|
+
if (formatting.fontFamily) span.style.fontFamily = formatting.fontFamily;
|
|
5888
|
+
if (void 0 !== formatting.wordLineHeightFactor) {
|
|
5889
|
+
const factor = formatLineHeightFactor(formatting.wordLineHeightFactor);
|
|
5890
|
+
span.dataset.officeWordLineHeightFactor = factor;
|
|
5891
|
+
span.style.setProperty('--work-document-word-line-height-factor', factor);
|
|
5892
|
+
}
|
|
5893
|
+
if (void 0 !== formatting.wordSnapToGrid) span.dataset.officeWordSnapToGrid = String(formatting.wordSnapToGrid);
|
|
5894
|
+
if (void 0 !== formatting.fontSize) span.style.fontSize = `${formatNumber(formatting.fontSize)}pt`;
|
|
5895
|
+
if (formatting.color) span.style.color = formatting.color;
|
|
5896
|
+
const themeColor = serializeDocxThemeReference(formatting.themeColor ?? null);
|
|
5897
|
+
if (themeColor) span.dataset.officeThemeColor = themeColor;
|
|
5898
|
+
if (formatting.backgroundColor) span.style.backgroundColor = formatting.backgroundColor;
|
|
5899
|
+
const themeFill = serializeDocxThemeReference(formatting.themeFill ?? null);
|
|
5900
|
+
if (themeFill) span.dataset.officeThemeFill = themeFill;
|
|
5901
|
+
const html = span.outerHTML;
|
|
5902
|
+
const tags = [
|
|
5903
|
+
...formatting.bold ? [
|
|
5904
|
+
'strong'
|
|
5905
|
+
] : [],
|
|
5906
|
+
...formatting.italic ? [
|
|
5907
|
+
'em'
|
|
5908
|
+
] : [],
|
|
5909
|
+
...formatting.underline ? [
|
|
5910
|
+
'u'
|
|
5911
|
+
] : [],
|
|
5912
|
+
...formatting.strike ? [
|
|
5913
|
+
's'
|
|
5914
|
+
] : [],
|
|
5915
|
+
...formatting.subscript ? [
|
|
5916
|
+
'sub'
|
|
5917
|
+
] : [],
|
|
5918
|
+
...formatting.superscript ? [
|
|
5919
|
+
'sup'
|
|
5920
|
+
] : []
|
|
5921
|
+
];
|
|
5922
|
+
return {
|
|
5923
|
+
start: `${html.slice(0, html.indexOf('>') + 1)}${tags.map((tag)=>`<${tag}>`).join('')}`,
|
|
5924
|
+
end: `${[
|
|
5925
|
+
...tags
|
|
5926
|
+
].reverse().map((tag)=>`</${tag}>`).join('')}</span>`
|
|
5927
|
+
};
|
|
5928
|
+
}
|
|
5929
|
+
function importedRunFormattingChange(runProperties, paragraphProperties, styles, contextualProperties, theme, runText) {
|
|
5930
|
+
const parsed = supportedRunFormattingChange(runProperties);
|
|
5931
|
+
if (!parsed) return;
|
|
5932
|
+
const beforeFormatting = resolvedRunFormatting(docxRunPropertySources(paragraphProperties, parsed.properties, styles, contextualProperties), theme, runText);
|
|
5933
|
+
return {
|
|
5934
|
+
id: `docx-format-change-${parsed.id}`,
|
|
5935
|
+
author: parsed.author,
|
|
5936
|
+
date: normalizeRevisionDate(parsed.date),
|
|
5937
|
+
before: importedDocumentCharacterFormatting({
|
|
5938
|
+
...beforeFormatting,
|
|
5939
|
+
themeColor: serializeDocxThemeReference(beforeFormatting.themeColor ?? null),
|
|
5940
|
+
themeFill: serializeDocxThemeReference(beforeFormatting.themeFill ?? null)
|
|
5941
|
+
})
|
|
5942
|
+
};
|
|
5943
|
+
}
|
|
5944
|
+
function isSupportedDocxRunFormattingChange(change) {
|
|
5945
|
+
return Boolean(supportedRunFormattingChangeElement(change));
|
|
5946
|
+
}
|
|
5947
|
+
function supportedRunFormattingChange(runProperties) {
|
|
5948
|
+
if (!runProperties) return null;
|
|
5949
|
+
const changes = Array.from(runProperties.children).filter((child)=>'rPrChange' === child.localName);
|
|
5950
|
+
return 1 === changes.length ? supportedRunFormattingChangeElement(changes[0]) : null;
|
|
5951
|
+
}
|
|
5952
|
+
function supportedRunFormattingChangeElement(change) {
|
|
5953
|
+
if ('rPrChange' !== change.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(change.namespaceURI ?? '')) return null;
|
|
5954
|
+
const properties = Array.from(change.children).filter((child)=>'rPr' === child.localName && DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? ''));
|
|
5955
|
+
if (1 !== properties.length || 1 !== change.children.length) return null;
|
|
5956
|
+
const source = properties[0];
|
|
5957
|
+
const names = new Set();
|
|
5958
|
+
for (const child of Array.from(source.children)){
|
|
5959
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? '') || !SUPPORTED_RUN_PROPERTY_CHANGE_CHILDREN.has(child.localName) || names.has(child.localName)) return null;
|
|
5960
|
+
names.add(child.localName);
|
|
5961
|
+
}
|
|
5962
|
+
const id = work_ooxml_package_attribute(change, 'id')?.trim() ?? '';
|
|
5963
|
+
const author = work_ooxml_package_attribute(change, 'author')?.trim() ?? '';
|
|
5964
|
+
const date = work_ooxml_package_attribute(change, 'date');
|
|
5965
|
+
if (!/^\+?\d{1,10}$/.test(id) || !author || author.length > 255) return null;
|
|
5966
|
+
if (date && !Number.isFinite(Date.parse(date))) return null;
|
|
5967
|
+
return {
|
|
5968
|
+
id,
|
|
5969
|
+
author,
|
|
5970
|
+
date,
|
|
5971
|
+
properties: source
|
|
5972
|
+
};
|
|
5973
|
+
}
|
|
5974
|
+
function formattingChangeMarkup(document, change) {
|
|
5975
|
+
const span = document.createElement('span');
|
|
5976
|
+
span.dataset.documentChange = 'true';
|
|
5977
|
+
span.dataset.changeKind = 'formatting';
|
|
5978
|
+
span.dataset.changeId = change.id;
|
|
5979
|
+
span.dataset.changeAuthor = change.author;
|
|
5980
|
+
span.dataset.changeDate = change.date;
|
|
5981
|
+
span.dataset.changeBefore = change.before;
|
|
5982
|
+
const html = span.outerHTML;
|
|
5983
|
+
return {
|
|
5984
|
+
start: html.slice(0, html.indexOf('>') + 1),
|
|
5985
|
+
end: '</span>'
|
|
5986
|
+
};
|
|
5987
|
+
}
|
|
5988
|
+
function normalizeRevisionDate(value) {
|
|
5989
|
+
if (!value) return '';
|
|
5990
|
+
const time = Date.parse(value);
|
|
5991
|
+
return Number.isFinite(time) ? new Date(time).toISOString() : '';
|
|
5992
|
+
}
|
|
5993
|
+
function work_docx_run_formatting_import_themeReference(element, themeName, tintName, shadeName, resolved) {
|
|
5994
|
+
const theme = work_docx_run_formatting_import_wordAttribute(element, themeName)?.trim();
|
|
5995
|
+
if (!theme) return;
|
|
5996
|
+
const tint = normalizedByteHex(work_docx_run_formatting_import_wordAttribute(element, tintName));
|
|
5997
|
+
const shade = normalizedByteHex(work_docx_run_formatting_import_wordAttribute(element, shadeName));
|
|
5998
|
+
return {
|
|
5999
|
+
theme,
|
|
6000
|
+
resolved,
|
|
6001
|
+
...tint ? {
|
|
6002
|
+
tint
|
|
6003
|
+
} : {},
|
|
6004
|
+
...shade ? {
|
|
6005
|
+
shade
|
|
6006
|
+
} : {}
|
|
6007
|
+
};
|
|
6008
|
+
}
|
|
6009
|
+
function normalizedByteHex(value) {
|
|
6010
|
+
const normalized = value?.trim().toUpperCase();
|
|
6011
|
+
return normalized && /^[0-9A-F]{2}$/.test(normalized) ? normalized : void 0;
|
|
6012
|
+
}
|
|
6013
|
+
function overriddenBoolean(current, next) {
|
|
6014
|
+
return void 0 === next ? current : next;
|
|
6015
|
+
}
|
|
6016
|
+
function onOffProperty(properties, propertyName) {
|
|
6017
|
+
const element = directChild(properties, propertyName);
|
|
6018
|
+
if (!element) return;
|
|
6019
|
+
const value = work_docx_run_formatting_import_wordAttribute(element, 'val')?.trim().toLowerCase();
|
|
6020
|
+
return '0' !== value && 'false' !== value && 'off' !== value;
|
|
6021
|
+
}
|
|
6022
|
+
function underlineProperty(properties) {
|
|
6023
|
+
const element = directChild(properties, 'u');
|
|
6024
|
+
if (!element) return;
|
|
6025
|
+
const value = work_docx_run_formatting_import_wordAttribute(element, 'val')?.trim().toLowerCase();
|
|
6026
|
+
return '0' !== value && 'false' !== value && 'off' !== value && 'none' !== value;
|
|
6027
|
+
}
|
|
6028
|
+
function directRunText(run) {
|
|
6029
|
+
return Array.from(run.children).filter((child)=>'t' === child.localName || 'delText' === child.localName).map((child)=>child.textContent ?? '').join('');
|
|
6030
|
+
}
|
|
6031
|
+
function work_docx_run_formatting_import_closestAncestor(element, localName) {
|
|
6032
|
+
let current = element.parentElement;
|
|
6033
|
+
while(current){
|
|
6034
|
+
if (current.localName === localName) return current;
|
|
6035
|
+
current = current.parentElement;
|
|
6036
|
+
}
|
|
6037
|
+
return null;
|
|
6038
|
+
}
|
|
6039
|
+
function assignFont(fonts, key, value) {
|
|
6040
|
+
const normalized = value?.trim();
|
|
6041
|
+
if (normalized) fonts[key] = normalized;
|
|
6042
|
+
}
|
|
6043
|
+
function resolvedFontHint(element) {
|
|
6044
|
+
const hint = work_docx_run_formatting_import_wordAttribute(element, 'hint')?.trim().toLowerCase();
|
|
6045
|
+
if ('eastasia' === hint) return 'eastAsia';
|
|
6046
|
+
if ('cs' === hint) return 'complex';
|
|
6047
|
+
if ('default' === hint) return 'ascii';
|
|
6048
|
+
}
|
|
6049
|
+
function orderedFonts(fonts, preferred) {
|
|
6050
|
+
const order = {
|
|
6051
|
+
ascii: [
|
|
6052
|
+
'ascii',
|
|
6053
|
+
'hAnsi',
|
|
6054
|
+
'eastAsia',
|
|
6055
|
+
'complex'
|
|
6056
|
+
],
|
|
6057
|
+
hAnsi: [
|
|
6058
|
+
'hAnsi',
|
|
6059
|
+
'ascii',
|
|
6060
|
+
'eastAsia',
|
|
6061
|
+
'complex'
|
|
6062
|
+
],
|
|
6063
|
+
eastAsia: [
|
|
6064
|
+
'eastAsia',
|
|
6065
|
+
'hAnsi',
|
|
6066
|
+
'ascii',
|
|
6067
|
+
'complex'
|
|
6068
|
+
],
|
|
6069
|
+
complex: [
|
|
6070
|
+
'complex',
|
|
6071
|
+
'hAnsi',
|
|
6072
|
+
'ascii',
|
|
6073
|
+
'eastAsia'
|
|
6074
|
+
]
|
|
6075
|
+
};
|
|
6076
|
+
return order[preferred].map((slot)=>fonts[slot]);
|
|
6077
|
+
}
|
|
6078
|
+
function docxFontSlotForText(text, hint) {
|
|
6079
|
+
for (const character of text){
|
|
6080
|
+
const codePoint = character.codePointAt(0);
|
|
6081
|
+
if (!(void 0 === codePoint || isNeutralCodePoint(codePoint))) {
|
|
6082
|
+
if (isComplexScriptCodePoint(codePoint)) return 'complex';
|
|
6083
|
+
if (isEastAsianCodePoint(codePoint)) return 'eastAsia';
|
|
6084
|
+
return codePoint <= 0x7f ? 'ascii' : 'hAnsi';
|
|
6085
|
+
}
|
|
6086
|
+
}
|
|
6087
|
+
return hint ?? 'ascii';
|
|
6088
|
+
}
|
|
6089
|
+
function isNeutralCodePoint(codePoint) {
|
|
6090
|
+
return codePoint <= 0x20 || codePoint <= 0x7f && !(codePoint >= 0x41 && codePoint <= 0x5a || codePoint >= 0x61 && codePoint <= 0x7a) || codePoint >= 0x300 && codePoint <= 0x36f || codePoint >= 0x2000 && codePoint <= 0x206f;
|
|
6091
|
+
}
|
|
6092
|
+
function isComplexScriptCodePoint(codePoint) {
|
|
6093
|
+
return codePoint >= 0x0590 && codePoint <= 0x08ff || codePoint >= 0xfb1d && codePoint <= 0xfdff || codePoint >= 0xfe70 && codePoint <= 0xfeff || codePoint >= 0x1ee00 && codePoint <= 0x1eeff;
|
|
6094
|
+
}
|
|
6095
|
+
function isEastAsianCodePoint(codePoint) {
|
|
6096
|
+
return codePoint >= 0x1100 && codePoint <= 0x11ff || codePoint >= 0x2e80 && codePoint <= 0xa4cf || codePoint >= 0xac00 && codePoint <= 0xd7af || codePoint >= 0xf900 && codePoint <= 0xfaff || codePoint >= 0xfe10 && codePoint <= 0xfe6f || codePoint >= 0xff00 && codePoint <= 0xffef || codePoint >= 0x20000 && codePoint <= 0x323af;
|
|
6097
|
+
}
|
|
6098
|
+
function resolvedFont(element, explicitName, themeName, theme) {
|
|
6099
|
+
const explicit = work_docx_run_formatting_import_wordAttribute(element, explicitName);
|
|
6100
|
+
if (explicit?.trim()) return explicit;
|
|
6101
|
+
return docxThemeFont(theme, work_docx_run_formatting_import_wordAttribute(element, themeName)) ?? null;
|
|
6102
|
+
}
|
|
6103
|
+
function uniqueFonts(values) {
|
|
6104
|
+
const fonts = [
|
|
6105
|
+
...new Set(values.filter((value)=>!!value))
|
|
6106
|
+
];
|
|
6107
|
+
return fonts.length ? fonts.map(cssFontFamily).join(', ') : void 0;
|
|
6108
|
+
}
|
|
6109
|
+
function cssFontFamily(value) {
|
|
6110
|
+
return /[\s"',]/.test(value) ? `"${value.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"` : value;
|
|
6111
|
+
}
|
|
6112
|
+
function numericAttribute(element, name) {
|
|
6113
|
+
if (!element) return;
|
|
6114
|
+
const raw = work_docx_run_formatting_import_wordAttribute(element, name);
|
|
6115
|
+
if (null === raw || !raw.trim()) return;
|
|
6116
|
+
const value = Number(raw);
|
|
6117
|
+
return Number.isFinite(value) ? value : void 0;
|
|
6118
|
+
}
|
|
6119
|
+
function work_docx_run_formatting_import_wordAttribute(element, name) {
|
|
6120
|
+
return work_ooxml_package_attribute(element, name) ?? work_ooxml_package_attribute(element, `w:${name}`);
|
|
6121
|
+
}
|
|
6122
|
+
function wordHighlightColor(value) {
|
|
6123
|
+
const colors = {
|
|
6124
|
+
black: '#000000',
|
|
6125
|
+
blue: '#0000ff',
|
|
6126
|
+
cyan: '#00ffff',
|
|
6127
|
+
darkblue: '#000080',
|
|
6128
|
+
darkcyan: '#008080',
|
|
6129
|
+
darkgray: '#808080',
|
|
6130
|
+
darkgreen: '#008000',
|
|
6131
|
+
darkmagenta: '#800080',
|
|
6132
|
+
darkred: '#800000',
|
|
6133
|
+
darkyellow: '#808000',
|
|
6134
|
+
green: '#00ff00',
|
|
6135
|
+
lightgray: '#c0c0c0',
|
|
6136
|
+
magenta: '#ff00ff',
|
|
6137
|
+
none: 'transparent',
|
|
6138
|
+
red: '#ff0000',
|
|
6139
|
+
white: '#ffffff',
|
|
6140
|
+
yellow: '#ffff00'
|
|
6141
|
+
};
|
|
6142
|
+
return colors[value] ?? 'transparent';
|
|
6143
|
+
}
|
|
6144
|
+
function formatNumber(value) {
|
|
6145
|
+
return Number(value.toFixed(2)).toString();
|
|
6146
|
+
}
|
|
6147
|
+
function formatLineHeightFactor(value) {
|
|
6148
|
+
return Number(value.toFixed(4)).toString();
|
|
6149
|
+
}
|
|
6150
|
+
export { applyImportedDocxEquationMarkers, applyImportedDocxParagraphBorderMarkers, applyImportedDocxParagraphShadingMarkers, applyImportedDocxRunFormattingMarkers, createDocxParagraphStyleResolver, createDocxTableStyleResolver, docxCaptionBookmark, docxCaptionReferenceTarget, docxCaptionSequenceKind, docxEquationHtml, docxFieldInstructions, docxFieldOccurrenceIsInlineEditable, docxFieldOccurrences, docxFieldResultText, docxParagraphPropertySources, docxTableCellStyleLayers, docxTableParagraphPropertySources, docxTablePropertySources, hasImportedDocxParagraphBorderMarkers, hasImportedDocxParagraphShadingMarkers, hasImportedDocxRunFormattingMarkers, hasInvalidDocxFieldStructure, inspectDocxEquation, inspectDocxPageBorders, inspectDocxPageMarginSettings, inspectDocxPageMargins, inspectDocxPageSize, inspectDocxPaperSource, isDocxEquationLikeRoot, isSupportedDocxEquationPlacement, isSupportedDocxRunFormattingChange, markDocxPackageEquations, markDocxParagraphBorders, markDocxParagraphShading, markDocxRunFormatting, parseDirectDocxParagraphShading, parseDocxPageBorders, parseDocxPageGeometry, parseDocxPageMargins, parseDocxPaperSource, resolveDocxParagraphBordersForParagraph, resolveDocxParagraphStyleResolver, resolveDocxTableStyleResolver };
|
|
@@ -769,7 +769,7 @@ function DocumentChangesPanel({ editor, changes, decisions = [], trackChanges, s
|
|
|
769
769
|
}).run(),
|
|
770
770
|
children: [
|
|
771
771
|
/*#__PURE__*/ jsx("span", {
|
|
772
|
-
children:
|
|
772
|
+
children: documentChangeKindLabel(change.kind)
|
|
773
773
|
}),
|
|
774
774
|
/*#__PURE__*/ jsx("strong", {
|
|
775
775
|
children: change.text.trim() || '(空白字符)'
|
|
@@ -868,6 +868,7 @@ function DocumentChangeDecisionHistory({ decisions }) {
|
|
|
868
868
|
/*#__PURE__*/ jsx("ol", {
|
|
869
869
|
children: visible.map((decision)=>/*#__PURE__*/ jsxs("li", {
|
|
870
870
|
"data-document-change-decision": decision.decision,
|
|
871
|
+
"data-document-change-kind": decision.changeKind,
|
|
871
872
|
children: [
|
|
872
873
|
/*#__PURE__*/ jsx("span", {
|
|
873
874
|
children: 'accept' === decision.decision ? '已接受' : '已拒绝'
|
|
@@ -892,6 +893,11 @@ function DocumentChangeDecisionHistory({ decisions }) {
|
|
|
892
893
|
function documentChangeDecisionKey(changeKey, decision) {
|
|
893
894
|
return `${changeKey}:${decision}`;
|
|
894
895
|
}
|
|
896
|
+
function documentChangeKindLabel(kind) {
|
|
897
|
+
if ('insertion' === kind) return '插入';
|
|
898
|
+
if ('formatting' === kind) return '格式';
|
|
899
|
+
return '删除';
|
|
900
|
+
}
|
|
895
901
|
function documentChangeWindowKey(change) {
|
|
896
902
|
return `${change.kind}:${change.id}`;
|
|
897
903
|
}
|