Re:SALOON & VBA

Node.js版 読書履歴管理システム

失業中の自己学習として(暇を持て余すので)
以前から気になっていた「Node.js」という
サーバーサイドのJavaScriptを試してます。



今までやって来たHTAも便利は便利なのですが、
厭くまでローカルの仕組み(プライベート)。
WEBの様で、WEBの勉強には今一つということでの「Node.js」です。
HTAよりは、ネットでの関連情報は多く(というか膨大)ヒットします。
HTAだと、このブログでもさえも、関連ワードさえ、何か入れれば検索エンジンでヒットしてしまいますが、
「Node.js」は、記事数が膨大なのでそんなことはありません。ありえない。
(この記事だと「Node.js版 読書履歴管理システム」としても出て来ないかも・・・)
HTAは趣味の範疇ですが、「Node.js」はちゃんと仕事になりえます。(僕には回って来ませんが…)
財団のページもあります。
https://nodejs.org/ja/

で、ネットで一週間ぐらい、あちこち見て歩いて
HTA版 読書履歴管理システムを移植してみました。
フレームワークは、ネットで盛んに喧伝されているEXPRESS
テンプレートエンジンは、EJS、
そしてDBは、得意のACCESSとの接続例(サンプル)がないので、止む無くMySQLにしました。
ちなみにブラウザは、IE11 限定です(Edgeでは上手く表示できないので断念しました。)
インストール(無料)のやり方は、他のサイト(Qiita等)を参考にして
悪戦苦闘しました。(その通りにやっているつもり(思い込み)なのに、うまく行かない等多々あり)
CSSの外部ファイル化も失敗(何んか読めません。で、ejsの中に書きました。)

書籍等のちゃんと体系化された情報をもとにせず、
まあネット検索で、つまみ食い的な理解度で(内容理解せずモノマネでコーディング)、
取りあえず、動くようにと、それで理解学習につなげようということで
一週間の素人で、バグ、非効率、理解不足は否めないものの
じゃあ、僕がそれを発展させてみようという人が現れること(たらいいな)を期待して
以下に掲載したいと思います。ダメな例として
でもこれだけのソースで、そこそこ動くものが出来るのが驚きです。ハイ!

※環境構築は面倒ですが、使い勝手のご意見や、
こうすれば、もっとよくなるよ的な猫煽て的アドバイスは大歓迎します。
(というか、コメント貰ったことほぼないブログですが・・・)
「無駄なことをするな」的、高所からの見下した切り捨てのコメントはご容赦下さい。

■一覧画面


■登録画面


■更新画面


※以下、ソースのHTMLのタグの< > は、全角に変換してペーストしています。
 また、インデントの為、半角スペース2文字を全角スペース1文字に変換しています。
※app.useの辺りは、理解せずに(意味分からず)サンプルのモノマネで書いてます。
※バグも含有してます。(念のため、お断り)
※完璧でないとダメという質ではなく、TRY & GO の性格です。

※課題
 簡単なエラーチェックしか入っていません。
 入力値が、適正でないと簡単に異常終了することもあります。
 ただ、console.logを書けば、簡単にトレース出来るので超便利です。
 Edge では、画像がでなかったり、幅がずれたりします。
 ↑直してくれる方がいれば、有難いですが・・・
 CSSが上手く効かない部分もあり、見栄えはこれでも随分苦労しました。

■テーブルの作成(CREATE TABLE) ============================
create table BOOKLOG(
ISBN13   varchar(13) NOT NULL,
ISBN10   varchar(10),
BookName  varchar(50) NOT NULL,
Author   varchar(25),
Publisher  varchar(25),
Genre    varchar(25),
IssueDate  date    ,
GetDate   date    ,
ReadDate  date    ,
Ownership  tinyint(1) ,
Purchase  int(11)  ,
Library   varchar(25),
Overview  varchar(255),
Impressions text    ,
State    varchar(10),
CoverImg  varchar(25),
PRIMARY KEY (ISBN13)
);

■app.js ========================================
var createError = require('http-errors');
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

// var indexRouter  = require('./routes/index');
// var usersRouter  = require('./routes/users');
//★1 用意したbooklog.jsをロード
var booklogRouter = require('./routes/booklog');
var addbookRouter = require('./routes/addbook');
var updbookRouter = require('./routes/updbook');
var bookinsRouter = require('./routes/bookins');
var bookupdRouter = require('./routes/bookupd');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// app.use('/', indexRouter);
// app.use('/users', usersRouter);
//★2 booklog.jsが実行されるアドレスを指定する。
app.use('/booklog', booklogRouter);
app.use('/addbook', addbookRouter);
app.use('/updbook', updbookRouter);
app.use('/bookins', bookinsRouter);
app.use('/bookupd', bookupdRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
 next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
 // set locals, only providing error in development
 res.locals.message = err.message;
 res.locals.error = req.app.get('env') === 'development' ? err : {};

 // render the error page
 res.status(err.status || 500);
 res.render('error');
});

module.exports = app;

■routes/booklog.js =================================
//★1 Expressのライブラリをロード
var express = require('express');
//★2 Routerオブジェクトの作成
var router = express.Router();

var mysql = require('mysql');
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'TestUser',
  password: 'TestUserPW',
  database: 'testdb'
});

/* GET tell page. */
//★3 GETされた時のルート情報を登録する
router.get('/', function(req, res, next) {
  var query = 'SELECT *,DATE_FORMAT(GetDate,"%Y-%m-%d") AS GDATE FROM testdb.booklog ORDER BY GetDate DESC,ReadDate DESC';
  connection.query(query, function (err, rows, fields) {
   if (err) { console.log('err: ' + err); }
   if (rows.length >= 0) {
   //★4 テンプレートファイルのレンダリング
     res.render('booklog', { books: rows });
   } else {
   // render not found page
     res.status(404).json({"status_code":404, "status_message": "Not found"});
   }
  });
});
//★5 exportsにrouterを設定
module.exports = router;

■routes/addbook.js =================================
//★1 Expressのライブラリをロード
var express = require('express');
//★2 Routerオブジェクトの作成
var router = express.Router();

/* GET tell page. */
//★3 GETされた時のルート情報を登録する
router.get('/', function(req, res, next) {
  var hiduke=new Date();
  var today = hiduke.getFullYear() + "-" + ("0"+(hiduke.getMonth() + 1)).slice(-2) + "-" + ("0"+hiduke.getDate()).slice(-2);
//★4 テンプレートファイルのレンダリング
  res.render('addbook',{ today: today });
});
//★5 exportsにrouterを設定
module.exports = router;

■routes/bookins.js =================================
//★1 Expressのライブラリをロード
var express = require('express');
//★2 Routerオブジェクトの作成
var router = express.Router();

var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

var mysql = require('mysql');
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'TestUser',
  password: 'TestUserPW',
  database: 'testdb'
});

//★3 POSTで受け取る(formのmethodがpostなので)
router.post('/', function(req, res) {
  res.setHeader('Content-Type', 'text/plain');
  // INSERT処理
  var query = 'INSERT INTO testdb.booklog VALUES ("';
  query += req.body.honban  + '","';
  query += req.body.amazonno + '","';
  query += req.body.honmei  + '","';
  query += req.body.sakusya  + '","';
  query += req.body.honya   + '","';
  query += req.body.bunrui  + '",';
  if (req.body.hakkoubi == "") {
   query += 'NULL,';
  } else {
   query += '"' + req.body.hakkoubi + '",';
  }
  if (req.body.iritebi == "") {
   query += 'NULL,';
  } else {
   query += '"' + req.body.iritebi + '",';
  }
  if (req.body.yondahi == "") {
   query += 'NULL,';
  } else {
   query += '"' + req.body.yondahi + '",';
  }
  query += req.body.shoyuu  + ',';
  query += req.body.hondai  + ',"';
  query += req.body.tosyokan + '","';
  query += req.body.gaiyou  + '","';
  query += req.body.kansou  + '","';
  query += req.body.jyokyo  + '","';
  query += req.body.gazoufile + '")';
  console.log(query);

  connection.query(query, function(err, result){
   if (err) { console.log('err: ' + err); }
   //★4 トップページにリダイレクト
   res.redirect('/booklog');
  });
});

//★5 exportsにrouterを設定
module.exports = router;

■views/booklog.ejs =================================
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>読書履歴</title>
<style>
 body{
  background-color:#8080ff;
  background:linear-gradient(to right, #00008b, #8080ff);
  "メイリオ";
 }
</style>
</head>
<body>
 <table border="0" bgcolor="#FFFFFF" align="center" valign="center" width="95%" height="95%">
  <tr valign="top">
  <td>
   <table width="95%" border="0" align="center" valign="center"
    cellspacing="2" cellpadding="2" align="left" style="margin:20px 0px;">
   <tr>
    <td height="1px" width="20%"> </td>
    <td height="1px" width="35%"> </td>
    <td height="1px" width="20%"> </td>
    <td height="1px" width="15%"> </td>
    <td height="1px" width="10%"> </td>
   </tr>
   <tr class="genrestr" bgcolor="#CCCCFF">
    <td colspan="3"><b> 読 書 履 歴 管 理</b></td>
    <td colspan="2" align="center"><a href="http://localhost:3000/addbook">新規追加</a></td>
   </tr>
   <tr align=center bgcolor="#CCCCFF">
    <td>ISBN-13</td>
    <td>書 名</td>
    <td>著 者</td>
    <td>入手日</td>
    <td>状 況</td>
   </tr>
   <% books.forEach(function(bookItem) { %>
    <tr bgcolor=#E0F1FF>
    <td align=center><a href="http://localhost:3000/updbook/<%= bookItem.ISBN13 %>">
     <%= bookItem.ISBN13 %></a></td>
    <td><%= bookItem.BookName %></td>
    <td><%= bookItem.Author %></td>
    <td align=center><%= bookItem.GDATE %></td>
    <td align=center><%= bookItem.State %></td>
    </tr>
   <% }); %>
   </table>
  </td>
  </tr>
 </table>
</body>
</html>

■views/addbook.ejs =================================
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>読書履歴追加</title>
<style>
 body{
  width :1100px ;
  background-color:#00008b;
  background:linear-gradient(to right, #00008b, #8080ff);
  "メイリオ";
 }
 .valueCstr{color:"#000077";font-size:12pt;font-style:normal;text-align=center;}
 .ministr {color:"#000077";font-size:8pt;font-style:normal;}
 .inpstr1 {color:"#000077";font-size:12pt;font-style:normal;text-align=center;width:155px;border:none;"メイリオ"; .inpstr1A {color:"#000077";font-size:12pt;font-style:normal;text-align=left; width:195px;border:none;"メイリオ";ime-mode: inactive;}
 .inpstr1R {color:"#000077";font-size:12pt;font-style:normal;         width:70px;border:none;"メイリオ";ime-mode: inactive;}
.inpstr1A {color:"#000077";font-size:12pt;font-style:normal;text-align=left; width:195px;border:none;"メイリオ";ime-mode: active;}
 .inpstr2 {color:"#000077";font-size:12pt;font-style:normal;text-align=left; width:320px;border:none;"メイリオ";ime-mode: active;}
 .inpstr4 {color:"#000077";font-size:12pt;font-style:normal;text-align=left; width:820px;border:none;"HGゴシックM";ime-mode: active;}
 .inpbox  {color:"#000077";font-size:11pt;font-style:normal;text-align=left;       border:none;"HGゴシックM";}
 .selbox  {color:"#000077";font-size:12pt;font-style:normal;text-align=center;width:80px;border:none;"メイリオ";}
 A:    {text-decoration: none }
 A:link  {color:"#000077"}
 A:active {color:steelblue}
 A:visited {color:"#000077"}
 A:hover  {color:steelblue}
</style>
<script type="text/javascript">
 <!--
  // http://www.html5.jp/tag/elements/forms-constraints.html
  function check1(elm) { 
   if (/9784000000000/.test(elm.value)) {
     elm.setCustomValidity('その番号は使えません');
   } else {
     elm.setCustomValidity('');
   }
  };
  function check2(elm) { 
   if (/4000000000/.test(elm.value)) {
     elm.setCustomValidity('その番号は使えません');
   } else {
     elm.setCustomValidity('');
   }
  };
 // -->
</script>
</head>
<body>
<form name="formA" method="post" action="/bookins">
  <input type="button" value="一覧に戻る" onClick="location.href='http://localhost:3000/booklog'" style="width: 8%; padding: 6px;">
  <input type="submit" value="登録する" style="width: 8%; padding: 6px;">
 <p>
 <table border="0" bgcolor="#00008b" align="center" valign="center" width="98%" height="95%>
  <tr valign="top">
  <td>
   <table width="98%" border="2" align="center" valign="center" bordercolor="#00008b"
    cellspacing="2" cellpadding="2" align="left" style="margin:20px 0px;" bgcolor="#00008b">
   <tr height="15px" bgcolor="#FFFFFF" bordercolor="#00008b">
    <td bgcolor="#E8E0FF" width="10%" align="center"><b>ISBN-13<font size="1" color="#FF3366">※</b></font></td>
    <td width="25%"> <input id="honban" name="honban" type="text" placeholder="9784000000000" class="inpstr1" required pattern="\d{13}" title="数字13桁" onchange='check1(this);' /></td>
    <td bgcolor="#E8E0FF" width="10%" align="center"><a href="https://www.amazon.co.jp/" target="_blank">ISBN-10</a><font size="1" color="#FF3366"></td>
    <td width="25%"> <input id="amazonno" name="amazonno" type="text" placeholder="4000000000" class="inpstr1" pattern="\d{10}" title="数字10桁" onchange='check2(this);' />
    <span class="error" aria-live="polite"></span></td>
    <td bgcolor="#E8E0FF" width="10%" align="center">状  況</td>
    <td> <select name="jyokyo" class="selbox">
    <option value="未読" selected>未読</option><option value="読書中">読書中</option><option value="読了">読了</option></select></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">書  名<font size="1" color="#FF3366">※</b></td>
    <td colspan="5" align="left"> <input id="honmei" name="honmei" type="text" class="inpstr4" required></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">著  者</td>
    <td colspan="3" align="left"> <input id="sakusya" name="sakusya" type="text" class="inpstr2"></td>
    <td bgcolor="#E8E0FF" align="center">ジャンル</td>
    <td align="left"> <input id="bunrui" name="bunrui" type="text" class="inpstr1A"></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">出 版 社</td>
    <td colspan="3" align="left"> <input id="honya" name="honya" type="text" class="inpstr2"></td>
    <td bgcolor="#DDEEFF" align="center">画  像</td>
    <td align="left"> <input id="gazoufile" name="gazoufile" type="text" class="inpstr1"></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#EEDDFF" align="center">発 行 日</td>
    <td> <input id="hakkoubi" name="hakkoubi" type="date" class="inpstr1" value="<%= today %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
    <td bgcolor="#E8E0FF" align="center">入 手 日</td>
    <td> <input id="iritebi" name="iritebi" type="date" class="inpstr1" value="<%= today %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
    <td bgcolor="#EEDDFF" align="center">読 了 日</td>
    <td> <input id="yondahi" name="yondahi" type="date" class="inpstr1" value="<%= today %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#DFDFFF" align="center">概  要</td>
    <td colspan="5" align="left"> <input id="gaiyou" name="gaiyou" type="text" class="inpstr4"></td>
   </tr>
   <tr bgcolor="#FFFFFF">
    <td bgcolor="#DFDFFF" align="center">感  想</td>
    <td colspan="5" align="center">
    <textarea name="kansou" cols="122" rows="10" class="inpbox"></textarea></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">所  有</td>
    <td> <select name="shoyuu" class="selbox">
    <option value="1" selected>購入</option><option value="0">非購入</option></select></td>
    <td bgcolor="#EEDDFF" align="center">購入金額</td>
    <td align="left"> \ <input id="hondai" name="hondai" type="number" class="inpstr1R" value=0 style="text-align: right;">-</td>
    <td bgcolor="#E8E0FF" align="center">図 書 館</td>
    <td align="left"> <input id="tosyokan" name="tosyokan" type="text" class="inpstr1A"></td>
   </tr>
   </table>
  </td>
  </tr>
  <tr>
  <td align="right">
   <font class="ministr"><font color="#FF3366">※</font><font color="#FFFFFF">の項目は入力必須項目です。</font>
  </td>
  </tr>
 </table>
</form>
</body>
</html>

※更新画面のソースは、Node.js版 読書履歴管理システム② に続く

コメント一覧

オーナー
Chromeもどうにか④
※これで最後になりますか?

    <td width="14%"> <input id="amazonno" name="amazonno" type="text" class="inpstr1" value="<%= bookItem.ISBN10 %>" pattern="\d{10}" title="数字10桁" onchange='check2(this);' /></td>
    <td bgcolor="#E8E0FF" width="9%" align="center">状  況</td>
    <td> <select name="jyokyo" class="selbox">
    <% if (bookItem.State === '未読') { %>
     <option value="未読" selected>未読</option>
     <option value="読書中">読書中</option>
     <option value="読了">読了</option>
    <% } else if (bookItem.State === '読書中') { %>
     <option value="未読">未読</option>
     <option value="読書中" selected>読書中</option>
     <option value="読了">読了</option>
    <% } else { %>
     <option value="未読">未読</option>
     <option value="読書中">読書中</option>
     <option value="読了" selected>読了</option>
    <% } %>
     </select></td>
    <td bgcolor="#DDEEFF" width="10%" align="center">画  像</td>
    <td align="left" width="18%"> <input id="gazoufile" name="gazoufile" type="text" class="inpstr1L" value="<%= bookItem.CoverImg %>"></td></tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">書  名<font size="1" color="#FF3366">※</b></td>
    <td colspan="5" align="left"> <input id="honmei" name="honmei" type="text" class="inpstr3" value="<%= bookItem.BookName %>" required></td>
    <td rowspan="8" colspan="2" align="center">
    <% if (bookItem.CoverImg !== "") { %>
     <img width="250" src="../images/<%= bookItem.CoverImg %>">
    <% } %>
    </td></tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">著  者</td>
    <td colspan="3" align="left"> <input id="sakusya" name="sakusya" type="text" class="inpstr2" value="<%= bookItem.Author %>"></td>
    <td bgcolor="#E8E0FF" align="center">ジャンル</td>
    <td align="left"> <input id="bunrui" name="bunrui"type="text" class="inpstr1A" value="<%= bookItem.Genre %>"></td></tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">出 版 社</td>
    <td colspan="5" align="left"> <input id="honya" name="honya" type="text" class="inpstr3" value="<%= bookItem.Publisher %>"></td></tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#EEDDFF" align="center">発 行 日</td>
    <td align="center"> <input id="hakkoubi" name="hakkoubi" type="date" class="inpstr1D" value="<%= bookItem.IDATE %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
    <td bgcolor="#E8E0FF" align="center">入 手 日</td>
    <td align="center"> <input id="iritebi" name="iritebi" type="date" class="inpstr1D" value="<%= bookItem.GDATE %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
    <td bgcolor="#EEDDFF" align="center">読 了 日</td>
    <td align="center"> <input id="yondahi" name="yondahi" type="date" class="inpstr1D" value="<%= bookItem.RDATE %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td></tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#DFDFFF" align="center">概  要</td>
    <td colspan="5" align="left"> <input id="gaiyou" name="gaiyou" type="text" class="inpstr3" value="<%= bookItem.Overview %>"></td></tr>
   <tr bgcolor="#FFFFFF">
    <td bgcolor="#DFDFFF" align="center">感  想</td>
    <td colspan="5" align="center">
    <textarea name="kansou" cols="85" rows="12" class="inpbox"><%= bookItem.Impressions %></textarea></td></tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">図 書 館</td>
    <td align="left"> <input id="tosyokan" name="tosyokan" type="text" class="inpstr1A" value="<%= bookItem.Library %>"></td>
    <td bgcolor="#E8E0FF" align="center">所  有</td>
    <td> <select name="shoyuu" class="selbox">
    <% if (bookItem.Ownership === 1) { %>
      <option value=true selected>購入</option>
      <option value=false>非購入</option>
    <% } else { %>
      <option value=true>購入</option>
      <option value=false selected>非購入</option>
    <% } %>
      </select></td>
    <td bgcolor="#EEDDFF" align="center">購入金額</td>
    <td align="left"> \ <input id="hondai" name="hondai" type="number" class="inpstr1R" value="<%= bookItem.Purchase %>" style="text-align: right;">-</td>
   </tr>
   </table>
  </td>
  </tr>
  <tr>
  <td align="right">
   <font class="ministr"><font color="#FF3366">※</font><font color="#FFFFFF">の項目は入力必須項目です。</font>
  </td>
  </tr>
 </table>
</form>
</body>
</html>
オーナー
Chromeもどうにか③
※また、切れたので続き

    <td bgcolor="#E8E0FF" align="center">図 書 館</td>
    <td align="left"> <input id="tosyokan" name="tosyokan" type="text" class="inpstr1A"></td>
   </tr>
   </table>
  </td>
  </tr>
  <tr>
  <td align="right">
   <font class="ministr"><font color="#FF3366">※</font><font color="#FFFFFF">の項目は入力必須項目です。</font>
  </td>
  </tr>
 </table>
</form>
</body>
</html>

■views/updbook.ejs =================================
<!-- script src="/javascripts/jquery-3.3.1.min.js"></script -->
<!-- script src="/javascripts/jquery-ui.min.js"></script -->
<!-- script src="/javascripts/datepicker_ja.js"></script -->
<!-- link type="text/css" rel="stylesheet" href="/stylesheets/jquery-ui.min.css" / -->
<script>
$(function() {
 var userAgent = window.navigator.userAgent.toLowerCase();
 if(userAgent.indexOf('msie') != -1 ||
   userAgent.indexOf('trident') != -1 ||
   userAgent.indexOf('edge') != -1) {
  $('#hakkoubi').datepicker({ dateFormat: 'yy-mm-dd' });
  $('#iritebi').datepicker({ dateFormat: 'yy-mm-dd' });
  $('#yondahi').datepicker({ dateFormat: 'yy-mm-dd' });
 }
});
</script>
<style>
 body{
  width :1120px ;
  background-color:#00008b;
  background:linear-gradient(to right, #00008b, #8080ff);
  font-family: "メイリオ";
  font-size:12pt;
 }
 .valueCstr{color:"#000077";font-size:12pt;font-style:normal;text-align="center";}
 .ministr {color:"#000077";font-size:8pt ;font-style:normal;}
 .inpstr1 {color:"#000077";font-size:11pt;font-style:normal;text-align="center";width:105px;border:none;font-family:"メイリオ";ime-mode: inactive;}
 .inpstr1D {color:"#000077";font-size:11pt;font-style:normal;text-align="center";width:140px;border:none;font-family:"メイリオ";ime-mode: inactive;}
 .inpstr1L {color:"#000077";font-size:12pt;font-style:normal;text-align="left"; width:155px;border:none;font-family:"メイリオ";ime-mode: inactive;}
 .inpstr1R {color:"#000077";font-size:12pt;font-style:normal;          width:70px ;border:none;font-family:"メイリオ";ime-mode: inactive;}
 .inpstr1A {color:"#000077";font-size:12pt;font-style:normal;text-align="left"; width:140px;border:none;font-family:"メイリオ";ime-mode: active;}
 .inpstr2 {color:"#000077";font-size:12pt;font-style:normal;text-align="left"; width:360px;border:none;font-family:"メイリオ";ime-mode: active;}
 .inpstr3 {color:"#000077";font-size:12pt;font-style:normal;text-align="left"; width:620px;border:none;font-family:"メイリオ";ime-mode: active;}
 .inpstr4 {color:"#000077";font-size:12pt;font-style:normal;text-align="left"; width:620px;border:none;font-family:"HGゴシックM";ime-mode: active;}
 .inpbox  {color:"#000077";font-size:11pt;font-style:normal;text-align="left";       border:none;font-family:"HGゴシックM";}
 .selbox  {color:"#000077";font-size:12pt;font-style:normal;text-align="center";width:80px ;border:none;font-family:"メイリオ";}
 A:    {text-decoration: none }
 A:link  {color:"#000077"}
 A:active {color:steelblue}
 A:visited {color:"#000077"}
 A:hover  {color:steelblue}
</style>
<script type="text/javascript">
 <!--
  function check(){
   if (document.formU.action.value == "DEL") {
    var msg = "削除してもいいですか?";
   } else {
    var msg = "更新してもいいですか?";
   }
   if (window.confirm(msg)){          // 確認ダイアログを表示
    return true; // 「OK」時は送信を実行
   } else {     // 「キャンセル」時の処理
    window.alert('キャンセルされました');  // 警告ダイアログを表示
    return false; // 送信を中止
   }
  };
  function check2(elm) { 
   if (/4000000000/.test(elm.value)) {
     elm.setCustomValidity('その番号は使えません');
   } else {
     elm.setCustomValidity('');
   }
  };
 // -->
</script>
</head>
<body>
<% var bookItem = books[0]; %>
<form name="formU" method="post" action="/bookupd" onSubmit="return check()">
  <input type="button" value="一覧に戻る" onClick="location.href='http://localhost:3000/booklog'" style="width: 8%; padding: 6px;">
  <button type="submit" value="UPD" name="action" style="width: 8%; padding: 6px;">更新する</button>
  <button type="submit" value="DEL" name="action" style="width: 8%; padding: 6px;">削除する</button>
 <p>
 <table border="0" bgcolor="#00008b" align="center" valign="center" width="98%" height="95%">
  <tr valign="top">
  <td>
   <table width="98%" border="2" align="center" valign="center" bordercolor="#00008b"
    cellspacing="2" cellpadding="2" align="left" style="margin:20px 0px;" bgcolor="#00008b">
   <tr height="15px" bgcolor="#FFFFFF" bordercolor="#00008b">
    <td bgcolor="#E8E0FF" width="10%" align="center"><b>ISBN-13<font size="1" color="#FF3366">※</b></font></td>
    <td align="center"><b><%= bookItem.ISBN13 %></b>
     <input type="hidden" name="honno" VALUE="<%= bookItem.ISBN13 %>">
    </td>
    <td bgcolor="#E8E0FF" width="9%" align="center"><a href="https://www.amazon.co.jp/dp/<%= bookItem.ISBN10 %>" target="_blank">ISBN-10</a><font size="1" color="#FF3366"></td>

※また、切れたので続く
オーナー
Chromeもどうにか②
※字数制限で切れたので、続きです。

 text-align=left; width:860px;border:none;font-family:"HGゴシックM";ime-mode: active;}
 .inpbox  {color:"#000077";font-size:11pt;font-style:normal;text-align=left;       border:none;font-family:"HGゴシックM";}
 .selbox  {color:"#000077";font-size:12pt;font-style:normal;text-align=center;width:80px; border:none;font-family:"メイリオ";}
 A:    {text-decoration: none }
 A:link  {color:"#000077"}
 A:active {color:steelblue}
 A:visited {color:"#000077"}
 A:hover  {color:steelblue}
</style>
<script type="text/javascript">
 <!--
  // http://www.html5.jp/tag/elements/forms-constraints.html
  function check1(elm) { 
   if (/9784000000000/.test(elm.value)) {
     elm.setCustomValidity('その番号は使えません');
   } else {
     elm.setCustomValidity('');
   }
  };
  function check2(elm) { 
   if (/4000000000/.test(elm.value)) {
     elm.setCustomValidity('その番号は使えません');
   } else {
     elm.setCustomValidity('');
   }
  };
 // -->
</script>
</head>
<body>
<form name="formA" method="post" action="/bookins">
  <input type="button" value="一覧に戻る" onClick="location.href='http://localhost:3000/booklog'" style="width: 8%; padding: 6px;">
  <input type="submit" value="登録する" style="width: 8%; padding: 6px;">
 <p>
 <table border="0" bgcolor="#00008b" align="center" valign="center" width="98%" height="95%>
  <tr valign="top">
  <td>
   <table width="98%" border="2" align="center" valign="center" bordercolor="#00008b"
    cellspacing="2" cellpadding="2" align="left" style="margin:20px 0px;" bgcolor="#00008b">
   <tr height="15px" bgcolor="#FFFFFF" bordercolor="#00008b">
    <td bgcolor="#E8E0FF" width="12%" align="center"><b>ISBN-13<font size="1" color="#FF3366">※</b></font></td>
    <td width="25%"> <input id="honban" name="honban" type="text" placeholder="9784000000000" class="inpstr1" required pattern="\d{13}" title="数字13桁" onchange='check1(this);' /></td>
    <td bgcolor="#E8E0FF" width="9%" align="center"><a href="https://www.amazon.co.jp/" target="_blank">ISBN-10</a><font size="1" color="#FF3366"></td>
    <td width="25%"> <input id="amazonno" name="amazonno"type="text" placeholder="4000000000" class="inpstr1" pattern="\d{10}" title="数字10桁" onchange='check2(this);' />
    <span class="error" aria-live="polite"></span></td>
    <td bgcolor="#E8E0FF" width="10%" align="center">状  況</td>
    <td> <select name="jyokyo" class="selbox">
    <option value="未読" selected>未読</option><option value="読書中">読書中</option><option value="読了">読了</option></select></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">書  名<font size="1" color="#FF3366">※</b></td>
    <td colspan="5" align="left"> <input id="honmei" name="honmei" type="text" class="inpstr4" required></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">著  者</td>
    <td colspan="3" align="left"> <input id="sakusya" name="sakusya" type="text" class="inpstr2"></td>
    <td bgcolor="#E8E0FF" align="center">ジャンル</td>
    <td align="left"> <input id="bunrui" name="bunrui" type="text" class="inpstr1A"></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">出 版 社</td>
    <td colspan="3" align="left"> <input id="honya" name="honya"type="text" class="inpstr2"></td>
    <td bgcolor="#DDEEFF" align="center">画  像</td>
    <td align="left"> <input id="gazoufile" name="gazoufile" type="text" class="inpstr1"></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#EEDDFF" align="center">発 行 日</td>
    <td> <input id="hakkoubi" name="hakkoubi" type="date" class="inpstr1" value="<%= today %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
    <td bgcolor="#E8E0FF" align="center">入 手 日</td>
    <td> <input id="iritebi" name="iritebi" type="date" class="inpstr1" value="<%= today %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
    <td bgcolor="#EEDDFF" align="center">読 了 日</td>
    <td> <input id="yondahi" name="yondahi" type="date" class="inpstr1" value="<%= today %>" pattern="\d{4}-\d{2}-\d{2}" title="YYYY-MM-DD"></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#DFDFFF" align="center">概  要</td>
    <td colspan="5" align="left"> <input id="gaiyou" name="gaiyou" type="text" class="inpstr4"></td>
   </tr>
   <tr bgcolor="#FFFFFF">
    <td bgcolor="#DFDFFF" align="center">感  想</td>
    <td colspan="5" align="center">
    <textarea name="kansou" cols="122" rows="10" class="inpbox"></textarea></td>
   </tr>
   <tr height="15px" bgcolor="#FFFFFF">
    <td bgcolor="#E8E0FF" align="center">所  有</td>
    <td> <select name="shoyuu" class="selbox">
    <option value="1" selected>購入</option><option value="0">非購入</option></select></td>
    <td bgcolor="#EEDDFF" align="center">購入金額</td>
    <td align="left"> \ <input id="hondai" name="hondai" type="number" class="inpstr1R" value=0 style="text-align: right;">-</td>
オーナー
Chromeもどうにか
Edge と GoogleChrome でも表示可能な様に、微調整しました。
InternetExplorerでの表示時には、横広の感が若干ありますが・・・

■views/booklog.ejs =================================
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>読書履歴</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
<link type="text/css" rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/overcast/jquery-ui.min.css" />
<script type="text/javascript">
 var page = 0;
 $(function() {
  var max = 10; // 1ページ単位の表示数
  function draw() {
   $('#page').html(page + 1);
   $('tr').hide();
   $('tr:lt(4),tr:gt(' + (page * max + 3) + '):lt(' + max + ')').show();
  }
  $('#prev').click(function() {
   if (page > 0) {
    page--;
    draw();
   }
  });
  $('#next').click(function() {
   if (page < ($('tr').size() - 4) / max - 1) {
    page++;
    draw();
   }
  });
  draw();
 });
</script>
<style>
 body{
  background-color:#8080ff;
  background:linear-gradient(to right, #00008b, #8080ff);
  font-family: "メイリオ";
  font-size:13pt;
 }
</style>
</head>
<body>
 <table border="0" bgcolor="#FFFFFF" align="center" valign="center" width="95%" height="95%">
  <tr valign="top">
  <td>
   <table width="95%" border="0" align="center" valign="center"
    cellspacing="2" cellpadding="2" align="left" style="margin:20px 0px;">
   <tr>
    <td height="1px" width="155px"> </td>
    <td height="1px"> </td>
    <td height="1px"> </td>
    <td height="1px" width="120px"> </td>
    <td height="1px" width="55px"> </td>
   </tr>
   <tr class="genrestr" bgcolor="#CCCCFF">
    <td colspan="3">
    <div style="float:left;"><b> 読 書 履 歴 管 理</b></div>
    <div style="text-align:center;"><span id="prev"><span id="page"></span><Prev</span> <span id="next">Next></span></div></td>
    <td colspan="2" align="center"><a href="http://localhost:3000/addbook">新規追加</a>
    </td>
   </tr>
   <tr align=center bgcolor="#CCCCFF">
    <th>ISBN-13</th>
    <th>書 名</th>
    <th>著 者</th>
    <th>入手日</th>
    <th>状 況</th>
   </tr>
   <% books.forEach(function(bookItem) { %>
    <tr bgcolor=#E0F1FF>
    <td align=center><a href="http://localhost:3000/updbook/<%= bookItem.ISBN13 %>">
     <%= bookItem.ISBN13 %></a></td>
    <td><%= bookItem.BookName %></td>
    <td><%= bookItem.Author %></td>
    <td align=center><%= bookItem.GDATE %></td>
    <td align=center><%= bookItem.State %></td>
    </tr>
   <% }); %>
   </table>
  </td>
  </tr>
 </table>
</body>
</html>

■views/addbook.ejs =================================
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>読書履歴追加</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
<link type="text/css" rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/overcast/jquery-ui.min.css" />
<!-- script src="/javascripts/jquery-3.3.1.min.js"></script -->
<!-- script src="/javascripts/jquery-ui.min.js"></script -->
<!-- script src="/javascripts/datepicker_ja.js"></script -->
<!-- link type="text/css" rel="stylesheet" href="/stylesheets/jquery-ui.min.css" / -->
<script>
$(function() {
 var userAgent = window.navigator.userAgent.toLowerCase();
 if(userAgent.indexOf('msie') != -1 ||
   userAgent.indexOf('trident') != -1 ||
   userAgent.indexOf('edge') != -1) {
  $('#hakkoubi').datepicker({ dateFormat: 'yy-mm-dd' });
  $('#iritebi').datepicker({ dateFormat: 'yy-mm-dd' });
  $('#yondahi').datepicker({ dateFormat: 'yy-mm-dd' });
 }
});
</script>
<style>
 body{
  width :1100px ;
  background-color:#00008b;
  background:linear-gradient(to right, #00008b, #8080ff);
  font-family: "メイリオ";
  font-size:13pt;
 }
 .valueCstr{color:"#000077";font-size:12pt;font-style:normal;text-align=center;}
 .ministr {color:"#000077";font-size:8pt;font-style:normal;}
 .inpstr1 {color:"#000077";font-size:12pt;font-style:normal;text-align=center;width:155px;border:none;font-family:"メイリオ";ime-mode: inactive;}
 .inpstr1R {color:"#000077";font-size:12pt;font-style:normal;         width:70px; border:none;font-family:"メイリオ";ime-mode: inactive;}
 .inpstr1A {color:"#000077";font-size:12pt;font-style:normal;text-align=left; width:160px;border:none;font-family:"メイリオ";ime-mode: active;}
 .inpstr2 {color:"#000077";font-size:12pt;font-style:normal;text-align=left; width:575px;border:none;font-family:"メイリオ";ime-mode: active;}
 .inpstr4 {color:"#000077";font-size:12pt;font-style:normal;text-align=left;

※次に続く
オーナー
ページングを追加
http://ponk.jp/jquery/basic/pagination
その後、自分用で使っているのですが、
登録数が増えると、ページャーを付けたくなりました。
で、ページネーション(というらしい)jQuery の部品を
ネットで漁ったんですが、(本格的なのは)うまく行かず
簡単なのを見付けて(NEXTとBEFOREで手繰るだけの)見つけて
実装してみました。

参考にしたのは、http://ponk.jp/jquery/basic/pagination
ポンクソフトさんありがとう。

やってることは、ページ番号で計算したTR要素だけを表示して
他を隠しているだけ(読込み、表示していない分も含めて全件です)
※1000件以上とかだと、方式を変える(表示分だけ読むとか)必要ありですが、当面は・・・

■views/booklog.ejs =================================
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>読書履歴</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
<link type="text/css" rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/overcast/jquery-ui.min.css" />
<script type="text/javascript">
 $(function() {
  var page = 0; // 現在のページ(先頭ページは、0)
  var max = 10; // 1ページ単位の表示数
  function draw() {
   $('#page').html(page + 1);
   $('tr').hide();
   $('tr:lt(4),tr:gt(' + (page * max + 3) + '):lt(' + max + ')').show();
  }
  $('#prev').click(function() {
   if (page > 0) {
    page--;
    draw();
   }
  });
  $('#next').click(function() {
   if (page < ($('tr').size() - 4) / max - 1) {
    page++;
    draw();
   }
  });
  draw();
 });
</script>
<style>
 body{
  background-color:#8080ff;
  background:linear-gradient(to right, #00008b, #8080ff);
  font-family: "メイリオ";
 }
</style>
</head>
<body>
 <table border="0" bgcolor="#FFFFFF" align="center" valign="center" width="95%" height="95%">
  <tr valign="top">
  <td>
   <table width="95%" border="0" align="center" valign="center"
    cellspacing="2" cellpadding="2" align="left" style="margin:20px 0px;">
   <tr>
    <td height="1px" width="150px"> </td>
    <td height="1px"> </td>
    <td height="1px"> </td>
    <td height="1px" width="115px"> </td>
    <td height="1px" width="60px"> </td>
   </tr>
   <tr class="genrestr" bgcolor="#CCCCFF">
    <td colspan="3"><b> 読 書 履 歴 管 理</b> 
    <span id="prev"><</span> <span id="page"></span> <span id="next">></span>
    </td>
    <td colspan="2" align="center"><a href="http://localhost:3000/addbook">新規追加</a>
    </td>
   </tr>
   <tr align=center bgcolor="#CCCCFF">
    <th>ISBN-13</th>
    <th>書 名</th>
    <th>著 者</th>
    <th>入手日</th>
    <th>状 況</th>
   </tr>
   <% books.forEach(function(bookItem) { %>
    <tr bgcolor=#E0F1FF>
    <td align=center><a href="http://localhost:3000/updbook/<%= bookItem.ISBN13 %>">
     <%= bookItem.ISBN13 %></a></td>
    <td><%= bookItem.BookName %></td>
    <td><%= bookItem.Author %></td>
    <td align=center><%= bookItem.GDATE %></td>
    <td align=center><%= bookItem.State %></td>
    </tr>
   <% }); %>
   </table>
  </td>
  </tr>
 </table>

</body>
</html>
オーナー
カレンダー部品
IE11 では、HTML5であっても
日付のカレンダー入力ができないので
jQuery を追加してみました。

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js"></script>
<link type="text/css" rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/overcast/jquery-ui.min.css" />
<script>
$(function() {
  $('#hakkoubi').datepicker({ dateFormat: 'yy-mm-dd' });
  $('#iritebi').datepicker({ dateFormat: 'yy-mm-dd' });
  $('#yondahi').datepicker({ dateFormat: 'yy-mm-dd' });
});
</script>
オーナー
参考にさせていただいたページ
MySQLインストール
https://www.dbonline.jp/mysql/install/

windowsにNode.jsをインストールする - Qiita
https://qiita.com/Masayuki-M/items/840a997a824e18f576d8

Express のインストール - Express.js
http://expressjs.com/ja/starter/installing.html

EJSテンプレートエンジンの使い方メモ | SAGA.TXT
http://sagatto.com/20160208_nodejs_ejs

Express 4でPOSTされたJSONを扱う - Qiita
https://qiita.com/mas0061/items/f6cb22db1a7ec121fd81

↑でも、一部です(参考にしたのはもっと多くのサイト)。
かつまた、つまみ食いで→全部まるまるではなく・・・
オーナー
追加
そうそう、書き忘れましたので追加

HTAのよいところは、
環境設定が不要なところです。
ブラウザは、ない訳ないし
僕の仕組みでは、ACCESS さえあれば・・・
無ければ、『Accessランタイム』をインストール(無料)すればいいので・・・
僕は、実は、そうしてました。

Node.js は、有料ではないものの
インストール(環境設定)が大変です。
勿論、僕は慣れていない(初めてなので)
もう、ネットでいくつもの入門ページを参照して、ようやく動くものになりました。
是非、あなたも苦労して下さい(身になります)

同行者を求めています。
こう直したら、効果的ですよ的なアドバイスが・・・あったらな・・・と思うこと度々。
少し、先輩が望ましいですが・・・
鬼コーチはご遠慮します。m(_ _)m
オーナー
Node.jsとHTAの比較
Node.jsとHTAの比較で言えば、

HTAは、HTMLベースであっても厭くまでアプリケーションなので
ブラウザで操作というのとは違います。別アプリです。
だから、ブラウザのメニューバー、ツールバーの機能などはないです。
単に、HTML、JavaScriptで書いているだけで・・・

Node.js は、ブラウザで操作する正真正銘のWebアプリです。
いいところは、ちゃんと、サーバーサイドとクライアントが区別されている
ところだと思います。
今回のだと、*.js がサーバーサイド
*.ejs がクライアント という僕の認識です。
ブラウザなので、お気に入りに登録できたり、履歴に残ったり・・・も普通に。
やってないけど、家庭内PCで共有とか出来るでしょうね。

HTAは、既にもう枯れていて、新しくなることがなく
最新のCSSの機能は使えなかったりします。(将来、OSがガラッと変わったら使えなくなる)
サーバーサイドとクライアントの分離はないので、js部分を外部ファイル化するものの
結局は、HTA単体で動く仕組みではないかなと思います。

ただ、Node.jsは、すでに
フレームワークありきになっていて、
素のJavaScriptではなくなっていて(サンプルがなければ僕はお手上げなので)
中身とか意味とか理解しないまま(僕の場合ですが)、
否、理解できないまま、どんどん進んでしまった感はあります。
(HTAは、jQueryを除けば、一応、理解し尽くして進んでいたと思いますけど)

でも、Node.js 常に進化しているので、
最新CSS(って僕が知らないだけなんですが)とか、
HTML5の機能とか、便利になっているんだなぁ~と
今回、勉強させてもらいました。

Qiitaには、お世話になりました。
https://qiita.com/tags/nodejs
Node.jsで検索すると、必ず出て来ます。

投稿者には感謝しかないですが、
でも、コメントが辛辣なんですよね、
フレンドリーな人もいますが、
技術系掲示板サイトにありがちな、高飛車な人(何様)
という人もいて・・・
正しいにしろ、僕はそういう人の「存在」が、気になってしまう(むかつく)ので…

今回、一応自分なりに、
図書履歴を管理できる仕組みが出来たので、大満足です。
EXCEL で間に合うって言われれば、それまでなんですが・・・

次、また、〇〇管理システムが思いついたら
Node.jsで作るつもりです。HTAは卒業です。
名前:
コメント:

※文字化け等の原因になりますので顔文字の投稿はお控えください。

コメント利用規約に同意の上コメント投稿を行ってください。

 

※ブログ作成者から承認されるまでコメントは反映されません。

  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最新の画像もっと見る

最近の「Node.js他(Python)」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事