JasonDavis JasonDavis - 27 days ago 6
Javascript Question

Change a parent window's URL using history pushState when link in Iframe is clicked

I have a page that has a header and sidebar with a right content panel that is an Iframe.

In a page loaded into the right content panel, I am trying to have a clicked link update the Browser URL in the parent window to the URL of the new page that is loaded into the Iframe.

I do not want the actual parent window to reload the URL but simply to update the URL in the address bar.

Something like:

window.history.pushState('obj', 'newtitle', '/bookmarks/list/');


Is this possible from an Iframe?

Answer

I was able to accomplish updating the parent windows URL in the address bar using history.pushState by sending the new URL to the parent from the child Iframe window using postMessage and on the parent window listening for this event.

WHen the parent receives the child iframes postMessage event, it updates the URL with pushSTate using the URL passed in that message.

Child Iframe

<script>
// Detect if this page is loaded inside an Iframe window
function inIframe() {
    try {
        return window.self !== window.top;
    } catch (e) {
        return true;
    }
}

// Detect if the CTRL key is pressed to be used when CTRL+Clicking a link
$(document).keydown(function(event){
    if(event.which=="17")
        cntrlIsPressed = true;
});
$(document).keyup(function(){
    cntrlIsPressed = false;
});
var cntrlIsPressed = false;

// check if page is loaded inside an Iframe?
if(inIframe()){
    // is the CTRL key pressed?
    if(cntrlIsPressed){
        // CTRL key is pressed, so link will open in a new tab/window so no need to append the URL of the link
    }else{

        // click even on links that are clicked without the CTRL key pressed
        $('a').on('click', function() {

            // is this link local on the same domain as this page is?
            if( window.location.hostname === this.hostname ) {

                // new URL with ?sidebar=no appended to the URL of local links that are clicked on inside of an iframe
                var linkUrl = $(this).attr('href');
                var noSidebarUrl = $(this).attr('href')+'?sidebar=no';

                // send URL to parent window
                parent.window.postMessage('message-for-parent=' +linkUrl , '*');

                alert('load URL with no sidebar: '+noSidebarUrl+' and update URL in arent window to: '+linkUrl);

                // load Iframe with clicked on URL content
                //document.location.href = url;
                //return false;
            }
        });
    }
}
</script>

Parent window

<script>

// parent_on_message(e) will handle the reception of postMessages (a.k.a. cross-document messaging or XDM).
function parent_on_message(e) {
    // You really should check origin for security reasons
    // https://developer.mozilla.org/en-US/docs/DOM/window.postMessage#Security_concerns
    //if (e.origin.search(/^http[s]?:\/\/.*\.localhost/) != -1
    //    && !($.browser.msie && $.browser.version <= 7)) {
        var returned_pair = e.data.split('=');
        if (returned_pair.length != 2){
            return;
        }
        if (returned_pair[0] === 'message-for-parent') {
            alert(returned_pair[1]);
            window.history.pushState('obj', 'newtitle', returned_pair[1]);
        }else{
            console.log("Parent received invalid message");
        }

    //}
}

jQuery(document).ready(function($) {
    // Setup XDM listener (except for IE < 8)
    if (!($.browser.msie && $.browser.version <= 7)) {
        // Connect the parent_on_message(e) handler function to the receive postMessage event
        if (window.addEventListener){
            window.addEventListener("message", parent_on_message, false);
        }else{
            window.attachEvent("onmessage", parent_on_message);
        }
    }
});
</script>