InDesign:セル群それぞれ結合 & セルのコピペ後に属性だけ復元

鮭がひたすら川の上流を目指すように、DTPオペレーターはデザイナーを志して然るべし、
と思っていた時期が長かったんですが(そのくせがんばってはいなかった)
トータルでディレクションできないぶんにはもにょる作業ばっかり多くて…
もうトシもトシなので、まず問題なく一丁前にできる事をやるのが筋だよなあ、てのもあり。

というわけで、行きがかりですが転職しました。年末に。
素人指示の素人赤字な現場にいたせいで、久々に組版してますという実感。自動化がいくらでも生きる職種。
つまり、イラスター現場からインデデ現場に戻ってきました。
以前のように慌ただしい月刊ファッション誌などではなく書籍系ですね。

そんなんで、また今後InDesignの記事ばっかりになっていくと思います。
というかInDesignしか触らないので、ほかの2つはほかの場でのみ使う感じになりそです。
衰えがこわい。


で、こないだ片付いたのがQuarkドキュメントの改版をInDesignで、というやつ…
もう聞いただけで笑顔が曇りますが。ひとごとならよかったのだがw

中でも表組が、あのー、
タブ送りの複数行に罫線を別置きしただけのやつ。


このまま表に変換してやればいいんだけど、各種セル属性の設定がめんどうなので作り置きの表に流し込みたい。
でも構造上、複数行のセルは実質複数段落でできているので、表に変換するとセルが小分けになっちゃってしまっちゃう。

ので、セルの結合をしたいんだけど、たとえば「n列の3、4行のセルを結合」を列ごとに、みたいなことは一括ではできない(と思う。標準機能で方法わかる方いらしたら教えてください)。

ので、スクリプト書きました。


id_mergeEachLines.jsx

お手元の環境で動かなかったらがまんしてください。


あそびかた

結合したい単位でセル群を選択します。
選択は、1行または1列以内であることが条件となります。
(作り込んでないので)

スクリプト実行します。
上図のような選択であれば、2行分のセルを列ごとに結合します。

で、このような結果に。

逆に、実行時にこのように選択していると、今度は行ごとに結合します。

という判別をしているので、2×2ごとに4つずつ結合、とかは今のところ非対応です。
できると便利なんだろうなあ!(中空を見つめている)


もうひとつある

で、で、整形された表になったとして、ヒョーマットにどう流し込むか、って事なんですけども。
選択セル群の行/列の個数が一致していれば表to表でコピペができます。
が、セルの属性もまるごとペーストされちゃってしまっちゃいます。
表スタイル/セルスタイルなどの用意があっても適用しなおしはちょっとめんどくさい。

ので、スクリプト書きました。


id_restoreCellStyles.jsx

お手元の環境以下略


あそびかた

まず、属性が崩れてもいいので、かまわず一旦コピペしちまいます。

ペースト後の選択状態を残したまま、スクリプトを実行。
セルの文字列を覚えて、ペーストを取り消しして、あらためて文字列を移植する、という処理です。

おーやったー。

コピー元とペースト先、同時には選択できないため、このような設計としてみました。
瞬発的に書いたものなので、複雑なカタチの表では試しておりません。

さあさあさあさあ早く帰りましょう。

 

でーす。

Facebooktwittergoogle_plus

「shag」のこと

えー、長く携わっておきながら自分のblogでは一切触れていなかった「shag」について、
現状とこれからのことをお話します。

「shag」計画は、中綴千頁さん作「仕上げ屋」を原型とする模倣品を制作とする物でした。
当時、本家のほうはInDesignのバージョン対応を兼ねた新バージョンがリリース目前、調整中といった様子のまま長らく動きを見せておらず、主要機能の模造を依頼されたときは業界の需要を感じ、なんとかかんとか形にしてリリースしました。
これがshagバージョン0.46です。

このあと、幾人かの開発協力を得てshagは機能を増やし、精度と信頼性を上げていきました。
当時のウチはコレを実務で大いに活用していたので、有用と思われる機能の発案はとどめるところを知らず。できるかできないかは後で考えるといった体で次第にパレットは肥大化していきました。ハリボテですけど。
それでいて操作性はそれなりのわかりやすさであったと自負していますが…
作り始めた当初、ここまで巨大なスクリプトになるとは思わず、ついついダラッとした設計をしてしまい、後でものすごく苦しむ事になりましたが。

といった流れでみちみちと完成に近付いていってたのですが。
が。
2014年夏、身辺に変化が起こりました。転職というやつです。
これにより、実務での実用・テストの機会を失いました。
加えて、アイドル歌手という職業に於けるタイトなスケジュール管理の下での開発時間捻出は非常に困難となりました。
ウチだけでなく主要開発陣についても同様の変化があったようです。
みんな忙しすぎて身動きが取れないのです。仕事の単価は下がる一方です。

そうしてほぼ2年が過ぎまして。
フリー版としてリリースした物に含まれていない機能は2つ。
処理範囲指定とフィルタリング。
処理範囲指定は完成しております。
画像の種類でふるい分けするフィルタリング機能は、脳内では完成しておりましたが手つかずに終わりました。
拙作「SelectionExpander.jsx」のソースを応用すれば雑作もない事ではあったのですが。

以上で「shag」計画はひとまずの区切りをつける形となりました。

今後のこと

正直なところ、当時の自分が書いたコードを今の自分が見て思った事は
「ぜんぜんわからん」、「ぐちゃぐちゃだなあ」、「見たくないなあ」です。
しかし根幹から書き直す時間的余裕はありません。
今後ですが、
・実装予定で結局実装しなかった機能のコントロールを削除(トルツメ)
・いずれ公開しようとしていたPro版にのみ搭載していた機能(ページ範囲指定など)を有効化
を整えた物を最終版として公開、以後はサポート作業のみ
という事で開発陣一同、手打ちとなりました。
それへの着手もいつになるかさっぱり見えないのですが。。

以上、さえない状況報告でした。

Facebooktwittergoogle_plus

タイトル考えてなかったけどInDesignでスクリプト覚えましょうそうしましょう(月)

はいはいどもども。続いてないけど続き。

前回はスクリプトで処理するってどういうこと、
プロパティ探せ、オーケー流星号
という内容でした。
部品だけ並べたてたかんじ。これだけではまだ敷居が高いと思わせてしまうでしょう。

今回は実際に白紙状態から組み立ててってみます。
実用的なヤツがいいよなあ。
でも長らく実務から離れてるんだよな。


んでは、

空の図形を削除するスクリプト

を作ってみるとします。一見かんたんっぽいし。

まずは脳内または紙面または画面上に、フローチャートを作成してみましょう。(実際あまりやったことありませんが…)
プログラマー的な書式がベストでしょうけど(ぐぐりましょう)、自分がわかれば(数日後の自分がわかれば)どんな書き方でもいいでしょう。

ここで、いま思い付く限りの可能性を書き出して対処していきます。
ウチはまるっきりの初心者ではないのでここでほぼばっちりめに書けてしまいますが、それだとちょっとあれなので、わざと過去の経験を生かし、見落としまみれの穴だらけにしてあります。
160512a

せめてもうちょっとまじめに書きましょうか。
あと、フリーフォントは字間がイラッとする事が多いので気をつけましょう(使わせてもらっといてなんなんですけど…)


というわけでまだまだ大ザッパだけど、こんなかんじ。
160512b

これを眺めた時点で、処理の流れが間違ってないか確認。
これだとうまく動かない要素が思い付く場合もありますが、実際にスクリプトを動かしてみてから吠え面かくのもアリでしょう。
ではこれを設計図として、実際にスクリプトを書いてみましょう。
※今回は不完全なソースコードがとっちらかるので、いつものkamisetoさんの置き場は使いません。

さて。いいのかこれで。ほんとにいいのか。


まず処理対象はドキュメント内すべてのページアイテムにしました(つもり)。
allPageItemsは前回まで扱ってきたコレクションオブジェクトと違い、ほぼ純粋に配列です。ただし読み取り専用です。ここから直接足したり引いたり書き換えたりはできません。これをループ処理。
allPageItemsのi番目の塗りカラー(fillColor)と線カラー(strokeColor)それぞれのnameプロパティを参照しています。
fillColorとsrtokeColorはどちらもSwatchクラスです。まーそのスウォッチ。これの名前が[なし]に一致しているかを見ているわけです。

注意点は、ベーシックなスウォッチ以外ではこの方法は万能ではないこと。ベーシックな物でも黒、白などはカラー値だけが一致していてスウォッチが適用されていない場合があるわけで。。
そんなこんなーで、塗り線とも[なし]なら、ブリッと削除。allPageItemsは読み取り専用ですが、要素のPageItemオブジェクトは削除とかできます。するとallPageItemsのlengthは1つ減ります。そして次のオブジェクトを、と順々処理。全部やったら挨拶して終了。
という内容ですが。
まあ、ザルですw 穴だらけ。


とりゃえず一番の問題点は、えー、前々回の図を参照。
160427d

ループ中、i = 0 のとき、アカレンジャーを削除すると残った人たちが一歩ずつ前に詰めます。
でも変数iはそんな事情なんか知りません。教えてないので。無邪気なままです。ループは淡々と繰り返され、今度は i = 1 で処理されます。
すると、アカの次にいたアオがスルーされてキレンジャーが次回の処理対象になってしまう。あらあら大変。
解決法はいくつか。


・allPageItemsをいちいち取得し直しているので、前もって代入しておいた配列変数をループ処理する
・allPageItemsを逆順(昇順 -> 降順)で処理する
・オブジェクトを削除した直後に変数iを -1 しておく
・すぐ削除せず、「あとで消す」と記憶だけしておいて、チェックのループが終わったら最後にまとめて削除する


4通りとも書いてみせるのもかさばるし紛らわしいので。1つめ+4つめの案だけ採用して書き直してみましょう。
※諸事情でそうなりましたが、実際のところ1つめ or 4つめ、どちらかだけの実装で直りますこれ。

しつこいけどフローチャートから直しておきますね。
がんばってかきました。
160512c

これをもとにスクリプトを書き直します。最後の挨拶は完全にネタなので気軽に消しました。

今度はどーでしょう。


「最後にまとめて削除する」と書きましたが、結局はまたループで、1個ずつ削除するわけですが…
削除を実行している行は、
hoge = kesuAry.shift( );
hoge.remove( );
を1行で済ませたもの、と考えてください。


これで「塗りも線も[なし]のオブジェクト」は残らず削除される事でしょう。
どうじゃ、ずんとましになったじゃろう。
これ、非表示レイヤーの中身も関係なく削除されるんですよー。すごいでしょー。
でも、レイヤーやオブジェクトそのものにロックがかかっていると削除できません。内包しているグループも同様です。


要件のアラ探しは尽きないんですが、望まぬ処理をしてくれようとしてエラーで止まるヤツは、自分使い用であれば無視してもいいかと思います。
もっとも、処理途中で止まるやつは取り消しも大変で厄介なこともあるんですが。。

さておき、ここでまた問題ですね、はい。


・非表示オブジェクトは許してあげたい(とした場合)
・ロックがかかってたら解除してから削除しないといけない
・でもレイヤーのロックは一時的に解除しても最後には元通りにしてあげたい(とした場合)


……とかですね。あのー今回はやりませんけども。特にロックはものすごくめんどくさい事になるのでやりません。今回は。

とりあえずこのへんで終わりにしたいんですけど、
気付かないフリをして進めた様々な問題を、脳内で思い付く限り晒して締めます。


・塗り&線カラーがあっても不透明度が0%だった場合は?
・回り込みオブジェクトだった場合は?
・テキストフレームだった場合は?
・画像が配置されたグラフィックフレームだった場合は?
・マスターページアイテムだったら?
・見えないボタンだったら?
・インラインオブジェクトは消せなくない?


……ぐらいですね。まだまだ出そうですけど。

以上、おそまつさまでした。
ちゃんとした人にはソースコード配置のため今回から使い出したGitHubが全然使いこなせてないのがマルバレでほんとお恥ずかしい限りですけども。
ちょっとこっち方面を覚えていかなければいけなくなってきているのでがんばります。

でーすー。

Facebooktwittergoogle_plus

ちょっとのスクリプト書いたから誰得だけどねちねち解説するよ

GW進行中いかがおすごしでしょうか。
客商売向けの印刷物を多く扱ってると死にますね、はい。
休みの分だけ余計に働く、じゃ済まない量っすよこれ。。
というか低予算での引っ越し作業がぶつかって個人的にやばかったです。
帰ってから23時過ぎまでバイクで荷物積んで往復往復。

というわけで、久々にInDesignさわりました。ほんっと久々。
で、原稿がエクセルだったのでデータ結合で流し込みなど。
そしたら原稿にない「商品名、いいとこで改行しといてー」が発生しまして。
改行のきっかけ箇所の動向はある程度つかめたので、
ある程度ではあるものの自動化自動化。
でもこのスクリプト、ニッチすぎて配布しても誰の役にも立たない。

160427a

ので、趣向を変えて(ネタ切れとも言う)ソースをひもといた解説などしてみましょうか、ということで。あまり自慢できそうな書き方もしてないですけども。
ちょっと書いてみたい人とか、ちょっと直してみたい人とか、
なんかそういう人のタシになれば。ならんかもなー。
独習を始めたばっかりの頃の自分へ向け、噛み砕いて書いています。用語は最小限にとどめています(わからないから)
横文字箇所についてはJavascript入門サイトやお手元の入門書など参照してください。
ツッコミどころは多々あると思います。適宜訂正お願いしますー。
自分のわかってなさが露見するようでやや汗かいてますが
ほぼほぼほぼ我流なので拾えるとこだけ拾ってくださいまし。

スクリプトはこちら



id_niceReturn.jsx

名前なんかわかればてきとうでいいのだ。
MacOSX 10.9.5、InDesignCS6で使用しました。
うっかりしてましたがヨコ組み専用です。タテ組みではまともに動きゃしません。
それは次回やりましょう。
また、X座標をダシにしているので、アホみたいに回転のかかったテキストフレームでもきちんと誤動作します。

2016.04.28 15:38 あるふぁさんよりご指摘があり7行目に処理を追記
2026.05.02 縦組みでも動きましたorz 勘違い大将。



 

ダウンロードしてもらったスクリプトには、各行これでもかってぐらいコメントを散りばめてありますが。

以下、自分なりの解説をだっらだらとしております。ウチと心が通じていればきっと理解できる(横暴)

 



3行目:
var tar = app.activeDocument.selection;

ここが実質の書き始め行ですが、この行はtarという変数を宣言しつつ、InDesign前面ドキュメント選択オブジェクト群を入れます、という式です。ここで変数に入れる理由は、以降でいちいちapp.activeDocument.selectionと書くのがめんどくさいからです。
appはアプリケーション(今回はInDesign)、activeDocumentは前面にいる書類、selectionは選択ハニー。

var は変数を宣言する時の物です。ヨソのスクリプトで同じ名前の変数があったとしてもそれはそれ、これはこれ、というやつです。
ここでvarを省略すると、InDesign上の他のスクリプトで別の意味で使用されている変数tarを書き換えてしまう恐れがあります。んなもん知るかよって言いたいとこですが、まあ、まあ。
プログラム(ここではInDesign)全体で参照できる物をグローバル変数、関数内(ここではひとつのスクリプトファイルがほぼ同義)だけで参照できる変数をローカル変数といいます。
変数名の競合を回避するためのクロージャ関数化というものがありますが、それは後述(と言っておいてそのまま忘れるやつ)。
tarは任意の変数名ですが、命名はてきとうです。自分でわかりやすければいいです。targetの略のつもりですが、tgtと書く人もいます。まあ自由です。予約語(スクリプトの命令や既存オブジェクト名)に名前がかぶらなければなんでもいいです。
えらい人の例文では、この任意の変数名も英語っぽい、いかにももっともらしい字面だったりするので、これはこういう決まりがあって、この通りにしないとちゃんと動かなかったり、笑われたり馬鹿にされたりするんだ、と思っていた時期がありました。

selectionは配列(Array)でできています。
オブジェクトがプチクリームパン1個だとすると、配列は、あのー…袋にプチクリームパンが5個ぐらい入ったやつ、みたいな…。
配列内の1つ1つのオブジェクトを、エレメントと呼ぶらしいです。今回のエレメントはドキュメント上で選択されたオブジェクトです。
配列のエレメントがさらに配列でできている物を二次元配列と呼ぶらしいです。プチクリームパンの袋が配列、それが入った段ボール箱が二次元配列、みたいな…。160427c
三次元、四次元などがあるかは知りません。そこはこだわらないほうがいいです。
仮に配列tarの2番目のエレメントをさわる時は、tar[1]と書きます。エレメントのインデックスは0から始まるためです。
選択オブジェクトの配列は、CS4以前は階層順、CS5以降は選択順となります。一括ドラッグ選択した場合は階層順となりますが、Shift+ドラッグ選択を複数回に分けて行った場合は並びが違ってくるのでご用心。


4行目:
if ( tar.length == ) exit ( );

分岐処理です。条件によって、やるやらないを振り分けます。
if (式) hoge; は、( )内の式の値がならhoge;を実行します。なら実行せず次へ行きます。
( )内には真偽値(Boolean、trueかfalseか)が出るような式を書きますが、
式の値が数値である場合は、0以外ならtrue、0ならfalseとして動作してくれます。例えマイナス1でもtrueです。
変数tarは現在、配列オブジェクトです。配列はlength(長さ)というプロパティを持っています。
プチクリームパンが何個入りかを調べるものです。ここでは選択オブジェクトの個数がtar.lengthというわけです。
選択されているオブジェクトがひとつもなければ(lengthの値が0なら)ここで終了したいので、配列tarのエレメント数が0と同じか、を比較して真偽値を得ます。
exit( )はスクリプトを終了する、メソッドという物です。18行目で後述する関数と同じような物です。後ろのパーレーン( )は必須です。忘れると動きません。
このexit( )は、PhotoshopにもIllustratorにもありません。べんりです。やったぜInDesign。
で、選択オブジェクトが1つでもある場合、次の処理にいけちゃいます。


6行目:
var obj, myFind;

なんか5行目に空行を入れていますが、自分で見やすくするためにてきとうに空けたやつです。そこは自由です。何行でもどうぞ。
この行では、のちのち使う2つの変数をあらかじめ宣言しています。
objはObjectの略のつもりですが、my〜は既存オブジェクトと名前がかぶっているかを調べるのがめんどくさい人がよくやるやつで、たいがい頭にmyをつけておけばかぶらない、という事らしいです。
varのあとに変数名を次々”,”で区切って宣言していけば、それぞれをvar付きで宣言したことになります。


7行目:
app.findGrepPreferences=NothingEnum.nothing;

※この行はあるふぁさんよりご提案いただき、まるもらいの上あとで追加しました。ありがとうございます。
GREP検索設定の一切を未定義化します。検索文字スタイルなど設定してあった場合はこれをしておかないと文字列だけマッチしても拾ってもらえなくなります。
とのことです。ごもっとも。。やられましたなあw

 


8行目:
app.findGrepPreferences.findWhat = “(?<=[! 産」)])[^ 産」\n\r]|[(「]”;

やや長いですが
この行はInDesignGREP検索設定検索文字列を定義しています。正規表現部分は、改行を入れる「いいところ」を探すやつです。
〜Preferense というのは、たいがい〜設定というやつです。今回は複数形のPreferencesですけど。


10〜16行目:
while ( tar.length ) { }

ループ文ってやつです。( )内の条件がtrueであるうちは延々{ }内(16行目まで)の処理をします。
{ }内でbreak;と書いておくと強引にwhile( )ループから抜ける(その先の処理にかかる)ことが可能です。
今回は{ }内でtar.lengthに変化を与える処理があり、配列tarのエレメント数が0になったら式の値はfalseとなりループを抜ける仕組みです(4行目の解説参照)。今回のスクリプトはこのループを抜けたら終了します。
ヒマな人は17行目に alert (“処理完了でーす”); とか書き足しておくと少しかわいいかもしれません。知らないけども。


11行目:
obj = tar.shift( );

shift( )は、配列から先頭エレメントをひとつ抜き出して代入するメソッドです。4行目にもメソッドexit( )が出てきましたが、あちらはオブジェクトにくっつけないで単体使用するもの、こちらは配列クラスのメソッドです。shift( )により配列tarからは先頭エレメントがなくなります。だんご3兄弟から長男がいなくなります。
このほか、三男がいなくなるpop( )、長男の前に1人追加するunshift( )、三男の後ろに四男を追加するpush( )などがあります。
160427d
(↑クリックでオリジナルサイズ見れます)
前行で参照していたtar.lengthは、ここで-1される事になり、16行目まで処理を続行したら10行目に折り返し、while( )内の式の値はfalseとなり、ループを抜ける、という流れ。
ここでは宣言済み(で中身まだナシ)の変数objに、配列tarの先頭エレメントを抜いて代入しています。これで変数objには選択オブジェクトの1つ目が入りました。この先objに対して何かを行うと、その選択オブジェクトに対して処理がされます。
それに対して、selection配列を参照した配列tarから1つ抜いてもselection配列は元のままです。選択が解除されたりはしません。
この違いについては、カラダで覚えるか、えらい人にききましょう。ウチは前者です。。


12行目:
if ( ! obj.hasOwnProperty ( “parentStory” ) ) continue;

if文2度目の登場。
( )内の先頭についた”!”は、式の演算結果の真偽値を逆転します。trueとfalseが逆になります。うそが本当に。
hasOwnProperty( )は、選択オブジェクトobjが”parentStory”というプロパティを持っているかを真偽値で返します。parentStoryはストーリーオブジェクトです。選択オブジェクトがテキストフレームの場合はobj.parentStoryと書くとそのストーリーを参照することができます。ここではそのストーリーオブジェクトが存在するかを見ています。存在しなければ選択しているのはテキストフレームではないと見なし、処理は行わずほっといて次に行きたいからです。
ただし先頭に”!”があるので、この場合は「選択オブジェクトにストーリーが存在しないか」となります。ちゃんとなかった場合、後ろのcontinue;が実行されます。
continueは、以降の処理(13〜15行目)をスルーしてループを続行します。ここでは10行目に飛びます。
もし”!”がなかったら、どう書くことになるか、というと
if ( obj.hasOwnProperty ( “parentStory” ) == false ) continue;
または
if ( obj.hasOwnProperty ( “parentStory” ) ) {
13〜15行目の処理
}
などと、少し冗長になったり、入り組んでしまったり。まあこの例文だと、ちょっとしか違わないじゃんって自分でも思いますが…13〜15行目がもっともーっと長い内容の場合とか、これが入れ子になって連続した場合、ちょっとかなり見たくない感じになってしまいます。まあ、たまにやるけど。


13〜15行目:
if ( obj.lines.length > obj.paragraphs.length ) {
pepsi( obj );
}

前行のif ( ! obj.hasOwnProperty ( “parentStory” ) ) continue; に引っ掛からなかったオブジェクト、つまりテキストフレームを相手にしています。
テキストフレーム内の行数 > テキストフレーム内の段落数であれば、objを関数pepsiで処理。
このスクリプトの目的は「いいとこで改行」なので、行の折り返しがある(行数と段落数が等しくない)物にしか用事がないわけです。
関数名pepsiは、これもてきとうです。ペプシ好きです。


18〜25行目:
function pepsi ( obj ) {

はい出ました関数。関数とメソッドの違いについてはけっこうめんどくさい論争に見えたのでウチは関わりません。同じだと思っていいんじゃないかなあ…
関数名 (引数)
という書き方をします。渡すべき引数がなくても( )は必須となります。
最初に覚えさせられるalert (“Hello World!”); も、alert( )が関数、文字列”Hello World!”が引数です。返り値(戻り値ともいう)を返す物もありますが今回は用事がないので触れません。
14行目で関数pepsiに引数objを渡しました。pepsiの中でそのobjを処理します。
function は関数の宣言です。function文はスクリプト内のどこに置いても構いませんが、今回は下のほうに集めてみました。


19〜24行目:
for ( var i = obj.lines.length – 2; i >= 0; i – – ) {

ループの花形、for文。
for (最初に実行される式; 条件式; 繰り返し時に実行される式) { 条件合致時の処理 } と書きます。
変数iを定義し、そのiの値が条件を満たす間{ }内を実行する、繰り返される時iの値が変動する、という仕組みです。

ここでは末尾から先頭に向けて処理しています。スクリプトの処理内容がテキストを改行していく物や字数が増減する物の場合、先頭順で処理するとあとの様子がどんどん変わっていき不具合が起きやすいので。テキストがあふれたりするとフォローがめんどくさいし。

以下、各式をちょっとこまかく

var i = obj.lines.length – 2;
テキストフレームobjのlinesコレクションのlength -2 を変数iに代入しています。配列およびコレクションのエレメントは0番目から始まるため、行数-2、つまり2行あれば0行目、3行あれば1行目から始めたい、ということになります。

ここで「じゃテキストが1行しかなかったらマイナス1行目ってなるじゃんすか!エラー出るよエラー!」などと思われた聡明な方は、13行目を見直しましょう。
行数が段落数より多い物しか、この行まで来れないことになっています。空っぽのテキストフレームでも行と段落は必ず1つある事になっているので、ここまで来たからには最低でも2行はあるわけです。やーいやーい。

i >= 0;
変数iが0以上、が条件式。0行目も処理したいので0も条件に含んでいます。

i – –
変数iの値を1つずつ減らします。2行目を処理したら次は1行目、0行目、と処理します。
i = i – 1; とわかりやすく書いてもかまいません。
– – i というのもありますが、ここでは適しません。それがなぜなのか気になったら調べてみましょう。

Linesクラスはコレクションクラスといい、アプリケーションに依存した物です。内包アイテム(エレメント)はLineオブジェクトだけとなりす。配列変数ではありません。ぱっと見は似てるし使い方も半分は同じなんですが別物です。


20行目:
myFind = obj.lines[i].findGrep ( );

冒頭で宣言したまま忘れかけていた変数myFindの登場。いろいろ書き直しているうちに関数の外で変数宣言してしまっていますが、関数の中でしか使わない変数は関数の中で宣言したほうがいいです。悪い見本ですが、なおしません。
変数myFindに、選択テキストフレームobj内のi行目のテキストを対象にGREP検索した検索結果を入れています。
findGrep( )はInDesignの「検索と置換」ウィンドウの「検索」ボタンと同様ですが、検索結果は選択ハニーにはならず、Textオブジェクトの配列が返り値として変数myFindに入れられます。


21〜23行目:
while ( myFind.length ) {

10行目と同じ、配列myFindのエレメント数が0になるまでのループ。


22行目:
drPepper ( obj.lines[i], myFind.shift ( ) );

2つ目の関数処理です。ドクターペッパー好きです。
今度は引数が2つ。変数objのi行目と、配列myFindの先頭エレメントを抜き取ったもの。
obj.lines[i]はLineオブジェクト、myFind.shift( )は配列となった検索結果の先頭にいるTextオブジェクト。
関数を使う理由については、まあ気分で。。
・処理が長くなって見づらくなったので、ここからここまでを関数にして外にどけてしまえ、
・ここからここまでの処理は他の所でも使うから関数にして使い回そう、
などなど。
経験上、一度できあがったスクリプトを一部関数化するときは変数の取り回しなどで人的エラーを起こしやすいのでご注意。※と書いたそばから、ほんとに自分で超ミスッてて大幅に修正しました…


27〜39行目:
function drPepper ( obj, chr ) {

引数が2つありますが、実は関数内の引数と関数呼び出し時の引数は変数名がぜんぜん違ってても関係ありません。何番目の引数か、で扱われます。処理内容によっては引数の個数が合わなくても平気だったりします。
第一引数のobjは、この関数の外のobjと名前が同じですが別物となります。この関数内だけのobjです。
第二引数chrもとくにvar宣言していませんが、引数で宣言した変数名は完全にこの関数内のローカル変数となります。varいりません。〈例文1〉
これに対し、関数外で宣言済みの変数名を関数内でvarなしで使用すると外のやつが書き変わってしまいます。varであらためてローカル変数を宣言した場合は別物として定義されます。〈例文2〉

———————
〈例文1〉関数drPepperの引数名objと関数外の変数objが別物である事の検証
function func ( a, b ) { //引数名にaとbをわざと使用
alert ( a + “, ” + b ); //関数内におけるaとbの正体をあばく–>”4, 5″と出る
}

var a = 2, b = 3; //変数aとbを定義
func ( 4, ); //関数funcに、a、bとは無関係な数値を渡す
alert ( a + “, ” + b ); //関数処理から抜けたら、同様にaとbの正体をあばく–>”2, 3″と出る
———————
〈例文2〉関数の構文内でも外にある変数は生きてるからさわれるんだぜ、の検証
function func1 ( ) { a = 1; } //変数aを1にしちゃうだけのぶっきらぼうな関数その1
function func2 ( ) { var a = 3; } //varをつけた関数2。aを3にしようとしている

var a = 2; //変数aにてきとうな値を定義
func1 ( ); //関数1を処理
alert ( a ); //aの値を出してみる –>”1″と出る
func2 ( ); //関数2を処理
alert ( a ); //aの値をまた出してみる –>やっぱり”1″と出る

これを利用してスクリプト全体をまるっと無名関数にしてしまうことでヨソのスクリプトとの変数名かぶりを回避するのがクロージャという物らしいのですが(←忘れてたので書き足した)、なんとなくイラッとするのでウチはやりません。なんとなく。


28〜38行目:
if ( chr ) {

chrは20行目で行ったGREP検索結果です。検索対象が検索文字列にひとつもマッチしなかった場合、配列myFindのエレメントはundefined(未定義)となります。undefinedはこれはこれでひとつのオブジェクトなのですが、条件式の場合はfalseと同義に扱われます。なので、ここではundefinedでなければ以下の処理を行う、ということになります。
12行目と同様にif (!chr) {return;}としてもよかったのですが。。にんげんだもの。


29行目:
var nextLine = obj.parentStory.lines.nextItem ( obj );

これより先、引数として持ってきたLineオブジェクトの次の行をひんぱんに参照するので、ちょっと長くてイヤなので変数に入れることにしました。
Lineオブジェクトobjを内包するストーリーの、行コレクションのうちobjの次の物、という内容です。


31行目:
var myEnd = Math.max ( nextLine.insertionPoints[-1].horizontalOffset, nextLine.insertionPoints[-2].horizontalOffset );

前行で宣言した変数nextLine内の挿入点のうち、末尾の物と後ろから二番目の物の水平座標を比較して、より大きい方を変数myEndに入れています。

InsertionPointsは挿入点コレクションです。変数nextLineはここでしか使っていないので、
var nextLine = obj.parentStory.lines.nextItem(obj).insertionPoints;
としてしまえばこの行の.insertionPointsがすっきりしたかも知れませんですな。いや逆に伝わりにくいかと思って。。
[-1]は、コレクションのアイテム(配列でいうエレメント)を末尾から参照します。[-1]で一番後ろ、後ろから2番目なら[-2]と書きます。[-0]はありません。配列オブジェクトにはこの書き方はできません。ちなみにこれもPhotoshopやIllustratorのコレクションクラスではできません。やったぜInDesign。

Mathは数学っぽい計算ができるクラスです。累乗とか平方根とか。max( ) は2つの引数のうち大きい物を返り値にするメソッドです。逆のmin( )とかもあります。まあ比べるやつです。

挿入点2つの座標を比較した理由というのが、行末に改行(改段)がいた場合、末尾の挿入点イコール次行先頭の挿入点となってしまい、座標が行頭になってしまっていたからです。比べてでっかい方を使います。


33〜36行目:
if ( chr.insertionPoints[0].horizontalOffset >= myEnd ) {

検索結果文字列の挿入点0番目と、Lineオブジェクトobjの次行の行末、それぞれの挿入点の水平座標を比較しています。これを調べておかないと、せっかく改行しても下の行でまた折り返しが発生してしまう。下行の行末よりも後ろの座標で改行したいのです。まあ禁則処理や均等割付如何で狙った通りにはいかないような気もしますが。。今回は商品名なので左揃えです。160427b


34行目:
chr.insertionPoints[0].contents = “\r”;

contentsは文字列。chr.parentStory.contentsと参照すれば対象テキストフレームの内包ストーリーの文字列がすべて取得できます。ここでは挿入点オブジェクトのcontentsに文字列”\r”を入れています。”\r”は改段記号ですね。えー、挿入点って文字と文字の間じゃないの、なんでContentsプロパティがあるの、などという疑問については、わかりません。。こういう用途で便利ではあるですが。


35行目:
myFind = [ ];

[ ]は中身カラッポの配列オブジェクトです。もうこの行はいちど改行したので、もうこれ以上の処理しません。なので21行目のループから抜けさせるためにわざとカラッポにしています。



とまあ、解説は以上。わかりにくいでしょうか。でしょうな。でしょうよ。。
次回、これを改良してタテ組にも対応させるとします。
体力があれば、その次は必要以上に回転のかかったテキストフレームにも対応したい。してみたい。してください。

 

でーす。

Facebooktwittergoogle_plus