layoutbridge-spm 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/LICENSE +26 -0
  3. package/README.de.md +318 -0
  4. package/README.md +304 -4
  5. package/THIRD-PARTY-NOTICES.md +2878 -0
  6. package/dist/src/mcp/config.js +125 -0
  7. package/dist/src/mcp/dispatch.js +123 -0
  8. package/dist/src/mcp/license/free-tools.js +16 -0
  9. package/dist/src/mcp/license/gate.js +209 -0
  10. package/dist/src/mcp/license/index.js +96 -0
  11. package/dist/src/mcp/license/instance-name.js +56 -0
  12. package/dist/src/mcp/license/key-source.js +58 -0
  13. package/dist/src/mcp/license/lemonsqueezy-verifier.js +207 -0
  14. package/dist/src/mcp/license/placeholder-verifier.js +10 -0
  15. package/dist/src/mcp/license/polar-ids.js +63 -0
  16. package/dist/src/mcp/license/polar-verifier.js +265 -0
  17. package/dist/src/mcp/license/product-ids.js +72 -0
  18. package/dist/src/mcp/license/state-store.js +91 -0
  19. package/dist/src/mcp/license/types.js +11 -0
  20. package/dist/src/mcp/logging.js +270 -0
  21. package/dist/src/mcp/product-info.js +48 -0
  22. package/dist/src/mcp/server.js +250 -0
  23. package/dist/src/mcp/setup.js +608 -0
  24. package/dist/src/mcp/start.cjs +95 -0
  25. package/dist/src/mcp/tool-definition.js +2 -0
  26. package/dist/src/mcp/tools.js +2004 -0
  27. package/dist/src/mcp/typography-rules.js +70 -0
  28. package/dist/src/transport/com.js +250 -0
  29. package/dist/src/transport/osascript.js +171 -0
  30. package/dist/src/transport/queue.js +19 -0
  31. package/dist/src/transport/script-bundle.js +92 -0
  32. package/dist/src/transport/transport.js +30 -0
  33. package/indesign/commands/10-app.js +6 -0
  34. package/indesign/commands/20-documents.js +513 -0
  35. package/indesign/commands/22-document-setup.js +118 -0
  36. package/indesign/commands/23-save-package.js +255 -0
  37. package/indesign/commands/25-export.js +379 -0
  38. package/indesign/commands/26-export-image.js +197 -0
  39. package/indesign/commands/27-textdefaults.js +151 -0
  40. package/indesign/commands/28-selection.js +174 -0
  41. package/indesign/commands/30-pages.js +1032 -0
  42. package/indesign/commands/31-view.js +210 -0
  43. package/indesign/commands/32-sections.js +203 -0
  44. package/indesign/commands/35-parents.js +428 -0
  45. package/indesign/commands/37-layout.js +760 -0
  46. package/indesign/commands/40-frames.js +836 -0
  47. package/indesign/commands/41-shapes.js +505 -0
  48. package/indesign/commands/42-groups.js +117 -0
  49. package/indesign/commands/43-layers.js +291 -0
  50. package/indesign/commands/44-effects.js +274 -0
  51. package/indesign/commands/45-frame-options.js +247 -0
  52. package/indesign/commands/47-anchored.js +287 -0
  53. package/indesign/commands/50-modify.js +781 -0
  54. package/indesign/commands/52-align.js +139 -0
  55. package/indesign/commands/55-fit.js +106 -0
  56. package/indesign/commands/60-images.js +771 -0
  57. package/indesign/commands/62-embed.js +120 -0
  58. package/indesign/commands/69-placeholders.js +127 -0
  59. package/indesign/commands/70-text.js +567 -0
  60. package/indesign/commands/71-outlines.js +92 -0
  61. package/indesign/commands/72-place-text.js +366 -0
  62. package/indesign/commands/74-stories.js +116 -0
  63. package/indesign/commands/75-tables.js +676 -0
  64. package/indesign/commands/76-text-variables.js +260 -0
  65. package/indesign/commands/77-story-options.js +86 -0
  66. package/indesign/commands/78-frame-lines.js +304 -0
  67. package/indesign/commands/79-check-typography.js +303 -0
  68. package/indesign/commands/80-styles.js +1620 -0
  69. package/indesign/commands/81-composition.js +355 -0
  70. package/indesign/commands/82-object-styles.js +263 -0
  71. package/indesign/commands/83-indents-tabs.js +237 -0
  72. package/indesign/commands/84-import-styles.js +142 -0
  73. package/indesign/commands/85-swatches.js +112 -0
  74. package/indesign/commands/86-gradients.js +185 -0
  75. package/indesign/commands/87-replace-swatch.js +180 -0
  76. package/indesign/commands/88-replace-font.js +217 -0
  77. package/indesign/interpreter.js +758 -0
  78. package/package.json +55 -6
  79. package/rules/typography-rules.json +31 -0
@@ -0,0 +1,836 @@
1
+ /* Bereich D – Rahmen und Objekte anlegen. */
2
+
3
+ /* bounds_mm {x, y, width, height} pruefen; x/y duerfen negativ sein. */
4
+ function idcBoundsArg(spec, field) {
5
+ if (!spec || typeof spec !== 'object') {
6
+ IDC.fail('invalid_argument', field + ' is required: { x, y, width, height } in mm.', null);
7
+ }
8
+ var keys = ['x', 'y', 'width', 'height'];
9
+ var i;
10
+ for (i = 0; i < keys.length; i++) {
11
+ if (typeof spec[keys[i]] !== 'number' || !isFinite(spec[keys[i]])) {
12
+ IDC.fail('invalid_argument', field + '.' + keys[i] + ' must be a number.', spec);
13
+ }
14
+ }
15
+ if (spec.width <= 0 || spec.height <= 0) {
16
+ IDC.fail('invalid_argument', field + '.width and ' + field + '.height must be greater than 0.', spec);
17
+ }
18
+ return { x: spec.x, y: spec.y, width: spec.width, height: spec.height };
19
+ }
20
+
21
+ function idcPointArg(spec, field) {
22
+ if (!spec || typeof spec !== 'object' || typeof spec.x !== 'number' || typeof spec.y !== 'number'
23
+ || !isFinite(spec.x) || !isFinite(spec.y)) {
24
+ IDC.fail('invalid_argument', field + ' is required: { x, y } in mm.', null);
25
+ }
26
+ return { x: spec.x, y: spec.y };
27
+ }
28
+
29
+ function idcCoordinateSpace(args) {
30
+ var space = args.coordinate_space;
31
+ if (space === undefined || space === null) { return 'page'; }
32
+ if (space !== 'page' && space !== 'spread') {
33
+ IDC.fail('invalid_argument', 'coordinate_space must be "page" or "spread".', { coordinate_space: space });
34
+ }
35
+ return space;
36
+ }
37
+
38
+ /* Seite (Dokument oder Muster) fuer page_id, sonst Fehler. */
39
+ function idcAnyPageById(doc, id) {
40
+ var found;
41
+ if (id === undefined || id === null) {
42
+ IDC.fail('invalid_argument', 'page_id is required.', null);
43
+ }
44
+ found = IDC.pageById(doc, id);
45
+ if (found === null) {
46
+ IDC.fail('not_found', 'No page with page_id ' + id + ' in this document.', { page_id: id });
47
+ }
48
+ return found;
49
+ }
50
+
51
+ /* [y1, x1, y2, x2] aus {x, y, width, height}. */
52
+ function idcRectToBounds(rect) {
53
+ return [rect.y, rect.x, rect.y + rect.height, rect.x + rect.width];
54
+ }
55
+
56
+ /* Seitenkoordinaten in Bogenkoordinaten: x um den Seitenversatz verschieben. */
57
+ function idcToSpreadBounds(page, bounds, space) {
58
+ var dx = space === 'spread' ? 0 : IDC.spreadOffsetOfPage(page);
59
+ return [bounds[0], bounds[1] + dx, bounds[2], bounds[3] + dx];
60
+ }
61
+
62
+ /*
63
+ * Objekt auf einer Seite anlegen. collectionName: 'textFrames' |
64
+ * 'rectangles' | 'graphicLines'. Angelegt wird immer unter Bogen-Nullpunkt
65
+ * mit umgerechneten Koordinaten – so ist eindeutig, wo das Objekt hinkommt,
66
+ * auch bei Anschnitt ueber den Bund (E-28).
67
+ */
68
+ function idcAddItem(doc, page, collectionName, bounds, space) {
69
+ var item;
70
+ var spreadBounds = idcToSpreadBounds(page, bounds, space);
71
+ try {
72
+ item = IDC.withRulerOrigin(doc, RulerOrigin.SPREAD_ORIGIN, function () {
73
+ var created = page[collectionName].add(undefined, undefined, undefined, { geometricBounds: spreadBounds });
74
+ return IDC.concrete(created);
75
+ });
76
+ } catch (e) {
77
+ IDC.fail('script_error', 'InDesign could not create the object: ' + String(e.message ? e.message : e),
78
+ { page_id: Number(page.id), bounds: bounds });
79
+ }
80
+ return item;
81
+ }
82
+
83
+ /* Landeprüfung (allgemeine Anforderung 4): Warnung bei Abweichung. */
84
+ function idcCheckLanding(ctx, item, wantedPage, what) {
85
+ var landing = IDC.landing(item);
86
+ if (landing.on_pasteboard) {
87
+ ctx.warn('The ' + what + ' landed on the pasteboard (Montageflaeche), not on page ' + String(wantedPage.name) + '.');
88
+ } else if (landing.page_id !== Number(wantedPage.id)) {
89
+ ctx.warn('The ' + what + ' landed on page ' + landing.page_name + ' (page_id ' + landing.page_id +
90
+ '), not on the requested page ' + String(wantedPage.name) + ' – InDesign assigns an object to the page holding most of it.');
91
+ }
92
+ return landing;
93
+ }
94
+
95
+ /* Begrenzung relativ zur Seite, auf der das Objekt gelandet ist (Montageflaeche: Bogen). */
96
+ function idcItemBounds(doc, item) {
97
+ try { return IDC.boundsOnOwnPage(doc, item); } catch (e) { return null; }
98
+ }
99
+
100
+ /*
101
+ * Koordinatenraum einer gelesenen Begrenzung: 'page' (Objekt liegt auf einer
102
+ * Seite, Werte relativ zu deren linker oberer Ecke) oder 'spread' (Montage-
103
+ * flaeche, Werte im Bogen). Lesende Werkzeuge geben ihn mit aus, damit die
104
+ * Werte unveraendert an set_frame_bounds zurueckgehen koennen (Vermerk E-63).
105
+ */
106
+ function idcBoundsSpace(item) {
107
+ var page = null, valid = false;
108
+ try { page = item.parentPage; } catch (e) { page = null; }
109
+ try { valid = page !== null && page !== undefined && page.isValid === true; } catch (e2) { valid = false; }
110
+ if (valid) { return 'page'; }
111
+ return 'spread';
112
+ }
113
+
114
+ /* Hat das Objekt Textumfluss (Textumfluss-Modus ungleich none)? */
115
+ function idcHasTextWrap(item) {
116
+ var name = idcTextWrapName(item);
117
+ if (name === null) { return false; }
118
+ return name !== 'none';
119
+ }
120
+
121
+ /* Zahl der Stories mit Uebersatz im Dokument; null, wenn nicht lesbar. */
122
+ function idcOversetStoryCount(doc) {
123
+ var count = 0, i, story, over;
124
+ try {
125
+ for (i = 0; i < doc.stories.length; i++) {
126
+ story = doc.stories.item(i);
127
+ over = null;
128
+ try { over = story.overflows === true; } catch (e) { over = null; }
129
+ if (over === true) { count = count + 1; }
130
+ }
131
+ } catch (e2) { return null; }
132
+ return count;
133
+ }
134
+
135
+ /* Uebersatzstand vor einer Aenderung an einem Rahmen mit Textumfluss; null ohne Textumfluss. */
136
+ function idcRecomposeBefore(doc, item) {
137
+ if (!idcHasTextWrap(item)) { return null; }
138
+ return { overset: idcOversetStoryCount(doc) };
139
+ }
140
+
141
+ /* Uebersatzstand ohne Bedingung (fuer Werkzeuge, die den Textumfluss selbst setzen). */
142
+ function idcOversetBefore(doc) {
143
+ return { overset: idcOversetStoryCount(doc) };
144
+ }
145
+
146
+ /*
147
+ * Nach der Aenderung: Umbruch erzwingen und den Uebersatzstand gegenhalten.
148
+ * InDesign bricht die Stories um einen Rahmen mit Textumfluss nach einer
149
+ * Geometrieaenderung nicht zuverlaessig vollstaendig neu um - der Umbruch
150
+ * blieb selbst nach Ruecknahme der Geometrie in einem Zwischenzustand, bis
151
+ * das Dokument geschlossen und neu geoeffnet wurde (Live-Fund 08.09.2026,
152
+ * Vermerk E-63).
153
+ */
154
+ function idcRecomposeAfter(ctx, doc, before) {
155
+ var out = { recomposed: false, overset_stories_before: null, overset_stories_after: null, overset_changed: null };
156
+ if (before === null || before === undefined) { return out; }
157
+ out.overset_stories_before = before.overset;
158
+ try { doc.recompose(); out.recomposed = true; } catch (e) { out.recomposed = false; }
159
+ if (out.recomposed !== true) {
160
+ ctx.warn('The object carries a text wrap, but InDesign could not recompose the document; the text flow around it may be stale - check preflight_document.');
161
+ return out;
162
+ }
163
+ out.overset_stories_after = idcOversetStoryCount(doc);
164
+ if (out.overset_stories_before !== null && out.overset_stories_after !== null) {
165
+ out.overset_changed = out.overset_stories_after !== out.overset_stories_before;
166
+ if (out.overset_stories_after > out.overset_stories_before) {
167
+ ctx.warn('The object carries a text wrap; after recomposing ' + out.overset_stories_after +
168
+ ' story/stories overflow (before: ' + out.overset_stories_before + ') - see list_stories or preflight_document.');
169
+ }
170
+ }
171
+ return out;
172
+ }
173
+
174
+ /* ------------------------------------------------------------- Farbfelder */
175
+
176
+ function idcParseHex(hex, field) {
177
+ var text = String(hex);
178
+ var match = text.match(/^#?([0-9a-fA-F]{6})$/);
179
+ if (!match) {
180
+ IDC.fail('invalid_argument', field + ' must be a hex colour like "#1A2B3C".', { value: text });
181
+ }
182
+ var h = match[1];
183
+ return {
184
+ r: parseInt(h.substr(0, 2), 16),
185
+ g: parseInt(h.substr(2, 2), 16),
186
+ b: parseInt(h.substr(4, 2), 16),
187
+ name: '#' + h.toUpperCase()
188
+ };
189
+ }
190
+
191
+ /* Farbfeld [None] – der Skriptname ist in jeder Sprachfassung "None". */
192
+ function idcNoneSwatch(doc) {
193
+ var swatch = null;
194
+ try {
195
+ swatch = doc.swatches.itemByName('None');
196
+ if (swatch && swatch.isValid === true) { return swatch; }
197
+ } catch (e) { /* weiter */ }
198
+ try {
199
+ swatch = doc.swatches.item(0);
200
+ if (swatch && swatch.isValid === true) { return swatch; }
201
+ } catch (e2) { /* weiter */ }
202
+ return null;
203
+ }
204
+
205
+ function idcBlackSwatch(doc) {
206
+ var swatch = null;
207
+ try {
208
+ swatch = doc.swatches.itemByName('Black');
209
+ if (swatch && swatch.isValid === true) { return swatch; }
210
+ } catch (e) { /* weiter */ }
211
+ return null;
212
+ }
213
+
214
+ /* RGB-Farbfeld zu einem Hexwert; vorhandenes gleichen Namens wird wiederverwendet. */
215
+ function idcSwatchForHex(doc, hex, field, created) {
216
+ var rgb = idcParseHex(hex, field);
217
+ var color = null;
218
+ try {
219
+ color = doc.colors.itemByName(rgb.name);
220
+ if (color && color.isValid === true) { return color; }
221
+ } catch (e) { color = null; }
222
+ try {
223
+ /* Colors.add nimmt nur withProperties – anders als die Rahmensammlungen (Live-Fund 04.09.2026). */
224
+ color = doc.colors.add({
225
+ name: rgb.name,
226
+ model: ColorModel.PROCESS,
227
+ space: ColorSpace.RGB,
228
+ colorValue: [rgb.r, rgb.g, rgb.b]
229
+ });
230
+ created.push(Number(color.id));
231
+ return color;
232
+ } catch (e2) {
233
+ IDC.fail('script_error', 'InDesign could not create the colour swatch ' + rgb.name + ': ' +
234
+ String(e2.message ? e2.message : e2), { hex: rgb.name });
235
+ }
236
+ return null;
237
+ }
238
+
239
+ /*
240
+ * Vorhandenes Farbfeld ueber seinen exakten Namen (Hausfarben, CMYK) –
241
+ * Alternative zu den Hex-Parametern, die RGB-Felder anlegen (Fund 7,
242
+ * Hefttest Sitzung 6). "none" ist nicht erlaubt; dafuer die Hex-Wege.
243
+ */
244
+ function idcSwatchArg(doc, name, field) {
245
+ var swatch;
246
+ if (typeof name !== 'string' || name === '') {
247
+ IDC.fail('invalid_argument', field + ' must be the exact name of an existing swatch.', { value: name });
248
+ }
249
+ if (name.charAt(0) === '[' || name.toLowerCase() === 'none') {
250
+ IDC.fail('invalid_argument', field + ' cannot be "' + name + '"; use the hex parameters or set_frame_appearance with "none".', { value: name });
251
+ }
252
+ swatch = idcSwatchByName(doc, name);
253
+ if (swatch === null) {
254
+ IDC.fail('not_found', 'Swatch "' + name + '" not found – names are exact (see list_swatches); create it with create_swatch.',
255
+ { swatch_name: name });
256
+ }
257
+ return swatch;
258
+ }
259
+
260
+ function idcBothGiven(args, a, b) {
261
+ if (args[a] !== undefined && args[a] !== null && args[b] !== undefined && args[b] !== null) {
262
+ IDC.fail('invalid_argument', 'Pass either ' + a + ' or ' + b + ', not both.', null);
263
+ }
264
+ }
265
+
266
+ function idcSetStrokeWeightPt(item, weight) {
267
+ IDC.inPoints(function () { item.strokeWeight = weight; });
268
+ }
269
+
270
+ /* Kontur und Flaeche zurücklesen: Staerke in Punkt, Farbfeldnamen. */
271
+ function idcAppearance(item) {
272
+ var out = { stroke_weight_pt: null, stroke_color: null, fill_color: null };
273
+ try { out.stroke_weight_pt = IDC.inPoints(function () { return IDC.round(Number(item.strokeWeight), 3); }); } catch (e1) { out.stroke_weight_pt = null; }
274
+ try { out.stroke_color = String(item.strokeColor.name); } catch (e2) { out.stroke_color = null; }
275
+ try { out.fill_color = String(item.fillColor.name); } catch (e3) { out.fill_color = null; }
276
+ return out;
277
+ }
278
+
279
+ function idcSetNoTextWrap(item) {
280
+ try {
281
+ if (typeof TextWrapModes !== 'undefined') {
282
+ item.textWrapPreferences.textWrapMode = TextWrapModes.NONE;
283
+ return true;
284
+ }
285
+ } catch (e) { /* kein Umfluss-Objekt */ }
286
+ return false;
287
+ }
288
+
289
+ function idcTextWrapName(item) {
290
+ var mode;
291
+ try { mode = item.textWrapPreferences.textWrapMode; } catch (e) { return null; }
292
+ if (typeof TextWrapModes === 'undefined') { return String(mode); }
293
+ if (IDC.enumIs(mode, TextWrapModes.NONE)) { return 'none'; }
294
+ if (IDC.enumIs(mode, TextWrapModes.BOUNDING_BOX_TEXT_WRAP)) { return 'bounding_box'; }
295
+ if (IDC.enumIs(mode, TextWrapModes.CONTOUR)) { return 'contour'; }
296
+ if (IDC.enumIs(mode, TextWrapModes.JUMP_OBJECT_TEXT_WRAP)) { return 'jump_object'; }
297
+ if (IDC.enumIs(mode, TextWrapModes.NEXT_COLUMN_TEXT_WRAP)) { return 'next_column'; }
298
+ return String(mode);
299
+ }
300
+
301
+ /* -------------------------------------------------------- create_text_frame */
302
+
303
+ IDC.register('create_text_frame', { needs_document: true, read_only: false, ruler: 'page' },
304
+ function (ctx) {
305
+ var args = ctx.args;
306
+ var doc = ctx.doc;
307
+ var found = idcAnyPageById(doc, args.page_id);
308
+ var page = found.page;
309
+ var rect = idcBoundsArg(args.bounds_mm, 'bounds_mm');
310
+ var space = idcCoordinateSpace(args);
311
+ var frame, landing, wrap;
312
+
313
+ if (args.text_wrap !== undefined && args.text_wrap !== null && args.text_wrap !== 'none') {
314
+ IDC.fail('invalid_argument', 'text_wrap supports only "none" when creating.', { text_wrap: args.text_wrap });
315
+ }
316
+ var vj = args.vertical_justification;
317
+ if (vj !== undefined && vj !== null && vj !== 'top' && vj !== 'center' && vj !== 'bottom' && vj !== 'justify') {
318
+ IDC.fail('invalid_argument', 'vertical_justification must be top, center, bottom or justify.', { vertical_justification: vj });
319
+ }
320
+ /* Rahmenoptionen (Wunschliste J, Sitzung 7): Grundlinienversatz, Umfluss ignorieren, Innenabstand. */
321
+ var fbo = args.first_baseline_offset;
322
+ var fboEnum = null;
323
+ if (fbo !== undefined && fbo !== null) {
324
+ fboEnum = idcFirstBaselineFor(fbo);
325
+ if (fboEnum === null) {
326
+ IDC.fail('invalid_argument', 'first_baseline_offset must be ascent, cap_height, leading, x_height, fixed or embox_top.', { first_baseline_offset: fbo });
327
+ }
328
+ }
329
+ var minFirst = args.min_first_baseline_pt;
330
+ if (minFirst !== undefined && minFirst !== null && (typeof minFirst !== 'number' || !isFinite(minFirst) || minFirst < 0)) {
331
+ IDC.fail('invalid_argument', 'min_first_baseline_pt must be a number of 0 or more (points).', { min_first_baseline_pt: minFirst });
332
+ }
333
+ var ignoreWrap = args.ignore_text_wrap;
334
+ if (ignoreWrap !== undefined && ignoreWrap !== null && typeof ignoreWrap !== 'boolean') {
335
+ IDC.fail('invalid_argument', 'ignore_text_wrap must be true or false.', { ignore_text_wrap: ignoreWrap });
336
+ }
337
+ var inset = null;
338
+ if (args.inset_mm !== undefined && args.inset_mm !== null) { inset = idcInsetArg(args.inset_mm, 'inset_mm'); }
339
+
340
+ frame = idcAddItem(doc, page, 'textFrames', idcRectToBounds(rect), space);
341
+
342
+ var expansion = { replaced: {}, unknown: [] };
343
+ try {
344
+ if (args.initial_text !== undefined && args.initial_text !== null && String(args.initial_text) !== '') {
345
+ /* A-8.8: Platzhalter; der Text selbst bleibt woertlich (E-30: kein LF-zu-CR hier). */
346
+ expansion = idcExpandPlaceholders(String(args.initial_text), args.placeholders !== false);
347
+ var split = idcSplitBreaks(expansion.text);
348
+ frame.contents = split.plain;
349
+ idcInsertBreaks(frame, 0, split.breaks);
350
+ }
351
+ if (args.text_wrap === 'none') { idcSetNoTextWrap(frame); }
352
+ if (vj !== undefined && vj !== null && typeof VerticalJustification !== 'undefined') {
353
+ /*
354
+ * Kein verschachtelter ?:-Ausdruck: ExtendScript klammert ihn links
355
+ * (a ? b : c ? d : e wird zu (a ? b : c) ? d : e), "top" und "center"
356
+ * landeten so auf BOTTOM_ALIGN – Ursache von Fund 3 (Sitzung 6),
357
+ * am 05.09.2026 live nachgewiesen.
358
+ */
359
+ frame.textFramePreferences.verticalJustification = idcVerticalJustificationFor(vj);
360
+ }
361
+ if (fboEnum !== null) { frame.textFramePreferences.firstBaselineOffset = fboEnum; }
362
+ if (minFirst !== undefined && minFirst !== null) {
363
+ IDC.inPoints(function () { frame.textFramePreferences.minimumFirstBaselineOffset = minFirst; });
364
+ }
365
+ if (ignoreWrap !== undefined && ignoreWrap !== null) { frame.textFramePreferences.ignoreWrap = ignoreWrap === true; }
366
+ if (inset !== null) { frame.textFramePreferences.insetSpacing = [inset.top, inset.left, inset.bottom, inset.right]; }
367
+ } catch (e) {
368
+ IDC.fail('script_error', 'The text frame was created (frame_id ' + Number(frame.id) + ') but could not be configured: ' +
369
+ String(e.message ? e.message : e), { frame_id: Number(frame.id) });
370
+ }
371
+
372
+ landing = idcCheckLanding(ctx, frame, page, 'text frame');
373
+ idcPlaceholderWarnings(ctx, expansion);
374
+ wrap = idcTextWrapName(frame);
375
+ if (wrap !== null && wrap !== 'none') {
376
+ ctx.warn('The new text frame inherited text wrap (Textumfluss) "' + wrap +
377
+ '" from the document defaults; text frames underneath may be pushed into overset. Pass text_wrap: "none" or use set_text_wrap.');
378
+ }
379
+
380
+ var options = idcTextFrameOptions(doc, frame);
381
+ ctx.changes = { created_frame_ids: [Number(frame.id)] };
382
+ return {
383
+ frame_id: Number(frame.id),
384
+ type: 'text',
385
+ page_id: Number(page.id),
386
+ coordinate_space: space,
387
+ bounds_mm: idcItemBounds(doc, frame),
388
+ landed_on_page_id: landing.page_id,
389
+ landed_on_page_name: landing.page_name,
390
+ on_parent_page: found.is_parent_page,
391
+ text_wrap: wrap,
392
+ vertical_justification: options.vertical_justification,
393
+ first_baseline_offset: options.first_baseline_offset,
394
+ min_first_baseline_pt: options.min_first_baseline_pt,
395
+ ignore_text_wrap: options.ignore_text_wrap,
396
+ inset_mm: options.inset_mm,
397
+ placeholders_replaced: expansion.replaced,
398
+ placeholders_unknown: expansion.unknown
399
+ };
400
+ });
401
+
402
+ /* ------------------------------------------------------- create_image_frame */
403
+
404
+ IDC.register('create_image_frame', { needs_document: true, read_only: false, ruler: 'page' },
405
+ function (ctx) {
406
+ var args = ctx.args;
407
+ var doc = ctx.doc;
408
+ var found = idcAnyPageById(doc, args.page_id);
409
+ var page = found.page;
410
+ var rect = idcBoundsArg(args.bounds_mm, 'bounds_mm');
411
+ var space = idcCoordinateSpace(args);
412
+ var keep = args.keep_default_appearance === true;
413
+ var frame, landing, cleared = false, none;
414
+
415
+ frame = idcAddItem(doc, page, 'rectangles', idcRectToBounds(rect), space);
416
+
417
+ if (!keep) {
418
+ try {
419
+ none = idcNoneSwatch(doc);
420
+ /* Reihenfolge: erst die Staerke, dann die Farben – sonst bleibt 1 pt stehen (Live-Fund 04.09.2026). */
421
+ idcSetStrokeWeightPt(frame, 0);
422
+ if (none !== null) {
423
+ frame.strokeColor = none;
424
+ frame.fillColor = none;
425
+ }
426
+ cleared = true;
427
+ } catch (e2) {
428
+ ctx.warn('Could not clear fill and stroke of the new frame: ' + String(e2.message ? e2.message : e2));
429
+ }
430
+ }
431
+ try {
432
+ if (typeof ContentType !== 'undefined') { frame.contentType = ContentType.GRAPHIC_TYPE; }
433
+ } catch (e0) { /* Inhaltstyp bleibt */ }
434
+ try {
435
+ if (typeof EmptyFrameFittingOptions !== 'undefined') {
436
+ frame.frameFittingOptions.fittingOnEmptyFrame = EmptyFrameFittingOptions.PROPORTIONALLY;
437
+ }
438
+ } catch (e1) { /* keine Einpassungsoptionen */ }
439
+
440
+ landing = idcCheckLanding(ctx, frame, page, 'image frame');
441
+ var look = idcAppearance(frame);
442
+ if (cleared && look.stroke_weight_pt !== null && look.stroke_weight_pt > 0) {
443
+ ctx.warn('The stroke weight reads ' + look.stroke_weight_pt + ' pt after clearing; run set_frame_appearance with stroke_weight_pt 0 and check the export.');
444
+ }
445
+
446
+ ctx.changes = { created_frame_ids: [Number(frame.id)] };
447
+ return {
448
+ frame_id: Number(frame.id),
449
+ type: 'rectangle',
450
+ page_id: Number(page.id),
451
+ coordinate_space: space,
452
+ bounds_mm: idcItemBounds(doc, frame),
453
+ appearance_cleared: cleared,
454
+ stroke_weight_pt: look.stroke_weight_pt,
455
+ stroke_color: look.stroke_color,
456
+ fill_color: look.fill_color,
457
+ landed_on_page_id: landing.page_id,
458
+ landed_on_page_name: landing.page_name,
459
+ on_parent_page: found.is_parent_page
460
+ };
461
+ });
462
+
463
+ /* --------------------------------------------------------- create_rectangle */
464
+
465
+ IDC.register('create_rectangle', { needs_document: true, read_only: false, ruler: 'page' },
466
+ function (ctx) {
467
+ var args = ctx.args;
468
+ var doc = ctx.doc;
469
+ var found = idcAnyPageById(doc, args.page_id);
470
+ var page = found.page;
471
+ var rect = idcBoundsArg(args.bounds_mm, 'bounds_mm');
472
+ var space = idcCoordinateSpace(args);
473
+ var swatchIds = [];
474
+ var fill = null, stroke = null, weight = null, radius = null;
475
+ var item, landing, none;
476
+
477
+ idcBothGiven(args, 'fill_hex', 'fill_swatch_name');
478
+ idcBothGiven(args, 'stroke_hex', 'stroke_swatch_name');
479
+ if (args.fill_hex !== undefined && args.fill_hex !== null) { fill = idcSwatchForHex(doc, args.fill_hex, 'fill_hex', swatchIds); }
480
+ if (args.fill_swatch_name !== undefined && args.fill_swatch_name !== null) { fill = idcSwatchArg(doc, args.fill_swatch_name, 'fill_swatch_name'); }
481
+ if (args.stroke_hex !== undefined && args.stroke_hex !== null) { stroke = idcSwatchForHex(doc, args.stroke_hex, 'stroke_hex', swatchIds); }
482
+ if (args.stroke_swatch_name !== undefined && args.stroke_swatch_name !== null) { stroke = idcSwatchArg(doc, args.stroke_swatch_name, 'stroke_swatch_name'); }
483
+ if (args.stroke_weight_pt !== undefined && args.stroke_weight_pt !== null) {
484
+ if (typeof args.stroke_weight_pt !== 'number' || args.stroke_weight_pt < 0) {
485
+ IDC.fail('invalid_argument', 'stroke_weight_pt must be a number of 0 or more.', { stroke_weight_pt: args.stroke_weight_pt });
486
+ }
487
+ weight = args.stroke_weight_pt;
488
+ }
489
+ radius = idcRadiusArg(args.corner_radius_mm, 'corner_radius_mm');
490
+ if (args.corner_type !== undefined && args.corner_type !== null) { idcCornerTypeFor(String(args.corner_type), 'corner_type'); }
491
+ var fillTint = idcTintArg(args.fill_tint_percent, 'fill_tint_percent');
492
+ var strokeTint = idcTintArg(args.stroke_tint_percent, 'stroke_tint_percent');
493
+ var fillAngle = idcAngleArg(args.gradient_fill_angle_deg, 'gradient_fill_angle_deg');
494
+ var strokeAngle = idcAngleArg(args.gradient_stroke_angle_deg, 'gradient_stroke_angle_deg');
495
+ if (args.text_wrap !== undefined && args.text_wrap !== null && args.text_wrap !== 'none' && args.text_wrap !== 'bounding_box' && args.text_wrap !== 'object_shape') {
496
+ IDC.fail('invalid_argument', 'text_wrap must be none, bounding_box or object_shape when creating.', { text_wrap: args.text_wrap });
497
+ }
498
+
499
+ item = idcAddShape(doc, page, 'rectangles', idcLayerForNew(doc, args), idcRectToBounds(rect), space, null);
500
+
501
+ try {
502
+ none = idcNoneSwatch(doc);
503
+ /*
504
+ * Reihenfolge: erst die Konturstaerke, dann die Konturfarbe, dann die
505
+ * Flaeche. Wird [None] als Konturfarbe vor der Staerke gesetzt, bleibt
506
+ * die Staerke bei 1 pt und die Farbe liest sich leer (Live-Fund
507
+ * 04.09.2026, InDesign 21.5) – die 1-pt-Kontur im Export.
508
+ */
509
+ var strokeSwatch = null;
510
+ var strokeWeight = 0;
511
+ if (stroke !== null) {
512
+ strokeSwatch = stroke;
513
+ strokeWeight = weight === null ? 1 : weight;
514
+ } else if (weight !== null && weight > 0) {
515
+ strokeSwatch = idcBlackSwatch(doc) || none;
516
+ strokeWeight = weight;
517
+ } else {
518
+ strokeSwatch = none;
519
+ strokeWeight = 0;
520
+ }
521
+ idcSetStrokeWeightPt(item, strokeWeight);
522
+ if (strokeSwatch !== null) { item.strokeColor = strokeSwatch; }
523
+ if (fill !== null) { item.fillColor = fill; }
524
+ else if (none !== null) { item.fillColor = none; }
525
+ /* A-8.3: corner_type (Vorgabe rounded, wenn nur corner_radius_mm > 0), A-8.5: Farbton und Verlaufswinkel. */
526
+ if (typeof CornerOptions !== 'undefined') { idcApplyCornerArgs(item, { corner_type: args.corner_type, corner_radius_mm: radius }); }
527
+ idcApplyTintsAndAngles(ctx, item, fillTint, strokeTint, fillAngle, strokeAngle);
528
+ idcApplyCreateTextWrap(item, args);
529
+ idcApplyName(item, args);
530
+ } catch (e) {
531
+ if (e && e.isIdcError) { throw e; }
532
+ IDC.fail('script_error', 'The rectangle was created (frame_id ' + Number(item.id) + ') but could not be styled: ' +
533
+ String(e.message ? e.message : e), { frame_id: Number(item.id) });
534
+ }
535
+
536
+ landing = idcCheckLanding(ctx, item, page, 'rectangle');
537
+ var wrap = idcTextWrapName(item);
538
+ if (wrap !== null && wrap !== 'none') {
539
+ ctx.warn('The rectangle carries text wrap (Textumfluss) "' + wrap + '" from the document defaults. Pass text_wrap: "none" or use set_text_wrap.');
540
+ }
541
+
542
+ var look = idcAppearanceFull(item);
543
+ var corners = idcReadCorners(item);
544
+ ctx.changes = { created_frame_ids: [Number(item.id)], created_swatch_ids: swatchIds };
545
+ return {
546
+ frame_id: Number(item.id),
547
+ type: 'rectangle',
548
+ page_id: Number(page.id),
549
+ coordinate_space: space,
550
+ bounds_mm: idcItemBounds(doc, item),
551
+ swatch_ids: swatchIds,
552
+ stroke_weight_pt: look.stroke_weight_pt,
553
+ stroke_color: look.stroke_color,
554
+ stroke_kind: look.stroke_kind,
555
+ fill_color: look.fill_color,
556
+ fill_kind: look.fill_kind,
557
+ fill_tint_percent: look.fill_tint_percent,
558
+ stroke_tint_percent: look.stroke_tint_percent,
559
+ gradient_fill_angle_deg: look.gradient_fill_angle_deg,
560
+ gradient_stroke_angle_deg: look.gradient_stroke_angle_deg,
561
+ corner_type: corners === null ? null : corners.top_left.type,
562
+ corners: corners === null ? null : { top_left: corners.top_left, top_right: corners.top_right, bottom_left: corners.bottom_left, bottom_right: corners.bottom_right },
563
+ landed_on_page_id: landing.page_id,
564
+ landed_on_page_name: landing.page_name,
565
+ on_parent_page: found.is_parent_page,
566
+ text_wrap: wrap,
567
+ layer_name: (function () { try { return String(item.itemLayer.name); } catch (eL) { return null; } })()
568
+ };
569
+ });
570
+
571
+ /* -------------------------------------------------------------- create_line */
572
+
573
+ /* Endpunkte relativ zur Landeseite: unter Bogen-Nullpunkt lesen, Seitenversatz abziehen. */
574
+ function idcLineEnds(doc, line) {
575
+ var landing = IDC.landing(line);
576
+ var found = landing.on_pasteboard ? null : IDC.pageById(doc, landing.page_id);
577
+ var dx = found === null ? 0 : IDC.spreadOffsetOfPage(found.page);
578
+ try {
579
+ return IDC.withRulerOrigin(doc, RulerOrigin.SPREAD_ORIGIN, function () {
580
+ var path = line.paths.item(0);
581
+ var a = path.pathPoints.item(0).anchor;
582
+ var b = path.pathPoints.item(path.pathPoints.length - 1).anchor;
583
+ return {
584
+ start_mm: { x: IDC.round(a[0] - dx), y: IDC.round(a[1]) },
585
+ end_mm: { x: IDC.round(b[0] - dx), y: IDC.round(b[1]) }
586
+ };
587
+ });
588
+ } catch (e) { return { start_mm: null, end_mm: null }; }
589
+ }
590
+
591
+ IDC.register('create_line', { needs_document: true, read_only: false, ruler: 'page' },
592
+ function (ctx) {
593
+ var args = ctx.args;
594
+ var doc = ctx.doc;
595
+ var found = idcAnyPageById(doc, args.page_id);
596
+ var page = found.page;
597
+ var start = idcPointArg(args.start_mm, 'start_mm');
598
+ var end = idcPointArg(args.end_mm, 'end_mm');
599
+ var space = idcCoordinateSpace(args);
600
+ var swatchIds = [];
601
+ var stroke = null, weight, line, landing, ends;
602
+
603
+ if (start.x === end.x && start.y === end.y) {
604
+ IDC.fail('invalid_argument', 'start_mm and end_mm must differ.', { start_mm: start, end_mm: end });
605
+ }
606
+ if (typeof args.stroke_weight_pt !== 'number' || !(args.stroke_weight_pt > 0)) {
607
+ IDC.fail('invalid_argument', 'stroke_weight_pt is required and must be greater than 0 (points).', { stroke_weight_pt: args.stroke_weight_pt });
608
+ }
609
+ weight = args.stroke_weight_pt;
610
+ idcBothGiven(args, 'stroke_hex', 'swatch_name');
611
+ if (args.stroke_hex !== undefined && args.stroke_hex !== null) { stroke = idcSwatchForHex(doc, args.stroke_hex, 'stroke_hex', swatchIds); }
612
+ if (args.swatch_name !== undefined && args.swatch_name !== null) { stroke = idcSwatchArg(doc, args.swatch_name, 'swatch_name'); }
613
+
614
+ var dx = space === 'spread' ? 0 : IDC.spreadOffsetOfPage(page);
615
+ try {
616
+ line = IDC.withRulerOrigin(doc, RulerOrigin.SPREAD_ORIGIN, function () {
617
+ var created = IDC.concrete(page.graphicLines.add());
618
+ created.paths.item(0).entirePath = [[start.x + dx, start.y], [end.x + dx, end.y]];
619
+ return created;
620
+ });
621
+ } catch (e) {
622
+ IDC.fail('script_error', 'InDesign could not create the line: ' + String(e.message ? e.message : e),
623
+ { page_id: Number(page.id), start_mm: start, end_mm: end });
624
+ }
625
+
626
+ var strokeTint = idcTintArg(args.stroke_tint_percent, 'stroke_tint_percent');
627
+ var strokeAngle = idcAngleArg(args.gradient_stroke_angle_deg, 'gradient_stroke_angle_deg');
628
+ try {
629
+ idcSetStrokeWeightPt(line, weight);
630
+ line.strokeColor = stroke !== null ? stroke : (idcBlackSwatch(doc) || line.strokeColor);
631
+ idcApplyTintsAndAngles(ctx, line, null, strokeTint, null, strokeAngle);
632
+ idcSetNoTextWrap(line);
633
+ } catch (e2) {
634
+ if (e2 && e2.isIdcError) { throw e2; }
635
+ IDC.fail('script_error', 'The line was created (frame_id ' + Number(line.id) + ') but could not be styled: ' +
636
+ String(e2.message ? e2.message : e2), { frame_id: Number(line.id) });
637
+ }
638
+
639
+ landing = idcCheckLanding(ctx, line, page, 'line');
640
+ ends = idcLineEnds(doc, line);
641
+ var weightBack = null;
642
+ try { weightBack = IDC.inPoints(function () { return IDC.round(Number(line.strokeWeight), 3); }); } catch (e3) { weightBack = null; }
643
+
644
+ var strokeName = null;
645
+ try { strokeName = String(line.strokeColor.name); } catch (e4) { strokeName = null; }
646
+ ctx.changes = { created_frame_ids: [Number(line.id)], created_swatch_ids: swatchIds };
647
+ return {
648
+ frame_id: Number(line.id),
649
+ type: 'line',
650
+ page_id: Number(page.id),
651
+ coordinate_space: space,
652
+ start_mm: ends.start_mm,
653
+ end_mm: ends.end_mm,
654
+ bounds_mm: idcItemBounds(doc, line),
655
+ stroke_weight_pt: weightBack,
656
+ stroke_color: strokeName,
657
+ stroke_kind: idcSwatchKindSafe(line, 'strokeColor'),
658
+ stroke_tint_percent: idcAppearanceFull(line).stroke_tint_percent,
659
+ gradient_stroke_angle_deg: idcAppearanceFull(line).gradient_stroke_angle_deg,
660
+ swatch_ids: swatchIds,
661
+ landed_on_page_id: landing.page_id,
662
+ landed_on_page_name: landing.page_name,
663
+ on_parent_page: found.is_parent_page
664
+ };
665
+ });
666
+
667
+ /* ---------------------------------------------------------- duplicate_frame */
668
+
669
+ function idcFrameArg(doc, args, field) {
670
+ var found;
671
+ if (args[field] === undefined || args[field] === null) {
672
+ IDC.fail('invalid_argument', field + ' is required.', null);
673
+ }
674
+ found = IDC.itemById(doc, args[field], 'any');
675
+ if (found === null) {
676
+ IDC.fail('not_found', 'No object with ' + field + ' ' + args[field] + ' in this document.', { frame_id: args[field] });
677
+ }
678
+ /*
679
+ * Schreibende Befehle scheitern an gesperrten Ebenen und gesperrten
680
+ * Objekten – frueher mit nacktem InDesign-Fehler oder gar nicht sichtbar
681
+ * (Wunschliste J Nr. 2). Deshalb hier zentral: invalid_state mit Ansage.
682
+ */
683
+ if (IDC.currentCommand !== null && IDC.currentCommand.read_only !== true) {
684
+ idcRejectLocked(doc, found.item, args[field], IDC.currentCommand.name);
685
+ }
686
+ return found;
687
+ }
688
+
689
+ IDC.register('duplicate_frame', { needs_document: true, read_only: false, ruler: 'page' },
690
+ function (ctx) {
691
+ var args = ctx.args;
692
+ var doc = ctx.doc;
693
+ var found = idcFrameArg(doc, args, 'frame_id');
694
+ var source = found.item;
695
+ var offset = { x: 0, y: 0 };
696
+ var copy, landing, sourceLanding;
697
+
698
+ if (args.offset_mm !== undefined && args.offset_mm !== null) { offset = idcPointArg(args.offset_mm, 'offset_mm'); }
699
+
700
+ try {
701
+ copy = source.duplicate(undefined, [offset.x, offset.y]);
702
+ if (IDC.isArray(copy)) { copy = copy[0]; }
703
+ copy = IDC.concrete(copy);
704
+ } catch (e) {
705
+ IDC.fail('script_error', 'InDesign could not duplicate object ' + args.frame_id + ': ' + String(e.message ? e.message : e),
706
+ { frame_id: args.frame_id });
707
+ }
708
+
709
+ sourceLanding = IDC.landing(source);
710
+ landing = IDC.landing(copy);
711
+ if (landing.on_pasteboard) {
712
+ ctx.warn('The duplicate landed on the pasteboard (Montageflaeche); it stays on the spread of the original – use move_frame_to_page for another page.');
713
+ } else if (!sourceLanding.on_pasteboard && landing.page_id !== sourceLanding.page_id) {
714
+ ctx.warn('The duplicate landed on page ' + landing.page_name + ', the original is on page ' + sourceLanding.page_name + '.');
715
+ }
716
+
717
+ ctx.changes = { new_frames: [Number(copy.id)], created_frame_ids: [Number(copy.id)] };
718
+ return {
719
+ source_frame_id: Number(source.id),
720
+ frame_id: Number(copy.id),
721
+ type: IDC.itemType(copy),
722
+ offset_mm: { x: offset.x, y: offset.y },
723
+ bounds_mm: idcItemBounds(doc, copy),
724
+ landed_on_page_id: landing.page_id,
725
+ landed_on_page_name: landing.page_name,
726
+ on_parent_page: found.on_parent
727
+ };
728
+ });
729
+
730
+ /* ------------------------------------------------------------- delete_frame */
731
+
732
+ function idcCollectIds(item, out) {
733
+ var i, all;
734
+ try { out.push(Number(item.id)); } catch (e0) { /* egal */ }
735
+ try {
736
+ all = item.allPageItems;
737
+ for (i = 0; i < all.length; i++) { out.push(Number(all[i].id)); }
738
+ } catch (e) { /* keine Kinder */ }
739
+ }
740
+
741
+ IDC.register('delete_frame', { needs_document: true, read_only: false, ruler: 'page' },
742
+ function (ctx) {
743
+ var args = ctx.args;
744
+ var doc = ctx.doc;
745
+ var found = idcFrameArg(doc, args, 'frame_id');
746
+ var item = found.item;
747
+ var type = IDC.itemType(item);
748
+ var landing = IDC.landing(item);
749
+ var ids = [];
750
+ var threaded = false, charactersRemoved = 0, bounds = idcItemBounds(doc, item);
751
+
752
+ idcCollectIds(item, ids);
753
+
754
+ if (type === 'text') {
755
+ threaded = idcIsThreaded(item);
756
+ if (threaded) {
757
+ /*
758
+ * Spezifikation: der Textanteil eines verketteten Rahmens geht mit.
759
+ * InDesign allein wuerde den Text in die Nachbarrahmen fliessen
760
+ * lassen; deshalb erst den Text dieses Rahmens entfernen.
761
+ */
762
+ try {
763
+ charactersRemoved = Number(item.texts.item(0).characters.length);
764
+ if (charactersRemoved > 0) { item.texts.item(0).remove(); }
765
+ } catch (et) {
766
+ ctx.warn('Could not remove the text of the threaded frame before deleting it; it may have flowed into the neighbouring frames: ' +
767
+ String(et.message ? et.message : et));
768
+ }
769
+ }
770
+ }
771
+
772
+ try {
773
+ item.remove();
774
+ } catch (e) {
775
+ IDC.fail('script_error', 'InDesign could not delete object ' + args.frame_id + ': ' + String(e.message ? e.message : e),
776
+ { frame_id: args.frame_id });
777
+ }
778
+ if (threaded) {
779
+ ctx.warn('The frame was threaded (verkettet); its text portion (' + charactersRemoved + ' characters) was removed with it. No undo.');
780
+ }
781
+
782
+ ctx.changes = { removed_frame_ids: ids };
783
+ return {
784
+ frame_id: Number(args.frame_id),
785
+ type: type,
786
+ was_threaded: threaded,
787
+ characters_removed: charactersRemoved,
788
+ removed_frame_ids: ids,
789
+ bounds_mm: bounds,
790
+ page_id: landing.page_id,
791
+ page_name: landing.page_name,
792
+ on_parent_page: found.on_parent
793
+ };
794
+ });
795
+
796
+ /* ------------------------------------------------------ clear_frame_content */
797
+
798
+ IDC.register('clear_frame_content', { needs_document: true, read_only: false, ruler: 'page' },
799
+ function (ctx) {
800
+ var args = ctx.args;
801
+ var doc = ctx.doc;
802
+ var found = idcFrameArg(doc, args, 'frame_id');
803
+ var item = found.item;
804
+ var typeBefore = IDC.itemType(item);
805
+ var removed = 0;
806
+ var i, graphics, names = [];
807
+
808
+ if (typeBefore === 'text') {
809
+ ctx.warn('Object ' + args.frame_id + ' is a text frame; its text is left untouched (use set_text with "" to empty it).');
810
+ } else if (typeBefore === 'line') {
811
+ ctx.warn('Object ' + args.frame_id + ' is a line; nothing to clear.');
812
+ } else {
813
+ try {
814
+ graphics = item.graphics;
815
+ for (i = graphics.length - 1; i >= 0; i--) {
816
+ try { names.push(String(graphics.item(i).itemLink.name)); } catch (en) { names.push(null); }
817
+ graphics.item(i).remove();
818
+ removed += 1;
819
+ }
820
+ } catch (e) {
821
+ IDC.fail('script_error', 'InDesign could not remove the graphic from object ' + args.frame_id + ': ' +
822
+ String(e.message ? e.message : e), { frame_id: args.frame_id, graphics_removed: removed });
823
+ }
824
+ }
825
+
826
+ if (removed > 0) { ctx.changes = { modified_frame_ids: [Number(item.id)] }; }
827
+ return {
828
+ frame_id: Number(item.id),
829
+ graphics_removed: removed,
830
+ removed_link_names: names,
831
+ type_before: typeBefore,
832
+ type_after: IDC.itemType(item),
833
+ bounds_mm: idcItemBounds(doc, item),
834
+ on_parent_page: found.on_parent
835
+ };
836
+ });