@a3s-lab/office 0.1.0 → 0.2.2
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 +101 -24
- package/dist/0~2582.js +485 -0
- package/dist/0~4595.js +14 -7
- package/dist/0~4750.js +939 -0
- package/dist/{0~work-document-paragraph-formatting.js → 0~5861.js} +174 -3
- package/dist/0~7048.js +8 -6
- package/dist/0~9512.js +7 -4
- package/dist/0~document-editor.js +3147 -531
- package/dist/0~markdown-editor.js +26 -1
- package/dist/0~presentation-editor.js +68 -12
- package/dist/0~spreadsheet-editor.js +37 -17
- package/dist/0~work-document-extensions.js +588 -13
- package/dist/0~work-document-model-codec.js +1 -1
- package/dist/0~work-docx-bibliography.js +1 -1
- package/dist/0~work-docx-export.js +116 -55
- package/dist/0~work-docx-import.js +766 -107
- package/dist/0~work-office-diagnostics.js +2 -2
- package/dist/{4704.js → 2881.js} +162 -71
- package/dist/4104.js +2 -62
- package/dist/internal/features/work/editors/document-comment-window.d.ts +37 -0
- package/dist/internal/features/work/editors/document-navigation-panel.d.ts +3 -1
- package/dist/internal/features/work/editors/document-navigation-window.d.ts +64 -0
- package/dist/internal/features/work/editors/document-outline-navigation.d.ts +11 -0
- package/dist/internal/features/work/editors/document-page-navigation.d.ts +11 -1
- package/dist/internal/features/work/editors/document-page-thumbnail.d.ts +31 -0
- package/dist/internal/features/work/editors/document-picture-properties-dialog-model.d.ts +28 -0
- package/dist/internal/features/work/editors/document-picture-properties-dialog.d.ts +4 -0
- package/dist/internal/features/work/editors/document-search-navigation.d.ts +12 -0
- package/dist/internal/features/work/editors/document-table-margins-popover.d.ts +4 -0
- package/dist/internal/features/work/editors/document-table-properties-dialog-model.d.ts +51 -0
- package/dist/internal/features/work/editors/document-table-properties-dialog-sections.d.ts +19 -0
- package/dist/internal/features/work/editors/document-table-properties-dialog.d.ts +8 -0
- package/dist/internal/features/work/editors/office-task-pane.d.ts +1 -1
- package/dist/internal/features/work/editors/presentation-chart-panel.d.ts +2 -1
- package/dist/internal/features/work/editors/presentation-comments-panel.d.ts +2 -1
- package/dist/internal/features/work/editors/spreadsheet-workbook-panel.d.ts +2 -1
- package/dist/internal/features/work/editors/use-document-pagination.d.ts +6 -0
- package/dist/internal/features/work/editors/use-presentation-review-commands.d.ts +1 -1
- package/dist/internal/features/work/work-document-image-layout.d.ts +11 -0
- package/dist/internal/features/work/work-document-page-capture.d.ts +15 -0
- package/dist/internal/features/work/work-document-paragraph-formatting.d.ts +4 -0
- package/dist/internal/features/work/work-document-section.d.ts +3 -1
- package/dist/internal/features/work/work-document-table-borders.d.ts +20 -0
- package/dist/internal/features/work/work-document-table-cell-formatting.d.ts +8 -5
- package/dist/internal/features/work/work-document-table-geometry.d.ts +41 -0
- package/dist/internal/features/work/work-document-table-property-changes.d.ts +25 -0
- package/dist/internal/features/work/work-document-table-sizing.d.ts +15 -2
- package/dist/internal/features/work/work-document-word-line-metrics.d.ts +11 -0
- package/dist/internal/features/work/work-docx-document-layout.d.ts +2 -0
- package/dist/internal/features/work/work-docx-paragraph-alignment-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-direction-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-indent-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-pagination-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-spacing-import.d.ts +3 -2
- package/dist/internal/features/work/work-docx-paragraph-styles.d.ts +2 -2
- package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +8 -1
- package/dist/internal/features/work/work-docx-tab-stop-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-table-cell-export.d.ts +1 -1
- package/dist/internal/features/work/work-docx-table-cell-import.d.ts +14 -4
- package/dist/internal/features/work/work-docx-table-sizing-export.d.ts +1 -1
- package/dist/internal/features/work/work-docx-table-sizing-import.d.ts +4 -3
- package/dist/internal/features/work/work-docx-table-styles.d.ts +22 -0
- package/dist/internal/features/work/work-types.d.ts +6 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +1288 -233
- package/docs/{browser-editor-architecture.md → latest/en/browser-editor-architecture.md} +144 -35
- package/package.json +9 -5
- package/dist/0~6552.js +0 -787
- package/dist/0~8155.js +0 -299
package/dist/0~4750.js
ADDED
|
@@ -0,0 +1,939 @@
|
|
|
1
|
+
import { Extension, ResizableNodeView, mergeAttributes } from "@tiptap/core";
|
|
2
|
+
import extension_image from "@tiptap/extension-image";
|
|
3
|
+
import { closeHistory } from "@tiptap/pm/history";
|
|
4
|
+
import { NodeSelection } from "@tiptap/pm/state";
|
|
5
|
+
import { TableMap, isInTable, selectedRect } from "@tiptap/pm/tables";
|
|
6
|
+
const DEFAULT_IMAGE_LAYOUT = 'inline';
|
|
7
|
+
const DEFAULT_IMAGE_ALIGNMENT = 'center';
|
|
8
|
+
const DEFAULT_WRAP_DISTANCE_MILLIMETERS = 3;
|
|
9
|
+
const MAX_WRAP_DISTANCE_MILLIMETERS = 25;
|
|
10
|
+
const DEFAULT_LOCK_ASPECT_RATIO = true;
|
|
11
|
+
const DocumentImage = extension_image.extend({
|
|
12
|
+
addCommands () {
|
|
13
|
+
return {
|
|
14
|
+
...this.parent?.() ?? {},
|
|
15
|
+
setDocumentImageProperties: (value, options = {})=>({ chain, state, tr })=>{
|
|
16
|
+
if (!isDocumentImageSelection(state.selection)) return false;
|
|
17
|
+
const attributes = documentImageAttributesForChanges(value);
|
|
18
|
+
if (!Object.keys(attributes).length) return false;
|
|
19
|
+
closeHistory(tr);
|
|
20
|
+
let commandChain = chain();
|
|
21
|
+
if (false !== options.restoreFocus) commandChain = commandChain.focus();
|
|
22
|
+
return commandChain.updateAttributes('image', attributes).run();
|
|
23
|
+
},
|
|
24
|
+
setDocumentImageAlternativeText: (alternativeText, options = {})=>({ commands })=>commands.setDocumentImageProperties({
|
|
25
|
+
alternativeText
|
|
26
|
+
}, options),
|
|
27
|
+
setDocumentImageLayoutOptions: (value, options = {})=>({ commands })=>commands.setDocumentImageProperties(value, options)
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
addAttributes () {
|
|
31
|
+
return {
|
|
32
|
+
...this.parent?.(),
|
|
33
|
+
layout: {
|
|
34
|
+
default: DEFAULT_IMAGE_LAYOUT,
|
|
35
|
+
parseHTML: (element)=>normalizeDocumentImageLayout(element.getAttribute('data-office-image-layout')),
|
|
36
|
+
renderHTML: (attributes)=>({
|
|
37
|
+
'data-office-image-layout': normalizeDocumentImageLayout(attributes.layout)
|
|
38
|
+
})
|
|
39
|
+
},
|
|
40
|
+
alignment: {
|
|
41
|
+
default: DEFAULT_IMAGE_ALIGNMENT,
|
|
42
|
+
parseHTML: (element)=>normalizeDocumentImageAlignment(element.getAttribute('data-office-image-alignment')),
|
|
43
|
+
renderHTML: (attributes)=>({
|
|
44
|
+
'data-office-image-alignment': normalizeDocumentImageAlignment(attributes.alignment)
|
|
45
|
+
})
|
|
46
|
+
},
|
|
47
|
+
wrapDistance: {
|
|
48
|
+
default: DEFAULT_WRAP_DISTANCE_MILLIMETERS,
|
|
49
|
+
parseHTML: (element)=>normalizeDocumentImageWrapDistance(element.getAttribute('data-office-image-wrap-distance')),
|
|
50
|
+
renderHTML: (attributes)=>{
|
|
51
|
+
const distance = normalizeDocumentImageWrapDistance(attributes.wrapDistance);
|
|
52
|
+
return {
|
|
53
|
+
'data-office-image-wrap-distance': formatImageLayoutNumber(distance),
|
|
54
|
+
style: `--work-document-image-wrap-distance:${formatImageLayoutNumber(distance)}mm`
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
lockAspectRatio: {
|
|
59
|
+
default: DEFAULT_LOCK_ASPECT_RATIO,
|
|
60
|
+
parseHTML: (element)=>normalizeDocumentImageLockAspectRatio(element.getAttribute('data-office-image-lock-aspect-ratio')),
|
|
61
|
+
renderHTML: (attributes)=>({
|
|
62
|
+
'data-office-image-lock-aspect-ratio': String(normalizeDocumentImageLockAspectRatio(attributes.lockAspectRatio))
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
addNodeView () {
|
|
68
|
+
const resize = this.options.resize;
|
|
69
|
+
if (false === resize || !resize.enabled || "u" < typeof document) return null;
|
|
70
|
+
const { directions, minWidth, minHeight, alwaysPreserveAspectRatio } = resize;
|
|
71
|
+
return ({ node, getPos, HTMLAttributes, editor })=>{
|
|
72
|
+
const element = document.createElement('img');
|
|
73
|
+
element.draggable = false;
|
|
74
|
+
applyInitialImageHtmlAttributes(element, HTMLAttributes);
|
|
75
|
+
element.style.visibility = 'hidden';
|
|
76
|
+
element.style.pointerEvents = 'none';
|
|
77
|
+
const reveal = ()=>{
|
|
78
|
+
element.style.visibility = '';
|
|
79
|
+
element.style.pointerEvents = '';
|
|
80
|
+
};
|
|
81
|
+
element.addEventListener('load', reveal);
|
|
82
|
+
element.addEventListener('error', reveal);
|
|
83
|
+
let container = null;
|
|
84
|
+
const sync = (updatedNode)=>{
|
|
85
|
+
syncDocumentImageNodeView(element, container, updatedNode.attrs);
|
|
86
|
+
};
|
|
87
|
+
const nodeView = new ResizableNodeView({
|
|
88
|
+
element,
|
|
89
|
+
editor,
|
|
90
|
+
node,
|
|
91
|
+
getPos,
|
|
92
|
+
onResize: (width, height)=>{
|
|
93
|
+
element.style.width = `${width}px`;
|
|
94
|
+
element.style.height = `${height}px`;
|
|
95
|
+
},
|
|
96
|
+
onCommit: (width, height)=>{
|
|
97
|
+
const position = getPos();
|
|
98
|
+
if (void 0 === position) return;
|
|
99
|
+
editor.chain().setNodeSelection(position).updateAttributes(this.name, {
|
|
100
|
+
width,
|
|
101
|
+
height
|
|
102
|
+
}).run();
|
|
103
|
+
},
|
|
104
|
+
onUpdate: (updatedNode)=>{
|
|
105
|
+
if (updatedNode.type !== node.type) return false;
|
|
106
|
+
if (!sameDocumentImageResizeConfiguration(node, updatedNode)) return false;
|
|
107
|
+
sync(updatedNode);
|
|
108
|
+
return true;
|
|
109
|
+
},
|
|
110
|
+
options: {
|
|
111
|
+
directions,
|
|
112
|
+
min: {
|
|
113
|
+
width: minWidth,
|
|
114
|
+
height: minHeight
|
|
115
|
+
},
|
|
116
|
+
preserveAspectRatio: null === node.attrs.lockAspectRatio || void 0 === node.attrs.lockAspectRatio ? true === alwaysPreserveAspectRatio : normalizeDocumentImageLockAspectRatio(node.attrs.lockAspectRatio)
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
container = nodeView.dom;
|
|
120
|
+
sync(node);
|
|
121
|
+
if (element.complete) reveal();
|
|
122
|
+
return nodeView;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
function documentImageLayoutOptions(editor) {
|
|
127
|
+
const attributes = editor.getAttributes('image');
|
|
128
|
+
return normalizeDocumentImageLayoutOptions(attributes);
|
|
129
|
+
}
|
|
130
|
+
function documentImageProperties(editor) {
|
|
131
|
+
const attributes = editor.getAttributes('image');
|
|
132
|
+
return {
|
|
133
|
+
...normalizeDocumentImageLayoutOptions(attributes),
|
|
134
|
+
width: normalizeDocumentImageDimension(attributes.width),
|
|
135
|
+
height: normalizeDocumentImageDimension(attributes.height),
|
|
136
|
+
lockAspectRatio: normalizeDocumentImageLockAspectRatio(attributes.lockAspectRatio),
|
|
137
|
+
alternativeText: documentImageAlternativeText(editor)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function documentImageAlternativeText(editor) {
|
|
141
|
+
if (!editor.isActive('image')) return '';
|
|
142
|
+
const attributes = editor.getAttributes('image');
|
|
143
|
+
const value = 'string' == typeof attributes.alt ? attributes.alt : 'string' == typeof attributes.title ? attributes.title : '';
|
|
144
|
+
return value.trim();
|
|
145
|
+
}
|
|
146
|
+
function documentImageLayoutFromElement(element) {
|
|
147
|
+
return normalizeDocumentImageLayoutOptions({
|
|
148
|
+
layout: element.getAttribute('data-office-image-layout'),
|
|
149
|
+
alignment: element.getAttribute('data-office-image-alignment'),
|
|
150
|
+
wrapDistance: element.getAttribute('data-office-image-wrap-distance')
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function normalizeDocumentImageLayoutOptions(value) {
|
|
154
|
+
return {
|
|
155
|
+
layout: normalizeDocumentImageLayout(value.layout),
|
|
156
|
+
alignment: normalizeDocumentImageAlignment(value.alignment),
|
|
157
|
+
wrapDistance: normalizeDocumentImageWrapDistance(value.wrapDistance)
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function normalizeDocumentImageLayout(value) {
|
|
161
|
+
return 'square' === value || 'topBottom' === value ? value : DEFAULT_IMAGE_LAYOUT;
|
|
162
|
+
}
|
|
163
|
+
function normalizeDocumentImageAlignment(value) {
|
|
164
|
+
return 'left' === value || 'right' === value ? value : DEFAULT_IMAGE_ALIGNMENT;
|
|
165
|
+
}
|
|
166
|
+
function normalizeDocumentImageWrapDistance(value) {
|
|
167
|
+
const number = 'number' == typeof value ? value : 'string' == typeof value && value.trim() ? Number(value) : DEFAULT_WRAP_DISTANCE_MILLIMETERS;
|
|
168
|
+
if (!Number.isFinite(number)) return DEFAULT_WRAP_DISTANCE_MILLIMETERS;
|
|
169
|
+
return Math.round(2 * Math.min(MAX_WRAP_DISTANCE_MILLIMETERS, Math.max(0, number))) / 2;
|
|
170
|
+
}
|
|
171
|
+
function normalizeDocumentImageDimension(value) {
|
|
172
|
+
if (null == value || '' === value) return null;
|
|
173
|
+
const number = 'number' == typeof value ? value : Number(value);
|
|
174
|
+
return Number.isFinite(number) && number > 0 ? Math.round(100 * number) / 100 : null;
|
|
175
|
+
}
|
|
176
|
+
function normalizeDocumentImageLockAspectRatio(value) {
|
|
177
|
+
return false === value || 'false' === value || 0 === value || '0' === value ? false : DEFAULT_LOCK_ASPECT_RATIO;
|
|
178
|
+
}
|
|
179
|
+
function formatImageLayoutNumber(value) {
|
|
180
|
+
return Number(value.toFixed(2)).toString();
|
|
181
|
+
}
|
|
182
|
+
function documentImageAttributesForChanges(value) {
|
|
183
|
+
const attributes = {};
|
|
184
|
+
if (Object.hasOwn(value, 'width')) attributes.width = normalizeDocumentImageDimension(value.width);
|
|
185
|
+
if (Object.hasOwn(value, 'height')) attributes.height = normalizeDocumentImageDimension(value.height);
|
|
186
|
+
if (Object.hasOwn(value, 'lockAspectRatio')) attributes.lockAspectRatio = normalizeDocumentImageLockAspectRatio(value.lockAspectRatio);
|
|
187
|
+
if (Object.hasOwn(value, 'layout')) attributes.layout = normalizeDocumentImageLayout(value.layout);
|
|
188
|
+
if (Object.hasOwn(value, 'alignment')) attributes.alignment = normalizeDocumentImageAlignment(value.alignment);
|
|
189
|
+
if (Object.hasOwn(value, 'wrapDistance')) attributes.wrapDistance = normalizeDocumentImageWrapDistance(value.wrapDistance);
|
|
190
|
+
if (Object.hasOwn(value, 'alternativeText')) {
|
|
191
|
+
const alternativeText = value.alternativeText?.trim() ?? '';
|
|
192
|
+
attributes.alt = alternativeText || null;
|
|
193
|
+
attributes.title = alternativeText || null;
|
|
194
|
+
}
|
|
195
|
+
return attributes;
|
|
196
|
+
}
|
|
197
|
+
function isDocumentImageSelection(selection) {
|
|
198
|
+
return selection instanceof NodeSelection && 'image' === selection.node.type.name;
|
|
199
|
+
}
|
|
200
|
+
function sameDocumentImageResizeConfiguration(initial, current) {
|
|
201
|
+
return normalizeDocumentImageDimension(initial.attrs.width) === normalizeDocumentImageDimension(current.attrs.width) && normalizeDocumentImageDimension(initial.attrs.height) === normalizeDocumentImageDimension(current.attrs.height) && normalizeDocumentImageLockAspectRatio(initial.attrs.lockAspectRatio) === normalizeDocumentImageLockAspectRatio(current.attrs.lockAspectRatio);
|
|
202
|
+
}
|
|
203
|
+
function applyInitialImageHtmlAttributes(element, attributes) {
|
|
204
|
+
const merged = mergeAttributes(attributes);
|
|
205
|
+
for (const [name, value] of Object.entries(merged))if (null != value && 'width' !== name && 'height' !== name) element.setAttribute(name, String(value));
|
|
206
|
+
}
|
|
207
|
+
function syncDocumentImageNodeView(element, container, attributes) {
|
|
208
|
+
const layout = normalizeDocumentImageLayout(attributes.layout);
|
|
209
|
+
const alignment = normalizeDocumentImageAlignment(attributes.alignment);
|
|
210
|
+
const wrapDistance = normalizeDocumentImageWrapDistance(attributes.wrapDistance);
|
|
211
|
+
const lockAspectRatio = normalizeDocumentImageLockAspectRatio(attributes.lockAspectRatio);
|
|
212
|
+
setOptionalImageAttribute(element, 'src', attributes.src);
|
|
213
|
+
setOptionalImageAttribute(element, 'alt', attributes.alt);
|
|
214
|
+
setOptionalImageAttribute(element, 'title', attributes.title);
|
|
215
|
+
element.dataset.officeImageLayout = layout;
|
|
216
|
+
element.dataset.officeImageAlignment = alignment;
|
|
217
|
+
element.dataset.officeImageWrapDistance = formatImageLayoutNumber(wrapDistance);
|
|
218
|
+
element.dataset.officeImageLockAspectRatio = String(lockAspectRatio);
|
|
219
|
+
element.style.setProperty('--work-document-image-wrap-distance', `${formatImageLayoutNumber(wrapDistance)}mm`);
|
|
220
|
+
syncImageDimension(element, 'width', attributes.width);
|
|
221
|
+
syncImageDimension(element, 'height', attributes.height);
|
|
222
|
+
if (!container) return;
|
|
223
|
+
container.dataset.officeImageLayout = layout;
|
|
224
|
+
container.dataset.officeImageAlignment = alignment;
|
|
225
|
+
container.dataset.officeImageWrapDistance = formatImageLayoutNumber(wrapDistance);
|
|
226
|
+
container.dataset.officeImageLockAspectRatio = String(lockAspectRatio);
|
|
227
|
+
container.style.setProperty('--work-document-image-wrap-distance', `${formatImageLayoutNumber(wrapDistance)}mm`);
|
|
228
|
+
}
|
|
229
|
+
function setOptionalImageAttribute(element, name, value) {
|
|
230
|
+
if ('string' == typeof value && value) element.setAttribute(name, value);
|
|
231
|
+
else element.removeAttribute(name);
|
|
232
|
+
}
|
|
233
|
+
function syncImageDimension(element, dimension, value) {
|
|
234
|
+
const pixels = 'number' == typeof value ? value : Number(value);
|
|
235
|
+
if (Number.isFinite(pixels) && pixels > 0) {
|
|
236
|
+
element.style[dimension] = `${pixels}px`;
|
|
237
|
+
element.setAttribute(dimension, String(Math.round(pixels)));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
element.style.removeProperty(dimension);
|
|
241
|
+
element.removeAttribute(dimension);
|
|
242
|
+
}
|
|
243
|
+
const MAX_DOCUMENT_TAB_POSITION_PX = 4096;
|
|
244
|
+
const MAX_DOCUMENT_TAB_STOPS = 64;
|
|
245
|
+
const DocumentParagraphTabStops = Extension.create({
|
|
246
|
+
name: 'documentParagraphTabStops',
|
|
247
|
+
addGlobalAttributes () {
|
|
248
|
+
return [
|
|
249
|
+
{
|
|
250
|
+
types: [
|
|
251
|
+
'paragraph',
|
|
252
|
+
'heading'
|
|
253
|
+
],
|
|
254
|
+
attributes: {
|
|
255
|
+
tabStops: {
|
|
256
|
+
default: null,
|
|
257
|
+
parseHTML: (element)=>normalizeDocumentTabStops(element.dataset.officeTabStops),
|
|
258
|
+
renderHTML: (attributes)=>{
|
|
259
|
+
const tabStops = normalizeDocumentTabStops(attributes.tabStops);
|
|
260
|
+
return tabStops.length ? {
|
|
261
|
+
'data-office-tab-stops': serializeDocumentTabStops(tabStops)
|
|
262
|
+
} : {};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
];
|
|
268
|
+
},
|
|
269
|
+
addCommands () {
|
|
270
|
+
return {
|
|
271
|
+
setDocumentParagraphTabStops: (tabStops, options = {})=>({ chain, editor })=>{
|
|
272
|
+
const nodeTypes = activeParagraphNodeTypes(editor);
|
|
273
|
+
if (!nodeTypes.length) return false;
|
|
274
|
+
const normalized = normalizeDocumentTabStops(tabStops);
|
|
275
|
+
let commandChain = chain();
|
|
276
|
+
if (false !== options.restoreFocus) commandChain = commandChain.focus();
|
|
277
|
+
for (const nodeType of nodeTypes)commandChain = commandChain.updateAttributes(nodeType, {
|
|
278
|
+
tabStops: normalized.length ? normalized : null
|
|
279
|
+
});
|
|
280
|
+
return commandChain.run();
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
function documentParagraphTabStops(editor) {
|
|
286
|
+
return normalizeDocumentTabStops(activeParagraphAttributes(editor).tabStops);
|
|
287
|
+
}
|
|
288
|
+
function normalizeDocumentTabStops(value) {
|
|
289
|
+
const source = parsedTabStopSource(value);
|
|
290
|
+
const byPosition = new Map();
|
|
291
|
+
for (const candidate of source.slice(0, 4 * MAX_DOCUMENT_TAB_STOPS)){
|
|
292
|
+
if (!isRecord(candidate)) continue;
|
|
293
|
+
const rawPosition = Number(candidate.position);
|
|
294
|
+
if (!Number.isFinite(rawPosition) || rawPosition <= 0) continue;
|
|
295
|
+
const position = normalizedTabPosition(rawPosition);
|
|
296
|
+
if (!(position <= 0)) byPosition.set(position, {
|
|
297
|
+
position,
|
|
298
|
+
alignment: normalizedTabAlignment(candidate.alignment),
|
|
299
|
+
leader: normalizedTabLeader(candidate.leader)
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return Array.from(byPosition.values()).sort((left, right)=>left.position - right.position).slice(0, MAX_DOCUMENT_TAB_STOPS);
|
|
303
|
+
}
|
|
304
|
+
function serializeDocumentTabStops(value) {
|
|
305
|
+
return JSON.stringify(normalizeDocumentTabStops(value));
|
|
306
|
+
}
|
|
307
|
+
function normalizedTabPosition(value) {
|
|
308
|
+
if (!Number.isFinite(value)) return 0;
|
|
309
|
+
return Math.min(MAX_DOCUMENT_TAB_POSITION_PX, Math.max(0, Math.round(100 * value) / 100));
|
|
310
|
+
}
|
|
311
|
+
function nextDocumentTabAlignment(alignment) {
|
|
312
|
+
if ('left' === alignment) return 'center';
|
|
313
|
+
if ('center' === alignment) return 'right';
|
|
314
|
+
if ('right' === alignment) return 'decimal';
|
|
315
|
+
return 'left';
|
|
316
|
+
}
|
|
317
|
+
function parsedTabStopSource(value) {
|
|
318
|
+
if (Array.isArray(value)) return value;
|
|
319
|
+
if ('string' != typeof value || !value.trim()) return [];
|
|
320
|
+
try {
|
|
321
|
+
const parsed = JSON.parse(value);
|
|
322
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
323
|
+
} catch {
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function normalizedTabAlignment(value) {
|
|
328
|
+
return 'center' === value || 'right' === value || 'decimal' === value ? value : 'left';
|
|
329
|
+
}
|
|
330
|
+
function normalizedTabLeader(value) {
|
|
331
|
+
return 'dot' === value || 'hyphen' === value || 'underscore' === value || 'middleDot' === value ? value : 'none';
|
|
332
|
+
}
|
|
333
|
+
function activeParagraphAttributes(editor) {
|
|
334
|
+
return editor.isActive('heading') ? editor.getAttributes('heading') : editor.getAttributes('paragraph');
|
|
335
|
+
}
|
|
336
|
+
function activeParagraphNodeTypes(editor) {
|
|
337
|
+
const types = [];
|
|
338
|
+
if (editor.isActive('paragraph')) types.push('paragraph');
|
|
339
|
+
if (editor.isActive('heading')) types.push('heading');
|
|
340
|
+
return types;
|
|
341
|
+
}
|
|
342
|
+
function isRecord(value) {
|
|
343
|
+
return 'object' == typeof value && null !== value && !Array.isArray(value);
|
|
344
|
+
}
|
|
345
|
+
const BORDER_EDGES = [
|
|
346
|
+
'top',
|
|
347
|
+
'right',
|
|
348
|
+
'bottom',
|
|
349
|
+
'left'
|
|
350
|
+
];
|
|
351
|
+
function uniformDocumentTableBorders(border) {
|
|
352
|
+
return {
|
|
353
|
+
top: {
|
|
354
|
+
...border
|
|
355
|
+
},
|
|
356
|
+
right: {
|
|
357
|
+
...border
|
|
358
|
+
},
|
|
359
|
+
bottom: {
|
|
360
|
+
...border
|
|
361
|
+
},
|
|
362
|
+
left: {
|
|
363
|
+
...border
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function documentTableBordersFromAttributes(attributes, fallback) {
|
|
368
|
+
const candidate = attributes.borders;
|
|
369
|
+
if (!candidate || 'object' != typeof candidate || Array.isArray(candidate)) return uniformDocumentTableBorders(fallback);
|
|
370
|
+
const record = candidate;
|
|
371
|
+
return {
|
|
372
|
+
top: normalizeDocumentTableBorder(record.top) ?? {
|
|
373
|
+
...fallback
|
|
374
|
+
},
|
|
375
|
+
right: normalizeDocumentTableBorder(record.right) ?? {
|
|
376
|
+
...fallback
|
|
377
|
+
},
|
|
378
|
+
bottom: normalizeDocumentTableBorder(record.bottom) ?? {
|
|
379
|
+
...fallback
|
|
380
|
+
},
|
|
381
|
+
left: normalizeDocumentTableBorder(record.left) ?? {
|
|
382
|
+
...fallback
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function documentTableBordersFromElement(element, fallback) {
|
|
387
|
+
const uniform = documentTableBorderFromElement(element, fallback);
|
|
388
|
+
return {
|
|
389
|
+
top: documentTableEdgeFromElement(element, 'top', uniform),
|
|
390
|
+
right: documentTableEdgeFromElement(element, 'right', uniform),
|
|
391
|
+
bottom: documentTableEdgeFromElement(element, 'bottom', uniform),
|
|
392
|
+
left: documentTableEdgeFromElement(element, 'left', uniform)
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
function renderDocumentTableBorders(borders) {
|
|
396
|
+
const normalized = documentTableBordersFromAttributes({
|
|
397
|
+
borders
|
|
398
|
+
}, borders.top);
|
|
399
|
+
const representative = uniformDocumentTableBorder(normalized) ?? normalized.top;
|
|
400
|
+
const attributes = {
|
|
401
|
+
'data-office-cell-border-color': representative.color,
|
|
402
|
+
'data-office-cell-border-style': representative.style,
|
|
403
|
+
'data-office-cell-border-width': String(representative.width)
|
|
404
|
+
};
|
|
405
|
+
for (const edge of BORDER_EDGES){
|
|
406
|
+
const border = normalized[edge];
|
|
407
|
+
attributes[`data-office-cell-border-${edge}-color`] = border.color;
|
|
408
|
+
attributes[`data-office-cell-border-${edge}-style`] = border.style;
|
|
409
|
+
attributes[`data-office-cell-border-${edge}-width`] = String(border.width);
|
|
410
|
+
}
|
|
411
|
+
const uniform = uniformDocumentTableBorder(normalized);
|
|
412
|
+
attributes.style = uniform ? `border: ${documentTableBorderCss(uniform)}` : BORDER_EDGES.map((edge)=>`border-${edge}: ${documentTableBorderCss(normalized[edge])}`).join('; ');
|
|
413
|
+
return attributes;
|
|
414
|
+
}
|
|
415
|
+
function uniformDocumentTableBorder(borders) {
|
|
416
|
+
const first = borders.top;
|
|
417
|
+
return BORDER_EDGES.every((edge)=>sameDocumentTableBorder(borders[edge], first)) ? first : null;
|
|
418
|
+
}
|
|
419
|
+
function normalizeDocumentTableBorder(value) {
|
|
420
|
+
if (!value || 'object' != typeof value || Array.isArray(value)) return null;
|
|
421
|
+
const record = value;
|
|
422
|
+
const color = normalizeTableColor(String(record.color ?? ''));
|
|
423
|
+
const style = normalizeDocumentTableBorderStyle(String(record.style ?? ''));
|
|
424
|
+
const width = normalizeDocumentTableBorderWidth(record.width);
|
|
425
|
+
if (!color || !style || null === width) return null;
|
|
426
|
+
return {
|
|
427
|
+
color,
|
|
428
|
+
style,
|
|
429
|
+
width: 'none' === style ? 0 : width
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function normalizeTableColor(value) {
|
|
433
|
+
const trimmed = value?.trim().toLowerCase();
|
|
434
|
+
if (!trimmed) return null;
|
|
435
|
+
if (/^#[0-9a-f]{3}$/.test(trimmed)) return `#${trimmed.slice(1).split('').map((part)=>`${part}${part}`).join('')}`;
|
|
436
|
+
if (/^#[0-9a-f]{6}$/.test(trimmed)) return trimmed;
|
|
437
|
+
const rgb = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/.exec(trimmed);
|
|
438
|
+
if (!rgb) return null;
|
|
439
|
+
const channels = rgb.slice(1, 4).map(Number);
|
|
440
|
+
if (channels.some((channel)=>channel < 0 || channel > 255)) return null;
|
|
441
|
+
return `#${channels.map((channel)=>channel.toString(16).padStart(2, '0')).join('')}`;
|
|
442
|
+
}
|
|
443
|
+
function normalizeDocumentTableBorderStyle(value) {
|
|
444
|
+
if ('solid' === value || 'dashed' === value || 'dotted' === value || 'double' === value || 'none' === value) return value;
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
function normalizeDocumentTableBorderWidth(value) {
|
|
448
|
+
const width = 'number' == typeof value ? value : Number.parseFloat(String(value ?? '').replace(/px$/i, ''));
|
|
449
|
+
if (!Number.isFinite(width) || width < 0 || width > 6) return null;
|
|
450
|
+
return Math.round(2 * width) / 2;
|
|
451
|
+
}
|
|
452
|
+
function setSelectedDocumentTableBorders({ dispatch, state }, target, requestedBorder) {
|
|
453
|
+
const border = normalizeDocumentTableBorder(requestedBorder);
|
|
454
|
+
const context = selectedTableBorderContext(state);
|
|
455
|
+
if (!border || !context) return false;
|
|
456
|
+
const transaction = state.tr;
|
|
457
|
+
const positions = context.map.cellsInRect(context.rectangle);
|
|
458
|
+
for (const relativePosition of positions){
|
|
459
|
+
const position = context.tableStart + relativePosition;
|
|
460
|
+
const cell = transaction.doc.nodeAt(position);
|
|
461
|
+
if (!cell || !isTableCell(cell)) continue;
|
|
462
|
+
const cellRectangle = context.map.findCell(relativePosition);
|
|
463
|
+
const edges = documentTableBorderTargetEdges(target, cellRectangle, context.rectangle);
|
|
464
|
+
if (!edges.length) continue;
|
|
465
|
+
const fallback = documentTableBorderFromAttributes(cell.attrs);
|
|
466
|
+
const borders = documentTableBordersFromAttributes(cell.attrs, fallback);
|
|
467
|
+
for (const edge of edges)borders[edge] = {
|
|
468
|
+
...border
|
|
469
|
+
};
|
|
470
|
+
const representative = uniformDocumentTableBorder(borders) ?? borders.top;
|
|
471
|
+
transaction.setNodeMarkup(position, void 0, {
|
|
472
|
+
...cell.attrs,
|
|
473
|
+
borderColor: representative.color,
|
|
474
|
+
borderStyle: representative.style,
|
|
475
|
+
borderWidth: representative.width,
|
|
476
|
+
borders
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
if (dispatch && transaction.docChanged) dispatch(transaction.scrollIntoView());
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
482
|
+
function selectedTableBorderContext(state) {
|
|
483
|
+
const selection = state.selection;
|
|
484
|
+
if (selection instanceof NodeSelection && 'table' === selection.node.type.spec.tableRole) {
|
|
485
|
+
const map = TableMap.get(selection.node);
|
|
486
|
+
return {
|
|
487
|
+
tableStart: selection.from + 1,
|
|
488
|
+
map,
|
|
489
|
+
rectangle: {
|
|
490
|
+
left: 0,
|
|
491
|
+
right: map.width,
|
|
492
|
+
top: 0,
|
|
493
|
+
bottom: map.height
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
if (!isInTable(state)) return null;
|
|
498
|
+
const rectangle = selectedRect(state);
|
|
499
|
+
return {
|
|
500
|
+
tableStart: rectangle.tableStart,
|
|
501
|
+
map: rectangle.map,
|
|
502
|
+
rectangle
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
function documentTableBorderTargetEdges(target, cell, selection) {
|
|
506
|
+
if ('all' === target) return [
|
|
507
|
+
...BORDER_EDGES
|
|
508
|
+
];
|
|
509
|
+
const edges = [];
|
|
510
|
+
const outside = 'outside' === target;
|
|
511
|
+
const inside = 'inside' === target;
|
|
512
|
+
if ('top' === target && cell.top === selection.top || outside && cell.top === selection.top || (inside || 'insideHorizontal' === target) && cell.top > selection.top) edges.push('top');
|
|
513
|
+
if ('right' === target && cell.right === selection.right || outside && cell.right === selection.right || (inside || 'insideVertical' === target) && cell.right < selection.right) edges.push('right');
|
|
514
|
+
if ('bottom' === target && cell.bottom === selection.bottom || outside && cell.bottom === selection.bottom || (inside || 'insideHorizontal' === target) && cell.bottom < selection.bottom) edges.push('bottom');
|
|
515
|
+
if ('left' === target && cell.left === selection.left || outside && cell.left === selection.left || (inside || 'insideVertical' === target) && cell.left > selection.left) edges.push('left');
|
|
516
|
+
return edges;
|
|
517
|
+
}
|
|
518
|
+
function documentTableBorderFromAttributes(attributes) {
|
|
519
|
+
return {
|
|
520
|
+
color: normalizeTableColor(String(attributes.borderColor ?? '')) ?? '#cfd5df',
|
|
521
|
+
style: normalizeDocumentTableBorderStyle(String(attributes.borderStyle ?? '')) ?? 'solid',
|
|
522
|
+
width: normalizeDocumentTableBorderWidth(attributes.borderWidth) ?? 1
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function documentTableBorderFromElement(element, fallback) {
|
|
526
|
+
const style = normalizeDocumentTableBorderStyle(element.dataset.officeCellBorderStyle || element.style.borderStyle) ?? fallback.style;
|
|
527
|
+
return {
|
|
528
|
+
color: normalizeTableColor(element.dataset.officeCellBorderColor || element.style.borderColor) ?? fallback.color,
|
|
529
|
+
style,
|
|
530
|
+
width: 'none' === style ? 0 : normalizeDocumentTableBorderWidth(element.dataset.officeCellBorderWidth || element.style.borderWidth) ?? fallback.width
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function documentTableEdgeFromElement(element, edge, fallback) {
|
|
534
|
+
const datasetPrefix = `officeCellBorder${capitalize(edge)}`;
|
|
535
|
+
const style = normalizeDocumentTableBorderStyle(element.dataset[`${datasetPrefix}Style`] || element.style.getPropertyValue(`border-${edge}-style`)) ?? fallback.style;
|
|
536
|
+
return {
|
|
537
|
+
color: normalizeTableColor(element.dataset[`${datasetPrefix}Color`] || element.style.getPropertyValue(`border-${edge}-color`)) ?? fallback.color,
|
|
538
|
+
style,
|
|
539
|
+
width: 'none' === style ? 0 : normalizeDocumentTableBorderWidth(element.dataset[`${datasetPrefix}Width`] || element.style.getPropertyValue(`border-${edge}-width`)) ?? fallback.width
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function documentTableBorderCss(border) {
|
|
543
|
+
return 'none' === border.style || 0 === border.width ? '0px none transparent' : `${border.width}px ${border.style} ${border.color}`;
|
|
544
|
+
}
|
|
545
|
+
function sameDocumentTableBorder(left, right) {
|
|
546
|
+
return left.color === right.color && left.style === right.style && left.width === right.width;
|
|
547
|
+
}
|
|
548
|
+
function isTableCell(node) {
|
|
549
|
+
return 'cell' === node.type.spec.tableRole || 'header_cell' === node.type.spec.tableRole;
|
|
550
|
+
}
|
|
551
|
+
function capitalize(value) {
|
|
552
|
+
return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
|
|
553
|
+
}
|
|
554
|
+
const MAX_TABLE_SIZE = 100000;
|
|
555
|
+
const MAX_CELL_MARGIN = 1000;
|
|
556
|
+
const TABLE_MARGIN_DATASET_KEYS = {
|
|
557
|
+
top: 'officeTableCellMarginTop',
|
|
558
|
+
right: 'officeTableCellMarginRight',
|
|
559
|
+
bottom: 'officeTableCellMarginBottom',
|
|
560
|
+
left: 'officeTableCellMarginLeft'
|
|
561
|
+
};
|
|
562
|
+
const CELL_MARGIN_DATASET_KEYS = {
|
|
563
|
+
top: 'officeCellMarginTop',
|
|
564
|
+
right: 'officeCellMarginRight',
|
|
565
|
+
bottom: 'officeCellMarginBottom',
|
|
566
|
+
left: 'officeCellMarginLeft'
|
|
567
|
+
};
|
|
568
|
+
const TABLE_MARGIN_CSS_PROPERTIES = {
|
|
569
|
+
top: '--work-table-cell-margin-top',
|
|
570
|
+
right: '--work-table-cell-margin-right',
|
|
571
|
+
bottom: '--work-table-cell-margin-bottom',
|
|
572
|
+
left: '--work-table-cell-margin-left'
|
|
573
|
+
};
|
|
574
|
+
const CELL_PADDING_STYLE_PROPERTIES = {
|
|
575
|
+
top: 'paddingTop',
|
|
576
|
+
right: 'paddingRight',
|
|
577
|
+
bottom: 'paddingBottom',
|
|
578
|
+
left: 'paddingLeft'
|
|
579
|
+
};
|
|
580
|
+
const DEFAULT_DOCUMENT_TABLE_CELL_MARGINS = {
|
|
581
|
+
top: 0,
|
|
582
|
+
right: 7.2,
|
|
583
|
+
bottom: 0,
|
|
584
|
+
left: 7.2
|
|
585
|
+
};
|
|
586
|
+
const DEFAULT_DOCUMENT_TABLE_GEOMETRY = {
|
|
587
|
+
layout: 'autofit',
|
|
588
|
+
width: {
|
|
589
|
+
type: 'percent',
|
|
590
|
+
value: 100
|
|
591
|
+
},
|
|
592
|
+
alignment: 'left',
|
|
593
|
+
indent: 0,
|
|
594
|
+
cellMargins: DEFAULT_DOCUMENT_TABLE_CELL_MARGINS
|
|
595
|
+
};
|
|
596
|
+
function normalizeDocumentTableGeometry(value, legacyLayoutMode) {
|
|
597
|
+
if (!work_document_table_geometry_isRecord(value)) return geometryForLegacyLayoutMode(legacyLayoutMode);
|
|
598
|
+
const layout = normalizeDocumentTableLayoutAlgorithm(value.layout);
|
|
599
|
+
const width = normalizeDocumentTablePreferredWidth(value.width);
|
|
600
|
+
const alignment = normalizeDocumentTableAlignment(value.alignment);
|
|
601
|
+
const indent = normalizeDimension(value.indent, MAX_TABLE_SIZE);
|
|
602
|
+
const cellMargins = normalizeDocumentTableCellMargins(value.cellMargins);
|
|
603
|
+
return {
|
|
604
|
+
layout: layout ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.layout,
|
|
605
|
+
width: width ?? clonePreferredWidth(DEFAULT_DOCUMENT_TABLE_GEOMETRY.width),
|
|
606
|
+
alignment: alignment ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.alignment,
|
|
607
|
+
indent: indent ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.indent,
|
|
608
|
+
cellMargins: cellMargins ?? cloneCellMargins(DEFAULT_DOCUMENT_TABLE_CELL_MARGINS)
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
function normalizeDocumentTableLayoutMode(value) {
|
|
612
|
+
return 'contents' === value || 'fixed' === value ? value : 'window';
|
|
613
|
+
}
|
|
614
|
+
function normalizeDocumentTableLayoutAlgorithm(value) {
|
|
615
|
+
return 'autofit' === value || 'fixed' === value ? value : null;
|
|
616
|
+
}
|
|
617
|
+
function normalizeDocumentTableAlignment(value) {
|
|
618
|
+
return 'center' === value || 'right' === value || 'left' === value ? value : null;
|
|
619
|
+
}
|
|
620
|
+
function normalizeDocumentTableProperties(value) {
|
|
621
|
+
if (!work_document_table_geometry_isRecord(value)) return null;
|
|
622
|
+
const width = normalizeDocumentTablePreferredWidth(value.width);
|
|
623
|
+
const alignment = normalizeDocumentTableAlignment(value.alignment);
|
|
624
|
+
const indent = normalizeDimension(value.indent, MAX_TABLE_SIZE);
|
|
625
|
+
return width && alignment && null !== indent ? {
|
|
626
|
+
width,
|
|
627
|
+
alignment,
|
|
628
|
+
indent
|
|
629
|
+
} : null;
|
|
630
|
+
}
|
|
631
|
+
function normalizeDocumentTableCellMargins(value) {
|
|
632
|
+
if (!work_document_table_geometry_isRecord(value)) return null;
|
|
633
|
+
const margins = normalizeDocumentTableCellMarginOverrides(value);
|
|
634
|
+
if (!margins || !hasAllMarginSides(margins)) return null;
|
|
635
|
+
return margins;
|
|
636
|
+
}
|
|
637
|
+
function normalizeDocumentTableCellMarginOverrides(value) {
|
|
638
|
+
if (!work_document_table_geometry_isRecord(value)) return null;
|
|
639
|
+
const margins = {};
|
|
640
|
+
for (const side of marginSides()){
|
|
641
|
+
const normalized = normalizeDimension(value[side], MAX_CELL_MARGIN);
|
|
642
|
+
if (null !== normalized) margins[side] = normalized;
|
|
643
|
+
}
|
|
644
|
+
return Object.keys(margins).length ? margins : null;
|
|
645
|
+
}
|
|
646
|
+
function documentTableLayoutMode(geometry) {
|
|
647
|
+
if ('autofit' === geometry.layout && 'auto' === geometry.width.type) return 'contents';
|
|
648
|
+
if ('autofit' === geometry.layout && 'percent' === geometry.width.type && 100 === geometry.width.value) return 'window';
|
|
649
|
+
return 'fixed';
|
|
650
|
+
}
|
|
651
|
+
function documentTableGeometryForLayoutMode(mode, current, renderedTableWidth) {
|
|
652
|
+
if ('contents' === mode) return {
|
|
653
|
+
...current,
|
|
654
|
+
layout: 'autofit',
|
|
655
|
+
width: {
|
|
656
|
+
type: 'auto',
|
|
657
|
+
value: null
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
if ('window' === mode) return {
|
|
661
|
+
...current,
|
|
662
|
+
layout: 'autofit',
|
|
663
|
+
width: {
|
|
664
|
+
type: 'percent',
|
|
665
|
+
value: 100
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
const rendered = normalizePositiveDimension(renderedTableWidth, MAX_TABLE_SIZE);
|
|
669
|
+
return {
|
|
670
|
+
...current,
|
|
671
|
+
layout: 'fixed',
|
|
672
|
+
width: rendered ? {
|
|
673
|
+
type: 'pixels',
|
|
674
|
+
value: rendered
|
|
675
|
+
} : 'pixels' === current.width.type ? clonePreferredWidth(current.width) : {
|
|
676
|
+
type: 'auto',
|
|
677
|
+
value: null
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
function documentTableGeometryFromElement(table) {
|
|
682
|
+
const rawLayout = table.dataset.officeTableLayout;
|
|
683
|
+
const exactLayout = normalizeDocumentTableLayoutAlgorithm(rawLayout);
|
|
684
|
+
const legacyMode = 'window' === rawLayout || 'contents' === rawLayout || 'fixed' === rawLayout ? rawLayout : void 0;
|
|
685
|
+
const width = preferredWidthFromElement(table, legacyMode);
|
|
686
|
+
const margins = tableCellMarginsFromElement(table);
|
|
687
|
+
const alignment = normalizeDocumentTableAlignment(table.dataset.officeTableAlignment);
|
|
688
|
+
const indent = normalizeDimension(table.dataset.officeTableIndent, MAX_TABLE_SIZE);
|
|
689
|
+
const hasGeometryAttributes = Boolean(rawLayout || table.dataset.officeTableWidthType || table.dataset.officeTableWidth || table.dataset.officeTableAlignment || table.dataset.officeTableIndent || margins);
|
|
690
|
+
if (!hasGeometryAttributes) return cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY);
|
|
691
|
+
return {
|
|
692
|
+
layout: exactLayout ?? ('fixed' === legacyMode ? 'fixed' : 'autofit'),
|
|
693
|
+
width,
|
|
694
|
+
alignment: alignment ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.alignment,
|
|
695
|
+
indent: indent ?? DEFAULT_DOCUMENT_TABLE_GEOMETRY.indent,
|
|
696
|
+
cellMargins: margins ?? cloneCellMargins(DEFAULT_DOCUMENT_TABLE_CELL_MARGINS)
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
function renderDocumentTableGeometry(value, legacyLayoutMode) {
|
|
700
|
+
const geometry = normalizeDocumentTableGeometry(value, legacyLayoutMode);
|
|
701
|
+
return {
|
|
702
|
+
'data-office-table-layout': geometry.layout,
|
|
703
|
+
'data-office-table-width-type': geometry.width.type,
|
|
704
|
+
...null === geometry.width.value ? {} : {
|
|
705
|
+
'data-office-table-width': formatNumber(geometry.width.value)
|
|
706
|
+
},
|
|
707
|
+
'data-office-table-alignment': geometry.alignment,
|
|
708
|
+
'data-office-table-indent': formatNumber(geometry.indent),
|
|
709
|
+
'data-office-table-cell-margin-top': formatNumber(geometry.cellMargins.top),
|
|
710
|
+
'data-office-table-cell-margin-right': formatNumber(geometry.cellMargins.right),
|
|
711
|
+
'data-office-table-cell-margin-bottom': formatNumber(geometry.cellMargins.bottom),
|
|
712
|
+
'data-office-table-cell-margin-left': formatNumber(geometry.cellMargins.left),
|
|
713
|
+
style: documentTableGeometryStyle(geometry)
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
function applyDocumentTableGeometryToElement(table, value, legacyLayoutMode) {
|
|
717
|
+
const geometry = normalizeDocumentTableGeometry(value, legacyLayoutMode);
|
|
718
|
+
const rendered = renderDocumentTableGeometry(geometry);
|
|
719
|
+
for (const attributeName of tableGeometryAttributeNames())table.removeAttribute(attributeName);
|
|
720
|
+
for (const [name, attributeValue] of Object.entries(rendered))if ('style' !== name) table.setAttribute(name, attributeValue);
|
|
721
|
+
table.style.removeProperty('table-layout');
|
|
722
|
+
table.style.removeProperty('width');
|
|
723
|
+
table.style.removeProperty('margin-left');
|
|
724
|
+
table.style.removeProperty('margin-right');
|
|
725
|
+
for (const property of Object.values(TABLE_MARGIN_CSS_PROPERTIES))table.style.removeProperty(property);
|
|
726
|
+
for (const declaration of rendered.style.split(';').map((part)=>part.trim()).filter(Boolean)){
|
|
727
|
+
const separator = declaration.indexOf(':');
|
|
728
|
+
if (!(separator < 0)) table.style.setProperty(declaration.slice(0, separator).trim(), declaration.slice(separator + 1).trim());
|
|
729
|
+
}
|
|
730
|
+
if ('auto' !== geometry.width.type) table.style.removeProperty('min-width');
|
|
731
|
+
}
|
|
732
|
+
function documentTableCellMarginOverridesFromElement(cell) {
|
|
733
|
+
const margins = {};
|
|
734
|
+
for (const side of marginSides()){
|
|
735
|
+
const datasetValue = cell.dataset[CELL_MARGIN_DATASET_KEYS[side]];
|
|
736
|
+
const styleValue = cell.style[CELL_PADDING_STYLE_PROPERTIES[side]];
|
|
737
|
+
const normalized = normalizeDimension(datasetValue, MAX_CELL_MARGIN) ?? cssPixels(styleValue);
|
|
738
|
+
if (null !== normalized) margins[side] = normalized;
|
|
739
|
+
}
|
|
740
|
+
return Object.keys(margins).length ? margins : null;
|
|
741
|
+
}
|
|
742
|
+
function renderDocumentTableCellMarginOverrides(value) {
|
|
743
|
+
const margins = normalizeDocumentTableCellMarginOverrides(value);
|
|
744
|
+
if (!margins) return {};
|
|
745
|
+
const attributes = {};
|
|
746
|
+
const styles = [];
|
|
747
|
+
for (const side of marginSides()){
|
|
748
|
+
const margin = margins[side];
|
|
749
|
+
if (void 0 !== margin) {
|
|
750
|
+
attributes[`data-office-cell-margin-${side}`] = formatNumber(margin);
|
|
751
|
+
styles.push(`padding-${side}: ${formatNumber(margin)}px`);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
...attributes,
|
|
756
|
+
style: styles.join('; ')
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
function preferredWidthFromElement(table, legacyMode) {
|
|
760
|
+
const type = normalizePreferredWidthType(table.dataset.officeTableWidthType);
|
|
761
|
+
const value = normalizePositiveDimension(table.dataset.officeTableWidth, MAX_TABLE_SIZE);
|
|
762
|
+
if ('auto' === type) return {
|
|
763
|
+
type,
|
|
764
|
+
value: null
|
|
765
|
+
};
|
|
766
|
+
if (type && null !== value) return {
|
|
767
|
+
type,
|
|
768
|
+
value
|
|
769
|
+
};
|
|
770
|
+
const styleWidth = cssPreferredWidth(table.style.width);
|
|
771
|
+
if (styleWidth) return styleWidth;
|
|
772
|
+
if ('contents' === legacyMode) return {
|
|
773
|
+
type: 'auto',
|
|
774
|
+
value: null
|
|
775
|
+
};
|
|
776
|
+
if ('fixed' === legacyMode) {
|
|
777
|
+
const columnWidth = firstRowColumnWidth(table);
|
|
778
|
+
return null === columnWidth ? {
|
|
779
|
+
type: 'auto',
|
|
780
|
+
value: null
|
|
781
|
+
} : {
|
|
782
|
+
type: 'pixels',
|
|
783
|
+
value: columnWidth
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
return clonePreferredWidth(DEFAULT_DOCUMENT_TABLE_GEOMETRY.width);
|
|
787
|
+
}
|
|
788
|
+
function tableCellMarginsFromElement(table) {
|
|
789
|
+
const margins = {};
|
|
790
|
+
for (const side of marginSides()){
|
|
791
|
+
const datasetValue = table.dataset[TABLE_MARGIN_DATASET_KEYS[side]];
|
|
792
|
+
const cssValue = table.style.getPropertyValue(TABLE_MARGIN_CSS_PROPERTIES[side]);
|
|
793
|
+
const normalized = normalizeDimension(datasetValue, MAX_CELL_MARGIN) ?? cssPixels(cssValue);
|
|
794
|
+
if (null !== normalized) margins[side] = normalized;
|
|
795
|
+
}
|
|
796
|
+
return hasAllMarginSides(margins) ? margins : null;
|
|
797
|
+
}
|
|
798
|
+
function documentTableGeometryStyle(geometry) {
|
|
799
|
+
const styles = [
|
|
800
|
+
`table-layout: ${'fixed' === geometry.layout ? 'fixed' : 'auto'}`
|
|
801
|
+
];
|
|
802
|
+
if ('percent' === geometry.width.type && null !== geometry.width.value) styles.push(`width: ${formatNumber(geometry.width.value)}%`);
|
|
803
|
+
else if ('pixels' === geometry.width.type && null !== geometry.width.value) styles.push(`width: ${formatNumber(geometry.width.value)}px`);
|
|
804
|
+
if ('center' === geometry.alignment) styles.push('margin-left: auto', 'margin-right: auto');
|
|
805
|
+
else if ('right' === geometry.alignment) styles.push('margin-left: auto', 'margin-right: 0px');
|
|
806
|
+
else styles.push(`margin-left: ${formatNumber(geometry.indent)}px`, 'margin-right: auto');
|
|
807
|
+
for (const side of marginSides())styles.push(`${TABLE_MARGIN_CSS_PROPERTIES[side]}: ${formatNumber(geometry.cellMargins[side])}px`);
|
|
808
|
+
return styles.join('; ');
|
|
809
|
+
}
|
|
810
|
+
function geometryForLegacyLayoutMode(value) {
|
|
811
|
+
const mode = normalizeDocumentTableLayoutMode(value);
|
|
812
|
+
if ('contents' === mode) return {
|
|
813
|
+
...cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY),
|
|
814
|
+
width: {
|
|
815
|
+
type: 'auto',
|
|
816
|
+
value: null
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
if ('fixed' === mode) return {
|
|
820
|
+
...cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY),
|
|
821
|
+
layout: 'fixed',
|
|
822
|
+
width: {
|
|
823
|
+
type: 'auto',
|
|
824
|
+
value: null
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
return cloneGeometry(DEFAULT_DOCUMENT_TABLE_GEOMETRY);
|
|
828
|
+
}
|
|
829
|
+
function normalizeDocumentTablePreferredWidth(value) {
|
|
830
|
+
if (!work_document_table_geometry_isRecord(value)) return null;
|
|
831
|
+
const type = normalizePreferredWidthType(value.type);
|
|
832
|
+
if (!type) return null;
|
|
833
|
+
if ('auto' === type) return {
|
|
834
|
+
type,
|
|
835
|
+
value: null
|
|
836
|
+
};
|
|
837
|
+
const width = normalizePositiveDimension(value.value, MAX_TABLE_SIZE);
|
|
838
|
+
return null === width ? null : {
|
|
839
|
+
type,
|
|
840
|
+
value: width
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
function normalizePreferredWidthType(value) {
|
|
844
|
+
return 'auto' === value || 'percent' === value || 'pixels' === value ? value : null;
|
|
845
|
+
}
|
|
846
|
+
function normalizeDimension(value, maximum) {
|
|
847
|
+
const numeric = 'number' == typeof value ? value : 'string' == typeof value && value.trim() ? Number(value) : NaN;
|
|
848
|
+
if (!Number.isFinite(numeric) || numeric < 0 || numeric > maximum) return null;
|
|
849
|
+
return Math.round(100 * numeric) / 100;
|
|
850
|
+
}
|
|
851
|
+
function normalizePositiveDimension(value, maximum) {
|
|
852
|
+
const normalized = normalizeDimension(value, maximum);
|
|
853
|
+
return null !== normalized && normalized > 0 ? normalized : null;
|
|
854
|
+
}
|
|
855
|
+
function cssPixels(value) {
|
|
856
|
+
const match = /^(-?\d+(?:\.\d+)?)px$/i.exec(value.trim());
|
|
857
|
+
return match ? normalizeDimension(match[1], MAX_CELL_MARGIN) : null;
|
|
858
|
+
}
|
|
859
|
+
function cssPreferredWidth(value) {
|
|
860
|
+
const normalized = value.trim();
|
|
861
|
+
const percentage = /^(\d+(?:\.\d+)?)%$/.exec(normalized);
|
|
862
|
+
if (percentage) {
|
|
863
|
+
const width = normalizePositiveDimension(percentage[1], MAX_TABLE_SIZE);
|
|
864
|
+
return null === width ? null : {
|
|
865
|
+
type: 'percent',
|
|
866
|
+
value: width
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
const pixels = /^(\d+(?:\.\d+)?)px$/.exec(normalized);
|
|
870
|
+
if (pixels) {
|
|
871
|
+
const width = normalizePositiveDimension(pixels[1], MAX_TABLE_SIZE);
|
|
872
|
+
return null === width ? null : {
|
|
873
|
+
type: 'pixels',
|
|
874
|
+
value: width
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
return 'auto' === normalized ? {
|
|
878
|
+
type: 'auto',
|
|
879
|
+
value: null
|
|
880
|
+
} : null;
|
|
881
|
+
}
|
|
882
|
+
function firstRowColumnWidth(table) {
|
|
883
|
+
const row = table.querySelector('tr');
|
|
884
|
+
if (!row) return null;
|
|
885
|
+
let total = 0;
|
|
886
|
+
for (const cell of Array.from(row.querySelectorAll(':scope > th, :scope > td'))){
|
|
887
|
+
const raw = cell.getAttribute('colwidth');
|
|
888
|
+
if (!raw) return null;
|
|
889
|
+
const widths = raw.split(',').map((part)=>normalizePositiveDimension(part, MAX_TABLE_SIZE));
|
|
890
|
+
if (!widths.length || widths.some((width)=>null === width)) return null;
|
|
891
|
+
total += widths.reduce((sum, width)=>sum + Number(width), 0);
|
|
892
|
+
}
|
|
893
|
+
return total > 0 ? Math.round(100 * total) / 100 : null;
|
|
894
|
+
}
|
|
895
|
+
function tableGeometryAttributeNames() {
|
|
896
|
+
return [
|
|
897
|
+
'data-office-table-layout',
|
|
898
|
+
'data-office-table-width-type',
|
|
899
|
+
'data-office-table-width',
|
|
900
|
+
'data-office-table-alignment',
|
|
901
|
+
'data-office-table-indent',
|
|
902
|
+
...marginSides().map((side)=>`data-office-table-cell-margin-${side}`)
|
|
903
|
+
];
|
|
904
|
+
}
|
|
905
|
+
function marginSides() {
|
|
906
|
+
return [
|
|
907
|
+
'top',
|
|
908
|
+
'right',
|
|
909
|
+
'bottom',
|
|
910
|
+
'left'
|
|
911
|
+
];
|
|
912
|
+
}
|
|
913
|
+
function hasAllMarginSides(value) {
|
|
914
|
+
return marginSides().every((side)=>void 0 !== value[side]);
|
|
915
|
+
}
|
|
916
|
+
function cloneGeometry(value) {
|
|
917
|
+
return {
|
|
918
|
+
...value,
|
|
919
|
+
width: clonePreferredWidth(value.width),
|
|
920
|
+
cellMargins: cloneCellMargins(value.cellMargins)
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
function clonePreferredWidth(value) {
|
|
924
|
+
return {
|
|
925
|
+
...value
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
function cloneCellMargins(value) {
|
|
929
|
+
return {
|
|
930
|
+
...value
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function formatNumber(value) {
|
|
934
|
+
return String(Math.round(100 * value) / 100);
|
|
935
|
+
}
|
|
936
|
+
function work_document_table_geometry_isRecord(value) {
|
|
937
|
+
return 'object' == typeof value && null !== value && !Array.isArray(value);
|
|
938
|
+
}
|
|
939
|
+
export { DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DEFAULT_DOCUMENT_TABLE_GEOMETRY, DocumentImage, DocumentParagraphTabStops, applyDocumentTableGeometryToElement, documentImageLayoutFromElement, documentImageLayoutOptions, documentImageProperties, documentParagraphTabStops, documentTableBordersFromAttributes, documentTableBordersFromElement, documentTableCellMarginOverridesFromElement, documentTableGeometryForLayoutMode, documentTableGeometryFromElement, documentTableLayoutMode, nextDocumentTabAlignment, normalizeDocumentImageAlignment, normalizeDocumentImageLayoutOptions, normalizeDocumentTabStops, normalizeDocumentTableAlignment, normalizeDocumentTableBorderStyle, normalizeDocumentTableBorderWidth, normalizeDocumentTableCellMarginOverrides, normalizeDocumentTableCellMargins, normalizeDocumentTableGeometry, normalizeDocumentTableProperties, normalizeTableColor, normalizedTabPosition, renderDocumentTableBorders, renderDocumentTableCellMarginOverrides, renderDocumentTableGeometry, serializeDocumentTabStops, setSelectedDocumentTableBorders, uniformDocumentTableBorder, uniformDocumentTableBorders };
|