Softstuff Consulting
My occasional musings of a technical nature
  • Send us a message
  • About Softstuff Consulting
  • Privacy Policy
  • Main Website
JavaScript

Sending messages between web pages without falling foul of cross-page scripting errors

by Ian Blair December 27, 2019 No Comments

As web page security has increased talking to your child web pages has gotten more difficult, but there is a simple way, and best of all it won’t throw security errors.

JavaScript comes with a PostMessage function that quickly allows parent pages to talk to children, and even more important for child pages to answer back.

As an example we will need two html pages containing some JavaScript, these will be masterpage.html and childpage.html. The source for this project is available here.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body onload="go()">
    <input type="button" onclick="openwindow()" value="Open Child Window" />
    <br />
    <input type="button" onclick="closewithmessage()" value="Close Child Window"/>
    <br />
    <input type="button" onclick="displaymessage()" value="Display Message" />
    <br />

    <script type="text/javascript">
        var myWindow = null;

        function go() {
            window.addEventListener('message', receiveMessage, false);
        }

        function makemessage(action, value) {
            var obj = new Object();
            obj.action = action;
            obj.value = value;
            return JSON.stringify(obj);
        }


        function receiveMessage(event) {
            if (event.origin = "https://localhost:44323") {
                if (event.data == "closed") {
                    myWindow = null;
                }
            }
        }

        function openwindow() {
            if (myWindow == null) {
                myWindow = window.open("childpage.html", "_blank");
            }
        }

       

        function closewithmessage() {
            if (myWindow != null) {
                myWindow.postMessage(makemessage('close',''), 'https://localhost:44323');               
            }
        }

        function displaymessage() {
            if (myWindow != null) {
                myWindow.postMessage(makemessage('text','This is the message to display'), 'https://localhost:44323');               
            }
        }
    </script>

</body>
</html>

And for childpage.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body onload="go()">
    <h2>Child Page</h2>
    <br/>
    <br/>
    <input type="text" id="textField" value="" />

    <script type="text/javascript">
        function go() {
            window.addEventListener('message', receiveMessage, false);
        }

        
        function receiveMessage(event) {
            if (event) {
                if (event.origin != "https://localhost:44323") return;
                var dta = JSON.parse(event.data);

                switch (dta.action) {

                    case 'close': {
                        event.source.postMessage("closed", "https://localhost:44323");
                        window.close();
                        break;
                    }

                    case 'text': {
                         var field = document.getElementById("textField");
                    if (field != null) field.value = dta.value;
                    }
                }
              
            }
        }
    
    </script>
</body>
</html>

They key to how this works is to create a listener event on the child page, and the master page if you want 2 way communication. This can be done in the onload event.

function go() {
     window.addEventListener('message', receiveMessage, false);
}

The receiveMessage function takes a single parameter of the event.

function receiveMessage(event) {
            if (event) {
                if (event.origin != "https://localhost:44323") return;
             }
}

The function needs to check if the event actually contains any information, and also for security the origin should be checked. If you don’t plan on receiving any cross page information then don’t create an event handler. It is possible to send messages with no origin attached but unless you can be sure your intranet is secure don’t do it.

Inside the event there is a property called event.data that contains the information passed. This can be a normal JavaScript variable or my preferred method is to pass JSON strings so that more than a single piece of information can be passed.

Sending data

Data is sent using the .postMessage function, this is done from the variable containing the window object, in the above text example it is the variable returned after the child window is opened. 

function makemessage(action, value) {
            var obj = new Object();
            obj.action = action;
            obj.value = value;
            return JSON.stringify(obj);
}


function openwindow() {
     if (myWindow == null) {
           myWindow = window.open("childpage.html", "_blank");
     }
}

function closewithmessage() {
            if (myWindow != null) {
                myWindow.postMessage(makemessage('close',''),'https://localhost:44323');               
            }
}

The function openWindow is called and it simply opens a child window, the child window contains the receiveMessage event handler and can receive information from the master window. The makemessage function simply creates a JSON string with two items in it, an ‘action’ value and a ‘value’ value. This allows the child event handler to deal with multiple message.

To close the child window we won’t use the window.close() functionality from the parent, we will send a JSON message like ‘action’:’close’,’value’:” to the child and the event handler that was attached with when the child page was opened will receive it and process it. This should also prevent any annoying ‘Do you want to close’ popup boxes, and it allows you the developer to keep the interface clean without leaving it to the user.

 

 function receiveMessage(event) {
            if (event) {
                if (event.origin != "https://localhost:44323") return;
                var dta = JSON.parse(event.data);

                switch (dta.action) {

                    case 'close': {
                        event.source.postMessage("closed", "https://localhost:44323");
                        window.close();
                        break;
                    }

                    case 'text': {
                         var field = document.getElementById("textField");
                    if (field != null) field.value = dta.value;
                    }
                }              
         }
 }

The event handler decodes the JSON and contains a switch statement that handles each kind of message. As you can see there is a ‘text’ option that will transfer plain text to the child page, but if you look at the ‘close’ statement closer you can see it tries to pass a message back to the parent using the event.source.postMessage statement. The source property of the event property contains the handle of the source of the message so we can easily send one back without having to use a call like this.parent.

function go() {
            window.addEventListener('message', receiveMessage, false);
}

function receiveMessage(event) {
     if (event.origin = "https://localhost:44323") {
           if (event.data == "closed") {
                myWindow = null;
            }
     }
}

And in the master page we created an event listener to handle the returned message and clear the window variable after the child window has closed. This ensures that the global variable used to store the child window handle is available for reuse even though the child window closed itself.

This is such a simple and effective method to pass information between web pages without worrying about cross page scripting errors or issues when you deploy to production systems.

cross page scriptingjavascriptmessages

  • Previous Flush the DNS cache in Windows 105 years ago
  • Next Access a Dynamics365 embedded webresource5 years ago

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • How to make your Powershell scripts more annoying
  • What motherboard is in my PC
  • A Dynamics365 plugin thought experiment
  • Registering a Dynamics365 plugin and I get an error
  • Going back in time with Dynamics365

Categories

  • Bootstrap
  • C#
  • CSS
  • Dot Net Core
  • Dynamics365
  • JavaScript
  • Powershell
  • T-SQL
  • Thoughts
  • VBScript
  • Visual Studio
  • Windows
  • Xamarin

Recent Comments

  • S0ftStuffB055 on Call a Dynamics365 workflow from JavaScript
  • Siva on Call a Dynamics365 workflow from JavaScript
  • TC Sharpe on Throw exceptions in Dynamics365 workflow plugins, or don’t
  • BigOwl on Throw exceptions in Dynamics365 workflow plugins, or don’t
  • CRMGod on Access a Dynamics365 embedded webresource

Archives

  • January 2021
  • May 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • October 2019
  • June 2019
  • May 2019
  • February 2019
2025 Softstuff Consulting. Donna Theme powered by WordPress
  • Twitter