Snippets | Nomads | Projects | Applications


Nomads | Philosophy | Index


NOMADS: | IFrame-Host | IFrame-Host-Demo | Sic et Non | IFrame-Source | HowTo


Dynamic iFrame Hosting Code

Auto-resizing iFrames for Dynamic/Responsive Pages

in JavaScript
by Kirk Siqveland
© 2022 CC-BY-NC-SA 4.0


You should only need these two files, and you should not need to modify them.

Everything In one Zip file: >> iFrame_Host.zip <<

or

The Host-Page Script File

The Host Page Script file:
>Show More<
/** ---------------------------------------------------------------------------------------------
    iframe_host.js 
    version 2022-11-10

    Copyright 2022 Kirk Siqveland (Kirk@SnippetsPub.com)
    Released under Creative Commons: CCBYNCSA40
    https://www.snippetspub.com/License/CCBYNCSA40hr     

    This code was initially developed to work with the PMWiki wiki framework, 
    however, it also works independently of the PMWiki environment.   

    For Non-PmWiki Sites see 
        https://www.snippetspub.com/Nomads/IFrame-Host

    For PmWiki Sites you may also want to see 
        https://www.pmwiki.org/wiki/Cookbook/BridgeSite

---------------------------------------------------------------------------------------------**/

/** First we make an array if all the BridgeSite Frames, then configure some style settings, **/
        var HostFrames  = document.getElementsByClassName('BridgeFrame') ;
        var FrameTally  = HostFrames.length ;
        var Injected    = new Array() ;
        var Tally       = 0 ;    
        var loadTimer       ;

    /** For each instance of a BridgeFrame we set an ID value and styles... 
        Included here to ensure things work better from the start, but you might
        want to remove the .style settings and handle it in your CSS files                  **/
        for (var tick = 0; tick < FrameTally; tick++) {
            HostFrames[tick].setAttribute("hfid", tick)  ;            
            HostFrames[tick].style.width      = "100%"   ;
            HostFrames[tick].style.margin     = "0"      ;
            HostFrames[tick].style.padding    = "0"      ;
            HostFrames[tick].style.border     = "none"   ;
            // HostFrames[tick].style.overflow   = "hidden" ;
        }

    /** -- Listen for messages from hosted ("guest") iframe-page(s)  **/
        window.addEventListener('message', function (RxMsg) {
            /** -- Parse Received Message - comma delimited  **/
                msg = RxMsg.data.split(",");
                /**  first number is height, second is array position **/
                /**  defaults to 0 if none given. **/
            
            switch(msg[0]) {
                case "SizeMe":
                    if (Number(msg[1]) > 0){
                        var HFid = Number(msg[2]||0) ;
                        HostFrames[HFid].style.height = msg[1] + "px" ;
                    }
                    break;

                case "guestLoaded":
                    /** Debugging or Logging option  **/
                    console.log("RX guestLoaded: "+msg[1]) ;
                    /** This bit allows a loading.gif as background for the iframe parent **/
                        var peg = Number(msg[1]) ;
                        try{HostFrames[peg].parentElement.style.background = "none" ;}
                        catch{console.log("guestLoaded clear loader.gif FAIL");}
                    break ;

                // case "echo":
                //     console.log("Echo recieved: "+msg[1]) ;
                //     break;

                default:
                    console.log("Rx message unkown: "+RxMsg.data);
            }                 
        }, false);

/** ----------------------------------------------------------------------------
        This Injects the iframe_guest.js file into the guest webpage
       ( Only works when guest has the same domain & port & protocol as the host. )
    ----------------------------------------------------------------------------**/

    /** Prepare the path for the injected iframe_guest.js file              **/
    /** getting the url for the current script (this file):                 **/
        var scripts     = document.getElementsByTagName("script")         ;
        /** This should be the latest script loaded, so:    **/
        var ScriptSRC   = scripts[scripts.length-1].src ;  //Script file path

    /** Swap in the iframe_guest.js filename, since they should be in the same place **/
        ScriptSRC           = ScriptSRC.replace("iframe_host","iframe_guest") ;
        console.log("ScriptSRC = "+ScriptSRC);
        if(typeof(ScriptSRC) == "undefined" || ScriptSRC == null || ScriptSRC == "") {
            ScriptSRC = document.currentScript.src ; }


    function scriptLoader() { 
        clearTimeout(loadTimer) ;
        Tally = 0 ;

        for (   var tick = 0; tick < FrameTally; tick++) {
            /** Tally all the guest already loaded (testing for title) **/

            var guestDoc  = HostFrames[tick].contentDocument;  

            if(guestDoc === null || guestDoc.title === undefined){ return; }

            /** We use the Title of the Guest document to indicate page loaded **/
            /** If the document has not title, then injecting will not work... **/
            if(guestDoc.title !== ""){ Tally++; }         
        }

        if( Tally < FrameTally ){ 
          /** If not all frames are loaded... wait and try again. **/
            loadTimer = window.setTimeout(scriptLoader, 120); 
            return;
        } else{
            console.log("scriptLoader - iFrames All Loaded!");
        }        


        for (   var tick = 0; tick < FrameTally; tick++) {  
            var guestDoc  = HostFrames[tick].contentDocument ; 
            /** It is possible to get this far and still not be able to inject... so **/
                if (guestDoc.body === null) return;   
             
            /** Test if guest iFrame includes iframe_guest script already  **/
            if(Injected[tick] === undefined || Injected[tick] !== "done"){
                if(guestDoc.body.innerHTML.includes("iframe_guest")){
                    Injected[tick] = "done" ;
                    // console.log("scriptLoader - iframe_guest already Loaded!");
                }else{              
                    /**  Build and inject a script element with the iframe_guest.js **/
                    /**  Which must be in the same directory as the iframe_host.js  **/
                        const newNode     = document.createElement("script");
                              newNode.src = ScriptSRC  ;   
                              newNode.setAttribute('id', 'iframe_guest');  

                        try{  guestDoc.body.appendChild(newNode) ; }
                            catch(err) {
                                loadTimer = window.setTimeout(scriptLoader, 500);
                                console.log(" append Sript Error: err.message = " + err.message);
                                return;
                            }
                        console.log("scriptLoader - Success injecting iFrame "+tick);
                        /** Flag completed injection  **/
                        Injected[tick] = "done" ;
                }
            }
        }  
    } /**  end of scriptLoader()  **/


    /** Run the scriptLoader once this file is loaded... **/
        scriptLoader() ;

The Guest-Page Script File

The Guest Page Script file:
> Show More <
/** ------------------------------------------------------------------------------------
    iframe_guest.js 

    Copyright 2022 Kirk Siqveland (Kirk@CyberTamer.com)

    This file is distributed under the terms of the GNU General Public 
    License as published by the Free Software Foundation; either 
    version 2 of the License.     

    This code was developed to work with the PMWiki wiki framework, 
    however, it also works independently of the PMWiki environment.   

    USAGE:
    for non-pmwiki sites:
    >> You will need a reference in your html to the iframe_host.js 
    >> iframe_host.js and iframe_guest.js must be in the same directory.
    >> the <iframe> tag in your html needs:
    >> class="BridgeFrame" and a sequential number from 0 for id  e.g. id="0" 

    >> in PMWiki you need the BridgeSite.php file in your {pmwiki}/cookbook directory
    >> you will also need the following lines into your {pmwiki}/local/config.php file:

        ## Include Code for BridgeSite - iFrame insertion tool recipe
            include_once ('cookbook/BridgeSite.php') ;
        ## Insert the iframe_host.js script to the bottom of your Skin template.
            $HTMLFooterFmt['BridgeSite'] = '<script src="$FarmPubDirUrl/iframe_host.js"></script>' ;

    >> See https://www.pmwiki.org/wiki/Cookbook/BridgeSite

/** -------------------------------------------------------------------------------------**/
/** -------------------------------------------------------------------------------------**/

    /** Timer Loop Rate  **/    
        TimerLoopRate = 400 ;

    /** Make sure this Guest will fit properly in the Host iFrame  **/
        document.body.style.margin   = "0"       ;
        document.body.style.overflow = "hidden"  ; 

    /** Get page id from host-iframe attribute "hfid"   (assigned in the host page ) **/
        var MyID =  window.frameElement.getAttribute("hfid") ;  

    /** The most dependable way to catch size changes: run a timer and check.  **/
        var resizeTimer     ;  // Establish a timer to use later
        var loadingTimer    ;  // Establish a timer to use later
        var pegHeight   = 0 ;  // Remember sizing changes to reduce cycle-time

/** -- Send messages to the parent/host window --  **/
    function sendMessage(TxMsg) {
        window.parent.postMessage(TxMsg, '*') ;
    }

/** -- Notify Host Only Once page is loaded **/
    function loadTimer(){
        clearTimeout(loadingTimer) ;
        if(MyID === null||MyID === NaN){
            loadingTimer = setTimeout(loadTimer, TimerLoopRate) ;
        }else{
            sizeTest() ;
            sendMessage("guestLoaded,"+MyID+",") ;
            var gotHeight = document.body.offsetHeight; 
            sendMessage("SizeMe," + gotHeight + "," + MyID + ",") ; 
            // loadingTimer = setTimeout(loadTimer, 3000) ;
        }
    }        

/** -- Check Current size against save size --  **/
    function sizeTest(){
        try {
            var gotHeight = document.body.offsetHeight;            
        }
        catch{
            resizeTimer = setTimeout(sizeTest, TimerLoopRate) ;
            return;
        }

        if (gotHeight != pegHeight){   
            /** Save the new size as a benchmark (peg)  **/
                pegHeight = gotHeight ;
            /** inform our Host of the change in size:  **/     
                sendMessage("SizeMe," + gotHeight + "," + MyID + ",") ; 
        }  
        resizeTimer = setTimeout(sizeTest, TimerLoopRate) ;
    }

/** Listen for messages from parent window  **/
    document.addEventListener('message',  function (RxMsg) {
        console.log ("Guest - got message: "+ RxMsg.data + " MyID:"+MyID) ; 
        msg = RxMsg.data.split(",") ;

        /** switch for easier development/mod  **/
        switch(msg[0]) {
              // case "ping":
              //   sendMessage("echo, pinged:" + msg[1] + " --  Respond:" + MyID + "#") ; 
              //   break ;

              case "reset":
                sizeMsg(0) ;
                break ;

              case "ID":
                console.log("Guest rx ID Message: " + msg[1]);
                // MyID = msg[1] ;
                // sizeMsg(0)    ;   
                break ;

              default:
                //console.info("Message Received = "+ RxMsg.data);
        }

        console.log ("Guest - got message: "+ RxMsg.data + " MyID:"+MyID);
            
    }, false) ;

/** -- RESPOND to RESIZE events **/
    window.addEventListener('resize', sizeTest, false);

/* Run the Timer-tests: */
loadTimer() ;
sizeTest()  ;



Here are copies of the HTML files I use for the Demo:

A Demo Host-Page HTML File

The Host Page Demo HTML file:
> Show More <
<!DOCTYPE html>
<html lang="en">
<head>
    <title>iFrame Host Test Page</title> 
    <meta charset="UTF-8"> 

    <style> 
        body {     
          color:            rgb(233, 230, 223) ;
          background-color: rgb( 34,  44,  51) ;
        }
        a  { color:         rgb(233, 230, 223) ; }
        h3 { color:         rgb(233, 230, 223) ; }

        .iframe_loading{
            background:url('loader.gif') center center no-repeat;
        }

    </style>

</head>
<body>
    <h1>iFrame Host Test Page</h1> 
    <p>Dynamic iFrame Hosting Code<br/>
    © 2022 by Kirk B. Siqveland<br/>
    licensed under CC BY-NC-SA 4.0</p>
    <br/><br/>
    <p>Details and Download Source Code from :<br/>
     <a href="https://www.snippetspub.com/Nomads/IFrame-Host">https://www.snippetspub.com/Nomads/IFrame-Host</a> 
     <br/><br/><hr><br>

    <p>Try clicking on each "Guest" iFrame</p>
    <p>Also, try resizing the window</p>
    <br/><br/>
    <h3>First Guest:</h3>
    <div class="iframe_loading">
        <iframe src="guest.html" class="BridgeFrame"  crossorigin="anonymous"></iframe>
    </div>

    <h3>Second Guest</h3>
    <div class="iframe_loading">
        <iframe src="guest.html" class="BridgeFrame"  crossorigin="anonymous"></iframe>
    </div>    

    <h3>Third Guest</h3>
    <div class="iframe_loading">
        <iframe src="guest.html" class="BridgeFrame"  crossorigin="anonymous"></iframe>
    </div>

    <script src="iframe_host.js"></script>
</body>
</html>

A Demo Guest-Page HTML File

The Guest Page Demo HTML file:
> Show More <
<!DOCTYPE html>
<html lang="en">
<head>
	<title>iFrame_Host Demo, Test Guest_Page</title>
	<meta charset="UTF-8">
	<style type="text/css">
		#one{
			color: rgb(212,212,212);
		}		
		#two{
			display: none;
			color: yellow;
		}
	</style>
</head>
<body>
	<div id="one">Hljóðs bið ek allar helgar kindir, meiri ok minni mögu Heimdallar; viltu, at ek, Valföðr! vel framtelja forn spjöll fíra, þau er fremst um man. Ek man jötna ár um borna, þá er forðum mik fœdda höfðu; níu man ek heima, níu íviði, mjötvið mœran fyr mold neðan. Ár var alda þar er Ýmir bygði, vara sandr né sær né svalar unnir, jörð fannsk æva né upphiminn, gap var ginnunga, en gras hvergi. Áðr Burs synir bjöðum um ypðu, þeir er Miðgarð mœran skópu; sól skein sunnan á salar steina, þá var grund gróin grœnum lauki. Sól varp sunnan, sinni mána, hendi inni hœgri um himinjódyr; sól þat ne vissi hvar hon sali átti, máni þat ne vissi hvat hann megins átti, stjörnur þat ne vissu hvar þær staði áttu.

	Þá gengu regin öll á rökstóla, ginnheilug goð, ok um þat gættusk; nátt ok niðjum nöfn um gáfu, morgin hétu ok miðjan dag, undorn ok aptan, árum at telja. Hittusk æsir á Iðavelli, þeir er hörg ok hof hátimbruðu, afla lögðu, auð smíðuðu, tangir skópu ok tól görðu. Tefldu í túni, teitir váru, var þeim vettugis vant ór gulli; unz þrjár kvámu þursa meyjar ámátkar mjök ór jötunheimum. Þá gengu regin öll á rökstóla, ginnheilug goð, ok um þat gættusk: hverr skyldi dverga drótt um skepja ór brimi blóðgu ok ór Bláins leggjum. Þar var Móðsognir mæztr um orðinn dverga allra, en Durinn annarr; þeir mannlíkun mörg um görðu dvergar í jörðu, sem Durinn sagði.
	</div>

	<div id="two">
	<hr/>	
	Nýi, Niði, Norðri, Suðri, Austri, Vestri, Alþjófr, Dvalinn, Nár ok Náinn, Nípingr, Dáinn, Bifurr, Bafurr, Bömburr, Nori, Ánn ok Ánarr, Óinn, Mjöðvitnir. Veggr ok Gandálfr, Vindálfr, Þorinn, Þrár ok Þráinn,  Þekkr, Litr ok Vitr, Nýr ok Nýráðr, nú hefi ek dverga, Reginn ok Ráðsviðr, rétt um talða. Fili, Kili, Fundinn, Nali, Hepti, Vili, Hanarr, Svíurr, Billingr, Brúni, Bildr ok Buri, Frár, Hornbori, Frægr ok Lóni, Aurvangr, Jari, Eikinskjaldi. Mál er dverga í Dvalins liði ljóna kindum til Lofars telja, þeir er sóttu frá  salar steini Aurvanga sjöt til Jöruvalla. Þar var Draupnir ok Dólgþrasir, Hár, Haugspori, Hlévangr, Glóinn, Dori, Ori, Dúfr, Andvari, Skirfir, Virfir, Skafiðr, Ai.

	Álfr ok Yngvi, Eikinskjaldi, Fjalarr ok Frosti, Finnr ok Ginnarr; þat man æ uppi, meðan öld lifir, langniðja tal Lofars hafat. Unz þrír kvámu ór því liði öflgir ok ástkir æsir at húsi, fundu á landi lítt megandi Ask ok Emblu örlöglausa. Önd þau ne áttu, óð þau ne höfðu, lá né læti né litu góða; önd gaf Óðinn, óð gaf Hœnir, lá gaf Lóðurr ok litu góða. Ask veit ek standa, heitir Yggdrasill hár baðmr, ausinn hvíta auri; þaðan koma döggvar þærs í dala falla; stendr æ yfir grœnn Urðar brunni. Þaðan koma meyjar margs vitandi þrjár, ór þeim sal er und þolli stendr; Urð hétu eina, aðra Verðandi, skáru á skíði,  Skuld ina þriðju; þær lög lögðu, þær líf kuru alda börnum, örlög seggja.
	</div>

	<script>
		document.addEventListener('click', function(){
			var showme = document.getElementById("two");
			if(showme.style.display === "block"){
				showme.style.display  = "none"  ;
			}else{
				showme.style.display  = "block" ;
			}
		}, false);
	</script>

	<!-- For differing domains insert guest.js here as a script -->

</body>
</html>