layoutbridge-light 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/LICENSE +26 -0
- package/README.de.md +367 -0
- package/README.md +353 -2
- package/THIRD-PARTY-NOTICES.md +2878 -0
- package/dist/src/mcp/catalog.js +131 -0
- package/dist/src/mcp/config.js +211 -0
- package/dist/src/mcp/content-credentials.js +65 -0
- package/dist/src/mcp/dispatch.js +171 -0
- package/dist/src/mcp/epub-check.js +331 -0
- package/dist/src/mcp/epub-orientation.js +132 -0
- package/dist/src/mcp/license/free-tools.js +16 -0
- package/dist/src/mcp/license/gate.js +210 -0
- package/dist/src/mcp/license/index.js +107 -0
- package/dist/src/mcp/license/instance-name.js +57 -0
- package/dist/src/mcp/license/key-source.js +59 -0
- package/dist/src/mcp/license/lemonsqueezy-verifier.js +207 -0
- package/dist/src/mcp/license/placeholder-verifier.js +10 -0
- package/dist/src/mcp/license/polar-ids.js +100 -0
- package/dist/src/mcp/license/polar-verifier.js +285 -0
- package/dist/src/mcp/license/product-ids.js +73 -0
- package/dist/src/mcp/license/state-store.js +91 -0
- package/dist/src/mcp/license/types.js +11 -0
- package/dist/src/mcp/logging.js +271 -0
- package/dist/src/mcp/pdf-postprocess.js +798 -0
- package/dist/src/mcp/product-info.js +54 -0
- package/dist/src/mcp/product.js +56 -0
- package/dist/src/mcp/server.js +253 -0
- package/dist/src/mcp/setup.js +680 -0
- package/dist/src/mcp/start.cjs +117 -0
- package/dist/src/mcp/target-folder.js +25 -0
- package/dist/src/mcp/tool-definition.js +2 -0
- package/dist/src/mcp/tools.js +2680 -0
- package/dist/src/mcp/typography-rules.js +70 -0
- package/dist/src/transport/com.js +436 -0
- package/dist/src/transport/osascript.js +171 -0
- package/dist/src/transport/queue.js +19 -0
- package/dist/src/transport/script-bundle.js +92 -0
- package/dist/src/transport/transport.js +52 -0
- package/indesign/commands/10-app.js +6 -0
- package/indesign/commands/20-documents.js +517 -0
- package/indesign/commands/22-document-setup.js +204 -0
- package/indesign/commands/23-save-package.js +258 -0
- package/indesign/commands/25-export.js +695 -0
- package/indesign/commands/26-export-image.js +202 -0
- package/indesign/commands/27-textdefaults.js +151 -0
- package/indesign/commands/28-selection.js +174 -0
- package/indesign/commands/30-pages.js +1032 -0
- package/indesign/commands/31-view.js +310 -0
- package/indesign/commands/32-sections.js +203 -0
- package/indesign/commands/35-parents.js +448 -0
- package/indesign/commands/37-layout.js +837 -0
- package/indesign/commands/40-frames.js +886 -0
- package/indesign/commands/41-shapes.js +505 -0
- package/indesign/commands/42-groups.js +117 -0
- package/indesign/commands/43-layers.js +310 -0
- package/indesign/commands/44-effects.js +274 -0
- package/indesign/commands/45-frame-options.js +247 -0
- package/indesign/commands/47-anchored.js +473 -0
- package/indesign/commands/50-modify.js +803 -0
- package/indesign/commands/52-align.js +139 -0
- package/indesign/commands/55-fit.js +106 -0
- package/indesign/commands/60-images.js +1154 -0
- package/indesign/commands/62-embed.js +120 -0
- package/indesign/commands/69-placeholders.js +132 -0
- package/indesign/commands/70-text.js +710 -0
- package/indesign/commands/71-outlines.js +92 -0
- package/indesign/commands/72-place-text.js +476 -0
- package/indesign/commands/73-story-lock.js +157 -0
- package/indesign/commands/74-stories.js +121 -0
- package/indesign/commands/75-tables.js +702 -0
- package/indesign/commands/76-text-variables.js +260 -0
- package/indesign/commands/77-story-options.js +86 -0
- package/indesign/commands/78-frame-lines.js +511 -0
- package/indesign/commands/79-check-typography.js +480 -0
- package/indesign/commands/80-styles.js +1960 -0
- package/indesign/commands/81-composition.js +355 -0
- package/indesign/commands/82-object-styles.js +263 -0
- package/indesign/commands/83-drop-caps.js +87 -0
- package/indesign/commands/83-indents-tabs.js +264 -0
- package/indesign/commands/84-import-styles.js +142 -0
- package/indesign/commands/85-swatches.js +112 -0
- package/indesign/commands/86-gradients.js +185 -0
- package/indesign/commands/87-replace-swatch.js +180 -0
- package/indesign/commands/88-replace-font.js +212 -0
- package/indesign/commands/89-toc-index.js +1002 -0
- package/indesign/commands/90-print-on-demand.js +495 -0
- package/indesign/commands/91-epub.js +629 -0
- package/indesign/commands/92-accessibility.js +1131 -0
- package/indesign/interpreter.js +829 -0
- package/package.json +41 -4
- package/rules/typography-rules.json +32 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Auftrag A-8.7 (Sitzung 9) – convert_text_to_outlines: Text eines Rahmens
|
|
3
|
+
* in Pfade umwandeln (unumkehrbar). Adobe-DOM (Auftrag, geprueft
|
|
4
|
+
* 05.09.2026): TextFrame.createOutlines(deleteOriginal) -> PageItem
|
|
5
|
+
* (Gruppe oder einzelnes Polygon; was InDesign bei mehreren Zeilen
|
|
6
|
+
* liefert: live pruefen, Journal).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* Schriften eines Rahmens: {family, style} je verwendeter Schrift (Reihenfolge des Auftretens). */
|
|
10
|
+
function idcFontsInFrame(frame) {
|
|
11
|
+
var out = [], seen = {}, ranges, i, run, font, key, family = null, style = null;
|
|
12
|
+
try { ranges = frame.parentStory.textStyleRanges; } catch (e0) { return out; }
|
|
13
|
+
for (i = 0; i < ranges.length; i++) {
|
|
14
|
+
try { run = ranges.item(i); } catch (e1) { continue; }
|
|
15
|
+
try { font = idcReadFontLoose(run); family = font.family; style = font.style; } catch (e2) { family = null; style = null; }
|
|
16
|
+
if (family === null) { continue; }
|
|
17
|
+
key = family + '\t' + (style === null ? '' : style);
|
|
18
|
+
if (IDC.hasOwn(seen, key)) { continue; }
|
|
19
|
+
seen[key] = 1;
|
|
20
|
+
out.push({ family: family, style: style });
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
IDC.register('convert_text_to_outlines', { needs_document: true, read_only: false, ruler: 'page' },
|
|
26
|
+
function (ctx) {
|
|
27
|
+
var args = ctx.args;
|
|
28
|
+
var doc = ctx.doc;
|
|
29
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
30
|
+
var frame = found.item;
|
|
31
|
+
var story = idcStoryOf(frame);
|
|
32
|
+
var deleteOriginal = args.delete_original !== false;
|
|
33
|
+
var characters = 0, frames = 0, result, concrete, type, memberCount = 0, fonts, landing, tables = 0, sourceId;
|
|
34
|
+
|
|
35
|
+
if (args.confirm !== true) {
|
|
36
|
+
IDC.fail('invalid_argument', 'convert_text_to_outlines is irreversible – pass confirm true to run it.', { frame_id: args.frame_id });
|
|
37
|
+
}
|
|
38
|
+
try { characters = Number(story.characters.length); } catch (e0) { characters = 0; }
|
|
39
|
+
if (characters === 0) {
|
|
40
|
+
IDC.fail('invalid_state', 'Text frame ' + args.frame_id + ' is empty; there is no text to convert.', { frame_id: args.frame_id });
|
|
41
|
+
}
|
|
42
|
+
try { frames = Number(story.textContainers.length); } catch (e1) { frames = 1; }
|
|
43
|
+
if (frames > 1) {
|
|
44
|
+
IDC.fail('invalid_state', 'Text frame ' + args.frame_id + ' is threaded (the story runs over ' + frames + ' frames); convert only unthreaded frames.', { frame_id: args.frame_id, frame_count: frames });
|
|
45
|
+
}
|
|
46
|
+
if (idcOverflows(frame) === true) {
|
|
47
|
+
IDC.fail('invalid_state', 'Text frame ' + args.frame_id + ' overflows; overset text would be lost. Enlarge the frame first.', { frame_id: args.frame_id });
|
|
48
|
+
}
|
|
49
|
+
try { tables = Number(story.tables.length); } catch (e2) { tables = 0; }
|
|
50
|
+
if (tables > 0) {
|
|
51
|
+
ctx.warn('The frame holds ' + tables + ' table(s); InDesign converts only the text, table cells may be dropped or changed – check the result.');
|
|
52
|
+
}
|
|
53
|
+
fonts = idcFontsInFrame(frame);
|
|
54
|
+
sourceId = Number(frame.id);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
result = frame.createOutlines(deleteOriginal);
|
|
58
|
+
} catch (e) {
|
|
59
|
+
IDC.fail('script_error', 'InDesign could not convert the text of frame ' + args.frame_id + ' to outlines: ' + String(e.message ? e.message : e), { frame_id: args.frame_id });
|
|
60
|
+
}
|
|
61
|
+
/* createOutlines liefert ein ExtendScript-Array (Live 05.09.2026), das IDC.isArray nicht erkennt – ueber Klassenname/length pruefen wie bei get_selection. */
|
|
62
|
+
if (IDC.isArray(result) || IDC.className(result) === 'Array' || (result && typeof result.length === 'number' && result.id === undefined)) {
|
|
63
|
+
result = result.length > 0 ? result[0] : null;
|
|
64
|
+
}
|
|
65
|
+
if (result === null || result === undefined) {
|
|
66
|
+
IDC.fail('script_error', 'InDesign returned no object after converting the text to outlines.', { frame_id: args.frame_id });
|
|
67
|
+
}
|
|
68
|
+
concrete = IDC.concrete(result);
|
|
69
|
+
type = IDC.itemType(concrete);
|
|
70
|
+
if (type === 'group') {
|
|
71
|
+
try { memberCount = Number(concrete.pageItems.length); } catch (e3) { memberCount = null; }
|
|
72
|
+
} else {
|
|
73
|
+
memberCount = 1;
|
|
74
|
+
}
|
|
75
|
+
landing = IDC.landing(concrete);
|
|
76
|
+
ctx.warn('The text is now outlines: it can no longer be searched or edited as text, and the fonts ' + (fonts.length > 0 ? '(' + (function () { var n = [], i; for (i = 0; i < fonts.length; i++) { n.push(fonts[i].family + (fonts[i].style ? ' ' + fonts[i].style : '')); } return n.join(', '); })() + ') ' : '') + 'are no longer needed for it.');
|
|
77
|
+
var changes = { created_frame_ids: [Number(concrete.id)] };
|
|
78
|
+
if (deleteOriginal) { changes.removed_frame_ids = [sourceId]; }
|
|
79
|
+
ctx.changes = changes;
|
|
80
|
+
return {
|
|
81
|
+
frame_id: Number(concrete.id),
|
|
82
|
+
type: type,
|
|
83
|
+
member_count: memberCount,
|
|
84
|
+
bounds_mm: idcItemBounds(doc, concrete),
|
|
85
|
+
page_id: landing.page_id,
|
|
86
|
+
page_name: landing.page_name,
|
|
87
|
+
source_frame_id: sourceId,
|
|
88
|
+
source_deleted: deleteOriginal,
|
|
89
|
+
characters_converted: characters,
|
|
90
|
+
fonts_used: fonts
|
|
91
|
+
};
|
|
92
|
+
});
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
/* Wunschliste J2 Nr. 15 (Sitzung 7) – Manuskript einfliessen lassen: place_text_file. */
|
|
2
|
+
|
|
3
|
+
/* Namen aller Absatzformate (auch in Gruppen) als Nachschlagetabelle. */
|
|
4
|
+
function idcParagraphStyleNames(doc) {
|
|
5
|
+
var names = {};
|
|
6
|
+
var all, i;
|
|
7
|
+
try {
|
|
8
|
+
all = doc.allParagraphStyles;
|
|
9
|
+
for (i = 0; i < all.length; i++) { names[String(all[i].name)] = true; }
|
|
10
|
+
} catch (e) { /* leer */ }
|
|
11
|
+
return names;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* Vorgaben eines Einstellungsobjekts merken, setzen und zurueckstellen. */
|
|
15
|
+
function idcWithPreferences(ctx, prefs, values, fn) {
|
|
16
|
+
var saved = {};
|
|
17
|
+
var key;
|
|
18
|
+
if (prefs === null || prefs === undefined) { return fn(); }
|
|
19
|
+
for (key in values) {
|
|
20
|
+
if (!IDC.hasOwn(values, key) || values[key] === null || values[key] === undefined) { continue; }
|
|
21
|
+
try { saved[key] = prefs[key]; } catch (e0) { continue; }
|
|
22
|
+
try { prefs[key] = values[key]; } catch (e1) { ctx.warn('Could not set import preference ' + key + ': ' + String(e1.message ? e1.message : e1)); }
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
return fn();
|
|
26
|
+
} finally {
|
|
27
|
+
for (key in saved) {
|
|
28
|
+
if (IDC.hasOwn(saved, key)) {
|
|
29
|
+
try { prefs[key] = saved[key]; } catch (e2) { ctx.warn('Could not restore import preference ' + key + '.'); }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* A-67 Punkt 2 (Sitzung 72): bis 1.0.3 hoechstens 200 Seiten je Aufruf; ein Roman mit gut 300 Seiten brach ab. */
|
|
36
|
+
var IDC_AUTOFLOW_MAX_PAGES = 2000;
|
|
37
|
+
|
|
38
|
+
IDC.register('place_text_file', { needs_document: true, read_only: false, ruler: 'none' },
|
|
39
|
+
function (ctx) {
|
|
40
|
+
var args = ctx.args;
|
|
41
|
+
var doc = ctx.doc;
|
|
42
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
43
|
+
var frame = found.item;
|
|
44
|
+
var story = idcStoryOf(frame);
|
|
45
|
+
var path = args.file_path;
|
|
46
|
+
var mode = args.mode === undefined || args.mode === null ? 'replace' : args.mode;
|
|
47
|
+
var retain = args.retain_formatting === true;
|
|
48
|
+
var styleMap = args.style_map === undefined || args.style_map === null ? null : args.style_map;
|
|
49
|
+
var styleName = args.paragraph_style === undefined || args.paragraph_style === null ? null : args.paragraph_style;
|
|
50
|
+
var typographersQuotes = args.typographers_quotes !== false;
|
|
51
|
+
var pageBreaks = args.page_breaks === undefined || args.page_breaks === null ? 'none' : args.page_breaks;
|
|
52
|
+
var file, ext, isWord, isText, lengthBefore = 0, lengthAfter = 0, insertAt, namesBefore, namesAfter, added = [];
|
|
53
|
+
var key, target, targetStyle, targets = {}, mapped = {}, placedRange, paragraphs, i, p, name, count = 0, insertion;
|
|
54
|
+
|
|
55
|
+
if (typeof path !== 'string' || path === '') {
|
|
56
|
+
IDC.fail('invalid_argument', 'file_path is required: a .docx, .doc, .rtf or .txt file on the machine running InDesign.', null);
|
|
57
|
+
}
|
|
58
|
+
if (mode !== 'replace' && mode !== 'append') {
|
|
59
|
+
IDC.fail('invalid_argument', 'mode must be replace (default) or append.', { mode: mode });
|
|
60
|
+
}
|
|
61
|
+
if (pageBreaks !== 'none' && pageBreaks !== 'page_break' && pageBreaks !== 'column_break') {
|
|
62
|
+
IDC.fail('invalid_argument', 'page_breaks must be none (default), page_break or column_break.', { page_breaks: pageBreaks });
|
|
63
|
+
}
|
|
64
|
+
var autoflow = args.autoflow === true;
|
|
65
|
+
var maxPages = idcCountArg(args.max_pages, 'max_pages', 1, IDC_AUTOFLOW_MAX_PAGES, 20);
|
|
66
|
+
/* Sitzung 10 (Demo-Heft-Befund 1): der Autofluss springt auf die neue Seite; Ansicht merken. */
|
|
67
|
+
var keepView = idcKeepViewArg(args);
|
|
68
|
+
var view = null, viewRestored = null;
|
|
69
|
+
ext = (path.match(/\.([A-Za-z0-9]+)$/) || ['', ''])[1].toLowerCase();
|
|
70
|
+
isWord = ext === 'docx' || ext === 'doc' || ext === 'rtf';
|
|
71
|
+
isText = ext === 'txt' || ext === 'text' || ext === 'md';
|
|
72
|
+
if (!isWord && !isText) {
|
|
73
|
+
IDC.fail('invalid_argument', 'file_path must end in .docx, .doc, .rtf or .txt (got .' + ext + ').', { file_path: path });
|
|
74
|
+
}
|
|
75
|
+
file = IDC.fileFor(path);
|
|
76
|
+
if (!file.exists) {
|
|
77
|
+
IDC.fail('not_found', 'File not found: ' + path, { file_path: path });
|
|
78
|
+
}
|
|
79
|
+
if (IDC.fileSize(file) === 0) {
|
|
80
|
+
IDC.fail('io_error', 'File is empty (0 bytes) – a cloud placeholder that is not downloaded yet? ' + path, { file_path: path });
|
|
81
|
+
}
|
|
82
|
+
idcRejectStoryLocked(story, Number(frame.id), 'place_text_file');
|
|
83
|
+
if (styleMap !== null) {
|
|
84
|
+
if (typeof styleMap !== 'object' || IDC.isArray(styleMap)) {
|
|
85
|
+
IDC.fail('invalid_argument', 'style_map must be an object { "Word style name": "InDesign style name" }.', null);
|
|
86
|
+
}
|
|
87
|
+
for (key in styleMap) {
|
|
88
|
+
if (!IDC.hasOwn(styleMap, key)) { continue; }
|
|
89
|
+
target = styleMap[key];
|
|
90
|
+
if (typeof target !== 'string' || target === '') {
|
|
91
|
+
IDC.fail('invalid_argument', 'style_map values must be style names.', { key: key, value: target });
|
|
92
|
+
}
|
|
93
|
+
targetStyle = IDC.paragraphStyleByName(doc, target);
|
|
94
|
+
if (targetStyle === null) {
|
|
95
|
+
IDC.fail('not_found', 'Paragraph style "' + target + '" (target of style_map "' + key + '") does not exist.', { style_name: target });
|
|
96
|
+
}
|
|
97
|
+
targets[key] = targetStyle;
|
|
98
|
+
}
|
|
99
|
+
retain = true;
|
|
100
|
+
}
|
|
101
|
+
if (styleName !== null) {
|
|
102
|
+
targetStyle = IDC.paragraphStyleByName(doc, styleName);
|
|
103
|
+
if (targetStyle === null) {
|
|
104
|
+
IDC.fail('not_found', 'Paragraph style "' + styleName + '" not found.', { style_name: styleName });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try { lengthBefore = Number(story.characters.length); } catch (e0) { lengthBefore = 0; }
|
|
109
|
+
namesBefore = idcParagraphStyleNames(doc);
|
|
110
|
+
|
|
111
|
+
if (mode === 'replace' && lengthBefore > 0) {
|
|
112
|
+
try { story.contents = ''; } catch (e1) {
|
|
113
|
+
IDC.fail('script_error', 'Could not clear the story before placing: ' + String(e1.message ? e1.message : e1), { frame_id: args.frame_id });
|
|
114
|
+
}
|
|
115
|
+
lengthBefore = 0;
|
|
116
|
+
}
|
|
117
|
+
insertAt = lengthBefore;
|
|
118
|
+
|
|
119
|
+
var wordValues = {
|
|
120
|
+
removeFormatting: !retain,
|
|
121
|
+
preserveLocalOverrides: retain,
|
|
122
|
+
importUnusedStyles: false,
|
|
123
|
+
useTypographersQuotes: typographersQuotes,
|
|
124
|
+
preserveGraphics: false,
|
|
125
|
+
preserveTrackChanges: false,
|
|
126
|
+
importFootnotes: true,
|
|
127
|
+
importEndnotes: true,
|
|
128
|
+
importIndex: false,
|
|
129
|
+
importTOC: false
|
|
130
|
+
};
|
|
131
|
+
if (typeof ResolveStyleClash !== 'undefined') {
|
|
132
|
+
wordValues.resolveParagraphStyleClash = ResolveStyleClash.RESOLVE_CLASH_USE_EXISTING;
|
|
133
|
+
wordValues.resolveCharacterStyleClash = ResolveStyleClash.RESOLVE_CLASH_USE_EXISTING;
|
|
134
|
+
}
|
|
135
|
+
/*
|
|
136
|
+
* A-67 Punkt 5 (Sitzung 72): bis 1.0.3 immer NONE – Seiten- und
|
|
137
|
+
* Spaltenumbrueche aus Word fielen weg, eine Titelei stand auf einer
|
|
138
|
+
* Seite. InDesigns eigene Vorgabe ist PAGE_BREAK (Live-Probe 28.10.2026);
|
|
139
|
+
* page_breaks waehlt, Vorgabe bleibt none (E-79).
|
|
140
|
+
*/
|
|
141
|
+
if (typeof ConvertPageBreaks !== 'undefined') {
|
|
142
|
+
wordValues.convertPageBreaks = pageBreaks === 'page_break' ? ConvertPageBreaks.PAGE_BREAK : ConvertPageBreaks.NONE;
|
|
143
|
+
if (pageBreaks === 'column_break') { wordValues.convertPageBreaks = ConvertPageBreaks.COLUMN_BREAK; }
|
|
144
|
+
}
|
|
145
|
+
var textValues = { useTypographersQuotes: typographersQuotes, stripReturnsBetweenLines: false, stripReturnsBetweenParagraphs: false };
|
|
146
|
+
if (typeof TextImportCharacterSet !== 'undefined') { textValues.characterSet = TextImportCharacterSet.UTF8; }
|
|
147
|
+
|
|
148
|
+
var prefs = null;
|
|
149
|
+
try { prefs = isWord ? app.wordRTFImportPreferences : app.textImportPreferences; } catch (e2) { prefs = null; }
|
|
150
|
+
|
|
151
|
+
idcWithPreferences(ctx, prefs, isWord ? wordValues : textValues, function () {
|
|
152
|
+
try {
|
|
153
|
+
insertion = story.insertionPoints.item(story.insertionPoints.length - 1);
|
|
154
|
+
placedRange = insertion.place(file);
|
|
155
|
+
} catch (e3) {
|
|
156
|
+
IDC.fail('io_error', 'InDesign could not place ' + path + ': ' + String(e3.message ? e3.message : e3), { file_path: path, frame_id: args.frame_id });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
try { lengthAfter = Number(story.characters.length); } catch (e4) { lengthAfter = lengthBefore; }
|
|
161
|
+
namesAfter = idcParagraphStyleNames(doc);
|
|
162
|
+
for (name in namesAfter) {
|
|
163
|
+
if (IDC.hasOwn(namesAfter, name) && !namesBefore[name]) { added.push(name); }
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* Absatzformate: erst die Zuordnung Word -> Haus, dann ein Format ueber alles Platzierte. */
|
|
167
|
+
/*
|
|
168
|
+
* Ueber story.paragraphs mit Zeichenzaehlung – characters.itemByRange(...)
|
|
169
|
+
* .paragraphs lieferte am lebenden InDesign 21.5 eine leere Sammlung
|
|
170
|
+
* (Live-Fund 05.09.2026), deshalb wurde nichts zugeordnet.
|
|
171
|
+
*/
|
|
172
|
+
try {
|
|
173
|
+
if (lengthAfter > insertAt) {
|
|
174
|
+
paragraphs = story.paragraphs;
|
|
175
|
+
var position = 0, plen;
|
|
176
|
+
for (i = 0; i < paragraphs.length; i++) {
|
|
177
|
+
p = paragraphs.item(i);
|
|
178
|
+
try { plen = Number(p.characters.length); } catch (ep) { plen = 0; }
|
|
179
|
+
if (position + plen <= insertAt) { position += plen; continue; }
|
|
180
|
+
position += plen;
|
|
181
|
+
count += 1;
|
|
182
|
+
if (styleMap !== null) {
|
|
183
|
+
name = idcParagraphStyleName(p);
|
|
184
|
+
if (name !== null && IDC.hasOwn(targets, name)) {
|
|
185
|
+
p.appliedParagraphStyle = targets[name];
|
|
186
|
+
mapped[name] = (mapped[name] || 0) + 1;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (styleName !== null) { p.appliedParagraphStyle = targetStyle; }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} catch (e5) {
|
|
193
|
+
ctx.warn('The text was placed, but the paragraph styles could not be applied: ' + String(e5.message ? e5.message : e5));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/*
|
|
197
|
+
* Zugeordnete Word-Formate wieder entfernen: sie kamen erst mit diesem
|
|
198
|
+
* Import und sind nach der Zuordnung an keinem Absatz mehr in Gebrauch.
|
|
199
|
+
* remove(ersatz) haengt eventuelle Reste an das Zielformat.
|
|
200
|
+
*/
|
|
201
|
+
var removed = [];
|
|
202
|
+
if (styleMap !== null) {
|
|
203
|
+
var remaining = [];
|
|
204
|
+
for (i = 0; i < added.length; i++) {
|
|
205
|
+
name = added[i];
|
|
206
|
+
if (IDC.hasOwn(targets, name)) {
|
|
207
|
+
try {
|
|
208
|
+
var stray = IDC.paragraphStyleByName(doc, name);
|
|
209
|
+
if (stray !== null) { stray.remove(targets[name]); removed.push(name); continue; }
|
|
210
|
+
} catch (e8) { ctx.warn('Imported style "' + name + '" could not be removed: ' + String(e8.message ? e8.message : e8)); }
|
|
211
|
+
}
|
|
212
|
+
remaining.push(name);
|
|
213
|
+
}
|
|
214
|
+
added = remaining;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
var overset = null;
|
|
218
|
+
try {
|
|
219
|
+
var containers = story.textContainers;
|
|
220
|
+
overset = containers[containers.length - 1].overflows === true;
|
|
221
|
+
} catch (e6) { try { overset = story.overflows === true; } catch (e7) { overset = null; } }
|
|
222
|
+
var flow = null;
|
|
223
|
+
if (overset === true && autoflow) {
|
|
224
|
+
if (keepView) { view = idcCaptureView(doc); }
|
|
225
|
+
flow = idcAutoflow(ctx, doc, story, maxPages);
|
|
226
|
+
overset = flow.overset;
|
|
227
|
+
if (view !== null) { viewRestored = view.window === null ? null : idcRestoreView(view); }
|
|
228
|
+
}
|
|
229
|
+
if (overset === true) {
|
|
230
|
+
ctx.warn('The story overflows (Uebersatz) after placing – ' + (autoflow ? 'autoflow stopped at max_pages ' + maxPages + '; raise it or shorten the text.' : 'thread more frames, pass autoflow true, or shorten the text.'));
|
|
231
|
+
}
|
|
232
|
+
if (added.length > 0) {
|
|
233
|
+
ctx.warn('The import added ' + added.length + ' paragraph style(s): ' + added.join(', ') + '.');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
ctx.changes = { modified_frame_ids: [Number(frame.id)], modified_story_ids: [Number(story.id)] };
|
|
237
|
+
if (flow !== null && flow.frames_added.length > 0) {
|
|
238
|
+
ctx.changes.created_frame_ids = [];
|
|
239
|
+
ctx.changes.created_page_ids = [];
|
|
240
|
+
for (i = 0; i < flow.frames_added.length; i++) { ctx.changes.created_frame_ids.push(flow.frames_added[i].frame_id); }
|
|
241
|
+
for (i = 0; i < flow.pages_added.length; i++) { ctx.changes.created_page_ids.push(flow.pages_added[i].page_id); }
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
frame_id: Number(frame.id),
|
|
245
|
+
story_id: Number(story.id),
|
|
246
|
+
file_name: String(path).replace(/^.*[\/\\]/, ''),
|
|
247
|
+
mode: mode,
|
|
248
|
+
retain_formatting: retain,
|
|
249
|
+
placed_start_index: insertAt,
|
|
250
|
+
placed_end_index: lengthAfter,
|
|
251
|
+
inserted_chars: lengthAfter - insertAt,
|
|
252
|
+
story_length: lengthAfter,
|
|
253
|
+
paragraph_count: count,
|
|
254
|
+
styles_added: added,
|
|
255
|
+
styles_mapped: mapped,
|
|
256
|
+
styles_removed: removed,
|
|
257
|
+
paragraph_style_applied: styleName,
|
|
258
|
+
page_breaks: isWord ? pageBreaks : null,
|
|
259
|
+
overset: overset,
|
|
260
|
+
autoflow: flow,
|
|
261
|
+
view_restored: viewRestored
|
|
262
|
+
};
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
/*
|
|
266
|
+
* A-67 Punkt 2 (Sitzung 72): Autofluss fuer eine Story, die schon im
|
|
267
|
+
* Dokument steht – ohne Datei. Bis 1.0.3 ging das nur ueber eine Datei mit
|
|
268
|
+
* einem Leerzeichen per place_text_file mode append. Gleiche Seiten, Rahmen
|
|
269
|
+
* und Rueckgabe autoflow {...} wie place_text_file.
|
|
270
|
+
*/
|
|
271
|
+
IDC.register('autoflow_story', { needs_document: true, read_only: false, ruler: 'none' },
|
|
272
|
+
function (ctx) {
|
|
273
|
+
var args = ctx.args;
|
|
274
|
+
var doc = ctx.doc;
|
|
275
|
+
var found = idcTextFrameArg(doc, args, 'frame_id');
|
|
276
|
+
var frame = found.item;
|
|
277
|
+
var story = idcStoryOf(frame);
|
|
278
|
+
var maxPages = idcCountArg(args.max_pages, 'max_pages', 1, IDC_AUTOFLOW_MAX_PAGES, 20);
|
|
279
|
+
var keepView = idcKeepViewArg(args);
|
|
280
|
+
var view = null, viewRestored = null, flow, overset = null, containers, i;
|
|
281
|
+
|
|
282
|
+
idcRejectStoryLocked(story, Number(frame.id), 'autoflow_story');
|
|
283
|
+
try {
|
|
284
|
+
containers = story.textContainers;
|
|
285
|
+
overset = containers[containers.length - 1].overflows === true;
|
|
286
|
+
} catch (e0) { try { overset = story.overflows === true; } catch (e1) { overset = null; } }
|
|
287
|
+
if (overset !== true) {
|
|
288
|
+
flow = { pages_added: [], frames_added: [], overset: overset === null ? null : false, stopped: 'fits' };
|
|
289
|
+
} else {
|
|
290
|
+
if (keepView) { view = idcCaptureView(doc); }
|
|
291
|
+
flow = idcAutoflow(ctx, doc, story, maxPages);
|
|
292
|
+
overset = flow.overset;
|
|
293
|
+
if (view !== null) { viewRestored = view.window === null ? null : idcRestoreView(view); }
|
|
294
|
+
}
|
|
295
|
+
if (overset === true) {
|
|
296
|
+
ctx.warn('The story still overflows (Uebersatz) – autoflow stopped at max_pages ' + maxPages + '; call again or raise max_pages.');
|
|
297
|
+
}
|
|
298
|
+
ctx.changes = { modified_frame_ids: [Number(frame.id)], modified_story_ids: [Number(story.id)] };
|
|
299
|
+
if (flow.frames_added.length > 0) {
|
|
300
|
+
ctx.changes.created_frame_ids = [];
|
|
301
|
+
ctx.changes.created_page_ids = [];
|
|
302
|
+
for (i = 0; i < flow.frames_added.length; i++) { ctx.changes.created_frame_ids.push(flow.frames_added[i].frame_id); }
|
|
303
|
+
for (i = 0; i < flow.pages_added.length; i++) { ctx.changes.created_page_ids.push(flow.pages_added[i].page_id); }
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
frame_id: Number(frame.id),
|
|
307
|
+
story_id: Number(story.id),
|
|
308
|
+
overset: overset === null ? null : overset === true,
|
|
309
|
+
autoflow: flow,
|
|
310
|
+
view_restored: viewRestored
|
|
311
|
+
};
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
/*
|
|
315
|
+
* Autoflow: solange die Story ueberlaeuft, hinter der Seite des letzten
|
|
316
|
+
* Rahmens eine Seite (gleiche Musterseite) anlegen, darauf einen Rahmen mit
|
|
317
|
+
* den Massen und Rahmenoptionen des letzten anlegen und verketten.
|
|
318
|
+
*/
|
|
319
|
+
function idcAutoflow(ctx, doc, story, maxPages) {
|
|
320
|
+
var out = { pages_added: [], frames_added: [], overset: true, stopped: '' };
|
|
321
|
+
var round, containers, last = null, page, rect, newPage, newFrame, prefsCopied, copied, placed;
|
|
322
|
+
for (round = 0; round < maxPages; round++) {
|
|
323
|
+
/*
|
|
324
|
+
* Der letzte Rahmen ist ab der zweiten Runde der eben angehaengte –
|
|
325
|
+
* textContainers waechst mit jeder Seite und wird nur einmal gelesen
|
|
326
|
+
* (A-67 Punkt 2, bis zu 2000 Seiten je Aufruf).
|
|
327
|
+
*/
|
|
328
|
+
if (last === null) {
|
|
329
|
+
try {
|
|
330
|
+
containers = story.textContainers;
|
|
331
|
+
last = IDC.concrete(containers[containers.length - 1]);
|
|
332
|
+
} catch (e0) { out.stopped = 'last frame unreadable'; return out; }
|
|
333
|
+
}
|
|
334
|
+
try { if (last.overflows !== true) { out.overset = false; out.stopped = 'fits'; return out; } } catch (e1) { /* weiter */ }
|
|
335
|
+
page = null;
|
|
336
|
+
try { page = last.parentPage; } catch (e2) { page = null; }
|
|
337
|
+
if (page === null || page === undefined || page.isValid !== true) {
|
|
338
|
+
IDC.fail('invalid_state', 'Autoflow needs the last frame on a document page (it lies on the pasteboard or a parent page).', null);
|
|
339
|
+
}
|
|
340
|
+
if (IDC.isOnParentSpread(last)) {
|
|
341
|
+
IDC.fail('invalid_state', 'Autoflow does not run on parent pages.', null);
|
|
342
|
+
}
|
|
343
|
+
rect = IDC.boundsOnPage(doc, last, page);
|
|
344
|
+
try {
|
|
345
|
+
newPage = doc.pages.add(LocationOptions.AFTER, page);
|
|
346
|
+
} catch (e3) {
|
|
347
|
+
IDC.fail('script_error', 'Autoflow could not add a page: ' + String(e3.message ? e3.message : e3), null);
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
if (page.appliedMaster && page.appliedMaster.isValid === true) { newPage.appliedMaster = page.appliedMaster; }
|
|
351
|
+
} catch (e4) { /* Vorgabe bleibt */ }
|
|
352
|
+
placed = idcAutoflowRect(doc, rect, page, newPage);
|
|
353
|
+
rect = placed.rect;
|
|
354
|
+
newFrame = idcAddItem(doc, newPage, 'textFrames', idcRectToBounds(rect), 'page');
|
|
355
|
+
/*
|
|
356
|
+
* Rahmenoptionen einzeln kopieren (Demo-Heft-Befund 4, 05.09.2026): die
|
|
357
|
+
* Zuweisung von textFramePreferences.properties liess am lebenden
|
|
358
|
+
* InDesign die Spalten des Ausgangsrahmens weg (neuer Rahmen einspaltig).
|
|
359
|
+
*/
|
|
360
|
+
copied = idcCopyTextFramePreferences(last, newFrame);
|
|
361
|
+
prefsCopied = copied.failed.length === 0;
|
|
362
|
+
try { newFrame.itemLayer = last.itemLayer; } catch (e6) { /* aktive Ebene */ }
|
|
363
|
+
try {
|
|
364
|
+
last.nextTextFrame = newFrame;
|
|
365
|
+
} catch (e7) {
|
|
366
|
+
IDC.fail('script_error', 'Autoflow could not thread the new frame: ' + String(e7.message ? e7.message : e7), { page_id: Number(newPage.id) });
|
|
367
|
+
}
|
|
368
|
+
out.pages_added.push({ page_id: Number(newPage.id), page_name: String(newPage.name) });
|
|
369
|
+
out.frames_added.push({
|
|
370
|
+
frame_id: Number(newFrame.id),
|
|
371
|
+
page_id: Number(newPage.id),
|
|
372
|
+
bounds_mm: rect,
|
|
373
|
+
placement: placed.placement,
|
|
374
|
+
frame_options_copied: prefsCopied,
|
|
375
|
+
frame_options_failed: copied.failed,
|
|
376
|
+
frame_options_skipped: copied.skipped,
|
|
377
|
+
columns: idcReadColumnsOf(newFrame)
|
|
378
|
+
});
|
|
379
|
+
last = newFrame;
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
containers = story.textContainers;
|
|
383
|
+
last = IDC.concrete(containers[containers.length - 1]);
|
|
384
|
+
out.overset = last.overflows === true;
|
|
385
|
+
} catch (e8) { out.overset = true; }
|
|
386
|
+
out.stopped = out.overset ? 'max_pages' : 'fits';
|
|
387
|
+
return out;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/*
|
|
391
|
+
* Lage des neuen Autoflow-Rahmens (A-43 Nr. 5, KDP-Befund 3): Bei
|
|
392
|
+
* Doppelseiten wechselt die Seite die Seite des Bundes. Fuellt der letzte
|
|
393
|
+
* Rahmen den Satzspiegel seiner Seite, kommt der neue in den Satzspiegel der
|
|
394
|
+
* neuen Seite ('type_area'); sonst wird er am Bund gespiegelt – gleicher
|
|
395
|
+
* Abstand zum Bund wie vorher ('mirrored'). Gleiche Seite des Bundes oder
|
|
396
|
+
* Einzelseiten: Masse unveraendert ('same'). Bis 1.0.1 bekam eine linke Seite
|
|
397
|
+
* die Koordinaten der rechten Startseite (Bundsteg und Aussensteg vertauscht).
|
|
398
|
+
*/
|
|
399
|
+
function idcAutoflowRect(doc, rect, fromPage, toPage) {
|
|
400
|
+
var fromSide = IDC.pageSide(fromPage);
|
|
401
|
+
var toSide = IDC.pageSide(toPage);
|
|
402
|
+
var fromArea, toArea, fromWidth, toWidth, inside, x;
|
|
403
|
+
if (!idcFacing(doc) || fromSide === 'SINGLE_SIDED' || toSide === 'SINGLE_SIDED' || fromSide === toSide) {
|
|
404
|
+
return { rect: rect, placement: 'same' };
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
fromArea = idcDescribeGrid(fromPage, false, true).type_area_mm;
|
|
408
|
+
toArea = idcDescribeGrid(toPage, false, true).type_area_mm;
|
|
409
|
+
if (Math.abs(rect.x - fromArea.x) <= 0.05 && Math.abs(rect.y - fromArea.y) <= 0.05
|
|
410
|
+
&& Math.abs(rect.width - fromArea.width) <= 0.05 && Math.abs(rect.height - fromArea.height) <= 0.05
|
|
411
|
+
&& toArea.width > 0 && toArea.height > 0) {
|
|
412
|
+
return { rect: { x: toArea.x, y: toArea.y, width: toArea.width, height: toArea.height }, placement: 'type_area' };
|
|
413
|
+
}
|
|
414
|
+
} catch (e0) { /* dann spiegeln */ }
|
|
415
|
+
fromWidth = IDC.pageSize(fromPage).width;
|
|
416
|
+
toWidth = IDC.pageSize(toPage).width;
|
|
417
|
+
inside = fromSide === 'RIGHT_HAND' ? rect.x : fromWidth - rect.x - rect.width;
|
|
418
|
+
x = toSide === 'RIGHT_HAND' ? inside : toWidth - inside - rect.width;
|
|
419
|
+
return { rect: { x: IDC.round(x), y: rect.y, width: rect.width, height: rect.height }, placement: 'mirrored' };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/*
|
|
423
|
+
* Rahmenoptionen eines Textrahmens auf einen anderen uebertragen – Wert fuer
|
|
424
|
+
* Wert, in der Reihenfolge, die InDesign verlangt (erst die Spaltenart, dann
|
|
425
|
+
* Zahl, Steg und feste Breite). Liefert copied[] und failed[] (Eigenschaft
|
|
426
|
+
* samt Meldung); Eigenschaften, die die Laufzeit nicht kennt, zaehlen nicht.
|
|
427
|
+
*/
|
|
428
|
+
/* Adobe-DOM TextFramePreference (geprueft 05.09.2026): alle schreibbar. Automatische Groesse und Spaltenlinien bleiben Vorgabe. */
|
|
429
|
+
var IDC_TEXT_FRAME_PREFS = [
|
|
430
|
+
'useFixedColumnWidth', 'useFlexibleColumnWidth', 'textColumnCount', 'textColumnGutter', 'textColumnFixedWidth',
|
|
431
|
+
'textColumnMaxWidth', 'insetSpacing', 'verticalJustification', 'verticalThreshold', 'firstBaselineOffset',
|
|
432
|
+
'minimumFirstBaselineOffset', 'ignoreWrap', 'verticalBalanceColumns'
|
|
433
|
+
];
|
|
434
|
+
|
|
435
|
+
function idcCopyTextFramePreferences(source, target) {
|
|
436
|
+
var out = { copied: [], skipped: [], failed: [] };
|
|
437
|
+
var from, to, i, key, value, justified = false, fixedWidth = false, flexibleWidth = false;
|
|
438
|
+
try { from = source.textFramePreferences; to = target.textFramePreferences; } catch (e0) {
|
|
439
|
+
out.failed.push({ property: 'textFramePreferences', message: String(e0.message ? e0.message : e0) });
|
|
440
|
+
return out;
|
|
441
|
+
}
|
|
442
|
+
/*
|
|
443
|
+
* Live-Fund 05.09.2026: verticalThreshold laesst sich nur setzen, wenn der
|
|
444
|
+
* Rahmen vertikal im Blocksatz steht ("Diese Eigenschaft ist im aktuellen
|
|
445
|
+
* Status nicht zutreffend."); die festen/flexiblen Spaltenbreiten gelten nur
|
|
446
|
+
* bei der jeweiligen Spaltenart. Was nicht zutrifft, wird uebersprungen.
|
|
447
|
+
*/
|
|
448
|
+
try { justified = typeof VerticalJustification !== 'undefined' && IDC.enumIs(from.verticalJustification, VerticalJustification.JUSTIFY_ALIGN); } catch (ej) { justified = false; }
|
|
449
|
+
try { fixedWidth = from.useFixedColumnWidth === true; } catch (ef) { fixedWidth = false; }
|
|
450
|
+
try { flexibleWidth = from.useFlexibleColumnWidth === true; } catch (ex) { flexibleWidth = false; }
|
|
451
|
+
for (i = 0; i < IDC_TEXT_FRAME_PREFS.length; i++) {
|
|
452
|
+
key = IDC_TEXT_FRAME_PREFS[i];
|
|
453
|
+
if ((key === 'verticalThreshold' && !justified) || (key === 'textColumnFixedWidth' && !fixedWidth) || (key === 'textColumnMaxWidth' && !flexibleWidth)) {
|
|
454
|
+
out.skipped.push(key);
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
try { value = from[key]; } catch (e1) { continue; }
|
|
458
|
+
if (value === undefined) { continue; }
|
|
459
|
+
if (IDC.isArray(value)) { value = value.slice(0); }
|
|
460
|
+
try {
|
|
461
|
+
to[key] = value;
|
|
462
|
+
out.copied.push(key);
|
|
463
|
+
} catch (e2) {
|
|
464
|
+
out.failed.push({ property: key, message: String(e2.message ? e2.message : e2) });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return out;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* Spalten eines Textrahmens zum Gegenlesen: {count, gutter_mm}. */
|
|
471
|
+
function idcReadColumnsOf(frame) {
|
|
472
|
+
var out = { count: null, gutter_mm: null };
|
|
473
|
+
try { out.count = Number(frame.textFramePreferences.textColumnCount); } catch (e0) { /* bleibt null */ }
|
|
474
|
+
try { out.gutter_mm = IDC.round(Number(frame.textFramePreferences.textColumnGutter)); } catch (e1) { /* bleibt null */ }
|
|
475
|
+
return out;
|
|
476
|
+
}
|