GASでjavascript入門

# I\. GASーjavascript入門
まずはGoole App Scriptでの演習から。
Googleサーバ上でGAS環境で試す場合と、クライアントのchrome上で試す場合の微妙な差を区別しておくと良い。
まずはGoogleサーバ上のGAS環境で試す。

## 1\.変数
```javascript
let name = 'John'; // 文字列型の変数
let age = 25; // 数値型の変数
let isStudent = true; // 真偽値型の変数

Logger.log(`名前: ${name}`);
Logger.log(`年齢: ${age}`);
Logger.log(`学生: ${isStudent ? 'はい' : 'いいえ'}`);
```

## 2\. 演算子と制御構文
```javascript
let num = 10;

// 条件分岐
if(num % 2 === 0) {
    Logger.log(`${num} は偶数です`);
} else {
    Logger.log(`${num} は奇数です`);
}

// ループ
for(let i = 0; i < 5; i++) {
    Logger.log(`現在の値: ${i}`);
}
```

## 3\. 配列と繰り返し

```javascript
let fruits = ['apple', 'banana', 'cherry'];

// 配列の要素数を表示
Logger.log(`配列の要素数: ${fruits.length}`);

// 配列の各要素を表示
for(let i = 0; i < fruits.length; i++) {
    Logger.log(`フルーツ${i+1}: ${fruits[i]}`);
}
```

# II\. GASとGoogle SpreadSheetの連携

## a) まず基本のGASでのdoGet()
まず、単なるdoGet()メソッドを作り、変数の中身をHTMLで表示させてみる。
HTMLは文字列であることに注意。

```javascript
function doGet() {
  // ダミーの最新メッセージを作成
  const dummyMessages = [
    ["Hello"],
    ["World"],
    ["How are you?"]
  ];

  // HTML 文字列を作成
  let output = '<html><head><title>メッセージ一覧</title></head><body>';
  output += '<h1>メッセージ一覧</h1>';
  output += '<ul>';
  dummyMessages.forEach(function(message) {
    output += '<li>' + message[0] + '</li>';
  });
  output += '</ul></body></html>';

  return HtmlService.createHtmlOutput(output);
}
```
## b) 演習
Google SpreadsheetのデータをHTMLを使ってクライアント側で表示できるようにしよう。

ヒントのプログラム

```javascript
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0]; // 最初のシートを取得
  const range = sheet.getRange("A1:A" + sheet.getLastRow());          // A列のデータ範囲
  const messages = range.getValues();                                 // 二次元配列で取得
```

HTMLのliタグ部分を生成するヒント

```javascript
  messages.forEach(function(row) {
    const message = row[0];
    if (message) {
      output += '<li>' + message + '</li>';
    }
  });
```


# III\. HTMLのフォームで入力を行う

## a) google側に置くHTMLファイル(form.html)

```html
<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <script>
    function showAlertAndSubmit(event) {
      event.preventDefault();
      alert('ボタンが押されました');
      document.getElementById('myForm').submit(); // 手動で送信
    }
  </script>
</head>
<body>
  <div class="container">
    <h2>送信フォーム</h2>
    <form id="myForm" method="POST" action="＊＊＊＊ここに注意＊＊＊＊＊" onsubmit="showAlertAndSubmit(event)">
      <button type="submit" name="confirm" value="true">送信</button>
    </form>
  </div>
</body>
</html>
```

## b) GASのdoPost()

form.htmlを一部変更が必要
```HTML
<form method="POST" action="＊＊＊＊ここに注意＊＊＊＊＊">
  <input type="text" name="inputData" placeholder="データを入力">
  <button type="submit" name="confirm" value="true">送信</button>
</form>
```

GAS側のプログラム

```javascript
function doPost(e) {
  const id = "あなたのSpreadsheet ID";
  const spreadsheet = SpreadsheetApp.openById(id);
  const sheet = spreadsheet.getSheetByName('シート1');

  if (!sheet) {
    return HtmlService.createHtmlOutput("エラー: シート 'シート1' が見つかりません。");
  }

  const inputData = e.parameter.inputData;
  if (!inputData) {
    return HtmlService.createHtmlOutput("エラー: inputData が空です。");
  }

  const lastRow = sheet.getLastRow();
  sheet.getRange(lastRow + 1, 1).setValue(inputData);

  return HtmlService.createHtmlOutput("データをスプレッドシートに追加しました。");
}

```

# IV\. 少しだけアプリっぽくしゅうせい

## a) form.htmlの修正
少しCSSで見た目を変えたform.html

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>MEMOアプリ</title>
  <style>
    body {
      background-color: #f8f9fa;
      font-family: sans-serif;
      margin: 0;
      padding: 20px;
    }

    .container {
      max-width: 600px;
      margin: 0 auto;
      background-color: white;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 0 10px rgba(0,0,0,0.1);
    }

    h1 {
      text-align: center;
      color: #17a2b8;
      margin-bottom: 20px;
    }

    form {
      margin-bottom: 20px;
    }

    input[type="text"] {
      width: 100%;
      padding: 12px;
      font-size: 16px;
      border: 1px solid #ccc;
      border-radius: 4px;
      box-sizing: border-box;
    }

    button {
      margin-top: 10px;
      width: 100%;
      padding: 12px;
      font-size: 16px;
      background-color: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }

    button:hover {
      background-color: #0056b3;
    }

    ul {
      list-style-type: none;
      padding-left: 0;
    }

    li {
      padding: 10px;
      border-bottom: 1px solid #ddd;
      color: #6c757d;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>MEMO</h1>
    <form id="form">
      <input type="text" id="memoinp" name="memo" placeholder="Memoを入力" autocomplete="off" />
      <button type="submit">追加</button>
    </form>
    <ul id="ul"></ul>
  </div>

  <script>
    const form = document.getElementById("form");
    const memoinp = document.getElementById("memoinp");
    const ul = document.getElementById("ul");

    form.addEventListener("submit", function (event) {
      event.preventDefault();
      const text = memoinp.value.trim();
      if (text !== "") {
        const li = document.createElement("li");
        li.textContent = text;
        ul.appendChild(li);

        fetch("https://script.google.com/macros/s/【あなたのWebアプリURL】/exec", {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded"
          },
          body: "memo=" + encodeURIComponent(text)
        }).then(response => response.text())
          .then(msg => console.log("GAS応答:", msg))
          .catch(err => console.error("送信失敗:", err));

        memoinp.value = "";
      }
    });
  </script>
</body>
</html>
```

## b) doPost()の修正

一応doGet()の定義も載せておきます。

```javascript
function doGet() {
  return HtmlService.createHtmlOutputFromFile("form");
}

function doPost(e) {
  const id = "あなたのスプレッドシートID";
  const spreadsheet = SpreadsheetApp.openById(id);
  const sheet = spreadsheet.getSheetByName('シート1');

  if (!sheet) {
    return HtmlService.createHtmlOutput("シートが見つかりません。");
  }

  const memo = e.parameter.memo;
  if (!memo) {
    return HtmlService.createHtmlOutput("memoが送信されていません。");
  }

  const timestamp = new Date();
  sheet.appendRow([timestamp, memo]);

  return HtmlService.createHtmlOutput("メモが追加されました。");
}

```

### Chrome上のdocumentオブジェクトの確認

ChromeのDevToolのConsoleからdocumentオブジェクトを確認する。
```javascript
document
```
さらに、メソッド、プロパティを確認
```javascript
document.getElementById("memoinp")
document.getElementById("memoinp").value
```


# X\. 予備：HTMLベースのjavascriptプログラム

## Canvas環境のプログラム
```html
<!DOCTYPE html>
<html>
<body>
    <canvas id="myCanvas" width="500" height="500" style="border:1px solid #d3d3d3;">
        Your browser does not support the HTML5 canvas tag.
    </canvas>

    <script>
        let canvas = document.getElementById('myCanvas');
        let ctx = canvas.getContext('2d');
        ctx.fillStyle = "#FF0000";
        ctx.fillRect(0, 0, 150, 75);
    </script>

</body>
</html>
```

## svgを使った描画
```javascript
<!DOCTYPE html>
<html>
<body>

<svg width="400" height="180">
  <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
</svg>

</body>
</html>
```