Navigating embedded Google Apps Script iFrame from the parent
I have a multi-page Web App. I want after login, a user sees the list of his teammate and marks their attendance status. My issue is I can't show that in an iFrame rather than google script original one.
For instance, I wanted to iFrame it to my own web page. it is two days I can't overcome this issue, I read lots of posts in this regard and also tried another app from scratch, but no luck yet.
For clarification, I am redirecting the user inside the frame using render function. So as @theMaster mentioned it is not a multi-page Web App.
here is my doGet and Render functions:
function doGet(e){
// Logger.log(e);
Route.path("login",loadLogin);
Route.path("admin",loadAdmin);
Route.path("view",loadView);
Route.path("form",loadForm);
if (e.parameters.id){
LastID=e.parameters.id[0];
}
if (e.parameters.t){
curT=e.parameters.t[0];
}
if (Route[e.parameters.v]) {
return Route[e.parameters.v]();
} else {
return render('W-home');
}
}
function render(file, argObject){
var page = HtmlService.createTemplateFromFile(file);
if (argObject){
var keys = Object.keys(argObject);
keys.forEach(function (k){
page[k]=argObject[k];
});
}
var evalPage =page.evaluate();
// if (!xFrame){return evalPage;};
return evalPage.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
I can go from home page to login page, but after that, even it doesn't let me go to google. In some cases also just returns a blank page inside the frame.
Here is my sample code for the client-side JavaScript.
function goToForm(EmpNo) {
var link = "<?!=ScriptApp.getService().getUrl()?>" + "?v=form&id=" + EmpNo[1] + "&t=" + EmpNo[2];
location.href = link;
// I tried different way to see if i can conqure this!
// if (clickBTN= 'a') {
// window.open(link, "_self");
// } if (clickBTN= 'b') {
// location.href=link;
// } if (clickBTN= 'c') {
// openNewURLInTheSameWindow(link);
// }
}
I also have two global variables xFrame
to set XframeOptionsMode to allowAll
or not and base
to switch base target on the HTM pages to "_top" or "_self".
Solution 1:
Issue:
You can try
window.top.location = link;
It'll load the link in the top frame. If you are framing the web-app itself in your website, then you should use
window.parent.parent.location = link;
But this won't work because the sandbox prevents navigating other frames in the document. sandbox="allow-top-navigation"
only allows top frame navigation and not the intermediate frames. Since the top frame is your site and not script.google.com
, it can't be navigated and you'll get the error
Unsafe JavaScript attempt to initiate navigation for frame with URL
https://myexamplesite.com
... from frame with URL https://*.googleusercontent.com/... The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.
Solution:
- Use
window.postMessage()
==================
|Your site |<-myexamplesite.com [TOP#0]
| |
| ============= |
| |GASWebApp |<-|--script.google.com[Frame#1]
| | | |
| |========= | |
| ||SandBox| | |
| ||User |<-|--|-- Where your html code is
| ||Frame | | | (*.googleusercontent.com)
| |========= | | [Frame#2 and #3(Double nested iframe)]
| | | |
| ============= |
| |
| |
| |
==================
Snippet:
Sandboxed Html:
<script>
if(window.parent.parent !== window.top){ //if #1 !== top
//Framed in a another web-app
//TODO Use proper target origin instead of *
window.parent.parent.parent.postMessage("[FRAME#1_LINK_TO_CHANGE]","*");//Post to #0
}
</script>
Top frame(#0):
<!-- Frame the Apps script Web-App Frame#1-->
<iframe
src="https://script.google.com/macros/s/[SCRIPT_DEPLOYMENT_ID]/exec"
>Loading...</iframe
>
<script type="text/javascript">
const handleMessage = function(event) {
if (
event.origin !==
'https://[SCRIPT_ORIGIN]script.googleusercontent.com'
) {
alert('Origin Disallowed');
return;
}
//TODO Check syntax of event.data before changing iframe src
document.querySelector('iframe').src = event.data; //Change #1 Link
};
window.addEventListener('message', handleMessage);
</script>
References:
-
Basic GAS webapp structure
-
postMessage
-
iFrame