87 votes

Redimensionnement des iframes inter-domaines

Comment redimensionner un iframe d'un autre domaine ?

-Editer

Faites défiler la page pour trouver des solutions ou lisez comment NE PAS le faire :D

Après de nombreuses heures de bidouillage de code, la conclusion est que tout ce qui se trouve à l'intérieur de l'iframe n'est pas accessible, même les barres de défilement qui s'affichent sur mon domaine. J'ai essayé de nombreuses techniques, sans succès.

Pour gagner du temps, n'empruntez pas cette voie, utilisez simplement sendMessages pour les communications entre domaines. Il y a des plug-ins pour HTML < 5 que j'utilise - Allez en bas pour un bel exemple :)


Ces derniers jours, j'ai essayé d'intégrer une iframe dans un site. Il s'agit d'une solution à court terme pendant que l'autre partie développe une API (cela pourrait prendre des mois...). Et parce qu'il s'agit d'une solution à court terme, nous ne voulons pas utiliser easyXDM - J'ai accès à l'autre domaine mais il est déjà assez difficile de leur demander d'ajouter l'en-tête p3p tel qu'il est......

3 iframes

La solution la plus proche que j'ai trouvée était les 3 iframes- mais cela fait perdre la tête à chrome et safari donc je ne peux pas l'utiliser.

ouvert en chrome

http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179

Mesurer les barres de défilement

J'ai trouvé un autre post sur la façon d'utiliser la hauteur de défilement pour essayer de redimensionner le formulaire en théorie, cela fonctionne bien mais je n'ai pas pu l'appliquer correctement en utilisant la hauteur de défilement des iframes .

document.body.scrollHeight

Cela utilise évidemment la hauteur des corps (il n'est pas possible d'accéder à ces propriétés - 100% est basé sur la zone d'affichage du client et non sur la hauteur du document du domaine X).

J'ai essayé d'utiliser Jquery pour obtenir la hauteur des iframes.

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

les valeurs de retour sont différentes dans chrome et ie - ou n'ont pas de sens du tout. Le problème est que tout ce qui se trouve à l'intérieur du cadre est refusé - même la barre de défilement...

Styles calculés

Mais si j'inspecte un élément de l'iframe dans Chrome, il me montre les dimensions du document à l'intérieur de l'iframe (en utilisant jquery x-domain pour obtenir iframe.heigh - accès refusé). Il n'y a rien dans le CSS calculé enter image description here

Maintenant, comment chrome calcule-t-il cela ? (edit- le navigateur re-rend la page en utilisant son moteur de rendu intégré pour calculer tous ces paramètres - mais ils ne sont attachés nulle part pour éviter la fraude inter-domaine donc )

HTML4

J'ai lu les spécifications de HTML4.x et il y est dit qu'il devrait y avoir des valeurs en lecture seule exposées via document.element mais l'accès est refusé via jquery.

Cadre Proxy

J'ai emprunté la voie de la transmission par proxy du site et du calcul, ce qui est correct, jusqu'à ce qu'un utilisateur se connecte via l'iframe et que le proxy reçoive une page de connexion au lieu du contenu réel. De plus, pour certains, appeler la page deux fois n'est pas acceptable.

http://www.codeproject.com/KB/aspnet/asproxy.aspx

http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/

Rendu de la page

Je ne suis pas allé aussi loin, mais il existe des moteurs jscript qui regardent la source et rendent à nouveau la page en se basant sur le fichier source... mais il faudrait pirater ces jscripts... et ce n'est pas une situation idéale pour les entités commerciales... et certains font appel à des applets java ou à un rendu côté serveur.

http://en.wikipedia.org/wiki/Server-side_JavaScript

http://htmlunit.sourceforge.net/ <-java pas jscript

http://maxq.tigris.org/


EDIT 09-2013 UPDATE

Tout cela peut être fait avec des sockets HTML5. Mais easyXDM est une excellente solution de repli pour les pages de plaintes non HTML5.

Solution 1 Très bonne solution !

Utilisation d'easyXDM

Sur votre serveur, vous avez mis en place une page sous la forme de

<html>
<head>
<script src="scripts/easyXDM.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">

    var transport = new easyXDM.Socket(/** The configuration */{
    remote: "http://www.OTHERDOMAIN.com/resize_intermediate.html?url=testpages/resized_iframe_1.html",

    //ID of the element to attach the inline frame to
    container: "embedded",
    onMessage: function (message, origin) {
        var settings = message.split(",");
        //Use jquery on a masterpage.
        //$('iframe').height(settings[0]);
        //$('iframe').width(settings[1]);

        //The normal solution without jquery if not using any complex pages (default)
        this.container.getElementsByTagName("iframe")[0].style.height = settings[0];
        this.container.getElementsByTagName("iframe")[0].style.width = settings[1];
    }
});

</script>

</head>

<body>
    <div id="embedded"></div>
</body>

et sur le domaine de l'appelant, il suffit d'ajouter le html intermiedate_frame et easyXDM.js au même endroit. Comme un dossier parent - vous pouvez alors accéder à des répertoires relatifs ou à un dossier contenu juste pour vous.

OPTION 1

Si vous ne voulez pas ajouter des scripts à toutes les pages, regardez l'option 2 !

Il leur suffit alors d'ajouter un simple jscript à la fin de chacune des pages sur lesquelles le redimensionnement doit avoir lieu. Il n'est pas nécessaire d'inclure l'easyxdm dans chacune de ces pages.

 <script type="text/javascript">
            window.onload = function(){ parent.socket.postMessage( (parseInt(document.body.clientHeight)) + "," + ( document.body.clientWidth ) );  };
        </script>

J'ai modifié les paramètres qu'il envoie. Si vous voulez que la largeur fonctionne correctement, les pages de l'autre domaine doivent inclure la largeur de la page dans un style quelque part qui ressemble à ceci :

<style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                background-color: rgb(75,0,85);
                color:white;
                width:660px
            }
            a {
            color:white;
            visited:white;
            }
        </style>

Cela fonctionne très bien pour moi. Si la largeur n'est pas incluse, le cadre se comporte un peu bizarrement et essaie de deviner ce qu'il devrait être et ne se rétrécit pas si vous en avez besoin.

OPTION 2

Modifier la trame intermédiaire afin d'interroger les changements

Votre cadre intermédiaire devrait ressembler à quelque chose comme ceci

    <!doctype html>
<html>
    <head>

        <title>Frame</title>
        <script type="text/javascript" src="easyXDM.js">
        </script>
        <script type="text/javascript">
            var iframe;
            var socket = new easyXDM.Socket({
                //This is a fallback- not needed in many cases
                swf: "easyxdm.swf",
                onReady: function(){
                    iframe = document.createElement("iframe");
                    iframe.frameBorder = 0;
                    document.body.appendChild(iframe);
                    iframe.src = "THE HOST FRAME";
            iframe.onchange = messageBack();

                },
                onMessage: function(url, origin){
                    iframe.src = url;
                }
            });

            //Probe child.frame for dimensions.
            function messageBack(){
                socket.postMessage ( iframe.contentDocument.body.clientHeight + "," + iframe.contentDocument.body.clientWidth); 
            };

            //Poll for changes on children every 500ms.
            setInterval("messageBack()",500); 

        </script>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                width: 100%;
                height: 100%;
            }

            iframe {
                width: 100%;
                height: 100%;
                border: 0px;
            }
        </style>
    </head>
    <body>

    </body>
</html>

L'intervalle pourrait être rendu plus efficace en vérifiant si la taille a changé et en ne l'envoyant que si les dimensions changent, au lieu d'envoyer un message toutes les 500 ms. Si vous mettez en œuvre cette vérification, vous pouvez réduire l'intervalle d'envoi à 50 ms !


Fonctionne sur tous les navigateurs et est rapide. Superbes fonctions de débogage !

Excellent Work to  Sean Kinsey  who made the script!!!

Solution 2 (Fonctionne mais n'est pas génial)

Donc, en gros, si vous avez un accord mutuel avec l'autre domaine, vous pouvez ajouter une bibliothèque pour gérer le sendmessage. Si vous n'avez pas d'accès à l'autre domaine Continuez à chercher d'autres astuces, car je n'ai pas pu trouver ou justifier pleinement celles que j'ai trouvées.

Ainsi, l'autre domaine inclura ces éléments dans sa balise Head.

<script src="scripts/jquery-1.5.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery.postmessage.min.js" type="text/javascript"></script>
<script src="scripts/club.js" type="text/javascript"></script>

Dans le club.js il y a juste quelques appels personnalisés que j'ai fait pour les appels de redimensionnement et contient

 $(document).ready(function () {   
    var parent_url = decodeURIComponent( document.location.hash.replace( /^#/, '' ) ),link;
//Add source url hash to each url to authorise callback when navigating inside the frame.Without this clicking any links will break the communication and no messages will be received
$('a[href]').each(function(){ 
     this.href = this.href + document.location.hash ;
});
//Get the dimensions and send back to calling page.
var h1 = document.body.scrollHeight;
var w1 = document.body.scrollWidth;
$.postMessage({ if_height: h1, if_width: w1 }, parent_url, parent );
  });

Et votre page fera tout le travail et aura un joli script...

  //This is almost like request.querystring used to get the iframe data
  function querySt(param, e) {
         gy = e.split("&");
         for (i = 0; i < gy.length; i++) {
             ft = gy[i].split("=");
             if (ft[0] == param) {
                 return ft[1];
             }
         }
     }

     $(function () {
         // Keep track of the iframe dimensions.
         var if_height;
         var if_width;
         // Pass the parent page URL into the Iframe in a meaningful way (this URL could be
         // passed via query string or hard coded into the child page, it depends on your needs).
         src = 'http://www.OTHERDOAMIN.co.uk/OTHERSTARTPAGE.htm' + '#' + encodeURIComponent(document.location.href),
         // Append the Iframe into the DOM.
         iframe = $('<iframe " src="' + src + '" width="100%" height="100%" scrolling="no" frameborder="0"><\/iframe>').appendTo('#iframe');

         // Setup a callback to handle the dispatched MessageEvent event. In cases where
         // window.postMessage is supported, the passed event will have .data, .origin and
         // .source properties. Otherwise, this will only have the .data property.
         $.receiveMessage(function (e) {
             // Get the height from the passsed data.
             //var h = Number(e.data.replace(/.*if_height=(\d+)(?:&|$)/, '$1'));
             var h = querySt("if_height", e.data);
             var w = querySt("if_width", e.data);

             if (!isNaN(h) && h > 0 && h !== if_height) {
                 // Height has changed, update the iframe.
                 iframe.height(if_height = h);
             }
             if (!isNaN(w) && w > 0 && w !== if_width) {
                 // Height has changed, update the iframe.
                 iframe.width(if_width = w);
             }
             //For debugging only really- can remove the next line if you want
             $('body').prepend("Recieved" + h + "hX" + w + "w .. ");
             // An optional origin URL (Ignored where window.postMessage is unsupported).
           //Here you must put the other domain.com name only! This is like an authentication to prevent spoofing and xss attacks! 
         }, 'http://www.OTHERDOMAIN.co.uk');
     });

OPTION 3

Il existe maintenant une petite bibliothèque JS pour gérer le redimensionnement des iFrames inter-domaines. Il faut toujours que l'iFrame contienne un peu de JavaScript, mais il ne s'agit que de 2,8k (765 octets compressés) de JS natif qui n'a pas de dépendances et qui ne fait rien tant qu'il n'est pas appelé par la page parent. Cela signifie que c'est un invité agréable sur les systèmes des autres.

Ce code utilise mutationObserver pour détecter les modifications du DOM et guette également les événements de redimensionnement, de sorte que l'iFrame reste à la taille du contenu. Fonctionne dans IE8+.

https://github.com/davidjbradshaw/iframe-resizer

0voto

sparkholiday Points 72

Avez-vous examiné les attributs "object-fit" de HTML5 ? Il met à l'échelle les vidéos et les images dans l'iframe, au lieu de mettre à l'échelle l'iframe (c'est bien si vous prenez une image de taille moyenne qui finit par faire 5 000 pixels de large). L'option "fit" (les autres sont "cover" et "fill") utilise une sorte de boîte à lettres pour adapter la source tout en préservant les rapports d'aspect. Pour ceux qui ne connaissent pas HTML5, il semble qu'il existe un grand nombre de polyfills disponibles. Celui-ci est génial, mais un bug au niveau d'Edge le rend incompatible avec le nouveau cauchemar de Microsoft depuis environ un an : https://github.com/anselmh/object-fit

EDIT : Pour contourner les problèmes de domaine croisé, vous pouvez toujours simplement faire le travail dans une extension Chrome Content script, puisqu'il pense qu'il fait partie de la page sur laquelle vous collez votre iframe.

0voto

Limitless isa Points 270

HTTPS un autre lien obtient la hauteur à iframe autoheight

https://-a.com contenu :

 <!DOCTYPE html>
    <html>
    <head>
        <title>Test Page</title>
    </head>
    <body>
        Test Page:
        <hr/>
        <iframe id="iframe" src="https://-b.com" style="width:100%;min-height:600px;border:none;" scrolling="no" ></iframe>
        <script>
        // browser compatibility: get method for event 
        // addEventListener(FF, Webkit, Opera, IE9+) and attachEvent(IE5-8)
        var myEventMethod = 
            window.addEventListener ? "addEventListener" : "attachEvent";
        // create event listener
        var myEventListener = window[myEventMethod];
        // browser compatibility: attach event uses onmessage
        var myEventMessage = 
            myEventMethod == "attachEvent" ? "onmessage" : "message";
        // register callback function on incoming message
        myEventListener(myEventMessage, function (e) {
            // we will get a string (better browser support) and validate
            // if it is an int - set the height of the iframe #my-iframe-id
            if (e.data === parseInt(e.data)) 
                document.getElementById('iframe').height = e.data + "px";
        }, false);
        </script>
    </body>
    </html>

https://-b.com le contenu de la iframe :

<!DOCTYPE html>
<html>
<head>
    <title>Test Iframe Content</title>
    <script type="text/javascript">
    // all content including images has been loaded
    window.onload = function() {
        // post our message to the parent
        window.parent.postMessage(
            // get height of the content
            document.body.scrollHeight
            // set target domain
            ,"*"
        )
    };
</script>
</head>
<body>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>1
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>2
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>3
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>4
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>5
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>6
</body>
</html>

Table de travail :

xcom http > ycom https TRAVAIL

xcom https > ycom https TRAVAIL

xcom http > ycom http TRAVAIL

xcom https > ycom http TRAVAIL

Test Work Screenshot

-2voto

anothershrubery Points 6104

Cherchez-vous à trouver la hauteur de la page contenue dans l'iframe ? J'ai fait fonctionner un javascript qui vérifie la hauteur du contenu de l'iframe puis règle la hauteur de l'iframe sur la hauteur du contenu.

var Height = document.getElementById('iFrameId').contentWindow.document.body.scrollHeight;

document.getElementById('iFrameId').height = Height;

Toutefois, cela ne fonctionne que si la page que vous affichez dans l'iframe se trouve sur le même domaine. Si ce n'est pas le cas, vous ne pouvez pas accéder aux informations requises. D'où l'erreur d'accès refusé.

-2voto

user2961151 Points 1

Pour redimensionner un iframe, voici un simple script :

ceci va dans la tête : (ceci a été écrit pour un script php script, pour le html, changez le ' en " et le \" en '....

<script type='text/javascript'>
<!--
function resizeIframe(id){
/*
this.obj=obj
//this.obj.width=null
//this.obj.width=window.frames[\"sizeframe1\"].document.body.scrollWidth
this.obj.style.height=\"\" // for Firefox and Opera
setTimeout(\"this.obj.style.height=this.obj.contentWindow.document.body.scrollHeight+(notIE?heightOffset:0)\",10) // setTimeout required for Opera
*/

el=document.getElementById(id)
el.style.height='200px' // for Firefox and Opera
setTimeout('el.style.height=el.contentWindow.document.body.scrollHeight+\"px\"',1) // setTimeout required for Opera
}

// -->
</script>"

fin de la tête

ceci va dans le corps (rappelez-vous, ceci a été écrit pour un script php, pour le html changez tous les ' en " et les '" en '...)

<iframe onload='resizeIframe(this.id)' allowTransparency=\"true\" name='ccpaymentwindow' id='sizeframe1' marginwidth='1' marginheight='1' height='700' width='690' border='0' frameborder='1' scrolling='no' src='ccmslink.php?variable1=" . $variable1 . "'></iframe>

bonus : il y a quelques conseils au-dessus. Comme il est paramétré pour le scripting php, vous pouvez en faire beaucoup... pour en savoir plus, faites-en plus...

la clé est "sizeframe1" .... pour plusieurs "resizers" sur la même page, copiez le même script mais changez l'id dans iframe et le nom dans le script dans head, et viola ! vous avez plusieurs resizers sur la même page...ça marche très bien !

ont le phun.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X