web-dev-qa-db-fra.com

redimensionnement iframe interdomaine

Comment redimensionner un iframe d'un autre domaine

-Modifier

Faites défiler vers le bas pour certaines solutions .. ou lisez comment ne pas faire ceci: D

Après de nombreuses heures de piratage 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é beaucoup de techniques en vain.

pour vous faire gagner du temps, n'utilisez même pas sendMessages pour les communications entre domaines.Il existe des plug-ins pour HTML <5 que j'utilise - Allez au bas de votre Bel exemple :)


Ces derniers jours, j'ai essayé d'intégrer un iframe à un site. C’est une solution à court terme pendant que l’autre partie développe une API (cela pourrait prendre des mois ...). Et parce que c’est une solution à court terme, nous voulons utiliser easyXDM- J'ai accès à l’autre domaine, mais il est assez difficile de leur demander de ajoute 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 évoque le chrome et le safari, je ne peux donc 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 article sur l'utilisation de scrollheight pour essayer de redimensionner le formulaire. En théorie, cela fonctionne bien, mais je ne pouvais pas l'appliquer correctement à l'aide de la hauteur de défilement iframes.

document.body.scrollHeight

Qu'il utilise de manière évidente la hauteur du corps (impossible d'accéder à ces propriétés, 100% est basé sur l'affichage client de canvaz et non sur la hauteur du document x-domain)

J'ai essayé d'utiliser jquery pour obtenir la hauteur d'iframes

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

renvoyer des valeurs différentes en chrome et c'est-à-dire - ou tout simplement 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 et que l'élément en chrome de l'iframe est bladdy, il me montre les dimensions du document à l'intérieur de l'iframe (en utilisant jquery x-domain pour obtenir l'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-Browser rend à nouveau la page à l’aide de son moteur de rendu intégré pour calculer tous ces paramètres, mais elle n’est attachée nulle part pour empêcher la fraude entre domaines.)

HTML4

J'ai lu la spécification de HTML4.x et il est indiqué qu'il devrait y avoir des valeurs en lecture seule exposées via document.element mais que son accès est refusé via jquery

Cadre proxy

Je suis allé dans la voie de proxy du site en arrière et de calculer ce qui est OK .. jusqu'à ce qu'un utilisateur se connecte via l'iframe et que le proxy obtienne une page de connexion au lieu du contenu réel. Aussi, pour certains, appeler deux fois la page 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/

Re-rendre la page

Je ne suis pas allé aussi loin, mais il existe des moteurs JScript qui vont examiner la source et restituer la page en fonction du fichier source. mais cela nécessiterait le piratage de ces scripts ... et ce n'est pas une situation idéale pour les entités commerciales ... et certains involent des applets Java pures ou un rendu côté serveur

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

http://htmlunit.sourceforge.net/ <-Java not jscript

http://maxq.tigris.org/


EDIT 09-2013UPDATE

Tout cela peut être fait avec les sockets HTML5. Mais easyXDM constitue un excellent secours pour les pages de réclamation non HTML5.

Solution 1 Très bonne solution!

Utiliser easyXDM

Sur votre serveur, vous configurez 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 des appelants, il leur suffit d'ajouter les noms intermiedate_frame html et easyXDM.js au même endroit. Comme un dossier parent - vous pouvez alors accéder aux répertoires relatifs ou à un dossier contenu juste pour vous.

OPTION 1

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

Ensuite, ils peuvent simplement ajouter un simple jscript à la fin de chaque page pour laquelle le redimensionnement est nécessaire. Pas besoin d'inclure 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, alors les pages de l'autre domaine doivent inclure la largeur de la page dans un style pouvant ressembler à quelque chose de similaire à:

<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 de manière un peu étrange et tente bien de deviner ce qu'il devrait être. Il ne diminuera pas si vous en avez besoin.

OPTION 2

Modifie l'image intermédiaire à interroger pour connaître les modifications

Votre cadre intermédiaire devrait ressembler à quelque chose comme ça.

    <!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>

Il serait peut-être plus efficace de contrôler l’intervalle si la taille change et de ne l’envoyer que si les changements de dimensions ne sont pas au-delà de la publication de messages toutes les 500 ms. Si vous implémentez cette vérification, vous pouvez modifier le vote aussi bas que 50 ms! s'amuser


Travaillez entre navigateurs et c'est rapide. Excellentes fonctionnalités de débogage !!

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

Solution 2 (fonctionne mais pas génial)

Donc, fondamentalement, si vous avez un accord mutuel avec l'autre domaine, vous pouvez ajouter une bibliothèque pour gérer sendmessage. Si vous n'avez aucun accès à l'autre domaine .. Continuez à chercher plus de piratages, car je ne pouvais pas trouver ou justifier complètement ceux que je trouvais.

Donc, l'autre domaine inclura ces derniers dans la 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, quelques appels personnalisés que j'ai faits pour redimensionner des appels sont contenus.

 $(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 difficile et a 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 s’agit maintenant d’une petite bibliothèque JS pour la gestion du redimensionnement d’iFrames interdomaines. Elle nécessite toujours que l’iFrame contienne un peu de JavaScript. Toutefois, il ne s’agit que de 2,8k (765 octets Gzipped) de JS natif ne dépendant et il ne fait rien jusqu'à ce qu'il soit appelé par la page parent. Cela signifie que c'est un gentil invité sur les systèmes d'autres personnes.

Ce code utilise mutationObserver pour détecter les modifications du DOM et recherche également des événements de redimensionnement, de sorte que l'iFrame reste dimensionné en fonction du contenu. Fonctionne dans IE8 +.

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

82
ppumkin

Le problème est le suivant: il n’ya pas d’autre moyen que d’utiliser la messagerie inter-domaines pour cela car vous devez obtenir la hauteur calculée d’un document d’un domaine à un autre.

Donc, soit vous faites cela en utilisant postMessage (fonctionne dans tous les navigateurs modernes), soit vous passez 5 minutes à adapter l’exemple resize iframe de easyXDM. 

L’autre partie a juste besoin de copier quelques fichiers sur son domaine et d’ajouter une seule ligne de code à son document.

10
Sean Kinsey

Semblable à ce que Sean a mentionné, vous pouvez utiliser postMessage. J'ai passé tellement de temps à essayer différentes manières de redimensionner iframe avec inter-domaines, mais pas de chance avant de tomber sur ce blog génial de David Walsh: http://davidwalsh.name/window-iframe

Ceci est une combinaison de mon code et de la solution de David. Ma solution est spécialement conçue pour le redimensionnement des iframes.

Dans la page enfant, recherchez la hauteur de la page et transmettez-la à la page parent (qui contient l'iframe). Remplacez element_id par votre identifiant d'élément (html, body, peu importe).

<script>
function adjust_iframe_height(){
    var actual_height = document.getElementById('element_id).scrollHeight;
    parent.postMessage(actual_height,"*"); 
    //* allows this to post to any parent iframe regardless of domain
}
</script>

<body onload="adjust_iframe_height();"> 
//call the function above after the content of the child loads

Sur la fenêtre parente, ajoutez ce code. Remplacez iframe_id par votre ID iframe:

<script>
// Create IE + others compatible event handler
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child window
eventer(messageEvent,function(e) {
  console.log('parent received message!:  ',e.data);
  document.getElementById('iframe_id').height = e.data + 'px';
},false);
</script>

Si vous ouvrez la console, vous verrez la hauteur en cours d’impression dans le journal de la console. Cela vous aidera dans le débogage, c'est pourquoi je l'ai laissé là. 

Meilleur, Baker

23
Baker Humadi

Après avoir examiné différentes solutions à ce problème, j'ai fini par écrire une simple petite bibliothèque afin de prendre en compte un certain nombre de cas d'utilisation différents. Comme j'avais besoin d'une solution qui prenne en charge plusieurs iFrames générés par les utilisateurs sur une page de portail, le navigateur pris en charge est redimensionné et peut faire face au chargement JavaScript de la page hôte après l'iFrame. J'ajoute également une prise en charge du dimensionnement à width et d'une fonction de rappel et autorise le remplacement de body.margin, car vous souhaiterez probablement que cette option soit définie sur zéro.

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

Le code iframe est juste un petit JavaScript autonome, ce qui en fait un bon invité sur les pages de contacts.

Le script est ensuite initialisé sur la page Hôte avec les options disponibles suivantes. 

iFrameResize({
    log                    : true,  // For development
    autoResize             : true,  // Trigering resize on events in iFrame
    contentWindowBodyMargin: 8,     // Set the default browser body margin style (in px)
    doHeight               : true,  // Calculates dynamic height
    doWidth                : false, // Calculates dynamic width
    enablePublicMethods    : true,  // Enable methods within iframe hosted page 
    interval               : 32,    // interval in ms to recalculate body height, 0 to disable refreshing
    scrolling              : false, // Enable the scrollbars in the iFrame
    callback               : function(messageData){ // Callback fn when message is received
        $('p#callback').html(
            '<b>Frame ID:</b> '    + messageData.iframe.id +
            ' <b>Height:</b> '     + messageData.height +
            ' <b>Width:</b> '      + messageData.width + 
            ' <b>Event type:</b> ' + messageData.type
        );
    }
});
6
David Bradshaw

Avez-vous examiné les attributs HTML5 "ajustement d'objet"? Met la vidéo/les images à l'échelle de l'iframe, plutôt que de la mettre à l'échelle (pratique si vous saisissez une image de taille moyenne dont la largeur est finalement de 5 000 pixels). L'option "Ajuster" (les autres sont "Couverture" et "Remplir") utilise une approche de type boîte aux lettres pour ajuster le source tout en préservant les proportions. Pour être visionné par le moins de HTML5, il semble y avoir un grand nombre de polyfill disponibles. Celui-ci est excellent, mais un bogue à la fin d'Edge l'a maintenu incompatible avec New Nightmare de Microsoft pendant environ un an, maintenant: https://github.com/anselmh/object-fit

EDIT: pour résoudre les problèmes de domaines multiples, vous pouvez toujours effectuer le travail dans un script de contenu d'extension Chrome, car il pense que cela fait partie de la page sur laquelle vous collez votre iframe.

0
sparkholiday

HTTPS un autre lien prend de la hauteur à iframe autoheight

https://-a.com content:

 <!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 contenu 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 WORK

xcom https> ycom https WORK

xcom http> ycom http WORK

xcom https> ycom http WORK

Test Work Screenshot

0
Limitless isa

À l'heure actuelle, il n'y a que 4 solutions que je connaisse:

Seul le troisième peut résoudre de nombreux problèmes. Par exemple, vous pouvez créer un iFrame réactif; fermez-le de l'intérieur ou vous pourrez communiquer avec lui. Mais pour cela, vous avez besoin de la solution de contournement "optionnelle" d'iFrame dans Iframe (facultative).

J'ai créé un article à ce sujet avec l'exemple suivant: iFrame interdomaine piloté par événement

0

Au lieu d'utiliser scroll = no sur l'iframe, je le change en "auto". Ensuite, je reçois la taille de la fenêtre réelle 

$(window).height();

et utilisez-le comme attribut iframe height.

Eh bien, le résultat est ...

Nous ne ferons jamais défiler la "page", mais uniquement le "iframe". Lorsque vous naviguez, le parchemin importe peu, mais le plus important est qu’il n’ya qu’un seul.

Eh bien, il y a le problème de l'utilisateur qui redimensionne simplement la fenêtre pendant qu'il navigue. Pour résoudre ce problème, j'utilise:

setInterval(getDocHeight, 1);

Avez-vous pensé que cette solution causerait des bugs? Cela fonctionne pour moi, et sur l'iFrame, j'avais un contact dynamique généré par php. J'ai peur des bugs futurs avec ça ...

0
Elton Morais