Closed Bug 1523270 Opened 5 years ago Closed 2 years ago

Editable component (textarea) ctrl+z undo history lost after value property assignment

Categories

(Core :: DOM: Editor, defect, P5)

defect

Tracking

()

RESOLVED INVALID
Tracking Status
firefox66 --- affected

People

(Reporter: myf, Unassigned)

Details

Attachments

(1 file)

Artificial (JavaScript) value change wipes textarea (text input) undo history, so invoking Undo command cannot revert it.

Simple test case in dataURI:

data:text/html,<!doctype html><title>Textarea history persistence test</title><textarea cols="50" rows="20" onblur="this.value+='\n\nValue amended. Now try to restore previous state.'">This is the initial value. Make some changes and then restore initial value using Menu - Edit - Undo (Ctrl+Z).%0A%0AThen press tab or click outside and try again.</textarea>

Expected outcome: Undo reverts both changes made by typing AND by JavaScript value assignment.

Actual outcome: Undo can revert only changes made by typing; JavaScript change sets initial state anew and erases prior history.


Haven't spotted exact version but appeared quite recently; bug is present in current stable branch (64), not present in older non-quantum fork [1]. As far as my memory goes, Firefox always retained history very well and I relied on it in my personal webapps quite blindly, so this is quite nasty regression FMOPW.

[1] (Tried current Basilisk with Gecko/20100101 Goanna/4.1 Firefox/60.9 Basilisk/20181218 , have nothing more at hand ATM.)

This is expected behavior (bug 1386484 and etc). Before landing some bugs, we always stored undo history even if setting value. Some browsers discard undo history by setting value and this causes performance issue (bug 1346723), so we decide that we change this behavior.

Priority: -- → P5

Oh, thanks for quick response. I was afraid it will be something like this. I understand that retaining history is expensive, but this certain optimization breaks UX of pretty much every 'simple JavaScript-aided textarea' in the wild: Wikipedia, Github [1] and even the MDN sample code showing principle of 'Inserting something to textarea' [2] comes into mind as notable examples.

I know performance is important and to be honest I always quite admired how much data could Firefox handle in such invisible detail as value history, but in this case it was too big sacrifice [3].

So is this decision final? If so, it should be mentioned at MDN page as a warning (First affected Firefox version was 57, is it right?), such as "Don't forget to implement own value history management if your script amends elements value", with corresponding code sample ("original ctrl-z restoring shim").


[1] Type word into comment textarea on e.g. Github issue page, select it, press Ctrl+B. Your word is now surrounded with asterisks. To revert it you have to manually delete asterisks on both sides. You have also lost undo history. /Better type them asterisks yourself next time./
[2] https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement#Insert_HTML_tags_example
[3] And if you want to be on par with "some browsers", keep in mind their history management is often a joke. Maybe performance improving joke, but still UX joke.

This is extremely annoying.
Many websites rely on the undo history not being reset when the contents of a textarea are changed, as mentioned before.
Implementing a custom undo system using javascript is messy and impractical (There appears to be no way to modify the undo buffer, or properly detect undo events (remember, not every OS uses ctrl+z))

This is great remark: I haven't realized there is no such event handler like onundo or onbeforeundo or anything similar what would be prerequisite for reliable way to revert to prior text value.

I was thinking about simplest shim remedying such crippling value assignment and thought it could be possible to, for example, "simply clone" (sic!) the textarea element, save and hide the original instance with history intact, save information about last selection "somewhere", amend the clone and swap to original when need arises (= history buffer of the clone reaches it's beginning, i.e. invoking undo there changes nothing). Like you said, there is no reliable way to know when such need arises, so any attempt to hotfix this in simple and reliable way is doomed in advance. Not only because listening to keyboard events is clearly wrong (as you mentioned), but moreover because undo command can be invoked from textarea context menu or even Main menu Edit submenu, i.e. "uncapturable" for JavaScript in the page.

So again, is it really worth to be broken (but, eh, "fast") the same way like every other current browser?
Should we (web developers) really throw away textarea elements and switch to something like Codemirror the moment we decide to add something like "make bold" / "add signature" button?

It would be nice competitive advantage to have reliable text fields again. I'd really like to show off how I could return back to any state my field had, regardless how was its content formed.

The bug has a release status flag that shows some version of Firefox is affected, thus it will be considered confirmed.

Status: UNCONFIRMED → NEW
Ever confirmed: true

Alright, I've since learned about document.execCommand() (and firefox has since added support for execCommand on textareas),
so I'm not bothered by this old bug/regression as much now. (I mean, it was a very nice feature, but...)

Note: For any web developers reading this, here's how to modify textarea contents without clearing the undo history:
(I've been using this on my website for ~4 months; no issues on any browser/device so far)

Replace/clear the value:

elem.select()
document.execCommand(str ? 'insertText' : 'delete', false, str)

Insert text at the cursor:

elem.focus()
document.execCommand('insertText', false, str)

Move the cursor / selection region:

(use elem.setSelectionRange() and related properties)

Thank you 12Me21.MC, that's right approach for working with current web API.

The new behavior is intentional (bug 1346723) and we've already supported execCommand in <input> and <textarea> since 89 (bug 1220696). This means that there is a new way to manage the value with keeping editing history so that we won't change the behavior back.

Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → INVALID

Few remarks from 2023-05

Thanks, 12Me21.MC

That remark was really helpful. Attaching a simple demo comparing "old" and "new" approaches, based on that information.

"Obsolete" sample in MDN Textarea content manipulation

Sample in the aforementioned article still uses textArea.value = newValue. (Will look at it if time and skills permit.)

"Deprecated" document.execCommand

That MDN article currently displays scary red box telling that the feature "may cease to work at any time", and also implying that there is no better replacement for "isertText".

Spreading awareness

So the last thing that remains is to convince rest of the devs who haven't caught on to change

t.value = 'Hi!';

in their scripts to

t.select();
document.execCommand('insertText', false, 'Hi!');

and

t.value += 'Good bye!';

to

t.focus();
let l = t.value.length;
t.setSelectionRange(l,l);
document.execCommand('insertText', false,  'Good bye!');

I do still stumble upon such untreated web apps, which made me revisit this issue today.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: