pptx-viewer-mcp 2.5.8 → 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 +16 -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/mcp/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
'use strict';
|
|
3
2
|
|
|
4
|
-
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
5
3
|
var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
6
4
|
var zod = require('zod');
|
|
7
|
-
var
|
|
5
|
+
var automation = require('ooxml-core/pptx/automation');
|
|
8
6
|
var promises = require('fs/promises');
|
|
9
7
|
var path = require('path');
|
|
10
8
|
|
|
9
|
+
// src/mcp/server.ts
|
|
11
10
|
var GetSlideSchema = zod.z.object({
|
|
12
11
|
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
13
12
|
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index")
|
|
@@ -932,3162 +931,86 @@ var SetOleObjectNameSchema = zod.z.object({
|
|
|
932
931
|
elementId: zod.z.string().describe("OLE element ID"),
|
|
933
932
|
name: zod.z.string().describe("New Object Name (p:oleObj/@name); blank/whitespace clears it")
|
|
934
933
|
});
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
}
|
|
1016
|
-
base.hasImageData = Boolean(img.imageData);
|
|
1017
|
-
}
|
|
1018
|
-
if (el.type === "table") {
|
|
1019
|
-
const tbl = el;
|
|
1020
|
-
if (tbl.tableData) {
|
|
1021
|
-
base.rowCount = tbl.tableData.rows.length;
|
|
1022
|
-
base.columnCount = tbl.tableData.columnWidths.length;
|
|
1023
|
-
base.cells = tbl.tableData.rows.map((row) => row.cells.map((cell) => cell.text ?? ""));
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
if (el.type === "chart" && el.chartData) {
|
|
1027
|
-
base.chartType = pptxViewerCore.resolveDisplayedChartTypeName(el.chartData);
|
|
1028
|
-
}
|
|
1029
|
-
if (el.type === "group") {
|
|
1030
|
-
const grp = el;
|
|
1031
|
-
base.childCount = grp.children?.length ?? 0;
|
|
1032
|
-
}
|
|
1033
|
-
return base;
|
|
1034
|
-
}
|
|
1035
|
-
function validateSlideIndex(slideIndex, slideCount) {
|
|
1036
|
-
if (slideIndex < 0 || slideIndex >= slideCount) {
|
|
1037
|
-
return `Slide index ${slideIndex} out of range (0\u2013${slideCount - 1}).`;
|
|
1038
|
-
}
|
|
1039
|
-
return null;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
// src/tools/chart-formatting-tools.ts
|
|
1043
|
-
function findChartElement(ctx, slideIndex, elementId) {
|
|
1044
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
1045
|
-
if (err) {
|
|
1046
|
-
throw new Error(err);
|
|
1047
|
-
}
|
|
1048
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
1049
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
1050
|
-
if (!el) {
|
|
1051
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
1052
|
-
}
|
|
1053
|
-
if (el.type !== "chart") {
|
|
1054
|
-
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
1055
|
-
}
|
|
1056
|
-
return el;
|
|
1057
|
-
}
|
|
1058
|
-
function formatChartDataPoint(ctx, params) {
|
|
1059
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1060
|
-
if (params.clearStyle) {
|
|
1061
|
-
pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, null);
|
|
1062
|
-
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0 || params.strokeDashStyle !== void 0) {
|
|
1063
|
-
pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, {
|
|
1064
|
-
...params.fillColor !== void 0 ? { fillColor: params.fillColor } : {},
|
|
1065
|
-
...params.strokeColor !== void 0 ? { strokeColor: params.strokeColor } : {},
|
|
1066
|
-
...params.strokeWidth !== void 0 ? { strokeWidth: params.strokeWidth } : {},
|
|
1067
|
-
...params.strokeDashStyle !== void 0 ? { strokeDashStyle: params.strokeDashStyle } : {}
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
if (params.explosion !== void 0) {
|
|
1071
|
-
pptxViewerCore.setChartDataPointExplosion(chart, params.seriesIndex, params.pointIndex, params.explosion);
|
|
1072
|
-
}
|
|
1073
|
-
if (params.marker !== void 0) {
|
|
1074
|
-
pptxViewerCore.setChartDataPointMarker(chart, params.seriesIndex, params.pointIndex, params.marker);
|
|
1075
|
-
}
|
|
1076
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1077
|
-
}
|
|
1078
|
-
function formatChartDataLabel(ctx, params) {
|
|
1079
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1080
|
-
if (params.remove) {
|
|
1081
|
-
pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, null);
|
|
1082
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1083
|
-
}
|
|
1084
|
-
pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, {
|
|
1085
|
-
...params.showValue !== void 0 ? { showValue: params.showValue } : {},
|
|
1086
|
-
...params.showCategory !== void 0 ? { showCategory: params.showCategory } : {},
|
|
1087
|
-
...params.showSeriesName !== void 0 ? { showSeriesName: params.showSeriesName } : {},
|
|
1088
|
-
...params.showPercent !== void 0 ? { showPercent: params.showPercent } : {},
|
|
1089
|
-
...params.showLegendKey !== void 0 ? { showLegendKey: params.showLegendKey } : {},
|
|
1090
|
-
...params.position !== void 0 ? { position: params.position } : {},
|
|
1091
|
-
...params.text !== void 0 ? { text: params.text } : {},
|
|
1092
|
-
...params.spPr !== void 0 ? { spPr: params.spPr } : {},
|
|
1093
|
-
...params.txPr !== void 0 ? { txPr: params.txPr } : {}
|
|
1094
|
-
});
|
|
1095
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1096
|
-
}
|
|
1097
|
-
function formatChartSeries(ctx, params) {
|
|
1098
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1099
|
-
if (params.marker !== void 0) {
|
|
1100
|
-
if (params.marker === null) {
|
|
1101
|
-
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, null);
|
|
1102
|
-
} else if (params.marker.strokeColor !== void 0 || params.marker.strokeWidth !== void 0 || params.marker.strokeDashStyle !== void 0) {
|
|
1103
|
-
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, {
|
|
1104
|
-
symbol: params.marker.symbol ?? "circle",
|
|
1105
|
-
...params.marker.size !== void 0 ? { size: params.marker.size } : {},
|
|
1106
|
-
spPr: {
|
|
1107
|
-
...params.marker.fillColor !== void 0 ? { fillColor: params.marker.fillColor } : {},
|
|
1108
|
-
...params.marker.strokeColor !== void 0 ? { strokeColor: params.marker.strokeColor } : {},
|
|
1109
|
-
...params.marker.strokeWidth !== void 0 ? { strokeWidth: params.marker.strokeWidth } : {},
|
|
1110
|
-
...params.marker.strokeDashStyle !== void 0 ? { strokeDashStyle: params.marker.strokeDashStyle } : {}
|
|
1111
|
-
}
|
|
1112
|
-
});
|
|
1113
|
-
} else {
|
|
1114
|
-
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, params.marker);
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
if (params.trendline !== void 0) {
|
|
1118
|
-
pptxViewerCore.setChartSeriesTrendline(chart, params.seriesIndex, params.trendline);
|
|
1119
|
-
}
|
|
1120
|
-
if (params.errorBars !== void 0) {
|
|
1121
|
-
pptxViewerCore.setChartSeriesErrorBars(chart, params.seriesIndex, params.errorBars);
|
|
1122
|
-
}
|
|
1123
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1124
|
-
}
|
|
1125
|
-
function setChartHelperLineT(ctx, params) {
|
|
1126
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1127
|
-
pptxViewerCore.setChartHelperLine(chart, params.line, params.style);
|
|
1128
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1129
|
-
}
|
|
1130
|
-
function setChartColorMapOverrideT(ctx, params) {
|
|
1131
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1132
|
-
pptxViewerCore.setChartColorMapOverride(chart, params.overrides);
|
|
1133
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
// src/tools/chart-pareto.ts
|
|
1137
|
-
function cumulativePercent(values) {
|
|
1138
|
-
const total = values.reduce((sum, value) => sum + value, 0);
|
|
1139
|
-
if (total === 0) {
|
|
1140
|
-
return values.map(() => 0);
|
|
1141
|
-
}
|
|
1142
|
-
let running = 0;
|
|
1143
|
-
return values.map((value) => {
|
|
1144
|
-
running += value;
|
|
1145
|
-
return Math.round(running / total * 1e4) / 100;
|
|
1146
|
-
});
|
|
1147
|
-
}
|
|
1148
|
-
function applyParetoChartTypeAlias(chart, requestedType) {
|
|
1149
|
-
if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
|
|
1150
|
-
return;
|
|
1151
|
-
}
|
|
1152
|
-
const data = chart.chartData;
|
|
1153
|
-
data.chartType = "histogram";
|
|
1154
|
-
const [frequency] = data.series;
|
|
1155
|
-
if (!frequency) {
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
|
|
1159
|
-
const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
|
|
1160
|
-
if (!hasParetoLine) {
|
|
1161
|
-
data.series.push({
|
|
1162
|
-
name: "Cumulative %",
|
|
1163
|
-
values: cumulativePercent(frequency.values),
|
|
1164
|
-
histogramOptions: { layout: "pareto" }
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
// src/tools/chart-tools.ts
|
|
1170
|
-
function updateChart(ctx, params) {
|
|
1171
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1172
|
-
if (err) {
|
|
1173
|
-
throw new Error(err);
|
|
1174
|
-
}
|
|
1175
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1176
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1177
|
-
if (!el) {
|
|
1178
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1179
|
-
}
|
|
1180
|
-
if (el.type !== "chart") {
|
|
1181
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1182
|
-
}
|
|
1183
|
-
const chart = el;
|
|
1184
|
-
if (params.chartType) {
|
|
1185
|
-
pptxViewerCore.setChartType(chart, params.chartType);
|
|
1186
|
-
applyParetoChartTypeAlias(chart, params.chartType);
|
|
1187
|
-
}
|
|
1188
|
-
if (params.title !== void 0) {
|
|
1189
|
-
pptxViewerCore.setChartTitle(chart, params.title);
|
|
1190
|
-
}
|
|
1191
|
-
if (params.grouping) {
|
|
1192
|
-
pptxViewerCore.setChartGrouping(chart, params.grouping);
|
|
1193
|
-
}
|
|
1194
|
-
if (params.legend) {
|
|
1195
|
-
pptxViewerCore.setChartLegend(chart, {
|
|
1196
|
-
show: params.legend.show,
|
|
1197
|
-
position: params.legend.position
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1200
|
-
if (params.dataLabels) {
|
|
1201
|
-
pptxViewerCore.setChartDataLabels(chart, params.dataLabels);
|
|
1202
|
-
}
|
|
1203
|
-
if (params.axis) {
|
|
1204
|
-
pptxViewerCore.setChartAxis(chart, params.axis.type, params.axis.edit);
|
|
1205
|
-
}
|
|
1206
|
-
if (params.categories) {
|
|
1207
|
-
pptxViewerCore.setChartCategories(chart, params.categories);
|
|
1208
|
-
}
|
|
1209
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1210
|
-
}
|
|
1211
|
-
function addChartSeriesT(ctx, params) {
|
|
1212
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1213
|
-
if (err) {
|
|
1214
|
-
throw new Error(err);
|
|
1215
|
-
}
|
|
1216
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1217
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1218
|
-
if (!el) {
|
|
1219
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1220
|
-
}
|
|
1221
|
-
if (el.type !== "chart") {
|
|
1222
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1223
|
-
}
|
|
1224
|
-
const chart = el;
|
|
1225
|
-
pptxViewerCore.addChartSeries(chart, { name: params.name, values: params.values, color: params.color });
|
|
1226
|
-
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
1227
|
-
return {
|
|
1228
|
-
pptxData: ctx.pptxData,
|
|
1229
|
-
dirty: true,
|
|
1230
|
-
result: { elementId: params.elementId, seriesCount }
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
function removeChartSeriesT(ctx, params) {
|
|
1234
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1235
|
-
if (err) {
|
|
1236
|
-
throw new Error(err);
|
|
1237
|
-
}
|
|
1238
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1239
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1240
|
-
if (!el) {
|
|
1241
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1242
|
-
}
|
|
1243
|
-
if (el.type !== "chart") {
|
|
1244
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1245
|
-
}
|
|
1246
|
-
const chart = el;
|
|
1247
|
-
pptxViewerCore.removeChartSeries(chart, params.seriesIndex);
|
|
1248
|
-
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
1249
|
-
return {
|
|
1250
|
-
pptxData: ctx.pptxData,
|
|
1251
|
-
dirty: true,
|
|
1252
|
-
result: { elementId: params.elementId, seriesCount }
|
|
1253
|
-
};
|
|
1254
|
-
}
|
|
1255
|
-
function updateChartSeriesData(ctx, params) {
|
|
1256
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1257
|
-
if (err) {
|
|
1258
|
-
throw new Error(err);
|
|
1259
|
-
}
|
|
1260
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1261
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1262
|
-
if (!el) {
|
|
1263
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1264
|
-
}
|
|
1265
|
-
if (el.type !== "chart") {
|
|
1266
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1267
|
-
}
|
|
1268
|
-
const chart = el;
|
|
1269
|
-
pptxViewerCore.updateChartSeriesValues(chart, params.seriesIndex, params.values);
|
|
1270
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1271
|
-
}
|
|
1272
|
-
function createChart(ctx, params) {
|
|
1273
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1274
|
-
if (err) {
|
|
1275
|
-
throw new Error(err);
|
|
1276
|
-
}
|
|
1277
|
-
const builder = pptxViewerCore.ChartBuilder.create(
|
|
1278
|
-
params.chartType
|
|
1279
|
-
);
|
|
1280
|
-
builder.position(params.x ?? 100, params.y ?? 100);
|
|
1281
|
-
builder.size(params.width ?? 500, params.height ?? 350);
|
|
1282
|
-
if (params.title) {
|
|
1283
|
-
builder.title(params.title);
|
|
1284
|
-
}
|
|
1285
|
-
if (params.categories) {
|
|
1286
|
-
builder.categories(params.categories);
|
|
1287
|
-
}
|
|
1288
|
-
if (params.series) {
|
|
1289
|
-
for (const s of params.series) {
|
|
1290
|
-
builder.addSeries(s.name, s.values, s.color);
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
if (params.legend) {
|
|
1294
|
-
builder.legend(
|
|
1295
|
-
params.legend.show,
|
|
1296
|
-
params.legend.position
|
|
1297
|
-
);
|
|
1298
|
-
}
|
|
1299
|
-
const chart = builder.build();
|
|
1300
|
-
applyParetoChartTypeAlias(chart, params.chartType);
|
|
1301
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1302
|
-
slide.elements.push(chart);
|
|
1303
|
-
return {
|
|
1304
|
-
pptxData: ctx.pptxData,
|
|
1305
|
-
dirty: true,
|
|
1306
|
-
result: { elementId: chart.id, slideIndex: params.slideIndex }
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
function findChartElement2(ctx, slideIndex, elementId) {
|
|
1310
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
1311
|
-
if (err) {
|
|
1312
|
-
throw new Error(err);
|
|
1313
|
-
}
|
|
1314
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
1315
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
1316
|
-
if (!el) {
|
|
1317
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
1318
|
-
}
|
|
1319
|
-
if (el.type !== "chart") {
|
|
1320
|
-
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
1321
|
-
}
|
|
1322
|
-
return el;
|
|
1323
|
-
}
|
|
1324
|
-
function buildShape(input) {
|
|
1325
|
-
return {
|
|
1326
|
-
kind: input.kind ?? "sp",
|
|
1327
|
-
anchor: input.anchor ?? "rel",
|
|
1328
|
-
from: input.from,
|
|
1329
|
-
...input.to ? { to: input.to } : {},
|
|
1330
|
-
...input.ext ? { ext: input.ext } : {},
|
|
1331
|
-
...input.prst ? { prst: input.prst } : {},
|
|
1332
|
-
...input.fill ? { fill: input.fill } : {},
|
|
1333
|
-
...input.stroke ? { stroke: input.stroke } : {},
|
|
1334
|
-
...input.strokeWidth !== void 0 ? { strokeWidth: input.strokeWidth } : {},
|
|
1335
|
-
...input.text ? { paragraphs: [{ text: input.text, align: "ctr" }] } : {}
|
|
1336
|
-
};
|
|
1337
|
-
}
|
|
1338
|
-
function listChartUserShapesT(ctx, params) {
|
|
1339
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1340
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { shapes: pptxViewerCore.listChartUserShapes(chart) } };
|
|
1341
|
-
}
|
|
1342
|
-
function addChartUserShapeT(ctx, params) {
|
|
1343
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1344
|
-
pptxViewerCore.addChartUserShape(chart, buildShape(params.shape));
|
|
1345
|
-
const index = (chart.chartData?.userShapes?.length ?? 1) - 1;
|
|
1346
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId, index } };
|
|
1347
|
-
}
|
|
1348
|
-
function updateChartUserShapeT(ctx, params) {
|
|
1349
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1350
|
-
const patch = {
|
|
1351
|
-
...params.patch.kind ? { kind: params.patch.kind } : {},
|
|
1352
|
-
...params.patch.anchor ? { anchor: params.patch.anchor } : {},
|
|
1353
|
-
...params.patch.from ? { from: params.patch.from } : {},
|
|
1354
|
-
...params.patch.to ? { to: params.patch.to } : {},
|
|
1355
|
-
...params.patch.ext ? { ext: params.patch.ext } : {},
|
|
1356
|
-
...params.patch.prst ? { prst: params.patch.prst } : {},
|
|
1357
|
-
...params.patch.fill ? { fill: params.patch.fill } : {},
|
|
1358
|
-
...params.patch.stroke ? { stroke: params.patch.stroke } : {},
|
|
1359
|
-
...params.patch.strokeWidth !== void 0 ? { strokeWidth: params.patch.strokeWidth } : {},
|
|
1360
|
-
...params.patch.text !== void 0 ? { paragraphs: [{ text: params.patch.text, align: "ctr" }] } : {}
|
|
1361
|
-
};
|
|
1362
|
-
pptxViewerCore.updateChartUserShape(chart, params.index, patch);
|
|
1363
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1364
|
-
}
|
|
1365
|
-
function removeChartUserShapeT(ctx, params) {
|
|
1366
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1367
|
-
pptxViewerCore.removeChartUserShape(chart, params.index);
|
|
1368
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
// src/tools/text-editing.ts
|
|
1372
|
-
function editRange(segments, start, end, replacement) {
|
|
1373
|
-
let offset = 0;
|
|
1374
|
-
let inserted = false;
|
|
1375
|
-
for (const segment of segments) {
|
|
1376
|
-
const text = segment.text;
|
|
1377
|
-
const next = offset + text.length;
|
|
1378
|
-
if (!segment.bulletInfo?.ownedByParagraph && next > start && offset < end) {
|
|
1379
|
-
const from = Math.max(0, start - offset);
|
|
1380
|
-
const to = Math.min(text.length, end - offset);
|
|
1381
|
-
segment.text = text.slice(0, from) + (inserted ? "" : replacement) + text.slice(to);
|
|
1382
|
-
inserted = true;
|
|
1383
|
-
} else if (!inserted && start === end && offset <= start && next >= start && !segment.bulletInfo?.ownedByParagraph) {
|
|
1384
|
-
const at = start - offset;
|
|
1385
|
-
segment.text = text.slice(0, at) + replacement + text.slice(at);
|
|
1386
|
-
inserted = true;
|
|
1387
|
-
}
|
|
1388
|
-
offset = next;
|
|
1389
|
-
}
|
|
1390
|
-
if (!inserted && replacement) {
|
|
1391
|
-
segments.push({ text: replacement, style: {} });
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
function changedRange(before, text) {
|
|
1395
|
-
let start = 0;
|
|
1396
|
-
while (start < before.length && start < text.length && before[start] === text[start]) {
|
|
1397
|
-
start++;
|
|
1398
|
-
}
|
|
1399
|
-
let suffix = 0;
|
|
1400
|
-
while (suffix < before.length - start && suffix < text.length - start && before[before.length - suffix - 1] === text[text.length - suffix - 1]) {
|
|
1401
|
-
suffix++;
|
|
1402
|
-
}
|
|
1403
|
-
return {
|
|
1404
|
-
start,
|
|
1405
|
-
end: before.length - suffix,
|
|
1406
|
-
replacement: text.slice(start, text.length - suffix)
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
function setElementText(element, text) {
|
|
1410
|
-
const segments = element.textSegments;
|
|
1411
|
-
if (segments?.length) {
|
|
1412
|
-
const before = segments.map((segment) => segment.text).join("");
|
|
1413
|
-
const oldLines = before.split("\n");
|
|
1414
|
-
const newLines = text.split("\n");
|
|
1415
|
-
if (oldLines.length === newLines.length) {
|
|
1416
|
-
let offset = before.length;
|
|
1417
|
-
for (let index = oldLines.length - 1; index >= 0; index--) {
|
|
1418
|
-
const line = oldLines[index];
|
|
1419
|
-
offset -= line.length;
|
|
1420
|
-
const edit = changedRange(line, newLines[index]);
|
|
1421
|
-
editRange(segments, offset + edit.start, offset + edit.end, edit.replacement);
|
|
1422
|
-
offset--;
|
|
1423
|
-
}
|
|
1424
|
-
} else {
|
|
1425
|
-
const edit = changedRange(before, text);
|
|
1426
|
-
editRange(segments, edit.start, edit.end, edit.replacement);
|
|
1427
|
-
}
|
|
1428
|
-
element.text = segments.map((segment) => segment.text).join("");
|
|
1429
|
-
} else {
|
|
1430
|
-
element.text = text;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
function replaceElementText(element, regex, replacement) {
|
|
1434
|
-
const before = element.text ?? element.textSegments?.map((segment) => segment.text).join("") ?? "";
|
|
1435
|
-
const matches = Array.from(before.matchAll(regex));
|
|
1436
|
-
if (before.replace(regex, replacement) === before) {
|
|
1437
|
-
return 0;
|
|
1438
|
-
}
|
|
1439
|
-
if (!element.textSegments?.length) {
|
|
1440
|
-
element.text = before.replace(regex, replacement);
|
|
1441
|
-
return matches.length;
|
|
1442
|
-
}
|
|
1443
|
-
for (const match of matches.reverse()) {
|
|
1444
|
-
const start = match.index;
|
|
1445
|
-
const end = start + match[0].length;
|
|
1446
|
-
const single = new RegExp(regex.source, `${regex.flags.replace("g", "")}y`);
|
|
1447
|
-
single.lastIndex = start;
|
|
1448
|
-
const after = before.replace(single, replacement);
|
|
1449
|
-
editRange(
|
|
1450
|
-
element.textSegments,
|
|
1451
|
-
start,
|
|
1452
|
-
end,
|
|
1453
|
-
after.slice(start, after.length - (before.length - end))
|
|
1454
|
-
);
|
|
1455
|
-
}
|
|
1456
|
-
element.text = element.textSegments.map((segment) => segment.text).join("");
|
|
1457
|
-
return matches.length;
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
// src/tools/content-tools.ts
|
|
1461
|
-
var MAX_REGEX_LEN = 200;
|
|
1462
|
-
function hasNestedUnboundedQuantifier(pattern) {
|
|
1463
|
-
return /\([^)]*[+*]\)[+*]/u.test(pattern);
|
|
1464
|
-
}
|
|
1465
|
-
function buildSearchRegex(query, useRegex, caseSensitive) {
|
|
1466
|
-
if (useRegex) {
|
|
1467
|
-
if (query.length > MAX_REGEX_LEN) {
|
|
1468
|
-
return null;
|
|
1469
|
-
}
|
|
1470
|
-
if (hasNestedUnboundedQuantifier(query)) {
|
|
1471
|
-
return null;
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
const pattern = useRegex ? query : query.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
1475
|
-
const flags = caseSensitive ? "g" : "gi";
|
|
1476
|
-
try {
|
|
1477
|
-
return new RegExp(pattern, flags);
|
|
1478
|
-
} catch {
|
|
1479
|
-
return null;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
function findText(ctx, params) {
|
|
1483
|
-
const regex = buildSearchRegex(
|
|
1484
|
-
params.query,
|
|
1485
|
-
params.useRegex === true,
|
|
1486
|
-
params.caseSensitive === true
|
|
1487
|
-
);
|
|
1488
|
-
if (!regex) {
|
|
1489
|
-
return {
|
|
1490
|
-
pptxData: ctx.pptxData,
|
|
1491
|
-
dirty: false,
|
|
1492
|
-
result: { query: params.query, matchCount: 0, matches: [] }
|
|
1493
|
-
};
|
|
1494
|
-
}
|
|
1495
|
-
const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
|
|
1496
|
-
const matches = [];
|
|
1497
|
-
for (const si of targetIndexes) {
|
|
1498
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
1499
|
-
if (err) {
|
|
1500
|
-
throw new Error(err);
|
|
1501
|
-
}
|
|
1502
|
-
const slide = ctx.pptxData.slides[si];
|
|
1503
|
-
for (const el of slide.elements) {
|
|
1504
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
1505
|
-
const textEl = el;
|
|
1506
|
-
if (textEl.text) {
|
|
1507
|
-
const localMatches = Array.from(textEl.text.matchAll(regex));
|
|
1508
|
-
for (const m of localMatches) {
|
|
1509
|
-
matches.push({
|
|
1510
|
-
slideIndex: si,
|
|
1511
|
-
elementId: el.id,
|
|
1512
|
-
elementType: el.type,
|
|
1513
|
-
matchedText: m[0],
|
|
1514
|
-
context: textEl.text.slice(
|
|
1515
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1516
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1517
|
-
)
|
|
1518
|
-
});
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
if (el.type === "table") {
|
|
1523
|
-
const tbl = el;
|
|
1524
|
-
if (tbl.tableData) {
|
|
1525
|
-
for (const row of tbl.tableData.rows) {
|
|
1526
|
-
for (const cell of row.cells) {
|
|
1527
|
-
if (cell.text) {
|
|
1528
|
-
const localMatches = Array.from(cell.text.matchAll(regex));
|
|
1529
|
-
for (const m of localMatches) {
|
|
1530
|
-
matches.push({
|
|
1531
|
-
slideIndex: si,
|
|
1532
|
-
elementId: el.id,
|
|
1533
|
-
elementType: "table-cell",
|
|
1534
|
-
matchedText: m[0],
|
|
1535
|
-
context: cell.text.slice(
|
|
1536
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1537
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1538
|
-
)
|
|
1539
|
-
});
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
if (slide.notes) {
|
|
1548
|
-
const noteMatches = Array.from(slide.notes.matchAll(regex));
|
|
1549
|
-
for (const m of noteMatches) {
|
|
1550
|
-
matches.push({
|
|
1551
|
-
slideIndex: si,
|
|
1552
|
-
elementId: "notes",
|
|
1553
|
-
elementType: "notes",
|
|
1554
|
-
matchedText: m[0],
|
|
1555
|
-
context: slide.notes.slice(
|
|
1556
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1557
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1558
|
-
)
|
|
1559
|
-
});
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
return {
|
|
1564
|
-
pptxData: ctx.pptxData,
|
|
1565
|
-
dirty: false,
|
|
1566
|
-
result: {
|
|
1567
|
-
query: params.query,
|
|
1568
|
-
matchCount: matches.length,
|
|
1569
|
-
matches
|
|
1570
|
-
}
|
|
1571
|
-
};
|
|
1572
|
-
}
|
|
1573
|
-
function replaceText(ctx, params) {
|
|
1574
|
-
const regex = buildSearchRegex(
|
|
1575
|
-
params.query,
|
|
1576
|
-
params.useRegex === true,
|
|
1577
|
-
params.caseSensitive === true
|
|
1578
|
-
);
|
|
1579
|
-
if (!regex) {
|
|
1580
|
-
return {
|
|
1581
|
-
pptxData: ctx.pptxData,
|
|
1582
|
-
dirty: false,
|
|
1583
|
-
result: { query: params.query, replacement: params.replacement, replacementCount: 0 }
|
|
1584
|
-
};
|
|
1585
|
-
}
|
|
1586
|
-
const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
|
|
1587
|
-
let count = 0;
|
|
1588
|
-
for (const si of targetIndexes) {
|
|
1589
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
1590
|
-
if (err) {
|
|
1591
|
-
throw new Error(err);
|
|
1592
|
-
}
|
|
1593
|
-
const slide = ctx.pptxData.slides[si];
|
|
1594
|
-
for (const el of slide.elements) {
|
|
1595
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
1596
|
-
const textEl = el;
|
|
1597
|
-
if (textEl.text) {
|
|
1598
|
-
const before = textEl.text;
|
|
1599
|
-
const after = before.replace(regex, params.replacement);
|
|
1600
|
-
if (after !== before) {
|
|
1601
|
-
const matchCount = Array.from(before.matchAll(regex)).length;
|
|
1602
|
-
count += matchCount;
|
|
1603
|
-
replaceElementText(textEl, regex, params.replacement);
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
if (el.type === "table") {
|
|
1608
|
-
const tbl = el;
|
|
1609
|
-
if (tbl.tableData) {
|
|
1610
|
-
for (const row of tbl.tableData.rows) {
|
|
1611
|
-
for (const cell of row.cells) {
|
|
1612
|
-
if (cell.text) {
|
|
1613
|
-
const before = cell.text;
|
|
1614
|
-
const after = before.replace(regex, params.replacement);
|
|
1615
|
-
if (after !== before) {
|
|
1616
|
-
count += Array.from(before.matchAll(regex)).length;
|
|
1617
|
-
cell.text = after;
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
if (slide.notes) {
|
|
1626
|
-
const before = slide.notes;
|
|
1627
|
-
const after = before.replace(regex, params.replacement);
|
|
1628
|
-
if (after !== before) {
|
|
1629
|
-
count += Array.from(before.matchAll(regex)).length;
|
|
1630
|
-
slide.notes = after;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
return {
|
|
1635
|
-
pptxData: ctx.pptxData,
|
|
1636
|
-
dirty: count > 0,
|
|
1637
|
-
result: {
|
|
1638
|
-
query: params.query,
|
|
1639
|
-
replacement: params.replacement,
|
|
1640
|
-
replacementCount: count
|
|
1641
|
-
}
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
function manageComments(ctx, params) {
|
|
1645
|
-
switch (params.action) {
|
|
1646
|
-
case "list": {
|
|
1647
|
-
const all = [];
|
|
1648
|
-
for (let si = 0; si < ctx.pptxData.slides.length; si++) {
|
|
1649
|
-
if (params.slideIndex !== void 0 && si !== params.slideIndex) {
|
|
1650
|
-
continue;
|
|
1651
|
-
}
|
|
1652
|
-
const slide = ctx.pptxData.slides[si];
|
|
1653
|
-
for (const c of slide.comments ?? []) {
|
|
1654
|
-
if (!params.includeResolved && c.resolved) {
|
|
1655
|
-
continue;
|
|
1656
|
-
}
|
|
1657
|
-
all.push({
|
|
1658
|
-
id: c.id,
|
|
1659
|
-
slideIndex: si,
|
|
1660
|
-
text: c.text,
|
|
1661
|
-
author: c.author,
|
|
1662
|
-
createdAt: c.createdAt,
|
|
1663
|
-
resolved: c.resolved
|
|
1664
|
-
});
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
return {
|
|
1668
|
-
pptxData: ctx.pptxData,
|
|
1669
|
-
dirty: false,
|
|
1670
|
-
result: { action: "list", comments: all, count: all.length }
|
|
1671
|
-
};
|
|
1672
|
-
}
|
|
1673
|
-
case "add": {
|
|
1674
|
-
if (params.slideIndex === void 0) {
|
|
1675
|
-
throw new Error("slideIndex is required for add action.");
|
|
1676
|
-
}
|
|
1677
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1678
|
-
if (err) {
|
|
1679
|
-
throw new Error(err);
|
|
1680
|
-
}
|
|
1681
|
-
if (!params.text) {
|
|
1682
|
-
throw new Error("text is required for add action.");
|
|
1683
|
-
}
|
|
1684
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1685
|
-
if (!slide.comments) {
|
|
1686
|
-
slide.comments = [];
|
|
1687
|
-
}
|
|
1688
|
-
const newId = `comment-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1689
|
-
slide.comments.push({
|
|
1690
|
-
id: newId,
|
|
1691
|
-
text: params.text,
|
|
1692
|
-
author: params.author,
|
|
1693
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1694
|
-
resolved: false
|
|
1695
|
-
});
|
|
1696
|
-
return {
|
|
1697
|
-
pptxData: ctx.pptxData,
|
|
1698
|
-
dirty: true,
|
|
1699
|
-
result: { action: "add", commentId: newId }
|
|
1700
|
-
};
|
|
1701
|
-
}
|
|
1702
|
-
case "delete": {
|
|
1703
|
-
if (!params.commentId) {
|
|
1704
|
-
throw new Error("commentId is required for delete action.");
|
|
1705
|
-
}
|
|
1706
|
-
let deleted = false;
|
|
1707
|
-
for (const slide of ctx.pptxData.slides) {
|
|
1708
|
-
if (!slide.comments) {
|
|
1709
|
-
continue;
|
|
1710
|
-
}
|
|
1711
|
-
const before = slide.comments.length;
|
|
1712
|
-
slide.comments = slide.comments.filter((c) => c.id !== params.commentId);
|
|
1713
|
-
if (slide.comments.length < before) {
|
|
1714
|
-
deleted = true;
|
|
1715
|
-
break;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
if (!deleted) {
|
|
1719
|
-
throw new Error(`Comment '${params.commentId}' not found.`);
|
|
1720
|
-
}
|
|
1721
|
-
return {
|
|
1722
|
-
pptxData: ctx.pptxData,
|
|
1723
|
-
dirty: true,
|
|
1724
|
-
result: { action: "delete", commentId: params.commentId }
|
|
1725
|
-
};
|
|
1726
|
-
}
|
|
1727
|
-
case "resolve": {
|
|
1728
|
-
if (!params.commentId) {
|
|
1729
|
-
throw new Error("commentId is required for resolve action.");
|
|
1730
|
-
}
|
|
1731
|
-
let found = false;
|
|
1732
|
-
for (const slide of ctx.pptxData.slides) {
|
|
1733
|
-
const comment = slide.comments?.find((c) => c.id === params.commentId);
|
|
1734
|
-
if (comment) {
|
|
1735
|
-
comment.resolved = params.resolved !== false;
|
|
1736
|
-
found = true;
|
|
1737
|
-
break;
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
if (!found) {
|
|
1741
|
-
throw new Error(`Comment '${params.commentId}' not found.`);
|
|
1742
|
-
}
|
|
1743
|
-
return {
|
|
1744
|
-
pptxData: ctx.pptxData,
|
|
1745
|
-
dirty: true,
|
|
1746
|
-
result: { action: "resolve", commentId: params.commentId }
|
|
1747
|
-
};
|
|
1748
|
-
}
|
|
1749
|
-
default: {
|
|
1750
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
async function convertToMarkdown(ctx, params) {
|
|
1755
|
-
const options = {
|
|
1756
|
-
mediaFolderName: params.mediaFolderName ?? "media",
|
|
1757
|
-
includeMetadata: params.includeMetadata !== false,
|
|
1758
|
-
slideRange: params.slideRange,
|
|
1759
|
-
includeSpeakerNotes: params.includeSpeakerNotes !== false,
|
|
1760
|
-
semanticMode: params.semanticMode === true,
|
|
1761
|
-
sourceName: params.sourceName ?? "unknown"
|
|
1762
|
-
};
|
|
1763
|
-
const outputDir = params.outputDir ?? ".";
|
|
1764
|
-
const safeOutputDir = params.scopeOutputDir ? params.scopeOutputDir(outputDir, params.rootDir) : outputDir;
|
|
1765
|
-
const converter = new pptxViewerCore.PptxMarkdownConverter(safeOutputDir, options);
|
|
1766
|
-
const markdown = await converter.convert(ctx.pptxData);
|
|
1767
|
-
return {
|
|
1768
|
-
pptxData: ctx.pptxData,
|
|
1769
|
-
dirty: false,
|
|
1770
|
-
result: {
|
|
1771
|
-
markdown,
|
|
1772
|
-
slidesConverted: converter.slidesConverted,
|
|
1773
|
-
totalSlides: converter.presentationSlides,
|
|
1774
|
-
imagesExtracted: converter.imagesExtracted
|
|
1775
|
-
}
|
|
1776
|
-
};
|
|
1777
|
-
}
|
|
1778
|
-
var ALT_TEXT_ELEMENT_TYPES = /* @__PURE__ */ new Set(["image", "picture", "table", "chart", "smartArt", "ole", "media", "text", "shape", "connector"]);
|
|
1779
|
-
var TITLE_ELEMENT_TYPES = /* @__PURE__ */ new Set([
|
|
1780
|
-
"table",
|
|
1781
|
-
"chart",
|
|
1782
|
-
"smartArt",
|
|
1783
|
-
"ole",
|
|
1784
|
-
"media",
|
|
1785
|
-
"text",
|
|
1786
|
-
"shape",
|
|
1787
|
-
"connector"
|
|
1788
|
-
]);
|
|
1789
|
-
function applyElementAltText(el, altText) {
|
|
1790
|
-
if (!ALT_TEXT_ELEMENT_TYPES.has(el.type)) {
|
|
1791
|
-
throw new Error(
|
|
1792
|
-
`Element '${el.id}' (${el.type}) does not support altText; only ${[...ALT_TEXT_ELEMENT_TYPES].join(", ")} elements do.`
|
|
1793
|
-
);
|
|
1794
|
-
}
|
|
1795
|
-
el.altText = altText;
|
|
1796
|
-
}
|
|
1797
|
-
function applyElementTitle(el, title) {
|
|
1798
|
-
if (!TITLE_ELEMENT_TYPES.has(el.type)) {
|
|
1799
|
-
throw new Error(
|
|
1800
|
-
`Element '${el.id}' (${el.type}) does not support title; only ${[...TITLE_ELEMENT_TYPES].join(", ")} elements do.`
|
|
1801
|
-
);
|
|
1802
|
-
}
|
|
1803
|
-
el.title = title;
|
|
1804
|
-
}
|
|
1805
|
-
function updateElementStyle(ctx, params) {
|
|
1806
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1807
|
-
if (err) {
|
|
1808
|
-
throw new Error(err);
|
|
1809
|
-
}
|
|
1810
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1811
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1812
|
-
if (!el) {
|
|
1813
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1814
|
-
}
|
|
1815
|
-
if ("shapeStyle" in el) {
|
|
1816
|
-
if (!el.shapeStyle) {
|
|
1817
|
-
el.shapeStyle = {};
|
|
1818
|
-
}
|
|
1819
|
-
const ss = el.shapeStyle;
|
|
1820
|
-
if (params.fillThemeColor !== void 0) {
|
|
1821
|
-
ss.fillColorRef = params.fillThemeColor;
|
|
1822
|
-
const resolved = pptxViewerCore.resolveThemeColorRef(params.fillThemeColor, ctx.pptxData.themeColorMap);
|
|
1823
|
-
if (params.fillColor !== void 0) {
|
|
1824
|
-
ss.fillColor = params.fillColor;
|
|
1825
|
-
} else if (resolved) {
|
|
1826
|
-
ss.fillColor = resolved;
|
|
1827
|
-
}
|
|
1828
|
-
} else if (params.fillColor !== void 0) {
|
|
1829
|
-
ss.fillColor = params.fillColor;
|
|
1830
|
-
ss.fillColorRef = void 0;
|
|
1831
|
-
}
|
|
1832
|
-
if (params.fillMode !== void 0) {
|
|
1833
|
-
ss.fillMode = params.fillMode;
|
|
1834
|
-
}
|
|
1835
|
-
if (params.fillGradientStops !== void 0) {
|
|
1836
|
-
ss.fillGradientStops = params.fillGradientStops;
|
|
1837
|
-
}
|
|
1838
|
-
if (params.fillGradientAngle !== void 0) {
|
|
1839
|
-
ss.fillGradientAngle = params.fillGradientAngle;
|
|
1840
|
-
}
|
|
1841
|
-
if (params.fillGradientType !== void 0) {
|
|
1842
|
-
ss.fillGradientType = params.fillGradientType;
|
|
1843
|
-
}
|
|
1844
|
-
if (params.fillOpacity !== void 0) {
|
|
1845
|
-
ss.fillOpacity = params.fillOpacity;
|
|
1846
|
-
}
|
|
1847
|
-
if (params.strokeThemeColor !== void 0) {
|
|
1848
|
-
ss.strokeColorRef = params.strokeThemeColor;
|
|
1849
|
-
const resolved = pptxViewerCore.resolveThemeColorRef(params.strokeThemeColor, ctx.pptxData.themeColorMap);
|
|
1850
|
-
if (params.strokeColor !== void 0) {
|
|
1851
|
-
ss.strokeColor = params.strokeColor;
|
|
1852
|
-
} else if (resolved) {
|
|
1853
|
-
ss.strokeColor = resolved;
|
|
1854
|
-
}
|
|
1855
|
-
} else if (params.strokeColor !== void 0) {
|
|
1856
|
-
ss.strokeColor = params.strokeColor;
|
|
1857
|
-
ss.strokeColorRef = void 0;
|
|
1858
|
-
}
|
|
1859
|
-
if (params.strokeWidth !== void 0) {
|
|
1860
|
-
ss.strokeWidth = params.strokeWidth;
|
|
1861
|
-
}
|
|
1862
|
-
if (params.strokeDash !== void 0) {
|
|
1863
|
-
ss.strokeDash = params.strokeDash;
|
|
1864
|
-
}
|
|
1865
|
-
if (params.strokeOpacity !== void 0) {
|
|
1866
|
-
ss.strokeOpacity = params.strokeOpacity;
|
|
1867
|
-
}
|
|
1868
|
-
if (params.shadowColor !== void 0) {
|
|
1869
|
-
ss.shadowColor = params.shadowColor;
|
|
1870
|
-
}
|
|
1871
|
-
if (params.shadowBlur !== void 0) {
|
|
1872
|
-
ss.shadowBlur = params.shadowBlur;
|
|
1873
|
-
}
|
|
1874
|
-
if (params.shadowOffsetX !== void 0) {
|
|
1875
|
-
ss.shadowOffsetX = params.shadowOffsetX;
|
|
1876
|
-
}
|
|
1877
|
-
if (params.shadowOffsetY !== void 0) {
|
|
1878
|
-
ss.shadowOffsetY = params.shadowOffsetY;
|
|
1879
|
-
}
|
|
1880
|
-
if (params.shadowOpacity !== void 0) {
|
|
1881
|
-
ss.shadowOpacity = params.shadowOpacity;
|
|
1882
|
-
}
|
|
1883
|
-
if (params.glowColor !== void 0) {
|
|
1884
|
-
ss.glowColor = params.glowColor;
|
|
1885
|
-
}
|
|
1886
|
-
if (params.glowRadius !== void 0) {
|
|
1887
|
-
ss.glowRadius = params.glowRadius;
|
|
1888
|
-
}
|
|
1889
|
-
if (params.glowOpacity !== void 0) {
|
|
1890
|
-
ss.glowOpacity = params.glowOpacity;
|
|
1891
|
-
}
|
|
1892
|
-
if (params.softEdgeRadius !== void 0) {
|
|
1893
|
-
ss.softEdgeRadius = params.softEdgeRadius;
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
if (params.altText !== void 0) {
|
|
1897
|
-
applyElementAltText(el, params.altText);
|
|
1898
|
-
}
|
|
1899
|
-
if (params.title !== void 0) {
|
|
1900
|
-
applyElementTitle(el, params.title);
|
|
1901
|
-
}
|
|
1902
|
-
if (el.type === "image" || el.type === "picture") {
|
|
1903
|
-
const img = el;
|
|
1904
|
-
if (params.cropLeft !== void 0) {
|
|
1905
|
-
img.cropLeft = params.cropLeft;
|
|
1906
|
-
}
|
|
1907
|
-
if (params.cropTop !== void 0) {
|
|
1908
|
-
img.cropTop = params.cropTop;
|
|
1909
|
-
}
|
|
1910
|
-
if (params.cropRight !== void 0) {
|
|
1911
|
-
img.cropRight = params.cropRight;
|
|
1912
|
-
}
|
|
1913
|
-
if (params.cropBottom !== void 0) {
|
|
1914
|
-
img.cropBottom = params.cropBottom;
|
|
1915
|
-
}
|
|
1916
|
-
if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
|
|
1917
|
-
if (!img.imageEffects) {
|
|
1918
|
-
img.imageEffects = {};
|
|
1919
|
-
}
|
|
1920
|
-
if (params.brightness !== void 0) {
|
|
1921
|
-
img.imageEffects.brightness = params.brightness;
|
|
1922
|
-
}
|
|
1923
|
-
if (params.contrast !== void 0) {
|
|
1924
|
-
img.imageEffects.contrast = params.contrast;
|
|
1925
|
-
}
|
|
1926
|
-
if (params.grayscale !== void 0) {
|
|
1927
|
-
img.imageEffects.grayscale = params.grayscale;
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
return {
|
|
1932
|
-
pptxData: ctx.pptxData,
|
|
1933
|
-
dirty: true,
|
|
1934
|
-
result: { elementId: params.elementId }
|
|
1935
|
-
};
|
|
1936
|
-
}
|
|
1937
|
-
function runAccessibilityCheck(ctx) {
|
|
1938
|
-
const issues = [];
|
|
1939
|
-
for (let si = 0; si < ctx.pptxData.slides.length; si++) {
|
|
1940
|
-
const slide = ctx.pptxData.slides[si];
|
|
1941
|
-
let slideHasText = false;
|
|
1942
|
-
for (const el of slide.elements) {
|
|
1943
|
-
if (el.type === "image" || el.type === "picture") {
|
|
1944
|
-
const img = el;
|
|
1945
|
-
if (!img.altText) {
|
|
1946
|
-
issues.push({
|
|
1947
|
-
slideIndex: si,
|
|
1948
|
-
elementId: el.id,
|
|
1949
|
-
severity: "error",
|
|
1950
|
-
message: `Image element '${el.id}' has no alt text.`
|
|
1951
|
-
});
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
1955
|
-
const textEl = el;
|
|
1956
|
-
slideHasText = true;
|
|
1957
|
-
if (!textEl.text || textEl.text.trim() === "") {
|
|
1958
|
-
issues.push({
|
|
1959
|
-
slideIndex: si,
|
|
1960
|
-
elementId: el.id,
|
|
1961
|
-
severity: "info",
|
|
1962
|
-
message: `Text element '${el.id}' is empty.`
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
const fs = textEl.textStyle?.fontSize;
|
|
1966
|
-
if (fs !== void 0 && fs < 10) {
|
|
1967
|
-
issues.push({
|
|
1968
|
-
slideIndex: si,
|
|
1969
|
-
elementId: el.id,
|
|
1970
|
-
severity: "warning",
|
|
1971
|
-
message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
|
|
1972
|
-
});
|
|
1973
|
-
}
|
|
1974
|
-
const textColor = textEl.textStyle?.color?.toLowerCase();
|
|
1975
|
-
const bgColor = slide.backgroundColor?.toLowerCase();
|
|
1976
|
-
if (textColor && bgColor && textColor === bgColor) {
|
|
1977
|
-
issues.push({
|
|
1978
|
-
slideIndex: si,
|
|
1979
|
-
elementId: el.id,
|
|
1980
|
-
severity: "error",
|
|
1981
|
-
message: `Text element '${el.id}' has same color as slide background (${textColor}).`
|
|
1982
|
-
});
|
|
1983
|
-
}
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
if (!slideHasText) {
|
|
1987
|
-
issues.push({
|
|
1988
|
-
slideIndex: si,
|
|
1989
|
-
severity: "warning",
|
|
1990
|
-
message: `Slide ${si + 1} contains no text elements.`
|
|
1991
|
-
});
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
1995
|
-
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
1996
|
-
const infoCount = issues.filter((i) => i.severity === "info").length;
|
|
1997
|
-
return {
|
|
1998
|
-
pptxData: ctx.pptxData,
|
|
1999
|
-
dirty: false,
|
|
2000
|
-
result: {
|
|
2001
|
-
slideCount: ctx.pptxData.slides.length,
|
|
2002
|
-
totalIssues: issues.length,
|
|
2003
|
-
errorCount,
|
|
2004
|
-
warningCount,
|
|
2005
|
-
infoCount,
|
|
2006
|
-
issues
|
|
2007
|
-
}
|
|
2008
|
-
};
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
// src/tools/element-tools.ts
|
|
2012
|
-
function addElement(ctx, params) {
|
|
2013
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2014
|
-
if (err) {
|
|
2015
|
-
throw new Error(err);
|
|
2016
|
-
}
|
|
2017
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2018
|
-
const id = generateElementId();
|
|
2019
|
-
const x = params.x ?? 100;
|
|
2020
|
-
const y = params.y ?? 100;
|
|
2021
|
-
const width = params.width ?? 300;
|
|
2022
|
-
const height = params.height ?? 60;
|
|
2023
|
-
switch (params.type) {
|
|
2024
|
-
case "text": {
|
|
2025
|
-
const el = {
|
|
2026
|
-
id,
|
|
2027
|
-
type: "text",
|
|
2028
|
-
x,
|
|
2029
|
-
y,
|
|
2030
|
-
width,
|
|
2031
|
-
height,
|
|
2032
|
-
text: params.text ?? "",
|
|
2033
|
-
textStyle: {
|
|
2034
|
-
fontSize: params.fontSize,
|
|
2035
|
-
fontFamily: params.fontFamily,
|
|
2036
|
-
color: params.fontColor,
|
|
2037
|
-
bold: params.bold,
|
|
2038
|
-
italic: params.italic,
|
|
2039
|
-
underline: params.underline,
|
|
2040
|
-
align: params.alignment
|
|
2041
|
-
},
|
|
2042
|
-
textSegments: [
|
|
2043
|
-
{
|
|
2044
|
-
text: params.text ?? "",
|
|
2045
|
-
style: {
|
|
2046
|
-
fontSize: params.fontSize,
|
|
2047
|
-
fontFamily: params.fontFamily,
|
|
2048
|
-
color: params.fontColor,
|
|
2049
|
-
bold: params.bold,
|
|
2050
|
-
italic: params.italic,
|
|
2051
|
-
underline: params.underline
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
]
|
|
2055
|
-
};
|
|
2056
|
-
slide.elements.push(el);
|
|
2057
|
-
break;
|
|
2058
|
-
}
|
|
2059
|
-
case "shape": {
|
|
2060
|
-
const el = {
|
|
2061
|
-
id,
|
|
2062
|
-
type: "shape",
|
|
2063
|
-
x,
|
|
2064
|
-
y,
|
|
2065
|
-
width,
|
|
2066
|
-
height,
|
|
2067
|
-
shapeType: params.shapeType ?? "rect",
|
|
2068
|
-
text: params.text,
|
|
2069
|
-
textStyle: params.text ? {
|
|
2070
|
-
fontSize: params.fontSize,
|
|
2071
|
-
fontFamily: params.fontFamily,
|
|
2072
|
-
color: params.fontColor,
|
|
2073
|
-
bold: params.bold,
|
|
2074
|
-
italic: params.italic,
|
|
2075
|
-
align: params.alignment
|
|
2076
|
-
} : void 0,
|
|
2077
|
-
shapeStyle: {
|
|
2078
|
-
fillColor: params.fillColor,
|
|
2079
|
-
strokeColor: params.strokeColor,
|
|
2080
|
-
strokeWidth: params.strokeWidth
|
|
2081
|
-
}
|
|
2082
|
-
};
|
|
2083
|
-
slide.elements.push(el);
|
|
2084
|
-
break;
|
|
2085
|
-
}
|
|
2086
|
-
case "image": {
|
|
2087
|
-
const el = {
|
|
2088
|
-
id,
|
|
2089
|
-
type: "image",
|
|
2090
|
-
x,
|
|
2091
|
-
y,
|
|
2092
|
-
width,
|
|
2093
|
-
height,
|
|
2094
|
-
imageData: params.imageData,
|
|
2095
|
-
altText: params.altText
|
|
2096
|
-
};
|
|
2097
|
-
slide.elements.push(el);
|
|
2098
|
-
break;
|
|
2099
|
-
}
|
|
2100
|
-
case "table": {
|
|
2101
|
-
const rowCount = params.rows ?? 2;
|
|
2102
|
-
const colCount = params.columns ?? 2;
|
|
2103
|
-
const colWidth = 1 / colCount;
|
|
2104
|
-
const tableRows = Array.from({ length: rowCount }, (_, r) => ({
|
|
2105
|
-
height: 40,
|
|
2106
|
-
cells: Array.from({ length: colCount }, (__, c) => ({
|
|
2107
|
-
text: params.cellData?.[r]?.[c] ?? ""
|
|
2108
|
-
}))
|
|
2109
|
-
}));
|
|
2110
|
-
const tableEl = {
|
|
2111
|
-
id,
|
|
2112
|
-
type: "table",
|
|
2113
|
-
x,
|
|
2114
|
-
y,
|
|
2115
|
-
width,
|
|
2116
|
-
height: params.height ?? rowCount * 40,
|
|
2117
|
-
tableData: {
|
|
2118
|
-
rows: tableRows,
|
|
2119
|
-
columnWidths: Array.from({ length: colCount }, () => colWidth),
|
|
2120
|
-
firstRowHeader: params.headerRow ?? false
|
|
2121
|
-
}
|
|
2122
|
-
};
|
|
2123
|
-
slide.elements.push(tableEl);
|
|
2124
|
-
break;
|
|
2125
|
-
}
|
|
2126
|
-
case "connector": {
|
|
2127
|
-
const el = {
|
|
2128
|
-
id,
|
|
2129
|
-
type: "connector",
|
|
2130
|
-
x,
|
|
2131
|
-
y,
|
|
2132
|
-
width,
|
|
2133
|
-
height,
|
|
2134
|
-
shapeStyle: {
|
|
2135
|
-
strokeColor: params.strokeColor ?? "#000000",
|
|
2136
|
-
strokeWidth: params.strokeWidth ?? 1,
|
|
2137
|
-
connectorStartArrow: params.startArrow,
|
|
2138
|
-
connectorEndArrow: params.endArrow
|
|
2139
|
-
}
|
|
2140
|
-
};
|
|
2141
|
-
slide.elements.push(el);
|
|
2142
|
-
break;
|
|
2143
|
-
}
|
|
2144
|
-
default: {
|
|
2145
|
-
throw new Error(`Unknown element type: ${String(params.type)}`);
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
return {
|
|
2149
|
-
pptxData: ctx.pptxData,
|
|
2150
|
-
dirty: true,
|
|
2151
|
-
result: { elementId: id, slideIndex: params.slideIndex }
|
|
2152
|
-
};
|
|
2153
|
-
}
|
|
2154
|
-
function updateElement(ctx, params) {
|
|
2155
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2156
|
-
if (err) {
|
|
2157
|
-
throw new Error(err);
|
|
2158
|
-
}
|
|
2159
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2160
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2161
|
-
if (!el) {
|
|
2162
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2163
|
-
}
|
|
2164
|
-
if (params.x !== void 0) {
|
|
2165
|
-
el.x = params.x;
|
|
2166
|
-
}
|
|
2167
|
-
if (params.y !== void 0) {
|
|
2168
|
-
el.y = params.y;
|
|
2169
|
-
}
|
|
2170
|
-
if (params.width !== void 0) {
|
|
2171
|
-
el.width = params.width;
|
|
2172
|
-
}
|
|
2173
|
-
if (params.height !== void 0) {
|
|
2174
|
-
el.height = params.height;
|
|
2175
|
-
}
|
|
2176
|
-
if (params.rotation !== void 0) {
|
|
2177
|
-
el.rotation = params.rotation;
|
|
2178
|
-
}
|
|
2179
|
-
if (params.opacity !== void 0) {
|
|
2180
|
-
el.opacity = params.opacity;
|
|
2181
|
-
}
|
|
2182
|
-
if (params.hidden !== void 0) {
|
|
2183
|
-
el.hidden = params.hidden;
|
|
2184
|
-
}
|
|
2185
|
-
if (params.flipH !== void 0) {
|
|
2186
|
-
el.flipHorizontal = params.flipH;
|
|
2187
|
-
}
|
|
2188
|
-
if (params.flipV !== void 0) {
|
|
2189
|
-
el.flipVertical = params.flipV;
|
|
2190
|
-
}
|
|
2191
|
-
if (params.altText !== void 0) {
|
|
2192
|
-
applyElementAltText(el, params.altText);
|
|
2193
|
-
}
|
|
2194
|
-
if (params.title !== void 0) {
|
|
2195
|
-
applyElementTitle(el, params.title);
|
|
2196
|
-
}
|
|
2197
|
-
if (pptxViewerCore.hasTextProperties(el)) {
|
|
2198
|
-
const textEl = el;
|
|
2199
|
-
if (params.textSegments !== void 0) {
|
|
2200
|
-
textEl.textSegments = structuredClone(params.textSegments);
|
|
2201
|
-
textEl.text = textEl.textSegments.map((segment) => segment.text).join("");
|
|
2202
|
-
} else if (params.text !== void 0) {
|
|
2203
|
-
setElementText(textEl, params.text);
|
|
2204
|
-
}
|
|
2205
|
-
if (!textEl.textStyle) {
|
|
2206
|
-
textEl.textStyle = {};
|
|
2207
|
-
}
|
|
2208
|
-
if (params.fontSize !== void 0) {
|
|
2209
|
-
textEl.textStyle.fontSize = params.fontSize;
|
|
2210
|
-
}
|
|
2211
|
-
if (params.fontFamily !== void 0) {
|
|
2212
|
-
textEl.textStyle.fontFamily = params.fontFamily;
|
|
2213
|
-
}
|
|
2214
|
-
if (params.fontThemeColor !== void 0) {
|
|
2215
|
-
textEl.textStyle.colorRef = params.fontThemeColor;
|
|
2216
|
-
const resolved = pptxViewerCore.resolveThemeColorRef(params.fontThemeColor, ctx.pptxData.themeColorMap);
|
|
2217
|
-
if (params.fontColor !== void 0) {
|
|
2218
|
-
textEl.textStyle.color = params.fontColor;
|
|
2219
|
-
} else if (resolved) {
|
|
2220
|
-
textEl.textStyle.color = resolved;
|
|
2221
|
-
}
|
|
2222
|
-
} else if (params.fontColor !== void 0) {
|
|
2223
|
-
textEl.textStyle.color = params.fontColor;
|
|
2224
|
-
textEl.textStyle.colorRef = void 0;
|
|
2225
|
-
}
|
|
2226
|
-
if (params.bold !== void 0) {
|
|
2227
|
-
textEl.textStyle.bold = params.bold;
|
|
2228
|
-
}
|
|
2229
|
-
if (params.italic !== void 0) {
|
|
2230
|
-
textEl.textStyle.italic = params.italic;
|
|
2231
|
-
}
|
|
2232
|
-
if (params.underline !== void 0) {
|
|
2233
|
-
textEl.textStyle.underline = params.underline;
|
|
2234
|
-
}
|
|
2235
|
-
if (params.alignment !== void 0) {
|
|
2236
|
-
textEl.textStyle.align = params.alignment;
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
if ("shapeStyle" in el && el.shapeStyle) {
|
|
2240
|
-
const ss = el.shapeStyle;
|
|
2241
|
-
if (params.fillColor !== void 0) {
|
|
2242
|
-
ss.fillColor = params.fillColor;
|
|
2243
|
-
}
|
|
2244
|
-
if (params.strokeColor !== void 0) {
|
|
2245
|
-
ss.strokeColor = params.strokeColor;
|
|
2246
|
-
}
|
|
2247
|
-
if (params.strokeWidth !== void 0) {
|
|
2248
|
-
ss.strokeWidth = params.strokeWidth;
|
|
2249
|
-
}
|
|
2250
|
-
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0) {
|
|
2251
|
-
if ("shapeStyle" in el) {
|
|
2252
|
-
el.shapeStyle = {
|
|
2253
|
-
fillColor: params.fillColor,
|
|
2254
|
-
strokeColor: params.strokeColor,
|
|
2255
|
-
strokeWidth: params.strokeWidth
|
|
2256
|
-
};
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
return {
|
|
2260
|
-
pptxData: ctx.pptxData,
|
|
2261
|
-
dirty: true,
|
|
2262
|
-
result: { elementId: params.elementId }
|
|
2263
|
-
};
|
|
2264
|
-
}
|
|
2265
|
-
function renameElement(ctx, params) {
|
|
2266
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2267
|
-
if (err) {
|
|
2268
|
-
throw new Error(err);
|
|
2269
|
-
}
|
|
2270
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2271
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2272
|
-
if (!el) {
|
|
2273
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2274
|
-
}
|
|
2275
|
-
const name = params.name.trim();
|
|
2276
|
-
if (name.length === 0) {
|
|
2277
|
-
delete el.name;
|
|
2278
|
-
} else {
|
|
2279
|
-
el.name = name;
|
|
2280
|
-
}
|
|
2281
|
-
return {
|
|
2282
|
-
pptxData: ctx.pptxData,
|
|
2283
|
-
dirty: true,
|
|
2284
|
-
result: { elementId: params.elementId, name }
|
|
2285
|
-
};
|
|
2286
|
-
}
|
|
2287
|
-
function deleteElements(ctx, params) {
|
|
2288
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2289
|
-
if (err) {
|
|
2290
|
-
throw new Error(err);
|
|
2291
|
-
}
|
|
2292
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2293
|
-
const idSet = new Set(params.elementIds);
|
|
2294
|
-
const existingIds = new Set(slide.elements.map((element) => element.id));
|
|
2295
|
-
const notFound = params.elementIds.filter((id) => !existingIds.has(id));
|
|
2296
|
-
if (notFound.length > 0) {
|
|
2297
|
-
throw new Error(`Elements not found: ${notFound.join(", ")}`);
|
|
2298
|
-
}
|
|
2299
|
-
const before = slide.elements.length;
|
|
2300
|
-
slide.elements = slide.elements.filter((e) => !idSet.has(e.id));
|
|
2301
|
-
return {
|
|
2302
|
-
pptxData: ctx.pptxData,
|
|
2303
|
-
dirty: true,
|
|
2304
|
-
result: { deletedCount: before - slide.elements.length }
|
|
2305
|
-
};
|
|
2306
|
-
}
|
|
2307
|
-
function arrangeElements(ctx, params) {
|
|
2308
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2309
|
-
if (err) {
|
|
2310
|
-
throw new Error(err);
|
|
2311
|
-
}
|
|
2312
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2313
|
-
if (params.action === "align") {
|
|
2314
|
-
if (!params.elementIds || params.elementIds.length === 0) {
|
|
2315
|
-
throw new Error("elementIds is required for align action.");
|
|
2316
|
-
}
|
|
2317
|
-
const targetIds = new Set(params.elementIds);
|
|
2318
|
-
const targets = slide.elements.filter((element) => targetIds.has(element.id));
|
|
2319
|
-
if (targets.length === 0) {
|
|
2320
|
-
throw new Error("No matching elements found for align.");
|
|
2321
|
-
}
|
|
2322
|
-
switch (params.alignment) {
|
|
2323
|
-
case "left": {
|
|
2324
|
-
const minX = Math.min(...targets.map((e) => e.x));
|
|
2325
|
-
for (const t of targets) {
|
|
2326
|
-
t.x = minX;
|
|
2327
|
-
}
|
|
2328
|
-
break;
|
|
2329
|
-
}
|
|
2330
|
-
case "right": {
|
|
2331
|
-
const maxRight = Math.max(...targets.map((e) => e.x + e.width));
|
|
2332
|
-
for (const t of targets) {
|
|
2333
|
-
t.x = maxRight - t.width;
|
|
2334
|
-
}
|
|
2335
|
-
break;
|
|
2336
|
-
}
|
|
2337
|
-
case "top": {
|
|
2338
|
-
const minY = Math.min(...targets.map((e) => e.y));
|
|
2339
|
-
for (const t of targets) {
|
|
2340
|
-
t.y = minY;
|
|
2341
|
-
}
|
|
2342
|
-
break;
|
|
2343
|
-
}
|
|
2344
|
-
case "bottom": {
|
|
2345
|
-
const maxBottom = Math.max(...targets.map((e) => e.y + e.height));
|
|
2346
|
-
for (const t of targets) {
|
|
2347
|
-
t.y = maxBottom - t.height;
|
|
2348
|
-
}
|
|
2349
|
-
break;
|
|
2350
|
-
}
|
|
2351
|
-
case "centerH": {
|
|
2352
|
-
const avgCX = targets.reduce((s, e) => s + e.x + e.width / 2, 0) / targets.length;
|
|
2353
|
-
for (const t of targets) {
|
|
2354
|
-
t.x = avgCX - t.width / 2;
|
|
2355
|
-
}
|
|
2356
|
-
break;
|
|
2357
|
-
}
|
|
2358
|
-
case "centerV": {
|
|
2359
|
-
const avgCY = targets.reduce((s, e) => s + e.y + e.height / 2, 0) / targets.length;
|
|
2360
|
-
for (const t of targets) {
|
|
2361
|
-
t.y = avgCY - t.height / 2;
|
|
2362
|
-
}
|
|
2363
|
-
break;
|
|
2364
|
-
}
|
|
2365
|
-
default: {
|
|
2366
|
-
throw new Error(`Unknown alignment: ${String(params.alignment)}`);
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
2369
|
-
} else if (params.action === "reorderLayer") {
|
|
2370
|
-
if (!params.elementId) {
|
|
2371
|
-
throw new Error("elementId is required for reorderLayer action.");
|
|
2372
|
-
}
|
|
2373
|
-
const idx = slide.elements.findIndex((e) => e.id === params.elementId);
|
|
2374
|
-
if (idx < 0) {
|
|
2375
|
-
throw new Error(`Element '${params.elementId}' not found.`);
|
|
2376
|
-
}
|
|
2377
|
-
const [el] = slide.elements.splice(idx, 1);
|
|
2378
|
-
switch (params.layerAction) {
|
|
2379
|
-
case "bringToFront":
|
|
2380
|
-
slide.elements.push(el);
|
|
2381
|
-
break;
|
|
2382
|
-
case "sendToBack":
|
|
2383
|
-
slide.elements.unshift(el);
|
|
2384
|
-
break;
|
|
2385
|
-
case "bringForward": {
|
|
2386
|
-
const newIdx = Math.min(idx + 1, slide.elements.length);
|
|
2387
|
-
slide.elements.splice(newIdx, 0, el);
|
|
2388
|
-
break;
|
|
2389
|
-
}
|
|
2390
|
-
case "sendBackward": {
|
|
2391
|
-
const newIdx = Math.max(idx - 1, 0);
|
|
2392
|
-
slide.elements.splice(newIdx, 0, el);
|
|
2393
|
-
break;
|
|
2394
|
-
}
|
|
2395
|
-
default: {
|
|
2396
|
-
slide.elements.splice(idx, 0, el);
|
|
2397
|
-
throw new Error(`Unknown layerAction: ${String(params.layerAction)}`);
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
} else {
|
|
2401
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
2402
|
-
}
|
|
2403
|
-
return {
|
|
2404
|
-
pptxData: ctx.pptxData,
|
|
2405
|
-
dirty: true,
|
|
2406
|
-
result: { slideIndex: params.slideIndex }
|
|
2407
|
-
};
|
|
2408
|
-
}
|
|
2409
|
-
function cloneElement(ctx, params) {
|
|
2410
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2411
|
-
if (err) {
|
|
2412
|
-
throw new Error(err);
|
|
2413
|
-
}
|
|
2414
|
-
const srcSlide = ctx.pptxData.slides[params.slideIndex];
|
|
2415
|
-
const original = srcSlide.elements.find((e) => e.id === params.elementId);
|
|
2416
|
-
if (!original) {
|
|
2417
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2418
|
-
}
|
|
2419
|
-
const targets = params.targetSlideIndexes ?? [params.slideIndex];
|
|
2420
|
-
const clonedIds = [];
|
|
2421
|
-
const offsetX = params.offsetX ?? 20;
|
|
2422
|
-
const offsetY = params.offsetY ?? 20;
|
|
2423
|
-
for (const targetIdx of targets) {
|
|
2424
|
-
const terr = validateSlideIndex(targetIdx, ctx.pptxData.slides.length);
|
|
2425
|
-
if (terr) {
|
|
2426
|
-
throw new Error(terr);
|
|
2427
|
-
}
|
|
2428
|
-
const clone = pptxViewerCore.cloneElement(original);
|
|
2429
|
-
const intoTemplate = pptxViewerCore.isTemplateElementId(original.id);
|
|
2430
|
-
clone.id = pptxViewerCore.makeStoreAwareId(intoTemplate, original.id);
|
|
2431
|
-
pptxViewerCore.reassignDescendantIds(clone, () => pptxViewerCore.makeStoreAwareId(intoTemplate, original.id));
|
|
2432
|
-
clone.x += offsetX;
|
|
2433
|
-
clone.y += offsetY;
|
|
2434
|
-
ctx.pptxData.slides[targetIdx].elements.push(clone);
|
|
2435
|
-
clonedIds.push(clone.id);
|
|
2436
|
-
}
|
|
2437
|
-
return {
|
|
2438
|
-
pptxData: ctx.pptxData,
|
|
2439
|
-
dirty: true,
|
|
2440
|
-
result: { clonedIds }
|
|
2441
|
-
};
|
|
2442
|
-
}
|
|
2443
|
-
function setElementAnimation(ctx, params) {
|
|
2444
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2445
|
-
if (err) {
|
|
2446
|
-
throw new Error(err);
|
|
2447
|
-
}
|
|
2448
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2449
|
-
const elExists = slide.elements.some((e) => e.id === params.elementId);
|
|
2450
|
-
if (!elExists) {
|
|
2451
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2452
|
-
}
|
|
2453
|
-
if (!slide.animations) {
|
|
2454
|
-
slide.animations = [];
|
|
2455
|
-
}
|
|
2456
|
-
const existing = slide.animations.find((a) => a.elementId === params.elementId);
|
|
2457
|
-
if (existing) {
|
|
2458
|
-
if (params.entrance !== void 0) {
|
|
2459
|
-
existing.entrance = params.entrance;
|
|
2460
|
-
}
|
|
2461
|
-
if (params.exit !== void 0) {
|
|
2462
|
-
existing.exit = params.exit;
|
|
2463
|
-
}
|
|
2464
|
-
if (params.durationMs !== void 0) {
|
|
2465
|
-
existing.durationMs = params.durationMs;
|
|
2466
|
-
}
|
|
2467
|
-
if (params.delayMs !== void 0) {
|
|
2468
|
-
existing.delayMs = params.delayMs;
|
|
2469
|
-
}
|
|
2470
|
-
if (params.order !== void 0) {
|
|
2471
|
-
existing.order = params.order;
|
|
2472
|
-
}
|
|
2473
|
-
} else {
|
|
2474
|
-
const anim = {
|
|
2475
|
-
elementId: params.elementId,
|
|
2476
|
-
entrance: params.entrance,
|
|
2477
|
-
exit: params.exit,
|
|
2478
|
-
durationMs: params.durationMs,
|
|
2479
|
-
delayMs: params.delayMs,
|
|
2480
|
-
order: params.order
|
|
2481
|
-
};
|
|
2482
|
-
slide.animations.push(anim);
|
|
2483
|
-
}
|
|
2484
|
-
return {
|
|
2485
|
-
pptxData: ctx.pptxData,
|
|
2486
|
-
dirty: true,
|
|
2487
|
-
result: { elementId: params.elementId }
|
|
2488
|
-
};
|
|
2489
|
-
}
|
|
2490
|
-
function groupElements(ctx, params) {
|
|
2491
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2492
|
-
if (err) {
|
|
2493
|
-
throw new Error(err);
|
|
2494
|
-
}
|
|
2495
|
-
if (params.elementIds.length < 2) {
|
|
2496
|
-
throw new Error("At least 2 elements are required to form a group.");
|
|
2497
|
-
}
|
|
2498
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2499
|
-
const idSet = new Set(params.elementIds);
|
|
2500
|
-
const found = new Set(slide.elements.filter((e) => idSet.has(e.id)).map((e) => e.id));
|
|
2501
|
-
if (found.size !== idSet.size) {
|
|
2502
|
-
const missing = params.elementIds.filter((id) => !found.has(id));
|
|
2503
|
-
throw new Error(`Elements not found: ${missing.join(", ")}`);
|
|
2504
|
-
}
|
|
2505
|
-
const groupId = generateElementId();
|
|
2506
|
-
const grouped = pptxViewerCore.groupElements(slide.elements, params.elementIds, groupId);
|
|
2507
|
-
slide.elements = grouped.elements;
|
|
2508
|
-
return {
|
|
2509
|
-
pptxData: ctx.pptxData,
|
|
2510
|
-
dirty: true,
|
|
2511
|
-
result: { groupId: grouped.groupId ?? groupId }
|
|
2512
|
-
};
|
|
2513
|
-
}
|
|
2514
|
-
function ungroupElements(ctx, params) {
|
|
2515
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2516
|
-
if (err) {
|
|
2517
|
-
throw new Error(err);
|
|
2518
|
-
}
|
|
2519
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2520
|
-
const group = slide.elements.find((e) => e.id === params.groupElementId);
|
|
2521
|
-
if (!group) {
|
|
2522
|
-
throw new Error(`Group element '${params.groupElementId}' not found.`);
|
|
2523
|
-
}
|
|
2524
|
-
if (group.type !== "group") {
|
|
2525
|
-
throw new Error(`Element '${params.groupElementId}' is not a group.`);
|
|
2526
|
-
}
|
|
2527
|
-
const intoTemplate = pptxViewerCore.isTemplateElementId(group.id);
|
|
2528
|
-
const childIds = group.children.map(
|
|
2529
|
-
(child) => pptxViewerCore.isTemplateElementId(child.id) === intoTemplate ? child.id : pptxViewerCore.makeStoreAwareId(intoTemplate, group.id)
|
|
2530
|
-
);
|
|
2531
|
-
const promoted = pptxViewerCore.ungroupElements(slide.elements, params.groupElementId, childIds, {
|
|
2532
|
-
intoTemplate
|
|
2533
|
-
});
|
|
2534
|
-
slide.elements = promoted.elements;
|
|
2535
|
-
return {
|
|
2536
|
-
pptxData: ctx.pptxData,
|
|
2537
|
-
dirty: true,
|
|
2538
|
-
result: { restoredIds: promoted.childIds }
|
|
2539
|
-
};
|
|
2540
|
-
}
|
|
2541
|
-
function batchUpdateElements(ctx, params) {
|
|
2542
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2543
|
-
if (err) {
|
|
2544
|
-
throw new Error(err);
|
|
2545
|
-
}
|
|
2546
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2547
|
-
const idSet = new Set(params.elementIds);
|
|
2548
|
-
let count = 0;
|
|
2549
|
-
for (const el of slide.elements) {
|
|
2550
|
-
if (!idSet.has(el.id)) {
|
|
2551
|
-
continue;
|
|
2552
|
-
}
|
|
2553
|
-
if (params.x !== void 0) {
|
|
2554
|
-
el.x = params.x;
|
|
2555
|
-
}
|
|
2556
|
-
if (params.y !== void 0) {
|
|
2557
|
-
el.y = params.y;
|
|
2558
|
-
}
|
|
2559
|
-
if (params.width !== void 0) {
|
|
2560
|
-
el.width = params.width;
|
|
2561
|
-
}
|
|
2562
|
-
if (params.height !== void 0) {
|
|
2563
|
-
el.height = params.height;
|
|
2564
|
-
}
|
|
2565
|
-
if (params.rotation !== void 0) {
|
|
2566
|
-
el.rotation = params.rotation;
|
|
2567
|
-
}
|
|
2568
|
-
if (params.opacity !== void 0) {
|
|
2569
|
-
el.opacity = params.opacity;
|
|
2570
|
-
}
|
|
2571
|
-
if (params.hidden !== void 0) {
|
|
2572
|
-
el.hidden = params.hidden;
|
|
2573
|
-
}
|
|
2574
|
-
count++;
|
|
2575
|
-
}
|
|
2576
|
-
return {
|
|
2577
|
-
pptxData: ctx.pptxData,
|
|
2578
|
-
dirty: true,
|
|
2579
|
-
result: { updatedCount: count }
|
|
2580
|
-
};
|
|
2581
|
-
}
|
|
2582
|
-
function exportToSvg(ctx, params) {
|
|
2583
|
-
if (params.slideIndices) {
|
|
2584
|
-
for (const si of params.slideIndices) {
|
|
2585
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
2586
|
-
if (err) {
|
|
2587
|
-
throw new Error(err);
|
|
2588
|
-
}
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
|
-
const options = {};
|
|
2592
|
-
if (params.slideIndices) {
|
|
2593
|
-
options.slideIndices = params.slideIndices;
|
|
2594
|
-
}
|
|
2595
|
-
if (params.includeHidden !== void 0) {
|
|
2596
|
-
options.includeHidden = params.includeHidden;
|
|
2597
|
-
}
|
|
2598
|
-
if (params.defaultFontFamily) {
|
|
2599
|
-
options.defaultFontFamily = params.defaultFontFamily;
|
|
2600
|
-
}
|
|
2601
|
-
if (params.defaultFontSize) {
|
|
2602
|
-
options.defaultFontSize = params.defaultFontSize;
|
|
2603
|
-
}
|
|
2604
|
-
const svgStrings = pptxViewerCore.SvgExporter.exportAll(ctx.pptxData, options);
|
|
2605
|
-
return {
|
|
2606
|
-
pptxData: ctx.pptxData,
|
|
2607
|
-
dirty: false,
|
|
2608
|
-
result: { svgStrings, slideCount: svgStrings.length }
|
|
2609
|
-
};
|
|
2610
|
-
}
|
|
2611
|
-
function exportSlideSvg(ctx, params) {
|
|
2612
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2613
|
-
if (err) {
|
|
2614
|
-
throw new Error(err);
|
|
2615
|
-
}
|
|
2616
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2617
|
-
const width = ctx.pptxData.width ?? 960;
|
|
2618
|
-
const height = ctx.pptxData.height ?? 540;
|
|
2619
|
-
const options = {};
|
|
2620
|
-
if (params.defaultFontFamily) {
|
|
2621
|
-
options.defaultFontFamily = params.defaultFontFamily;
|
|
2622
|
-
}
|
|
2623
|
-
if (params.defaultFontSize) {
|
|
2624
|
-
options.defaultFontSize = params.defaultFontSize;
|
|
2625
|
-
}
|
|
2626
|
-
const svg = pptxViewerCore.SvgExporter.exportSlide(slide, width, height, options);
|
|
2627
|
-
return {
|
|
2628
|
-
pptxData: ctx.pptxData,
|
|
2629
|
-
dirty: false,
|
|
2630
|
-
result: { svg, slideIndex: params.slideIndex }
|
|
2631
|
-
};
|
|
2632
|
-
}
|
|
2633
|
-
function replaceGeometry(ctx, params) {
|
|
2634
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2635
|
-
if (err) {
|
|
2636
|
-
throw new Error(err);
|
|
2637
|
-
}
|
|
2638
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2639
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2640
|
-
if (!el) {
|
|
2641
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2642
|
-
}
|
|
2643
|
-
if (el.type !== "shape") {
|
|
2644
|
-
throw new Error(`Element '${params.elementId}' is not a shape.`);
|
|
2645
|
-
}
|
|
2646
|
-
const shape = el;
|
|
2647
|
-
if (params.svgPath) {
|
|
2648
|
-
pptxViewerCore.replaceWithCustomGeometry(shape, params.svgPath, params.pathWidth, params.pathHeight);
|
|
2649
|
-
return {
|
|
2650
|
-
pptxData: ctx.pptxData,
|
|
2651
|
-
dirty: true,
|
|
2652
|
-
result: { elementId: params.elementId, geometryType: "custom" }
|
|
2653
|
-
};
|
|
2654
|
-
}
|
|
2655
|
-
if (params.shapeType) {
|
|
2656
|
-
pptxViewerCore.replaceShapeGeometry(shape, params.shapeType, params.adjustments);
|
|
2657
|
-
return {
|
|
2658
|
-
pptxData: ctx.pptxData,
|
|
2659
|
-
dirty: true,
|
|
2660
|
-
result: { elementId: params.elementId, geometryType: params.shapeType }
|
|
2661
|
-
};
|
|
2662
|
-
}
|
|
2663
|
-
throw new Error("Either shapeType or svgPath must be provided.");
|
|
2664
|
-
}
|
|
2665
|
-
|
|
2666
|
-
// src/tools/hyperlink-tools.ts
|
|
2667
|
-
function manageHyperlinks(ctx, params) {
|
|
2668
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2669
|
-
if (err) {
|
|
2670
|
-
throw new Error(err);
|
|
2671
|
-
}
|
|
2672
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2673
|
-
switch (params.action) {
|
|
2674
|
-
case "list": {
|
|
2675
|
-
const hyperlinks = [];
|
|
2676
|
-
for (const el of slide.elements) {
|
|
2677
|
-
if (el.actionClick) {
|
|
2678
|
-
hyperlinks.push({
|
|
2679
|
-
elementId: el.id,
|
|
2680
|
-
trigger: "click",
|
|
2681
|
-
url: el.actionClick.url,
|
|
2682
|
-
tooltip: el.actionClick.tooltip,
|
|
2683
|
-
targetSlideIndex: el.actionClick.targetSlideIndex,
|
|
2684
|
-
actionType: el.actionClick.action
|
|
2685
|
-
});
|
|
2686
|
-
}
|
|
2687
|
-
if (el.actionHover) {
|
|
2688
|
-
hyperlinks.push({
|
|
2689
|
-
elementId: el.id,
|
|
2690
|
-
trigger: "hover",
|
|
2691
|
-
url: el.actionHover.url,
|
|
2692
|
-
tooltip: el.actionHover.tooltip,
|
|
2693
|
-
targetSlideIndex: el.actionHover.targetSlideIndex,
|
|
2694
|
-
actionType: el.actionHover.action
|
|
2695
|
-
});
|
|
2696
|
-
}
|
|
2697
|
-
}
|
|
2698
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", hyperlinks } };
|
|
2699
|
-
}
|
|
2700
|
-
case "set": {
|
|
2701
|
-
if (!params.elementId) {
|
|
2702
|
-
throw new Error("elementId is required for set action.");
|
|
2703
|
-
}
|
|
2704
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2705
|
-
if (!el) {
|
|
2706
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2707
|
-
}
|
|
2708
|
-
const trigger = params.trigger ?? "click";
|
|
2709
|
-
const action = {};
|
|
2710
|
-
if (params.url) {
|
|
2711
|
-
action.url = params.url;
|
|
2712
|
-
}
|
|
2713
|
-
if (params.tooltip) {
|
|
2714
|
-
action.tooltip = params.tooltip;
|
|
2715
|
-
}
|
|
2716
|
-
if (params.targetSlideIndex !== void 0) {
|
|
2717
|
-
action.targetSlideIndex = params.targetSlideIndex;
|
|
2718
|
-
}
|
|
2719
|
-
if (params.actionType) {
|
|
2720
|
-
switch (params.actionType) {
|
|
2721
|
-
case "url":
|
|
2722
|
-
action.action = "ppaction://hlinkpres";
|
|
2723
|
-
break;
|
|
2724
|
-
case "slide":
|
|
2725
|
-
action.action = "ppaction://hlinksldjump";
|
|
2726
|
-
break;
|
|
2727
|
-
case "nextSlide":
|
|
2728
|
-
action.action = "ppaction://hlinkshowjump?jump=nextslide";
|
|
2729
|
-
break;
|
|
2730
|
-
case "prevSlide":
|
|
2731
|
-
action.action = "ppaction://hlinkshowjump?jump=previousslide";
|
|
2732
|
-
break;
|
|
2733
|
-
case "firstSlide":
|
|
2734
|
-
action.action = "ppaction://hlinkshowjump?jump=firstslide";
|
|
2735
|
-
break;
|
|
2736
|
-
case "lastSlide":
|
|
2737
|
-
action.action = "ppaction://hlinkshowjump?jump=lastslide";
|
|
2738
|
-
break;
|
|
2739
|
-
case "endShow":
|
|
2740
|
-
action.action = "ppaction://hlinkshowjump?jump=endshow";
|
|
2741
|
-
break;
|
|
2742
|
-
}
|
|
2743
|
-
}
|
|
2744
|
-
if (trigger === "click") {
|
|
2745
|
-
el.actionClick = action;
|
|
2746
|
-
} else {
|
|
2747
|
-
el.actionHover = action;
|
|
2748
|
-
}
|
|
2749
|
-
return {
|
|
2750
|
-
pptxData: ctx.pptxData,
|
|
2751
|
-
dirty: true,
|
|
2752
|
-
result: { action: "set", elementId: params.elementId }
|
|
2753
|
-
};
|
|
2754
|
-
}
|
|
2755
|
-
case "remove": {
|
|
2756
|
-
if (!params.elementId) {
|
|
2757
|
-
throw new Error("elementId is required for remove action.");
|
|
2758
|
-
}
|
|
2759
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2760
|
-
if (!el) {
|
|
2761
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2762
|
-
}
|
|
2763
|
-
const trigger = params.trigger ?? "click";
|
|
2764
|
-
if (trigger === "click") {
|
|
2765
|
-
el.actionClick = void 0;
|
|
2766
|
-
} else {
|
|
2767
|
-
el.actionHover = void 0;
|
|
2768
|
-
}
|
|
2769
|
-
return {
|
|
2770
|
-
pptxData: ctx.pptxData,
|
|
2771
|
-
dirty: true,
|
|
2772
|
-
result: { action: "remove", elementId: params.elementId }
|
|
2773
|
-
};
|
|
2774
|
-
}
|
|
2775
|
-
default:
|
|
2776
|
-
throw new Error(`Unknown hyperlink action: ${String(params.action)}`);
|
|
2777
|
-
}
|
|
2778
|
-
}
|
|
2779
|
-
function exportToJson(ctx, params) {
|
|
2780
|
-
const document = pptxViewerCore.buildPptxJsonDocument(ctx.pptxData, { generator: "pptx-viewer-mcp" });
|
|
2781
|
-
const json = JSON.stringify(document, null, params.pretty === false ? void 0 : 2);
|
|
2782
|
-
return {
|
|
2783
|
-
pptxData: ctx.pptxData,
|
|
2784
|
-
dirty: false,
|
|
2785
|
-
result: {
|
|
2786
|
-
json,
|
|
2787
|
-
slideCount: document.slideCount,
|
|
2788
|
-
byteSize: new TextEncoder().encode(json).byteLength,
|
|
2789
|
-
assets: document.assets
|
|
2790
|
-
}
|
|
2791
|
-
};
|
|
2792
|
-
}
|
|
2793
|
-
function importFromJson(ctx, params) {
|
|
2794
|
-
const imported = pptxViewerCore.deserializePptxFromJson(params.json);
|
|
2795
|
-
pptxViewerCore.applyImportedPptxData(ctx.pptxData, imported);
|
|
2796
|
-
return {
|
|
2797
|
-
pptxData: ctx.pptxData,
|
|
2798
|
-
dirty: true,
|
|
2799
|
-
result: {
|
|
2800
|
-
slideCount: ctx.pptxData.slides.length,
|
|
2801
|
-
width: ctx.pptxData.width,
|
|
2802
|
-
height: ctx.pptxData.height
|
|
2803
|
-
}
|
|
2804
|
-
};
|
|
2805
|
-
}
|
|
2806
|
-
function getLayouts(ctx) {
|
|
2807
|
-
const layouts = [];
|
|
2808
|
-
if (ctx.pptxData.slideMasters) {
|
|
2809
|
-
for (const master of ctx.pptxData.slideMasters) {
|
|
2810
|
-
if (master.layouts) {
|
|
2811
|
-
for (const layout of master.layouts) {
|
|
2812
|
-
layouts.push({
|
|
2813
|
-
name: layout.name ?? "Unknown",
|
|
2814
|
-
path: layout.path
|
|
2815
|
-
});
|
|
2816
|
-
}
|
|
2817
|
-
}
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
2820
|
-
if (ctx.pptxData.layoutOptions) {
|
|
2821
|
-
for (const opt of ctx.pptxData.layoutOptions) {
|
|
2822
|
-
if (!layouts.some((l) => l.path === opt.path)) {
|
|
2823
|
-
layouts.push({ name: opt.name, path: opt.path, type: opt.type });
|
|
2824
|
-
}
|
|
2825
|
-
}
|
|
2826
|
-
}
|
|
2827
|
-
return {
|
|
2828
|
-
pptxData: ctx.pptxData,
|
|
2829
|
-
dirty: false,
|
|
2830
|
-
result: { layouts, count: layouts.length }
|
|
2831
|
-
};
|
|
2832
|
-
}
|
|
2833
|
-
function applyLayout(ctx, params) {
|
|
2834
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2835
|
-
if (err) {
|
|
2836
|
-
throw new Error(err);
|
|
2837
|
-
}
|
|
2838
|
-
let layout;
|
|
2839
|
-
if (params.layoutName) {
|
|
2840
|
-
layout = pptxViewerCore.findLayoutByName(ctx.pptxData, params.layoutName);
|
|
2841
|
-
} else if (params.layoutType) {
|
|
2842
|
-
layout = pptxViewerCore.findLayoutByType(ctx.pptxData, params.layoutType);
|
|
2843
|
-
} else {
|
|
2844
|
-
throw new Error("Either layoutName or layoutType must be provided.");
|
|
2845
|
-
}
|
|
2846
|
-
if (!layout) {
|
|
2847
|
-
throw new Error(
|
|
2848
|
-
`Layout not found: ${params.layoutName ?? params.layoutType}. Use get_layouts to see available layouts.`
|
|
2849
|
-
);
|
|
2850
|
-
}
|
|
2851
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2852
|
-
slide.layoutName = layout.name;
|
|
2853
|
-
if (layout.path) {
|
|
2854
|
-
slide.layoutPath = layout.path;
|
|
2855
|
-
}
|
|
2856
|
-
const master = ctx.pptxData.slideMasters?.find(
|
|
2857
|
-
(candidate) => candidate.layouts?.some((definition2) => definition2.path === layout.path)
|
|
2858
|
-
);
|
|
2859
|
-
const definition = master?.layouts?.find((candidate) => candidate.path === layout.path);
|
|
2860
|
-
for (const frame of definition?.placeholders ?? []) {
|
|
2861
|
-
if (["dt", "ftr", "sldnum", "hdr"].includes(frame.type)) {
|
|
2862
|
-
continue;
|
|
2863
|
-
}
|
|
2864
|
-
const ph = {
|
|
2865
|
-
"@_type": frame.type === "ctrtitle" ? "ctrTitle" : frame.type,
|
|
2866
|
-
...frame.idx !== void 0 ? { "@_idx": frame.idx } : {}
|
|
2867
|
-
};
|
|
2868
|
-
if (slide.elements.some((element) => {
|
|
2869
|
-
const nv = element.rawXml?.["p:nvSpPr"];
|
|
2870
|
-
const nvPr = nv?.["p:nvPr"];
|
|
2871
|
-
const existing = nvPr?.["p:ph"];
|
|
2872
|
-
return element.placeholderType === frame.type && String(existing?.["@_idx"] ?? "0") === String(frame.idx ?? "0");
|
|
2873
|
-
})) {
|
|
2874
|
-
continue;
|
|
2875
|
-
}
|
|
2876
|
-
const inherited = master?.placeholders?.find(
|
|
2877
|
-
(candidate) => candidate.type === frame.type && (candidate.idx ?? "0") === (frame.idx ?? "0")
|
|
2878
|
-
) ?? master?.placeholders?.find((candidate) => candidate.type === frame.type);
|
|
2879
|
-
slide.elements.push({
|
|
2880
|
-
id: generateElementId(),
|
|
2881
|
-
type: "text",
|
|
2882
|
-
placeholderType: frame.type,
|
|
2883
|
-
x: frame.x ?? inherited?.x ?? 0,
|
|
2884
|
-
y: frame.y ?? inherited?.y ?? 0,
|
|
2885
|
-
width: frame.width ?? inherited?.width ?? ctx.pptxData.width,
|
|
2886
|
-
height: frame.height ?? inherited?.height ?? ctx.pptxData.height,
|
|
2887
|
-
text: "",
|
|
2888
|
-
textSegments: [{ text: "", style: {} }],
|
|
2889
|
-
rawXml: {
|
|
2890
|
-
"p:nvSpPr": {
|
|
2891
|
-
"p:cNvPr": { "@_name": frame.type },
|
|
2892
|
-
"p:cNvSpPr": {},
|
|
2893
|
-
"p:nvPr": { "p:ph": ph }
|
|
2894
|
-
},
|
|
2895
|
-
"p:spPr": {}
|
|
2896
|
-
}
|
|
2897
|
-
});
|
|
2898
|
-
}
|
|
2899
|
-
return {
|
|
2900
|
-
pptxData: ctx.pptxData,
|
|
2901
|
-
dirty: true,
|
|
2902
|
-
result: { slideIndex: params.slideIndex, layoutName: layout.name ?? "Unknown" }
|
|
2903
|
-
};
|
|
2904
|
-
}
|
|
2905
|
-
function setElementLockT(ctx, params) {
|
|
2906
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2907
|
-
if (err) {
|
|
2908
|
-
throw new Error(err);
|
|
2909
|
-
}
|
|
2910
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2911
|
-
const idx = slide.elements.findIndex((e) => e.id === params.elementId);
|
|
2912
|
-
if (idx < 0) {
|
|
2913
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2914
|
-
}
|
|
2915
|
-
const extraLocks = {};
|
|
2916
|
-
if (params.noMove !== void 0) {
|
|
2917
|
-
extraLocks["noMove"] = params.noMove;
|
|
2918
|
-
}
|
|
2919
|
-
if (params.noResize !== void 0) {
|
|
2920
|
-
extraLocks["noResize"] = params.noResize;
|
|
2921
|
-
}
|
|
2922
|
-
if (params.noRotation !== void 0) {
|
|
2923
|
-
extraLocks["noRotation"] = params.noRotation;
|
|
2924
|
-
}
|
|
2925
|
-
if (params.noSelect !== void 0) {
|
|
2926
|
-
extraLocks["noSelect"] = params.noSelect;
|
|
2927
|
-
}
|
|
2928
|
-
if (params.noTextEdit !== void 0) {
|
|
2929
|
-
extraLocks["noTextEdit"] = params.noTextEdit;
|
|
2930
|
-
}
|
|
2931
|
-
const updated = pptxViewerCore.setElementLocked(slide.elements[idx], params.locked, extraLocks);
|
|
2932
|
-
slide.elements[idx] = updated;
|
|
2933
|
-
return {
|
|
2934
|
-
pptxData: ctx.pptxData,
|
|
2935
|
-
dirty: true,
|
|
2936
|
-
result: { elementId: params.elementId, locked: params.locked }
|
|
2937
|
-
};
|
|
2938
|
-
}
|
|
2939
|
-
|
|
2940
|
-
// src/tools/metadata-tools.ts
|
|
2941
|
-
function getMetadata(ctx) {
|
|
2942
|
-
return {
|
|
2943
|
-
pptxData: ctx.pptxData,
|
|
2944
|
-
dirty: false,
|
|
2945
|
-
result: {
|
|
2946
|
-
coreProperties: ctx.pptxData.coreProperties,
|
|
2947
|
-
appProperties: ctx.pptxData.appProperties,
|
|
2948
|
-
customProperties: ctx.pptxData.customProperties,
|
|
2949
|
-
slideCount: ctx.pptxData.slides.length
|
|
2950
|
-
}
|
|
2951
|
-
};
|
|
2952
|
-
}
|
|
2953
|
-
function updateMetadata(ctx, params) {
|
|
2954
|
-
const updated = [];
|
|
2955
|
-
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) {
|
|
2956
|
-
if (!ctx.pptxData.coreProperties) {
|
|
2957
|
-
ctx.pptxData.coreProperties = {};
|
|
2958
|
-
}
|
|
2959
|
-
const cp = ctx.pptxData.coreProperties;
|
|
2960
|
-
if (params.title !== void 0) {
|
|
2961
|
-
cp.title = params.title;
|
|
2962
|
-
updated.push("title");
|
|
2963
|
-
}
|
|
2964
|
-
if (params.subject !== void 0) {
|
|
2965
|
-
cp.subject = params.subject;
|
|
2966
|
-
updated.push("subject");
|
|
2967
|
-
}
|
|
2968
|
-
if (params.creator !== void 0) {
|
|
2969
|
-
cp.creator = params.creator;
|
|
2970
|
-
updated.push("creator");
|
|
2971
|
-
}
|
|
2972
|
-
if (params.keywords !== void 0) {
|
|
2973
|
-
cp.keywords = params.keywords;
|
|
2974
|
-
updated.push("keywords");
|
|
2975
|
-
}
|
|
2976
|
-
if (params.description !== void 0) {
|
|
2977
|
-
cp.description = params.description;
|
|
2978
|
-
updated.push("description");
|
|
2979
|
-
}
|
|
2980
|
-
if (params.lastModifiedBy !== void 0) {
|
|
2981
|
-
cp.lastModifiedBy = params.lastModifiedBy;
|
|
2982
|
-
updated.push("lastModifiedBy");
|
|
2983
|
-
}
|
|
2984
|
-
if (params.category !== void 0) {
|
|
2985
|
-
cp.category = params.category;
|
|
2986
|
-
updated.push("category");
|
|
2987
|
-
}
|
|
2988
|
-
}
|
|
2989
|
-
if (params.company !== void 0 || params.manager !== void 0) {
|
|
2990
|
-
if (!ctx.pptxData.appProperties) {
|
|
2991
|
-
ctx.pptxData.appProperties = {};
|
|
2992
|
-
}
|
|
2993
|
-
const ap = ctx.pptxData.appProperties;
|
|
2994
|
-
if (params.company !== void 0) {
|
|
2995
|
-
ap.company = params.company;
|
|
2996
|
-
updated.push("company");
|
|
2997
|
-
}
|
|
2998
|
-
if (params.manager !== void 0) {
|
|
2999
|
-
ap.manager = params.manager;
|
|
3000
|
-
updated.push("manager");
|
|
3001
|
-
}
|
|
3002
|
-
}
|
|
3003
|
-
if (params.customProperties) {
|
|
3004
|
-
if (!ctx.pptxData.customProperties) {
|
|
3005
|
-
ctx.pptxData.customProperties = [];
|
|
3006
|
-
}
|
|
3007
|
-
for (const cp of params.customProperties) {
|
|
3008
|
-
const valueStr = String(cp.value);
|
|
3009
|
-
const vtType = typeof cp.value === "number" ? "i4" : typeof cp.value === "boolean" ? "bool" : "lpwstr";
|
|
3010
|
-
const existing = ctx.pptxData.customProperties.find((p) => p.name === cp.name);
|
|
3011
|
-
if (existing) {
|
|
3012
|
-
existing.value = valueStr;
|
|
3013
|
-
existing.type = vtType;
|
|
3014
|
-
} else {
|
|
3015
|
-
ctx.pptxData.customProperties.push({ name: cp.name, value: valueStr, type: vtType });
|
|
3016
|
-
}
|
|
3017
|
-
updated.push(`custom:${cp.name}`);
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
|
-
return {
|
|
3021
|
-
pptxData: ctx.pptxData,
|
|
3022
|
-
dirty: updated.length > 0,
|
|
3023
|
-
result: { updated }
|
|
3024
|
-
};
|
|
3025
|
-
}
|
|
3026
|
-
function resolveOleElement(ctx, slideIndex, elementId) {
|
|
3027
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
3028
|
-
if (err) {
|
|
3029
|
-
throw new Error(err);
|
|
3030
|
-
}
|
|
3031
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
3032
|
-
const index = slide.elements.findIndex((e) => e.id === elementId);
|
|
3033
|
-
if (index === -1) {
|
|
3034
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
3035
|
-
}
|
|
3036
|
-
const element = slide.elements[index];
|
|
3037
|
-
if (element.type !== "ole") {
|
|
3038
|
-
throw new Error(`Element '${elementId}' is not an OLE object.`);
|
|
3039
|
-
}
|
|
3040
|
-
return { slide, element, index };
|
|
3041
|
-
}
|
|
3042
|
-
function commitOleElement(slide, index, updated) {
|
|
3043
|
-
slide.elements.splice(index, 1, updated);
|
|
3044
|
-
slide.isDirty = true;
|
|
3045
|
-
}
|
|
3046
|
-
async function getOleContent(ctx, params) {
|
|
3047
|
-
const { element } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3048
|
-
const kind = await pptxViewerCore.resolveOleEditorKindFromPayload(element);
|
|
3049
|
-
const base = { pptxData: ctx.pptxData, dirty: false };
|
|
3050
|
-
switch (kind) {
|
|
3051
|
-
case "sheet-xlsx":
|
|
3052
|
-
case "sheet-xls": {
|
|
3053
|
-
const sheet = await pptxViewerCore.getOleSheetGrid(element);
|
|
3054
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, sheet } };
|
|
3055
|
-
}
|
|
3056
|
-
case "document-docx":
|
|
3057
|
-
case "document-doc": {
|
|
3058
|
-
const paragraphs = await pptxViewerCore.getOleDocumentParagraphs(element);
|
|
3059
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, paragraphs } };
|
|
3060
|
-
}
|
|
3061
|
-
case "deck-pptx": {
|
|
3062
|
-
const deckSlides = await pptxViewerCore.getOleNestedDeckDetail(element);
|
|
3063
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, deckSlides } };
|
|
3064
|
-
}
|
|
3065
|
-
default:
|
|
3066
|
-
return {
|
|
3067
|
-
...base,
|
|
3068
|
-
result: {
|
|
3069
|
-
elementId: element.id,
|
|
3070
|
-
kind,
|
|
3071
|
-
editable: false,
|
|
3072
|
-
message: `This OLE object's content (${kind}) is not directly editable; use ole_replace_file to replace it wholesale.`
|
|
3073
|
-
}
|
|
3074
|
-
};
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
async function setOleSheetCell(ctx, params) {
|
|
3078
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3079
|
-
const updated = await pptxViewerCore.applyOleSheetCellEdit(element, {
|
|
3080
|
-
row: params.row,
|
|
3081
|
-
col: params.col,
|
|
3082
|
-
value: params.value
|
|
3083
|
-
});
|
|
3084
|
-
const changed = updated !== element;
|
|
3085
|
-
if (changed) {
|
|
3086
|
-
commitOleElement(slide, index, updated);
|
|
3087
|
-
}
|
|
3088
|
-
return {
|
|
3089
|
-
pptxData: ctx.pptxData,
|
|
3090
|
-
dirty: changed,
|
|
3091
|
-
result: { elementId: params.elementId, changed }
|
|
3092
|
-
};
|
|
3093
|
-
}
|
|
3094
|
-
async function setOleDocumentParagraph(ctx, params) {
|
|
3095
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3096
|
-
const updated = await pptxViewerCore.applyOleDocumentParagraphEdit(element, params.paragraphIndex, params.text);
|
|
3097
|
-
const changed = updated !== element;
|
|
3098
|
-
if (changed) {
|
|
3099
|
-
commitOleElement(slide, index, updated);
|
|
3100
|
-
}
|
|
3101
|
-
return {
|
|
3102
|
-
pptxData: ctx.pptxData,
|
|
3103
|
-
dirty: changed,
|
|
3104
|
-
result: { elementId: params.elementId, changed }
|
|
3105
|
-
};
|
|
3106
|
-
}
|
|
3107
|
-
async function setOleDeckSlideTitle(ctx, params) {
|
|
3108
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3109
|
-
const updated = await pptxViewerCore.applyOleNestedDeckElementTextEdit(
|
|
3110
|
-
element,
|
|
3111
|
-
params.deckSlideIndex,
|
|
3112
|
-
params.deckElementId,
|
|
3113
|
-
params.title
|
|
3114
|
-
);
|
|
3115
|
-
const changed = updated !== element;
|
|
3116
|
-
if (changed) {
|
|
3117
|
-
commitOleElement(slide, index, updated);
|
|
3118
|
-
}
|
|
3119
|
-
return {
|
|
3120
|
-
pptxData: ctx.pptxData,
|
|
3121
|
-
dirty: changed,
|
|
3122
|
-
result: { elementId: params.elementId, changed }
|
|
3123
|
-
};
|
|
3124
|
-
}
|
|
3125
|
-
async function setOleObjectNameT(ctx, params) {
|
|
3126
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3127
|
-
const updated = await pptxViewerCore.setOleObjectName(element, params.name);
|
|
3128
|
-
commitOleElement(slide, index, updated);
|
|
3129
|
-
return {
|
|
3130
|
-
pptxData: ctx.pptxData,
|
|
3131
|
-
dirty: true,
|
|
3132
|
-
result: { elementId: params.elementId, changed: true }
|
|
3133
|
-
};
|
|
3134
|
-
}
|
|
3135
|
-
async function replaceOleFileT(ctx, params) {
|
|
3136
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3137
|
-
const parsed = pptxViewerCore.parseDataUrlToBytes(params.fileData);
|
|
3138
|
-
if (!parsed) {
|
|
3139
|
-
throw new Error('fileData must be a base64 data URL, e.g. "data:<mime-type>;base64,<...>".');
|
|
3140
|
-
}
|
|
3141
|
-
const updated = await pptxViewerCore.replaceOleFile(element, parsed.bytes, params.fileName);
|
|
3142
|
-
commitOleElement(slide, index, updated);
|
|
3143
|
-
return {
|
|
3144
|
-
pptxData: ctx.pptxData,
|
|
3145
|
-
dirty: true,
|
|
3146
|
-
result: { elementId: params.elementId, changed: true }
|
|
3147
|
-
};
|
|
3148
|
-
}
|
|
3149
|
-
|
|
3150
|
-
// src/tools/presentation-tools.ts
|
|
3151
|
-
function getPresentationProperties(ctx) {
|
|
3152
|
-
return {
|
|
3153
|
-
pptxData: ctx.pptxData,
|
|
3154
|
-
dirty: false,
|
|
3155
|
-
result: {
|
|
3156
|
-
properties: ctx.pptxData.presentationProperties,
|
|
3157
|
-
slideCount: ctx.pptxData.slides.length,
|
|
3158
|
-
width: ctx.pptxData.width,
|
|
3159
|
-
height: ctx.pptxData.height
|
|
3160
|
-
}
|
|
3161
|
-
};
|
|
3162
|
-
}
|
|
3163
|
-
function updatePresentationProperties(ctx, params) {
|
|
3164
|
-
if (!ctx.pptxData.presentationProperties) {
|
|
3165
|
-
ctx.pptxData.presentationProperties = {};
|
|
3166
|
-
}
|
|
3167
|
-
const pp = ctx.pptxData.presentationProperties;
|
|
3168
|
-
if (params.showType !== void 0) {
|
|
3169
|
-
pp.showType = params.showType;
|
|
3170
|
-
}
|
|
3171
|
-
if (params.loopContinuously !== void 0) {
|
|
3172
|
-
pp.loopContinuously = params.loopContinuously;
|
|
3173
|
-
}
|
|
3174
|
-
if (params.showWithNarration !== void 0) {
|
|
3175
|
-
pp.showWithNarration = params.showWithNarration;
|
|
3176
|
-
}
|
|
3177
|
-
if (params.showWithAnimation !== void 0) {
|
|
3178
|
-
pp.showWithAnimation = params.showWithAnimation;
|
|
3179
|
-
}
|
|
3180
|
-
if (params.advanceMode !== void 0) {
|
|
3181
|
-
pp.advanceMode = params.advanceMode;
|
|
3182
|
-
}
|
|
3183
|
-
if (params.showSlidesMode !== void 0) {
|
|
3184
|
-
pp.showSlidesMode = params.showSlidesMode;
|
|
3185
|
-
}
|
|
3186
|
-
if (params.showSlidesFrom !== void 0) {
|
|
3187
|
-
pp.showSlidesFrom = params.showSlidesFrom;
|
|
3188
|
-
}
|
|
3189
|
-
if (params.showSlidesTo !== void 0) {
|
|
3190
|
-
pp.showSlidesTo = params.showSlidesTo;
|
|
3191
|
-
}
|
|
3192
|
-
if (params.penColor !== void 0) {
|
|
3193
|
-
pp.penColor = params.penColor;
|
|
3194
|
-
}
|
|
3195
|
-
return {
|
|
3196
|
-
pptxData: ctx.pptxData,
|
|
3197
|
-
dirty: true,
|
|
3198
|
-
result: { properties: pp }
|
|
3199
|
-
};
|
|
3200
|
-
}
|
|
3201
|
-
function manageSections(ctx, params) {
|
|
3202
|
-
switch (params.action) {
|
|
3203
|
-
case "list": {
|
|
3204
|
-
const sections = (ctx.pptxData.sections ?? []).map((s) => ({
|
|
3205
|
-
id: s.id,
|
|
3206
|
-
name: s.name,
|
|
3207
|
-
slideIds: s.slideIds,
|
|
3208
|
-
collapsed: s.collapsed,
|
|
3209
|
-
color: s.color
|
|
3210
|
-
}));
|
|
3211
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", sections } };
|
|
3212
|
-
}
|
|
3213
|
-
case "add": {
|
|
3214
|
-
if (!params.name) {
|
|
3215
|
-
throw new Error("name is required for add action.");
|
|
3216
|
-
}
|
|
3217
|
-
const section = pptxViewerCore.addSection(ctx.pptxData, params.name, params.slideIndices ?? []);
|
|
3218
|
-
return {
|
|
3219
|
-
pptxData: ctx.pptxData,
|
|
3220
|
-
dirty: true,
|
|
3221
|
-
result: {
|
|
3222
|
-
action: "add",
|
|
3223
|
-
section: { id: section.id, name: section.name, slideIds: section.slideIds }
|
|
3224
|
-
}
|
|
3225
|
-
};
|
|
3226
|
-
}
|
|
3227
|
-
case "remove": {
|
|
3228
|
-
if (!params.sectionId) {
|
|
3229
|
-
throw new Error("sectionId is required for remove action.");
|
|
3230
|
-
}
|
|
3231
|
-
const success = pptxViewerCore.removeSection(ctx.pptxData, params.sectionId);
|
|
3232
|
-
return { pptxData: ctx.pptxData, dirty: success, result: { action: "remove", success } };
|
|
3233
|
-
}
|
|
3234
|
-
case "reorder": {
|
|
3235
|
-
if (!params.sectionIds) {
|
|
3236
|
-
throw new Error("sectionIds is required for reorder action.");
|
|
3237
|
-
}
|
|
3238
|
-
pptxViewerCore.reorderSections(ctx.pptxData, params.sectionIds);
|
|
3239
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { action: "reorder", success: true } };
|
|
3240
|
-
}
|
|
3241
|
-
case "moveSlides": {
|
|
3242
|
-
if (!params.sectionId) {
|
|
3243
|
-
throw new Error("sectionId is required for moveSlides action.");
|
|
3244
|
-
}
|
|
3245
|
-
if (!params.slideIndices) {
|
|
3246
|
-
throw new Error("slideIndices is required for moveSlides action.");
|
|
3247
|
-
}
|
|
3248
|
-
const success = pptxViewerCore.moveSlidesToSection(ctx.pptxData, params.slideIndices, params.sectionId);
|
|
3249
|
-
return { pptxData: ctx.pptxData, dirty: success, result: { action: "moveSlides", success } };
|
|
3250
|
-
}
|
|
3251
|
-
case "getForSlide": {
|
|
3252
|
-
if (params.slideIndex === void 0) {
|
|
3253
|
-
throw new Error("slideIndex is required for getForSlide action.");
|
|
3254
|
-
}
|
|
3255
|
-
const section = pptxViewerCore.getSectionForSlide(ctx.pptxData, params.slideIndex);
|
|
3256
|
-
const info = section ? { id: section.id, name: section.name, slideIds: section.slideIds } : null;
|
|
3257
|
-
return {
|
|
3258
|
-
pptxData: ctx.pptxData,
|
|
3259
|
-
dirty: false,
|
|
3260
|
-
result: { action: "getForSlide", section: info }
|
|
3261
|
-
};
|
|
3262
|
-
}
|
|
3263
|
-
default:
|
|
3264
|
-
throw new Error(`Unknown section action: ${String(params.action)}`);
|
|
3265
|
-
}
|
|
3266
|
-
}
|
|
3267
|
-
|
|
3268
|
-
// src/tools/slide-tools.ts
|
|
3269
|
-
function getSlide(ctx, params) {
|
|
3270
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3271
|
-
if (err) {
|
|
3272
|
-
throw new Error(err);
|
|
3273
|
-
}
|
|
3274
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3275
|
-
return {
|
|
3276
|
-
pptxData: ctx.pptxData,
|
|
3277
|
-
dirty: false,
|
|
3278
|
-
result: {
|
|
3279
|
-
slideIndex: params.slideIndex,
|
|
3280
|
-
slideNumber: slide.slideNumber,
|
|
3281
|
-
hidden: slide.hidden ?? false,
|
|
3282
|
-
layoutName: slide.layoutName,
|
|
3283
|
-
backgroundColor: slide.backgroundColor,
|
|
3284
|
-
notes: slide.notes ?? "",
|
|
3285
|
-
commentCount: slide.comments?.length ?? 0,
|
|
3286
|
-
elements: slide.elements.map(describeElement)
|
|
3287
|
-
}
|
|
3288
|
-
};
|
|
3289
|
-
}
|
|
3290
|
-
function addSlide(ctx, params) {
|
|
3291
|
-
const { slides } = ctx.pptxData;
|
|
3292
|
-
const insertAt = params.insertAfterIndex !== void 0 && params.insertAfterIndex >= 0 ? Math.min(params.insertAfterIndex + 1, slides.length) : slides.length;
|
|
3293
|
-
const newSlide = {
|
|
3294
|
-
id: generateSlideId(),
|
|
3295
|
-
rId: "",
|
|
3296
|
-
slideNumber: insertAt + 1,
|
|
3297
|
-
elements: [],
|
|
3298
|
-
backgroundColor: params.backgroundColor
|
|
3299
|
-
};
|
|
3300
|
-
slides.splice(insertAt, 0, newSlide);
|
|
3301
|
-
slides.forEach((s, i) => {
|
|
3302
|
-
s.slideNumber = i + 1;
|
|
3303
|
-
});
|
|
3304
|
-
return {
|
|
3305
|
-
pptxData: ctx.pptxData,
|
|
3306
|
-
dirty: true,
|
|
3307
|
-
result: { newSlideIndex: insertAt, slideCount: slides.length }
|
|
3308
|
-
};
|
|
3309
|
-
}
|
|
3310
|
-
function deleteSlides(ctx, params) {
|
|
3311
|
-
const { slides } = ctx.pptxData;
|
|
3312
|
-
if (!params.slideIndexes || params.slideIndexes.length === 0) {
|
|
3313
|
-
throw new Error("slideIndexes is required for the delete action.");
|
|
3314
|
-
}
|
|
3315
|
-
const indexSet = new Set(params.slideIndexes);
|
|
3316
|
-
const invalid = params.slideIndexes.filter((i) => i < 0 || i >= slides.length);
|
|
3317
|
-
if (invalid.length > 0) {
|
|
3318
|
-
throw new Error(
|
|
3319
|
-
`Invalid slide indexes: ${invalid.join(", ")}. Valid range: 0\u2013${slides.length - 1}.`
|
|
3320
|
-
);
|
|
3321
|
-
}
|
|
3322
|
-
if (indexSet.size >= slides.length) {
|
|
3323
|
-
throw new Error("Cannot delete all slides. At least one slide must remain.");
|
|
3324
|
-
}
|
|
3325
|
-
ctx.pptxData.slides = slides.filter((_, i) => !indexSet.has(i));
|
|
3326
|
-
ctx.pptxData.slides.forEach((s, i) => {
|
|
3327
|
-
s.slideNumber = i + 1;
|
|
3328
|
-
});
|
|
3329
|
-
return {
|
|
3330
|
-
pptxData: ctx.pptxData,
|
|
3331
|
-
dirty: true,
|
|
3332
|
-
result: { deletedCount: indexSet.size, slideCount: ctx.pptxData.slides.length }
|
|
3333
|
-
};
|
|
3334
|
-
}
|
|
3335
|
-
function reorderSlides(ctx, params) {
|
|
3336
|
-
const { slides } = ctx.pptxData;
|
|
3337
|
-
if (!params.newOrder || params.newOrder.length !== slides.length) {
|
|
3338
|
-
throw new Error(
|
|
3339
|
-
`newOrder must have exactly ${slides.length} indexes. Got ${params.newOrder?.length ?? 0}.`
|
|
3340
|
-
);
|
|
3341
|
-
}
|
|
3342
|
-
const sorted = [...params.newOrder].sort((a, b) => a - b);
|
|
3343
|
-
const expected = slides.map((_, i) => i);
|
|
3344
|
-
if (JSON.stringify(sorted) !== JSON.stringify(expected)) {
|
|
3345
|
-
throw new Error(
|
|
3346
|
-
`newOrder must contain each index from 0 to ${slides.length - 1} exactly once.`
|
|
3347
|
-
);
|
|
3348
|
-
}
|
|
3349
|
-
ctx.pptxData.slides = params.newOrder.map((idx) => slides[idx]);
|
|
3350
|
-
ctx.pptxData.slides.forEach((s, i) => {
|
|
3351
|
-
s.slideNumber = i + 1;
|
|
3352
|
-
});
|
|
3353
|
-
return {
|
|
3354
|
-
pptxData: ctx.pptxData,
|
|
3355
|
-
dirty: true,
|
|
3356
|
-
result: { slideCount: ctx.pptxData.slides.length }
|
|
3357
|
-
};
|
|
3358
|
-
}
|
|
3359
|
-
function duplicateSlide(ctx, params) {
|
|
3360
|
-
const { slides } = ctx.pptxData;
|
|
3361
|
-
const err = validateSlideIndex(params.slideIndex, slides.length);
|
|
3362
|
-
if (err) {
|
|
3363
|
-
throw new Error(err);
|
|
3364
|
-
}
|
|
3365
|
-
const original = slides[params.slideIndex];
|
|
3366
|
-
const clone = structuredClone(original);
|
|
3367
|
-
clone.id = generateSlideId();
|
|
3368
|
-
clone.rId = "";
|
|
3369
|
-
for (const el of clone.elements) {
|
|
3370
|
-
el.id = generateElementId();
|
|
3371
|
-
}
|
|
3372
|
-
const insertIndex = params.targetIndex ?? params.slideIndex + 1;
|
|
3373
|
-
slides.splice(insertIndex, 0, clone);
|
|
3374
|
-
slides.forEach((s, i) => {
|
|
3375
|
-
s.slideNumber = i + 1;
|
|
3376
|
-
});
|
|
3377
|
-
return {
|
|
3378
|
-
pptxData: ctx.pptxData,
|
|
3379
|
-
dirty: true,
|
|
3380
|
-
result: { newSlideIndex: insertIndex, slideCount: slides.length }
|
|
3381
|
-
};
|
|
3382
|
-
}
|
|
3383
|
-
function updateSlideProperties(ctx, params) {
|
|
3384
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3385
|
-
if (err) {
|
|
3386
|
-
throw new Error(err);
|
|
3387
|
-
}
|
|
3388
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3389
|
-
if (params.backgroundColor !== void 0) {
|
|
3390
|
-
slide.backgroundColor = params.backgroundColor;
|
|
3391
|
-
}
|
|
3392
|
-
if (params.backgroundGradient !== void 0) {
|
|
3393
|
-
slide.backgroundGradient = params.backgroundGradient;
|
|
3394
|
-
}
|
|
3395
|
-
if (params.backgroundImage !== void 0) {
|
|
3396
|
-
slide.backgroundImage = params.backgroundImage;
|
|
3397
|
-
}
|
|
3398
|
-
if (params.notes !== void 0) {
|
|
3399
|
-
slide.notes = params.notes;
|
|
3400
|
-
}
|
|
3401
|
-
if (params.hidden !== void 0) {
|
|
3402
|
-
slide.hidden = params.hidden;
|
|
3403
|
-
}
|
|
3404
|
-
return {
|
|
3405
|
-
pptxData: ctx.pptxData,
|
|
3406
|
-
dirty: true,
|
|
3407
|
-
result: { slideIndex: params.slideIndex }
|
|
3408
|
-
};
|
|
3409
|
-
}
|
|
3410
|
-
function setSlideTransition(ctx, params) {
|
|
3411
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3412
|
-
if (err) {
|
|
3413
|
-
throw new Error(err);
|
|
3414
|
-
}
|
|
3415
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3416
|
-
if (params.type === "none") {
|
|
3417
|
-
slide.transition = void 0;
|
|
3418
|
-
} else {
|
|
3419
|
-
const transition = {
|
|
3420
|
-
type: params.type
|
|
3421
|
-
};
|
|
3422
|
-
if (params.durationMs !== void 0) {
|
|
3423
|
-
transition.durationMs = params.durationMs;
|
|
3424
|
-
}
|
|
3425
|
-
if (params.direction !== void 0) {
|
|
3426
|
-
transition.direction = params.direction;
|
|
3427
|
-
}
|
|
3428
|
-
if (params.advanceOnClick !== void 0) {
|
|
3429
|
-
transition.advanceOnClick = params.advanceOnClick;
|
|
3430
|
-
}
|
|
3431
|
-
if (params.advanceAfterMs !== void 0) {
|
|
3432
|
-
transition.advanceAfterMs = params.advanceAfterMs;
|
|
3433
|
-
}
|
|
3434
|
-
slide.transition = transition;
|
|
3435
|
-
}
|
|
3436
|
-
return {
|
|
3437
|
-
pptxData: ctx.pptxData,
|
|
3438
|
-
dirty: true,
|
|
3439
|
-
result: { slideIndex: params.slideIndex, transitionType: params.type }
|
|
3440
|
-
};
|
|
3441
|
-
}
|
|
3442
|
-
function setCanvasSize(ctx, params) {
|
|
3443
|
-
ctx.pptxData.width = params.width;
|
|
3444
|
-
ctx.pptxData.height = params.height;
|
|
3445
|
-
if (ctx.pptxData.widthEmu !== void 0) {
|
|
3446
|
-
ctx.pptxData.widthEmu = Math.round(params.width * 12700);
|
|
3447
|
-
}
|
|
3448
|
-
if (ctx.pptxData.heightEmu !== void 0) {
|
|
3449
|
-
ctx.pptxData.heightEmu = Math.round(params.height * 12700);
|
|
3450
|
-
}
|
|
3451
|
-
return {
|
|
3452
|
-
pptxData: ctx.pptxData,
|
|
3453
|
-
dirty: true,
|
|
3454
|
-
result: { canvasWidth: params.width, canvasHeight: params.height }
|
|
3455
|
-
};
|
|
3456
|
-
}
|
|
3457
|
-
function extractNodes(data) {
|
|
3458
|
-
if (!data.nodes) {
|
|
3459
|
-
return [];
|
|
3460
|
-
}
|
|
3461
|
-
return data.nodes.map((n) => ({
|
|
3462
|
-
id: n.id,
|
|
3463
|
-
text: n.text ?? "",
|
|
3464
|
-
children: n.children?.map((c) => ({ id: c.id, text: c.text ?? "" }))
|
|
3465
|
-
}));
|
|
3466
|
-
}
|
|
3467
|
-
function manageSmartArt(ctx, params) {
|
|
3468
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3469
|
-
if (err) {
|
|
3470
|
-
throw new Error(err);
|
|
3471
|
-
}
|
|
3472
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3473
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
3474
|
-
if (!el) {
|
|
3475
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
3476
|
-
}
|
|
3477
|
-
if (el.type !== "smartArt") {
|
|
3478
|
-
throw new Error(`Element '${params.elementId}' is not a SmartArt.`);
|
|
3479
|
-
}
|
|
3480
|
-
const smartArt = el;
|
|
3481
|
-
if (!smartArt.smartArtData) {
|
|
3482
|
-
throw new Error(`SmartArt '${params.elementId}' has no data.`);
|
|
3483
|
-
}
|
|
3484
|
-
switch (params.action) {
|
|
3485
|
-
case "getNodes": {
|
|
3486
|
-
return {
|
|
3487
|
-
pptxData: ctx.pptxData,
|
|
3488
|
-
dirty: false,
|
|
3489
|
-
result: {
|
|
3490
|
-
action: "getNodes",
|
|
3491
|
-
elementId: params.elementId,
|
|
3492
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3493
|
-
}
|
|
3494
|
-
};
|
|
3495
|
-
}
|
|
3496
|
-
case "addNode": {
|
|
3497
|
-
smartArt.smartArtData = pptxViewerCore.addSmartArtNode(
|
|
3498
|
-
smartArt.smartArtData,
|
|
3499
|
-
params.text ?? "",
|
|
3500
|
-
params.afterNodeId
|
|
3501
|
-
);
|
|
3502
|
-
return {
|
|
3503
|
-
pptxData: ctx.pptxData,
|
|
3504
|
-
dirty: true,
|
|
3505
|
-
result: {
|
|
3506
|
-
action: "addNode",
|
|
3507
|
-
elementId: params.elementId,
|
|
3508
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3509
|
-
}
|
|
3510
|
-
};
|
|
3511
|
-
}
|
|
3512
|
-
case "removeNode": {
|
|
3513
|
-
if (!params.nodeId) {
|
|
3514
|
-
throw new Error("nodeId is required for removeNode.");
|
|
3515
|
-
}
|
|
3516
|
-
smartArt.smartArtData = pptxViewerCore.removeSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
3517
|
-
return {
|
|
3518
|
-
pptxData: ctx.pptxData,
|
|
3519
|
-
dirty: true,
|
|
3520
|
-
result: {
|
|
3521
|
-
action: "removeNode",
|
|
3522
|
-
elementId: params.elementId,
|
|
3523
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3524
|
-
}
|
|
3525
|
-
};
|
|
3526
|
-
}
|
|
3527
|
-
case "updateNodeText": {
|
|
3528
|
-
if (!params.nodeId) {
|
|
3529
|
-
throw new Error("nodeId is required for updateNodeText.");
|
|
3530
|
-
}
|
|
3531
|
-
smartArt.smartArtData = pptxViewerCore.updateSmartArtNodeText(
|
|
3532
|
-
smartArt.smartArtData,
|
|
3533
|
-
params.nodeId,
|
|
3534
|
-
params.text ?? ""
|
|
3535
|
-
);
|
|
3536
|
-
return {
|
|
3537
|
-
pptxData: ctx.pptxData,
|
|
3538
|
-
dirty: true,
|
|
3539
|
-
result: { action: "updateNodeText", elementId: params.elementId }
|
|
3540
|
-
};
|
|
3541
|
-
}
|
|
3542
|
-
case "reorderNode": {
|
|
3543
|
-
if (!params.nodeId) {
|
|
3544
|
-
throw new Error("nodeId is required for reorderNode.");
|
|
3545
|
-
}
|
|
3546
|
-
const dir = params.direction ?? 1;
|
|
3547
|
-
smartArt.smartArtData = pptxViewerCore.reorderSmartArtNode(smartArt.smartArtData, params.nodeId, dir);
|
|
3548
|
-
return {
|
|
3549
|
-
pptxData: ctx.pptxData,
|
|
3550
|
-
dirty: true,
|
|
3551
|
-
result: {
|
|
3552
|
-
action: "reorderNode",
|
|
3553
|
-
elementId: params.elementId,
|
|
3554
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3555
|
-
}
|
|
3556
|
-
};
|
|
3557
|
-
}
|
|
3558
|
-
case "promoteNode": {
|
|
3559
|
-
if (!params.nodeId) {
|
|
3560
|
-
throw new Error("nodeId is required for promoteNode.");
|
|
3561
|
-
}
|
|
3562
|
-
smartArt.smartArtData = pptxViewerCore.promoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
3563
|
-
return {
|
|
3564
|
-
pptxData: ctx.pptxData,
|
|
3565
|
-
dirty: true,
|
|
3566
|
-
result: {
|
|
3567
|
-
action: "promoteNode",
|
|
3568
|
-
elementId: params.elementId,
|
|
3569
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3570
|
-
}
|
|
3571
|
-
};
|
|
3572
|
-
}
|
|
3573
|
-
case "demoteNode": {
|
|
3574
|
-
if (!params.nodeId) {
|
|
3575
|
-
throw new Error("nodeId is required for demoteNode.");
|
|
3576
|
-
}
|
|
3577
|
-
smartArt.smartArtData = pptxViewerCore.demoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
3578
|
-
return {
|
|
3579
|
-
pptxData: ctx.pptxData,
|
|
3580
|
-
dirty: true,
|
|
3581
|
-
result: {
|
|
3582
|
-
action: "demoteNode",
|
|
3583
|
-
elementId: params.elementId,
|
|
3584
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3585
|
-
}
|
|
3586
|
-
};
|
|
3587
|
-
}
|
|
3588
|
-
case "decompose": {
|
|
3589
|
-
const bounds = {
|
|
3590
|
-
x: smartArt.x,
|
|
3591
|
-
y: smartArt.y,
|
|
3592
|
-
width: smartArt.width,
|
|
3593
|
-
height: smartArt.height
|
|
3594
|
-
};
|
|
3595
|
-
const decomposed = pptxViewerCore.decomposeSmartArt(smartArt.smartArtData, bounds);
|
|
3596
|
-
if (!decomposed || decomposed.length === 0) {
|
|
3597
|
-
throw new Error("Failed to decompose SmartArt into shapes.");
|
|
3598
|
-
}
|
|
3599
|
-
const idx = slide.elements.indexOf(el);
|
|
3600
|
-
slide.elements.splice(idx, 1, ...decomposed);
|
|
3601
|
-
return {
|
|
3602
|
-
pptxData: ctx.pptxData,
|
|
3603
|
-
dirty: true,
|
|
3604
|
-
result: {
|
|
3605
|
-
action: "decompose",
|
|
3606
|
-
elementId: params.elementId,
|
|
3607
|
-
decomposedCount: decomposed.length
|
|
3608
|
-
}
|
|
3609
|
-
};
|
|
3610
|
-
}
|
|
3611
|
-
default:
|
|
3612
|
-
throw new Error(`Unknown SmartArt action: ${String(params.action)}`);
|
|
3613
|
-
}
|
|
3614
|
-
}
|
|
3615
|
-
function findTableElement(ctx, slideIndex, elementId) {
|
|
3616
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
3617
|
-
if (err) {
|
|
3618
|
-
throw new Error(err);
|
|
3619
|
-
}
|
|
3620
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
3621
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
3622
|
-
if (!el) {
|
|
3623
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
3624
|
-
}
|
|
3625
|
-
if (el.type !== "table") {
|
|
3626
|
-
throw new Error(`Element '${elementId}' is not a table.`);
|
|
3627
|
-
}
|
|
3628
|
-
return el;
|
|
3629
|
-
}
|
|
3630
|
-
function tableStyleIdsInUse(ctx) {
|
|
3631
|
-
const used = /* @__PURE__ */ new Set();
|
|
3632
|
-
for (const slide of ctx.pptxData.slides) {
|
|
3633
|
-
for (const el of slide.elements) {
|
|
3634
|
-
if (el.type === "table" && el.tableData?.tableStyleId) {
|
|
3635
|
-
used.add(pptxViewerCore.normalizeTableStyleGuid(el.tableData.tableStyleId));
|
|
3636
|
-
}
|
|
3637
|
-
}
|
|
3638
|
-
}
|
|
3639
|
-
return used;
|
|
3640
|
-
}
|
|
3641
|
-
function setTableStyleSection(ctx, params) {
|
|
3642
|
-
if (!pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.includes(params.section)) {
|
|
3643
|
-
throw new Error(
|
|
3644
|
-
`Unknown table style section '${params.section}'. Valid sections: ${pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.join(", ")}.`
|
|
3645
|
-
);
|
|
3646
|
-
}
|
|
3647
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3648
|
-
ctx.pptxData.tableStyleMap = map;
|
|
3649
|
-
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
|
|
3650
|
-
const entry = map[normalizedId];
|
|
3651
|
-
if (!entry) {
|
|
3652
|
-
throw new Error(
|
|
3653
|
-
`Table style '${params.styleId}' is not loaded in this presentation. Use create_table_style to add a new one.`
|
|
3654
|
-
);
|
|
3655
|
-
}
|
|
3656
|
-
if (params.styleName !== void 0) {
|
|
3657
|
-
entry.styleName = params.styleName;
|
|
3658
|
-
}
|
|
3659
|
-
const mutableEntry = entry;
|
|
3660
|
-
if (params.fill !== void 0) {
|
|
3661
|
-
mutableEntry[`${params.section}Fill`] = params.fill;
|
|
3662
|
-
}
|
|
3663
|
-
if (params.text !== void 0) {
|
|
3664
|
-
mutableEntry[`${params.section}Text`] = params.text;
|
|
3665
|
-
}
|
|
3666
|
-
if (params.borders !== void 0) {
|
|
3667
|
-
mutableEntry[`${params.section}Borders`] = params.borders;
|
|
3668
|
-
}
|
|
3669
|
-
if (params.cell3D !== void 0) {
|
|
3670
|
-
mutableEntry[`${params.section}Cell3D`] = params.cell3D;
|
|
3671
|
-
}
|
|
3672
|
-
return {
|
|
3673
|
-
pptxData: ctx.pptxData,
|
|
3674
|
-
dirty: true,
|
|
3675
|
-
result: { styleId: normalizedId, section: params.section }
|
|
3676
|
-
};
|
|
3677
|
-
}
|
|
3678
|
-
function createTableStyle(ctx, params) {
|
|
3679
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3680
|
-
ctx.pptxData.tableStyleMap = map;
|
|
3681
|
-
const basedOn = params.basedOnStyleId ? map[pptxViewerCore.normalizeTableStyleGuid(params.basedOnStyleId)] : void 0;
|
|
3682
|
-
if (params.basedOnStyleId && !basedOn) {
|
|
3683
|
-
throw new Error(`basedOnStyleId '${params.basedOnStyleId}' is not a loaded table style.`);
|
|
3684
|
-
}
|
|
3685
|
-
const entry = pptxViewerCore.createTableStyleEntry(map, { styleName: params.styleName, basedOn });
|
|
3686
|
-
pptxViewerCore.addTableStyleToMap(map, entry);
|
|
3687
|
-
return {
|
|
3688
|
-
pptxData: ctx.pptxData,
|
|
3689
|
-
dirty: true,
|
|
3690
|
-
result: { styleId: entry.styleId },
|
|
3691
|
-
...params.setAsDefault ? { saveOptions: { tableStylesDefaultId: entry.styleId } } : {}
|
|
3692
|
-
};
|
|
3693
|
-
}
|
|
3694
|
-
function deleteTableStyle(ctx, params) {
|
|
3695
|
-
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
|
|
3696
|
-
if (!params.force) {
|
|
3697
|
-
const used = tableStyleIdsInUse(ctx);
|
|
3698
|
-
if (used.has(normalizedId)) {
|
|
3699
|
-
throw new Error(
|
|
3700
|
-
`Table style '${params.styleId}' is assigned to at least one table on this deck. Reassign those tables first, or pass force: true.`
|
|
3701
|
-
);
|
|
3702
|
-
}
|
|
3703
|
-
}
|
|
3704
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3705
|
-
ctx.pptxData.tableStyleMap = map;
|
|
3706
|
-
pptxViewerCore.deleteTableStyleFromMap(map, normalizedId);
|
|
3707
|
-
return {
|
|
3708
|
-
pptxData: ctx.pptxData,
|
|
3709
|
-
dirty: true,
|
|
3710
|
-
result: { deleted: true },
|
|
3711
|
-
saveOptions: { tableStylesToDelete: [normalizedId] }
|
|
3712
|
-
};
|
|
3713
|
-
}
|
|
3714
|
-
function assignTableStyle(ctx, params) {
|
|
3715
|
-
const el = findTableElement(ctx, params.slideIndex, params.elementId);
|
|
3716
|
-
if (!el.tableData) {
|
|
3717
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3718
|
-
}
|
|
3719
|
-
const styleId = params.styleId ?? ctx.pptxData.tableStylesDefaultId;
|
|
3720
|
-
if (!styleId) {
|
|
3721
|
-
throw new Error(
|
|
3722
|
-
"styleId was not provided and this presentation has no tableStylesDefaultId to fall back to."
|
|
3723
|
-
);
|
|
3724
|
-
}
|
|
3725
|
-
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(styleId);
|
|
3726
|
-
el.tableData.tableStyleId = normalizedId;
|
|
3727
|
-
if (params.bandedRows !== void 0) {
|
|
3728
|
-
el.tableData.bandedRows = params.bandedRows;
|
|
3729
|
-
}
|
|
3730
|
-
if (params.bandedColumns !== void 0) {
|
|
3731
|
-
el.tableData.bandedColumns = params.bandedColumns;
|
|
3732
|
-
}
|
|
3733
|
-
if (params.firstRowHeader !== void 0) {
|
|
3734
|
-
el.tableData.firstRowHeader = params.firstRowHeader;
|
|
3735
|
-
}
|
|
3736
|
-
if (params.lastRow !== void 0) {
|
|
3737
|
-
el.tableData.lastRow = params.lastRow;
|
|
3738
|
-
}
|
|
3739
|
-
if (params.firstCol !== void 0) {
|
|
3740
|
-
el.tableData.firstCol = params.firstCol;
|
|
3741
|
-
}
|
|
3742
|
-
if (params.lastCol !== void 0) {
|
|
3743
|
-
el.tableData.lastCol = params.lastCol;
|
|
3744
|
-
}
|
|
3745
|
-
return {
|
|
3746
|
-
pptxData: ctx.pptxData,
|
|
3747
|
-
dirty: true,
|
|
3748
|
-
result: { elementId: params.elementId, styleId: normalizedId }
|
|
3749
|
-
};
|
|
3750
|
-
}
|
|
3751
|
-
function updateTableCells(ctx, params) {
|
|
3752
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3753
|
-
if (err) {
|
|
3754
|
-
throw new Error(err);
|
|
3755
|
-
}
|
|
3756
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3757
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
3758
|
-
if (!el) {
|
|
3759
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
3760
|
-
}
|
|
3761
|
-
if (el.type !== "table") {
|
|
3762
|
-
throw new Error(`Element '${params.elementId}' is not a table.`);
|
|
3763
|
-
}
|
|
3764
|
-
const tbl = el;
|
|
3765
|
-
if (!tbl.tableData) {
|
|
3766
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3767
|
-
}
|
|
3768
|
-
let count = 0;
|
|
3769
|
-
for (const cellUpdate of params.cells) {
|
|
3770
|
-
const row = tbl.tableData.rows[cellUpdate.row];
|
|
3771
|
-
if (!row) {
|
|
3772
|
-
throw new Error(
|
|
3773
|
-
`Row ${cellUpdate.row} out of range (table has ${tbl.tableData.rows.length} rows).`
|
|
3774
|
-
);
|
|
3775
|
-
}
|
|
3776
|
-
const cell = row.cells[cellUpdate.col];
|
|
3777
|
-
if (!cell) {
|
|
3778
|
-
throw new Error(`Column ${cellUpdate.col} out of range (row has ${row.cells.length} cells).`);
|
|
3779
|
-
}
|
|
3780
|
-
cell.text = cellUpdate.text;
|
|
3781
|
-
count++;
|
|
3782
|
-
}
|
|
3783
|
-
return {
|
|
3784
|
-
pptxData: ctx.pptxData,
|
|
3785
|
-
dirty: true,
|
|
3786
|
-
result: { updatedCount: count }
|
|
3787
|
-
};
|
|
3788
|
-
}
|
|
3789
|
-
function manageTableStructure(ctx, params) {
|
|
3790
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3791
|
-
if (err) {
|
|
3792
|
-
throw new Error(err);
|
|
3793
|
-
}
|
|
3794
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3795
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
3796
|
-
if (!el) {
|
|
3797
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
3798
|
-
}
|
|
3799
|
-
if (el.type !== "table") {
|
|
3800
|
-
throw new Error(`Element '${params.elementId}' is not a table.`);
|
|
3801
|
-
}
|
|
3802
|
-
const tbl = el;
|
|
3803
|
-
if (!tbl.tableData) {
|
|
3804
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3805
|
-
}
|
|
3806
|
-
const { rows, columnWidths } = tbl.tableData;
|
|
3807
|
-
const source = { ...tbl, tableData: structuredClone(tbl.tableData) };
|
|
3808
|
-
let edit;
|
|
3809
|
-
const colCount = columnWidths.length;
|
|
3810
|
-
const rowCount = rows.length;
|
|
3811
|
-
switch (params.action) {
|
|
3812
|
-
case "insertRow": {
|
|
3813
|
-
const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), rowCount) : rowCount;
|
|
3814
|
-
const newRow = {
|
|
3815
|
-
height: 40,
|
|
3816
|
-
cells: Array.from({ length: colCount }, (_, c) => ({
|
|
3817
|
-
text: params.cellTexts?.[c] ?? ""
|
|
3818
|
-
}))
|
|
3819
|
-
};
|
|
3820
|
-
rows.splice(pos, 0, newRow);
|
|
3821
|
-
edit = { axis: "row", action: "insert", index: pos };
|
|
3822
|
-
break;
|
|
3823
|
-
}
|
|
3824
|
-
case "deleteRow": {
|
|
3825
|
-
if (rowCount <= 1) {
|
|
3826
|
-
throw new Error("Cannot delete the last row of a table.");
|
|
3827
|
-
}
|
|
3828
|
-
const ref = params.referenceIndex ?? rowCount - 1;
|
|
3829
|
-
if (ref < 0 || ref >= rowCount) {
|
|
3830
|
-
throw new Error(`Row index ${ref} out of range (0\u2013${rowCount - 1}).`);
|
|
3831
|
-
}
|
|
3832
|
-
rows.splice(ref, 1);
|
|
3833
|
-
edit = { axis: "row", action: "delete", index: ref };
|
|
3834
|
-
break;
|
|
3835
|
-
}
|
|
3836
|
-
case "insertColumn": {
|
|
3837
|
-
const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), colCount) : colCount;
|
|
3838
|
-
const newWidth = 1 / (colCount + 1);
|
|
3839
|
-
const scaleFactor = colCount / (colCount + 1);
|
|
3840
|
-
for (let i = 0; i < columnWidths.length; i++) {
|
|
3841
|
-
columnWidths[i] *= scaleFactor;
|
|
3842
|
-
}
|
|
3843
|
-
columnWidths.splice(pos, 0, newWidth);
|
|
3844
|
-
edit = { axis: "column", action: "insert", index: pos };
|
|
3845
|
-
for (let r = 0; r < rows.length; r++) {
|
|
3846
|
-
rows[r].cells.splice(pos, 0, {
|
|
3847
|
-
text: params.cellTexts?.[r] ?? ""
|
|
3848
|
-
});
|
|
3849
|
-
}
|
|
3850
|
-
break;
|
|
3851
|
-
}
|
|
3852
|
-
case "deleteColumn": {
|
|
3853
|
-
if (colCount <= 1) {
|
|
3854
|
-
throw new Error("Cannot delete the last column of a table.");
|
|
3855
|
-
}
|
|
3856
|
-
const ref = params.referenceIndex ?? colCount - 1;
|
|
3857
|
-
if (ref < 0 || ref >= colCount) {
|
|
3858
|
-
throw new Error(`Column index ${ref} out of range (0\u2013${colCount - 1}).`);
|
|
3859
|
-
}
|
|
3860
|
-
const removedWidth = columnWidths[ref];
|
|
3861
|
-
columnWidths.splice(ref, 1);
|
|
3862
|
-
edit = { axis: "column", action: "delete", index: ref };
|
|
3863
|
-
const remaining = columnWidths.length;
|
|
3864
|
-
if (remaining > 0) {
|
|
3865
|
-
const extra = removedWidth / remaining;
|
|
3866
|
-
for (let i = 0; i < columnWidths.length; i++) {
|
|
3867
|
-
columnWidths[i] += extra;
|
|
3868
|
-
}
|
|
3869
|
-
}
|
|
3870
|
-
for (const row of rows) {
|
|
3871
|
-
row.cells.splice(ref, 1);
|
|
3872
|
-
}
|
|
3873
|
-
break;
|
|
3874
|
-
}
|
|
3875
|
-
default: {
|
|
3876
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
3877
|
-
}
|
|
3878
|
-
}
|
|
3879
|
-
const rawXml = pptxViewerCore.rebuildTableStructureInRawXml(source, tbl.tableData, edit);
|
|
3880
|
-
if (rawXml) {
|
|
3881
|
-
tbl.rawXml = rawXml;
|
|
3882
|
-
}
|
|
3883
|
-
return {
|
|
3884
|
-
pptxData: ctx.pptxData,
|
|
3885
|
-
dirty: true,
|
|
3886
|
-
result: {
|
|
3887
|
-
rowCount: tbl.tableData.rows.length,
|
|
3888
|
-
columnCount: tbl.tableData.columnWidths.length
|
|
3889
|
-
}
|
|
3890
|
-
};
|
|
3891
|
-
}
|
|
3892
|
-
function findPlaceholdersT(ctx) {
|
|
3893
|
-
const placeholders = pptxViewerCore.findPlaceholders(ctx.pptxData);
|
|
3894
|
-
return {
|
|
3895
|
-
pptxData: ctx.pptxData,
|
|
3896
|
-
dirty: false,
|
|
3897
|
-
result: { placeholders, count: placeholders.length }
|
|
3898
|
-
};
|
|
3899
|
-
}
|
|
3900
|
-
function applyTemplateT(ctx, params) {
|
|
3901
|
-
pptxViewerCore.applyTemplate(ctx.pptxData, params.data);
|
|
3902
|
-
return {
|
|
3903
|
-
pptxData: ctx.pptxData,
|
|
3904
|
-
dirty: true,
|
|
3905
|
-
result: { applied: true, slideCount: ctx.pptxData.slides.length }
|
|
3906
|
-
};
|
|
3907
|
-
}
|
|
3908
|
-
function getThemeInfo(ctx) {
|
|
3909
|
-
const theme = ctx.pptxData.theme;
|
|
3910
|
-
return {
|
|
3911
|
-
pptxData: ctx.pptxData,
|
|
3912
|
-
dirty: false,
|
|
3913
|
-
result: {
|
|
3914
|
-
themeName: theme?.name,
|
|
3915
|
-
colorScheme: theme?.colorScheme,
|
|
3916
|
-
fontScheme: theme?.fontScheme,
|
|
3917
|
-
availablePresets: Object.keys(pptxViewerCore.ThemePresets)
|
|
3918
|
-
}
|
|
3919
|
-
};
|
|
3920
|
-
}
|
|
3921
|
-
function applyThemePreset(ctx, params) {
|
|
3922
|
-
const preset = pptxViewerCore.getThemePreset(params.presetName);
|
|
3923
|
-
if (!preset) {
|
|
3924
|
-
throw new Error(
|
|
3925
|
-
`Unknown theme preset: "${params.presetName}". Available: ${Object.keys(pptxViewerCore.ThemePresets).join(", ")}`
|
|
3926
|
-
);
|
|
3927
|
-
}
|
|
3928
|
-
if (!ctx.pptxData.theme) {
|
|
3929
|
-
ctx.pptxData.theme = {};
|
|
3930
|
-
}
|
|
3931
|
-
const theme = ctx.pptxData.theme;
|
|
3932
|
-
theme.name = preset.name;
|
|
3933
|
-
theme.colorScheme = preset.colors;
|
|
3934
|
-
if (preset.fonts) {
|
|
3935
|
-
theme.fontScheme = preset.fonts;
|
|
3936
|
-
}
|
|
3937
|
-
return {
|
|
3938
|
-
pptxData: ctx.pptxData,
|
|
3939
|
-
dirty: true,
|
|
3940
|
-
result: {
|
|
3941
|
-
appliedPreset: params.presetName,
|
|
3942
|
-
colorScheme: theme.colorScheme
|
|
3943
|
-
}
|
|
3944
|
-
};
|
|
3945
|
-
}
|
|
3946
|
-
function updateThemeColors(ctx, params) {
|
|
3947
|
-
if (!ctx.pptxData.theme) {
|
|
3948
|
-
ctx.pptxData.theme = {};
|
|
3949
|
-
}
|
|
3950
|
-
const theme = ctx.pptxData.theme;
|
|
3951
|
-
if (!theme.colorScheme) {
|
|
3952
|
-
theme.colorScheme = {
|
|
3953
|
-
dk1: "#000000",
|
|
3954
|
-
lt1: "#FFFFFF",
|
|
3955
|
-
dk2: "#44546A",
|
|
3956
|
-
lt2: "#E7E6E6",
|
|
3957
|
-
accent1: "#4472C4",
|
|
3958
|
-
accent2: "#ED7D31",
|
|
3959
|
-
accent3: "#A5A5A5",
|
|
3960
|
-
accent4: "#FFC000",
|
|
3961
|
-
accent5: "#5B9BD5",
|
|
3962
|
-
accent6: "#70AD47",
|
|
3963
|
-
hlink: "#0563C1",
|
|
3964
|
-
folHlink: "#954F72"
|
|
3965
|
-
};
|
|
3966
|
-
}
|
|
3967
|
-
const cs = theme.colorScheme;
|
|
3968
|
-
for (const key of Object.keys(params)) {
|
|
3969
|
-
if (params[key] !== void 0) {
|
|
3970
|
-
cs[key] = params[key];
|
|
3971
|
-
}
|
|
3972
|
-
}
|
|
3973
|
-
return {
|
|
3974
|
-
pptxData: ctx.pptxData,
|
|
3975
|
-
dirty: true,
|
|
3976
|
-
result: { colorScheme: cs }
|
|
3977
|
-
};
|
|
3978
|
-
}
|
|
3979
|
-
function updateThemeFonts(ctx, params) {
|
|
3980
|
-
if (!ctx.pptxData.theme) {
|
|
3981
|
-
ctx.pptxData.theme = {};
|
|
3982
|
-
}
|
|
3983
|
-
const theme = ctx.pptxData.theme;
|
|
3984
|
-
if (!theme.fontScheme) {
|
|
3985
|
-
theme.fontScheme = {};
|
|
3986
|
-
}
|
|
3987
|
-
if (params.majorFont !== void 0) {
|
|
3988
|
-
theme.fontScheme.majorFont = { latin: params.majorFont };
|
|
3989
|
-
}
|
|
3990
|
-
if (params.minorFont !== void 0) {
|
|
3991
|
-
theme.fontScheme.minorFont = { latin: params.minorFont };
|
|
3992
|
-
}
|
|
3993
|
-
return {
|
|
3994
|
-
pptxData: ctx.pptxData,
|
|
3995
|
-
dirty: true,
|
|
3996
|
-
result: { fontScheme: theme.fontScheme }
|
|
3997
|
-
};
|
|
3998
|
-
}
|
|
3999
|
-
async function validatePresentation(rawBytes) {
|
|
4000
|
-
const result = await pptxViewerCore.validatePptx(rawBytes);
|
|
4001
|
-
return {
|
|
4002
|
-
valid: result.valid,
|
|
4003
|
-
issueCount: result.issues.length,
|
|
4004
|
-
errors: result.issues.filter((i) => i.severity === "error").length,
|
|
4005
|
-
warnings: result.issues.filter((i) => i.severity === "warning").length,
|
|
4006
|
-
issues: result.issues
|
|
4007
|
-
};
|
|
4008
|
-
}
|
|
4009
|
-
async function repairPresentation(rawBytes) {
|
|
4010
|
-
const result = await pptxViewerCore.repairPptx(rawBytes);
|
|
4011
|
-
return {
|
|
4012
|
-
result: {
|
|
4013
|
-
repairCount: result.repairs.length,
|
|
4014
|
-
repairs: result.repairs
|
|
4015
|
-
},
|
|
4016
|
-
repairedBytes: result.repaired
|
|
4017
|
-
};
|
|
4018
|
-
}
|
|
4019
|
-
var PPTX_MIME_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
4020
|
-
async function loadPresentation(filePath, execCtx) {
|
|
4021
|
-
const rawBytes = await execCtx.filesystem.readFile(filePath);
|
|
4022
|
-
if (execCtx.collaboration) {
|
|
4023
|
-
const room = execCtx.collaboration.getRoom(filePath);
|
|
4024
|
-
if (room) {
|
|
4025
|
-
const codec = execCtx.collaboration.getCodec(filePath);
|
|
4026
|
-
if (codec) {
|
|
4027
|
-
const currentBytes = await codec.dehydrate(room.ydoc);
|
|
4028
|
-
const handler2 = new pptxViewerCore.PptxHandler();
|
|
4029
|
-
const pptxData2 = await handler2.load(currentBytes.buffer);
|
|
4030
|
-
return { pptxData: pptxData2, rawBytes };
|
|
4031
|
-
}
|
|
4032
|
-
}
|
|
4033
|
-
}
|
|
4034
|
-
const handler = new pptxViewerCore.PptxHandler();
|
|
4035
|
-
const pptxData = await handler.load(rawBytes.buffer);
|
|
4036
|
-
return { pptxData, rawBytes };
|
|
4037
|
-
}
|
|
4038
|
-
async function savePresentation(filePath, pptxData, rawBytes, execCtx, tableStyleSaveOptions) {
|
|
4039
|
-
const handler = new pptxViewerCore.PptxHandler();
|
|
4040
|
-
await handler.load(rawBytes.buffer);
|
|
4041
|
-
const outputBytes = await handler.save(pptxData.slides, {
|
|
4042
|
-
headerFooter: pptxData.headerFooter,
|
|
4043
|
-
// `pptxData.tableStyleMap` carries any in-memory table-style edits a
|
|
4044
|
-
// tool made (e.g. `set_table_style_section`, `create_table_style`);
|
|
4045
|
-
// without forwarding it here those edits were silently dropped on
|
|
4046
|
-
// save even though the core save pipeline already supports them.
|
|
4047
|
-
tableStyles: pptxData.tableStyleMap,
|
|
4048
|
-
...tableStyleSaveOptions
|
|
4049
|
-
});
|
|
4050
|
-
if (execCtx.collaboration) {
|
|
4051
|
-
const room = execCtx.collaboration.getRoom(filePath);
|
|
4052
|
-
if (room) {
|
|
4053
|
-
const codec = execCtx.collaboration.getCodec(filePath);
|
|
4054
|
-
if (codec) {
|
|
4055
|
-
const origin = execCtx.collaboration.agentOrigin(execCtx.agentName ?? "pptx-tool");
|
|
4056
|
-
await codec.hydrate(room.ydoc, outputBytes, origin);
|
|
4057
|
-
if (execCtx.viewer) {
|
|
4058
|
-
execCtx.viewer.replaceContent(filePath, outputBytes, {
|
|
4059
|
-
markDirty: false,
|
|
4060
|
-
mimeType: PPTX_MIME_TYPE
|
|
4061
|
-
});
|
|
4062
|
-
}
|
|
4063
|
-
return { savedToDisk: false, routedThroughCollaboration: true };
|
|
4064
|
-
}
|
|
4065
|
-
}
|
|
4066
|
-
}
|
|
4067
|
-
await execCtx.filesystem.writeFile(filePath, outputBytes);
|
|
4068
|
-
if (execCtx.viewer) {
|
|
4069
|
-
execCtx.viewer.replaceContent(filePath, outputBytes, {
|
|
4070
|
-
markDirty: false,
|
|
4071
|
-
mimeType: PPTX_MIME_TYPE
|
|
4072
|
-
});
|
|
4073
|
-
}
|
|
4074
|
-
return { savedToDisk: true, routedThroughCollaboration: false };
|
|
4075
|
-
}
|
|
4076
|
-
async function executeToolWithContext(filePath, execCtx, toolFn) {
|
|
4077
|
-
const { pptxData, rawBytes } = await loadPresentation(filePath, execCtx);
|
|
4078
|
-
const toolResult = await toolFn({ pptxData });
|
|
4079
|
-
if (toolResult.dirty) {
|
|
4080
|
-
const saveResult = await savePresentation(
|
|
4081
|
-
filePath,
|
|
4082
|
-
toolResult.pptxData,
|
|
4083
|
-
rawBytes,
|
|
4084
|
-
execCtx,
|
|
4085
|
-
toolResult.saveOptions
|
|
4086
|
-
);
|
|
4087
|
-
return { ...toolResult.result, ...saveResult };
|
|
4088
|
-
}
|
|
4089
|
-
return toolResult.result;
|
|
4090
|
-
}
|
|
934
|
+
var formatChartDataPoint = automation.apiToolsChartFormattingTools.formatChartDataPoint;
|
|
935
|
+
var formatChartDataLabel = automation.apiToolsChartFormattingTools.formatChartDataLabel;
|
|
936
|
+
var formatChartSeries = automation.apiToolsChartFormattingTools.formatChartSeries;
|
|
937
|
+
var setChartHelperLineT = automation.apiToolsChartFormattingTools.setChartHelperLineT;
|
|
938
|
+
var setChartColorMapOverrideT = automation.apiToolsChartFormattingTools.setChartColorMapOverrideT;
|
|
939
|
+
var updateChart = automation.apiToolsChartTools.updateChart;
|
|
940
|
+
var addChartSeriesT = automation.apiToolsChartTools.addChartSeriesT;
|
|
941
|
+
var removeChartSeriesT = automation.apiToolsChartTools.removeChartSeriesT;
|
|
942
|
+
var updateChartSeriesData = automation.apiToolsChartTools.updateChartSeriesData;
|
|
943
|
+
var createChart = automation.apiToolsChartTools.createChart;
|
|
944
|
+
var listChartUserShapesT = automation.apiToolsChartUserShapeTools.listChartUserShapesT;
|
|
945
|
+
var addChartUserShapeT = automation.apiToolsChartUserShapeTools.addChartUserShapeT;
|
|
946
|
+
var updateChartUserShapeT = automation.apiToolsChartUserShapeTools.updateChartUserShapeT;
|
|
947
|
+
var removeChartUserShapeT = automation.apiToolsChartUserShapeTools.removeChartUserShapeT;
|
|
948
|
+
var findText = automation.apiToolsContentTools.findText;
|
|
949
|
+
var replaceText = automation.apiToolsContentTools.replaceText;
|
|
950
|
+
var manageComments = automation.apiToolsContentTools.manageComments;
|
|
951
|
+
var convertToMarkdown = automation.apiToolsConversionTools.convertToMarkdown;
|
|
952
|
+
var addElement = automation.apiToolsElementTools.addElement;
|
|
953
|
+
var updateElement = automation.apiToolsElementTools.updateElement;
|
|
954
|
+
var renameElement = automation.apiToolsElementTools.renameElement;
|
|
955
|
+
var deleteElements = automation.apiToolsElementTools.deleteElements;
|
|
956
|
+
var arrangeElements = automation.apiToolsElementTools.arrangeElements;
|
|
957
|
+
var cloneElement = automation.apiToolsElementTools.cloneElement;
|
|
958
|
+
var setElementAnimation = automation.apiToolsElementTools.setElementAnimation;
|
|
959
|
+
var groupElements = automation.apiToolsElementTools.groupElements;
|
|
960
|
+
var ungroupElements = automation.apiToolsElementTools.ungroupElements;
|
|
961
|
+
var batchUpdateElements = automation.apiToolsElementTools.batchUpdateElements;
|
|
962
|
+
var exportToSvg = automation.apiToolsExportTools.exportToSvg;
|
|
963
|
+
var exportSlideSvg = automation.apiToolsExportTools.exportSlideSvg;
|
|
964
|
+
var replaceGeometry = automation.apiToolsGeometryTools.replaceGeometry;
|
|
965
|
+
var manageHyperlinks = automation.apiToolsHyperlinkTools.manageHyperlinks;
|
|
966
|
+
var exportToJson = automation.apiToolsJsonTools.exportToJson;
|
|
967
|
+
var importFromJson = automation.apiToolsJsonTools.importFromJson;
|
|
968
|
+
var getLayouts = automation.apiToolsLayoutTools.getLayouts;
|
|
969
|
+
var applyLayout = automation.apiToolsLayoutTools.applyLayout;
|
|
970
|
+
var setElementLockT = automation.apiToolsLockTools.setElementLockT;
|
|
971
|
+
var getMetadata = automation.apiToolsMetadataTools.getMetadata;
|
|
972
|
+
var updateMetadata = automation.apiToolsMetadataTools.updateMetadata;
|
|
973
|
+
var getOleContent = automation.apiToolsOleTools.getOleContent;
|
|
974
|
+
var setOleSheetCell = automation.apiToolsOleTools.setOleSheetCell;
|
|
975
|
+
var setOleDocumentParagraph = automation.apiToolsOleTools.setOleDocumentParagraph;
|
|
976
|
+
var setOleDeckSlideTitle = automation.apiToolsOleTools.setOleDeckSlideTitle;
|
|
977
|
+
var setOleObjectNameT = automation.apiToolsOleTools.setOleObjectNameT;
|
|
978
|
+
var replaceOleFileT = automation.apiToolsOleTools.replaceOleFileT;
|
|
979
|
+
var getPresentationProperties = automation.apiToolsPresentationTools.getPresentationProperties;
|
|
980
|
+
var updatePresentationProperties = automation.apiToolsPresentationTools.updatePresentationProperties;
|
|
981
|
+
var manageSections = automation.apiToolsSectionTools.manageSections;
|
|
982
|
+
var getSlide = automation.apiToolsSlideTools.getSlide;
|
|
983
|
+
var addSlide = automation.apiToolsSlideTools.addSlide;
|
|
984
|
+
var deleteSlides = automation.apiToolsSlideTools.deleteSlides;
|
|
985
|
+
var reorderSlides = automation.apiToolsSlideTools.reorderSlides;
|
|
986
|
+
var duplicateSlide = automation.apiToolsSlideTools.duplicateSlide;
|
|
987
|
+
var updateSlideProperties = automation.apiToolsSlideTools.updateSlideProperties;
|
|
988
|
+
var setSlideTransition = automation.apiToolsSlideTools.setSlideTransition;
|
|
989
|
+
var setCanvasSize = automation.apiToolsSlideTools.setCanvasSize;
|
|
990
|
+
var manageSmartArt = automation.apiToolsSmartartTools.manageSmartArt;
|
|
991
|
+
automation.apiToolsStyleTools.ALT_TEXT_ELEMENT_TYPES;
|
|
992
|
+
automation.apiToolsStyleTools.TITLE_ELEMENT_TYPES;
|
|
993
|
+
automation.apiToolsStyleTools.applyElementAltText;
|
|
994
|
+
automation.apiToolsStyleTools.applyElementTitle;
|
|
995
|
+
var updateElementStyle = automation.apiToolsStyleTools.updateElementStyle;
|
|
996
|
+
var runAccessibilityCheck = automation.apiToolsStyleTools.runAccessibilityCheck;
|
|
997
|
+
var setTableStyleSection = automation.apiToolsTableStyleTools.setTableStyleSection;
|
|
998
|
+
var createTableStyle = automation.apiToolsTableStyleTools.createTableStyle;
|
|
999
|
+
var deleteTableStyle = automation.apiToolsTableStyleTools.deleteTableStyle;
|
|
1000
|
+
var assignTableStyle = automation.apiToolsTableStyleTools.assignTableStyle;
|
|
1001
|
+
var updateTableCells = automation.apiToolsTableTools.updateTableCells;
|
|
1002
|
+
var manageTableStructure = automation.apiToolsTableTools.manageTableStructure;
|
|
1003
|
+
var findPlaceholdersT = automation.apiToolsTemplateTools.findPlaceholdersT;
|
|
1004
|
+
var applyTemplateT = automation.apiToolsTemplateTools.applyTemplateT;
|
|
1005
|
+
var getThemeInfo = automation.apiToolsThemeTools.getThemeInfo;
|
|
1006
|
+
var applyThemePreset = automation.apiToolsThemeTools.applyThemePreset;
|
|
1007
|
+
var updateThemeColors = automation.apiToolsThemeTools.updateThemeColors;
|
|
1008
|
+
var updateThemeFonts = automation.apiToolsThemeTools.updateThemeFonts;
|
|
1009
|
+
var validatePresentation = automation.apiToolsValidationTools.validatePresentation;
|
|
1010
|
+
var repairPresentation = automation.apiToolsValidationTools.repairPresentation;
|
|
1011
|
+
automation.apiExecution.loadPresentation;
|
|
1012
|
+
automation.apiExecution.savePresentation;
|
|
1013
|
+
var executeToolWithContext = automation.apiExecution.executeToolWithContext;
|
|
4091
1014
|
|
|
4092
1015
|
// src/mcp/handlers.ts
|
|
4093
1016
|
var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([".pptx", ".ppt"]);
|
|
@@ -4139,19 +1062,26 @@ async function runMcpTool(filePath, fn, options) {
|
|
|
4139
1062
|
}
|
|
4140
1063
|
|
|
4141
1064
|
// src/mcp/server.ts
|
|
4142
|
-
function createServer() {
|
|
4143
|
-
const
|
|
1065
|
+
function createServer(options) {
|
|
1066
|
+
const server = new mcp_js.McpServer({
|
|
4144
1067
|
name: "pptx-viewer-tools",
|
|
4145
1068
|
version: "1.0.0"
|
|
4146
1069
|
});
|
|
4147
|
-
|
|
1070
|
+
registerTools(server, options);
|
|
1071
|
+
return server;
|
|
1072
|
+
}
|
|
1073
|
+
function registerTools(server, options) {
|
|
1074
|
+
const runMcpTool2 = (filePath, fn) => runMcpTool(filePath, fn, options);
|
|
1075
|
+
const resolveScopedDir2 = (dir) => resolveScopedDir(dir, options?.rootDir);
|
|
1076
|
+
const resolveScopedFilePath2 = (filePath) => resolveScopedFilePath(filePath, options?.rootDir);
|
|
1077
|
+
server.registerTool(
|
|
4148
1078
|
"get_slide",
|
|
4149
1079
|
{
|
|
4150
1080
|
description: "Inspect a single slide: returns layout, notes, elements",
|
|
4151
1081
|
inputSchema: GetSlideSchema.shape
|
|
4152
1082
|
},
|
|
4153
1083
|
async (params) => {
|
|
4154
|
-
const result = await
|
|
1084
|
+
const result = await runMcpTool2(
|
|
4155
1085
|
params.filePath,
|
|
4156
1086
|
(ctx) => getSlide(ctx, { slideIndex: params.slideIndex })
|
|
4157
1087
|
);
|
|
@@ -4165,14 +1095,14 @@ function createServer() {
|
|
|
4165
1095
|
};
|
|
4166
1096
|
}
|
|
4167
1097
|
);
|
|
4168
|
-
|
|
1098
|
+
server.registerTool(
|
|
4169
1099
|
"add_slide",
|
|
4170
1100
|
{
|
|
4171
1101
|
description: "Add a new blank slide to the presentation",
|
|
4172
1102
|
inputSchema: AddSlideSchema.shape
|
|
4173
1103
|
},
|
|
4174
1104
|
async (params) => {
|
|
4175
|
-
const result = await
|
|
1105
|
+
const result = await runMcpTool2(params.filePath, (ctx) => addSlide(ctx, params));
|
|
4176
1106
|
return {
|
|
4177
1107
|
content: [
|
|
4178
1108
|
{
|
|
@@ -4183,14 +1113,14 @@ function createServer() {
|
|
|
4183
1113
|
};
|
|
4184
1114
|
}
|
|
4185
1115
|
);
|
|
4186
|
-
|
|
1116
|
+
server.registerTool(
|
|
4187
1117
|
"delete_slides",
|
|
4188
1118
|
{
|
|
4189
1119
|
description: "Delete one or more slides by index",
|
|
4190
1120
|
inputSchema: DeleteSlidesSchema.shape
|
|
4191
1121
|
},
|
|
4192
1122
|
async (params) => {
|
|
4193
|
-
const result = await
|
|
1123
|
+
const result = await runMcpTool2(
|
|
4194
1124
|
params.filePath,
|
|
4195
1125
|
(ctx) => deleteSlides(ctx, {
|
|
4196
1126
|
slideIndexes: params.slideIndexes
|
|
@@ -4206,14 +1136,14 @@ function createServer() {
|
|
|
4206
1136
|
};
|
|
4207
1137
|
}
|
|
4208
1138
|
);
|
|
4209
|
-
|
|
1139
|
+
server.registerTool(
|
|
4210
1140
|
"reorder_slides",
|
|
4211
1141
|
{
|
|
4212
1142
|
description: "Reorder slides by providing a new index array",
|
|
4213
1143
|
inputSchema: ReorderSlidesSchema.shape
|
|
4214
1144
|
},
|
|
4215
1145
|
async (params) => {
|
|
4216
|
-
const result = await
|
|
1146
|
+
const result = await runMcpTool2(
|
|
4217
1147
|
params.filePath,
|
|
4218
1148
|
(ctx) => reorderSlides(ctx, { newOrder: params.newOrder })
|
|
4219
1149
|
);
|
|
@@ -4227,14 +1157,14 @@ function createServer() {
|
|
|
4227
1157
|
};
|
|
4228
1158
|
}
|
|
4229
1159
|
);
|
|
4230
|
-
|
|
1160
|
+
server.registerTool(
|
|
4231
1161
|
"duplicate_slide",
|
|
4232
1162
|
{
|
|
4233
1163
|
description: "Duplicate a slide with new element IDs",
|
|
4234
1164
|
inputSchema: DuplicateSlideSchema.shape
|
|
4235
1165
|
},
|
|
4236
1166
|
async (params) => {
|
|
4237
|
-
const result = await
|
|
1167
|
+
const result = await runMcpTool2(
|
|
4238
1168
|
params.filePath,
|
|
4239
1169
|
(ctx) => duplicateSlide(ctx, params)
|
|
4240
1170
|
);
|
|
@@ -4248,14 +1178,14 @@ function createServer() {
|
|
|
4248
1178
|
};
|
|
4249
1179
|
}
|
|
4250
1180
|
);
|
|
4251
|
-
|
|
1181
|
+
server.registerTool(
|
|
4252
1182
|
"update_slide_properties",
|
|
4253
1183
|
{
|
|
4254
1184
|
description: "Update slide background, notes, or visibility",
|
|
4255
1185
|
inputSchema: UpdateSlidePropertiesSchema.shape
|
|
4256
1186
|
},
|
|
4257
1187
|
async (params) => {
|
|
4258
|
-
const result = await
|
|
1188
|
+
const result = await runMcpTool2(
|
|
4259
1189
|
params.filePath,
|
|
4260
1190
|
(ctx) => updateSlideProperties(ctx, params)
|
|
4261
1191
|
);
|
|
@@ -4269,14 +1199,14 @@ function createServer() {
|
|
|
4269
1199
|
};
|
|
4270
1200
|
}
|
|
4271
1201
|
);
|
|
4272
|
-
|
|
1202
|
+
server.registerTool(
|
|
4273
1203
|
"set_slide_transition",
|
|
4274
1204
|
{
|
|
4275
1205
|
description: "Set or remove a slide transition effect",
|
|
4276
1206
|
inputSchema: SetSlideTransitionSchema.shape
|
|
4277
1207
|
},
|
|
4278
1208
|
async (params) => {
|
|
4279
|
-
const result = await
|
|
1209
|
+
const result = await runMcpTool2(
|
|
4280
1210
|
params.filePath,
|
|
4281
1211
|
(ctx) => setSlideTransition(ctx, params)
|
|
4282
1212
|
);
|
|
@@ -4290,14 +1220,14 @@ function createServer() {
|
|
|
4290
1220
|
};
|
|
4291
1221
|
}
|
|
4292
1222
|
);
|
|
4293
|
-
|
|
1223
|
+
server.registerTool(
|
|
4294
1224
|
"set_canvas_size",
|
|
4295
1225
|
{
|
|
4296
1226
|
description: "Change the presentation canvas dimensions",
|
|
4297
1227
|
inputSchema: SetCanvasSizeSchema.shape
|
|
4298
1228
|
},
|
|
4299
1229
|
async (params) => {
|
|
4300
|
-
const result = await
|
|
1230
|
+
const result = await runMcpTool2(
|
|
4301
1231
|
params.filePath,
|
|
4302
1232
|
(ctx) => setCanvasSize(ctx, params)
|
|
4303
1233
|
);
|
|
@@ -4311,14 +1241,14 @@ function createServer() {
|
|
|
4311
1241
|
};
|
|
4312
1242
|
}
|
|
4313
1243
|
);
|
|
4314
|
-
|
|
1244
|
+
server.registerTool(
|
|
4315
1245
|
"add_element",
|
|
4316
1246
|
{
|
|
4317
1247
|
description: "Add a text, shape, image, table, or connector element",
|
|
4318
1248
|
inputSchema: AddElementSchema.shape
|
|
4319
1249
|
},
|
|
4320
1250
|
async (params) => {
|
|
4321
|
-
const result = await
|
|
1251
|
+
const result = await runMcpTool2(
|
|
4322
1252
|
params.filePath,
|
|
4323
1253
|
(ctx) => addElement(ctx, params)
|
|
4324
1254
|
);
|
|
@@ -4332,14 +1262,14 @@ function createServer() {
|
|
|
4332
1262
|
};
|
|
4333
1263
|
}
|
|
4334
1264
|
);
|
|
4335
|
-
|
|
1265
|
+
server.registerTool(
|
|
4336
1266
|
"update_element",
|
|
4337
1267
|
{
|
|
4338
1268
|
description: "Update element position, size, text, or style",
|
|
4339
1269
|
inputSchema: UpdateElementSchema.shape
|
|
4340
1270
|
},
|
|
4341
1271
|
async (params) => {
|
|
4342
|
-
const result = await
|
|
1272
|
+
const result = await runMcpTool2(
|
|
4343
1273
|
params.filePath,
|
|
4344
1274
|
(ctx) => updateElement(ctx, params)
|
|
4345
1275
|
);
|
|
@@ -4353,14 +1283,14 @@ function createServer() {
|
|
|
4353
1283
|
};
|
|
4354
1284
|
}
|
|
4355
1285
|
);
|
|
4356
|
-
|
|
1286
|
+
server.registerTool(
|
|
4357
1287
|
"rename_element",
|
|
4358
1288
|
{
|
|
4359
1289
|
description: "Rename an element (the selection pane's display name; cNvPr/@name)",
|
|
4360
1290
|
inputSchema: RenameElementSchema.shape
|
|
4361
1291
|
},
|
|
4362
1292
|
async (params) => {
|
|
4363
|
-
const result = await
|
|
1293
|
+
const result = await runMcpTool2(
|
|
4364
1294
|
params.filePath,
|
|
4365
1295
|
(ctx) => renameElement(ctx, params)
|
|
4366
1296
|
);
|
|
@@ -4374,14 +1304,14 @@ function createServer() {
|
|
|
4374
1304
|
};
|
|
4375
1305
|
}
|
|
4376
1306
|
);
|
|
4377
|
-
|
|
1307
|
+
server.registerTool(
|
|
4378
1308
|
"delete_elements",
|
|
4379
1309
|
{
|
|
4380
1310
|
description: "Delete one or more elements by ID",
|
|
4381
1311
|
inputSchema: DeleteElementsSchema.shape
|
|
4382
1312
|
},
|
|
4383
1313
|
async (params) => {
|
|
4384
|
-
const result = await
|
|
1314
|
+
const result = await runMcpTool2(
|
|
4385
1315
|
params.filePath,
|
|
4386
1316
|
(ctx) => deleteElements(ctx, params)
|
|
4387
1317
|
);
|
|
@@ -4395,14 +1325,14 @@ function createServer() {
|
|
|
4395
1325
|
};
|
|
4396
1326
|
}
|
|
4397
1327
|
);
|
|
4398
|
-
|
|
1328
|
+
server.registerTool(
|
|
4399
1329
|
"arrange_elements",
|
|
4400
1330
|
{
|
|
4401
1331
|
description: "Align elements or change z-order (layer)",
|
|
4402
1332
|
inputSchema: ArrangeElementsSchema.shape
|
|
4403
1333
|
},
|
|
4404
1334
|
async (params) => {
|
|
4405
|
-
const result = await
|
|
1335
|
+
const result = await runMcpTool2(
|
|
4406
1336
|
params.filePath,
|
|
4407
1337
|
(ctx) => arrangeElements(ctx, params)
|
|
4408
1338
|
);
|
|
@@ -4416,14 +1346,14 @@ function createServer() {
|
|
|
4416
1346
|
};
|
|
4417
1347
|
}
|
|
4418
1348
|
);
|
|
4419
|
-
|
|
1349
|
+
server.registerTool(
|
|
4420
1350
|
"clone_element",
|
|
4421
1351
|
{
|
|
4422
1352
|
description: "Clone an element within or across slides",
|
|
4423
1353
|
inputSchema: CloneElementSchema.shape
|
|
4424
1354
|
},
|
|
4425
1355
|
async (params) => {
|
|
4426
|
-
const result = await
|
|
1356
|
+
const result = await runMcpTool2(
|
|
4427
1357
|
params.filePath,
|
|
4428
1358
|
(ctx) => cloneElement(ctx, params)
|
|
4429
1359
|
);
|
|
@@ -4437,14 +1367,14 @@ function createServer() {
|
|
|
4437
1367
|
};
|
|
4438
1368
|
}
|
|
4439
1369
|
);
|
|
4440
|
-
|
|
1370
|
+
server.registerTool(
|
|
4441
1371
|
"set_element_animation",
|
|
4442
1372
|
{
|
|
4443
1373
|
description: "Set entrance/exit animation on an element",
|
|
4444
1374
|
inputSchema: SetElementAnimationSchema.shape
|
|
4445
1375
|
},
|
|
4446
1376
|
async (params) => {
|
|
4447
|
-
const result = await
|
|
1377
|
+
const result = await runMcpTool2(
|
|
4448
1378
|
params.filePath,
|
|
4449
1379
|
(ctx) => setElementAnimation(ctx, params)
|
|
4450
1380
|
);
|
|
@@ -4458,14 +1388,14 @@ function createServer() {
|
|
|
4458
1388
|
};
|
|
4459
1389
|
}
|
|
4460
1390
|
);
|
|
4461
|
-
|
|
1391
|
+
server.registerTool(
|
|
4462
1392
|
"group_elements",
|
|
4463
1393
|
{
|
|
4464
1394
|
description: "Group multiple elements into a group",
|
|
4465
1395
|
inputSchema: GroupElementsSchema.shape
|
|
4466
1396
|
},
|
|
4467
1397
|
async (params) => {
|
|
4468
|
-
const result = await
|
|
1398
|
+
const result = await runMcpTool2(
|
|
4469
1399
|
params.filePath,
|
|
4470
1400
|
(ctx) => groupElements(ctx, params)
|
|
4471
1401
|
);
|
|
@@ -4479,14 +1409,14 @@ function createServer() {
|
|
|
4479
1409
|
};
|
|
4480
1410
|
}
|
|
4481
1411
|
);
|
|
4482
|
-
|
|
1412
|
+
server.registerTool(
|
|
4483
1413
|
"ungroup_elements",
|
|
4484
1414
|
{
|
|
4485
1415
|
description: "Ungroup a group element back to individual elements",
|
|
4486
1416
|
inputSchema: UngroupElementsSchema.shape
|
|
4487
1417
|
},
|
|
4488
1418
|
async (params) => {
|
|
4489
|
-
const result = await
|
|
1419
|
+
const result = await runMcpTool2(
|
|
4490
1420
|
params.filePath,
|
|
4491
1421
|
(ctx) => ungroupElements(ctx, params)
|
|
4492
1422
|
);
|
|
@@ -4500,14 +1430,14 @@ function createServer() {
|
|
|
4500
1430
|
};
|
|
4501
1431
|
}
|
|
4502
1432
|
);
|
|
4503
|
-
|
|
1433
|
+
server.registerTool(
|
|
4504
1434
|
"batch_update_elements",
|
|
4505
1435
|
{
|
|
4506
1436
|
description: "Apply the same properties to multiple elements",
|
|
4507
1437
|
inputSchema: BatchUpdateElementsSchema.shape
|
|
4508
1438
|
},
|
|
4509
1439
|
async (params) => {
|
|
4510
|
-
const result = await
|
|
1440
|
+
const result = await runMcpTool2(
|
|
4511
1441
|
params.filePath,
|
|
4512
1442
|
(ctx) => batchUpdateElements(ctx, params)
|
|
4513
1443
|
);
|
|
@@ -4521,14 +1451,14 @@ function createServer() {
|
|
|
4521
1451
|
};
|
|
4522
1452
|
}
|
|
4523
1453
|
);
|
|
4524
|
-
|
|
1454
|
+
server.registerTool(
|
|
4525
1455
|
"update_table_cells",
|
|
4526
1456
|
{
|
|
4527
1457
|
description: "Update text content of table cells",
|
|
4528
1458
|
inputSchema: UpdateTableCellsSchema.shape
|
|
4529
1459
|
},
|
|
4530
1460
|
async (params) => {
|
|
4531
|
-
const result = await
|
|
1461
|
+
const result = await runMcpTool2(
|
|
4532
1462
|
params.filePath,
|
|
4533
1463
|
(ctx) => updateTableCells(ctx, params)
|
|
4534
1464
|
);
|
|
@@ -4542,14 +1472,14 @@ function createServer() {
|
|
|
4542
1472
|
};
|
|
4543
1473
|
}
|
|
4544
1474
|
);
|
|
4545
|
-
|
|
1475
|
+
server.registerTool(
|
|
4546
1476
|
"manage_table_structure",
|
|
4547
1477
|
{
|
|
4548
1478
|
description: "Insert or delete table rows and columns",
|
|
4549
1479
|
inputSchema: ManageTableStructureSchema.shape
|
|
4550
1480
|
},
|
|
4551
1481
|
async (params) => {
|
|
4552
|
-
const result = await
|
|
1482
|
+
const result = await runMcpTool2(
|
|
4553
1483
|
params.filePath,
|
|
4554
1484
|
(ctx) => manageTableStructure(ctx, params)
|
|
4555
1485
|
);
|
|
@@ -4563,14 +1493,14 @@ function createServer() {
|
|
|
4563
1493
|
};
|
|
4564
1494
|
}
|
|
4565
1495
|
);
|
|
4566
|
-
|
|
1496
|
+
server.registerTool(
|
|
4567
1497
|
"set_table_style_section",
|
|
4568
1498
|
{
|
|
4569
1499
|
description: "Patch the fill, text, borders, or cell3D of one section (wholeTbl, banding, first/last row/col, or a corner cell) of an existing loaded table style",
|
|
4570
1500
|
inputSchema: SetTableStyleSectionSchema.shape
|
|
4571
1501
|
},
|
|
4572
1502
|
async (params) => {
|
|
4573
|
-
const result = await
|
|
1503
|
+
const result = await runMcpTool2(
|
|
4574
1504
|
params.filePath,
|
|
4575
1505
|
(ctx) => setTableStyleSection(ctx, params)
|
|
4576
1506
|
);
|
|
@@ -4579,14 +1509,14 @@ function createServer() {
|
|
|
4579
1509
|
};
|
|
4580
1510
|
}
|
|
4581
1511
|
);
|
|
4582
|
-
|
|
1512
|
+
server.registerTool(
|
|
4583
1513
|
"create_table_style",
|
|
4584
1514
|
{
|
|
4585
1515
|
description: "Create a new table style (optionally cloned from an existing one) and optionally set it as the default",
|
|
4586
1516
|
inputSchema: CreateTableStyleSchema.shape
|
|
4587
1517
|
},
|
|
4588
1518
|
async (params) => {
|
|
4589
|
-
const result = await
|
|
1519
|
+
const result = await runMcpTool2(
|
|
4590
1520
|
params.filePath,
|
|
4591
1521
|
(ctx) => createTableStyle(ctx, params)
|
|
4592
1522
|
);
|
|
@@ -4595,14 +1525,14 @@ function createServer() {
|
|
|
4595
1525
|
};
|
|
4596
1526
|
}
|
|
4597
1527
|
);
|
|
4598
|
-
|
|
1528
|
+
server.registerTool(
|
|
4599
1529
|
"delete_table_style",
|
|
4600
1530
|
{
|
|
4601
1531
|
description: "Remove a table style from the presentation",
|
|
4602
1532
|
inputSchema: DeleteTableStyleSchema.shape
|
|
4603
1533
|
},
|
|
4604
1534
|
async (params) => {
|
|
4605
|
-
const result = await
|
|
1535
|
+
const result = await runMcpTool2(
|
|
4606
1536
|
params.filePath,
|
|
4607
1537
|
(ctx) => deleteTableStyle(ctx, params)
|
|
4608
1538
|
);
|
|
@@ -4611,14 +1541,14 @@ function createServer() {
|
|
|
4611
1541
|
};
|
|
4612
1542
|
}
|
|
4613
1543
|
);
|
|
4614
|
-
|
|
1544
|
+
server.registerTool(
|
|
4615
1545
|
"assign_table_style",
|
|
4616
1546
|
{
|
|
4617
1547
|
description: "Assign a table style (and row/column emphasis flags) to an existing table",
|
|
4618
1548
|
inputSchema: AssignTableStyleSchema.shape
|
|
4619
1549
|
},
|
|
4620
1550
|
async (params) => {
|
|
4621
|
-
const result = await
|
|
1551
|
+
const result = await runMcpTool2(
|
|
4622
1552
|
params.filePath,
|
|
4623
1553
|
(ctx) => assignTableStyle(ctx, params)
|
|
4624
1554
|
);
|
|
@@ -4627,14 +1557,14 @@ function createServer() {
|
|
|
4627
1557
|
};
|
|
4628
1558
|
}
|
|
4629
1559
|
);
|
|
4630
|
-
|
|
1560
|
+
server.registerTool(
|
|
4631
1561
|
"update_element_style",
|
|
4632
1562
|
{
|
|
4633
1563
|
description: "Update fill, stroke, shadow, glow, or image effects",
|
|
4634
1564
|
inputSchema: UpdateElementStyleSchema.shape
|
|
4635
1565
|
},
|
|
4636
1566
|
async (params) => {
|
|
4637
|
-
const result = await
|
|
1567
|
+
const result = await runMcpTool2(
|
|
4638
1568
|
params.filePath,
|
|
4639
1569
|
(ctx) => updateElementStyle(ctx, params)
|
|
4640
1570
|
);
|
|
@@ -4648,14 +1578,14 @@ function createServer() {
|
|
|
4648
1578
|
};
|
|
4649
1579
|
}
|
|
4650
1580
|
);
|
|
4651
|
-
|
|
1581
|
+
server.registerTool(
|
|
4652
1582
|
"run_accessibility_check",
|
|
4653
1583
|
{
|
|
4654
1584
|
description: "Audit the presentation for accessibility issues",
|
|
4655
1585
|
inputSchema: AccessibilityCheckSchema.shape
|
|
4656
1586
|
},
|
|
4657
1587
|
async (params) => {
|
|
4658
|
-
const result = await
|
|
1588
|
+
const result = await runMcpTool2(
|
|
4659
1589
|
params.filePath,
|
|
4660
1590
|
(ctx) => runAccessibilityCheck(ctx)
|
|
4661
1591
|
);
|
|
@@ -4669,14 +1599,14 @@ function createServer() {
|
|
|
4669
1599
|
};
|
|
4670
1600
|
}
|
|
4671
1601
|
);
|
|
4672
|
-
|
|
1602
|
+
server.registerTool(
|
|
4673
1603
|
"find_text",
|
|
4674
1604
|
{
|
|
4675
1605
|
description: "Search for text across all slides",
|
|
4676
1606
|
inputSchema: FindTextSchema.shape
|
|
4677
1607
|
},
|
|
4678
1608
|
async (params) => {
|
|
4679
|
-
const result = await
|
|
1609
|
+
const result = await runMcpTool2(params.filePath, (ctx) => findText(ctx, params));
|
|
4680
1610
|
return {
|
|
4681
1611
|
content: [
|
|
4682
1612
|
{
|
|
@@ -4687,14 +1617,14 @@ function createServer() {
|
|
|
4687
1617
|
};
|
|
4688
1618
|
}
|
|
4689
1619
|
);
|
|
4690
|
-
|
|
1620
|
+
server.registerTool(
|
|
4691
1621
|
"replace_text",
|
|
4692
1622
|
{
|
|
4693
1623
|
description: "Find and replace text across slides",
|
|
4694
1624
|
inputSchema: ReplaceTextSchema.shape
|
|
4695
1625
|
},
|
|
4696
1626
|
async (params) => {
|
|
4697
|
-
const result = await
|
|
1627
|
+
const result = await runMcpTool2(
|
|
4698
1628
|
params.filePath,
|
|
4699
1629
|
(ctx) => replaceText(ctx, params)
|
|
4700
1630
|
);
|
|
@@ -4708,14 +1638,14 @@ function createServer() {
|
|
|
4708
1638
|
};
|
|
4709
1639
|
}
|
|
4710
1640
|
);
|
|
4711
|
-
|
|
1641
|
+
server.registerTool(
|
|
4712
1642
|
"manage_comments",
|
|
4713
1643
|
{
|
|
4714
1644
|
description: "List, add, delete, or resolve slide comments",
|
|
4715
1645
|
inputSchema: ManageCommentsSchema.shape
|
|
4716
1646
|
},
|
|
4717
1647
|
async (params) => {
|
|
4718
|
-
const result = await
|
|
1648
|
+
const result = await runMcpTool2(
|
|
4719
1649
|
params.filePath,
|
|
4720
1650
|
(ctx) => manageComments(ctx, params)
|
|
4721
1651
|
);
|
|
@@ -4729,16 +1659,16 @@ function createServer() {
|
|
|
4729
1659
|
};
|
|
4730
1660
|
}
|
|
4731
1661
|
);
|
|
4732
|
-
|
|
1662
|
+
server.registerTool(
|
|
4733
1663
|
"convert_to_markdown",
|
|
4734
1664
|
{
|
|
4735
1665
|
description: "Convert the presentation to Markdown format",
|
|
4736
1666
|
inputSchema: ConvertToMarkdownSchema.shape
|
|
4737
1667
|
},
|
|
4738
1668
|
async (params) => {
|
|
4739
|
-
const result = await
|
|
1669
|
+
const result = await runMcpTool2(
|
|
4740
1670
|
params.filePath,
|
|
4741
|
-
(ctx) => convertToMarkdown(ctx, { ...params, scopeOutputDir:
|
|
1671
|
+
(ctx) => convertToMarkdown(ctx, { ...params, scopeOutputDir: resolveScopedDir2 })
|
|
4742
1672
|
);
|
|
4743
1673
|
return {
|
|
4744
1674
|
content: [
|
|
@@ -4750,414 +1680,414 @@ function createServer() {
|
|
|
4750
1680
|
};
|
|
4751
1681
|
}
|
|
4752
1682
|
);
|
|
4753
|
-
|
|
1683
|
+
server.registerTool(
|
|
4754
1684
|
"get_theme_info",
|
|
4755
1685
|
{
|
|
4756
1686
|
description: "Get current theme information (colors, fonts, available presets)",
|
|
4757
1687
|
inputSchema: GetThemeInfoSchema.shape
|
|
4758
1688
|
},
|
|
4759
1689
|
async (params) => {
|
|
4760
|
-
const result = await
|
|
1690
|
+
const result = await runMcpTool2(params.filePath, (ctx) => getThemeInfo(ctx));
|
|
4761
1691
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4762
1692
|
}
|
|
4763
1693
|
);
|
|
4764
|
-
|
|
1694
|
+
server.registerTool(
|
|
4765
1695
|
"apply_theme_preset",
|
|
4766
1696
|
{
|
|
4767
1697
|
description: "Apply a built-in theme preset to the presentation",
|
|
4768
1698
|
inputSchema: ApplyThemePresetSchema.shape
|
|
4769
1699
|
},
|
|
4770
1700
|
async (params) => {
|
|
4771
|
-
const result = await
|
|
1701
|
+
const result = await runMcpTool2(
|
|
4772
1702
|
params.filePath,
|
|
4773
1703
|
(ctx) => applyThemePreset(ctx, params)
|
|
4774
1704
|
);
|
|
4775
1705
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4776
1706
|
}
|
|
4777
1707
|
);
|
|
4778
|
-
|
|
1708
|
+
server.registerTool(
|
|
4779
1709
|
"update_theme_colors",
|
|
4780
1710
|
{
|
|
4781
1711
|
description: "Update individual theme colors (accent1-6, dk1/2, lt1/2, hlink, folHlink)",
|
|
4782
1712
|
inputSchema: UpdateThemeColorsSchema.shape
|
|
4783
1713
|
},
|
|
4784
1714
|
async (params) => {
|
|
4785
|
-
const result = await
|
|
1715
|
+
const result = await runMcpTool2(
|
|
4786
1716
|
params.filePath,
|
|
4787
1717
|
(ctx) => updateThemeColors(ctx, params)
|
|
4788
1718
|
);
|
|
4789
1719
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4790
1720
|
}
|
|
4791
1721
|
);
|
|
4792
|
-
|
|
1722
|
+
server.registerTool(
|
|
4793
1723
|
"update_theme_fonts",
|
|
4794
1724
|
{
|
|
4795
1725
|
description: "Update theme heading (major) and body (minor) fonts",
|
|
4796
1726
|
inputSchema: UpdateThemeFontsSchema.shape
|
|
4797
1727
|
},
|
|
4798
1728
|
async (params) => {
|
|
4799
|
-
const result = await
|
|
1729
|
+
const result = await runMcpTool2(
|
|
4800
1730
|
params.filePath,
|
|
4801
1731
|
(ctx) => updateThemeFonts(ctx, params)
|
|
4802
1732
|
);
|
|
4803
1733
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4804
1734
|
}
|
|
4805
1735
|
);
|
|
4806
|
-
|
|
1736
|
+
server.registerTool(
|
|
4807
1737
|
"update_chart",
|
|
4808
1738
|
{
|
|
4809
1739
|
description: "Update chart type, title, legend, data labels, axis, or categories",
|
|
4810
1740
|
inputSchema: UpdateChartSchema.shape
|
|
4811
1741
|
},
|
|
4812
1742
|
async (params) => {
|
|
4813
|
-
const result = await
|
|
1743
|
+
const result = await runMcpTool2(
|
|
4814
1744
|
params.filePath,
|
|
4815
1745
|
(ctx) => updateChart(ctx, params)
|
|
4816
1746
|
);
|
|
4817
1747
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4818
1748
|
}
|
|
4819
1749
|
);
|
|
4820
|
-
|
|
1750
|
+
server.registerTool(
|
|
4821
1751
|
"add_chart_series",
|
|
4822
1752
|
{
|
|
4823
1753
|
description: "Add a data series to an existing chart",
|
|
4824
1754
|
inputSchema: AddChartSeriesSchema.shape
|
|
4825
1755
|
},
|
|
4826
1756
|
async (params) => {
|
|
4827
|
-
const result = await
|
|
1757
|
+
const result = await runMcpTool2(
|
|
4828
1758
|
params.filePath,
|
|
4829
1759
|
(ctx) => addChartSeriesT(ctx, params)
|
|
4830
1760
|
);
|
|
4831
1761
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4832
1762
|
}
|
|
4833
1763
|
);
|
|
4834
|
-
|
|
1764
|
+
server.registerTool(
|
|
4835
1765
|
"remove_chart_series",
|
|
4836
1766
|
{
|
|
4837
1767
|
description: "Remove a data series from a chart by index",
|
|
4838
1768
|
inputSchema: RemoveChartSeriesSchema.shape
|
|
4839
1769
|
},
|
|
4840
1770
|
async (params) => {
|
|
4841
|
-
const result = await
|
|
1771
|
+
const result = await runMcpTool2(
|
|
4842
1772
|
params.filePath,
|
|
4843
1773
|
(ctx) => removeChartSeriesT(ctx, params)
|
|
4844
1774
|
);
|
|
4845
1775
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4846
1776
|
}
|
|
4847
1777
|
);
|
|
4848
|
-
|
|
1778
|
+
server.registerTool(
|
|
4849
1779
|
"update_chart_series_data",
|
|
4850
1780
|
{
|
|
4851
1781
|
description: "Update data values for a chart series",
|
|
4852
1782
|
inputSchema: UpdateChartSeriesDataSchema.shape
|
|
4853
1783
|
},
|
|
4854
1784
|
async (params) => {
|
|
4855
|
-
const result = await
|
|
1785
|
+
const result = await runMcpTool2(
|
|
4856
1786
|
params.filePath,
|
|
4857
1787
|
(ctx) => updateChartSeriesData(ctx, params)
|
|
4858
1788
|
);
|
|
4859
1789
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4860
1790
|
}
|
|
4861
1791
|
);
|
|
4862
|
-
|
|
1792
|
+
server.registerTool(
|
|
4863
1793
|
"create_chart",
|
|
4864
1794
|
{
|
|
4865
1795
|
description: "Create a new chart element on a slide",
|
|
4866
1796
|
inputSchema: CreateChartSchema.shape
|
|
4867
1797
|
},
|
|
4868
1798
|
async (params) => {
|
|
4869
|
-
const result = await
|
|
1799
|
+
const result = await runMcpTool2(
|
|
4870
1800
|
params.filePath,
|
|
4871
1801
|
(ctx) => createChart(ctx, params)
|
|
4872
1802
|
);
|
|
4873
1803
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4874
1804
|
}
|
|
4875
1805
|
);
|
|
4876
|
-
|
|
1806
|
+
server.registerTool(
|
|
4877
1807
|
"format_chart_data_point",
|
|
4878
1808
|
{
|
|
4879
1809
|
description: "Set per-data-point chart formatting: fill/stroke colour, stroke width, dash style (c:dPt/c:spPr), explosion, and marker override",
|
|
4880
1810
|
inputSchema: FormatChartDataPointSchema.shape
|
|
4881
1811
|
},
|
|
4882
1812
|
async (params) => {
|
|
4883
|
-
const result = await
|
|
1813
|
+
const result = await runMcpTool2(
|
|
4884
1814
|
params.filePath,
|
|
4885
1815
|
(ctx) => formatChartDataPoint(ctx, params)
|
|
4886
1816
|
);
|
|
4887
1817
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4888
1818
|
}
|
|
4889
1819
|
);
|
|
4890
|
-
|
|
1820
|
+
server.registerTool(
|
|
4891
1821
|
"format_chart_data_label",
|
|
4892
1822
|
{
|
|
4893
1823
|
description: "Set a per-data-point data-label override (c:dLbl): show flags, position, custom text, and the label's own fill/line formatting (c:spPr) and font (c:txPr)",
|
|
4894
1824
|
inputSchema: FormatChartDataLabelSchema.shape
|
|
4895
1825
|
},
|
|
4896
1826
|
async (params) => {
|
|
4897
|
-
const result = await
|
|
1827
|
+
const result = await runMcpTool2(
|
|
4898
1828
|
params.filePath,
|
|
4899
1829
|
(ctx) => formatChartDataLabel(ctx, params)
|
|
4900
1830
|
);
|
|
4901
1831
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4902
1832
|
}
|
|
4903
1833
|
);
|
|
4904
|
-
|
|
1834
|
+
server.registerTool(
|
|
4905
1835
|
"format_chart_series",
|
|
4906
1836
|
{
|
|
4907
1837
|
description: "Set a chart series marker (c:marker), trendline (c:trendline, incl. line width/dash), or error bars (c:errBars, incl. line width/dash)",
|
|
4908
1838
|
inputSchema: FormatChartSeriesSchema.shape
|
|
4909
1839
|
},
|
|
4910
1840
|
async (params) => {
|
|
4911
|
-
const result = await
|
|
1841
|
+
const result = await runMcpTool2(
|
|
4912
1842
|
params.filePath,
|
|
4913
1843
|
(ctx) => formatChartSeries(ctx, params)
|
|
4914
1844
|
);
|
|
4915
1845
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4916
1846
|
}
|
|
4917
1847
|
);
|
|
4918
|
-
|
|
1848
|
+
server.registerTool(
|
|
4919
1849
|
"set_chart_helper_line",
|
|
4920
1850
|
{
|
|
4921
1851
|
description: "Set or remove a chart-level helper line on a line/stock/combo chart: c:dropLines or c:hiLowLines",
|
|
4922
1852
|
inputSchema: SetChartHelperLineSchema.shape
|
|
4923
1853
|
},
|
|
4924
1854
|
async (params) => {
|
|
4925
|
-
const result = await
|
|
1855
|
+
const result = await runMcpTool2(
|
|
4926
1856
|
params.filePath,
|
|
4927
1857
|
(ctx) => setChartHelperLineT(ctx, params)
|
|
4928
1858
|
);
|
|
4929
1859
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4930
1860
|
}
|
|
4931
1861
|
);
|
|
4932
|
-
|
|
1862
|
+
server.registerTool(
|
|
4933
1863
|
"set_chart_color_map_override",
|
|
4934
1864
|
{
|
|
4935
1865
|
description: "Set or remove a chart's theme colour-map override (c:clrMapOvr), remapping theme colour roles for this chart only",
|
|
4936
1866
|
inputSchema: SetChartColorMapOverrideSchema.shape
|
|
4937
1867
|
},
|
|
4938
1868
|
async (params) => {
|
|
4939
|
-
const result = await
|
|
1869
|
+
const result = await runMcpTool2(
|
|
4940
1870
|
params.filePath,
|
|
4941
1871
|
(ctx) => setChartColorMapOverrideT(ctx, params)
|
|
4942
1872
|
);
|
|
4943
1873
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4944
1874
|
}
|
|
4945
1875
|
);
|
|
4946
|
-
|
|
1876
|
+
server.registerTool(
|
|
4947
1877
|
"chart_user_shape_list",
|
|
4948
1878
|
{
|
|
4949
1879
|
description: "List a chart's drawing-overlay shapes (c:userShapes)",
|
|
4950
1880
|
inputSchema: ListChartUserShapesSchema.shape
|
|
4951
1881
|
},
|
|
4952
1882
|
async (params) => {
|
|
4953
|
-
const result = await
|
|
1883
|
+
const result = await runMcpTool2(
|
|
4954
1884
|
params.filePath,
|
|
4955
1885
|
(ctx) => listChartUserShapesT(ctx, params)
|
|
4956
1886
|
);
|
|
4957
1887
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4958
1888
|
}
|
|
4959
1889
|
);
|
|
4960
|
-
|
|
1890
|
+
server.registerTool(
|
|
4961
1891
|
"chart_user_shape_add",
|
|
4962
1892
|
{
|
|
4963
1893
|
description: "Add a drawing-overlay shape (text box or connector) to a chart's c:userShapes",
|
|
4964
1894
|
inputSchema: AddChartUserShapeSchema.shape
|
|
4965
1895
|
},
|
|
4966
1896
|
async (params) => {
|
|
4967
|
-
const result = await
|
|
1897
|
+
const result = await runMcpTool2(
|
|
4968
1898
|
params.filePath,
|
|
4969
1899
|
(ctx) => addChartUserShapeT(ctx, params)
|
|
4970
1900
|
);
|
|
4971
1901
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4972
1902
|
}
|
|
4973
1903
|
);
|
|
4974
|
-
|
|
1904
|
+
server.registerTool(
|
|
4975
1905
|
"chart_user_shape_update",
|
|
4976
1906
|
{
|
|
4977
1907
|
description: "Move, resize, or restyle one of a chart's drawing-overlay shapes by index",
|
|
4978
1908
|
inputSchema: UpdateChartUserShapeSchema.shape
|
|
4979
1909
|
},
|
|
4980
1910
|
async (params) => {
|
|
4981
|
-
const result = await
|
|
1911
|
+
const result = await runMcpTool2(
|
|
4982
1912
|
params.filePath,
|
|
4983
1913
|
(ctx) => updateChartUserShapeT(ctx, params)
|
|
4984
1914
|
);
|
|
4985
1915
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4986
1916
|
}
|
|
4987
1917
|
);
|
|
4988
|
-
|
|
1918
|
+
server.registerTool(
|
|
4989
1919
|
"chart_user_shape_remove",
|
|
4990
1920
|
{
|
|
4991
1921
|
description: "Remove one of a chart's drawing-overlay shapes by index",
|
|
4992
1922
|
inputSchema: RemoveChartUserShapeSchema.shape
|
|
4993
1923
|
},
|
|
4994
1924
|
async (params) => {
|
|
4995
|
-
const result = await
|
|
1925
|
+
const result = await runMcpTool2(
|
|
4996
1926
|
params.filePath,
|
|
4997
1927
|
(ctx) => removeChartUserShapeT(ctx, params)
|
|
4998
1928
|
);
|
|
4999
1929
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5000
1930
|
}
|
|
5001
1931
|
);
|
|
5002
|
-
|
|
1932
|
+
server.registerTool(
|
|
5003
1933
|
"manage_smart_art",
|
|
5004
1934
|
{
|
|
5005
1935
|
description: "Manage SmartArt: get nodes, add/remove/reorder/promote/demote nodes, or decompose to shapes",
|
|
5006
1936
|
inputSchema: ManageSmartArtSchema.shape
|
|
5007
1937
|
},
|
|
5008
1938
|
async (params) => {
|
|
5009
|
-
const result = await
|
|
1939
|
+
const result = await runMcpTool2(
|
|
5010
1940
|
params.filePath,
|
|
5011
1941
|
(ctx) => manageSmartArt(ctx, params)
|
|
5012
1942
|
);
|
|
5013
1943
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5014
1944
|
}
|
|
5015
1945
|
);
|
|
5016
|
-
|
|
1946
|
+
server.registerTool(
|
|
5017
1947
|
"find_placeholders",
|
|
5018
1948
|
{
|
|
5019
1949
|
description: "Discover all {{placeholder}} tokens in the presentation",
|
|
5020
1950
|
inputSchema: FindPlaceholdersSchema.shape
|
|
5021
1951
|
},
|
|
5022
1952
|
async (params) => {
|
|
5023
|
-
const result = await
|
|
1953
|
+
const result = await runMcpTool2(
|
|
5024
1954
|
params.filePath,
|
|
5025
1955
|
(ctx) => findPlaceholdersT(ctx)
|
|
5026
1956
|
);
|
|
5027
1957
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5028
1958
|
}
|
|
5029
1959
|
);
|
|
5030
|
-
|
|
1960
|
+
server.registerTool(
|
|
5031
1961
|
"apply_template",
|
|
5032
1962
|
{
|
|
5033
1963
|
description: "Replace {{placeholder}} tokens with provided values (mail merge)",
|
|
5034
1964
|
inputSchema: ApplyTemplateSchema.shape
|
|
5035
1965
|
},
|
|
5036
1966
|
async (params) => {
|
|
5037
|
-
const result = await
|
|
1967
|
+
const result = await runMcpTool2(
|
|
5038
1968
|
params.filePath,
|
|
5039
1969
|
(ctx) => applyTemplateT(ctx, { data: params.data })
|
|
5040
1970
|
);
|
|
5041
1971
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5042
1972
|
}
|
|
5043
1973
|
);
|
|
5044
|
-
|
|
1974
|
+
server.registerTool(
|
|
5045
1975
|
"get_metadata",
|
|
5046
1976
|
{
|
|
5047
1977
|
description: "Get presentation metadata (title, author, keywords, custom properties)",
|
|
5048
1978
|
inputSchema: GetMetadataSchema.shape
|
|
5049
1979
|
},
|
|
5050
1980
|
async (params) => {
|
|
5051
|
-
const result = await
|
|
1981
|
+
const result = await runMcpTool2(params.filePath, (ctx) => getMetadata(ctx));
|
|
5052
1982
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5053
1983
|
}
|
|
5054
1984
|
);
|
|
5055
|
-
|
|
1985
|
+
server.registerTool(
|
|
5056
1986
|
"update_metadata",
|
|
5057
1987
|
{
|
|
5058
1988
|
description: "Update presentation metadata (title, author, company, custom properties)",
|
|
5059
1989
|
inputSchema: UpdateMetadataSchema.shape
|
|
5060
1990
|
},
|
|
5061
1991
|
async (params) => {
|
|
5062
|
-
const result = await
|
|
1992
|
+
const result = await runMcpTool2(
|
|
5063
1993
|
params.filePath,
|
|
5064
1994
|
(ctx) => updateMetadata(ctx, params)
|
|
5065
1995
|
);
|
|
5066
1996
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5067
1997
|
}
|
|
5068
1998
|
);
|
|
5069
|
-
|
|
1999
|
+
server.registerTool(
|
|
5070
2000
|
"manage_sections",
|
|
5071
2001
|
{
|
|
5072
2002
|
description: "List, add, remove, reorder sections or move slides between sections",
|
|
5073
2003
|
inputSchema: ManageSectionsSchema.shape
|
|
5074
2004
|
},
|
|
5075
2005
|
async (params) => {
|
|
5076
|
-
const result = await
|
|
2006
|
+
const result = await runMcpTool2(
|
|
5077
2007
|
params.filePath,
|
|
5078
2008
|
(ctx) => manageSections(ctx, params)
|
|
5079
2009
|
);
|
|
5080
2010
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5081
2011
|
}
|
|
5082
2012
|
);
|
|
5083
|
-
|
|
2013
|
+
server.registerTool(
|
|
5084
2014
|
"export_to_svg",
|
|
5085
2015
|
{
|
|
5086
2016
|
description: "Export all or specific slides to SVG strings",
|
|
5087
2017
|
inputSchema: ExportToSvgSchema.shape
|
|
5088
2018
|
},
|
|
5089
2019
|
async (params) => {
|
|
5090
|
-
const result = await
|
|
2020
|
+
const result = await runMcpTool2(
|
|
5091
2021
|
params.filePath,
|
|
5092
2022
|
(ctx) => exportToSvg(ctx, params)
|
|
5093
2023
|
);
|
|
5094
2024
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5095
2025
|
}
|
|
5096
2026
|
);
|
|
5097
|
-
|
|
2027
|
+
server.registerTool(
|
|
5098
2028
|
"export_slide_svg",
|
|
5099
2029
|
{
|
|
5100
2030
|
description: "Export a single slide to SVG",
|
|
5101
2031
|
inputSchema: ExportSlideSvgSchema.shape
|
|
5102
2032
|
},
|
|
5103
2033
|
async (params) => {
|
|
5104
|
-
const result = await
|
|
2034
|
+
const result = await runMcpTool2(
|
|
5105
2035
|
params.filePath,
|
|
5106
2036
|
(ctx) => exportSlideSvg(ctx, params)
|
|
5107
2037
|
);
|
|
5108
2038
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5109
2039
|
}
|
|
5110
2040
|
);
|
|
5111
|
-
|
|
2041
|
+
server.registerTool(
|
|
5112
2042
|
"export_to_json",
|
|
5113
2043
|
{
|
|
5114
2044
|
description: "Export the presentation to the portable pptx-viewer-json document format (self-contained, binary assets embedded as base64)",
|
|
5115
2045
|
inputSchema: ExportToJsonSchema.shape
|
|
5116
2046
|
},
|
|
5117
2047
|
async (params) => {
|
|
5118
|
-
const result = await
|
|
2048
|
+
const result = await runMcpTool2(
|
|
5119
2049
|
params.filePath,
|
|
5120
2050
|
(ctx) => exportToJson(ctx, params)
|
|
5121
2051
|
);
|
|
5122
2052
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5123
2053
|
}
|
|
5124
2054
|
);
|
|
5125
|
-
|
|
2055
|
+
server.registerTool(
|
|
5126
2056
|
"import_from_json",
|
|
5127
2057
|
{
|
|
5128
2058
|
description: "Replace the presentation content with a deck imported from a pptx-viewer-json document",
|
|
5129
2059
|
inputSchema: ImportFromJsonSchema.shape
|
|
5130
2060
|
},
|
|
5131
2061
|
async (params) => {
|
|
5132
|
-
const result = await
|
|
2062
|
+
const result = await runMcpTool2(
|
|
5133
2063
|
params.filePath,
|
|
5134
2064
|
(ctx) => importFromJson(ctx, params)
|
|
5135
2065
|
);
|
|
5136
2066
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5137
2067
|
}
|
|
5138
2068
|
);
|
|
5139
|
-
|
|
2069
|
+
server.registerTool(
|
|
5140
2070
|
"manage_hyperlinks",
|
|
5141
2071
|
{
|
|
5142
2072
|
description: "List, set, or remove hyperlinks/actions on elements",
|
|
5143
2073
|
inputSchema: ManageHyperlinksSchema.shape
|
|
5144
2074
|
},
|
|
5145
2075
|
async (params) => {
|
|
5146
|
-
const result = await
|
|
2076
|
+
const result = await runMcpTool2(
|
|
5147
2077
|
params.filePath,
|
|
5148
2078
|
(ctx) => manageHyperlinks(ctx, params)
|
|
5149
2079
|
);
|
|
5150
2080
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5151
2081
|
}
|
|
5152
2082
|
);
|
|
5153
|
-
|
|
2083
|
+
server.registerTool(
|
|
5154
2084
|
"replace_geometry",
|
|
5155
2085
|
{
|
|
5156
2086
|
description: "Replace a shape element geometry with a preset or custom SVG path",
|
|
5157
2087
|
inputSchema: ReplaceGeometrySchema.shape
|
|
5158
2088
|
},
|
|
5159
2089
|
async (params) => {
|
|
5160
|
-
const result = await
|
|
2090
|
+
const result = await runMcpTool2(
|
|
5161
2091
|
params.filePath,
|
|
5162
2092
|
(ctx) => replaceGeometry(ctx, {
|
|
5163
2093
|
...params,
|
|
@@ -5167,21 +2097,21 @@ function createServer() {
|
|
|
5167
2097
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5168
2098
|
}
|
|
5169
2099
|
);
|
|
5170
|
-
|
|
2100
|
+
server.registerTool(
|
|
5171
2101
|
"set_element_lock",
|
|
5172
2102
|
{
|
|
5173
2103
|
description: "Lock or unlock an element (prevent move, resize, rotation, selection, text edit)",
|
|
5174
2104
|
inputSchema: SetElementLockSchema.shape
|
|
5175
2105
|
},
|
|
5176
2106
|
async (params) => {
|
|
5177
|
-
const result = await
|
|
2107
|
+
const result = await runMcpTool2(
|
|
5178
2108
|
params.filePath,
|
|
5179
2109
|
(ctx) => setElementLockT(ctx, params)
|
|
5180
2110
|
);
|
|
5181
2111
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5182
2112
|
}
|
|
5183
2113
|
);
|
|
5184
|
-
|
|
2114
|
+
server.registerTool(
|
|
5185
2115
|
"validate_presentation",
|
|
5186
2116
|
{
|
|
5187
2117
|
description: "Validate PPTX structural integrity (content types, relationships, XML)",
|
|
@@ -5189,13 +2119,13 @@ function createServer() {
|
|
|
5189
2119
|
},
|
|
5190
2120
|
async (params) => {
|
|
5191
2121
|
const { readFile: readFile2 } = await import('fs/promises');
|
|
5192
|
-
const safePath =
|
|
2122
|
+
const safePath = resolveScopedFilePath2(params.filePath);
|
|
5193
2123
|
const bytes = await readFile2(safePath);
|
|
5194
2124
|
const result = await validatePresentation(bytes.buffer);
|
|
5195
2125
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5196
2126
|
}
|
|
5197
2127
|
);
|
|
5198
|
-
|
|
2128
|
+
server.registerTool(
|
|
5199
2129
|
"repair_presentation",
|
|
5200
2130
|
{
|
|
5201
2131
|
description: "Auto-repair common PPTX structural issues",
|
|
@@ -5203,7 +2133,7 @@ function createServer() {
|
|
|
5203
2133
|
},
|
|
5204
2134
|
async (params) => {
|
|
5205
2135
|
const { readFile: readFile2, writeFile: writeFile2 } = await import('fs/promises');
|
|
5206
|
-
const safePath =
|
|
2136
|
+
const safePath = resolveScopedFilePath2(params.filePath);
|
|
5207
2137
|
const bytes = await readFile2(safePath);
|
|
5208
2138
|
const { result, repairedBytes } = await repairPresentation(
|
|
5209
2139
|
bytes.buffer
|
|
@@ -5214,147 +2144,144 @@ function createServer() {
|
|
|
5214
2144
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5215
2145
|
}
|
|
5216
2146
|
);
|
|
5217
|
-
|
|
2147
|
+
server.registerTool(
|
|
5218
2148
|
"get_presentation_properties",
|
|
5219
2149
|
{
|
|
5220
2150
|
description: "Get slideshow properties (show type, loop, advance mode, slide range)",
|
|
5221
2151
|
inputSchema: GetPresentationPropertiesSchema.shape
|
|
5222
2152
|
},
|
|
5223
2153
|
async (params) => {
|
|
5224
|
-
const result = await
|
|
2154
|
+
const result = await runMcpTool2(
|
|
5225
2155
|
params.filePath,
|
|
5226
2156
|
(ctx) => getPresentationProperties(ctx)
|
|
5227
2157
|
);
|
|
5228
2158
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5229
2159
|
}
|
|
5230
2160
|
);
|
|
5231
|
-
|
|
2161
|
+
server.registerTool(
|
|
5232
2162
|
"update_presentation_properties",
|
|
5233
2163
|
{
|
|
5234
2164
|
description: "Update slideshow properties (show type, loop, advance mode, pen color)",
|
|
5235
2165
|
inputSchema: UpdatePresentationPropertiesSchema.shape
|
|
5236
2166
|
},
|
|
5237
2167
|
async (params) => {
|
|
5238
|
-
const result = await
|
|
2168
|
+
const result = await runMcpTool2(
|
|
5239
2169
|
params.filePath,
|
|
5240
2170
|
(ctx) => updatePresentationProperties(ctx, params)
|
|
5241
2171
|
);
|
|
5242
2172
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5243
2173
|
}
|
|
5244
2174
|
);
|
|
5245
|
-
|
|
2175
|
+
server.registerTool(
|
|
5246
2176
|
"get_layouts",
|
|
5247
2177
|
{
|
|
5248
2178
|
description: "List available slide layouts from the presentation masters",
|
|
5249
2179
|
inputSchema: GetLayoutsSchema.shape
|
|
5250
2180
|
},
|
|
5251
2181
|
async (params) => {
|
|
5252
|
-
const result = await
|
|
2182
|
+
const result = await runMcpTool2(params.filePath, (ctx) => getLayouts(ctx));
|
|
5253
2183
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5254
2184
|
}
|
|
5255
2185
|
);
|
|
5256
|
-
|
|
2186
|
+
server.registerTool(
|
|
5257
2187
|
"apply_layout",
|
|
5258
2188
|
{
|
|
5259
2189
|
description: "Apply a slide layout to a specific slide",
|
|
5260
2190
|
inputSchema: ApplyLayoutSchema.shape
|
|
5261
2191
|
},
|
|
5262
2192
|
async (params) => {
|
|
5263
|
-
const result = await
|
|
2193
|
+
const result = await runMcpTool2(
|
|
5264
2194
|
params.filePath,
|
|
5265
2195
|
(ctx) => applyLayout(ctx, params)
|
|
5266
2196
|
);
|
|
5267
2197
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5268
2198
|
}
|
|
5269
2199
|
);
|
|
5270
|
-
|
|
2200
|
+
server.registerTool(
|
|
5271
2201
|
"ole_get_content",
|
|
5272
2202
|
{
|
|
5273
2203
|
description: "Inspect an embedded OLE object's editable content: resolved kind, plus the sheet grid, paragraph list, or nested-deck slide summaries, whichever applies",
|
|
5274
2204
|
inputSchema: GetOleContentSchema.shape
|
|
5275
2205
|
},
|
|
5276
2206
|
async (params) => {
|
|
5277
|
-
const result = await
|
|
2207
|
+
const result = await runMcpTool2(
|
|
5278
2208
|
params.filePath,
|
|
5279
2209
|
(ctx) => getOleContent(ctx, params)
|
|
5280
2210
|
);
|
|
5281
2211
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5282
2212
|
}
|
|
5283
2213
|
);
|
|
5284
|
-
|
|
2214
|
+
server.registerTool(
|
|
5285
2215
|
"ole_set_sheet_cell",
|
|
5286
2216
|
{
|
|
5287
2217
|
description: "Edit one cell of an embedded Excel OLE object's first worksheet",
|
|
5288
2218
|
inputSchema: SetOleSheetCellSchema.shape
|
|
5289
2219
|
},
|
|
5290
2220
|
async (params) => {
|
|
5291
|
-
const result = await
|
|
2221
|
+
const result = await runMcpTool2(
|
|
5292
2222
|
params.filePath,
|
|
5293
2223
|
(ctx) => setOleSheetCell(ctx, params)
|
|
5294
2224
|
);
|
|
5295
2225
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5296
2226
|
}
|
|
5297
2227
|
);
|
|
5298
|
-
|
|
2228
|
+
server.registerTool(
|
|
5299
2229
|
"ole_set_document_paragraph",
|
|
5300
2230
|
{
|
|
5301
2231
|
description: "Replace one paragraph's text in an embedded Word (.docx or legacy .doc) OLE object",
|
|
5302
2232
|
inputSchema: SetOleDocumentParagraphSchema.shape
|
|
5303
2233
|
},
|
|
5304
2234
|
async (params) => {
|
|
5305
|
-
const result = await
|
|
2235
|
+
const result = await runMcpTool2(
|
|
5306
2236
|
params.filePath,
|
|
5307
2237
|
(ctx) => setOleDocumentParagraph(ctx, params)
|
|
5308
2238
|
);
|
|
5309
2239
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5310
2240
|
}
|
|
5311
2241
|
);
|
|
5312
|
-
|
|
2242
|
+
server.registerTool(
|
|
5313
2243
|
"ole_set_deck_slide_title",
|
|
5314
2244
|
{
|
|
5315
2245
|
description: "Edit one text-bearing shape on one slide of an embedded nested-deck (PowerPoint) OLE object, via a full load/save round-trip through the nested deck (call ole_get_content first to discover each slide's elementIds)",
|
|
5316
2246
|
inputSchema: SetOleDeckSlideTitleSchema.shape
|
|
5317
2247
|
},
|
|
5318
2248
|
async (params) => {
|
|
5319
|
-
const result = await
|
|
2249
|
+
const result = await runMcpTool2(
|
|
5320
2250
|
params.filePath,
|
|
5321
2251
|
(ctx) => setOleDeckSlideTitle(ctx, params)
|
|
5322
2252
|
);
|
|
5323
2253
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5324
2254
|
}
|
|
5325
2255
|
);
|
|
5326
|
-
|
|
2256
|
+
server.registerTool(
|
|
5327
2257
|
"ole_replace_file",
|
|
5328
2258
|
{
|
|
5329
2259
|
description: `Replace an embedded OLE object's payload wholesale with an arbitrary file; works for any OLE kind, including a generic "Package" object or an unsupported format`,
|
|
5330
2260
|
inputSchema: ReplaceOleFileSchema.shape
|
|
5331
2261
|
},
|
|
5332
2262
|
async (params) => {
|
|
5333
|
-
const result = await
|
|
2263
|
+
const result = await runMcpTool2(
|
|
5334
2264
|
params.filePath,
|
|
5335
2265
|
(ctx) => replaceOleFileT(ctx, params)
|
|
5336
2266
|
);
|
|
5337
2267
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5338
2268
|
}
|
|
5339
2269
|
);
|
|
5340
|
-
|
|
2270
|
+
server.registerTool(
|
|
5341
2271
|
"ole_set_object_name",
|
|
5342
2272
|
{
|
|
5343
2273
|
description: "Rename an OLE object's Object Name (p:oleObj/@name); regenerates the baked-in icon caption too when the object is displayed as an icon",
|
|
5344
2274
|
inputSchema: SetOleObjectNameSchema.shape
|
|
5345
2275
|
},
|
|
5346
2276
|
async (params) => {
|
|
5347
|
-
const result = await
|
|
2277
|
+
const result = await runMcpTool2(
|
|
5348
2278
|
params.filePath,
|
|
5349
2279
|
(ctx) => setOleObjectNameT(ctx, params)
|
|
5350
2280
|
);
|
|
5351
2281
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5352
2282
|
}
|
|
5353
2283
|
);
|
|
5354
|
-
return server2;
|
|
5355
2284
|
}
|
|
5356
2285
|
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
var transport = new stdio_js.StdioServerTransport();
|
|
5360
|
-
void server.connect(transport);
|
|
2286
|
+
exports.createServer = createServer;
|
|
2287
|
+
exports.registerTools = registerTools;
|