guardian / scribe

DEPRECATED: A rich text editor framework for the web platform
http://guardian.github.io/scribe/
Apache License 2.0
3.5k stars 245 forks source link

contenteditable="false" behavior #411

Open webdesserts opened 9 years ago

webdesserts commented 9 years ago

We're trying to use scribe to produce editable templates for our users that contain "variables" that can be automatically populated with data from our database. We originally tried ckeditor to achieve this and were able to do so by adding contenteditable="false" to a span with data attributes attached.

When I attempt to create a span with contenteditable="false" while using scribe the behavior isn't quite what I would expect. Here's a clip of what I'm seeing:

scribe-contenteditable-bug

There's three issues to note here:

  1. After inserting an uneditable span with the inserthtml command, it seems that the cursor is placed inside the span (in the video I try to hit space multiple times immediately after inserting with no effect).
  2. When trying to select an uneditable span the cursor always moves one extra character past the span.
  3. When I attempt to delete anything in the editor, the span is removed (but not its content), it doesn't matter where the cursor is placed. (this seems like a formatting cleanup issue?)

I could see how cursor placement could be my responsibility as a plugin editor, but the other two definitely seem like abnormal behavior.

I'm not quite sure on your stance on nested contenteditable regions. It seems you've done some fixes, but they seem specific to block elements. Is this something I could fix myself or is this a bug within scribe?

Thanks!


Here's the content of that variable plugin:

  var command = new scribe.api.Command('insertHTML');

  command.execute = function (value) {
    scribe.api.Command.prototype.execute.call( this, '<span contenteditable="false">variable</span>')
  }

  scribe.commands['variable'] = command

contenteditable="false" Inconsistencies and Bugs

There are apparently more bugs out there than the ones listed above. I've started collecting them here for reference sake.

Browser Behavior

testing environment

  1. When attempting to insert an uneditable element with inserthtml, the span is removed. Strangely enough if you undo that insert. the span will be placed intact at the end of the editable content. [Chrome, Safari]
  2. When inserting a contenteditable="false" span through the inserthtml command, the cursor is placed inside the uneditable region and the user is unable to make changes until they click elsewhere in the editor. [Firefox, can't confirm in other browsers due to issue 1]
  3. When attempting to select a variable with Shift + {arrow key} the cursor will always select 1 extra character to the right or left of the uneditable element. [Firefox]
  4. When multiple uneditable elements are next to each other, you can not use the arrow keys to jump in between them. see this SO question [Chrome]
  5. The cursor sometimes disappears when next to an uneditable span. [Firefox, Chrome]
  6. An uneditable element cannot be deleted using backspace unless it is first selected. /via @robinedman bugzilla [Firefox]

    Scribe Specific Behavior

testing environment

  1. Scribe will delete any span with contenteditable="false" when backspace is pressed anywhere within a scribe editable element.
webdesserts commented 9 years ago

Here's the default behavior without scribe Seems that issue 2 still exists, and again, issue 1 is probably just an issue with cursor placement. Issue 3 (which is the main problem) does not exist normally.

hmgibson23 commented 9 years ago

We've had a lot of issues with caret placement, maybe @cutandpastey and @redman can elaborate.

robinedman commented 9 years ago

Have you tried whether this works in a plain contenteditable in Firefox? (See https://bugzilla.mozilla.org/show_bug.cgi?id=685445).

If this doesn't work consistently across browsers the best approach might be to create a Scribe patch that implements the expected behaviour.

We've implemented our own caret positioning in scribe-plugin-noting. The basic approach is to make use of zero width spaces to be able to place the caret where you want (since Chrome normalises the cursor position), do anything you need to do (such as delete the contents of a span), then clean up after yourself.

webdesserts commented 9 years ago

Ok, just a quick run through testing out that jsbin in different browsers:

Firefox seems to be the main offender of issue 2, Chrome and Safari act fine. Also @robinedman, I took a look at it, and yes, that bug apparently still persists in Firefox. I don't have a means to test IE or mobile at the moment (our app is more of a desktop app so we don't develop for either). Chrome and Safari have another problem that I missed (with scribe) where the span is removed before the html is inserted.

scribe-contenteditable-chrome-bug

I'm going to create another jsbin with the scribe stuff for testing purposes and record any inconsistencies I find up top.

webdesserts commented 9 years ago

@robinedman also, thanks for pointing out the noting plugin. Since scribe's docs, and especially contenteditable's docs, still haven't been fleshed out, examples help tremendiously.

bradvogel commented 9 years ago

Try using an iframe instead, e.g. <iframe srcdoc="variable"></iframe>

webdesserts commented 9 years ago

@bradvogel the iframes do have something closer to the behavior I'm looking for though I will say I don't think we'd be too excited about the idea of scattering 20+ iframes across our document for single word spans (though I guess it's better than nothing).

Btw, we were able to accomplish this in Ckeditor with their widgets it looks like they might have some of their own patches on top of contenteditable="false" that they used for the widget plugin.

webdesserts commented 9 years ago

<input type="button" value="variable" /> is actually acting a bit closer to what I'm looking for without having to resort to iframes. We would just maybe have to fix some carret placement. I am having a problem with scribe preventing us from inserting an input, whereas input insertion works normally with a normal contenteditable. Any idea what might be causing scribe to prevent this?

robinedman commented 9 years ago

I suspect it's scribe-plugin-sanitizer getting in the way. You could try disabling it to see if that's the case.

The sanitizer plugin uses HtmlJanitor which has whitelists of allowed elements. You might want to add BUTTON as an allowed tag there or potentially in the sanitizer plugin itself.

rrees commented 9 years ago

You can embed a contenteditable="false" inside a contenteditable="true"?

rrees commented 9 years ago

@robinedman @webdesserts I'm not sure the sanitizer is a default plugin, could you point us towards an example page or share the config you're trying to use?

webdesserts commented 9 years ago

@robinedman @rees I figured it out, it was an issue with my jsbin, not scribe, so it's just the weird behavior with firefox caret placement.

webdesserts commented 9 years ago

So we went and did some research into which weird elements worked best for our purposes. We're going to try out using an input[type=text,disabled] because it's probably the least horrible of the available solutions where we didn't need to patch too many things. Thought y'all might find some use in the data we collected if you ever wanted to support weird elements within scribe, so here's our notes.

note: this is all tested with scribe. so I'm not sure how scribe affects any of these interactions

timmyg commented 8 years ago

@webdesserts do you have a demo of the implementation of the "add variable" that you have in your clip? Am trying to do just that but having issues. (preferably uneditable, don't really care the element type as long as it works)

webdesserts commented 8 years ago

@timmyg This was the code I tested everything in the notes with: http://jsbin.com/piyeka/33/edit?html,css,js,output

If you want the original code look at the "testing environment" links in the original post. They are probably a bit more straightforward.

timmyg commented 8 years ago

@webdesserts awesome! exactly what I needed. Did you play around with drag/drop at all and/or dragging from within the editor on a previously dropped element?

webdesserts commented 8 years ago

@timmyg I did not, sorry. That project got put on hold.