Notes開発者のためのXPagesデザインレシピ

簡単でCoolなXPagesアプリケーションを作るための情報を発信していきます

連続講座

ChatGPTとペアプログラミングで画像リサイズ機能を作ろう(課題解決編)

はじめに(共通)

このブログ記事は下記三部作の後編です。検索エンジンでたどり着いた方は他の関連記事も御覧下さい。

  1. ChatGPTとペアプログラミングで画像リサイズ機能を作ろう(実装検討編)
  2. ChatGPTとペアプログラミングで画像リサイズ機能を作ろう(実装編)
  3. ChatGPTとペアプログラミングで画像リサイズ機能を作ろう(課題解決編) ←ココ


リサイズ機能の課題

前回、添付画像のリサイズ機能は完成しましたが、下記の3つの課題があることがわかりました。

  1. ファイルのダウンロード時に拡張子がjpgではなく、jiffになってしまう。
  2. 画像ファイルを複数添付した際にメモリエラーで落ちてしまう。
  3. 画像ファイルを複数添付した際の待ち時間中に他のボタンを押せてしまう。

今回はそれぞれの解決策を実装していきます。


現象①:ファイルのダウンロード時に拡張子がjpgではなく、jfifになってしまう

■原因

アップロードした画像をクリックし、ダウンロードしようとした際に拡張子が「jfif」になってしまう原因は、WindowsUpdateです。
WindowsUpdateがMIMEタイプのレジストリを書き換えるために起こります。
WindowsUpdate!またお前か!!

■対策

レジストリエディタで「HKEY_CURRENT_USER\SOFTWARE\Classes\MIME\Database\Content Type\image/jpeg」にある「Extension」を「.jfif」から「.jpg」に変更すると、「.jpg」で保存できるようになります。
※レジストリ設定を誤るとWindowsが起動しなくなる場合がありますので、十分に注意して行って下さい。



現象②:画像ファイルを複数添付した際にメモリエラーで落ちてしまう

■現象

複数画像を添付して保存すると、メモリエラーで処理が落ちてしまい、サーバーには下記のログが表示されます。

2023/07/25 09:33:28 HTTP JVM: CLFAD0317E: The XPages runtime engine faced an OutOfMemoryError
2023/07/25 09:33:28 HTTP JVM: CLFAD0316E: You can fix this by increasing the value of the HTTPJVMMaxHeapSize variable in notes.ini

■原因

JavaのHeapMemory設定が64MBなどの場合、メモリ不足でエラーになります。

■対策

notes.iniの「HTTPJVMMaxHeapSize」を変更し、ヒープサイズを拡大します。私の環境では64MB→256MBに変更しました。

https://support.hcltechsw.com/csm?id=kb_article&sysparm_article=KB0025607



現象③:画像ファイルを複数添付した際の待ち時間中に他のボタンを押せてしまう

■現象

画像ファイルを複数添付した場合、サーバー側で画像のリサイズが行われると数秒間画面が止まったままになります。
ユーザーには処理中であることがわからず、他のボタンもクリックできてしまうため、運用トラブルの原因になりかねません。
今回UIフレームワークとして使っているBootstrapにはスピナーの機能があるようです。
そこでスピナー機能を実装してみようと思います。

https://getbootstrap.com/docs/5.1/components/spinners/



ボタンのDisable化とスピナーの実装

スピナーを表示するだけでは、処理中であることを示すことはできても、他のボタンを押してしまうことは禁止できません。
ですので、保存ボタンクリックと同時に<button>タグにDisable属性を追加することでクリックできないようにし、スピナーを表示する機能をCSJSで実装します。

  1. カスタムコントロール「ccModalDocument」を開き、保存ボタンの<xp:button>タグの内側にスピナーの<span>タグを追加します。
<span class="spinner-border spinner-border-sm me-3 d-none" role="status" aria-hidden="true" id="spanSpin"></span>

【解説】
<span>タグに指定している「spinner-border spinner-border-sm」がスピナーを実現するためのクラス、「me-3」が保存という文字とスピナーがくっつきすぎないようにするための後方マージン、「d-none」が非表示にするためのdisplay:noneを示すクラスです。
保存ボタンをクリックした際にCSJSでこの「d-none」クラスを除去するとスピナーが表示されるという仕組みです。

  1. 「コード>スクリプトライブラリ」を選択し、[新規スクリプトライブラリ]ボタンで「csjs_common」を作成します。

名前

csjs_common

コメント

 

タイプ

JavaScript

  1. 作成した「csjs_common」に、すべての<button>タグにDisableを設定、指定されたidのタグから「d-none」クラスを削除する関数を追加します。
//Button Disabled
function setButtonDisabled(targetSpanId){
	// button tag disabled
	var buttons = document.querySelectorAll("button");
	buttons.forEach(function(button){
		button.disabled = true;
	});
	
	// Spinner ON
	var spanElement = document.getElementById(targetSpanId);
	spanElement.classList.remove("d-none");
}

【解説】
前半のコードで、すべての<button>タグにDisable属性を追加することでボタンを押せなくしています。
後半のコードで、引数で受け取ったIDをキーにスピナーの<span>タグを特定し、非表示を表す「d-none」クラスを除去することで、スピナーを表示します。

  1. カスタムコントロール「ccModalDocument」を開き、作成した「csjs_common」を追加します。(呼び出し元は環境に応じて変更して下さい。)

  1. 保存ボタンのonClickイベントでCSJSを追加し、スクリプトライブラリに追加した関数を実行する。
setButtonDisabled("spanSpin")

【解説】

onclickイベントのサーバータブにはSSJSの関数(保存ボタン処理)が記述されており、今回はクライアントタブにCSJSの関数を設定します。
クライアントとサーバーの両方のタブにコードが実装されている場合、クライアント側の処理がブラウザ上で実行された後、サーバー側の処理がDominoサーバーで実行されます。
どのような動作になるか?と活用シーンは次の補足解説で説明します。



補足解説:CSJSとSSJSの同時実行

■CSJSでalertやconfirmなどユーザーの入力を求めるコードとSSJSを同時に実行した場合

  1. alertやconfirmのOKボタン、キャンセルボタンが押された後にSSJSが実行される
  2. confirmの場合、キャンセルボタンでもSSJSが実行されるため、実行確認用途には使えない
  3. 実行確認を行いたいのであれば、シンプルアクションで「アクションの確認」とSSJSを組み合わせた方が簡単に実装できる

■CSJSでHTML内のクラス書き換えなどユーザー操作を伴わないコードとSSJSを同時に実行した場合

  1. CSJSが実行された後、SSJSが実行される
  2. SSJSの実行後、リロードが行われるタイミングでCSJSがリセットされ停止する
  3. スピナーの表示などリロード後リセットされて良いような機能と相性が良い



完成

これで画像ファイルのリサイズ機能は完成です。
Notesクライアント開発、XPages開発の個人ブログは減少傾向にありますが、ChatGPTとディスカッションしながら新しいアイディアで開発を行えば、他人の知見からではないオリジナルの価値が生み出せそうです。
今回のリサイズ処理そのものはJavaライブラリでの実行なので、Notesクラス部分をNotesJavaクラスに置き換え、エージェントなどに変更すればNotesクライアントで添付された画像ファイルをサーバー側でリサイズするようなことも出来ると思います。