[JavaScript] 08 デジタル時計配置

[M1 Mac, Big Sur 11.7.2]

MySQLアプリにプログレスバーを実装するのに手間取っていて、解決への取っ掛かりとしてHTMLの正常動作を確認するためデジタル時計を配置しました。

setInterval関数の第1引数に繰り返し実行する関数を入れるのですが、なぜかシングルクオートで囲む仕様になっています。

インタプリタの観点からは関数が格納されているメモリアドレスにアクセスするという意味合いなのでしょうが、正直ユーザーフレンドリーではないですね。

#MySQLアプリ #PHP

<span id="clockTime"></span>
<script type="text/javascript">
	function set2fig(num) {
		var ret;
		if( num < 10 ) { ret = "0" + num; }
		else { ret = num; }
	return ret;
	}

	function showTime() {
		var now = new Date();
		var nowhour = set2fig(now.getHours());
		var nowminutes = set2fig(now.getMinutes());
		var nowseconds = set2fig(now.getSeconds());
	
		var clockTime = "現在時刻 " + nowhour + ":" + nowminutes + ":" + nowseconds;
		console.log(clockTime);
		document.getElementById("clockTime").innerHTML = clockTime;
    
    return clockTime;
  	}
	
	setInterval('showTime()', 1000);
</script>

参考サイト

[JXA] 04 ローマ字を漢字に変換 その2 クリップボード反映待ち

JXA : JavaScript for Automation
[M1 Mac, Ventura 13.0]

クリップボードへのコピーは即時ではないことが判明したため、do…while文でループさせました。これで動作の再現性がようやく確保できました。

Google Chrome, Safari, Microsoft Excelではこのスクリプトで問題なく変換しますが、肝心のVSCodeがどうしてもダメです。

もう少しなので何とかしたいところです。

function run(input, parameters) {
    var se = Application("System Events");
    se.includeStandardAdditions = true;
    var txt0 = se.theClipboard();

    se.keystroke("a", {using:"command down"});
    se.keystroke("c", {using:"command down"});

    do {
        var txt1 = se.theClipboard();
    } while (txt0 == txt1);

    // se.displayDialog(txt1);

    lib = Library('convertlib');
    var ret = lib.romaji_to_hiragana(txt1);

    se.setTheClipboardTo(ret);
    do {
        var txt2 = se.theClipboard();
    } while (txt1 == txt2);

    // se.displayDialog(txt2);
    
    se.keystroke("v", {using:"command down"});
    se.keystroke("a", {using:"command down"});

    // VSCodeを別扱いにしたいがうまくいかず
    // var curApp = Application.currentApplication();
    // var nameApp = curApp.name();
    // se.displayDialog(nameApp);

    se.keyCode(104);
    se.keyCode(104);
    // または
    // se.keystroke("r", {using:["control down", "shift down"]});
            
    return input;
}

[JXA] 03 ローマ字を漢字に変換 その1

JXA : JavaScript for Automation
[M1 Mac, Big Sur 11.6.8, Ventura 13.0]

JXAでアプリ上のローマ字をひらがなに変換し、さらに漢字に変換するスクリプトを書きました。

やはりAppleScriptと同様にVenturaではまともに動きませんでした。クリップボードをコントロールすることができなくなっています。

調べてみるとクリップボードへの反映にやや時間が掛かるとのことなので、もう少し検討を続けます。

function run(input, parameters) {
    var se = Application("System Events");
    se.includeStandardAdditions = true;

    se.keystroke("a", {using:"command down"});
    se.keystroke("c", {using:"command down"});

    var txt = se.theClipboard();

    lib = Library('convertlib');
    var ret = lib.romaji_to_hiragana(txt);

    se.setTheClipboardTo("");
    se.setTheClipboardTo(ret);

    se.keystroke("v", {using:"command down"});
    se.keystroke("a", {using:"command down"});

    se.keyCode(104);
    se.keyCode(104);
    // または
    // se.keystroke("r", {using:["control down", "shift down"]});
             
    return input;
}

[JXA] 02 ローマ字をひらがなに変換

JXA : JavaScript for Automation
[M1 Mac, Ventura 13.0]

JXAでローマ字をひらがなに変換するライブラリをスクリプトバンドルとして保存し、実行してみました。

ライブラリはネットにあったものをそのまま拝借しました。

次はエディタに記述したローマ字をクリップボードにコピーしてひらがな変換するコードを書く予定です。

function run(input, parameters) {
    var se = Application("System Events");
    se.includeStandardAdditions = true;

    lib = Library('convertlib');
    const text = "toukyou";
    var ret = lib.romaji_to_hiragana(text);

    se.displayDialog(ret);
            
    return input;
}

参考サイト

[JXA] 01 ライブラリ作成

JXA : JavaScript for Automation
[M1 Mac, Ventura 13.0]

JXAにて自製ライブラリを作成し使用してみました。

スクリプトエディタでライブラリの内容を記述し、/Library/Script Librariesにスクリプトバンドルとして保存しました。

ダイアログが出るようにするまで2時間ほどトライ&エラーを繰り返しました。とにかく情報が少ないので大変です。途中でスクリプトエディタ内にドキュメント(名称は”ライブラリ”)があることを知り、少し楽になりました。

かなりのポテンシャルを感じさせる仕様ですが、あまり普及していないところを見ると、この先地雷が待ち受けている予感しかしませんね。

Automatorのワークフローファイル保存ディレクトリがおぼえにくいので、Finder画像をアップしておきます。/Users/[ユーザ名]/Library/Servicesにあります。

function run(input, parameters) {
    // System Eventsの変数を設定する
    var se = Application("System Events");

    // 標準機能拡張(StandardAdditions.osax)を有効にする
    se.includeStandardAdditions = true;

    // testライブラリのtest1関数を実行する
    lib = Library('test');
    var test1 = lib.test1();

    // 戻り値をダイアログに表示する
    se.displayDialog(test1);
      
    return input;
}
ワークフローファイル保存ディレクトリ

[JavaScript] 06 ElectronによるGUIアプリ作成 その4 windowを閉じてアプリ終了

[macOS Catalina 10.15.7]

Electronの教本を購入してそれなりに本腰を入れて取り組むことにしました。さくっと概要をつかむだけのつもりがそうもいかなかったので。

OpenJS FoundationのElectronサイトを見て、かなりのポテンシャルの高さを感じました。その恩恵を享受するにはある程度の専門知識が必要だと悟りました。私のような初心者が片手間で扱おうなんて土台無理な話です。サイトの内容が実装できるのであれば、多少のコストは惜しみません。

とりあえずElectronで立ち上げたウィンドウを閉じると同時にアプリも終わらせるようにしました。私自身根っこがWindowsなのでmacOSのDockで待機というのがどうも好きになれません。

教本に同様の内容が掲載されていましたが、いきなりコードが間違っていました。そのコードではWindowsやLinuxでしか終われないです。本の構成はしっかりしてそうなのに大丈夫なのだろうか。

ゆくゆくはElectronで競馬データベースアプリを作り、JavaのSwingベースの自製アプリと処理速度や機能を競わせてみたいです。Javaと比べてSQLコマンド作成速度等がどんな感じなのか興味津々です。

正直GUIアプリ開発において動的型付け言語にはさほど期待していなかったのですが、JavaScriptという意外な伏兵の出現でモチベーションが上がってきています。処理速度的に問題があってもTypeScriptという選択肢もあり、いずれにせよ有意義な検討になりそうです。

app.on('window-all-closed', () => {
    console.log('app.window-all-closed');
    app.quit();
  }
);

[JavaScript] 05 ElectronによるGUIアプリ作成 その3 positionプロパティ

前回コンテナの位置を上げられなかった件に関しては、positionプロパティでtopの相対位置をマイナスに設定して解決しました。

次にボタン押下時のアクション設定なんですが、調べてみると色々ややこしくて今度こそ撤退になりそうです。

やろうとしていることに対して、覚えるべきスキル・コード記述量・ファイル数が多いという印象です。労力的時間的コスパが良くないですし、動的型付け言語としてのメリットが感じられないのは残念です。

JavaScriptによるデスクトップアプリGUI作成は思っていたよりハードルが高かったです。もし同様に困っている方々がいらっしゃったら、PythonのtkinterやJavaのSwing、JavaFXを自信を持ってお勧めします。

1日粘ったものの、結局JavaScriptアレルギーが悪化しただけのような気がします。浅いながらも様々なプログラミング言語を学びポジティブな刺激を受けてきましたが、今回に限っては何とも形容し難い不思議な心境です。

.container {
    display: grid;
    grid-template-columns: 224px 60px;
    position: relative;
    top: -10px;
}

[JavaScript] 04 ElectronによるGUIアプリ作成 その2

一旦撤退を決意しましたが以前もWordPressのCSSに悩まされたことを思い出し、ある程度のレベルに達するまでもうひと頑張りすることにしました。

GUIのレイアウトをそれなりに整えました。WordPressの時もそうでしたがMac版Chromeで発生する謎の上部空白(≠margin)については、リセットCSS(destyle.css)を使っても解決しませんでした。

次はボタン押下によるイベントについてコードを記述していきます。

<html>
<head>
 <meta charset="UTF-8">
 <title>CHARACTER CODE CONVERTOR</title>
 <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <div class="container2">
            <text id="lbl1">Path</text>
            <input id="txt1" type="TEXT"></input>
        </div>
        <button id="btn1" >判定</button>

        <div class="container3">
            <text id="lbl2">文字コード</text>
            <input id="txt2" type="TEXT"></input>
        </div>
        <button id="btn2" >変換</button>
    </div>
</body>
</html>
body {
    background-color: #91d8e8;
    margin:0px 8px 8px 8px;
}
.container {
    display: grid;
    grid-template-rows: 1fr 1fr;
    grid-template-columns: 224px 60px;
    vertical-align:top;
}
.container2 {
    display: inline;
    margin:4px 2px 2px 2px;
}
.container3 {
    display: inline;
    margin:4px 2px 2px 2px;
}
#lbl1 {
    grid-row:1;
    grid-column:1;
}
#txt1 {
    grid-row:1;
    grid-column: 1;
    width:170px;
    margin:0px 0px 0px 2px;
}
#btn1 {
    grid-row:1;
    grid-column:2;
    margin:4px 4px 4px 4px;
}
#lbl2 {
    grid-row:2;
    grid-column:1;
}
#txt2 {
    grid-row:2;
    grid-column:1;
    width:80px;
    margin:0px 0px 0px 2px;
}
#btn2 {
    grid-row:2;
    grid-column:2;
    margin:4px 4px 4px 4px;
}

[JavaScript] 03 ElectronによるGUIアプリ作成 その1

ElectronによるGUIアプリ作成に取り掛かりましたが、やはりJavaFXで要素を自在にドラッグする快適さが忘れられず、とりあえず下記コードまでにしてJRuby+JavaFXでの開発環境構築に移行します。

style.cssファイルにてグリッド設定を書いていて、あまりの面倒さに頭が拒否反応を示しました。paddingを書く気力が早々になくなりました。おそらくHTMLやCSSの文法が私には合わないのでしょう。Sassのようにfor文を使えたらまだいいんですが。

これなら多少不満があってもPythonのtkinterで書きます。せっかくJavaScriptとお近づきになれたのに残念です。

どうやら日々のプログラミング生活でロジカル思考が染み付いてしまい、ルールに縛られた上での思考が苦手になっているのでしょう。なので異なるプログラミング言語間の行き来は比較的容易でも、論理よりもルールが優先のスタイルシート言語等ではストレスが溜まるようです。

次にJavaScriptのコードを書くのはいつになることでしょう。

const {app, BrowserWindow} = require('electron');

// メインウィンドウ
let mainWindow;

function createWindow() {
  // メインウィンドウ作成
  mainWindow = new BrowserWindow({
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: false
    },
    width: 300, height: 150,
  });

  // メインウィンドウに表示するhtmlファイル指定
  mainWindow.loadFile('index.html');

  // メインウィンドウが閉じられたときの処理
  mainWindow.on('closed', () => {
    mainWindow = null;
  });
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {
    app.quit();
});

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow();
  }
});
<html>
<head>
 <meta charset="UTF-8">
 <title>CHARACTER CODE CONVERTOR</title>
 <link rel="stylesheet" href="style.css">
</head>

<body>
    <div id="container">

    <text id="lbl1">Path</text>
    <input id="txt1" type="TEXT"></input>
    <button id="btn1" >判定</button>

    <text id="lbl2">コード</text>
    <input id="txt2" type="TEXT"></input>
    <button id="btn2" >変換</button>

    </div>
</body>
</html>
body {
    background-color: #91d8e8;
}
#container {
    display: grid;
    grid-template-rows: 50px 50px;
    grid-template-columns: 50px 50px 50px 50px;
    position:relative;
    top: 10px;
}
#lbl1 {
    grid-row:1;
    grid-column:1;
}
#txt1 {
    grid-row:1;
    grid-column: 2 / 4;
}
#btn1 {
    grid-row:1;
    grid-column:4;
}

#lbl2 {
    grid-row:2;
    grid-column:1;
}

#txt2 {
    grid-row:2;
    grid-column:2;
}

#btn2 {
    grid-row:2;
    grid-column:4;
}