Keep an unsent message as a draft while switching rooms

The composer stores what's being written in localStorage per room and
restores it when the room is opened again. Sending clears it.
This commit is contained in:
Stanko K.R.
2026-09-26 10:38:13 +02:00
parent 8fa6138fb9
commit 5c5821a395
3 changed files with 46 additions and 1 deletions
@@ -12,11 +12,21 @@ export default class extends Controller {
#files = []
connect() {
this.#restoreDraft()
if (!this.#usingTouchDevice) {
onNextEventLoopTick(() => this.textTarget.focus())
}
}
saveDraft() {
if (this.textTarget.isBlank) {
localStorage.removeItem(this.#draftKey)
} else {
localStorage.setItem(this.#draftKey, this.textTarget.value)
}
}
submit(event) {
event.preventDefault()
@@ -107,6 +117,19 @@ export default class extends Controller {
this.fieldsTarget.disabled = true
}
#restoreDraft() {
const draft = localStorage.getItem(this.#draftKey)
if (draft) {
this.textTarget.value = draft
this.textTarget.selection.placeCursorAtTheEnd()
}
}
get #draftKey() {
return `composer-draft-${this.roomIdValue}`
}
get #usingTouchDevice() {
return 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
}
@@ -158,6 +181,7 @@ export default class extends Controller {
#reset() {
this.textTarget.value = ""
localStorage.removeItem(this.#draftKey)
}
#updateFileList() {
+1 -1
View File
@@ -25,7 +25,7 @@
"permitted-attachment-types": "application/vnd.campfire.mention application/vnd.actiontext.opengraph-embed",
data: {
controller: "unfurl",
action: "#{rich_text_data_actions} lexxy:insert-link->unfurl#unfurl",
action: "#{rich_text_data_actions} lexxy:change->composer#saveDraft lexxy:insert-link->unfurl#unfurl",
composer_target: "text" } do %>
<%= mention_prompt_tag room %>
<% end %>
+21
View File
@@ -29,6 +29,27 @@ class ComposerTest < ApplicationSystemTestCase
assert_composer_empty
end
test "an unsent message is kept as a draft while hopping between rooms" do
type_in_composer "Still writing this"
join_room rooms(:hq)
assert_composer_empty
type_in_composer "And this one too"
join_room rooms(:designers)
assert_composer_text "Still writing this"
press_in_composer :enter
assert_message_text "Still writing this"
join_room rooms(:hq)
assert_composer_text "And this one too"
join_room rooms(:designers)
assert_composer_empty
end
test "markdown strikethrough survives sanitization" do
type_in_composer "Hello ~~Claude~~ World"
press_in_composer :enter