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.
- package/CHANGELOG.md +171 -0
- package/LICENSE +26 -0
- package/README.de.md +318 -0
- package/README.md +304 -4
- package/THIRD-PARTY-NOTICES.md +2878 -0
- package/dist/src/mcp/config.js +125 -0
- package/dist/src/mcp/dispatch.js +123 -0
- package/dist/src/mcp/license/free-tools.js +16 -0
- package/dist/src/mcp/license/gate.js +209 -0
- package/dist/src/mcp/license/index.js +96 -0
- package/dist/src/mcp/license/instance-name.js +56 -0
- package/dist/src/mcp/license/key-source.js +58 -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 +63 -0
- package/dist/src/mcp/license/polar-verifier.js +265 -0
- package/dist/src/mcp/license/product-ids.js +72 -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 +270 -0
- package/dist/src/mcp/product-info.js +48 -0
- package/dist/src/mcp/server.js +250 -0
- package/dist/src/mcp/setup.js +608 -0
- package/dist/src/mcp/start.cjs +95 -0
- package/dist/src/mcp/tool-definition.js +2 -0
- package/dist/src/mcp/tools.js +2004 -0
- package/dist/src/mcp/typography-rules.js +70 -0
- package/dist/src/transport/com.js +250 -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 +30 -0
- package/indesign/commands/10-app.js +6 -0
- package/indesign/commands/20-documents.js +513 -0
- package/indesign/commands/22-document-setup.js +118 -0
- package/indesign/commands/23-save-package.js +255 -0
- package/indesign/commands/25-export.js +379 -0
- package/indesign/commands/26-export-image.js +197 -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 +210 -0
- package/indesign/commands/32-sections.js +203 -0
- package/indesign/commands/35-parents.js +428 -0
- package/indesign/commands/37-layout.js +760 -0
- package/indesign/commands/40-frames.js +836 -0
- package/indesign/commands/41-shapes.js +505 -0
- package/indesign/commands/42-groups.js +117 -0
- package/indesign/commands/43-layers.js +291 -0
- package/indesign/commands/44-effects.js +274 -0
- package/indesign/commands/45-frame-options.js +247 -0
- package/indesign/commands/47-anchored.js +287 -0
- package/indesign/commands/50-modify.js +781 -0
- package/indesign/commands/52-align.js +139 -0
- package/indesign/commands/55-fit.js +106 -0
- package/indesign/commands/60-images.js +771 -0
- package/indesign/commands/62-embed.js +120 -0
- package/indesign/commands/69-placeholders.js +127 -0
- package/indesign/commands/70-text.js +567 -0
- package/indesign/commands/71-outlines.js +92 -0
- package/indesign/commands/72-place-text.js +366 -0
- package/indesign/commands/74-stories.js +116 -0
- package/indesign/commands/75-tables.js +676 -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 +304 -0
- package/indesign/commands/79-check-typography.js +303 -0
- package/indesign/commands/80-styles.js +1620 -0
- package/indesign/commands/81-composition.js +355 -0
- package/indesign/commands/82-object-styles.js +263 -0
- package/indesign/commands/83-indents-tabs.js +237 -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 +217 -0
- package/indesign/interpreter.js +758 -0
- package/package.json +55 -6
- package/rules/typography-rules.json +31 -0
|
@@ -0,0 +1,1620 @@
|
|
|
1
|
+
/* Bereich H – Formate und Zeichenformatierung. */
|
|
2
|
+
|
|
3
|
+
/* ------------------------------------------------------------- Hilfen */
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Vorhanden? DOM-Objekte (Color, Swatch) ueberladen === in ExtendScript und
|
|
7
|
+
* werfen beim Vergleich mit null ("Color.===() cannot work with instances of
|
|
8
|
+
* this class", Live-Fund 04.09.2026) – wirft der Vergleich, ist es ein Objekt.
|
|
9
|
+
*/
|
|
10
|
+
function idcPresent(value) {
|
|
11
|
+
try {
|
|
12
|
+
return !(value === null || value === undefined);
|
|
13
|
+
} catch (e) { return true; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* NothingEnum.NOTHING: so liest InDesign ein nicht gesetztes Attribut (Zeichenformate). */
|
|
17
|
+
function idcIsNothing(value) {
|
|
18
|
+
if (!idcPresent(value)) { return true; }
|
|
19
|
+
try {
|
|
20
|
+
if (typeof NothingEnum !== 'undefined' && IDC.enumIs(value, NothingEnum.NOTHING)) { return true; }
|
|
21
|
+
} catch (e) { /* kein Enum */ }
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Schrift eines Text- oder Formatobjekts; nicht gesetzte Attribute bleiben null. */
|
|
26
|
+
function idcReadFontLoose(target) {
|
|
27
|
+
var raw;
|
|
28
|
+
try { raw = target.appliedFont; } catch (e) { raw = null; }
|
|
29
|
+
if (idcIsNothing(raw)) {
|
|
30
|
+
var style = null;
|
|
31
|
+
try { style = target.fontStyle; } catch (e2) { style = null; }
|
|
32
|
+
return { family: null, style: idcIsNothing(style) ? null : String(style) };
|
|
33
|
+
}
|
|
34
|
+
var read = idcReadDefaultFont(target);
|
|
35
|
+
/* Nicht gesetzte Familie eines Zeichenformats liest sich als "" oder "undefined" (Live-Fund 04.09.2026). */
|
|
36
|
+
if (read.family === '' || read.family === 'undefined') { read.family = null; }
|
|
37
|
+
if (read.style === '' || read.style === 'undefined') { read.style = null; }
|
|
38
|
+
return read;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Punktwert lesen (Schriftgrad, Abstand): unter Punkt-Masseinheit, null wenn nicht gesetzt. */
|
|
42
|
+
function idcReadPt(target, property) {
|
|
43
|
+
var value;
|
|
44
|
+
try {
|
|
45
|
+
value = IDC.inPoints(function () { return target[property]; });
|
|
46
|
+
} catch (e) { return null; }
|
|
47
|
+
if (idcIsNothing(value)) { return null; }
|
|
48
|
+
return IDC.round(Number(value), 3);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Zeilenabstand: { pt, auto } – pt null bei automatischem Zeilenabstand. */
|
|
52
|
+
function idcReadLeading(target) {
|
|
53
|
+
var value;
|
|
54
|
+
try {
|
|
55
|
+
value = IDC.inPoints(function () { return target.leading; });
|
|
56
|
+
} catch (e) { return { pt: null, auto: false }; }
|
|
57
|
+
if (idcIsNothing(value)) { return { pt: null, auto: false }; }
|
|
58
|
+
if (typeof Leading !== 'undefined' && IDC.enumIs(value, Leading.AUTO)) { return { pt: null, auto: true }; }
|
|
59
|
+
var n = Number(value);
|
|
60
|
+
if (isNaN(n)) { return { pt: null, auto: false }; }
|
|
61
|
+
return { pt: IDC.round(n, 3), auto: false };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function idcReadNumberLoose(target, property, digits) {
|
|
65
|
+
var value;
|
|
66
|
+
try { value = target[property]; } catch (e) { return null; }
|
|
67
|
+
if (idcIsNothing(value)) { return null; }
|
|
68
|
+
var n = Number(value);
|
|
69
|
+
return isNaN(n) ? null : IDC.round(n, digits === undefined ? 3 : digits);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function idcReadBoolLoose(target, property) {
|
|
73
|
+
var value;
|
|
74
|
+
try { value = target[property]; } catch (e) { return null; }
|
|
75
|
+
if (idcIsNothing(value)) { return null; }
|
|
76
|
+
return value === true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function idcReadSwatchName(target, property) {
|
|
80
|
+
var value;
|
|
81
|
+
try { value = target[property]; } catch (e) { return null; }
|
|
82
|
+
if (idcIsNothing(value)) { return null; }
|
|
83
|
+
try { return String(value.name); } catch (e2) { return null; }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Gruppenpfad eines Formats ("Group/Subgroup"), leer auf oberster Ebene. */
|
|
87
|
+
function idcStyleGroupPath(style) {
|
|
88
|
+
var names = [];
|
|
89
|
+
var current, name, step;
|
|
90
|
+
try { current = style.parent; } catch (e) { return ''; }
|
|
91
|
+
for (step = 0; step < 12; step++) {
|
|
92
|
+
if (current === null || current === undefined) { break; }
|
|
93
|
+
name = IDC.className(current);
|
|
94
|
+
if (name === 'ParagraphStyleGroup' || name === 'CharacterStyleGroup') {
|
|
95
|
+
try { names.unshift(String(current.name)); } catch (e2) { break; }
|
|
96
|
+
try { current = current.parent; } catch (e3) { break; }
|
|
97
|
+
} else {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return names.join('/');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Name des Grundlagenformats; die Wurzel ([Kein Absatzformat]) kommt als Verweis ohne lesbaren Namen zurueck (Live-Fund 04.09.2026) – dann null. */
|
|
105
|
+
function idcBasedOnName(style) {
|
|
106
|
+
var base, name;
|
|
107
|
+
try { base = style.basedOn; } catch (e) { return null; }
|
|
108
|
+
if (idcIsNothing(base)) { return null; }
|
|
109
|
+
if (typeof base === 'string') { return base === '' || base === 'undefined' ? null : base; }
|
|
110
|
+
try { name = String(base.name); } catch (e2) { name = 'undefined'; }
|
|
111
|
+
if (name === 'undefined' || name === '') {
|
|
112
|
+
try { name = String(IDC.concrete(base).name); } catch (e3) { name = 'undefined'; }
|
|
113
|
+
}
|
|
114
|
+
return name === 'undefined' || name === '' ? null : name;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Ausrichtungsname zu einem Justification-Wert. */
|
|
118
|
+
function idcJustificationName(value) {
|
|
119
|
+
if (typeof Justification === 'undefined') { return value === undefined ? null : String(value); }
|
|
120
|
+
if (idcIsNothing(value)) { return null; }
|
|
121
|
+
var table = [
|
|
122
|
+
['left', Justification.LEFT_ALIGN],
|
|
123
|
+
['center', Justification.CENTER_ALIGN],
|
|
124
|
+
['right', Justification.RIGHT_ALIGN],
|
|
125
|
+
['justify_left', Justification.LEFT_JUSTIFIED],
|
|
126
|
+
['justify_center', Justification.CENTER_JUSTIFIED],
|
|
127
|
+
['justify_right', Justification.RIGHT_JUSTIFIED],
|
|
128
|
+
['justify_full', Justification.FULLY_JUSTIFIED],
|
|
129
|
+
['away_from_binding', Justification.AWAY_FROM_BINDING_SIDE],
|
|
130
|
+
['to_binding', Justification.TO_BINDING_SIDE]
|
|
131
|
+
];
|
|
132
|
+
var i;
|
|
133
|
+
for (i = 0; i < table.length; i++) {
|
|
134
|
+
if (IDC.enumIs(value, table[i][1])) { return table[i][0]; }
|
|
135
|
+
}
|
|
136
|
+
return String(value);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Justification-Wert zu einem Ausrichtungsnamen; "justify" = Blocksatz, letzte Zeile links. */
|
|
140
|
+
function idcJustificationFor(name, field) {
|
|
141
|
+
var text = String(name);
|
|
142
|
+
if (typeof Justification === 'undefined') {
|
|
143
|
+
IDC.fail('invalid_state', 'This runtime has no Justification enumeration.', null);
|
|
144
|
+
}
|
|
145
|
+
if (text === 'left') { return Justification.LEFT_ALIGN; }
|
|
146
|
+
if (text === 'center') { return Justification.CENTER_ALIGN; }
|
|
147
|
+
if (text === 'right') { return Justification.RIGHT_ALIGN; }
|
|
148
|
+
if (text === 'justify' || text === 'justify_left') { return Justification.LEFT_JUSTIFIED; }
|
|
149
|
+
if (text === 'justify_center') { return Justification.CENTER_JUSTIFIED; }
|
|
150
|
+
if (text === 'justify_right') { return Justification.RIGHT_JUSTIFIED; }
|
|
151
|
+
if (text === 'justify_full') { return Justification.FULLY_JUSTIFIED; }
|
|
152
|
+
IDC.fail('invalid_argument', field + ' must be one of left, center, right, justify, justify_left, justify_center, justify_right, justify_full.', { value: text });
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function idcStyleNameArg(value, field) {
|
|
157
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
158
|
+
IDC.fail('invalid_argument', field + ' is required (a non-empty string).', null);
|
|
159
|
+
}
|
|
160
|
+
if (value.charAt(0) === '[') {
|
|
161
|
+
IDC.fail('invalid_argument', field + ' must not start with "[" – those names are reserved for InDesign\'s internal styles.', { value: value });
|
|
162
|
+
}
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function idcCollisionArg(value) {
|
|
167
|
+
if (value === undefined || value === null) { return 'error'; }
|
|
168
|
+
if (value !== 'error' && value !== 'update' && value !== 'version') {
|
|
169
|
+
IDC.fail('invalid_argument', 'on_collision must be error, update or version.', { value: value });
|
|
170
|
+
}
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function idcNumberArg(value, field, min, max) {
|
|
175
|
+
if (typeof value !== 'number' || !isFinite(value)) {
|
|
176
|
+
IDC.fail('invalid_argument', field + ' must be a number.', { value: value });
|
|
177
|
+
}
|
|
178
|
+
if (min !== null && value < min) {
|
|
179
|
+
IDC.fail('invalid_argument', field + ' must be ' + min + ' or more.', { value: value });
|
|
180
|
+
}
|
|
181
|
+
if (max !== null && value > max) {
|
|
182
|
+
IDC.fail('invalid_argument', field + ' must be ' + max + ' or less.', { value: value });
|
|
183
|
+
}
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function idcGiven(value) {
|
|
188
|
+
return value !== undefined && value !== null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* Zeichenformat ueber den Namen, auch in Formatgruppen. */
|
|
192
|
+
function idcCharacterStyleByName(doc, name) {
|
|
193
|
+
var style, all, i;
|
|
194
|
+
try {
|
|
195
|
+
style = doc.characterStyles.itemByName(name);
|
|
196
|
+
if (style && style.isValid === true) { return style; }
|
|
197
|
+
} catch (e) { /* weiter */ }
|
|
198
|
+
try {
|
|
199
|
+
all = doc.allCharacterStyles;
|
|
200
|
+
for (i = 0; i < all.length; i++) {
|
|
201
|
+
if (String(all[i].name) === String(name)) { return all[i]; }
|
|
202
|
+
}
|
|
203
|
+
} catch (e2) { /* weiter */ }
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* Alle Absatz- bzw. Zeichenformate als Array, auch aus Gruppen. */
|
|
208
|
+
function idcAllStyles(doc, kind) {
|
|
209
|
+
var out = [];
|
|
210
|
+
var all, collection, i;
|
|
211
|
+
try {
|
|
212
|
+
all = kind === 'character' ? doc.allCharacterStyles : doc.allParagraphStyles;
|
|
213
|
+
for (i = 0; i < all.length; i++) { out.push(all[i]); }
|
|
214
|
+
return out;
|
|
215
|
+
} catch (e) { /* Rueckfall: nur die oberste Ebene */ }
|
|
216
|
+
try {
|
|
217
|
+
collection = kind === 'character' ? doc.characterStyles : doc.paragraphStyles;
|
|
218
|
+
for (i = 0; i < collection.length; i++) { out.push(collection.item(i)); }
|
|
219
|
+
} catch (e2) { /* leer */ }
|
|
220
|
+
return out;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* Naechster freier Name "Name 2", "Name 3" ... fuer Absatz-/Zeichenformat oder Farbfeld. */
|
|
224
|
+
function idcFreeName(doc, base, kind) {
|
|
225
|
+
var n = 2;
|
|
226
|
+
var candidate;
|
|
227
|
+
function taken(name) {
|
|
228
|
+
if (kind === 'paragraph') { return IDC.paragraphStyleByName(doc, name) !== null; }
|
|
229
|
+
if (kind === 'character') { return idcCharacterStyleByName(doc, name) !== null; }
|
|
230
|
+
return idcPresent(idcSwatchByName(doc, name));
|
|
231
|
+
}
|
|
232
|
+
for (n = 2; n < 1000; n++) {
|
|
233
|
+
candidate = base + ' ' + n;
|
|
234
|
+
if (!taken(candidate)) { return candidate; }
|
|
235
|
+
}
|
|
236
|
+
IDC.fail('invalid_state', 'No free name found for "' + base + '".', { name: base });
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function idcSwatchByName(doc, name) {
|
|
241
|
+
var swatch = null;
|
|
242
|
+
try {
|
|
243
|
+
swatch = doc.swatches.itemByName(String(name));
|
|
244
|
+
if (swatch && swatch.isValid === true) { return swatch; }
|
|
245
|
+
} catch (e) { /* weiter */ }
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* Zeichenformat [None]; der Skriptname ist in jeder Sprachfassung "[None]". */
|
|
250
|
+
function idcNoneCharacterStyle(doc) {
|
|
251
|
+
var style = null;
|
|
252
|
+
try {
|
|
253
|
+
style = doc.characterStyles.itemByName('[None]');
|
|
254
|
+
if (style && style.isValid === true) { return style; }
|
|
255
|
+
} catch (e) { /* weiter */ }
|
|
256
|
+
try {
|
|
257
|
+
style = doc.characterStyles.item(0);
|
|
258
|
+
if (style && style.isValid === true) { return style; }
|
|
259
|
+
} catch (e2) { /* weiter */ }
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Ist ein Zeichenformat das eingebaute [None]? Sein Name ist lokalisiert ("[Ohne]" in der deutschen Fassung, Live-Fund 04.09.2026) – deshalb ueber die ID. */
|
|
264
|
+
function idcIsNoneCharacterStyle(doc, style) {
|
|
265
|
+
var none = idcNoneCharacterStyle(doc);
|
|
266
|
+
if (!idcPresent(style) || none === null) { return null; }
|
|
267
|
+
try { return Number(style.id) === Number(none.id); } catch (e) { /* weiter */ }
|
|
268
|
+
try { return String(style.name).charAt(0) === '['; } catch (e2) { return null; }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* Beschreibung eines Absatzformats fuer list_paragraph_styles und debug_inspect_run. */
|
|
272
|
+
function idcDescribeParagraphStyle(style) {
|
|
273
|
+
var font = idcReadFontLoose(style);
|
|
274
|
+
var leading = idcReadLeading(style);
|
|
275
|
+
var id = null, name = null, alignment = null;
|
|
276
|
+
try { id = Number(style.id); } catch (e1) { id = null; }
|
|
277
|
+
try { name = String(style.name); } catch (e2) { name = null; }
|
|
278
|
+
try { alignment = idcJustificationName(style.justification); } catch (e3) { alignment = null; }
|
|
279
|
+
return {
|
|
280
|
+
name: name,
|
|
281
|
+
style_id: id,
|
|
282
|
+
group: idcStyleGroupPath(style),
|
|
283
|
+
based_on: idcBasedOnName(style),
|
|
284
|
+
font_family: font.family,
|
|
285
|
+
font_style: font.style,
|
|
286
|
+
point_size: idcReadPt(style, 'pointSize'),
|
|
287
|
+
leading_pt: leading.pt,
|
|
288
|
+
leading_auto: leading.auto,
|
|
289
|
+
fill_swatch: idcReadSwatchName(style, 'fillColor'),
|
|
290
|
+
alignment: alignment,
|
|
291
|
+
space_before_pt: idcReadPt(style, 'spaceBefore'),
|
|
292
|
+
space_after_pt: idcReadPt(style, 'spaceAfter'),
|
|
293
|
+
hyphenation: idcReadBoolLoose(style, 'hyphenation'),
|
|
294
|
+
tracking: idcReadNumberLoose(style, 'tracking', 1),
|
|
295
|
+
/* A-7.1 bis A-7.3 (81-composition.js) */
|
|
296
|
+
keep_options: idcReadKeepOptions(style),
|
|
297
|
+
hyphenation_options: idcReadHyphenationOptions(style),
|
|
298
|
+
justification_options: idcReadJustificationOptions(style),
|
|
299
|
+
/* Sitzung 10, Demo-Heft-Befund 3 (83-indents-tabs.js) */
|
|
300
|
+
indents: idcReadIndentTabLanguage(style)
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/* Beschreibung eines Zeichenformats; nicht gesetzte Attribute sind null. */
|
|
305
|
+
function idcDescribeCharacterStyle(style) {
|
|
306
|
+
var font = idcReadFontLoose(style);
|
|
307
|
+
var id = null, name = null;
|
|
308
|
+
try { id = Number(style.id); } catch (e1) { id = null; }
|
|
309
|
+
try { name = String(style.name); } catch (e2) { name = null; }
|
|
310
|
+
return {
|
|
311
|
+
name: name,
|
|
312
|
+
style_id: id,
|
|
313
|
+
group: idcStyleGroupPath(style),
|
|
314
|
+
based_on: idcBasedOnName(style),
|
|
315
|
+
font_family: font.family,
|
|
316
|
+
font_style: font.style,
|
|
317
|
+
point_size: idcReadPt(style, 'pointSize'),
|
|
318
|
+
fill_swatch: idcReadSwatchName(style, 'fillColor'),
|
|
319
|
+
tracking: idcReadNumberLoose(style, 'tracking', 1)
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* ------------------------------------------------------------ Schriften */
|
|
324
|
+
|
|
325
|
+
function idcFontStatusName(status) {
|
|
326
|
+
if (typeof FontStatus === 'undefined' || idcIsNothing(status)) { return 'installed'; }
|
|
327
|
+
if (IDC.enumIs(status, FontStatus.INSTALLED)) { return 'installed'; }
|
|
328
|
+
if (IDC.enumIs(status, FontStatus.SUBSTITUTED)) { return 'substituted'; }
|
|
329
|
+
if (IDC.enumIs(status, FontStatus.FAUXED)) { return 'substituted'; }
|
|
330
|
+
if (IDC.enumIs(status, FontStatus.NOT_AVAILABLE)) { return 'not_available'; }
|
|
331
|
+
if (IDC.enumIs(status, FontStatus.UNKNOWN)) { return 'not_available'; }
|
|
332
|
+
return 'not_available';
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/*
|
|
336
|
+
* Alle Schriften, die InDesign kennt: [{ family, style, status }]. Ueber
|
|
337
|
+
* everyItem() in drei DOM-Aufrufen; faellt auf die Schleife zurueck, wo es
|
|
338
|
+
* everyItem() nicht gibt.
|
|
339
|
+
*/
|
|
340
|
+
function idcFontCatalogue() {
|
|
341
|
+
var out = [];
|
|
342
|
+
var families, styles, statuses, i, entry;
|
|
343
|
+
try {
|
|
344
|
+
families = app.fonts.everyItem().fontFamily;
|
|
345
|
+
styles = app.fonts.everyItem().fontStyleName;
|
|
346
|
+
statuses = app.fonts.everyItem().status;
|
|
347
|
+
if (IDC.isArray(families) && families.length === styles.length) {
|
|
348
|
+
for (i = 0; i < families.length; i++) {
|
|
349
|
+
out.push({ family: String(families[i]), style: String(styles[i]), status: idcFontStatusName(statuses[i]) });
|
|
350
|
+
}
|
|
351
|
+
return out;
|
|
352
|
+
}
|
|
353
|
+
} catch (e) { /* Schleife */ }
|
|
354
|
+
out = [];
|
|
355
|
+
try {
|
|
356
|
+
for (i = 0; i < app.fonts.length; i++) {
|
|
357
|
+
entry = app.fonts.item(i);
|
|
358
|
+
out.push({ family: String(entry.fontFamily), style: String(entry.fontStyleName), status: idcFontStatusName(entry.status) });
|
|
359
|
+
}
|
|
360
|
+
} catch (e2) { /* was da ist */ }
|
|
361
|
+
return out;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function idcSameText(a, b) {
|
|
365
|
+
return String(a).toLowerCase() === String(b).toLowerCase();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/*
|
|
369
|
+
* Familienname ohne Formatzusatz: InDesign haengt " (OTF)", " (TT)" oder
|
|
370
|
+
* " (T1)" an, wenn es eine Familie in mehreren Formaten kennt (Demo-Heft-
|
|
371
|
+
* Befund 7, 05.09.2026: "Source Sans 3 (OTF)"). Vergleiche von Familiennamen
|
|
372
|
+
* lassen den Zusatz auf beiden Seiten weg.
|
|
373
|
+
*/
|
|
374
|
+
function idcFamilyKey(name) {
|
|
375
|
+
return String(name).toLowerCase().replace(/\s*\((otf|tt|t1|ttf|opentype|truetype|type ?1)\)\s*$/, '');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function idcSameFamily(a, b) {
|
|
379
|
+
return idcFamilyKey(a) === idcFamilyKey(b);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* Schnitte einer Familie aus dem Katalog. */
|
|
383
|
+
function idcStylesOfFamily(catalogue, family) {
|
|
384
|
+
var out = [];
|
|
385
|
+
var i;
|
|
386
|
+
for (i = 0; i < catalogue.length; i++) {
|
|
387
|
+
if (idcSameFamily(catalogue[i].family, family)) { out.push(catalogue[i].style); }
|
|
388
|
+
}
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function idcCatalogueStatus(catalogue, family, style) {
|
|
393
|
+
var i;
|
|
394
|
+
for (i = 0; i < catalogue.length; i++) {
|
|
395
|
+
if (idcSameFamily(catalogue[i].family, family) && idcSameText(catalogue[i].style, style)) { return catalogue[i].status; }
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* Status der im Dokument benutzten Schriften: { "Familie\tSchnitt": status }. */
|
|
401
|
+
function idcDocumentFontStatuses(doc) {
|
|
402
|
+
var out = {};
|
|
403
|
+
var i, entry, name, status;
|
|
404
|
+
try {
|
|
405
|
+
for (i = 0; i < doc.fonts.length; i++) {
|
|
406
|
+
entry = doc.fonts.item(i);
|
|
407
|
+
name = String(entry.name);
|
|
408
|
+
try { status = idcFontStatusName(entry.status); } catch (e1) { status = 'installed'; }
|
|
409
|
+
out[name] = status;
|
|
410
|
+
try {
|
|
411
|
+
out[String(entry.fontFamily) + '\t' + String(entry.fontStyleName)] = status;
|
|
412
|
+
} catch (e2) { /* Name reicht */ }
|
|
413
|
+
}
|
|
414
|
+
} catch (e) { /* leer */ }
|
|
415
|
+
return out;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/*
|
|
419
|
+
* Schrift auf ein Format oder eine Textstelle setzen. Beides: ueber das
|
|
420
|
+
* Font-Objekt, wenn installiert, sonst als "Familie\tSchnitt" (InDesign fuehrt
|
|
421
|
+
* sie dann als fehlend). Nur Familie: InDesign behaelt eine unbekannte
|
|
422
|
+
* Familie stillschweigend – deshalb zuruecklesen.
|
|
423
|
+
*/
|
|
424
|
+
function idcApplyFont(ctx, target, family, styleName, catalogue, probe) {
|
|
425
|
+
var fontObject, text, after;
|
|
426
|
+
var applied = [];
|
|
427
|
+
var reader = idcPresent(probe) ? probe : target;
|
|
428
|
+
if (idcGiven(family) && idcGiven(styleName)) {
|
|
429
|
+
text = String(family) + '\t' + String(styleName);
|
|
430
|
+
fontObject = null;
|
|
431
|
+
try {
|
|
432
|
+
fontObject = app.fonts.itemByName(text);
|
|
433
|
+
if (!fontObject || fontObject.isValid !== true) { fontObject = null; }
|
|
434
|
+
} catch (e0) { fontObject = null; }
|
|
435
|
+
try {
|
|
436
|
+
if (fontObject !== null) { target.appliedFont = fontObject; }
|
|
437
|
+
else { target.appliedFont = text; }
|
|
438
|
+
} catch (e1) {
|
|
439
|
+
/* InDesign 21.5: "Die gewuenschte Schriftfamilie ist nicht verfuegbar." – eine fehlende Schrift laesst sich per Skript nicht setzen (Live-Fund 04.09.2026). */
|
|
440
|
+
IDC.fail('not_found', 'Font "' + String(family) + ' ' + String(styleName) + '" is not installed; InDesign rejects it: ' + String(e1.message ? e1.message : e1),
|
|
441
|
+
{ font_family: family, font_style: styleName, available_styles: idcStylesOfFamily(catalogue, family) });
|
|
442
|
+
}
|
|
443
|
+
after = idcReadFontLoose(reader);
|
|
444
|
+
if (fontObject === null) {
|
|
445
|
+
if (after.family !== null && !idcSameFamily(after.family, family)) {
|
|
446
|
+
IDC.fail('not_found', 'Font "' + String(family) + ' ' + String(styleName) + '" is not installed; InDesign kept "' + after.family + ' ' + after.style + '".',
|
|
447
|
+
{ font_family: family, font_style: styleName, available_styles: idcStylesOfFamily(catalogue, family) });
|
|
448
|
+
}
|
|
449
|
+
ctx.warn('Font "' + String(family) + ' ' + String(styleName) + '" is not installed; InDesign lists it as missing (fehlende Schrift).');
|
|
450
|
+
}
|
|
451
|
+
applied.push('font_family');
|
|
452
|
+
applied.push('font_style');
|
|
453
|
+
return applied;
|
|
454
|
+
}
|
|
455
|
+
if (idcGiven(family)) {
|
|
456
|
+
try { target.appliedFont = String(family); } catch (e2) {
|
|
457
|
+
/* InDesign 21.5 wirft auch bei der Familie allein (Live-Fund 04.09.2026, Suite Lauf 2). */
|
|
458
|
+
IDC.fail('not_found', 'Font family "' + String(family) + '" is not installed; InDesign rejects it: ' + String(e2.message ? e2.message : e2), { font_family: family });
|
|
459
|
+
}
|
|
460
|
+
after = idcReadFontLoose(reader);
|
|
461
|
+
if (after.family === null || !idcSameFamily(after.family, family)) {
|
|
462
|
+
IDC.fail('not_found', 'Font family "' + String(family) + '" is not installed; InDesign kept "' + after.family + '". Pass font_style as well to define a missing font on purpose.',
|
|
463
|
+
{ font_family: family });
|
|
464
|
+
}
|
|
465
|
+
applied.push('font_family');
|
|
466
|
+
return applied;
|
|
467
|
+
}
|
|
468
|
+
if (idcGiven(styleName)) {
|
|
469
|
+
var before = idcReadFontLoose(reader);
|
|
470
|
+
try { target.fontStyle = String(styleName); } catch (e3) {
|
|
471
|
+
IDC.fail('invalid_argument', 'Font style "' + String(styleName) + '" is not available for "' + before.family + '" – use get_font_info_at_index for the exact style names (e.g. "75 Bold").',
|
|
472
|
+
{ font_style: styleName, font_family: before.family, available_styles: before.family === null ? [] : idcStylesOfFamily(catalogue, before.family) });
|
|
473
|
+
}
|
|
474
|
+
after = idcReadFontLoose(reader);
|
|
475
|
+
if (after.style === null || !idcSameText(after.style, styleName)) {
|
|
476
|
+
IDC.fail('invalid_argument', 'Font style "' + String(styleName) + '" is not available for "' + before.family + '"; InDesign kept "' + after.style + '" – use get_font_info_at_index for the exact style names.',
|
|
477
|
+
{ font_style: styleName, font_family: before.family, available_styles: before.family === null ? [] : idcStylesOfFamily(catalogue, before.family) });
|
|
478
|
+
}
|
|
479
|
+
applied.push('font_style');
|
|
480
|
+
return applied;
|
|
481
|
+
}
|
|
482
|
+
return applied;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* Gemeinsame Attribute von define_paragraph_style und define_character_style. */
|
|
486
|
+
function idcApplyStyleAttributes(ctx, doc, style, args, created, kind) {
|
|
487
|
+
var applied = [];
|
|
488
|
+
var catalogue = null;
|
|
489
|
+
var fontApplied, leading, swatch, hex;
|
|
490
|
+
|
|
491
|
+
if (idcGiven(args.font_family) || idcGiven(args.font_style)) {
|
|
492
|
+
catalogue = idcFontCatalogue();
|
|
493
|
+
fontApplied = idcApplyFont(ctx, style, args.font_family, args.font_style, catalogue);
|
|
494
|
+
applied = applied.concat(fontApplied);
|
|
495
|
+
}
|
|
496
|
+
if (kind === 'paragraph' && idcGiven(args.size_pt)) {
|
|
497
|
+
idcNumberArg(args.size_pt, 'size_pt', 0.1, 1296);
|
|
498
|
+
IDC.inPoints(function () { style.pointSize = args.size_pt; });
|
|
499
|
+
applied.push('size_pt');
|
|
500
|
+
}
|
|
501
|
+
if (kind === 'character' && idcGiven(args.point_size)) {
|
|
502
|
+
idcNumberArg(args.point_size, 'point_size', 0.1, 1296);
|
|
503
|
+
IDC.inPoints(function () { style.pointSize = args.point_size; });
|
|
504
|
+
applied.push('point_size');
|
|
505
|
+
}
|
|
506
|
+
if (idcGiven(args.leading_pt)) {
|
|
507
|
+
leading = args.leading_pt;
|
|
508
|
+
if (leading === 'auto') {
|
|
509
|
+
if (typeof Leading === 'undefined') { IDC.fail('invalid_state', 'This runtime has no Leading enumeration.', null); }
|
|
510
|
+
style.leading = Leading.AUTO;
|
|
511
|
+
} else {
|
|
512
|
+
idcNumberArg(leading, 'leading_pt', 0, 5000);
|
|
513
|
+
IDC.inPoints(function () { style.leading = leading; });
|
|
514
|
+
}
|
|
515
|
+
applied.push('leading_pt');
|
|
516
|
+
}
|
|
517
|
+
if (idcGiven(args.alignment)) {
|
|
518
|
+
style.justification = idcJustificationFor(args.alignment, 'alignment');
|
|
519
|
+
applied.push('alignment');
|
|
520
|
+
}
|
|
521
|
+
hex = kind === 'paragraph' ? args.color_hex : args.fill_hex;
|
|
522
|
+
/* A-9.3: swatch_name setzt ein vorhandenes Farbfeld (CMYK, Vollton, Ton, Verlauf) statt ueber Hex ein RGB-Feld anzulegen. */
|
|
523
|
+
if (idcGiven(hex) && idcGiven(args.swatch_name)) {
|
|
524
|
+
IDC.fail('invalid_argument', 'Pass either ' + (kind === 'paragraph' ? 'color_hex' : 'fill_hex') + ' or swatch_name, not both.', null);
|
|
525
|
+
}
|
|
526
|
+
if (idcGiven(hex)) {
|
|
527
|
+
swatch = idcSwatchForHex(doc, hex, kind === 'paragraph' ? 'color_hex' : 'fill_hex', created);
|
|
528
|
+
style.fillColor = swatch;
|
|
529
|
+
applied.push(kind === 'paragraph' ? 'color_hex' : 'fill_hex');
|
|
530
|
+
}
|
|
531
|
+
if (idcGiven(args.swatch_name)) {
|
|
532
|
+
swatch = idcSwatchArg(doc, args.swatch_name, 'swatch_name');
|
|
533
|
+
style.fillColor = swatch;
|
|
534
|
+
applied.push('fill_swatch');
|
|
535
|
+
}
|
|
536
|
+
if (idcGiven(args.space_before_pt)) {
|
|
537
|
+
idcNumberArg(args.space_before_pt, 'space_before_pt', 0, 8640);
|
|
538
|
+
IDC.inPoints(function () { style.spaceBefore = args.space_before_pt; });
|
|
539
|
+
applied.push('space_before_pt');
|
|
540
|
+
}
|
|
541
|
+
if (idcGiven(args.space_after_pt)) {
|
|
542
|
+
idcNumberArg(args.space_after_pt, 'space_after_pt', 0, 8640);
|
|
543
|
+
IDC.inPoints(function () { style.spaceAfter = args.space_after_pt; });
|
|
544
|
+
applied.push('space_after_pt');
|
|
545
|
+
}
|
|
546
|
+
if (idcGiven(args.tracking)) {
|
|
547
|
+
idcNumberArg(args.tracking, 'tracking', -1000, 10000);
|
|
548
|
+
style.tracking = args.tracking;
|
|
549
|
+
applied.push('tracking');
|
|
550
|
+
}
|
|
551
|
+
if (idcGiven(args.hyphenation)) {
|
|
552
|
+
if (typeof args.hyphenation !== 'boolean') { IDC.fail('invalid_argument', 'hyphenation must be true or false.', { value: args.hyphenation }); }
|
|
553
|
+
style.hyphenation = args.hyphenation;
|
|
554
|
+
applied.push('hyphenation');
|
|
555
|
+
}
|
|
556
|
+
if (kind === 'paragraph') {
|
|
557
|
+
applied = applied.concat(idcApplyCompositionOptions(style, args));
|
|
558
|
+
applied = applied.concat(idcApplyIndentTabLanguage(doc, style, args));
|
|
559
|
+
}
|
|
560
|
+
return applied;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/*
|
|
564
|
+
* Farbfelder wieder entfernen, die dieser Aufruf angelegt hat (Ruecknahme).
|
|
565
|
+
* Nur ueber die ID, damit kein gleichnamiges Farbfeld des Hefts getroffen wird.
|
|
566
|
+
*/
|
|
567
|
+
function idcRemoveSwatchesById(doc, ids) {
|
|
568
|
+
var i, j, swatch, id;
|
|
569
|
+
if (!ids || ids.length === 0) { return; }
|
|
570
|
+
for (i = 0; i < ids.length; i++) {
|
|
571
|
+
id = Number(ids[i]);
|
|
572
|
+
for (j = doc.swatches.length - 1; j >= 0; j--) {
|
|
573
|
+
swatch = doc.swatches.item(j);
|
|
574
|
+
try {
|
|
575
|
+
if (Number(swatch.id) === id) { swatch.remove(); break; }
|
|
576
|
+
} catch (e) { /* naechstes */ }
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/*
|
|
582
|
+
* Attribute setzen, aber nichts Halbfertiges hinterlassen: schlaegt ein
|
|
583
|
+
* Attribut fehl (etwa eine nicht installierte Schrift), wird das in diesem
|
|
584
|
+
* Aufruf neu angelegte Format samt seiner neuen Farbfelder wieder entfernt
|
|
585
|
+
* und der Fehler weitergereicht. Ein mit on_collision "update" veraendertes
|
|
586
|
+
* Format bleibt stehen – es gehoerte dem Dokument schon vorher.
|
|
587
|
+
* Live-Fund 04.09.2026 (E-46).
|
|
588
|
+
*/
|
|
589
|
+
function idcApplyStyleAttributesOrRollback(ctx, doc, style, args, created, kind, isNew) {
|
|
590
|
+
try {
|
|
591
|
+
return idcApplyStyleAttributes(ctx, doc, style, args, created, kind);
|
|
592
|
+
} catch (e) {
|
|
593
|
+
if (isNew) {
|
|
594
|
+
try { style.remove(); } catch (e1) { /* bleibt stehen */ }
|
|
595
|
+
}
|
|
596
|
+
try { idcRemoveSwatchesById(doc, created); } catch (e2) { /* bleibt stehen */ }
|
|
597
|
+
throw e;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/* ---------------------------------------------------- list_paragraph_styles */
|
|
602
|
+
|
|
603
|
+
IDC.register('list_paragraph_styles', { needs_document: true, read_only: true, ruler: 'none' },
|
|
604
|
+
function (ctx) {
|
|
605
|
+
var doc = ctx.doc;
|
|
606
|
+
var styles = [];
|
|
607
|
+
var characterStyles = [];
|
|
608
|
+
var internal = 0;
|
|
609
|
+
var all, i, entry, name;
|
|
610
|
+
|
|
611
|
+
all = idcAllStyles(doc, 'paragraph');
|
|
612
|
+
for (i = 0; i < all.length; i++) {
|
|
613
|
+
try { name = String(all[i].name); } catch (e1) { continue; }
|
|
614
|
+
if (name.charAt(0) === '[') { internal += 1; continue; }
|
|
615
|
+
entry = idcDescribeParagraphStyle(all[i]);
|
|
616
|
+
styles.push(entry);
|
|
617
|
+
}
|
|
618
|
+
all = idcAllStyles(doc, 'character');
|
|
619
|
+
for (i = 0; i < all.length; i++) {
|
|
620
|
+
try { name = String(all[i].name); } catch (e2) { continue; }
|
|
621
|
+
if (name.charAt(0) === '[') { internal += 1; continue; }
|
|
622
|
+
characterStyles.push(idcDescribeCharacterStyle(all[i]));
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
styles: styles,
|
|
626
|
+
count: styles.length,
|
|
627
|
+
character_styles: characterStyles,
|
|
628
|
+
character_style_count: characterStyles.length,
|
|
629
|
+
internal_styles_excluded: internal
|
|
630
|
+
};
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
/* --------------------------------------------------- define_paragraph_style */
|
|
634
|
+
|
|
635
|
+
IDC.register('define_paragraph_style', { needs_document: true, read_only: false, ruler: 'none' },
|
|
636
|
+
function (ctx) {
|
|
637
|
+
var args = ctx.args;
|
|
638
|
+
var doc = ctx.doc;
|
|
639
|
+
var name = idcStyleNameArg(args.name, 'name');
|
|
640
|
+
var onCollision = idcCollisionArg(args.on_collision);
|
|
641
|
+
var existing = IDC.paragraphStyleByName(doc, name);
|
|
642
|
+
var collision = 'none';
|
|
643
|
+
var chosenName = name;
|
|
644
|
+
var createdSwatches = [];
|
|
645
|
+
var style = null;
|
|
646
|
+
var applied, changes;
|
|
647
|
+
|
|
648
|
+
if (existing !== null) {
|
|
649
|
+
if (onCollision === 'error') {
|
|
650
|
+
IDC.fail('invalid_state', 'Paragraph style "' + name + '" exists already. Pass on_collision "update" to change it or "version" to add "' + name + ' 2".',
|
|
651
|
+
{ name: name, style_id: (function () { try { return Number(existing.id); } catch (e) { return null; } })() });
|
|
652
|
+
}
|
|
653
|
+
if (onCollision === 'update') {
|
|
654
|
+
style = existing;
|
|
655
|
+
collision = 'updated';
|
|
656
|
+
} else {
|
|
657
|
+
chosenName = idcFreeName(doc, name, 'paragraph');
|
|
658
|
+
collision = 'versioned';
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (style === null) {
|
|
662
|
+
try {
|
|
663
|
+
style = doc.paragraphStyles.add({ name: chosenName });
|
|
664
|
+
} catch (e) {
|
|
665
|
+
IDC.fail('script_error', 'InDesign could not create the paragraph style "' + chosenName + '": ' + String(e.message ? e.message : e), { name: chosenName });
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
applied = idcApplyStyleAttributesOrRollback(ctx, doc, style, args, createdSwatches, 'paragraph', collision !== 'updated');
|
|
669
|
+
|
|
670
|
+
changes = collision === 'updated'
|
|
671
|
+
? { modified_style_ids: [Number(style.id)] }
|
|
672
|
+
: { created_style_ids: [Number(style.id)] };
|
|
673
|
+
if (createdSwatches.length > 0) { changes.created_swatch_ids = createdSwatches; }
|
|
674
|
+
ctx.changes = changes;
|
|
675
|
+
return {
|
|
676
|
+
style_id: Number(style.id),
|
|
677
|
+
name: String(style.name),
|
|
678
|
+
collision: collision,
|
|
679
|
+
existed: existing !== null,
|
|
680
|
+
applied: applied,
|
|
681
|
+
definition: idcDescribeParagraphStyle(style)
|
|
682
|
+
};
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
/* --------------------------------------------------- define_character_style */
|
|
686
|
+
|
|
687
|
+
IDC.register('define_character_style', { needs_document: true, read_only: false, ruler: 'none' },
|
|
688
|
+
function (ctx) {
|
|
689
|
+
var args = ctx.args;
|
|
690
|
+
var doc = ctx.doc;
|
|
691
|
+
var name = idcStyleNameArg(args.name, 'name');
|
|
692
|
+
var onCollision = idcCollisionArg(args.on_collision);
|
|
693
|
+
var existing = idcCharacterStyleByName(doc, name);
|
|
694
|
+
var collision = 'none';
|
|
695
|
+
var chosenName = name;
|
|
696
|
+
var createdSwatches = [];
|
|
697
|
+
var style = null;
|
|
698
|
+
var applied, changes;
|
|
699
|
+
|
|
700
|
+
if (!idcGiven(args.font_family) && !idcGiven(args.font_style) && !idcGiven(args.point_size) && !idcGiven(args.fill_hex) && !idcGiven(args.swatch_name) && !idcGiven(args.tracking)) {
|
|
701
|
+
IDC.fail('invalid_argument', 'At least one attribute is required: font_family, font_style, point_size, fill_hex, swatch_name or tracking.', null);
|
|
702
|
+
}
|
|
703
|
+
if (existing !== null) {
|
|
704
|
+
if (onCollision === 'error') {
|
|
705
|
+
IDC.fail('invalid_state', 'Character style "' + name + '" exists already. Pass on_collision "update" to change it or "version" to add "' + name + ' 2".',
|
|
706
|
+
{ name: name, style_id: (function () { try { return Number(existing.id); } catch (e) { return null; } })() });
|
|
707
|
+
}
|
|
708
|
+
if (onCollision === 'update') {
|
|
709
|
+
style = existing;
|
|
710
|
+
collision = 'updated';
|
|
711
|
+
} else {
|
|
712
|
+
chosenName = idcFreeName(doc, name, 'character');
|
|
713
|
+
collision = 'versioned';
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
if (style === null) {
|
|
717
|
+
try {
|
|
718
|
+
style = doc.characterStyles.add({ name: chosenName });
|
|
719
|
+
} catch (e) {
|
|
720
|
+
IDC.fail('script_error', 'InDesign could not create the character style "' + chosenName + '": ' + String(e.message ? e.message : e), { name: chosenName });
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
applied = idcApplyStyleAttributesOrRollback(ctx, doc, style, args, createdSwatches, 'character', collision !== 'updated');
|
|
724
|
+
|
|
725
|
+
changes = collision === 'updated'
|
|
726
|
+
? { modified_style_ids: [Number(style.id)] }
|
|
727
|
+
: { created_style_ids: [Number(style.id)] };
|
|
728
|
+
if (createdSwatches.length > 0) { changes.created_swatch_ids = createdSwatches; }
|
|
729
|
+
ctx.changes = changes;
|
|
730
|
+
return {
|
|
731
|
+
style_id: Number(style.id),
|
|
732
|
+
name: String(style.name),
|
|
733
|
+
collision: collision,
|
|
734
|
+
existed: existing !== null,
|
|
735
|
+
applied: applied,
|
|
736
|
+
definition: idcDescribeCharacterStyle(style)
|
|
737
|
+
};
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
/* --------------------------------------------------------- Zeichenbereiche */
|
|
741
|
+
|
|
742
|
+
/*
|
|
743
|
+
* Zeichenbereich [start_index, end_index) einer Story wie in Bereich G:
|
|
744
|
+
* start einschliesslich, end ausschliesslich, beide aus get_frame_text.
|
|
745
|
+
* Liefert { start, end, text } mit text = characters.itemByRange(start, end - 1).
|
|
746
|
+
*/
|
|
747
|
+
function idcRangeArg(story, args, allowEmpty) {
|
|
748
|
+
var start = args.start_index;
|
|
749
|
+
var end = args.end_index;
|
|
750
|
+
var length = 0;
|
|
751
|
+
var text;
|
|
752
|
+
if (typeof start !== 'number' || Math.floor(start) !== start || start < 0) {
|
|
753
|
+
IDC.fail('invalid_argument', 'start_index must be a whole number of 0 or more (inclusive).', { start_index: start });
|
|
754
|
+
}
|
|
755
|
+
if (typeof end !== 'number' || Math.floor(end) !== end || end < start) {
|
|
756
|
+
IDC.fail('invalid_argument', 'end_index must be a whole number not smaller than start_index (exclusive).', { start_index: start, end_index: end });
|
|
757
|
+
}
|
|
758
|
+
try { length = Number(story.characters.length); } catch (e0) { length = 0; }
|
|
759
|
+
if (end > length) {
|
|
760
|
+
IDC.fail('invalid_argument', 'end_index ' + end + ' exceeds the story length ' + length + '.', { end_index: end, story_length: length });
|
|
761
|
+
}
|
|
762
|
+
if (end === start && allowEmpty !== true) {
|
|
763
|
+
IDC.fail('invalid_argument', 'The range is empty (start_index equals end_index); formatting needs at least one character.', { start_index: start, end_index: end });
|
|
764
|
+
}
|
|
765
|
+
try {
|
|
766
|
+
text = story.characters.itemByRange(start, end - 1);
|
|
767
|
+
} catch (e) {
|
|
768
|
+
IDC.fail('script_error', 'InDesign could not address characters ' + start + '–' + end + ': ' + String(e.message ? e.message : e),
|
|
769
|
+
{ start_index: start, end_index: end });
|
|
770
|
+
}
|
|
771
|
+
return { start: start, end: end, text: text };
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/* Erstes Zeichen eines Bereichs (fuer Gegenproben). */
|
|
775
|
+
function idcFirstCharacter(story, index) {
|
|
776
|
+
try { return story.characters.item(index); } catch (e) { return null; }
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/*
|
|
780
|
+
* Absatzformat sauber zuweisen: Format mit "Abweichungen loeschen", danach
|
|
781
|
+
* Zeichenformat [None], alle lokalen Abweichungen weg, Format noch einmal.
|
|
782
|
+
* So stimmt nicht nur der Formatname, sondern auch der Druck.
|
|
783
|
+
*/
|
|
784
|
+
function idcApplyParagraphStyleClean(doc, textObject, style, clearOverrides) {
|
|
785
|
+
var none;
|
|
786
|
+
try {
|
|
787
|
+
textObject.applyParagraphStyle(style, clearOverrides === true);
|
|
788
|
+
} catch (e) {
|
|
789
|
+
textObject.appliedParagraphStyle = style;
|
|
790
|
+
}
|
|
791
|
+
if (clearOverrides !== true) { return; }
|
|
792
|
+
none = idcNoneCharacterStyle(doc);
|
|
793
|
+
if (none !== null) {
|
|
794
|
+
try { textObject.applyCharacterStyle(none); } catch (e1) {
|
|
795
|
+
try { textObject.appliedCharacterStyle = none; } catch (e1b) { /* dann bleibt es */ }
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
try {
|
|
799
|
+
if (typeof OverrideType !== 'undefined') { textObject.clearOverrides(OverrideType.ALL); }
|
|
800
|
+
else { textObject.clearOverrides(); }
|
|
801
|
+
} catch (e2) { /* nicht ueberall vorhanden */ }
|
|
802
|
+
try {
|
|
803
|
+
textObject.applyParagraphStyle(style, true);
|
|
804
|
+
} catch (e3) {
|
|
805
|
+
textObject.appliedParagraphStyle = style;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function idcParagraphStyleArg(doc, name, field) {
|
|
810
|
+
var style;
|
|
811
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
812
|
+
IDC.fail('invalid_argument', field + ' is required.', null);
|
|
813
|
+
}
|
|
814
|
+
style = IDC.paragraphStyleByName(doc, name);
|
|
815
|
+
if (style === null) {
|
|
816
|
+
IDC.fail('not_found', 'Paragraph style "' + name + '" not found – list_paragraph_styles shows the names (groups as "Gruppe/Name" are matched by the style name alone).',
|
|
817
|
+
{ style_name: name });
|
|
818
|
+
}
|
|
819
|
+
return style;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/* Absaetze der Story (als Array), die den Zeichenbereich [start, end) beruehren. */
|
|
823
|
+
function idcStoryParagraphsInRange(story, start, end) {
|
|
824
|
+
var out = [];
|
|
825
|
+
var i, p, position = 0, length;
|
|
826
|
+
try {
|
|
827
|
+
for (i = 0; i < story.paragraphs.length; i++) {
|
|
828
|
+
p = story.paragraphs.item(i);
|
|
829
|
+
try { length = Number(p.characters.length); } catch (e1) { length = 0; }
|
|
830
|
+
if (position < end && position + length > start) { out.push(p); }
|
|
831
|
+
position += length;
|
|
832
|
+
if (position >= end) { break; }
|
|
833
|
+
}
|
|
834
|
+
} catch (e) { /* was da ist */ }
|
|
835
|
+
return out;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function idcParagraphStart(paragraph) {
|
|
839
|
+
try { return Number(paragraph.characters.item(0).index); } catch (e) { return null; }
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function idcParagraphEnd(paragraph) {
|
|
843
|
+
var start = idcParagraphStart(paragraph);
|
|
844
|
+
if (start === null) { return null; }
|
|
845
|
+
try { return start + Number(paragraph.characters.length); } catch (e) { return null; }
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
/* ---------------------------------------------------- apply_paragraph_style */
|
|
849
|
+
|
|
850
|
+
IDC.register('apply_paragraph_style', { needs_document: true, read_only: false, ruler: 'none' },
|
|
851
|
+
function (ctx) {
|
|
852
|
+
var args = ctx.args;
|
|
853
|
+
var doc = ctx.doc;
|
|
854
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
855
|
+
var frame = found.item;
|
|
856
|
+
var style = idcParagraphStyleArg(doc, args.style_name, 'style_name');
|
|
857
|
+
var clear = args.clear_overrides !== false;
|
|
858
|
+
var paragraphs, count = 0, i, threaded;
|
|
859
|
+
|
|
860
|
+
try {
|
|
861
|
+
paragraphs = frame.paragraphs;
|
|
862
|
+
count = Number(paragraphs.length);
|
|
863
|
+
} catch (e0) { count = 0; }
|
|
864
|
+
if (count === 0) {
|
|
865
|
+
ctx.warn('The frame holds no text; nothing was formatted.');
|
|
866
|
+
return { frame_id: Number(frame.id), style_applied: String(style.name), affected_paragraphs: 0, overrides_cleared: clear, threaded: idcIsThreaded(frame) };
|
|
867
|
+
}
|
|
868
|
+
try {
|
|
869
|
+
for (i = 0; i < count; i++) {
|
|
870
|
+
idcApplyParagraphStyleClean(doc, paragraphs.item(i), style, clear);
|
|
871
|
+
}
|
|
872
|
+
} catch (e) {
|
|
873
|
+
IDC.fail('script_error', 'InDesign could not apply the paragraph style "' + args.style_name + '" to frame ' + args.frame_id + ': ' + String(e.message ? e.message : e),
|
|
874
|
+
{ frame_id: args.frame_id, style_name: args.style_name, paragraphs_done: i });
|
|
875
|
+
}
|
|
876
|
+
threaded = idcIsThreaded(frame);
|
|
877
|
+
if (threaded) {
|
|
878
|
+
ctx.warn('The frame is threaded (verkettet): only the ' + count + ' paragraph(s) touching this frame were formatted – use apply_paragraph_style_to_range over the whole story for the rest.');
|
|
879
|
+
}
|
|
880
|
+
if (!clear) {
|
|
881
|
+
ctx.warn('clear_overrides is false: local character formatting and character styles stay in place – the style name is right, the print may not be.');
|
|
882
|
+
}
|
|
883
|
+
ctx.changes = { modified_frame_ids: [Number(frame.id)] };
|
|
884
|
+
return {
|
|
885
|
+
frame_id: Number(frame.id),
|
|
886
|
+
style_applied: String(style.name),
|
|
887
|
+
affected_paragraphs: count,
|
|
888
|
+
overrides_cleared: clear,
|
|
889
|
+
threaded: threaded
|
|
890
|
+
};
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
/* ------------------------------------------- apply_paragraph_style_to_range */
|
|
894
|
+
|
|
895
|
+
IDC.register('apply_paragraph_style_to_range', { needs_document: true, read_only: false, ruler: 'none' },
|
|
896
|
+
function (ctx) {
|
|
897
|
+
var args = ctx.args;
|
|
898
|
+
var doc = ctx.doc;
|
|
899
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
900
|
+
var frame = found.item;
|
|
901
|
+
var story = idcStoryOf(frame);
|
|
902
|
+
var style = idcParagraphStyleArg(doc, args.style_name, 'style_name');
|
|
903
|
+
var range = idcRangeArg(story, args, false);
|
|
904
|
+
var paragraphs, count = 0, i, first, firstStart = null, lastEnd = null, startChar;
|
|
905
|
+
|
|
906
|
+
startChar = idcFirstCharacter(story, range.start);
|
|
907
|
+
try {
|
|
908
|
+
if (startChar !== null && String(startChar.contents).charCodeAt(0) === 13) {
|
|
909
|
+
ctx.warn('start_index ' + range.start + ' is the paragraph mark of the preceding paragraph – that paragraph is formatted too. Start one character later to leave it alone.');
|
|
910
|
+
}
|
|
911
|
+
} catch (e0) { /* egal */ }
|
|
912
|
+
|
|
913
|
+
try {
|
|
914
|
+
paragraphs = range.text.paragraphs;
|
|
915
|
+
count = Number(paragraphs.length);
|
|
916
|
+
} catch (e1) {
|
|
917
|
+
IDC.fail('script_error', 'InDesign could not read the paragraphs of the range: ' + String(e1.message ? e1.message : e1), { start_index: range.start, end_index: range.end });
|
|
918
|
+
}
|
|
919
|
+
try {
|
|
920
|
+
for (i = 0; i < count; i++) {
|
|
921
|
+
idcApplyParagraphStyleClean(doc, paragraphs.item(i), style, true);
|
|
922
|
+
}
|
|
923
|
+
} catch (e) {
|
|
924
|
+
IDC.fail('script_error', 'InDesign could not apply the paragraph style "' + args.style_name + '": ' + String(e.message ? e.message : e),
|
|
925
|
+
{ frame_id: args.frame_id, style_name: args.style_name, paragraphs_done: i });
|
|
926
|
+
}
|
|
927
|
+
if (count > 0) {
|
|
928
|
+
first = paragraphs.item(0);
|
|
929
|
+
firstStart = idcParagraphStart(first);
|
|
930
|
+
lastEnd = idcParagraphEnd(paragraphs.item(count - 1));
|
|
931
|
+
}
|
|
932
|
+
ctx.changes = { modified_frame_ids: [Number(frame.id)] };
|
|
933
|
+
return {
|
|
934
|
+
frame_id: Number(frame.id),
|
|
935
|
+
story_id: (function () { try { return Number(story.id); } catch (e2) { return null; } })(),
|
|
936
|
+
style_applied: String(style.name),
|
|
937
|
+
affected_paragraphs: count,
|
|
938
|
+
start_index: range.start,
|
|
939
|
+
end_index: range.end,
|
|
940
|
+
first_paragraph_start_index: firstStart,
|
|
941
|
+
last_paragraph_end_index: lastEnd,
|
|
942
|
+
overrides_cleared: true
|
|
943
|
+
};
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
/* ------------------------------------------- apply_character_style_to_range */
|
|
947
|
+
|
|
948
|
+
IDC.register('apply_character_style_to_range', { needs_document: true, read_only: false, ruler: 'none' },
|
|
949
|
+
function (ctx) {
|
|
950
|
+
var args = ctx.args;
|
|
951
|
+
var doc = ctx.doc;
|
|
952
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
953
|
+
var frame = found.item;
|
|
954
|
+
var story = idcStoryOf(frame);
|
|
955
|
+
var name = args.character_style_name;
|
|
956
|
+
var style, range;
|
|
957
|
+
|
|
958
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
959
|
+
IDC.fail('invalid_argument', 'character_style_name is required.', null);
|
|
960
|
+
}
|
|
961
|
+
style = idcCharacterStyleByName(doc, name);
|
|
962
|
+
if (style === null) {
|
|
963
|
+
IDC.fail('not_found', 'Character style "' + name + '" not found – define it with define_character_style first; list_paragraph_styles lists the existing ones.',
|
|
964
|
+
{ character_style_name: name });
|
|
965
|
+
}
|
|
966
|
+
range = idcRangeArg(story, args, false);
|
|
967
|
+
try {
|
|
968
|
+
range.text.applyCharacterStyle(style);
|
|
969
|
+
} catch (e) {
|
|
970
|
+
try { range.text.appliedCharacterStyle = style; } catch (e2) {
|
|
971
|
+
IDC.fail('script_error', 'InDesign could not apply the character style "' + name + '": ' + String(e.message ? e.message : e), { character_style_name: name });
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
/*
|
|
975
|
+
* Demo-Heft-Befund 9 (Sitzung 10): die Laufweite des Zeichenformats ersetzt
|
|
976
|
+
* die des Absatzformats – die wirksame Laufweite am ersten Zeichen zurueckgeben.
|
|
977
|
+
*/
|
|
978
|
+
var styleTracking = idcReadNumberLoose(style, 'tracking', 1);
|
|
979
|
+
var effective = null, paragraphTracking = null, firstChar = null, paragraphStyle = null;
|
|
980
|
+
try { firstChar = idcFirstCharacter(story, range.start); } catch (e3) { firstChar = null; }
|
|
981
|
+
if (firstChar !== null) {
|
|
982
|
+
effective = idcReadNumberLoose(firstChar, 'tracking', 1);
|
|
983
|
+
try { paragraphStyle = firstChar.appliedParagraphStyle; } catch (e4) { paragraphStyle = null; }
|
|
984
|
+
if (paragraphStyle !== null && paragraphStyle !== undefined) { paragraphTracking = idcReadNumberLoose(paragraphStyle, 'tracking', 1); }
|
|
985
|
+
}
|
|
986
|
+
ctx.changes = { modified_frame_ids: [Number(frame.id)] };
|
|
987
|
+
return {
|
|
988
|
+
frame_id: Number(frame.id),
|
|
989
|
+
characters_affected: range.end - range.start,
|
|
990
|
+
style_applied: String(style.name),
|
|
991
|
+
start_index: range.start,
|
|
992
|
+
end_index: range.end,
|
|
993
|
+
tracking: { effective: effective, character_style: styleTracking, paragraph_style: paragraphTracking }
|
|
994
|
+
};
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
/* ------------------------------------------ apply_character_format_to_range */
|
|
998
|
+
|
|
999
|
+
IDC.register('apply_character_format_to_range', { needs_document: true, read_only: false, ruler: 'none' },
|
|
1000
|
+
function (ctx) {
|
|
1001
|
+
var args = ctx.args;
|
|
1002
|
+
var doc = ctx.doc;
|
|
1003
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
1004
|
+
var frame = found.item;
|
|
1005
|
+
var story = idcStoryOf(frame);
|
|
1006
|
+
var applied = [];
|
|
1007
|
+
var range, catalogue, swatch, first, font, sizeApplied = null, fill = null;
|
|
1008
|
+
|
|
1009
|
+
if (!idcGiven(args.font_family) && !idcGiven(args.font_style) && !idcGiven(args.swatch_name) && !idcGiven(args.superscript) &&
|
|
1010
|
+
!idcGiven(args.tracking) && !idcGiven(args.point_size)) {
|
|
1011
|
+
IDC.fail('invalid_argument', 'At least one attribute is required: font_style, swatch_name, superscript, tracking or point_size.', null);
|
|
1012
|
+
}
|
|
1013
|
+
range = idcRangeArg(story, args, false);
|
|
1014
|
+
|
|
1015
|
+
if (idcGiven(args.font_family) || idcGiven(args.font_style)) {
|
|
1016
|
+
catalogue = idcFontCatalogue();
|
|
1017
|
+
applied = applied.concat(idcApplyFont(ctx, range.text, args.font_family, args.font_style, catalogue, idcFirstCharacter(story, range.start)));
|
|
1018
|
+
}
|
|
1019
|
+
if (idcGiven(args.swatch_name)) {
|
|
1020
|
+
swatch = idcSwatchByName(doc, args.swatch_name);
|
|
1021
|
+
if (!idcPresent(swatch)) {
|
|
1022
|
+
IDC.fail('not_found', 'Swatch "' + args.swatch_name + '" not found – create it with create_swatch (names are exact; the built-in ones are "Black", "Paper", "None").',
|
|
1023
|
+
{ swatch_name: args.swatch_name });
|
|
1024
|
+
}
|
|
1025
|
+
try { range.text.fillColor = swatch; } catch (e1) {
|
|
1026
|
+
IDC.fail('script_error', 'InDesign could not set the fill colour: ' + String(e1.message ? e1.message : e1), { swatch_name: args.swatch_name });
|
|
1027
|
+
}
|
|
1028
|
+
applied.push('swatch_name');
|
|
1029
|
+
}
|
|
1030
|
+
if (idcGiven(args.superscript)) {
|
|
1031
|
+
if (typeof args.superscript !== 'boolean') { IDC.fail('invalid_argument', 'superscript must be true or false.', { value: args.superscript }); }
|
|
1032
|
+
if (typeof Position === 'undefined') { IDC.fail('invalid_state', 'This runtime has no Position enumeration.', null); }
|
|
1033
|
+
try { range.text.position = args.superscript ? Position.SUPERSCRIPT : Position.NORMAL; } catch (e2) {
|
|
1034
|
+
IDC.fail('script_error', 'InDesign could not set the superscript position: ' + String(e2.message ? e2.message : e2), null);
|
|
1035
|
+
}
|
|
1036
|
+
applied.push('superscript');
|
|
1037
|
+
}
|
|
1038
|
+
if (idcGiven(args.tracking)) {
|
|
1039
|
+
idcNumberArg(args.tracking, 'tracking', -1000, 10000);
|
|
1040
|
+
/* Toleranz nur aus der Serverkonfiguration (tracking_warn_beyond, E-54); ohne Eintrag keine Warnung. */
|
|
1041
|
+
if (typeof args.tracking_warn_beyond === 'number' && isFinite(args.tracking_warn_beyond)
|
|
1042
|
+
&& Math.abs(args.tracking) > args.tracking_warn_beyond) {
|
|
1043
|
+
ctx.warn('tracking ' + args.tracking + ' is beyond the configured tolerance of \u00b1' + args.tracking_warn_beyond + ' (tracking_warn_beyond).');
|
|
1044
|
+
}
|
|
1045
|
+
try { range.text.tracking = args.tracking; } catch (e3) {
|
|
1046
|
+
IDC.fail('script_error', 'InDesign could not set the tracking: ' + String(e3.message ? e3.message : e3), null);
|
|
1047
|
+
}
|
|
1048
|
+
applied.push('tracking');
|
|
1049
|
+
}
|
|
1050
|
+
if (idcGiven(args.point_size)) {
|
|
1051
|
+
idcNumberArg(args.point_size, 'point_size', 0.1, 1296);
|
|
1052
|
+
try { IDC.inPoints(function () { range.text.pointSize = args.point_size; }); } catch (e4) {
|
|
1053
|
+
IDC.fail('script_error', 'InDesign could not set the point size: ' + String(e4.message ? e4.message : e4), null);
|
|
1054
|
+
}
|
|
1055
|
+
applied.push('point_size');
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
first = idcFirstCharacter(story, range.start);
|
|
1059
|
+
if (first !== null) {
|
|
1060
|
+
sizeApplied = idcReadPt(first, 'pointSize');
|
|
1061
|
+
font = idcReadFontLoose(first);
|
|
1062
|
+
fill = idcReadSwatchName(first, 'fillColor');
|
|
1063
|
+
} else {
|
|
1064
|
+
font = { family: null, style: null };
|
|
1065
|
+
}
|
|
1066
|
+
ctx.changes = { modified_frame_ids: [Number(frame.id)] };
|
|
1067
|
+
return {
|
|
1068
|
+
frame_id: Number(frame.id),
|
|
1069
|
+
start_index: range.start,
|
|
1070
|
+
end_index: range.end,
|
|
1071
|
+
characters_affected: range.end - range.start,
|
|
1072
|
+
applied: applied,
|
|
1073
|
+
point_size_applied: sizeApplied,
|
|
1074
|
+
font_family: font.family,
|
|
1075
|
+
font_style: font.style,
|
|
1076
|
+
fill_color: fill
|
|
1077
|
+
};
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
/* ----------------------------------------------------- set_paragraph_options */
|
|
1081
|
+
|
|
1082
|
+
IDC.register('set_paragraph_options', { needs_document: true, read_only: false, ruler: 'none' },
|
|
1083
|
+
function (ctx) {
|
|
1084
|
+
var args = ctx.args;
|
|
1085
|
+
var doc = ctx.doc;
|
|
1086
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
1087
|
+
var frame = found.item;
|
|
1088
|
+
var story = idcStoryOf(frame);
|
|
1089
|
+
var changed = [];
|
|
1090
|
+
var justification = null;
|
|
1091
|
+
var paragraphs, count = 0, i, p, range = null, first;
|
|
1092
|
+
|
|
1093
|
+
if (!idcGiven(args.alignment) && !idcGiven(args.hyphenation) && !idcGiven(args.no_break) && !idcCompositionGiven(args) && !idcIndentTabLanguageGiven(args)) {
|
|
1094
|
+
IDC.fail('invalid_argument', 'At least one of alignment, hyphenation, no_break, keep_options, hyphenation_options, justification_options, left_indent_mm, first_line_indent_mm, right_indent_mm, last_line_indent_mm, tab_stops or language is required.', null);
|
|
1095
|
+
}
|
|
1096
|
+
if (idcGiven(args.alignment)) {
|
|
1097
|
+
justification = idcJustificationFor(args.alignment, 'alignment');
|
|
1098
|
+
if (String(args.alignment) === 'justify') {
|
|
1099
|
+
IDC.fail('invalid_argument', 'alignment must name the last line: justify_left, justify_center, justify_right or justify_full.', { value: args.alignment });
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
if (idcGiven(args.hyphenation) && typeof args.hyphenation !== 'boolean') {
|
|
1103
|
+
IDC.fail('invalid_argument', 'hyphenation must be true or false.', { value: args.hyphenation });
|
|
1104
|
+
}
|
|
1105
|
+
if (idcGiven(args.no_break) && typeof args.no_break !== 'boolean') {
|
|
1106
|
+
IDC.fail('invalid_argument', 'no_break must be true or false.', { value: args.no_break });
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
if (idcGiven(args.start_index) || idcGiven(args.end_index)) {
|
|
1110
|
+
range = idcRangeArg(story, args, false);
|
|
1111
|
+
/*
|
|
1112
|
+
* Nicht range.text.paragraphs: an deren Absaetzen bleibt hyphenation
|
|
1113
|
+
* wirkungslos (Live-Fund 04.09.2026, justification greift). Die
|
|
1114
|
+
* Absaetze der Story, die den Bereich beruehren, verhalten sich wie
|
|
1115
|
+
* frame.paragraphs.
|
|
1116
|
+
*/
|
|
1117
|
+
paragraphs = idcStoryParagraphsInRange(story, range.start, range.end);
|
|
1118
|
+
count = paragraphs.length;
|
|
1119
|
+
} else {
|
|
1120
|
+
/*
|
|
1121
|
+
* Nicht frame.paragraphs waehrend der Schleife: Umbruchoptionen schieben
|
|
1122
|
+
* Absaetze in die naechste Spalte oder den Uebersatz, die Rahmensammlung
|
|
1123
|
+
* schrumpft und item(i) wird "Object is invalid" (Live-Fund 05.09.2026).
|
|
1124
|
+
* Deshalb die Absaetze der Story nehmen, die den Rahmenanteil beruehren –
|
|
1125
|
+
* die bleiben gueltig, wohin der Text auch laeuft.
|
|
1126
|
+
*/
|
|
1127
|
+
var frameStart = null, frameLength = 0;
|
|
1128
|
+
try { frameLength = Number(frame.characters.length); } catch (e1) { frameLength = 0; }
|
|
1129
|
+
try { if (frameLength > 0) { frameStart = Number(frame.characters.item(0).index); } } catch (e1b) { frameStart = null; }
|
|
1130
|
+
if (frameStart !== null && frameLength > 0) {
|
|
1131
|
+
paragraphs = idcStoryParagraphsInRange(story, frameStart, frameStart + frameLength);
|
|
1132
|
+
count = paragraphs.length;
|
|
1133
|
+
range = { start: frameStart, end: frameStart + frameLength, whole_frame: true };
|
|
1134
|
+
} else {
|
|
1135
|
+
count = 0;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
if (count === 0) {
|
|
1139
|
+
ctx.warn('No paragraphs in the given scope; nothing was changed.');
|
|
1140
|
+
return { frame_id: Number(frame.id), paragraphs_changed: 0, alignment: null, hyphenation: null, no_break: null, changed: [],
|
|
1141
|
+
keep_options: null, hyphenation_options: null, justification_options: null, indents: null, overset: null };
|
|
1142
|
+
}
|
|
1143
|
+
/* Die Optionsgruppen zuerst am ersten Absatz pruefen (Fehler vor jeder Aenderung). */
|
|
1144
|
+
var groups = [];
|
|
1145
|
+
var indentFields = [];
|
|
1146
|
+
try {
|
|
1147
|
+
for (i = 0; i < count; i++) {
|
|
1148
|
+
p = paragraphs[i];
|
|
1149
|
+
if (justification !== null) { p.justification = justification; }
|
|
1150
|
+
if (idcGiven(args.hyphenation)) { p.hyphenation = args.hyphenation; }
|
|
1151
|
+
if (idcGiven(args.no_break)) { p.noBreak = args.no_break; }
|
|
1152
|
+
groups = idcApplyCompositionOptions(p, args);
|
|
1153
|
+
indentFields = idcApplyIndentTabLanguage(doc, p, args);
|
|
1154
|
+
}
|
|
1155
|
+
} catch (e) {
|
|
1156
|
+
if (e && e.isIdcError) { throw e; }
|
|
1157
|
+
IDC.fail('script_error', 'InDesign could not change the paragraph options: ' + String(e.message ? e.message : e), { frame_id: args.frame_id, paragraphs_done: i });
|
|
1158
|
+
}
|
|
1159
|
+
if (justification !== null) { changed.push('alignment'); }
|
|
1160
|
+
if (idcGiven(args.hyphenation)) { changed.push('hyphenation'); }
|
|
1161
|
+
if (idcGiven(args.no_break)) { changed.push('no_break'); }
|
|
1162
|
+
changed = changed.concat(groups).concat(indentFields);
|
|
1163
|
+
|
|
1164
|
+
first = paragraphs[0];
|
|
1165
|
+
var composition = idcReadCompositionOptions(first);
|
|
1166
|
+
var overset = null;
|
|
1167
|
+
try { overset = story.overflows === true; } catch (e3) { overset = null; }
|
|
1168
|
+
if (overset === true && groups.length > 0) {
|
|
1169
|
+
ctx.warn('The story overflows after the change – strict keep or justification options can push text out; check get_frame_lines.');
|
|
1170
|
+
}
|
|
1171
|
+
ctx.changes = { modified_frame_ids: [Number(frame.id)] };
|
|
1172
|
+
return {
|
|
1173
|
+
frame_id: Number(frame.id),
|
|
1174
|
+
paragraphs_changed: count,
|
|
1175
|
+
alignment: (function () { try { return idcJustificationName(first.justification); } catch (e2) { return null; } })(),
|
|
1176
|
+
hyphenation: idcReadBoolLoose(first, 'hyphenation'),
|
|
1177
|
+
no_break: idcReadBoolLoose(first, 'noBreak'),
|
|
1178
|
+
changed: changed,
|
|
1179
|
+
scope: range.whole_frame === true ? 'frame' : 'range',
|
|
1180
|
+
start_index: range.whole_frame === true ? null : range.start,
|
|
1181
|
+
end_index: range.whole_frame === true ? null : range.end,
|
|
1182
|
+
keep_options: composition.keep_options,
|
|
1183
|
+
hyphenation_options: composition.hyphenation_options,
|
|
1184
|
+
justification_options: composition.justification_options,
|
|
1185
|
+
indents: idcReadIndentTabLanguage(first),
|
|
1186
|
+
overset: overset
|
|
1187
|
+
};
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
/* ---------------------------------------------------- get_font_info_at_index */
|
|
1191
|
+
|
|
1192
|
+
IDC.register('get_font_info_at_index', { needs_document: true, read_only: true, ruler: 'none' },
|
|
1193
|
+
function (ctx) {
|
|
1194
|
+
var args = ctx.args;
|
|
1195
|
+
var doc = ctx.doc;
|
|
1196
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
1197
|
+
var frame = found.item;
|
|
1198
|
+
var story = idcStoryOf(frame);
|
|
1199
|
+
var index = args.index;
|
|
1200
|
+
var length = 0;
|
|
1201
|
+
var character, font, catalogue, status, text = null;
|
|
1202
|
+
|
|
1203
|
+
if (typeof index !== 'number' || Math.floor(index) !== index || index < 0) {
|
|
1204
|
+
IDC.fail('invalid_argument', 'index must be a whole number of 0 or more (a story index from get_frame_text).', { index: index });
|
|
1205
|
+
}
|
|
1206
|
+
try { length = Number(story.characters.length); } catch (e0) { length = 0; }
|
|
1207
|
+
if (index >= length) {
|
|
1208
|
+
IDC.fail('invalid_argument', 'index ' + index + ' is beyond the story length ' + length + '.', { index: index, story_length: length });
|
|
1209
|
+
}
|
|
1210
|
+
character = idcFirstCharacter(story, index);
|
|
1211
|
+
if (character === null) {
|
|
1212
|
+
IDC.fail('script_error', 'InDesign could not address character ' + index + '.', { index: index });
|
|
1213
|
+
}
|
|
1214
|
+
font = idcReadFontLoose(character);
|
|
1215
|
+
try { text = String(character.contents); } catch (e1) { text = null; }
|
|
1216
|
+
catalogue = idcFontCatalogue();
|
|
1217
|
+
status = font.family === null ? null : idcCatalogueStatus(catalogue, font.family, font.style);
|
|
1218
|
+
if (status === null && font.family !== null) {
|
|
1219
|
+
status = idcDocumentFontStatuses(doc)[font.family + '\t' + font.style] || 'not_available';
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
frame_id: Number(frame.id),
|
|
1223
|
+
index: index,
|
|
1224
|
+
character: text,
|
|
1225
|
+
font_family: font.family,
|
|
1226
|
+
font_style: font.style,
|
|
1227
|
+
font_status: status,
|
|
1228
|
+
available_styles: font.family === null ? [] : idcStylesOfFamily(catalogue, font.family),
|
|
1229
|
+
point_size: idcReadPt(character, 'pointSize'),
|
|
1230
|
+
paragraph_style: idcReadSwatchName(character, 'appliedParagraphStyle'),
|
|
1231
|
+
character_style: idcReadSwatchName(character, 'appliedCharacterStyle'),
|
|
1232
|
+
character_style_is_none: (function () { try { return idcIsNoneCharacterStyle(doc, character.appliedCharacterStyle); } catch (e2) { return null; } })()
|
|
1233
|
+
};
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
/* ----------------------------------------------------------- find_font_usage */
|
|
1237
|
+
|
|
1238
|
+
/* Rahmen eines Textlaufs: IDs und Seite des ersten Rahmens. */
|
|
1239
|
+
function idcRunFrames(textObject) {
|
|
1240
|
+
var out = { frame_ids: [], page_id: null, page_name: '', is_master: false };
|
|
1241
|
+
var frames, i, frame, landing;
|
|
1242
|
+
try {
|
|
1243
|
+
frames = textObject.parentTextFrames;
|
|
1244
|
+
for (i = 0; i < frames.length; i++) {
|
|
1245
|
+
frame = IDC.concrete(frames[i]);
|
|
1246
|
+
out.frame_ids.push(Number(frame.id));
|
|
1247
|
+
if (i === 0) {
|
|
1248
|
+
landing = IDC.landing(frame);
|
|
1249
|
+
out.page_id = landing.page_id;
|
|
1250
|
+
out.page_name = landing.page_name;
|
|
1251
|
+
out.is_master = IDC.isOnParentSpread(frame);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
} catch (e) { /* Uebersatz ohne Rahmen */ }
|
|
1255
|
+
return out;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/* Liegt eine Story (ueber ihren ersten Rahmen) auf einer Musterseite? */
|
|
1259
|
+
function idcStoryOnMaster(story) {
|
|
1260
|
+
var containers, first;
|
|
1261
|
+
try {
|
|
1262
|
+
containers = story.textContainers;
|
|
1263
|
+
if (containers && containers.length > 0) {
|
|
1264
|
+
first = IDC.concrete(containers[0]);
|
|
1265
|
+
return IDC.isOnParentSpread(first);
|
|
1266
|
+
}
|
|
1267
|
+
} catch (e) { /* unbekannt */ }
|
|
1268
|
+
return false;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
function idcSnippet(text, max) {
|
|
1272
|
+
/* Absatz-/Zeilenwechsel, Sonderzeichen und das Tabellenzeichen U+0016 (live 05.09.2026) werden Leerzeichen. */
|
|
1273
|
+
var s = String(text).replace(/[\r\n\u000e\u000f\u0010\u0011\u0012\u0016\u0007\u0008]/g, ' ');
|
|
1274
|
+
if (s.length > max) { s = s.substr(0, max) + '...'; }
|
|
1275
|
+
return s.replace(/\s+$/, '');
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
function idcMergeIds(target, extra) {
|
|
1279
|
+
var i, j, seen;
|
|
1280
|
+
for (i = 0; i < extra.length; i++) {
|
|
1281
|
+
seen = false;
|
|
1282
|
+
for (j = 0; j < target.length; j++) { if (target[j] === extra[i]) { seen = true; break; } }
|
|
1283
|
+
if (!seen) { target.push(extra[i]); }
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
IDC.register('find_font_usage', { needs_document: true, read_only: true, ruler: 'none' },
|
|
1288
|
+
function (ctx) {
|
|
1289
|
+
var args = ctx.args;
|
|
1290
|
+
var doc = ctx.doc;
|
|
1291
|
+
var wantFamily = idcGiven(args.font_family) ? String(args.font_family) : null;
|
|
1292
|
+
var wantStyle = idcGiven(args.font_style) ? String(args.font_style) : null;
|
|
1293
|
+
var onlyMissing = args.only_missing === true;
|
|
1294
|
+
var includeMasters = args.include_master_pages !== false;
|
|
1295
|
+
var maxOccurrences = 500;
|
|
1296
|
+
var docStatuses = idcDocumentFontStatuses(doc);
|
|
1297
|
+
var catalogue = null;
|
|
1298
|
+
var used = {};
|
|
1299
|
+
var usedOrder = [];
|
|
1300
|
+
var occurrences = [];
|
|
1301
|
+
var totalMatching = 0;
|
|
1302
|
+
var storyCount = 0, s, story, storyId, onMaster, ranges, r, run, runs, range, font, key, start, length, frames, snippet, i, entry;
|
|
1303
|
+
|
|
1304
|
+
function statusOf(family, style) {
|
|
1305
|
+
var name = family + '\t' + style;
|
|
1306
|
+
var status = docStatuses[name];
|
|
1307
|
+
if (status !== undefined) { return status; }
|
|
1308
|
+
if (catalogue === null) { catalogue = idcFontCatalogue(); }
|
|
1309
|
+
status = idcCatalogueStatus(catalogue, family, style);
|
|
1310
|
+
return status === null ? 'not_available' : status;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
function matches(runEntry, status) {
|
|
1314
|
+
if (wantFamily !== null && !idcSameFamily(runEntry.family, wantFamily)) { return false; }
|
|
1315
|
+
if (wantStyle !== null && !idcSameText(runEntry.style, wantStyle)) { return false; }
|
|
1316
|
+
if (onlyMissing && status === 'installed') { return false; }
|
|
1317
|
+
return true;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
try { storyCount = Number(doc.stories.length); } catch (e0) {
|
|
1321
|
+
IDC.fail('script_error', 'InDesign could not list the stories of the document.', null);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
for (s = 0; s < storyCount; s++) {
|
|
1325
|
+
story = doc.stories.item(s);
|
|
1326
|
+
try { storyId = Number(story.id); } catch (e1) { storyId = null; }
|
|
1327
|
+
onMaster = idcStoryOnMaster(story);
|
|
1328
|
+
if (onMaster && !includeMasters) { continue; }
|
|
1329
|
+
runs = [];
|
|
1330
|
+
try {
|
|
1331
|
+
ranges = story.textStyleRanges;
|
|
1332
|
+
for (r = 0; r < ranges.length; r++) {
|
|
1333
|
+
range = ranges.item(r);
|
|
1334
|
+
font = idcReadFontLoose(range);
|
|
1335
|
+
if (font.family === null) { continue; }
|
|
1336
|
+
key = font.family + '\t' + (font.style === null ? '' : font.style);
|
|
1337
|
+
try { start = Number(range.index); } catch (e2) { start = null; }
|
|
1338
|
+
try { length = Number(range.characters.length); } catch (e3) { length = 0; }
|
|
1339
|
+
if (start === null) {
|
|
1340
|
+
try { start = Number(range.characters.item(0).index); } catch (e3b) { start = 0; }
|
|
1341
|
+
}
|
|
1342
|
+
frames = idcRunFrames(range);
|
|
1343
|
+
if (runs.length > 0 && runs[runs.length - 1].key === key && runs[runs.length - 1].end === start) {
|
|
1344
|
+
run = runs[runs.length - 1];
|
|
1345
|
+
run.end = start + length;
|
|
1346
|
+
idcMergeIds(run.frame_ids, frames.frame_ids);
|
|
1347
|
+
if (run.page_id === null) { run.page_id = frames.page_id; run.page_name = frames.page_name; }
|
|
1348
|
+
if (run.raw.length < 60) {
|
|
1349
|
+
try { run.raw += String(range.contents); } catch (e4b) { /* bleibt */ }
|
|
1350
|
+
}
|
|
1351
|
+
} else {
|
|
1352
|
+
try { snippet = String(range.contents); } catch (e4) { snippet = ''; }
|
|
1353
|
+
runs.push({
|
|
1354
|
+
key: key, family: font.family, style: font.style === null ? '' : font.style,
|
|
1355
|
+
start: start, end: start + length, raw: snippet,
|
|
1356
|
+
frame_ids: frames.frame_ids, page_id: frames.page_id, page_name: frames.page_name,
|
|
1357
|
+
is_master: onMaster || frames.is_master
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
} catch (e5) {
|
|
1362
|
+
ctx.warn('Story ' + storyId + ' could not be read completely: ' + String(e5.message ? e5.message : e5));
|
|
1363
|
+
}
|
|
1364
|
+
for (i = 0; i < runs.length; i++) {
|
|
1365
|
+
run = runs[i];
|
|
1366
|
+
entry = used[run.key];
|
|
1367
|
+
if (entry === undefined) {
|
|
1368
|
+
entry = { family: run.family, style: run.style, status: statusOf(run.family, run.style), occurrences: 0, characters: 0 };
|
|
1369
|
+
used[run.key] = entry;
|
|
1370
|
+
usedOrder.push(run.key);
|
|
1371
|
+
}
|
|
1372
|
+
entry.occurrences += 1;
|
|
1373
|
+
entry.characters += run.end - run.start;
|
|
1374
|
+
if (matches(run, entry.status)) {
|
|
1375
|
+
totalMatching += 1;
|
|
1376
|
+
if (occurrences.length < maxOccurrences) {
|
|
1377
|
+
occurrences.push({
|
|
1378
|
+
family: run.family, style: run.style, status: entry.status,
|
|
1379
|
+
story_id: storyId, frame_ids: run.frame_ids, page_id: run.page_id, page_name: run.page_name,
|
|
1380
|
+
is_master: run.is_master, start_index: run.start, end_index: run.end, snippet: idcSnippet(run.raw, 60)
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
var fontsUsed = [];
|
|
1388
|
+
for (i = 0; i < usedOrder.length; i++) { fontsUsed.push(used[usedOrder[i]]); }
|
|
1389
|
+
fontsUsed.sort(function (a, b) {
|
|
1390
|
+
var ka = (a.family + '\t' + a.style).toLowerCase();
|
|
1391
|
+
var kb = (b.family + '\t' + b.style).toLowerCase();
|
|
1392
|
+
return ka < kb ? -1 : (ka > kb ? 1 : 0);
|
|
1393
|
+
});
|
|
1394
|
+
if (totalMatching > maxOccurrences) {
|
|
1395
|
+
ctx.warn('Only the first ' + maxOccurrences + ' of ' + totalMatching + ' matching occurrences are listed.');
|
|
1396
|
+
}
|
|
1397
|
+
return {
|
|
1398
|
+
fonts_used: fontsUsed,
|
|
1399
|
+
occurrences: occurrences,
|
|
1400
|
+
occurrence_count: totalMatching,
|
|
1401
|
+
stories_scanned: storyCount,
|
|
1402
|
+
filter: { font_family: wantFamily, font_style: wantStyle, only_missing: onlyMissing, include_master_pages: includeMasters }
|
|
1403
|
+
};
|
|
1404
|
+
});
|
|
1405
|
+
|
|
1406
|
+
/* ----------------------------------------------------------- debug_inspect_run */
|
|
1407
|
+
|
|
1408
|
+
function idcFrameScale(frame) {
|
|
1409
|
+
var h = null, v = null;
|
|
1410
|
+
try { h = IDC.round(Number(frame.absoluteHorizontalScale), 3); } catch (e1) { h = null; }
|
|
1411
|
+
try { v = IDC.round(Number(frame.absoluteVerticalScale), 3); } catch (e2) { v = null; }
|
|
1412
|
+
if (h === null) { try { h = IDC.round(Number(frame.horizontalScale), 3); } catch (e3) { h = null; } }
|
|
1413
|
+
if (v === null) { try { v = IDC.round(Number(frame.verticalScale), 3); } catch (e4) { v = null; } }
|
|
1414
|
+
return { horizontal: h, vertical: v };
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
/* Absatz des Zeichens mit Umbruch-, Trennungs- und Blocksatzoptionen (A-7). */
|
|
1418
|
+
function idcInspectParagraph(character) {
|
|
1419
|
+
var paragraph = null;
|
|
1420
|
+
var out;
|
|
1421
|
+
try { paragraph = character.paragraphs.item(0); } catch (e) { paragraph = null; }
|
|
1422
|
+
if (paragraph === null || paragraph === undefined) { return null; }
|
|
1423
|
+
out = idcReadCompositionOptions(paragraph);
|
|
1424
|
+
/* Live 05.09.2026: Paragraph.index ist der Zeichenindex des Absatzanfangs, keine Ordnungszahl – deshalb beides ausdruecklich. */
|
|
1425
|
+
out.start_index = idcParagraphStart(paragraph);
|
|
1426
|
+
out.index = null;
|
|
1427
|
+
try {
|
|
1428
|
+
var story = paragraph.parentStory, ordinal, probe;
|
|
1429
|
+
for (ordinal = 0; ordinal < story.paragraphs.length; ordinal++) {
|
|
1430
|
+
probe = idcParagraphStart(story.paragraphs.item(ordinal));
|
|
1431
|
+
if (probe === out.start_index) { out.index = ordinal; break; }
|
|
1432
|
+
if (probe !== null && probe > out.start_index) { break; }
|
|
1433
|
+
}
|
|
1434
|
+
} catch (e2) { out.index = null; }
|
|
1435
|
+
try { out.alignment = idcJustificationName(paragraph.justification); } catch (e3) { out.alignment = null; }
|
|
1436
|
+
out.hyphenation = idcReadBoolLoose(paragraph, 'hyphenation');
|
|
1437
|
+
return out;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
IDC.register('debug_inspect_run', { needs_document: true, read_only: true, ruler: 'none' },
|
|
1441
|
+
function (ctx) {
|
|
1442
|
+
var args = ctx.args;
|
|
1443
|
+
var doc = ctx.doc;
|
|
1444
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
1445
|
+
var frame = found.item;
|
|
1446
|
+
var story = idcStoryOf(frame);
|
|
1447
|
+
var index = idcGiven(args.index) ? args.index : 0;
|
|
1448
|
+
var length = 0;
|
|
1449
|
+
var character, font, out, styleInfo = null, all, i, name, hits, kind;
|
|
1450
|
+
|
|
1451
|
+
if (typeof index !== 'number' || Math.floor(index) !== index || index < 0) {
|
|
1452
|
+
IDC.fail('invalid_argument', 'index must be a whole number of 0 or more.', { index: index });
|
|
1453
|
+
}
|
|
1454
|
+
try { length = Number(story.characters.length); } catch (e0) { length = 0; }
|
|
1455
|
+
if (length === 0) {
|
|
1456
|
+
IDC.fail('invalid_state', 'The frame holds no text; there is no character to inspect.', { frame_id: args.frame_id });
|
|
1457
|
+
}
|
|
1458
|
+
if (index >= length) {
|
|
1459
|
+
IDC.fail('invalid_argument', 'index ' + index + ' is beyond the story length ' + length + '.', { index: index, story_length: length });
|
|
1460
|
+
}
|
|
1461
|
+
character = idcFirstCharacter(story, index);
|
|
1462
|
+
font = idcReadFontLoose(character);
|
|
1463
|
+
out = {
|
|
1464
|
+
frame_id: Number(frame.id),
|
|
1465
|
+
index: index,
|
|
1466
|
+
character: (function () { try { return String(character.contents); } catch (e1) { return null; } })(),
|
|
1467
|
+
point_size: idcReadPt(character, 'pointSize'),
|
|
1468
|
+
leading_pt: idcReadLeading(character).pt,
|
|
1469
|
+
leading_auto: idcReadLeading(character).auto,
|
|
1470
|
+
applied_paragraph_style: idcReadSwatchName(character, 'appliedParagraphStyle'),
|
|
1471
|
+
applied_character_style: idcReadSwatchName(character, 'appliedCharacterStyle'),
|
|
1472
|
+
character_style_is_none: (function () { try { return idcIsNoneCharacterStyle(doc, character.appliedCharacterStyle); } catch (e1b) { return null; } })(),
|
|
1473
|
+
fill_color: idcReadSwatchName(character, 'fillColor'),
|
|
1474
|
+
applied_font: font.family,
|
|
1475
|
+
font_style: font.style,
|
|
1476
|
+
tracking: idcReadNumberLoose(character, 'tracking', 1),
|
|
1477
|
+
horizontal_scale: idcReadNumberLoose(character, 'horizontalScale', 3),
|
|
1478
|
+
vertical_scale: idcReadNumberLoose(character, 'verticalScale', 3),
|
|
1479
|
+
style_overridden: idcReadBoolLoose(character, 'styleOverridden'),
|
|
1480
|
+
frame_scale: idcFrameScale(frame),
|
|
1481
|
+
paragraph: idcInspectParagraph(character)
|
|
1482
|
+
};
|
|
1483
|
+
|
|
1484
|
+
if (idcGiven(args.style_name)) {
|
|
1485
|
+
name = String(args.style_name);
|
|
1486
|
+
hits = [];
|
|
1487
|
+
kind = null;
|
|
1488
|
+
all = idcAllStyles(doc, 'paragraph');
|
|
1489
|
+
for (i = 0; i < all.length; i++) {
|
|
1490
|
+
try { if (String(all[i].name) === name) { hits.push(all[i]); } } catch (e2) { /* weiter */ }
|
|
1491
|
+
}
|
|
1492
|
+
if (hits.length > 0) { kind = 'paragraph'; }
|
|
1493
|
+
else {
|
|
1494
|
+
all = idcAllStyles(doc, 'character');
|
|
1495
|
+
for (i = 0; i < all.length; i++) {
|
|
1496
|
+
try { if (String(all[i].name) === name) { hits.push(all[i]); } } catch (e3) { /* weiter */ }
|
|
1497
|
+
}
|
|
1498
|
+
if (hits.length > 0) { kind = 'character'; }
|
|
1499
|
+
}
|
|
1500
|
+
if (hits.length === 0) {
|
|
1501
|
+
styleInfo = { name: name, found: false, kind: null, matches: 0, duplicated: false, nested: false, definition: null, groups: [] };
|
|
1502
|
+
} else {
|
|
1503
|
+
var groups = [];
|
|
1504
|
+
for (i = 0; i < hits.length; i++) { groups.push(idcStyleGroupPath(hits[i])); }
|
|
1505
|
+
styleInfo = {
|
|
1506
|
+
name: name,
|
|
1507
|
+
found: true,
|
|
1508
|
+
kind: kind,
|
|
1509
|
+
matches: hits.length,
|
|
1510
|
+
duplicated: hits.length > 1,
|
|
1511
|
+
nested: groups[0] !== '',
|
|
1512
|
+
groups: groups,
|
|
1513
|
+
definition: kind === 'paragraph' ? idcDescribeParagraphStyle(hits[0]) : idcDescribeCharacterStyle(hits[0])
|
|
1514
|
+
};
|
|
1515
|
+
if (hits.length > 1) {
|
|
1516
|
+
ctx.warn('The style name "' + name + '" occurs ' + hits.length + ' times (in groups: ' + groups.join(', ') + ') – apply by name may pick the wrong one.');
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
out.style = styleInfo;
|
|
1520
|
+
}
|
|
1521
|
+
return out;
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
/* --------------------------------------------------------------- create_swatch */
|
|
1525
|
+
|
|
1526
|
+
function idcCmykArg(spec) {
|
|
1527
|
+
var keys = ['c', 'm', 'y', 'k'];
|
|
1528
|
+
var out = [];
|
|
1529
|
+
var i, v;
|
|
1530
|
+
if (typeof spec !== 'object' || spec === null || IDC.isArray(spec)) {
|
|
1531
|
+
IDC.fail('invalid_argument', 'cmyk must be an object { c, m, y, k } with values 0–100.', { value: spec });
|
|
1532
|
+
}
|
|
1533
|
+
for (i = 0; i < keys.length; i++) {
|
|
1534
|
+
v = spec[keys[i]];
|
|
1535
|
+
if (typeof v !== 'number' || !isFinite(v) || v < 0 || v > 100) {
|
|
1536
|
+
IDC.fail('invalid_argument', 'cmyk.' + keys[i] + ' must be a number from 0 to 100.', { value: v });
|
|
1537
|
+
}
|
|
1538
|
+
out.push(v);
|
|
1539
|
+
}
|
|
1540
|
+
return out;
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
IDC.register('create_swatch', { needs_document: true, read_only: false, ruler: 'none' },
|
|
1544
|
+
function (ctx) {
|
|
1545
|
+
var args = ctx.args;
|
|
1546
|
+
var doc = ctx.doc;
|
|
1547
|
+
var name = args.name;
|
|
1548
|
+
var onCollision = idcCollisionArg(args.on_collision);
|
|
1549
|
+
var hasHex = idcGiven(args.hex);
|
|
1550
|
+
var hasCmyk = idcGiven(args.cmyk);
|
|
1551
|
+
var values, space, spaceName, existing, collision = 'none', chosenName, swatch = null, className;
|
|
1552
|
+
var haveSwatch = false, existed = false;
|
|
1553
|
+
|
|
1554
|
+
if (typeof name !== 'string' || name.length < 1 || name.length > 60) {
|
|
1555
|
+
IDC.fail('invalid_argument', 'name is required (1–60 characters).', { name: name });
|
|
1556
|
+
}
|
|
1557
|
+
if (name.charAt(0) === '[') {
|
|
1558
|
+
IDC.fail('invalid_argument', 'name must not start with "[" – those names are reserved for InDesign\'s built-in swatches.', { name: name });
|
|
1559
|
+
}
|
|
1560
|
+
if (hasHex === hasCmyk) {
|
|
1561
|
+
IDC.fail('invalid_argument', 'Pass exactly one of hex (RGB, e.g. "#1A2B3C") or cmyk ({ c, m, y, k } in percent).', null);
|
|
1562
|
+
}
|
|
1563
|
+
if (hasHex) {
|
|
1564
|
+
var rgb = idcParseHex(args.hex, 'hex');
|
|
1565
|
+
values = [rgb.r, rgb.g, rgb.b];
|
|
1566
|
+
space = ColorSpace.RGB;
|
|
1567
|
+
spaceName = 'rgb';
|
|
1568
|
+
} else {
|
|
1569
|
+
values = idcCmykArg(args.cmyk);
|
|
1570
|
+
space = ColorSpace.CMYK;
|
|
1571
|
+
spaceName = 'cmyk';
|
|
1572
|
+
}
|
|
1573
|
+
chosenName = name;
|
|
1574
|
+
existing = idcSwatchByName(doc, name);
|
|
1575
|
+
existed = idcPresent(existing);
|
|
1576
|
+
if (existed) {
|
|
1577
|
+
if (onCollision === 'error') {
|
|
1578
|
+
IDC.fail('invalid_state', 'Swatch "' + name + '" exists already. Pass on_collision "update" to change it or "version" to add "' + name + ' 2".',
|
|
1579
|
+
{ name: name, swatch_id: (function () { try { return Number(existing.id); } catch (e) { return null; } })() });
|
|
1580
|
+
}
|
|
1581
|
+
if (onCollision === 'update') {
|
|
1582
|
+
className = IDC.className(existing);
|
|
1583
|
+
if (className !== 'Color' && className !== 'Swatch') {
|
|
1584
|
+
IDC.fail('invalid_state', 'Swatch "' + name + '" is a ' + className + ', not a colour; it cannot be updated with values.', { name: name, type: className });
|
|
1585
|
+
}
|
|
1586
|
+
swatch = existing;
|
|
1587
|
+
haveSwatch = true;
|
|
1588
|
+
collision = 'updated';
|
|
1589
|
+
try {
|
|
1590
|
+
swatch.model = ColorModel.PROCESS;
|
|
1591
|
+
swatch.space = space;
|
|
1592
|
+
swatch.colorValue = values;
|
|
1593
|
+
} catch (e1) {
|
|
1594
|
+
IDC.fail('script_error', 'InDesign could not update the swatch "' + name + '": ' + String(e1.message ? e1.message : e1), { name: name });
|
|
1595
|
+
}
|
|
1596
|
+
} else {
|
|
1597
|
+
chosenName = idcFreeName(doc, name, 'swatch');
|
|
1598
|
+
collision = 'versioned';
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
if (!haveSwatch) {
|
|
1602
|
+
try {
|
|
1603
|
+
/* Colors.add nimmt nur withProperties (Live-Fund Sitzung 3). */
|
|
1604
|
+
swatch = doc.colors.add({ name: chosenName, model: ColorModel.PROCESS, space: space, colorValue: values });
|
|
1605
|
+
} catch (e2) {
|
|
1606
|
+
IDC.fail('script_error', 'InDesign could not create the swatch "' + chosenName + '": ' + String(e2.message ? e2.message : e2), { name: chosenName });
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
ctx.changes = collision === 'updated'
|
|
1610
|
+
? { modified_swatch_ids: [Number(swatch.id)] }
|
|
1611
|
+
: { created_swatch_ids: [Number(swatch.id)] };
|
|
1612
|
+
return {
|
|
1613
|
+
name: String(swatch.name),
|
|
1614
|
+
swatch_id: Number(swatch.id),
|
|
1615
|
+
collision: collision,
|
|
1616
|
+
existed: existed,
|
|
1617
|
+
space: spaceName,
|
|
1618
|
+
values: values
|
|
1619
|
+
};
|
|
1620
|
+
});
|