DTPab

DTPにまつわるあれこれ

InDesign ExtendScriptで「テキストを選択しているかどうか」の判定方法

InDesignのExtendScriptでは、テキストに関するサブクラスがたくさんあります。これらを使って「選択しているオブジェクトはなにか?」というのをよく実装するわけですが、毎度毎度「TextStyleRangeと、あとなんだっけ……」みたいに全部をパッと思い出せないんですよね。
なのでちょっとまとめてみました。InDesignスクリプターの方にお役立ていただけると嬉しいです。

  • Story
  • Character
  • Word
  • Line
  • TextColumn
  • Paragraph
  • TextStyleRange
  • InsertionPoint

それぞれ個別に説明はしませんが、Textオブジェクトのサブクラスだけでこれだけあります*1。ほかにもTextFrame、Cell、Tableなども含めるかどうか。

で、これだけあるので、「選択しているオブジェクトがテキストの時」という条件をトリガーにする場合、どのように実装するのがベターか悩むんですよね。

var sel = app.activeDocument.selection[0];
if (sel.constructor.name === "Character" ||
    sel.constructor.name === "Word" ||
    sel.constructor.name === "Line" ||
    sel.constructor.name === "TextColumn" ||
    sel.constructor.name === "Paragraph" ||
    sel.constructor.name === "TextStyleRange" ||
    sel.constructor.name === "InsertionPoint") {
    //なんらかの処理
}

って総当たりでやるのがセオリーなんですが、冗長ですよね。
ほかには、例えば選択したオブジェクトがtextsプロパティを持っているかどうか、というやり方もあります。

var sel = app.activeDocument.selection[0];
if (sel.hasOwnProperty("texts")) {
    //なんらかの処理
}

ただ、これには前掲のリストに加えて、TextFrameオブジェクトやCellオブジェクトも問答無用で含まれます。どちらのやり方も一長一短ですので、目的とする条件を達成するのにもっとも効率がいい書き方を選べればいいと思います。

ECMAScript5で配列オブジェクトに実装されたsomeメソッド*2をポリフィルしておいて、こんな書き方をすることもたまにあります。

var acceptClasses = [
    "Text",
    "TextColumn",
    "Story",
    "Paragraph",
    "Line",
    "Word",
    "Character",
    "TextStyleRange",
    "Table",
    "Cell"
];

if (app.selection.length !== 1
    || !acceptClasses.some(function(el){
        return el === app.selection[0].constructor.name;
    })) {
    myerror("文字か表組を選択してから実行してください");
}

ちなみに僕が使っているsomeメソッドのコードはこちら(Gistです)。

まぁ、ここまで書いたらアロー関数も使いたいよね…w

*1:Storyは正確にはTextオブジェクトのサブクラスではないです

*2:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/some