I've been following the instructions here to have my Gmail signature template display the image stored on Google Drive as a logo.
The goal is to have the 'src' attribute of the image tag point to the image and display it inline. In the answer linked above, the image blob is fetched using UrlFetchApp. In my code, I'm calling the openById(id) method of the DriveApp to open the image file and get the blob.
However, neither approach seems to work. It's only when I have the 'src' point directly to the image URL that it loads the image. I tried using both base64Encode and base64EncodeWebSafe but the signature only shows the empty container for the image.
What am I missing here?
HTML template
<table>
<tbody>
<tr>
<td>
<img src="{{config.imgData}}" alt="my logo">
</td>
<td>
<table>
<tbody>
<tr><td> My name is {{config.name}} </td> </tr>
<tr><td> www.example.com </td> </tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
GS code
var config = {
name: "Anton",
imgData: ""
}
function updateSignature() {
var imgFileId = "DRIVE FILE ID";
var imgFile = DriveApp.getFileById(imgFileId);
var imgBlob = imgFile.getBlob().getAs("image/png"); //getAs doesn't change anything
//Get content type and bytes
var contentType = imgBlob.getContentType();
var imgBytes = imgBlob.getBytes();
var imgData = contentType + ";base64," + Utilities.base64Encode(imgData);
config.imgData = imgData;
var alias = Gmail.Users.Settings.SendAs.get("me", myEmail);
//Get signature html as a string
var templateString = HtmlService.createHtmlOutputFromFile("signature_template").getContent();
for (var configKey in config) {
if (config.hasOwnProperty(configKey)) {
templateString = templateString.replace("{{config." + configKey + "}}", config[configKey]);
}
}
var finalTemplate = HtmlService.createHtmlOutput(templateString).getContent();
alias.signature = finalTemplate;
Gmail.Users.Settings.SendAs.update(alias, "me", myEmail);
}
You want to put an image of your Google Drive to your Gmail signature using the template HTML.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Issue and workaround:
When I checked the official document, I saw the image for the signature as follows.
If you added a photo or image from Google Drive, you'll need to share your image publicly for it to appear in your signature. Note: If you use Gmail with your work or school account, ask your administrator to let you share images publicly.
Search for an image, like your company logo, then get the image URL.
Add your own image to Google and use that URL.
When data:image/png;base64,### is used for src of the image tag, it was found that the signature updated with Gmail.Users.Settings.SendAs.update() doesn't include src attribute. When https://### is used, the signature updated with Gmail.Users.Settings.SendAs.update() includes the src attribute.
From above situation, it is considered that data:image/png;base64,### might not be able to be used to src of the image tag of the signature. This might be the specification.
So in order to put the image from Google Drive, how about the following flow? I think that this is the method showing at the official document.
Publicly share the image in Google Drive.
Put the URL of the image to the signature.
Modified script:
When your script is modified, how about the following modification?
From:
var imgBlob = imgFile.getBlob().getAs("image/png"); //getAs doesn't change anything
//Get content type and bytes
var contentType = imgBlob.getContentType();
var imgBytes = imgBlob.getBytes();
var imgData = contentType + ";base64," + Utilities.base64Encode(imgData);
To:
imgFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var imgData = "https://drive.google.com/uc?export=download&id=" + imgFileId;
Note:
When the image is manually put to the signature, above URL is used and the file is automatically shared publicly.
By the way, in your current script, imgData of var imgData = contentType + ";base64," + Utilities.base64Encode(imgData); might be imgBytes. And when you want to put the image to src using the base64 data, please use src="data:image/png;base64,###". In your script, src="image/png;base64,###" is used.
References:
Create a Gmail signature
Users.settings.sendAs: update
If I misunderstood your question and this was not the direction you want, I apologize.
Try this:
All you need to do is to add a default image file id to the function convertImageToDataURI and then launch the dialog. Or you can deploy as a webapp also. For my purposes I usually reduce the size of the images to something less than 1000 pixels wide and keep the aspect ratio less than one.
Code.gs:
function onOpen() {
SpreadsheetApp.getUi().createMenu('My Tools')
.addItem('Display Dialog', 'displayDialog')
.addItem('Get File Ids from FolderId','getFileIds')
.addToUi();
}
function convertImageToDataURI(fileId) {
var fileId=fileId||'default image file id';
if(fileId) {
var file=DriveApp.getFileById(fileId);
var blob=file.getBlob();
var dataUri='data:' + blob.getContentType() + ';base64,' + Utilities.base64Encode(blob.getBytes());
return dataUri;
}
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function displayDialog() {
var userInterface=HtmlService.createTemplateFromFile('image').evaluate();
SpreadsheetApp.getUi().showModelessDialog(userInterface, "For the Birds");
}
function doGet() {
return HtmlService.createTemplateFromFile('image').evaluate();
}
resources.html:(not required for this example)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
css.html:(not required for this example)
<style>
body {background-color:#ffffff;}
input{padding:2px;margin:2px;}
</style>
script.html:(not required for this example)
<script>
console.log('script.html code');
</script>
content.html is empty
images.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('resources') ?>
<?!= include('css') ?>
</head>
<body>
<img id="birds" src="<?!=convertImageToDataURI()?>" width="320" />
<?!= include('content') ?>
<?!= include('script') ?>
</body>
</html>
<html><head>
If you need a tool to get the file ids of images in a folder try this function:
function getFileIds() {
var resp=SpreadsheetApp.getUi().prompt("Folder Id","Enter Folder Id", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if(resp.getSelectedButton()==SpreadsheetApp.getUi().Button.OK && resp.getResponseText().length>0) {
try{
var folder=DriveApp.getFolderById(resp.getResponseText());
var files=folder.getFiles();
var html='<style>td,th{border:1px solid black;padding:2px 5px;}</style><table><tr><th>File Name</th><th>File Id</th><th>Type</th></tr>';
while(files.hasNext()) {
var file=files.next();
html+=Utilities.formatString('<tr><td>%s</td><td>%s</td><td>%s</td></tr>', file.getName(),file.getId(),file.getMimeType());
}
html+='</table><br /><input type="button" value="Close" onClick="google.script.host.close();" />';
var userInterface=HtmlService.createHtmlOutput(html).setWidth(800).setHeight(400);
SpreadsheetApp.getUi().showModelessDialog(userInterface, "Files in Folder");
}
catch(e){SpreadsheetApp.getUi().alert(e);}
}else{
SpreadsheetApp.getUi().alert("Invalid or Missing Inputs: No FileId Provided");
}
}
Scriplets
Web Apps
This is what my dialog looks like:
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'm new in both Google App Scripting and JavaScript. So, I'm trying to display the grabbed files from my Google Drive with links however when running displayData(); it's literally showing the link and the title of the file on the page without the actual link in it. Here's picture of the html
output.
Here's what I have so far:
Code.gs
function doGet() {
var output = HtmlService.createTemplateFromFile('Page').evaluate();
return output;
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
function displayData() {
var dir = 'Somefoldername';
var foldername = DriveApp.getFoldersByName(dir).next();
var foldercont = foldername.getFiles();
var listicon = '<img src="https://drive-thirdparty.googleusercontent.com/16/type/application/vnd.google-apps.document">';
var file, title, links, list = [];
while (contents.hasNext()) {
file = foldercont.next();
title = file.getName();
links = file.getUrl();
date = file.getDateCreated();
list.push('<tr><td>' + listicon + '<a href ="' + links + '">' + title +'</td></tr>');
}
return list;
Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('Stylesheet'); ?>
</head>
<body>
<div class="doclist">
<?= displayData(); ?>
</div>
</body>
</html>
How would I display the Google Drive file hyperlinks in the html template?
Thank you.
Here is a Sample Code:
Note:
I temporarily removed <?!= include('Stylesheet'); ?> in the html file since it is not defined.
Code.gs
function doGet() {
var output = HtmlService.createTemplateFromFile('Page').evaluate();
return output;
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
function displayData() {
var dir = 'Somefoldername';
var foldername = DriveApp.getFoldersByName(dir).next();
var foldercont = foldername.getFiles();
var listicon = '<img src="https://drive-thirdparty.googleusercontent.com/16/type/application/vnd.google-apps.document">';
var file, title, links, list = [];
while (foldercont.hasNext()) {
file = foldercont.next();
title = file.getName();
links = file.getUrl();
date = file.getDateCreated();
list.push('<tr><td>' + listicon + '<a href ="' + links + '">' + title +'</td></tr>');
}
return list.join(' ');
}
Modifications done:
Replace while (contents.hasNext()) with while (foldercont.hasNext())
Combine your array list into a single string using array.join(' ') with spaces as its separator
Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<script>
google.script.run.withSuccessHandler(function(tblStr){
document.getElementById('FileList').innerHTML = tblStr;
}).displayData();
</script>
<table id="FileList">
</table>
</body>
</html>
Modifications done:
I added a table in the html body with the id "FileList"
I called the server-side function displayData() using google.script.run.withSuccessHandler(function).displayData(). The return value of displayData() will be passed to the callback function's first parameter.
I updated the table's content based on the displayData()'s return value using this procedure document.getElementById('FileList').innerHTML = tblStr;
Output:
Some observations:
The function is returning an array list = [], and you are pushing data into that array.
Your HTML in the screenshot has stray commas in it between each item: ...</td></tr>,<tr><td>....
You shouldn't place a <div> inside a table.
Both of these suggest that you should be appending your data to a string variable, instead of pushing data into an array.
Then return that string from your function, instead of the array.
The string variable will contain the entire contents of your HTML rows and columns.
For the <div>, remove it and place the class in the body:
<body class="doclist">
Depending on how your CSS is set up, that may need modifying to accommodate this change.
Final suggestion: take the resulting HTML which is generated and run it through a validator - for example: https://validator.w3.org/#validate_by_input
That may find some additional issues which need correcting.
I am trying to implement a workflow - I need to send an email with links to approve/reject a candidate to Level 1 Manager and then to Level 2 Manager. Once both approve, a confirmation email is sent to the candidate.
I have a custom function say main_function() that executes before sending each of the two emails. This function needs to pull data from the spreadsheet to which the script is bound.
Since I have a two-step approval, I created different projects to get separate WebApp URLs for each approval step.
I am including the main_function() function as a library in the two projects.
main_function() sends an email with approve/reject link and when the link is clicked an HTML opens with an input box to take comments.
Then the HTML includes a call to a script function saveToSheets() to save the data to google sheet.
The HTML shows up but data is not getting saved because saveToSheets() is not called. How can I resolve this?
Main function in Library myLib
main_function(){
//do something
Logger.log("function called!");
var htmlTemplate = HtmlService.createTemplateFromFile('Index2.html');
htmlTemplate.ID = ID; //pass variables from script to HTML
htmlTemplate.decision = decision;
htmlTemplate= htmlTemplate.evaluate().setTitle('Comments').setSandboxMode(HtmlService.SandboxMode.NATIVE);
return htmlTemplate.asTemplate();
}
saveToSheets(inputArray){
//do something
}
Index2.html in Library myLib
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
</style>
</head>
<body>
// Includes a COMMENT BOX with id comment1
//include DIV element with id output to catch error
<script>
function runGoogleScript() {
var item0 = "<?= ID ?>";
var item1 = "<?= decision ?>";
var item2 = document.getElementById('comment1').value; //comments
var inputArray =[item0,item1,item2];
google.script.run.withFailureHandler(onFailure).myLib.saveToSheets(inputArray);
}
function onFailure(error) {
var div = document.getElementById('output');
div.innerHTML = "ERROR: " + error.message;
}
function onSuccess() {
}
</script>
</body>
</html>
Function in another project that needs to reuse the script and HTML through mylib
myfunction(){
var htmlTemplate = mylib.main_function();
return htmlTemplate.evaluate();
}
It is incorrect to say "Index.html is not accessible from project". When you deploy a project as a library, its HTML files are in the context of the library.
But if you want to pass an evaluated HTML template from a library as a template you should use asTemplate()
Example:
main_function(){
//do something
Logger.log("function called!");
var htmlTemplate = HtmlService.createTemplateFromFile('Index.html');
htmlTemplate= htmlTemplate.evaluate();
return htmlTemplate.asTemplate();
}
Using google app script, the adresse mail filled in the variable , from google sheet API and then, I want to join "mailto:" with the variable of adress mail . This allows to appear this variable in html .
How to do it ?
in google app script:
var Email_user = Session.getActiveUser().getEmail();
var hrefmail = "mailto:"+Email_user ;
var val_htm_mail_1 =hrefmail ;
:
:
:
theHTML.linkEmail = val_htm_mail_1; ( this is to fill the variable "val_htm_mail_1" to send it to HTML
in html :
<span id="linkEmail"><?=linkEmail?></span><br />
thank you in advance for this helpness
I recommend using HTML DOM Edit HTML content instead of a scriptlet. Here's the w3 reference so you can try to write it yourself, instead of just copying mine. Here is an example program:
code.gs
function doGet() {
return HtmlService.createTemplateFromFile('Index')
.evaluate();
}
function include(filename) {
var Email_user = Session.getActiveUser().getEmail();
var hrefmail = "mailto:"+Email_user ;
val_htm_mail_1 = hrefmail ;
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<span id="linkEmail">...</span><br/>
<script>
document.getElementById("linkEmail").innerHTML = this.val_htm_mail_1;
</script>
<?!= include ('javascript'); ?>
</body>
</html>
javascript.html
<script>
window.addEventListener('load', function() {
console.log('Page is loaded');
});
</script>
*Note you may need to adjust this depending on your browser settings
The Google support article example under the Forms heading is broken. From the article:
If you call a server function with a form element as a parameter, the form becomes a single object with field names as keys and field values as values. The values are all converted to strings, except for the contents of file-input fields, which become Blob objects.
I tested this by passing a Form element containing 5 text inputs and a file, then logging Object.keys() on the form object. It returned only the 5 text fields, the file was stripped from the form object. Attempting to assign the file blob directly returned Exception: Invalid argument: blob
How do I pass the file blob from the client-side Form to the server-side Apps Script?
EDIT: To clarify, I also copy-pasted the example provided by Google verbatim. It errors with Exception: Invalid argument: blob.
To reproduce:
Create new Google Apps Script project
Index.html contents:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
</head>
<body>
<form id="myForm" onsubmit="handleFormSubmit(this)">
<input name="myFile" type="file" />
<input type="submit" value="Submit" />
</form>
<div id="output"></div>
</body>
</html>
Code.gs contents:
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function processForm(formObject) {
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}
Publish as Web App
Submit the form with any file
Observe error in View -> Stackdriver Logging -> Apps Script Dashboard
Here's an example:
html:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
function fileUploadJs(frmData) {
document.getElementById('status').style.display ='inline';
google.script.run
.withSuccessHandler(updateOutput)
.uploadTheFile(frmData)
}
function updateOutput(info) {
var br='<br />';
var outputDiv = document.getElementById('status');
outputDiv.innerHTML = br + 'File Upload Successful.' + br + 'File Name: ' + info.name + br + 'Content Type: ' + info.type + br + 'Folder Name: ' + info.folder;
}
console.log('My Code');
</script>
<style>
body {background-color:#ffffff;}
input{padding:2px;margin:2px;}
</style>
</head>
<body>
<h1 id="main-heading">Walking Tracks</h1>
<h3>Upload GPS Tracks Files</h3>
<div id="formDiv">
<form id="myForm">
<input name="fileToLoad" type="file" /><br/>
<input type="button" value="Submit" onclick="fileUploadJs(this.parentNode)" />
</form>
</div>
<div id="status" style="display: none">
<!-- div will be filled with innerHTML after form submission. -->
Uploading. Please wait...
</div>
<div id="controls">
<input type="button" value="Close" onClick="google.script.host.close();" />
</div>
</body>
</html>
server code:
function uploadTheFile(theForm) {
var fileBlob=theForm.fileToLoad;
var fldr = DriveApp.getFolderById('FolderId');
var file=fldr.createFile(fileBlob);
var fi=formatFileName(file);
var fileInfo={'name':fi.getName(),'type':fileBlob.getContentType(), 'size':fileBlob.getBytes(), 'folder':fldr.getName()};
return fileInfo;
}
I can confirm that this doesn't work in G-Suite Enterprise. I don't know why because I cannot find documentation that says how Google is serializing the data. It could be a browser/computer security setting or something in G-Suite.
However, there is an easier way to accomplish your need. You can use a Google Form with a file upload question and then create an on form submit trigger/event on it to copy the file to a team/shared drive. Here is sample code if you want to attach the trigger to the Google Form itself:
// ID of the destnation folder to save the file in
var destinationFolderID = "10gkU_2V9iYy-VKudOCOjydEpoepPTgPv"
function saveFileToTeamDrive(e)
{
// a place to save the URL of the uploaded file
var fileID;
// go through all of the responses to find the URL of the uploaded file
e.response.getItemResponses().forEach(function(itemResponse){
// once we find the question with the file
if(itemResponse.getItem().getTitle() == "File Upload Test")
{
// get the file ID from the response
fileID = itemResponse.getResponse();
return;
}
});
// stop if we didn't have one
if(!fileID.length) return;
// get the first index in the array
fileID = fileID[0];
// get the file
var file = DriveApp.getFileById(fileID);
// get the destination folder
var destinationFolder = DriveApp.getFolderById(destinationFolderID);
// make a copy
var newFile = file.makeCopy(destinationFolder);
Logger.log(newFile.getUrl());
}
You can also attach to the on form submit event of a Google Sheet that is linked to a Google Form. I find that way easier cause the Google Sheet on form submit trigger/event includes a JSON of the question/answers so you don't have to iterate all of them to find it. It also means you can re-run a submission if it failed.
WARNING
One important note, if you do either of these things do not give anyone else edit access to the code. This is because as soon as you create and authorize the trigger, anyone who has edit access to the code would be able to use it to gain access to your Google Drive (and anything else the trigger is authorized for). Please see securing a Google Apps Script linked to an authorized trigger so others can edit for more information.