事務系で役立つかもしれないJavaScript - Excel編

初投稿です。
ちゃんと書けたかな？

## 概要
VBAェ...
Excel表をイマドキなJavaScriptで何とかする為の、WebApplicationの自分用テンプレートです。


## 経緯
事務作業でExcelをこねくり回す時、今更VBA...と思ったのがきっかけ。

"表は2次元配列にしてしまえば勝ち"
というパワープレイ思考をもとに、最近かじり始めたJavaScriptで、勉強も兼ねて書いてみる事にしました。

残念ながら、日本社会において絶対神Excelから逃れる事は不可能なので、せめてもの足掻き。


## 決め事
- カンマ区切CSV(UTF-8)のみ
- xlsx/csvの相互変換は手動で済ます
- 素のjsでやりきる
- 最新版Chromeで使う

色々と決め打ちが多いですが、その分コードはかなり簡素化されてると思います。


## 中身
<details><summary>JavaScript</summary><div>

```javascript:hoge.js
// onchange: 読込ファイル名表示
function displayFileName(type){
    if(document.getElementById(type).files[0]){
        document.getElementById(type + "_name").innerHTML = document.getElementById(type).files[0].name;
    }else{
        document.getElementById(type + "_name").innerHTML = "";
    }
}

// メインプロセス
async function executeProcess(){

    const json = new Object();
    const csv = new Array();

    await readFile(document.getElementById("json_config").files[0])
        .then((result)=>{
            json.config = JSON.parse(result)
        });
    await readFile(document.getElementById("csv_table1").files[0])
        .then((result)=>{
            csv.table1 = parseCsv(result);
        });
    // 2次元配列化完了
    // オマケでJSONも取り込んでます

    // ココにお好みの処理を･･･

    // 処理後
    downloadFile(json.config, "json-config.csv");
    downloadFile(csv.table1, "csv-table1.csv");
}


// ファイル読込
function readFile(file){
    return new Promise((resolve, reject)=>{
        const reader = new FileReader();
        reader.onload = ()=>{
            resolve(reader.result);
        }
        reader.onerror = (event)=>{
            reject(event);
        }
        reader.readAsText(file);
    });
}

// ダウンロード
function downloadFile(body, name){
    // const bom = "\uEFBBBF";
    const link = document.createElement("a");
    link.href = URL.createObjectURL(new Blob([body], {type: "text/plain"}));
    link.download = name;
    link.click();
}

// CSV分解
function parseCsv(text){
    const csv = new Array();
    const line = text.split("\r\n");
    for(let i = 0; i < line.length; i++){
        csv[i] = line[i].split(',');
    }
    return csv;
}

// CSV結合
function joinCsv(csv){
    let text = new String();
    for(let i = 0; i < csv.length; i++){
        text += csv[i].join(',');
        text += "\r\n"
    }
    return text;
}
```
</div></details>

<details><summary>HTML</summary><div>

```html:hoge.html
<!DOCTYPE html>
<html lang="ja">

    <head>
        <meta charset="utf-8">
        <title>タイトル</title>
    </head>

    <body>
        <p><table>
            <tr>
                <td class="description">
                    テキストを入力
                </td>
                <td>
                    <input type="text" id="text_input" class="text text-search" placeholder="hoge"/>
                </td>
            </tr>
        </table></p>

        <p><table>
            <tr>
                <td>
                    <label class="hide button button-file">JSONを選択
                        <input type="file" id="json_config" accept=".json" onchange="displayFileName('json_config');"/>
                    </label>
                    <span id="json_config_name" class="description"/>
                </td>
            </tr>
            <tr>
                <td>
                    <label class="hide button button-file">CSVを選択
                        <input type="file" id="csv_table1" accept=".csv" onchange="displayFileName('csv_table1');"/>
                    </label>
                    <span id="csv_table1_name" class="description"/>
                </td>
            </tr>
        </table></p>

        <p><table>
            <tr>
                <td>
                    <label class="hide button button-execute">実行
                        <button onclick="executeProcess();"/>
                    </label>
                </td>
            </tr>
        </table></p>

    </body>
</html>
```
</div></details>

<details><summary>CSS</summary><div>

```css:hoge.css
/***** フォーム隠蔽: input *****/
.hide > input {
    display: none;
}

/***** フォーム隠蔽: button *****/
.hide > button {
    display: none;
}

/***** テキスト: 説明文 *****/
.description {
    user-select: none;
}

/***** テキストボックス: 共通 *****/
input.text {
    cursor: text;
    display: inline-block;
    font-size: 14px;
    height: 1.5em;
    border:solid 1px #9f9f9f;
    border-radius: 4px;
}

/***** テキストボックス - カラー: ホバー *****/
input.text-search:hover {
    border:solid 1px #0fb920;
}

/***** ボタン: 共通 *****/
label.button {
    user-select: none;
    cursor: pointer;
    display: inline-block;
    padding: 0.1em 0.4em;
    font-size: 14px;
    text-decoration: none;
    border-radius: 4px;
    transition: 0.2s;
}

/***** ボタン - カラー: ファイル *****/
label.button-file {
    color: #cf33dd;
    border: solid 2px #cf33dd;
    background: white;
}
label.button-file:active {
    color: white;
    background: #cf33dd;
}

/***** ボタン - カラー: 実行 *****/
label.button-execute {
    color: #1c9ce6;
    border: solid 2px #1c9ce6;
    background: white;
}
label.button-execute:active {
    color: white;
    background: #1c9ce6;
}

/***** ボタン: トグル *****/
input.toggle {
    position: absolute;
    margin-left: -9999px;
}
input.toggle + label {
    user-select: none;
    display: block;
    position: relative;
    cursor: pointer;
    outline: none;
    user-select: none;
    padding: 2px;
    height: 18px;
    width: 36px;
    background-color: #9f9f9f;
    border-radius: 36px;
    transition: 0.2s;
}
input.toggle + label:before, input.toggle + label:after {
    display: block;
    position: absolute;
    content: "";
}
input.toggle + label:before {
    top: 2px;
    left: 2px;
    bottom: 2px;
    right: 2px;
    background-color: #ffffff;
    border-radius: 36px;
    transition: 0.2s;
}
input.toggle + label:after {
    top: 4px;
    left: 4px;
    bottom: 4px;
    width: 14px;
    background-color: #9f9f9f;
    border-radius: 36px;
    transition: 0.2s;
}
input.toggle:checked + label {
    background-color: #0fb920;
}
input.toggle:checked + label:after {
    margin-left: 18px;
    background-color: #0fb920;
}
```
</div></details>

## 振り返り
- FileReader便利
- Promiseの使い方は何となく掴んだ
- アローはとりあえず即時関数として使えば良いのかな？

ファイル編集は今までC#で行っていたのですが、簡単な処理ならjsでも全然行けますね。

コンパイルやUI作る手間がだいぶ省けるので、ちょっとしたオートメーション化に活用できそうです。
(VSCodeだけで完結可能なのは嬉しい)