Rich Text Editor Not Behaving Correctly
Asked Answered
L

4

11

I am trying to create a rich text editor on a text field. In an attempt to do this, I'm using Summernote. I have the editor initializing close to the way I want. I'd really like the airmode to behave on hover instead of on-click. Still, there is an odd behavior that is my real problem.

As shown in this Fiddle, a user can begin typing in one of the three editors on the screen. However, as soon as you enter a space, the text goes to the line above the input field. It does not stay on the same line. Strangely, the text just above the input line does not allow for rich-editing. I'm initializing the text fields like this:

  var optionEditors = $('.option-editor');
  for (var i=0; i<optionEditors.length; i++) {
    $(optionEditors[i]).summernote({
      airMode: true,
      popover: {
        air: [
          ['font', ['bold', 'underline', 'clear']]
        ]
      }
    });
  }

What am I missing? Everything looks correct. Its just that the behavior seems wrong. Thank you.

Longwood answered 9/8, 2016 at 17:21 Comment(0)
D
1

Another solution is to hide the inputs with CSS and make summernote looks like a form-control :

for (var i=0; i<optionEditors.length; i++) {
    $(optionEditors[i]).summernote({
      airMode: true,
      popover: {
        air: [
          ['font', ['bold', 'underline', 'clear']]
        ]
      },
      callbacks: {
        onInit: function() {
               // make the editor like a "form-control"
               $('.note-editor').addClass('form-control');
               // Force editor height adding one space 
               $(this).summernote('code', ' ');
            }
        }      
    });

}

@see working example https://jsfiddle.net/v8zhvsmo/

Dayflower answered 18/8, 2016 at 15:45 Comment(0)
L
0

Bootstrap plugins depend on jQuery; they'll fail if it doesn't load first:

Plugin dependencies

Some plugins and CSS components depend on other plugins. If you include plugins individually, make sure to check for these dependencies in the docs. Also note that all plugins depend on jQuery (this means jQuery must be included before the plugin files). Consult our bower.json to see which versions of jQuery are supported.

The defer attribute in your jQuery script loading tag is causing it to load after you call addAllElements in your onload event.

defer

This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed. Since this feature hasn't yet been implemented by all other major browsers, authors should not assume that the script’s execution will actually be deferred. The defer attribute shouldn't be used on scripts that don't have the src attribute. Since Gecko 1.9.2, the defer attribute is ignored on scripts that don't have the src attribute. However, in Gecko 1.9.1 even inline scripts are deferred if the defer attribute is set.

Larvicide answered 11/8, 2016 at 17:59 Comment(0)
Z
0

The reason this is happening doesn't seem to be related to jQuery, it seems to be related to how summernote initializes an editor. The optional-editor attribute you're grabbing is a div element and is being initialized, not the input element.

What happens next is summernote then takes this div and creates a couple of other div elements inside with classes like note-editor, note-dropzone, note-editing-area, etc. The inner-most div has a class called note-editable and inside this div is your input element. The note-editable div is what summernote considers to be the actual rich-text editor, not the input element. That said, you can still click on the input element and type in whatever you want.

Summernote places some event listeners on the onkeydown event (see the docs here) and since it's a rich text editor it seems to be checking for the spacebar character (among others, e.g. enter which becomes a new paragraph) so that it can escape it in the HTML (space becomes &nbsp;). Since you're typing inside the note-editable div even if you're technically typing inside your input element, this key press will be caught by summernote and it seems to be placing the escaped space character inside the div, not inside the input. This results in the text being placed above your input element. You'll notice you can use ctrl+A when your cursor is above the input element to highlight everything inside this editable div and you can even delete your input element.

My suggestion would be to remove the input element altogether and just use the containing div as that seems to be the most common use case scenario. You could also try overriding the onkeydown event listener and append the space to inside the input, but this seems like a very roundabout way of trying to solve something that doesn't really need to be solved.

Edit: It looks like summernote clones the node that's designated to be the rich text editor which would end up removing any event listeners on said element, including its children, so you can't override the keydown event for the text input element before initializing summernote. Trying to provide an override callback for the keyDown event through init configuration of summernote is possible, but very ugly and has quirks due to the pre-configured event handlers set by summernote.

In the fiddle I only used one text input and gave it the id richTextInput. Also, I removed onchange="onAnswerChoiceChange(this);" as this was causing an error.

To provide an override in the configuration, use this:

$(optionEditors[i]).summernote({
  airMode: true,
  popover: {
    air: [
      ['font', ['bold', 'underline', 'clear']]
    ]
  },
  callbacks: {
    onKeydown: function(e) {
      if (e.keyCode === 32) { // catch "space"
        e.preventDefault();
        $('.note-editable>#richTextInput').val($('.note-editable>#richTextInput').val() + " ");
      }
    }
  }
});

The note-editable class is the container div created by summernote after initialization. We need to specify this because summernote automatically copies all contents of the "rich-text-editor-to-be" before initialization, then hides them with display:none so just trying to reference the input with $('#richTextInput') will not work because you'll be grabbing the hidden input.

Quirks: You'll notice that if you try to use this code summernote will try to automatically provide focus to the actual rich text editor div which is due to the behavior provided in the event listener registered by summernote. You could get around this by providing a timeout like so:

setTimeout(function() {
    $('.note-editable>#richTextInput').focus();
}, 1); 

As I said before, this is really not a good solution and although it may do the trick, I think the better route would be to ditch the text input altogether and just initialize a div or textarea without anything nested inside as the library expects. It'd be easier to do that and then style them accordingly. Using the material design styles/components probably won't work well together since material needs input or textarea elements and summernote transforms the textarea into a div, but that's a different problem.

Zalea answered 11/8, 2016 at 18:32 Comment(6)
I tried to do this without any luck. Any chance you could take the Fiddle I provided and show me what you're referring to?Longwood
@Longwood I updated my answer to show you what I was referring to. Hope this helpsZalea
Where is the fiddle that you mentioned? I do not see a link to the fiddle anywhere. Thank youLongwood
@Longwood here is a fiddle with what I mentioned. Hope this helpsZalea
@stevenlberger - So, maybe I'm confused. But when I visit the fiddle you posted, click the text field, I can enter text. However, I never see the summernote rich text editor options appear. Am I misunderstanding something?Longwood
@Longwood Unfortunately, I'm afraid you're right. Those options won't appear unless you're typing into the actual RTE div itself. Even if you take airmode off, you'll have to place the cursor into the actual div to apply any formatting. It just doesn't look like summernote is capable of providing a RTE on a text input element alone. Sorry I couldn't be of further help.Zalea
R
0

maybe solution was simple. <div contenteditable="true"> parent is created ( and maybe you dont need <input>), where RICH-EDITING happens actually.

1) airmode ON: https://jsfiddle.net/hwd5efe0/13/
2) airmode OFF: https://jsfiddle.net/hwd5efe0/18/

(p.s. only changed JS )

Reest answered 18/8, 2016 at 9:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.