コモノExtendScript100本ノック

超初心者のDTPオペレーターが週にひとつスクリプトを書くブログ

はじめに

超初心者DTPオペレータのExtendScript練習帳です。
主にInDesignで動く小さなものを書いていきます。

勉強中のメモとして書き残しています。
掲載しているスクリプト・情報は、誤った記述を含む可能性があります🙇

ルール📖
  • 週に1つつくる
  • 未完成のものもそこで区切る
目的🎯

079.【Id】タブ区切りテキストのテーブルをJSON形式(っぽい配列)にする

タブ区切りの文字列をJSON形式(っぽい配列)にする関数です。
事前にタブ区切りのtxtデータを読み込んでから実行することを想定しています。
生成した配列を使ってInDesignで自動組版したり、JSONファイルを作成して他のアプリケーションに渡したりするために作りました。
指定した行をヘッダーとして扱い、それより上の行はスキップします。

引数

書名:   令和3年度 論文集           
                
ページ番号 氏名  学年  学籍番号    写真ファイル名
14  田中一郎    1   1111    1111.psd
16  田中二郎    2   2222    2222.psd
18  田中三郎    3   3333    3333.psd
32  田中四郎    4   4444    4444.psd

戻り値

[
  { ページ番号: '14', 氏名: '田中一郎', 学年: '1', 学籍番号: '1111', 写真ファイル名: '1111.psd' },
  { ページ番号: '16', 氏名: '田中二郎', 学年: '2', 学籍番号: '2222', 写真ファイル名: '2222.psd' },
  { ページ番号: '18', 氏名: '田中三郎', 学年: '3', 学籍番号: '3333', 写真ファイル名: '3333.psd' },
  { ページ番号: '32', 氏名: '田中四郎', 学年: '4', 学籍番号: '4444', 写真ファイル名: '4444.psd' },
];

コード

メモ

例外処理

throw - JavaScript | MDN

throw 文は、ユーザー定義の例外を発生させます。現在の関数の実行は停止し(throw の後の文は実行されません)、
コールスタック内の最初のcatchブロックに制御を移します。呼び出し元の関数にcatchブロックが存在しない場合は、プログラムが終了します。

→関数内でエラーを投げると以降の処理がなされないので、ファイルを開いたあとclose()する前にエラーを投げないようにする。
→関数でエラーを投げる場合は、必ずtry/catch/finallyとともに呼び出す。

CSV

CSVにも対応したかったのだけど、結構めんどうそう。
フィールド内にカンマやダブルコーテーションが含まれていた場合を考えると、単純にsplit(',')ではうまくいかない。

デフォルト引数

function txt2json(str, separator, header = 0) {...のように記述することで、関数の定義時に引数にデフォルト値を設定することができる。
該当の引数が渡されなかった場合や undefined が渡された場合にこの値が用いられる。
この仕様はES2015(ES6)からサポートされている。
つまりES3準拠であるExtendScriptでは使えない。

代わりに今回は var header = header || 0; という書き方をした。
あとになって、こういった場合の理想の書き方はどないなもんか気になり、デフォルト引数を使用した関数をTypeScriptで書いてコンパイルしてみた。

//default_arg_test.ts
function default_arg_test (a = 0) {
  const res = a;
  return res;
}
const output = default_arg_test()
$.writeln(output); //0

これが

//default_arg_test.js
"use strict";
function default_arg_test(a) {
    if (a === void 0) { a = 0; }
    var res = a;
    return res;
}
var output = default_arg_test();
$.writeln(output); //0

こうなる。
if (a === void 0) { a = 0; } が今回知りたかったところ。
void演算子は必ずundefinedを返す演算子
なぜa === 'undefined'で判定するよりよろしいかというと、undefinedが書き換え可能であるから(少なくともES3においては)。

var a

$.writeln(a) //undefined

$.writeln(a === undefined) //true
$.writeln(a === void 0)    //true

var undefined = "test" //書き換えると…

$.writeln(a === undefined) //false!!
$.writeln(a === void 0)    //true

(ES5.1以降ではグローバルなundefinedは書き換え不可となっているようです)
今後はa === void 0typeof a === 'undefined'を使おうと思います。

その他

  • includeはエイリアスは読みこんでくれない。
  • デスクトップはパスで指定せずともFolder.desktopでOK。
  • 引数の名前をcharとしようとしたら「予約語だからだめ」と怒られた。予約語なんですね。
  • Excelデータをタブ区切りテキストとして保存すると、カンマが入っている場合にダブルコーテーションで囲まれる。カンマ区切りじゃないのに。
  • xlsxデータはFile.read()できない。exclude()で開くことはできる。

参考

追記

ExtendScriptでのjsonファイルの読み込みについて、後日ひとつ学びがあったので追記。

sysys.blog.shinobi.jp

ExtendScriptのオブジェクトとしてそのまま読めるようなjsonファイルであれば、

var hoge=
#include "hoge.json"

とするだけで、変数hogehoge.jsonをパースしたオブジェクトが入ります。」

便利!

さらに追記

dataはMapにした方が安全かもしれない。

(2022/05/09)

ExtendScriptにおける三項演算子の不具合(?)

追記(2021/10/26)

Twitterあるふぁ(仮)さんに教えていただきました!

2つ目のツイートでご紹介いただいているのはこちらの記事です。 sysys.blog.shinobi.jp

また、Uske-Sさんが詳しく検証・解説してくださっています!

uske-s.hatenablog.com

私が投稿した以下の文章には誤りが含まれますので、正しい情報をお探しの方はこちらの記事をご覧になることをおすすめします。

(2021/10/26)

 


 

ExtendScriptでは、三項演算子入れ子にするとシンタックスエラーになります。

var x = 30;
var y = (x > 10) ? (x < 50) ? 'a' : 'b' : 'c';
$.writeln(y); //条件1・2ともtrueなので"a"になるはずだが、Syntax Errorになる

これについてはフォーラムで解説されています。

community.adobe.com

それとは別に、よく分からない挙動に行きあったので記録しておきます。
簡単に述べると、別の書き方で入れ子にしたときに、エラーを出さずに誤った値が返されることがあるようです(私が何か誤解しているのでなければ…)。

var x = 30;

var z = (x < 10) ? 'a' : 
        (x < 50) ? 'b' : 
        'c';
$.writeln(z); // => b これは問題無し
//Google Chrome デベロッパー・ツールでは
//console.log(z); => b

var zz = (x < 10) ? 'aa' : 
         (x < 50) ? 'bb' : 
         (x < 90) ? 'cc' : 
         'dd';
$.writeln(zz); // => cc これは誤り
//Google Chrome デベロッパー・ツールでは
//console.log(zz); => bb

var zzz = (x < 10) ? 'aaa' : 
          (x < 50) ? 'bbb' : 
          (x < 90) ? 'ccc' : 
          (x < 120) ? 'ddd' : 
          'eee';
$.writeln(zzz); // => ddd これは誤り
//Google Chrome デベロッパー・ツールでは
//console.log(zzz); => bbb

最初にご紹介したフォーラムのスレッドには、

there seems to be some differences in operator precedence in ExtendScript vs. modern JavaScript versions
ExtendScriptと最新のJavaScriptバージョンでは、演算子の優先順位にいくつかの違いがあるようだ)

とあります。
もしかしたらこのことが関係しているのかもしれません。

個人的には三項演算子を使うことはほとんどありません。
他の方が作成されたスクリプトを読むときのために、心に留めておこうと思います。

参考

078.【Acrobat】注釈の外観・プロパティを統一する

概要

「複数人で校正・校閲してPDFに注釈を入れたため、作成者や色がバラバラになっている。著者に送る前に統一したい」というケースを想定しています。

次の処理を行います。

  • 注釈の作成者名を「XXXX」に統一
  • ハイライト注釈の色と不透明度を統一
  • 図形注釈の線の色と太さを統一
  • コメントが「著者問い合わせ」で始まっていたら「【確認】」に置き換える
  • コメントが「【確認】」で始まっていなかったら加筆

使い方

コード

メモ

分からなかったこと

テキストボックス注釈のstrokeTypeを変更すると、中の文字の色まで変わってしまう。
外枠の色だけ変えたい。

参考

GitHubやAdobeフォーラムでコード以外の箇所だけ日本語翻訳する方法

Webサイト上で外国語の文章を読む際は、コンテクストメニューからGoogle日本語翻訳を行っています。
素のままのChromeでこれを行うと、コードブロック内も翻訳されてしまうという難点があります。
「ScriptAutoRunner」というChrome拡張で解決できるので手順を記録しておきます。

ScriptAutoRunnerとは

chrome.google.com

Chrome拡張機能
指定したサイトを開くたびに任意のjavascriptを実行します。

設定

f:id:haraguai_is_bad:20211004132634p:plain

①部分をクリックします。
②実行内容のタイトルを入力します。
③実行内容を入力します。
Adobeフォーラム、GitHub、Indiscriptsの場合

Array.prototype.forEach.call(document.getElementsByTagName('pre'), x => x.classList.add('notranslate'))

・Gistの場合

Array.prototype.forEach.call(document.getElementsByClassName('js-gist-file-update-container js-task-list-container file-box'), x => x.classList.add('notranslate'))

④実行するサイトのホストを入力します。
Adobeフォーラム、GitHub、Indiscriptsの場合

community.adobe.com, github.com, indiscripts.com

・Gistの場合

gist.github.com

⑤プラグをクリックし、有効にします。

参考

077.【Id】ドキュメントを開くときに毎回リンクをチェックする

概要

スタートアップスクリプトとして実行することで、ドキュメントを開くたびにリンクの状態とパスをチェックするように設定します。
下記の状態が検出された場合は、ドキュメントがあるフォルダにテキストを書き出します。

  • リンク切れ
  • パスにアクセスできない
  • リンクの更新が必要
  • リンク先がドキュメントの同階層の(L|l)inks*フォルダ内でない

使い方

  1. アプリケーションの📁Scripts内に「Startup Scripts」という名前のフォルダを作成します。
  2. InDesignが起動していない状態で📁Startup Scriptsに当該jsxを保存します。
  3. InDesignを起動します。
  4. 以降は、特に何もせずともドキュメントを開くたびにリンクチェックの処理が実行されます。

結果表示

  • リンクが正常の場合
    f:id:haraguai_is_bad:20210913115505p:plain:w200
  • リンクに不備がある場合
    f:id:haraguai_is_bad:20210913115535p:plain:w200

f:id:haraguai_is_bad:20210913115545p:plain:w400
(自動でテキストエディタが立ち上がります)

  • indtや別バージョンのinddを開いた場合
    f:id:haraguai_is_bad:20210913115558p:plain:w200

コード

参考

追記(2021/09/16)

リンクファイル名に半角パーレンが含まれていてうまくいかない例に遭遇した。
おそらくメタ文字があることでtest()の結果が意図しないものになったのだと思う。
まだ確認できていないけれど、とりあえずFIXMEを追加した。

076.【Id】別のinddからフォームフィールドを読み込む

挙動

ダイアログに従って、
1. 読み込み元のindd
2. 読み込み先のindd
を選択すると、1のinddに含まれるラジオボタンチェックボックス・テキストフィールドが、2のinddに読み込まれる。 (タブオーダーは変わってしまう)

コード

メモ

読み込んだ後はタブオーダーがめちゃくちゃになっているので、タブオーダーを並べかえるスクリプトを使用したりする。

積み残し

  • タブオーダーも読み込む。
  • フォームのコピー・リネームの処理を、ラジオボタンチェックボックス・テキストフィールドそれぞれに対して繰り返しているので、1まとめにしたい。