js.documents 12.0.0 → 13.0.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/dist/edit/odf-repeated-runs.cjs +99 -0
- package/dist/edit/odf-repeated-runs.d.cts +22 -0
- package/dist/edit/odf-repeated-runs.d.ts +22 -0
- package/dist/edit/odf-repeated-runs.js +87 -0
- package/dist/edit/ods/address.cjs +9 -101
- package/dist/edit/ods/address.d.cts +2 -18
- package/dist/edit/ods/address.d.ts +2 -18
- package/dist/edit/ods/address.js +4 -86
- package/dist/edit/ods/column-row.cjs +7 -6
- package/dist/edit/ods/column-row.js +2 -1
- package/dist/edit/ods/floating.cjs +5 -4
- package/dist/edit/ods/floating.js +2 -1
- package/dist/edit/ods/print-settings.cjs +8 -7
- package/dist/edit/ods/print-settings.js +2 -1
- package/dist/edit/ods/sheet.cjs +2 -1
- package/dist/edit/ods/sheet.js +2 -1
- package/dist/edit/odt/table.cjs +56 -17
- package/dist/edit/odt/table.js +56 -17
- package/dist/edit/pptx/content.cjs +1 -0
- package/dist/edit/pptx/content.js +1 -0
- package/dist/edit/pptx/slide.d.cts +1 -1
- package/dist/edit/pptx/slide.d.ts +1 -1
- package/dist/edit/pptx/table.cjs +25 -0
- package/dist/edit/pptx/table.d.cts +1 -1
- package/dist/edit/pptx/table.d.ts +1 -1
- package/dist/edit/pptx/table.js +25 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/{table-D2CgT0Gf.d.ts → table-BuNLtwgL.d.ts} +3 -1
- package/dist/{table-CtbzOK8s.d.cts → table-ukpjK2hS.d.cts} +3 -1
- package/package.json +2 -2
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/edit/odf-repeated-runs.ts
|
|
3
|
+
const ROW_TAG = "table:table-row";
|
|
4
|
+
const CELL_TAG = "table:table-cell";
|
|
5
|
+
const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
6
|
+
const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
7
|
+
const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
8
|
+
function isElementWithTag(tag) {
|
|
9
|
+
return (node) => node.type === "element" && node.tag === tag;
|
|
10
|
+
}
|
|
11
|
+
function isCellOrCoveredCell(node) {
|
|
12
|
+
return node.type === "element" && (node.tag === "table:table-cell" || node.tag === "table:covered-table-cell");
|
|
13
|
+
}
|
|
14
|
+
function validateIndex(value, label) {
|
|
15
|
+
if (!Number.isInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer, got ${value}`);
|
|
16
|
+
}
|
|
17
|
+
function readRunRepeatCount(node, attrName) {
|
|
18
|
+
const raw = node.attributes.find((attribute) => attribute.name === attrName)?.value;
|
|
19
|
+
if (raw === void 0) return 1;
|
|
20
|
+
const parsed = Number.parseInt(raw, 10);
|
|
21
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
22
|
+
}
|
|
23
|
+
function collectRunMembers(children, isMember, headerWrapperTag) {
|
|
24
|
+
const members = [];
|
|
25
|
+
children.forEach((node, outerPosition) => {
|
|
26
|
+
if (node.type !== "element") return;
|
|
27
|
+
if (headerWrapperTag !== void 0 && node.tag === headerWrapperTag) {
|
|
28
|
+
node.children.forEach((inner, innerPosition) => {
|
|
29
|
+
if (isMember(inner)) members.push({
|
|
30
|
+
node: inner,
|
|
31
|
+
container: node.children,
|
|
32
|
+
containerPosition: innerPosition,
|
|
33
|
+
outerPosition
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (isMember(node)) members.push({
|
|
39
|
+
node,
|
|
40
|
+
container: children,
|
|
41
|
+
containerPosition: outerPosition,
|
|
42
|
+
outerPosition
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
return members;
|
|
46
|
+
}
|
|
47
|
+
function withRepeatCount(node, attrName, count) {
|
|
48
|
+
const clone = structuredClone(node);
|
|
49
|
+
clone.attributes = clone.attributes.filter((attribute) => attribute.name !== attrName);
|
|
50
|
+
if (count > 1) clone.attributes.push({
|
|
51
|
+
name: attrName,
|
|
52
|
+
value: String(count)
|
|
53
|
+
});
|
|
54
|
+
return clone;
|
|
55
|
+
}
|
|
56
|
+
function replaceRun(children, isMember, targetIndex, repeatAttr, buildEmpty, headerWrapperTag) {
|
|
57
|
+
validateIndex(targetIndex, "targetIndex");
|
|
58
|
+
const members = collectRunMembers(children, isMember, headerWrapperTag);
|
|
59
|
+
let cursor = 0;
|
|
60
|
+
for (const member of members) {
|
|
61
|
+
const count = readRunRepeatCount(member.node, repeatAttr);
|
|
62
|
+
if (targetIndex < cursor + count) {
|
|
63
|
+
const offset = targetIndex - cursor;
|
|
64
|
+
if (count === 1) return member.node;
|
|
65
|
+
const before = offset > 0 ? withRepeatCount(member.node, repeatAttr, offset) : void 0;
|
|
66
|
+
const target = withRepeatCount(member.node, repeatAttr, 1);
|
|
67
|
+
const replacement = [
|
|
68
|
+
before,
|
|
69
|
+
target,
|
|
70
|
+
count - offset - 1 > 0 ? withRepeatCount(member.node, repeatAttr, count - offset - 1) : void 0
|
|
71
|
+
].filter((candidate) => candidate !== void 0);
|
|
72
|
+
member.container.splice(member.containerPosition, 1, ...replacement);
|
|
73
|
+
return target;
|
|
74
|
+
}
|
|
75
|
+
cursor += count;
|
|
76
|
+
}
|
|
77
|
+
const gap = targetIndex - cursor;
|
|
78
|
+
const lastMember = members[members.length - 1];
|
|
79
|
+
const insertAt = lastMember === void 0 ? children.length : lastMember.outerPosition + 1;
|
|
80
|
+
const toInsert = [];
|
|
81
|
+
if (gap > 0) toInsert.push(withRepeatCount(buildEmpty(), repeatAttr, gap));
|
|
82
|
+
const target = buildEmpty();
|
|
83
|
+
toInsert.push(target);
|
|
84
|
+
children.splice(insertAt, 0, ...toInsert);
|
|
85
|
+
return target;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
exports.CELL_TAG = CELL_TAG;
|
|
89
|
+
exports.COLUMN_REPEAT_ATTR = COLUMN_REPEAT_ATTR;
|
|
90
|
+
exports.COVERED_CELL_TAG = COVERED_CELL_TAG;
|
|
91
|
+
exports.ROW_REPEAT_ATTR = ROW_REPEAT_ATTR;
|
|
92
|
+
exports.ROW_TAG = ROW_TAG;
|
|
93
|
+
exports.collectRunMembers = collectRunMembers;
|
|
94
|
+
exports.isCellOrCoveredCell = isCellOrCoveredCell;
|
|
95
|
+
exports.isElementWithTag = isElementWithTag;
|
|
96
|
+
exports.readRunRepeatCount = readRunRepeatCount;
|
|
97
|
+
exports.replaceRun = replaceRun;
|
|
98
|
+
exports.validateIndex = validateIndex;
|
|
99
|
+
exports.withRepeatCount = withRepeatCount;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { XmlElement, XmlNode } from "odf.js";
|
|
2
|
+
//#region src/edit/odf-repeated-runs.d.ts
|
|
3
|
+
declare const ROW_TAG = "table:table-row";
|
|
4
|
+
declare const CELL_TAG = "table:table-cell";
|
|
5
|
+
declare const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
6
|
+
declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
7
|
+
declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
8
|
+
declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
|
|
9
|
+
declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
|
|
10
|
+
declare function validateIndex(value: number, label: string): void;
|
|
11
|
+
declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
|
|
12
|
+
interface RunMember {
|
|
13
|
+
readonly node: XmlElement;
|
|
14
|
+
readonly container: XmlNode[];
|
|
15
|
+
readonly containerPosition: number;
|
|
16
|
+
readonly outerPosition: number;
|
|
17
|
+
}
|
|
18
|
+
declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
|
|
19
|
+
declare function withRepeatCount(node: XmlElement, attrName: string, count: number): XmlElement;
|
|
20
|
+
declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { CELL_TAG, COLUMN_REPEAT_ATTR, COVERED_CELL_TAG, ROW_REPEAT_ATTR, ROW_TAG, RunMember, collectRunMembers, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, validateIndex, withRepeatCount };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { XmlElement, XmlNode } from "odf.js";
|
|
2
|
+
//#region src/edit/odf-repeated-runs.d.ts
|
|
3
|
+
declare const ROW_TAG = "table:table-row";
|
|
4
|
+
declare const CELL_TAG = "table:table-cell";
|
|
5
|
+
declare const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
6
|
+
declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
7
|
+
declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
8
|
+
declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
|
|
9
|
+
declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
|
|
10
|
+
declare function validateIndex(value: number, label: string): void;
|
|
11
|
+
declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
|
|
12
|
+
interface RunMember {
|
|
13
|
+
readonly node: XmlElement;
|
|
14
|
+
readonly container: XmlNode[];
|
|
15
|
+
readonly containerPosition: number;
|
|
16
|
+
readonly outerPosition: number;
|
|
17
|
+
}
|
|
18
|
+
declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
|
|
19
|
+
declare function withRepeatCount(node: XmlElement, attrName: string, count: number): XmlElement;
|
|
20
|
+
declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { CELL_TAG, COLUMN_REPEAT_ATTR, COVERED_CELL_TAG, ROW_REPEAT_ATTR, ROW_TAG, RunMember, collectRunMembers, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, validateIndex, withRepeatCount };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
//#region src/edit/odf-repeated-runs.ts
|
|
2
|
+
const ROW_TAG = "table:table-row";
|
|
3
|
+
const CELL_TAG = "table:table-cell";
|
|
4
|
+
const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
5
|
+
const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
6
|
+
const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
7
|
+
function isElementWithTag(tag) {
|
|
8
|
+
return (node) => node.type === "element" && node.tag === tag;
|
|
9
|
+
}
|
|
10
|
+
function isCellOrCoveredCell(node) {
|
|
11
|
+
return node.type === "element" && (node.tag === "table:table-cell" || node.tag === "table:covered-table-cell");
|
|
12
|
+
}
|
|
13
|
+
function validateIndex(value, label) {
|
|
14
|
+
if (!Number.isInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer, got ${value}`);
|
|
15
|
+
}
|
|
16
|
+
function readRunRepeatCount(node, attrName) {
|
|
17
|
+
const raw = node.attributes.find((attribute) => attribute.name === attrName)?.value;
|
|
18
|
+
if (raw === void 0) return 1;
|
|
19
|
+
const parsed = Number.parseInt(raw, 10);
|
|
20
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
21
|
+
}
|
|
22
|
+
function collectRunMembers(children, isMember, headerWrapperTag) {
|
|
23
|
+
const members = [];
|
|
24
|
+
children.forEach((node, outerPosition) => {
|
|
25
|
+
if (node.type !== "element") return;
|
|
26
|
+
if (headerWrapperTag !== void 0 && node.tag === headerWrapperTag) {
|
|
27
|
+
node.children.forEach((inner, innerPosition) => {
|
|
28
|
+
if (isMember(inner)) members.push({
|
|
29
|
+
node: inner,
|
|
30
|
+
container: node.children,
|
|
31
|
+
containerPosition: innerPosition,
|
|
32
|
+
outerPosition
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (isMember(node)) members.push({
|
|
38
|
+
node,
|
|
39
|
+
container: children,
|
|
40
|
+
containerPosition: outerPosition,
|
|
41
|
+
outerPosition
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return members;
|
|
45
|
+
}
|
|
46
|
+
function withRepeatCount(node, attrName, count) {
|
|
47
|
+
const clone = structuredClone(node);
|
|
48
|
+
clone.attributes = clone.attributes.filter((attribute) => attribute.name !== attrName);
|
|
49
|
+
if (count > 1) clone.attributes.push({
|
|
50
|
+
name: attrName,
|
|
51
|
+
value: String(count)
|
|
52
|
+
});
|
|
53
|
+
return clone;
|
|
54
|
+
}
|
|
55
|
+
function replaceRun(children, isMember, targetIndex, repeatAttr, buildEmpty, headerWrapperTag) {
|
|
56
|
+
validateIndex(targetIndex, "targetIndex");
|
|
57
|
+
const members = collectRunMembers(children, isMember, headerWrapperTag);
|
|
58
|
+
let cursor = 0;
|
|
59
|
+
for (const member of members) {
|
|
60
|
+
const count = readRunRepeatCount(member.node, repeatAttr);
|
|
61
|
+
if (targetIndex < cursor + count) {
|
|
62
|
+
const offset = targetIndex - cursor;
|
|
63
|
+
if (count === 1) return member.node;
|
|
64
|
+
const before = offset > 0 ? withRepeatCount(member.node, repeatAttr, offset) : void 0;
|
|
65
|
+
const target = withRepeatCount(member.node, repeatAttr, 1);
|
|
66
|
+
const replacement = [
|
|
67
|
+
before,
|
|
68
|
+
target,
|
|
69
|
+
count - offset - 1 > 0 ? withRepeatCount(member.node, repeatAttr, count - offset - 1) : void 0
|
|
70
|
+
].filter((candidate) => candidate !== void 0);
|
|
71
|
+
member.container.splice(member.containerPosition, 1, ...replacement);
|
|
72
|
+
return target;
|
|
73
|
+
}
|
|
74
|
+
cursor += count;
|
|
75
|
+
}
|
|
76
|
+
const gap = targetIndex - cursor;
|
|
77
|
+
const lastMember = members[members.length - 1];
|
|
78
|
+
const insertAt = lastMember === void 0 ? children.length : lastMember.outerPosition + 1;
|
|
79
|
+
const toInsert = [];
|
|
80
|
+
if (gap > 0) toInsert.push(withRepeatCount(buildEmpty(), repeatAttr, gap));
|
|
81
|
+
const target = buildEmpty();
|
|
82
|
+
toInsert.push(target);
|
|
83
|
+
children.splice(insertAt, 0, ...toInsert);
|
|
84
|
+
return target;
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
export { CELL_TAG, COLUMN_REPEAT_ATTR, COVERED_CELL_TAG, ROW_REPEAT_ATTR, ROW_TAG, collectRunMembers, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, validateIndex, withRepeatCount };
|
|
@@ -1,126 +1,34 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_xml_fragment = require("../../xml/fragment.cjs");
|
|
3
|
+
const require_edit_odf_repeated_runs = require("../odf-repeated-runs.cjs");
|
|
3
4
|
//#region src/edit/ods/address.ts
|
|
4
|
-
const ROW_TAG = "table:table-row";
|
|
5
5
|
const COLUMN_TAG = "table:table-column";
|
|
6
|
-
const CELL_TAG = "table:table-cell";
|
|
7
|
-
const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
8
|
-
const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
9
|
-
const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
10
6
|
const HEADER_ROWS_TAG = "table:table-header-rows";
|
|
11
7
|
const HEADER_COLUMNS_TAG = "table:table-header-columns";
|
|
12
|
-
function isElementWithTag(tag) {
|
|
13
|
-
return (node) => node.type === "element" && node.tag === tag;
|
|
14
|
-
}
|
|
15
|
-
function isCellOrCoveredCell(node) {
|
|
16
|
-
return node.type === "element" && (node.tag === "table:table-cell" || node.tag === "table:covered-table-cell");
|
|
17
|
-
}
|
|
18
|
-
function validateIndex(value, label) {
|
|
19
|
-
if (!Number.isInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer, got ${value}`);
|
|
20
|
-
}
|
|
21
|
-
function readRunRepeatCount(node, attrName) {
|
|
22
|
-
const raw = node.attributes.find((attribute) => attribute.name === attrName)?.value;
|
|
23
|
-
if (raw === void 0) return 1;
|
|
24
|
-
const parsed = Number.parseInt(raw, 10);
|
|
25
|
-
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
26
|
-
}
|
|
27
|
-
function collectRunMembers(children, isMember, headerWrapperTag) {
|
|
28
|
-
const members = [];
|
|
29
|
-
children.forEach((node, outerPosition) => {
|
|
30
|
-
if (node.type !== "element") return;
|
|
31
|
-
if (headerWrapperTag !== void 0 && node.tag === headerWrapperTag) {
|
|
32
|
-
node.children.forEach((inner, innerPosition) => {
|
|
33
|
-
if (isMember(inner)) members.push({
|
|
34
|
-
node: inner,
|
|
35
|
-
container: node.children,
|
|
36
|
-
containerPosition: innerPosition,
|
|
37
|
-
outerPosition
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (isMember(node)) members.push({
|
|
43
|
-
node,
|
|
44
|
-
container: children,
|
|
45
|
-
containerPosition: outerPosition,
|
|
46
|
-
outerPosition
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
return members;
|
|
50
|
-
}
|
|
51
|
-
function withRepeatCount(node, attrName, count) {
|
|
52
|
-
const clone = structuredClone(node);
|
|
53
|
-
clone.attributes = clone.attributes.filter((attribute) => attribute.name !== attrName);
|
|
54
|
-
if (count > 1) clone.attributes.push({
|
|
55
|
-
name: attrName,
|
|
56
|
-
value: String(count)
|
|
57
|
-
});
|
|
58
|
-
return clone;
|
|
59
|
-
}
|
|
60
|
-
function replaceRun(children, isMember, targetIndex, repeatAttr, buildEmpty, headerWrapperTag) {
|
|
61
|
-
validateIndex(targetIndex, "targetIndex");
|
|
62
|
-
const members = collectRunMembers(children, isMember, headerWrapperTag);
|
|
63
|
-
let cursor = 0;
|
|
64
|
-
for (const member of members) {
|
|
65
|
-
const count = readRunRepeatCount(member.node, repeatAttr);
|
|
66
|
-
if (targetIndex < cursor + count) {
|
|
67
|
-
const offset = targetIndex - cursor;
|
|
68
|
-
if (count === 1) return member.node;
|
|
69
|
-
const before = offset > 0 ? withRepeatCount(member.node, repeatAttr, offset) : void 0;
|
|
70
|
-
const target = withRepeatCount(member.node, repeatAttr, 1);
|
|
71
|
-
const replacement = [
|
|
72
|
-
before,
|
|
73
|
-
target,
|
|
74
|
-
count - offset - 1 > 0 ? withRepeatCount(member.node, repeatAttr, count - offset - 1) : void 0
|
|
75
|
-
].filter((candidate) => candidate !== void 0);
|
|
76
|
-
member.container.splice(member.containerPosition, 1, ...replacement);
|
|
77
|
-
return target;
|
|
78
|
-
}
|
|
79
|
-
cursor += count;
|
|
80
|
-
}
|
|
81
|
-
const gap = targetIndex - cursor;
|
|
82
|
-
const lastMember = members[members.length - 1];
|
|
83
|
-
const insertAt = lastMember === void 0 ? children.length : lastMember.outerPosition + 1;
|
|
84
|
-
const toInsert = [];
|
|
85
|
-
if (gap > 0) toInsert.push(withRepeatCount(buildEmpty(), repeatAttr, gap));
|
|
86
|
-
const target = buildEmpty();
|
|
87
|
-
toInsert.push(target);
|
|
88
|
-
children.splice(insertAt, 0, ...toInsert);
|
|
89
|
-
return target;
|
|
90
|
-
}
|
|
91
8
|
function ensureColumnCoverage(tableElement, minCount) {
|
|
92
9
|
if (minCount <= 0) return;
|
|
93
|
-
const columnMembers = collectRunMembers(tableElement.children, isElementWithTag(COLUMN_TAG), HEADER_COLUMNS_TAG);
|
|
94
|
-
const covered = columnMembers.reduce((sum, member) => sum + readRunRepeatCount(member.node, COLUMN_REPEAT_ATTR), 0);
|
|
10
|
+
const columnMembers = require_edit_odf_repeated_runs.collectRunMembers(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(COLUMN_TAG), HEADER_COLUMNS_TAG);
|
|
11
|
+
const covered = columnMembers.reduce((sum, member) => sum + require_edit_odf_repeated_runs.readRunRepeatCount(member.node, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR), 0);
|
|
95
12
|
if (covered >= minCount) return;
|
|
96
13
|
const additional = minCount - covered;
|
|
97
|
-
const newColumn = withRepeatCount(require_xml_fragment.el(COLUMN_TAG), COLUMN_REPEAT_ATTR, additional);
|
|
14
|
+
const newColumn = require_edit_odf_repeated_runs.withRepeatCount(require_xml_fragment.el(COLUMN_TAG), require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, additional);
|
|
98
15
|
const lastColumn = columnMembers[columnMembers.length - 1];
|
|
99
16
|
if (lastColumn === void 0) {
|
|
100
|
-
const firstRowOrHeaderPosition = tableElement.children.findIndex((node) => isElementWithTag("table:table-row")(node) || isElementWithTag("table:table-header-rows")(node));
|
|
17
|
+
const firstRowOrHeaderPosition = tableElement.children.findIndex((node) => require_edit_odf_repeated_runs.isElementWithTag("table:table-row")(node) || require_edit_odf_repeated_runs.isElementWithTag("table:table-header-rows")(node));
|
|
101
18
|
const insertAt = firstRowOrHeaderPosition === -1 ? tableElement.children.length : firstRowOrHeaderPosition;
|
|
102
19
|
tableElement.children.splice(insertAt, 0, newColumn);
|
|
103
20
|
} else tableElement.children.splice(lastColumn.outerPosition + 1, 0, newColumn);
|
|
104
21
|
}
|
|
105
22
|
function resolveCellNode(tableElement, row, column) {
|
|
106
|
-
validateIndex(row, "row");
|
|
107
|
-
validateIndex(column, "column");
|
|
23
|
+
require_edit_odf_repeated_runs.validateIndex(row, "row");
|
|
24
|
+
require_edit_odf_repeated_runs.validateIndex(column, "column");
|
|
108
25
|
ensureColumnCoverage(tableElement, column + 1);
|
|
109
|
-
|
|
26
|
+
const rowElement = require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_odf_repeated_runs.ROW_TAG), row, require_edit_odf_repeated_runs.ROW_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_odf_repeated_runs.ROW_TAG), HEADER_ROWS_TAG);
|
|
27
|
+
return require_edit_odf_repeated_runs.replaceRun(rowElement.children, require_edit_odf_repeated_runs.isCellOrCoveredCell, column, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_odf_repeated_runs.CELL_TAG));
|
|
110
28
|
}
|
|
111
29
|
//#endregion
|
|
112
|
-
exports.CELL_TAG = CELL_TAG;
|
|
113
|
-
exports.COLUMN_REPEAT_ATTR = COLUMN_REPEAT_ATTR;
|
|
114
30
|
exports.COLUMN_TAG = COLUMN_TAG;
|
|
115
|
-
exports.COVERED_CELL_TAG = COVERED_CELL_TAG;
|
|
116
31
|
exports.HEADER_COLUMNS_TAG = HEADER_COLUMNS_TAG;
|
|
117
32
|
exports.HEADER_ROWS_TAG = HEADER_ROWS_TAG;
|
|
118
|
-
exports.ROW_REPEAT_ATTR = ROW_REPEAT_ATTR;
|
|
119
|
-
exports.ROW_TAG = ROW_TAG;
|
|
120
|
-
exports.collectRunMembers = collectRunMembers;
|
|
121
33
|
exports.ensureColumnCoverage = ensureColumnCoverage;
|
|
122
|
-
exports.isCellOrCoveredCell = isCellOrCoveredCell;
|
|
123
|
-
exports.isElementWithTag = isElementWithTag;
|
|
124
|
-
exports.readRunRepeatCount = readRunRepeatCount;
|
|
125
|
-
exports.replaceRun = replaceRun;
|
|
126
34
|
exports.resolveCellNode = resolveCellNode;
|
|
@@ -1,25 +1,9 @@
|
|
|
1
|
-
import { XmlElement
|
|
1
|
+
import { XmlElement } from "odf.js";
|
|
2
2
|
//#region src/edit/ods/address.d.ts
|
|
3
|
-
declare const ROW_TAG = "table:table-row";
|
|
4
3
|
declare const COLUMN_TAG = "table:table-column";
|
|
5
|
-
declare const CELL_TAG = "table:table-cell";
|
|
6
|
-
declare const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
7
|
-
declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
8
|
-
declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
9
4
|
declare const HEADER_ROWS_TAG = "table:table-header-rows";
|
|
10
5
|
declare const HEADER_COLUMNS_TAG = "table:table-header-columns";
|
|
11
|
-
declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
|
|
12
|
-
declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
|
|
13
|
-
declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
|
|
14
|
-
interface RunMember {
|
|
15
|
-
readonly node: XmlElement;
|
|
16
|
-
readonly container: XmlNode[];
|
|
17
|
-
readonly containerPosition: number;
|
|
18
|
-
readonly outerPosition: number;
|
|
19
|
-
}
|
|
20
|
-
declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
|
|
21
|
-
declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
|
|
22
6
|
declare function ensureColumnCoverage(tableElement: XmlElement, minCount: number): void;
|
|
23
7
|
declare function resolveCellNode(tableElement: XmlElement, row: number, column: number): XmlElement;
|
|
24
8
|
//#endregion
|
|
25
|
-
export {
|
|
9
|
+
export { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ensureColumnCoverage, resolveCellNode };
|
|
@@ -1,25 +1,9 @@
|
|
|
1
|
-
import { XmlElement
|
|
1
|
+
import { XmlElement } from "odf.js";
|
|
2
2
|
//#region src/edit/ods/address.d.ts
|
|
3
|
-
declare const ROW_TAG = "table:table-row";
|
|
4
3
|
declare const COLUMN_TAG = "table:table-column";
|
|
5
|
-
declare const CELL_TAG = "table:table-cell";
|
|
6
|
-
declare const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
7
|
-
declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
8
|
-
declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
9
4
|
declare const HEADER_ROWS_TAG = "table:table-header-rows";
|
|
10
5
|
declare const HEADER_COLUMNS_TAG = "table:table-header-columns";
|
|
11
|
-
declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
|
|
12
|
-
declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
|
|
13
|
-
declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
|
|
14
|
-
interface RunMember {
|
|
15
|
-
readonly node: XmlElement;
|
|
16
|
-
readonly container: XmlNode[];
|
|
17
|
-
readonly containerPosition: number;
|
|
18
|
-
readonly outerPosition: number;
|
|
19
|
-
}
|
|
20
|
-
declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
|
|
21
|
-
declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
|
|
22
6
|
declare function ensureColumnCoverage(tableElement: XmlElement, minCount: number): void;
|
|
23
7
|
declare function resolveCellNode(tableElement: XmlElement, row: number, column: number): XmlElement;
|
|
24
8
|
//#endregion
|
|
25
|
-
export {
|
|
9
|
+
export { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ensureColumnCoverage, resolveCellNode };
|
package/dist/edit/ods/address.js
CHANGED
|
@@ -1,92 +1,9 @@
|
|
|
1
1
|
import { el } from "../../xml/fragment.js";
|
|
2
|
+
import { CELL_TAG, COLUMN_REPEAT_ATTR, ROW_REPEAT_ATTR, ROW_TAG, collectRunMembers, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, validateIndex, withRepeatCount } from "../odf-repeated-runs.js";
|
|
2
3
|
//#region src/edit/ods/address.ts
|
|
3
|
-
const ROW_TAG = "table:table-row";
|
|
4
4
|
const COLUMN_TAG = "table:table-column";
|
|
5
|
-
const CELL_TAG = "table:table-cell";
|
|
6
|
-
const COVERED_CELL_TAG = "table:covered-table-cell";
|
|
7
|
-
const ROW_REPEAT_ATTR = "table:number-rows-repeated";
|
|
8
|
-
const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
|
|
9
5
|
const HEADER_ROWS_TAG = "table:table-header-rows";
|
|
10
6
|
const HEADER_COLUMNS_TAG = "table:table-header-columns";
|
|
11
|
-
function isElementWithTag(tag) {
|
|
12
|
-
return (node) => node.type === "element" && node.tag === tag;
|
|
13
|
-
}
|
|
14
|
-
function isCellOrCoveredCell(node) {
|
|
15
|
-
return node.type === "element" && (node.tag === "table:table-cell" || node.tag === "table:covered-table-cell");
|
|
16
|
-
}
|
|
17
|
-
function validateIndex(value, label) {
|
|
18
|
-
if (!Number.isInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer, got ${value}`);
|
|
19
|
-
}
|
|
20
|
-
function readRunRepeatCount(node, attrName) {
|
|
21
|
-
const raw = node.attributes.find((attribute) => attribute.name === attrName)?.value;
|
|
22
|
-
if (raw === void 0) return 1;
|
|
23
|
-
const parsed = Number.parseInt(raw, 10);
|
|
24
|
-
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
25
|
-
}
|
|
26
|
-
function collectRunMembers(children, isMember, headerWrapperTag) {
|
|
27
|
-
const members = [];
|
|
28
|
-
children.forEach((node, outerPosition) => {
|
|
29
|
-
if (node.type !== "element") return;
|
|
30
|
-
if (headerWrapperTag !== void 0 && node.tag === headerWrapperTag) {
|
|
31
|
-
node.children.forEach((inner, innerPosition) => {
|
|
32
|
-
if (isMember(inner)) members.push({
|
|
33
|
-
node: inner,
|
|
34
|
-
container: node.children,
|
|
35
|
-
containerPosition: innerPosition,
|
|
36
|
-
outerPosition
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (isMember(node)) members.push({
|
|
42
|
-
node,
|
|
43
|
-
container: children,
|
|
44
|
-
containerPosition: outerPosition,
|
|
45
|
-
outerPosition
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
return members;
|
|
49
|
-
}
|
|
50
|
-
function withRepeatCount(node, attrName, count) {
|
|
51
|
-
const clone = structuredClone(node);
|
|
52
|
-
clone.attributes = clone.attributes.filter((attribute) => attribute.name !== attrName);
|
|
53
|
-
if (count > 1) clone.attributes.push({
|
|
54
|
-
name: attrName,
|
|
55
|
-
value: String(count)
|
|
56
|
-
});
|
|
57
|
-
return clone;
|
|
58
|
-
}
|
|
59
|
-
function replaceRun(children, isMember, targetIndex, repeatAttr, buildEmpty, headerWrapperTag) {
|
|
60
|
-
validateIndex(targetIndex, "targetIndex");
|
|
61
|
-
const members = collectRunMembers(children, isMember, headerWrapperTag);
|
|
62
|
-
let cursor = 0;
|
|
63
|
-
for (const member of members) {
|
|
64
|
-
const count = readRunRepeatCount(member.node, repeatAttr);
|
|
65
|
-
if (targetIndex < cursor + count) {
|
|
66
|
-
const offset = targetIndex - cursor;
|
|
67
|
-
if (count === 1) return member.node;
|
|
68
|
-
const before = offset > 0 ? withRepeatCount(member.node, repeatAttr, offset) : void 0;
|
|
69
|
-
const target = withRepeatCount(member.node, repeatAttr, 1);
|
|
70
|
-
const replacement = [
|
|
71
|
-
before,
|
|
72
|
-
target,
|
|
73
|
-
count - offset - 1 > 0 ? withRepeatCount(member.node, repeatAttr, count - offset - 1) : void 0
|
|
74
|
-
].filter((candidate) => candidate !== void 0);
|
|
75
|
-
member.container.splice(member.containerPosition, 1, ...replacement);
|
|
76
|
-
return target;
|
|
77
|
-
}
|
|
78
|
-
cursor += count;
|
|
79
|
-
}
|
|
80
|
-
const gap = targetIndex - cursor;
|
|
81
|
-
const lastMember = members[members.length - 1];
|
|
82
|
-
const insertAt = lastMember === void 0 ? children.length : lastMember.outerPosition + 1;
|
|
83
|
-
const toInsert = [];
|
|
84
|
-
if (gap > 0) toInsert.push(withRepeatCount(buildEmpty(), repeatAttr, gap));
|
|
85
|
-
const target = buildEmpty();
|
|
86
|
-
toInsert.push(target);
|
|
87
|
-
children.splice(insertAt, 0, ...toInsert);
|
|
88
|
-
return target;
|
|
89
|
-
}
|
|
90
7
|
function ensureColumnCoverage(tableElement, minCount) {
|
|
91
8
|
if (minCount <= 0) return;
|
|
92
9
|
const columnMembers = collectRunMembers(tableElement.children, isElementWithTag(COLUMN_TAG), HEADER_COLUMNS_TAG);
|
|
@@ -105,7 +22,8 @@ function resolveCellNode(tableElement, row, column) {
|
|
|
105
22
|
validateIndex(row, "row");
|
|
106
23
|
validateIndex(column, "column");
|
|
107
24
|
ensureColumnCoverage(tableElement, column + 1);
|
|
108
|
-
|
|
25
|
+
const rowElement = replaceRun(tableElement.children, isElementWithTag(ROW_TAG), row, ROW_REPEAT_ATTR, () => el(ROW_TAG), HEADER_ROWS_TAG);
|
|
26
|
+
return replaceRun(rowElement.children, isCellOrCoveredCell, column, COLUMN_REPEAT_ATTR, () => el(CELL_TAG));
|
|
109
27
|
}
|
|
110
28
|
//#endregion
|
|
111
|
-
export {
|
|
29
|
+
export { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ensureColumnCoverage, resolveCellNode };
|
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_xml_fragment = require("../../xml/fragment.cjs");
|
|
3
3
|
const require_xml_edit = require("../../xml/edit.cjs");
|
|
4
4
|
const require_edit_odt_automatic_styles = require("../odt/automatic-styles.cjs");
|
|
5
|
+
const require_edit_odf_repeated_runs = require("../odf-repeated-runs.cjs");
|
|
5
6
|
const require_edit_ods_address = require("./address.cjs");
|
|
6
7
|
let ooxml_js = require("ooxml.js");
|
|
7
8
|
let odf_js = require("odf.js");
|
|
@@ -32,7 +33,7 @@ function currentRowStyleProperties(pkg, rowElement) {
|
|
|
32
33
|
}
|
|
33
34
|
function applyColumnStyleProperties(pkg, tableElement, index, changes) {
|
|
34
35
|
require_edit_ods_address.ensureColumnCoverage(tableElement, index + 1);
|
|
35
|
-
const columnElement =
|
|
36
|
+
const columnElement = require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_ods_address.COLUMN_TAG), index, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_ods_address.COLUMN_TAG), require_edit_ods_address.HEADER_COLUMNS_TAG);
|
|
36
37
|
const current = currentColumnStyleProperties(pkg, columnElement);
|
|
37
38
|
const widthPt = changes.widthPt ?? current.widthPt;
|
|
38
39
|
const manualBreak = changes.manualBreak ?? current.manualBreak;
|
|
@@ -48,7 +49,7 @@ function applyColumnStyleProperties(pkg, tableElement, index, changes) {
|
|
|
48
49
|
require_xml_edit.setAttr(columnElement, "table:style-name", styleName);
|
|
49
50
|
}
|
|
50
51
|
function applyRowStyleProperties(pkg, tableElement, index, changes) {
|
|
51
|
-
const rowElement =
|
|
52
|
+
const rowElement = require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_odf_repeated_runs.ROW_TAG), index, require_edit_odf_repeated_runs.ROW_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_odf_repeated_runs.ROW_TAG), require_edit_ods_address.HEADER_ROWS_TAG);
|
|
52
53
|
const current = currentRowStyleProperties(pkg, rowElement);
|
|
53
54
|
const heightPt = changes.heightPt ?? current.heightPt;
|
|
54
55
|
const manualBreak = changes.manualBreak ?? current.manualBreak;
|
|
@@ -71,10 +72,10 @@ function writeRowHeight(pkg, tableElement, index, heightPt) {
|
|
|
71
72
|
}
|
|
72
73
|
function ensureColumnDefaultWidth(pkg, tableElement, index) {
|
|
73
74
|
require_edit_ods_address.ensureColumnCoverage(tableElement, index + 1);
|
|
74
|
-
if (currentColumnStyleProperties(pkg,
|
|
75
|
+
if (currentColumnStyleProperties(pkg, require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag("table:table-column"), index, "table:number-columns-repeated", () => require_xml_fragment.el("table:table-column"), "table:table-header-columns")).widthPt === void 0) writeColumnWidth(pkg, tableElement, index, DEFAULT_COLUMN_WIDTH_PT);
|
|
75
76
|
}
|
|
76
77
|
function ensureRowDefaultHeight(pkg, tableElement, index) {
|
|
77
|
-
if (currentRowStyleProperties(pkg,
|
|
78
|
+
if (currentRowStyleProperties(pkg, require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag("table:table-row"), index, "table:number-rows-repeated", () => require_xml_fragment.el("table:table-row"), "table:table-header-rows")).heightPt === void 0) writeRowHeight(pkg, tableElement, index, DEFAULT_ROW_HEIGHT_PT);
|
|
78
79
|
}
|
|
79
80
|
function ensureColumnElementDefaultWidth(pkg, columnElement) {
|
|
80
81
|
if (currentColumnStyleProperties(pkg, columnElement).widthPt !== void 0) return;
|
|
@@ -104,13 +105,13 @@ function writeRowManualBreak(pkg, tableElement, index) {
|
|
|
104
105
|
}
|
|
105
106
|
function writeColumnHidden(pkg, tableElement, index, hidden) {
|
|
106
107
|
ensureColumnDefaultWidth(pkg, tableElement, index);
|
|
107
|
-
const columnElement =
|
|
108
|
+
const columnElement = require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_ods_address.COLUMN_TAG), index, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_ods_address.COLUMN_TAG), require_edit_ods_address.HEADER_COLUMNS_TAG);
|
|
108
109
|
if (hidden) require_xml_edit.setAttr(columnElement, VISIBILITY_ATTR, VISIBILITY_COLLAPSE);
|
|
109
110
|
else require_xml_edit.removeAttr(columnElement, VISIBILITY_ATTR);
|
|
110
111
|
}
|
|
111
112
|
function writeRowHidden(pkg, tableElement, index, hidden) {
|
|
112
113
|
ensureRowDefaultHeight(pkg, tableElement, index);
|
|
113
|
-
const rowElement =
|
|
114
|
+
const rowElement = require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_odf_repeated_runs.ROW_TAG), index, require_edit_odf_repeated_runs.ROW_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_odf_repeated_runs.ROW_TAG), require_edit_ods_address.HEADER_ROWS_TAG);
|
|
114
115
|
if (hidden) require_xml_edit.setAttr(rowElement, VISIBILITY_ATTR, VISIBILITY_COLLAPSE);
|
|
115
116
|
else require_xml_edit.removeAttr(rowElement, VISIBILITY_ATTR);
|
|
116
117
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { el } from "../../xml/fragment.js";
|
|
2
2
|
import { directChildElement, removeAttr, setAttr } from "../../xml/edit.js";
|
|
3
3
|
import { ensureAutomaticStyles, nextStyleName } from "../odt/automatic-styles.js";
|
|
4
|
-
import { COLUMN_REPEAT_ATTR,
|
|
4
|
+
import { COLUMN_REPEAT_ATTR, ROW_REPEAT_ATTR, ROW_TAG, isElementWithTag, replaceRun } from "../odf-repeated-runs.js";
|
|
5
|
+
import { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ensureColumnCoverage } from "./address.js";
|
|
5
6
|
import { attr } from "ooxml.js";
|
|
6
7
|
import { findStyleElement, formatOdfLength, parseOdfLength } from "odf.js";
|
|
7
8
|
//#region src/edit/ods/column-row.ts
|
|
@@ -3,6 +3,7 @@ const require_xml_fragment = require("../../xml/fragment.cjs");
|
|
|
3
3
|
const require_xml_edit = require("../../xml/edit.cjs");
|
|
4
4
|
const require_odf_package_formula = require("../../odf-package/formula.cjs");
|
|
5
5
|
const require_odf_package_media = require("../../odf-package/media.cjs");
|
|
6
|
+
const require_edit_odf_repeated_runs = require("../odf-repeated-runs.cjs");
|
|
6
7
|
const require_edit_ods_address = require("./address.cjs");
|
|
7
8
|
let ooxml_js = require("ooxml.js");
|
|
8
9
|
let odf_js = require("odf.js");
|
|
@@ -39,9 +40,9 @@ function resolvedRowHeightPt(pkg, rowElement) {
|
|
|
39
40
|
function cumulativeColumnOffsetPt(pkg, tableElement, anchorColumn) {
|
|
40
41
|
let cursor = 0;
|
|
41
42
|
let offsetPt = 0;
|
|
42
|
-
for (const member of
|
|
43
|
+
for (const member of require_edit_odf_repeated_runs.collectRunMembers(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_ods_address.COLUMN_TAG), require_edit_ods_address.HEADER_COLUMNS_TAG)) {
|
|
43
44
|
if (cursor >= anchorColumn) break;
|
|
44
|
-
const count =
|
|
45
|
+
const count = require_edit_odf_repeated_runs.readRunRepeatCount(member.node, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR);
|
|
45
46
|
const overlap = Math.min(count, anchorColumn - cursor);
|
|
46
47
|
offsetPt += overlap * resolvedColumnWidthPt(pkg, member.node);
|
|
47
48
|
cursor += count;
|
|
@@ -52,9 +53,9 @@ function cumulativeColumnOffsetPt(pkg, tableElement, anchorColumn) {
|
|
|
52
53
|
function cumulativeRowOffsetPt(pkg, tableElement, anchorRow) {
|
|
53
54
|
let cursor = 0;
|
|
54
55
|
let offsetPt = 0;
|
|
55
|
-
for (const member of
|
|
56
|
+
for (const member of require_edit_odf_repeated_runs.collectRunMembers(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_odf_repeated_runs.ROW_TAG), require_edit_ods_address.HEADER_ROWS_TAG)) {
|
|
56
57
|
if (cursor >= anchorRow) break;
|
|
57
|
-
const count =
|
|
58
|
+
const count = require_edit_odf_repeated_runs.readRunRepeatCount(member.node, require_edit_odf_repeated_runs.ROW_REPEAT_ATTR);
|
|
58
59
|
const overlap = Math.min(count, anchorRow - cursor);
|
|
59
60
|
offsetPt += overlap * resolvedRowHeightPt(pkg, member.node);
|
|
60
61
|
cursor += count;
|
|
@@ -2,7 +2,8 @@ import { el } from "../../xml/fragment.js";
|
|
|
2
2
|
import { directChildElement } from "../../xml/edit.js";
|
|
3
3
|
import { addFormulaObject } from "../../odf-package/formula.js";
|
|
4
4
|
import { addImageMedia } from "../../odf-package/media.js";
|
|
5
|
-
import { COLUMN_REPEAT_ATTR,
|
|
5
|
+
import { COLUMN_REPEAT_ATTR, ROW_REPEAT_ATTR, ROW_TAG, collectRunMembers, isElementWithTag, readRunRepeatCount } from "../odf-repeated-runs.js";
|
|
6
|
+
import { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG } from "./address.js";
|
|
6
7
|
import { attr } from "ooxml.js";
|
|
7
8
|
import { base64ToBytes as base64ToBytes$1, findStyleElement, formatOdfLength, parseOdfLength, writeEmbeddedObject } from "odf.js";
|
|
8
9
|
//#region src/edit/ods/floating.ts
|
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_xml_fragment = require("../../xml/fragment.cjs");
|
|
3
3
|
const require_xml_edit = require("../../xml/edit.cjs");
|
|
4
4
|
const require_edit_odt_automatic_styles = require("../odt/automatic-styles.cjs");
|
|
5
|
+
const require_edit_odf_repeated_runs = require("../odf-repeated-runs.cjs");
|
|
5
6
|
const require_edit_ods_address = require("./address.cjs");
|
|
6
7
|
const require_edit_ods_column_row = require("./column-row.cjs");
|
|
7
8
|
let ooxml_js = require("ooxml.js");
|
|
@@ -56,12 +57,12 @@ function scanTableStructure(pkg, tableElement) {
|
|
|
56
57
|
const manualBreakRows = [];
|
|
57
58
|
function processColumn(columnElement) {
|
|
58
59
|
if (hasManualBreak(pkg, columnElement, "table-column", "style:table-column-properties")) manualBreakColumns.push(columnCursor);
|
|
59
|
-
columnCursor +=
|
|
60
|
+
columnCursor += require_edit_odf_repeated_runs.readRunRepeatCount(columnElement, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR);
|
|
60
61
|
}
|
|
61
62
|
function processRow(rowElement) {
|
|
62
63
|
const startIndex = rowCursor;
|
|
63
64
|
if (hasManualBreak(pkg, rowElement, "table-row", "style:table-row-properties")) manualBreakRows.push(startIndex);
|
|
64
|
-
rowCursor +=
|
|
65
|
+
rowCursor += require_edit_odf_repeated_runs.readRunRepeatCount(rowElement, require_edit_odf_repeated_runs.ROW_REPEAT_ATTR);
|
|
65
66
|
}
|
|
66
67
|
for (const child of tableElement.children) {
|
|
67
68
|
if (child.type !== "element") continue;
|
|
@@ -174,7 +175,7 @@ function collectRangeElements(children, tag, repeatAttr, start, end) {
|
|
|
174
175
|
const found = [];
|
|
175
176
|
children.forEach((node, position) => {
|
|
176
177
|
if (node.type !== "element" || node.tag !== tag) return;
|
|
177
|
-
const count =
|
|
178
|
+
const count = require_edit_odf_repeated_runs.readRunRepeatCount(node, repeatAttr);
|
|
178
179
|
if (cursor >= start && cursor + count - 1 <= end) found.push({
|
|
179
180
|
position,
|
|
180
181
|
element: node
|
|
@@ -184,8 +185,8 @@ function collectRangeElements(children, tag, repeatAttr, start, end) {
|
|
|
184
185
|
return found;
|
|
185
186
|
}
|
|
186
187
|
function wrapRepeatRange(tableElement, memberTag, repeatAttr, wrapperTag, range, buildEmpty, pkg) {
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(memberTag), range.start, repeatAttr, buildEmpty);
|
|
189
|
+
require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(memberTag), range.end, repeatAttr, buildEmpty);
|
|
189
190
|
for (const entry of collectRangeElements(tableElement.children, memberTag, repeatAttr, 0, range.end)) if (memberTag === "table:table-column") require_edit_ods_column_row.ensureColumnElementDefaultWidth(pkg, entry.element);
|
|
190
191
|
else require_edit_ods_column_row.ensureRowElementDefaultHeight(pkg, entry.element);
|
|
191
192
|
const found = collectRangeElements(tableElement.children, memberTag, repeatAttr, range.start, range.end);
|
|
@@ -235,9 +236,9 @@ function writeSheetPrintSettings(pkg, tableElement, settings) {
|
|
|
235
236
|
require_xml_edit.setAttr(tableElement, "table:print-ranges", formatPrintRange(sheetName, settings.printRange));
|
|
236
237
|
}
|
|
237
238
|
unwrapHeaderGroup(tableElement, require_edit_ods_address.HEADER_COLUMNS_TAG);
|
|
238
|
-
if (settings.repeatColumns !== void 0) wrapRepeatRange(tableElement, require_edit_ods_address.COLUMN_TAG,
|
|
239
|
+
if (settings.repeatColumns !== void 0) wrapRepeatRange(tableElement, require_edit_ods_address.COLUMN_TAG, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, require_edit_ods_address.HEADER_COLUMNS_TAG, settings.repeatColumns, () => require_xml_fragment.el(require_edit_ods_address.COLUMN_TAG), pkg);
|
|
239
240
|
unwrapHeaderGroup(tableElement, require_edit_ods_address.HEADER_ROWS_TAG);
|
|
240
|
-
if (settings.repeatRows !== void 0) wrapRepeatRange(tableElement,
|
|
241
|
+
if (settings.repeatRows !== void 0) wrapRepeatRange(tableElement, require_edit_odf_repeated_runs.ROW_TAG, require_edit_odf_repeated_runs.ROW_REPEAT_ATTR, require_edit_ods_address.HEADER_ROWS_TAG, settings.repeatRows, () => require_xml_fragment.el(require_edit_odf_repeated_runs.ROW_TAG), pkg);
|
|
241
242
|
if (settings.manualBreaks !== void 0) {
|
|
242
243
|
for (const columnIndex of settings.manualBreaks.columns) require_edit_ods_column_row.writeColumnManualBreak(pkg, tableElement, columnIndex);
|
|
243
244
|
for (const rowIndex of settings.manualBreaks.rows) require_edit_ods_column_row.writeRowManualBreak(pkg, tableElement, rowIndex);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { el } from "../../xml/fragment.js";
|
|
2
2
|
import { setAttr } from "../../xml/edit.js";
|
|
3
3
|
import { nextStyleName } from "../odt/automatic-styles.js";
|
|
4
|
-
import { COLUMN_REPEAT_ATTR,
|
|
4
|
+
import { COLUMN_REPEAT_ATTR, ROW_REPEAT_ATTR, ROW_TAG, isElementWithTag, readRunRepeatCount, replaceRun } from "../odf-repeated-runs.js";
|
|
5
|
+
import { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG } from "./address.js";
|
|
5
6
|
import { ensureColumnElementDefaultWidth, ensureRowElementDefaultHeight, writeColumnManualBreak, writeRowManualBreak } from "./column-row.js";
|
|
6
7
|
import { attr } from "ooxml.js";
|
|
7
8
|
import { PAGE_SIZE_A4, cellReference, parseCellReference } from "document-schema.js";
|
package/dist/edit/ods/sheet.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_xml_edit = require("../../xml/edit.cjs");
|
|
3
|
+
const require_edit_odf_repeated_runs = require("../odf-repeated-runs.cjs");
|
|
3
4
|
const require_edit_ods_address = require("./address.cjs");
|
|
4
5
|
const require_edit_ods_cell = require("./cell.cjs");
|
|
5
6
|
const require_edit_ods_column_row = require("./column-row.cjs");
|
|
@@ -86,7 +87,7 @@ var OdsSheet = class {
|
|
|
86
87
|
for (let rowOffset = 0; rowOffset < rowSpan; rowOffset++) for (let columnOffset = 0; columnOffset < colSpan; columnOffset++) {
|
|
87
88
|
if (rowOffset === 0 && columnOffset === 0) continue;
|
|
88
89
|
const coveredNode = require_edit_ods_address.resolveCellNode(tableElement, startRow + rowOffset, startColumn + columnOffset);
|
|
89
|
-
coveredNode.tag =
|
|
90
|
+
coveredNode.tag = require_edit_odf_repeated_runs.COVERED_CELL_TAG;
|
|
90
91
|
coveredNode.attributes = [];
|
|
91
92
|
coveredNode.children = [];
|
|
92
93
|
}
|
package/dist/edit/ods/sheet.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { removeChild, setAttr } from "../../xml/edit.js";
|
|
2
|
-
import { COVERED_CELL_TAG
|
|
2
|
+
import { COVERED_CELL_TAG } from "../odf-repeated-runs.js";
|
|
3
|
+
import { resolveCellNode } from "./address.js";
|
|
3
4
|
import { OdsCell } from "./cell.js";
|
|
4
5
|
import { ensureColumnDefaultWidth, ensureRowDefaultHeight, writeColumnHidden, writeColumnWidth, writeRowHeight, writeRowHidden } from "./column-row.js";
|
|
5
6
|
import { insertSheetEmbeddedObject, insertSheetImage } from "./floating.js";
|
package/dist/edit/odt/table.cjs
CHANGED
|
@@ -4,6 +4,7 @@ const require_xml_edit = require("../../xml/edit.cjs");
|
|
|
4
4
|
const require_edit_table_grid = require("../table-grid.cjs");
|
|
5
5
|
const require_edit_odt_automatic_styles = require("./automatic-styles.cjs");
|
|
6
6
|
const require_edit_odt_paragraph = require("./paragraph.cjs");
|
|
7
|
+
const require_edit_odf_repeated_runs = require("../odf-repeated-runs.cjs");
|
|
7
8
|
let ooxml_js = require("ooxml.js");
|
|
8
9
|
let document_schema_js = require("document-schema.js");
|
|
9
10
|
let odf_js = require("odf.js");
|
|
@@ -250,16 +251,41 @@ function retagAsCovered(element) {
|
|
|
250
251
|
element.attributes = element.attributes.filter((attribute) => attribute.name === COVERED_CELL_KEPT_ATTRIBUTE);
|
|
251
252
|
element.children = [];
|
|
252
253
|
}
|
|
253
|
-
function
|
|
254
|
+
function gridColumnElements(row) {
|
|
254
255
|
const out = [];
|
|
255
|
-
|
|
256
|
+
let columnIndex = 0;
|
|
257
|
+
for (const member of require_edit_odf_repeated_runs.collectRunMembers(row.children, require_edit_odf_repeated_runs.isCellOrCoveredCell, void 0)) {
|
|
258
|
+
const repeat = require_edit_odf_repeated_runs.readRunRepeatCount(member.node, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR);
|
|
259
|
+
for (let offset = 0; offset < repeat; offset++) out.push({
|
|
260
|
+
columnIndex: columnIndex + offset,
|
|
261
|
+
element: member.node
|
|
262
|
+
});
|
|
263
|
+
columnIndex += repeat;
|
|
264
|
+
}
|
|
256
265
|
return out;
|
|
257
266
|
}
|
|
267
|
+
function rowGridColumnCount(row) {
|
|
268
|
+
return require_edit_odf_repeated_runs.collectRunMembers(row.children, require_edit_odf_repeated_runs.isCellOrCoveredCell, void 0).reduce((sum, member) => sum + require_edit_odf_repeated_runs.readRunRepeatCount(member.node, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR), 0);
|
|
269
|
+
}
|
|
270
|
+
function locateGridColumnElement(row, columnIndex) {
|
|
271
|
+
if (columnIndex < 0) return;
|
|
272
|
+
let cursor = 0;
|
|
273
|
+
for (const member of require_edit_odf_repeated_runs.collectRunMembers(row.children, require_edit_odf_repeated_runs.isCellOrCoveredCell, void 0)) {
|
|
274
|
+
const count = require_edit_odf_repeated_runs.readRunRepeatCount(member.node, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR);
|
|
275
|
+
if (columnIndex < cursor + count) return member.node;
|
|
276
|
+
cursor += count;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function individuateGridColumn(row, columnIndex) {
|
|
280
|
+
return require_edit_odf_repeated_runs.replaceRun(row.children, require_edit_odf_repeated_runs.isCellOrCoveredCell, columnIndex, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, () => {
|
|
281
|
+
throw new Error(`individuateGridColumn: column ${columnIndex} has no existing element to individuate in this row -- callers must bounds-check against rowGridColumnCount first`);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
258
284
|
function tableRowElements(table) {
|
|
259
285
|
return table.children.filter((child) => child.type === "element" && child.tag === "table:table-row");
|
|
260
286
|
}
|
|
261
287
|
function placedCells(row, pkg) {
|
|
262
|
-
return
|
|
288
|
+
return gridColumnElements(row).flatMap(({ columnIndex, element }) => {
|
|
263
289
|
if (element.tag !== "table:table-cell") return [];
|
|
264
290
|
const cell = new OdtTableCell(element, pkg);
|
|
265
291
|
return [{
|
|
@@ -275,7 +301,7 @@ function resolveOdtGrid(table, pkg) {
|
|
|
275
301
|
let declaredColumns = 0;
|
|
276
302
|
for (const child of table.children) {
|
|
277
303
|
if (child.type !== "element") continue;
|
|
278
|
-
if (child.tag === "table:table-column") declaredColumns
|
|
304
|
+
if (child.tag === "table:table-column") declaredColumns += require_edit_odf_repeated_runs.readRunRepeatCount(child, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR);
|
|
279
305
|
else if (child.tag === "table:table-row") placedRows.push(placedCells(child, pkg));
|
|
280
306
|
}
|
|
281
307
|
return require_edit_table_grid.resolveLiveTableGrid(placedRows, declaredColumns);
|
|
@@ -319,14 +345,15 @@ function refuseMerge(rowIndex, reason) {
|
|
|
319
345
|
}
|
|
320
346
|
function planMerge(table, pkg, target, rows) {
|
|
321
347
|
const [anchorRow, ...coveredRows] = rows;
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
const anchor = anchorCells[target.column];
|
|
325
|
-
if (anchor === void 0) return refuseMerge(target.row, `column ${target.column} does not exist in this row`);
|
|
348
|
+
const anchorElement = locateGridColumnElement(anchorRow, target.column);
|
|
349
|
+
if (anchorElement === void 0) return refuseMerge(target.row, `column ${target.column} does not exist in this row`);
|
|
326
350
|
const endColumn = target.column + target.columnSpan;
|
|
327
|
-
for (const [offset,
|
|
351
|
+
for (const [offset, row] of rows.entries()) {
|
|
352
|
+
const totalColumns = rowGridColumnCount(row);
|
|
353
|
+
if (endColumn > totalColumns) return refuseMerge(target.row + offset, `colSpan ${target.columnSpan} starting at column ${target.column} exceeds this row's own ${totalColumns} grid columns`);
|
|
354
|
+
}
|
|
328
355
|
const regions = anchorRegions(resolveOdtGrid(table, pkg));
|
|
329
|
-
if (
|
|
356
|
+
if (anchorElement.tag === "table:covered-table-cell") {
|
|
330
357
|
const covering = regions.find((region) => regionCovers(region, target.row, target.column));
|
|
331
358
|
return refuseMerge(target.row, covering === void 0 ? `column ${target.column} is a covered position that no merge anchors` : `column ${target.column} is covered by ${describeRegionAnchor(covering)}`);
|
|
332
359
|
}
|
|
@@ -335,14 +362,26 @@ function planMerge(table, pkg, target, rows) {
|
|
|
335
362
|
const column = Math.max(cutting.column, target.column);
|
|
336
363
|
return refuseMerge(Math.max(cutting.row, target.row), `column ${column} belongs to ${describeRegionAnchor(cutting)}, which reaches outside the region being merged and cannot be merged over`);
|
|
337
364
|
}
|
|
365
|
+
const consumed = [];
|
|
366
|
+
for (let column = target.column + 1; column < endColumn; column++) consumed.push({
|
|
367
|
+
row: anchorRow,
|
|
368
|
+
column
|
|
369
|
+
});
|
|
370
|
+
for (const row of coveredRows) for (let column = target.column; column < endColumn; column++) consumed.push({
|
|
371
|
+
row,
|
|
372
|
+
column
|
|
373
|
+
});
|
|
338
374
|
return {
|
|
339
|
-
anchor
|
|
340
|
-
|
|
375
|
+
anchor: {
|
|
376
|
+
row: anchorRow,
|
|
377
|
+
column: target.column
|
|
378
|
+
},
|
|
379
|
+
consumed
|
|
341
380
|
};
|
|
342
381
|
}
|
|
343
382
|
function applyMerge(plan, target, pkg) {
|
|
344
|
-
for (const
|
|
345
|
-
const anchor = new OdtTableCell(plan.anchor, pkg);
|
|
383
|
+
for (const position of plan.consumed) retagAsCovered(individuateGridColumn(position.row, position.column));
|
|
384
|
+
const anchor = new OdtTableCell(individuateGridColumn(plan.anchor.row, plan.anchor.column), pkg);
|
|
346
385
|
anchor.colSpan = target.columnSpan;
|
|
347
386
|
if (target.rowSpan > 1) anchor.rowSpan = target.rowSpan;
|
|
348
387
|
return anchor;
|
|
@@ -402,12 +441,12 @@ var OdtTableRow = class {
|
|
|
402
441
|
return applyMerge(plan, target, this.pkg);
|
|
403
442
|
}
|
|
404
443
|
markCellCovered(columnIndex) {
|
|
405
|
-
const
|
|
406
|
-
if (
|
|
444
|
+
const totalColumns = rowGridColumnCount(this.node);
|
|
445
|
+
if (columnIndex < 0 || columnIndex >= totalColumns) throw new Error(`markCellCovered: column ${columnIndex} does not exist in this row`);
|
|
407
446
|
const rowIndex = tableRowElements(this.table).indexOf(this.node);
|
|
408
447
|
const anchored = anchorRegions(resolveOdtGrid(this.table, this.pkg)).find((region) => region.row === rowIndex && region.column === columnIndex && (region.rowSpan > 1 || region.columnSpan > 1));
|
|
409
448
|
if (anchored !== void 0) throw new Error(`markCellCovered: column ${columnIndex} anchors a merge with rowSpan ${anchored.rowSpan} and colSpan ${anchored.columnSpan}, so covering it would leave the rest of that merge without an anchor`);
|
|
410
|
-
retagAsCovered(
|
|
449
|
+
retagAsCovered(individuateGridColumn(this.node, columnIndex));
|
|
411
450
|
}
|
|
412
451
|
};
|
|
413
452
|
function buildCell(pkg) {
|
package/dist/edit/odt/table.js
CHANGED
|
@@ -3,6 +3,7 @@ import { removeAttr, removeChild, setAttr } from "../../xml/edit.js";
|
|
|
3
3
|
import { resolveLiveTableGrid } from "../table-grid.js";
|
|
4
4
|
import { ensureAutomaticStyles, nextStyleName } from "./automatic-styles.js";
|
|
5
5
|
import { OdtParagraph, buildParagraph } from "./paragraph.js";
|
|
6
|
+
import { COLUMN_REPEAT_ATTR, collectRunMembers, isCellOrCoveredCell, readRunRepeatCount, replaceRun } from "../odf-repeated-runs.js";
|
|
6
7
|
import { attr } from "ooxml.js";
|
|
7
8
|
import { tableCellColumnSpan, tableCellRowSpan } from "document-schema.js";
|
|
8
9
|
import { findStyleElement, formatOdfColor, formatOdfLength, parseOdfColor, parseOdfLength } from "odf.js";
|
|
@@ -249,16 +250,41 @@ function retagAsCovered(element) {
|
|
|
249
250
|
element.attributes = element.attributes.filter((attribute) => attribute.name === COVERED_CELL_KEPT_ATTRIBUTE);
|
|
250
251
|
element.children = [];
|
|
251
252
|
}
|
|
252
|
-
function
|
|
253
|
+
function gridColumnElements(row) {
|
|
253
254
|
const out = [];
|
|
254
|
-
|
|
255
|
+
let columnIndex = 0;
|
|
256
|
+
for (const member of collectRunMembers(row.children, isCellOrCoveredCell, void 0)) {
|
|
257
|
+
const repeat = readRunRepeatCount(member.node, COLUMN_REPEAT_ATTR);
|
|
258
|
+
for (let offset = 0; offset < repeat; offset++) out.push({
|
|
259
|
+
columnIndex: columnIndex + offset,
|
|
260
|
+
element: member.node
|
|
261
|
+
});
|
|
262
|
+
columnIndex += repeat;
|
|
263
|
+
}
|
|
255
264
|
return out;
|
|
256
265
|
}
|
|
266
|
+
function rowGridColumnCount(row) {
|
|
267
|
+
return collectRunMembers(row.children, isCellOrCoveredCell, void 0).reduce((sum, member) => sum + readRunRepeatCount(member.node, COLUMN_REPEAT_ATTR), 0);
|
|
268
|
+
}
|
|
269
|
+
function locateGridColumnElement(row, columnIndex) {
|
|
270
|
+
if (columnIndex < 0) return;
|
|
271
|
+
let cursor = 0;
|
|
272
|
+
for (const member of collectRunMembers(row.children, isCellOrCoveredCell, void 0)) {
|
|
273
|
+
const count = readRunRepeatCount(member.node, COLUMN_REPEAT_ATTR);
|
|
274
|
+
if (columnIndex < cursor + count) return member.node;
|
|
275
|
+
cursor += count;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function individuateGridColumn(row, columnIndex) {
|
|
279
|
+
return replaceRun(row.children, isCellOrCoveredCell, columnIndex, COLUMN_REPEAT_ATTR, () => {
|
|
280
|
+
throw new Error(`individuateGridColumn: column ${columnIndex} has no existing element to individuate in this row -- callers must bounds-check against rowGridColumnCount first`);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
257
283
|
function tableRowElements(table) {
|
|
258
284
|
return table.children.filter((child) => child.type === "element" && child.tag === "table:table-row");
|
|
259
285
|
}
|
|
260
286
|
function placedCells(row, pkg) {
|
|
261
|
-
return
|
|
287
|
+
return gridColumnElements(row).flatMap(({ columnIndex, element }) => {
|
|
262
288
|
if (element.tag !== "table:table-cell") return [];
|
|
263
289
|
const cell = new OdtTableCell(element, pkg);
|
|
264
290
|
return [{
|
|
@@ -274,7 +300,7 @@ function resolveOdtGrid(table, pkg) {
|
|
|
274
300
|
let declaredColumns = 0;
|
|
275
301
|
for (const child of table.children) {
|
|
276
302
|
if (child.type !== "element") continue;
|
|
277
|
-
if (child.tag === "table:table-column") declaredColumns
|
|
303
|
+
if (child.tag === "table:table-column") declaredColumns += readRunRepeatCount(child, COLUMN_REPEAT_ATTR);
|
|
278
304
|
else if (child.tag === "table:table-row") placedRows.push(placedCells(child, pkg));
|
|
279
305
|
}
|
|
280
306
|
return resolveLiveTableGrid(placedRows, declaredColumns);
|
|
@@ -318,14 +344,15 @@ function refuseMerge(rowIndex, reason) {
|
|
|
318
344
|
}
|
|
319
345
|
function planMerge(table, pkg, target, rows) {
|
|
320
346
|
const [anchorRow, ...coveredRows] = rows;
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
const anchor = anchorCells[target.column];
|
|
324
|
-
if (anchor === void 0) return refuseMerge(target.row, `column ${target.column} does not exist in this row`);
|
|
347
|
+
const anchorElement = locateGridColumnElement(anchorRow, target.column);
|
|
348
|
+
if (anchorElement === void 0) return refuseMerge(target.row, `column ${target.column} does not exist in this row`);
|
|
325
349
|
const endColumn = target.column + target.columnSpan;
|
|
326
|
-
for (const [offset,
|
|
350
|
+
for (const [offset, row] of rows.entries()) {
|
|
351
|
+
const totalColumns = rowGridColumnCount(row);
|
|
352
|
+
if (endColumn > totalColumns) return refuseMerge(target.row + offset, `colSpan ${target.columnSpan} starting at column ${target.column} exceeds this row's own ${totalColumns} grid columns`);
|
|
353
|
+
}
|
|
327
354
|
const regions = anchorRegions(resolveOdtGrid(table, pkg));
|
|
328
|
-
if (
|
|
355
|
+
if (anchorElement.tag === "table:covered-table-cell") {
|
|
329
356
|
const covering = regions.find((region) => regionCovers(region, target.row, target.column));
|
|
330
357
|
return refuseMerge(target.row, covering === void 0 ? `column ${target.column} is a covered position that no merge anchors` : `column ${target.column} is covered by ${describeRegionAnchor(covering)}`);
|
|
331
358
|
}
|
|
@@ -334,14 +361,26 @@ function planMerge(table, pkg, target, rows) {
|
|
|
334
361
|
const column = Math.max(cutting.column, target.column);
|
|
335
362
|
return refuseMerge(Math.max(cutting.row, target.row), `column ${column} belongs to ${describeRegionAnchor(cutting)}, which reaches outside the region being merged and cannot be merged over`);
|
|
336
363
|
}
|
|
364
|
+
const consumed = [];
|
|
365
|
+
for (let column = target.column + 1; column < endColumn; column++) consumed.push({
|
|
366
|
+
row: anchorRow,
|
|
367
|
+
column
|
|
368
|
+
});
|
|
369
|
+
for (const row of coveredRows) for (let column = target.column; column < endColumn; column++) consumed.push({
|
|
370
|
+
row,
|
|
371
|
+
column
|
|
372
|
+
});
|
|
337
373
|
return {
|
|
338
|
-
anchor
|
|
339
|
-
|
|
374
|
+
anchor: {
|
|
375
|
+
row: anchorRow,
|
|
376
|
+
column: target.column
|
|
377
|
+
},
|
|
378
|
+
consumed
|
|
340
379
|
};
|
|
341
380
|
}
|
|
342
381
|
function applyMerge(plan, target, pkg) {
|
|
343
|
-
for (const
|
|
344
|
-
const anchor = new OdtTableCell(plan.anchor, pkg);
|
|
382
|
+
for (const position of plan.consumed) retagAsCovered(individuateGridColumn(position.row, position.column));
|
|
383
|
+
const anchor = new OdtTableCell(individuateGridColumn(plan.anchor.row, plan.anchor.column), pkg);
|
|
345
384
|
anchor.colSpan = target.columnSpan;
|
|
346
385
|
if (target.rowSpan > 1) anchor.rowSpan = target.rowSpan;
|
|
347
386
|
return anchor;
|
|
@@ -401,12 +440,12 @@ var OdtTableRow = class {
|
|
|
401
440
|
return applyMerge(plan, target, this.pkg);
|
|
402
441
|
}
|
|
403
442
|
markCellCovered(columnIndex) {
|
|
404
|
-
const
|
|
405
|
-
if (
|
|
443
|
+
const totalColumns = rowGridColumnCount(this.node);
|
|
444
|
+
if (columnIndex < 0 || columnIndex >= totalColumns) throw new Error(`markCellCovered: column ${columnIndex} does not exist in this row`);
|
|
406
445
|
const rowIndex = tableRowElements(this.table).indexOf(this.node);
|
|
407
446
|
const anchored = anchorRegions(resolveOdtGrid(this.table, this.pkg)).find((region) => region.row === rowIndex && region.column === columnIndex && (region.rowSpan > 1 || region.columnSpan > 1));
|
|
408
447
|
if (anchored !== void 0) throw new Error(`markCellCovered: column ${columnIndex} anchors a merge with rowSpan ${anchored.rowSpan} and colSpan ${anchored.columnSpan}, so covering it would leave the rest of that merge without an anchor`);
|
|
409
|
-
retagAsCovered(
|
|
448
|
+
retagAsCovered(individuateGridColumn(this.node, columnIndex));
|
|
410
449
|
}
|
|
411
450
|
};
|
|
412
451
|
function buildCell(pkg) {
|
|
@@ -138,6 +138,7 @@ function populatePptxTable(table, block, resolveHyperlinkRId) {
|
|
|
138
138
|
function applyCellDecoration(target, cell) {
|
|
139
139
|
if (cell.background !== void 0) target.background = (0, document_schema_js.resolveCellFillColor)(cell.background);
|
|
140
140
|
target.borders = cell.borders;
|
|
141
|
+
target.verticalAlign = cell.verticalAlign;
|
|
141
142
|
}
|
|
142
143
|
//#endregion
|
|
143
144
|
exports.buildPptxPackage = buildPptxPackage;
|
|
@@ -137,6 +137,7 @@ function populatePptxTable(table, block, resolveHyperlinkRId) {
|
|
|
137
137
|
function applyCellDecoration(target, cell) {
|
|
138
138
|
if (cell.background !== void 0) target.background = resolveCellFillColor(cell.background);
|
|
139
139
|
target.borders = cell.borders;
|
|
140
|
+
target.verticalAlign = cell.verticalAlign;
|
|
140
141
|
}
|
|
141
142
|
//#endregion
|
|
142
143
|
export { buildPptxPackage, embeddedPresentationSerialiser };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as ImageInit } from "../../image-C3L2cCLQ.cjs";
|
|
2
2
|
import { r as PptxShape } from "../../shape-C2ef6uwC.cjs";
|
|
3
|
-
import { r as PptxTableInit, t as PptxTable } from "../../table-
|
|
3
|
+
import { r as PptxTableInit, t as PptxTable } from "../../table-ukpjK2hS.cjs";
|
|
4
4
|
import { Box, ContentVector } from "document-schema.js";
|
|
5
5
|
import { Package, XmlElement, XmlNode } from "ooxml.js";
|
|
6
6
|
//#region src/edit/pptx/slide.d.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as ImageInit } from "../../image-CAeD6ZbR.js";
|
|
2
2
|
import { r as PptxShape } from "../../shape-DwZouh8R.js";
|
|
3
|
-
import { r as PptxTableInit, t as PptxTable } from "../../table-
|
|
3
|
+
import { r as PptxTableInit, t as PptxTable } from "../../table-BuNLtwgL.js";
|
|
4
4
|
import { Package, XmlElement, XmlNode } from "ooxml.js";
|
|
5
5
|
import { Box, ContentVector } from "document-schema.js";
|
|
6
6
|
//#region src/edit/pptx/slide.d.ts
|
package/dist/edit/pptx/table.cjs
CHANGED
|
@@ -10,6 +10,16 @@ let document_schema_js = require("document-schema.js");
|
|
|
10
10
|
const DEFAULT_TABLE_WIDTH_PT = 468;
|
|
11
11
|
const DEFAULT_ROW_HEIGHT_PT = 20;
|
|
12
12
|
const TABLE_GRAPHIC_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
|
|
13
|
+
const PPTX_TABLE_CELL_VERTICAL_ALIGN_ANCHOR = {
|
|
14
|
+
top: "t",
|
|
15
|
+
center: "ctr",
|
|
16
|
+
bottom: "b"
|
|
17
|
+
};
|
|
18
|
+
const ANCHOR_TABLE_CELL_VERTICAL_ALIGN = /* @__PURE__ */ new Map([
|
|
19
|
+
["t", "top"],
|
|
20
|
+
["ctr", "center"],
|
|
21
|
+
["b", "bottom"]
|
|
22
|
+
]);
|
|
13
23
|
var PptxTableCell = class {
|
|
14
24
|
node;
|
|
15
25
|
constructor(node) {
|
|
@@ -108,6 +118,21 @@ var PptxTableCell = class {
|
|
|
108
118
|
tcPr.children.push(require_xml_fragment.el(tag, { w: String(require_model_units.ptToEmu(border.widthPt)) }, [require_xml_fragment.el("a:solidFill", {}, [require_xml_fragment.el("a:srgbClr", { val: require_edit_drawingml_vector.drawingMlColorHex(border.color) })])]));
|
|
109
119
|
}
|
|
110
120
|
}
|
|
121
|
+
get verticalAlign() {
|
|
122
|
+
const tcPr = this.tcPrElement(false);
|
|
123
|
+
if (tcPr === void 0) return;
|
|
124
|
+
const anchor = (0, ooxml_js.attr)(tcPr, "anchor");
|
|
125
|
+
return anchor === void 0 ? void 0 : ANCHOR_TABLE_CELL_VERTICAL_ALIGN.get(anchor);
|
|
126
|
+
}
|
|
127
|
+
set verticalAlign(value) {
|
|
128
|
+
if (value === void 0) {
|
|
129
|
+
const tcPr = this.tcPrElement(false);
|
|
130
|
+
if (tcPr !== void 0) require_xml_edit.removeAttr(tcPr, "anchor");
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const tcPr = this.tcPrElement(true);
|
|
134
|
+
require_xml_edit.setAttr(tcPr, "anchor", PPTX_TABLE_CELL_VERTICAL_ALIGN_ANCHOR[value]);
|
|
135
|
+
}
|
|
111
136
|
readBorder(lnElement) {
|
|
112
137
|
if (lnElement === void 0) return;
|
|
113
138
|
const w = (0, ooxml_js.attr)(lnElement, "w");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as buildDrawingTable, i as PptxTableRow, n as PptxTableCell, o as buildTableGraphicFrame, r as PptxTableInit, s as findGraphicFrameTable, t as PptxTable } from "../../table-
|
|
1
|
+
import { a as buildDrawingTable, i as PptxTableRow, n as PptxTableCell, o as buildTableGraphicFrame, r as PptxTableInit, s as findGraphicFrameTable, t as PptxTable } from "../../table-ukpjK2hS.cjs";
|
|
2
2
|
export { PptxTable, PptxTableCell, PptxTableInit, PptxTableRow, buildDrawingTable, buildTableGraphicFrame, findGraphicFrameTable };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as buildDrawingTable, i as PptxTableRow, n as PptxTableCell, o as buildTableGraphicFrame, r as PptxTableInit, s as findGraphicFrameTable, t as PptxTable } from "../../table-
|
|
1
|
+
import { a as buildDrawingTable, i as PptxTableRow, n as PptxTableCell, o as buildTableGraphicFrame, r as PptxTableInit, s as findGraphicFrameTable, t as PptxTable } from "../../table-BuNLtwgL.js";
|
|
2
2
|
export { PptxTable, PptxTableCell, PptxTableInit, PptxTableRow, buildDrawingTable, buildTableGraphicFrame, findGraphicFrameTable };
|
package/dist/edit/pptx/table.js
CHANGED
|
@@ -9,6 +9,16 @@ import { rgbHexToColor } from "document-schema.js";
|
|
|
9
9
|
const DEFAULT_TABLE_WIDTH_PT = 468;
|
|
10
10
|
const DEFAULT_ROW_HEIGHT_PT = 20;
|
|
11
11
|
const TABLE_GRAPHIC_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
|
|
12
|
+
const PPTX_TABLE_CELL_VERTICAL_ALIGN_ANCHOR = {
|
|
13
|
+
top: "t",
|
|
14
|
+
center: "ctr",
|
|
15
|
+
bottom: "b"
|
|
16
|
+
};
|
|
17
|
+
const ANCHOR_TABLE_CELL_VERTICAL_ALIGN = /* @__PURE__ */ new Map([
|
|
18
|
+
["t", "top"],
|
|
19
|
+
["ctr", "center"],
|
|
20
|
+
["b", "bottom"]
|
|
21
|
+
]);
|
|
12
22
|
var PptxTableCell = class {
|
|
13
23
|
node;
|
|
14
24
|
constructor(node) {
|
|
@@ -107,6 +117,21 @@ var PptxTableCell = class {
|
|
|
107
117
|
tcPr.children.push(el(tag, { w: String(ptToEmu(border.widthPt)) }, [el("a:solidFill", {}, [el("a:srgbClr", { val: drawingMlColorHex(border.color) })])]));
|
|
108
118
|
}
|
|
109
119
|
}
|
|
120
|
+
get verticalAlign() {
|
|
121
|
+
const tcPr = this.tcPrElement(false);
|
|
122
|
+
if (tcPr === void 0) return;
|
|
123
|
+
const anchor = attr(tcPr, "anchor");
|
|
124
|
+
return anchor === void 0 ? void 0 : ANCHOR_TABLE_CELL_VERTICAL_ALIGN.get(anchor);
|
|
125
|
+
}
|
|
126
|
+
set verticalAlign(value) {
|
|
127
|
+
if (value === void 0) {
|
|
128
|
+
const tcPr = this.tcPrElement(false);
|
|
129
|
+
if (tcPr !== void 0) removeAttr(tcPr, "anchor");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const tcPr = this.tcPrElement(true);
|
|
133
|
+
setAttr(tcPr, "anchor", PPTX_TABLE_CELL_VERTICAL_ALIGN_ANCHOR[value]);
|
|
134
|
+
}
|
|
110
135
|
readBorder(lnElement) {
|
|
111
136
|
if (lnElement === void 0) return;
|
|
112
137
|
const w = attr(lnElement, "w");
|
package/dist/index.d.cts
CHANGED
|
@@ -66,7 +66,7 @@ import { PptShape, PptSlide } from "./edit/ppt/slide.cjs";
|
|
|
66
66
|
import { CreatePptOptions, PptEditor, createPpt, openPpt } from "./edit/ppt/editor.cjs";
|
|
67
67
|
import { BuildPptxPackageOptions, buildPptxPackage, embeddedPresentationSerialiser } from "./edit/pptx/content.cjs";
|
|
68
68
|
import { n as DrawingRunInit, r as PptxShape, t as DrawingParagraphInit } from "./shape-C2ef6uwC.cjs";
|
|
69
|
-
import { i as PptxTableRow, n as PptxTableCell, r as PptxTableInit, t as PptxTable } from "./table-
|
|
69
|
+
import { i as PptxTableRow, n as PptxTableCell, r as PptxTableInit, t as PptxTable } from "./table-ukpjK2hS.cjs";
|
|
70
70
|
import { PptxSlide, SlideImageInit as SlideImageInit$1, SlideTableInit as SlideTableInit$1, TextBoxInit as TextBoxInit$2 } from "./edit/pptx/slide.cjs";
|
|
71
71
|
import { CreatePptxOptions, PptxEditor, createPptx, openPptx } from "./edit/pptx/editor.cjs";
|
|
72
72
|
import { CreateEmptyPptxPackageOptions } from "./edit/pptx/scaffold.cjs";
|
package/dist/index.d.ts
CHANGED
|
@@ -66,7 +66,7 @@ import { PptShape, PptSlide } from "./edit/ppt/slide.js";
|
|
|
66
66
|
import { CreatePptOptions, PptEditor, createPpt, openPpt } from "./edit/ppt/editor.js";
|
|
67
67
|
import { BuildPptxPackageOptions, buildPptxPackage, embeddedPresentationSerialiser } from "./edit/pptx/content.js";
|
|
68
68
|
import { n as DrawingRunInit, r as PptxShape, t as DrawingParagraphInit } from "./shape-DwZouh8R.js";
|
|
69
|
-
import { i as PptxTableRow, n as PptxTableCell, r as PptxTableInit, t as PptxTable } from "./table-
|
|
69
|
+
import { i as PptxTableRow, n as PptxTableCell, r as PptxTableInit, t as PptxTable } from "./table-BuNLtwgL.js";
|
|
70
70
|
import { PptxSlide, SlideImageInit as SlideImageInit$1, SlideTableInit as SlideTableInit$1, TextBoxInit as TextBoxInit$2 } from "./edit/pptx/slide.js";
|
|
71
71
|
import { CreatePptxOptions, PptxEditor, createPptx, openPptx } from "./edit/pptx/editor.js";
|
|
72
72
|
import { CreateEmptyPptxPackageOptions } from "./edit/pptx/scaffold.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as DrawingParagraphInit } from "./shape-DwZouh8R.js";
|
|
2
2
|
import { XmlElement } from "ooxml.js";
|
|
3
|
-
import { Box, Color, ContentCellBorders } from "document-schema.js";
|
|
3
|
+
import { Box, Color, ContentCellBorders, ContentTableCell } from "document-schema.js";
|
|
4
4
|
//#region src/edit/pptx/table.d.ts
|
|
5
5
|
interface PptxTableInit {
|
|
6
6
|
readonly rows: number;
|
|
@@ -22,6 +22,8 @@ declare class PptxTableCell {
|
|
|
22
22
|
set background(value: Color | undefined);
|
|
23
23
|
get borders(): ContentCellBorders | undefined;
|
|
24
24
|
set borders(value: ContentCellBorders | undefined);
|
|
25
|
+
get verticalAlign(): ContentTableCell["verticalAlign"];
|
|
26
|
+
set verticalAlign(value: ContentTableCell["verticalAlign"]);
|
|
25
27
|
private readBorder;
|
|
26
28
|
setParagraphs(paragraphs: readonly DrawingParagraphInit[]): void;
|
|
27
29
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as DrawingParagraphInit } from "./shape-C2ef6uwC.cjs";
|
|
2
|
-
import { Box, Color, ContentCellBorders } from "document-schema.js";
|
|
2
|
+
import { Box, Color, ContentCellBorders, ContentTableCell } from "document-schema.js";
|
|
3
3
|
import { XmlElement } from "ooxml.js";
|
|
4
4
|
//#region src/edit/pptx/table.d.ts
|
|
5
5
|
interface PptxTableInit {
|
|
@@ -22,6 +22,8 @@ declare class PptxTableCell {
|
|
|
22
22
|
set background(value: Color | undefined);
|
|
23
23
|
get borders(): ContentCellBorders | undefined;
|
|
24
24
|
set borders(value: ContentCellBorders | undefined);
|
|
25
|
+
get verticalAlign(): ContentTableCell["verticalAlign"];
|
|
26
|
+
set verticalAlign(value: ContentTableCell["verticalAlign"]);
|
|
25
27
|
private readBorder;
|
|
26
28
|
setParagraphs(paragraphs: readonly DrawingParagraphInit[]): void;
|
|
27
29
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js.documents",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"description": "Bidirectional docx/pptx <-> PDF conversion and a read+write editable OOXML document model, built on ooxml.js and Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"fflate": "0.8.3",
|
|
86
86
|
"markdown-codec": "10.0.0",
|
|
87
87
|
"odf.js": "10.0.0",
|
|
88
|
-
"ooxml.js": "11.
|
|
88
|
+
"ooxml.js": "11.1.0",
|
|
89
89
|
"pdf-codec": "5.2.3",
|
|
90
90
|
"ppt-codec": "2.0.4",
|
|
91
91
|
"rtf-codec": "7.0.0",
|