コモノExtendScript100本ノック

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

018.【ID】1列の中で行長が最も長いセルが中央揃えになるよう他の行の小数点揃えタブを設定

こんな感じにしたい。
f:id:haraguai_is_bad:20190214120624p:plain:w300

書いたコード

// * 横組み限定 *
// * ピリオドが複数含まれるケースには未対応 *

var doc = app.activeDocument;
var sel = doc.selection;
var selNum = sel.length;
var stopFlag = false;
var cellProps = [];

// 選択対象がセルでなければ止める
for (var i = 0; i < selNum; i++) {
  if (sel[i].constructor.name !== "Cell" && sel[i].constructor.name !== "Table") {
    stopFlag = true;
    alert("複数のセルを選択してください");
    break;
  }
}

L:
  if (!stopFlag) {
    var myCells = sel[0].cells
    var myCellsNum = myCells.length;
    for (var j = 0; j < myCellsNum; j++) {
      // 2行以上なら止める
      if (myCells[j].lines.length > 1) {
        alert("複数行には対応していません");
        break L;
      }
      // セルの位置・セル内マージン・行長を取得 
      var cellNameTmp = myCells[j].name;
      var leftInsetTmp = myCells[j].leftInset;
      var lineLenTmp = getLineLen(myCells[j].lines[0]);
      cellProps[j] = [j, leftInsetTmp, lineLenTmp];
    };

    // 行長を基準に降順ソート
    cellProps.sort(function (a, b) {
      if (a[2] > b[2]) return -1;
      if (a[2] < b[2]) return 1;
      // セル番地も降順ソート
      if (a[0] > b[0]) return -1;
      if (a[0] < b[0]) return 1;
      return 0;
    });

    // 最長行のピリオド位置を取得
    // まずインデント削除+左揃えして行頭位置を取得
    var refCellProp = cellProps[0];
    var refCell = myCells[refCellProp[0]];
    var refInset = refCellProp[1];
    refCell.lines[0].firstLineIndent = lastLineIndent = leftIndent = rightIndent = 0;
    refCell.lines[0].justification = Justification.leftAlign;
    var refPosition = refCell.lines[0].insertionPoints[0].horizontalOffset;
    // 中央揃えにしてピリオド位置取得
    refCell.lines[0].justification = Justification.centerAlign;
    if (refCell.contents.indexOf(".") !== -1) {
      var piriodId = refCell.contents.indexOf(".");
      var piriodPosition = refCell.lines[0].insertionPoints[piriodId].horizontalOffset;

    } else {
      var tmpArr = refCell.contents.match(/\d/g); // ピリオドが含まれていなければ最後の数字
      var piriodId = refCell.contents.lastIndexOf(tmpArr[tmpArr.length - 1]);
      var piriodPosition = refCell.lines[0].insertionPoints[piriodId + 1].horizontalOffset;
    }
    // ピリオドと行頭の座標の差分を取得
    var piriodOffset = piriodPosition - refPosition;

    // 最長行に合わせ全てのセルの左右セル内マージン・インデント・タブを設定
    for (var k = 0; k < myCellsNum; k++) {
      myCells[k].leftInset = myCells[k].rightInset = refInset;
      myCells[k].lines[0].firstLineIndent = lastLineIndent = leftIndent = rightIndent = 0;
      myCells[k].lines[0].justification = Justification.leftAlign;
      resetTab(myCells[k].lines[0])
      setCharAlignTab(myCells[k].lines[0], ".", piriodOffset)
    }

    // やったぜ
    alert("完了")
  }

// 行長取得
function getLineLen(myLine) {
  if (myLine.constructor.name !== "Line") {
    return;
  } else {
    var lineLen = myLine.endHorizontalOffset - myLine.horizontalOffset;
    return lineLen;
  }
}

// 全タブリセット
function resetTab(myLine) {
  for (var p = 0; p < myLine.tabStops.length; p++) {
    myLine.tabStops[p].remove()
  }
}

// 指定文字区切りタブ設定
function setCharAlignTab(myLine, myChar, myPosition) {
  myLine.tabStops.add({
    alignment: TabStopAlignment.CHARACTER_ALIGN,
    alignmentCharacter: myChar,
    position: myPosition

  })
}

メモ

あとで調べる

「こういう条件だったら処理全体を抜ける」というような条件が複数ある場合のよいやり方。
「選択対象の数が2より少ない」かつ「選択対象がセルでない」場合、スクリプト全体を止めたい。
こういうとき、

if(!条件A){} else if (!条件B) {} else {
// メインの処理
}

みたいなのが続いて入れ子が深くなってしまうことがままある。
今回はその回避策として、条件に合致していたら「stopFlag=true」とするようにしたけどあんまり上手くいってない。
単純な条件なら「!条件A&&!条件B」とすればいいんだろうけど。
ちょっとググってみたけどどうにも上手く見つけられなかった。
これに限らず、具体的なメソッドとかうんぬん以前の、javascriptの書き方についてちゃんと学ばなきゃ感がある。

積み残し