layoutbridge-light 0.0.0-stage → 1.0.1
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 +105 -0
- package/LICENSE +26 -0
- package/README.de.md +367 -0
- package/README.md +353 -2
- package/THIRD-PARTY-NOTICES.md +2878 -0
- package/dist/src/mcp/catalog.js +131 -0
- package/dist/src/mcp/config.js +211 -0
- package/dist/src/mcp/content-credentials.js +65 -0
- package/dist/src/mcp/dispatch.js +171 -0
- package/dist/src/mcp/epub-check.js +331 -0
- package/dist/src/mcp/epub-orientation.js +132 -0
- package/dist/src/mcp/license/free-tools.js +16 -0
- package/dist/src/mcp/license/gate.js +210 -0
- package/dist/src/mcp/license/index.js +107 -0
- package/dist/src/mcp/license/instance-name.js +57 -0
- package/dist/src/mcp/license/key-source.js +59 -0
- package/dist/src/mcp/license/lemonsqueezy-verifier.js +207 -0
- package/dist/src/mcp/license/placeholder-verifier.js +10 -0
- package/dist/src/mcp/license/polar-ids.js +100 -0
- package/dist/src/mcp/license/polar-verifier.js +285 -0
- package/dist/src/mcp/license/product-ids.js +73 -0
- package/dist/src/mcp/license/state-store.js +91 -0
- package/dist/src/mcp/license/types.js +11 -0
- package/dist/src/mcp/logging.js +271 -0
- package/dist/src/mcp/pdf-postprocess.js +798 -0
- package/dist/src/mcp/product-info.js +54 -0
- package/dist/src/mcp/product.js +56 -0
- package/dist/src/mcp/server.js +253 -0
- package/dist/src/mcp/setup.js +680 -0
- package/dist/src/mcp/start.cjs +117 -0
- package/dist/src/mcp/target-folder.js +25 -0
- package/dist/src/mcp/tool-definition.js +2 -0
- package/dist/src/mcp/tools.js +2680 -0
- package/dist/src/mcp/typography-rules.js +70 -0
- package/dist/src/transport/com.js +436 -0
- package/dist/src/transport/osascript.js +171 -0
- package/dist/src/transport/queue.js +19 -0
- package/dist/src/transport/script-bundle.js +92 -0
- package/dist/src/transport/transport.js +52 -0
- package/indesign/commands/10-app.js +6 -0
- package/indesign/commands/20-documents.js +517 -0
- package/indesign/commands/22-document-setup.js +204 -0
- package/indesign/commands/23-save-package.js +258 -0
- package/indesign/commands/25-export.js +695 -0
- package/indesign/commands/26-export-image.js +202 -0
- package/indesign/commands/27-textdefaults.js +151 -0
- package/indesign/commands/28-selection.js +174 -0
- package/indesign/commands/30-pages.js +1032 -0
- package/indesign/commands/31-view.js +310 -0
- package/indesign/commands/32-sections.js +203 -0
- package/indesign/commands/35-parents.js +448 -0
- package/indesign/commands/37-layout.js +837 -0
- package/indesign/commands/40-frames.js +886 -0
- package/indesign/commands/41-shapes.js +505 -0
- package/indesign/commands/42-groups.js +117 -0
- package/indesign/commands/43-layers.js +310 -0
- package/indesign/commands/44-effects.js +274 -0
- package/indesign/commands/45-frame-options.js +247 -0
- package/indesign/commands/47-anchored.js +473 -0
- package/indesign/commands/50-modify.js +803 -0
- package/indesign/commands/52-align.js +139 -0
- package/indesign/commands/55-fit.js +106 -0
- package/indesign/commands/60-images.js +1154 -0
- package/indesign/commands/62-embed.js +120 -0
- package/indesign/commands/69-placeholders.js +132 -0
- package/indesign/commands/70-text.js +710 -0
- package/indesign/commands/71-outlines.js +92 -0
- package/indesign/commands/72-place-text.js +476 -0
- package/indesign/commands/73-story-lock.js +157 -0
- package/indesign/commands/74-stories.js +121 -0
- package/indesign/commands/75-tables.js +702 -0
- package/indesign/commands/76-text-variables.js +260 -0
- package/indesign/commands/77-story-options.js +86 -0
- package/indesign/commands/78-frame-lines.js +511 -0
- package/indesign/commands/79-check-typography.js +480 -0
- package/indesign/commands/80-styles.js +1960 -0
- package/indesign/commands/81-composition.js +355 -0
- package/indesign/commands/82-object-styles.js +263 -0
- package/indesign/commands/83-drop-caps.js +87 -0
- package/indesign/commands/83-indents-tabs.js +264 -0
- package/indesign/commands/84-import-styles.js +142 -0
- package/indesign/commands/85-swatches.js +112 -0
- package/indesign/commands/86-gradients.js +185 -0
- package/indesign/commands/87-replace-swatch.js +180 -0
- package/indesign/commands/88-replace-font.js +212 -0
- package/indesign/commands/89-toc-index.js +1002 -0
- package/indesign/commands/90-print-on-demand.js +495 -0
- package/indesign/commands/91-epub.js +629 -0
- package/indesign/commands/92-accessibility.js +1131 -0
- package/indesign/interpreter.js +829 -0
- package/package.json +41 -4
- package/rules/typography-rules.json +32 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class SerialTransport {
|
|
2
|
+
inner;
|
|
3
|
+
chain = Promise.resolve();
|
|
4
|
+
constructor(inner) {
|
|
5
|
+
this.inner = inner;
|
|
6
|
+
}
|
|
7
|
+
get name() {
|
|
8
|
+
return this.inner.name;
|
|
9
|
+
}
|
|
10
|
+
send(command, options) {
|
|
11
|
+
const run = this.chain.then(() => this.inner.send(command, options), () => this.inner.send(command, options));
|
|
12
|
+
this.chain = run.then(() => undefined, () => undefined);
|
|
13
|
+
return run;
|
|
14
|
+
}
|
|
15
|
+
close() {
|
|
16
|
+
return this.inner.close();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setzt das Skript zusammen, das in InDesign laeuft: Interpreter-Kern plus
|
|
3
|
+
* alle Handler aus indesign/commands. Der Interpreter darf kein #include
|
|
4
|
+
* benutzen (ExtendScript-eigen, in UXP nicht vorhanden), deshalb haengt der
|
|
5
|
+
* Server die Dateien aneinander.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
|
|
8
|
+
import { dirname, join } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
let cached = null;
|
|
11
|
+
/** Dateiliste mit Aenderungszeiten, mit der das Buendel gebaut wurde. */
|
|
12
|
+
let cachedSignature = '';
|
|
13
|
+
/** Handler-Dateien alphabetisch, wie sie ins Buendel kommen. */
|
|
14
|
+
function commandFiles(root) {
|
|
15
|
+
return readdirSync(join(root, 'commands'))
|
|
16
|
+
.filter((name) => name.endsWith('.js'))
|
|
17
|
+
.sort();
|
|
18
|
+
}
|
|
19
|
+
/*
|
|
20
|
+
* Signatur aus Pfaden und Aenderungszeiten. Aendert sich eine Handler-Datei
|
|
21
|
+
* (Bausitzung mit laufendem Server), wird das Buendel beim naechsten Aufruf
|
|
22
|
+
* neu gelesen – ohne Neustart von Claude Desktop. Ein Stat je Datei und
|
|
23
|
+
* Aufruf ist gegen die Laufzeit eines InDesign-Skripts vernachlaessigbar.
|
|
24
|
+
*/
|
|
25
|
+
export function bundleSignature(root = findScriptRoot()) {
|
|
26
|
+
return signature(root, commandFiles(root));
|
|
27
|
+
}
|
|
28
|
+
function signature(root, files) {
|
|
29
|
+
const parts = [root + ':' + statSync(join(root, 'interpreter.js')).mtimeMs];
|
|
30
|
+
for (const name of files) {
|
|
31
|
+
parts.push(name + ':' + statSync(join(root, 'commands', name)).mtimeMs);
|
|
32
|
+
}
|
|
33
|
+
return parts.join('|');
|
|
34
|
+
}
|
|
35
|
+
/** Sucht aufwaerts nach dem Repo-/Paketwurzelordner mit indesign/interpreter.js. */
|
|
36
|
+
export function findScriptRoot(startDir) {
|
|
37
|
+
let dir = startDir ?? dirname(fileURLToPath(import.meta.url));
|
|
38
|
+
for (let step = 0; step < 12; step += 1) {
|
|
39
|
+
if (existsSync(join(dir, 'indesign', 'interpreter.js'))) {
|
|
40
|
+
return join(dir, 'indesign');
|
|
41
|
+
}
|
|
42
|
+
const parent = dirname(dir);
|
|
43
|
+
if (parent === dir)
|
|
44
|
+
break;
|
|
45
|
+
dir = parent;
|
|
46
|
+
}
|
|
47
|
+
throw new Error('indesign/interpreter.js not found – package layout is broken.');
|
|
48
|
+
}
|
|
49
|
+
/** Interpreter und Handler in fester Reihenfolge, Dateinamen alphabetisch. */
|
|
50
|
+
export function buildScriptBundle(force = false) {
|
|
51
|
+
const root = findScriptRoot();
|
|
52
|
+
const files = commandFiles(root);
|
|
53
|
+
let current = '';
|
|
54
|
+
try {
|
|
55
|
+
current = signature(root, files);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
current = '';
|
|
59
|
+
}
|
|
60
|
+
if (cached !== null && !force && current !== '' && current === cachedSignature)
|
|
61
|
+
return cached;
|
|
62
|
+
const parts = [];
|
|
63
|
+
parts.push('/* layoutbridge-spm – zusammengesetztes Skript */');
|
|
64
|
+
parts.push(readFileSync(join(root, 'interpreter.js'), 'utf8'));
|
|
65
|
+
const commandDir = join(root, 'commands');
|
|
66
|
+
for (const name of files) {
|
|
67
|
+
parts.push('\n/* ---- commands/' + name + ' ---- */\n');
|
|
68
|
+
parts.push(readFileSync(join(commandDir, name), 'utf8'));
|
|
69
|
+
}
|
|
70
|
+
cached = parts.join('\n');
|
|
71
|
+
cachedSignature = current;
|
|
72
|
+
return cached;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* JSON, in dem jedes Zeichen ausserhalb von ASCII als \uXXXX steht. So ist das
|
|
76
|
+
* erzeugte Skript reines ASCII und die Zeichensatzfrage stellt sich nicht.
|
|
77
|
+
*/
|
|
78
|
+
export function toAsciiJson(value) {
|
|
79
|
+
const json = JSON.stringify(value ?? null);
|
|
80
|
+
let out = '';
|
|
81
|
+
for (let i = 0; i < json.length; i += 1) {
|
|
82
|
+
const code = json.charCodeAt(i);
|
|
83
|
+
if (code < 0x20 || code > 0x7e) {
|
|
84
|
+
out += '\\u' + code.toString(16).padStart(4, '0');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
out += json.charAt(i);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=script-bundle.js.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transportschnittstelle.
|
|
3
|
+
*
|
|
4
|
+
* Der Transport ist die einzige Stelle mit Plattformwissen. Alles darueber
|
|
5
|
+
* kennt nur diese Schnittstelle: einen Befehl hinschicken, ein Ergebnis
|
|
6
|
+
* zurueckbekommen.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Fehlerarten nach Spezifikation, allgemeine Anforderung 5; dazu "license"
|
|
10
|
+
* fuer die Lizenzschranke (Auftrag A-6, E-60, Spezifikation S11) – sie
|
|
11
|
+
* greift vor dem Transport, InDesign ist nicht beteiligt.
|
|
12
|
+
*/
|
|
13
|
+
export const ERROR_KINDS = [
|
|
14
|
+
'app_not_available',
|
|
15
|
+
'invalid_argument',
|
|
16
|
+
'not_found',
|
|
17
|
+
'invalid_state',
|
|
18
|
+
'io_error',
|
|
19
|
+
'timeout',
|
|
20
|
+
'script_error',
|
|
21
|
+
'license',
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Zeitanteile eines Aufrufs fuer das Protokoll (A-74, Sitzung 80). Haengt
|
|
25
|
+
* unter einem Symbol am Ergebnis: JSON.stringify und Object.keys sehen es
|
|
26
|
+
* nicht, die Antwort an den Client bleibt also unveraendert. Der Aufrufer
|
|
27
|
+
* nimmt es mit takeTiming() ab.
|
|
28
|
+
*/
|
|
29
|
+
export const TIMING = Symbol('idc.timing');
|
|
30
|
+
export function attachTiming(result, timing) {
|
|
31
|
+
Object.defineProperty(result, TIMING, { value: timing, enumerable: false, configurable: true });
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
/** Liest die Zeitanteile und entfernt sie vom Ergebnis; null, wenn keine da sind. */
|
|
35
|
+
export function takeTiming(result) {
|
|
36
|
+
if (result === null || typeof result !== 'object')
|
|
37
|
+
return null;
|
|
38
|
+
const holder = result;
|
|
39
|
+
const timing = holder[TIMING];
|
|
40
|
+
if (timing === undefined)
|
|
41
|
+
return null;
|
|
42
|
+
delete holder[TIMING];
|
|
43
|
+
return timing;
|
|
44
|
+
}
|
|
45
|
+
/** Baut einen Fehlerumschlag, ohne dass InDesign beteiligt war. */
|
|
46
|
+
export function transportError(kind, message, details = null) {
|
|
47
|
+
return { ok: false, warnings: [], error: { kind, message, details } };
|
|
48
|
+
}
|
|
49
|
+
export function isErrorKind(value) {
|
|
50
|
+
return typeof value === 'string' && ERROR_KINDS.includes(value);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -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
|
+
});
|