Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removal of browser built-in Undo stack functionality from contenteditable #150

Open
johanneswilm opened this issue Sep 24, 2016 · 75 comments

Comments

@johanneswilm
Copy link
Contributor

johanneswilm commented Sep 24, 2016

The subject of removing the undo manager functionality from contenteditable by default came up at the Editing Taskforce F2F meeting on 2016-09-22 at TPAC in Lisboa, Portugal. It was pointed out that the browser's undo stack would be entirely useless once the JS editor interrupt the default behavior even in just a few limited cases. No-one present opposed the idea of removing the browser's undo functionality for contenteditable and replacing it by a way for the JS to enable/disable the menu entries for redo and undo + giving the ability to listen for redo/undo being triggered via beforeinput events.

Everyone agreed to turn this functionality of by default. (given that there seems to be no authoritative spec that says that undo IS provided, we may only need to spec that undo is turned off be default).

In addition, the following JS editor projects were contacted and all of them responded that the browser's undo stack and default undo behavior was either useless or harmful:

  • CKEditor
  • ProseMirror
  • QuillJS
  • ContentTools library
  • Substance.io
  • TinyMCE
  • Froala

The following applications were investigated and it was determined that they use their own undo stacks (a separate stack for each input field):

  • Medium.js
  • Google Gmail
  • Microsoft Office 365
  • Apple iCloud Pages
  • Google Docs (only using very limited amount of contenteditable anyway)
  • Facebook's various input fields
  • Wikimedia Visual editor

Two working contenteditable webapps were found that makes use of the browser's undo stack:

  • Facebook's draft-js uses its own undo stack, but falls through to the native undo stack in case the last change was a spell checker fix, so that the browser learns that the change was unwanted and stops making the same suggestion in the future [1].
  • TypeIt.org is a barebones JavaScript editor that uses contenteditable on platforms other than Android. It's purpose is to give extra buttons so that users who don't have a specific language keyboard can write a text in that language relatively easily. It does not allow saving text and it's not guaranteeing that text pasted from other sources will be editable and not behave as expected.

[1] https://github.com/facebook/draft-js/blob/67c5e69499e3b0c149ce83b004872afdf4180463/src/component/handlers/edit/commands/keyCommandUndo.js#L24-L27

(This issue is updated as responses from developers arrive.)

Edit 2019-11-27: Added TypeIt.org

@rniwa
Copy link
Contributor

rniwa commented Sep 24, 2016

Disabling undo/redo is possible but enabling undo/redo would require each app inserting an undo item into the browser's undo stack (NSUndoManager) on Safari (both Mac & iOS). This is precisely why the old undo manager spec, which Gecko implemented at some point, had an explicit mechanism to insert and remove undo entries.

@johanneswilm
Copy link
Contributor Author

johanneswilm commented Sep 24, 2016

@rniwa On iOS/Safari, what are the ways that undo/redo can be activated? The issue of having to have an item in the undo stack in order to have the menu enabled is something that is part of the OS, somehow?

Is there absolutely no way that Safari could take care of inserting this token item into the undo stack when there is focus on the contenteditable element and undo/redo is to be enabled and remove that item again when moving the focus? That would be preferable, as that way the JS editor developer doesn't have to program something specific just for Safari.

The browser would still take care of undo-handling of textareas and input=text elements.

@rniwa
Copy link
Contributor

rniwa commented Sep 24, 2016

Could Safari take care of inserting this token item into the undo stack when there is focus on the contenteditable element and undo/redo is to be enabled, and then somehow also empty the entire undo/redo stack when it has to be disabled?

Not really. Clearing undo stack is possible but then we'd have no way of inserting undo items back. I investigated this problem four years ago. Please go ahead and read old discussions on public-webapps.

Web apps really need to be using browser's undo stack. Also, talking about enabling / disabling menu item is extremely shortsighted approach. There is a reason some operating system provide a high-level abstraction for undo/redo, and any approach that relies on some existent UI tends to be not forward compatible. For example, how is an assistant technology supposed to expose undo/redo stacks if the only thing the browser knows is that there is something undoable? We need to be able to describe to the user what undo does.

@johanneswilm
Copy link
Contributor Author

Web apps really need to be using browser's undo stack. Also, talking about enabling / disabling menu item is extremely shortsighted approach. There is a reason some operating system provide a high-level abstraction for undo/redo, and any approach that relies on some existent UI tends to be not forward compatible.

The issue here is that the browser's undo-stack is unusable in the case of all editors that use even just a little bit of JavaScript to manipulate the DOM due to user intentions. Given that raw contenteditable doesn't work, this includes all existing editors. Some editors are reporting that they need to "fight" the browser in it's attempt to undo itself. Others are apparently intercepting the keyboard shortcuts and the menu items are just not working.

So the question is not about throwing out a technology that is working. It is about removing something that is entirely unusable and replacing it with something that reduces the number of unused/non-working menu entries.

For example, how is an assistant technology supposed to expose undo/redo stacks if the only thing the browser knows is that there is something undoable?

That may be a good point. Do we have specific requirements for what has to be known for these technologies? Is it more than a title for what the next redo or undo would do?

We need to be able to describe to the user what undo does.

This is part of the Apple platform requirements or of assistant technologies?

@johanneswilm
Copy link
Contributor Author

Having the webapp add and remove items from a browser-held undo history may work, if they can add something like a dictionary of their own data. Changing the DOM automatically is not something the browser should be engaged in.

Also, it needs to be able to add and remove great numbers of items to the undo and redo stack at arbitrary positions. For use cases such as;

User A and B are writing together in a collaborative editor. Their document is 3 paragraphs long. User A types 3 words in paragraph one, 10 words in paragraph two, and 4 words in paragraph three.User B then deletes paragraph two. The undo stack for User A should now contain 7 items, and that of User B should contain 1 item. If User B undos once, the undo stack of User A should contain 17 items, and that of User B should contain 0 items.

@johanneswilm
Copy link
Contributor Author

Testing: Undo/redo browser native menu items don't work at all in Google Docs and Office 365 on Safari/Mac OS X.

Do these applications work with assistant technologies?

@johanneswilm
Copy link
Contributor Author

@rniwa I have been looking through old discussions, but all I can find is a system whereby the browser changes the DOM and automatically applies DOM changes. That seems to be what we want to get away from now.

@rniwa
Copy link
Contributor

rniwa commented Sep 26, 2016

The issue here is that the browser's undo-stack is unusable in the case of all editors that use even just a little bit of JavaScript to manipulate the DOM due to user intentions.

The issue is well understood. The problem is that your proposed solution is not implementable.

Also, it needs to be able to add and remove great numbers of items to the undo and redo stack at arbitrary positions.

Removing and inserting arbitrary number of items is possible but not at arbitrary positions for the same reason we can't just enable/disable undo/redo. In order to do that kind of manipulation, one has to remove all entries up to the entry to be removed, and re-insert all succeeding entries.

@rniwa I have been looking through old discussions, but all I can find is a system whereby the browser changes the DOM and automatically applies DOM changes. That seems to be what we want to get away from now.

The old undo manager API did support automatically rolling DOM changes, but also provided a mechanism to insert an entry without any DOM mutations that get automatically unapplied & reapplied. Basically, you just create a DOM transaction, don't do anything inside the transaction, and insert it to the undo manager. Because a transaction can be associated with any JS data, and undo / redo events will be fired upon unapplying and reapplying those transactions, scripts can do whatever they want to do upon receiving those events.

@johanneswilm
Copy link
Contributor Author

The issue is well understood. The problem is that your proposed solution is not implementable.

You seem to be the first browser person saying this, so I would like to find out what exactly is hindering this from happening. Maybe it's just browser developers who have to rethink about how some things can be put together. Or maybe we need to reformulate this slightly to get around restrictions browser makers face.

Removing and inserting arbitrary number of items is possible but not at arbitrary positions for the same reason we can't just enable/disable undo/redo. In order to do that kind of manipulation, one has to remove all entries up to the entry to be removed, and re-insert all succeeding entries.

Ok, well that means it's kind of useless. What exactly is hindering browsers from creating two new menu entries that have nothing to do with the existing undo/redo functionality that are labeled "undo" and "redo" which are shown whenever the selection is in a contenteditable area?

The old undo manager API did support automatically rolling DOM changes, but also provided a mechanism to insert an entry without any DOM mutations that get automatically unapplied & reapplied.

I've had a look at it. So far I have not been able to find any JavaScript project that would seem to have any use of it. It would just mean they have to spend a lot of time implementing something that gives them no advantage.

I think we need to look at what advantages assistant technologies have from using the current native undo stack, and then look at how we can give access to that to the JavaScript undo stacks editors are using anyway.

@rniwa
Copy link
Contributor

rniwa commented Sep 26, 2016

The issue is well understood. The problem is that your proposed solution is not implementable.

You seem to be the first browser person saying this, so I would like to find out what exactly is hindering this from happening. Maybe it's just browser developers who have to rethink about how some things can be put together. Or maybe we need to reformulate this slightly to get around restrictions browser makers face.

We've gone though that exercise four years ago. I find your dismissal attitude with regards to all these discussion extremely offensive. I'm gonna stop following this discussion because it's really affecting my well being at this point.

@johanneswilm
Copy link
Contributor Author

I am not trying todismiss anything. I looked through the old spec and I searched the email list. Maybe you could provide me with a link?
I think what's new now is that we actually have JS editor and browser developers come together and try to find a solution for the problems editors run into. That's fairly new. Now we just need to find away around the hacks editor developers run into.

@johanneswilm
Copy link
Contributor Author

Another problem with the undo manager proposal seems to be that it only allows one, global undo stack. This is not how applications like Google Docs and Office 365 work as of today. The same is true for all the other editor projects as they all have their own undo stack.

@johanneswilm
Copy link
Contributor Author

@rniwa: What part exactly is the impossible? Is it

A) Allowing JS to disable the undo/redo menu entries? As I understood your proposal, this wasn't an issue.

B) Enabling the undo/redo items if JS requests this. If the menu entries are directly linked to the OS, this could be done by adding fake items there if the stacks are empty and removing them when the editor loses focus. Given that the global undo stack is broken anyway, this shouldn't matter, should it?

C) Triggering a beforeinput event for undo/redo?

D) Not changing the DOM be default if beforeinput isn't canceled? This seems like it would be a minor issue.

@rniwa
Copy link
Contributor

rniwa commented Sep 26, 2016

B. Adding a fake item, etc... doesn't work because of the way it integrates with the rest of the browser.

Mutating DOM is not necessary at all. It was merely a convenience feature we wanted to add at the time.

The bottom line is, the only way we can support something like this would be JS authors pushing and popping an entry into and from the native undo stack we manage. We can provide an API, etc... to associate and dissociate arbitrary JS data.

The thing is I've stated our requirements. I'm not going into details of what is and what is not possible with the native API because such is an outside the scope of the standardization process. I'm simply giving an implementation feedback that what you proposed is not implementable, and I've proposed an alternative, which gives full control of DOM mutations and allows authors to remove/add their own undo entries so I don't know what else I can say.

@johanneswilm
Copy link
Contributor Author

Ok, but if I understand the alternative correctly it:

  • Imposes having a global undo stack for all input fields on one page, which is not what webapps currently do, not even those by browser vendors such as Google or Microsoft.
  • Doesn't work with collaborative editors where an arbitrary number of items have to be added or removed from some point in the past.
  • If one imports 1000 undo items from previous doc edits that were stored on the server, it means that the history of all other input fields is unreachable.

But how about this: If you implement that undomanager, it should allow JS to push one fake undo step and one fake redo step when the focus is on the editor and then to consume those when the focus moves away, right? So it would basically be the same thing with the only difference being that JS needs to add 1-3 extra lines of code for Safari. I think that should work!

@johanneswilm
Copy link
Contributor Author

I guess this can be done even now, as long as Safari supports execCommand, by executing two commands, then undoing one, then putting the DOM back to its initial state by manipulating it directly in JS. Now both menus should be enabled. It's a bit of a hack, but it would be a solution that would make beforeinput useful for undo/redo immediately when beforeinput has been implemented in Safari. Solving it all in a non-hackish way could be a next step.

@rniwa
Copy link
Contributor

rniwa commented Sep 27, 2016

Imposes having a global undo stack for all input fields on one page, which is not what webapps currently do, not even those by browser vendors such as Google or Microsoft.

Chrome certainly shares a single undo stack for the entire page. You can test this by typing text into a text field across iframe boundaries: https://jsfiddle.net/buny13mz/

Changing this behavior in regular case (i.e. ones that doesn't invoke custom editor) is unacceptable because it breaks a key browser UX.

Doesn't work with collaborative editors where an arbitrary number of items have to be added or removed from some point in the past.

When we designed the old Undo Manager API, we specifically worked with Google Docs team to ensure their undo worked with the API so this assertion is false.

If you implement that undomanager, it should allow JS to push one fake undo step and one fake redo step when the focus is on the editor and then to consume those when the focus moves away, right? So it would basically be the same thing with the only difference being that JS needs to add 1-3 extra lines of code for Safari.

Not quite. This would still break semantics of the shared undo stack across documents. So you'd have to insert a fake undo/redo for the collaborative undo/redo part at the beginning, and then insert new undo/redo entry as the current client modifies content. You'd just ignore callbacks and pop more entires when undo/redo fires on things that were supposed to be removed earlier. You don't have to actually remove it from the browser's undo stack as they happen.

@johanneswilm
Copy link
Contributor Author

Imposes having a global undo stack for all input fields on one page, which is not what webapps currently do, not even those by browser vendors such as Google or Microsoft.

Chrome certainly shares a single undo stack for the entire page. You can test this by typing text into a text field across iframe boundaries: https://jsfiddle.net/buny13mz/

Yes, but that's the undo stack noone uses for richtext beyond demo purposes. If you go to actual applications Google has made, like Gmail or Google Docs, you'll see that they have implemented it with a different undo stack for each input field.

Changing this behavior in regular case (i.e. ones that doesn't invoke custom editor) is unacceptable because it breaks a key browser UX.

But every time contenteditable is involved, a custom editor will be involved. And all of them create their own undo stack.

The place where the global undo stack still may be used is if you have a series of input text fields in a form. For that case it's fine. I am only talking about contenteditable here.

Doesn't work with collaborative editors where an arbitrary number of items have to be added or removed from some point in the past.

When we designed the old Undo Manager API, we specifically worked with Google Docs team to ensure their undo worked with the API so this assertion is false.

But if I understood you correctly, you said that it cannot include add and remove undo steps at an arbitrary point in the past? (usecase: #150 (comment) )

Not quite. This would still break semantics of the shared undo stack across documents.

The global undo stack is already broken as it is -- in all of the web apps, because it's global, because changes are added via JS, etc. . As long as contenteditable adds items to this global undo stack, it will be broken. That's what this issue was about. Your undo manager may still be useful for other areas - form filling, textareas, SVG editing, etc, so I'm not suggesting you stop working on it. It's just not the solution for richtext editing.

I figured out how to make sure that both undo and redo are enabled in Chrome and Firefox. It doesn't quite work in Safari, because Safari seems to join several edit operations into a single item in the undo stack, but with a few hours of trial and error, I'm sure JS developers could find a solution there as well:

<!DOCTYPE html>
<html>
<head>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
  // Enable undo and redo menu entries
  var undoEl = document.createElement('div');
  undoEl.setAttribute('contenteditable','true');
  undoEl.innerHTML = "b";
  var undoElText = undoEl.firstChild;
  document.body.appendChild(undoEl);
  var r = document.createRange();
  r.setStart(undoElText, 0);
  r.setEnd(undoElText, 1);
  var s = window.getSelection();
  s.removeAllRanges();
  s.addRange(r);
  document.execCommand('bold');
  document.execCommand('bold');
  document.execCommand('undo');
  document.body.removeChild(undoEl);
});
</script>
</head>
<body>
<div contenteditable="true">
<h1>Title</h1>
<p>Text...</p>
</div>
</body>
</html>

@johanneswilm
Copy link
Contributor Author

johanneswilm commented Sep 27, 2016

Not quite. This would still break semantics of the shared undo stack across documents.

The global undo stack is already broken as it is -- in all of the web apps, because it's global, because changes are added via JS, etc. . As long as contenteditable adds items to this global undo stack, it will be broken.

The other option---and this is what was proposed by Chrome and Edge representatives at the F2F---is to exclude contenteditable from the global history and add a way to enable/disable the undo/redo menu entries so that the editor can receive the corresponding beforeinput event.

That is of course a much cleaner solution as it doesn't interfere with the global undo stack used by other fields. I opened this issue primarily to figure out if there is actually no use for the global undo stack at all. And there I found the draft-js issue which probably needs further investigation.

Now if Safari cannot do what was proposed by the other browser vendors, then we need a solution for that. At this early stage, it maybe enough to find a JS hack to get around the disabled undo/redo menu items. At the next stage, I would think it would make sense to find some less hacky solution, but we can talk about it at that time.

@chaals
Copy link

chaals commented Sep 27, 2016

The problem with not integrating into the global undo stack is that users have historically been given only one stack. And their memory of what they have done doesn't usually distinguish between different input fields.

This is changing, because as Johannes says, editing systems are making a custom undo stack per editable region.

There are also systems that offer more information about what "undo" will actually do - which is good because it isn't often very clear. In particular, it is sometimes very hard to know what can be undone, and what cannot.

It would be good to get telemetry from editor apps as well as browsers on how often, and how far, people actually use undo…

@johanneswilm
Copy link
Contributor Author

johanneswilm commented Sep 27, 2016

The problem with not integrating into the global undo stack is that users have historically been given only one stack. And their memory of what they have done doesn't usually distinguish between different input fields.

True, although we may have to go a while back. Before working on this, I wasn't aware that there was something like a global undo stack as I had only ever had to deal with undo stacks per editable element (an exception being editable elements contained in other editable elements). Maybe we could talk to Google Docs, Office 365, Gmail & others who "voluntarily" chose to switch toward having multiple undo stacks and find out how long time ago they made this decision?

There are also systems that offer more information about what "undo" will actually do - which is good because it isn't often very clear. In particular, it is sometimes very hard to know what can be undone, and what cannot.

This is also where assistant technologies come in? Do we have a description ok what exactly they need? For example: do they need a written description and possibly type for the next possible undo or redo step, or do they need to go even further back?

It would be good to get telemetry from editor apps as well as browsers on how often, and how far, people actually use undo…

I think we have already taken one step in the right direction: focusing on editing apps and their developers. Going all the way to the end user would make the process of figuring out what we need to provide even more perfect. But it may not be without problems.

I wonder what type of data actually exists on this. The first post here is a result of me sending out a simple one-question survey to the various editor apps. Additionally, I looked at the source code or tried the app in the case of the editor apps where I couldn't get a response or didn't know who to contact.

Maybe we should design a more complex survey which also includes questions about their end users and how much they know about them. They may not be willing to share much more than their final conclusion though, given that they are competing with oneanother.

Of course, with every new survey there is the chance that people don't bother answering us.

@johanneswilm
Copy link
Contributor Author

I just tried iCloud Pages on Safari/Mac OS X, and it also maintains different undo stacks for each input window (font size, comment, main doc). The browser's redo/undo menu entries are not working (same as Google Docs and Ms Office 365). Instead it provides undo/redo buttons in the apps UI that switch whenever the user switches from one input box to the next.

@rniwa I'm trying to understand Apple's overall UX policy in this area. Is the rule you mention about having one global undo stack something that only applies for pages where the editor is not the main element? Wouldn't it be good to provide menu entries that would allow iCloud Pages to function as it does now, but with working Undo/Redo buttons? It Apple's policy requires having one global undo stack on some types of pages, should we maybe look for a solution that allows for both a global undo stack and one that has separate undo stacks?

@rniwa
Copy link
Contributor

rniwa commented Sep 27, 2016

Wouldn't it be good to provide menu entries that would allow iCloud Pages to function as it does now, but with working Undo/Redo buttons? It Apple's policy requires having one global undo stack on some types of pages, should we maybe look for a solution that allows for both a global undo stack and one that has separate undo stacks?

Right, this is likely to be implementation-dependent behavior like focus and selection. The key here is to allow browser vendors to implement either behavior and let web authors choose which behaviors they want. This is why the old undo manager API had undoscope attribute.

The only problem with the old API was that being able to add a new undoscope via a content attribute made things way too complicated for implementors. I think a better solution would be adding a flag on ShadowRoot. Since builtin text fields are modeled like they have their own shadow root, any UA that uses a separate undo stack per text field (e.g. Gecko) can be modeled using this way.

@johanneswilm
Copy link
Contributor Author

Right, this is likely to be implementation-dependent behavior like focus and selection.

Implementation as in "webpage app implementation" or as in "UA implementation"? As far as I can tell, all these JS editors on all the platforms, have separate undo stacks for each input field.

We may need to look at that a bit more in details: Some of these apps are "forced" to have a separate undo stack, because the current one is useless. This would be the case for the smaller editors that can be one of several components on a webpage. The other ones "voluntarily" have separate undo stacks. This would be the case of the bigger webapps that fill the entire page with various input boxes which they all all control. They could have created one global undo stack for all their input fields, but instead they chose to have separate undo stacks for each input field - this is the case with the various products of Microsoft, Apple, Google, etc. .

The big question is here: Would there be simple a richtext editor that would prefer the global undo stack, if they could? From their responses, I haven't come across such an editor project, but that doesn't mean they don't exist.

In any case, we should plan for the separate undo stack, because this seems to be the main usecase and defacto standard as of now.

If the undo manager can be adjusted to accommodate for local undo stacks and be implementable -- that's great. The question is then just what the advantage for the web developer would be to use this undo manager. If the web developer can add two "fake" edit operations to an undo stack that is local to just one element, so that the undo/redo buttons are shown, and then intercepts all edit operations with beforeinput, that should work without contaminating the global undo stack, right?

Personally I wouldn't mind using a built-in undo manager. But as soon as it restricts me in any way even with a more exotic operation, I would likely away from it rather immediately, at least if there is no perceived advantage with using it.

@rniwa
Copy link
Contributor

rniwa commented Sep 27, 2016

In any case, we should plan for the separate undo stack, because this seems to be the main use case and defacto standard as of now.

We're fine with having that as an option but forcing that on all contenteditable content is definitely not okay for us.

@johanneswilm
Copy link
Contributor Author

In any case, we should plan for the separate undo stack, because this seems to be the main use case and defacto standard as of now.

We're fine with having that as an option but forcing that on all contenteditable content is definitely not okay for us.

Great! Then we are in full agreement.

Then we just need to figure out how to do it in combination with the beforeinput system and the inputTypes undo and redo. Say we simply combine beforeinput with a future undomanager that always for the insertion of arbitrary JS objects to be stored with the undo entry. Undert these circumstances, what kind of data should we get in the beforeinput events for undo and redo? Should we simply get access to the item in the undo stack that would be applied if we don't preventDefault it?

And can we have an intermediate solution until we get the undo manager so that we can ensure that undo and redo always are enabled when we need them to? Or should we just say that JS developers simply need to use a hack as I posted above, in the meantime?

@rniwa
Copy link
Contributor

rniwa commented Sep 28, 2016

Again, the problem here is that there is no intermediate solution for us. We can't arbitrarily enable undo/redo menu item in Safari without having the capability to push/pop undo stack items.

@dmonad
Copy link

dmonad commented Nov 27, 2019

Related to this discussion is maybe https://github.com/jaredreich/pell (11k stars) . Pell is a tiny richtext editor which uses execCommand and native undo functionality. The appeal of pell is that it is well suited for websites that don't really need a fully fledged rich text editor, while providing basic functionality at little cost (1.38 kb).

execCommand is pretty useful at the moment for building tiny editors. Although you can probably write a small script that polyfills it.

@johanneswilm
Copy link
Contributor Author

@tszynalski I added TypeIt to the original post. As for the size, I did a quick check for how big each of the demo sites are compared to your language input for Czech language:

CKEditor 4: 740kb https://ckeditor.com/docs/ckeditor4/latest/examples/basicstyles.html
CKEditor 5: 1.55 MB https://ckeditor.com/docs/ckeditor5/latest/examples/builds/classic-editor.html
TinyMCE: 1.86MB https://www.tiny.cloud/docs/demo/basic-example/
ProseMirror: 312kb https://prosemirror.net/examples/basic/
TypeIt: 340kb https://czech.typeit.org/

It's not an entirely fair comparison as the editors show different things on their basic editor pages and you also need to include advertisement, but I think it does show that you would have some options and that even if execCommand were gone, you could continue with the framework (and without all the bugs that come with using execCommand).

I will close this issue now as the proposal isn;t needed with the undo manager being present, but feel free to continue posting here.

@johanneswilm
Copy link
Contributor Author

@dmonad I am not directly associated with any of the JavaScritp editors out there, but it is my udnerstanding from talking to them that this kind of line of argument "for websites that don't really need a fully fledged rich text editor, while providing basic functionality at little cost" is what they have heard a Billion times before and get quite frustrated about it. The thing is that yes, it's possible to create a tiny editor using execCommand. People are creating hundreds of those every year, and every time they get cool new titles. The problem is that they don't actually work in production and those who actually spend the needed X number of years then have to sit through meetings with potential clients arguing "why is your editor so large? There is this new kid that's just 10% as large and we don't really need a lot of editing anyway. I think you are just old and bulky,m like the Soviet Union." And then that client tries using that library, throws a few developers at it for some months when they notice they cannot use it directly, and after wasting X amount of resources they come back to one of the really working editors anyway. So I mean it's possible that pell is different than the thousands that have been there before it, but chances are that they are not because execCommand continues to be as broken as it always was.

I think the case of TypeIt is slightly different because they don't actually pretend to be a full editor.They are going for one real issue that people switching between different European languages really have, and with some luck, where users don't paste arbitrary content into their editor, users don't try to do a lot of formatting in TypeIt and the receiving editor is able to clean up the html that comes out of TypeIt, I can see how this can work for some users.

@johanneswilm
Copy link
Contributor Author

@dmonad Yeah so I was able to break pell within a few seconds. And in the code I cannot see how this is any different from all the other ones that came before it.

It's fun to write a few letters in a demo, but it breaks immediately once you try to use it for anything real. Imagine the frustration if you type 7 paragraphs in this and then you try to paste just one more sentence that you copied out of an email and the entire thing just blows up.

The fundamentals of this just won't change unless there is some major change in all browsers to execCommand. So no, no reason to start discussing execCommand again over this, is my reaction so far.

@dmonad
Copy link

dmonad commented Nov 27, 2019

@johanneswilm I see how my statement was problematic. You are absolutely right. Using an editor like pell for any serious editor work (copy-past in particular) is pure madness. IMHO execCommand has inherent problems and should be deprecated.

I was more thinking about an alternative for input forms, where you maybe want to support bold, italic, underline. Or use-cases like TypeIt: it is a really nice website and the author apparently put much work into creating a tiny fast website. I see that it is frustrating that editors with input-validation are so large. I have not yet seen an editor with input-validation that is smaller than 40kb (this is the size of TypeIt website, compressed). Although I'm sure it is possible to write a tiny editor with input validation.

I'm not sure if using an editor based on native browser features is the right solution in these cases, but I definitely see why people are compelled to use them. If you do, you should be aware that copy-paste will almost always break the editor content. In the case of TypeIt it is probably an acceptable trade-off.

@johanneswilm
Copy link
Contributor Author

@dmonad Yes, I can see why one would want those. And of course my first attempt at adding an editor was also to throw out all frameworks and just start something small myself. And then a year later I just had to give up. Part of me reiterating over and over that execcommand will cause trouble is trying to stop others from wasting that year.

The thing is that some editors may not need more than say two styles (bold and italic). And so one would think that - hey why not just cook something small up right here? The problem is that even with something so tiny, people will still want to paste from other places and then immediately you start having the issue of arbitrary content.

Or even without pasting anything, try to write a sentence in typeit, then make something bold, italic and underline. Then hit enter in the middle of the bold/italic/underline part. Inspect the dom structure. The second paragraph is in a <div> while the first is not. Then put it back together by hitting backspace. Then inspect the dom structure of that sentence. You'll see that it didn't actually merge the bold/italic/underline back together. And so on and on. In this case it likely will work because the user will need to get the content out via copy and then clean it up in another editor. But it's not something you should be saving. Because yes, we should try to provide tools JS editors can use, but not things that just cause garbage content to be created.

I think the size would not be as important if there were one simple editor package that everyone is using through a CDN, like was the case with jQuery ten years ago. If that was in place, then all these small editors could use that.

@tszynalski
Copy link

@johanneswilm

I'd just like to address some of your comments.

Firstly, my editor is one JS file that is only ~30 KB minified, and that's mostly because of the various extra functionality related to the extensive keyboard shortcut system, continuity between languages, etc.. The execCommand stuff itself takes very few lines of code. TinyMCE is 140 KB minified. So my JS would jump from 30 KB to about 160 KB (I'd still have to add all the custom code that's not in TinyMCE).

The idea of using CDN-hosted files, or files cached across sites, misses the fact that all that JavaScript will still have to be parsed by the browser, extra HTTP requests will have be made (in the case of TinyMCE it's actually several files, at least 3 JS files and 1 CSS file, maybe more). All of that stuff takes time and makes for a slower experience for users, especially mobile users. I should not have to do that just to get bold text in a textbox.

Second, the issue of copy & paste. Yes, you are right. Things look ugly when you try to paste a webpage into TypeIt. But you can press Ctrl+Shift+V to paste unformatted text, which produces cleaner results, and takes care of your "copy one extra sentence from an email" example. Generally, I'm not sure who would expect to paste a webpage into a Web editor and expect good results with regard to formatting. Perhaps I lack imagination...

Also, I noticed that the cleanup performed by TinyMCE doesn't preserve formatting if you copy from MS Word to TinyMCE, then to MS Word again. There goes one potential use case. Similarly, I'm not sure if users can copy from one JS editor to another. When I tried to copy formatted text from Google Docs to TinyMCE, it didn't work. Maybe I'm missing something, but JS editors don't seem that great to me...

Third,

And who is to decide what goes into a mini version? Bold and italic is something probably all can agree on. But I see you also have underline, sup and sub. Then someone else may argue they also need font color, etc. and then very quickly we are back at what we have now.

As with any feature, you have to draw the line somewhere. Of course, the W3C would decide the scope, based on demand. I think the key is to start small. Define something like <textarea type=rich> and allow only a very restrictive subset of HTML. Let's say, whatever formatting is allowed in a Reddit comment. The goal would be to allow faithful copying from one textarea to another, even across browsers.

@johanneswilm
Copy link
Contributor Author

Firstly, my editor is one JS file that is only ~30 KB minified, and that's mostly because of the various extra functionality related to the extensive keyboard shortcut system, continuity between languages, etc..

Right, but the user still needs to download all that other stuff to get to see the page. So it's doesn't really matter if your library is only 40kb if in the end you do require the user to download 300+kb to get access to your site.

Every time the users update their browser (on desktop every 6 weeks), they also need to download some extra bytes of code related to execCommand.

Generally, I'm not sure who would expect to paste a webpage into a Web editor and expect good results with regard to formatting. Perhaps I lack imagination...

Actually, all modern production ready JS editors that are not just a little shim on top of execCommand should deliver decent results. It's not just about a test where one pastes an entire webpage. It's also when you select and copy an email address and accidentally grab a little too much so that you also took in a table cell that surrounded the email without realizing it. Or as I demonstrated above even without any pasting just by hitting "enter" in a paragraph on pure contenteditable in Chrome.

I don't think we should encourage filling the web with more garbage content nor web sites that are not working well - which is what happens if we tell people they should use execCommand-based editors for "simple editors". Note though that I think your case is different because you don't have a save function - that means that the output of your editor will necessarily have to go through a second editor before being saved. For this reason I think you actually found a case that's different from previous cases. Note though that your editor only functions well because other editors do the cleanup that yours does not.

Also, I noticed that the cleanup performed by TinyMCE doesn't preserve formatting if you copy from MS Word to TinyMCE, then to MS Word again. There goes one potential use case.

That's right, it will always require white listing and for the editor to actually grasp what they are dealing with. You cannot just let the browser throw anything in, but you have to write filters that interprete the incoming text.

As with any feature, you have to draw the line somewhere. Of course, the W3C would decide the scope, based on demand. I think the key is to start small. Define something like <textarea type=rich> and allow only a very restrictive subset of HTML. Let's say, whatever formatting is allowed in a Reddit comment. The goal would be to allow faithful copying from one textarea to another, even across browsers.

See the thing is that I have been at this for around 5-6 years. Others have been at it for a decade before that. It's just not that simple, and so we gave up on trying to standardize the exact dom manipulations that come out of execCommand a long time ago.

I think that your usecase is one in which execCommand isn't overly problematic if your users don't accidentally paste something in there that breaks it. But besides a minor improvement in download speed, I don't really see any advantage for you either going that route.

Altogether, I don't think it's a usecase that by itself justifies us spending maybe a decade or two trying to standardize and fix the dom manipulation aspect of browser's native contenteditable implementations + execCommand. That will likely also turn into an increase in browser download size so the advantage of your site being 330kb rather than say 600 kb is not really an improvement for the users anyway.

@johanneswilm
Copy link
Contributor Author

@tszynalski just FYI - this is how it's handled in the word processor I am working on: There is a walker that goes through the document structure and tries to figure out what is what. If it can sniff the source of the content, it uses that information to get better formatting [1]. I am not saying this is how everyone should do it, but it's one safe way you can use to get the best possible import if paste import from word processors are a priority for you. I have previously suggested that one come up with something like a data interchange format (simplified HTML) for richtext that is put onto the clipboard as one of the alternatives to make it easier to move content between various editors. The comments that I received was that this that is probably a good idea, but it's not really something for the W3C to deal with. I agree, but I don't really know which other organization would be better suited either. Maybe some day there will be a series of meetings between major text editors where this topic could be placed. Until such time, I think here in this Editing Taskforce we should prioritize safety over exactness of style conversions.

[1] https://github.com/fiduswriter/fiduswriter/tree/master/fiduswriter/document/static/js/modules/editor/clipboard/paste

@tszynalski
Copy link

Firstly, my editor is one JS file that is only ~30 KB minified, and that's mostly because of the various extra functionality related to the extensive keyboard shortcut system, continuity between languages, etc..

Right, but the user still needs to download all that other stuff to get to see the page. So it's doesn't really matter if your library is only 40kb if in the end you do require the user to download 300+kb to get access to your site.

The minimum payload is about 80 KB (after compression), though it will depend on the ad that gets loaded. If the user has disabled ads, it's about 40 KB compressed. I am assuming that the user will have the Google ad scripts cached.
You also seem to have missed my comments about the time spent parsing and executing all that complex editor code.

Every time the users update their browser (on desktop every 6 weeks), they also need to download some extra bytes of code related to execCommand.

A specious argument. Updating your browser is not an activity where responsiveness is important, unlike navigating between web pages.

Generally, I'm not sure who would expect to paste a webpage into a Web editor and expect good results with regard to formatting. Perhaps I lack imagination...

Actually, all modern production ready JS editors that are not just a little shim on top of execCommand should deliver decent results. It's not just about a test where one pastes an entire webpage. It's also when you select and copy an email address and accidentally grab a little too much so that you also took in a table cell that surrounded the email without realizing it.

Out of curiosity, I just tried to grab a table cell with an email address from a webpage, and paste it into TinyMCE. It created a table, just like contenteditable.

Or as I demonstrated above even without any pasting just by hitting "enter" in a paragraph on pure contenteditable in Chrome.

Hmmm... that doesn't affect the functionality and if you're concerned about how the HTML looks, you can always renormalize the HTML -- if there are two adjacent <b> tags, merge them.

I don't think we should encourage filling the web with more garbage content nor web sites that are not working well - which is what happens if we tell people they should use execCommand-based editors for "simple editors".

Assuming the "simple editor" does not generate its own markup, but relies exclusively on execCommand, are there any serious problems?

Note though that your editor only functions well because other editors do the cleanup that yours does not.

It seems to work fine when I copy some formatted text from my editor opened in Firefox to my editor opened in Chrome.

As with any feature, you have to draw the line somewhere. Of course, the W3C would decide the scope, based on demand. I think the key is to start small. Define something like <textarea type=rich> and allow only a very restrictive subset of HTML. Let's say, whatever formatting is allowed in a Reddit comment. The goal would be to allow faithful copying from one textarea to another, even across browsers.

See the thing is that I have been at this for around 5-6 years. Others have been at it for a decade before that. It's just not that simple, and so we gave up on trying to standardize the exact dom manipulations that come out of execCommand a long time ago.

Maybe you don't need to standardize the caret/selection operations. It's okay if the widget behaves slightly differently across browsers with respect to things like which parts of nodes get selected when I change the selection. Every editor app works a little differently anyway. (In fact I think it's humanly impossible for two teams to write two text editors that behave identically. Too complex.) Just make sure the HTML output can be understood by another browser. But perhaps it already works all right in that respect?

I think that your usecase is one in which execCommand isn't overly problematic if your users don't accidentally paste something in there that breaks it. But besides a minor improvement in download speed, I don't really see any advantage for you either going that route.

OK, so you think it's a minor speed difference, but what would be the advantage of going with an external JS editor? What exactly does TinyMCE do better than bare contenteditable?

@johanneswilm
Copy link
Contributor Author

Out of curiosity, I just tried to grab a table cell with an email address from a webpage, and paste it into TinyMCE. It created a table, just like contenteditable.

Sure, if your editor has tables whitelisted and grab enough of a table it will paste a table. The difference to your editor is that it can then guarantee that it can handle that table correctly and the user will not her/himself in a situation where a pasted table somehow breaks the rest of the editing experience.

Assuming the "simple editor" does not generate its own markup, but relies exclusively on execCommand, are there any serious problems?

Yes, there a lot of problems. The structure of the html being strange is just the beginning. And you cannot actually just renormalize everything without understanding the semantic meaning of the content. You can have spans that have completely different meanings.

What exactly does TinyMCE do better than bare contenteditable?

I skipped the other points, because I think this is the most important bit. See I think that is the problem I tried to refer to above that TinymCE, CKEditor, ProseMirror and other production ready editors find themselves in: For a group of executives of a company that sets up their website who spend 5 minutes typing a few words on the keyboard they seem all the same. It's first when they have real users in production mode and they actually rely on the thing not messing up your formatting or eat user content that they notice it makes a difference.

In your case your users don't have to sign up, so you don't communicate with them and you don't actually know whether your users run into any issues, right? See if you do look at those issues and try to fix them, my prediction is that you'll quickly run into the contenteditable trap that so many of us have experienced before. I defer to this very nice blog post from Piotr (CKEditor): https://ckeditor.com/blog/ContentEditable-The-Good-the-Bad-and-the-Ugly/ There are more links in there.

@waterplea
Copy link

This arguing is heading to the Land of Pointless. I have a contenteditable with a few buttons, a reply input. I want user to be able to press Ctrl+B to make text bold or click a button if he doesn't know the hotkey. I just clean all dropped and pasted content to text only. I live my happy little life. Please don't remove browser native functionality being there for ages just because Google Docs behemoth requires a bit more to work properly.

@johanneswilm
Copy link
Contributor Author

Please don't remove browser native functionality being there for ages

@waterplea As mentioned above, noone is proposing removing anything at this stage.

I live my happy little life.

Yeah this is actually an argument FOR removing it or at least throwing warning messages in the development console if you do create an editor based on execCommand. If a careless developer just quickly throws together an editor, not noticing how broken it is in real-life usage, then that is worsening the experience of regular people using the web. A regular user should not have to wonder whether or not their content might get destroyed when they use a simple functionality like "paste" an a random web page.

This is not about Google Docs and other large efforts - there are now several relatively open source libraries out there that allow also those running small websites to include a custom richtext editor.

@tszynalski
Copy link

Out of curiosity, I just tried to grab a table cell with an email address from a webpage, and paste it into TinyMCE. It created a table, just like contenteditable.

Sure, if your editor has tables whitelisted and grab enough of a table it will paste a table. The difference to your editor is that it can then guarantee that it can handle that table correctly and the user will not her/himself in a situation where a pasted table somehow breaks the rest of the editing experience.

Your optimism is endearing. I, on the other hand, have near-zero expectation that TinyMCE (or any other JS editor) will handle any table I paste into it without weird editing behavior. Not even Word, after decades of development, handles tables 100% correctly. Just for kicks, I tried adding a table in TinyMCE (using the built-in feature, I didn't even have to paste anything), and after 30 seconds, I already ran into an issue where I had an empty paragraph above the table that was undeletable.
So I ask you, in the interest of everyone concerned, to revise your rosy picture of JS editors.

It's first when they have real users in production mode and they actually rely on the thing not messing up your formatting or eat user content that they notice it makes a difference.

Every rich text editor I've used has some quirks. For example, in TinyMCE, when you press Backspace here: text <a href="ddd">e</a>|, the result will be text| (why did it "eat" the space after "text"?). And the markup it generates is much uglier than contenteditable (perhaps it is customizable, I haven't checked). Tons of housekeeping attributes on elements, dummy <br> elements...

Generally, based on my 30+ years of experience using various text editors, I do not expect them to behave predictably during certain operations, such as deleting the last character of a link (will it preserve the link formatting despite the fact that no characters are left?) or whether the caret is (in the "mind" of the editor) inside or outside some formatted block. I simply avoid those "borderline" operations if I can, and when I have to do them, I brace myself for the pain of having to redo some small part of my work because the editor just won't let me do the exact selection I need. I suspect other users have similar "coping" mechanisms. Furthermore, nobody with any experience expects MS Word to behave the same as Thunderbird or GMail or TinyMCE. That's just the reality we live in. The fact that execCommand has its own quirks is hardly a deal-breaker.

I defer to this very nice blog post from Piotr (CKEditor): https://ckeditor.com/blog/ContentEditable-The-Good-the-Bad-and-the-Ugly/ There are more links in there.

First off, thank you for the link. I spent over an hour carefully reading Piotr Koszuliński's blog post, as well as several related resources that I found thanks to it, e.g. Fixing Contenteditable, Why ContentEditable is Terrible and this public-webapps post from Piotr. That last post actually has a more comprehensive list of problems with contentEditable than the blog post.

The picture I get is the following:

  • There are a lot of complaints about the fact that contenteditable generates "ugly" markup and that you cannot control whether you get <b> or <strong>, etc. Let me play devil's advocate here and ask, why should you care about the underlying markup? When you write a document in Word, the editor has some internal representation of the text. Do you worry about whether this internal representation is pretty? OK, the markup may matter in some interop scenarios, or when you want to allow the user to edit the HTML source (although mixing manual edits with WYSIWYG has never worked well), but what percent of usage is that?
  • Another set of frequently mentioned issues concerns poor handling of editing operations on "advanced" elements like tables, images. These are complex things and I would support removing them from contentEditable altogether (for example, by enforcing a restricted set of markup, as I described in my <textarea type=rich> idea).

Other than these, I don't see any huge problems with contentEditable. Some of the issues PK writes about have actually been fixed since the time of writing. For example, 2 out of these 4 issues (related to backspace handling) no longer exist. I am not saying it works perfectly. For example, I have discovered that when you press Backspace here: text| <a href="ddd">eee</a>, the result will be tex&nbsp;<a href="ddd">eee</a> (where did the nbsp come from?).

To sum up my current thinking on the issue:

  • "Bare" contentEditable with execCommand quite possibly works "well enough" for simple editing, so long as you don't care whether the generated HTML looks pretty, whether paragraphs are done with <p> or <div>, etc. You keep calling it "broken", but maybe this is because you have this perspective of a JS editor developer (which I sympathize with, but it's not the only perspective).
  • For most users, ensuring the ability to copy & paste between different rich textboxes will be more important than the "purity" of the HTML. Therefore, a harmonized set of markup across browsers (e.g. <b> for bold) may be more important than the freedom of editor developers to micromanage the DOM.
  • Advanced JS editors like TinyMCE have their own share of issues, so outsourcing the editing tasks to external JS dependencies is no silver bullet. In fact, all text editors I have ever used (incuding multi-million dollar products) have issues that could be described as "messing up the formatting", and behave inconsistently. So I would argue that your opinion of 3rd party libs is too high (and by comparison, you judge execCommand too harshly).
  • Even if execCommand was really bad, and external JS editors really good, the whole idea of dropping native rich text editing from W3C specs and instead forcing everyone to rely on third-party libraries goes against the general philosophy of including more and more useful stuff in the browser. This philosophy is why we get new HTML5 and CSS features all the time. A rich-text textbox is a perfectly reasonable input type to have, and the fact that so many sites have to rely on Markdown in 2019 is mindboggling. Considering your position as a W3C editor, reading your comments is a little like listening to the Minister of Health argue in favor of selling off all the hospitals, because only the private sector is smart enough to work out all the issues. :)

@johanneswilm
Copy link
Contributor Author

Just for kicks, I tried adding a table in TinyMCE (using the built-in feature, I didn't even have to paste anything), and after 30 seconds, I already ran into an issue where I had an empty paragraph above the table that was undeletable.
So I ask you, in the interest of everyone concerned, to revise your rosy picture of JS editors.

Could you give reproduceable steps as to how to get to that state?

As every other JavaScript developer, I do not personally use all the professional JavaScript editors out there. But in order for me to really be able to represent the views of JavaScript editors in general, I do not just focus on the editing framework I use myself at this moment.

For that reason also, I am not an expert on every possible bug in every software out there.

Of course there are also bugs in all of the editing frameworks out there, just as there are bugs in all known software, and if you found a new one I encourage you to file a bug about it. But that doesn't put all editors on an equal footing. If you found a bug in a JavaScript framework with an active team behind it, there is someone you can report bugs to with a real interest in getting them fixed.

On the other hand, if you file a bug on the browsers relating to contenteditable, there is a good chance they will not be touched for a decade or longer. I say that as someone who has filed bugs against browsers years ago who would very much like for browsers to get that interest, and who has been traveling to W3C editing taskforce meetings on different continents for several years to try to get more interest in browser makers in editing to at least fix those bugs that JavaScript frameworks cannot work around. But I also understand that their priorities are elsewhere. So the best I think we can hope for is access to those primitives that JS frameworks need to provide editors that are on par with native apps. Then, maybe another 15-30 years down the line when the frameworks really have evolved a lot and do not change that much any more, maybe we see one that is really dominating the field and is close to bug free, and then that can be turned into a web standard of its own and translated to C++ to be bundled with all the browsers.

Even if execCommand was really bad, and external JS editors really good, the whole idea of dropping native rich text editing from W3C specs and instead forcing everyone to rely on third-party libraries goes against the general philosophy of including more and more useful stuff in the browser.

That's actually not the ruling philosophy by browser makers as of today in my experience. They have actually removed several ambitions efforts that were to enter the browsers (such as MathML or CSS Regions) and have delegated the responsibility for this to JavaScript libraries (and going forward likely wasm in some cases). And it's actually oftentimes difficult to argue why contenteditable should be worth their time at all, given the relatively low percentage of pages that contain contenteditable. Have you seen the extensible web manifesto? It's the access to primitives that that is advocating that we have been working on here over the past few years.

@johanneswilm
Copy link
Contributor Author

johanneswilm commented Dec 2, 2019

You keep calling it "broken", but maybe this is because you have this perspective of a JS editor developer (which I sympathize with, but it's not the only perspective).

I wish I were. I tried, like you, to build my own editor on top of contenteditable several years ago. That was the first few years of Fidus Writer. I spent every awake moment fixing bugs until I finally gave up trying to create both an editing framework and a working editor (with export to various formats, document management, etc.) at the same time and switched to an editing framework for the document manipulation part.

But I try as much as possible not just to represent the interests of that particular framework, and I communicate with other frameworks and individual, production level editors before and after W3C meetings to make sure their voices get heard.

For most users, ensuring the ability to copy & paste between different rich textboxes will be more important than the "purity" of the HTML. Therefore, a harmonized set of markup across browsers (e.g. <b> for bold) may be more important than the freedom of editor developers to micromanage the DOM.

I disagree. About 10-15 years ago that's what everyone did. The result then was that people would write blog posts in various word processors and pasted it into the JavaScript text editor of their platform (for example Joomla). The result would be a horrible mishmash of differently styles and noone really wants that, which is why CKEditor, TinyMCE & co improved over time.

Look, noone can stop you from creating a broken web experience. We are doing all we can to warn you against doing that, and to learn from the experiences of the web, but in the end you an still create an editor that behaves as broken as what was common in 2005 and noone will stop you from doing so. In another project someone even argued for using old browsers on old computers and to only program for that usecase because that person thought there are no advantages to using newer machines, and it is entirely legal to think and do that. For now the browser makers' view is that execCommand and contenteditable is used in so many old web sites that it will not be removable for decades to come. So you should be fine.

@johanneswilm
Copy link
Contributor Author

@tszynalski : Now I actually had time to try out TinyMCE and look at the bugs you thought you had found:

after 30 seconds, I already ran into an issue where I had an empty paragraph above the table that was undeletable.

That's actually a feature in many JS editors. When I had more framework-less editor I also did that (guarantee that there is always a paragraph before, after and in-between tables). The point of that is that otherwise it is impossible to get the caret to move to some places around tables. Other editing frameworks deal with that differently - for example the framework can draw a sideway caret if it otherwise is in a place that it would be impossible to reach. I think it's one of those examples where it's a good idea to let different editors experiment with different solutions and then eventually one of those solutions will likely be what wins because it seems most intuitive to users. And then everyone adopts that.

For example, in TinyMCE, when you press Backspace here: text <a href="ddd">e</a>|, the result will be text| (why did it "eat" the space after "text"?).

That's another feature. If you do what you describe but with a linked word that is a bit longer, it will first highlight the entire word and then delete the word letter by letter. Once the last letter of the link has been deleted, it also deleted the space after it because otherwise there would either be two spaces or one space and then a period or comma or whatever comes after it, which most likely is not what you want.

And the markup it generates is much uglier than contenteditable (perhaps it is customizable, I haven't checked). Tons of housekeeping attributes on elements, dummy <br> elements...

I am in no way a TinyMCE expert, but you do realize that it differentiates between the HTML that it maintains in the DOM during editing and the HTML it outputs as final output, right? (You get the output by means of a method [1]). The reason for this difference in many editors is that it needs one HTML to maintain certain information in the editor and also to get the caret to move in one specific way, but then it doesn't want or need all that when it exports the HTML.

[1] https://www.tiny.cloud/docs/api/tinymce.html/tinymce.html.writer/#getcontent

@tszynalski
Copy link

That's actually not the ruling philosophy by browser makers as of today in my experience. They have actually removed several ambitions efforts that were to enter the browsers (such as MathML or CSS Regions) and have delegated the responsibility for this to JavaScript libraries (and going forward likely wasm in some cases). And it's actually oftentimes difficult to argue why contenteditable should be worth their time at all

Well, you probably know more than me about the current thinking among browser devs, but I am genuinely surprised to see you dismiss the importance of having a native HTML textbox with basic formatting when almost every forum/blog software out there has support for formattable comments. How can you compare an essential feature like that to niche proposals like MathML or CSS Regions?

Contenteditable may not be very popular (I take your word for it), but I would argue that's because it tries to do too much (and does a mediocre job of it). It's just not a great match if you're writing a comment feature (how do you prevent people from pasting some tag soup in?). But if you reduced the scope and allowed authors to customize what tags are allowed, it could replace Markdown. Browser devs might also be more interested if the scope was less daunting. You really see no problem with the fact that we have to do ** for bold in 2019?

You keep calling it "broken", but maybe this is because you have this perspective of a JS editor developer (which I sympathize with, but it's not the only perspective).

I wish I were. I tried, like you, to build my own editor on top of contenteditable several years ago. That was the first few years of Fidus Writer. I spent every awake moment fixing bugs until I finally gave up trying to create both an editing framework and a working editor (with export to various formats, document management, etc.) at the same time and switched to an editing framework for the document manipulation part.

You say "I wish I were", and then you write a whole paragraph confirming that you do in fact take the perspective of a JS editor developer :) Whereas I am talking about someone who just wants a basic rich text widget.

For most users, ensuring the ability to copy & paste between different rich textboxes will be more important than the "purity" of the HTML. Therefore, a harmonized set of markup across browsers (e.g. <b> for bold) may be more important than the freedom of editor developers to micromanage the DOM.

I disagree. About 10-15 years ago that's what everyone did. The result then was that people would write blog posts in various word processors and pasted it into the JavaScript text editor of their platform (for example Joomla). The result would be a horrible mishmash of differently styles and noone really wants that, which is why CKEditor, TinyMCE & co improved over time.

I'm not sure what you mean by "That's what everyone did" (What did they do? Harmonize markup across browsers?), but copying from word processors is not relevant here. That's probably a lost cause (you think TinyMCE will preserve my Word formatting perfectly?). I'm talking about copying formatted text from one Web textbox to another (possibly across browsers).

I want the ability to copy & paste between different native textboxes while preserving the formatting. That's why I'm talking about standardizing that <b> means bold in a rich textbox. I suppose you want formatting to get mangled when the user copies from CKEditor to TinyMCE and then back to CKEditor. Because that's what you'll get if you allow each editor to have its own markup conventions.

Again, I am not against opening up primitives -- FidusWriter seems like a prime example of an advanced project that could benefit from low-level access.

Look, no one can stop you from creating a broken web experience.

I would be more worried if you actually provided some examples of serious contenteditable bugs other than "it doesn't generate the tags I want", "it doesn't play well with direct DOM manipulation", "it has no ability to edit tables/images" or "it breaks when you paste from Word". As it stands, I don't see it as being significantly worse than editors in many applications I use everyday. I'd be happy to change my mind! It's quite possible I'm missing something.

@johanneswilm
Copy link
Contributor Author

How can you compare an essential feature like that to niche proposals like MathML or CSS Regions?

I am arguing all the time that it really is important. And that although the percentage of websites using contenteditable may be low, almost all content on the web has gone through contenteditable as part of the production process.

That being said, it's apparently not important enough for browser makers to where they employ and entirely "department of contenteditable" which would be needed if it is really should solve all the issues there are.

Contenteditable may not be very popular (I take your word for it), but I would argue that's because it tries to do too much (and does a mediocre job of it).

Yeah, so kind of. Raw contenteditable is not used much. But contenteditable + a ton of JavaScript is used in just about all editors because for some things there is no way around contenteditable.

And yes, so given the situation: understaffing at all browser makers, other groups that are interested, we have tried to come up with a sort of slimmer contenteditable that doesn't do things that are surprising to JavaScript developers and that they therefore more easily can write a working editor on top of. You can see the proposals of a contenteditable="typing", etc. in our draft spec. The idea was initially to combine that with beforeinput events to make it quite straightforward to create an editor. Unfortunately for various reasons Chrome decided last minute that beforeinput was not going to work well for them due to some Android issues. So they implemented "Input Events, level 1", which is basically half of what is needed. That was two years ago. This year there is a new proposal "EditContext" which hopefully develops into a replacement for that. Let's see where it is heading...

But if you reduced the scope and allowed authors to customize what tags are allowed, it could replace Markdown. Browser devs might also be more interested if the scope was less daunting. You really see no problem with the fact that we have to do ** for bold in 2019?

I actually don't think the issue here is that it's too difficult to make a richtext comment form editor. I think on sites that are for less techy people that's what is done. On github they have this markdown editor---I am guessing---because they found out that tech people prefer being able to type the entire thing rather than interrupt their typing to click on a bold-button.

I want the ability to copy & paste between different native textboxes while preserving the formatting.
...
I suppose you want formatting to get mangled when the user copies from CKEditor to TinyMCE and then back to CKEditor. Because that's what you'll get if you allow each editor to have its own markup conventions.

Yeah so one case that I thought was really relevant for what you are saying is text that is being copied from Google Docs to Wordpress. At least before Gutenberg it got mangled and had to be cleaned up manually. Simple paragraphs would get double line breaks between themselves once in Wordpress. I thought it was a good example because this exact copy operation between these two software packages must be something millions of users must be doing every day, yet it wasn't just working. So for that exact purpose I would have liked to have some kind of standardization. But after talking to the browser developers I realized that that is not something they wanted to be part of - this would have to be something the two JavaScript developer teams would have to standardize. I am not heman and my time on this planet is somewhat limited so I don't have plans for setting such a standardization up, but I agree 100% that it would be a good idea to have such a standardization to be used for copy/paste between different text editors. If someone else organizes it, I'll be happy to participate.

So to go back to your point:

I want the ability to copy & paste between different native textboxes while preserving the formatting.

In around 2005 it was apparently the common thinking that preserving style should be the top 1 priority. Preserving styles is still important, but it seems it has now switched to where one wants the style to fit in with other texts on the target end. Imagine github had a raw contenteditable commenting system here and each one of us would be using a different service like typeit to write our answers and then paste it in here and so the flow of comments ends up being a mix where I write in Times New Roman, blue 32pt, and you in some Caligraph font, grey, 8pt. Even though the style was preserved for each comment perfectly, the end result is undesirable in most cases.

I would be more worried if you actually provided some examples of serious contenteditable bugs

Well, just look for it in your favorite search engine and you will find all kinds of issues with it. I already explained how I could break your editor within a few seconds, but there are many other examples out there.

@waterplea
Copy link

There's no need to preserve styles, just semantics. What execCommand and raw contenteditable and hotkey actually do just fine. Bold, italic, underline. Firefox has image resize, I believe — the only functionality missing from contenteditable in Chrome to make it serviceable for what 90% of the users use it, without fancy tables and copying stuff from Word with it's broken internal layout. Speaking of Guttenberg, Medium and many other block editors — they also don't need any of that. They have dedicated table blocks while actual text styles are limited to basic semantics. Because of those awesome JS editors with fake caret and whatnot I was unable to move by word with Ctrl + Arrow keys for a month on my WordPress blog until they fixed it. Contenteditable works just fine for rich text. Just clean format on drop/paste and don't over overcomplicate your stuff. I hear you, @tszynalski

@johanneswilm
Copy link
Contributor Author

johanneswilm commented Dec 9, 2019 via email

@tszynalski
Copy link

I actually don't think the issue here is that it's too difficult to make a richtext comment form editor.

It's harder than it should be, because contenteditable is too permissive. If you want to save formatted comments in a backend, you have to clean up and sanitize the markup yourself (you don't want a tag soup in your database). Instead, I would argue the browser should support a textbox with a strictly defined set of markup.

I think on sites that are for less techy people that's what is done.

Yes, on techie sites Markdown is probably a better fit. But Markdown is also used on non-techie sites*, which I think is due to technical problems with contenteditable. Of course I cannot prove it, but I think if we had a <textarea type=rich>, many non-techie sites would use it.

*) For example, the classic UI of Reddit uses Markdown for comments. So does Trello. Here's Trello CEO saying it was probably a mistake to go with Markdown.

@johanneswilm
Copy link
Contributor Author

@tszynalski I agree that it would be nice to have something like a very simple richtext editor bundled with browsers as long as we can agree that it's not just something that can be done by 3 devs doing a handful of small adjustments to contenteditable that can be done within a weekend long hackathon. Some serious time would have to be dedicated to this, and it will have to offer much less than what contenteditable currently promises to offer and isn't quite able to deliver.

I don't know if browser makers will be up for doing something like that any time in the near future, but it could be put up as a proposal as something that could be of interest to end users at a an editing taskforce meetings where also browser devs will attend to make them aware of this wish and to hear from them how realistic it would be for them to implement it. Feel free to start write a draft spec that could be presented at such a meeting. I'll try to contribute. Maybe one way to help convince them would be to create a JavaScript polyfill for such an element that could be shipped with any browser until that browser manages to implement the element in native code.

Still that's no guarantee that they will be interested. They may just say that they prefer for end users to use JavaScript editors until around 2030/40 or so, and only once one of them really dominates then implement that one into native browser code.

@mikkorantalainen
Copy link

Why this issue has state "closed"? I couldn't see any rationale for closing this issue in the history of the issue.

@johanneswilm
Copy link
Contributor Author

I wrote:

I will close this issue now as the proposal isn;t needed with the undo manager being present, but feel free to continue posting here.

At that time that no browser maker was against that alternative solution to the same problem. Since then, I don't think much gas happened with the undo manager. We can reopen if we want to discuss this again.

@johanneswilm johanneswilm reopened this May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants