APEXアプリケーションの画面にメンテナンスの告知などの通知を表示させるには、という質問を見かけたので、試しにいくつか実装してみました。
APEX標準の機能としては、グローバル通知があります。それ以外にも、グローバル・ページにリージョンを作成することにより、通知を実装できます。
以下の4つを試してみました。
- アプリケーション定義のグローバル通知を使う。
- グローバル・ページに静的コンテンツのリージョンを作成する - 表示はブラウザ側のJavaScriptで制御する。
- グローバル・ページに静的コンテンツのリージョンを作成する - 表示はAPEXのユーザー・プリファレンスを使って、サーバー側で制御する。
- グローバル・ページにインライン・ダイアログのリージョンを作成する。
通知の実装には、サンプル・データセットのEMP/DEPTをインストールすると作成できるアプリケーションデモ - 従業員 / 部門を使用します。アプリケーションの内容に依存する作業はないため、どのようなAPEXアプリケーションを元にしても、通知の実装を試すことができます。
SQLワークショップのユーティリティのサンプル・データセットから、EMP/DEPTのデータセットをインストールします。すでにインストール済みの場合は、アプリケーションを作成するために更新を実行します。
画面の案内に従ってデータセットのインストールまたは既存のデータセットのリフレッシュを実行すると、アプリケーションの作成を呼び出す画面に移ります。
アプリケーションの作成をクリックします。
アプリケーション作成ウィザードが起動したら、機能は使わないので、すべてをチェックをクリックし、チェックを全部外してアプリケーションに組み込まれないようにします。
アプリケーションの作成をクリックすると、今回の実装の元になるアプリケーションが作成されます。
アプリケーション定義のグローバル通知を使う
以下のように通知が表示される実装を行います。
アプリケーション定義のグローバル通知として、以下を記述します。
<div class="global-notification-area" align="center">
<pre class="banner-content">
2022年4月17日午前9:00より10:00まで、メンテナンスのため本アプリケーションは利用できません。
詳しくは<a href="http://........./notice.html">http://........./notice.html</a>を参照してください。
</pre>
</div>
通知文にはCSSのクラスbanner-contentを指定しています。このクラスによって、通知の表示スタイルを調整します。
CSSの定義はアプリケーションに含まれるすべてのページから参照できるよう、静的アプリケーション・ファイルに記述します。複数のアプリケーションから参照させる場合は、静的ワークスペース・ファイルとして作成します。
共有コンポーネントの静的アプリケーション・ファイルを開きます。
ファイルの作成を実行します。
ファイル名としてmy-notification-class.cssを入力し、作成をクリックします。
.banner-content {
box-sizing: border-box;
width: 80%;
border: solid rgba(73, 73, 85, 0.2) 2px;
padding: 5px;
box-shadow: 12px 12px 2px 1px rgba(73, 73, 85, 0.2);
white-space: pre-wrap;
background-color: rgba(255, 255, 0, 0.2);
}
変更の保存をクリックします。変更が保存されたら、静的アプリケーション・ファイルの一覧へ戻ります。
グローバル通知はアプリケーションのすべての画面で表示されます。以下のようにログイン画面も含みます。
ページ・デザイナにてグローバル・ページ(ページ番号0)を開き、左ペインで動的アクション・ビューを表示させます。
イベントのページのロード上でコンテキスト・メニューを表示させ、動的アクションの作成を実行します。
作成された動的アクションを選択します。
識別の名前はonPageLoad Globalとします。タイミングはページのロードです。クライアント側の条件のタイプとして、JavaScript式を選択し、JavaScript式に以下を記述します。
apex.env.APP_PAGE_ID == 9999
以上で、通知がBannerの位置に表示されるようになりました。
追加でTRUEアクションを作成します。
ページのロード時にブラウザのsessionStorageのhide-global-notification-bannerを評価して、trueでなければリージョン通知を表示するように、動的アクションを作成します。
ページ番号が9999、つまりログイン・ページであればTRUEアクションを実行します。
TRUEアクションを選択し、識別のアクションとして、スタイルの設定を選択します。設定のスタイル名はdisplay、値はnoneと記述します。影響を受ける要素の選択タイプとしてjQueryセレクタを選択し、jQueryセレクタとして.global-notification-areaを指定します。
動的アクションには非表示もありますが、これはスタイルとしてはvisibility: hiddenに対応しています。今回の用途ではdisplay: noneの方が適切なので、動的アクションとしては、スタイルの設定を選んでいます。
通知メッセージの一番外側のdivタグに、CSSクラスglobal-notification-areaを設定しています。そのクラスをjQueryセレクタに指定しています。
以上で、サインイン画面を除いたすべてのページで、メンテナンスに関する通知が表示されるようになりました。
グローバル・ページに静的コンテンツのリージョンを作成する - 表示はブラウザ側のJavaScriptで制御する
ページの先頭に通知を表示します。また、ボタンをクリックして通知を削除できるようにします。通知の削除は、JavaScriptによりブラウザ側で制御します。
通知はAPEX 21.2から導入されたBannerの位置に表示しています。そのため、APEX 21.2以降が実装の要件になります。
ページ・デザイナでグローバル・ページを開きます。
コンポーネントまたはBody上でコンテキスト・メニューを開き、リージョンの作成を実行します。
リージョンが作成されます。
識別の名前を通知、タイプとして静的コンテンツを選択します。ソースのHTMLコードには、通知したい以下の文章を記述します。
2022年4月17日午前9:00より10:00まで、メンテナンスのため本アプリケーションは利用できません。
詳しくは<a href="http://........./notice.html">http://........./notice.html</a>を参照してください。
レイアウトの位置にBanner、外観のテンプレートとしてAlertを選択します。
テンプレート・オプションを開き、Bottom MarginをNoneに変更します。
グローバル通知とは異なり、Bannerが位置として定義されているページ・テンプレートでのみ、リージョン通知が表示されます。ログイン・ページやダイアログにはBannerの位置が定義されていないため、通知は表示されません。
通知の削除を実装します。
リージョン通知にボタンを作成します。
識別のボタン名はB_NOTIFICATION_HIDEとします。外観のボタン・テンプレートとしてIconを選択します(そのため、ラベルは表示されないので特に変更しません)。右端に表示されるようCSSクラスにu-pullRight、アイコンとしてfa-window-close-oを選択します。
動作のアクションとして、動的アクションで定義を選択します。
ボタンに動的アクションを作成します。
識別の名前をonClick B_NOTIFICATION_HIDEとします。タイミングはイベントはクリック、選択タイプはボタン、ボタンはB_NOTIFICATION_HIDEになります。
ここまでの実装は、ブラウザ側でもサーバー側でも一緒です(サーバー側での実装を説明するときは、この作業以降から始めます)。
ここから、ブラウザ側のJavaScriptによる実装になります。
作成済みのTRUEアクションを選択します。
識別のアクションとしてスタイルの設定を選択します。設定のスタイル名はdisplay、値はnoneとします。影響を受ける要素の選択タイプとしてリージョンを選び、リージョンは通知とします。実行オプションの初期化時に実行はOFFにします。
識別のアクションとしてJavaScriptコードの実行を選択します。設定のコードには以下を記述します。
sessionStorage.setItem("hide-global-notification-banner","true");
window.location.reload();
ブラウザのsesssionStorageにhide-global-notification-bannerとしてtrueを保存した後、ページ全体をリロードしています。
もっと良いやり方があるはずですが、JavaScriptとCSSが得意ではないのでこれ以上は分かりませんでした。多分、スタイルの設定ではなく、もっと凝ったCSSクラスを静的アプリケーション・ファイルに定義し、動的アクションのアクションとしてはクラスの追加やクラスの削除を使うことになる思います。
リージョン通知が初期状態で非表示になるよう、詳細のカスタム属性に以下を記述します。
style="display: none"
右ペインにて動的アクション・ビューを開き、ページのロードで動的アクションの作成を実行します。
作成された動的アクションの識別の名前をonPageLoad Globalとします。クライアント側の条件として以下を記述します。
sessionStorage.getItem("hide-global-notification-banner") != "true"
作成済みのTRUEアクションを選択します。
識別のアクションとしてスタイルの設定を選択します。設定のスタイル名はdisplay、値はcontentsとします。影響を受ける要素の選択タイプはリージョン、リージョンとして通知を選択します。
今回は、リージョン通知のカスタム属性としてstyle="display: none"を設定し、ページのロード時に(通知を表示する場合は)display: contentsを設定しています。この設定が逆(HTMLが生成されるときはdisplayの指定が無く、ページのロード時にdisplay: noneを設定して非表示にする)になっていると、ページが表示されるときに一瞬ですがリージョン通知が表示されてしまいます。
以上で通知の実装は完了です。
sessionStorageに通知の表示/非表示の選択を保存しているため、一旦通知を閉じるとブラウザを終了するまで通知が再表示されることはありません。
グローバル・ページに静的コンテンツのリージョンを作成する - 表示はAPEXのユーザー・プリファレンスを使って、サーバー側で制御する
通知を削除するボタンに作成した、TRUEアクションの設定から始めます。
識別のアクションとして、サーバー側のコードを実行を選択します。設定のPL/SQLコードとして以下を記述します。
apex_util.set_preference(
p_preference => 'HIDE_GLOBAL_NOTIFICATION_BANNER'
, p_value => 'TRUE'
);
実行オプションの初期化時に実行はOFFです。
追加でTRUEアクションを作成します。
識別のアクションとしてJavaScriptコードの実行を選択します。設定のコードには以下を記述します。
window.location.reload();
今回はリージョン通知はサーバー側の条件で非表示にします。そのため、ページの再読み込みを行う必要があります。
リージョン通知を選択し、サーバー側の条件を設定します。
サーバー側の条件のタイプとして、ユーザー・プリファレンス != 値を選択します。プリファレンスはHIDE_GLOBAL_NOTIFICATION_BANNERとし、値にはTRUEを指定します。
ユーザー・プリファレンスは一旦設定するとずっと維持されます。つまり永遠に通知が表示されなくなります。それだと困るため、サインアウトすると設定をリセットするようにします。
共有コンポーネントのアプリケーション・プロセスを開きます。
作成済みのアプリケーション・プロセスの一覧が表示されます。
作成をクリックします。
名前はRESET_HIDE_GLOBAL_NOTIFICATION_BANNERとします。ポイントは認証後です。ユーザー・プリファレンスはユーザーに対する設定なので、一般ユーザーが操作するためには、ユーザー認証が完了している必要があります。
次へ進みます。
コードとして以下を記述します。ユーザー・プリファレンスHIDE_GLOBAL_NOTIFICATION_BANNERを削除します。
apex_util.remove_preference(
p_preference => 'HIDE_GLOBAL_NOTIFICATION_BANNER'
);
次へ進みます。
条件タイプの設定は不要です。プロセスの作成を実行します。
通知の非表示設定をリセットするアプリケーション・プロセスが作成されました。
以上で通知の実装は完了です。
おおむねJavaScriptでの実装と同じ動作をしますが、サインインし直すと通知が再度表示されるところが異なります。
この例ではユーザー・プリファレンスを使用して通知の表示を制御していますが、サーバー側の条件であれば、他のデータベースに保存されている情報を元にして、通知の表示の有無を決めることができます。
グローバル・ページにインライン・ダイアログのリージョンを作成する
サインイン直後に通知として、以下のようにダイアログを開きます。
データセットから作成したアプリケーションを元に実装を始めます。
ページ・デザイナにてグローバル・ページを開き、リージョンを作成します。
作成されたリージョンの識別のタイトルは通知、タイプは静的コンテンツとします。ソースのHTMLコードに以下を記述します。
2022年4月17日午前9:00より10:00まで、メンテナンスのため本アプリケーションは利用できません。
詳しくは<a href="http://........./notice.html">http://........./notice.html</a>を参照してください。
レイアウトの位置はBodyのまま、変更しません。
外観のテンプレートとしてInline Dialogを選択します。
通知となるインライン・ダイアログが、サインイン後に開かれるように動的アクションを作成します。
左ペインで動的アクション・ビューを開き、ページのロードで動的アクションの作成を実行します。
作成された動的アクションの、識別の名前はonPageLoad Globalとします。
作成済みのTRUEアクションを選択します。
識別のアクションとしてリージョンを開くを選択します。影響を受ける要素の選択タイプにリージョンを選び、リージョンとして通知を指定します。実行オプションの初期化時に実行はOFFです。クライアント側の条件のタイプとして、JavaScript式を選択し、JavaScript式に以下を記述します。
sessionStorage.getItem("hide-global-notification-dialog") != "true"
&
apex.env.APP_PAGE_ID != 9999
この後に、sessionStorageのhide-global-notification-dialogにtrueを設定するJavaScriptコードを実行するアクションを定義します。
ページ番号9999はログイン・ページです。結果としてログイン・ページではダイアログは表示されず、また、一度ダイアログが表示されるとブラウザを終了するまではダイアログが再表示されることはありません。
追加でTRUEアクションを作成します。
作成したTRUEアクションの識別のアクションとして、JavaScriptコードの実行を選択します。設定のコードに以下を記述します。
sessionStorage.setItem("hide-global-notification-dialog","true");
クライアント側の条件は、先行するTRUEアクションリージョンを開くと同じ設定にします。アクションリージョンを開くが実行されていれば、hide-global-notification-dialogにtrueが設定されます。
以上で通知の実装は完了です。
今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/demo-notification-global.sql
https://github.com/ujnak/apexapps/blob/master/exports/demo-notification-javascript.sql
https://github.com/ujnak/apexapps/blob/master/exports/demo-notification-plsql.sql
https://github.com/ujnak/apexapps/blob/master/exports/demo-notification-dialog.sql
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完