k_ikiの雑記帳

DTPのこと、創作のことなど、思いつくまま

ルビ親文字差し替え

随分と昔、それこそAdobe CSシリーズの最初のバージョン向け(いや、もしかしたら2.0向けの時点で既に、かも)に流星さんがVBで作ってくださったスクリプトに、表題のようなものがありました。
振られているルビに影響を与えず、その親文字だけ文字を差し替えるためのスクリプトです。
そこで、書いてみましたがうまくいきません。

var my_sel = app.selection;
if (my_sel[0].rubyFlag == false){
    alert("ルビが設定された文字を選択してください");
    exit();
    }

var my_str = prompt("新しい親文字を入力してください。", my_sel[0].contents);
var my_ruby = my_sel[0].rubyString;
my_sel[0].contents = my_str;
my_sel[0].rubyFlag = true;
my_sel[0].rubyString = my_ruby;

説明のため、一旦話題を変えて標準機能のルビダイアログについて。
標準機能だと、複数の親文字にスペース区切りでモノルビが設定されている場合、親文字のどちらか一方を選んでルビダイアログを開くと……

こんな風に、ルビが設定された親文字全てを選んでくれます。

では、スクリプトの話に戻します。
上記のスクリプトだと、選択した文字しか拾ってくれません。例えば、図示したテキスト最初の文字「山」を選択した場合は「山」だけを。なんだか当然の事を言っているようですが、標準機能のルビダイアログとは動作が違うよ、ということです。
そのまま強引に文字を差し替えてみましょう。例えば、「山」を「川」に。

「路」のルビが見た目には消えてしまいました。ですが、情報としてはルビが残ったままの状態です。
一旦こうなると、ルビを一旦クリアして打ち直してやらないと直りません。
あるいは、上記スクリプトで親文字を両方とも選んで打ち直す(または打ち直さずそのままOKを押す)ことでも直ることは直ります。
 
このスクリプトの改善点としては、複数文字列にルビが設定されている場合、一文字だけ選んだ時の動作が標準機能によるルビダイアログと同様の選択結果になるのが理想ですが、そこで詰まってます。
なんか、すっごく単純なことのような気がするのですが、実際にはそうではありませんでした(^^;
 
今回もまた流星さんのお力をお借りし、上記の私のソースを改変していただきました。
複数文字列にルビが設定されている際、例えば先頭の一文字だけを選んでやれば対象の親文字を全て拾ってくれます。

#target indesign
// つか、メンドイんすけど、コレwww
if (app.selection!=0){
    var sel=app.selection[0];
    if (sel.constructor.name.match(/^Character|Text|Paragraph|Line|TextStyleRange|Word|TextColumn$/)){
        // ルビ文字判定
        if ( ! sel.rubyFlag ) {
            // ルビじゃない文字入ってるぜ
            alert("ルビが設定された文字を選択してください");
            exit();
            }
        // 選択範囲の前方確認
        var fc=sel.characters[0]; // 最初の文字
        if (fc.rubyFlag){
            /* 最初の文字がルビの親文字だったら、その前の文字も同じルビ文字を持つか? */
            rs=fc.rubyString;
            if (fc.index>1){
                ge=fc.parentStory.characters[fc.index-1];
                var aa=[];
                for (;;){
                        if (ge.rubyFlag==true && fc.rubyString==rs && ge.contents!="\r") { // 同じルビ文字だ
                            aa.push(ge.index);
                            if (ge.index-1==fc.parentStory.characters.length-2){ break }
                            ge.select(SelectionOptions.addTo); // 選択範囲に含むぜ
                            ge=fc.parentStory.characters[ge.index-1]; // 対象を変更
                        }else{ break }
                    }
                }
            } // 前方確認完了
        // 選択範囲の後方確認
        var lc=sel.characters[sel.characters.length-1]; // 最後の文字
        if (lc.rubyFlag){
            /* 最後の文字がルビの親文字だったら、その次の文字も同じルビ文字を持つか? */
            rs=lc.rubyString;
//~             alert(lc.index+1);
//~             alert(lc.parentStory.characters.length-1);
            if (lc.index+1<lc.parentStory.characters.length){
                ge=lc.parentStory.characters[lc.index+1];
                for (;;){
                        if (ge.rubyFlag==true && lc.rubyString==rs && ge.contents!="\r") { // 同じルビ文字だ
                            ge.select(SelectionOptions.addTo); // 選択範囲に含むぜ
                            if (ge.index+1<lc.parentStory.characters.length){
                                ge=lc.parentStory.characters[ge.index+1]; // 対象を変更
                                }else if(ge.index+1==lc.parentStory.characters.length){
                                    break;
                                }
                        }else{ break }}
                }
            } // 後方確認完了
        // 親文字入力プロンプトを表示する
        var my_sel=app.selection[0];
        var my_str=prompt("新しい親文字を入力してください。", my_sel.contents);
        if (my_str==null){ // キャンセルされたとき
            // 元の選択範囲を掴み直す
            sel.select();
            exit();
            }
        if (my_str !="") {
            var my_ruby=my_sel.rubyString;
            my_sel.contents=my_str;
            my_sel.rubyFlag=true;
            my_sel.rubyString=my_ruby;
        }
    }
    exit();
}