Comment redimensionner un iframe d'un autre domaine
-Éditer
Faites défiler vers le bas pour trouver des solutions ... ou lisez comment NE PAS faire cela: 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é de nombreuses techniques en vain.
Pour gagner du temps, n'empruntez même pas cette voie, utilisez simplement sendMessages pour les communications interdomaines. Il y a des plug-ins pour HTML <5 que j'utilise - Allez en bas pour un bel exemple :)
Depuis quelques jours, j'ai essayé d'intégrer une iframe dans un site. C'est une solution à court terme pendant que l'autre côté développe et 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 c'est déjà assez difficile de leur demander de ajouter l'en-tête p3p tel quel .....
3 iframes
La solution la plus proche que j'ai trouvée était les 3 iframes - mais cela devient mental de chrome et de 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 article 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 ne pouvais pas l'appliquer correctement en utilisant la hauteur de défilement des iframes.
document.body.scrollHeight
Cela utilise évidemment la hauteur du corps (impossible d'accéder à ces propriétés à 100% est basé sur l'affichage canvaz des clients et non sur la hauteur du document x-domaines)
J'ai essayé d'utiliser jquery pour obtenir la hauteur des iframes
$('#frameId').Height()
$('#frameId').clientHeight
$('#frameId').scrollHeight
renvoyer des valeurs différentes dans chrome et ie - ou tout simplement n'ont aucun sens. 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 dans le chrome de l'iframe, il me montre les dimensions des documents à 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é
Maintenant, comment Chrome calcule-t-il cela? (edit-browser re-rend la page en utilisant son moteur de rendu intégré pour calculer tous ces paramètres - mais ne sont attachés nulle part pour éviter la fraude inter-domaines .. donc ..)
HTML4
J'ai lu la spécification de HTML4.x et il y est dit qu'il devrait y avoir des valeurs en lecture seule exposées via document.element mais son accès est refusé via jquery
Cadre proxy
J'ai emprunté la voie consistant à renvoyer le site par proxy et à 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 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/
Rendre la page
Je ne suis pas allé jusque-là, mais il existe des moteurs jscript qui regardent la source et re-rendent la page en fonction du fichier source. mais cela exigerait le piratage de ces jscripts .. et ce n'est pas une situation idéale pour les entités commerciales ... et certaines applets java purs ou le rendu côté serveur
http://en.wikipedia.org/wiki/Server-side_JavaScript
http://htmlunit.sourceforge.net/ <-java pas jscript
MODIFIER LA MISE À JOUR 09-2013
Tout cela peut être fait avec des sockets HTML5. Mais easyXDM est une excellente solution de secours pour les pages de plainte non HTML5.
Solution 1 Très bonne solution!
Utilisation d'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 le html intermiedate_frame et easyXDM.js au même endroit. Comme un dossier parent - alors vous pouvez accéder aux répertoires relatifs ou à un dossier contenu rien que 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 chacune des pages dont vous avez besoin pour le redimensionnement. 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, les pages de l'autre domaine doivent inclure la largeur de la page dans un style qui ressemble à 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, alors le cadre se comporte un peu bizarrement et kind'of essaie de deviner ce qu'il devrait être .. et ne rétrécira pas si vous en avez besoin.
OPTION 2
Modifier le cadre intermédiaire pour interroger les modifications
Votre cadre intermédiaire doit ressembler à 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 pour vérifier si la taille a changé et envoyer uniquement si les dimensions changent avant de publier un message toutes les 500 ms. Si vous implémentez cette vérification, vous pouvez modifier l'interrogation aussi bas que 50 ms! s'amuser
Travaillez sur tous les navigateurs et est rapide. Excellentes fonctionnalités de débogage !!
Excellent Work to Sean Kinsey who made the script!!!
Solution 2 (fonctionne mais pas super)
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 d'autres hacks - parce que je n'ai pas pu trouver ou justifier pleinement ceux que j'ai trouvés.
Donc, l'autre domaine les inclura 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, il y a juste quelques appels personnalisés que j'ai faits pour redimensionner les appels 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 acharné 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 gérer le redimensionnement des iFrames inter-domaines, il faut toujours que l'iFrame contienne un peu de JavaScript, cependant, il ne s'agit que de 2,8k (765 octets gzippés) de JS natif qui n'a pas de dépendances et il ne fait rien tant qu'il n'est pas appelé par la page parent. Cela signifie que c'est un bon invité sur d'autres systèmes de personnes.
Ce code utilise mutationObserver pour détecter les changements DOM et recherche également les événements de redimensionnement, de sorte que l'iFrame reste dimensionné en fonction du contenu. Fonctionne dans IE8 +.