Skip to content

Instantly share code, notes, and snippets.

@AJABON
Last active October 23, 2025 07:29
Show Gist options
  • Save AJABON/bb120b07abbd2798acbd9d00e8a8b823 to your computer and use it in GitHub Desktop.
Save AJABON/bb120b07abbd2798acbd9d00e8a8b823 to your computer and use it in GitHub Desktop.
InDesign: 文字数単位でインデント値を制御するやつ。未選択のときは段落スタイルパネルで選択されているスタイルを制御します。
// File: mojindent.jsx
// Author: (z-) ajabon.catfood.jp
// Date: 2025-10-16
// Version: 1.1.0
// Desc: InDesignで段落のインデント値を「文字数」で扱うScriptUI。
// 同一設定であれば複数処理が可能。
// オブジェクト未選択状態ではドキュメントデフォルトの段落スタイル設定が変更されます。
// ※縦組みは(まだ)考慮していません
//
// shiftキー併用で増減値が5になります
#target indesign
#targetengine "mojindent"
// 条件が揃っているか調べる
if(!app.documents.length) exit();
var doc = app.activeDocument;
var paragraphs, pointSizeUnitValue, pointSizeVal, leftIndentVal, firstLineIndentVal, rightIndentVal, lastLineIndentVal;
var lastTime = 0; // キー入力イベントの発火がダブるのと、イベント伝播を正しく制御できないので代替措置。ChatGPTにきいた。
var sel; // 選択範囲
// 単位名の変換用
var getUnitName = {
AGATES : "ag",
AMERICAN_POINTS : "ap",
CENTIMETERS : "cm",
CICEROS : "c",
HA : "H",
INCHES : "in",
INCHES_DECIMAL : "in", //暫定
MILLIMETERS : "mm",
PICAS : "p",
POINTS : "pt",
Q : "Q",
CUSTOM : "pt" //暫定
}
// ScriptUI
var win = new Window("""palette{text: "文字数でインデントするから mojindent", orientation: "column", alignChildren: "center",
prms: Panel{orientation: "row",spacing: 28,
left: Group{orientation: "column", spacing: 4, alignChildren: "right",
leftIndent: Group{orientation: "row", spacing: 2,
s: StaticText{text:"   左 : "},
ctrl: Group{orientation: "column", spacing: 8,
up: StaticText{text: "︿", size: [20, 12]},
dn: StaticText{text: "﹀", size: [20, 12]}
},
e: EditText{characters: 6, text: "", minus: false, order: 0}
},
firstLineIndent: Group{orientation: "row", spacing: 2,
s: StaticText{text:"1 行目左 : "},
ctrl: Group{orientation: "column", spacing: 8,
up: StaticText{text: "︿", size: [20, 12]},
dn: StaticText{text: "﹀", size: [20, 12]}
},
e: EditText{characters: 6, text: "", minus: true, order: 1}
}
},
right: Group{orientation: "column", spacing: 4, alignChildren: "right",
rightIndent: Group{orientation: "row", spacing: 2,
s: StaticText{text:"   右 : "},
ctrl: Group{orientation: "column", spacing: 8,
up: StaticText{text: "︿", size: [20, 12]},
dn: StaticText{text: "﹀", size: [20, 12]}
},
e: EditText{characters: 6, text: "", minus: false, order: 2}
},
lastLineIndent: Group{orientation: "row", spacing: 2,
s: StaticText{text:"最終行の右 : "},
ctrl: Group{orientation: "column", spacing: 8,
up: StaticText{text: "︿", size: [20, 12]},
dn: StaticText{text: "﹀", size: [20, 12]}
},
e: EditText{characters: 6, text: "", minus: true, order: 3}
}
}
}
s: StaticText{text: "選択なしでドキュメントデフォルトの段落スタイルが対象となります"},
bottom: Group{orientation: "row", spacing: 2,
s: StaticText{text: "対象文字サイズ:", characters: 20},
space: StaticText{characters: 6},
capBtn: Button{text: "とりこみ", helpTip: "選択オブジェクトの設定を反映しますよ"}
}
}""");
// ヘンスー
var UIleftIndent = win.prms.left.leftIndent;
var UIfirstLineIndent = win.prms.left.firstLineIndent;
var UIrightIndent = win.prms.right.rightIndent;
var UIlastLineIndent = win.prms.right.lastLineIndent;
// tebキーで送る順番
var etAry = [UIleftIndent, UIfirstLineIndent, UIrightIndent, UIlastLineIndent];
/* イベントハンドラ */
// 値のダイレクト入力 単位の入力は不可
UIleftIndent.e.onEnterKey = UIleftIndent.e.onChange = function(){
getIndents();
var val = veryfyValue(this.text, false);
if(val == undefined) return;
app.doScript("func_left(" + val + ")", ScriptLanguage.JAVASCRIPT, [], UndoModes.FAST_ENTIRE_SCRIPT);
}
UIfirstLineIndent.e.onEnterKey = UIfirstLineIndent.e.onChange = function(){
getIndents();
var val = veryfyValue(this.text, true);
if(val == undefined) return;
app.doScript("func_first(" + val + ")", ScriptLanguage.JAVASCRIPT, [], UndoModes.FAST_ENTIRE_SCRIPT);
}
UIrightIndent.e.onEnterKey = UIrightIndent.e.onChange = function(){
getIndents();
var val = veryfyValue(this.text, false);
if(val == undefined) return;
app.doScript("func_right(" + val + ")", ScriptLanguage.JAVASCRIPT, [], UndoModes.FAST_ENTIRE_SCRIPT);
}
UIlastLineIndent.e.onEnterKey = UIlastLineIndent.e.onChange = function(){
getIndents();
var val = veryfyValue(this.text, true);
if(val == undefined) return;
app.doScript("func_last(" + val + ")", ScriptLanguage.JAVASCRIPT, [], UndoModes.FAST_ENTIRE_SCRIPT);
}
// StaticTextをクリックしたら同一グループのEditTextにフォーカス
UIleftIndent.s.addEventListener("click", focusEditText);
UIfirstLineIndent.s.addEventListener("click", focusEditText);
UIrightIndent.s.addEventListener("click", focusEditText);
UIlastLineIndent.s.addEventListener("click", focusEditText);
// 値の上下ボタン操作
UIleftIndent.ctrl.up.addEventListener("click", upBtn);
UIleftIndent.ctrl.dn.addEventListener("click", dnBtn);
UIfirstLineIndent.ctrl.up.addEventListener("click", upBtn);
UIfirstLineIndent.ctrl.dn.addEventListener("click", dnBtn);
UIrightIndent.ctrl.up.addEventListener("click", upBtn);
UIrightIndent.ctrl.dn.addEventListener("click", dnBtn);
UIlastLineIndent.ctrl.up.addEventListener("click", upBtn);
UIlastLineIndent.ctrl.dn.addEventListener("click", dnBtn);
// 値のフィールドで矢印キー上下の操作、tebでフィールド送り、shiftキー併用で逆送り
UIleftIndent.e.addEventListener ("keydown", keyDownFunc);
UIfirstLineIndent.e.addEventListener ("keydown", keyDownFunc);
UIrightIndent.e.addEventListener ("keydown", keyDownFunc);
UIlastLineIndent.e.addEventListener ("keydown", keyDownFunc);
// 選択とりこみボタン
win.bottom.capBtn.onClick = function(){
// 設定値の取得とUI反映
getIndents();
inputToUI();
}
// 初期動作
win.bottom.capBtn.notify("onClick");
win.show();
////////////// カンスー ///////////////////
// 左インデント
function func_left(val){
for(var i = 0; i < paragraphs.length; i++){
paragraphs[i].leftIndent = pointSizeUnitValue * val;
if(paragraphs[i].firstLineIndent < -paragraphs[i].leftIndent){
paragraphs[i].firstLineIndent = -paragraphs[i].leftIndent;
}
}
win.bottom.capBtn.notify("onClick");
}
// 1行目 左インデント
function func_first(val){
for(var i = 0; i < paragraphs.length; i++){
while(val < 0 && toNum(paragraphs[i].leftIndent) < toNum(-pointSizeUnitValue * val)){
paragraphs[i].leftIndent += pointSizeUnitValue;
}
paragraphs[i].firstLineIndent = pointSizeUnitValue * val;
}
win.bottom.capBtn.notify("onClick");
}
// 右インデント
function func_right(val){
for(var i = 0; i < paragraphs.length; i++){
paragraphs[i].rightIndent = pointSizeUnitValue * val;
if(paragraphs[i].lastLineIndent < -paragraphs[i].rightIndent){
paragraphs[i].lastLineIndent = -paragraphs[i].rightIndent;
}
}
win.bottom.capBtn.notify("onClick");
}
// 最終行の右インデント
function func_last(val){
for(var i = 0; i < paragraphs.length; i++){
while(val < 0 && toNum(paragraphs[i].rightIndent) < toNum(-pointSizeUnitValue * val)){
paragraphs[i].rightIndent += pointSizeUnitValue;
}
paragraphs[i].lastLineIndent = pointSizeUnitValue * val;
}
win.bottom.capBtn.notify("onClick");
}
// キーボード操作
function keyDownFunc(ev){
var now = new Date().getTime();
if (now - lastTime < 50) return; // 50ms
lastTime = now;
if(ev.keyName == "Up"){
upFunc(this);
}
if(ev.keyName == "Down"){
dnFunc(this);
}
if(ev.keyName == "Tab"){
if(ScriptUI.environment.keyboardState.shiftKey){
etAry[(this.order - 1 + 4) % 4].e.active = true;
} else{
etAry[(this.order + 1) % 4].e.active = true;
}
ev.preventDefault();
}
}
// StaticTextのクリックで同グループのEditTextにフォーカス
function focusEditText(ev){
ev.target.parent.e.active = true;
}
// ふえボタン
function upBtn(ev){
upFunc(ev.target.parent.parent.e);
}
// へりボタン
function dnBtn(ev){
dnFunc(ev.target.parent.parent.e);
}
// 値のボタン操作による増加 シフトキーで5ずつ
function upFunc(et){
var val = et.text - 0;
var bs = ScriptUI.environment.keyboardState.shiftKey ? 5 : 1;
var res = val - val % bs;
if(res <= val) res += bs;
et.text = res;
et.notify("onChange");
}
// 値のボタン操作による減少 シフトキーで5ずつ minus: マイナスを許可するboolean
function dnFunc(et){
var val = et.text - 0 + 1000;
var bs = ScriptUI.environment.keyboardState.shiftKey ? 5 : 1;
var res = val - (val % bs == 0? bs : val % bs);
res -= 1000;
et.text = res < 0 && et.minus == false? 0 : res;
et.notify("onChange");
}
// インデント値を取得
function getIndents(){
paragraphs = getParagraphs();
pointSizeVal = isOneValue(paragraphs, "pointSize");
leftIndentVal = isOneValue(paragraphs, "leftIndent");
firstLineIndentVal = isOneValue(paragraphs, "firstLineIndent");
rightIndentVal = isOneValue(paragraphs, "rightIndent");
lastLineIndentVal = isOneValue(paragraphs, "lastLineIndent");
}
// 取得した値をUIに反映
function inputToUI(){
if(pointSizeVal == undefined){
valueFunc(["", "", "", ""]);
return;
}
var defaultMU = app.scriptPreferences.measurementUnit;
var vp = doc.viewPreferences;
var tmu = vp.textSizeMeasurementUnits;
pointSizeUnitValue = toUnitValue(sel[0].insertionPoints[0].pointSize, getUnitName[tmu.toString()]).as(getUnitName[vp.horizontalMeasurementUnits.toString()]); //1文字の寸法をインデントの単位に変換
// app.scriptPreferences.measurementUnit = tmu; // 単位を文字サイズに
// app.scriptPreferences.measurementUnit = AutoEnum.AUTO_VALUE;
app.scriptPreferences.measurementUnit = vp.horizontalMeasurementUnits; // 単位を定規:水平に
valueFunc(leftIndentVal, UIleftIndent);
valueFunc(firstLineIndentVal, UIfirstLineIndent);
valueFunc(rightIndentVal, UIrightIndent);
valueFunc(lastLineIndentVal, UIlastLineIndent);
app.scriptPreferences.measurementUnit = defaultMU;
}
// EditTextの値を評価 flag:マイナス値を許容するか
function veryfyValue(txt, flag){
if(pointSizeVal == undefined) return;
var val = eval(txt);
if(isNaN(val)){
alert("入力値が気に入らないので考え直してください");
return;
}
if(val < 0 && flag == false){
alert("マイナスだめです");
return;
}
return val;
}
// 段落群を取得
function getParagraphs(){
doc = app.activeDocument;
sel = doc.selection;
var ary = [];
if(sel.length == 0){
// 未選択時はドキュメントデフォルトの段落スタイルをいじる
ary.push(doc.textDefaults.appliedParagraphStyle);
}
for(var i = 0; i < sel.length; i++){
if(sel[i].hasOwnProperty("paragraphs")){
ary = ary.concat(sel[i].paragraphs.everyItem().getElements());
}
}
return ary;
}
// 丸め誤差対策
function toNum(num){
return Number(num.toString());
}
// 引数 [値, 単位] をUnitValueで返す.Q, H を考慮
function toUnitValue(val, unitName){
win.bottom.s.text = win.bottom.s.text.replace(/:.*$/, ":" + val + " " + unitName);
if(val == 0) return new UnitValue(0, "pt");
if(/^[QH]$/.test(unitName)){
val *= 0.25;
unitName = "mm";
}
return new UnitValue(val, unitName);
}
// 選択範囲内すべて一意かをみる 一意ならその値、ばらついたらundefinedを返す
function isOneValue(paragraphs, prop){
if(paragraphs.length == 0) return undefined;
// var val = eval("paragraphs[0]." + prop);
var val = paragraphs[0][prop];
if(paragraphs.length == 1) return val;
for(var i = 1; i < paragraphs.length; i++){
// if(eval("paragraphs[i]." + prop) != val){
if(paragraphs[i][prop] != val){
return undefined;
}
}
return val;
}
function valueFunc(val, obj){
obj.e.text = val == undefined? "" : val / pointSizeUnitValue;
// obj.e.text = val == undefined? "" : val;
}
// function absFloor(val){ /*小数第5位ぐらいで四捨五入してから正数化*/
// return Math.abs(Math.round(val * 10000) / 10000);
// }
// チェック用
function cp(mes){
// alert(mes);
// $.writeln(mes);
}
@AJABON
Copy link
Author

AJABON commented Oct 17, 2025

説明は以下でしてます
https://ajabon.catfood.jp/?p=2805

@AJABON
Copy link
Author

AJABON commented Oct 20, 2025

1.1.0 とりこみボタン操作時、段落の先頭文字ではなく選択テキストの先頭挿入点に対象を変更。
また対象文字サイズをUI下部に表示するよう追記。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment