layoutbridge-light 0.0.0-stage → 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 (88) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +26 -0
  3. package/README.de.md +338 -0
  4. package/README.md +325 -2
  5. package/THIRD-PARTY-NOTICES.md +2878 -0
  6. package/dist/src/mcp/catalog.js +126 -0
  7. package/dist/src/mcp/config.js +211 -0
  8. package/dist/src/mcp/dispatch.js +164 -0
  9. package/dist/src/mcp/epub-check.js +331 -0
  10. package/dist/src/mcp/epub-orientation.js +132 -0
  11. package/dist/src/mcp/license/free-tools.js +16 -0
  12. package/dist/src/mcp/license/gate.js +210 -0
  13. package/dist/src/mcp/license/index.js +107 -0
  14. package/dist/src/mcp/license/instance-name.js +57 -0
  15. package/dist/src/mcp/license/key-source.js +59 -0
  16. package/dist/src/mcp/license/lemonsqueezy-verifier.js +207 -0
  17. package/dist/src/mcp/license/placeholder-verifier.js +10 -0
  18. package/dist/src/mcp/license/polar-ids.js +100 -0
  19. package/dist/src/mcp/license/polar-verifier.js +285 -0
  20. package/dist/src/mcp/license/product-ids.js +73 -0
  21. package/dist/src/mcp/license/state-store.js +91 -0
  22. package/dist/src/mcp/license/types.js +11 -0
  23. package/dist/src/mcp/logging.js +271 -0
  24. package/dist/src/mcp/product-info.js +54 -0
  25. package/dist/src/mcp/product.js +56 -0
  26. package/dist/src/mcp/server.js +253 -0
  27. package/dist/src/mcp/setup.js +680 -0
  28. package/dist/src/mcp/start.cjs +117 -0
  29. package/dist/src/mcp/tool-definition.js +2 -0
  30. package/dist/src/mcp/tools.js +2425 -0
  31. package/dist/src/mcp/typography-rules.js +70 -0
  32. package/dist/src/transport/com.js +250 -0
  33. package/dist/src/transport/osascript.js +171 -0
  34. package/dist/src/transport/queue.js +19 -0
  35. package/dist/src/transport/script-bundle.js +92 -0
  36. package/dist/src/transport/transport.js +30 -0
  37. package/indesign/commands/10-app.js +6 -0
  38. package/indesign/commands/20-documents.js +517 -0
  39. package/indesign/commands/22-document-setup.js +204 -0
  40. package/indesign/commands/23-save-package.js +258 -0
  41. package/indesign/commands/25-export.js +448 -0
  42. package/indesign/commands/26-export-image.js +202 -0
  43. package/indesign/commands/27-textdefaults.js +151 -0
  44. package/indesign/commands/28-selection.js +174 -0
  45. package/indesign/commands/30-pages.js +1032 -0
  46. package/indesign/commands/31-view.js +210 -0
  47. package/indesign/commands/32-sections.js +203 -0
  48. package/indesign/commands/35-parents.js +428 -0
  49. package/indesign/commands/37-layout.js +837 -0
  50. package/indesign/commands/40-frames.js +851 -0
  51. package/indesign/commands/41-shapes.js +505 -0
  52. package/indesign/commands/42-groups.js +117 -0
  53. package/indesign/commands/43-layers.js +310 -0
  54. package/indesign/commands/44-effects.js +274 -0
  55. package/indesign/commands/45-frame-options.js +247 -0
  56. package/indesign/commands/47-anchored.js +331 -0
  57. package/indesign/commands/50-modify.js +781 -0
  58. package/indesign/commands/52-align.js +139 -0
  59. package/indesign/commands/55-fit.js +106 -0
  60. package/indesign/commands/60-images.js +1128 -0
  61. package/indesign/commands/62-embed.js +120 -0
  62. package/indesign/commands/69-placeholders.js +127 -0
  63. package/indesign/commands/70-text.js +675 -0
  64. package/indesign/commands/71-outlines.js +92 -0
  65. package/indesign/commands/72-place-text.js +476 -0
  66. package/indesign/commands/73-story-lock.js +157 -0
  67. package/indesign/commands/74-stories.js +121 -0
  68. package/indesign/commands/75-tables.js +676 -0
  69. package/indesign/commands/76-text-variables.js +260 -0
  70. package/indesign/commands/77-story-options.js +86 -0
  71. package/indesign/commands/78-frame-lines.js +452 -0
  72. package/indesign/commands/79-check-typography.js +341 -0
  73. package/indesign/commands/80-styles.js +1865 -0
  74. package/indesign/commands/81-composition.js +355 -0
  75. package/indesign/commands/82-object-styles.js +263 -0
  76. package/indesign/commands/83-drop-caps.js +87 -0
  77. package/indesign/commands/83-indents-tabs.js +264 -0
  78. package/indesign/commands/84-import-styles.js +142 -0
  79. package/indesign/commands/85-swatches.js +112 -0
  80. package/indesign/commands/86-gradients.js +185 -0
  81. package/indesign/commands/87-replace-swatch.js +180 -0
  82. package/indesign/commands/88-replace-font.js +212 -0
  83. package/indesign/commands/89-toc-index.js +945 -0
  84. package/indesign/commands/90-print-on-demand.js +495 -0
  85. package/indesign/commands/91-epub.js +546 -0
  86. package/indesign/interpreter.js +779 -0
  87. package/package.json +41 -4
  88. package/rules/typography-rules.json +31 -0
@@ -0,0 +1,517 @@
1
+ /* Bereich A – Dokumente. */
2
+
3
+ /* Pfad eines Dokuments, leer wenn nie gespeichert. */
4
+ function idcDocumentPath(doc) {
5
+ try {
6
+ if (doc.saved) { return IDC.fsPath(doc.fullName); }
7
+ } catch (e) { /* leer */ }
8
+ return '';
9
+ }
10
+
11
+ /* Fehlende und veraltete Verknuepfungen sowie fehlende Schriften. */
12
+ function idcDocumentIssues(doc) {
13
+ var missingLinks = [];
14
+ var outOfDateLinks = [];
15
+ var missingFonts = [];
16
+ var i, link, font, name;
17
+
18
+ try {
19
+ for (i = 0; i < doc.links.length; i++) {
20
+ link = doc.links.item(i);
21
+ if (IDC.enumIs(link.status, LinkStatus.LINK_MISSING)) {
22
+ missingLinks.push(String(link.name));
23
+ } else if (IDC.enumIs(link.status, LinkStatus.LINK_OUT_OF_DATE)) {
24
+ outOfDateLinks.push(String(link.name));
25
+ }
26
+ }
27
+ } catch (e1) { /* Liste bleibt so weit, wie sie kam */ }
28
+
29
+ try {
30
+ for (i = 0; i < doc.fonts.length; i++) {
31
+ font = doc.fonts.item(i);
32
+ if (!IDC.enumIs(font.status, FontStatus.INSTALLED)) {
33
+ name = String(font.name);
34
+ missingFonts.push(name);
35
+ }
36
+ }
37
+ } catch (e2) { /* dito */ }
38
+
39
+ return {
40
+ missing_links: missingLinks,
41
+ out_of_date_links: outOfDateLinks,
42
+ missing_fonts: missingFonts
43
+ };
44
+ }
45
+
46
+ IDC.register('list_documents', { needs_document: false, read_only: true, ruler: 'none' },
47
+ function () {
48
+ var documents = [];
49
+ var activeId = null;
50
+ var i, doc, isActive;
51
+
52
+ /*
53
+ * Ueber die ID vergleichen, nicht ueber equals(): equals() lieferte am
54
+ * lebenden Dokument false, obwohl nur ein Dokument offen war.
55
+ */
56
+ try {
57
+ if (app.documents.length > 0) { activeId = Number(app.activeDocument.id); }
58
+ } catch (e) { activeId = null; }
59
+
60
+ for (i = 0; i < app.documents.length; i++) {
61
+ doc = app.documents.item(i);
62
+ isActive = false;
63
+ try {
64
+ if (activeId !== null) { isActive = Number(doc.id) === activeId; }
65
+ } catch (e2) { isActive = false; }
66
+ documents.push({
67
+ document_id: Number(doc.id),
68
+ name: String(doc.name),
69
+ saved: doc.saved === true,
70
+ path: idcDocumentPath(doc),
71
+ page_count: doc.pages.length,
72
+ is_active: isActive,
73
+ managed_story_count: idcManagedStoryCount(doc)
74
+ });
75
+ }
76
+ return { documents: documents, count: documents.length };
77
+ });
78
+
79
+ IDC.register('open_document', { needs_document: false, read_only: false, ruler: 'none' },
80
+ function (ctx) {
81
+ var args = ctx.args;
82
+ if (typeof args.path !== 'string' || args.path.length === 0) {
83
+ IDC.fail('invalid_argument', 'path is required and must be a file path.', null);
84
+ }
85
+
86
+ var file = IDC.fileFor(args.path);
87
+ if (!file.exists) {
88
+ IDC.fail('not_found', 'File does not exist: ' + args.path, { path: args.path });
89
+ }
90
+ var wantedPath = IDC.fsPath(file);
91
+
92
+ var isTemplate = /\.indt$/i.test(args.path);
93
+ var openCopy = args.open_copy === true || (args.open_copy !== false && isTemplate);
94
+
95
+ /*
96
+ * Schon offen? Dann nicht doppelt oeffnen – ausser jemand will ausdruecklich
97
+ * eine Kopie: die ist ein neues, unbenanntes Dokument und kollidiert mit
98
+ * nichts.
99
+ */
100
+ var i, candidate, doc = null;
101
+ if (!openCopy) {
102
+ for (i = 0; i < app.documents.length; i++) {
103
+ candidate = app.documents.item(i);
104
+ if (idcDocumentPath(candidate) === wantedPath && wantedPath !== '') {
105
+ doc = candidate;
106
+ break;
107
+ }
108
+ }
109
+ }
110
+
111
+ var alreadyOpen = doc !== null;
112
+ if (!alreadyOpen) {
113
+ var showWindow = args.show_window === false ? false : true;
114
+ var openOption = openCopy ? OpenOptions.OPEN_COPY : OpenOptions.OPEN_ORIGINAL;
115
+ try {
116
+ doc = app.open(file, showWindow, openOption);
117
+ } catch (e) {
118
+ IDC.fail('io_error', 'InDesign could not open the file: ' + String(e.message ? e.message : e),
119
+ { path: args.path });
120
+ }
121
+ if (IDC.isArray(doc)) { doc = doc[0]; }
122
+ } else {
123
+ ctx.warn('Document was already open; it was not opened a second time.');
124
+ }
125
+
126
+ var issues = idcDocumentIssues(doc);
127
+ if (issues.missing_links.length > 0) {
128
+ ctx.warn('Missing links (fehlende Verknuepfungen): ' + issues.missing_links.join(', '));
129
+ }
130
+ if (issues.out_of_date_links.length > 0) {
131
+ ctx.warn('Out of date links (veraltete Verknuepfungen): ' + issues.out_of_date_links.join(', '));
132
+ }
133
+ if (issues.missing_fonts.length > 0) {
134
+ ctx.warn('Missing fonts (fehlende Schriften): ' + issues.missing_fonts.join(', '));
135
+ }
136
+
137
+ ctx.changes = { opened_document_ids: alreadyOpen ? [] : [Number(doc.id)] };
138
+
139
+ return {
140
+ document_id: Number(doc.id),
141
+ name: String(doc.name),
142
+ page_count: doc.pages.length,
143
+ facing_pages: doc.documentPreferences.facingPages === true,
144
+ already_open: alreadyOpen,
145
+ path: idcDocumentPath(doc),
146
+ missing_links: issues.missing_links,
147
+ out_of_date_links: issues.out_of_date_links,
148
+ missing_fonts: issues.missing_fonts,
149
+ managed_story_count: idcManagedStoryCount(doc)
150
+ };
151
+ });
152
+
153
+ IDC.register('close_document', { needs_document: true, read_only: false, ruler: 'none' },
154
+ function (ctx) {
155
+ var args = ctx.args;
156
+ var doc = ctx.doc;
157
+
158
+ if (args.save_changes !== 'yes' && args.save_changes !== 'no') {
159
+ IDC.fail('invalid_argument',
160
+ 'save_changes is required and must be "yes" or "no" (InDesign save dialogs are suppressed).',
161
+ { save_changes: args.save_changes === undefined ? null : String(args.save_changes) });
162
+ }
163
+
164
+ var documentId = Number(doc.id);
165
+ var name = String(doc.name);
166
+ var hadUnsavedChanges = doc.modified === true;
167
+ var currentPath = idcDocumentPath(doc);
168
+ var savedTo = '';
169
+ var target = null;
170
+
171
+ if (args.save_changes === 'yes') {
172
+ if (typeof args.path === 'string' && args.path.length > 0) {
173
+ target = IDC.fileFor(args.path);
174
+ savedTo = String(args.path);
175
+ } else if (currentPath === '') {
176
+ IDC.fail('invalid_argument',
177
+ 'This document has never been saved; path is required when save_changes is "yes".', null);
178
+ } else {
179
+ savedTo = currentPath;
180
+ }
181
+ }
182
+
183
+ try {
184
+ if (args.save_changes === 'yes') {
185
+ if (target !== null) { doc.close(SaveOptions.YES, target); }
186
+ else { doc.close(SaveOptions.YES); }
187
+ } else {
188
+ doc.close(SaveOptions.NO);
189
+ }
190
+ } catch (e) {
191
+ IDC.fail('io_error', 'InDesign could not close the document: ' + String(e.message ? e.message : e),
192
+ { document_id: documentId });
193
+ }
194
+
195
+ var remaining = [];
196
+ var i;
197
+ for (i = 0; i < app.documents.length; i++) {
198
+ remaining.push(Number(app.documents.item(i).id));
199
+ }
200
+
201
+ ctx.changes = { closed_document_ids: [documentId] };
202
+
203
+ return {
204
+ document_id: documentId,
205
+ name: name,
206
+ saved_to: savedTo,
207
+ had_unsaved_changes: hadUnsavedChanges,
208
+ remaining_document_ids: remaining
209
+ };
210
+ });
211
+
212
+ /* ------------------------------------------------------- create_document */
213
+
214
+ var IDC_PAGE_PRESETS = {
215
+ A4: { width: 210, height: 297 },
216
+ Letter: { width: 215.9, height: 279.4 },
217
+ Legal: { width: 215.9, height: 355.6 },
218
+ Tabloid: { width: 279.4, height: 431.8 }
219
+ };
220
+
221
+ function idcIsNumber(value) {
222
+ return typeof value === 'number' && isFinite(value);
223
+ }
224
+
225
+ /* Seitenformat aus preset oder width_mm/height_mm, Ausrichtung beachten. */
226
+ function idcPageSize(args) {
227
+ var width = null;
228
+ var height = null;
229
+ var preset;
230
+ var swap;
231
+
232
+ if (args.preset !== undefined && args.preset !== null) {
233
+ preset = IDC_PAGE_PRESETS[String(args.preset)];
234
+ if (!preset) {
235
+ IDC.fail('invalid_argument', 'preset must be one of A4, Letter, Legal, Tabloid.',
236
+ { preset: String(args.preset) });
237
+ }
238
+ width = preset.width;
239
+ height = preset.height;
240
+ }
241
+ if (idcIsNumber(args.width_mm)) { width = args.width_mm; }
242
+ if (idcIsNumber(args.height_mm)) { height = args.height_mm; }
243
+ if (width === null || height === null) {
244
+ IDC.fail('invalid_argument', 'Pass preset or both width_mm and height_mm.', null);
245
+ }
246
+ if (width <= 0 || height <= 0) {
247
+ IDC.fail('invalid_argument', 'width_mm and height_mm must be greater than 0.',
248
+ { width_mm: width, height_mm: height });
249
+ }
250
+
251
+ if (args.orientation === 'landscape') { swap = width < height; }
252
+ else if (args.orientation === 'portrait' || args.orientation === undefined) { swap = args.orientation === 'portrait' && width > height; }
253
+ else {
254
+ IDC.fail('invalid_argument', 'orientation must be "portrait" or "landscape".',
255
+ { orientation: String(args.orientation) });
256
+ }
257
+ if (swap) { return { width: height, height: width }; }
258
+ return { width: width, height: height };
259
+ }
260
+
261
+ /*
262
+ * Stege. InDesign kennt in der Skriptschnittstelle nur left/right; bei
263
+ * Doppelseiten bedeutet left "innen" und right "aussen" (Bund- und
264
+ * Aussensteg). inside/outside werden deshalb darauf abgebildet.
265
+ */
266
+ function idcMargins(spec, facing, ctx) {
267
+ var out = { top: null, bottom: null, left: null, right: null };
268
+ var hasLR, hasIO;
269
+
270
+ if (!spec || typeof spec !== 'object') {
271
+ IDC.fail('invalid_argument',
272
+ 'margins_mm is required: { top, bottom, left, right } or { top, bottom, inside, outside }.', null);
273
+ }
274
+ hasLR = idcIsNumber(spec.left) && idcIsNumber(spec.right);
275
+ hasIO = idcIsNumber(spec.inside) && idcIsNumber(spec.outside);
276
+ if (!idcIsNumber(spec.top) || !idcIsNumber(spec.bottom) || (!hasLR && !hasIO)) {
277
+ IDC.fail('invalid_argument',
278
+ 'margins_mm needs top, bottom and either left/right or inside/outside, all numbers.', spec);
279
+ }
280
+ out.top = spec.top;
281
+ out.bottom = spec.bottom;
282
+ if (hasIO) {
283
+ out.left = spec.inside;
284
+ out.right = spec.outside;
285
+ if (!facing) { ctx.warn('inside/outside given for single pages: inside is used as left, outside as right.'); }
286
+ } else {
287
+ out.left = spec.left;
288
+ out.right = spec.right;
289
+ if (facing) { ctx.warn('left/right given for facing pages: left is the inside margin (Bundsteg), right the outside margin.'); }
290
+ }
291
+ var k;
292
+ for (k in out) {
293
+ if (IDC.hasOwn(out, k) && out[k] < 0) {
294
+ IDC.fail('invalid_argument', 'margins_mm.' + k + ' must not be negative.', spec);
295
+ }
296
+ }
297
+ return out;
298
+ }
299
+
300
+ function idcApplyMargins(target, margins, columns) {
301
+ var prefs = target.marginPreferences;
302
+ prefs.top = margins.top;
303
+ prefs.bottom = margins.bottom;
304
+ prefs.left = margins.left;
305
+ prefs.right = margins.right;
306
+ if (columns !== null) {
307
+ prefs.columnCount = columns.count;
308
+ prefs.columnGutter = columns.gutter_mm;
309
+ }
310
+ }
311
+
312
+ IDC.register('create_document', { needs_document: false, read_only: false, ruler: 'none' },
313
+ function (ctx) {
314
+ var args = ctx.args;
315
+ var size = idcPageSize(args);
316
+ var facing = args.facing_pages === undefined ? true : args.facing_pages === true;
317
+ var pages = args.pages === undefined ? 1 : args.pages;
318
+ var columns = null;
319
+ var margins;
320
+ var doc, prefs, i, j, spread, page;
321
+ var pageIds = [];
322
+
323
+ if (!idcIsNumber(pages) || pages < 1 || Math.floor(pages) !== pages || pages > 9999) {
324
+ IDC.fail('invalid_argument', 'pages must be a whole number from 1 to 9999.', { pages: args.pages });
325
+ }
326
+ margins = idcMargins(args.margins_mm, facing, ctx);
327
+ if (args.columns !== undefined && args.columns !== null) {
328
+ if (typeof args.columns !== 'object' || !idcIsNumber(args.columns.count) || args.columns.count < 1) {
329
+ IDC.fail('invalid_argument', 'columns must be { count, gutter_mm } with count >= 1.', args.columns);
330
+ }
331
+ columns = {
332
+ count: Math.floor(args.columns.count),
333
+ gutter_mm: idcIsNumber(args.columns.gutter_mm) ? args.columns.gutter_mm : 4.233
334
+ };
335
+ }
336
+
337
+ try {
338
+ doc = app.documents.add();
339
+ } catch (e) {
340
+ IDC.fail('script_error', 'InDesign could not create a document: ' + String(e.message ? e.message : e), null);
341
+ }
342
+
343
+ try {
344
+ prefs = doc.documentPreferences;
345
+ prefs.facingPages = facing;
346
+ prefs.pageWidth = size.width;
347
+ prefs.pageHeight = size.height;
348
+ prefs.pagesPerDocument = pages;
349
+
350
+ /* Vorgabe fuer kuenftige Seiten, dann Musterseiten, dann die Seiten selbst. */
351
+ idcApplyMargins(doc, margins, columns);
352
+ for (i = 0; i < doc.masterSpreads.length; i++) {
353
+ spread = doc.masterSpreads.item(i);
354
+ for (j = 0; j < spread.pages.length; j++) {
355
+ idcApplyMargins(spread.pages.item(j), margins, columns);
356
+ }
357
+ }
358
+ for (i = 0; i < doc.pages.length; i++) {
359
+ page = doc.pages.item(i);
360
+ idcApplyMargins(page, margins, columns);
361
+ pageIds.push(Number(page.id));
362
+ }
363
+ } catch (e2) {
364
+ IDC.fail('script_error', 'Document was created but could not be set up: ' + String(e2.message ? e2.message : e2),
365
+ { document_id: Number(doc.id) });
366
+ }
367
+
368
+ ctx.changes = { created_document_ids: [Number(doc.id)] };
369
+
370
+ return {
371
+ document_id: Number(doc.id),
372
+ name: String(doc.name),
373
+ page_ids: pageIds,
374
+ page_count: doc.pages.length,
375
+ page_width_mm: IDC.round(prefs.pageWidth),
376
+ page_height_mm: IDC.round(prefs.pageHeight),
377
+ facing_pages: prefs.facingPages === true
378
+ };
379
+ });
380
+
381
+ /* --------------------------------------------------------- save_document */
382
+
383
+ IDC.register('save_document', { needs_document: true, read_only: false, ruler: 'none' },
384
+ function (ctx) {
385
+ var args = ctx.args;
386
+ var doc = ctx.doc;
387
+ var target = null;
388
+
389
+ if (args.path !== undefined && args.path !== null) {
390
+ if (typeof args.path !== 'string' || args.path.length === 0) {
391
+ IDC.fail('invalid_argument', 'path must be a non-empty file path.', null);
392
+ }
393
+ target = IDC.fileFor(args.path);
394
+ if (!IDC.fileParentExists(target)) {
395
+ IDC.fail('io_error', 'The folder for the target path does not exist: ' + args.path, { path: args.path });
396
+ }
397
+ } else if (doc.saved !== true) {
398
+ IDC.fail('io_error',
399
+ 'This document has never been saved; path is required for the first save.', null);
400
+ }
401
+
402
+ try {
403
+ if (target !== null) { doc.save(target); }
404
+ else { doc.save(); }
405
+ } catch (e) {
406
+ IDC.fail('io_error', 'InDesign could not save the document: ' + String(e.message ? e.message : e),
407
+ { path: target === null ? idcDocumentPath(doc) : args.path });
408
+ }
409
+
410
+ idcManagedSaveWarning(ctx, doc, target === null ? 'Only the layout file was saved.' :
411
+ 'The document now continues under the new file and still links to the same story files.');
412
+ ctx.changes = { saved_document_ids: [Number(doc.id)] };
413
+ return {
414
+ document_id: Number(doc.id),
415
+ name: String(doc.name),
416
+ path: idcDocumentPath(doc)
417
+ };
418
+ });
419
+
420
+ /* ---------------------------------------------------- set_document_bleed */
421
+
422
+ /* Zahl = alle Kanten; Objekt = nur die genannten Kanten; Grenzen pruefen. */
423
+ function idcEdges(value, field, max) {
424
+ var out = { top: null, left: null, bottom: null, right: null };
425
+ var keys = ['top', 'left', 'bottom', 'right'];
426
+ var i, k, any = false;
427
+
428
+ if (idcIsNumber(value)) {
429
+ for (i = 0; i < keys.length; i++) { out[keys[i]] = value; }
430
+ any = true;
431
+ } else if (value && typeof value === 'object') {
432
+ for (i = 0; i < keys.length; i++) {
433
+ k = keys[i];
434
+ if (value[k] !== undefined && value[k] !== null) {
435
+ if (!idcIsNumber(value[k])) {
436
+ IDC.fail('invalid_argument', field + '.' + k + ' must be a number.', value);
437
+ }
438
+ out[k] = value[k];
439
+ any = true;
440
+ }
441
+ }
442
+ } else {
443
+ IDC.fail('invalid_argument', field + ' must be a number or an object with top/left/bottom/right.', null);
444
+ }
445
+ if (!any) {
446
+ IDC.fail('invalid_argument', field + ' names no edge.', value);
447
+ }
448
+ for (i = 0; i < keys.length; i++) {
449
+ k = keys[i];
450
+ if (out[k] !== null && (out[k] < 0 || out[k] > max)) {
451
+ IDC.fail('invalid_argument', field + '.' + k + ' must be between 0 and ' + max + ' mm.', value);
452
+ }
453
+ }
454
+ return out;
455
+ }
456
+
457
+ function idcAllEqual(edges) {
458
+ return edges.top !== null && edges.left !== null && edges.bottom !== null && edges.right !== null
459
+ && edges.top === edges.left && edges.top === edges.bottom && edges.top === edges.right;
460
+ }
461
+
462
+ IDC.register('set_document_bleed', { needs_document: true, read_only: false, ruler: 'none' },
463
+ function (ctx) {
464
+ var args = ctx.args;
465
+ var prefs = ctx.doc.documentPreferences;
466
+ var bleed = null;
467
+ var slug = null;
468
+ var changed = false;
469
+
470
+ if (args.bleed_mm !== undefined && args.bleed_mm !== null) { bleed = idcEdges(args.bleed_mm, 'bleed_mm', 50); }
471
+ if (args.slug_mm !== undefined && args.slug_mm !== null) { slug = idcEdges(args.slug_mm, 'slug_mm', 50); }
472
+
473
+ if (bleed !== null) {
474
+ prefs.documentBleedUniformSize = false;
475
+ if (bleed.top !== null) { prefs.documentBleedTopOffset = bleed.top; }
476
+ if (bleed.bottom !== null) { prefs.documentBleedBottomOffset = bleed.bottom; }
477
+ if (bleed.left !== null) { prefs.documentBleedInsideOrLeftOffset = bleed.left; }
478
+ if (bleed.right !== null) { prefs.documentBleedOutsideOrRightOffset = bleed.right; }
479
+ /* uniform nach dem, was jetzt wirklich steht – auch wenn nur eine Kante genannt war */
480
+ if (idcAllEqual({
481
+ top: prefs.documentBleedTopOffset, left: prefs.documentBleedInsideOrLeftOffset,
482
+ bottom: prefs.documentBleedBottomOffset, right: prefs.documentBleedOutsideOrRightOffset
483
+ })) { prefs.documentBleedUniformSize = true; }
484
+ changed = true;
485
+ }
486
+ if (slug !== null) {
487
+ prefs.documentSlugUniformSize = false;
488
+ if (slug.top !== null) { prefs.slugTopOffset = slug.top; }
489
+ if (slug.bottom !== null) { prefs.slugBottomOffset = slug.bottom; }
490
+ if (slug.left !== null) { prefs.slugInsideOrLeftOffset = slug.left; }
491
+ if (slug.right !== null) { prefs.slugRightOrOutsideOffset = slug.right; }
492
+ if (idcAllEqual({
493
+ top: prefs.slugTopOffset, left: prefs.slugInsideOrLeftOffset,
494
+ bottom: prefs.slugBottomOffset, right: prefs.slugRightOrOutsideOffset
495
+ })) { prefs.documentSlugUniformSize = true; }
496
+ changed = true;
497
+ }
498
+ if (!changed) { ctx.warn('Neither bleed_mm nor slug_mm given; nothing changed, current values returned.'); }
499
+ else { ctx.changes = { modified_document_ids: [Number(ctx.doc.id)] }; }
500
+
501
+ return {
502
+ bleed_mm: {
503
+ top: IDC.round(prefs.documentBleedTopOffset),
504
+ left: IDC.round(prefs.documentBleedInsideOrLeftOffset),
505
+ bottom: IDC.round(prefs.documentBleedBottomOffset),
506
+ right: IDC.round(prefs.documentBleedOutsideOrRightOffset)
507
+ },
508
+ slug_mm: {
509
+ top: IDC.round(prefs.slugTopOffset),
510
+ left: IDC.round(prefs.slugInsideOrLeftOffset),
511
+ bottom: IDC.round(prefs.slugBottomOffset),
512
+ right: IDC.round(prefs.slugRightOrOutsideOffset)
513
+ },
514
+ bleed_uniform: prefs.documentBleedUniformSize === true,
515
+ slug_uniform: prefs.documentSlugUniformSize === true
516
+ };
517
+ });