【教師オリジナルアプリを作ろう】Excelからコピペで簡単編集!行事予定表アプリの作り方をはじめから(Jspreadsheet/JavaScript/PHP)

カレンダーパーツを用いて表示される予定表は,見る側にとっては便利なものでも,更新作業をする側にとっては負担が大きくなりがちです。

通常,行事予定はExcelで作成します。ところが,それをホームページに掲載しようとすると,大抵はイベントを1つ1つ書き写してマウス・クリック→登録という,かなり煩雑な作業に陥ります。

そこで,もともとのデータがExcelで作られることを前提に,そのデータをコピペで一気に流し込めるようなユーザーインターフェースを実現してみよう,というのが今回の試みです。

プログラミング初心者のために,その仕組みをなるべく丁寧に解説していきます。

初期テーブルの作成

まず,行事予定を格納するためのファイルを作成します。ファイル名を calendar-generator.php として保存します。

<?php
//日付データの初期化
$start_date = '2020-04-01';
$end_date = '2050-04-01';
$data = [];
$date = new DateTime($start_date);
$day = ['日', '月', '火', '水', '木', '金', '土'];
while($date->format('Y-m-d') != $end_date) {
    $record = [$date->format('Y-m-d'), $day[$date->format('w')], false, ''];
    array_push($data, $record);
    $date->modify('+1 day');
}
$data_json = json_encode($data);
$handle = fopen('./event-schedule.json','w');
fwrite($handle, $data_json);
fclose($handle);
?>

プログラムを実行するためには,XAMPPをインストールしましょう。そして,ファイルをローカルドライブのxampp/htdocs内に置き,chromeなどのブラウザでアドレスにlocalhost://calenda-generator.phpと入力すると,コードが実行されます。

コードの説明は省略しますが,実行すると同じフォルダー内にevent-schedule.jsonというファイルが作られます。中身は以下のようなものです。

[["2020-04-01","水",false,""],
 ["2020-04-02","木",false,""],
 ["2020-04-03","金",false,""],
 ["2020-04-04","土",false,""],
 ["2020-04-05","日",false,""],
 ["2020-04-06","月",false,""], ・・・

ファイルの中には二次元配列がJSON形式で記述されています。データは日付ごとに構成されていて,日付,曜日,祝日かどうか,行事予定,の順にデータが並んでいます。

このようにして,いったん日付ごとの配列を用意して,あとから行事予定のデータを追加していきます。

今回用意した初期データでは,2020年4月1日から2050年3月31日まで対応することができます。これを変更したい場合には,コードの$start_date$end_dateの値を書き換えます。

初期化されたファイルを作成したら,実際に行事予定を書き込んでみましょう。

編集画面

編集画面のコードをeditor.phpとします。コードの全体は最後に示します。編集画面では,1年分の入力画面が一度に表示されます。こうすることで,年間行事予定をExcelからコピー&ペーストで一気に流し込めるようにします。

中身を確認していきましょう。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://bossanova.uk/jspreadsheet/v4/jexcel.js"></script>
<link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v4/jexcel.css" type="text/css" />
<script src="https://jsuites.net/v4/jsuites.js"></script>
<link rel="stylesheet" href="https://jsuites.net/v4/jsuites.css" type="text/css" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">

ヘッダー部で,使用する外部コードを読み込んでいきます。ここでは,jqueryJspreadsheetbootstrapを使用しています。

Jspreadsheetはブラウザ上でExcelのようなシートの表示,編集を可能にするものです。また,ExcelやLibreOfficeからデータを直接コピーして貼り付けることができます。ここでは,Excelライクな画面に実際のExcelのデータをコピー&ペーストすることで直感的な操作を可能にし,生産性を向上しようというワケです。

<input type="number" class="form-control-paintext mb-1" id="year"
  maxlength="4" style="width:4rem;" min="2020" max="2049">
年度 ※「祝日」にチェックを入れると曜日が赤文字で表示されます。

inputは年度を入力するテキストボックスを表示します。2021などの数字を入力するのでtype="number"とします。class="form-control-paintext mb-1"はbootstrapの設定です。

id="year"は,あとからテキストボックスに入力された年度の値を取り出すときに必要となるものです。maxlength="4"は入力できる文字数が最大4文字であることを示します。style="width:4rem;"はテキストボックスの幅を示します。min="2020" max="2049"は入力できる値の最小値と最大値を示します。初期化したデータファイルが対応できる範囲が2020年度から2049年度までだったので,それ以外の値を入力できないようにします。

    <form method="post">
        <button type="button" id="save" class="btn btn-primary">予定表を保存</button>
    </form>

データを保存するボタンを設置します。ボタンが押されたときの処理はあとで記述します。

    <div id="spreadsheet"></div>

Jspreadsheetでシートを表示するためのブロック要素を設置しておきます。実際の中身は,あとから記述することになります。

次にJavaScriptのコードに移ります。

const today = new Date();

Date()は日付オブジェクトを作成します。todayの中には現在の日付や時刻が格納されます。

$('#year').val(today.getFullYear());

id="year"で設定されたテキストボックスに現在の年を入力します。getFullYear()は日付オブジェクトから年を取り出します。たとえば,現在が2021年ならtoday.getFullYear() = 2021となります。

let table = jspreadsheet(document.getElementById('spreadsheet'), { 
    data: data,   
    allowInsertRow: false,
    allowInsertColumn: false,
    allowDeleteRow: false,
    allowDeleteColumn: false,
    columns: [
        { type: 'text', title:'日付', width:120 },
        { type: 'text', title:'曜日', width:40 },
        { type: 'checkbox', title:'祝日', width:40 },
        { type: 'text', title:'行事予定', width:300 }
    ],
    onchange: changed
});

Jspreadsheetを使って,シートを設置します。関数jspreadsheet()のさまざまな情報がオブジェクトtableに格納されます。あとで,このオブジェクトからシート内のデータを取り出したりできます。この時点では,シートの中身は空の状態です。

data: dataはシートのデータとして配列dataを指定します。allowInsertRow:falseなどは行や列の追加・削除を禁止することを示しています。今回は必要ないので禁止していますが,本来,JspreadsheetはExcelと同じように行や列を追加したり削除することができます。

columnsは列のデータ型などを指定します。ここでは,日付,曜日,祝日,行事予定の4つの列を用意します。データ型は基本的には'text'を指定すれば良いのですが,祝日の列はチェックボックスを用いています。チェックボックスにチェックを入れると,データ上はtrueが格納されます。

あとで説明しますが,祝日のチェックボックスにチェックを入れておくと,行事予定の表示画面でその行の曜日が赤文字で表示されます。

onchange: changedはデータが入力されたときの処理を指定します。changedはオブジェクトで,その中身は以下のようになります。

let changed = function(instance, cell, x, y, value) {
    const record = table.getRowData(y);
    for(let i = 0; i < whole_data.length; i++) {
        if(whole_data[i][0] == record[0]) {
            whole_data[i] = record;
        }
    }
}

table.getRowData(y)はデータが入力されたときに,更新された行のデータを返します。yは行番号を表します。たとえば行事予定を入力したときに,recordには["2020-04-01","水",false,"年度初め"]のような配列が格納されます。

whole_dataにはevent-schedule.jsonから読み込んだ全体のデータが格納されています。for文で全体のデータとrecordの日付を突き合わせて,[0]番目に格納されている日付どうしが一致した場合に,該当部分を入力されたデータに書き換えます。

ちなみに,オブジェクトchangedはオブジェクトtableよりも先に記述しておく必要があります。

$(document).ready(function() {
    fetch('./event-schedule.json', { cache: 'no-cache' })
    .then(res => res.json())
    .then(data => {
        whole_data = data;
        dump_sheet();
    })
});

$(document).ready()は画面がロードされたときの処理を記述します。これはjqueryの機能です。

ここで,サーバー上のファイルを読み込むためにfetch()を用います。詳細は省きますが,取り込んだ二次元配列をwhole_dataに格納して,関数dump_sheet()で画面上に表示します。

特定のデータのみ,シートとして表示する

function dump_sheet() {

次に,関数dump_sheet()の説明に移ります。dump_sheet()は全体のデータから,テキストボックスに入力された年度のデータのみを抽出して表示します。

    const result = whole_data.filter(function(value){
        const date = new Date(value[0]);
        const year = Number($('#year').val());
        const start_date = new Date((year) + '-04-01');
        const end_date = new Date((year + 1) + '-03-31');
        if(date >= start_date && date <= end_date) {
            return value;
        }
    });

whole_dataevent-schedule.jsonに保存された全体のデータを格納しています。

whole_data = [["2020-04-01","水",false,""],["2020-04-02","木",false,""],["2020-04-03","金",false,""],["2020-04-04","土",false,""],["2020-04-05","日",false,""],["2020-04-06","月",false,""], ・・・

filter()は,全体からデータを1つずつ取り出して,条件に一致するものを返します。コードを見ていきましょう。

        const date = new Date(value[0]);

上で登場した,日付オブジェクトDate()を作成しています。valueにはwhole_dataのデータが1つずつ格納されています。たとえば,value = ["2020-04-01","水",false,""]のような状態になっています。このとき,value[0] = "2020-04-01" となります。

        const year = Number($('#year').val());

次に,年度を入力したテキストボックスから値を取り出し,yearに格納します。例えば,テキストボックスの値が2021なら,$('#year').val() = 2021です。Number()は値を数値として扱うことを意味しています。テキストボックスの値は文字列として解釈されるので,ここで値を数値として扱うことを宣言しておきます。

        const start_date = new Date((year) + '-04-01');

シートには,テキストボックスに入力された年度について,4月1日から3月31日までのデータを表示します。year = 2021なら,(year) + '-04-01' = '2021-04-01'となり,年度の初めの日を表す文字列を作ります。

これをもとに,日付オブジェクトを作成し,start_dateに格納します。

        const end_date = new Date((year + 1) + '-03-31');

同様に,年度の終わりの日付をend_dateに格納します。

        if(date >= start_date && date <= end_date) {
            return value;
        }

最終的に,whole_dataのそれぞれの日付と,年度の初め・終わりを比較します。テキストボックスに入力された年度に一致するデータがreturnで返され,resultに格納されます。

結果として,テキストボックスに入力された値が2021なら,全体のデータから2021年4月1日から2022年3月31日の間のデータが抽出され,resultに格納されることになります。

    table.setData(result);

こうして,抽出されたデータをsetData()でシートに送ります。画面上には,テキストボックスに入力された年度のデータのみが表示されます。

    for(let i = 0; i < result.length; i++) {
        let day = table.getValue(jexcel.getColumnNameFromId([1, i]));
        if(day == '土') {
            table.setStyle(jexcel.getColumnNameFromId([1, i]), 'background-color', '#CCDDFF');
        }
        if(day == '日') {
            table.setStyle(jexcel.getColumnNameFromId([1, i]), 'background-color', '#FFCACA');
        }
    }

画面に表示されたシートのうち,土曜日と日曜日についてセルの背景色を変更します。詳細は省きます。

テキストボックスが変更されたときの処理

$('#year').on('change', function() {
    dump_sheet();
});

テキストボックスの値が変更されたときの処理です。イベントリスナーを設置して,入力された年度に応じたデータを再描画します。

データの送信

$('#save').on('click', function() {
    let post_data = JSON.stringify(whole_data);
    console.log(post_data);
    fetch('event-schedule-save.php', {
        method: 'POST',
        body: post_data
    })
    .then(res => res.text())
    .then(dat => {
        alert('予定表が保存されました。');
    })
    .catch((error) => {
        console.error(error);
    });
});

「予定表を保存」ボタンが押されたときの処理です。イベントリスナーon('click'はボタンがクリックされたときに以下の処理を実行します。

ここでもfetch()を用いてデータを保存しますが,その仕組みを学ぶ必要があります。

JavaScript側からサーバーに直接データを書き込むことはできません。サーバーに保存したい場合は,いったんphpなどのサーバー側で動くプログラムにデータを渡して,phpの側で保存処理を行います。ここではPOSTという方式を用いて,データを送ります。

    let post_data = JSON.stringify(whole_data);

POSTでデータを送信するとき,配列をそのまま送ることができません。そこで,全体のデータwhole_dataJSON.stringify()でJSON文字列に変換します。これをpost_dataに格納します。

post_data = [["2020-04-01","水",false,""],["2020-04-02","木",false,""],["2020-04-03","金",false,""],["2020-04-04","土",false,""],["2020-04-05","日",false,""],["2020-04-06","月",false,""], ・・・

もともとの配列は値のみですが,それに[]がついたり,文字列を""で囲み,コンマで区切るなどして一続きの文字列にします。これがJSON形式です。

    fetch('event-schedule-save.php', {
        method: 'POST',
        body: post_data
    })
    .then(res => res.text())
    .then(dat => {
        alert('予定表が保存されました。');
    })
    .catch((error) => {
        console.error(error);
    });

fetch()でデータを送信します。method: 'POST'とすることでPOST方式を指定し,body: post_dataで送信するJSON文字列を指定します。送られたデータはevent-schedule-save.phpで受け取ります。

送信が完了するとalert('予定表が保存されました。')で完了のメッセージを表示します。

editor.phpの動作は以上です。全体のコードを示します。

<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>行事予定表アプリ編集画面</title> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://bossanova.uk/jspreadsheet/v4/jexcel.js"></script>
<link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v4/jexcel.css" type="text/css" />
<script src="https://jsuites.net/v4/jsuites.js"></script>
<link rel="stylesheet" href="https://jsuites.net/v4/jsuites.css" type="text/css" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
</head>
<body>
<div calss="container" style="margin:1rem;">
    <input type="number" class="form-control-paintext mb-1" id="year" maxlength="4" style="width:4rem;" min="2020" max="2049">年度 ※「祝日」にチェックを入れると曜日が赤文字で表示されます。
    <form method="post">
        <button type="button" id="save" class="btn btn-primary">予定表を保存</button>
    </form>
    <div id="spreadsheet"></div>
</div>
<script>
//テーブルの設置
const today = new Date();
let whole_data;
let data;
//セルの値の更新時にもとのデータも更新する
let changed = function(instance, cell, x, y, value) {
    const record = table.getRowData(y);
    for(let i = 0; i < whole_data.length; i++) {
        if(whole_data[i][0] == record[0]) {
            whole_data[i] = record;
        }
    }
}
$('#year').val(today.getFullYear());
let table = jspreadsheet(document.getElementById('spreadsheet'), { 
    data: data,   
    allowInsertRow: false,
    allowInsertColumn: false,
    allowDeleteRow: false,
    allowDeleteColumn: false,
    columns: [
        { type: 'text', title:'日付', width:120 },
        { type: 'text', title:'曜日', width:40 },
        { type: 'checkbox', title:'祝日', width:40 },
        { type: 'text', title:'行事予定', width:300 }
    ],
    onchange: changed
});
//ページロード完了時の処理
$(document).ready(function() {
    fetch('./event-schedule.json', { cache: 'no-cache' })
    .then(res => res.json())
    .then(data => {
        whole_data = data;
        dump_sheet();
    })
});
//シートの出力
function dump_sheet() {
    const result = whole_data.filter(function(value){
        const date = new Date(value[0]);
        const year = Number($('#year').val());
        const start_date = new Date((year) + '-04-01');
        const end_date = new Date((year + 1) + '-03-31');
        if(date >= start_date && date <= end_date) {
            return value;
        }
    });
    table.setData(result);
    //曜日の色付け
    for(let i = 0; i < result.length; i++) {
        let day = table.getValue(jexcel.getColumnNameFromId([1, i]));
        if(day == '土') {
            table.setStyle(jexcel.getColumnNameFromId([1, i]), 'background-color', '#CCDDFF');
        }
        if(day == '日') {
            table.setStyle(jexcel.getColumnNameFromId([1, i]), 'background-color', '#FFCACA');
        }
    }
}
//年度の変更
$('#year').on('change', function() {
    dump_sheet();
});
//保存処理
$('#save').on('click', function() {
    let post_data = JSON.stringify(whole_data);
    console.log(post_data);
    fetch('event-schedule-save.php', {
        method: 'POST',
        body: post_data
    })
    .then(res => res.text())
    .then(dat => {
        alert('予定表が保存されました。');
    })
    .catch((error) => {
        console.error(error);
    });
});
</script>
</body>
</html>

データの保存

送信されたデータはevent-schedule-save.phpで受け取ります。editor.phpと同じフォルダに以下のコードを入力したファイルを作り,event-schedule-save.phpとして保存しておきます。

<?php
$handle = fopen('./event-schedule.json', 'w');
$params = file_get_contents('php://input');
fwrite($handle, $params);
fclose($handle);
?>

まず,fopen()でデータを保存するファイルを作成します。ここでは,event-schedule.jsonという名前で保存されます。

file_get_contents('php://input')は,送信されたデータを取り出すための命令です。$paramには先ほどPOSTで送信したJSON文字列が格納されます。

そして,fwrite()でJSON文字列をファイルに書き込み,最後にfclose()でファイルを閉じます。

行事予定表の表示

こうして作成された行事予定表を表示するホームページを作ります。ファイル名をindex.htmlとします。

まずはヘッダー部です。

<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>【Excelからコピペで簡単編集】行事予定表アプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<style>
td { border: solid 1px #BFBFBF; padding: 0.25rem; }
.event-name { width:350px; }
.date { text-align: right; }
.char-blue { color: #003399; font-weight: 600;}
.char-red { color: #CC0000; font-weight: 600; }
</style>
</head>

ヘッダー部で,jqueryとbootstrapを読み込みます。また,今回はcssファイルを用意するのが面倒だったので,<style></style>に直接書き込んでいます。

次に,body部です。

<body>
<div class="container">
<div id="event_schedule">
    <p>
        行事予定
        <input type="number" class="form-control-paintext" id="year" maxlength="4" style="width:4rem;">年
        <input type="number" class="form-control-paintext" id="month" maxlength="2" min="0" max="13" style="width:4rem;">月
    </p>
    <div id="schedule"></div>
</div>
</div>
<script>

年と月を入力するテキストボックスと,予定表を表示するブロック要素<div id="schedule"></div>を設置します。

ブロック要素の中に予定表を書き込んでいきましょう。

$(document).ready(function() {
    const date = new Date();
    const year = Number(date.getFullYear());
    const month = Number(date.getMonth()) + 1;
    $('#year').val(year);
    $('#month').val(month);
    dump_schedule(year, month);
});

画面ロード時の処理です。テキストボックスに現在の年と月の値を書き込み,関数dump_schedule(year, month)で,指定した年と月の予定表を表示させます。

function dump_schedule(year, month) {
    fetch('./event-schedule.json', { cache: 'no-cache' })
    .then(res => res.json())
    .then(data => {
        const result = data.filter(function(value){
            const record_date = new Date(value[0]);
            const record_year = record_date.getFullYear();
            const record_month = Number(record_date.getMonth()) + 1;
            if(record_year == year && record_month == month) {
                return value;
            }
        });

関数dump_schedule()を定義していきます。fetch()を用いて保存されたデータを読み込みます。また,filter()を用いてyearmonthで指定された年と月のデータを抽出し,配列resultに格納します。

        if(result.length > 0) {
            let tableHTML = '<table>';
            result.forEach(function(value) {
                const date = new Date(value[0]);
                tableHTML += '<tr><td class="date">' + date.getDate() + '</td>'
                if(value[1] == '土'){  //土曜日のとき文字を青に
                    tableHTML += '<td class="char-blue">'
                } else if(value[1] == '日' || value[2]) { //日祝のとき文字を赤に
                    tableHTML += '<td class="char-red">'
                } else {
                    tableHTML += '<td>'
                }
                tableHTML += value[1] + '</td>'
                    + '<td class="event-name">' + value[3] + '</td></tr>';
            });
            tableHTML += '</table>';
            $('#schedule').html(tableHTML);
        } else {
            $('#schedule').html('予定はまだ作成されていません。');
        }

編集画面では抽出したデータをjspreadsheetに流し込みましたが,表示画面では,テーブルに流し込みます。

            let tableHTML = '<table>';

テーブルはHTMLで表示します。いったん,文字列tableHTMLにHTMLのコードを書きこんで,最後に表示します。

            result.forEach(function(value) {

forEachは配列を1つずつ処理します。たとえば,resultに抽出されたデータが30日分であれば,それを1日分ごとに取り出してvalueに格納します。このように,配列のそれぞれの要素について処理を行いたいときにはforEachを使います。

                const date = new Date(value[0]);

取り出した配列はvalue = ["2020-04-01","水",false,""]のような状態になっています。したがって,value[0]="2020-04-01"となり,それをもとに日付オブジェクトを作りdateに格納します。

                tableHTML += '<tr><td class="date">' + date.getDate() + '</td>'

getDate()は日付オブジェクトから日を取り出します。value[0]="2020-04-01"なら,その値は1となります。こうして,1列目にその月の日を表示します。

                if(value[1] == '土'){  //土曜日のとき文字を青に
                    tableHTML += '<td class="char-blue">'
                } else if(value[1] == '日' || value[2]) { //日祝のとき文字を赤に
                    tableHTML += '<td class="char-red">'
                } else {
                    tableHTML += '<td>'
                }
                tableHTML += value[1] + '</td>'

次に2列目の曜日です。ここでは,土日祝日のときに色を変えるように設定します。

                    + '<td class="event-name">' + value[3] + '</td></tr>';

3列目に行事予定を表示します。value[3]には行事の文字列が格納されています。

            tableHTML += '</table>';
            $('#schedule').html(tableHTML);

最後にテーブルタグを閉じて,ブロック要素scheduleにHTMLコードとして表示します。

最後に,コード全体を示します。

<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>【Excelからコピペで簡単編集】行事予定表アプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<style>
td { border: solid 1px #BFBFBF; padding: 0.25rem; }
.event-name { width:350px; }
.date { text-align: right; }
.char-blue { color: #003399; font-weight: 600;}
.char-red { color: #CC0000; font-weight: 600; }
</style>
</head>
<body>
<div class="container">
<div id="event_schedule">
    <p>
        行事予定
        <input type="number" class="form-control-paintext" id="year" maxlength="4" style="width:4rem;">年
        <input type="number" class="form-control-paintext" id="month" maxlength="2" min="0" max="13" style="width:4rem;">月
    </p>
    <div id="schedule"></div>
</div>
</div>
<script>
//ページロード時に予定表を表示
$(document).ready(function() {
    const date = new Date();
    const year = Number(date.getFullYear());
    const month = Number(date.getMonth()) + 1;
    $('#year').val(year);
    $('#month').val(month);
    dump_schedule(year, month);
});
//月が変更されたときに予定表を表示
$('#month').on('change', function() {
    let year = Number($('#year').val());
    let month = Number($('#month').val());
    if(month >= 13) {
        year += 1;
        month = 1;
    }
    if(month <= 0) {
        year -= 1;
        month = 12;
    }
    $('#year').val(year);
    $('#month').val(month);
    dump_schedule(year, month);
});
//予定表の表示
function dump_schedule(year, month) {
    fetch('./event-schedule.json', { cache: 'no-cache' })
    .then(res => res.json())
    .then(data => {
        const result = data.filter(function(value){
            const record_date = new Date(value[0]);
            const record_year = record_date.getFullYear();
            const record_month = Number(record_date.getMonth()) + 1;
            if(record_year == year && record_month == month) {
                return value;
            }
        });
        if(result.length > 0) {
            let tableHTML = '<table>';
            result.forEach(function(value) {
                const date = new Date(value[0]);
                tableHTML += '<tr><td class="date">' + date.getDate() + '</td>'
                if(value[1] == '土'){  //土曜日のとき文字を青に
                    tableHTML += '<td class="char-blue">'
                } else if(value[1] == '日' || value[2]) { //日祝のとき文字を赤に
                    tableHTML += '<td class="char-red">'
                } else {
                    tableHTML += '<td>'
                }
                tableHTML += value[1] + '</td>'
                    + '<td class="event-name">' + value[3] + '</td></tr>';
            });
            tableHTML += '</table>';
            $('#schedule').html(tableHTML);
        } else {
            $('#schedule').html('予定はまだ作成されていません。');
        }
    });
}
</script>
</body>
</html>

まとめ

ここでは,ブラウザ上でExcelと同様のインターフェースを実現するJspreadsheetを用いて,Excelの表形式データを行事予定表にまとめてコピー&ペーストする方法を示しました。

この方法を応用することで,Excelで作成されたデータを手軽にWeb上に反映させることができるようになります。また,ExcelVBAの代わりにJavaScriptやphpでデータを加工し,Web上で結果を得ることが可能になるので,クラウドベースの業務システムを作成する際にも活用できるでしょう。