【GoogleSS】縦にチェックするチェックリストをつくりたい

おでかけの際の持ち物チェックリストをめちゃくちゃ作りこんだ。

# 目次
[1. 概要](#1-概要)
[2. 構成](#2-構成)
[3. スクリプト](#3-スクリプト)
[4. 感想](#4-感想)

# 1. こんな感じで動きます
スクリプトを実行すると、別シートで作成済みのチェックポイントリストを、チェック対象リストに召喚します。
![temp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643466/388452a0-c979-de2c-81d8-5be031a391fa.gif)



# 2. 構成
垂直チェックシートは下記により構成されます。

- チェック対象リスト
- チェックポイントリスト


▼チェック対象リスト
![temp2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643466/d4493c03-7244-eda3-48c6-792c92487133.png)


▼チェックポイントリスト
![temp3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1643466/0162b5e5-97c0-6685-ba41-e70d87ab8b6c.png)


# 3. スクリプト

```verticalChecksheet.js
let ss = SpreadsheetApp.openById("1_qk14As_2XVGlAeCBIJkfC0onuok9P64fvrFNCEPvcs");
let ctlSh = ss.getSheetByName("チェック対象リスト");

let actSs = SpreadsheetApp.getActiveSpreadsheet();
let actSh = actSs.getActiveSheet();
let actRow = actSh.getActiveCell().getRow();

let numCol = 1
let catCol = 4

/* //━━━━━━━━━━━━━━━
メイン関数
*/ //━━━━━━━━━━━━━━━
function genCpl() {
  let shouldDo = chkShouldGenCpl();
  if (shouldDo == true) {
    callCpl();
    inputStatFunc();
  }  
}

/* //━━━━━━━━━━━━━━━
CPL召喚要否判定
*/ //━━━━━━━━━━━━━━━
function chkShouldGenCpl() {
  let isNotDecimal = chkIsNotDecimal(actRow + 1, numCol);
  if (isNotDecimal &&
      actSh.getRange(actRow, catCol).getValue() != "") {
    return true;
  }
}

function chkIsNotDecimal(row, col) {
  let val = actSh.getRange(row, col).getValue();
  if (isFinite(val)) {
    let isInteger = Number.isInteger(val);
    if (isInteger) {
      var rslt = "notDecimal"; 
    } else {
      var rslt = "decimal";
    }
    if (rslt == "notDecimal") {
      return true;
    } else {
      return false;
    }
  } else {
    return true;
  }
}

/* //━━━━━━━━━━━━━━━
CPL召喚
*/ //━━━━━━━━━━━━━━━
function callCpl() {
  let cat = actSh.getRange(actRow, catCol).getValue();
  let cplShName = "CPL-" + cat;
  let cplSh = ss.getSheetByName(cplShName);
  let cplRows = cplSh.getLastRow();

  insertRow(cplRows);
  insertNumber(cplRows);
  blindNumber(cplRows)
  copyCpl(cplSh, cplRows);
}

 function insertRow(cplRows) {
  ctlSh.insertRowsAfter(actRow, cplRows + 1);
  ctlSh.getRange(actRow + 1, 1, cplRows + 1, actSh.getLastColumn()).
  setBorder(null, null, null, null, true, true, "#ffffff",
   SpreadsheetApp.BorderStyle.SOLID);
}

  function insertNumber(cplRows) {
  for (let i = 1; i <= cplRows + 1; i++) {
    let init = ctlSh.getRange(actRow, numCol).getValue()
    let num = 0.001 * i + init;
    ctlSh.getRange(actRow + i, 1).setValue(num);
  }  
}

  function blindNumber(cplRows) {
    ctlSh.getRange(actRow + 1, 1, cplRows + 1, 1)
    .setFontColor("#ffffff");
  }

  function copyCpl(cplSh, cplRows) {
    cplSh.getRange(1, 1, cplRows, cplSh.getLastColumn())
    .copyTo(ctlSh.getRange(actRow + 1, 2));
}


/* //━━━━━━━━━━━━━━━
ステータス関数入力
*/ //━━━━━━━━━━━━━━━
function inputStatFunc() {
  let cat = actSh.getRange(actRow, catCol).getValue();
  let cplShName = "CPL-" + cat;
  let cplSh = ss.getSheetByName(cplShName);
  let cpNum = cplSh.getLastRow() - 1;
  let cpStartRow = actRow + 2;
  let cpEndRow = actRow + cpNum + 1;
  let statCol = 5;
  let subStatCol = statCol + 1;
  let cpRsltCol = 5;

  iputTotalStatFuncstr(cpStartRow, cpEndRow, cpRsltCol, statCol);
  inputSubStatFuncstr(cpStartRow, cpEndRow, cpRsltCol, subStatCol);
}

//全体ステータス入力関数
function iputTotalStatFuncstr(cpStartRow, cpEndRow, cpRsltCol, statCol) {
  let str = genCountifFuncstr(cpStartRow, cpEndRow, cpRsltCol);
  ctlSh.getRange(actRow, statCol).setValue(str);
}

//サブステータス入力関数
function inputSubStatFuncstr(cpStartRow, cpEndRow, cpRsltCol, subStatCol) {
  let priCpCol = 3;
  let cpCol = priCpCol + 1;

  let priCplStartRow = getPriColStartRow(cpStartRow, cpEndRow, priCpCol);
  let priCplEndRow = getPriColEndRow(cpStartRow, cpEndRow, priCpCol, cpCol);
  let priCpNum = priCplStartRow.length;
  for (let i = 1; i <= priCpNum; i++) {
    let inputCol = subStatCol - 1 + i
    let inputRng = actSh.getRange(actRow, inputCol);
    let inputStartRow = priCplStartRow[i - 1];
    let inputEndRow = priCplEndRow[i - 1];
    let inputStr = genCountifFuncstr(inputStartRow, inputEndRow, cpRsltCol);
    inputRng.setValue(inputStr);
  }
}

function getPriColStartRow(startRow, endRow, priCpCol) {
  let arr = [];
  let cpNum = endRow - startRow;
  for (let i = 1; i <= cpNum + 1; i++) {
    let row = startRow - 1 + i;
    let val = actSh.getRange(row, priCpCol).getValue();
    if (val != "") {
      arr.push(row);
    }
  }
  return arr;
}

function getPriColEndRow(startRow, endRow, priCpCol, cpCol) {
  let arr = [];
  let cpNum = endRow - startRow;
  for (let i = 1; i <= cpNum + 1; i++) {
    let row = startRow - 1 + i
    let priCp = actSh.getRange(row, priCpCol).getValue();
    let cp = actSh.getRange(row, cpCol).getValue();
    let nextPriCp = actSh.getRange(row + 1, priCpCol).getValue();
    let nextCp = actSh.getRange(row + 1, cpCol).getValue();

    //左に文字列かつ左下に文字列かつ下に文字列　→　終行
    //下に文字列かつ左下に文字列　→　終行
    //下が空白　かつ左　が空白　　→　終行
    //下が空白　かつ左　に文字列　→　終行

    if (priCp != "" && nextCp != "" && nextPriCp != "" ||
        nextCp != "" && nextPriCp != "" ||
        nextCp == "" && priCp == "" ||
        nextCp == "" && priCp != ""){
      arr.push(row);
    }
  }
  return arr;
}

//コンポーネント
function genCountifFuncstr(startRow, endRow, col) {
  let rng = convCol(col) + startRow + ":" + convCol(col) + endRow;
  return "=if(counta(" + rng + ")=countif(" + rng + ",true),\"完了\",\"未完了\")"
}

function convCol(num) {
  var rslt = actSh.getRange(1, num);
  rslt = rslt.getA1Notation();
  rslt = rslt.replace(/\d/,'');
  return rslt;
}

```