[GHS] Allow the cursor to leave <div>s and other HTML elements at document start or end

Created on 25 February 2023, over 1 year ago
Updated 23 February 2024, 9 months ago

Problem/Motivation

It should be, but is not possible to get the cursor out of HTML elements including <figure>, <div>, <aside> and <section>, when there are no paragraphs before or after, without resorting to source editing. This prevents you typing between any such elements, typing before such elements at the document start, or after such elements at the document end.

Steps to reproduce

  1. Create new article (with CKEditor5 and the default Full HTML text format)
  2. Turn on source editing
  3. Enter <div>Text Here</div>
  4. Turn off source editing
  5. Attempt to make a new paragraph outside of the newly created div, using both mouse clicks and arrow keys
  6. Turn on source editing
  7. Note that everything added will be placed inside the initially created div

Proposed resolution(s)

A. somehow allow enable Magicline to be enabled... (if it's still called that) at the start and end of elements other than <table>, <hr /> and <img>
B. allow a temporary <p> tag outside the element to be created whenever you use the arrow keys to try and leave

🐛 Bug report
Status

Postponed: needs info

Version

11.0 🔥

Component
CKEditor 5 

Last updated about 4 hours ago

Created by

🇬🇧United Kingdom jacobupal Leeds

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @jacobupal
  • 🇬🇧United Kingdom jacobupal Leeds
  • Is this bug an attribute of this module or of CKEditor?

  • 🇬🇧United Kingdom jacobupal Leeds

    CKEditor itself contains the bug, but I don't know if the module can address it or not. This demo shows the same behaviour: General HTML Support.

    Actually I just found the same issue here on their repository issues: [GHS] It is not possible to leave DIV element

  • Status changed to Postponed: needs info over 1 year ago
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Note that everything added will be placed inside the initially created div

    That's not what I see if I follow your steps to reproduce, I see:

    … which is arguably sane behavior. But I think you would expect <p>s to be created by default, not new <div>s?

  • 🇬🇧United Kingdom jacobupal Leeds

    Hey @Wim Leers thanks for pointing this out - That's a little different to what I experienced. I can confirm that I am now seeing the same as you on the CKE5 General HTML Support demo page (which seems to have been updated) but I still feel the behaviour seen there is not ok.

    At first this behaviour seems like a slight improvement because, after a line break you can change the newly generated div into a paragraph. However that is no longer true if the div element contains a paragraph, in which case the experience is exactly the same as described above. When the div itself contains <p> elements, a line break simply produces a new paragraph within the div. This is the expected behaviour for a line break as far as I am concerned, and I don't see it as a problem per se. But it does mean that again our cursor is trapped in a div element albeit nested in a paragraph.

    Regardless of how deeply nested the current cursor is, I would expect it to always be possible to create an empty, unformatted, unnested new paragraph at the end or beginning of a document. With the cursor trapped, for writers unfamiliar with source editing, it is not.

    I would expect the arrow keys (Down, or Right, in the case of LTR text) to be capable of moving the cursor out of that context. Magic-lines achieve the same thing for those who might might want to achieve the same thing with mouse clicks.

    Interestingly, when I write within a <section> element <p> elements automatically wrap my text, the same goes for <article> and <aside>, and so for these semantic elements that behaviour is unchanged. I haven't tried the others.

    To get the same behaviour as me, it seems you would now have to use:

    Text Here

    or <article>Text Here</article> or <section>Text Here</section> or <aside>Text Here</aside>

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Hey @jacobupal, sorry for the silence!

    Can you still reproduce this in Drupal 10.2?

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
  • 🇬🇧United Kingdom jacobupal Leeds

    Thanks Wim, that's perfectly OK! And thanks for pushing for improvements upstream.

    I just tried it on a Drupal 10.2 demo site where I added

    , and to Basic HTML's "Manually editable HTML tags" list.

    I think this is pretty much what we saw in April. I have attached a video where I start with a div, a section and an aside element, and a bit of extra css on-top to show what's going on... The div behaves a bit like a paragraph itself, whereas the other two receive generated paragraphs within. The problem for both remains the same though, you cannot get the cursor out of the elements with arrow keys, carriage returns or mouse clicks.

    I feel like, at the very least it'd be cool to get that 'horizontal' cursor position we see when we keyboard-navigate out of a table or click between elements.

  • 🇬🇧United Kingdom jacobupal Leeds

    here it is as a gif for brevity.

  • 🇬🇧United Kingdom jacobupal Leeds

    This patch #70 from 'CKEditor 5 support for Content Templates' CKEditor 5 support for Content Templates Needs review does a bunch of stuff to "Add widget functionality to all templates" - and this part of the patched "ckeditorTemplatesEditing.js made me wonder if we can use the schema definitions the same way, on just like a list of elements?

    import { Plugin } from "ckeditor5/src/core";
    import { toWidget, toWidgetEditable } from "ckeditor5/src/widget";
    import { Widget } from "ckeditor5/src/widget";
    import CKEditorTemplatesCommand from "./ckeditorTemplatesCommand";
    
    /**
     * Handles the plugin functionality.
     */
    export default class CKEditorTemplatesEditing extends Plugin {
    
      /**
       * @inheritdoc
       */
      static get requires() {
        return [Widget];
      }
    
      /**
       * @inheritdoc
       */
      init() {
        this._defineSchema();
        this._defineConverters();
        this.editor.commands.add(
          "ckeditorTemplates",
          new CKEditorTemplatesCommand(this.editor)
        );
      }
    
      /*
       * This registers the structure that will be seen by CKEditor 5 as
       *
       * The logic in _defineConverters() will determine how this is converted to
       * markup.
       */
      _defineSchema() {
        // Schemas are registered via the central `editor` object.
        const schema = this.editor.model.schema;
    
        schema.register("ckeditorTemplates", {
          // Behaves like a self-contained object (e.g. an image).
          isObject: true,
          // Allow in places where other blocks are allowed (e.g. directly in the root).
          allowWhere: '$block',
        });
    
    ...
    

    There's obviously a lot more to it than I can get my head around, but if there is a way of telling CKEditor to treat all divs/sections/etc like "self-contained" objects might that be done right?

  • 🇺🇸United States joshuami Portland, OR

    @jacobupal, I think you might be on to something, but the approach in patch #70 in CKEditor 5 support for Content Templates CKEditor 5 support for Content Templates Needs review creates a command called "ckeditorTemplates" in /js/ckeditor5_plugins/ckeditor_templates/src/ckeditorTemplatesCommand.js that is called in /js/ckeditor5_plugins/ckeditor_templates/src/ckeditorTemplatesEditing.js. That command is inserting a section around every template when embedded:

    +          <section class="ckeditor-template-wrapper">
    +            <div class="ckeditor-template-content">
    +              ${htmlCode}
    +            </div>
    +          </section>
    

    That section getting converted into a widgetEditable with the widgetTypeAround handles. I didn't test that patch in particular, but that's what I'm seeing in the code. It kinda looks like they were following the tutorial at https://ckeditor.com/docs/ckeditor5/latest/tutorials/widgets/implementin....

    That said, it would be awesome if we could target any element + attribute combination to make it an editable block widget when in focus. A horizontal rule gets upcast into a widget, why can't we do that with other element + attribute combinations. It might fix some issues like the ability to edit a <cite> within a <blockquote>.

Production build 0.71.5 2024