Oracle APEX 23.1よりリッチ・テキスト・エディタの実装がCKEditorからTinyMCEに置き換えられました。今のところCKEditorも使用できますが、TinyMCEへ移行した方が良いことは間違いありません。
CKEditorをカスタマイズせずに使用している範囲であれば、設定のライブラリをCKEditorからTinyMCEに問題なく切り替えられるはずです。プラグインを使用してカスタマイズしている場合は、TinyMCEに同等のカスタマイズを行う必要があります。
CKEditorのイメージ・アップロードについては、以下の記事を書いています。
CKEditor5による画像アップロードを実装する(1) - 準備CKEditor5による画像アップロードを実装する(2) - REST APIの作成
CKEditor5による画像アップロードを実装する(3) - 完成
CKEditor5による画像アップロードを実装する(4) - 画像をオブジェクト・ストレージに保存する
CKEditor5による画像アップロードを実装する(5) - 動的コンテンツを使う
TinyMCEを使用するにあたって、上記の実装の変更点について記述します。
CKEditorのイメージ・アップロードと同様に、Louis Moreauxさんのブログ記事 -
Oracle APEX 23.1 - TinyMCE and image upload - を参考にしています。
Oracle APEX 23.1 - TinyMCE and image upload - を参考にしています。
APEXアプリケーションの変更
ページ番号2のフォームのページを変更します。
ページ・プロパティのJavaScriptのファンクションおよびグローバル変数の宣言で、images_upload_handlerを定義します。
images_upload_handlerについては、TinyMCE DocumentationのImage Uploads - images_upload_handlerで説明されています。
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
const apexSession = apex.env.APP_ID + ',' + apex.env.APP_SESSION; | |
const imageUrl = "&G_IMAGE_URL."; | |
const image_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => { | |
const xhr = new XMLHttpRequest(); | |
xhr.withCredentials = false; | |
xhr.open('POST', imageUrl); | |
xhr.setRequestHeader("Apex-Session", apexSession); // APEXセッションでの認証を付加 | |
xhr.upload.onprogress = (e) => { | |
progress(e.loaded / e.total * 100); | |
}; | |
xhr.onload = () => { | |
if (xhr.status === 403) { | |
reject({ message: 'HTTP Error: ' + xhr.status, remove: true }); | |
return; | |
} | |
if (xhr.status < 200 || xhr.status >= 300) { | |
reject('HTTP Error: ' + xhr.status); | |
return; | |
} | |
const json = JSON.parse(xhr.responseText); | |
// json.locationからjson.urlへ変更。 | |
if (!json || typeof json.url != 'string') { | |
reject('Invalid JSON: ' + xhr.responseText); | |
return; | |
} | |
resolve(json.url + '?_apex_session=' + apexSession); // APEXセッションでの認証を付加 | |
}; | |
xhr.onerror = () => { | |
reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status); | |
}; | |
const formData = new FormData(); | |
formData.append('file', blobInfo.blob(), blobInfo.filename()); | |
xhr.send(formData); | |
}); |
マニュアルに記載されているimages_upload_handlerの例に、APEXセッションで認証するためのコードを数行追加しています。また、TinyMCEのimages_upload_handlerの例では、画像アップロードのレスポンスが{ location: "画像のURL" }という形式で返されることが想定されていますが、今回の実装では{ url: "画像のURL" }なので、その点も修正しています。
TinyMCEのimageプラグインを有効にし、images_upload_handlerを設定します。
ページ・アイテムP2_CONTENTの設定のライブラリをTinyMCEに変更し、詳細の初期化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){ | |
// Add the plugin and the toolbar option | |
options.editorOptions.plugins += " image"; | |
options.editorOptions.toolbar += " image"; | |
// Use the custom upload handler | |
options.editorOptions.images_upload_handler = image_upload_handler; | |
// Disable relative url | |
options.editorOptions.relative_urls = false; | |
// Replace the editor content | |
options.editorOptions.init_instance_callback = (editor) => { | |
editor.setContent(editor.getContent()); | |
} | |
// Define the URL converter and enable it | |
options.editorOptions.convert_urls = true; | |
options.editorOptions.urlconverter_callback = function(url, node, on_save, name) { | |
console.log(url, node, on_save, name); | |
if (node === "img" && name === "src" ){ | |
url = url.split("?")[0] + '?_apex_session=' + apexSession; | |
console.log(url); | |
} | |
return url; | |
} | |
return options; | |
} |
ここで、urlconverter_callbackとして定義したファンクションで、列CONTENTに含まれるイメージURLに、APEXセッションで認証する引数_apex_sessionを追加しています。
CKEditorとは異なり、urlconverter_callbackによるイメージURLの置き換えは、ページ・アイテムP2_CONTENTが保持しているデータを置き換えます。そのまま、作成や変更の適用を実行すると、イメージURLに?_apex_session=....の認証子が付加されてデータベースに保存されます。
ワークアラウンドとして、データを保存する前に?_apex_session=...の認証子をP2_CONTENTの内容から取り除くプロセスを作成します。
作成したプロセスはプロセスプロセス・フォームDocumentの上に配置し、先に実行されるようにします。
識別の名前はapex_sessionの削除、タイプはコードを実行、ソースの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_apex_session varchar2(80); | |
begin | |
l_apex_session := '?_apex_session=' || :APP_ID || ',' || :APP_SESSION; | |
:P2_CONTENT := replace(:P2_CONTENT, l_apex_session, ''); | |
end; |
サーバー側の条件のタイプにリクエストは値に含まれるを選び、値にCREATE,SAVEを設定します。
CKEditorが必要としていた、ページ・ロード時の動的アクションP2_CONTENTの再ロードは、TinyMCEでは不要なので削除します。
以上でTinyMCEへの変更は完了です。アプリケーションはCKEditorのときと同様に動作します。
TinyMCEに変更したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/tinymce-image-sample.zip
オブジェクト・ストレージを使うアプリの変更
オブジェクト・ストレージを使うAPEXアプリは、?_apex_session=の認証子をイメージURLに追加する代わりに、オブジェクト・ストレージの事前承認リクエストに置き換えるように変更します。
ページ番号2のページ・プロパティの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
const apexSession = apex.env.APP_ID + ',' + apex.env.APP_SESSION; | |
const imageUrl = "&G_IMAGE_URL."; | |
const image_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => { | |
const xhr = new XMLHttpRequest(); | |
xhr.withCredentials = false; | |
xhr.open('POST', imageUrl); | |
xhr.setRequestHeader("Apex-Session", apexSession); // APEXセッションでの認証を付加 | |
xhr.upload.onprogress = (e) => { | |
progress(e.loaded / e.total * 100); | |
}; | |
xhr.onload = () => { | |
if (xhr.status === 403) { | |
reject({ message: 'HTTP Error: ' + xhr.status, remove: true }); | |
return; | |
} | |
if (xhr.status < 200 || xhr.status >= 300) { | |
reject('HTTP Error: ' + xhr.status); | |
return; | |
} | |
const json = JSON.parse(xhr.responseText); | |
// json.locationをjson.urlに変更する。 | |
if (!json || typeof json.url != 'string') { | |
reject('Invalid JSON: ' + xhr.responseText); | |
return; | |
} | |
/* 事前承認済みURLに置き換える。 */ | |
resolve(json.url.replace('&G_OBJECT_STORAGE_URL!RAW.','&G_PREAUTH_URL!RAW.')); | |
}; | |
xhr.onerror = () => { | |
reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status); | |
}; | |
const formData = new FormData(); | |
formData.append('file', blobInfo.blob(), blobInfo.filename()); | |
xhr.send(formData); | |
}); |
TinyMCEの初期化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){ | |
// Add the plugin and the toolbar option | |
options.editorOptions.plugins += " image"; | |
options.editorOptions.toolbar += " image"; | |
// Use the custom upload handler | |
options.editorOptions.images_upload_handler = image_upload_handler; | |
// Disable relative url | |
options.editorOptions.relative_urls = false; | |
// Replace the editor content | |
options.editorOptions.init_instance_callback = (editor) => { | |
editor.setContent(editor.getContent()); | |
} | |
// Define the URL converter and enable it | |
options.editorOptions.convert_urls = true; | |
options.editorOptions.urlconverter_callback = function(url, node, on_save, name) { | |
if (node === "img" && name === "src" ){ | |
url = url.replace('&G_OBJECT_STORAGE_URL!RAW.','&G_PREAUTH_URL!RAW.'); | |
} | |
return url; | |
} | |
return options; | |
} |
ページ・アイテムP2_CONTENTを保存する前に、事前承認リクエストを取り除くプロセスのPL/SQLコードは以下になります。名前は事前承認URLの削除とします。
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
begin | |
:P2_CONTENT := replace(:P2_CONTENT, :G_PREAUTH_URL, :G_OBJECT_STORAGE_URL); | |
end; |
アプリケーションのエクスポートは以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/tinymce-image-sample-obs.zip
こちらの記事で紹介している動的コンテンツの追加手順に変更はありません。
動的コンテンツのページを追加したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/tinymce-image-sample-dyn.zip
以上になります。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完