pptx-viewer-mcp 2.5.9 → 2.6.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/CHANGELOG.md +6 -0
- package/LICENSE +202 -0
- package/README.md +8 -0
- package/dist/codec/index.d.ts +4 -49
- package/dist/codec/index.d.ts.map +1 -1
- package/dist/codec/index.js +7 -357
- package/dist/codec/index.mjs +7 -357
- package/dist/index.d.ts +192 -1277
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +90 -3204
- package/dist/index.mjs +89 -3204
- package/dist/mcp/cli.d.ts +1 -0
- package/dist/mcp/cli.js +2288 -0
- package/dist/mcp/cli.mjs +2286 -0
- package/dist/mcp/index.d.ts +18 -1
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +240 -3313
- package/dist/mcp/index.mjs +239 -3313
- package/dist/types-BUuwyzY-.d.ts +11 -0
- package/dist/types-BUuwyzY-.d.ts.map +1 -0
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,3214 +1,100 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var automation = require('ooxml-core/pptx/automation');
|
|
4
|
+
var pptx = require('ooxml-core/pptx');
|
|
4
5
|
|
|
5
6
|
// src/execution.ts
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (el.rotation) {
|
|
94
|
-
base.rotation = el.rotation;
|
|
95
|
-
}
|
|
96
|
-
if (el.hidden) {
|
|
97
|
-
base.hidden = true;
|
|
98
|
-
}
|
|
99
|
-
if (el.opacity !== void 0 && el.opacity !== 1) {
|
|
100
|
-
base.opacity = el.opacity;
|
|
101
|
-
}
|
|
102
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
103
|
-
base.text = el.text ?? "";
|
|
104
|
-
if (el.textStyle) {
|
|
105
|
-
const ts = {};
|
|
106
|
-
if (el.textStyle.fontSize) {
|
|
107
|
-
ts.fontSize = el.textStyle.fontSize;
|
|
108
|
-
}
|
|
109
|
-
if (el.textStyle.fontFamily) {
|
|
110
|
-
ts.fontFamily = el.textStyle.fontFamily;
|
|
111
|
-
}
|
|
112
|
-
if (el.textStyle.bold) {
|
|
113
|
-
ts.bold = true;
|
|
114
|
-
}
|
|
115
|
-
if (el.textStyle.italic) {
|
|
116
|
-
ts.italic = true;
|
|
117
|
-
}
|
|
118
|
-
if (el.textStyle.underline) {
|
|
119
|
-
ts.underline = el.textStyle.underline;
|
|
120
|
-
}
|
|
121
|
-
if (el.textStyle.align) {
|
|
122
|
-
ts.align = el.textStyle.align;
|
|
123
|
-
}
|
|
124
|
-
if (el.textStyle.color) {
|
|
125
|
-
ts.color = el.textStyle.color;
|
|
126
|
-
}
|
|
127
|
-
if (Object.keys(ts).length > 0) {
|
|
128
|
-
base.textStyle = ts;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if ("shapeType" in el && el.shapeType) {
|
|
133
|
-
base.shapeType = el.shapeType;
|
|
134
|
-
}
|
|
135
|
-
if ("shapeStyle" in el && el.shapeStyle) {
|
|
136
|
-
const ss = {};
|
|
137
|
-
const style = el.shapeStyle;
|
|
138
|
-
if (style.fillColor) {
|
|
139
|
-
ss.fillColor = style.fillColor;
|
|
140
|
-
}
|
|
141
|
-
if (style.strokeColor) {
|
|
142
|
-
ss.strokeColor = style.strokeColor;
|
|
143
|
-
}
|
|
144
|
-
if (style.strokeWidth) {
|
|
145
|
-
ss.strokeWidth = style.strokeWidth;
|
|
146
|
-
}
|
|
147
|
-
if (Object.keys(ss).length > 0) {
|
|
148
|
-
base.shapeStyle = ss;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (el.type === "image" || el.type === "picture") {
|
|
152
|
-
const img = el;
|
|
153
|
-
if (img.altText) {
|
|
154
|
-
base.altText = img.altText;
|
|
155
|
-
}
|
|
156
|
-
if (img.imagePath) {
|
|
157
|
-
base.imagePath = img.imagePath;
|
|
158
|
-
}
|
|
159
|
-
base.hasImageData = Boolean(img.imageData);
|
|
160
|
-
}
|
|
161
|
-
if (el.type === "table") {
|
|
162
|
-
const tbl = el;
|
|
163
|
-
if (tbl.tableData) {
|
|
164
|
-
base.rowCount = tbl.tableData.rows.length;
|
|
165
|
-
base.columnCount = tbl.tableData.columnWidths.length;
|
|
166
|
-
base.cells = tbl.tableData.rows.map((row) => row.cells.map((cell) => cell.text ?? ""));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (el.type === "chart" && el.chartData) {
|
|
170
|
-
base.chartType = pptxViewerCore.resolveDisplayedChartTypeName(el.chartData);
|
|
171
|
-
}
|
|
172
|
-
if (el.type === "group") {
|
|
173
|
-
const grp = el;
|
|
174
|
-
base.childCount = grp.children?.length ?? 0;
|
|
175
|
-
}
|
|
176
|
-
return base;
|
|
177
|
-
}
|
|
178
|
-
function extractSlideText(slide) {
|
|
179
|
-
const texts = [];
|
|
180
|
-
for (const el of slide.elements) {
|
|
181
|
-
if (pptxViewerCore.hasTextProperties(el) && el.text) {
|
|
182
|
-
texts.push(el.text);
|
|
183
|
-
}
|
|
184
|
-
if (el.type === "table") {
|
|
185
|
-
const tbl = el;
|
|
186
|
-
if (tbl.tableData) {
|
|
187
|
-
for (const row of tbl.tableData.rows) {
|
|
188
|
-
for (const cell of row.cells) {
|
|
189
|
-
if (cell.text) {
|
|
190
|
-
texts.push(cell.text);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
if (slide.notes) {
|
|
198
|
-
texts.push(slide.notes);
|
|
199
|
-
}
|
|
200
|
-
return texts.join(" ");
|
|
201
|
-
}
|
|
202
|
-
function validateSlideIndex(slideIndex, slideCount) {
|
|
203
|
-
if (slideIndex < 0 || slideIndex >= slideCount) {
|
|
204
|
-
return `Slide index ${slideIndex} out of range (0\u2013${slideCount - 1}).`;
|
|
205
|
-
}
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// src/tools/slide-tools.ts
|
|
210
|
-
function getSlide(ctx, params) {
|
|
211
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
212
|
-
if (err) {
|
|
213
|
-
throw new Error(err);
|
|
214
|
-
}
|
|
215
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
216
|
-
return {
|
|
217
|
-
pptxData: ctx.pptxData,
|
|
218
|
-
dirty: false,
|
|
219
|
-
result: {
|
|
220
|
-
slideIndex: params.slideIndex,
|
|
221
|
-
slideNumber: slide.slideNumber,
|
|
222
|
-
hidden: slide.hidden ?? false,
|
|
223
|
-
layoutName: slide.layoutName,
|
|
224
|
-
backgroundColor: slide.backgroundColor,
|
|
225
|
-
notes: slide.notes ?? "",
|
|
226
|
-
commentCount: slide.comments?.length ?? 0,
|
|
227
|
-
elements: slide.elements.map(describeElement)
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
function addSlide(ctx, params) {
|
|
232
|
-
const { slides } = ctx.pptxData;
|
|
233
|
-
const insertAt = params.insertAfterIndex !== void 0 && params.insertAfterIndex >= 0 ? Math.min(params.insertAfterIndex + 1, slides.length) : slides.length;
|
|
234
|
-
const newSlide = {
|
|
235
|
-
id: generateSlideId(),
|
|
236
|
-
rId: "",
|
|
237
|
-
slideNumber: insertAt + 1,
|
|
238
|
-
elements: [],
|
|
239
|
-
backgroundColor: params.backgroundColor
|
|
240
|
-
};
|
|
241
|
-
slides.splice(insertAt, 0, newSlide);
|
|
242
|
-
slides.forEach((s, i) => {
|
|
243
|
-
s.slideNumber = i + 1;
|
|
244
|
-
});
|
|
245
|
-
return {
|
|
246
|
-
pptxData: ctx.pptxData,
|
|
247
|
-
dirty: true,
|
|
248
|
-
result: { newSlideIndex: insertAt, slideCount: slides.length }
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
function deleteSlides(ctx, params) {
|
|
252
|
-
const { slides } = ctx.pptxData;
|
|
253
|
-
if (!params.slideIndexes || params.slideIndexes.length === 0) {
|
|
254
|
-
throw new Error("slideIndexes is required for the delete action.");
|
|
255
|
-
}
|
|
256
|
-
const indexSet = new Set(params.slideIndexes);
|
|
257
|
-
const invalid = params.slideIndexes.filter((i) => i < 0 || i >= slides.length);
|
|
258
|
-
if (invalid.length > 0) {
|
|
259
|
-
throw new Error(
|
|
260
|
-
`Invalid slide indexes: ${invalid.join(", ")}. Valid range: 0\u2013${slides.length - 1}.`
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
if (indexSet.size >= slides.length) {
|
|
264
|
-
throw new Error("Cannot delete all slides. At least one slide must remain.");
|
|
265
|
-
}
|
|
266
|
-
ctx.pptxData.slides = slides.filter((_, i) => !indexSet.has(i));
|
|
267
|
-
ctx.pptxData.slides.forEach((s, i) => {
|
|
268
|
-
s.slideNumber = i + 1;
|
|
269
|
-
});
|
|
270
|
-
return {
|
|
271
|
-
pptxData: ctx.pptxData,
|
|
272
|
-
dirty: true,
|
|
273
|
-
result: { deletedCount: indexSet.size, slideCount: ctx.pptxData.slides.length }
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
function reorderSlides(ctx, params) {
|
|
277
|
-
const { slides } = ctx.pptxData;
|
|
278
|
-
if (!params.newOrder || params.newOrder.length !== slides.length) {
|
|
279
|
-
throw new Error(
|
|
280
|
-
`newOrder must have exactly ${slides.length} indexes. Got ${params.newOrder?.length ?? 0}.`
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
const sorted = [...params.newOrder].sort((a, b) => a - b);
|
|
284
|
-
const expected = slides.map((_, i) => i);
|
|
285
|
-
if (JSON.stringify(sorted) !== JSON.stringify(expected)) {
|
|
286
|
-
throw new Error(
|
|
287
|
-
`newOrder must contain each index from 0 to ${slides.length - 1} exactly once.`
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
ctx.pptxData.slides = params.newOrder.map((idx) => slides[idx]);
|
|
291
|
-
ctx.pptxData.slides.forEach((s, i) => {
|
|
292
|
-
s.slideNumber = i + 1;
|
|
293
|
-
});
|
|
294
|
-
return {
|
|
295
|
-
pptxData: ctx.pptxData,
|
|
296
|
-
dirty: true,
|
|
297
|
-
result: { slideCount: ctx.pptxData.slides.length }
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
function duplicateSlide(ctx, params) {
|
|
301
|
-
const { slides } = ctx.pptxData;
|
|
302
|
-
const err = validateSlideIndex(params.slideIndex, slides.length);
|
|
303
|
-
if (err) {
|
|
304
|
-
throw new Error(err);
|
|
305
|
-
}
|
|
306
|
-
const original = slides[params.slideIndex];
|
|
307
|
-
const clone = structuredClone(original);
|
|
308
|
-
clone.id = generateSlideId();
|
|
309
|
-
clone.rId = "";
|
|
310
|
-
for (const el of clone.elements) {
|
|
311
|
-
el.id = generateElementId();
|
|
312
|
-
}
|
|
313
|
-
const insertIndex = params.targetIndex ?? params.slideIndex + 1;
|
|
314
|
-
slides.splice(insertIndex, 0, clone);
|
|
315
|
-
slides.forEach((s, i) => {
|
|
316
|
-
s.slideNumber = i + 1;
|
|
317
|
-
});
|
|
318
|
-
return {
|
|
319
|
-
pptxData: ctx.pptxData,
|
|
320
|
-
dirty: true,
|
|
321
|
-
result: { newSlideIndex: insertIndex, slideCount: slides.length }
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
function updateSlideProperties(ctx, params) {
|
|
325
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
326
|
-
if (err) {
|
|
327
|
-
throw new Error(err);
|
|
328
|
-
}
|
|
329
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
330
|
-
if (params.backgroundColor !== void 0) {
|
|
331
|
-
slide.backgroundColor = params.backgroundColor;
|
|
332
|
-
}
|
|
333
|
-
if (params.backgroundGradient !== void 0) {
|
|
334
|
-
slide.backgroundGradient = params.backgroundGradient;
|
|
335
|
-
}
|
|
336
|
-
if (params.backgroundImage !== void 0) {
|
|
337
|
-
slide.backgroundImage = params.backgroundImage;
|
|
338
|
-
}
|
|
339
|
-
if (params.notes !== void 0) {
|
|
340
|
-
slide.notes = params.notes;
|
|
341
|
-
}
|
|
342
|
-
if (params.hidden !== void 0) {
|
|
343
|
-
slide.hidden = params.hidden;
|
|
344
|
-
}
|
|
345
|
-
return {
|
|
346
|
-
pptxData: ctx.pptxData,
|
|
347
|
-
dirty: true,
|
|
348
|
-
result: { slideIndex: params.slideIndex }
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
function setSlideTransition(ctx, params) {
|
|
352
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
353
|
-
if (err) {
|
|
354
|
-
throw new Error(err);
|
|
355
|
-
}
|
|
356
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
357
|
-
if (params.type === "none") {
|
|
358
|
-
slide.transition = void 0;
|
|
359
|
-
} else {
|
|
360
|
-
const transition = {
|
|
361
|
-
type: params.type
|
|
362
|
-
};
|
|
363
|
-
if (params.durationMs !== void 0) {
|
|
364
|
-
transition.durationMs = params.durationMs;
|
|
365
|
-
}
|
|
366
|
-
if (params.direction !== void 0) {
|
|
367
|
-
transition.direction = params.direction;
|
|
368
|
-
}
|
|
369
|
-
if (params.advanceOnClick !== void 0) {
|
|
370
|
-
transition.advanceOnClick = params.advanceOnClick;
|
|
371
|
-
}
|
|
372
|
-
if (params.advanceAfterMs !== void 0) {
|
|
373
|
-
transition.advanceAfterMs = params.advanceAfterMs;
|
|
374
|
-
}
|
|
375
|
-
slide.transition = transition;
|
|
376
|
-
}
|
|
377
|
-
return {
|
|
378
|
-
pptxData: ctx.pptxData,
|
|
379
|
-
dirty: true,
|
|
380
|
-
result: { slideIndex: params.slideIndex, transitionType: params.type }
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
function setCanvasSize(ctx, params) {
|
|
384
|
-
ctx.pptxData.width = params.width;
|
|
385
|
-
ctx.pptxData.height = params.height;
|
|
386
|
-
if (ctx.pptxData.widthEmu !== void 0) {
|
|
387
|
-
ctx.pptxData.widthEmu = Math.round(params.width * 12700);
|
|
388
|
-
}
|
|
389
|
-
if (ctx.pptxData.heightEmu !== void 0) {
|
|
390
|
-
ctx.pptxData.heightEmu = Math.round(params.height * 12700);
|
|
391
|
-
}
|
|
392
|
-
return {
|
|
393
|
-
pptxData: ctx.pptxData,
|
|
394
|
-
dirty: true,
|
|
395
|
-
result: { canvasWidth: params.width, canvasHeight: params.height }
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
var ALT_TEXT_ELEMENT_TYPES = /* @__PURE__ */ new Set(["image", "picture", "table", "chart", "smartArt", "ole", "media", "text", "shape", "connector"]);
|
|
399
|
-
var TITLE_ELEMENT_TYPES = /* @__PURE__ */ new Set([
|
|
400
|
-
"table",
|
|
401
|
-
"chart",
|
|
402
|
-
"smartArt",
|
|
403
|
-
"ole",
|
|
404
|
-
"media",
|
|
405
|
-
"text",
|
|
406
|
-
"shape",
|
|
407
|
-
"connector"
|
|
408
|
-
]);
|
|
409
|
-
function applyElementAltText(el, altText) {
|
|
410
|
-
if (!ALT_TEXT_ELEMENT_TYPES.has(el.type)) {
|
|
411
|
-
throw new Error(
|
|
412
|
-
`Element '${el.id}' (${el.type}) does not support altText; only ${[...ALT_TEXT_ELEMENT_TYPES].join(", ")} elements do.`
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
el.altText = altText;
|
|
416
|
-
}
|
|
417
|
-
function applyElementTitle(el, title) {
|
|
418
|
-
if (!TITLE_ELEMENT_TYPES.has(el.type)) {
|
|
419
|
-
throw new Error(
|
|
420
|
-
`Element '${el.id}' (${el.type}) does not support title; only ${[...TITLE_ELEMENT_TYPES].join(", ")} elements do.`
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
el.title = title;
|
|
424
|
-
}
|
|
425
|
-
function updateElementStyle(ctx, params) {
|
|
426
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
427
|
-
if (err) {
|
|
428
|
-
throw new Error(err);
|
|
429
|
-
}
|
|
430
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
431
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
432
|
-
if (!el) {
|
|
433
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
434
|
-
}
|
|
435
|
-
if ("shapeStyle" in el) {
|
|
436
|
-
if (!el.shapeStyle) {
|
|
437
|
-
el.shapeStyle = {};
|
|
438
|
-
}
|
|
439
|
-
const ss = el.shapeStyle;
|
|
440
|
-
if (params.fillThemeColor !== void 0) {
|
|
441
|
-
ss.fillColorRef = params.fillThemeColor;
|
|
442
|
-
const resolved = pptxViewerCore.resolveThemeColorRef(params.fillThemeColor, ctx.pptxData.themeColorMap);
|
|
443
|
-
if (params.fillColor !== void 0) {
|
|
444
|
-
ss.fillColor = params.fillColor;
|
|
445
|
-
} else if (resolved) {
|
|
446
|
-
ss.fillColor = resolved;
|
|
447
|
-
}
|
|
448
|
-
} else if (params.fillColor !== void 0) {
|
|
449
|
-
ss.fillColor = params.fillColor;
|
|
450
|
-
ss.fillColorRef = void 0;
|
|
451
|
-
}
|
|
452
|
-
if (params.fillMode !== void 0) {
|
|
453
|
-
ss.fillMode = params.fillMode;
|
|
454
|
-
}
|
|
455
|
-
if (params.fillGradientStops !== void 0) {
|
|
456
|
-
ss.fillGradientStops = params.fillGradientStops;
|
|
457
|
-
}
|
|
458
|
-
if (params.fillGradientAngle !== void 0) {
|
|
459
|
-
ss.fillGradientAngle = params.fillGradientAngle;
|
|
460
|
-
}
|
|
461
|
-
if (params.fillGradientType !== void 0) {
|
|
462
|
-
ss.fillGradientType = params.fillGradientType;
|
|
463
|
-
}
|
|
464
|
-
if (params.fillOpacity !== void 0) {
|
|
465
|
-
ss.fillOpacity = params.fillOpacity;
|
|
466
|
-
}
|
|
467
|
-
if (params.strokeThemeColor !== void 0) {
|
|
468
|
-
ss.strokeColorRef = params.strokeThemeColor;
|
|
469
|
-
const resolved = pptxViewerCore.resolveThemeColorRef(params.strokeThemeColor, ctx.pptxData.themeColorMap);
|
|
470
|
-
if (params.strokeColor !== void 0) {
|
|
471
|
-
ss.strokeColor = params.strokeColor;
|
|
472
|
-
} else if (resolved) {
|
|
473
|
-
ss.strokeColor = resolved;
|
|
474
|
-
}
|
|
475
|
-
} else if (params.strokeColor !== void 0) {
|
|
476
|
-
ss.strokeColor = params.strokeColor;
|
|
477
|
-
ss.strokeColorRef = void 0;
|
|
478
|
-
}
|
|
479
|
-
if (params.strokeWidth !== void 0) {
|
|
480
|
-
ss.strokeWidth = params.strokeWidth;
|
|
481
|
-
}
|
|
482
|
-
if (params.strokeDash !== void 0) {
|
|
483
|
-
ss.strokeDash = params.strokeDash;
|
|
484
|
-
}
|
|
485
|
-
if (params.strokeOpacity !== void 0) {
|
|
486
|
-
ss.strokeOpacity = params.strokeOpacity;
|
|
487
|
-
}
|
|
488
|
-
if (params.shadowColor !== void 0) {
|
|
489
|
-
ss.shadowColor = params.shadowColor;
|
|
490
|
-
}
|
|
491
|
-
if (params.shadowBlur !== void 0) {
|
|
492
|
-
ss.shadowBlur = params.shadowBlur;
|
|
493
|
-
}
|
|
494
|
-
if (params.shadowOffsetX !== void 0) {
|
|
495
|
-
ss.shadowOffsetX = params.shadowOffsetX;
|
|
496
|
-
}
|
|
497
|
-
if (params.shadowOffsetY !== void 0) {
|
|
498
|
-
ss.shadowOffsetY = params.shadowOffsetY;
|
|
499
|
-
}
|
|
500
|
-
if (params.shadowOpacity !== void 0) {
|
|
501
|
-
ss.shadowOpacity = params.shadowOpacity;
|
|
502
|
-
}
|
|
503
|
-
if (params.glowColor !== void 0) {
|
|
504
|
-
ss.glowColor = params.glowColor;
|
|
505
|
-
}
|
|
506
|
-
if (params.glowRadius !== void 0) {
|
|
507
|
-
ss.glowRadius = params.glowRadius;
|
|
508
|
-
}
|
|
509
|
-
if (params.glowOpacity !== void 0) {
|
|
510
|
-
ss.glowOpacity = params.glowOpacity;
|
|
511
|
-
}
|
|
512
|
-
if (params.softEdgeRadius !== void 0) {
|
|
513
|
-
ss.softEdgeRadius = params.softEdgeRadius;
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
if (params.altText !== void 0) {
|
|
517
|
-
applyElementAltText(el, params.altText);
|
|
518
|
-
}
|
|
519
|
-
if (params.title !== void 0) {
|
|
520
|
-
applyElementTitle(el, params.title);
|
|
521
|
-
}
|
|
522
|
-
if (el.type === "image" || el.type === "picture") {
|
|
523
|
-
const img = el;
|
|
524
|
-
if (params.cropLeft !== void 0) {
|
|
525
|
-
img.cropLeft = params.cropLeft;
|
|
526
|
-
}
|
|
527
|
-
if (params.cropTop !== void 0) {
|
|
528
|
-
img.cropTop = params.cropTop;
|
|
529
|
-
}
|
|
530
|
-
if (params.cropRight !== void 0) {
|
|
531
|
-
img.cropRight = params.cropRight;
|
|
532
|
-
}
|
|
533
|
-
if (params.cropBottom !== void 0) {
|
|
534
|
-
img.cropBottom = params.cropBottom;
|
|
535
|
-
}
|
|
536
|
-
if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
|
|
537
|
-
if (!img.imageEffects) {
|
|
538
|
-
img.imageEffects = {};
|
|
539
|
-
}
|
|
540
|
-
if (params.brightness !== void 0) {
|
|
541
|
-
img.imageEffects.brightness = params.brightness;
|
|
542
|
-
}
|
|
543
|
-
if (params.contrast !== void 0) {
|
|
544
|
-
img.imageEffects.contrast = params.contrast;
|
|
545
|
-
}
|
|
546
|
-
if (params.grayscale !== void 0) {
|
|
547
|
-
img.imageEffects.grayscale = params.grayscale;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
return {
|
|
552
|
-
pptxData: ctx.pptxData,
|
|
553
|
-
dirty: true,
|
|
554
|
-
result: { elementId: params.elementId }
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
function runAccessibilityCheck(ctx) {
|
|
558
|
-
const issues = [];
|
|
559
|
-
for (let si = 0; si < ctx.pptxData.slides.length; si++) {
|
|
560
|
-
const slide = ctx.pptxData.slides[si];
|
|
561
|
-
let slideHasText = false;
|
|
562
|
-
for (const el of slide.elements) {
|
|
563
|
-
if (el.type === "image" || el.type === "picture") {
|
|
564
|
-
const img = el;
|
|
565
|
-
if (!img.altText) {
|
|
566
|
-
issues.push({
|
|
567
|
-
slideIndex: si,
|
|
568
|
-
elementId: el.id,
|
|
569
|
-
severity: "error",
|
|
570
|
-
message: `Image element '${el.id}' has no alt text.`
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
575
|
-
const textEl = el;
|
|
576
|
-
slideHasText = true;
|
|
577
|
-
if (!textEl.text || textEl.text.trim() === "") {
|
|
578
|
-
issues.push({
|
|
579
|
-
slideIndex: si,
|
|
580
|
-
elementId: el.id,
|
|
581
|
-
severity: "info",
|
|
582
|
-
message: `Text element '${el.id}' is empty.`
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
const fs = textEl.textStyle?.fontSize;
|
|
586
|
-
if (fs !== void 0 && fs < 10) {
|
|
587
|
-
issues.push({
|
|
588
|
-
slideIndex: si,
|
|
589
|
-
elementId: el.id,
|
|
590
|
-
severity: "warning",
|
|
591
|
-
message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
const textColor = textEl.textStyle?.color?.toLowerCase();
|
|
595
|
-
const bgColor = slide.backgroundColor?.toLowerCase();
|
|
596
|
-
if (textColor && bgColor && textColor === bgColor) {
|
|
597
|
-
issues.push({
|
|
598
|
-
slideIndex: si,
|
|
599
|
-
elementId: el.id,
|
|
600
|
-
severity: "error",
|
|
601
|
-
message: `Text element '${el.id}' has same color as slide background (${textColor}).`
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
if (!slideHasText) {
|
|
607
|
-
issues.push({
|
|
608
|
-
slideIndex: si,
|
|
609
|
-
severity: "warning",
|
|
610
|
-
message: `Slide ${si + 1} contains no text elements.`
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
615
|
-
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
616
|
-
const infoCount = issues.filter((i) => i.severity === "info").length;
|
|
617
|
-
return {
|
|
618
|
-
pptxData: ctx.pptxData,
|
|
619
|
-
dirty: false,
|
|
620
|
-
result: {
|
|
621
|
-
slideCount: ctx.pptxData.slides.length,
|
|
622
|
-
totalIssues: issues.length,
|
|
623
|
-
errorCount,
|
|
624
|
-
warningCount,
|
|
625
|
-
infoCount,
|
|
626
|
-
issues
|
|
627
|
-
}
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// src/tools/text-editing.ts
|
|
632
|
-
function editRange(segments, start, end, replacement) {
|
|
633
|
-
let offset = 0;
|
|
634
|
-
let inserted = false;
|
|
635
|
-
for (const segment of segments) {
|
|
636
|
-
const text = segment.text;
|
|
637
|
-
const next = offset + text.length;
|
|
638
|
-
if (!segment.bulletInfo?.ownedByParagraph && next > start && offset < end) {
|
|
639
|
-
const from = Math.max(0, start - offset);
|
|
640
|
-
const to = Math.min(text.length, end - offset);
|
|
641
|
-
segment.text = text.slice(0, from) + (inserted ? "" : replacement) + text.slice(to);
|
|
642
|
-
inserted = true;
|
|
643
|
-
} else if (!inserted && start === end && offset <= start && next >= start && !segment.bulletInfo?.ownedByParagraph) {
|
|
644
|
-
const at = start - offset;
|
|
645
|
-
segment.text = text.slice(0, at) + replacement + text.slice(at);
|
|
646
|
-
inserted = true;
|
|
647
|
-
}
|
|
648
|
-
offset = next;
|
|
649
|
-
}
|
|
650
|
-
if (!inserted && replacement) {
|
|
651
|
-
segments.push({ text: replacement, style: {} });
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
function changedRange(before, text) {
|
|
655
|
-
let start = 0;
|
|
656
|
-
while (start < before.length && start < text.length && before[start] === text[start]) {
|
|
657
|
-
start++;
|
|
658
|
-
}
|
|
659
|
-
let suffix = 0;
|
|
660
|
-
while (suffix < before.length - start && suffix < text.length - start && before[before.length - suffix - 1] === text[text.length - suffix - 1]) {
|
|
661
|
-
suffix++;
|
|
662
|
-
}
|
|
663
|
-
return {
|
|
664
|
-
start,
|
|
665
|
-
end: before.length - suffix,
|
|
666
|
-
replacement: text.slice(start, text.length - suffix)
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
function setElementText(element, text) {
|
|
670
|
-
const segments = element.textSegments;
|
|
671
|
-
if (segments?.length) {
|
|
672
|
-
const before = segments.map((segment) => segment.text).join("");
|
|
673
|
-
const oldLines = before.split("\n");
|
|
674
|
-
const newLines = text.split("\n");
|
|
675
|
-
if (oldLines.length === newLines.length) {
|
|
676
|
-
let offset = before.length;
|
|
677
|
-
for (let index = oldLines.length - 1; index >= 0; index--) {
|
|
678
|
-
const line = oldLines[index];
|
|
679
|
-
offset -= line.length;
|
|
680
|
-
const edit = changedRange(line, newLines[index]);
|
|
681
|
-
editRange(segments, offset + edit.start, offset + edit.end, edit.replacement);
|
|
682
|
-
offset--;
|
|
683
|
-
}
|
|
684
|
-
} else {
|
|
685
|
-
const edit = changedRange(before, text);
|
|
686
|
-
editRange(segments, edit.start, edit.end, edit.replacement);
|
|
687
|
-
}
|
|
688
|
-
element.text = segments.map((segment) => segment.text).join("");
|
|
689
|
-
} else {
|
|
690
|
-
element.text = text;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
function replaceElementText(element, regex, replacement) {
|
|
694
|
-
const before = element.text ?? element.textSegments?.map((segment) => segment.text).join("") ?? "";
|
|
695
|
-
const matches = Array.from(before.matchAll(regex));
|
|
696
|
-
if (before.replace(regex, replacement) === before) {
|
|
697
|
-
return 0;
|
|
698
|
-
}
|
|
699
|
-
if (!element.textSegments?.length) {
|
|
700
|
-
element.text = before.replace(regex, replacement);
|
|
701
|
-
return matches.length;
|
|
702
|
-
}
|
|
703
|
-
for (const match of matches.reverse()) {
|
|
704
|
-
const start = match.index;
|
|
705
|
-
const end = start + match[0].length;
|
|
706
|
-
const single = new RegExp(regex.source, `${regex.flags.replace("g", "")}y`);
|
|
707
|
-
single.lastIndex = start;
|
|
708
|
-
const after = before.replace(single, replacement);
|
|
709
|
-
editRange(
|
|
710
|
-
element.textSegments,
|
|
711
|
-
start,
|
|
712
|
-
end,
|
|
713
|
-
after.slice(start, after.length - (before.length - end))
|
|
714
|
-
);
|
|
715
|
-
}
|
|
716
|
-
element.text = element.textSegments.map((segment) => segment.text).join("");
|
|
717
|
-
return matches.length;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// src/tools/element-tools.ts
|
|
721
|
-
function addElement(ctx, params) {
|
|
722
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
723
|
-
if (err) {
|
|
724
|
-
throw new Error(err);
|
|
725
|
-
}
|
|
726
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
727
|
-
const id = generateElementId();
|
|
728
|
-
const x = params.x ?? 100;
|
|
729
|
-
const y = params.y ?? 100;
|
|
730
|
-
const width = params.width ?? 300;
|
|
731
|
-
const height = params.height ?? 60;
|
|
732
|
-
switch (params.type) {
|
|
733
|
-
case "text": {
|
|
734
|
-
const el = {
|
|
735
|
-
id,
|
|
736
|
-
type: "text",
|
|
737
|
-
x,
|
|
738
|
-
y,
|
|
739
|
-
width,
|
|
740
|
-
height,
|
|
741
|
-
text: params.text ?? "",
|
|
742
|
-
textStyle: {
|
|
743
|
-
fontSize: params.fontSize,
|
|
744
|
-
fontFamily: params.fontFamily,
|
|
745
|
-
color: params.fontColor,
|
|
746
|
-
bold: params.bold,
|
|
747
|
-
italic: params.italic,
|
|
748
|
-
underline: params.underline,
|
|
749
|
-
align: params.alignment
|
|
750
|
-
},
|
|
751
|
-
textSegments: [
|
|
752
|
-
{
|
|
753
|
-
text: params.text ?? "",
|
|
754
|
-
style: {
|
|
755
|
-
fontSize: params.fontSize,
|
|
756
|
-
fontFamily: params.fontFamily,
|
|
757
|
-
color: params.fontColor,
|
|
758
|
-
bold: params.bold,
|
|
759
|
-
italic: params.italic,
|
|
760
|
-
underline: params.underline
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
]
|
|
764
|
-
};
|
|
765
|
-
slide.elements.push(el);
|
|
766
|
-
break;
|
|
767
|
-
}
|
|
768
|
-
case "shape": {
|
|
769
|
-
const el = {
|
|
770
|
-
id,
|
|
771
|
-
type: "shape",
|
|
772
|
-
x,
|
|
773
|
-
y,
|
|
774
|
-
width,
|
|
775
|
-
height,
|
|
776
|
-
shapeType: params.shapeType ?? "rect",
|
|
777
|
-
text: params.text,
|
|
778
|
-
textStyle: params.text ? {
|
|
779
|
-
fontSize: params.fontSize,
|
|
780
|
-
fontFamily: params.fontFamily,
|
|
781
|
-
color: params.fontColor,
|
|
782
|
-
bold: params.bold,
|
|
783
|
-
italic: params.italic,
|
|
784
|
-
align: params.alignment
|
|
785
|
-
} : void 0,
|
|
786
|
-
shapeStyle: {
|
|
787
|
-
fillColor: params.fillColor,
|
|
788
|
-
strokeColor: params.strokeColor,
|
|
789
|
-
strokeWidth: params.strokeWidth
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
slide.elements.push(el);
|
|
793
|
-
break;
|
|
794
|
-
}
|
|
795
|
-
case "image": {
|
|
796
|
-
const el = {
|
|
797
|
-
id,
|
|
798
|
-
type: "image",
|
|
799
|
-
x,
|
|
800
|
-
y,
|
|
801
|
-
width,
|
|
802
|
-
height,
|
|
803
|
-
imageData: params.imageData,
|
|
804
|
-
altText: params.altText
|
|
805
|
-
};
|
|
806
|
-
slide.elements.push(el);
|
|
807
|
-
break;
|
|
808
|
-
}
|
|
809
|
-
case "table": {
|
|
810
|
-
const rowCount = params.rows ?? 2;
|
|
811
|
-
const colCount = params.columns ?? 2;
|
|
812
|
-
const colWidth = 1 / colCount;
|
|
813
|
-
const tableRows = Array.from({ length: rowCount }, (_, r) => ({
|
|
814
|
-
height: 40,
|
|
815
|
-
cells: Array.from({ length: colCount }, (__, c) => ({
|
|
816
|
-
text: params.cellData?.[r]?.[c] ?? ""
|
|
817
|
-
}))
|
|
818
|
-
}));
|
|
819
|
-
const tableEl = {
|
|
820
|
-
id,
|
|
821
|
-
type: "table",
|
|
822
|
-
x,
|
|
823
|
-
y,
|
|
824
|
-
width,
|
|
825
|
-
height: params.height ?? rowCount * 40,
|
|
826
|
-
tableData: {
|
|
827
|
-
rows: tableRows,
|
|
828
|
-
columnWidths: Array.from({ length: colCount }, () => colWidth),
|
|
829
|
-
firstRowHeader: params.headerRow ?? false
|
|
830
|
-
}
|
|
831
|
-
};
|
|
832
|
-
slide.elements.push(tableEl);
|
|
833
|
-
break;
|
|
834
|
-
}
|
|
835
|
-
case "connector": {
|
|
836
|
-
const el = {
|
|
837
|
-
id,
|
|
838
|
-
type: "connector",
|
|
839
|
-
x,
|
|
840
|
-
y,
|
|
841
|
-
width,
|
|
842
|
-
height,
|
|
843
|
-
shapeStyle: {
|
|
844
|
-
strokeColor: params.strokeColor ?? "#000000",
|
|
845
|
-
strokeWidth: params.strokeWidth ?? 1,
|
|
846
|
-
connectorStartArrow: params.startArrow,
|
|
847
|
-
connectorEndArrow: params.endArrow
|
|
848
|
-
}
|
|
849
|
-
};
|
|
850
|
-
slide.elements.push(el);
|
|
851
|
-
break;
|
|
852
|
-
}
|
|
853
|
-
default: {
|
|
854
|
-
throw new Error(`Unknown element type: ${String(params.type)}`);
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
return {
|
|
858
|
-
pptxData: ctx.pptxData,
|
|
859
|
-
dirty: true,
|
|
860
|
-
result: { elementId: id, slideIndex: params.slideIndex }
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
function updateElement(ctx, params) {
|
|
864
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
865
|
-
if (err) {
|
|
866
|
-
throw new Error(err);
|
|
867
|
-
}
|
|
868
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
869
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
870
|
-
if (!el) {
|
|
871
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
872
|
-
}
|
|
873
|
-
if (params.x !== void 0) {
|
|
874
|
-
el.x = params.x;
|
|
875
|
-
}
|
|
876
|
-
if (params.y !== void 0) {
|
|
877
|
-
el.y = params.y;
|
|
878
|
-
}
|
|
879
|
-
if (params.width !== void 0) {
|
|
880
|
-
el.width = params.width;
|
|
881
|
-
}
|
|
882
|
-
if (params.height !== void 0) {
|
|
883
|
-
el.height = params.height;
|
|
884
|
-
}
|
|
885
|
-
if (params.rotation !== void 0) {
|
|
886
|
-
el.rotation = params.rotation;
|
|
887
|
-
}
|
|
888
|
-
if (params.opacity !== void 0) {
|
|
889
|
-
el.opacity = params.opacity;
|
|
890
|
-
}
|
|
891
|
-
if (params.hidden !== void 0) {
|
|
892
|
-
el.hidden = params.hidden;
|
|
893
|
-
}
|
|
894
|
-
if (params.flipH !== void 0) {
|
|
895
|
-
el.flipHorizontal = params.flipH;
|
|
896
|
-
}
|
|
897
|
-
if (params.flipV !== void 0) {
|
|
898
|
-
el.flipVertical = params.flipV;
|
|
899
|
-
}
|
|
900
|
-
if (params.altText !== void 0) {
|
|
901
|
-
applyElementAltText(el, params.altText);
|
|
902
|
-
}
|
|
903
|
-
if (params.title !== void 0) {
|
|
904
|
-
applyElementTitle(el, params.title);
|
|
905
|
-
}
|
|
906
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
907
|
-
const textEl = el;
|
|
908
|
-
if (params.textSegments !== void 0) {
|
|
909
|
-
textEl.textSegments = structuredClone(params.textSegments);
|
|
910
|
-
textEl.text = textEl.textSegments.map((segment) => segment.text).join("");
|
|
911
|
-
} else if (params.text !== void 0) {
|
|
912
|
-
setElementText(textEl, params.text);
|
|
913
|
-
}
|
|
914
|
-
if (!textEl.textStyle) {
|
|
915
|
-
textEl.textStyle = {};
|
|
916
|
-
}
|
|
917
|
-
if (params.fontSize !== void 0) {
|
|
918
|
-
textEl.textStyle.fontSize = params.fontSize;
|
|
919
|
-
}
|
|
920
|
-
if (params.fontFamily !== void 0) {
|
|
921
|
-
textEl.textStyle.fontFamily = params.fontFamily;
|
|
922
|
-
}
|
|
923
|
-
if (params.fontThemeColor !== void 0) {
|
|
924
|
-
textEl.textStyle.colorRef = params.fontThemeColor;
|
|
925
|
-
const resolved = pptxViewerCore.resolveThemeColorRef(params.fontThemeColor, ctx.pptxData.themeColorMap);
|
|
926
|
-
if (params.fontColor !== void 0) {
|
|
927
|
-
textEl.textStyle.color = params.fontColor;
|
|
928
|
-
} else if (resolved) {
|
|
929
|
-
textEl.textStyle.color = resolved;
|
|
930
|
-
}
|
|
931
|
-
} else if (params.fontColor !== void 0) {
|
|
932
|
-
textEl.textStyle.color = params.fontColor;
|
|
933
|
-
textEl.textStyle.colorRef = void 0;
|
|
934
|
-
}
|
|
935
|
-
if (params.bold !== void 0) {
|
|
936
|
-
textEl.textStyle.bold = params.bold;
|
|
937
|
-
}
|
|
938
|
-
if (params.italic !== void 0) {
|
|
939
|
-
textEl.textStyle.italic = params.italic;
|
|
940
|
-
}
|
|
941
|
-
if (params.underline !== void 0) {
|
|
942
|
-
textEl.textStyle.underline = params.underline;
|
|
943
|
-
}
|
|
944
|
-
if (params.alignment !== void 0) {
|
|
945
|
-
textEl.textStyle.align = params.alignment;
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
if ("shapeStyle" in el && el.shapeStyle) {
|
|
949
|
-
const ss = el.shapeStyle;
|
|
950
|
-
if (params.fillColor !== void 0) {
|
|
951
|
-
ss.fillColor = params.fillColor;
|
|
952
|
-
}
|
|
953
|
-
if (params.strokeColor !== void 0) {
|
|
954
|
-
ss.strokeColor = params.strokeColor;
|
|
955
|
-
}
|
|
956
|
-
if (params.strokeWidth !== void 0) {
|
|
957
|
-
ss.strokeWidth = params.strokeWidth;
|
|
958
|
-
}
|
|
959
|
-
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0) {
|
|
960
|
-
if ("shapeStyle" in el) {
|
|
961
|
-
el.shapeStyle = {
|
|
962
|
-
fillColor: params.fillColor,
|
|
963
|
-
strokeColor: params.strokeColor,
|
|
964
|
-
strokeWidth: params.strokeWidth
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
return {
|
|
969
|
-
pptxData: ctx.pptxData,
|
|
970
|
-
dirty: true,
|
|
971
|
-
result: { elementId: params.elementId }
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
function renameElement(ctx, params) {
|
|
975
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
976
|
-
if (err) {
|
|
977
|
-
throw new Error(err);
|
|
978
|
-
}
|
|
979
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
980
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
981
|
-
if (!el) {
|
|
982
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
983
|
-
}
|
|
984
|
-
const name = params.name.trim();
|
|
985
|
-
if (name.length === 0) {
|
|
986
|
-
delete el.name;
|
|
987
|
-
} else {
|
|
988
|
-
el.name = name;
|
|
989
|
-
}
|
|
990
|
-
return {
|
|
991
|
-
pptxData: ctx.pptxData,
|
|
992
|
-
dirty: true,
|
|
993
|
-
result: { elementId: params.elementId, name }
|
|
994
|
-
};
|
|
995
|
-
}
|
|
996
|
-
function deleteElements(ctx, params) {
|
|
997
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
998
|
-
if (err) {
|
|
999
|
-
throw new Error(err);
|
|
1000
|
-
}
|
|
1001
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1002
|
-
const idSet = new Set(params.elementIds);
|
|
1003
|
-
const existingIds = new Set(slide.elements.map((element) => element.id));
|
|
1004
|
-
const notFound = params.elementIds.filter((id) => !existingIds.has(id));
|
|
1005
|
-
if (notFound.length > 0) {
|
|
1006
|
-
throw new Error(`Elements not found: ${notFound.join(", ")}`);
|
|
1007
|
-
}
|
|
1008
|
-
const before = slide.elements.length;
|
|
1009
|
-
slide.elements = slide.elements.filter((e) => !idSet.has(e.id));
|
|
1010
|
-
return {
|
|
1011
|
-
pptxData: ctx.pptxData,
|
|
1012
|
-
dirty: true,
|
|
1013
|
-
result: { deletedCount: before - slide.elements.length }
|
|
1014
|
-
};
|
|
1015
|
-
}
|
|
1016
|
-
function arrangeElements(ctx, params) {
|
|
1017
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1018
|
-
if (err) {
|
|
1019
|
-
throw new Error(err);
|
|
1020
|
-
}
|
|
1021
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1022
|
-
if (params.action === "align") {
|
|
1023
|
-
if (!params.elementIds || params.elementIds.length === 0) {
|
|
1024
|
-
throw new Error("elementIds is required for align action.");
|
|
1025
|
-
}
|
|
1026
|
-
const targetIds = new Set(params.elementIds);
|
|
1027
|
-
const targets = slide.elements.filter((element) => targetIds.has(element.id));
|
|
1028
|
-
if (targets.length === 0) {
|
|
1029
|
-
throw new Error("No matching elements found for align.");
|
|
1030
|
-
}
|
|
1031
|
-
switch (params.alignment) {
|
|
1032
|
-
case "left": {
|
|
1033
|
-
const minX = Math.min(...targets.map((e) => e.x));
|
|
1034
|
-
for (const t of targets) {
|
|
1035
|
-
t.x = minX;
|
|
1036
|
-
}
|
|
1037
|
-
break;
|
|
1038
|
-
}
|
|
1039
|
-
case "right": {
|
|
1040
|
-
const maxRight = Math.max(...targets.map((e) => e.x + e.width));
|
|
1041
|
-
for (const t of targets) {
|
|
1042
|
-
t.x = maxRight - t.width;
|
|
1043
|
-
}
|
|
1044
|
-
break;
|
|
1045
|
-
}
|
|
1046
|
-
case "top": {
|
|
1047
|
-
const minY = Math.min(...targets.map((e) => e.y));
|
|
1048
|
-
for (const t of targets) {
|
|
1049
|
-
t.y = minY;
|
|
1050
|
-
}
|
|
1051
|
-
break;
|
|
1052
|
-
}
|
|
1053
|
-
case "bottom": {
|
|
1054
|
-
const maxBottom = Math.max(...targets.map((e) => e.y + e.height));
|
|
1055
|
-
for (const t of targets) {
|
|
1056
|
-
t.y = maxBottom - t.height;
|
|
1057
|
-
}
|
|
1058
|
-
break;
|
|
1059
|
-
}
|
|
1060
|
-
case "centerH": {
|
|
1061
|
-
const avgCX = targets.reduce((s, e) => s + e.x + e.width / 2, 0) / targets.length;
|
|
1062
|
-
for (const t of targets) {
|
|
1063
|
-
t.x = avgCX - t.width / 2;
|
|
1064
|
-
}
|
|
1065
|
-
break;
|
|
1066
|
-
}
|
|
1067
|
-
case "centerV": {
|
|
1068
|
-
const avgCY = targets.reduce((s, e) => s + e.y + e.height / 2, 0) / targets.length;
|
|
1069
|
-
for (const t of targets) {
|
|
1070
|
-
t.y = avgCY - t.height / 2;
|
|
1071
|
-
}
|
|
1072
|
-
break;
|
|
1073
|
-
}
|
|
1074
|
-
default: {
|
|
1075
|
-
throw new Error(`Unknown alignment: ${String(params.alignment)}`);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
} else if (params.action === "reorderLayer") {
|
|
1079
|
-
if (!params.elementId) {
|
|
1080
|
-
throw new Error("elementId is required for reorderLayer action.");
|
|
1081
|
-
}
|
|
1082
|
-
const idx = slide.elements.findIndex((e) => e.id === params.elementId);
|
|
1083
|
-
if (idx < 0) {
|
|
1084
|
-
throw new Error(`Element '${params.elementId}' not found.`);
|
|
1085
|
-
}
|
|
1086
|
-
const [el] = slide.elements.splice(idx, 1);
|
|
1087
|
-
switch (params.layerAction) {
|
|
1088
|
-
case "bringToFront":
|
|
1089
|
-
slide.elements.push(el);
|
|
1090
|
-
break;
|
|
1091
|
-
case "sendToBack":
|
|
1092
|
-
slide.elements.unshift(el);
|
|
1093
|
-
break;
|
|
1094
|
-
case "bringForward": {
|
|
1095
|
-
const newIdx = Math.min(idx + 1, slide.elements.length);
|
|
1096
|
-
slide.elements.splice(newIdx, 0, el);
|
|
1097
|
-
break;
|
|
1098
|
-
}
|
|
1099
|
-
case "sendBackward": {
|
|
1100
|
-
const newIdx = Math.max(idx - 1, 0);
|
|
1101
|
-
slide.elements.splice(newIdx, 0, el);
|
|
1102
|
-
break;
|
|
1103
|
-
}
|
|
1104
|
-
default: {
|
|
1105
|
-
slide.elements.splice(idx, 0, el);
|
|
1106
|
-
throw new Error(`Unknown layerAction: ${String(params.layerAction)}`);
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
} else {
|
|
1110
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
1111
|
-
}
|
|
1112
|
-
return {
|
|
1113
|
-
pptxData: ctx.pptxData,
|
|
1114
|
-
dirty: true,
|
|
1115
|
-
result: { slideIndex: params.slideIndex }
|
|
1116
|
-
};
|
|
1117
|
-
}
|
|
1118
|
-
function cloneElement(ctx, params) {
|
|
1119
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1120
|
-
if (err) {
|
|
1121
|
-
throw new Error(err);
|
|
1122
|
-
}
|
|
1123
|
-
const srcSlide = ctx.pptxData.slides[params.slideIndex];
|
|
1124
|
-
const original = srcSlide.elements.find((e) => e.id === params.elementId);
|
|
1125
|
-
if (!original) {
|
|
1126
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1127
|
-
}
|
|
1128
|
-
const targets = params.targetSlideIndexes ?? [params.slideIndex];
|
|
1129
|
-
const clonedIds = [];
|
|
1130
|
-
const offsetX = params.offsetX ?? 20;
|
|
1131
|
-
const offsetY = params.offsetY ?? 20;
|
|
1132
|
-
for (const targetIdx of targets) {
|
|
1133
|
-
const terr = validateSlideIndex(targetIdx, ctx.pptxData.slides.length);
|
|
1134
|
-
if (terr) {
|
|
1135
|
-
throw new Error(terr);
|
|
1136
|
-
}
|
|
1137
|
-
const clone = pptxViewerCore.cloneElement(original);
|
|
1138
|
-
const intoTemplate = pptxViewerCore.isTemplateElementId(original.id);
|
|
1139
|
-
clone.id = pptxViewerCore.makeStoreAwareId(intoTemplate, original.id);
|
|
1140
|
-
pptxViewerCore.reassignDescendantIds(clone, () => pptxViewerCore.makeStoreAwareId(intoTemplate, original.id));
|
|
1141
|
-
clone.x += offsetX;
|
|
1142
|
-
clone.y += offsetY;
|
|
1143
|
-
ctx.pptxData.slides[targetIdx].elements.push(clone);
|
|
1144
|
-
clonedIds.push(clone.id);
|
|
1145
|
-
}
|
|
1146
|
-
return {
|
|
1147
|
-
pptxData: ctx.pptxData,
|
|
1148
|
-
dirty: true,
|
|
1149
|
-
result: { clonedIds }
|
|
1150
|
-
};
|
|
1151
|
-
}
|
|
1152
|
-
function setElementAnimation(ctx, params) {
|
|
1153
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1154
|
-
if (err) {
|
|
1155
|
-
throw new Error(err);
|
|
1156
|
-
}
|
|
1157
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1158
|
-
const elExists = slide.elements.some((e) => e.id === params.elementId);
|
|
1159
|
-
if (!elExists) {
|
|
1160
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1161
|
-
}
|
|
1162
|
-
if (!slide.animations) {
|
|
1163
|
-
slide.animations = [];
|
|
1164
|
-
}
|
|
1165
|
-
const existing = slide.animations.find((a) => a.elementId === params.elementId);
|
|
1166
|
-
if (existing) {
|
|
1167
|
-
if (params.entrance !== void 0) {
|
|
1168
|
-
existing.entrance = params.entrance;
|
|
1169
|
-
}
|
|
1170
|
-
if (params.exit !== void 0) {
|
|
1171
|
-
existing.exit = params.exit;
|
|
1172
|
-
}
|
|
1173
|
-
if (params.durationMs !== void 0) {
|
|
1174
|
-
existing.durationMs = params.durationMs;
|
|
1175
|
-
}
|
|
1176
|
-
if (params.delayMs !== void 0) {
|
|
1177
|
-
existing.delayMs = params.delayMs;
|
|
1178
|
-
}
|
|
1179
|
-
if (params.order !== void 0) {
|
|
1180
|
-
existing.order = params.order;
|
|
1181
|
-
}
|
|
1182
|
-
} else {
|
|
1183
|
-
const anim = {
|
|
1184
|
-
elementId: params.elementId,
|
|
1185
|
-
entrance: params.entrance,
|
|
1186
|
-
exit: params.exit,
|
|
1187
|
-
durationMs: params.durationMs,
|
|
1188
|
-
delayMs: params.delayMs,
|
|
1189
|
-
order: params.order
|
|
1190
|
-
};
|
|
1191
|
-
slide.animations.push(anim);
|
|
1192
|
-
}
|
|
1193
|
-
return {
|
|
1194
|
-
pptxData: ctx.pptxData,
|
|
1195
|
-
dirty: true,
|
|
1196
|
-
result: { elementId: params.elementId }
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
function groupElements(ctx, params) {
|
|
1200
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1201
|
-
if (err) {
|
|
1202
|
-
throw new Error(err);
|
|
1203
|
-
}
|
|
1204
|
-
if (params.elementIds.length < 2) {
|
|
1205
|
-
throw new Error("At least 2 elements are required to form a group.");
|
|
1206
|
-
}
|
|
1207
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1208
|
-
const idSet = new Set(params.elementIds);
|
|
1209
|
-
const found = new Set(slide.elements.filter((e) => idSet.has(e.id)).map((e) => e.id));
|
|
1210
|
-
if (found.size !== idSet.size) {
|
|
1211
|
-
const missing = params.elementIds.filter((id) => !found.has(id));
|
|
1212
|
-
throw new Error(`Elements not found: ${missing.join(", ")}`);
|
|
1213
|
-
}
|
|
1214
|
-
const groupId = generateElementId();
|
|
1215
|
-
const grouped = pptxViewerCore.groupElements(slide.elements, params.elementIds, groupId);
|
|
1216
|
-
slide.elements = grouped.elements;
|
|
1217
|
-
return {
|
|
1218
|
-
pptxData: ctx.pptxData,
|
|
1219
|
-
dirty: true,
|
|
1220
|
-
result: { groupId: grouped.groupId ?? groupId }
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
function ungroupElements(ctx, params) {
|
|
1224
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1225
|
-
if (err) {
|
|
1226
|
-
throw new Error(err);
|
|
1227
|
-
}
|
|
1228
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1229
|
-
const group = slide.elements.find((e) => e.id === params.groupElementId);
|
|
1230
|
-
if (!group) {
|
|
1231
|
-
throw new Error(`Group element '${params.groupElementId}' not found.`);
|
|
1232
|
-
}
|
|
1233
|
-
if (group.type !== "group") {
|
|
1234
|
-
throw new Error(`Element '${params.groupElementId}' is not a group.`);
|
|
1235
|
-
}
|
|
1236
|
-
const intoTemplate = pptxViewerCore.isTemplateElementId(group.id);
|
|
1237
|
-
const childIds = group.children.map(
|
|
1238
|
-
(child) => pptxViewerCore.isTemplateElementId(child.id) === intoTemplate ? child.id : pptxViewerCore.makeStoreAwareId(intoTemplate, group.id)
|
|
1239
|
-
);
|
|
1240
|
-
const promoted = pptxViewerCore.ungroupElements(slide.elements, params.groupElementId, childIds, {
|
|
1241
|
-
intoTemplate
|
|
1242
|
-
});
|
|
1243
|
-
slide.elements = promoted.elements;
|
|
1244
|
-
return {
|
|
1245
|
-
pptxData: ctx.pptxData,
|
|
1246
|
-
dirty: true,
|
|
1247
|
-
result: { restoredIds: promoted.childIds }
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
function batchUpdateElements(ctx, params) {
|
|
1251
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1252
|
-
if (err) {
|
|
1253
|
-
throw new Error(err);
|
|
1254
|
-
}
|
|
1255
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1256
|
-
const idSet = new Set(params.elementIds);
|
|
1257
|
-
let count = 0;
|
|
1258
|
-
for (const el of slide.elements) {
|
|
1259
|
-
if (!idSet.has(el.id)) {
|
|
1260
|
-
continue;
|
|
1261
|
-
}
|
|
1262
|
-
if (params.x !== void 0) {
|
|
1263
|
-
el.x = params.x;
|
|
1264
|
-
}
|
|
1265
|
-
if (params.y !== void 0) {
|
|
1266
|
-
el.y = params.y;
|
|
1267
|
-
}
|
|
1268
|
-
if (params.width !== void 0) {
|
|
1269
|
-
el.width = params.width;
|
|
1270
|
-
}
|
|
1271
|
-
if (params.height !== void 0) {
|
|
1272
|
-
el.height = params.height;
|
|
1273
|
-
}
|
|
1274
|
-
if (params.rotation !== void 0) {
|
|
1275
|
-
el.rotation = params.rotation;
|
|
1276
|
-
}
|
|
1277
|
-
if (params.opacity !== void 0) {
|
|
1278
|
-
el.opacity = params.opacity;
|
|
1279
|
-
}
|
|
1280
|
-
if (params.hidden !== void 0) {
|
|
1281
|
-
el.hidden = params.hidden;
|
|
1282
|
-
}
|
|
1283
|
-
count++;
|
|
1284
|
-
}
|
|
1285
|
-
return {
|
|
1286
|
-
pptxData: ctx.pptxData,
|
|
1287
|
-
dirty: true,
|
|
1288
|
-
result: { updatedCount: count }
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
function updateTableCells(ctx, params) {
|
|
1292
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1293
|
-
if (err) {
|
|
1294
|
-
throw new Error(err);
|
|
1295
|
-
}
|
|
1296
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1297
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1298
|
-
if (!el) {
|
|
1299
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1300
|
-
}
|
|
1301
|
-
if (el.type !== "table") {
|
|
1302
|
-
throw new Error(`Element '${params.elementId}' is not a table.`);
|
|
1303
|
-
}
|
|
1304
|
-
const tbl = el;
|
|
1305
|
-
if (!tbl.tableData) {
|
|
1306
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
1307
|
-
}
|
|
1308
|
-
let count = 0;
|
|
1309
|
-
for (const cellUpdate of params.cells) {
|
|
1310
|
-
const row = tbl.tableData.rows[cellUpdate.row];
|
|
1311
|
-
if (!row) {
|
|
1312
|
-
throw new Error(
|
|
1313
|
-
`Row ${cellUpdate.row} out of range (table has ${tbl.tableData.rows.length} rows).`
|
|
1314
|
-
);
|
|
1315
|
-
}
|
|
1316
|
-
const cell = row.cells[cellUpdate.col];
|
|
1317
|
-
if (!cell) {
|
|
1318
|
-
throw new Error(`Column ${cellUpdate.col} out of range (row has ${row.cells.length} cells).`);
|
|
1319
|
-
}
|
|
1320
|
-
cell.text = cellUpdate.text;
|
|
1321
|
-
count++;
|
|
1322
|
-
}
|
|
1323
|
-
return {
|
|
1324
|
-
pptxData: ctx.pptxData,
|
|
1325
|
-
dirty: true,
|
|
1326
|
-
result: { updatedCount: count }
|
|
1327
|
-
};
|
|
1328
|
-
}
|
|
1329
|
-
function manageTableStructure(ctx, params) {
|
|
1330
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1331
|
-
if (err) {
|
|
1332
|
-
throw new Error(err);
|
|
1333
|
-
}
|
|
1334
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1335
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1336
|
-
if (!el) {
|
|
1337
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1338
|
-
}
|
|
1339
|
-
if (el.type !== "table") {
|
|
1340
|
-
throw new Error(`Element '${params.elementId}' is not a table.`);
|
|
1341
|
-
}
|
|
1342
|
-
const tbl = el;
|
|
1343
|
-
if (!tbl.tableData) {
|
|
1344
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
1345
|
-
}
|
|
1346
|
-
const { rows, columnWidths } = tbl.tableData;
|
|
1347
|
-
const source = { ...tbl, tableData: structuredClone(tbl.tableData) };
|
|
1348
|
-
let edit;
|
|
1349
|
-
const colCount = columnWidths.length;
|
|
1350
|
-
const rowCount = rows.length;
|
|
1351
|
-
switch (params.action) {
|
|
1352
|
-
case "insertRow": {
|
|
1353
|
-
const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), rowCount) : rowCount;
|
|
1354
|
-
const newRow = {
|
|
1355
|
-
height: 40,
|
|
1356
|
-
cells: Array.from({ length: colCount }, (_, c) => ({
|
|
1357
|
-
text: params.cellTexts?.[c] ?? ""
|
|
1358
|
-
}))
|
|
1359
|
-
};
|
|
1360
|
-
rows.splice(pos, 0, newRow);
|
|
1361
|
-
edit = { axis: "row", action: "insert", index: pos };
|
|
1362
|
-
break;
|
|
1363
|
-
}
|
|
1364
|
-
case "deleteRow": {
|
|
1365
|
-
if (rowCount <= 1) {
|
|
1366
|
-
throw new Error("Cannot delete the last row of a table.");
|
|
1367
|
-
}
|
|
1368
|
-
const ref = params.referenceIndex ?? rowCount - 1;
|
|
1369
|
-
if (ref < 0 || ref >= rowCount) {
|
|
1370
|
-
throw new Error(`Row index ${ref} out of range (0\u2013${rowCount - 1}).`);
|
|
1371
|
-
}
|
|
1372
|
-
rows.splice(ref, 1);
|
|
1373
|
-
edit = { axis: "row", action: "delete", index: ref };
|
|
1374
|
-
break;
|
|
1375
|
-
}
|
|
1376
|
-
case "insertColumn": {
|
|
1377
|
-
const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), colCount) : colCount;
|
|
1378
|
-
const newWidth = 1 / (colCount + 1);
|
|
1379
|
-
const scaleFactor = colCount / (colCount + 1);
|
|
1380
|
-
for (let i = 0; i < columnWidths.length; i++) {
|
|
1381
|
-
columnWidths[i] *= scaleFactor;
|
|
1382
|
-
}
|
|
1383
|
-
columnWidths.splice(pos, 0, newWidth);
|
|
1384
|
-
edit = { axis: "column", action: "insert", index: pos };
|
|
1385
|
-
for (let r = 0; r < rows.length; r++) {
|
|
1386
|
-
rows[r].cells.splice(pos, 0, {
|
|
1387
|
-
text: params.cellTexts?.[r] ?? ""
|
|
1388
|
-
});
|
|
1389
|
-
}
|
|
1390
|
-
break;
|
|
1391
|
-
}
|
|
1392
|
-
case "deleteColumn": {
|
|
1393
|
-
if (colCount <= 1) {
|
|
1394
|
-
throw new Error("Cannot delete the last column of a table.");
|
|
1395
|
-
}
|
|
1396
|
-
const ref = params.referenceIndex ?? colCount - 1;
|
|
1397
|
-
if (ref < 0 || ref >= colCount) {
|
|
1398
|
-
throw new Error(`Column index ${ref} out of range (0\u2013${colCount - 1}).`);
|
|
1399
|
-
}
|
|
1400
|
-
const removedWidth = columnWidths[ref];
|
|
1401
|
-
columnWidths.splice(ref, 1);
|
|
1402
|
-
edit = { axis: "column", action: "delete", index: ref };
|
|
1403
|
-
const remaining = columnWidths.length;
|
|
1404
|
-
if (remaining > 0) {
|
|
1405
|
-
const extra = removedWidth / remaining;
|
|
1406
|
-
for (let i = 0; i < columnWidths.length; i++) {
|
|
1407
|
-
columnWidths[i] += extra;
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
for (const row of rows) {
|
|
1411
|
-
row.cells.splice(ref, 1);
|
|
1412
|
-
}
|
|
1413
|
-
break;
|
|
1414
|
-
}
|
|
1415
|
-
default: {
|
|
1416
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
const rawXml = pptxViewerCore.rebuildTableStructureInRawXml(source, tbl.tableData, edit);
|
|
1420
|
-
if (rawXml) {
|
|
1421
|
-
tbl.rawXml = rawXml;
|
|
1422
|
-
}
|
|
1423
|
-
return {
|
|
1424
|
-
pptxData: ctx.pptxData,
|
|
1425
|
-
dirty: true,
|
|
1426
|
-
result: {
|
|
1427
|
-
rowCount: tbl.tableData.rows.length,
|
|
1428
|
-
columnCount: tbl.tableData.columnWidths.length
|
|
1429
|
-
}
|
|
1430
|
-
};
|
|
1431
|
-
}
|
|
1432
|
-
function findTableElement(ctx, slideIndex, elementId) {
|
|
1433
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
1434
|
-
if (err) {
|
|
1435
|
-
throw new Error(err);
|
|
1436
|
-
}
|
|
1437
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
1438
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
1439
|
-
if (!el) {
|
|
1440
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
1441
|
-
}
|
|
1442
|
-
if (el.type !== "table") {
|
|
1443
|
-
throw new Error(`Element '${elementId}' is not a table.`);
|
|
1444
|
-
}
|
|
1445
|
-
return el;
|
|
1446
|
-
}
|
|
1447
|
-
function tableStyleIdsInUse(ctx) {
|
|
1448
|
-
const used = /* @__PURE__ */ new Set();
|
|
1449
|
-
for (const slide of ctx.pptxData.slides) {
|
|
1450
|
-
for (const el of slide.elements) {
|
|
1451
|
-
if (el.type === "table" && el.tableData?.tableStyleId) {
|
|
1452
|
-
used.add(pptxViewerCore.normalizeTableStyleGuid(el.tableData.tableStyleId));
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
return used;
|
|
1457
|
-
}
|
|
1458
|
-
function setTableStyleSection(ctx, params) {
|
|
1459
|
-
if (!pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.includes(params.section)) {
|
|
1460
|
-
throw new Error(
|
|
1461
|
-
`Unknown table style section '${params.section}'. Valid sections: ${pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.join(", ")}.`
|
|
1462
|
-
);
|
|
1463
|
-
}
|
|
1464
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
1465
|
-
ctx.pptxData.tableStyleMap = map;
|
|
1466
|
-
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
|
|
1467
|
-
const entry = map[normalizedId];
|
|
1468
|
-
if (!entry) {
|
|
1469
|
-
throw new Error(
|
|
1470
|
-
`Table style '${params.styleId}' is not loaded in this presentation. Use create_table_style to add a new one.`
|
|
1471
|
-
);
|
|
1472
|
-
}
|
|
1473
|
-
if (params.styleName !== void 0) {
|
|
1474
|
-
entry.styleName = params.styleName;
|
|
1475
|
-
}
|
|
1476
|
-
const mutableEntry = entry;
|
|
1477
|
-
if (params.fill !== void 0) {
|
|
1478
|
-
mutableEntry[`${params.section}Fill`] = params.fill;
|
|
1479
|
-
}
|
|
1480
|
-
if (params.text !== void 0) {
|
|
1481
|
-
mutableEntry[`${params.section}Text`] = params.text;
|
|
1482
|
-
}
|
|
1483
|
-
if (params.borders !== void 0) {
|
|
1484
|
-
mutableEntry[`${params.section}Borders`] = params.borders;
|
|
1485
|
-
}
|
|
1486
|
-
if (params.cell3D !== void 0) {
|
|
1487
|
-
mutableEntry[`${params.section}Cell3D`] = params.cell3D;
|
|
1488
|
-
}
|
|
1489
|
-
return {
|
|
1490
|
-
pptxData: ctx.pptxData,
|
|
1491
|
-
dirty: true,
|
|
1492
|
-
result: { styleId: normalizedId, section: params.section }
|
|
1493
|
-
};
|
|
1494
|
-
}
|
|
1495
|
-
function createTableStyle(ctx, params) {
|
|
1496
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
1497
|
-
ctx.pptxData.tableStyleMap = map;
|
|
1498
|
-
const basedOn = params.basedOnStyleId ? map[pptxViewerCore.normalizeTableStyleGuid(params.basedOnStyleId)] : void 0;
|
|
1499
|
-
if (params.basedOnStyleId && !basedOn) {
|
|
1500
|
-
throw new Error(`basedOnStyleId '${params.basedOnStyleId}' is not a loaded table style.`);
|
|
1501
|
-
}
|
|
1502
|
-
const entry = pptxViewerCore.createTableStyleEntry(map, { styleName: params.styleName, basedOn });
|
|
1503
|
-
pptxViewerCore.addTableStyleToMap(map, entry);
|
|
1504
|
-
return {
|
|
1505
|
-
pptxData: ctx.pptxData,
|
|
1506
|
-
dirty: true,
|
|
1507
|
-
result: { styleId: entry.styleId },
|
|
1508
|
-
...params.setAsDefault ? { saveOptions: { tableStylesDefaultId: entry.styleId } } : {}
|
|
1509
|
-
};
|
|
1510
|
-
}
|
|
1511
|
-
function deleteTableStyle(ctx, params) {
|
|
1512
|
-
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
|
|
1513
|
-
if (!params.force) {
|
|
1514
|
-
const used = tableStyleIdsInUse(ctx);
|
|
1515
|
-
if (used.has(normalizedId)) {
|
|
1516
|
-
throw new Error(
|
|
1517
|
-
`Table style '${params.styleId}' is assigned to at least one table on this deck. Reassign those tables first, or pass force: true.`
|
|
1518
|
-
);
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
1522
|
-
ctx.pptxData.tableStyleMap = map;
|
|
1523
|
-
pptxViewerCore.deleteTableStyleFromMap(map, normalizedId);
|
|
1524
|
-
return {
|
|
1525
|
-
pptxData: ctx.pptxData,
|
|
1526
|
-
dirty: true,
|
|
1527
|
-
result: { deleted: true },
|
|
1528
|
-
saveOptions: { tableStylesToDelete: [normalizedId] }
|
|
1529
|
-
};
|
|
1530
|
-
}
|
|
1531
|
-
function assignTableStyle(ctx, params) {
|
|
1532
|
-
const el = findTableElement(ctx, params.slideIndex, params.elementId);
|
|
1533
|
-
if (!el.tableData) {
|
|
1534
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
1535
|
-
}
|
|
1536
|
-
const styleId = params.styleId ?? ctx.pptxData.tableStylesDefaultId;
|
|
1537
|
-
if (!styleId) {
|
|
1538
|
-
throw new Error(
|
|
1539
|
-
"styleId was not provided and this presentation has no tableStylesDefaultId to fall back to."
|
|
1540
|
-
);
|
|
1541
|
-
}
|
|
1542
|
-
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(styleId);
|
|
1543
|
-
el.tableData.tableStyleId = normalizedId;
|
|
1544
|
-
if (params.bandedRows !== void 0) {
|
|
1545
|
-
el.tableData.bandedRows = params.bandedRows;
|
|
1546
|
-
}
|
|
1547
|
-
if (params.bandedColumns !== void 0) {
|
|
1548
|
-
el.tableData.bandedColumns = params.bandedColumns;
|
|
1549
|
-
}
|
|
1550
|
-
if (params.firstRowHeader !== void 0) {
|
|
1551
|
-
el.tableData.firstRowHeader = params.firstRowHeader;
|
|
1552
|
-
}
|
|
1553
|
-
if (params.lastRow !== void 0) {
|
|
1554
|
-
el.tableData.lastRow = params.lastRow;
|
|
1555
|
-
}
|
|
1556
|
-
if (params.firstCol !== void 0) {
|
|
1557
|
-
el.tableData.firstCol = params.firstCol;
|
|
1558
|
-
}
|
|
1559
|
-
if (params.lastCol !== void 0) {
|
|
1560
|
-
el.tableData.lastCol = params.lastCol;
|
|
1561
|
-
}
|
|
1562
|
-
return {
|
|
1563
|
-
pptxData: ctx.pptxData,
|
|
1564
|
-
dirty: true,
|
|
1565
|
-
result: { elementId: params.elementId, styleId: normalizedId }
|
|
1566
|
-
};
|
|
1567
|
-
}
|
|
1568
|
-
var MAX_REGEX_LEN = 200;
|
|
1569
|
-
function hasNestedUnboundedQuantifier(pattern) {
|
|
1570
|
-
return /\([^)]*[+*]\)[+*]/u.test(pattern);
|
|
1571
|
-
}
|
|
1572
|
-
function buildSearchRegex(query, useRegex, caseSensitive) {
|
|
1573
|
-
if (useRegex) {
|
|
1574
|
-
if (query.length > MAX_REGEX_LEN) {
|
|
1575
|
-
return null;
|
|
1576
|
-
}
|
|
1577
|
-
if (hasNestedUnboundedQuantifier(query)) {
|
|
1578
|
-
return null;
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
const pattern = useRegex ? query : query.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
1582
|
-
const flags = caseSensitive ? "g" : "gi";
|
|
1583
|
-
try {
|
|
1584
|
-
return new RegExp(pattern, flags);
|
|
1585
|
-
} catch {
|
|
1586
|
-
return null;
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
function findText(ctx, params) {
|
|
1590
|
-
const regex = buildSearchRegex(
|
|
1591
|
-
params.query,
|
|
1592
|
-
params.useRegex === true,
|
|
1593
|
-
params.caseSensitive === true
|
|
1594
|
-
);
|
|
1595
|
-
if (!regex) {
|
|
1596
|
-
return {
|
|
1597
|
-
pptxData: ctx.pptxData,
|
|
1598
|
-
dirty: false,
|
|
1599
|
-
result: { query: params.query, matchCount: 0, matches: [] }
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
|
|
1603
|
-
const matches = [];
|
|
1604
|
-
for (const si of targetIndexes) {
|
|
1605
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
1606
|
-
if (err) {
|
|
1607
|
-
throw new Error(err);
|
|
1608
|
-
}
|
|
1609
|
-
const slide = ctx.pptxData.slides[si];
|
|
1610
|
-
for (const el of slide.elements) {
|
|
1611
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
1612
|
-
const textEl = el;
|
|
1613
|
-
if (textEl.text) {
|
|
1614
|
-
const localMatches = Array.from(textEl.text.matchAll(regex));
|
|
1615
|
-
for (const m of localMatches) {
|
|
1616
|
-
matches.push({
|
|
1617
|
-
slideIndex: si,
|
|
1618
|
-
elementId: el.id,
|
|
1619
|
-
elementType: el.type,
|
|
1620
|
-
matchedText: m[0],
|
|
1621
|
-
context: textEl.text.slice(
|
|
1622
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1623
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1624
|
-
)
|
|
1625
|
-
});
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
if (el.type === "table") {
|
|
1630
|
-
const tbl = el;
|
|
1631
|
-
if (tbl.tableData) {
|
|
1632
|
-
for (const row of tbl.tableData.rows) {
|
|
1633
|
-
for (const cell of row.cells) {
|
|
1634
|
-
if (cell.text) {
|
|
1635
|
-
const localMatches = Array.from(cell.text.matchAll(regex));
|
|
1636
|
-
for (const m of localMatches) {
|
|
1637
|
-
matches.push({
|
|
1638
|
-
slideIndex: si,
|
|
1639
|
-
elementId: el.id,
|
|
1640
|
-
elementType: "table-cell",
|
|
1641
|
-
matchedText: m[0],
|
|
1642
|
-
context: cell.text.slice(
|
|
1643
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1644
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1645
|
-
)
|
|
1646
|
-
});
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
if (slide.notes) {
|
|
1655
|
-
const noteMatches = Array.from(slide.notes.matchAll(regex));
|
|
1656
|
-
for (const m of noteMatches) {
|
|
1657
|
-
matches.push({
|
|
1658
|
-
slideIndex: si,
|
|
1659
|
-
elementId: "notes",
|
|
1660
|
-
elementType: "notes",
|
|
1661
|
-
matchedText: m[0],
|
|
1662
|
-
context: slide.notes.slice(
|
|
1663
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1664
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1665
|
-
)
|
|
1666
|
-
});
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
return {
|
|
1671
|
-
pptxData: ctx.pptxData,
|
|
1672
|
-
dirty: false,
|
|
1673
|
-
result: {
|
|
1674
|
-
query: params.query,
|
|
1675
|
-
matchCount: matches.length,
|
|
1676
|
-
matches
|
|
1677
|
-
}
|
|
1678
|
-
};
|
|
1679
|
-
}
|
|
1680
|
-
function replaceText(ctx, params) {
|
|
1681
|
-
const regex = buildSearchRegex(
|
|
1682
|
-
params.query,
|
|
1683
|
-
params.useRegex === true,
|
|
1684
|
-
params.caseSensitive === true
|
|
1685
|
-
);
|
|
1686
|
-
if (!regex) {
|
|
1687
|
-
return {
|
|
1688
|
-
pptxData: ctx.pptxData,
|
|
1689
|
-
dirty: false,
|
|
1690
|
-
result: { query: params.query, replacement: params.replacement, replacementCount: 0 }
|
|
1691
|
-
};
|
|
1692
|
-
}
|
|
1693
|
-
const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
|
|
1694
|
-
let count = 0;
|
|
1695
|
-
for (const si of targetIndexes) {
|
|
1696
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
1697
|
-
if (err) {
|
|
1698
|
-
throw new Error(err);
|
|
1699
|
-
}
|
|
1700
|
-
const slide = ctx.pptxData.slides[si];
|
|
1701
|
-
for (const el of slide.elements) {
|
|
1702
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
1703
|
-
const textEl = el;
|
|
1704
|
-
if (textEl.text) {
|
|
1705
|
-
const before = textEl.text;
|
|
1706
|
-
const after = before.replace(regex, params.replacement);
|
|
1707
|
-
if (after !== before) {
|
|
1708
|
-
const matchCount = Array.from(before.matchAll(regex)).length;
|
|
1709
|
-
count += matchCount;
|
|
1710
|
-
replaceElementText(textEl, regex, params.replacement);
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
if (el.type === "table") {
|
|
1715
|
-
const tbl = el;
|
|
1716
|
-
if (tbl.tableData) {
|
|
1717
|
-
for (const row of tbl.tableData.rows) {
|
|
1718
|
-
for (const cell of row.cells) {
|
|
1719
|
-
if (cell.text) {
|
|
1720
|
-
const before = cell.text;
|
|
1721
|
-
const after = before.replace(regex, params.replacement);
|
|
1722
|
-
if (after !== before) {
|
|
1723
|
-
count += Array.from(before.matchAll(regex)).length;
|
|
1724
|
-
cell.text = after;
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
}
|
|
1732
|
-
if (slide.notes) {
|
|
1733
|
-
const before = slide.notes;
|
|
1734
|
-
const after = before.replace(regex, params.replacement);
|
|
1735
|
-
if (after !== before) {
|
|
1736
|
-
count += Array.from(before.matchAll(regex)).length;
|
|
1737
|
-
slide.notes = after;
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1741
|
-
return {
|
|
1742
|
-
pptxData: ctx.pptxData,
|
|
1743
|
-
dirty: count > 0,
|
|
1744
|
-
result: {
|
|
1745
|
-
query: params.query,
|
|
1746
|
-
replacement: params.replacement,
|
|
1747
|
-
replacementCount: count
|
|
1748
|
-
}
|
|
1749
|
-
};
|
|
1750
|
-
}
|
|
1751
|
-
function manageComments(ctx, params) {
|
|
1752
|
-
switch (params.action) {
|
|
1753
|
-
case "list": {
|
|
1754
|
-
const all = [];
|
|
1755
|
-
for (let si = 0; si < ctx.pptxData.slides.length; si++) {
|
|
1756
|
-
if (params.slideIndex !== void 0 && si !== params.slideIndex) {
|
|
1757
|
-
continue;
|
|
1758
|
-
}
|
|
1759
|
-
const slide = ctx.pptxData.slides[si];
|
|
1760
|
-
for (const c of slide.comments ?? []) {
|
|
1761
|
-
if (!params.includeResolved && c.resolved) {
|
|
1762
|
-
continue;
|
|
1763
|
-
}
|
|
1764
|
-
all.push({
|
|
1765
|
-
id: c.id,
|
|
1766
|
-
slideIndex: si,
|
|
1767
|
-
text: c.text,
|
|
1768
|
-
author: c.author,
|
|
1769
|
-
createdAt: c.createdAt,
|
|
1770
|
-
resolved: c.resolved
|
|
1771
|
-
});
|
|
1772
|
-
}
|
|
1773
|
-
}
|
|
1774
|
-
return {
|
|
1775
|
-
pptxData: ctx.pptxData,
|
|
1776
|
-
dirty: false,
|
|
1777
|
-
result: { action: "list", comments: all, count: all.length }
|
|
1778
|
-
};
|
|
1779
|
-
}
|
|
1780
|
-
case "add": {
|
|
1781
|
-
if (params.slideIndex === void 0) {
|
|
1782
|
-
throw new Error("slideIndex is required for add action.");
|
|
1783
|
-
}
|
|
1784
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1785
|
-
if (err) {
|
|
1786
|
-
throw new Error(err);
|
|
1787
|
-
}
|
|
1788
|
-
if (!params.text) {
|
|
1789
|
-
throw new Error("text is required for add action.");
|
|
1790
|
-
}
|
|
1791
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1792
|
-
if (!slide.comments) {
|
|
1793
|
-
slide.comments = [];
|
|
1794
|
-
}
|
|
1795
|
-
const newId = `comment-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1796
|
-
slide.comments.push({
|
|
1797
|
-
id: newId,
|
|
1798
|
-
text: params.text,
|
|
1799
|
-
author: params.author,
|
|
1800
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1801
|
-
resolved: false
|
|
1802
|
-
});
|
|
1803
|
-
return {
|
|
1804
|
-
pptxData: ctx.pptxData,
|
|
1805
|
-
dirty: true,
|
|
1806
|
-
result: { action: "add", commentId: newId }
|
|
1807
|
-
};
|
|
1808
|
-
}
|
|
1809
|
-
case "delete": {
|
|
1810
|
-
if (!params.commentId) {
|
|
1811
|
-
throw new Error("commentId is required for delete action.");
|
|
1812
|
-
}
|
|
1813
|
-
let deleted = false;
|
|
1814
|
-
for (const slide of ctx.pptxData.slides) {
|
|
1815
|
-
if (!slide.comments) {
|
|
1816
|
-
continue;
|
|
1817
|
-
}
|
|
1818
|
-
const before = slide.comments.length;
|
|
1819
|
-
slide.comments = slide.comments.filter((c) => c.id !== params.commentId);
|
|
1820
|
-
if (slide.comments.length < before) {
|
|
1821
|
-
deleted = true;
|
|
1822
|
-
break;
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
if (!deleted) {
|
|
1826
|
-
throw new Error(`Comment '${params.commentId}' not found.`);
|
|
1827
|
-
}
|
|
1828
|
-
return {
|
|
1829
|
-
pptxData: ctx.pptxData,
|
|
1830
|
-
dirty: true,
|
|
1831
|
-
result: { action: "delete", commentId: params.commentId }
|
|
1832
|
-
};
|
|
1833
|
-
}
|
|
1834
|
-
case "resolve": {
|
|
1835
|
-
if (!params.commentId) {
|
|
1836
|
-
throw new Error("commentId is required for resolve action.");
|
|
1837
|
-
}
|
|
1838
|
-
let found = false;
|
|
1839
|
-
for (const slide of ctx.pptxData.slides) {
|
|
1840
|
-
const comment = slide.comments?.find((c) => c.id === params.commentId);
|
|
1841
|
-
if (comment) {
|
|
1842
|
-
comment.resolved = params.resolved !== false;
|
|
1843
|
-
found = true;
|
|
1844
|
-
break;
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
if (!found) {
|
|
1848
|
-
throw new Error(`Comment '${params.commentId}' not found.`);
|
|
1849
|
-
}
|
|
1850
|
-
return {
|
|
1851
|
-
pptxData: ctx.pptxData,
|
|
1852
|
-
dirty: true,
|
|
1853
|
-
result: { action: "resolve", commentId: params.commentId }
|
|
1854
|
-
};
|
|
1855
|
-
}
|
|
1856
|
-
default: {
|
|
1857
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
async function convertToMarkdown(ctx, params) {
|
|
1862
|
-
const options = {
|
|
1863
|
-
mediaFolderName: params.mediaFolderName ?? "media",
|
|
1864
|
-
includeMetadata: params.includeMetadata !== false,
|
|
1865
|
-
slideRange: params.slideRange,
|
|
1866
|
-
includeSpeakerNotes: params.includeSpeakerNotes !== false,
|
|
1867
|
-
semanticMode: params.semanticMode === true,
|
|
1868
|
-
sourceName: params.sourceName ?? "unknown"
|
|
1869
|
-
};
|
|
1870
|
-
const outputDir = params.outputDir ?? ".";
|
|
1871
|
-
const safeOutputDir = params.scopeOutputDir ? params.scopeOutputDir(outputDir, params.rootDir) : outputDir;
|
|
1872
|
-
const converter = new pptxViewerCore.PptxMarkdownConverter(safeOutputDir, options);
|
|
1873
|
-
const markdown = await converter.convert(ctx.pptxData);
|
|
1874
|
-
return {
|
|
1875
|
-
pptxData: ctx.pptxData,
|
|
1876
|
-
dirty: false,
|
|
1877
|
-
result: {
|
|
1878
|
-
markdown,
|
|
1879
|
-
slidesConverted: converter.slidesConverted,
|
|
1880
|
-
totalSlides: converter.presentationSlides,
|
|
1881
|
-
imagesExtracted: converter.imagesExtracted
|
|
1882
|
-
}
|
|
1883
|
-
};
|
|
1884
|
-
}
|
|
1885
|
-
function getThemeInfo(ctx) {
|
|
1886
|
-
const theme = ctx.pptxData.theme;
|
|
1887
|
-
return {
|
|
1888
|
-
pptxData: ctx.pptxData,
|
|
1889
|
-
dirty: false,
|
|
1890
|
-
result: {
|
|
1891
|
-
themeName: theme?.name,
|
|
1892
|
-
colorScheme: theme?.colorScheme,
|
|
1893
|
-
fontScheme: theme?.fontScheme,
|
|
1894
|
-
availablePresets: Object.keys(pptxViewerCore.ThemePresets)
|
|
1895
|
-
}
|
|
1896
|
-
};
|
|
1897
|
-
}
|
|
1898
|
-
function applyThemePreset(ctx, params) {
|
|
1899
|
-
const preset = pptxViewerCore.getThemePreset(params.presetName);
|
|
1900
|
-
if (!preset) {
|
|
1901
|
-
throw new Error(
|
|
1902
|
-
`Unknown theme preset: "${params.presetName}". Available: ${Object.keys(pptxViewerCore.ThemePresets).join(", ")}`
|
|
1903
|
-
);
|
|
1904
|
-
}
|
|
1905
|
-
if (!ctx.pptxData.theme) {
|
|
1906
|
-
ctx.pptxData.theme = {};
|
|
1907
|
-
}
|
|
1908
|
-
const theme = ctx.pptxData.theme;
|
|
1909
|
-
theme.name = preset.name;
|
|
1910
|
-
theme.colorScheme = preset.colors;
|
|
1911
|
-
if (preset.fonts) {
|
|
1912
|
-
theme.fontScheme = preset.fonts;
|
|
1913
|
-
}
|
|
1914
|
-
return {
|
|
1915
|
-
pptxData: ctx.pptxData,
|
|
1916
|
-
dirty: true,
|
|
1917
|
-
result: {
|
|
1918
|
-
appliedPreset: params.presetName,
|
|
1919
|
-
colorScheme: theme.colorScheme
|
|
1920
|
-
}
|
|
1921
|
-
};
|
|
1922
|
-
}
|
|
1923
|
-
function updateThemeColors(ctx, params) {
|
|
1924
|
-
if (!ctx.pptxData.theme) {
|
|
1925
|
-
ctx.pptxData.theme = {};
|
|
1926
|
-
}
|
|
1927
|
-
const theme = ctx.pptxData.theme;
|
|
1928
|
-
if (!theme.colorScheme) {
|
|
1929
|
-
theme.colorScheme = {
|
|
1930
|
-
dk1: "#000000",
|
|
1931
|
-
lt1: "#FFFFFF",
|
|
1932
|
-
dk2: "#44546A",
|
|
1933
|
-
lt2: "#E7E6E6",
|
|
1934
|
-
accent1: "#4472C4",
|
|
1935
|
-
accent2: "#ED7D31",
|
|
1936
|
-
accent3: "#A5A5A5",
|
|
1937
|
-
accent4: "#FFC000",
|
|
1938
|
-
accent5: "#5B9BD5",
|
|
1939
|
-
accent6: "#70AD47",
|
|
1940
|
-
hlink: "#0563C1",
|
|
1941
|
-
folHlink: "#954F72"
|
|
1942
|
-
};
|
|
1943
|
-
}
|
|
1944
|
-
const cs = theme.colorScheme;
|
|
1945
|
-
for (const key of Object.keys(params)) {
|
|
1946
|
-
if (params[key] !== void 0) {
|
|
1947
|
-
cs[key] = params[key];
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
return {
|
|
1951
|
-
pptxData: ctx.pptxData,
|
|
1952
|
-
dirty: true,
|
|
1953
|
-
result: { colorScheme: cs }
|
|
1954
|
-
};
|
|
1955
|
-
}
|
|
1956
|
-
function updateThemeFonts(ctx, params) {
|
|
1957
|
-
if (!ctx.pptxData.theme) {
|
|
1958
|
-
ctx.pptxData.theme = {};
|
|
1959
|
-
}
|
|
1960
|
-
const theme = ctx.pptxData.theme;
|
|
1961
|
-
if (!theme.fontScheme) {
|
|
1962
|
-
theme.fontScheme = {};
|
|
1963
|
-
}
|
|
1964
|
-
if (params.majorFont !== void 0) {
|
|
1965
|
-
theme.fontScheme.majorFont = { latin: params.majorFont };
|
|
1966
|
-
}
|
|
1967
|
-
if (params.minorFont !== void 0) {
|
|
1968
|
-
theme.fontScheme.minorFont = { latin: params.minorFont };
|
|
1969
|
-
}
|
|
1970
|
-
return {
|
|
1971
|
-
pptxData: ctx.pptxData,
|
|
1972
|
-
dirty: true,
|
|
1973
|
-
result: { fontScheme: theme.fontScheme }
|
|
1974
|
-
};
|
|
1975
|
-
}
|
|
1976
|
-
|
|
1977
|
-
// src/tools/chart-pareto.ts
|
|
1978
|
-
function cumulativePercent(values) {
|
|
1979
|
-
const total = values.reduce((sum, value) => sum + value, 0);
|
|
1980
|
-
if (total === 0) {
|
|
1981
|
-
return values.map(() => 0);
|
|
1982
|
-
}
|
|
1983
|
-
let running = 0;
|
|
1984
|
-
return values.map((value) => {
|
|
1985
|
-
running += value;
|
|
1986
|
-
return Math.round(running / total * 1e4) / 100;
|
|
1987
|
-
});
|
|
1988
|
-
}
|
|
1989
|
-
function applyParetoChartTypeAlias(chart, requestedType) {
|
|
1990
|
-
if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
|
|
1991
|
-
return;
|
|
1992
|
-
}
|
|
1993
|
-
const data = chart.chartData;
|
|
1994
|
-
data.chartType = "histogram";
|
|
1995
|
-
const [frequency] = data.series;
|
|
1996
|
-
if (!frequency) {
|
|
1997
|
-
return;
|
|
1998
|
-
}
|
|
1999
|
-
frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
|
|
2000
|
-
const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
|
|
2001
|
-
if (!hasParetoLine) {
|
|
2002
|
-
data.series.push({
|
|
2003
|
-
name: "Cumulative %",
|
|
2004
|
-
values: cumulativePercent(frequency.values),
|
|
2005
|
-
histogramOptions: { layout: "pareto" }
|
|
2006
|
-
});
|
|
2007
|
-
}
|
|
2008
|
-
}
|
|
2009
|
-
|
|
2010
|
-
// src/tools/chart-tools.ts
|
|
2011
|
-
function updateChart(ctx, params) {
|
|
2012
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2013
|
-
if (err) {
|
|
2014
|
-
throw new Error(err);
|
|
2015
|
-
}
|
|
2016
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2017
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2018
|
-
if (!el) {
|
|
2019
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2020
|
-
}
|
|
2021
|
-
if (el.type !== "chart") {
|
|
2022
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
2023
|
-
}
|
|
2024
|
-
const chart = el;
|
|
2025
|
-
if (params.chartType) {
|
|
2026
|
-
pptxViewerCore.setChartType(chart, params.chartType);
|
|
2027
|
-
applyParetoChartTypeAlias(chart, params.chartType);
|
|
2028
|
-
}
|
|
2029
|
-
if (params.title !== void 0) {
|
|
2030
|
-
pptxViewerCore.setChartTitle(chart, params.title);
|
|
2031
|
-
}
|
|
2032
|
-
if (params.grouping) {
|
|
2033
|
-
pptxViewerCore.setChartGrouping(chart, params.grouping);
|
|
2034
|
-
}
|
|
2035
|
-
if (params.legend) {
|
|
2036
|
-
pptxViewerCore.setChartLegend(chart, {
|
|
2037
|
-
show: params.legend.show,
|
|
2038
|
-
position: params.legend.position
|
|
2039
|
-
});
|
|
2040
|
-
}
|
|
2041
|
-
if (params.dataLabels) {
|
|
2042
|
-
pptxViewerCore.setChartDataLabels(chart, params.dataLabels);
|
|
2043
|
-
}
|
|
2044
|
-
if (params.axis) {
|
|
2045
|
-
pptxViewerCore.setChartAxis(chart, params.axis.type, params.axis.edit);
|
|
2046
|
-
}
|
|
2047
|
-
if (params.categories) {
|
|
2048
|
-
pptxViewerCore.setChartCategories(chart, params.categories);
|
|
2049
|
-
}
|
|
2050
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2051
|
-
}
|
|
2052
|
-
function addChartSeriesT(ctx, params) {
|
|
2053
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2054
|
-
if (err) {
|
|
2055
|
-
throw new Error(err);
|
|
2056
|
-
}
|
|
2057
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2058
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2059
|
-
if (!el) {
|
|
2060
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2061
|
-
}
|
|
2062
|
-
if (el.type !== "chart") {
|
|
2063
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
2064
|
-
}
|
|
2065
|
-
const chart = el;
|
|
2066
|
-
pptxViewerCore.addChartSeries(chart, { name: params.name, values: params.values, color: params.color });
|
|
2067
|
-
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
2068
|
-
return {
|
|
2069
|
-
pptxData: ctx.pptxData,
|
|
2070
|
-
dirty: true,
|
|
2071
|
-
result: { elementId: params.elementId, seriesCount }
|
|
2072
|
-
};
|
|
2073
|
-
}
|
|
2074
|
-
function removeChartSeriesT(ctx, params) {
|
|
2075
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2076
|
-
if (err) {
|
|
2077
|
-
throw new Error(err);
|
|
2078
|
-
}
|
|
2079
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2080
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2081
|
-
if (!el) {
|
|
2082
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2083
|
-
}
|
|
2084
|
-
if (el.type !== "chart") {
|
|
2085
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
2086
|
-
}
|
|
2087
|
-
const chart = el;
|
|
2088
|
-
pptxViewerCore.removeChartSeries(chart, params.seriesIndex);
|
|
2089
|
-
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
2090
|
-
return {
|
|
2091
|
-
pptxData: ctx.pptxData,
|
|
2092
|
-
dirty: true,
|
|
2093
|
-
result: { elementId: params.elementId, seriesCount }
|
|
2094
|
-
};
|
|
2095
|
-
}
|
|
2096
|
-
function updateChartSeriesData(ctx, params) {
|
|
2097
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2098
|
-
if (err) {
|
|
2099
|
-
throw new Error(err);
|
|
2100
|
-
}
|
|
2101
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2102
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2103
|
-
if (!el) {
|
|
2104
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2105
|
-
}
|
|
2106
|
-
if (el.type !== "chart") {
|
|
2107
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
2108
|
-
}
|
|
2109
|
-
const chart = el;
|
|
2110
|
-
pptxViewerCore.updateChartSeriesValues(chart, params.seriesIndex, params.values);
|
|
2111
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2112
|
-
}
|
|
2113
|
-
function createChart(ctx, params) {
|
|
2114
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2115
|
-
if (err) {
|
|
2116
|
-
throw new Error(err);
|
|
2117
|
-
}
|
|
2118
|
-
const builder = pptxViewerCore.ChartBuilder.create(
|
|
2119
|
-
params.chartType
|
|
2120
|
-
);
|
|
2121
|
-
builder.position(params.x ?? 100, params.y ?? 100);
|
|
2122
|
-
builder.size(params.width ?? 500, params.height ?? 350);
|
|
2123
|
-
if (params.title) {
|
|
2124
|
-
builder.title(params.title);
|
|
2125
|
-
}
|
|
2126
|
-
if (params.categories) {
|
|
2127
|
-
builder.categories(params.categories);
|
|
2128
|
-
}
|
|
2129
|
-
if (params.series) {
|
|
2130
|
-
for (const s of params.series) {
|
|
2131
|
-
builder.addSeries(s.name, s.values, s.color);
|
|
2132
|
-
}
|
|
2133
|
-
}
|
|
2134
|
-
if (params.legend) {
|
|
2135
|
-
builder.legend(
|
|
2136
|
-
params.legend.show,
|
|
2137
|
-
params.legend.position
|
|
2138
|
-
);
|
|
2139
|
-
}
|
|
2140
|
-
const chart = builder.build();
|
|
2141
|
-
applyParetoChartTypeAlias(chart, params.chartType);
|
|
2142
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2143
|
-
slide.elements.push(chart);
|
|
2144
|
-
return {
|
|
2145
|
-
pptxData: ctx.pptxData,
|
|
2146
|
-
dirty: true,
|
|
2147
|
-
result: { elementId: chart.id, slideIndex: params.slideIndex }
|
|
2148
|
-
};
|
|
2149
|
-
}
|
|
2150
|
-
function findChartElement(ctx, slideIndex, elementId) {
|
|
2151
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
2152
|
-
if (err) {
|
|
2153
|
-
throw new Error(err);
|
|
2154
|
-
}
|
|
2155
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
2156
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
2157
|
-
if (!el) {
|
|
2158
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
2159
|
-
}
|
|
2160
|
-
if (el.type !== "chart") {
|
|
2161
|
-
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
2162
|
-
}
|
|
2163
|
-
return el;
|
|
2164
|
-
}
|
|
2165
|
-
function formatChartDataPoint(ctx, params) {
|
|
2166
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
2167
|
-
if (params.clearStyle) {
|
|
2168
|
-
pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, null);
|
|
2169
|
-
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0 || params.strokeDashStyle !== void 0) {
|
|
2170
|
-
pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, {
|
|
2171
|
-
...params.fillColor !== void 0 ? { fillColor: params.fillColor } : {},
|
|
2172
|
-
...params.strokeColor !== void 0 ? { strokeColor: params.strokeColor } : {},
|
|
2173
|
-
...params.strokeWidth !== void 0 ? { strokeWidth: params.strokeWidth } : {},
|
|
2174
|
-
...params.strokeDashStyle !== void 0 ? { strokeDashStyle: params.strokeDashStyle } : {}
|
|
2175
|
-
});
|
|
2176
|
-
}
|
|
2177
|
-
if (params.explosion !== void 0) {
|
|
2178
|
-
pptxViewerCore.setChartDataPointExplosion(chart, params.seriesIndex, params.pointIndex, params.explosion);
|
|
2179
|
-
}
|
|
2180
|
-
if (params.marker !== void 0) {
|
|
2181
|
-
pptxViewerCore.setChartDataPointMarker(chart, params.seriesIndex, params.pointIndex, params.marker);
|
|
2182
|
-
}
|
|
2183
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2184
|
-
}
|
|
2185
|
-
function formatChartDataLabel(ctx, params) {
|
|
2186
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
2187
|
-
if (params.remove) {
|
|
2188
|
-
pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, null);
|
|
2189
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2190
|
-
}
|
|
2191
|
-
pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, {
|
|
2192
|
-
...params.showValue !== void 0 ? { showValue: params.showValue } : {},
|
|
2193
|
-
...params.showCategory !== void 0 ? { showCategory: params.showCategory } : {},
|
|
2194
|
-
...params.showSeriesName !== void 0 ? { showSeriesName: params.showSeriesName } : {},
|
|
2195
|
-
...params.showPercent !== void 0 ? { showPercent: params.showPercent } : {},
|
|
2196
|
-
...params.showLegendKey !== void 0 ? { showLegendKey: params.showLegendKey } : {},
|
|
2197
|
-
...params.position !== void 0 ? { position: params.position } : {},
|
|
2198
|
-
...params.text !== void 0 ? { text: params.text } : {},
|
|
2199
|
-
...params.spPr !== void 0 ? { spPr: params.spPr } : {},
|
|
2200
|
-
...params.txPr !== void 0 ? { txPr: params.txPr } : {}
|
|
2201
|
-
});
|
|
2202
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2203
|
-
}
|
|
2204
|
-
function formatChartSeries(ctx, params) {
|
|
2205
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
2206
|
-
if (params.marker !== void 0) {
|
|
2207
|
-
if (params.marker === null) {
|
|
2208
|
-
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, null);
|
|
2209
|
-
} else if (params.marker.strokeColor !== void 0 || params.marker.strokeWidth !== void 0 || params.marker.strokeDashStyle !== void 0) {
|
|
2210
|
-
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, {
|
|
2211
|
-
symbol: params.marker.symbol ?? "circle",
|
|
2212
|
-
...params.marker.size !== void 0 ? { size: params.marker.size } : {},
|
|
2213
|
-
spPr: {
|
|
2214
|
-
...params.marker.fillColor !== void 0 ? { fillColor: params.marker.fillColor } : {},
|
|
2215
|
-
...params.marker.strokeColor !== void 0 ? { strokeColor: params.marker.strokeColor } : {},
|
|
2216
|
-
...params.marker.strokeWidth !== void 0 ? { strokeWidth: params.marker.strokeWidth } : {},
|
|
2217
|
-
...params.marker.strokeDashStyle !== void 0 ? { strokeDashStyle: params.marker.strokeDashStyle } : {}
|
|
2218
|
-
}
|
|
2219
|
-
});
|
|
2220
|
-
} else {
|
|
2221
|
-
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, params.marker);
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2224
|
-
if (params.trendline !== void 0) {
|
|
2225
|
-
pptxViewerCore.setChartSeriesTrendline(chart, params.seriesIndex, params.trendline);
|
|
2226
|
-
}
|
|
2227
|
-
if (params.errorBars !== void 0) {
|
|
2228
|
-
pptxViewerCore.setChartSeriesErrorBars(chart, params.seriesIndex, params.errorBars);
|
|
2229
|
-
}
|
|
2230
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2231
|
-
}
|
|
2232
|
-
function setChartHelperLineT(ctx, params) {
|
|
2233
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
2234
|
-
pptxViewerCore.setChartHelperLine(chart, params.line, params.style);
|
|
2235
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2236
|
-
}
|
|
2237
|
-
function setChartColorMapOverrideT(ctx, params) {
|
|
2238
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
2239
|
-
pptxViewerCore.setChartColorMapOverride(chart, params.overrides);
|
|
2240
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2241
|
-
}
|
|
2242
|
-
function findChartElement2(ctx, slideIndex, elementId) {
|
|
2243
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
2244
|
-
if (err) {
|
|
2245
|
-
throw new Error(err);
|
|
2246
|
-
}
|
|
2247
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
2248
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
2249
|
-
if (!el) {
|
|
2250
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
2251
|
-
}
|
|
2252
|
-
if (el.type !== "chart") {
|
|
2253
|
-
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
2254
|
-
}
|
|
2255
|
-
return el;
|
|
2256
|
-
}
|
|
2257
|
-
function buildShape(input) {
|
|
2258
|
-
return {
|
|
2259
|
-
kind: input.kind ?? "sp",
|
|
2260
|
-
anchor: input.anchor ?? "rel",
|
|
2261
|
-
from: input.from,
|
|
2262
|
-
...input.to ? { to: input.to } : {},
|
|
2263
|
-
...input.ext ? { ext: input.ext } : {},
|
|
2264
|
-
...input.prst ? { prst: input.prst } : {},
|
|
2265
|
-
...input.fill ? { fill: input.fill } : {},
|
|
2266
|
-
...input.stroke ? { stroke: input.stroke } : {},
|
|
2267
|
-
...input.strokeWidth !== void 0 ? { strokeWidth: input.strokeWidth } : {},
|
|
2268
|
-
...input.text ? { paragraphs: [{ text: input.text, align: "ctr" }] } : {}
|
|
2269
|
-
};
|
|
2270
|
-
}
|
|
2271
|
-
function listChartUserShapesT(ctx, params) {
|
|
2272
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
2273
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { shapes: pptxViewerCore.listChartUserShapes(chart) } };
|
|
2274
|
-
}
|
|
2275
|
-
function addChartUserShapeT(ctx, params) {
|
|
2276
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
2277
|
-
pptxViewerCore.addChartUserShape(chart, buildShape(params.shape));
|
|
2278
|
-
const index = (chart.chartData?.userShapes?.length ?? 1) - 1;
|
|
2279
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId, index } };
|
|
2280
|
-
}
|
|
2281
|
-
function updateChartUserShapeT(ctx, params) {
|
|
2282
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
2283
|
-
const patch = {
|
|
2284
|
-
...params.patch.kind ? { kind: params.patch.kind } : {},
|
|
2285
|
-
...params.patch.anchor ? { anchor: params.patch.anchor } : {},
|
|
2286
|
-
...params.patch.from ? { from: params.patch.from } : {},
|
|
2287
|
-
...params.patch.to ? { to: params.patch.to } : {},
|
|
2288
|
-
...params.patch.ext ? { ext: params.patch.ext } : {},
|
|
2289
|
-
...params.patch.prst ? { prst: params.patch.prst } : {},
|
|
2290
|
-
...params.patch.fill ? { fill: params.patch.fill } : {},
|
|
2291
|
-
...params.patch.stroke ? { stroke: params.patch.stroke } : {},
|
|
2292
|
-
...params.patch.strokeWidth !== void 0 ? { strokeWidth: params.patch.strokeWidth } : {},
|
|
2293
|
-
...params.patch.text !== void 0 ? { paragraphs: [{ text: params.patch.text, align: "ctr" }] } : {}
|
|
2294
|
-
};
|
|
2295
|
-
pptxViewerCore.updateChartUserShape(chart, params.index, patch);
|
|
2296
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2297
|
-
}
|
|
2298
|
-
function removeChartUserShapeT(ctx, params) {
|
|
2299
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
2300
|
-
pptxViewerCore.removeChartUserShape(chart, params.index);
|
|
2301
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
2302
|
-
}
|
|
2303
|
-
function extractNodes(data) {
|
|
2304
|
-
if (!data.nodes) {
|
|
2305
|
-
return [];
|
|
2306
|
-
}
|
|
2307
|
-
return data.nodes.map((n) => ({
|
|
2308
|
-
id: n.id,
|
|
2309
|
-
text: n.text ?? "",
|
|
2310
|
-
children: n.children?.map((c) => ({ id: c.id, text: c.text ?? "" }))
|
|
2311
|
-
}));
|
|
2312
|
-
}
|
|
2313
|
-
function manageSmartArt(ctx, params) {
|
|
2314
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2315
|
-
if (err) {
|
|
2316
|
-
throw new Error(err);
|
|
2317
|
-
}
|
|
2318
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2319
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2320
|
-
if (!el) {
|
|
2321
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2322
|
-
}
|
|
2323
|
-
if (el.type !== "smartArt") {
|
|
2324
|
-
throw new Error(`Element '${params.elementId}' is not a SmartArt.`);
|
|
2325
|
-
}
|
|
2326
|
-
const smartArt = el;
|
|
2327
|
-
if (!smartArt.smartArtData) {
|
|
2328
|
-
throw new Error(`SmartArt '${params.elementId}' has no data.`);
|
|
2329
|
-
}
|
|
2330
|
-
switch (params.action) {
|
|
2331
|
-
case "getNodes": {
|
|
2332
|
-
return {
|
|
2333
|
-
pptxData: ctx.pptxData,
|
|
2334
|
-
dirty: false,
|
|
2335
|
-
result: {
|
|
2336
|
-
action: "getNodes",
|
|
2337
|
-
elementId: params.elementId,
|
|
2338
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
2339
|
-
}
|
|
2340
|
-
};
|
|
2341
|
-
}
|
|
2342
|
-
case "addNode": {
|
|
2343
|
-
smartArt.smartArtData = pptxViewerCore.addSmartArtNode(
|
|
2344
|
-
smartArt.smartArtData,
|
|
2345
|
-
params.text ?? "",
|
|
2346
|
-
params.afterNodeId
|
|
2347
|
-
);
|
|
2348
|
-
return {
|
|
2349
|
-
pptxData: ctx.pptxData,
|
|
2350
|
-
dirty: true,
|
|
2351
|
-
result: {
|
|
2352
|
-
action: "addNode",
|
|
2353
|
-
elementId: params.elementId,
|
|
2354
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
2355
|
-
}
|
|
2356
|
-
};
|
|
2357
|
-
}
|
|
2358
|
-
case "removeNode": {
|
|
2359
|
-
if (!params.nodeId) {
|
|
2360
|
-
throw new Error("nodeId is required for removeNode.");
|
|
2361
|
-
}
|
|
2362
|
-
smartArt.smartArtData = pptxViewerCore.removeSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
2363
|
-
return {
|
|
2364
|
-
pptxData: ctx.pptxData,
|
|
2365
|
-
dirty: true,
|
|
2366
|
-
result: {
|
|
2367
|
-
action: "removeNode",
|
|
2368
|
-
elementId: params.elementId,
|
|
2369
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
2370
|
-
}
|
|
2371
|
-
};
|
|
2372
|
-
}
|
|
2373
|
-
case "updateNodeText": {
|
|
2374
|
-
if (!params.nodeId) {
|
|
2375
|
-
throw new Error("nodeId is required for updateNodeText.");
|
|
2376
|
-
}
|
|
2377
|
-
smartArt.smartArtData = pptxViewerCore.updateSmartArtNodeText(
|
|
2378
|
-
smartArt.smartArtData,
|
|
2379
|
-
params.nodeId,
|
|
2380
|
-
params.text ?? ""
|
|
2381
|
-
);
|
|
2382
|
-
return {
|
|
2383
|
-
pptxData: ctx.pptxData,
|
|
2384
|
-
dirty: true,
|
|
2385
|
-
result: { action: "updateNodeText", elementId: params.elementId }
|
|
2386
|
-
};
|
|
2387
|
-
}
|
|
2388
|
-
case "reorderNode": {
|
|
2389
|
-
if (!params.nodeId) {
|
|
2390
|
-
throw new Error("nodeId is required for reorderNode.");
|
|
2391
|
-
}
|
|
2392
|
-
const dir = params.direction ?? 1;
|
|
2393
|
-
smartArt.smartArtData = pptxViewerCore.reorderSmartArtNode(smartArt.smartArtData, params.nodeId, dir);
|
|
2394
|
-
return {
|
|
2395
|
-
pptxData: ctx.pptxData,
|
|
2396
|
-
dirty: true,
|
|
2397
|
-
result: {
|
|
2398
|
-
action: "reorderNode",
|
|
2399
|
-
elementId: params.elementId,
|
|
2400
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
2401
|
-
}
|
|
2402
|
-
};
|
|
2403
|
-
}
|
|
2404
|
-
case "promoteNode": {
|
|
2405
|
-
if (!params.nodeId) {
|
|
2406
|
-
throw new Error("nodeId is required for promoteNode.");
|
|
2407
|
-
}
|
|
2408
|
-
smartArt.smartArtData = pptxViewerCore.promoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
2409
|
-
return {
|
|
2410
|
-
pptxData: ctx.pptxData,
|
|
2411
|
-
dirty: true,
|
|
2412
|
-
result: {
|
|
2413
|
-
action: "promoteNode",
|
|
2414
|
-
elementId: params.elementId,
|
|
2415
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
2416
|
-
}
|
|
2417
|
-
};
|
|
2418
|
-
}
|
|
2419
|
-
case "demoteNode": {
|
|
2420
|
-
if (!params.nodeId) {
|
|
2421
|
-
throw new Error("nodeId is required for demoteNode.");
|
|
2422
|
-
}
|
|
2423
|
-
smartArt.smartArtData = pptxViewerCore.demoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
2424
|
-
return {
|
|
2425
|
-
pptxData: ctx.pptxData,
|
|
2426
|
-
dirty: true,
|
|
2427
|
-
result: {
|
|
2428
|
-
action: "demoteNode",
|
|
2429
|
-
elementId: params.elementId,
|
|
2430
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
2431
|
-
}
|
|
2432
|
-
};
|
|
2433
|
-
}
|
|
2434
|
-
case "decompose": {
|
|
2435
|
-
const bounds = {
|
|
2436
|
-
x: smartArt.x,
|
|
2437
|
-
y: smartArt.y,
|
|
2438
|
-
width: smartArt.width,
|
|
2439
|
-
height: smartArt.height
|
|
2440
|
-
};
|
|
2441
|
-
const decomposed = pptxViewerCore.decomposeSmartArt(smartArt.smartArtData, bounds);
|
|
2442
|
-
if (!decomposed || decomposed.length === 0) {
|
|
2443
|
-
throw new Error("Failed to decompose SmartArt into shapes.");
|
|
2444
|
-
}
|
|
2445
|
-
const idx = slide.elements.indexOf(el);
|
|
2446
|
-
slide.elements.splice(idx, 1, ...decomposed);
|
|
2447
|
-
return {
|
|
2448
|
-
pptxData: ctx.pptxData,
|
|
2449
|
-
dirty: true,
|
|
2450
|
-
result: {
|
|
2451
|
-
action: "decompose",
|
|
2452
|
-
elementId: params.elementId,
|
|
2453
|
-
decomposedCount: decomposed.length
|
|
2454
|
-
}
|
|
2455
|
-
};
|
|
2456
|
-
}
|
|
2457
|
-
default:
|
|
2458
|
-
throw new Error(`Unknown SmartArt action: ${String(params.action)}`);
|
|
2459
|
-
}
|
|
2460
|
-
}
|
|
2461
|
-
function mergePresentationT(ctx, params) {
|
|
2462
|
-
const options = {};
|
|
2463
|
-
if (params.slideIndices) {
|
|
2464
|
-
options.slideIndices = params.slideIndices;
|
|
2465
|
-
}
|
|
2466
|
-
if (params.insertAt !== void 0) {
|
|
2467
|
-
options.insertAt = params.insertAt;
|
|
2468
|
-
}
|
|
2469
|
-
if (params.keepSourceTheme !== void 0) {
|
|
2470
|
-
options.keepSourceTheme = params.keepSourceTheme;
|
|
2471
|
-
}
|
|
2472
|
-
const added = pptxViewerCore.mergePresentation(ctx.pptxData, params.sourceData, options);
|
|
2473
|
-
return {
|
|
2474
|
-
pptxData: ctx.pptxData,
|
|
2475
|
-
dirty: added > 0,
|
|
2476
|
-
result: { slidesAdded: added, totalSlides: ctx.pptxData.slides.length }
|
|
2477
|
-
};
|
|
2478
|
-
}
|
|
2479
|
-
function diffPresentationsT(ctx, params) {
|
|
2480
|
-
const diff = pptxViewerCore.diffPresentations(ctx.pptxData, params.otherData);
|
|
2481
|
-
return {
|
|
2482
|
-
pptxData: ctx.pptxData,
|
|
2483
|
-
dirty: false,
|
|
2484
|
-
result: diff
|
|
2485
|
-
};
|
|
2486
|
-
}
|
|
2487
|
-
function findPlaceholdersT(ctx) {
|
|
2488
|
-
const placeholders = pptxViewerCore.findPlaceholders(ctx.pptxData);
|
|
2489
|
-
return {
|
|
2490
|
-
pptxData: ctx.pptxData,
|
|
2491
|
-
dirty: false,
|
|
2492
|
-
result: { placeholders, count: placeholders.length }
|
|
2493
|
-
};
|
|
2494
|
-
}
|
|
2495
|
-
function applyTemplateT(ctx, params) {
|
|
2496
|
-
pptxViewerCore.applyTemplate(ctx.pptxData, params.data);
|
|
2497
|
-
return {
|
|
2498
|
-
pptxData: ctx.pptxData,
|
|
2499
|
-
dirty: true,
|
|
2500
|
-
result: { applied: true, slideCount: ctx.pptxData.slides.length }
|
|
2501
|
-
};
|
|
2502
|
-
}
|
|
2503
|
-
|
|
2504
|
-
// src/tools/metadata-tools.ts
|
|
2505
|
-
function getMetadata(ctx) {
|
|
2506
|
-
return {
|
|
2507
|
-
pptxData: ctx.pptxData,
|
|
2508
|
-
dirty: false,
|
|
2509
|
-
result: {
|
|
2510
|
-
coreProperties: ctx.pptxData.coreProperties,
|
|
2511
|
-
appProperties: ctx.pptxData.appProperties,
|
|
2512
|
-
customProperties: ctx.pptxData.customProperties,
|
|
2513
|
-
slideCount: ctx.pptxData.slides.length
|
|
2514
|
-
}
|
|
2515
|
-
};
|
|
2516
|
-
}
|
|
2517
|
-
function updateMetadata(ctx, params) {
|
|
2518
|
-
const updated = [];
|
|
2519
|
-
if (params.title !== void 0 || params.subject !== void 0 || params.creator !== void 0 || params.keywords !== void 0 || params.description !== void 0 || params.lastModifiedBy !== void 0 || params.category !== void 0) {
|
|
2520
|
-
if (!ctx.pptxData.coreProperties) {
|
|
2521
|
-
ctx.pptxData.coreProperties = {};
|
|
2522
|
-
}
|
|
2523
|
-
const cp = ctx.pptxData.coreProperties;
|
|
2524
|
-
if (params.title !== void 0) {
|
|
2525
|
-
cp.title = params.title;
|
|
2526
|
-
updated.push("title");
|
|
2527
|
-
}
|
|
2528
|
-
if (params.subject !== void 0) {
|
|
2529
|
-
cp.subject = params.subject;
|
|
2530
|
-
updated.push("subject");
|
|
2531
|
-
}
|
|
2532
|
-
if (params.creator !== void 0) {
|
|
2533
|
-
cp.creator = params.creator;
|
|
2534
|
-
updated.push("creator");
|
|
2535
|
-
}
|
|
2536
|
-
if (params.keywords !== void 0) {
|
|
2537
|
-
cp.keywords = params.keywords;
|
|
2538
|
-
updated.push("keywords");
|
|
2539
|
-
}
|
|
2540
|
-
if (params.description !== void 0) {
|
|
2541
|
-
cp.description = params.description;
|
|
2542
|
-
updated.push("description");
|
|
2543
|
-
}
|
|
2544
|
-
if (params.lastModifiedBy !== void 0) {
|
|
2545
|
-
cp.lastModifiedBy = params.lastModifiedBy;
|
|
2546
|
-
updated.push("lastModifiedBy");
|
|
2547
|
-
}
|
|
2548
|
-
if (params.category !== void 0) {
|
|
2549
|
-
cp.category = params.category;
|
|
2550
|
-
updated.push("category");
|
|
2551
|
-
}
|
|
2552
|
-
}
|
|
2553
|
-
if (params.company !== void 0 || params.manager !== void 0) {
|
|
2554
|
-
if (!ctx.pptxData.appProperties) {
|
|
2555
|
-
ctx.pptxData.appProperties = {};
|
|
2556
|
-
}
|
|
2557
|
-
const ap = ctx.pptxData.appProperties;
|
|
2558
|
-
if (params.company !== void 0) {
|
|
2559
|
-
ap.company = params.company;
|
|
2560
|
-
updated.push("company");
|
|
2561
|
-
}
|
|
2562
|
-
if (params.manager !== void 0) {
|
|
2563
|
-
ap.manager = params.manager;
|
|
2564
|
-
updated.push("manager");
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
if (params.customProperties) {
|
|
2568
|
-
if (!ctx.pptxData.customProperties) {
|
|
2569
|
-
ctx.pptxData.customProperties = [];
|
|
2570
|
-
}
|
|
2571
|
-
for (const cp of params.customProperties) {
|
|
2572
|
-
const valueStr = String(cp.value);
|
|
2573
|
-
const vtType = typeof cp.value === "number" ? "i4" : typeof cp.value === "boolean" ? "bool" : "lpwstr";
|
|
2574
|
-
const existing = ctx.pptxData.customProperties.find((p) => p.name === cp.name);
|
|
2575
|
-
if (existing) {
|
|
2576
|
-
existing.value = valueStr;
|
|
2577
|
-
existing.type = vtType;
|
|
2578
|
-
} else {
|
|
2579
|
-
ctx.pptxData.customProperties.push({ name: cp.name, value: valueStr, type: vtType });
|
|
2580
|
-
}
|
|
2581
|
-
updated.push(`custom:${cp.name}`);
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
return {
|
|
2585
|
-
pptxData: ctx.pptxData,
|
|
2586
|
-
dirty: updated.length > 0,
|
|
2587
|
-
result: { updated }
|
|
2588
|
-
};
|
|
2589
|
-
}
|
|
2590
|
-
function manageSections(ctx, params) {
|
|
2591
|
-
switch (params.action) {
|
|
2592
|
-
case "list": {
|
|
2593
|
-
const sections = (ctx.pptxData.sections ?? []).map((s) => ({
|
|
2594
|
-
id: s.id,
|
|
2595
|
-
name: s.name,
|
|
2596
|
-
slideIds: s.slideIds,
|
|
2597
|
-
collapsed: s.collapsed,
|
|
2598
|
-
color: s.color
|
|
2599
|
-
}));
|
|
2600
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", sections } };
|
|
2601
|
-
}
|
|
2602
|
-
case "add": {
|
|
2603
|
-
if (!params.name) {
|
|
2604
|
-
throw new Error("name is required for add action.");
|
|
2605
|
-
}
|
|
2606
|
-
const section = pptxViewerCore.addSection(ctx.pptxData, params.name, params.slideIndices ?? []);
|
|
2607
|
-
return {
|
|
2608
|
-
pptxData: ctx.pptxData,
|
|
2609
|
-
dirty: true,
|
|
2610
|
-
result: {
|
|
2611
|
-
action: "add",
|
|
2612
|
-
section: { id: section.id, name: section.name, slideIds: section.slideIds }
|
|
2613
|
-
}
|
|
2614
|
-
};
|
|
2615
|
-
}
|
|
2616
|
-
case "remove": {
|
|
2617
|
-
if (!params.sectionId) {
|
|
2618
|
-
throw new Error("sectionId is required for remove action.");
|
|
2619
|
-
}
|
|
2620
|
-
const success = pptxViewerCore.removeSection(ctx.pptxData, params.sectionId);
|
|
2621
|
-
return { pptxData: ctx.pptxData, dirty: success, result: { action: "remove", success } };
|
|
2622
|
-
}
|
|
2623
|
-
case "reorder": {
|
|
2624
|
-
if (!params.sectionIds) {
|
|
2625
|
-
throw new Error("sectionIds is required for reorder action.");
|
|
2626
|
-
}
|
|
2627
|
-
pptxViewerCore.reorderSections(ctx.pptxData, params.sectionIds);
|
|
2628
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { action: "reorder", success: true } };
|
|
2629
|
-
}
|
|
2630
|
-
case "moveSlides": {
|
|
2631
|
-
if (!params.sectionId) {
|
|
2632
|
-
throw new Error("sectionId is required for moveSlides action.");
|
|
2633
|
-
}
|
|
2634
|
-
if (!params.slideIndices) {
|
|
2635
|
-
throw new Error("slideIndices is required for moveSlides action.");
|
|
2636
|
-
}
|
|
2637
|
-
const success = pptxViewerCore.moveSlidesToSection(ctx.pptxData, params.slideIndices, params.sectionId);
|
|
2638
|
-
return { pptxData: ctx.pptxData, dirty: success, result: { action: "moveSlides", success } };
|
|
2639
|
-
}
|
|
2640
|
-
case "getForSlide": {
|
|
2641
|
-
if (params.slideIndex === void 0) {
|
|
2642
|
-
throw new Error("slideIndex is required for getForSlide action.");
|
|
2643
|
-
}
|
|
2644
|
-
const section = pptxViewerCore.getSectionForSlide(ctx.pptxData, params.slideIndex);
|
|
2645
|
-
const info = section ? { id: section.id, name: section.name, slideIds: section.slideIds } : null;
|
|
2646
|
-
return {
|
|
2647
|
-
pptxData: ctx.pptxData,
|
|
2648
|
-
dirty: false,
|
|
2649
|
-
result: { action: "getForSlide", section: info }
|
|
2650
|
-
};
|
|
2651
|
-
}
|
|
2652
|
-
default:
|
|
2653
|
-
throw new Error(`Unknown section action: ${String(params.action)}`);
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
function exportToSvg(ctx, params) {
|
|
2657
|
-
if (params.slideIndices) {
|
|
2658
|
-
for (const si of params.slideIndices) {
|
|
2659
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
2660
|
-
if (err) {
|
|
2661
|
-
throw new Error(err);
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
const options = {};
|
|
2666
|
-
if (params.slideIndices) {
|
|
2667
|
-
options.slideIndices = params.slideIndices;
|
|
2668
|
-
}
|
|
2669
|
-
if (params.includeHidden !== void 0) {
|
|
2670
|
-
options.includeHidden = params.includeHidden;
|
|
2671
|
-
}
|
|
2672
|
-
if (params.defaultFontFamily) {
|
|
2673
|
-
options.defaultFontFamily = params.defaultFontFamily;
|
|
2674
|
-
}
|
|
2675
|
-
if (params.defaultFontSize) {
|
|
2676
|
-
options.defaultFontSize = params.defaultFontSize;
|
|
2677
|
-
}
|
|
2678
|
-
const svgStrings = pptxViewerCore.SvgExporter.exportAll(ctx.pptxData, options);
|
|
2679
|
-
return {
|
|
2680
|
-
pptxData: ctx.pptxData,
|
|
2681
|
-
dirty: false,
|
|
2682
|
-
result: { svgStrings, slideCount: svgStrings.length }
|
|
2683
|
-
};
|
|
2684
|
-
}
|
|
2685
|
-
function exportSlideSvg(ctx, params) {
|
|
2686
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2687
|
-
if (err) {
|
|
2688
|
-
throw new Error(err);
|
|
2689
|
-
}
|
|
2690
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2691
|
-
const width = ctx.pptxData.width ?? 960;
|
|
2692
|
-
const height = ctx.pptxData.height ?? 540;
|
|
2693
|
-
const options = {};
|
|
2694
|
-
if (params.defaultFontFamily) {
|
|
2695
|
-
options.defaultFontFamily = params.defaultFontFamily;
|
|
2696
|
-
}
|
|
2697
|
-
if (params.defaultFontSize) {
|
|
2698
|
-
options.defaultFontSize = params.defaultFontSize;
|
|
2699
|
-
}
|
|
2700
|
-
const svg = pptxViewerCore.SvgExporter.exportSlide(slide, width, height, options);
|
|
2701
|
-
return {
|
|
2702
|
-
pptxData: ctx.pptxData,
|
|
2703
|
-
dirty: false,
|
|
2704
|
-
result: { svg, slideIndex: params.slideIndex }
|
|
2705
|
-
};
|
|
2706
|
-
}
|
|
2707
|
-
function exportToJson(ctx, params) {
|
|
2708
|
-
const document = pptxViewerCore.buildPptxJsonDocument(ctx.pptxData, { generator: "pptx-viewer-mcp" });
|
|
2709
|
-
const json = JSON.stringify(document, null, params.pretty === false ? void 0 : 2);
|
|
2710
|
-
return {
|
|
2711
|
-
pptxData: ctx.pptxData,
|
|
2712
|
-
dirty: false,
|
|
2713
|
-
result: {
|
|
2714
|
-
json,
|
|
2715
|
-
slideCount: document.slideCount,
|
|
2716
|
-
byteSize: new TextEncoder().encode(json).byteLength,
|
|
2717
|
-
assets: document.assets
|
|
2718
|
-
}
|
|
2719
|
-
};
|
|
2720
|
-
}
|
|
2721
|
-
function importFromJson(ctx, params) {
|
|
2722
|
-
const imported = pptxViewerCore.deserializePptxFromJson(params.json);
|
|
2723
|
-
pptxViewerCore.applyImportedPptxData(ctx.pptxData, imported);
|
|
2724
|
-
return {
|
|
2725
|
-
pptxData: ctx.pptxData,
|
|
2726
|
-
dirty: true,
|
|
2727
|
-
result: {
|
|
2728
|
-
slideCount: ctx.pptxData.slides.length,
|
|
2729
|
-
width: ctx.pptxData.width,
|
|
2730
|
-
height: ctx.pptxData.height
|
|
2731
|
-
}
|
|
2732
|
-
};
|
|
2733
|
-
}
|
|
2734
|
-
|
|
2735
|
-
// src/tools/hyperlink-tools.ts
|
|
2736
|
-
function manageHyperlinks(ctx, params) {
|
|
2737
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2738
|
-
if (err) {
|
|
2739
|
-
throw new Error(err);
|
|
2740
|
-
}
|
|
2741
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2742
|
-
switch (params.action) {
|
|
2743
|
-
case "list": {
|
|
2744
|
-
const hyperlinks = [];
|
|
2745
|
-
for (const el of slide.elements) {
|
|
2746
|
-
if (el.actionClick) {
|
|
2747
|
-
hyperlinks.push({
|
|
2748
|
-
elementId: el.id,
|
|
2749
|
-
trigger: "click",
|
|
2750
|
-
url: el.actionClick.url,
|
|
2751
|
-
tooltip: el.actionClick.tooltip,
|
|
2752
|
-
targetSlideIndex: el.actionClick.targetSlideIndex,
|
|
2753
|
-
actionType: el.actionClick.action
|
|
2754
|
-
});
|
|
2755
|
-
}
|
|
2756
|
-
if (el.actionHover) {
|
|
2757
|
-
hyperlinks.push({
|
|
2758
|
-
elementId: el.id,
|
|
2759
|
-
trigger: "hover",
|
|
2760
|
-
url: el.actionHover.url,
|
|
2761
|
-
tooltip: el.actionHover.tooltip,
|
|
2762
|
-
targetSlideIndex: el.actionHover.targetSlideIndex,
|
|
2763
|
-
actionType: el.actionHover.action
|
|
2764
|
-
});
|
|
2765
|
-
}
|
|
2766
|
-
}
|
|
2767
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", hyperlinks } };
|
|
2768
|
-
}
|
|
2769
|
-
case "set": {
|
|
2770
|
-
if (!params.elementId) {
|
|
2771
|
-
throw new Error("elementId is required for set action.");
|
|
2772
|
-
}
|
|
2773
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2774
|
-
if (!el) {
|
|
2775
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2776
|
-
}
|
|
2777
|
-
const trigger = params.trigger ?? "click";
|
|
2778
|
-
const action = {};
|
|
2779
|
-
if (params.url) {
|
|
2780
|
-
action.url = params.url;
|
|
2781
|
-
}
|
|
2782
|
-
if (params.tooltip) {
|
|
2783
|
-
action.tooltip = params.tooltip;
|
|
2784
|
-
}
|
|
2785
|
-
if (params.targetSlideIndex !== void 0) {
|
|
2786
|
-
action.targetSlideIndex = params.targetSlideIndex;
|
|
2787
|
-
}
|
|
2788
|
-
if (params.actionType) {
|
|
2789
|
-
switch (params.actionType) {
|
|
2790
|
-
case "url":
|
|
2791
|
-
action.action = "ppaction://hlinkpres";
|
|
2792
|
-
break;
|
|
2793
|
-
case "slide":
|
|
2794
|
-
action.action = "ppaction://hlinksldjump";
|
|
2795
|
-
break;
|
|
2796
|
-
case "nextSlide":
|
|
2797
|
-
action.action = "ppaction://hlinkshowjump?jump=nextslide";
|
|
2798
|
-
break;
|
|
2799
|
-
case "prevSlide":
|
|
2800
|
-
action.action = "ppaction://hlinkshowjump?jump=previousslide";
|
|
2801
|
-
break;
|
|
2802
|
-
case "firstSlide":
|
|
2803
|
-
action.action = "ppaction://hlinkshowjump?jump=firstslide";
|
|
2804
|
-
break;
|
|
2805
|
-
case "lastSlide":
|
|
2806
|
-
action.action = "ppaction://hlinkshowjump?jump=lastslide";
|
|
2807
|
-
break;
|
|
2808
|
-
case "endShow":
|
|
2809
|
-
action.action = "ppaction://hlinkshowjump?jump=endshow";
|
|
2810
|
-
break;
|
|
2811
|
-
}
|
|
2812
|
-
}
|
|
2813
|
-
if (trigger === "click") {
|
|
2814
|
-
el.actionClick = action;
|
|
2815
|
-
} else {
|
|
2816
|
-
el.actionHover = action;
|
|
2817
|
-
}
|
|
2818
|
-
return {
|
|
2819
|
-
pptxData: ctx.pptxData,
|
|
2820
|
-
dirty: true,
|
|
2821
|
-
result: { action: "set", elementId: params.elementId }
|
|
2822
|
-
};
|
|
2823
|
-
}
|
|
2824
|
-
case "remove": {
|
|
2825
|
-
if (!params.elementId) {
|
|
2826
|
-
throw new Error("elementId is required for remove action.");
|
|
2827
|
-
}
|
|
2828
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2829
|
-
if (!el) {
|
|
2830
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2831
|
-
}
|
|
2832
|
-
const trigger = params.trigger ?? "click";
|
|
2833
|
-
if (trigger === "click") {
|
|
2834
|
-
el.actionClick = void 0;
|
|
2835
|
-
} else {
|
|
2836
|
-
el.actionHover = void 0;
|
|
2837
|
-
}
|
|
2838
|
-
return {
|
|
2839
|
-
pptxData: ctx.pptxData,
|
|
2840
|
-
dirty: true,
|
|
2841
|
-
result: { action: "remove", elementId: params.elementId }
|
|
2842
|
-
};
|
|
2843
|
-
}
|
|
2844
|
-
default:
|
|
2845
|
-
throw new Error(`Unknown hyperlink action: ${String(params.action)}`);
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
function replaceGeometry(ctx, params) {
|
|
2849
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2850
|
-
if (err) {
|
|
2851
|
-
throw new Error(err);
|
|
2852
|
-
}
|
|
2853
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2854
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2855
|
-
if (!el) {
|
|
2856
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2857
|
-
}
|
|
2858
|
-
if (el.type !== "shape") {
|
|
2859
|
-
throw new Error(`Element '${params.elementId}' is not a shape.`);
|
|
2860
|
-
}
|
|
2861
|
-
const shape = el;
|
|
2862
|
-
if (params.svgPath) {
|
|
2863
|
-
pptxViewerCore.replaceWithCustomGeometry(shape, params.svgPath, params.pathWidth, params.pathHeight);
|
|
2864
|
-
return {
|
|
2865
|
-
pptxData: ctx.pptxData,
|
|
2866
|
-
dirty: true,
|
|
2867
|
-
result: { elementId: params.elementId, geometryType: "custom" }
|
|
2868
|
-
};
|
|
2869
|
-
}
|
|
2870
|
-
if (params.shapeType) {
|
|
2871
|
-
pptxViewerCore.replaceShapeGeometry(shape, params.shapeType, params.adjustments);
|
|
2872
|
-
return {
|
|
2873
|
-
pptxData: ctx.pptxData,
|
|
2874
|
-
dirty: true,
|
|
2875
|
-
result: { elementId: params.elementId, geometryType: params.shapeType }
|
|
2876
|
-
};
|
|
2877
|
-
}
|
|
2878
|
-
throw new Error("Either shapeType or svgPath must be provided.");
|
|
2879
|
-
}
|
|
2880
|
-
function setElementLockT(ctx, params) {
|
|
2881
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2882
|
-
if (err) {
|
|
2883
|
-
throw new Error(err);
|
|
2884
|
-
}
|
|
2885
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2886
|
-
const idx = slide.elements.findIndex((e) => e.id === params.elementId);
|
|
2887
|
-
if (idx < 0) {
|
|
2888
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2889
|
-
}
|
|
2890
|
-
const extraLocks = {};
|
|
2891
|
-
if (params.noMove !== void 0) {
|
|
2892
|
-
extraLocks["noMove"] = params.noMove;
|
|
2893
|
-
}
|
|
2894
|
-
if (params.noResize !== void 0) {
|
|
2895
|
-
extraLocks["noResize"] = params.noResize;
|
|
2896
|
-
}
|
|
2897
|
-
if (params.noRotation !== void 0) {
|
|
2898
|
-
extraLocks["noRotation"] = params.noRotation;
|
|
2899
|
-
}
|
|
2900
|
-
if (params.noSelect !== void 0) {
|
|
2901
|
-
extraLocks["noSelect"] = params.noSelect;
|
|
2902
|
-
}
|
|
2903
|
-
if (params.noTextEdit !== void 0) {
|
|
2904
|
-
extraLocks["noTextEdit"] = params.noTextEdit;
|
|
2905
|
-
}
|
|
2906
|
-
const updated = pptxViewerCore.setElementLocked(slide.elements[idx], params.locked, extraLocks);
|
|
2907
|
-
slide.elements[idx] = updated;
|
|
2908
|
-
return {
|
|
2909
|
-
pptxData: ctx.pptxData,
|
|
2910
|
-
dirty: true,
|
|
2911
|
-
result: { elementId: params.elementId, locked: params.locked }
|
|
2912
|
-
};
|
|
2913
|
-
}
|
|
2914
|
-
async function validatePresentation(rawBytes) {
|
|
2915
|
-
const result = await pptxViewerCore.validatePptx(rawBytes);
|
|
2916
|
-
return {
|
|
2917
|
-
valid: result.valid,
|
|
2918
|
-
issueCount: result.issues.length,
|
|
2919
|
-
errors: result.issues.filter((i) => i.severity === "error").length,
|
|
2920
|
-
warnings: result.issues.filter((i) => i.severity === "warning").length,
|
|
2921
|
-
issues: result.issues
|
|
2922
|
-
};
|
|
2923
|
-
}
|
|
2924
|
-
async function repairPresentation(rawBytes) {
|
|
2925
|
-
const result = await pptxViewerCore.repairPptx(rawBytes);
|
|
2926
|
-
return {
|
|
2927
|
-
result: {
|
|
2928
|
-
repairCount: result.repairs.length,
|
|
2929
|
-
repairs: result.repairs
|
|
2930
|
-
},
|
|
2931
|
-
repairedBytes: result.repaired
|
|
2932
|
-
};
|
|
2933
|
-
}
|
|
2934
|
-
|
|
2935
|
-
// src/tools/presentation-tools.ts
|
|
2936
|
-
function getPresentationProperties(ctx) {
|
|
2937
|
-
return {
|
|
2938
|
-
pptxData: ctx.pptxData,
|
|
2939
|
-
dirty: false,
|
|
2940
|
-
result: {
|
|
2941
|
-
properties: ctx.pptxData.presentationProperties,
|
|
2942
|
-
slideCount: ctx.pptxData.slides.length,
|
|
2943
|
-
width: ctx.pptxData.width,
|
|
2944
|
-
height: ctx.pptxData.height
|
|
2945
|
-
}
|
|
2946
|
-
};
|
|
2947
|
-
}
|
|
2948
|
-
function updatePresentationProperties(ctx, params) {
|
|
2949
|
-
if (!ctx.pptxData.presentationProperties) {
|
|
2950
|
-
ctx.pptxData.presentationProperties = {};
|
|
2951
|
-
}
|
|
2952
|
-
const pp = ctx.pptxData.presentationProperties;
|
|
2953
|
-
if (params.showType !== void 0) {
|
|
2954
|
-
pp.showType = params.showType;
|
|
2955
|
-
}
|
|
2956
|
-
if (params.loopContinuously !== void 0) {
|
|
2957
|
-
pp.loopContinuously = params.loopContinuously;
|
|
2958
|
-
}
|
|
2959
|
-
if (params.showWithNarration !== void 0) {
|
|
2960
|
-
pp.showWithNarration = params.showWithNarration;
|
|
2961
|
-
}
|
|
2962
|
-
if (params.showWithAnimation !== void 0) {
|
|
2963
|
-
pp.showWithAnimation = params.showWithAnimation;
|
|
2964
|
-
}
|
|
2965
|
-
if (params.advanceMode !== void 0) {
|
|
2966
|
-
pp.advanceMode = params.advanceMode;
|
|
2967
|
-
}
|
|
2968
|
-
if (params.showSlidesMode !== void 0) {
|
|
2969
|
-
pp.showSlidesMode = params.showSlidesMode;
|
|
2970
|
-
}
|
|
2971
|
-
if (params.showSlidesFrom !== void 0) {
|
|
2972
|
-
pp.showSlidesFrom = params.showSlidesFrom;
|
|
2973
|
-
}
|
|
2974
|
-
if (params.showSlidesTo !== void 0) {
|
|
2975
|
-
pp.showSlidesTo = params.showSlidesTo;
|
|
2976
|
-
}
|
|
2977
|
-
if (params.penColor !== void 0) {
|
|
2978
|
-
pp.penColor = params.penColor;
|
|
2979
|
-
}
|
|
2980
|
-
return {
|
|
2981
|
-
pptxData: ctx.pptxData,
|
|
2982
|
-
dirty: true,
|
|
2983
|
-
result: { properties: pp }
|
|
2984
|
-
};
|
|
2985
|
-
}
|
|
2986
|
-
function getLayouts(ctx) {
|
|
2987
|
-
const layouts = [];
|
|
2988
|
-
if (ctx.pptxData.slideMasters) {
|
|
2989
|
-
for (const master of ctx.pptxData.slideMasters) {
|
|
2990
|
-
if (master.layouts) {
|
|
2991
|
-
for (const layout of master.layouts) {
|
|
2992
|
-
layouts.push({
|
|
2993
|
-
name: layout.name ?? "Unknown",
|
|
2994
|
-
path: layout.path
|
|
2995
|
-
});
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
}
|
|
2999
|
-
}
|
|
3000
|
-
if (ctx.pptxData.layoutOptions) {
|
|
3001
|
-
for (const opt of ctx.pptxData.layoutOptions) {
|
|
3002
|
-
if (!layouts.some((l) => l.path === opt.path)) {
|
|
3003
|
-
layouts.push({ name: opt.name, path: opt.path, type: opt.type });
|
|
3004
|
-
}
|
|
3005
|
-
}
|
|
3006
|
-
}
|
|
3007
|
-
return {
|
|
3008
|
-
pptxData: ctx.pptxData,
|
|
3009
|
-
dirty: false,
|
|
3010
|
-
result: { layouts, count: layouts.length }
|
|
3011
|
-
};
|
|
3012
|
-
}
|
|
3013
|
-
function applyLayout(ctx, params) {
|
|
3014
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3015
|
-
if (err) {
|
|
3016
|
-
throw new Error(err);
|
|
3017
|
-
}
|
|
3018
|
-
let layout;
|
|
3019
|
-
if (params.layoutName) {
|
|
3020
|
-
layout = pptxViewerCore.findLayoutByName(ctx.pptxData, params.layoutName);
|
|
3021
|
-
} else if (params.layoutType) {
|
|
3022
|
-
layout = pptxViewerCore.findLayoutByType(ctx.pptxData, params.layoutType);
|
|
3023
|
-
} else {
|
|
3024
|
-
throw new Error("Either layoutName or layoutType must be provided.");
|
|
3025
|
-
}
|
|
3026
|
-
if (!layout) {
|
|
3027
|
-
throw new Error(
|
|
3028
|
-
`Layout not found: ${params.layoutName ?? params.layoutType}. Use get_layouts to see available layouts.`
|
|
3029
|
-
);
|
|
3030
|
-
}
|
|
3031
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3032
|
-
slide.layoutName = layout.name;
|
|
3033
|
-
if (layout.path) {
|
|
3034
|
-
slide.layoutPath = layout.path;
|
|
3035
|
-
}
|
|
3036
|
-
const master = ctx.pptxData.slideMasters?.find(
|
|
3037
|
-
(candidate) => candidate.layouts?.some((definition2) => definition2.path === layout.path)
|
|
3038
|
-
);
|
|
3039
|
-
const definition = master?.layouts?.find((candidate) => candidate.path === layout.path);
|
|
3040
|
-
for (const frame of definition?.placeholders ?? []) {
|
|
3041
|
-
if (["dt", "ftr", "sldnum", "hdr"].includes(frame.type)) {
|
|
3042
|
-
continue;
|
|
3043
|
-
}
|
|
3044
|
-
const ph = {
|
|
3045
|
-
"@_type": frame.type === "ctrtitle" ? "ctrTitle" : frame.type,
|
|
3046
|
-
...frame.idx !== void 0 ? { "@_idx": frame.idx } : {}
|
|
3047
|
-
};
|
|
3048
|
-
if (slide.elements.some((element) => {
|
|
3049
|
-
const nv = element.rawXml?.["p:nvSpPr"];
|
|
3050
|
-
const nvPr = nv?.["p:nvPr"];
|
|
3051
|
-
const existing = nvPr?.["p:ph"];
|
|
3052
|
-
return element.placeholderType === frame.type && String(existing?.["@_idx"] ?? "0") === String(frame.idx ?? "0");
|
|
3053
|
-
})) {
|
|
3054
|
-
continue;
|
|
3055
|
-
}
|
|
3056
|
-
const inherited = master?.placeholders?.find(
|
|
3057
|
-
(candidate) => candidate.type === frame.type && (candidate.idx ?? "0") === (frame.idx ?? "0")
|
|
3058
|
-
) ?? master?.placeholders?.find((candidate) => candidate.type === frame.type);
|
|
3059
|
-
slide.elements.push({
|
|
3060
|
-
id: generateElementId(),
|
|
3061
|
-
type: "text",
|
|
3062
|
-
placeholderType: frame.type,
|
|
3063
|
-
x: frame.x ?? inherited?.x ?? 0,
|
|
3064
|
-
y: frame.y ?? inherited?.y ?? 0,
|
|
3065
|
-
width: frame.width ?? inherited?.width ?? ctx.pptxData.width,
|
|
3066
|
-
height: frame.height ?? inherited?.height ?? ctx.pptxData.height,
|
|
3067
|
-
text: "",
|
|
3068
|
-
textSegments: [{ text: "", style: {} }],
|
|
3069
|
-
rawXml: {
|
|
3070
|
-
"p:nvSpPr": {
|
|
3071
|
-
"p:cNvPr": { "@_name": frame.type },
|
|
3072
|
-
"p:cNvSpPr": {},
|
|
3073
|
-
"p:nvPr": { "p:ph": ph }
|
|
3074
|
-
},
|
|
3075
|
-
"p:spPr": {}
|
|
3076
|
-
}
|
|
3077
|
-
});
|
|
3078
|
-
}
|
|
3079
|
-
return {
|
|
3080
|
-
pptxData: ctx.pptxData,
|
|
3081
|
-
dirty: true,
|
|
3082
|
-
result: { slideIndex: params.slideIndex, layoutName: layout.name ?? "Unknown" }
|
|
3083
|
-
};
|
|
3084
|
-
}
|
|
3085
|
-
function resolveOleElement(ctx, slideIndex, elementId) {
|
|
3086
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
3087
|
-
if (err) {
|
|
3088
|
-
throw new Error(err);
|
|
3089
|
-
}
|
|
3090
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
3091
|
-
const index = slide.elements.findIndex((e) => e.id === elementId);
|
|
3092
|
-
if (index === -1) {
|
|
3093
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
3094
|
-
}
|
|
3095
|
-
const element = slide.elements[index];
|
|
3096
|
-
if (element.type !== "ole") {
|
|
3097
|
-
throw new Error(`Element '${elementId}' is not an OLE object.`);
|
|
3098
|
-
}
|
|
3099
|
-
return { slide, element, index };
|
|
3100
|
-
}
|
|
3101
|
-
function commitOleElement(slide, index, updated) {
|
|
3102
|
-
slide.elements.splice(index, 1, updated);
|
|
3103
|
-
slide.isDirty = true;
|
|
3104
|
-
}
|
|
3105
|
-
async function getOleContent(ctx, params) {
|
|
3106
|
-
const { element } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3107
|
-
const kind = await pptxViewerCore.resolveOleEditorKindFromPayload(element);
|
|
3108
|
-
const base = { pptxData: ctx.pptxData, dirty: false };
|
|
3109
|
-
switch (kind) {
|
|
3110
|
-
case "sheet-xlsx":
|
|
3111
|
-
case "sheet-xls": {
|
|
3112
|
-
const sheet = await pptxViewerCore.getOleSheetGrid(element);
|
|
3113
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, sheet } };
|
|
3114
|
-
}
|
|
3115
|
-
case "document-docx":
|
|
3116
|
-
case "document-doc": {
|
|
3117
|
-
const paragraphs = await pptxViewerCore.getOleDocumentParagraphs(element);
|
|
3118
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, paragraphs } };
|
|
3119
|
-
}
|
|
3120
|
-
case "deck-pptx": {
|
|
3121
|
-
const deckSlides = await pptxViewerCore.getOleNestedDeckDetail(element);
|
|
3122
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, deckSlides } };
|
|
3123
|
-
}
|
|
3124
|
-
default:
|
|
3125
|
-
return {
|
|
3126
|
-
...base,
|
|
3127
|
-
result: {
|
|
3128
|
-
elementId: element.id,
|
|
3129
|
-
kind,
|
|
3130
|
-
editable: false,
|
|
3131
|
-
message: `This OLE object's content (${kind}) is not directly editable; use ole_replace_file to replace it wholesale.`
|
|
3132
|
-
}
|
|
3133
|
-
};
|
|
3134
|
-
}
|
|
3135
|
-
}
|
|
3136
|
-
async function setOleSheetCell(ctx, params) {
|
|
3137
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3138
|
-
const updated = await pptxViewerCore.applyOleSheetCellEdit(element, {
|
|
3139
|
-
row: params.row,
|
|
3140
|
-
col: params.col,
|
|
3141
|
-
value: params.value
|
|
3142
|
-
});
|
|
3143
|
-
const changed = updated !== element;
|
|
3144
|
-
if (changed) {
|
|
3145
|
-
commitOleElement(slide, index, updated);
|
|
3146
|
-
}
|
|
3147
|
-
return {
|
|
3148
|
-
pptxData: ctx.pptxData,
|
|
3149
|
-
dirty: changed,
|
|
3150
|
-
result: { elementId: params.elementId, changed }
|
|
3151
|
-
};
|
|
3152
|
-
}
|
|
3153
|
-
async function setOleDocumentParagraph(ctx, params) {
|
|
3154
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3155
|
-
const updated = await pptxViewerCore.applyOleDocumentParagraphEdit(element, params.paragraphIndex, params.text);
|
|
3156
|
-
const changed = updated !== element;
|
|
3157
|
-
if (changed) {
|
|
3158
|
-
commitOleElement(slide, index, updated);
|
|
3159
|
-
}
|
|
3160
|
-
return {
|
|
3161
|
-
pptxData: ctx.pptxData,
|
|
3162
|
-
dirty: changed,
|
|
3163
|
-
result: { elementId: params.elementId, changed }
|
|
3164
|
-
};
|
|
3165
|
-
}
|
|
3166
|
-
async function setOleDeckSlideTitle(ctx, params) {
|
|
3167
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3168
|
-
const updated = await pptxViewerCore.applyOleNestedDeckElementTextEdit(
|
|
3169
|
-
element,
|
|
3170
|
-
params.deckSlideIndex,
|
|
3171
|
-
params.deckElementId,
|
|
3172
|
-
params.title
|
|
3173
|
-
);
|
|
3174
|
-
const changed = updated !== element;
|
|
3175
|
-
if (changed) {
|
|
3176
|
-
commitOleElement(slide, index, updated);
|
|
3177
|
-
}
|
|
3178
|
-
return {
|
|
3179
|
-
pptxData: ctx.pptxData,
|
|
3180
|
-
dirty: changed,
|
|
3181
|
-
result: { elementId: params.elementId, changed }
|
|
3182
|
-
};
|
|
3183
|
-
}
|
|
3184
|
-
async function setOleObjectNameT(ctx, params) {
|
|
3185
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3186
|
-
const updated = await pptxViewerCore.setOleObjectName(element, params.name);
|
|
3187
|
-
commitOleElement(slide, index, updated);
|
|
3188
|
-
return {
|
|
3189
|
-
pptxData: ctx.pptxData,
|
|
3190
|
-
dirty: true,
|
|
3191
|
-
result: { elementId: params.elementId, changed: true }
|
|
3192
|
-
};
|
|
3193
|
-
}
|
|
3194
|
-
async function replaceOleFileT(ctx, params) {
|
|
3195
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3196
|
-
const parsed = pptxViewerCore.parseDataUrlToBytes(params.fileData);
|
|
3197
|
-
if (!parsed) {
|
|
3198
|
-
throw new Error('fileData must be a base64 data URL, e.g. "data:<mime-type>;base64,<...>".');
|
|
3199
|
-
}
|
|
3200
|
-
const updated = await pptxViewerCore.replaceOleFile(element, parsed.bytes, params.fileName);
|
|
3201
|
-
commitOleElement(slide, index, updated);
|
|
3202
|
-
return {
|
|
3203
|
-
pptxData: ctx.pptxData,
|
|
3204
|
-
dirty: true,
|
|
3205
|
-
result: { elementId: params.elementId, changed: true }
|
|
3206
|
-
};
|
|
3207
|
-
}
|
|
7
|
+
var loadPresentation = automation.apiExecution.loadPresentation;
|
|
8
|
+
var savePresentation = automation.apiExecution.savePresentation;
|
|
9
|
+
var executeToolWithContext = automation.apiExecution.executeToolWithContext;
|
|
10
|
+
var getSlide = automation.apiToolsSlideTools.getSlide;
|
|
11
|
+
var addSlide = automation.apiToolsSlideTools.addSlide;
|
|
12
|
+
var deleteSlides = automation.apiToolsSlideTools.deleteSlides;
|
|
13
|
+
var reorderSlides = automation.apiToolsSlideTools.reorderSlides;
|
|
14
|
+
var duplicateSlide = automation.apiToolsSlideTools.duplicateSlide;
|
|
15
|
+
var updateSlideProperties = automation.apiToolsSlideTools.updateSlideProperties;
|
|
16
|
+
var setSlideTransition = automation.apiToolsSlideTools.setSlideTransition;
|
|
17
|
+
var setCanvasSize = automation.apiToolsSlideTools.setCanvasSize;
|
|
18
|
+
var generateElementId = automation.apiToolsHelpers.generateElementId;
|
|
19
|
+
var generateSlideId = automation.apiToolsHelpers.generateSlideId;
|
|
20
|
+
var describeElement = automation.apiToolsHelpers.describeElement;
|
|
21
|
+
var extractSlideText = automation.apiToolsHelpers.extractSlideText;
|
|
22
|
+
var validateSlideIndex = automation.apiToolsHelpers.validateSlideIndex;
|
|
23
|
+
var addElement = automation.apiToolsElementTools.addElement;
|
|
24
|
+
var updateElement = automation.apiToolsElementTools.updateElement;
|
|
25
|
+
var renameElement = automation.apiToolsElementTools.renameElement;
|
|
26
|
+
var deleteElements = automation.apiToolsElementTools.deleteElements;
|
|
27
|
+
var arrangeElements = automation.apiToolsElementTools.arrangeElements;
|
|
28
|
+
var cloneElement = automation.apiToolsElementTools.cloneElement;
|
|
29
|
+
var setElementAnimation = automation.apiToolsElementTools.setElementAnimation;
|
|
30
|
+
var groupElements = automation.apiToolsElementTools.groupElements;
|
|
31
|
+
var ungroupElements = automation.apiToolsElementTools.ungroupElements;
|
|
32
|
+
var batchUpdateElements = automation.apiToolsElementTools.batchUpdateElements;
|
|
33
|
+
var updateTableCells = automation.apiToolsTableTools.updateTableCells;
|
|
34
|
+
var manageTableStructure = automation.apiToolsTableTools.manageTableStructure;
|
|
35
|
+
var setTableStyleSection = automation.apiToolsTableStyleTools.setTableStyleSection;
|
|
36
|
+
var createTableStyle = automation.apiToolsTableStyleTools.createTableStyle;
|
|
37
|
+
var deleteTableStyle = automation.apiToolsTableStyleTools.deleteTableStyle;
|
|
38
|
+
var assignTableStyle = automation.apiToolsTableStyleTools.assignTableStyle;
|
|
39
|
+
automation.apiToolsStyleTools.ALT_TEXT_ELEMENT_TYPES;
|
|
40
|
+
automation.apiToolsStyleTools.TITLE_ELEMENT_TYPES;
|
|
41
|
+
automation.apiToolsStyleTools.applyElementAltText;
|
|
42
|
+
automation.apiToolsStyleTools.applyElementTitle;
|
|
43
|
+
var updateElementStyle = automation.apiToolsStyleTools.updateElementStyle;
|
|
44
|
+
var runAccessibilityCheck = automation.apiToolsStyleTools.runAccessibilityCheck;
|
|
45
|
+
var findText = automation.apiToolsContentTools.findText;
|
|
46
|
+
var replaceText = automation.apiToolsContentTools.replaceText;
|
|
47
|
+
var manageComments = automation.apiToolsContentTools.manageComments;
|
|
48
|
+
var convertToMarkdown = automation.apiToolsConversionTools.convertToMarkdown;
|
|
49
|
+
var getThemeInfo = automation.apiToolsThemeTools.getThemeInfo;
|
|
50
|
+
var applyThemePreset = automation.apiToolsThemeTools.applyThemePreset;
|
|
51
|
+
var updateThemeColors = automation.apiToolsThemeTools.updateThemeColors;
|
|
52
|
+
var updateThemeFonts = automation.apiToolsThemeTools.updateThemeFonts;
|
|
53
|
+
var updateChart = automation.apiToolsChartTools.updateChart;
|
|
54
|
+
var addChartSeriesT = automation.apiToolsChartTools.addChartSeriesT;
|
|
55
|
+
var removeChartSeriesT = automation.apiToolsChartTools.removeChartSeriesT;
|
|
56
|
+
var updateChartSeriesData = automation.apiToolsChartTools.updateChartSeriesData;
|
|
57
|
+
var createChart = automation.apiToolsChartTools.createChart;
|
|
58
|
+
var formatChartDataPoint = automation.apiToolsChartFormattingTools.formatChartDataPoint;
|
|
59
|
+
var formatChartDataLabel = automation.apiToolsChartFormattingTools.formatChartDataLabel;
|
|
60
|
+
var formatChartSeries = automation.apiToolsChartFormattingTools.formatChartSeries;
|
|
61
|
+
var setChartHelperLineT = automation.apiToolsChartFormattingTools.setChartHelperLineT;
|
|
62
|
+
var setChartColorMapOverrideT = automation.apiToolsChartFormattingTools.setChartColorMapOverrideT;
|
|
63
|
+
var listChartUserShapesT = automation.apiToolsChartUserShapeTools.listChartUserShapesT;
|
|
64
|
+
var addChartUserShapeT = automation.apiToolsChartUserShapeTools.addChartUserShapeT;
|
|
65
|
+
var updateChartUserShapeT = automation.apiToolsChartUserShapeTools.updateChartUserShapeT;
|
|
66
|
+
var removeChartUserShapeT = automation.apiToolsChartUserShapeTools.removeChartUserShapeT;
|
|
67
|
+
var manageSmartArt = automation.apiToolsSmartartTools.manageSmartArt;
|
|
68
|
+
var mergePresentationT = automation.apiToolsMergeTools.mergePresentationT;
|
|
69
|
+
var diffPresentationsT = automation.apiToolsMergeTools.diffPresentationsT;
|
|
70
|
+
var findPlaceholdersT = automation.apiToolsTemplateTools.findPlaceholdersT;
|
|
71
|
+
var applyTemplateT = automation.apiToolsTemplateTools.applyTemplateT;
|
|
72
|
+
var getMetadata = automation.apiToolsMetadataTools.getMetadata;
|
|
73
|
+
var updateMetadata = automation.apiToolsMetadataTools.updateMetadata;
|
|
74
|
+
var manageSections = automation.apiToolsSectionTools.manageSections;
|
|
75
|
+
var exportToSvg = automation.apiToolsExportTools.exportToSvg;
|
|
76
|
+
var exportSlideSvg = automation.apiToolsExportTools.exportSlideSvg;
|
|
77
|
+
var exportToJson = automation.apiToolsJsonTools.exportToJson;
|
|
78
|
+
var importFromJson = automation.apiToolsJsonTools.importFromJson;
|
|
79
|
+
var manageHyperlinks = automation.apiToolsHyperlinkTools.manageHyperlinks;
|
|
80
|
+
var replaceGeometry = automation.apiToolsGeometryTools.replaceGeometry;
|
|
81
|
+
var setElementLockT = automation.apiToolsLockTools.setElementLockT;
|
|
82
|
+
var validatePresentation = automation.apiToolsValidationTools.validatePresentation;
|
|
83
|
+
var repairPresentation = automation.apiToolsValidationTools.repairPresentation;
|
|
84
|
+
var getPresentationProperties = automation.apiToolsPresentationTools.getPresentationProperties;
|
|
85
|
+
var updatePresentationProperties = automation.apiToolsPresentationTools.updatePresentationProperties;
|
|
86
|
+
var getLayouts = automation.apiToolsLayoutTools.getLayouts;
|
|
87
|
+
var applyLayout = automation.apiToolsLayoutTools.applyLayout;
|
|
88
|
+
var getOleContent = automation.apiToolsOleTools.getOleContent;
|
|
89
|
+
var setOleSheetCell = automation.apiToolsOleTools.setOleSheetCell;
|
|
90
|
+
var setOleDocumentParagraph = automation.apiToolsOleTools.setOleDocumentParagraph;
|
|
91
|
+
var setOleDeckSlideTitle = automation.apiToolsOleTools.setOleDeckSlideTitle;
|
|
92
|
+
var setOleObjectNameT = automation.apiToolsOleTools.setOleObjectNameT;
|
|
93
|
+
var replaceOleFileT = automation.apiToolsOleTools.replaceOleFileT;
|
|
3208
94
|
|
|
3209
95
|
Object.defineProperty(exports, "PptxHandler", {
|
|
3210
96
|
enumerable: true,
|
|
3211
|
-
get: function () { return
|
|
97
|
+
get: function () { return pptx.PptxHandler; }
|
|
3212
98
|
});
|
|
3213
99
|
exports.addChartSeriesT = addChartSeriesT;
|
|
3214
100
|
exports.addChartUserShapeT = addChartUserShapeT;
|