ファイルアップロードのライフサイクルイベントを追加
<lexxy-editor> 要素でファイルアップロードの開始・進捗・終了を検知できる3つのカスタムイベントが追加されました。これにより、アップロード中のフォーム送信ブロックやカスタムプログレスUIの実装が、DOM操作のハックなしに実現できます。
背景
これまで lexxy では、アップロード中かどうかを判定する公式な手段が提供されていませんでした。#735 で報告されているように、コンシューマーはアップロード進行中の判定に <lexxy-editor> 内の progress 要素の存在をDOMクエリで確認するという回避策を取らざるを得ませんでした。
具体的には、lexxy:change イベントのたびに this.element.querySelector("lexxy-editor progress") !== null を評価してアップロード中フラグを推測し、送信ボタンの disabled を切り替えるといった実装が必要でした。
この回避策はアップロード状態の内部表現(progress 要素)に依存しているため、実装の詳細変化に脆弱でした。専用イベントの追加はこの脆弱な結合を解消します。
技術的な変更
ActionTextAttachmentUploadNode クラスに #dispatchEvent プライベートメソッドが追加され、アップロードの各フェーズで3種類のイベントをディスパッチするようになりました。
変更前:
import { createElement } from "../helpers/html_helper"
// ...
upload.create((error, blob) => {
if (error) {
this.#handleUploadError(error)
} else {
this.#showUploadedAttachment(blob)
}
})
// ...
#handleUploadProgress(event) {
this.#setProgress(Math.round(event.loaded / event.total * 100))
}
変更後:
import { createElement, dispatch } from "../helpers/html_helper"
// ...
this.#dispatchEvent("lexxy:upload-start", { file: this.file })
upload.create((error, blob) => {
if (error) {
this.#dispatchEvent("lexxy:upload-end", { file: this.file, error })
this.#handleUploadError(error)
} else {
this.#dispatchEvent("lexxy:upload-end", { file: this.file, error: null })
this.#showUploadedAttachment(blob)
}
})
// ...
#handleUploadProgress(event) {
const progress = Math.round(event.loaded / event.total * 100)
this.#setProgress(progress)
this.#dispatchEvent("lexxy:upload-progress", { file: this.file, progress })
}
// ...
#dispatchEvent(name, detail) {
const figure = this.editor.getElementByKey(this.getKey())
if (figure) dispatch(figure, name, detail)
}
イベントのディスパッチ元は figure 要素(アタッチメントのDOM表現)です。イベントはバブルアップするため、親の <lexxy-editor> 要素でリッスンできます。各イベントの detail には以下が含まれます:
-
lexxy:upload-start:{ file }— アップロード対象のファイル -
lexxy:upload-progress:{ file, progress }— ファイルと0〜100の進捗値 -
lexxy:upload-end:{ file, error }— 成功時はerror: null、失敗時はエラーオブジェクト
#dispatchEvent は figure 要素が存在する場合のみディスパッチするガード節を持っており、ノードがDOMに未マウントの状態での呼び出しに対して安全です。
設計判断
イベントのディスパッチ元として、エディタルート要素ではなく figure 要素 が選ばれています。
これにより、複数ファイルが同時にアップロードされる場合でも、各イベントの発生元ノードを event.target で区別できます。一方でバブルアップを利用することで、<lexxy-editor> 要素の単一リスナーで全アップロードイベントをまとめて処理することも可能です。
lexxy:upload-end の detail.error は成功時に null として明示的に含まれており、'error' in event.detail による存在確認ではなく event.detail.error !== null という統一した判定パターンで成否を識別できます。このインターフェース設計は、成功・失敗の両パスで同じ detail 構造を保証します。
まとめ
本PRは、DOM内部構造への依存という脆弱な回避策を、公式イベントAPIへ置き換える変更です。figure 要素からのバブルアップという設計により、単一ファイルの追跡と複数ファイルの一括監視の両方のユースケースを一つのイベントモデルで実現しています。