本記事ではp5.jsのJavaScriptのコードを、REPL(Read-Eval-Print Loop)風に実行するAPEXアプリケーションを作成します。JavaScriptコードの入力には、Ronny Weissさん作成のリージョン・プラグインAPEX-Monaco-Editor-and-Diff-Viewerを使用します。
作成したAPEXアプリケーションは以下のように動作します。
以下よりAPEXアプリケーションの作成手順を紹介します。
最初にクイックSQLの以下のモデルより表P5_SCRIPTSを作成します。この表に図形やアニメーションを描画するJavaScriptのコードを保存します。
# pk: identity
p5_scripts
title vc80 /nn
script clob;
空のAPEXアプリケーションを作成します。名前はp5.jsとします。
図形を描画するコードの入力はホーム・ページで行い、そのコードを実行して図形やアニメーションを描画するのは、非モーダル・ダイアログで行うことにします。
図形を描画するページを作成します。ページの作成をクリックします。
空白ページを選択します。
新規に作成するページ番号は2、名前はSketchとします。このページは非モーダル・ダイアログにする予定ですが、ページ・モードの選択肢に非モーダル・ダイアログはありません。形式が一番近いモーダル・ダイアログを選択し、ページ作成後にモードを変更します。
ページの作成をクリックします。
新規にページが作成されます。
外観のページ・モードを非モーダル・ダイアログに変更します。ダイアログの幅は800、高さは800としています。この値は便宜的なものなので、それぞれ、使い勝手のよい値を設定します。必須ではありませんが、チェーンはオフにしています。
JavaScriptのファイルURLに以下を設定します。p5.jsのライブラリをAPEXのページにロードします。
https://cdn.jsdelivr.net/npm/p5@2.0.5/lib/p5.min.js
スクリプトが保存されている表P5_SCRIPTSの列IDの値を保持するページ・アイテムを、P2_IDとして作成します。ページ・アイテムのタイプは非表示です。
表P5_SCRIPTSに保存されているJavaScriptのコードを保持するページ・アイテムを、P2_CODEとして作成します。こちらもタイプは非表示です。
セッション・ステートのデータ型はCLOB、ストレージはリクエストごと(メモリーのみ)を選択します。
一般的にはフォームを作成して、そのソースを元にフォームの初期化プロセスを実行することにより、フォームに紐づくページ・アイテムに値を設定します。今回は初期化するページ・アイテムはP2_CODEのみなので、フォームの作成は省略しています。
プロセスのソースのPL/SQLコードに以下を記述します。
select script into :P2_CODE from p5_scripts where id = :P2_ID;
JavaScriptのコードを実行し、p5.jsによる図形やアニメーションを描画するリージョンを作成します。
名前はSketch、タイプに静的コンテンツを選択します。
ソースのHTMLコードに以下を記述します。
外観のテンプレートに装飾の少ないBlank with Attributes (No Grid)を選択します。
以上で、図形やアニメーションを描画する非モーダル・ダイアログのページができました。
続いて、コードを記述する機能をホーム・ページに実装します。
APEX-Monaco-Editor-and-Diff-Viewerのページより、region_type_plugin_rw_apex_vs_monaco_editor.sqlをダウンロードします。
共有コンポーネントのプラグインを開きます。
プラグインの一覧画面よりインポートをクリックします。
インポートするファイルとして、先ほどダウンロードしたregion_type_plugin_rw_apex_vs_monaco_editor.sqlを選択します。プラグインよりインポート画面を開いているため、ファイル・タイプはプラグインが選択済みです。
次へ進みます。
プラグインをインストールします。次へ進みます。
Monaco EditorのJavaScriptライブラリの参照先となるCDNのURLを確認します。Monaco Editorの最新版は0.53.0のようですが、0.53.0に置き換えるとプラグインが動作しないので、このBase URLは変更しない方が良いでしょう。
https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.51.0
属性を開き、ButtonsのSwitch between Single Editor and Diff-Editorのチェックを外します。
以上でポップアップLOVで選択したスクリプトが、コード・エディタに表示されるようになりました。また、選択されたスクリプトがコード・エディタでの保存先になります。
変更の適用をクリックします。
以上でプラグインのインストールは完了です。
ホーム・ページにコード・エディタを組み込みます。
非モーダル・ダイアログを開くボタンOPEN_SKETCHを作成します。
ボタン名はOPEN_SKETCH、ラベルはOpen Sketchとします。非モーダル・ダイアログのページを開くために、動作のアクションにこのアプリケーションのページにリダイレクトを選択し、ターゲットのページに2を設定します。
一般的にページを開く場合は、遷移先のページに主キーの値を引き継ぎます。今回の実装を例にとると、リンク・ビルダーのアイテムの設定の名前にP2_ID、値に&P1_ID.といった設定を行います。
この設定は行なっていません。値の&P1_ID.ですが、ボタンのアクションがリダイレクトの場合、ホーム・ページが開いた時点で設定されているP1_IDの値で置換されます。ページ上の操作によってP1_IDの値が変更されても、リダイレクト時に渡される値には反映されません。
今回はホーム・ページが表示された後にページ・アイテムP1_IDの値を変更するため、変更されたP1_IDの値でページ・アイテムP2_IDを直接更新することにより、リンクの引数による値の引き渡しを省略しました。
表P5_SCRIPTS内で、更新の対象としているスクリプトのIDを保持するページ・アイテムとして、P1_IDを作成します。タイプはポップアップLOV、LOVのタイプにSQL問合せを選択し、SQL問合せとして以下を記述します。
select title d, id r from p5_scripts order by r asc
追加値の表示はオフにします。
新規に登録するスクリプトのタイトルを入力するページ・アイテムとして、P1_TITLEを作成します。タイプはテキスト・フィールドです。
ラベルはTitle、セッション・ステートのストレージはリクエストごと(メモリーのみ)を設定します。
表P5_SCRIPTSに新規行を保存するボタンとして、CREATEを作成します。P1_TITLEを列TITLEに保存し、自動採番されたIDをP1_IDに戻します。列SCRIPTに保存するスクリプトはスクリプト・エディタから保存します。そのため、ボタンCREATEではスクリプトを保存しません。
動作のアクションはデフォルトのページの送信です。
ボタンCREATEをクリックしたときに実行されるプロセスを作成します。名前はCreateとします。
ソースのPL/SQLコードとして以下を記述します。
insert into p5_scripts(title) values(:P1_TITLE) returning id into :P1_ID;
サーバー側の条件のボタン押下時にCREATEを設定します。
コード・エディタのリージョンを作成します。
名前はEditorとし、タイプにプラグインのAPEX-VS-Monaco-Editorを選択します。プラグインのソースのSQL問合せとして以下を記述します。
外観のテンプレートに装飾の少ないBlank with Attributesを選択します。
Execute on Saveに以下を記述します。
begin
update p5_scripts set script = :CLOB where id = :P1_ID;
end;
この時点でアプリケーションを実行すると、新規スクリプトの作成ができます。
下段のページ・アイテムにTitleを入力してボタンCreateをクリックすると、表P5_SCRIPTSに1行追加されます。
コード・エディタの保存アイコンをクリックすると、上段のTitleで選択されているスクリプトとして保存されます。
ページ・アイテムP1_IDに動的アクションを作成して、選択したIDのスクリプトがコード・エディタにロードされるようにします。
作成する動的アクションの名前はonChange P1_IDとします。タイミングのイベントはページ・アイテムのデフォルトである変更です。
ページ・アイテムP1_IDの値が変更されたときにページ・アイテムP2_IDに同じ値を設定するよう、TRUEアクションとしてサーバー側のコードを実行します。
設定のPL/SQLコードとして以下を記述します。
begin
apex_session_state.set_value('P2_ID', :P1_ID);
end;
P1_IDが変更したときに限らず、ページが表示された時点でのP1_IDの値もP2_IDに保存するため、実行の初期化時に実行をオンにします。
変更されたP1_IDのスクリプトを読み込むため、コード・エディタのリージョンであるEditorを、TRUEアクションでリフレッシュします。
選択されたスクリプトを表P5_SCRIPTSより削除するボタンとして、DELETEを作成します。
動作のアクションはページの送信です。削除は注意が必要な処理なので、動作の確認の要求をオンにします。確認のメッセージに「削除しますか?」を記述し、スタイルに警告を設定します。
ボタンDELETEをクリックしたときに実行されるプロセスを作成します。名前はDeleteとします。
ソースのPL/SQLコードに以下を記述します。
delete from p5_scripts where id = :P1_ID;
サーバー側の条件のボタン押下時にDELETEを設定します。
以上で、アプリケーションの動作に関しては実装が完了しました。
少し見栄えを調整します。
静的コンテンツのリージョンとしてSelect Scriptを作成し、外観のテンプレートにItem Containerを選択します。そのリージョンのItemのスロットにページ・アイテムP1_ID、Button EndのスロットにボタンDELETEを配置します。
同様に静的コンテンツのリージョンとしてNew Scriptを作成し、そのリージョンのItemのスロットにページ・アイテムP1_TITLE、Button EndのスロットにボタンCREATEを配置します。New ScriptはSelect Scriptの右隣に配置するため、レイアウトの新規行の開始はオフにしします。
以上でアプリケーションは完成です。実行すると記事の先頭のGIF動画のように動作します。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-repl-p5-js.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完