WordPress.org

Ready to get started?Download WordPress

Forums

Advanced iFrame
[resolved] Auto-resize breaks JavScript in the iframe (29 posts)

  1. Jason Judge
    Member
    Posted 6 months ago #

    I have the auto-resize working, with the iframe content provided by an app on another domain. The content is a form with a number of dynamic elements and bootstrap. The dynamic elements include re-populating select lists, showing and hiding fields and some AJAX and jQuery.

    Without the auto-resize JavaScript included, it words fine in an iframe, although having to set a massively high iframe (we want to avoid scrollbars) is not very helpful.

    The form, when run outside of the iframe, works fine whether the auto-resize JavaScript is in or not.

    However, run in an iframe, with the auto-resize javascript, the form breaks. A JS error means that JS halts and no JS then runs on the form.

    Here is our tag:

    [advanced_iframe securitykey="xxxxxxxxxxxxe4e3789e426bba4dxxxxxxxxxxxx" src="http://www.mysite.co.uk/myform" resize_on_ajax="100" resize_on_click="100" onload_resize_width="false" onload_resize="false" onload=""]

    Here is the JS error we are seeing on loading the iframe:

    Error: Permission denied to access property 'document'
    http://main-site.com/test-page/
    Line 185

    Line 185:

    <script>
    function ai_jquery_ajax_resize_advanced_iframe() {
    jQuery("#advanced_iframe").bind("load",function(){
    vvvvvvvvvvvvvvvvvvvv
    doc = this.contentWindow.document;doc.addEventListener("click",
    function(evt) { if (checkIfValidTarget(evt,"a")) { local_resize_advanced_iframe(100); }}, true);});
    ^^^^^^^^^^^^^^^^^^^^
    }ai_jquery_ajax_resize_advanced_iframe();</script><script>
    var send_advanced_iframe = ifrm_advanced_iframe.contentWindow.XMLHttpRequest.prototype.send,
    onReadyStateChange_advanced_iframe;

    http://wordpress.org/plugins/advanced-iframe/

  2. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    Why do you use
    resize_on_click_elements?

    you work on different domains so you have to use the autoresize workaround like described in the documentation.

    All the features for autoresize on the same domain have to be turned off.

    Best, Michael

  3. Jason Judge
    Member
    Posted 6 months ago #

    Thanks. I'm away for a few days, but will try changing this when I get back later in the week, and report back.

  4. Jason Judge
    Member
    Posted 6 months ago #

    I set resize_on_click_elements="false" on the quick tag, but that has made no difference. The JavaScript inside the page is still disabled due to the error.

    Is there an example quick tag published anywhere that I can try out? I just need a simple tag that resizes to the content, auto-resizes when the content changes size, and works with content on a different domain. Whether it works or not needs to be independent of the default global settings in the module, obviously.

  5. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    No. I mean you work on different domains so you have to use the autoresize workaround like described in the documentation.

    You cannot use any of the features which try to access the iframe directly. This will cause an Javascript error!

  6. Jason Judge
    Member
    Posted 6 months ago #

    "the autoresize workaround like described in the documentation" - what exactly am I looking for here that I have not already done? The auto-resizing is working (for the initial page load at least) but then all JavaScript stops working due to the JS error.

    One thing the documentation does not give, and something I have not been able to find anywhere, are some simple examples of the shortcode tag.

    So, I have iframe content on another domain, and the iframe needs to autosize with the content. Simple. What would the shortcode tag look like? I have read the documentation and done what I believe it says, so what next?

  7. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    Simple examples for the short code tag are in the FAQ (http://www.tinywebgallery.com/blog/advanced-iframe/advanced-iframe-faq) and also in the administration. The shortcode can be very simple because you do all the settings in the administration. In the shortcode you only overwrite settings.

    So what have you done? You have to use the external workaround which means you have to include Javascript to the remote page.

    About the Javascript error I can only repeat again: You cannot use any of the features which try to access the iframe directly. This will cause an Javascript error! You have to turn them off. Which also means you have to disable the auto height in the config becaushe this is the one for iframes on the same domain.

  8. Jason Judge
    Member
    Posted 6 months ago #

    I'm taking the approach that the tag should set all the settings that are necessary for it to work. Assuming the default settings in the admin panel are going to work for ALL the iframes that may work in very different ways across many pages of a site, is just asking for trouble. I'm leaving the defaults as they are, and creating the tag configured to do what that tag specifically needs to do.

    The iframe *is* resizing - I've mentioned that a couple of times. To resize, the JavaScript in the remote iframe content must be loaded from the WP site. That is done, and that is how it is resizing.

    Do I need to turn off the auto-height in the config even if it is turned off in the tag? You say the tag just overrides the defaults in the config, so to me that means the config can be ignored and everything required set up in the tag. Is that the case? If so, then there must be a minimum example tag that should just work. Is there not an example of a tag I just copy and paste? Just one example of a tag that simply works with an external URL? There is no mention of external domains on the documentation link you gave.

    Can you see where I am coming from? I have a URL, I have placed the required JS in the iframe source page, so I should simply be able to paste a tag into the WP site to make it work. Is it not that simple? Am I just missing the point?

  9. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    You can simply use the parameter
    use_shortcode_attributes_only="true"
    then the default are not used at all.

    than the minimum shortcode looks like
    [advanced_iframe securitykey="<your shortcode>" use_shortcode_attributes_only="yes" src="http://www.tinywebgallery.com"]
    (This is also described in the documentation)

    External domains do not need any special shortcode. Otherwise it would be mentioned in the documentation of the workaround.
    Your problem is that Javascript is rendered that tries to access the external iframe because of a setting you do.

    I only see http://www.consil.co.uk/blog. Where is the iframe located?
    then I can take a look which maybe solve the problem in a few seconds.

    Your shortcode
    [advanced_iframe securitykey="xxxxxxxxxxxxe4e3789e426bba4dxxxxxxxxxxxx" src="http://www.mysite.co.uk/myform" resize_on_ajax="100" resize_on_click="100" onload_resize_width="false" onload_resize="false" onload=""]

    should be
    [advanced_iframe securitykey="xxxxxxxxxxxxe4e3789e426bba4dxxxxxxxxxxxx" src="http://www.mysite.co.uk/myform"]

    and if you like the configure all the tags
    [advanced_iframe securitykey="xxxxxxxxxxxxe4e3789e426bba4dxxxxxxxxxxxx" src="http://www.mysite.co.uk/myform" resize_on_ajax="" resize_on_click="" onload_resize_width="false" onload_resize="false" onload=""]

    resize_on_ajax and resize_on_click does also render Javascript which is only allowed on the same domain. They are in the section for settings which work on the same domain only.

    Best, Michael

  10. Jason Judge
    Member
    Posted 6 months ago #

    Okay, so I have done this:

    [advanced_iframe securitykey="<your shortcode>" use_shortcode_attributes_only="yes" src="http://mypage.example.com/"]

    [advanced_iframe securitykey="<my shortcode>" src="http://mysite.example.co.uk/" resize_on_ajax="" resize_on_click="" onload_resize_width="false" onload_resize="false" onload=""]

    I have also set "use_shortcode_attributes_only" in the config page.

    Here is the test page:

    http://opwall.com/test-eoi/

    It resizes, but then the JS within the page dies. There is a select2 item in there, and various blocks get shown or hidden on clicking the checkboxes.

    The live page is here and shows how it should work, but has a fixed height set:

    http://opwall.com/get-involved/expression-of-interest/

    Thank you for your patience.

  11. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    The form has also onload events which maybe interferes with the onload handling of the advanced iframe.
    Your form uses jQuery while I have a method which also works without jQuery.

    What you can do is to use the jQuery method also for advanced iframe.

    At the end of the ai_external.js you find

    addOnloadEvent(aiUpdateIframeHeight);

    replace this with

    $(document).ready(function() {
    aiUpdateIframeHeight();
    });

    be aware that ai_external.js is generated from ai_external.template.js and the ai_external.js is generated each time you save the config. So when this works also do this modification in ai_external.template.js.

    If this works I try to to a jQuery detection first and then use the jQuery way to add the onload event.

    Best, Michael

  12. Jason Judge
    Member
    Posted 6 months ago #

    Cool, I'll give that a go later on today. I assume ai_external.js can be copied to anywhere on the site, once it is set up? So long as it does not have any dependencies requiring it to be located in that directory, then I could put it into a custom plugin or stick it in uploads.

  13. Jason Judge
    Member
    Posted 6 months ago #

    I've tried this, and it does not seem to make a difference. The iframe resizes correctly, as always, but the JavaScript inside it no longer operates. Firebug does not give me any JS errors, but I am finding Firebug is not consistent with reporting errors in iframes anyway.

    Edit: you have to enable Firebug for the iframe's domain to see errors in the iframe. Makes sense. The error that stops the JS working is this:

    TypeError: y is null
    http://opwall.com/wp-includes/js/jquery/jquery.js?ver=1.8.3
    Line 2

    I guess that's not much use without a stack trace, but it might give some clues. The iframe content runs fine on its own:

    http://www.acadweb.co.uk/opwall/eoi

  14. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    The error is not really helpful because y is not a variable I use.

    What you also can try is to remove the last line which adds the onload and put the onload directly to
    1. the body <body onload="aiUpdateIframeHeight();">
    2. into the ready function of the select2.js

    Always make sure to clean the browser cache after such modifications because js is cached by the browser.

  15. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    I just did some debugging. The select2.js is called but no ajax request is sent afterwards.
    I don't see any Javascript errors. What have you done to enable this?

  16. Jason Judge
    Member
    Posted 6 months ago #

    You can see the JS errors if you right-click in the iframe then enable Firebug from there. If you just enable Firebug from the outer page, then the JS errors inside the iframe don't show up.

  17. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    One more thought. As it loads standalone the different onload events seem to work together without error.

    In the beginning of the function I have a
    if (window!=window.top) { /* I'm in a frame! */
    which only modifies the dom when used inside an iframe.

    What I do is to add an extra div for measuring. this one has the id ai_wrapper_div. Maybe this extra div kills your Javascript because the dom tree is different.
    If this is the case you could use the existing one in your code by removing the 3 lines after
    // add a wrapper div below the body to measure

    Than your content div "content" is used which is fine also.

    Best, Michael

  18. Jason Judge
    Member
    Posted 6 months ago #

    I can display an alert before and after the remote JavaScript (ai_external) is called. So the error is not happening inside that code. However, running that code does then set up some kind of state that causes the later jQuery onload handlers to fail somewhere.

    The select2 item does initialise, as it shows up (that form item is just a hidden input field to start with). Disabling all the select2 code makes no difference to the operation of JS on other parts of the form.

  19. Jason Judge
    Member
    Posted 6 months ago #

    Just looking through your code, the resizer wraps the content of the body tag with a DIV so its height can be measured. It does this by putting the body content into variable, wrapping that variable, then putting the content back into the body.

    Now, my various other events will have been set on lots of elements inside this body. By converting the body into a string, wrapping it in DIVs, then converting it back into a DOM, will that not destroy all the elements that my jQuery code has events linked to?

    I'm guessing I could use jQuery's live() function so that the events get rebound when the page is reparsed from HTML back into the DOM, but I won't be able to do that with any plugins I'm using.

    So - and this is assuming I'm right on this hunch - is there a better way to wrao the body in a DIV element without destroying and rebuilding the DOM BODY elements from scratch?

  20. Jason Judge
    Member
    Posted 6 months ago #

    Ah, here you go. A ten second search and Stack Overflow delivers the goods, as usual. This my problem described to a tee, your code almost word-for-word, the conclusion I came to, and the solution that the OP says works like a dream:

    http://stackoverflow.com/questions/1577814/wrapping-a-div-around-the-document-body

    Can't get better than that :-)

    Edit: reading back I realised you had come to the same conclusion, but with a different solution. I think the SO way looks spot-on, and would recommend you try that out. If it works, it should benefit many your users, whether they are using jQuery or their own non-jQuery javascript in their iframe content.

  21. Jason Judge
    Member
    Posted 6 months ago #

    And yes, it works. Replacing these lines:

    var org_html = document.body.innerHTML;
          var new_html = '<div id="ai_wrapper_div" style="margin:0px;padding:0px;border: 1px solid transparent;">' + org_html + '</div>';
          document.body.innerHTML = new_html;

    with this:

    // Jason's experiment.
    	var div = document.createElement("div");
    	div.id = "ai_wrapper_div";
    	div.style = "margin:0px;padding:0px;border: 1px solid transparent;";
    
    	// Move the body's children into this wrapper
    	while (document.body.firstChild)
    	{
    		div.appendChild(document.body.firstChild);
    	}
    
    	// Append the wrapper to the body
    	document.body.appendChild(div);

    and the resize JS no longer breaks the JS inside the iframe content.

  22. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    You are right.
    I totally missed that point while implementing this lines.

    If you look at the aiCreate create function I have: It is almost the same code.

    I will also improve the code that the wrapper div is only added when needed! Because if the first element is a div and the only child element than the wrapper is not needed at all.
    I will integrate this into the next version.

    Best, Michael

  23. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    Is it o.k. to give you credit for this solition in the readme?

  24. Jason Judge
    Member
    Posted 6 months ago #

    Sure - a credit would be great. But don't feel obliged - the help goes down a long line, through Stack Overflow and people we have never met, and framework creators, and so on.

    I pretty much said that on a Laravel discussion yesterday:

    https://github.com/laravel/framework/commit/ee97de894c179d2401179331921b124156a2e3fb#commitcomment-4316287

    But yeah, gratefully received :-)

  25. Jason Judge
    Member
    Posted 6 months ago #

    There are a few little tweaks to get it finally working.

    Firstly, after resizing the iframe, overflow for the iframe was set to hidden. That hid the scrollbars, but also hid the iframe content if it lengthened at all.

    Ideally if the iframe content changes size, then the JS should resize the iframe to match. For now, I have just taken out the "overflow:hidden" and that allows scrollbars to appear if the content gets longer than its initial length.

    To stop the scollbars flashing up at the start, it may be an idea to set overflow to hidden initially, then resize the iframe, and then set overflow back to auto (or display, or whatever it is), then the scrollbars can appear if they need to. I haven't tried that though - just needed to get it working for the live site.

  26. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    The overflow hidden is actually only for the time the iframe is resized.
    after the resize there should be no scrollbars anymore.

    Are they maybe because of the width does not fit?

    Best, Michael

  27. Jason Judge
    Member
    Posted 6 months ago #

    No, it has nothing to do with the width. The iframe content page can change length when elements are selected or de-selected in it. The outer iframe either needs to resize itself when this happens, or vertical scroll-bars are needed. The default display:hidden just means that parts of the iframe content get hidden when the content changes length.

  28. mdempfle
    Member
    Plugin Author

    Posted 6 months ago #

    right. For the "same domain" solution I have "resize on ajax events" and resize on click events.
    Something like this would have to be in the external workaround also.

  29. Jason Judge
    Member
    Posted 6 months ago #

    You can bind to a resize event on the window, and since the window of the remote iframe content takes up the whole iframe (which has been resized to the size of the wrapper div that is created, which wraps the whole page, then any resize of the window would mean the iframe needs to be resized.

    I may be mistaken on that though. I'm assuming a page in an iframe sees the iframe as its "window". Dunno, new territory for me.

Reply

You must log in to post.

About this Plugin

About this Topic

Tags

No tags yet.