前段
InDesignの各Preference
にはたいていproperties
という便利なプロパティがいて、例えばこんなふうに使うことができます。
app.findGrepPreferences.properties = { findWhat: "hoge", fillColor: "blue" }; app.changeGrepPreferences.properties = { changeTo: "fuga", fillColor: "green" };
すごく便利で、僕もスクリプトを作る際に何度もお世話になっています。以前このブログで紹介し、InDesign日本語版リリース20周年イベントでも紹介した、InDesignのサンプルスクリプト「FindChangeByList.jsx」にも使われています。
問題
つい先日、たまたまそのスクリプトのコードを読みながら動作を試していて気づきました。
存在しない塗色(fillColor
)を指定したらその設定が無視されて置換が実行されてしまう。
例えば先の例文では、blueというスウォッチで塗られたhogeという文字を、fugaに置換して色をgreenにする検索置換を実行したいわけです。これを該当のスウォッチが存在しないドキュメントで実行すると、すべてのhogeがfugaになってしまう。
これは「FindChangeByList.jsx」のせいではなく、このPreference.properties
プロパティの仕様(なのかバグなのかはわからないけど)によるものです。
問題の切り分け
いったん「FindChangeByList.jsx」から離れて、このPreference.properties
の挙動についておさらいしましょう。
存在しないプロパティ
app.findGrepPreferences.properties = { findwhat: "hoge", fillColor: "blue" }; app.changeGrepPreferences.properties = { changeTo: "fuga", fillColor: "green" }; app.activeDocument.changeGrep();
上のように、もとのpreference
に存在しないプロパティを指定する(例えばfindWhat
ではなくfindwhat
など)と、ちゃんとエラーになります。
型違反
app.findGrepPreferences.properties = { findWhat: ["hoge"], fillColor: "blue" }; app.changeGrepPreferences.properties = { changeTo: "fuga", fillColor: "green" }; app.activeDocument.changeGrep();
上のように、本来文字列型しか取れないfindWhat
プロパティに配列を渡すと、ちゃんとエラーになります。
fillColor
がおかしいのか?
じゃぁfillColor
プロパティがおかしいのかというと、そうではないです。他にもエラーが起きずに無視されてしまうものがありました。
app.findGrepPreferences.properties = { findWhat: "hoge", appliedCharacterStyle: "blue" }; app.changeGrepPreferences.properties = { changeTo: "fuga", fillColor: "green" }; app.activeDocument.changeGrep();
例えばappliedCharacterStyle
(当たっている文字スタイル)。
このときの検索置換ダイアログはこうです。
取得できても利用できないオブジェクト
そうなると、怪しいのは「取得できるけど実際には利用(適用)できないタイプのオブジェクト」ではないか? と思うわけです。
試してみよう
app.findGrepPreferences.properties = { findWhat: "hoge", appliedCharacterStyle: "blue", appliedParagraphStyles: "blue", kinsokuSet: "blue", appliedFonts: "blue", }; app.changeGrepPreferences.properties = { changeTo: "fuga", fillColor: "green" };
これを実行した結果の検索置換ダイアログがこれ。
禁則設定の場合「禁則を使用しない」が設定されたこと以外、ほぼ予想通りでした。
与える値によって適用される結果が異なるプロパティはあるものの、本来やりたかった検索条件通りには検索できなくなるという結果は同じです。
どうやって回避する?
自前のスクリプトであれば、与えようとするオブジェクトとその値が実際に利用可能かどうか、isValid
プロパティを確認すべきでしょう。
ただ、FindChangeByList.jsxのように、こういう使い方をしているケースではとても難しいと思います。
var myString = "app.findGrepPreferences.properties = " + myFindPreferences + ";"; myString += "app.changeGrepPreferences.properties = " + myChangePreferences + ";"; myString += "app.findChangeGrepOptions.properties = " + myFindChangeOptions + ";"; app.doScript(myString, ScriptLanguage.javascript); var myFoundItems = myObject.changeGrep();
文字列を渡してdoScript()
メソッドを使っているのです。
本来であればこのproperties
プロパティに値を渡す際、存在しない(利用できない)値であればエラーを吐かせるべきところ、どうやらInDesign側がそうなっていない。そうなると自衛のためにスクリプトを利用する側が配慮する必要があります。このような使い方(文字列を渡してdoScript()
メソッドを使う)では、オブジェクトが実体化するのがdoScript()
メソッドの内側になり、実体化されたタイミングと検索置換パネルに情報が登録されるタイミングを切り分けられず、チェックする機会を失います。
具体的な解決方法がまだ見つけられていませんが、アイディアとしては下記あたりでどうかと考えています。
- 事前にテキストを
eval()
メソッドを使って実体化させる→それをチェックする - 事前にテキストを
eval()
メソッドを使って実体化させる→検索置換パネルに情報を登録する→登録されたそれぞれの情報を再チェックする
1はあまり現実的ではない、2はさすがに遠回りすぎ、と思うのですが、現実的なやり方では2が確実かなという印象です。もし1なら、そもそもproperties
を使わずにひとつずつ値を設定していったほうが合理的でしょう。
まとめ
ということで、FindChangeByList.jsxの使い方をまとめると下記のとおりです。
- 存在しない文字スタイルや段落スタイルなどを検索置換の条件に入れてもエラーにならず、そのまま置換が実行されるケースがある
- 設定ファイルに記述したものがあるかないか、事前に全部把握してから利用したほうがよい
- 意図したとおりに置換されたか最後にチェックする
findGrepPreference.properties
とchangeGrepPreference.properties
については下記のとおり。
- 事前にオブジェクトが利用可能か調べてから値を利用する
- でなければ検索置換パネルの内容を再チェックするタイミングを作る
- でなければ
properties
は使わない
余談
FIndChangeByList.jsx、設定ファイルのパスが固定だとずっと思ってたのですが、そのパスにファイルが見つからない場合、設定ファイルを選べる仕様になっていました。
これはこれで便利。