画像ボタンのファイルピッカーを画像・動画に限定し、モバイルネイティブピッカーを活性化
ツールバーの画像ボタン(name="image")に accept="image/*,video/*" を設定することで、iOS・Androidのネイティブフォト/ビデオピッカーが起動するようになりました。ファイルボタン(name="file")は従来どおり制限なしのファイルピッカーを開きます。
背景
変更前は、画像ボタンとファイルボタンの両方が同一の uploadAttachments コマンドを呼び出しており、どちらも accept 属性のない汎用ファイルピッカーを開く動作でした。モバイルブラウザでは accept 属性の有無によってUIが大きく異なり、accept="image/*,video/*" を指定するとOSのネイティブ写真・動画ライブラリが直接開きます。画像アップロード用のボタンが汎用ファイルブラウザを開くことは、モバイルユーザーにとって直感的ではありませんでした。
この差異を解消するために、画像ボタンとファイルボタンのコマンドが分離され、それぞれの用途に適したファイルピッカーが起動するよう変更されました。
技術的な変更
CommandDispatcher のリファクタリングにより、単一だった uploadAttachments コマンドが uploadImage と uploadFile の2つに分離されました。共通のファイル入力生成ロジックはプライベートメソッド #dispatchUploadAttachment に集約されています。
変更前:
dispatchUploadAttachments() {
const input = createElement("input", {
type: "file",
multiple: true,
style: "display: none;",
onchange: ({ target: { files } }) => {
this.contents.uploadFiles(files, { selectLast: true })
}
})
// ...
}
変更後:
dispatchUploadImage() {
this.#dispatchUploadAttachment("image/*,video/*")
}
dispatchUploadFile() {
this.#dispatchUploadAttachment()
}
#dispatchUploadAttachment(accept = null) {
const attributes = {
type: "file",
multiple: true,
style: "display: none;",
onchange: ({ target: { files } }) => {
this.contents.uploadFiles(files, { selectLast: true })
}
}
if (accept) attributes.accept = accept
const input = createElement("input", attributes)
// ...
}
accept が null の場合は属性自体を設定しないため、ファイルボタンの動作は変更前と完全に同一です。ツールバーの data-command 属性も対応して更新されており、画像ボタンは uploadImage、ファイルボタンは uploadFile を参照します。なお、画像ボタンの title も "Add images" から "Add images and video" に更新され、動画も受け付けることが明示されました。
設計判断
共通ロジックをプライベートメソッドに委譲する設計 が採用されました。uploadImage と uploadFile はそれぞれ1行で #dispatchUploadAttachment に処理を委ねており、accept 値の違いだけで振る舞いを切り替えています。これにより、ファイル入力の生成・DOM操作・イベントハンドリングといったコアロジックの重複を避けつつ、各コマンドのインターフェースをシンプルに保っています。
テスト側では、EditorHandle#uploadFile に { via: "image" } または { via: "file" } オプションが追加され、どちらのボタンを経由するかを選択できるようになりました。既存のブラウザテストは via: "file" に更新されており、PDFやテキストファイルのアップロードテストが引き続き制限なしのファイルボタンを使用することが明示されています。また、accept 属性の有無を検証する新テストがそれぞれ追加されており、モバイルピッカーの動作仕様がテストとして文書化されています。
まとめ
本PRは、単一コマンドの分離と accept 属性の追加という最小限の変更で、モバイルユーザーの操作体験を改善した変更です。プライベートメソッドへの委譲パターンにより後方互換性を維持しながら、画像・動画アップロードとファイルアップロードの意図的な使い分けをコードレベルで明確に表現しています。