コモノExtendScript100本ノック

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

059.【Id】年月を指定してカレンダーを作る(日本の祝日対応版)

挙動

  1. あらかじめ内閣府webサイトから国民の祝日csvをダウンロードしておく。
  2. 実行するとウィンドウが立ち上がるので、年と月を入力して実行ボタンを押す。
  3. 祝日csvを要求されるので、上記csvを選択する。
  4. カレンダーに記載する日付(先月の末日~今月~来月の頭)の配列が生成される。
  5. 新規ドキュメントが作成される。
  6. 必要な段落・文字・セル・表スタイルが作成される。
  7. テキストフレームが作成され、「○年○月」と記入される。
  8. 同フレーム内に表が作成される。
  9. 表に日付と祝日が記入される。
  10. ヘッダー(曜日)行が追加される。
  11. スタイルがあてがわれる。
  12. 完了。あとは手動でスタイルを整える。

コード

//@targetengine "createCalender2"

// ウィンドウを作成
var dialog = new Window("dialog");
dialog.text = "カレンダー作成";

var group1 = dialog.add("group");
group1.orientation = "row";

var edittext1 = group1.add("edittext");
var s = [50, 25];
edittext1.preferredSize = s;
var statictext1 = group1.add("statictext").text = "年";
var edittext2 = group1.add("edittext");
edittext2.preferredSize = s;
var statictext2 = group1.add("statictext").text = "月のカレンダーを作成します。";
var button1 = dialog.add("button")
button1.text = "実行";
button1.onClick = function() {
    dialog.close(1);
}
var dlgResult = dialog.show();
if (dlgResult !== 1) {
    alert("中断しました");
    exit();
}

// 日本の祝日を全て取得
var nationalHolidays = [];
var csvObj = File("~/Desktop").openDlg("祝日csvを指定してください", "*.csv");
if (!csvObj) {
    alert("キャンセルしました");
    exit();
} else {
    csvObj.open("r");
    var c = csvObj.read();
    var rs = c.split(/\r\n|\r|\n/);
    var rsCnt = rs.length-1; //1行目はフィールド名
    for (var i = 1; i < rsCnt+1; i++) {
        nationalHolidays.push({
          name: rs[i].split(",")[1].replace("休日", "振替休日"),
          date: rs[i].split(",")[0]
          })
    }
}

// 日付の配列を作成
var myYear = parseInt(edittext1.text);
var myMonth = parseInt(edittext2.text) - 1; // monthは0はじまり
if (!myYear || !myMonth || myYear < 1 || myMonth < 1 || myMonth > 12) {
    alert("適切な値を入力してください");
    exit();
}
var list = [];

// 前月末分を取得
var startDate = new Date(myYear, myMonth, 1);
var lastCnt = startDate.getDay(); // 前月末の日数に等しい
for (var i = 0; i < lastCnt; i++) {
    var l = new Date(myYear, myMonth, 0 - i);
    var tmp = {
        year: myYear,
        month: (myMonth - 1) + 1,
        date: l.getDate(),
        day: l.getDay(),
        holiday: ""
    }
    list.push(tmp)
}
list.reverse();

// 今月分を取得
var daysCnt = new Date(myYear, myMonth + 1, 0).getDate(); // 今月の日数
for (var i = 1; i <= daysCnt; i++) {
    var tmp = {
        year: myYear,
        month: myMonth + 1,
        date: i,
        day: new Date(myYear, myMonth, i).getDay(),
        holiday: ""
    }
    list.push(tmp)
}

// 来月頭分を取得
var nextCnt = 35 - list.length;
for (var i = 1; i <= nextCnt; i++) {
    var tmp = {
        year: myYear,
        month: (myMonth + 1) + 1,
        date: i,
        day: new Date(myYear, myMonth + 1, i).getDay(),
        holiday: ""
    }
    list.push(tmp);
}

// 記載する日本の祝日を取得
for (var i = 0; i < list.length; i++) {
  for (var j =0;j<rsCnt; j++){
    if (list[i].year + "/" + list[i].month +"/"+list[i].date===nationalHolidays[j].date){
      list[i].holiday = nationalHolidays[j].name
      }
  }
}

// 新規ドキュメント作成
var doc = app.documents.add();

// 段落スタイル作成
var titleStyle = doc.paragraphStyles.add({
    name: "タイトル"
});
var headerStyle = doc.paragraphStyles.add({
    name: "ヘッダー"
});
var monthStyle = doc.paragraphStyles.add({
    name: "今月",
    pointSize: "13Q",
    leading: "16H"
});
var monthStyle2 = doc.paragraphStyles.add({
    name: "先月来月",
    basedOn: monthStyle,
    fillTint: 40
});
var holidayStyle = doc.paragraphStyles.add({
    name: "祝日",
    pointSize: "9Q",
    leading: "11H"
});

// 文字スタイル作成
var sunSwatch = app.activeDocument.colors.add({
    name: "日曜祝日",
    model: ColorModel.PROCESS,
    space: ColorSpace.CMYK,
    colorValue: [0, 100, 100, 0]
});
var satSwatch = app.activeDocument.colors.add({
    name: "土曜",
    model: ColorModel.PROCESS,
    space: ColorSpace.CMYK,
    colorValue: [100, 0, 0, 0]
});
var sunStyle = doc.characterStyles.add({
    name: "日曜祝日",
    fillColor: sunSwatch
});
var satStyle = doc.characterStyles.add({
    name: "土曜",
    fillColor: satSwatch
});

// セルスタイル作成
var headerCellStyle = doc.cellStyles.add({
    name: "ヘッダー",
    appliedParagraphStyle: headerStyle
});
var dateCellStyle = doc.cellStyles.add({
    name: "日付",
    appliedParagraphStyle: monthStyle
});

// 表スタイル作成
var calenderTblStyle = doc.tableStyles.add({
    name: "カレンダー",
    headerRegionCellStyle: headerCellStyle,
    bodyRegionCellStyle: dateCellStyle
})

// 表作成
var tf = doc.pages[0].textFrames.add();
tf.geometricBounds = [0, 0, 297, 210];
tf.contents = myYear + "年" + (myMonth + 1) + "月\r";
tf.paragraphs[0].applyParagraphStyle(titleStyle);
var tbl = tf.tables.add(LocationOptions.AT_END, tf, {
    appliedTableStyle: calenderTblStyle
});
tbl.columnCount = 7;
tbl.bodyRowCount = 5;
tbl.cells.everyItem().height = "15mm";
tbl.cells.everyItem().autoGrow = false;
tbl.cells.everyItem().width = "15mm";

// テキスト流し込み
for (var i = 0; i < list.length; i++) {
  if (i<35) {
    tbl.cells[i].contents = list[i].date.toString()+"\r" +list[i].holiday;
    } else {
      tbl.cells[i-7].verticalJustification = VerticalJustification.JUSTIFY_ALIGN;
      tbl.cells[i-7].paragraphs.lastItem().contents = tbl.cells[i-7].paragraphs.lastItem().contents + "\r\u0008" + list[i].date.toString();
      if(list[i].holiday!==""){
        tbl.cells[i-7].paragraphs.lastItem().contents = tbl.cells[i-7].paragraphs.lastItem().contents+"\r\u0008" +list[i].holiday;
        }
      tbl.cells[i-7].topRightDiagonalLine = true;
      }
    
}
for (var i = 0; i < tbl.cells.length; i++) {
    for (var j = 0; j < tbl.cells[i].paragraphs.length; j++) {
        tbl.cells[i].paragraphs[j].appliedParagraphStyle = (j % 2 === 0) ? monthStyle : holidayStyle;
    }
}
tbl.rows.add(LocationOptions.AT_BEGINNING, tbl.rows[0]);
var days = ["日", "月", "火", "水", "木", "金", "土"];
for (var i = 0; i < 7; i++) {
    tbl.cells[i].contents = days[i];
}
tbl.rows[0].height = "5mm";

// スタイル適用
tbl.columns[0].cells.everyItem().paragraphs.everyItem().appliedCharacterStyle = sunStyle;
tbl.columns[6].cells.everyItem().paragraphs.everyItem().appliedCharacterStyle = satStyle;
tbl.rows[0].cells.everyItem().paragraphs[0].appliedCharacterStyle = doc.characterStyles[0]; // ヘッダー行は文字スタイルを外す
tbl.rows[0].rowType = RowTypes.HEADER_ROW;
tbl.rows[0].cells.everyItem().clearCellStyleOverrides();
for (var i = 0; i < lastCnt; i++) {
    tbl.rows[1].cells[i].paragraphs[0].applyParagraphStyle(monthStyle2);
}
for (var i = 0; i < nextCnt; i++) {
    tbl.rows[5].cells[6 - i].paragraphs[0].applyParagraphStyle(monthStyle2);
}

alert("完了しました");

メモ

分からなかったこと

  • セルに言葉を追加すると同時にそれに段落スタイルをあてたい。
    paragraph.add()みたいなものがあるかと思ったが無かった。
    新しくparagraphオブジェクトを作成すればよかったのかも。要確認。
  • セルからオーバーフローした分も含めてcellオブジェクトのcontentsを取りたい場合にどうするのがよいか。
    cell.paragraphs[0].parentStoryは表の親テキストフレームのparentStoryになってしまう。
    (今回は文字を追加したいだけだったのでparagraphs.lastItem().contentsに追加するかたちにした)