最終更新日 2024-09-25

「レンダリング枠」の記述パターン

ここでは「レンダリング」枠を表示して、利用する黄金パターンを提示します。

マクロライブラリのサンプルにあるのは危険

https://hide.maruo.co.jp/lib/macro/v922macsamples.htmlにあるサンプルは様々なことを省略してしまっており、
これらをそのままに利用するのは適切ではありません。

レンダリング枠は1つとは限らないので、UIクラスに独自の名前を付けて管理しよう

test.mac
hidemaruversion "9.25.99";

jsmode "WebView2\\" + currentmacrofilename; // currentmacrofilenameのところは、特定の名前を付ける場合、マクロファイルや役割に応じて変更する

js {

objUITemplate?._destructor();

class UITemplate { // ここのクラス名はマクロファイル名ごとに書き換える。「ここだけではなく、このファイル内全てのUITemplate」を変更する必要がある。
    static strTargetLabel = "";
    static idInitInterval;
    static idUpdateInterval;
    static strHtmlFileName = "";

    constructor(option) {
        UITemplate.strTargetLabel = option.target;
        UITemplate.strHtmlFileName = option.html;
        UITemplate.openRenderPane();
        UITemplate.setInitInterval();
        UITemplate.setUpdateInterval();
    }

    _destructor() {
        UITemplate.clearInitInterval();
        UITemplate.clearUpdateInterval();
    }

    static clearAllInterval() {
        UITemplate.clearInitInterval();
        UITemplate.clearUpdateInterval();
    }

    static setInitInterval() {
        UITemplate.idInitInterval = hidemaru.setInterval(UITemplate.checkCompleteRenderPane, 500);
    }

    static clearInitInterval() {
        hidemaru.clearInterval(UITemplate.idInitInterval);
    }

    static outputAlert(err) {
        let dll = loaddll("HmOutputPane.dll");
        dll.dllFunc.Output(hidemaru.getCurrentWindowHandle(), err + "\r\n");
    }

    static setUpdateInterval() {
        UITemplate.idUpdateInterval = hidemaru.setInterval(UITemplate.updateRenderPane, 1000);
    }

    static clearUpdateInterval() {
        hidemaru.clearInterval(UITemplate.idUpdateInterval);
    }

    static makeUrl() {
        let absoluteUrl = new URL(currentmacrodirectory() + "\\" + UITemplate.strHtmlFileName);
        let idCallBack = hidemaru.getFunctionId(UITemplate.onHtmlButtonClick);
        let params = new URLSearchParams();
        params.set("strIDCallBack", String(idCallBack));
        absoluteUrl.search = new URLSearchParams(params).toString();
        return absoluteUrl;
    }

    static openRenderPane() {
        let absoluteUrl = UITemplate.makeUrl();
        const json_arg = {
            target: UITemplate.strTargetLabel,
            uri: absoluteUrl.href,
            show: 1,
            place: "leftside",
            initialize: "async",
        };

        renderpanecommand(json_arg);

    }

    static closeRenderPane() {
        const json_arg = {
            target: UITemplate.strTargetLabel,
            show: 0,
        };

        renderpanecommand(json_arg);
    }

    static checkCompleteRenderPane() {
        try {
            let readyState = renderpanecommand({ target: UITemplate.strTargetLabel, get: "readyState" });
            if (readyState == "complete") {
                UITemplate.clearInitInterval();
                UITemplate.onRenderPaneCompleted();
            }
        } catch (err) {
            UITemplate.outputAlert(err);
        }
    }

    static onRenderPaneCompleted() {
        try {
            renderpanecommand({
                target: UITemplate.strTargetLabel,
                focus: 1,
            });
        } catch (err) {
            UITemplate.outputAlert(err);
        }
    }

    static updateRenderPane() {
        try {
            let isShowNow = renderpanecommand({ target: UITemplate.strTargetLabel, get: "show" });
            if (isShowNow == "0") { // 数値ではなく文字列なので注意...
                UITemplate.clearAllInterval();
            }
        } catch (err) {
            UITemplate.outputAlert(err);
        }
    }

    static onHtmlButtonClick(json_obj) {
        try {
            // UI系の全ての非同期タイマーを止める
            UITemplate.clearAllInterval();
            // レンダリングパネルを閉じる
            renderpanecommand({
                target: UITemplate.strTargetLabel,
                show: 0,
            });

            // HTMLの情報を引数として、onMyFunction という自分の関数を実行する。
            let json_text = JSON.stringify(json_obj);

            // ファーストトライ。残念ながら 秀丸 v9.22~v9.34では「hidemaru.setTimeoutは実行されないかもしれない」というとんでもないバグがある...
            let isScheduled = 0;
            hidemaru.setTimeout(()=>{
                isScheduled = hidemaru.postExecMacroMemory("js {onMyFunction(" + json_text + ")}") ?? 1;
            }, 0);

            // 秀丸 v9.22~v9.34の間は、同一フレーム(1秒=60フレーム)内に複数のsetTimeoutを実行すると、
            // どれか1つしか実行せず、別のsetTimeoutは実行されないというとても痛いバグがあるので、ここでフォローする。
            let peRetry = hidemaru.setInterval(()=>{
                if (!isScheduled) {
                    isScheduled = hidemaru.postExecMacroMemory("js {onMyFunction(" + json_text + ")}") ?? 1;
                }
                if (isScheduled) { hidemaru.clearInterval(peRetry); }
            }, 100);
        } catch (err) {
            UITemplate.outputAlert(err);
        }
    }
}

try {
    // let ではなく寿命が残るvarである必要がある。
    // "RenderPane"のところはレンダリングペインの種類ごとに必ず変更すること
    var objUITemplate = new UITemplate(
                        {
                           target: "RenderPane",
                           html: "RenderPane.html"
                        }
                        );
} catch (err) {
    objUITemplate?._destructor();
    UITemplate.outputAlert(err);
}

function onMyFunction(json_text) {
    debuginfo(2);
    console.log(json_text);
}

} // js

HTML 側

test.mac
<!DOCTYPE html>
<html lang="ja">
<head>
<title>ボタンクリックサンプル</title>
<style>
@media (prefers-color-scheme: dark) {
    :root {
        color-scheme: dark;
    }
    body {
        background-color:#222244;
    }
}
@media (prefers-color-scheme: light) {
    :root {
        color-scheme: light;
    }
    body {
        background-color:#eeeeff;
    }
}
</style>
</head>

<body>
1番目のパラメータ:<br>
&nbsp;<input type="text" id="input_1"><br>
<br>
2番目のパラメータ:<br>
&nbsp;<input type="text" id="input_2"><br>
<br>
&nbsp;<button id="button_1">OK</button><br>

<script>
// ボタンを取得
const btn_1 = document.getElementById("button_1");
// window.alert(btn_1);

let idCallback = 0;
// 現在のURLを取得
let url = new URL(window.location.href);
// パラメータを取得
let params = new URLSearchParams(url.search);
let strIDCallBack = params.get('strIDCallBack');
idCallback = Number(strIDCallBack);

try {
    // ボタンがクリックされた時の処理
    btn_1.addEventListener("click", function () {
        let message_obj = {
            input_1: input_1.value,
            input_2: input_2.value,
        };
        let json = JSON.stringify(message_obj);
        window.chrome.webview.postMessage({ funcid: idCallback, message: json });
    });
}
catch (err) {
}
</script>
</body>

</html>
    

注意点など