pptx-viewer-mcp 1.1.26 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codec/index.d.mts +5 -0
- package/dist/codec/index.d.ts +5 -0
- package/dist/index.d.mts +378 -2
- package/dist/index.d.ts +378 -2
- package/dist/index.js +968 -0
- package/dist/index.mjs +942 -2
- package/dist/mcp/index.js +1621 -106
- package/dist/mcp/index.mjs +1622 -107
- package/dist/schemas/index.d.mts +280 -1
- package/dist/schemas/index.d.ts +280 -1
- package/dist/schemas/index.js +261 -0
- package/dist/schemas/index.mjs +236 -1
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -262,6 +262,241 @@ var ManageCommentsSchema = zod.z.object({
|
|
|
262
262
|
resolved: zod.z.boolean().optional(),
|
|
263
263
|
includeResolved: zod.z.boolean().optional()
|
|
264
264
|
});
|
|
265
|
+
var GetThemeInfoSchema = zod.z.object({
|
|
266
|
+
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
267
|
+
});
|
|
268
|
+
var ApplyThemePresetSchema = zod.z.object({
|
|
269
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
270
|
+
presetName: zod.z.string().describe(
|
|
271
|
+
'Theme preset name (e.g. "OFFICE", "MODERN_BLUE", "EARTH", "MONOCHROME", "VIBRANT", "CORPORATE", "MINIMAL", "DARK")'
|
|
272
|
+
)
|
|
273
|
+
});
|
|
274
|
+
var UpdateThemeColorsSchema = zod.z.object({
|
|
275
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
276
|
+
dk1: zod.z.string().optional().describe("Dark 1 color (hex)"),
|
|
277
|
+
lt1: zod.z.string().optional().describe("Light 1 color (hex)"),
|
|
278
|
+
dk2: zod.z.string().optional().describe("Dark 2 color (hex)"),
|
|
279
|
+
lt2: zod.z.string().optional().describe("Light 2 color (hex)"),
|
|
280
|
+
accent1: zod.z.string().optional().describe("Accent 1 color (hex)"),
|
|
281
|
+
accent2: zod.z.string().optional().describe("Accent 2 color (hex)"),
|
|
282
|
+
accent3: zod.z.string().optional().describe("Accent 3 color (hex)"),
|
|
283
|
+
accent4: zod.z.string().optional().describe("Accent 4 color (hex)"),
|
|
284
|
+
accent5: zod.z.string().optional().describe("Accent 5 color (hex)"),
|
|
285
|
+
accent6: zod.z.string().optional().describe("Accent 6 color (hex)"),
|
|
286
|
+
hlink: zod.z.string().optional().describe("Hyperlink color (hex)"),
|
|
287
|
+
folHlink: zod.z.string().optional().describe("Followed hyperlink color (hex)")
|
|
288
|
+
});
|
|
289
|
+
var UpdateThemeFontsSchema = zod.z.object({
|
|
290
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
291
|
+
majorFont: zod.z.string().optional().describe("Heading (major) font family"),
|
|
292
|
+
minorFont: zod.z.string().optional().describe("Body (minor) font family")
|
|
293
|
+
});
|
|
294
|
+
var UpdateChartSchema = zod.z.object({
|
|
295
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
296
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
297
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
298
|
+
chartType: zod.z.string().optional().describe("New chart type (bar, line, pie, scatter, area, doughnut, radar)"),
|
|
299
|
+
title: zod.z.string().optional().describe("Chart title"),
|
|
300
|
+
grouping: zod.z.enum(["clustered", "stacked", "percentStacked"]).optional().describe("Bar/column grouping"),
|
|
301
|
+
legend: zod.z.object({
|
|
302
|
+
show: zod.z.boolean().optional(),
|
|
303
|
+
position: zod.z.string().optional().describe("Legend position: b, t, l, r, tr")
|
|
304
|
+
}).optional().describe("Legend configuration"),
|
|
305
|
+
dataLabels: zod.z.object({
|
|
306
|
+
show: zod.z.boolean().optional(),
|
|
307
|
+
showValue: zod.z.boolean().optional(),
|
|
308
|
+
showCategory: zod.z.boolean().optional(),
|
|
309
|
+
showSeriesName: zod.z.boolean().optional(),
|
|
310
|
+
showPercent: zod.z.boolean().optional()
|
|
311
|
+
}).optional().describe("Data label configuration"),
|
|
312
|
+
axis: zod.z.object({
|
|
313
|
+
type: zod.z.string().describe("Axis type: valAx, catAx, dateAx, serAx"),
|
|
314
|
+
edit: zod.z.object({
|
|
315
|
+
min: zod.z.number().nullable().optional(),
|
|
316
|
+
max: zod.z.number().nullable().optional(),
|
|
317
|
+
majorUnit: zod.z.number().nullable().optional(),
|
|
318
|
+
title: zod.z.string().nullable().optional(),
|
|
319
|
+
numberFormat: zod.z.string().optional(),
|
|
320
|
+
majorGridlines: zod.z.boolean().optional(),
|
|
321
|
+
minorGridlines: zod.z.boolean().optional()
|
|
322
|
+
})
|
|
323
|
+
}).optional().describe("Axis configuration"),
|
|
324
|
+
categories: zod.z.array(zod.z.string()).optional().describe("Category axis labels")
|
|
325
|
+
});
|
|
326
|
+
var AddChartSeriesSchema = zod.z.object({
|
|
327
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
328
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
329
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
330
|
+
name: zod.z.string().describe("Series name"),
|
|
331
|
+
values: zod.z.array(zod.z.number()).describe("Data values"),
|
|
332
|
+
color: zod.z.string().optional().describe("Series color (hex)")
|
|
333
|
+
});
|
|
334
|
+
var RemoveChartSeriesSchema = zod.z.object({
|
|
335
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
336
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
337
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
338
|
+
seriesIndex: zod.z.number().int().min(0).describe("Zero-based series index to remove")
|
|
339
|
+
});
|
|
340
|
+
var UpdateChartSeriesDataSchema = zod.z.object({
|
|
341
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
342
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
343
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
344
|
+
seriesIndex: zod.z.number().int().min(0).describe("Zero-based series index"),
|
|
345
|
+
values: zod.z.array(zod.z.number()).describe("New data values")
|
|
346
|
+
});
|
|
347
|
+
var CreateChartSchema = zod.z.object({
|
|
348
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
349
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
350
|
+
chartType: zod.z.string().describe("Chart type (bar, line, pie, scatter, area, doughnut, radar)"),
|
|
351
|
+
x: zod.z.number().optional().describe("X position in points"),
|
|
352
|
+
y: zod.z.number().optional().describe("Y position in points"),
|
|
353
|
+
width: zod.z.number().optional().describe("Width in points"),
|
|
354
|
+
height: zod.z.number().optional().describe("Height in points"),
|
|
355
|
+
title: zod.z.string().optional().describe("Chart title"),
|
|
356
|
+
categories: zod.z.array(zod.z.string()).optional().describe("Category labels"),
|
|
357
|
+
series: zod.z.array(
|
|
358
|
+
zod.z.object({
|
|
359
|
+
name: zod.z.string(),
|
|
360
|
+
values: zod.z.array(zod.z.number()),
|
|
361
|
+
color: zod.z.string().optional()
|
|
362
|
+
})
|
|
363
|
+
).optional().describe("Data series"),
|
|
364
|
+
legend: zod.z.object({
|
|
365
|
+
show: zod.z.boolean(),
|
|
366
|
+
position: zod.z.string().optional()
|
|
367
|
+
}).optional().describe("Legend configuration")
|
|
368
|
+
});
|
|
369
|
+
var ManageSmartArtSchema = zod.z.object({
|
|
370
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
371
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
372
|
+
elementId: zod.z.string().describe("SmartArt element ID"),
|
|
373
|
+
action: zod.z.enum([
|
|
374
|
+
"getNodes",
|
|
375
|
+
"addNode",
|
|
376
|
+
"removeNode",
|
|
377
|
+
"updateNodeText",
|
|
378
|
+
"reorderNode",
|
|
379
|
+
"promoteNode",
|
|
380
|
+
"demoteNode",
|
|
381
|
+
"decompose"
|
|
382
|
+
]).describe("SmartArt action"),
|
|
383
|
+
nodeId: zod.z.string().optional().describe("Node ID (required for most actions)"),
|
|
384
|
+
text: zod.z.string().optional().describe("Text for addNode or updateNodeText"),
|
|
385
|
+
afterNodeId: zod.z.string().optional().describe("Insert after this node ID"),
|
|
386
|
+
direction: zod.z.number().optional().describe("Reorder direction: 1 (forward) or -1 (backward)")
|
|
387
|
+
});
|
|
388
|
+
var FindPlaceholdersSchema = zod.z.object({
|
|
389
|
+
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
390
|
+
});
|
|
391
|
+
var ApplyTemplateSchema = zod.z.object({
|
|
392
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
393
|
+
data: zod.z.record(zod.z.string(), zod.z.unknown()).describe("Template data: keys are placeholder names, values are replacement values")
|
|
394
|
+
});
|
|
395
|
+
var GetMetadataSchema = zod.z.object({
|
|
396
|
+
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
397
|
+
});
|
|
398
|
+
var UpdateMetadataSchema = zod.z.object({
|
|
399
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
400
|
+
title: zod.z.string().optional().describe("Presentation title"),
|
|
401
|
+
subject: zod.z.string().optional().describe("Subject"),
|
|
402
|
+
creator: zod.z.string().optional().describe("Creator/author name"),
|
|
403
|
+
keywords: zod.z.string().optional().describe("Keywords (comma-separated)"),
|
|
404
|
+
description: zod.z.string().optional().describe("Description/comments"),
|
|
405
|
+
lastModifiedBy: zod.z.string().optional().describe("Last modified by"),
|
|
406
|
+
category: zod.z.string().optional().describe("Category"),
|
|
407
|
+
company: zod.z.string().optional().describe("Company name"),
|
|
408
|
+
manager: zod.z.string().optional().describe("Manager name"),
|
|
409
|
+
customProperties: zod.z.array(
|
|
410
|
+
zod.z.object({
|
|
411
|
+
name: zod.z.string(),
|
|
412
|
+
value: zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean()])
|
|
413
|
+
})
|
|
414
|
+
).optional().describe("Custom properties to set")
|
|
415
|
+
});
|
|
416
|
+
var ManageSectionsSchema = zod.z.object({
|
|
417
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
418
|
+
action: zod.z.enum(["list", "add", "remove", "reorder", "moveSlides", "getForSlide"]).describe("Section action"),
|
|
419
|
+
name: zod.z.string().optional().describe("Section name (for add)"),
|
|
420
|
+
slideIndices: zod.z.array(zod.z.number().int().min(0)).optional().describe("Slide indices (for add, moveSlides)"),
|
|
421
|
+
sectionId: zod.z.string().optional().describe("Section ID (for remove, moveSlides)"),
|
|
422
|
+
sectionIds: zod.z.array(zod.z.string()).optional().describe("Ordered section IDs (for reorder)"),
|
|
423
|
+
slideIndex: zod.z.number().int().min(0).optional().describe("Slide index (for getForSlide)")
|
|
424
|
+
});
|
|
425
|
+
var ExportToSvgSchema = zod.z.object({
|
|
426
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
427
|
+
slideIndices: zod.z.array(zod.z.number().int().min(0)).optional().describe("Specific slides to export (all if omitted)"),
|
|
428
|
+
includeHidden: zod.z.boolean().optional().describe("Include hidden slides"),
|
|
429
|
+
defaultFontFamily: zod.z.string().optional().describe("Default font family for SVG"),
|
|
430
|
+
defaultFontSize: zod.z.number().optional().describe("Default font size")
|
|
431
|
+
});
|
|
432
|
+
var ExportSlideSvgSchema = zod.z.object({
|
|
433
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
434
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index to export"),
|
|
435
|
+
defaultFontFamily: zod.z.string().optional().describe("Default font family for SVG"),
|
|
436
|
+
defaultFontSize: zod.z.number().optional().describe("Default font size")
|
|
437
|
+
});
|
|
438
|
+
var ManageHyperlinksSchema = zod.z.object({
|
|
439
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
440
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
441
|
+
action: zod.z.enum(["list", "set", "remove"]).describe("Hyperlink action"),
|
|
442
|
+
elementId: zod.z.string().optional().describe("Element ID (for set/remove)"),
|
|
443
|
+
trigger: zod.z.enum(["click", "hover"]).optional().describe("Action trigger (default: click)"),
|
|
444
|
+
url: zod.z.string().optional().describe("URL for the hyperlink"),
|
|
445
|
+
tooltip: zod.z.string().optional().describe("Tooltip text"),
|
|
446
|
+
targetSlideIndex: zod.z.number().int().min(0).optional().describe("Target slide index for internal links"),
|
|
447
|
+
actionType: zod.z.enum(["url", "slide", "nextSlide", "prevSlide", "firstSlide", "lastSlide", "endShow"]).optional().describe("Link action type")
|
|
448
|
+
});
|
|
449
|
+
var ReplaceGeometrySchema = zod.z.object({
|
|
450
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
451
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
452
|
+
elementId: zod.z.string().describe("Shape element ID"),
|
|
453
|
+
shapeType: zod.z.string().optional().describe('Preset shape type (e.g. "roundRect", "star5", "ellipse", "diamond")'),
|
|
454
|
+
svgPath: zod.z.string().optional().describe("Custom SVG path data (mutually exclusive with shapeType)"),
|
|
455
|
+
pathWidth: zod.z.number().optional().describe("Width of SVG path coordinate space"),
|
|
456
|
+
pathHeight: zod.z.number().optional().describe("Height of SVG path coordinate space"),
|
|
457
|
+
adjustments: zod.z.record(zod.z.string(), zod.z.number()).optional().describe("Shape adjustment values")
|
|
458
|
+
});
|
|
459
|
+
var SetElementLockSchema = zod.z.object({
|
|
460
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
461
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
462
|
+
elementId: zod.z.string().describe("Element ID to lock/unlock"),
|
|
463
|
+
locked: zod.z.boolean().describe("Whether the element should be locked"),
|
|
464
|
+
noMove: zod.z.boolean().optional().describe("Prevent moving"),
|
|
465
|
+
noResize: zod.z.boolean().optional().describe("Prevent resizing"),
|
|
466
|
+
noRotation: zod.z.boolean().optional().describe("Prevent rotation"),
|
|
467
|
+
noSelect: zod.z.boolean().optional().describe("Prevent selection"),
|
|
468
|
+
noTextEdit: zod.z.boolean().optional().describe("Prevent text editing")
|
|
469
|
+
});
|
|
470
|
+
var ValidatePresentationSchema = zod.z.object({
|
|
471
|
+
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
472
|
+
});
|
|
473
|
+
var RepairPresentationSchema = zod.z.object({
|
|
474
|
+
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
475
|
+
});
|
|
476
|
+
var GetPresentationPropertiesSchema = zod.z.object({
|
|
477
|
+
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
478
|
+
});
|
|
479
|
+
var UpdatePresentationPropertiesSchema = zod.z.object({
|
|
480
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
481
|
+
showType: zod.z.enum(["presented", "browsed", "kiosk"]).optional().describe("Slideshow mode"),
|
|
482
|
+
loopContinuously: zod.z.boolean().optional().describe("Loop the slideshow"),
|
|
483
|
+
showWithNarration: zod.z.boolean().optional().describe("Play narration"),
|
|
484
|
+
showWithAnimation: zod.z.boolean().optional().describe("Play animations"),
|
|
485
|
+
advanceMode: zod.z.enum(["manual", "useTimings"]).optional().describe("Slide advance mode"),
|
|
486
|
+
showSlidesMode: zod.z.enum(["all", "customShow", "range"]).optional().describe("Which slides to show"),
|
|
487
|
+
showSlidesFrom: zod.z.number().int().min(1).optional().describe("Range start (1-based)"),
|
|
488
|
+
showSlidesTo: zod.z.number().int().min(1).optional().describe("Range end (1-based)"),
|
|
489
|
+
penColor: zod.z.string().optional().describe("Annotation pen color (hex)")
|
|
490
|
+
});
|
|
491
|
+
var GetLayoutsSchema = zod.z.object({
|
|
492
|
+
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
493
|
+
});
|
|
494
|
+
var ApplyLayoutSchema = zod.z.object({
|
|
495
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
496
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
497
|
+
layoutName: zod.z.string().optional().describe("Layout name to apply"),
|
|
498
|
+
layoutType: zod.z.string().optional().describe("Layout type to apply (alternative to name)")
|
|
499
|
+
});
|
|
265
500
|
function generateElementId() {
|
|
266
501
|
return `el-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
267
502
|
}
|
|
@@ -369,7 +604,144 @@ function validateSlideIndex(slideIndex, slideCount) {
|
|
|
369
604
|
return null;
|
|
370
605
|
}
|
|
371
606
|
|
|
372
|
-
// src/tools/
|
|
607
|
+
// src/tools/chart-tools.ts
|
|
608
|
+
function updateChart(ctx, params) {
|
|
609
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
610
|
+
if (err) {
|
|
611
|
+
throw new Error(err);
|
|
612
|
+
}
|
|
613
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
614
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
615
|
+
if (!el) {
|
|
616
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
617
|
+
}
|
|
618
|
+
if (el.type !== "chart") {
|
|
619
|
+
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
620
|
+
}
|
|
621
|
+
const chart = el;
|
|
622
|
+
if (params.chartType) {
|
|
623
|
+
pptxViewerCore.setChartType(chart, params.chartType);
|
|
624
|
+
}
|
|
625
|
+
if (params.title !== void 0) {
|
|
626
|
+
pptxViewerCore.setChartTitle(chart, params.title);
|
|
627
|
+
}
|
|
628
|
+
if (params.grouping) {
|
|
629
|
+
pptxViewerCore.setChartGrouping(chart, params.grouping);
|
|
630
|
+
}
|
|
631
|
+
if (params.legend) {
|
|
632
|
+
pptxViewerCore.setChartLegend(chart, {
|
|
633
|
+
show: params.legend.show,
|
|
634
|
+
position: params.legend.position
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
if (params.dataLabels) {
|
|
638
|
+
pptxViewerCore.setChartDataLabels(chart, params.dataLabels);
|
|
639
|
+
}
|
|
640
|
+
if (params.axis) {
|
|
641
|
+
pptxViewerCore.setChartAxis(chart, params.axis.type, params.axis.edit);
|
|
642
|
+
}
|
|
643
|
+
if (params.categories) {
|
|
644
|
+
pptxViewerCore.setChartCategories(chart, params.categories);
|
|
645
|
+
}
|
|
646
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
647
|
+
}
|
|
648
|
+
function addChartSeriesT(ctx, params) {
|
|
649
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
650
|
+
if (err) {
|
|
651
|
+
throw new Error(err);
|
|
652
|
+
}
|
|
653
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
654
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
655
|
+
if (!el) {
|
|
656
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
657
|
+
}
|
|
658
|
+
if (el.type !== "chart") {
|
|
659
|
+
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
660
|
+
}
|
|
661
|
+
const chart = el;
|
|
662
|
+
pptxViewerCore.addChartSeries(chart, { name: params.name, values: params.values, color: params.color });
|
|
663
|
+
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
664
|
+
return {
|
|
665
|
+
pptxData: ctx.pptxData,
|
|
666
|
+
dirty: true,
|
|
667
|
+
result: { elementId: params.elementId, seriesCount }
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function removeChartSeriesT(ctx, params) {
|
|
671
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
672
|
+
if (err) {
|
|
673
|
+
throw new Error(err);
|
|
674
|
+
}
|
|
675
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
676
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
677
|
+
if (!el) {
|
|
678
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
679
|
+
}
|
|
680
|
+
if (el.type !== "chart") {
|
|
681
|
+
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
682
|
+
}
|
|
683
|
+
const chart = el;
|
|
684
|
+
pptxViewerCore.removeChartSeries(chart, params.seriesIndex);
|
|
685
|
+
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
686
|
+
return {
|
|
687
|
+
pptxData: ctx.pptxData,
|
|
688
|
+
dirty: true,
|
|
689
|
+
result: { elementId: params.elementId, seriesCount }
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function updateChartSeriesData(ctx, params) {
|
|
693
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
694
|
+
if (err) {
|
|
695
|
+
throw new Error(err);
|
|
696
|
+
}
|
|
697
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
698
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
699
|
+
if (!el) {
|
|
700
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
701
|
+
}
|
|
702
|
+
if (el.type !== "chart") {
|
|
703
|
+
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
704
|
+
}
|
|
705
|
+
const chart = el;
|
|
706
|
+
pptxViewerCore.updateChartSeriesValues(chart, params.seriesIndex, params.values);
|
|
707
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
708
|
+
}
|
|
709
|
+
function createChart(ctx, params) {
|
|
710
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
711
|
+
if (err) {
|
|
712
|
+
throw new Error(err);
|
|
713
|
+
}
|
|
714
|
+
const builder = pptxViewerCore.ChartBuilder.create(
|
|
715
|
+
params.chartType
|
|
716
|
+
);
|
|
717
|
+
builder.position(params.x ?? 100, params.y ?? 100);
|
|
718
|
+
builder.size(params.width ?? 500, params.height ?? 350);
|
|
719
|
+
if (params.title) {
|
|
720
|
+
builder.title(params.title);
|
|
721
|
+
}
|
|
722
|
+
if (params.categories) {
|
|
723
|
+
builder.categories(params.categories);
|
|
724
|
+
}
|
|
725
|
+
if (params.series) {
|
|
726
|
+
for (const s of params.series) {
|
|
727
|
+
builder.addSeries(s.name, s.values, s.color);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (params.legend) {
|
|
731
|
+
builder.legend(
|
|
732
|
+
params.legend.show,
|
|
733
|
+
params.legend.position
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
const chart = builder.build();
|
|
737
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
738
|
+
slide.elements.push(chart);
|
|
739
|
+
return {
|
|
740
|
+
pptxData: ctx.pptxData,
|
|
741
|
+
dirty: true,
|
|
742
|
+
result: { elementId: chart.id, slideIndex: params.slideIndex }
|
|
743
|
+
};
|
|
744
|
+
}
|
|
373
745
|
var MAX_REGEX_LEN = 200;
|
|
374
746
|
function hasNestedUnboundedQuantifier(pattern) {
|
|
375
747
|
return /\([^)]*[+*]\)[+*]/u.test(pattern);
|
|
@@ -1257,129 +1629,621 @@ function batchUpdateElements(ctx, params) {
|
|
|
1257
1629
|
result: { updatedCount: count }
|
|
1258
1630
|
};
|
|
1259
1631
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1268
|
-
return {
|
|
1269
|
-
pptxData: ctx.pptxData,
|
|
1270
|
-
dirty: false,
|
|
1271
|
-
result: {
|
|
1272
|
-
slideIndex: params.slideIndex,
|
|
1273
|
-
slideNumber: slide.slideNumber,
|
|
1274
|
-
hidden: slide.hidden ?? false,
|
|
1275
|
-
layoutName: slide.layoutName,
|
|
1276
|
-
backgroundColor: slide.backgroundColor,
|
|
1277
|
-
notes: slide.notes ?? "",
|
|
1278
|
-
commentCount: slide.comments?.length ?? 0,
|
|
1279
|
-
elements: slide.elements.map(describeElement)
|
|
1632
|
+
function exportToSvg(ctx, params) {
|
|
1633
|
+
if (params.slideIndices) {
|
|
1634
|
+
for (const si of params.slideIndices) {
|
|
1635
|
+
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
1636
|
+
if (err) {
|
|
1637
|
+
throw new Error(err);
|
|
1638
|
+
}
|
|
1280
1639
|
}
|
|
1281
|
-
};
|
|
1282
|
-
}
|
|
1283
|
-
function addSlide(ctx, params) {
|
|
1284
|
-
const { slides } = ctx.pptxData;
|
|
1285
|
-
const insertAt = params.insertAfterIndex !== void 0 && params.insertAfterIndex >= 0 ? Math.min(params.insertAfterIndex + 1, slides.length) : slides.length;
|
|
1286
|
-
const newSlide = {
|
|
1287
|
-
id: generateSlideId(),
|
|
1288
|
-
rId: "",
|
|
1289
|
-
slideNumber: insertAt + 1,
|
|
1290
|
-
elements: [],
|
|
1291
|
-
backgroundColor: params.backgroundColor
|
|
1292
|
-
};
|
|
1293
|
-
slides.splice(insertAt, 0, newSlide);
|
|
1294
|
-
slides.forEach((s, i) => {
|
|
1295
|
-
s.slideNumber = i + 1;
|
|
1296
|
-
});
|
|
1297
|
-
return {
|
|
1298
|
-
pptxData: ctx.pptxData,
|
|
1299
|
-
dirty: true,
|
|
1300
|
-
result: { newSlideIndex: insertAt, slideCount: slides.length }
|
|
1301
|
-
};
|
|
1302
|
-
}
|
|
1303
|
-
function deleteSlides(ctx, params) {
|
|
1304
|
-
const { slides } = ctx.pptxData;
|
|
1305
|
-
if (!params.slideIndexes || params.slideIndexes.length === 0) {
|
|
1306
|
-
throw new Error("slideIndexes is required for the delete action.");
|
|
1307
1640
|
}
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
throw new Error(
|
|
1312
|
-
`Invalid slide indexes: ${invalid.join(", ")}. Valid range: 0\u2013${slides.length - 1}.`
|
|
1313
|
-
);
|
|
1641
|
+
const options = {};
|
|
1642
|
+
if (params.slideIndices) {
|
|
1643
|
+
options.slideIndices = params.slideIndices;
|
|
1314
1644
|
}
|
|
1315
|
-
if (
|
|
1316
|
-
|
|
1645
|
+
if (params.includeHidden !== void 0) {
|
|
1646
|
+
options.includeHidden = params.includeHidden;
|
|
1317
1647
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
s.slideNumber = i + 1;
|
|
1321
|
-
});
|
|
1322
|
-
return {
|
|
1323
|
-
pptxData: ctx.pptxData,
|
|
1324
|
-
dirty: true,
|
|
1325
|
-
result: { deletedCount: indexSet.size, slideCount: ctx.pptxData.slides.length }
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
function reorderSlides(ctx, params) {
|
|
1329
|
-
const { slides } = ctx.pptxData;
|
|
1330
|
-
if (!params.newOrder || params.newOrder.length !== slides.length) {
|
|
1331
|
-
throw new Error(
|
|
1332
|
-
`newOrder must have exactly ${slides.length} indexes. Got ${params.newOrder?.length ?? 0}.`
|
|
1333
|
-
);
|
|
1648
|
+
if (params.defaultFontFamily) {
|
|
1649
|
+
options.defaultFontFamily = params.defaultFontFamily;
|
|
1334
1650
|
}
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
if (JSON.stringify(sorted) !== JSON.stringify(expected)) {
|
|
1338
|
-
throw new Error(
|
|
1339
|
-
`newOrder must contain each index from 0 to ${slides.length - 1} exactly once.`
|
|
1340
|
-
);
|
|
1651
|
+
if (params.defaultFontSize) {
|
|
1652
|
+
options.defaultFontSize = params.defaultFontSize;
|
|
1341
1653
|
}
|
|
1342
|
-
|
|
1343
|
-
ctx.pptxData.slides.forEach((s, i) => {
|
|
1344
|
-
s.slideNumber = i + 1;
|
|
1345
|
-
});
|
|
1654
|
+
const svgStrings = pptxViewerCore.SvgExporter.exportAll(ctx.pptxData, options);
|
|
1346
1655
|
return {
|
|
1347
1656
|
pptxData: ctx.pptxData,
|
|
1348
|
-
dirty:
|
|
1349
|
-
result: { slideCount:
|
|
1657
|
+
dirty: false,
|
|
1658
|
+
result: { svgStrings, slideCount: svgStrings.length }
|
|
1350
1659
|
};
|
|
1351
1660
|
}
|
|
1352
|
-
function
|
|
1353
|
-
const
|
|
1354
|
-
const err = validateSlideIndex(params.slideIndex, slides.length);
|
|
1661
|
+
function exportSlideSvg(ctx, params) {
|
|
1662
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1355
1663
|
if (err) {
|
|
1356
1664
|
throw new Error(err);
|
|
1357
1665
|
}
|
|
1358
|
-
const
|
|
1359
|
-
const
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1666
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1667
|
+
const width = ctx.pptxData.width ?? 960;
|
|
1668
|
+
const height = ctx.pptxData.height ?? 540;
|
|
1669
|
+
const options = {};
|
|
1670
|
+
if (params.defaultFontFamily) {
|
|
1671
|
+
options.defaultFontFamily = params.defaultFontFamily;
|
|
1364
1672
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
});
|
|
1673
|
+
if (params.defaultFontSize) {
|
|
1674
|
+
options.defaultFontSize = params.defaultFontSize;
|
|
1675
|
+
}
|
|
1676
|
+
const svg = pptxViewerCore.SvgExporter.exportSlide(slide, width, height, options);
|
|
1370
1677
|
return {
|
|
1371
1678
|
pptxData: ctx.pptxData,
|
|
1372
|
-
dirty:
|
|
1373
|
-
result: {
|
|
1679
|
+
dirty: false,
|
|
1680
|
+
result: { svg, slideIndex: params.slideIndex }
|
|
1374
1681
|
};
|
|
1375
1682
|
}
|
|
1376
|
-
function
|
|
1683
|
+
function replaceGeometry(ctx, params) {
|
|
1377
1684
|
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1378
1685
|
if (err) {
|
|
1379
1686
|
throw new Error(err);
|
|
1380
1687
|
}
|
|
1381
1688
|
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1382
|
-
|
|
1689
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1690
|
+
if (!el) {
|
|
1691
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1692
|
+
}
|
|
1693
|
+
if (el.type !== "shape") {
|
|
1694
|
+
throw new Error(`Element '${params.elementId}' is not a shape.`);
|
|
1695
|
+
}
|
|
1696
|
+
const shape = el;
|
|
1697
|
+
if (params.svgPath) {
|
|
1698
|
+
pptxViewerCore.replaceWithCustomGeometry(shape, params.svgPath, params.pathWidth, params.pathHeight);
|
|
1699
|
+
return {
|
|
1700
|
+
pptxData: ctx.pptxData,
|
|
1701
|
+
dirty: true,
|
|
1702
|
+
result: { elementId: params.elementId, geometryType: "custom" }
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
if (params.shapeType) {
|
|
1706
|
+
pptxViewerCore.replaceShapeGeometry(shape, params.shapeType, params.adjustments);
|
|
1707
|
+
return {
|
|
1708
|
+
pptxData: ctx.pptxData,
|
|
1709
|
+
dirty: true,
|
|
1710
|
+
result: { elementId: params.elementId, geometryType: params.shapeType }
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
throw new Error("Either shapeType or svgPath must be provided.");
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
// src/tools/hyperlink-tools.ts
|
|
1717
|
+
function manageHyperlinks(ctx, params) {
|
|
1718
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1719
|
+
if (err) {
|
|
1720
|
+
throw new Error(err);
|
|
1721
|
+
}
|
|
1722
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1723
|
+
switch (params.action) {
|
|
1724
|
+
case "list": {
|
|
1725
|
+
const hyperlinks = [];
|
|
1726
|
+
for (const el of slide.elements) {
|
|
1727
|
+
if (el.actionClick) {
|
|
1728
|
+
hyperlinks.push({
|
|
1729
|
+
elementId: el.id,
|
|
1730
|
+
trigger: "click",
|
|
1731
|
+
url: el.actionClick.url,
|
|
1732
|
+
tooltip: el.actionClick.tooltip,
|
|
1733
|
+
targetSlideIndex: el.actionClick.targetSlideIndex,
|
|
1734
|
+
actionType: el.actionClick.action
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
if (el.actionHover) {
|
|
1738
|
+
hyperlinks.push({
|
|
1739
|
+
elementId: el.id,
|
|
1740
|
+
trigger: "hover",
|
|
1741
|
+
url: el.actionHover.url,
|
|
1742
|
+
tooltip: el.actionHover.tooltip,
|
|
1743
|
+
targetSlideIndex: el.actionHover.targetSlideIndex,
|
|
1744
|
+
actionType: el.actionHover.action
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", hyperlinks } };
|
|
1749
|
+
}
|
|
1750
|
+
case "set": {
|
|
1751
|
+
if (!params.elementId) {
|
|
1752
|
+
throw new Error("elementId is required for set action.");
|
|
1753
|
+
}
|
|
1754
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1755
|
+
if (!el) {
|
|
1756
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1757
|
+
}
|
|
1758
|
+
const trigger = params.trigger ?? "click";
|
|
1759
|
+
const action = {};
|
|
1760
|
+
if (params.url) {
|
|
1761
|
+
action.url = params.url;
|
|
1762
|
+
}
|
|
1763
|
+
if (params.tooltip) {
|
|
1764
|
+
action.tooltip = params.tooltip;
|
|
1765
|
+
}
|
|
1766
|
+
if (params.targetSlideIndex !== void 0) {
|
|
1767
|
+
action.targetSlideIndex = params.targetSlideIndex;
|
|
1768
|
+
}
|
|
1769
|
+
if (params.actionType) {
|
|
1770
|
+
switch (params.actionType) {
|
|
1771
|
+
case "url":
|
|
1772
|
+
action.action = "ppaction://hlinkpres";
|
|
1773
|
+
break;
|
|
1774
|
+
case "slide":
|
|
1775
|
+
action.action = "ppaction://hlinksldjump";
|
|
1776
|
+
break;
|
|
1777
|
+
case "nextSlide":
|
|
1778
|
+
action.action = "ppaction://hlinkshowjump?jump=nextslide";
|
|
1779
|
+
break;
|
|
1780
|
+
case "prevSlide":
|
|
1781
|
+
action.action = "ppaction://hlinkshowjump?jump=previousslide";
|
|
1782
|
+
break;
|
|
1783
|
+
case "firstSlide":
|
|
1784
|
+
action.action = "ppaction://hlinkshowjump?jump=firstslide";
|
|
1785
|
+
break;
|
|
1786
|
+
case "lastSlide":
|
|
1787
|
+
action.action = "ppaction://hlinkshowjump?jump=lastslide";
|
|
1788
|
+
break;
|
|
1789
|
+
case "endShow":
|
|
1790
|
+
action.action = "ppaction://hlinkshowjump?jump=endshow";
|
|
1791
|
+
break;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
if (trigger === "click") {
|
|
1795
|
+
el.actionClick = action;
|
|
1796
|
+
} else {
|
|
1797
|
+
el.actionHover = action;
|
|
1798
|
+
}
|
|
1799
|
+
return {
|
|
1800
|
+
pptxData: ctx.pptxData,
|
|
1801
|
+
dirty: true,
|
|
1802
|
+
result: { action: "set", elementId: params.elementId }
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
case "remove": {
|
|
1806
|
+
if (!params.elementId) {
|
|
1807
|
+
throw new Error("elementId is required for remove action.");
|
|
1808
|
+
}
|
|
1809
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1810
|
+
if (!el) {
|
|
1811
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1812
|
+
}
|
|
1813
|
+
const trigger = params.trigger ?? "click";
|
|
1814
|
+
if (trigger === "click") {
|
|
1815
|
+
el.actionClick = void 0;
|
|
1816
|
+
} else {
|
|
1817
|
+
el.actionHover = void 0;
|
|
1818
|
+
}
|
|
1819
|
+
return {
|
|
1820
|
+
pptxData: ctx.pptxData,
|
|
1821
|
+
dirty: true,
|
|
1822
|
+
result: { action: "remove", elementId: params.elementId }
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
default:
|
|
1826
|
+
throw new Error(`Unknown hyperlink action: ${String(params.action)}`);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
function getLayouts(ctx) {
|
|
1830
|
+
const layouts = [];
|
|
1831
|
+
if (ctx.pptxData.slideMasters) {
|
|
1832
|
+
for (const master of ctx.pptxData.slideMasters) {
|
|
1833
|
+
if (master.layouts) {
|
|
1834
|
+
for (const layout of master.layouts) {
|
|
1835
|
+
layouts.push({
|
|
1836
|
+
name: layout.name ?? "Unknown",
|
|
1837
|
+
path: layout.path
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
if (ctx.pptxData.layoutOptions) {
|
|
1844
|
+
for (const opt of ctx.pptxData.layoutOptions) {
|
|
1845
|
+
if (!layouts.some((l) => l.path === opt.path)) {
|
|
1846
|
+
layouts.push({ name: opt.name, path: opt.path, type: opt.type });
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
return {
|
|
1851
|
+
pptxData: ctx.pptxData,
|
|
1852
|
+
dirty: false,
|
|
1853
|
+
result: { layouts, count: layouts.length }
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
function applyLayout(ctx, params) {
|
|
1857
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1858
|
+
if (err) {
|
|
1859
|
+
throw new Error(err);
|
|
1860
|
+
}
|
|
1861
|
+
let layout;
|
|
1862
|
+
if (params.layoutName) {
|
|
1863
|
+
layout = pptxViewerCore.findLayoutByName(ctx.pptxData, params.layoutName);
|
|
1864
|
+
} else if (params.layoutType) {
|
|
1865
|
+
layout = pptxViewerCore.findLayoutByType(ctx.pptxData, params.layoutType);
|
|
1866
|
+
} else {
|
|
1867
|
+
throw new Error("Either layoutName or layoutType must be provided.");
|
|
1868
|
+
}
|
|
1869
|
+
if (!layout) {
|
|
1870
|
+
throw new Error(
|
|
1871
|
+
`Layout not found: ${params.layoutName ?? params.layoutType}. Use get_layouts to see available layouts.`
|
|
1872
|
+
);
|
|
1873
|
+
}
|
|
1874
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1875
|
+
slide.layoutName = layout.name;
|
|
1876
|
+
if (layout.path) {
|
|
1877
|
+
slide.layoutPath = layout.path;
|
|
1878
|
+
}
|
|
1879
|
+
return {
|
|
1880
|
+
pptxData: ctx.pptxData,
|
|
1881
|
+
dirty: true,
|
|
1882
|
+
result: { slideIndex: params.slideIndex, layoutName: layout.name ?? "Unknown" }
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1885
|
+
function setElementLockT(ctx, params) {
|
|
1886
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1887
|
+
if (err) {
|
|
1888
|
+
throw new Error(err);
|
|
1889
|
+
}
|
|
1890
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1891
|
+
const idx = slide.elements.findIndex((e) => e.id === params.elementId);
|
|
1892
|
+
if (idx < 0) {
|
|
1893
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1894
|
+
}
|
|
1895
|
+
const extraLocks = {};
|
|
1896
|
+
if (params.noMove !== void 0) {
|
|
1897
|
+
extraLocks["noMove"] = params.noMove;
|
|
1898
|
+
}
|
|
1899
|
+
if (params.noResize !== void 0) {
|
|
1900
|
+
extraLocks["noResize"] = params.noResize;
|
|
1901
|
+
}
|
|
1902
|
+
if (params.noRotation !== void 0) {
|
|
1903
|
+
extraLocks["noRotation"] = params.noRotation;
|
|
1904
|
+
}
|
|
1905
|
+
if (params.noSelect !== void 0) {
|
|
1906
|
+
extraLocks["noSelect"] = params.noSelect;
|
|
1907
|
+
}
|
|
1908
|
+
if (params.noTextEdit !== void 0) {
|
|
1909
|
+
extraLocks["noTextEdit"] = params.noTextEdit;
|
|
1910
|
+
}
|
|
1911
|
+
const updated = pptxViewerCore.setElementLocked(slide.elements[idx], params.locked, extraLocks);
|
|
1912
|
+
slide.elements[idx] = updated;
|
|
1913
|
+
return {
|
|
1914
|
+
pptxData: ctx.pptxData,
|
|
1915
|
+
dirty: true,
|
|
1916
|
+
result: { elementId: params.elementId, locked: params.locked }
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
// src/tools/metadata-tools.ts
|
|
1921
|
+
function getMetadata(ctx) {
|
|
1922
|
+
return {
|
|
1923
|
+
pptxData: ctx.pptxData,
|
|
1924
|
+
dirty: false,
|
|
1925
|
+
result: {
|
|
1926
|
+
coreProperties: ctx.pptxData.coreProperties,
|
|
1927
|
+
appProperties: ctx.pptxData.appProperties,
|
|
1928
|
+
customProperties: ctx.pptxData.customProperties,
|
|
1929
|
+
slideCount: ctx.pptxData.slides.length
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
function updateMetadata(ctx, params) {
|
|
1934
|
+
const updated = [];
|
|
1935
|
+
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) {
|
|
1936
|
+
if (!ctx.pptxData.coreProperties) {
|
|
1937
|
+
ctx.pptxData.coreProperties = {};
|
|
1938
|
+
}
|
|
1939
|
+
const cp = ctx.pptxData.coreProperties;
|
|
1940
|
+
if (params.title !== void 0) {
|
|
1941
|
+
cp.title = params.title;
|
|
1942
|
+
updated.push("title");
|
|
1943
|
+
}
|
|
1944
|
+
if (params.subject !== void 0) {
|
|
1945
|
+
cp.subject = params.subject;
|
|
1946
|
+
updated.push("subject");
|
|
1947
|
+
}
|
|
1948
|
+
if (params.creator !== void 0) {
|
|
1949
|
+
cp.creator = params.creator;
|
|
1950
|
+
updated.push("creator");
|
|
1951
|
+
}
|
|
1952
|
+
if (params.keywords !== void 0) {
|
|
1953
|
+
cp.keywords = params.keywords;
|
|
1954
|
+
updated.push("keywords");
|
|
1955
|
+
}
|
|
1956
|
+
if (params.description !== void 0) {
|
|
1957
|
+
cp.description = params.description;
|
|
1958
|
+
updated.push("description");
|
|
1959
|
+
}
|
|
1960
|
+
if (params.lastModifiedBy !== void 0) {
|
|
1961
|
+
cp.lastModifiedBy = params.lastModifiedBy;
|
|
1962
|
+
updated.push("lastModifiedBy");
|
|
1963
|
+
}
|
|
1964
|
+
if (params.category !== void 0) {
|
|
1965
|
+
cp.category = params.category;
|
|
1966
|
+
updated.push("category");
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
if (params.company !== void 0 || params.manager !== void 0) {
|
|
1970
|
+
if (!ctx.pptxData.appProperties) {
|
|
1971
|
+
ctx.pptxData.appProperties = {};
|
|
1972
|
+
}
|
|
1973
|
+
const ap = ctx.pptxData.appProperties;
|
|
1974
|
+
if (params.company !== void 0) {
|
|
1975
|
+
ap.company = params.company;
|
|
1976
|
+
updated.push("company");
|
|
1977
|
+
}
|
|
1978
|
+
if (params.manager !== void 0) {
|
|
1979
|
+
ap.manager = params.manager;
|
|
1980
|
+
updated.push("manager");
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
if (params.customProperties) {
|
|
1984
|
+
if (!ctx.pptxData.customProperties) {
|
|
1985
|
+
ctx.pptxData.customProperties = [];
|
|
1986
|
+
}
|
|
1987
|
+
for (const cp of params.customProperties) {
|
|
1988
|
+
const valueStr = String(cp.value);
|
|
1989
|
+
const vtType = typeof cp.value === "number" ? "i4" : typeof cp.value === "boolean" ? "bool" : "lpwstr";
|
|
1990
|
+
const existing = ctx.pptxData.customProperties.find((p) => p.name === cp.name);
|
|
1991
|
+
if (existing) {
|
|
1992
|
+
existing.value = valueStr;
|
|
1993
|
+
existing.type = vtType;
|
|
1994
|
+
} else {
|
|
1995
|
+
ctx.pptxData.customProperties.push({ name: cp.name, value: valueStr, type: vtType });
|
|
1996
|
+
}
|
|
1997
|
+
updated.push(`custom:${cp.name}`);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
return {
|
|
2001
|
+
pptxData: ctx.pptxData,
|
|
2002
|
+
dirty: updated.length > 0,
|
|
2003
|
+
result: { updated }
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// src/tools/presentation-tools.ts
|
|
2008
|
+
function getPresentationProperties(ctx) {
|
|
2009
|
+
return {
|
|
2010
|
+
pptxData: ctx.pptxData,
|
|
2011
|
+
dirty: false,
|
|
2012
|
+
result: {
|
|
2013
|
+
properties: ctx.pptxData.presentationProperties,
|
|
2014
|
+
slideCount: ctx.pptxData.slides.length,
|
|
2015
|
+
width: ctx.pptxData.width,
|
|
2016
|
+
height: ctx.pptxData.height
|
|
2017
|
+
}
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
function updatePresentationProperties(ctx, params) {
|
|
2021
|
+
if (!ctx.pptxData.presentationProperties) {
|
|
2022
|
+
ctx.pptxData.presentationProperties = {};
|
|
2023
|
+
}
|
|
2024
|
+
const pp = ctx.pptxData.presentationProperties;
|
|
2025
|
+
if (params.showType !== void 0) {
|
|
2026
|
+
pp.showType = params.showType;
|
|
2027
|
+
}
|
|
2028
|
+
if (params.loopContinuously !== void 0) {
|
|
2029
|
+
pp.loopContinuously = params.loopContinuously;
|
|
2030
|
+
}
|
|
2031
|
+
if (params.showWithNarration !== void 0) {
|
|
2032
|
+
pp.showWithNarration = params.showWithNarration;
|
|
2033
|
+
}
|
|
2034
|
+
if (params.showWithAnimation !== void 0) {
|
|
2035
|
+
pp.showWithAnimation = params.showWithAnimation;
|
|
2036
|
+
}
|
|
2037
|
+
if (params.advanceMode !== void 0) {
|
|
2038
|
+
pp.advanceMode = params.advanceMode;
|
|
2039
|
+
}
|
|
2040
|
+
if (params.showSlidesMode !== void 0) {
|
|
2041
|
+
pp.showSlidesMode = params.showSlidesMode;
|
|
2042
|
+
}
|
|
2043
|
+
if (params.showSlidesFrom !== void 0) {
|
|
2044
|
+
pp.showSlidesFrom = params.showSlidesFrom;
|
|
2045
|
+
}
|
|
2046
|
+
if (params.showSlidesTo !== void 0) {
|
|
2047
|
+
pp.showSlidesTo = params.showSlidesTo;
|
|
2048
|
+
}
|
|
2049
|
+
if (params.penColor !== void 0) {
|
|
2050
|
+
pp.penColor = params.penColor;
|
|
2051
|
+
}
|
|
2052
|
+
return {
|
|
2053
|
+
pptxData: ctx.pptxData,
|
|
2054
|
+
dirty: true,
|
|
2055
|
+
result: { properties: pp }
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
function manageSections(ctx, params) {
|
|
2059
|
+
switch (params.action) {
|
|
2060
|
+
case "list": {
|
|
2061
|
+
const sections = (ctx.pptxData.sections ?? []).map((s) => ({
|
|
2062
|
+
id: s.id,
|
|
2063
|
+
name: s.name,
|
|
2064
|
+
slideIds: s.slideIds,
|
|
2065
|
+
collapsed: s.collapsed,
|
|
2066
|
+
color: s.color
|
|
2067
|
+
}));
|
|
2068
|
+
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", sections } };
|
|
2069
|
+
}
|
|
2070
|
+
case "add": {
|
|
2071
|
+
if (!params.name) {
|
|
2072
|
+
throw new Error("name is required for add action.");
|
|
2073
|
+
}
|
|
2074
|
+
const section = pptxViewerCore.addSection(ctx.pptxData, params.name, params.slideIndices ?? []);
|
|
2075
|
+
return {
|
|
2076
|
+
pptxData: ctx.pptxData,
|
|
2077
|
+
dirty: true,
|
|
2078
|
+
result: {
|
|
2079
|
+
action: "add",
|
|
2080
|
+
section: { id: section.id, name: section.name, slideIds: section.slideIds }
|
|
2081
|
+
}
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2084
|
+
case "remove": {
|
|
2085
|
+
if (!params.sectionId) {
|
|
2086
|
+
throw new Error("sectionId is required for remove action.");
|
|
2087
|
+
}
|
|
2088
|
+
const success = pptxViewerCore.removeSection(ctx.pptxData, params.sectionId);
|
|
2089
|
+
return { pptxData: ctx.pptxData, dirty: success, result: { action: "remove", success } };
|
|
2090
|
+
}
|
|
2091
|
+
case "reorder": {
|
|
2092
|
+
if (!params.sectionIds) {
|
|
2093
|
+
throw new Error("sectionIds is required for reorder action.");
|
|
2094
|
+
}
|
|
2095
|
+
pptxViewerCore.reorderSections(ctx.pptxData, params.sectionIds);
|
|
2096
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { action: "reorder", success: true } };
|
|
2097
|
+
}
|
|
2098
|
+
case "moveSlides": {
|
|
2099
|
+
if (!params.sectionId) {
|
|
2100
|
+
throw new Error("sectionId is required for moveSlides action.");
|
|
2101
|
+
}
|
|
2102
|
+
if (!params.slideIndices) {
|
|
2103
|
+
throw new Error("slideIndices is required for moveSlides action.");
|
|
2104
|
+
}
|
|
2105
|
+
const success = pptxViewerCore.moveSlidesToSection(ctx.pptxData, params.slideIndices, params.sectionId);
|
|
2106
|
+
return { pptxData: ctx.pptxData, dirty: success, result: { action: "moveSlides", success } };
|
|
2107
|
+
}
|
|
2108
|
+
case "getForSlide": {
|
|
2109
|
+
if (params.slideIndex === void 0) {
|
|
2110
|
+
throw new Error("slideIndex is required for getForSlide action.");
|
|
2111
|
+
}
|
|
2112
|
+
const section = pptxViewerCore.getSectionForSlide(ctx.pptxData, params.slideIndex);
|
|
2113
|
+
const info = section ? { id: section.id, name: section.name, slideIds: section.slideIds } : null;
|
|
2114
|
+
return {
|
|
2115
|
+
pptxData: ctx.pptxData,
|
|
2116
|
+
dirty: false,
|
|
2117
|
+
result: { action: "getForSlide", section: info }
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
default:
|
|
2121
|
+
throw new Error(`Unknown section action: ${String(params.action)}`);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
// src/tools/slide-tools.ts
|
|
2126
|
+
function getSlide(ctx, params) {
|
|
2127
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2128
|
+
if (err) {
|
|
2129
|
+
throw new Error(err);
|
|
2130
|
+
}
|
|
2131
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2132
|
+
return {
|
|
2133
|
+
pptxData: ctx.pptxData,
|
|
2134
|
+
dirty: false,
|
|
2135
|
+
result: {
|
|
2136
|
+
slideIndex: params.slideIndex,
|
|
2137
|
+
slideNumber: slide.slideNumber,
|
|
2138
|
+
hidden: slide.hidden ?? false,
|
|
2139
|
+
layoutName: slide.layoutName,
|
|
2140
|
+
backgroundColor: slide.backgroundColor,
|
|
2141
|
+
notes: slide.notes ?? "",
|
|
2142
|
+
commentCount: slide.comments?.length ?? 0,
|
|
2143
|
+
elements: slide.elements.map(describeElement)
|
|
2144
|
+
}
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
2147
|
+
function addSlide(ctx, params) {
|
|
2148
|
+
const { slides } = ctx.pptxData;
|
|
2149
|
+
const insertAt = params.insertAfterIndex !== void 0 && params.insertAfterIndex >= 0 ? Math.min(params.insertAfterIndex + 1, slides.length) : slides.length;
|
|
2150
|
+
const newSlide = {
|
|
2151
|
+
id: generateSlideId(),
|
|
2152
|
+
rId: "",
|
|
2153
|
+
slideNumber: insertAt + 1,
|
|
2154
|
+
elements: [],
|
|
2155
|
+
backgroundColor: params.backgroundColor
|
|
2156
|
+
};
|
|
2157
|
+
slides.splice(insertAt, 0, newSlide);
|
|
2158
|
+
slides.forEach((s, i) => {
|
|
2159
|
+
s.slideNumber = i + 1;
|
|
2160
|
+
});
|
|
2161
|
+
return {
|
|
2162
|
+
pptxData: ctx.pptxData,
|
|
2163
|
+
dirty: true,
|
|
2164
|
+
result: { newSlideIndex: insertAt, slideCount: slides.length }
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
function deleteSlides(ctx, params) {
|
|
2168
|
+
const { slides } = ctx.pptxData;
|
|
2169
|
+
if (!params.slideIndexes || params.slideIndexes.length === 0) {
|
|
2170
|
+
throw new Error("slideIndexes is required for the delete action.");
|
|
2171
|
+
}
|
|
2172
|
+
const indexSet = new Set(params.slideIndexes);
|
|
2173
|
+
const invalid = params.slideIndexes.filter((i) => i < 0 || i >= slides.length);
|
|
2174
|
+
if (invalid.length > 0) {
|
|
2175
|
+
throw new Error(
|
|
2176
|
+
`Invalid slide indexes: ${invalid.join(", ")}. Valid range: 0\u2013${slides.length - 1}.`
|
|
2177
|
+
);
|
|
2178
|
+
}
|
|
2179
|
+
if (indexSet.size >= slides.length) {
|
|
2180
|
+
throw new Error("Cannot delete all slides. At least one slide must remain.");
|
|
2181
|
+
}
|
|
2182
|
+
ctx.pptxData.slides = slides.filter((_, i) => !indexSet.has(i));
|
|
2183
|
+
ctx.pptxData.slides.forEach((s, i) => {
|
|
2184
|
+
s.slideNumber = i + 1;
|
|
2185
|
+
});
|
|
2186
|
+
return {
|
|
2187
|
+
pptxData: ctx.pptxData,
|
|
2188
|
+
dirty: true,
|
|
2189
|
+
result: { deletedCount: indexSet.size, slideCount: ctx.pptxData.slides.length }
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
2192
|
+
function reorderSlides(ctx, params) {
|
|
2193
|
+
const { slides } = ctx.pptxData;
|
|
2194
|
+
if (!params.newOrder || params.newOrder.length !== slides.length) {
|
|
2195
|
+
throw new Error(
|
|
2196
|
+
`newOrder must have exactly ${slides.length} indexes. Got ${params.newOrder?.length ?? 0}.`
|
|
2197
|
+
);
|
|
2198
|
+
}
|
|
2199
|
+
const sorted = [...params.newOrder].sort((a, b) => a - b);
|
|
2200
|
+
const expected = slides.map((_, i) => i);
|
|
2201
|
+
if (JSON.stringify(sorted) !== JSON.stringify(expected)) {
|
|
2202
|
+
throw new Error(
|
|
2203
|
+
`newOrder must contain each index from 0 to ${slides.length - 1} exactly once.`
|
|
2204
|
+
);
|
|
2205
|
+
}
|
|
2206
|
+
ctx.pptxData.slides = params.newOrder.map((idx) => slides[idx]);
|
|
2207
|
+
ctx.pptxData.slides.forEach((s, i) => {
|
|
2208
|
+
s.slideNumber = i + 1;
|
|
2209
|
+
});
|
|
2210
|
+
return {
|
|
2211
|
+
pptxData: ctx.pptxData,
|
|
2212
|
+
dirty: true,
|
|
2213
|
+
result: { slideCount: ctx.pptxData.slides.length }
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
function duplicateSlide(ctx, params) {
|
|
2217
|
+
const { slides } = ctx.pptxData;
|
|
2218
|
+
const err = validateSlideIndex(params.slideIndex, slides.length);
|
|
2219
|
+
if (err) {
|
|
2220
|
+
throw new Error(err);
|
|
2221
|
+
}
|
|
2222
|
+
const original = slides[params.slideIndex];
|
|
2223
|
+
const clone = structuredClone(original);
|
|
2224
|
+
clone.id = generateSlideId();
|
|
2225
|
+
clone.rId = "";
|
|
2226
|
+
for (const el of clone.elements) {
|
|
2227
|
+
el.id = generateElementId();
|
|
2228
|
+
}
|
|
2229
|
+
const insertIndex = params.targetIndex ?? params.slideIndex + 1;
|
|
2230
|
+
slides.splice(insertIndex, 0, clone);
|
|
2231
|
+
slides.forEach((s, i) => {
|
|
2232
|
+
s.slideNumber = i + 1;
|
|
2233
|
+
});
|
|
2234
|
+
return {
|
|
2235
|
+
pptxData: ctx.pptxData,
|
|
2236
|
+
dirty: true,
|
|
2237
|
+
result: { newSlideIndex: insertIndex, slideCount: slides.length }
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
function updateSlideProperties(ctx, params) {
|
|
2241
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2242
|
+
if (err) {
|
|
2243
|
+
throw new Error(err);
|
|
2244
|
+
}
|
|
2245
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2246
|
+
if (params.backgroundColor !== void 0) {
|
|
1383
2247
|
slide.backgroundColor = params.backgroundColor;
|
|
1384
2248
|
}
|
|
1385
2249
|
if (params.backgroundGradient !== void 0) {
|
|
@@ -1447,6 +2311,164 @@ function setCanvasSize(ctx, params) {
|
|
|
1447
2311
|
result: { canvasWidth: params.width, canvasHeight: params.height }
|
|
1448
2312
|
};
|
|
1449
2313
|
}
|
|
2314
|
+
function extractNodes(data) {
|
|
2315
|
+
if (!data.nodes) {
|
|
2316
|
+
return [];
|
|
2317
|
+
}
|
|
2318
|
+
return data.nodes.map((n) => ({
|
|
2319
|
+
id: n.id,
|
|
2320
|
+
text: n.text ?? "",
|
|
2321
|
+
children: n.children?.map((c) => ({ id: c.id, text: c.text ?? "" }))
|
|
2322
|
+
}));
|
|
2323
|
+
}
|
|
2324
|
+
function manageSmartArt(ctx, params) {
|
|
2325
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2326
|
+
if (err) {
|
|
2327
|
+
throw new Error(err);
|
|
2328
|
+
}
|
|
2329
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2330
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2331
|
+
if (!el) {
|
|
2332
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2333
|
+
}
|
|
2334
|
+
if (el.type !== "smartArt") {
|
|
2335
|
+
throw new Error(`Element '${params.elementId}' is not a SmartArt.`);
|
|
2336
|
+
}
|
|
2337
|
+
const smartArt = el;
|
|
2338
|
+
if (!smartArt.smartArtData) {
|
|
2339
|
+
throw new Error(`SmartArt '${params.elementId}' has no data.`);
|
|
2340
|
+
}
|
|
2341
|
+
switch (params.action) {
|
|
2342
|
+
case "getNodes": {
|
|
2343
|
+
return {
|
|
2344
|
+
pptxData: ctx.pptxData,
|
|
2345
|
+
dirty: false,
|
|
2346
|
+
result: {
|
|
2347
|
+
action: "getNodes",
|
|
2348
|
+
elementId: params.elementId,
|
|
2349
|
+
nodes: extractNodes(smartArt.smartArtData)
|
|
2350
|
+
}
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
case "addNode": {
|
|
2354
|
+
smartArt.smartArtData = pptxViewerCore.addSmartArtNode(
|
|
2355
|
+
smartArt.smartArtData,
|
|
2356
|
+
params.text ?? "",
|
|
2357
|
+
params.afterNodeId
|
|
2358
|
+
);
|
|
2359
|
+
return {
|
|
2360
|
+
pptxData: ctx.pptxData,
|
|
2361
|
+
dirty: true,
|
|
2362
|
+
result: {
|
|
2363
|
+
action: "addNode",
|
|
2364
|
+
elementId: params.elementId,
|
|
2365
|
+
nodes: extractNodes(smartArt.smartArtData)
|
|
2366
|
+
}
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
case "removeNode": {
|
|
2370
|
+
if (!params.nodeId) {
|
|
2371
|
+
throw new Error("nodeId is required for removeNode.");
|
|
2372
|
+
}
|
|
2373
|
+
smartArt.smartArtData = pptxViewerCore.removeSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
2374
|
+
return {
|
|
2375
|
+
pptxData: ctx.pptxData,
|
|
2376
|
+
dirty: true,
|
|
2377
|
+
result: {
|
|
2378
|
+
action: "removeNode",
|
|
2379
|
+
elementId: params.elementId,
|
|
2380
|
+
nodes: extractNodes(smartArt.smartArtData)
|
|
2381
|
+
}
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
case "updateNodeText": {
|
|
2385
|
+
if (!params.nodeId) {
|
|
2386
|
+
throw new Error("nodeId is required for updateNodeText.");
|
|
2387
|
+
}
|
|
2388
|
+
smartArt.smartArtData = pptxViewerCore.updateSmartArtNodeText(
|
|
2389
|
+
smartArt.smartArtData,
|
|
2390
|
+
params.nodeId,
|
|
2391
|
+
params.text ?? ""
|
|
2392
|
+
);
|
|
2393
|
+
return {
|
|
2394
|
+
pptxData: ctx.pptxData,
|
|
2395
|
+
dirty: true,
|
|
2396
|
+
result: { action: "updateNodeText", elementId: params.elementId }
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
case "reorderNode": {
|
|
2400
|
+
if (!params.nodeId) {
|
|
2401
|
+
throw new Error("nodeId is required for reorderNode.");
|
|
2402
|
+
}
|
|
2403
|
+
const dir = params.direction ?? 1;
|
|
2404
|
+
smartArt.smartArtData = pptxViewerCore.reorderSmartArtNode(smartArt.smartArtData, params.nodeId, dir);
|
|
2405
|
+
return {
|
|
2406
|
+
pptxData: ctx.pptxData,
|
|
2407
|
+
dirty: true,
|
|
2408
|
+
result: {
|
|
2409
|
+
action: "reorderNode",
|
|
2410
|
+
elementId: params.elementId,
|
|
2411
|
+
nodes: extractNodes(smartArt.smartArtData)
|
|
2412
|
+
}
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
case "promoteNode": {
|
|
2416
|
+
if (!params.nodeId) {
|
|
2417
|
+
throw new Error("nodeId is required for promoteNode.");
|
|
2418
|
+
}
|
|
2419
|
+
smartArt.smartArtData = pptxViewerCore.promoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
2420
|
+
return {
|
|
2421
|
+
pptxData: ctx.pptxData,
|
|
2422
|
+
dirty: true,
|
|
2423
|
+
result: {
|
|
2424
|
+
action: "promoteNode",
|
|
2425
|
+
elementId: params.elementId,
|
|
2426
|
+
nodes: extractNodes(smartArt.smartArtData)
|
|
2427
|
+
}
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
case "demoteNode": {
|
|
2431
|
+
if (!params.nodeId) {
|
|
2432
|
+
throw new Error("nodeId is required for demoteNode.");
|
|
2433
|
+
}
|
|
2434
|
+
smartArt.smartArtData = pptxViewerCore.demoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
2435
|
+
return {
|
|
2436
|
+
pptxData: ctx.pptxData,
|
|
2437
|
+
dirty: true,
|
|
2438
|
+
result: {
|
|
2439
|
+
action: "demoteNode",
|
|
2440
|
+
elementId: params.elementId,
|
|
2441
|
+
nodes: extractNodes(smartArt.smartArtData)
|
|
2442
|
+
}
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
case "decompose": {
|
|
2446
|
+
const bounds = {
|
|
2447
|
+
x: smartArt.x,
|
|
2448
|
+
y: smartArt.y,
|
|
2449
|
+
width: smartArt.width,
|
|
2450
|
+
height: smartArt.height
|
|
2451
|
+
};
|
|
2452
|
+
const decomposed = pptxViewerCore.decomposeSmartArt(smartArt.smartArtData, bounds);
|
|
2453
|
+
if (!decomposed || decomposed.length === 0) {
|
|
2454
|
+
throw new Error("Failed to decompose SmartArt into shapes.");
|
|
2455
|
+
}
|
|
2456
|
+
const idx = slide.elements.indexOf(el);
|
|
2457
|
+
slide.elements.splice(idx, 1, ...decomposed);
|
|
2458
|
+
return {
|
|
2459
|
+
pptxData: ctx.pptxData,
|
|
2460
|
+
dirty: true,
|
|
2461
|
+
result: {
|
|
2462
|
+
action: "decompose",
|
|
2463
|
+
elementId: params.elementId,
|
|
2464
|
+
decomposedCount: decomposed.length
|
|
2465
|
+
}
|
|
2466
|
+
};
|
|
2467
|
+
}
|
|
2468
|
+
default:
|
|
2469
|
+
throw new Error(`Unknown SmartArt action: ${String(params.action)}`);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
1450
2472
|
function updateElementStyle(ctx, params) {
|
|
1451
2473
|
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1452
2474
|
if (err) {
|
|
@@ -1751,17 +2773,144 @@ function manageTableStructure(ctx, params) {
|
|
|
1751
2773
|
}
|
|
1752
2774
|
break;
|
|
1753
2775
|
}
|
|
1754
|
-
default: {
|
|
1755
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
2776
|
+
default: {
|
|
2777
|
+
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
return {
|
|
2781
|
+
pptxData: ctx.pptxData,
|
|
2782
|
+
dirty: true,
|
|
2783
|
+
result: {
|
|
2784
|
+
rowCount: tbl.tableData.rows.length,
|
|
2785
|
+
columnCount: tbl.tableData.columnWidths.length
|
|
2786
|
+
}
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
function findPlaceholdersT(ctx) {
|
|
2790
|
+
const placeholders = pptxViewerCore.findPlaceholders(ctx.pptxData);
|
|
2791
|
+
return {
|
|
2792
|
+
pptxData: ctx.pptxData,
|
|
2793
|
+
dirty: false,
|
|
2794
|
+
result: { placeholders, count: placeholders.length }
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2797
|
+
function applyTemplateT(ctx, params) {
|
|
2798
|
+
pptxViewerCore.applyTemplate(ctx.pptxData, params.data);
|
|
2799
|
+
return {
|
|
2800
|
+
pptxData: ctx.pptxData,
|
|
2801
|
+
dirty: true,
|
|
2802
|
+
result: { applied: true, slideCount: ctx.pptxData.slides.length }
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2805
|
+
function getThemeInfo(ctx) {
|
|
2806
|
+
const theme = ctx.pptxData.theme;
|
|
2807
|
+
return {
|
|
2808
|
+
pptxData: ctx.pptxData,
|
|
2809
|
+
dirty: false,
|
|
2810
|
+
result: {
|
|
2811
|
+
themeName: theme?.name,
|
|
2812
|
+
colorScheme: theme?.colorScheme,
|
|
2813
|
+
fontScheme: theme?.fontScheme,
|
|
2814
|
+
availablePresets: Object.keys(pptxViewerCore.ThemePresets)
|
|
2815
|
+
}
|
|
2816
|
+
};
|
|
2817
|
+
}
|
|
2818
|
+
function applyThemePreset(ctx, params) {
|
|
2819
|
+
const preset = pptxViewerCore.getThemePreset(params.presetName);
|
|
2820
|
+
if (!preset) {
|
|
2821
|
+
throw new Error(
|
|
2822
|
+
`Unknown theme preset: "${params.presetName}". Available: ${Object.keys(pptxViewerCore.ThemePresets).join(", ")}`
|
|
2823
|
+
);
|
|
2824
|
+
}
|
|
2825
|
+
if (!ctx.pptxData.theme) {
|
|
2826
|
+
ctx.pptxData.theme = {};
|
|
2827
|
+
}
|
|
2828
|
+
const theme = ctx.pptxData.theme;
|
|
2829
|
+
theme.name = preset.name;
|
|
2830
|
+
theme.colorScheme = preset.colors;
|
|
2831
|
+
if (preset.fonts) {
|
|
2832
|
+
theme.fontScheme = preset.fonts;
|
|
2833
|
+
}
|
|
2834
|
+
return {
|
|
2835
|
+
pptxData: ctx.pptxData,
|
|
2836
|
+
dirty: true,
|
|
2837
|
+
result: {
|
|
2838
|
+
appliedPreset: params.presetName,
|
|
2839
|
+
colorScheme: theme.colorScheme
|
|
2840
|
+
}
|
|
2841
|
+
};
|
|
2842
|
+
}
|
|
2843
|
+
function updateThemeColors(ctx, params) {
|
|
2844
|
+
if (!ctx.pptxData.theme) {
|
|
2845
|
+
ctx.pptxData.theme = {};
|
|
2846
|
+
}
|
|
2847
|
+
const theme = ctx.pptxData.theme;
|
|
2848
|
+
if (!theme.colorScheme) {
|
|
2849
|
+
theme.colorScheme = {
|
|
2850
|
+
dk1: "#000000",
|
|
2851
|
+
lt1: "#FFFFFF",
|
|
2852
|
+
dk2: "#44546A",
|
|
2853
|
+
lt2: "#E7E6E6",
|
|
2854
|
+
accent1: "#4472C4",
|
|
2855
|
+
accent2: "#ED7D31",
|
|
2856
|
+
accent3: "#A5A5A5",
|
|
2857
|
+
accent4: "#FFC000",
|
|
2858
|
+
accent5: "#5B9BD5",
|
|
2859
|
+
accent6: "#70AD47",
|
|
2860
|
+
hlink: "#0563C1",
|
|
2861
|
+
folHlink: "#954F72"
|
|
2862
|
+
};
|
|
2863
|
+
}
|
|
2864
|
+
const cs = theme.colorScheme;
|
|
2865
|
+
for (const key of Object.keys(params)) {
|
|
2866
|
+
if (params[key] !== void 0) {
|
|
2867
|
+
cs[key] = params[key];
|
|
1756
2868
|
}
|
|
1757
2869
|
}
|
|
1758
2870
|
return {
|
|
1759
2871
|
pptxData: ctx.pptxData,
|
|
1760
2872
|
dirty: true,
|
|
2873
|
+
result: { colorScheme: cs }
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2876
|
+
function updateThemeFonts(ctx, params) {
|
|
2877
|
+
if (!ctx.pptxData.theme) {
|
|
2878
|
+
ctx.pptxData.theme = {};
|
|
2879
|
+
}
|
|
2880
|
+
const theme = ctx.pptxData.theme;
|
|
2881
|
+
if (!theme.fontScheme) {
|
|
2882
|
+
theme.fontScheme = {};
|
|
2883
|
+
}
|
|
2884
|
+
if (params.majorFont !== void 0) {
|
|
2885
|
+
theme.fontScheme.majorFont = { latin: params.majorFont };
|
|
2886
|
+
}
|
|
2887
|
+
if (params.minorFont !== void 0) {
|
|
2888
|
+
theme.fontScheme.minorFont = { latin: params.minorFont };
|
|
2889
|
+
}
|
|
2890
|
+
return {
|
|
2891
|
+
pptxData: ctx.pptxData,
|
|
2892
|
+
dirty: true,
|
|
2893
|
+
result: { fontScheme: theme.fontScheme }
|
|
2894
|
+
};
|
|
2895
|
+
}
|
|
2896
|
+
async function validatePresentation(rawBytes) {
|
|
2897
|
+
const result = await pptxViewerCore.validatePptx(rawBytes);
|
|
2898
|
+
return {
|
|
2899
|
+
valid: result.valid,
|
|
2900
|
+
issueCount: result.issues.length,
|
|
2901
|
+
errors: result.issues.filter((i) => i.severity === "error").length,
|
|
2902
|
+
warnings: result.issues.filter((i) => i.severity === "warning").length,
|
|
2903
|
+
issues: result.issues
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
async function repairPresentation(rawBytes) {
|
|
2907
|
+
const result = await pptxViewerCore.repairPptx(rawBytes);
|
|
2908
|
+
return {
|
|
1761
2909
|
result: {
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
}
|
|
2910
|
+
repairCount: result.repairs.length,
|
|
2911
|
+
repairs: result.repairs
|
|
2912
|
+
},
|
|
2913
|
+
repairedBytes: result.repaired
|
|
1765
2914
|
};
|
|
1766
2915
|
}
|
|
1767
2916
|
var PPTX_MIME_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
@@ -2400,6 +3549,372 @@ function createServer() {
|
|
|
2400
3549
|
};
|
|
2401
3550
|
}
|
|
2402
3551
|
);
|
|
3552
|
+
server2.registerTool(
|
|
3553
|
+
"get_theme_info",
|
|
3554
|
+
{
|
|
3555
|
+
description: "Get current theme information (colors, fonts, available presets)",
|
|
3556
|
+
inputSchema: GetThemeInfoSchema.shape
|
|
3557
|
+
},
|
|
3558
|
+
async (params) => {
|
|
3559
|
+
const result = await runMcpTool(params.filePath, (ctx) => getThemeInfo(ctx));
|
|
3560
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3561
|
+
}
|
|
3562
|
+
);
|
|
3563
|
+
server2.registerTool(
|
|
3564
|
+
"apply_theme_preset",
|
|
3565
|
+
{
|
|
3566
|
+
description: "Apply a built-in theme preset to the presentation",
|
|
3567
|
+
inputSchema: ApplyThemePresetSchema.shape
|
|
3568
|
+
},
|
|
3569
|
+
async (params) => {
|
|
3570
|
+
const result = await runMcpTool(
|
|
3571
|
+
params.filePath,
|
|
3572
|
+
(ctx) => applyThemePreset(ctx, params)
|
|
3573
|
+
);
|
|
3574
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3575
|
+
}
|
|
3576
|
+
);
|
|
3577
|
+
server2.registerTool(
|
|
3578
|
+
"update_theme_colors",
|
|
3579
|
+
{
|
|
3580
|
+
description: "Update individual theme colors (accent1-6, dk1/2, lt1/2, hlink, folHlink)",
|
|
3581
|
+
inputSchema: UpdateThemeColorsSchema.shape
|
|
3582
|
+
},
|
|
3583
|
+
async (params) => {
|
|
3584
|
+
const result = await runMcpTool(
|
|
3585
|
+
params.filePath,
|
|
3586
|
+
(ctx) => updateThemeColors(ctx, params)
|
|
3587
|
+
);
|
|
3588
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3589
|
+
}
|
|
3590
|
+
);
|
|
3591
|
+
server2.registerTool(
|
|
3592
|
+
"update_theme_fonts",
|
|
3593
|
+
{
|
|
3594
|
+
description: "Update theme heading (major) and body (minor) fonts",
|
|
3595
|
+
inputSchema: UpdateThemeFontsSchema.shape
|
|
3596
|
+
},
|
|
3597
|
+
async (params) => {
|
|
3598
|
+
const result = await runMcpTool(
|
|
3599
|
+
params.filePath,
|
|
3600
|
+
(ctx) => updateThemeFonts(ctx, params)
|
|
3601
|
+
);
|
|
3602
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3603
|
+
}
|
|
3604
|
+
);
|
|
3605
|
+
server2.registerTool(
|
|
3606
|
+
"update_chart",
|
|
3607
|
+
{
|
|
3608
|
+
description: "Update chart type, title, legend, data labels, axis, or categories",
|
|
3609
|
+
inputSchema: UpdateChartSchema.shape
|
|
3610
|
+
},
|
|
3611
|
+
async (params) => {
|
|
3612
|
+
const result = await runMcpTool(
|
|
3613
|
+
params.filePath,
|
|
3614
|
+
(ctx) => updateChart(ctx, params)
|
|
3615
|
+
);
|
|
3616
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3617
|
+
}
|
|
3618
|
+
);
|
|
3619
|
+
server2.registerTool(
|
|
3620
|
+
"add_chart_series",
|
|
3621
|
+
{
|
|
3622
|
+
description: "Add a data series to an existing chart",
|
|
3623
|
+
inputSchema: AddChartSeriesSchema.shape
|
|
3624
|
+
},
|
|
3625
|
+
async (params) => {
|
|
3626
|
+
const result = await runMcpTool(
|
|
3627
|
+
params.filePath,
|
|
3628
|
+
(ctx) => addChartSeriesT(ctx, params)
|
|
3629
|
+
);
|
|
3630
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3631
|
+
}
|
|
3632
|
+
);
|
|
3633
|
+
server2.registerTool(
|
|
3634
|
+
"remove_chart_series",
|
|
3635
|
+
{
|
|
3636
|
+
description: "Remove a data series from a chart by index",
|
|
3637
|
+
inputSchema: RemoveChartSeriesSchema.shape
|
|
3638
|
+
},
|
|
3639
|
+
async (params) => {
|
|
3640
|
+
const result = await runMcpTool(
|
|
3641
|
+
params.filePath,
|
|
3642
|
+
(ctx) => removeChartSeriesT(ctx, params)
|
|
3643
|
+
);
|
|
3644
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3645
|
+
}
|
|
3646
|
+
);
|
|
3647
|
+
server2.registerTool(
|
|
3648
|
+
"update_chart_series_data",
|
|
3649
|
+
{
|
|
3650
|
+
description: "Update data values for a chart series",
|
|
3651
|
+
inputSchema: UpdateChartSeriesDataSchema.shape
|
|
3652
|
+
},
|
|
3653
|
+
async (params) => {
|
|
3654
|
+
const result = await runMcpTool(
|
|
3655
|
+
params.filePath,
|
|
3656
|
+
(ctx) => updateChartSeriesData(ctx, params)
|
|
3657
|
+
);
|
|
3658
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3659
|
+
}
|
|
3660
|
+
);
|
|
3661
|
+
server2.registerTool(
|
|
3662
|
+
"create_chart",
|
|
3663
|
+
{
|
|
3664
|
+
description: "Create a new chart element on a slide",
|
|
3665
|
+
inputSchema: CreateChartSchema.shape
|
|
3666
|
+
},
|
|
3667
|
+
async (params) => {
|
|
3668
|
+
const result = await runMcpTool(
|
|
3669
|
+
params.filePath,
|
|
3670
|
+
(ctx) => createChart(ctx, params)
|
|
3671
|
+
);
|
|
3672
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3673
|
+
}
|
|
3674
|
+
);
|
|
3675
|
+
server2.registerTool(
|
|
3676
|
+
"manage_smart_art",
|
|
3677
|
+
{
|
|
3678
|
+
description: "Manage SmartArt: get nodes, add/remove/reorder/promote/demote nodes, or decompose to shapes",
|
|
3679
|
+
inputSchema: ManageSmartArtSchema.shape
|
|
3680
|
+
},
|
|
3681
|
+
async (params) => {
|
|
3682
|
+
const result = await runMcpTool(
|
|
3683
|
+
params.filePath,
|
|
3684
|
+
(ctx) => manageSmartArt(ctx, params)
|
|
3685
|
+
);
|
|
3686
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3687
|
+
}
|
|
3688
|
+
);
|
|
3689
|
+
server2.registerTool(
|
|
3690
|
+
"find_placeholders",
|
|
3691
|
+
{
|
|
3692
|
+
description: "Discover all {{placeholder}} tokens in the presentation",
|
|
3693
|
+
inputSchema: FindPlaceholdersSchema.shape
|
|
3694
|
+
},
|
|
3695
|
+
async (params) => {
|
|
3696
|
+
const result = await runMcpTool(
|
|
3697
|
+
params.filePath,
|
|
3698
|
+
(ctx) => findPlaceholdersT(ctx)
|
|
3699
|
+
);
|
|
3700
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3701
|
+
}
|
|
3702
|
+
);
|
|
3703
|
+
server2.registerTool(
|
|
3704
|
+
"apply_template",
|
|
3705
|
+
{
|
|
3706
|
+
description: "Replace {{placeholder}} tokens with provided values (mail merge)",
|
|
3707
|
+
inputSchema: ApplyTemplateSchema.shape
|
|
3708
|
+
},
|
|
3709
|
+
async (params) => {
|
|
3710
|
+
const result = await runMcpTool(
|
|
3711
|
+
params.filePath,
|
|
3712
|
+
(ctx) => applyTemplateT(ctx, { data: params.data })
|
|
3713
|
+
);
|
|
3714
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3715
|
+
}
|
|
3716
|
+
);
|
|
3717
|
+
server2.registerTool(
|
|
3718
|
+
"get_metadata",
|
|
3719
|
+
{
|
|
3720
|
+
description: "Get presentation metadata (title, author, keywords, custom properties)",
|
|
3721
|
+
inputSchema: GetMetadataSchema.shape
|
|
3722
|
+
},
|
|
3723
|
+
async (params) => {
|
|
3724
|
+
const result = await runMcpTool(
|
|
3725
|
+
params.filePath,
|
|
3726
|
+
(ctx) => getMetadata(ctx)
|
|
3727
|
+
);
|
|
3728
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3729
|
+
}
|
|
3730
|
+
);
|
|
3731
|
+
server2.registerTool(
|
|
3732
|
+
"update_metadata",
|
|
3733
|
+
{
|
|
3734
|
+
description: "Update presentation metadata (title, author, company, custom properties)",
|
|
3735
|
+
inputSchema: UpdateMetadataSchema.shape
|
|
3736
|
+
},
|
|
3737
|
+
async (params) => {
|
|
3738
|
+
const result = await runMcpTool(
|
|
3739
|
+
params.filePath,
|
|
3740
|
+
(ctx) => updateMetadata(ctx, params)
|
|
3741
|
+
);
|
|
3742
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3743
|
+
}
|
|
3744
|
+
);
|
|
3745
|
+
server2.registerTool(
|
|
3746
|
+
"manage_sections",
|
|
3747
|
+
{
|
|
3748
|
+
description: "List, add, remove, reorder sections or move slides between sections",
|
|
3749
|
+
inputSchema: ManageSectionsSchema.shape
|
|
3750
|
+
},
|
|
3751
|
+
async (params) => {
|
|
3752
|
+
const result = await runMcpTool(
|
|
3753
|
+
params.filePath,
|
|
3754
|
+
(ctx) => manageSections(ctx, params)
|
|
3755
|
+
);
|
|
3756
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3757
|
+
}
|
|
3758
|
+
);
|
|
3759
|
+
server2.registerTool(
|
|
3760
|
+
"export_to_svg",
|
|
3761
|
+
{
|
|
3762
|
+
description: "Export all or specific slides to SVG strings",
|
|
3763
|
+
inputSchema: ExportToSvgSchema.shape
|
|
3764
|
+
},
|
|
3765
|
+
async (params) => {
|
|
3766
|
+
const result = await runMcpTool(
|
|
3767
|
+
params.filePath,
|
|
3768
|
+
(ctx) => exportToSvg(ctx, params)
|
|
3769
|
+
);
|
|
3770
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3771
|
+
}
|
|
3772
|
+
);
|
|
3773
|
+
server2.registerTool(
|
|
3774
|
+
"export_slide_svg",
|
|
3775
|
+
{
|
|
3776
|
+
description: "Export a single slide to SVG",
|
|
3777
|
+
inputSchema: ExportSlideSvgSchema.shape
|
|
3778
|
+
},
|
|
3779
|
+
async (params) => {
|
|
3780
|
+
const result = await runMcpTool(
|
|
3781
|
+
params.filePath,
|
|
3782
|
+
(ctx) => exportSlideSvg(ctx, params)
|
|
3783
|
+
);
|
|
3784
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3785
|
+
}
|
|
3786
|
+
);
|
|
3787
|
+
server2.registerTool(
|
|
3788
|
+
"manage_hyperlinks",
|
|
3789
|
+
{
|
|
3790
|
+
description: "List, set, or remove hyperlinks/actions on elements",
|
|
3791
|
+
inputSchema: ManageHyperlinksSchema.shape
|
|
3792
|
+
},
|
|
3793
|
+
async (params) => {
|
|
3794
|
+
const result = await runMcpTool(
|
|
3795
|
+
params.filePath,
|
|
3796
|
+
(ctx) => manageHyperlinks(ctx, params)
|
|
3797
|
+
);
|
|
3798
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3799
|
+
}
|
|
3800
|
+
);
|
|
3801
|
+
server2.registerTool(
|
|
3802
|
+
"replace_geometry",
|
|
3803
|
+
{
|
|
3804
|
+
description: "Replace a shape element geometry with a preset or custom SVG path",
|
|
3805
|
+
inputSchema: ReplaceGeometrySchema.shape
|
|
3806
|
+
},
|
|
3807
|
+
async (params) => {
|
|
3808
|
+
const result = await runMcpTool(
|
|
3809
|
+
params.filePath,
|
|
3810
|
+
(ctx) => replaceGeometry(ctx, {
|
|
3811
|
+
...params,
|
|
3812
|
+
adjustments: params.adjustments
|
|
3813
|
+
})
|
|
3814
|
+
);
|
|
3815
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3816
|
+
}
|
|
3817
|
+
);
|
|
3818
|
+
server2.registerTool(
|
|
3819
|
+
"set_element_lock",
|
|
3820
|
+
{
|
|
3821
|
+
description: "Lock or unlock an element (prevent move, resize, rotation, selection, text edit)",
|
|
3822
|
+
inputSchema: SetElementLockSchema.shape
|
|
3823
|
+
},
|
|
3824
|
+
async (params) => {
|
|
3825
|
+
const result = await runMcpTool(
|
|
3826
|
+
params.filePath,
|
|
3827
|
+
(ctx) => setElementLockT(ctx, params)
|
|
3828
|
+
);
|
|
3829
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3830
|
+
}
|
|
3831
|
+
);
|
|
3832
|
+
server2.registerTool(
|
|
3833
|
+
"validate_presentation",
|
|
3834
|
+
{
|
|
3835
|
+
description: "Validate PPTX structural integrity (content types, relationships, XML)",
|
|
3836
|
+
inputSchema: ValidatePresentationSchema.shape
|
|
3837
|
+
},
|
|
3838
|
+
async (params) => {
|
|
3839
|
+
const { readFile: readFile2 } = await import('fs/promises');
|
|
3840
|
+
const safePath = resolveScopedFilePath(params.filePath);
|
|
3841
|
+
const bytes = await readFile2(safePath);
|
|
3842
|
+
const result = await validatePresentation(bytes.buffer);
|
|
3843
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3844
|
+
}
|
|
3845
|
+
);
|
|
3846
|
+
server2.registerTool(
|
|
3847
|
+
"repair_presentation",
|
|
3848
|
+
{
|
|
3849
|
+
description: "Auto-repair common PPTX structural issues",
|
|
3850
|
+
inputSchema: RepairPresentationSchema.shape
|
|
3851
|
+
},
|
|
3852
|
+
async (params) => {
|
|
3853
|
+
const { readFile: readFile2, writeFile: writeFile2 } = await import('fs/promises');
|
|
3854
|
+
const safePath = resolveScopedFilePath(params.filePath);
|
|
3855
|
+
const bytes = await readFile2(safePath);
|
|
3856
|
+
const { result, repairedBytes } = await repairPresentation(
|
|
3857
|
+
bytes.buffer
|
|
3858
|
+
);
|
|
3859
|
+
if (result.repairCount > 0) {
|
|
3860
|
+
await writeFile2(safePath, new Uint8Array(repairedBytes));
|
|
3861
|
+
}
|
|
3862
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3863
|
+
}
|
|
3864
|
+
);
|
|
3865
|
+
server2.registerTool(
|
|
3866
|
+
"get_presentation_properties",
|
|
3867
|
+
{
|
|
3868
|
+
description: "Get slideshow properties (show type, loop, advance mode, slide range)",
|
|
3869
|
+
inputSchema: GetPresentationPropertiesSchema.shape
|
|
3870
|
+
},
|
|
3871
|
+
async (params) => {
|
|
3872
|
+
const result = await runMcpTool(
|
|
3873
|
+
params.filePath,
|
|
3874
|
+
(ctx) => getPresentationProperties(ctx)
|
|
3875
|
+
);
|
|
3876
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3877
|
+
}
|
|
3878
|
+
);
|
|
3879
|
+
server2.registerTool(
|
|
3880
|
+
"update_presentation_properties",
|
|
3881
|
+
{
|
|
3882
|
+
description: "Update slideshow properties (show type, loop, advance mode, pen color)",
|
|
3883
|
+
inputSchema: UpdatePresentationPropertiesSchema.shape
|
|
3884
|
+
},
|
|
3885
|
+
async (params) => {
|
|
3886
|
+
const result = await runMcpTool(
|
|
3887
|
+
params.filePath,
|
|
3888
|
+
(ctx) => updatePresentationProperties(ctx, params)
|
|
3889
|
+
);
|
|
3890
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3891
|
+
}
|
|
3892
|
+
);
|
|
3893
|
+
server2.registerTool(
|
|
3894
|
+
"get_layouts",
|
|
3895
|
+
{
|
|
3896
|
+
description: "List available slide layouts from the presentation masters",
|
|
3897
|
+
inputSchema: GetLayoutsSchema.shape
|
|
3898
|
+
},
|
|
3899
|
+
async (params) => {
|
|
3900
|
+
const result = await runMcpTool(params.filePath, (ctx) => getLayouts(ctx));
|
|
3901
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3902
|
+
}
|
|
3903
|
+
);
|
|
3904
|
+
server2.registerTool(
|
|
3905
|
+
"apply_layout",
|
|
3906
|
+
{
|
|
3907
|
+
description: "Apply a slide layout to a specific slide",
|
|
3908
|
+
inputSchema: ApplyLayoutSchema.shape
|
|
3909
|
+
},
|
|
3910
|
+
async (params) => {
|
|
3911
|
+
const result = await runMcpTool(
|
|
3912
|
+
params.filePath,
|
|
3913
|
+
(ctx) => applyLayout(ctx, params)
|
|
3914
|
+
);
|
|
3915
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3916
|
+
}
|
|
3917
|
+
);
|
|
2403
3918
|
return server2;
|
|
2404
3919
|
}
|
|
2405
3920
|
|