DTPab

DTPにまつわるあれこれ

DTPerのスクリプトもくもく会#6 開催報告

改めまして、先日、DTPerのスクリプトもくもく会#6を開催しました。
いろいろありましたので、前回記事もお目通しください。

保留中の宿題まとめ

過去開催回でいただいた、まだ解決していない宿題をまとめました。もし「お前やるって言ったのにその後音沙汰ないじゃないか!」ってのがありましたらご指摘ください。しかる後に対応させていただきます…。

  • BridgeTalkによる非同期処理(#5)
  • ESTK事始めのスライドの補足(#5)
  • InDesignで開いているウィンドウの数を調べたい(#6)
  • OMVのカスタマイズと入力補完(#6)

スライドの補足とOMVのカスタマイズは「やります」といってやってないやつです(最上級土下座)。とりあえず上記宿題より3つめの、ウィンドウの数を調べる方法を考えてみました。

開いているウィンドウの数を調べたい

Application.windowsまたはApplication.layoutWindowsが開かれているドキュメントのウィンドウ、それぞれのlengthプロパティで数を数えられるわけですが、これがどうやら「開いているドキュメントのウィンドウ数」を返すようなのですね。
タブで結合したウィンドウは「1」にカウントしたいのですが…。
というご質問だったので、その場では分からず宿題となりました。

座標を調べて比較しよう

絶対、もっとスマートな方法があると思うのですが、泥臭く、各ウィンドウの座標値を取得する方法で解決してみました。

var w = app.layoutWindows;
var res = [];

for (var i=0; i<w.length; i++){
    if (res.join("|").indexOf(w[i].bounds) < 0) res.push(w[i].bounds);
    }

alert(res.length);

どうです?とても泥臭いでしょうwww
配列をjoinメソッドで適当に文字列に連結し、それをindexOfメソッドを利用して同じ値がないか調べています…。いや、ExtendScriptArray.filterみたいなものが実装されてないのがいけないんですよ!
まぁ、それはそれとして、もっといい方法というか、ちゃんとした正攻法みたいなものをご存知の方、ぜひぜひご教示くださいませ。
少し解説しておくと、すべてのLayoutWindowオブジェクトからLayoutWindow.boundsプロパティを引っ張り出します。それを適当な配列respush(配列の末尾に追加)するのですが、配列に同じものがある場合は除外して追加します。そうすることで同じウィンドウで複数のドキュメントを開いていても重複カウントせず、ウィンドウの数を正しく取得できます。
その除外して追加する=重複を排除するという処理に、filterメソッドとか使いたいな…って思うんですよね*1

余談

Application.layoutWindowsApplication.windowsって似たような2つのコレクションオブジェクトが実はあります。このコードではlayoutWindowsを使ったわけですが、その違いについてTwitterで教えていただいたので共有しておきますね。

あるふぁ(仮)さん、いつもありがとうございます!
というわけで、Application.windowsは「ストーリーエディタ」も含んでlengthプロパティを返します。一方でApplication.layoutWindowsは「ストーリーエディタ」を含まないのですね。勉強になりました。

いただいた質問

前回いただいた質問とその回答を一応アップしておきます。

  • everyItemメソッドの使い方
  • イベントリスナーのイベントトリガーはどうやって調べるのか

everyItemメソッド

コレクションオブジェクトで使えるeveryItemメソッドですが、コレクションオブジェクトから特定のプロパティをまとめて抽出したいときにとても便利です。
例えば、段落スタイル名の一覧はこのように(for文を使わず)簡単に書くことができます。

var para = app.activeDocument.paragraphStyles;
$.writeln(para.everyItem().name.join("\n"));

joinメソッドを使っていることから分かるように、everyItemメソッド(の各プロパティ)の戻り値は配列になります。コレクションオブジェクトに内包する個別のオブジェクトたちのプロパティをまとめて配列にしてくれる便利なやつです。しかし、例えば以下のような例ではエラーにならないですが、何も変わりません。

var allCells = app.activeDocument.selection[0].cells;
var allContents = allCells.everyItem().contents;
allContents[1] = "何も変わりません";

これは、選択した複数のセルのうち2番目のセルの中身(文字列)を書き換えたいのですが、うまく動作しません。実はこのeveryItemには、大事な女房役のメソッドがいます。それがgetElementsメソッドです。
このコードを以下のように書き換えてみてください。意図した通り動作するようになります。

var allCells = app.activeDocument.selection[0].cells;
var allContents = allCells.everyItem().getElements();
allContents[1].contents = "これは更新できます";

まとめると、

  • everyItemメソッドは、コレクションオブジェクトの個々のプロパティを配列にして返す
  • everyItemメソッドで取得したプロパティの配列を(スクリプト上では)変更することはできるが、InDesignに反映することはできない
  • getElementesメソッドを使うことで、通常のプロパティと同じように扱うことができるようになる

ということになります。慣れるととても便利な2つのメソッドです。ぜひ覚えておいてください。

イベントリスナーのトリガー

"afterOpen"とか"beforeSave"とか、どこかに一覧があるのでしょうか? というご質問をいただきました。探しにくいだけで実はOMVに全部載っています。
文字だけだと伝えにくいので、以下の画像を参照してください。

f:id:uske_S:20180329210306p:plain

f:id:uske_S:20180329210316p:plain

f:id:uske_S:20180329210324p:plain

という感じです。
注意して欲しいのは、古いInDesignのバージョンほどイベントトリガーが少ないということです。イベントスクリプトの動作確認は、なるべく古いバージョンで行ったほうが確実です。

SUI事始めのスライド

今回Dropbox Paperというサービスを使ってみました。
決してスライドとして用意するのが面倒だったからとかそういうわけではn(以下自重)
発表時はスライドに大事な内容をひとつ入れそびれていたので補記してあります(showメソッドについてです)。
もし間違いや分かりにくいところがあればTwitterなり記事のコメントなりでご質問ください。

paper.dropbox.com

次回予告

さて、本日21:00より、DTPerのスクリプトもくもく会#7の募集を開始しました!

dtpmkmk.connpass.com

今回は都合によりコワーキングスペースでの開催で、会場費がかかるため有料開催としました。参加者の皆さんには申し訳ないのですが、ご理解のほど、お願いいたします。
スペースにはWi-Fiの用意があるのですが、暗号化規格までは調べられませんでした*2。なのでDropboxの更新やWebメールなどでセキュリティが心配な方は、ご自身で何かご用意いただいたほうがいいかもしれません。
一応、主催を含まず6人くらい参加していただけるようなら敢行し、参加人数で会場費を頭割りにしようと思っています。人数が多いほうが1人当たりが安く開催できますので、皆さま、どうぞ奮ってご参加ください!www

*1:ECMAScript5(JavaScriptの規格のことで、ExtendScriptはES3基準)以降で使えるJavaScriptのメソッドです。

*2:問い合わせたのですが、運営側もそこまで把握してませんでした…。