前回の記事で、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化は次の記事で!

Categories:

category