[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
ただいまコメントを受けつけておりません。
Google Sheets(俗にスプシ等と呼ばれる)は複数人で多数のデータを編集するのには向くが、閲覧するにはあまり有力ではない。
しかし、Google Sites で多人数が編集する場合には公開タイミング等に面倒が伴う。フォーマットとかそろわないし。
そこで、Google Sheets に入力した情報をそのまま出力することでフォーマットを揃えつつも編集を楽にする。
ただ、この方法は社内公開したりするには行けそうだが全世界公開をキメるにはかなり不便であった。つらい。
Google Sheets 上で FAQ を蓄積するスプレッドシートをまずは用意する。
とりあえずサンプルを用意した。ポイントは左端にカテゴリ列を入れているところだろうか。後はなんでもいい。
Google Sheets 画面上部のツールからスクリプトエディタを選び、エディタを起動する。
全体をいい感じにするユーティリティおよび、スクリプトにアクセスした際に発生することを code.gs として記載する。
function doGet() {
return HtmlService.createTemplateFromFile('index').evaluate();
}
function include(fileName) {
return HtmlService.createHtmlOutputFromFile(fileName).getContent();
}
function getTable() {
// xxxxxxxxxxxxxxxxxx の代わりにスプレッドシートの ID を入れること。
// スプレッドシートの ID は URL に含まれている。
// https://docs.google.com/spreadsheets/d/1KCCyepWlIEG7siX-r0Y-B0kmtrVC_4A2YuvUr6T3wV6/ ならば
// 1KCCyepWlIEG7siX-r0Y-B0kmtrVC_4A2YuvUr6T3wV6 である
const result = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxx').getActiveSheet().getDataRange().getValues();
return result;
}
CSS ファイルを置いてそれをダイレクトに読む、はできないので html の一部として CSS を書く。
<style>
td {
padding:4px;
}
.category {
display:inline-block;
width: 300px;
border:2px double black;
padding:4px;
margin:2px;
}
.category:hover {
background-color:lightyellow;
border: 2px double tan;
}
</style>
本丸。基本的にここに処理を書いている。ここでは直に書いているけど、JS は CSS と同じく外だししても良い気はする
<!DOCTYPE html>
<html>
<head>
<?!= include('index_css'); ?>
<base target="_top">
<?
const data = getTable();
const index = {};
data.forEach((row, id)=>{
if(id !== 0) {
if(! Boolean(index[row[0]])) {
index[row[0]] = [0];
}
index[row[0]].push(id);
}
});
?>
</head>
<body>
<h1>ソードワールド 2.5 - よくある質問ストック</h1>
<p>もちろん非公式です。『ソード・ワールド2.5』は、「グループSNE」及び「KADOKAWA」の著作物です。</p>
<div class="categories">
<h2>質問のカテゴリ</h2>
<? for(var categoryName in index) { ?>
<div class="category" value="<?= categoryName ?>"><?= categoryName ?></div>
<?} ?>
</div>
<h2>質問と回答</h2>
<table border="1">
<?
const content = data.forEach((row, id)=>{ ?>
<tr style='display:none;' class="question" id="question_<?= id?>">
<? const columns = row.forEach((field, colId)=>{
if(colId === 0) {return;}
?>
<td style="min-width:140px">
<?!= field.replaceAll(/<\/?[^>]*>/gm, '').split('\n').join('<br/>') ?>
</td>
<?
}) ?>
</tr>
<? }) ?>
</table>
<script>
const dataIndex = JSON.parse(<?= JSON.stringify(index) ?>);
const hideQuestions = ()=>{
Array.from(document.getElementsByClassName('question')).forEach((element)=>{
element.style.display = 'none';
});
};
const showQuestions = (category)=>{
console.log(category, dataIndex, dataIndex[category]);
dataIndex[category].forEach((questionId)=>{
console.log(questionId);
document.getElementById(`question_${questionId}`).style.display = '';
});
};
Array.from(document.getElementsByClassName('category')).forEach((element)=>{
element.addEventListener('click', (e)=>{
hideQuestions();
showQuestions(element.innerText);
});
});
</script>
</body>
</html>
const dataIndex = JSON.parse(<?= JSON.stringify(index) ?>);
「何やっているの?」って感じである。
<div class="category" value="<?= categoryName ?>"><?= categoryName ?></div>
これをみていただくと分かる通り<?=と?>で囲んだものはtoString された結果がそのまま HTML に書き込まれる。getTable は <?と?>で囲んだ範囲でしか使えず、script 要素内では呼べないのでこのようにしている(getTable の計算結果を dataIndex に格納しているが getTable の結果を直接格納してもいいはず)。
じゃあ、次の書き方でもいいのではないか? と思うがこれは上手くいかない。
const dataIndex = <?= index ?>);
dataIndex に格納されるのは[object Object]である。一旦 JSON.stringify して文字列として吐いた後、<?と?>の外側で JSON.parse してあげないとならない。
もうちょっといい方法が有る気はするけれども。
デプロイすればすぐにアクセスできる。ただ、認可が求められたり危険だよページが出力されたりするので面倒である。ウェブで公開するには向かないかも。社内 FAQ ページとかには使えるでしょうね。
ただいまコメントを受けつけておりません。