前回の記事で、electronのpreload.jsの機能とipc通信について書きました。この後は、①htmlとcssの作りこみ → ②renderer.jsとmain.jsの作りこみ → ③ウィンドウズ用にexe化 Mac用にapp化 の流れです。この記事では、②まで記録しておきます。
htmlとcssの作りこみ
htmlとcssの作りこみで以下のような画面を作りました。cssにはbootstrap、headerのところにvegas.js、ボタンの操作にjqueryを使っています。
つまずいた点
- Content-Security-Policy
- jQueryが使えない??
- Enterボタンで画面がリフレッシュされる
Content-Security-Policy
htmlのセキュリティを高めるためのものだそうです。何回もコメントアウトしたり、追加したりと繰り返して意味が分かって気ました。以下が最終的に落ち着いたコードです。
<meta http-equiv="Content-Security-Policy"
content="default-src 'self' 'unsafe-inline' ; script-src-elem 'self' https://*.github.io/ ">
“default-src ‘self’ ‘unsafe-inline’ ;
これは、デフォルトのソースはどこにするかということを問われています。カレントディレクトリ内のものはOKという意味でselfを指定しています。また、unsafe-inlineはhtmlのinlineスクリプトを許す設定です。datalistのoptionを付けると、inlineスクリプトとみなされてしまうようなのでどうしても、付け加える必要がありました。datalistで自由記入欄にプルダウンを作りたかったのでdatalistにoptionを付けたらpolicy違反だといわれ、渋々この文言を加えました。ここ以外はscriptないのに。。
script-src-elem ‘self’ https://*.github.io/ “
郵便番号を入力すると自動で住所が記入される仕組みをajaxzip3で入れたのですが、外部通信してgithubのデータサーバから情報を取ってくる仕組みでした。最初はpolicy違反だといわれたのですが、上記のような記述することでgithub.io外部通信を許したらできるようになりました。
jQueryが使えない??
$がundifinedだといわれました。色々色々した結果、main.jsでcontextIsolation:trueとnodeIntegration:falseにすることで、通常通り使えるようになりました。jqueryはダウンロードして使っています。最初は、preload.jsに書き込む必要があるのかなと思って色々contextbridgeしてみたりしました。結局だめで、<link jquery>の前段後段に、window objectを退去させてまた戻すみたなやつもやったけど結局ダメでした。main.jsを見ると、contextIsolation:falseとnodeintegration:tureにしてて、知らない間にデフォルト状態から変えていました。ここを戻すと、通常通りhtmlにリンクを張るだけで不通に使えました。
Enterボタンで画面がリフレッシュされる
なぜ?? とりあえずrenderer.jsでEnterを無効化してみる。
function enter(){
if( window.event.keyCode == 13 ){
return false;
}
};
document.onkeypress = enter;
とりあえず、リフレッシュできなくなったけど!けど、textareaで改行できなくなった。。。
解決策1:buttonタグをすべてtype=”submit”からtype=”button”に変更する。 → 全く効かない
解決策2:formタグをみつけてはすべて<form onsubmit=”return false”>にする。 → 効いた
renderer.jsとmain.jsの作りこみ
①renderer.jsだけで完結するものと、②renderer.jsとmain.jsとの通信が必要なものの2つがあります。
①renderer.jsのみで完結する機能
- ページが読み込まれると同時に診療日を入力
- header部分のスライドショー
- resetボタンの挙動
- 誕生日を入れると年齢が自動で計算される
- 郵便番号を入力すると自動で住所が記入される
ページが読み込まれると同時に診療日を入力
window.onload = function () {
const today = new Date();
const y1 = today.getFullYear().toString().padStart(4, '0');
const m1 = (today.getMonth() + 1).toString().padStart(2, '0');
const d1 = today.getDate().toString().padStart(2, '0');
document.getElementById("shinryobi").value = `${y1}-${m1}-${d1}`
preloaded.send("onload-action", "wake up")
};
header部分のスライドショー vegas.jsを使用させていただいております。
$(".jumbotron").vegas({
overlay: true,
timer: false,
delay: 10000,
slidesToKeep: 1,
transition: 'fade2',
transitionDuration: 8000,
animation: 'random',
animationDuration: 10000,
slides: [
{ src: "img/dog.jpg" },
{ src: "img/flower_1.jpg" },
{ src: "img/cat.jpg" },
{ src: "img/flower_2.jpg" }
]
});
resetボタンの挙動
子要素を全て消すコードが含まれています。
$("#reset").click(function () {
document.getElementById("kanjyabango").value = ""
document.getElementById("tanto").value = ""
document.getElementById("kainushiname").value = ""
document.getElementById("denwa").value = ""
document.getElementById("inputAddress01").value = ""
document.getElementById("inputAddress02").value = ""
document.getElementById("name").value = ""
document.getElementById("animalList").value = ""
document.getElementById("sexList").value = ""
document.getElementById("birthDay").value = ""
document.getElementById("age").value = ""
document.getElementById("syuso").value = ""
document.getElementById("shindan").value = ""
document.getElementById("kensa").value = ""
document.getElementById("chiryohoushin").value = ""
document.getElementById("formFileMultiple").value = ""
document.getElementById("belowsave").innerText = ""
//// 以前の診療データを表示したtable要素の子要素を全部消去する
let div_previous_view = document.getElementById('previous_view');
if (document.querySelector("table") != null) { //// 既にファイルを読み込みが行われているかをtable要素の有無で判定する
while (div_previous_view.firstChild) {
div_previous_view.removeChild(div_previous_view.firstChild); //// 子要素を全て消すアルゴリズム
}
};
});
誕生日を入れると年齢が自動で計算される
$('#birthDay').change(function () {
const birthDate = new Date($('#birthDay').val())
// 文字列に分解
const y2 = birthDate.getFullYear().toString().padStart(4, '0');
const m2 = (birthDate.getMonth() + 1).toString().padStart(2, '0');
const d2 = birthDate.getDate().toString().padStart(2, '0');
// 今日の日付
const today = new Date();
const y1 = today.getFullYear().toString().padStart(4, '0');
const m1 = (today.getMonth() + 1).toString().padStart(2, '0');
const d1 = today.getDate().toString().padStart(2, '0');
// 引き算
const age = Math.floor((Number(y1 + m1 + d1) - Number(y2 + m2 + d2)) / 10000);
document.getElementById("age").value = age
});
郵便番号を入力すると自動で住所が記入される ajaxzip3を使用させていただいています。
$("#inputAddress01").keyup(function () {
AjaxZip3.zip2addr(this, '', 'addr11', 'addr11');
});
②renderer.jsとmain.jsとの通信が必要なもの
- データベース接続ボタンの挙動
- 患者番号を入力し終えたときに、患者データをデータベースから呼びだしてHTMLで書き込む
- 保存ボタンの挙動
- などなど
データベース接続ボタンの挙動を例として記載します。
renderer.js → main.js → renderer.js の順番で信号がやり取りします。
renderer.jsで、データベース接続ボタンが押されたときに、preload.jsで設定したpreload.send()をつかって、ipcRender.send(“データのラベル” ,データ)の機能を使う。これで、main processに信号を送ります。
$("#database").click(function () {
preloaded.send("database", "connected")
});
main.jsではこうです。ipcMain.on(“データのラベル”, (event, arg) => { event.reply(“返事のラベル” ,返事データ)})が基本形です。argは、renderer.jsから送られてきたデータです。リストの場合は、arg[0]とかでスライスできます。
ipcMain.on("database", (event, arg) => {
let database_list = dialog.showOpenDialogSync({
properties: ['openDirectory']
});
if (typeof database_list !== 'undefined') { //cansel押したときは実行しない
database = database_list[0]
writeFile("config.txt", database, function (err) {
if (err) {
throw err;
}
});
event.reply("database-reply", database)
}
});
こんどは、main.jsからの返事をrenderer.jsが受け取ります。
preloaded.on("database-reply", (event, arg) => {
let databasebutton = document.getElementById('database');
databasebutton.innerText = "データベース接続中"
databasebutton.classList.remove("btn-info") //色変更
databasebutton.classList.add("btn-primary") //色変更
});
exe化、app化は次の記事で!