basecamp / trix

A rich text editor for everyday writing
https://trix-editor.org/
MIT License
19.11k stars 1.12k forks source link

Editor loses focus when `enter`-ing and `backspace`ing around attachments #206

Closed balanceiskey closed 8 years ago

balanceiskey commented 8 years ago

In certain instances when typing enter or backspace around an inserted attachment, the editor can lose focus. This is particularly bad in backspace scenarios as a user may continue hitting backspace causing the browser’s back behavior to be triggered. I can, with some amount of certainty, say that we’re seeing this in recent versions of Chrome but I haven’t done an exhaustive check against other browsers.

To recreate from the Trix site:

  1. Insert an attachment from the console:

     const attachment = new Trix.Attachment({content: '<iframe width="560" height="315" src="https://www.youtube.com/embed/_UbDeqPdUek" frameborder="0" allowfullscreen></iframe>'});
    
     document.querySelector('trix-editor').editor.insertAttachment(attachment);
  2. Focus cursor at the front of inserted video and hit enter a few times. Editor should lose focus. Similarly, and this is a little harder to reproduce, if you arrow around the attachment and hit backspace the editor will eventually lose focus as well.
javan commented 8 years ago

This isn't an issue with attachments generally, but rather with content attachments containing an <iframe>. <iframe>s are reloaded when they're moved in the DOM, and I suspect this causes a focus or selection change. It's possible this issue is specific to Youtube embeds. I haven't tested others. The only workaround I can think of for now to avoid inserting iframes and use a placeholder image instead. If anything, it would prevent the frequent reloading when Trix renders.

In Basecamp, we use preview image when editing and swap in the actual embed when rendering.

embed

balanceiskey commented 8 years ago

Thanks @javan, this helps a ton. I'll close this ticket now as I think that answers what we were seeing and how to potentially solve it.

heidiv commented 8 years ago

In Basecamp, we use preview image when editing and swap in the actual embed when rendering.

hi @javan, are you able to share some code for this functionality?

For youtube embed, I'm currently inserting an iframe, like in #120, but content attachments are put into a <figure> tag. Also the shifting focus (mentioned above) within the editor is an accessibility blocker, so your method with an image placeholder is definitely the way to go.

Any guidance appreciated! Thanks.

jeffreyguenther commented 8 years ago

@heidiv once we receive an answer, let's capture these techniques on the wiki. I imagine many people will need to solve this problem for themselves and it would be nice to have the techniques in a place that doesn't involve searching the issue tracker. Ping me if you'd like me help. I'm happy to!

heidiv commented 8 years ago

@jrguenther nice yeah. I have the preview image happening (code snippet below - youtube specific)

screen shot 2016-07-14 at 3 14 47 pm

videlement = document.querySelector("input[name=insertvideo]")
youtube_id = videlement.value.split('=').pop()
preview_image = 'http://img.youtube.com/vi/'+youtube_id+'/0.jpg'                 
element.editor.insertHTML("<img src='"+preview_image+"' alt='Placeholder image for video'>")

and the embed attachment code would be

embed = '<iframe width="420" height="315" src="https://www.youtube.com/embed/'+youtube_id+'" frameborder="0" allowfullscreen></iframe>'
attachment = new Trix.Attachment({content: embed})
element.editor.insertAttachment(attachment)

Still need to do the switcheroo from image to vid. Perhaps there's a way to attache as <video> instead of figure...

javan commented 8 years ago

are you able to share some code for this functionality?

There are a number of moving parts on both the server and client so it's not exactly a shareable snippet. We get the preview image from YouTube's (and other services) oEmbed API leaning on ruby-oembed for help with that. When rendering, we filter the content throught a custom html-pipeline filter that scans for relevant Trix attachments and swaps them out with the oEmbed content.

heidiv commented 8 years ago

Ok, thanks @javan !

AlvaroSenorale commented 6 years ago

Hey, I'm trying to implement the youtube embedding thing but I can't capture the "Insert" button event.

myDialogHtml =
    '<div class="trix-dialog trix-dialog--link" data-trix-dialog="myDialog" data-trix-dialog-attribute="src">
        <div class="dialog-content">
           <div class="trix-dialog__link-fields">
            <input type="url" name="src" class="trix-input trix-input--dialog" placeholder="Enter a URL…" required="" data-trix-input="" disabled="disabled">
            <div class="trix-button-group">
              <input type="button" class="trix-button trix-button--dialog" value="Insert" data-trix-method="makeAttachment">
            </div>
          </div>
        </div>
      </div>';
  dialogElement = event.target.toolbarElement.querySelector(".trix-dialogs");
  dialogElement.insertAdjacentHTML("beforeend", myDialogHtml);

and then:

makeAttachment = (_) ->
  console.log 'TODO Attachment'

But the makeAttachment method is never fired. any thoughts?

SudharakaP commented 3 years ago

@javan: I am trying to make sure the iframe is replaced by a preview image and then when saving the content replacing that image with the iframe again when saving. Is there some kind of event that is triggered when the content of the editor is saved? So that I could replace the images with the iframes again? 🤔

Reference PR: https://github.com/opencollective/opencollective-frontend/pull/6327