【InDesign】親ページを一括で指定するスクリプト
昨日このようなnoteを書きました。
note.com
これと関連するというか、この後の処理で親ページを割り当てる作業があると思います。
このときに親ページが5つあったとしたら、5回も"親ページを適用"をしなくてはならず、なかなか面倒です。

今回は、これを一括指定できるスクリプトをGeminiと相談して作りました。
4年前にはこんなものも作っていましたが、使いづらくて使っていませんでしたw
p-makes-p.hatenablog.com
生成AIもだいぶ進化しているのでしょうね。Geminiとのやり取りの回数もだいぶ減ったと思います。
まずスクリプトを実行すると図のような画面が出ます。

画面左側には親ページの名前が表示されます。そしてその横の空欄には適用したいページを入力します。
こんな感じで入力すれば、入力したとおりに親ページを適用してくれます。

入力されなかったページは親ページ[なし]のままです。

あと、親ページが8個以上の場合は右側にスクロールバーが出るようにしました。

また、既に親ページが適用されているドキュメントに対しては、このスクリプトを実行すると、現在どのページにどの親ページが当たっているかが表示されます。

この状態で[適用]を押すと、再度新たに親ページを当て直してしまうのでご注意ください。
確認するだけならそのまま[キャンセル]です。
お~まちさんからご指摘をいただき、ここは修正しました。
すでに設定したい親ページが適用されている場合は、再適用せずに、処理をスキップします。
一部だけ割り当てる親ページを変更したいという場合には、標準機能の[親ページを適用]を使った方がよいと思います。
もしよかったら使ってみてください。
drive.google.com
/* * Quick Master Assigner(親ページを一括指定するスクリプト) * 制作:制作課長くれそん * 制作日:2026年7月29日 * * 【免責事項】 * 本スクリプトの使用により生じた損害等について、制作者は一切の責任を負いません。 * 必ず自己責任においてご使用・テストを行ってください。 */ #target indesign (function() { // 1. ドキュメントの存在確認 if (app.documents.length === 0) { alert("ドキュメントが開かれていません。"); return; } var doc = app.activeDocument; var totalPages = doc.pages.length; var masters = doc.masterSpreads; if (masters.length === 0) { alert("適用できる親ページ(マスタースプレッド)がありません。"); return; } var noneMaster = NothingEnum.NOTHING; // --- 補助関数: 配列 [1,2,3, 5,6, 8] を "1-3, 5-6, 8" 文字列に変換 --- function pagesToRangeString(pageList) { if (!pageList || pageList.length === 0) return ""; pageList.sort(function(a, b) { return a - b; }); var ranges = []; var rangeStart = pageList[0]; var prev = pageList[0]; for (var i = 1; i < pageList.length; i++) { var curr = pageList[i]; if (curr === prev + 1) { prev = curr; } else { if (rangeStart === prev) { ranges.push(rangeStart.toString()); } else { ranges.push(rangeStart + "-" + prev); } rangeStart = curr; prev = curr; } } if (rangeStart === prev) { ranges.push(rangeStart.toString()); } else { ranges.push(rangeStart + "-" + prev); } return ranges.join(", "); } // --- 補助関数: "1-7, 9-10" 文字列を数値配列 [1,2,3,4,5,6,7, 9,10] に解析 --- function parseRangeString(str) { var result = []; if (!str || str.replace(/^\s+|\s+$/g, "") === "") return result; var normalized = str.replace(/,/g, ",") .replace(/[ー―—–-]/g, "-") .replace(/\s+/g, ""); var parts = normalized.split(","); for (var i = 0; i < parts.length; i++) { var part = parts[i]; if (part === "") continue; if (part.indexOf("-") !== -1) { var rangeParts = part.split("-"); if (rangeParts.length !== 2) return null; var start = parseInt(rangeParts[0], 10); var end = parseInt(rangeParts[1], 10); if (isNaN(start) || isNaN(end) || start > end) return null; for (var p = start; p <= end; p++) { result.push(p); } } else { var num = parseInt(part, 10); if (isNaN(num)) return null; result.push(num); } } return result; } // 2. ドキュメント内の現在の親ページ適用状況を解析・集計 var masterPagesMap = {}; for (var mIdx = 0; mIdx < masters.length; mIdx++) { masterPagesMap[masters[mIdx].id] = []; } for (var pIdx = 0; pIdx < doc.pages.length; pIdx++) { var page = doc.pages[pIdx]; var applied = page.appliedMaster; if (applied !== null && applied.isValid) { if (masterPagesMap[applied.id]) { masterPagesMap[applied.id].push(pIdx + 1); } } } // 3. UI(ダイアログ)の構築 var win = new Window("dialog", "親ページの適用範囲"); win.orientation = "column"; win.alignChildren = ["fill", "top"]; win.spacing = 10; win.margins = 16; // ヘッダー固定エリア var headerGroup = win.add("group"); headerGroup.orientation = "row"; headerGroup.alignment = ["fill", "top"]; var lblMaster = headerGroup.add("statictext", undefined, "親ページ名"); lblMaster.preferredSize.width = 160; var lblRange = headerGroup.add("statictext", undefined, "適用ページ(例: 1-7, 9-12)"); lblRange.preferredSize.width = 160; // 仕切り線1 var sep1 = win.add("panel", undefined, ""); sep1.alignment = ["fill", "top"]; sep1.preferredSize.height = 1; // --- スクロールエリアの設定 --- var maxVisible = 7; // 最大7行表示(8行目以降はスクロール) var itemHeight = 32; // 1行あたりの実際の高さ(px) var spacingHeight = 4; // 行間余白(px) // 実際に表示する行数 var visibleRows = (masters.length > maxVisible) ? maxVisible : masters.length; // 全高さを正確に計算 var viewHeight = (visibleRows * itemHeight) + ((visibleRows - 1) * spacingHeight); var needScroll = masters.length > maxVisible; // スクロール枠の外側コンテナ var scrollContainer = win.add("group"); scrollContainer.orientation = "row"; scrollContainer.alignment = ["fill", "top"]; scrollContainer.alignChildren = ["left", "top"]; scrollContainer.preferredSize.height = viewHeight; // リスト領域(表示ウィンドウ) var listViewport = scrollContainer.add("group"); listViewport.orientation = "column"; listViewport.alignChildren = ["left", "top"]; listViewport.spacing = 0; listViewport.preferredSize.height = viewHeight; listViewport.maximumSize.height = viewHeight; // リスト本体(実際にスクロール移動させる枠) var contentGroup = listViewport.add("group"); contentGroup.orientation = "column"; contentGroup.alignChildren = ["left", "top"]; contentGroup.spacing = spacingHeight; // 各親ページの行を追加 var rows = []; for (var i = 0; i < masters.length; i++) { var m = masters[i]; var row = contentGroup.add("group"); row.orientation = "row"; row.alignChildren = ["left", "center"]; row.preferredSize.height = itemHeight; var nameText = row.add("statictext", undefined, m.name); nameText.preferredSize.width = 160; var initString = pagesToRangeString(masterPagesMap[m.id]); var rangeEdit = row.add("edittext", undefined, initString); rangeEdit.preferredSize.width = 150; rows.push({ master: m, input: rangeEdit }); } // 7個を超える場合のみ右側にスクロールバーを追加 if (needScroll) { var sb = scrollContainer.add("scrollbar", undefined, 0, 0, 10); sb.preferredSize.width = 15; sb.preferredSize.height = viewHeight; sb.alignment = ["right", "fill"]; sb.onChanging = function() { contentGroup.location.y = -this.value; }; } // 仕切り線2 var sep2 = win.add("panel", undefined, ""); sep2.alignment = ["fill", "top"]; sep2.preferredSize.height = 1; // ボタンエリア(最下部に固定) var btnGroup = win.add("group"); btnGroup.alignment = ["right", "bottom"]; var btnCancel = btnGroup.add("button", undefined, "キャンセル", { name: "cancel" }); var btnApply = btnGroup.add("button", undefined, "適用", { name: "ok" }); // スクロールバーの初期化・上限値セット win.onShow = function() { if (needScroll) { win.layout.layout(true); var totalH = contentGroup.size.height; var maxScroll = totalH - viewHeight; if (maxScroll > 0) { sb.maxvalue = maxScroll; sb.stepdelta = itemHeight + spacingHeight; sb.jumpdelta = (itemHeight + spacingHeight) * 3; } } }; // 4. 「適用」ボタンクリック時の処理 btnApply.onClick = function() { var pageAssignments = {}; var usedPages = {}; for (var k = 0; k < rows.length; k++) { var r = rows[k]; var inputText = r.input.text.replace(/^\s+|\s+$/g, ""); if (inputText !== "") { var pageList = parseRangeString(inputText); if (pageList === null) { alert("「" + r.master.name + "」の入力形式が正しくありません。\n半角の数字、ハイフン(-)、カンマ(,)を使用してください。(例: 1-7, 9-12)"); return; } for (var pIdx = 0; pIdx < pageList.length; pIdx++) { var pNum = pageList[pIdx]; if (pNum < 1 || pNum > totalPages) { alert("「" + r.master.name + "」に指定されたページ(" + pNum + ")は、ドキュメントの範囲(1 ~ " + totalPages + ")を超えています。"); return; } if (usedPages[pNum]) { alert("ページ " + pNum + " が複数の親ページ(" + usedPages[pNum] + " と " + r.master.name + ")で重複指定されています。"); return; } usedPages[pNum] = r.master.name; pageAssignments[pNum] = r.master; } } } // 5. 実行処理(Undo対応) app.doScript(function() { for (var idx = 0; idx < doc.pages.length; idx++) { var pg = idx + 1; var targetMaster = pageAssignments[pg] ? pageAssignments[pg] : noneMaster; if (doc.pages[idx].appliedMaster == targetMaster) continue; doc.pages[idx].appliedMaster = targetMaster; } }, ScriptLanguage.JAVASCRIPT, [], UndoModes.ENTIRE_SCRIPT, "親ページの一括適用"); win.close(1); // 6. 親ページが「なし」になっているページを検出して通知 var unassignedPages = []; for (var checkPage = 1; checkPage <= totalPages; checkPage++) { if (!usedPages[checkPage]) { unassignedPages.push(checkPage); } } if (unassignedPages.length > 0) { var unassignedStr = pagesToRangeString(unassignedPages); alert("処理が完了しました。\n\n" + unassignedStr + " ページは親ページ[なし]です。"); } else { alert("すべてのページに親ページを適用しました。"); } }; win.show(); })();









































