Attention Onebox experts: Help requested resizing an iFrame embedded via oEmbed

I’ve extracted this question from this thread

I’ve been working on an oEmbed endpoint for consider.it that returns HTML that can be Oneboxed in a Discourse thread. Currently, the oEmbed html snippet is mostly just an iframe, along with a small javascript library injected into the containing window. This javascript library is capable of communicating with the iframe to dynamically adjust its height. This library is designed to play nicely with the containing window.

The specific code is e.g. :

   <iframe id='considerit-embed-4186' src='https://dao.consider.it/embed/proposal/slockit1' width='700' frameborder='0' style='overflow:hidden' scrolling='no'></iframe>
   <script src='https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.3/iframeResizer.min.js'></script>
   <script type='application/javascript'>
     var resize_interval=setInterval(function(){
       if (typeof iFrameResize != 'undefined'){
         iFrameResize({log:false, checkOrigin:false}, document.getElementById('considerit-embed-4186'))
         clearInterval(resize_interval)
       }
     }, 40)
   </script>

The javascript in the above code is unfortunately not consistently executing in a Discourse thread, and I’m at a loss as to why. I’ve observed the following bizarre but replicable behavior from Discourse:

  • javascript DOES NOT run if I just load a thread containing a Oneboxed considerit link
  • javascript DOES run if I have the post editor open with the link, but only for the Oneboxed link in the thread, not in the preview window.

This behavior is consistent when refreshing the page. I recorded this riveting 40 second video to demonstrate the behavior.

I can’t tell if:

  1. Discourse intends to disable javascript for Onebox’d html oEmbeds (and the edit post behavior is a bug), or
  2. Discourse intends to enable javascript but there is a bug in Discourse or my own code that is preventing it from happening.

If (1), is there a recommended method for the provider to enable dynamically resizing Oneboxed content? Or is it impossible to dynamically resize Oneboxed content in Discourse?

If (2), is there a workaround or recommended course of action?

Thanks for your time,
Travis

4 Likes

The iframe must be fixed size; even better, do not use an iframe at all.

Ok, so I’m inferring this a Discourse constraint?

Not using an iframe isn’t an option.

From the posts I’ve followed it seemed like using an Iframe would be the way to go?
Could you please elaborate?

I really hope this feature can be integrated, since it would help our forum a lot

1 Like

I really hope too since this feature will definitely make the difference in our forum !

try this link for soution - http://stackoverflow.com/questions/35744575/bind-iframe-height-to-its-content-height-with-jquery

adds/injects iframe resizer script to iframe

@rxhector: That runs into the same problem that I described, namely that the containing window has to be allowed to execute javascript.

I think, but am not sure, that Discourse/Onebox has a policy that javascript cannot be injected by an oEmbed provider. It is hard to tell though because sometimes Discourse allows injected javascript to execute. I’m having a hard time getting an answer on what Discourse’s intention is!

1 Like

This feature will have a huge impact on our forum, would love to see a solution.

general intention is to avoid risking crashing your browser just because somebody oneboxed something :slight_smile:

There is huge levels of risk in allowing 3rd parties to execute JS mid topic, we like to keep it to an absolute minimum.

2 Likes

Great, thanks @sam!

The only javascript I’m running is iFrame resizing, using a library engineered to play nicely with the containing window.

Is the Discourse code engineered to prevent the running of any javascript injected by a third party?

Yes, unless strictly whitelisted in a custom onebox.

3 Likes

Great info, thanks @sam

Two responses:

  1. I think the short video I recorded above demonstrates a situation where my non-whitelisted javascript is executed against Discourse’s policy. So it might be a bug. If you think it is worthwhile, I’d be happy to file a report.

  2. Is it possible for me to create a custom onebox where I can get the above javascript whitelisted? If so, a little hint about how I could get started would be appreciated!

1 Like

Reviving an old thread: I’d like the same functionality, dynamically resized iframes. Since it seems allowing oembed providers to include script tags isn’t likely to happen (which I completely understand), a reasonable alternative would be for Discourse to implement a pretty simple hook.

Embed.ly provides this functionality by just sending a fairly simple postMessage, and on the host page, their library includes essentially this snippet:

window.addEventListener('message', function(e) {
  var data;
  try {
    data = JSON.parse(e.data);
  } catch (e) {
    return false;
  }

  if (data.context !== 'iframe.resize') {
    return false;
  }

  var iframe = document.querySelector('iframe[src="' + data.src + '"]');

  if (!iframe) {
    return false;
  }
 
  if (data.height) {
    iframe.height = data.height;
  }
});

Discourse could implement something compatible with this same message and a lot of things that work with embed.ly would just automatically work. From the implementor’s perspective, it’s as simple as sending this JSON whenever your iframe needs to be resized:

{
  "src": window.location.toString(),
  "context": "iframe.resize",
  "height": 999
}

The problem with this is that Discourse really wants to know the vertical size of things when it lays out posts. Otherwise you can be looking at a post, and something above it forces the document to layout again, again and you lose the spot you’re reading because everything’s been pushed down.

But the size of something can change once you’ve interacted with it, which negates that argument – I’m not trying to keep my reading spot, I’m trying to interact with a widget.

For a specific example, look at how my product, RunKit, works once you click “run”:

https://runkit.com/boucher/595fef8bd1960b00121d1026

To clarify what you’re seeing (or not seeing) is that the results are below the lower edge of frame.

Can you just provide enough vertical height upfront for the results? (even with cached results)

(replace “” with [cached])

Another simpler option is to add an extra tab for results and then you flick back and forth without forcing page reflows on run.

Note: I am not entirely against the post message solution after run, but I do worry big time that it will get abused.

Not possible, the nature of scrolling in Discourse requires the frame size to be known in advance.

If user interaction changes the size that is much more defensible.

I think that is the argument, cause the embed would raise an event to discourse telling it to resize when you click run.

However, it is an abuse vector cause the embed could just do it anyway if it was allowed to, and wreak havoc on initial render, so we would probably have to ignore the event for N seconds or something.

Yes exactly, how would we ensure that a resize event was only based on user interaction and not initial load?

Only if it bubbles from a click event from the user. Same way pop up blockers worked for a long time, as I understand it.

1 Like