I have this code inside a iframe:
window.addEventListener('message', function(e){
if(e.data == 'test')
console.log(e);
}, false);
and this inside the parent document:
$('#the_iframe').get(0).contentWindow.postMessage('test', 'http://localhost/');
So the parent document sends a "test" message to the iframe and it works.
But how can I define a function in the parent document, and somehow send this function through postMessage to the iframe, which will execute the function locally?
The function does some changes to the document like this:
var func = function(){
$("#some_div").addClass('sss');
}
(#some_div
exists in the iframe, not the parent document)
postMessage() The window. postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.
postMessage() sends a message back to the main page. The two ends can listen to messages from the other using window. addEventListener("message", (event) => {...}) .
postMessage method allows different windows or iframes to communicate directly, even if they were loaded from different origins, circumventing the usual same-origin policy. The sender of the message can restrict the origin of the receiver by specifying a target origin.
There's nothing that would prevent you from passing a stringified function as postmessage event data. Implementation is trivial, for any function declaration like
function doSomething(){
alert("hello world!");
}
You could encodeURI
its string interpretation:
console.log(encodeURI(doSomething.toString()));
//function%20doSomething()%20%7B%0A%20%20%20%20alert(%22hello%20world!%22);%0A%7D
It can then be executed as part of a closure - something not overly imaginative like
eval('('+decodeURI(strCallback)+')();');
There's a fiddle'd proof of concept without the cross-frame architecture - I'll see if I can put together a postMessage version, but it would be non-trivial to host w/jsfiddle
As promised, a full mockup that works (links below). With correct event.origin
checks this would be sufficiently inpenetrable, but I know for the fact that our security team would never let eval
into production like this :)
Given the option I'd suggest the functionality be normalized across the two pages so that only a parametric message would need to be passed (i.e. pass arguments not functions); however there are definitely a few scenarios where this is a preferred approach.
Parent code:
document.domain = "fiddle.jshell.net";//sync the domains
window.addEventListener("message", receiveMessage, false);//set up the listener
function receiveMessage(e) {
try {
//attempt to deserialize function and execute as closure
eval('(' + decodeURI(e.data) + ')();');
} catch(e) {}
}
Iframe code:
document.domain = "fiddle.jshell.net";//sync the domains
window.addEventListener("message", receiveMessage, false);//set up the listener
function receiveMessage(e) {
//"reply" with a serialized function
e.source.postMessage(serializeFunction(doSomething), "http://fiddle.jshell.net");
}
function serializeFunction(f) {
return encodeURI(f.toString());
}
function doSomething() {
alert("hello world!");
}
Prototype mockup: parent code and iframe code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With