I want to have my browser tab title for Gmail show the Subject for the current email because I have software that helps time tracking by capturing tab titles. Unfortunately, it shows Inbox (6) - my.name#mycompany.com all the time.
I see Change Title With Javascript provides javascript to change the tab title to alternative text. How would I get the Subject of the current message in Gmail in a Gmail add-on?
assuming you are retrieving a message of type GmailMessage and that you are running your js client side in an HTML context such as a webapp you could:
create a function in app script that calls the method getSubject()
Serve HTML
call backend function with google.script.run
call a success handler that changes title when async function is completed with success.
in your HTML
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onSuccess(subject) {
document.title = subject
}
google.script.run.withSuccessHandler(onSuccess)
.getSubject();
</script>
</head>
<body>
<div id="output"></div>
</body>
</html>
and in your .gs
getSubject(){
//get your message here
return (message.getSubject());
}
REFERENCES
Serving HTML on web app
google.script.run
Related
I am developing a web app on App Script (to use Google APIs). I have a chrome extension that works alongside the web app so that I can send information about the browser.
I am using a content script that initializes once the Web App loads. I want to simply send a message from the extension to the web app through the content script. However, DOM doesn't work because App Script uses iFrames. Here is the code from my actual web app:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<input type="text" id="pageId" onchange="updateSessionInfo()">
</body>
<script>
function updateSessionInfo(){
var pageId = document.getElementById("pageId").value;
google.script.run.update(pageId);
}
</script>
</html>
I was trying to use DOM to send the pageId to the input element and by having a change in the value, the update function would send the information.
However, this is the structure I receive on my browser:
Chrome Dev Tools
Am I thinking correctly? Or is editing the DOM both dirty and unfeasible? Is there another way?
UPDATE:
I have found the actual document HTML elements by looking deeper down the tree:
New Console
But if the element with id="pageId" is down there, why does it return null when I call it?
UPDATE:
I noticed times when it returns null, and sometimes where the element is detected:
Newest Console
This works for me as a dialog:
Typically I would expect that if this will run as a dialog it will also run as a webapp with the addition of a doget();
gs:
function runmydialog() {
const ui = SpreadsheetApp.getUi();
ui.showModelessDialog(HtmlService.createHtmlOutputFromFile('ah2'),'test');
}
function update(msg) {
SpreadsheetApp.getUi().alert(msg);
}
html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<body>
<input type="text" id="pageId" onchange="updateSessionInfo()">
<script>
function updateSessionInfo(){
var pageId = document.getElementById("pageId").value;
google.script.run.update(pageId);
}
</script>
</body>
</html>
Dialog:
Alert:
I noticed that your script is not inside the body. I don't know if that makes a difference.
I'm learning how to use Google Web App and am following this YouTube video Google Sheets Web App Example - Google Apps Script Web App Tutorial - Part 1 and I am really enjoying the series. It is very easy to follow along with the videos. But I am running into a little issue with the first video. For some reason when I try to do log the button click on the HTML page, nothing happens. I sure it's going to be something silly. But I have been at this now for a few hours and I can't figure out what is wrong.
Code.gs:
function doGet(e) {
Logger.log(e.parameter);
return HtmlService.createHtmlOutputFromFile("page");
}
function userClicked(name){
Logger.log(name + " & noah clicked it!");
}
page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>Hello</h1>
<label>Name:</label><input type="text" id="username">
<button id="btn">Run It!</button>
<script>
document.getElementByID("btn").addEventListener("click",doStuff);
function doStuff(){
var uname document.getElementByID("username").value;
google.script.run.userClicked(uname);
}
</script>
</body>
</html>
Please tell me there is something silly that I am just not seeing.
I think that your script of HTML side is not correct. By this, the script is not run. So I think that Logger.log is not run. Please modify your script of HTML side as follows and test it again.
Modification points:
getElementByID is getElementById.
var uname document.getElementByID("username").value; is var uname = document.getElementById("username").value;.
Modified script:
From:
<script>
document.getElementByID("btn").addEventListener("click",doStuff);
function doStuff(){
var uname document.getElementByID("username").value;
google.script.run.userClicked(uname);
}
</script>
To:
<script>
document.getElementById("btn").addEventListener("click",doStuff); // Modified
function doStuff(){
var uname = document.getElementById("username").value; // Modified
google.script.run.userClicked(uname);
}
</script>
By this modification, you can see the log at Apps Script Dashboard.
IMPORTANT:
In your case, when you access to the Web Apps using your browser by logging in to your Google account, the log can be seen. But if you want to access to a script and curl, please include the access token to the request header. By this, the log can be seen. Please be careful this.
When you cannot include the access token to the request header, in that case, please link the Google Apps Script project to Google Cloud Platform (GCP) Project. By this, the log can be seen at Apps Script Dashboard.
References:
getElementById()
Apps Script Dashboard
I created an Google login button:
<!DOCTYPE html>
<html>
<head>
<title>Google Auth Demo</title>
<meta name="google-signin-client_id" content="xxxx.apps.googleusercontent.com">
<script src="https://apis.google.com/js/platform.js" async defer></script>
<script>
function signOut() {
gapi.auth2.getAuthInstance().signOut().then(function() {
console.log('user signed out')
})};
function onSignIn(googleUser) {
console.log(googleUser.getBasicProfile());
}
</script>
</head>
<body>
<h1>Welcome to the Demo</h1>
<div class="g-signin2" data-onsuccess="onSignIn" data-ux_mode="redirect" ></div>
<button onclick="signOut()" >Sign out</button>
</body>
</html>
I changed a param from popup to data-ux_mode="redirect". How do I configure the field Authorized redirect URIs or change somethingelse for my app on https://console.developer.google so I can use it on localhost?
I had find a close issues here: https://github.com/google/google-api-javascript-client/issues/288#issuecomment-289064472 . So it's availabe for implement code authen button Google sample without open popup?
You need to add authorized domains and redirect URI's to your client ID or API keys using this URL
https://console.cloud.google.com/apis/credentials?project={YOUR-GOOGLE-CLOUD-PROJECT-NAME}
Basically in the GCP console, on the left navigation bar go to APIs and Services. Over there look for the oAuth2.0 client ID you are using in your project. Once you click on it you have an interface to configure Authorized redirect URIs and Authorized JavaScript origins
Edit: upon going through the linked github issue(which is still open by the way) it is not possible to get the token to a local machine using the redirect UX. They have plans to support it in the future but currently only works with popup method.
Hi #Jeevsxp, this is not possible to obtain an authorization code
without popup. This is a security restriction: an offline code will
allow you to obtain a refresh_token in the server, that gives you the
possibility to obtain a fresh access_token anytime you want. For that,
the user needs explicit consent
Say I have an HTML file with various inputs. According to these inputs I would like to send an email and then display a thank you message or redirect to a thank you page.
I am loading the index.html file in the doGet() as below:
function doGet(){
var template = HtmlService.createTemplateFromFile('index');
template.action = ScriptApp.getService().getUrl();
return template.evaluate();
}
After adding the implementation which I require in doPost(e) function, deploying the code into a web app, filling in the form and submitting, everything seems to be working perfectly apart from the last bit. I want to show an output message or redirect to a thank you page, or something of the sort, but all I am seeing is a blank page, where there would have been the HTML form.
I have tried:
function doPost(e) {
//all logic
return ContentService.createTextOutput("Thank you");
}
And..
function doPost(e) {
//all logic
return ContentService.createTextOutput(JSON.stringify(e.parameter));
}
And..
function doPost(e) {
//all logic
var htmlBody = "<h1>Thank you.</h1>";
return HtmlService.createHtmlOutput(htmlBody);
}
And..
function doPost(e) {
//all logic
var template = HtmlService.createTemplateFromFile('Thanks');
return template.evaluate();
}
In all the listed cases the HTML form simply seems to disappear and I can only see a blank screen.
Any ideas?
In GAS, sending a POST request via web app is not as simple as it seems. Go ahead and try a little experiment: add the following JS code to the HTML page served by the doGet() function just before the closing <body> tag:
...
<script>
console.log(window.location);
</script>
</body>
When inspecting the output in the console, you'll likely get something like:
The issue is that the web app URL ending with '/exec' doesn't actually link to self. Ratner, the googleusercontent.com link is the URL you'll be redirected to when opening links and forms. However, in order to get the form submit to work, the POST request should be sent to the "published" URL of your web app (the one ending with '/exec').
You must therefore override the defaults by implementing your own routing. There are many ways to achieve this result - here's the easiest one:
<form method="post" action="<?!= ScriptApp.getService().getUrl() ?>">
<input type="submit" value="submit">
</form>
If the <?!= ?> notation looks unfamiliar to you, please check the section on scriptlets and HTML templates in GAS https://developers.google.com/apps-script/guides/html/templates
Basically, what happens is that the web app URL is force-printed to the template before raw HTML is sent to your browser for rendering. This makes sure you'll hit the correct URL when 'submit' event occurs.
I'm just learning google script and want to start by making a simple hello world. I have done google's tutorial and when I click "test this code" on the publish web app popup, the code runs and I get my basic hello world result. Great. But When I paste the provided URL into the browser or embed that same URL into google sites, I just get a blank page.
How do I run an web app? Am I missing something?
code.gs:
function doGet() {
var html= HtmlService
.createTemplateFromFile('Index');
html.name = 'David';
return html.evaluate();
}
index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<b>Hi <?=name?>!</b>
</body>
</html>
Coming from a basic PHP background, I'm used to just going to the URL of the .php file and bang, away it goes... I'm so confused.
https://stackoverflow.com/a/40843413/6288442
Google had just recently enabled this feature. It has been under a
'feature request' status for quite a long time. Link here
You can now explicitly define X-Frame-Options.
To allow embedding under another domain, the option should be
HtmlService.XFrameOptionsMode.ALLOWALL
Google documentation on the subject:
https://developers.google.com/apps-script/reference/html/html-output#setXFrameOptionsMode(XFrameOptionsMode)
Example:
function doGet() {
return HtmlService.createTemplateFromFile('form.html')
.evaluate() // evaluate MUST come before setting the Sandbox mode
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL); }
Hope this helps!
I think this should work
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<b>Hi <?!=name?></b>
</body>
</html>
https://developers.google.com/apps-script/guides/html/templates#force-printing_scriptlets
Name of file should also be exactly same
I think Index and index won't work