layoutbridge-light 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/LICENSE +26 -0
- package/README.de.md +338 -0
- package/README.md +325 -2
- package/THIRD-PARTY-NOTICES.md +2878 -0
- package/dist/src/mcp/catalog.js +126 -0
- package/dist/src/mcp/config.js +211 -0
- package/dist/src/mcp/dispatch.js +164 -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/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/tool-definition.js +2 -0
- package/dist/src/mcp/tools.js +2425 -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 +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 +448 -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 +210 -0
- package/indesign/commands/32-sections.js +203 -0
- package/indesign/commands/35-parents.js +428 -0
- package/indesign/commands/37-layout.js +837 -0
- package/indesign/commands/40-frames.js +851 -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 +331 -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 +1128 -0
- package/indesign/commands/62-embed.js +120 -0
- package/indesign/commands/69-placeholders.js +127 -0
- package/indesign/commands/70-text.js +675 -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 +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 +452 -0
- package/indesign/commands/79-check-typography.js +341 -0
- package/indesign/commands/80-styles.js +1865 -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 +945 -0
- package/indesign/commands/90-print-on-demand.js +495 -0
- package/indesign/commands/91-epub.js +546 -0
- package/indesign/interpreter.js +779 -0
- package/package.json +41 -4
- package/rules/typography-rules.json +31 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Auftrag A-7.5 (Sitzung 9) – get_frame_lines: den Umbruch direkt in
|
|
3
|
+
* InDesign lesen – Zeilen je Textspalte eines Rahmens mit Grundlinie,
|
|
4
|
+
* Story-Indizes, Absatzstellung und Kennzahlen (Hurenkind-/Schusterjungen-
|
|
5
|
+
* Verdacht, Trennstrichleitern, Leerzeilen). Rein lesend.
|
|
6
|
+
*
|
|
7
|
+
* Adobe-DOM (geprueft 05.09.2026): TextFrame.textColumns, TextFrame.lines,
|
|
8
|
+
* Line {baseline, ascent, descent, horizontalOffset, endHorizontalOffset,
|
|
9
|
+
* characters, paragraphs, words, contents}. TextColumn lieferte 404 – die
|
|
10
|
+
* Klasse ist ein Text-Objekt mit lines; ohne textColumns gilt der Rahmen
|
|
11
|
+
* als eine Spalte.
|
|
12
|
+
*
|
|
13
|
+
* Grundlinien und horizontale Lagen werden unter Bogen-Nullpunkt gelesen
|
|
14
|
+
* (Millimeter ueber die Masseinheiten-Klammer) und um den Seitenversatz
|
|
15
|
+
* verschoben – wie IDC.boundsOnPage.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/* Bindestrich, weicher Trennstrich, Trennstrich, geschuetzter Trennstrich. */
|
|
19
|
+
var IDC_LINE_HYPHENS = {};
|
|
20
|
+
IDC_LINE_HYPHENS['-'] = 1;
|
|
21
|
+
IDC_LINE_HYPHENS['\u00AD'] = 1;
|
|
22
|
+
IDC_LINE_HYPHENS['\u2010'] = 1;
|
|
23
|
+
IDC_LINE_HYPHENS['\u2011'] = 1;
|
|
24
|
+
|
|
25
|
+
function idcIsLetter(ch) {
|
|
26
|
+
if (ch === '' || ch === null || ch === undefined) { return false; }
|
|
27
|
+
return /[A-Za-z\u00C0-\u024F\u0370-\u03FF\u0400-\u04FF]/.test(ch);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Story-Index des ersten Zeichens eines Textobjekts (Zeile, Absatz). */
|
|
31
|
+
function idcTextStartIndex(textObject) {
|
|
32
|
+
try { return Number(textObject.characters.item(0).index); } catch (e) { return null; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function idcTextLength(textObject) {
|
|
36
|
+
try { return Number(textObject.characters.length); } catch (e) { return null; }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Ergebnis eines everyItem()-Lesens als Array mit genau count Eintraegen, sonst null. */
|
|
40
|
+
function idcBundled(value, count) {
|
|
41
|
+
if (value === null || value === undefined) { return null; }
|
|
42
|
+
if (!IDC.isArray(value)) { value = [value]; }
|
|
43
|
+
return value.length === count ? value : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* Absaetze der Story: Startindex -> Ordnungszahl (erster Absatz mit diesem
|
|
48
|
+
* Start), einmal je Story. A-69: frueher je Rahmen und mit Laenge und
|
|
49
|
+
* Zeilenzahl jedes Absatzes der ganzen Kette – beides unbenutzt, die
|
|
50
|
+
* Zeilenzahl liest idcDescribeLine nur fuer den Absatz der Zeile.
|
|
51
|
+
* A-69 Teil 2 (Live-Probe 30.10.2026, 3185 Absaetze): paragraphs.item(i)
|
|
52
|
+
* wird mit i langsamer (16,5 s fuer alle), everyItem() liest alle Starts in
|
|
53
|
+
* 0,6 s mit denselben Werten. starts (aufsteigend) und end (Laenge der
|
|
54
|
+
* Story) tragen idcLineDataBundled; ohne everyItem() der Weg je Absatz.
|
|
55
|
+
*/
|
|
56
|
+
function idcParagraphMap(story) {
|
|
57
|
+
var map = { byStart: {}, count: 0, starts: null, end: null };
|
|
58
|
+
var paragraphs, i, start, starts = null;
|
|
59
|
+
try { paragraphs = story.paragraphs; map.count = Number(paragraphs.length); } catch (e0) { return map; }
|
|
60
|
+
if (map.count === 0) { return map; }
|
|
61
|
+
try { starts = idcBundled(paragraphs.everyItem().characters.firstItem().index, map.count); } catch (e1) { starts = null; }
|
|
62
|
+
if (starts !== null) {
|
|
63
|
+
for (i = 0; i < map.count; i++) {
|
|
64
|
+
start = Number(starts[i]);
|
|
65
|
+
if (i > 0 && !(start >= starts[i - 1])) { starts = null; break; }
|
|
66
|
+
starts[i] = start;
|
|
67
|
+
if (!IDC.hasOwn(map.byStart, 'k' + start)) { map.byStart['k' + start] = i; }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (starts !== null) {
|
|
71
|
+
map.starts = starts;
|
|
72
|
+
try { map.end = Number(story.characters.length); } catch (e2) { map.starts = null; }
|
|
73
|
+
return map;
|
|
74
|
+
}
|
|
75
|
+
map.byStart = {};
|
|
76
|
+
for (i = 0; i < map.count; i++) {
|
|
77
|
+
start = idcTextStartIndex(paragraphs.item(i));
|
|
78
|
+
if (start !== null && !IDC.hasOwn(map.byStart, 'k' + start)) { map.byStart['k' + start] = i; }
|
|
79
|
+
}
|
|
80
|
+
return map;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Ordnungszahl des Absatzes, in dem der Story-Index liegt (letzter Start <= index). */
|
|
84
|
+
function idcParagraphAt(map, index) {
|
|
85
|
+
var lo = 0, hi = map.starts.length - 1, mid;
|
|
86
|
+
if (hi < 0 || index < map.starts[0]) { return -1; }
|
|
87
|
+
while (lo < hi) {
|
|
88
|
+
mid = Math.floor((lo + hi + 1) / 2);
|
|
89
|
+
if (map.starts[mid] <= index) { lo = mid; } else { hi = mid - 1; }
|
|
90
|
+
}
|
|
91
|
+
return lo;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function idcParagraphOrdinal(map, startIndex) {
|
|
95
|
+
if (startIndex === null || !IDC.hasOwn(map.byStart, 'k' + startIndex)) { return null; }
|
|
96
|
+
return map.byStart['k' + startIndex];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/*
|
|
100
|
+
* Was alle Rahmen einer Story teilen (A-69): Absatztabelle, Lage jedes
|
|
101
|
+
* Rahmens in der Kette (frame id -> Index) und Uebersatz. check_typography
|
|
102
|
+
* legt es einmal je Story an; get_frame_lines fuer seinen einen Rahmen.
|
|
103
|
+
*/
|
|
104
|
+
function idcStoryLineCache(story) {
|
|
105
|
+
var cache = { map: idcParagraphMap(story), frameIndexById: {}, overset: null, paragraphLines: {} };
|
|
106
|
+
var containers, i, key;
|
|
107
|
+
try {
|
|
108
|
+
containers = story.textContainers;
|
|
109
|
+
for (i = 0; i < containers.length; i++) {
|
|
110
|
+
key = 'k' + Number(containers[i].id);
|
|
111
|
+
if (!IDC.hasOwn(cache.frameIndexById, key)) { cache.frameIndexById[key] = i; }
|
|
112
|
+
}
|
|
113
|
+
} catch (e1) { cache.frameIndexById = {}; }
|
|
114
|
+
try { cache.overset = story.overflows === true; } catch (e2) { cache.overset = null; }
|
|
115
|
+
return cache;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Spaltenbegrenzungen aus Rahmen, Innenabstand, Spaltenzahl und Steg (Seitenkoordinaten). */
|
|
119
|
+
function idcColumnBounds(doc, frame, page, count) {
|
|
120
|
+
var bounds = IDC.boundsOnPage(doc, frame, page);
|
|
121
|
+
var inset = [0, 0, 0, 0];
|
|
122
|
+
var gutter = 0;
|
|
123
|
+
var out = [], i, width, x;
|
|
124
|
+
try { inset = frame.textFramePreferences.insetSpacing; } catch (e0) { inset = [0, 0, 0, 0]; }
|
|
125
|
+
if (!IDC.isArray(inset) || inset.length < 4) { inset = [0, 0, 0, 0]; }
|
|
126
|
+
try { gutter = Number(frame.textFramePreferences.textColumnGutter); } catch (e1) { gutter = 0; }
|
|
127
|
+
if (isNaN(gutter)) { gutter = 0; }
|
|
128
|
+
width = (bounds.width - Number(inset[1]) - Number(inset[3]) - (count - 1) * gutter) / count;
|
|
129
|
+
for (i = 0; i < count; i++) {
|
|
130
|
+
x = bounds.x + Number(inset[1]) + i * (width + gutter);
|
|
131
|
+
out.push({
|
|
132
|
+
x: IDC.round(x),
|
|
133
|
+
y: IDC.round(bounds.y + Number(inset[0])),
|
|
134
|
+
width: IDC.round(width),
|
|
135
|
+
height: IDC.round(bounds.height - Number(inset[0]) - Number(inset[2]))
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function idcDescribeLine(doc, line, indexInColumn, map, dx, includeText) {
|
|
142
|
+
var start = idcTextStartIndex(line);
|
|
143
|
+
var length = idcTextLength(line);
|
|
144
|
+
var paragraph = null, pStart = null, pLength = null, pLines = null;
|
|
145
|
+
var contents = '', wordCount = null, geometry = {};
|
|
146
|
+
|
|
147
|
+
try { paragraph = line.paragraphs.item(0); } catch (e0) { paragraph = null; }
|
|
148
|
+
if (paragraph !== null) {
|
|
149
|
+
pStart = idcTextStartIndex(paragraph);
|
|
150
|
+
pLength = idcTextLength(paragraph);
|
|
151
|
+
try { pLines = Number(paragraph.lines.length); } catch (e1) { pLines = null; }
|
|
152
|
+
}
|
|
153
|
+
try { contents = String(line.contents); } catch (e2) { contents = ''; }
|
|
154
|
+
try { wordCount = Number(line.words.length); } catch (e3) { wordCount = null; }
|
|
155
|
+
try { geometry.baseline = Number(line.baseline); } catch (e4) { /* null */ }
|
|
156
|
+
try { geometry.ascent = IDC.inPoints(function () { return Number(line.ascent); }); } catch (e5) { /* null */ }
|
|
157
|
+
try { geometry.descent = IDC.inPoints(function () { return Number(line.descent); }); } catch (e6) { /* null */ }
|
|
158
|
+
try { geometry.left = Number(line.horizontalOffset); } catch (e7) { /* null */ }
|
|
159
|
+
try { geometry.right = Number(line.endHorizontalOffset); } catch (e8) { /* null */ }
|
|
160
|
+
return idcLineEntry(indexInColumn, start, length, pStart,
|
|
161
|
+
pStart === null || pLength === null ? null : pStart + pLength,
|
|
162
|
+
pStart === null ? null : idcParagraphOrdinal(map, pStart), pLines, contents, wordCount, geometry, dx, includeText);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
* Eine Zeile aus gelesenen Werten – gemeinsam fuer den Weg je Zeile
|
|
167
|
+
* (idcDescribeLine) und das gebuendelte Lesen (idcLineDataBundled), damit
|
|
168
|
+
* beide dieselbe Ausgabe liefern. pEnd = Story-Index hinter dem Absatz;
|
|
169
|
+
* geometry {baseline, left, right} in mm, {ascent, descent} in pt, fehlende
|
|
170
|
+
* Werte bleiben null.
|
|
171
|
+
*/
|
|
172
|
+
function idcLineEntry(indexInColumn, start, length, pStart, pEnd, pIndex, pLines, contents, wordCount, geometry, dx, includeText) {
|
|
173
|
+
var lastChar = '', out;
|
|
174
|
+
if (contents.length > 0) { lastChar = contents.charAt(contents.length - 1); }
|
|
175
|
+
if (contents.replace(/[\r\n\s]/g, '') === '') { wordCount = 0; }
|
|
176
|
+
|
|
177
|
+
out = {
|
|
178
|
+
index: indexInColumn,
|
|
179
|
+
start_index: start,
|
|
180
|
+
end_index: start === null || length === null ? null : start + length,
|
|
181
|
+
baseline_mm: null,
|
|
182
|
+
ascent_pt: null,
|
|
183
|
+
descent_pt: null,
|
|
184
|
+
left_mm: null,
|
|
185
|
+
right_mm: null,
|
|
186
|
+
paragraph_index: pIndex,
|
|
187
|
+
is_first_line_of_paragraph: pStart !== null && start === pStart,
|
|
188
|
+
is_last_line_of_paragraph: pEnd !== null && start !== null && length !== null && start + length === pEnd,
|
|
189
|
+
paragraph_line_count: pLines,
|
|
190
|
+
ends_with_hyphen: IDC.hasOwn(IDC_LINE_HYPHENS, lastChar),
|
|
191
|
+
is_empty: length !== null && (length === 0 || (length === 1 && (lastChar === '\r' || lastChar === '\n'))),
|
|
192
|
+
word_count: wordCount,
|
|
193
|
+
last_char: lastChar === '\r' ? '\\r' : lastChar
|
|
194
|
+
};
|
|
195
|
+
if (geometry.baseline !== undefined) { out.baseline_mm = IDC.round(geometry.baseline); }
|
|
196
|
+
if (geometry.ascent !== undefined) { out.ascent_pt = IDC.round(geometry.ascent, 3); }
|
|
197
|
+
if (geometry.descent !== undefined) { out.descent_pt = IDC.round(geometry.descent, 3); }
|
|
198
|
+
if (geometry.left !== undefined) { out.left_mm = IDC.round(geometry.left - dx); }
|
|
199
|
+
if (geometry.right !== undefined) { out.right_mm = IDC.round(geometry.right - dx); }
|
|
200
|
+
if (includeText) { out.text = contents.replace(/[\r\n]+$/, ''); }
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/*
|
|
205
|
+
* Alle Zeilen einer Spalte (oder eines Rahmens) gebuendelt lesen (A-69 Teil 2,
|
|
206
|
+
* Live-Probe 30.10.2026: je Rahmen ~50 ms statt ~290 ms, Werte in 228 Zeilen
|
|
207
|
+
* gleich dem Weg je Zeile). Je Eigenschaft ein everyItem()-Zugriff; den Absatz
|
|
208
|
+
* jeder Zeile liefert die Absatztabelle der Story (map.starts). Zeilenzahl des
|
|
209
|
+
* Absatzes: liegen erste und letzte Zeile in dieser Spalte, wird gezaehlt,
|
|
210
|
+
* sonst einmal je Absatz paragraph.lines (in cache.paragraphLines).
|
|
211
|
+
* lean: word_count nur fuer letzte Absatzzeilen (die Regeln brauchen ihn nur
|
|
212
|
+
* dort), sonst null. Liefert null, wenn etwas nicht gebuendelt lesbar ist
|
|
213
|
+
* (z. B. eine leere Zeile) – dann gilt der Weg je Zeile.
|
|
214
|
+
*/
|
|
215
|
+
function idcLineDataBundled(textObject, map, dx, includeText, cache, lean) {
|
|
216
|
+
var lines, n, every, starts, lasts, contents, baselines, lefts, rights, metrics, i;
|
|
217
|
+
var entries = [], keys = [], pIndex, pStart, pEnd, start, length, word, key, firstIn = {}, lastIn = {}, countIn = {};
|
|
218
|
+
if (map.starts === null) { return null; }
|
|
219
|
+
try {
|
|
220
|
+
lines = textObject.lines;
|
|
221
|
+
n = Number(lines.length);
|
|
222
|
+
if (n === 0) { return { entries: entries, contents: [] }; }
|
|
223
|
+
every = lines.everyItem();
|
|
224
|
+
starts = idcBundled(every.index, n);
|
|
225
|
+
lasts = idcBundled(every.characters.lastItem().index, n);
|
|
226
|
+
contents = idcBundled(every.contents, n);
|
|
227
|
+
baselines = idcBundled(every.baseline, n);
|
|
228
|
+
lefts = idcBundled(every.horizontalOffset, n);
|
|
229
|
+
rights = idcBundled(every.endHorizontalOffset, n);
|
|
230
|
+
metrics = IDC.inPoints(function () { return [idcBundled(every.ascent, n), idcBundled(every.descent, n)]; });
|
|
231
|
+
} catch (e0) { return null; }
|
|
232
|
+
if (starts === null || lasts === null || contents === null || baselines === null || lefts === null || rights === null || metrics[0] === null || metrics[1] === null) { return null; }
|
|
233
|
+
|
|
234
|
+
for (i = 0; i < n; i++) {
|
|
235
|
+
start = Number(starts[i]);
|
|
236
|
+
length = Number(lasts[i]) - start + 1;
|
|
237
|
+
pIndex = idcParagraphAt(map, start);
|
|
238
|
+
if (pIndex < 0) { return null; }
|
|
239
|
+
pStart = map.starts[pIndex];
|
|
240
|
+
pEnd = pIndex + 1 < map.starts.length ? map.starts[pIndex + 1] : map.end;
|
|
241
|
+
entries.push(idcLineEntry(i, start, length, pStart, pEnd, idcParagraphOrdinal(map, pStart), null,
|
|
242
|
+
String(contents[i]), null,
|
|
243
|
+
{ baseline: Number(baselines[i]), ascent: Number(metrics[0][i]), descent: Number(metrics[1][i]), left: Number(lefts[i]), right: Number(rights[i]) },
|
|
244
|
+
dx, includeText));
|
|
245
|
+
key = 'k' + pStart;
|
|
246
|
+
keys.push(key);
|
|
247
|
+
if (entries[i].is_first_line_of_paragraph) { firstIn[key] = true; }
|
|
248
|
+
if (entries[i].is_last_line_of_paragraph) { lastIn[key] = true; }
|
|
249
|
+
countIn[key] = (countIn[key] || 0) + 1;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
for (i = 0; i < n; i++) {
|
|
253
|
+
key = keys[i];
|
|
254
|
+
if (firstIn[key] === true && lastIn[key] === true) {
|
|
255
|
+
entries[i].paragraph_line_count = countIn[key];
|
|
256
|
+
} else {
|
|
257
|
+
if (!IDC.hasOwn(cache.paragraphLines, key)) {
|
|
258
|
+
try { cache.paragraphLines[key] = Number(lines.item(i).paragraphs.item(0).lines.length); } catch (e1) { cache.paragraphLines[key] = null; }
|
|
259
|
+
}
|
|
260
|
+
entries[i].paragraph_line_count = cache.paragraphLines[key];
|
|
261
|
+
}
|
|
262
|
+
if (!lean || (entries[i].is_last_line_of_paragraph && !entries[i].is_empty)) {
|
|
263
|
+
word = null;
|
|
264
|
+
try { word = Number(lines.item(i).words.length); } catch (e2) { word = null; }
|
|
265
|
+
if (String(contents[i]).replace(/[\r\n\s]/g, '') === '') { word = 0; }
|
|
266
|
+
entries[i].word_count = word;
|
|
267
|
+
}
|
|
268
|
+
contents[i] = String(contents[i]);
|
|
269
|
+
}
|
|
270
|
+
return { entries: entries, contents: contents };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/*
|
|
274
|
+
* Automatische Trennung: der Trennstrich steht nicht im Text. Endet eine
|
|
275
|
+
* Zeile mit einem Buchstaben und beginnt die naechste Zeile desselben
|
|
276
|
+
* Absatzes mit einem Buchstaben, ist das Wort getrennt (oder erzwungen
|
|
277
|
+
* gebrochen) – ends_with_hyphen wird dann gesetzt.
|
|
278
|
+
*/
|
|
279
|
+
function idcMarkSoftHyphens(lines, texts) {
|
|
280
|
+
var i, a, b;
|
|
281
|
+
for (i = 0; i + 1 < lines.length; i++) {
|
|
282
|
+
a = lines[i];
|
|
283
|
+
b = lines[i + 1];
|
|
284
|
+
if (a.ends_with_hyphen) { continue; }
|
|
285
|
+
if (a.paragraph_index === null || a.paragraph_index !== b.paragraph_index) { continue; }
|
|
286
|
+
if (a.is_last_line_of_paragraph) { continue; }
|
|
287
|
+
if (idcIsLetter(texts[i].last) && idcIsLetter(texts[i + 1].first)) { a.ends_with_hyphen = true; }
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function idcColumnFigures(lines) {
|
|
292
|
+
var out = {
|
|
293
|
+
line_count: lines.length,
|
|
294
|
+
first_baseline_mm: null,
|
|
295
|
+
last_baseline_mm: null,
|
|
296
|
+
starts_with_last_line_of_paragraph: false,
|
|
297
|
+
ends_with_first_line_of_paragraph: false,
|
|
298
|
+
starts_with_empty_line: false,
|
|
299
|
+
consecutive_hyphens_max: 0,
|
|
300
|
+
ends_with_single_word: false,
|
|
301
|
+
single_word_last_lines: []
|
|
302
|
+
};
|
|
303
|
+
var i, run = 0, first, last;
|
|
304
|
+
if (lines.length === 0) { return out; }
|
|
305
|
+
first = lines[0];
|
|
306
|
+
last = lines[lines.length - 1];
|
|
307
|
+
out.first_baseline_mm = first.baseline_mm;
|
|
308
|
+
out.last_baseline_mm = last.baseline_mm;
|
|
309
|
+
out.starts_with_last_line_of_paragraph = first.is_last_line_of_paragraph && !first.is_first_line_of_paragraph && !first.is_empty;
|
|
310
|
+
out.ends_with_first_line_of_paragraph = last.is_first_line_of_paragraph && !last.is_last_line_of_paragraph && !last.is_empty;
|
|
311
|
+
out.starts_with_empty_line = first.is_empty === true;
|
|
312
|
+
for (i = 0; i < lines.length; i++) {
|
|
313
|
+
if (lines[i].ends_with_hyphen) { run += 1; if (run > out.consecutive_hyphens_max) { out.consecutive_hyphens_max = run; } }
|
|
314
|
+
else { run = 0; }
|
|
315
|
+
if (lines[i].is_last_line_of_paragraph && !lines[i].is_empty && lines[i].word_count === 1 && lines[i].paragraph_line_count !== null && lines[i].paragraph_line_count > 1) {
|
|
316
|
+
out.single_word_last_lines.push(lines[i].index);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
out.ends_with_single_word = last.is_last_line_of_paragraph && !last.is_empty && last.word_count === 1 && last.paragraph_line_count !== null && last.paragraph_line_count > 1;
|
|
320
|
+
return out;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* Zeilen einer Spalte (TextColumn) oder des ganzen Rahmens als Array. */
|
|
324
|
+
function idcLinesOf(textObject) {
|
|
325
|
+
var out = [], lines, i;
|
|
326
|
+
try { lines = textObject.lines; } catch (e0) { return out; }
|
|
327
|
+
for (i = 0; i < lines.length; i++) { out.push(lines.item(i)); }
|
|
328
|
+
return out;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function idcFrameColumns(frame) {
|
|
332
|
+
var out = [], columns, i;
|
|
333
|
+
try { columns = frame.textColumns; } catch (e0) { columns = null; }
|
|
334
|
+
if (columns === null || columns === undefined) { return null; }
|
|
335
|
+
try {
|
|
336
|
+
for (i = 0; i < columns.length; i++) { out.push(columns.item(i)); }
|
|
337
|
+
} catch (e1) { return null; }
|
|
338
|
+
return out;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/*
|
|
342
|
+
* Zeilen eines Rahmens je Spalte samt Kennzahlen – gemeinsam fuer
|
|
343
|
+
* get_frame_lines und check_typography. Warnungen gehen an ctx (null =
|
|
344
|
+
* keine). cache aus idcStoryLineCache(story); ohne wird er hier angelegt.
|
|
345
|
+
* lean (check_typography): word_count nur, wo die Regeln ihn lesen.
|
|
346
|
+
*/
|
|
347
|
+
function idcFrameLineData(doc, frame, story, includeText, maxLines, ctx, cache, lean) {
|
|
348
|
+
var page = null, dx = 0, columns, columnObjects, i, c, lines, entries, texts, raw, bundled, line, total = 0, truncated = false, overset = null;
|
|
349
|
+
var map, bounds, frameIndex = null, frameKey;
|
|
350
|
+
|
|
351
|
+
try { page = frame.parentPage; } catch (e0) { page = null; }
|
|
352
|
+
try { if (page !== null && page !== undefined && page.isValid !== true) { page = null; } } catch (e0b) { page = null; }
|
|
353
|
+
if (page === null || page === undefined) { page = null; }
|
|
354
|
+
dx = page === null ? 0 : IDC.spreadOffsetOfPage(page);
|
|
355
|
+
|
|
356
|
+
if (cache === undefined || cache === null) { cache = idcStoryLineCache(story); }
|
|
357
|
+
try {
|
|
358
|
+
frameKey = 'k' + Number(frame.id);
|
|
359
|
+
if (IDC.hasOwn(cache.frameIndexById, frameKey)) { frameIndex = cache.frameIndexById[frameKey]; }
|
|
360
|
+
} catch (e1) { frameIndex = null; }
|
|
361
|
+
overset = cache.overset;
|
|
362
|
+
map = cache.map;
|
|
363
|
+
columnObjects = idcFrameColumns(frame);
|
|
364
|
+
if (columnObjects === null || columnObjects.length === 0) { columnObjects = [frame]; }
|
|
365
|
+
bounds = idcColumnBounds(doc, frame, page, columnObjects.length);
|
|
366
|
+
|
|
367
|
+
columns = [];
|
|
368
|
+
for (c = 0; c < columnObjects.length; c++) {
|
|
369
|
+
bundled = idcLineDataBundled(columnObjects[c], map, dx, includeText, cache, lean === true);
|
|
370
|
+
entries = [];
|
|
371
|
+
raw = [];
|
|
372
|
+
if (bundled !== null) {
|
|
373
|
+
for (i = 0; i < bundled.entries.length; i++) {
|
|
374
|
+
if (total >= maxLines) { truncated = true; break; }
|
|
375
|
+
entries.push(bundled.entries[i]);
|
|
376
|
+
raw.push(bundled.contents[i]);
|
|
377
|
+
total += 1;
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
lines = idcLinesOf(columnObjects[c]);
|
|
381
|
+
for (i = 0; i < lines.length; i++) {
|
|
382
|
+
if (total >= maxLines) { truncated = true; break; }
|
|
383
|
+
line = lines[i];
|
|
384
|
+
entries.push(idcDescribeLine(doc, line, i, map, dx, includeText));
|
|
385
|
+
try { raw.push(String(line.contents)); } catch (e3) { raw.push(''); }
|
|
386
|
+
total += 1;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
texts = [];
|
|
390
|
+
for (i = 0; i < raw.length; i++) {
|
|
391
|
+
/* Endet die Zeile mit Absatzmarke, erzwungenem Umbruch (Live-Fund 05.09.2026: initial_text mit LF) oder Zeilentrenner, ist nichts getrennt. */
|
|
392
|
+
var rawLast = raw[i].charAt(raw[i].length - 1);
|
|
393
|
+
var brokenByBreak = rawLast === '\r' || rawLast === '\n' || rawLast === '\u2028' || rawLast === '\u2029';
|
|
394
|
+
texts.push({ first: raw[i].charAt(0), last: brokenByBreak ? '' : rawLast });
|
|
395
|
+
}
|
|
396
|
+
idcMarkSoftHyphens(entries, texts);
|
|
397
|
+
var figures = idcColumnFigures(entries);
|
|
398
|
+
figures.column_index = c;
|
|
399
|
+
figures.bounds_mm = bounds[c] || null;
|
|
400
|
+
figures.lines = entries;
|
|
401
|
+
columns.push(figures);
|
|
402
|
+
if (truncated) { break; }
|
|
403
|
+
}
|
|
404
|
+
if (ctx !== null && truncated) {
|
|
405
|
+
ctx.warn('More than ' + maxLines + ' lines; output cut at max_lines (truncated true).');
|
|
406
|
+
}
|
|
407
|
+
if (ctx !== null && total === 0) {
|
|
408
|
+
ctx.warn('The frame shows no composed line – it is empty, or the text is overset before it.');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
frame_id: Number(frame.id),
|
|
413
|
+
story_id: Number(story.id),
|
|
414
|
+
frame_index: frameIndex,
|
|
415
|
+
page_id: page === null ? null : Number(page.id),
|
|
416
|
+
page_name: page === null ? '' : String(page.name),
|
|
417
|
+
paragraph_count: map.count,
|
|
418
|
+
column_count: columns.length,
|
|
419
|
+
line_count: total,
|
|
420
|
+
columns: columns,
|
|
421
|
+
overset: overset,
|
|
422
|
+
truncated: truncated
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
IDC.register('get_frame_lines', { needs_document: true, read_only: true, ruler: 'spread' },
|
|
427
|
+
function (ctx) {
|
|
428
|
+
var args = ctx.args;
|
|
429
|
+
var doc = ctx.doc;
|
|
430
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
431
|
+
var frame = found.item;
|
|
432
|
+
var story = idcStoryOf(frame);
|
|
433
|
+
var includeText = args.include_text === true;
|
|
434
|
+
var maxLines = idcGiven(args.max_lines) ? args.max_lines : 500;
|
|
435
|
+
|
|
436
|
+
if (typeof maxLines !== 'number' || Math.floor(maxLines) !== maxLines || maxLines < 1 || maxLines > 5000) {
|
|
437
|
+
IDC.fail('invalid_argument', 'max_lines must be a whole number between 1 and 5000.', { max_lines: args.max_lines });
|
|
438
|
+
}
|
|
439
|
+
var data = idcFrameLineData(doc, frame, story, includeText, maxLines, ctx);
|
|
440
|
+
return {
|
|
441
|
+
frame_id: data.frame_id,
|
|
442
|
+
story_id: data.story_id,
|
|
443
|
+
frame_index: data.frame_index,
|
|
444
|
+
page_id: data.page_id,
|
|
445
|
+
coordinate_space: data.page_id === null ? 'spread' : 'page',
|
|
446
|
+
column_count: data.column_count,
|
|
447
|
+
line_count: data.line_count,
|
|
448
|
+
columns: data.columns,
|
|
449
|
+
overset: data.overset,
|
|
450
|
+
truncated: data.truncated
|
|
451
|
+
};
|
|
452
|
+
});
|