リッチテキストのフォームフィールドを検証する
必須のリッチテキストのフィールドには、アプリケーション側のルールが必要です。文書にテキストがなくても、HTML は空でないことがあるからです。エディターの現在のコンテンツを検証し、それを送信するフィールドにコピーし、サーバーでも同じルールを繰り返してください。
1. 何をコンテンツとみなすかを決める
サポートチケットの説明であれば、テキストを必須にしたいでしょう。画像にキャプションを付けるツールであれば、アップロードした画像だけでも有効な文書になりえます。テキストだけをチェックする場合は、有効な投稿をうっかり失うのではなく、意図して画像だけの文書を拒否するようにしなければなりません。
必須のコンテンツ、テキストの最小の長さ、ペイロードの最大サイズは、別々のルールとして定義してください。HTML の長さはマークアップも数えるので、読める文字の数ではありません。getCharCount() や getPlainText() を使う場合は、その結果を業務ルールとして使う前に、インストールしているバージョンが空白、リスト、改行をどう扱うかを確認してください。
2. 空のマークアップではなく、空のテキストを検出する
// Application policy: this field requires text, not an image-only document.
// Browser-side validation helper. This is NOT an HTML sanitizer.
function hasRequiredText(html) {
const template = document.createElement("template");
template.innerHTML = html;
template.content.querySelectorAll("script, style, template")
.forEach(node => node.remove());
return (template.content.textContent || "")
.replace(/[\s\u00a0\u200b\ufeff]/gu, "").length > 0;
}この例では、空の段落、改行、改行しないスペース、画像だけのコンテンツを拒否します。切り離された template に解析するので、そのコンテンツを実際のページに挿入することはありません。これはテキストの有無のチェックであり、セキュリティのフィルターや見た目のレイアウトのテストではありません。CSS で非表示にしたテキストや、アプリケーション固有のウィジェットには、それぞれ独自のポリシーが必要です。
最小の長さについては、コード単位、Unicode のコードポイント、ユーザーが認識する文字のどれで数えるかを決めてください。JavaScript の文字列の長さでは、絵文字が見た目の文字数とは異なって数えられることがあります。リクエストの両側で同じポリシーを使ってください。
3. 現在の HTML をコピーし、役に立つエラーを表示する
// Assumes editor1 is ready and these elements exist on your page.
// Leave the editor's hidden textarea without a native required attribute.
const form = document.querySelector("#ticket");
const field = document.querySelector("#body");
const message = document.querySelector("#body-error"); // e.g. <p role="alert">
form.addEventListener("submit", event => {
const html = editor1.getHTMLCode();
field.value = html; // Include programmatic edits in the submitted value.
if (!hasRequiredText(html)) {
event.preventDefault();
message.textContent = "Please enter a description.";
editor1.focus();
return;
}
message.textContent = "";
// Normal form submission continues to your application's endpoint.
});textarea が非表示になった後は、ブラウザーのネイティブの required 検証を、エディターの必須項目のルールとして確実に使うことはできません。通常のフォームコントロールには通常の検証をそのまま使い、エディターのルールはその現在のコンテンツに対して実装してください。非表示の背後のフィールドにネイティブの required 制約を付けて、フォーカスできるエラーを期待してはいけません。
初期化が終わるまで「保存」は無効にしておきます。失敗した場合は、下書きを保持し、フィールドの近くに見えるメッセージを表示し、フォーカスをエディターに戻します。メッセージは、組み込み方がサポートするアクセシビリティ用のフックを使って、実際の編集面に関連付けてください。非表示の textarea の属性だけでは、編集面にラベルは付きません。
このスニペットが扱うのは、同期的なテキストの検証だけです。画像をアップロード中の場合は、送信する前にアップロードの完了と保存の手順に従ってください。React では、エディターの状態と保存で説明しているように、送信時に現在のコンテンツを読み取ってください。
4. サーバー側のサニタイズの後に検証を繰り返す
クライアントはブラウザーのチェックを回避できます。保存の認証と認可を行い、リクエストと保存のサイズ制限を適用し、保守されているパーサーベースのポリシーで HTML をサニタイズしてから、受け入れた文書がコンテンツのルールを満たしているかどうかを評価してください。拒否されたマークアップだけを含む文書が、受け入れられた空のレコードになってはいけません。
フィールドに固有のエラーを返し、ユーザーの下書きを使える状態に保ってください。拒否した HTML を、エラーのレスポンスでエスケープせずに表示してはいけません。コンテンツを受け取って保存する C# や PHP の例については、まず各言語のデモとリッチテキストの保存ガイドを参照してください。
受け入れのチェックリスト
- 空のエディター、空白の段落、改行しないスペースは拒否される。
- 通常のテキスト、書式付きのテキスト、ユーザーが入力する言語は受け入れられる。
- 画像だけのコンテンツは、明示的なポリシーに従って扱われる。
- プログラムで読み込んだコンテンツも送信に含まれる。
- 検証エラーがあってもコンテンツは保持され、エラーにはキーボードとスクリーンリーダーで到達できる。
- サーバーは、JavaScript に頼らずに、無効な直接のリクエストを拒否する。
フォーム送信のデモを試すか、必須項目が空の HTML を受け入れてしまう理由を読むか、textarea へのインストールを確認してください。