I'm making a program that will automatically open the launch meeting page to take me to my next ZOOM class on time, and our schools have 'a days' and 'b days', each with a different schedule, so I have an HTML page that has two buttons, one that will trigger the schedule for an A day and another that triggers the schedule for a B day. I'm testing the functions that will open the new tab and run that function from the HTML, but when I run it from the HTML, I get an error message in my executions that says cannot call DocumentApp.getUI from this context. My code is here, if you put it into GAS you can see for yourself.
Part of my code came from this answer
My code.gs file
function doGet() {
return HtmlService.createHtmlOutputFromFile('index.html');
}
function openUrl( url ){
var html = HtmlService.createHtmlOutput('<html><script>'
+'window.close = function(){window.setTimeout(function(){google.script.host.close()},9)};'
+'var a = document.createElement("a"); a.href="'+url+'"; a.target="_blank";'
+'if(document.createEvent){'
+' var event=document.createEvent("MouseEvents");'
+' if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1){window.document.body.append(a)}'
+' event.initEvent("click",true,true); a.dispatchEvent(event);'
+'}else{ a.click() }'
+'close();'
+'</script>'
+'<body style="word-break:break-word;font-family:sans-serif;">Failed to open automatically. Click here to proceed.</body>'
+'<script>google.script.host.setHeight(40);google.script.host.setWidth(410)</script>'
+'</html>')
.setWidth( 90 ).setHeight( 1 );
DocumentApp.getUi().showModalDialog( html, "Opening ..." );
}
function LaZoom(){
openUrl('https://op97-org.zoom.us/j/9622570589');
}
My HTML file
<!DOCTYPE html>
<html>
<button onclick = 'aDay()'>A day</button>
<button onclick = 'bDay()'>B day</button>
</html>
<script>
function aDay(){
google.script.run.LaZoom();
alert('ran')
}
</script>
You can easily do this client side using window.open instead of going back and forth between server and client.
function aDay(){window.open('A_URL')}
Related
Is there a way to write a google apps script so when ran, a second browser window opens to www.google.com (or another site of my choice)?
I am trying to come up with a work-around to my previous question here:
Can I add a hyperlink inside a message box of a Google Apps spreadsheet
This function opens a URL without requiring additional user interaction.
/**
* Open a URL in a new tab.
*/
function openUrl( url ){
var html = HtmlService.createHtmlOutput('<html><script>'
+'window.close = function(){window.setTimeout(function(){google.script.host.close()},9)};'
+'var a = document.createElement("a"); a.href="'+url+'"; a.target="_blank";'
+'if(document.createEvent){'
+' var event=document.createEvent("MouseEvents");'
+' if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1){window.document.body.append(a)}'
+' event.initEvent("click",true,true); a.dispatchEvent(event);'
+'}else{ a.click() }'
+'close();'
+'</script>'
// Offer URL as clickable link in case above code fails.
+'<body style="word-break:break-word;font-family:sans-serif;">Failed to open automatically. Click here to proceed.</body>'
+'<script>google.script.host.setHeight(40);google.script.host.setWidth(410)</script>'
+'</html>')
.setWidth( 90 ).setHeight( 1 );
SpreadsheetApp.getUi().showModalDialog( html, "Opening ..." );
}
This method works by creating a temporary dialog box, so it will not work in contexts where the UI service is not accessible, such as the script editor or a custom G Sheets formula.
You can build a small UI that does the job like this :
function test(){
showURL("http://www.google.com")
}
//
function showURL(href){
var app = UiApp.createApplication().setHeight(50).setWidth(200);
app.setTitle("Show URL");
var link = app.createAnchor('open ', href).setId("link");
app.add(link);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
If you want to 'show' the URL, just change this line like this :
var link = app.createAnchor(href, href).setId("link");
EDIT : link to a demo spreadsheet in read only because too many people keep writing unwanted things on it (just make a copy to use instead).
EDIT : UiApp was deprecated by Google on 11th Dec 2014, this method could break at any time and needs updating to use HTML service instead!
EDIT :
below is an implementation using html service.
function testNew(){
showAnchor('Stackoverflow','http://stackoverflow.com/questions/tagged/google-apps-script');
}
function showAnchor(name,url) {
var html = '<html><body>'+name+'</body></html>';
var ui = HtmlService.createHtmlOutput(html)
SpreadsheetApp.getUi().showModelessDialog(ui,"demo");
}
There really isn't a need to create a custom click event as suggested in the bountied answer or to show the url as suggested in the accepted answer.
window.open(url)1 does open web pages automatically without user interaction, provided pop- up blockers are disabled(as is the case with Stephen's answer)
openUrl.html
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<script>
const url1 ='https://stackoverflow.com/a/54675103';
const winRef = window.open(url1);
winRef ? google.script.host.close() : window.alert('Allow popup to redirect you to '+url1) ;
window.onload=function(){document.getElementById('url').href = url1;}
</script>
</head>
<body>
Kindly allow pop ups</br>
Or <a id='url'>Click here </a>to continue!!!
</body>
</html>
code.gs:
function modalUrl(){
SpreadsheetApp.getUi()
.showModalDialog(
HtmlService.createHtmlOutputFromFile('openUrl').setHeight(50),
'Opening StackOverflow'
)
}
Google Apps Script will not open automatically web pages, but it could be used to display a message with links, buttons that the user could click on them to open the desired web pages or even to use the Window object and methods like addEventListener() to open URLs.
It's worth to note that UiApp is now deprecated. From Class UiApp - Google Apps Script - Google Developers
Deprecated. The UI service was deprecated on December 11, 2014. To
create user interfaces, use the HTML service instead.
The example in the HTML Service linked page is pretty simple,
Code.gs
// Use this code for Google Docs, Forms, or new Sheets.
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu('Dialog')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Dialog title');
}
A customized version of index.html to show two hyperlinks
<a href='http://stackoverflow.com' target='_blank'>Stack Overflow</a>
<br/>
<a href='http://meta.stackoverflow.com/' target='_blank'>Meta Stack Overflow</a>
Building of off an earlier example, I think there is a cleaner way of doing this. Create an index.html file in your project and using Stephen's code from above, just convert it into an HTML doc.
<!DOCTYPE html>
<html>
<base target="_top">
<script>
function onSuccess(url) {
var a = document.createElement("a");
a.href = url;
a.target = "_blank";
window.close = function () {
window.setTimeout(function() {
google.script.host.close();
}, 9);
};
if (document.createEvent) {
var event = document.createEvent("MouseEvents");
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
window.document.body.append(a);
}
event.initEvent("click", true, true);
a.dispatchEvent(event);
} else {
a.click();
}
close();
}
function onFailure(url) {
var div = document.getElementById('failureContent');
var link = 'Process';
div.innerHtml = "Failure to open automatically: " + link;
}
google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).getUrl();
</script>
<body>
<div id="failureContent"></div>
</body>
<script>
google.script.host.setHeight(40);
google.script.host.setWidth(410);
</script>
</html>
Then, in your Code.gs script, you can have something like the following,
function getUrl() {
return 'http://whatever.com';
}
function openUrl() {
var html = HtmlService.createHtmlOutputFromFile("index");
html.setWidth(90).setHeight(1);
var ui = SpreadsheetApp.getUi().showModalDialog(html, "Opening ..." );
}
I liked #Stephen M. Harris's answer, and it worked for me until recently. I'm not sure why it stopped working.
What works for me now on 2021-09-01:
function openUrl( url ){
Logger.log('openUrl. url: ' + url);
const html = `<html>
<a id='url' href="${url}">Click here</a>
<script>
var winRef = window.open("${url}");
winRef ? google.script.host.close() : window.alert('Configure browser to allow popup to redirect you to ${url}') ;
</script>
</html>`;
Logger.log('openUrl. html: ' + html);
var htmlOutput = HtmlService.createHtmlOutput(html).setWidth( 250 ).setHeight( 300 );
Logger.log('openUrl. htmlOutput: ' + htmlOutput);
SpreadsheetApp.getUi().showModalDialog( htmlOutput, `openUrl function in generic.gs is now opening a URL...` ); // https://developers.google.com/apps-script/reference/base/ui#showModalDialog(Object,String) Requires authorization with this scope: https://www.googleapis.com/auth/script.container.ui See https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes
}
https://developers.google.com/apps-script/reference/base/ui#showModalDialog(Object,String) Requires authorization with this scope: https://www.googleapis.com/auth/script.container.ui See https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes
I need help with Google App Script on a Google Sheet and an Html form. I just cannot get them to connect properly. The form has a text box and two buttons. The user enters a name in the text box and press the start button. The start button records time to a variable. When finished, the user presses finish. The finish button records the time and processes the text box and start button. This info is sent back to the Google App Script to be written to the Sheet. I would like to use an AJAX or JQuery call, but it doesn't seem to be working. Need a little help getting the nice form working. I have tried doGet(e) and doGet() functions, but those aren't working. I have tried lots of different versions of the code. This isn't my final html form, but it has the same point. If I click the button, AJAX should return something to the Google App Script after processing. New to Google App Scripting and need help. Thanks!
code.gs
function doGet(e) {
var result = "";
try {
result = "Hi" + e.queryString;
//should write to the spreadsheet the information here
} catch (f) {
result= "Error" + f.toString();
}
result=JSON.stringify({"result":result});
return ContentService
.createTextOutput( "(" + result + ")")
.setMimeType(ContentService.MimeType.JAVASCRIPT);
}
//where does HtmlService.createHtmlOutput('index.html') go?
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
// Make an AJAX call to Google Script
function callGoogleScript() {
var url = "https://script.google.com/macros/s/" my script id "/exec";
var data = { name: "Tom", city: "Nowhere" };
var request = jQuery.ajax({
url:url+encodeURIComponent(data),
method: "GET",
dataType: "jsonp"
});
}
// print the returned data
function ctrlq(e) {
console.log(e.result)
}
</script>
</head>
<body>
<button id="test" name="test" onclick="callGoogleScript()">Test</script>
</body>
</html>
Edit: This is for a Web App.
Can anyone help me with, I am trying to create a download counter to my website.
I have a ajax script that counts up by 1 when the users clicks the download link, the issue I am having is on some browsers it goes to the download link before completing the ajax count script.
Is there a way that I can redirect to the download file once the script has completed. At the moment I have as follows
This is the link :-
<a href='downloads/".$downfile."' onclick=\"Counter('$referid');\"'>Download File</a>
This is the counter script:-
<script type="text/javascript">
function Counter(id)
{
$.get("clickcounter.php?id="+id);
{
return false;
}
}
</script>
This is the php script (clickcounter.php)
<?php
include('dbutils.php');
$referid = $_GET['id'];
$q = "SELECT * FROM downloads WHERE downid =".$referid;
$r = mysql_query($q);
while ($row = mysql_fetch_array($r))
{
$click = stripslashes(trim($row['downcount']));
$download = $row['downfile'];
}
$countup = $click + 1;
$qUpdate = "UPDATE downloads
SET downcount=$countup
WHERE downid=$referid";
$rUpdate = mysql_query($qUpdate);
?>
A few relatively small modifications should solve the problem. First, change the onclick to the following:
onclick=\"Counter('$referid', this); return false;\"
What we have done is to send in this as the second argument to the Counter function so we have a reference to the clicked link. Secondly, we have added return false, which blocks the browser from navigating to the url specified in the href.
The modified counter function looks like this:
function Counter(id, link) {
$.get("clickcounter.php?id=" + id, function() {
location.href = $(link).attr("href");
});
}
We now have a reference to the clicked link. A function has now been specified as the second argument to $.get(). This is the success-function, which is called when the ajax call has been successfully called. Inside that function we now redirect to the url specified in the href attribute on the clicked link.
I feel I should point out that the recommended way is to bind the onclick using jQuery separate from the html. The referid can be stored in a data attribute (which I chose to call data-rid):
<a href='downloads/".$downfile."' class='dl' data-rid='$referid'>Download File</a>
Then you bind the onclick for all download links (a elements with a "dl" class):
$(function() {
$("a.dl").click(function() {
var id = $(this).attr("data-rid");
var href = $(this).attr("href");
$.get("clickcounter.php?id=" + id, function() {
location.href = href;
});
return false;
});
});
(I feel I should point out that the code has not been tested, so it's possible that a typo has snuck in somewhere)
I have an Ajax call back function which call to a PHP function check the file modified time.
I uses timer to execute it every 50 seconds.
<script type="text/javascript">
setInterval("_checkPopUpUpdate()", 50000); //50 seconds
</script>
function _checkPopUpUpdate()
{
var callback=new Object();
callback.success=this.onExternalSuccess;
callback.failure=this.onExternalFailure;
YAHOO.util.Connect.asyncRequest('GET','/ci/ajaxCustom/ajaxCheckPopupUpdate',callback);
};
The PHP function checks whether the file modified time has different between the first load session time
$announcement_Popup_Path = HTMLROOT . $this->data['attrs']['file_path'];
// Call model function
if($this->data['attrs']['file_path'] !== '' && file_exists($announcement_Popup_Path))
{
//When the announcement content load, it always stores the modified time into session
$this->CI->load->model('custom/checkupdate_model');
$firstloadTime = filemtime($announcement_Popup_Path);
$this->CI->checkupdate_model->store_AnnouncementPopupSession($firstloadTime);
//$this->data['Popup'] = file_get_contents($announcement_Popup_Path);
}
function store_AnnouncementPopupSession ($popupTime)
{
$sessionPopupTime =array("annoucementPopUp"=> $popupTime);
$this->session->setSessionData($sessionPopupTime);
}
function announcement_pop()
{
$file_path='/euf/assets/announcements/pop_up_announcement.html';
$announcement_Popup_Path = HTMLROOT . $file_path;
if(file_exists($announcement_Popup_Path)) {
$currentAnnouncementPopUpTime = filemtime($announcement_Popup_Path);
$oldannouncementPopupTime = $this->session->getSessionData("annoucementPopUp");
if($currentAnnouncementPopUpTime !=$oldannouncementPopupTime) {
//comparing the content and update the time, when they are different, send back update content
$this->store_AnnouncementPopupSession($currentAnnouncementPopUpTime);
//echo $currentAnnouncementPopUpTime;
echo $file_path;
}
else {
echo "no update";
}
}
}
When the file modifed time has changed, it will return to ajax call back and grab the HTML content in my web server to Pop up an annoucement pop up window.
function onExternalSuccess (o){
if(o.responseText!==undefined)
{
var str=o.responseText;
if(str !== 'no update') // Then pop up.
{
L=screen.width-200;
T=screen.height;
popup=window.open(str," ",'alwaysRaised=yes,status=no,toolbar=no,location=no,menubar=no,directories=no,resizable=no,scrollbars=no,height=150,width=364,left="+L+",top="+T');
//popup=window.open(str,"",'alwaysRaised=yes,status=no,toolbar=no,location=no,menubar=no,directories=no,resizable=no,scrollbars=no,height=100,width=330');
for (i=0;i<200;i++)
{
T=T-1;
popup.moveTo(L,T);
}
}
}
};
It works fine for Firefox and Chrome, however IE7 is a bit bugy, sometime the pop up does not come out.
<html>
<head>
<title>Internal alert</title>
<link rel="stylesheet" type="text/css" href="/euf/assets/css/pop_up_ann.css" media="screen, projection" />
<script type="text/javascript">
var howLong = 50000; //5 minutes, 1 seconds = 1000 milliseconds.
t = null;
function closeMe(){
t = setTimeout("self.close()",howLong);
}
</script>
</head>
<body onLoad="closeMe();self.focus();">
<div id="cs_popup">
<div class="popup_rounded-corner-top">
<div id="popup_ann">
<div id="popup_ann_title">IE7 pop-up EMEA test close </div>
<div id="popup_ann_from"> PLC team - 05/01/2011 at 12:10</div>
<div id="popup_ann_content">
Something has changed in the<em>"Alerts"</em> section of S4S since your last visit.
Make sure you go there as soon as you can to be informed about the current situation.
</div>
</div>
</div>
<div class="popup_rounded-corner-bottom"></div>
</div>
</body>
</html>
The main problem i have here it is self-close function. It close my pop up window and the website as well. Any hints? Also, i am not sure whether my whole pop up annoucement logical structure is correct, is there anyway? thanks
Opening a popup window for an announcement like this could be problematic for people running popup blockers, which typically only allow popups to appear in response to a user-initiated event like clicking on something. A better approach would be to use an inline popup which would also give you the opportunity to display the popup modally (i.e. mask the rest of the page with a semi-transparent div) if you require them to acknowledge your message.
The use of self.close() should not close the original window/tab opened by the user, it should only close things that have been 'open'ed so I'm not sure what's going on there, I suspect you haven't told us everything :) An alternate approach might be to modify your popup function to close the window rather than have the window close itself.
// open popup ... then set timeout to close it
var popupDelay = 50000;
setTimeout(function() {
popup.close();
}, popupDelay);
This may work a little better, not sure. But in the long run, I highly recommend avoiding popups and using something inline instead.
I am using an iFrame with a form that return some content with an AJAX link.
I am then moving the returned content out of the iFrame into the main page.
However, then the ajax link does not work and the error "Element is null" is created once the link is clicked.
How can I move content from the iFrame and still have the AJAX link working?
Here's the code returned by the iFrame:
<span id="top">
<a id="link8" onclick=" event.returnValue = false; return false;" href="/item_pictures/delete/7">
<img src="/img/delete.bmp"/>
</a>
<script type="text/javascript">
parent.Event.observe('link8', 'click', function(event) {
new Ajax.Updater('top','/item_pictures/delete/3', {
asynchronous:true, evalScripts:true,
onCreate:function(request, xhr) {
document.getElementById("top").innerHTML = "<img src=\"/img/spinner_small.gif\">";
},
requestHeaders:['X-Update', 'top']
})
}, false);
</script>
</span>
I see two problems with your code.
First the solution (I think :-))
When your iframe loads, the javascript in it runs. Javascript attaches an observer to parent document's link8.
Inside the observer you define another function (onCreate). This function will run in iframe context, making document object refer to iframe and not to main document. When you remove link8 from iframe to move it to main document, document.getElementById("top") will become null - hence error.
Perhaps change it to:
parent.document.getElementById("top").innerHTML = "<img src=\"/img/spinner_small.gif\">";
Second problem (that is not really a problem in this particular case) is, if you move whole span (including the script) to main document, the javascript will run again in main document's context. In your case, you should see an error or warning after you move the content, stating that parent is null (or similar).
To remove the second problem, return your iframe data in two divs or similar. Then copy only div with html to main document.
What I did was move the AJAX call out to an external js file and called the function once the link was clicked. It works now.