问题
i have a multi page Web App. I want after log in, user sees the list of his team mate and mark 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 iFram 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. Can you guys please help me on this?
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 don'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 java script.
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 variable xFrame
to set XframeOptionsMode to allowAll or not and base
to switch base target on the HTM pages to "_top" or "_self".
Please advise, M
回答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 ... from frame with URL .... The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.
Solution:
- Use
window.postMessage()
==================
|Your site |<-mysite.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:
- postMessage
- iFrame
来源:https://stackoverflow.com/questions/56400233/issue-with-embedding-google-apps-script-in-an-iframe