Windows + Adobe CC illustrator / CEP 5 でイラレのカスタム UI を作ってみる (3) ボタンを作ってリロードする


Introduction

Adobe illustrator (イラレ) の仕事では線幅やカラーが厳格に指定されている図形を多用する場合があります。(例えば地図作成や誌面デザイン、手芸の手順書 etc.)
illustrator では既定で直線や円などの描画モードがワンボタンで選べるので、同様に所定の図形をワンボタン化できないか調べてまとめました。

この記事は CC 版 illustrator / Windows 環境が対象です。この章ではボタン作成の第一歩として、エクステンションをリロードするためのボタンを作ってみます。

illustrator のエクステンションはリロードが大変

エクステンション開発に当たっては、コードを組んでは試すような試行錯誤が必要になります。ところが illustrator でこれをやろうとするとリロードの問題に突き当たります。エクステンションの中身を更新しても、illustrator を再起動しない限り変更が反映されないのです。

試しにサンプルプログラムでボタン押下時に出力されるアラートの文章を変えてみましょう。
これは jsx フォルダ下に入っている hostscript.jsx に記述されています。以下の "hello from~" の中身を書き換えればアラートが変わるはずなのですが、

変更前
function sayHello(){
    alert("hello from ExtendScript");
}    
変更後
function sayHello(){
    alert("hello from ExtendScript_changed");
}    

illustrator を起動した状態でこのように変えて hostscript.jsx を保存しても、アラートは変わりません。エクステンションを閉じて開きなおしてもダメです。CefClient もこのツールを裏から覗いているだけなので、クライアント側でリロードしても反映されません。
変えるには illustrator 自体の再起動が必要になります。

スクリプトを少し変えるたびに illustrator を再起動するのは大変です。
今回はスクリプトをリロードして変更をすぐに反映できるような、リロードボタンを作ってみましょう。

ボタンを作る

CSS の解説のところで少しやりましたが、要は button タグでただ作るのではなく関連する CSS を指定してあげ、なおかつ処理を呼び出すための ID を一意に与えてあげれば OK です。ここでは btn_reloadpageandscriptとしました。
結局 [Call ExtensionScript] のところをそっくり真似して、index.html を以下のようにします。

変更前
        <div>                
            <button id="btn_test" class="topcoat-button--large hostFontSize">Call ExtendScript</button>                
        </div>   
変更後
        <div>                
            <button id="btn_test" class="topcoat-button--large hostFontSize">Call ExtendScript</button>                
            <!--リロード用のボタンを追加-->
            <button id="btn_reloadpageandscript" class="topcoat-button--large hostFontSize">Reload</button>                
        </div>   

この状態で index.html の見た目はこのようになります。

なるほど、これでもいいんですが [Call ExtendScript] ボタンと同じく、[Reload] も横長に引き延ばしてみましょう。
styles.css に btn_reloadpageandscript 専用の記述を加えます。

変更前
#btn_test{
    width: 100%;
}
変更後
#btn_test{
    width: 100%;
}

#btn_reloadpageandscript{
    width: 100%;
}

横に伸びました。一旦これで行きましょう。

リロード処理を書く

それでは、[Reload] ボタンをクリックしたときにエクステンションがリロードされる処理を記述していきましょう。
まずはユーザーの目に触れる部分である index.html の更新です。これはブラウザで [F5] を押すがごとく、ページを更新してしまえば完了です。
JSX は基本 index.html 表示に干渉できない (らしい) ので、これは main.js の方に書きましょう。例によって、今ある #btn_test の記法をいただいて #btn_reloadpageandscript の処理を記述します。画面更新の window.location.reload() を追加します。

変更前
        $("#btn_test").click(function () {
            csInterface.evalScript('sayHello()');
        });

変更後
        $("#btn_test").click(function () {
            csInterface.evalScript('sayHello()');
        });

        $("#btn_reloadpageandscript").click(function (){
            //リロードのための追加スクリプト\
            window.location.reload();
            //ここまで
        });

これで index.html を編集した後に Reload ボタンを押すと、すぐに反映するようになるはずです。たとえば [Call ExtendScript] ボタンの表示を適当に変えて Reload を押すと、

すぐに反映されました。

ところが JSX についてはまだリロードできません。たとえば sayHello() のアラートで出てくる文言を以下のように変えてみても反映されません。ウィンドウをリロードしても JSX スクリプトは併せて読み込まれないようです。

hostscript.jsx
    alert("hello from ExtendScript_changed");

これを攻略するためには main.js 側で明示的に hostscript.jsx を呼び出します。sayHello() を読んでしまうとアラートが出るだけなので、そうではなくて JSX 全体を読むことにします。

hostscript.jsx は絶対パスで指定して読み込まないといけません。ベタ打ちでもいいのですがシステム側でエクステンションファイルのパスは読み込んでいるので、これに "/jsx/hostscript.jsx" のパスを付け加えて絶対パスを作ります。

(以下参考)
https://ten-artai.com/2018/07/1404/

変更前
(function () {
    'use strict';
    var csInterface = new CSInterface();

変更後
(function () {
    'use strict';
    var csInterface = new CSInterface();

    //JSXファイルパスの取得
    var jsxPath = csInterface.getSystemPath(SystemPath.EXTENSION) + '/jsx/hostscript.jsx';
    var jsxscr = '$.evalFile("' + jsxPath + '");';

    //ログ出力
    console.log(jsxscr);

これで、後で evalScript() に渡すための文字列 evalFile("C:\Users~~<パス>") ができたはずです。ログ出力するようにしておいたので、例のデバッグ用ブラウザ (CefClient) で見てみましょう。

コンソールを見ると、以下のように出力されています。よさそうです。

Reload ボタンを押したとき、jsxscr に格納したパスのスクリプトを読み込むように以下のように変更します。

変更前
        $("#btn_reloadpageandscript").click(function (){
            //リロードのための追加スクリプト\
            window.location.reload();
            //ここまで
        });
変更後
        $("#btn_reloadpageandscript").click(function (){
            //リロードのための追加スクリプト\
            window.location.reload();
            csInterface.evalScript(jsxscr);
            //ここまで
        });

以上で変更は終了です![Reload] ボタンをもう一度押すと、今度はアラートが変更されています。

おまけ: 画面リロード処理の場所の検討

今回、リロード処理はすべて main.js の中に書きました。これは CEP における処理の呼び出しが index.html --> main.js --> hostscript.jsx の順になっており、さらに main.js 側の JQuery 流の記述で「どのボタンで呼び出されるか?」を指定する方式になっているためです。

筆者はしばらくこの方式でリロードボタンを愛用していたのですが、一点問題が出てきました。main.js の途中で、リロードボタンの処理の記述より前の段階でタイプミスなどのバグが出てしまうとリロードが効かなくなり、illustrator を再起動せざるを得なくなるのです。

この後の章で書くように今後は main.js は橋渡し程度しか担わないので、main.js を触ってバグが出てしまう場面は少ないのですが、対策するとすれば画面のロード window.location.reload() は index.html 側に書けば OK です。main.js が壊れていても、index.html 側でリロードを呼び出せるからです。

index.html
    <div>
        <!--リロード用のボタンを追加-->
        <button id="btn_reloadpageandscript" class="topcoat-button--large hostFontSize" onClick = 'window.location.reload();'>Reload</button>                
    </div>   

ただし例外的に index.html 側に処理を書くことになるので違和感はありますが。

まとめ

ここまででリロードボタンの実装は完了です。
次章以降ではこの機能を使って効率よく試行錯誤していきましょう。