サンプル・アプリケーションを作成するにあたって、以下のサイトや記事を参考にさせていただきました。
htmxの本家にあるReference
https://htmx.org/reference/
@twrcd1227 (Tomoki Ota)さんによるQiitaの記事
もうjsなんていらない!世界で流行っているHTMXについてまとめてみたhttps://qiita.com/twrcd1227/items/7bce18167fb02ec22729
@tsmd (Takayuki Shimada)さんによるQiitaの記事
htmxとは何なのか? その背景にある思想についてhttps://qiita.com/tsmd/items/0d07feb8e02cfa213cc4
作成するアプリケーションは以下のように動作します。アプリケーション自体はhtmxを使わなければ作れない、というものではありません。htmxの面白いところは、JavaScriptを書かずに以下ような処理を実装できることです。
最初にクイックSQLの以下のモデルより、画像を保存する表EBMJ_IMAGESを作成します。
# prefix: ebmj
images /unique title
title vc80 /nn
content file
レビューおよび実行をクリックし、表が作成されるまで作業を進めます。
表EBMJ_IMAGESが作成されたら、アプリケーションの作成をクリックします。確認画面が開くので、そこでもアプリケーションの作成をクリックします。
生成されたアプリケーションの雛形には、作成した表EBMJ_IMAGESをソースとしたフォーム付き対話モード・レポートのページが含まれています。これはそのまま使用します。htmxを使った画像の表示はホーム・ページに実装します。
アプリケーションの名前をSample htmxとし、アプリケーションの作成をクリックします。
アプリケーションが作成されます。対話モード・レポートとフォームのページでのBLOB列の扱いを修正します。
ページ番号2の対話モード・レポートのページを開きます。
リージョンImagesに含まれる列CONTENTを選択し、BLOB属性に含まれるMIMEタイプ列にCONTENT_MIMETYPE、ファイル名列にCONTENT_FILENAME、最終更新列にCONTENT_LASTUPD、文字セット列にCONTENT_CHARSETを設定します。
リージョンImageに含まれるページ・アイテムP3_CONTENTを選択し、ストレージに含まれるMIMEタイプ列にCONTENT_MIMETYPE、ファイル名列にCONTENT_FILENAME、文字セット列にCONTENT_CHARSET、BLOB最終更新列にCONTENT_LASTUPDを設定します。
以上で表EBMJ_IMAGESに画像をアップロードする準備ができました。
アプリケーションを実行し、いくつか画像をアップロードします。
ナビゲーション・メニューからImagesを開き、レポート上の作成をクリックして適当な画像をアップロードします。
画像を選んでアップロードします。
その他にも、いくつかの画像をアップロードします。今回の作業では、たぬき、シマウマ、レッサーパンダの画像をアップロードしています。
SQLワークショップのRESTfulサービスを開きます。
左ペインのツリーよりモジュールを選択し、モジュールの作成をクリックします。
作成するモジュール名はsample.htmx、ベース・パスは/htmx/とします。
モジュールの作成をクリックします。
モジュールsample.htmxが作成されます。続けてテンプレートを作成します。
テンプレートの作成をクリックします。
URIテンプレートとしてimage/:titleを設定します。:titleがハンドラのコード内で、バインド変数として参照できる引数になります。
テンプレートの作成をクリックします。
リソース・テンプレートが作成されます。続けてハンドラを作成します。
ハンドラの作成をクリックします。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_response clob; | |
l_clob clob; | |
l_offset integer; | |
l_length integer; | |
l_image ebmj_images%rowtype; | |
l_output varchar2(80); | |
begin | |
owa_util.mime_header('text/html', false, 'utf-8'); | |
owa_util.http_header_close; | |
select * into l_image from ebmj_images where title = :title; | |
dbms_lob.createTemporary(l_response, false, dbms_lob.CALL); | |
/* open img tag */ | |
l_output := q'~<img src="data:~'; | |
dbms_lob.writeAppend(l_response, length(l_output), l_output); | |
l_output := l_image.content_mimetype; | |
dbms_lob.writeAppend(l_response, length(l_output), l_output); | |
l_output := q'~;base64,~'; | |
dbms_lob.writeAppend(l_response, length(l_output), l_output); | |
/* base64 encoded image */ | |
l_clob := apex_web_service.blob2clobbase64(l_image.content, 'N'); | |
l_length := dbms_lob.getlength(l_clob); | |
l_offset := dbms_lob.getlength(l_response) + 1; | |
dbms_lob.copy( | |
dest_lob => l_response | |
,src_lob => l_clob | |
,amount => l_length | |
,dest_offset => l_offset | |
,src_offset => 1 | |
); | |
/* close img tag */ | |
l_output := q'~">~'; | |
dbms_lob.writeAppend(l_response, length(l_output), l_output); | |
/* return img tag */ | |
apex_util.prn(l_response, false); | |
dbms_lob.freeTemporary(l_response); | |
exception | |
when no_data_found then | |
:status_code := 204; | |
htp.p('<div>no data found</div>'); | |
end; |
ハンドラの作成をクリックします。
GETハンドラが作成されます。完全なURLをコピーし、ブラウザまたはPostmanなどのツールより、作成したRESTサービスが正常に動作することを確認します。
RESTサービスが正常に動作することを確認したのち、APEXで認証されたセッション内からの呼び出しに限り、実行を許可するように権限を設定します。
左ペインより権限を選択し、権限の作成をクリックします。
特権定義の名前はsample.htmx、タイトルはsample.htmxとします。ロールとしてRESTful Services、保護されたモジュールとしてsample.htmxを選択します。
権限の作成をクリックします。
権限としてsample.htmxが作成されます。
サインインするユーザーにロールRESTful Servicesを割り当てます。
管理メニューよりユーザーとグループの管理を開きます。
権限を割り当てるユーザーの編集画面を開きます。
グループ割当てのセクションに移動し、グループ割当てとしてRESTful Servicesを選択します。
変更の適用をクリックします。
以上で作成したRESTサービスの保護が完了しました。
先ほど実施した動作確認を再度行います。今度は応答が401 Unauthorizedになります。
RESTfulサービスを使った作業は以上で完了です。
アプリケーション・ビルダーに移り、htmxを組み込んだページを作成します。
ページ・デザイナでホーム・ページを開きます。
作成済みのリージョンページ・ナビゲーションを削除します。
画像を表示するためのボタンを配置するリージョンを作成します。
識別の名前はButtons、タイプは静的コンテンツです。外観のテンプレートとしてButtons Containerを選択します。
識別の名前はImage、タイプは静的コンテンツです。外観のテンプレートにBlank with Attributes (No Grid)を選択し、CSSクラスとしてw800 h800 margin-autoを指定します。リージョンの幅と高さを800ピクセルに設定し、中央揃えにしています。
詳細の静的IDとしてimageを設定します。
ページ内でhtmxの機能を使えるように構成します。
ページ・プロパティのJavaScriptのファイルURLに以下を指定します。
https://unpkg.com/htmx.org@2.0.0
ページ・ロード時に実行に以下を記述し、htmxがRESTサービスを呼び出す際に、認証に必要なApex-Sessionヘッダーを追加します。
document.body.addEventListener('htmx:configRequest', function(evt) {
evt.detail.headers['Apex-Session'] = apex.env.APP_ID + ',' + apex.env.APP_SESSION;
});
表示する画像をリージョン内に収めるために、CSSのインラインに以下を記述します。
img {
max-width:100%;
max-height: 100%;
width: auto;
height: auto;
}
以上でhtmxが提供する属性を要素に指定できるようになりました。
これから画像を表示するためのボタンを、リージョンButtonsに作成します。
識別のボタン名はBUTTON1、ラベルはたぬきとします。たぬきの画像を表示するボタンになります。
動作のアクションとして動的アクションで定義を選択し、詳細のカスタム属性として以下を記述します。hx-get、hx-target、hx-swapはhtmxが提供している属性です。
hx-get="apexdev/htmx/image/たぬき" hx-target="#image" hx-swap="innerHTML"
これでボタンたぬきをクリックすると、リージョンImageにたぬきの画像が表示されます。
識別のボタン名はBUTTON2、ラベルはシマウマ、詳細のカスタム属性として以下を記述します。
hx-get="apexdev/htmx/image/シマウマ" hx-target="#image" hx-swap="innerHTML"
レッサーパンダの画像を表示するボタンを作成します。
識別のボタン名はBUTTON3、ラベルはレッサーパンダ、詳細のカスタム属性として以下を記述します。
hx-get="apexdev/htmx/image/レッサーパンダ" hx-target="#image" hx-swap="innerHTML"
htmxには指定できる属性が他にも沢山あります。確かにJavaScriptを書かずに色々な処理を行なうことができるので、巷の話題にあがるのも納得できます。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-htmx.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完