DTPab

DTPにまつわるあれこれ

DTPerのスクリプトもくもく会#7を開催しました

【追記 5/24 12:00】
あるふぁ(仮)さんから、メニューオブジェクトを辿る方法も教えていただきました!いつもありがとうございます!

謝辞

去る5/19(土)、DTPerのスクリプトもくもく会#7を開催しました。ご参加くださった皆さま、ありがとうございました。
再三書いているように、今回はコワーキングスペースでの初めての有料開催ということで少し緊張しましたが、滞りなく、しかも持出しもなく、無事に開催することができました。改めて参加者の皆さまに支えられて成り立っているのだなぁとしみじみと思うのでした。

雑感

さて、今回のもくもく会は久しぶりにもくもく会らしいもくもく会で、みんなが作業に没頭しながら、質問しあったり、お互いの情報交換をしたりと、ひとつの理想形としてのもくもく会だったように思います。
めんたいこさんが遠方よりご参加くださったことも一因にありますが、特に懇親会が盛り上がり、第7回にして初めて懇親会二次会が開催されましたw
話の内容もどんどん濃厚になり、お互いへのリスペクトがあり、フリーランスとしての矜持や、仕事への価値観などなど、まる1冊本になるんじゃないかと思えるくらいいろんな話がありました。
DTPerとしては「こいつら何の話してるんだ」という用語連発のこともありましたがw、参加された皆さまからは好評をいただき、主催者としては胸をなでおろしました。
次回は7月開催予定ですので、また詳細が決まり次第ご連絡したいと思います。

もくもく成果

僕自身は「ページパネルで選択しているページに任意のカラーラベルを充てる」というUI込みのInDesignスクリプトを作り(作ろうと取組み)ました。残念ながらもくもく会中では完成できなかったものの、つまづきポイントを含めて仕上げたスクリプトを紹介します。

想定した処理フロー

  1. ページパネルで選択しているページを取得する
  2. ScriptUIで「何色のラベルを付けるか」をユーザーに選択させる
  3. 2で選んだカラーラベルを1で選択しているページに設定する

と見込んでいたのですが、まず1でつまづきました。
ページパネルで選択しているページを取得できないのですね。そこで次のようにフローを変更しました。

実際の処理フロー

  1. ScriptUIで「何色のラベルを付けるか」をユーザーに選択させる
  2. 「カラーラベル」のメニューアクションが実行可能か調べる
  3. メニューアクションを利用してカラーラベルを設定する

ということで、まずは必要になるであろう変数の宣言を行います(全体のコードは記事末尾に掲載しています)。

変数の定義

var myDoc = app.activeDocument; //前面ドキュメントを取得

//menuActionコマンドが特定のareaにあるかを調べ、そのindexを返す関数
var getAreaIndex = function (menu){
    for (var i=0; i<menu.area.length; i++){
        if (menu.area[i] === "パネルメニュー:ページ") return i;
    }
};
//指定したindexのmenuActionを取得する関数
var getMenuAction = function (menu, index){
    return menu.getElements()[index];
}
//ページパネルから設定できるUIColorsのリスト名
var pageColors = [
    "なし", // PageColorOptions.NOTHING
    "ホワイト", // UIColors.WHITE
    "ピンク", // UIColors.PINK
    "金色", // UIColors.GOLD
    "イエロー", // UIColors.YELLOW
    "緑", // UIColors.GREEN
    "ライトブルー", // UIColors.LIGHT_BLUE
    "ラベンダー", // UIColors.LAVENDER
    "グレー", // UIColors.GRAY
    "赤", // UIColors.RED
    "オレンジ", // UIColors.ORANGE
    "黄褐色", // UIColors.SULPHUR
    "ダークグリーン", // UIColors.DARK_GREEN
    "青", // UIColors.BLUE
    "すみれ色", // UIColors.VIOLET
    "黒" // UIColors.BLACK
];
//メニューアクションのリストを作成
var myActionsAry = [];
(function (){
    for (var i=0; i<pageColors.length; i++){
        var myAction = app.menuActions.itemByName(pageColors[i]);
        var myIndex = getAreaIndex (myAction) || 0; //同名アクションが存在しなければindexは0でOK
        myActionsAry.push(getMenuAction (myAction, myIndex));
    }
})();

変数定義とともに適宜関数を定義しました。以下、順番に見ていきます。

同名メニューアクションの絞込み

メニューアクションは、InDesignに表示されるコマンド名を一字一句正しくmenuActions.itemByNameメソッドに渡すことで、そのコマンドを定義できます。しかし、コマンド名だけの指定では(特に「なし」などはさまざまなメニューに登録されているため)、メニュー間でダブってしまいます。それを回避するためにgetAreaIndex関数と、getMenuAction関数を定義しています。

getAreaIndex関数

var getAreaIndex = function (menu){
    for (var i=0; i<menu.area.length; i++){
        if (menu.area[i] === "パネルメニュー:ページ") return i;
    }
};

ページパネルのメニューアクションを特定するための関数です。メニューアクションのareaプロパティが「パネルメニュー:ページ」であるメニューアクションのindexを返します。

getMenuAction関数

var getMenuAction = function (menu, index){
    return menu.getElements()[index];
}

先のgetAreaIndex関数で取得したindexを元に、メニューアクションをふるいにかけて特定します。getElementsメソッドを利用することで、メニューアクションを実体化し、コレクションオブジェクトとして利用できるようにしています。

わざわざ関数をふたつに分けましたが、分かりやすくするために機能を細分化しただけですので、統合してしまってもいいし、力業で「パネルメニュー:ページ」のメニューアクションを割り出してもいいです。

カラーラベル名の定義

ページパネルのカラーラベルは、デフォルトで用意されているUIColorsオブジェクトをそのまま利用しています*1。今回はメニューアクションを利用するためUIColorsオブジェクトは使いません(というか使えない)が、Page.pageColorプロパティにUIColorsオブジェクトを渡すことで、特定のページやマスタースプレッドにカラーラベルを設定できます。
面白いことに、ページパネルから選べる色はUIColorsオブジェクトに用意されているものから一部抽出されたもので、スクリプトからはすべてのUIColorsオブジェクトを設定できます。RGBの指定によるカスタム値も定義できますので、スクリプトであれば任意の色を設定することが可能です。
参考までに、UIColorsオブジェクトの列挙値をコメントアウトしましたので、もしメニューアクションではなくPage.pageColorプロパティに直接アクセスしてカラーラベルを設定したい、任意の色に変更したい、という場合は参考にしてください。

var pageColors = [
    "なし", // PageColorOptions.NOTHING
    "ホワイト", // UIColors.WHITE
    "ピンク", // UIColors.PINK
    "金色", // UIColors.GOLD
    "イエロー", // UIColors.YELLOW
    "緑", // UIColors.GREEN
    "ライトブルー", // UIColors.LIGHT_BLUE
    "ラベンダー", // UIColors.LAVENDER
    "グレー", // UIColors.GRAY
    "赤", // UIColors.RED
    "オレンジ", // UIColors.ORANGE
    "黄褐色", // UIColors.SULPHUR
    "ダークグリーン", // UIColors.DARK_GREEN
    "青", // UIColors.BLUE
    "すみれ色", // UIColors.VIOLET
    "黒" // UIColors.BLACK
];

メニューアクションの特定とリスト化

var myActionsAry = [];
(function (){
    for (var i=0; i<pageColors.length; i++){
        var myAction = app.menuActions.itemByName(pageColors[i]);
        var myIndex = getAreaIndex (myAction) || 0; //同名アクションが存在しなければindexは0でOK
        myActionsAry.push(getMenuAction (myAction, myIndex));
    }
})();

以上の2つの関数、そしてカラーラベル名の定義を終えたところで、実際にメニューアクションを定義しているのがこの部分です。1度呼び出せば十分なので、匿名関数を即時実行する形を採用しました。
myAction変数にはカラーラベル名からメニューアクションを取得しています。先述の通り「なし」など他のパネルなどでも使われる場合を想定して、次のmyIndex変数では、MenuActions.areaプロパティを調べて、そのindexを取得します。
このとき、areaが複数に跨がらない(MenuActions.itemByNameが一意に定義できる)場合はundefinedが戻るので、その場合は論理OR演算子を使ってmyIndexに0が定義されます。
最後にgetMenuAction関数を使ってメニューアクションを一意に定義し、myActionsAry変数に配列として追加(Array.pushメソッド)しています。

ここまでがメニューアクションの定義とリスト化です。

ScriptUIの生成

//ScriptUIを生成
var dlg = new Window("dialog", "カラーラベルを適用");
var label = dlg.add("dropdownlist", undefined, pageColors);
label.title = "カラーラベル";
label.selection = 0;
dlg.add("button", undefined, "適用", {name: "ok"}).onClick = function (){
    dlg.close(3);
}

ScriptUIは細かい説明をするとキリがないので、分からない部分があればTwitterやこの記事のコメントにご連絡ください。一応、かなりベーシックな書式で書いたつもりです。

スクリプト処理

やっと変数の定義とSUIの生成が終わりました。ここからやっとスクリプトのメイン処理になります。

if (dlg.show() !== 3) exit();
if (!myActionsAry[label.selection.index].enabled){
    alert("カラーラベルは現在実行できません");
    exit();
}
myActionsAry[label.selection.index].invoke();
alert("カラーラベルを適用しました");

といってもこの7行でおしまいです。
menuActionオブジェクトが利用可能かどうかをenabledプロパティを参照して確認しています(したたか企画さんからいただいたアイディアです!多謝!)。問題なければMenuAction.invokeメソッドを使って、メニューアクションを実行しています。

以上が今回のカラーラベルを設定するスクリプトです。

ただ、ちょっと使いにくいかなって思ってます。スクリプトを実行する度にダイアログが消えてしまうし、ScriptUIをpaletteにしてフローティングウィンドウにしたほうがいいのかな。CC2015以降ならCEPにしてもいいのかもしれない。あと、リストに実際の色のサムネイルを表示したいですね。

f:id:uske_S:20180522191634p:plain

例えばこんな感じで(これはデフォルトのページパネルからカラーラベルを参照しているところですが)。
どういう形にするかは追々検討したいと思います。

スクリプトコード全文

/**
* @@@BUILD INFO@@@
* Name: applyColorLabel
* FileName: applyColorLabel.jsx
* Version: 0.0.1
* CreationDate: Tue May 22 2018 11:42:50 GMT+0900 (JST)
* Author: @Uske_S(Yusuke SAEGUSA)
* Copyright: @Uske_S(Yusuke SAEGUSA)
* Notice: 
* 著作者に無断で転載・配布・販売することを禁止します。
* 個人利用の限りにおいて改変は可能とします。
* スクリプトの使用により不都合・不具合が生じても責任は負いかねます。
* Discription: 
* ページパネル上で選択しているページにカラーラベルを設定します。
* 動作保証バージョンはInDesignCS6以降です。
*/

#targetengine session
//InDesign用スクリプトであることを明示
#target indesign

//--- 実行環境調査 ---//
if (app.documents.length === 0) exit(); //ドキュメントが開かれていなければ終了

//--- 変数宣言 ---//
var myDoc = app.activeDocument; //前面ドキュメントを取得

//menuActionコマンドが特定のareaにあるかを調べ、そのindexを返す関数
var getAreaIndex = function (menu){
    for (var i=0; i<menu.area.length; i++){
        if (menu.area[i] === "パネルメニュー:ページ") return i;
    }
};
//指定したindexのmenuActionを取得する関数
var getMenuAction = function (menu, index){
    return menu.getElements()[index];
}
//ページパネルから設定できるUIColorsのリスト名
var pageColors = [
    "なし", // PageColorOptions.NOTHING
    "ホワイト", // UIColors.WHITE
    "ピンク", // UIColors.PINK
    "金色", // UIColors.GOLD
    "イエロー", // UIColors.YELLOW
    "緑", // UIColors.GREEN
    "ライトブルー", // UIColors.LIGHT_BLUE
    "ラベンダー", // UIColors.LAVENDER
    "グレー", // UIColors.GRAY
    "赤", // UIColors.RED
    "オレンジ", // UIColors.ORANGE
    "黄褐色", // UIColors.SULPHUR
    "ダークグリーン", // UIColors.DARK_GREEN
    "青", // UIColors.BLUE
    "すみれ色", // UIColors.VIOLET
    "黒" // UIColors.BLACK
];
//メニューアクションのリストを作成
var myActionsAry = [];
(function (){
    for (var i=0; i<pageColors.length; i++){
        var myAction = app.menuActions.itemByName(pageColors[i]);
        var myIndex = getAreaIndex (myAction) || 0; //同名アクションが存在しなければindexは0でOK
        myActionsAry.push(getMenuAction (myAction, myIndex));
    }
})();

//ScriptUIを生成
var dlg = new Window("dialog", "カラーラベルを適用");
var label = dlg.add("dropdownlist", undefined, pageColors);
label.title = "カラーラベル";
label.selection = 0;
dlg.add("button", undefined, "適用", {name: "ok"}).onClick = function (){
    dlg.close(3);
}

//--- 変数宣言ここまで ---//

if (dlg.show() !== 3) exit();
if (!myActionsAry[label.selection.index].enabled){
    alert("カラーラベルは現在実行できません");
    exit();
}
myActionsAry[label.selection.index].invoke();
alert("カラーラベルを適用しました");

ダウンロード

コピペが面倒な方はこちらからどうぞ。

www.dropbox.com

改めて

次回DTPerのスクリプトもくもく会(#8)は7月開催予定です。
それと、来月よりお〜まちさんの「InDesignで学ぶJavaScript教室」が開催されます。参加される皆さま、僕もアシスタントとして参加しますのでよろしくお願いします。

また、このお〜まちさんの講習会は引き続き次回開催希望者を募集中です。人数がある程度集まらないと開催できませんので、今回参加が間に合わなかった方もぜひぜひ、お〜まちさんのサイトより、フォームから申請をお願いします(僕が次回もアシスタントとして参加できるかはわかりませんが)。

cs5.xyz

*1:例えばレイヤーパネルの設定画面から選べる「カラー」に定義されている色です。