2024年6月24日月曜日

Oracle APEXでUnpolyを使用する

Oracle APEXでhtmxを使う方法Turbo Framesを使う方法を紹介してきたので、Unpolyについても紹介します。

htmx向けのアプリケーションからの変更点を紹介します。

今回作成したアプリケーションも今までと同じく、見かけはTurbo Framsを使ったものと同じです。


以下にアプリケーションの変更点を紹介します。

アプリケーションを実装しているホーム・ページのページ・プロパティの変更から始めます。

JavaScriptファイルURLの指定は以下になります。UnpolyのJavaScriptのコードをロードします。

https://cdn.jsdelivr.net/npm/unpoly@3.8.0/unpoly#MIN#.js

CSSファイルURLとして以下を指定します。

https://cdn.jsdelivr.net/npm/unpoly@3.8.0/unpoly#MIN#.css

データ・ロード時に実行に以下のコードを記述します。UnpolyがAjaxコールを発行する際に、Apex-Sessionヘッダーを追加します。
document.addEventListener("up:request:load", (event) => {
    event.request.headers["Apex-Session"] = apex.env.APP_ID + "," + apex.env.APP_SESSION;
    // console.log(event);
});

画像を表示する静的コンテンツのソースHTMLコードとして、以下を記述します。DIV要素にIDとしてimage_1を与えています。この要素を、REST APIを呼び出して取得した画像で置き換えます。

<div id="image_1"></div>


画像を返すRESTサービスでは、更新対象を示すDIV要素(Turbo Framesのときはturbo-frame要素でした)にIMG要素を含めて、HTMLを返すようにコードを変更します。

モジュール・パス/unpoly/テンプレートimage/:title/:idとし、更新対象とするDIV要素のidを引数に含めました。

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);
/* set element to refresh by Unpoly */
l_output := q'~<div id="~';
dbms_lob.writeAppend(l_response, length(l_output), l_output);
l_output := coalesce(:id, 'no-element');
dbms_lob.writeAppend(l_response, length(l_output), l_output);
l_output := q'~">~';
dbms_lob.writeAppend(l_response, length(l_output), l_output);
/* 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);
l_output := q'~</div>~';
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;


UnpolyでのHTML要素の入れ替えをA要素で行います。画像を更新する領域はup-target属性で指定します。
<div id="action_1">
<a class="t-Button" href="apexdev/unpoly/image/たぬき/image_1" up-target="#image_1">たぬき</a>
<a class="t-Button" href="apexdev/unpoly/image/シマウマ/image_1" up-target="#image_1">シマウマ</a>
<a class="t-Button" href="apexdev/unpoly/image/レッサーパンダ/image_1" up-target="#image_1">レッサーパンダ</a>
</div>

Unpolyを使うために実施した変更は以上になります。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-unpoly.zip

サンプル・アプリケーションには、以前にAjaxリクエストに認証ヘッダーを追加する方法がわからなかった時に作成した、up.renderを呼び出す動的アクションの実装も含んでいます。

Oracle APEXのアプリケーション作成の参考になれば幸いです。