追記: APEX 23.1よりリッチ・テキスト・エディタはCKEditor5からTinyMCEへ置き換えられます。CKEditor5のカスタマイズ方法はTinyMCEには適用できません。
----
Louis Moreauxさんが彼のブログにCKEditor5 mention featureという記事を載せていました。面白い内容だったので、自分でも実装してみました。
以下より、上記のサンプル・アプリケーションを作ったときの作業を記述します。今回はテスト・データの生成にOracle APEX 22.1の新機能であるデータ・ジェネレータを使いました。
クイックSQLを使って、ユーザーの一覧を保存する表CKE_USERSを作成します。
SQLワークショップのユーティリティのクイックSQLを開きます。クイックSQLのモデルとして以下を記述します。
# prefix: cke
users
first_name vc80 /nn
last_name vc80 /nn
email_address vc40
shortname vc8 /nn
SQLの生成、SQLスクリプトを保存、レビューおよび実行を順次クリックします。表の作成までを実施し、アプリケーションの作成は行いません。
表CKE_USERSが作成されます。
作成した表CKE_USERSにテスト・データを投入します。
SQLワークショップのユーティリティのデータ・ジェネレータを開きます。
作成済みのブループリントが一覧されます。生成するテスト・データの定義は、ブループリントというJSON形式のファイルとして保存されます。
ブループリントの作成をクリックします。
ブループリントの作成方法を選択します。今回は先ほど作成した表CKE_USERSを元にブループリントを作成します。
既存の表の使用を選択します。
以上の設定を行い、ブループリントの作成をクリックします。
TablesにあるCKE_USERSを選択し、設定を確認します。
行数が50行になっています。このブループリントを元に生成されるテスト・データは50行です。表の名前として設定されているCKE_USERSに50行のテスト・データが挿入されます。
列IDを選択します。
データ・ソースとして組込み、組込みとしてnumber.guid:NUMBERが設定されています。sys_guid()の結果が列IDのテスト・データとして生成されます。しかし、列IDは自動生成になっており、値を投入すると一意性を担保できなくなります。
列IDをテスト・データ生成の対象から外すため、列の削除を実行します。
列FIRST_NAMEを選択します。データ・ソースは組込み、組込みとしてperson.first_name:VARCHAR2が選択されています。Oracle APEXが事前定義しているperson.first_nameのデータが、テスト・データとして使用されます。現在のところ英語のデータのみで、詳細の言語もen以外は選択できません。最大長は表CKE_USERSの列FIRST_NAMEのサイズを考慮していないようです。表定義に合わせて最大長を80に変更します。
列LAST_NAMEを選択します。こちらも最大長を80に変更します。
列SHORTNAMEを選択します。データ・ソースとして式を選択し、式として以下を記述します。
upper(substr({FIRST_NAME},1,1) || substr({LAST_NAME},1,7))
列FIRST_NAMEの先頭1文字と列LAST_NAMEの先頭7文字を連結した、最大8文字の値を列SHORTNAMEとして生成します。
以上でブループリントが作成できました。
データのプレビューをクリックして、生成されるテスト・データを確認します。
列FIRST_NAME、LAST_NAME、EMAIL_ADDRESS、それと式によって定義している列SHORTNAMEも想定したテスト・データになっています。
プレビューを確認した後、データの作成に進みます。
アクションとしてデータベースへの挿入を選択します。生成されたテスト・データは表CKE_USERSへ直接書き込まれます。挿入メソッドは挿入、行スケーリングは1xとします。
アクションとしてファイル・エクスポートを選択すると、JSON、CSVまたはSQLのinsert文としてテスト・データをファイルに出力できます。生成したテスト・データを別のプラットフォームにロードする際に役立つでしょう。
データを挿入を実行します。
テスト・データが挿入されるとダイアログにメッセージが表示されますが、ダイアログは閉じません。続けてデータを挿入を実行すると、さらにテスト・データが挿入されます。今回の例では50行が追加され、100行になります。
テスト・データの作成が終わったら、取消をクリックしてダイアログを閉じます。
SQLワークショップのオブジェクト・ブラウザなどを使用して、表CKE_USERSに投入されたテスト・データを確認します。
表CKE_USERSとテスト・データの準備ができたので、CKEditor5のmentionの機能を使うAPEXアプリケーションを作成します。
アプリケーション作成ウィザードを起動します。
アプリケーションの名前はCKEditor5 mention featureとします。それ以外は変更せず、アプリケーションの作成を実行します。
アプリケーションはすべてホーム・ページに実装します。
アプリケーションが作成されたら、ホーム・ページをページ・デザイナで開きます。
ページ・アイテムP1_TEXTを作成します。このページ・アイテムのタイプをリッチ・テキスト・エディタ(実体はCKEditor5)とし、mentionを使えるようにします。
識別の名前をP1_TEXT、タイプとしてリッチ・テキスト・エディタを選択します。ラベルはTextとします。ソースのタイプはNULL、使用はセッション・ステートの値がNULLの場合のみ、セッション・ステートの保持にセッションごと(ディスク)を選択します。
ページ・アイテムP1_TEXTの値はセッション・ステートにのみ保存し、表やAPEXコレクションは用意しません。
送信ボタンを作成します。
識別のボタン名はB_SUBMIT、ラベルはSubmitとします。動作のアクションとしてページの送信を選択します。
このボタンをクリックすると、ページ・アイテムP1_TEXTの値がセッション・ステートに保存されます。
識別の名前をP1_LIMIT、タイプとして非表示を選択します。ソースのタイプとして静的値を選択し、静的値に5を指定します。一度に検索されるmentionの上限を5に設定しています。使用はセッション・ステートの値がNULLの場合のみ、セッション・ステートの保持にリクエストごと(メモリーのみ)を選択します。
CKEditor5が発行する検索要求を受け付けて、ユーザーの一覧を返すAjaxコールバックを作成します。
Ajaxコールバックにプロセスを作成します。
識別の名前はGET_USERS、タイプとしてコードを実行を選択します。ソースのPL/SQLコードとして、以下を記述します。
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_regexp varchar2(4000); | |
l_users clob; | |
begin | |
l_regexp := apex_escape.regexp(apex_application.g_x01); | |
select | |
json_arrayagg( | |
json_object( | |
key 'id' value '@' || shortname, | |
key 'text' value first_name || ' ' || last_name, | |
key 'email' value email_address | |
) | |
returning clob) | |
into l_users | |
from cke_users | |
where regexp_like(first_name, l_regexp, 'i') or regexp_like(last_name, l_regexp, 'i') | |
fetch first :P1_LIMIT rows only; | |
apex_json.open_object; | |
apex_json.write('success', true); | |
apex_json.write('matchFound', (l_users is not null)); | |
apex_json.write('users', l_users); | |
apex_json.close_object; | |
end; |
CKEditor5のプラグインmentionを有効にします。
ページ・アイテムP1_TEXTの詳細のJavaScript初期化コードとして、以下を記述します。
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
function(options){ | |
options.editorOptions.extraPlugins.push(CKEditor5.mention.Mention); | |
options.editorOptions.mention = { | |
dropdownLimit: apex.items.P1_LIMIT.value, | |
feeds: [ | |
{ | |
marker: '@', | |
feed: getUserItems, | |
minimumCharacters: 1, | |
itemRenderer: userItemRenderer | |
} | |
] | |
}; | |
return options; | |
} |
初期化コードで呼び出しているファンクションgetUserItems、userItemRendererを、ページ・プロパティのJavaScriptのファンクションおよびグローバル変数の宣言に記述します。
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
function getUserItems( queryText ) { | |
return new Promise( resolve => { | |
apex.server.process ( | |
"GET_USERS", | |
{ | |
x01: queryText, | |
pageItems: "#P1_LIMIT" | |
}, | |
{ | |
// dataType: "text", | |
success: function( pData ) { | |
let users = []; | |
if ( pData.matchFound ) { | |
users = JSON.parse(pData.users); | |
} | |
resolve(users); | |
} | |
} | |
); | |
}) | |
} | |
function userItemRenderer( item ) { | |
const itemElement = document.createElement( 'div' ); | |
itemElement.id = 'mention-list-item-id-${ item.id }'; | |
const usernameElement = document.createElement( 'span' ); | |
usernameElement.classList.add( 'padding-right-sm'); | |
usernameElement.textContent = item.text; | |
itemElement.appendChild( usernameElement ); | |
const emailElement = document.createElement( 'span' ); | |
emailElement.classList.add( 'u-italics' ); | |
emailElement.textContent = item.email; | |
itemElement.appendChild( emailElement ); | |
return itemElement; | |
} |
以上でAPEXアプリケーションは完成です。
アプリケーションを実行すると、記事の先頭にあるGIF動画のような動作をします。
開発者ツール・バーよりセッション・ステートを表示させ、ページ・アイテムP1_TEXTに保存されているHTML文書を確認します。
<div class="ck-content"><p><span class="mention" data-mention="@PMOREL">Parker Morel</span> さんへ、</p><p>mention機能については、 <span class="mention" data-mention="@WPICKENP">Winter Pickenpaugh</span> さんへ、</p></div>
mentionの部分に限ると、以下です。data-mention属性としてAjaxコールバックGET_USERSがidとして返した値、span要素のテキストとしてtextが設定されています。
<span class="mention" data-mention="@PMOREL">Parker Morel</span>
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/ckeditor5-mention-feature.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完