This is a followup on this post.
I'm now trying to use a template file so I can pull in some css, etc. I am publishing this as a web app. The output should be a list of the files in a Google Drive directory contained in an iframe.
The loading message appears in the iframe and I don't get any syntax errors but the list of files in the directory does not appear.
code.gs:
function doGet() {
return HtmlService.createHtmlOutputFromFile('page');
}
function FileList() {
// my folder ID
var dir = '[MY_FOLDER_ID]';
var folder = DriveApp.getFolderById(dir);
var contents = folder.getFiles();
var filelist = [];
var file, name, url, idName = [];
while (contents.hasNext()) {
file = contents.next();
name = file.getName();
idName = name.toUpperCase();
url = file.getUrl();
// add table row html to filelist array
filelist = filelist.concat('<tr><td><a id="' + idName + '" target="_blank" href="' + url + '">' + name + '</a></td></tr>');
}
// alpha sort filelist array
filelist.sort();
// turn filelist into a string
filelist = filelist.join("");
return filelist;
}
page.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onSuccess(foo) {
var table = document.getElementById('output');
table.innerHTML = foo;
}
google.script.run.withSuccessHandler(onSuccess).getFileList();
</script>
</head>
<body>
<table id="output">Loading Files...</table>
</body>
</html>
There is syntax/typo in your code here:
google.script.run.withSuccessHandler(onSuccess).getFileList();
it should be
google.script.run.withSuccessHandler(onSuccess).FileList();
Since the function name in google script is FileList and not getFileList().
Tip: You can use inspect or developer console in google chrome to see your errors when you run web app.(Not sure if you knew it.)
Hope that helps, good luck!
Related
I am using gnuplot-js https://github.com/chhu/gnuplot-JS when I am without my laptop at university.
Is it possible to use an external url for gnuplot.js file? I host index.html, gnuplot_api.js on https://mywebsite.com/ but I would like to use another url for gnuplot.js file (for example https://external.com/blabla/ok/no/gnuplot.js) because this file is really big!
Maybe this is the part I should edit on index.html. How? :
<script src='gnuplot_api.js'></script>
<script>
gnuplot = new Gnuplot('gnuplot.js');
gnuplot.onOutput = function(text) {
document.getElementById('output').value += text + '\n';
document.getElementById('output').scrollTop = 99999;
};
or maybe this part on gnuplot_api.js?:
var Gnuplot = function(js_filename) {
this.worker = new Worker(js_filename);
this.output = [];
this.error = [];
this.isRunning = false;
Thank you very much for your support
It appears Gnuplot use an onboard webworker, so the path provided to the constructor should be on the same domain than the script.
<script src='https://cdn.jsdelivr.net/gh/chhu/gnuplot-JS/www/gnuplot_api.js'></script>
<script>
gnuplot = new Gnuplot('https://cdn.jsdelivr.net/gh/chhu/gnuplot-JS/www/gnuplot.js');
</script>
First, this is a google-app-script issue... I can't seem to capture the second (or subsequent) parameters within the HTML page (i.e. "item" in this example)... I've seen many examples using "location.search" and "window.location.search", but none of these seem to work. Could it possibly be as simple as "location.search" is not the correct usage?
Example
Code.gs
var myParam;
/**
* Get the URL for the Google Apps Script running as a WebApp.
*/
function getScriptUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
/**
* Get "home page", or a requested page.
* Expects a 'page' parameter in querystring.
*
* #param {event} e Event passed to doGet, with querystring
* #returns {String/html} Html to be served
*/
function doGet(e) {
//Logger.log( Utilities.jsonStringify(e) );
Logger.log(e.parameter.page);
var pgToLoad = e.parameter.page;
if (!e.parameter.page) {
Logger.log('!e.parameter.page')
// When no specific page requested, return "home page"
// return HtmlService.createTemplateFromFile('my1').evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
return HtmlService.createTemplateFromFile('my1').evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
Logger.log('there is something for the page');
// else, use page parameter to pick an html file from the script
// return HtmlService.createTemplateFromFile(pgToLoad).evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
return HtmlService.createTemplateFromFile(pgToLoad).evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
I have multiple HTML files, but they are basically the same as my1.html below...
my1.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>Source = my1.html</h1>
<p id=myParam>Placeholder</p>
<?var url = getScriptUrl();?><a href='<?=url?>?page=my2&item=1-234'> <input type='button' name='button' value='my2.html'></a>
<?var url = getScriptUrl();?><a href='<?=url?>?page=my3&item=1-345'> <input type='button' name='button' value='my3.html'></a>
</body>
</html>
<script>
function getParam(sname)
{
var params = location.search;
var sval = "";
params = params.split("&");
// split param and value into individual pieces
for (var i=0; i<params.length; i++)
{
temp = params[i].split("=");
if ( temp[0] == sname ) { sval = temp[1]; }
}
return sval;
}
function changeItem() {
var param = getParam("item");
var myItem = "Item:-"+param+"-";
document.getElementById("myParam").innerHTML = myItem;
}
window.onload = changeItem;
</script>
I think I know what you want to do. It looks like you are getting the search string parameters from the doGet(e) function on the server side, then you are trying to get the same search string parameters again on the "client side" from the onload function? If this is the case, I would abandon trying to get the search string parameters from the client side.
You could store the search string parameters in the browsers sessionStorage:
window.sessionStorage.setItem("searchStringOne","Value One");
and to retrieve:
var valueOne = window.sessionStorage.getItem("searchStringOne");
Session Storage Information
Here's an example to show how to get the query string parameters to serve different html templates using html-service of app script :
function doGet(e) {
Logger.log( Utilities.jsonStringify(e) );
// Load a home page when no parameter is specified
if (!e.parameter.redirect) {
var template = HtmlService.createTemplateFromFile('home');
var htmlOutput = template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setTitle('Home');
return htmlOutput;
}
//get the page from parameter and load it
else{
var template=HtmlService.createTemplateFromFile(e.parameter['redirect']);
var htmlOutput = template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setTitle('Other Page');
return htmlOutput;
}
}
function getScriptUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
then HTML will look like this :
home.html
<?var url = getScriptUrl();?>
You are on Home Page.
<a href='<?=url?>?redirect=pagex'>Goto PageX</a>
<a href='<?=url?>?redirect=pagey'>Goto PageY</a>
pagex.html
You are on PageX
pagey.html
You are on PageY
Hope this helps!
My current script uses the code below to download a CSV file to local drive,
function table2CSV() {
var dataURL = '',
fieldSeparator = ',',
textField = '"',
lineSeparator = '\n',
regExpTesto = /(")/g,
regExp = /[";]/;
$('table tr').each(function() {
var dataRow = '';
if ($('input:checkbox', this).is(':checked') || $(this).is(':first- child'))
{
$('td', this).not(':last').each(function() {
var value = $(this).text();
if (dataRow !== '') dataRow += fieldSeparator;
if (regExp.test(value)) {
value = textField + value.replace(regExpTesto, '$1$1') + textField;
}
dataRow += value;
});
if (dataURL !== '') dataURL += lineSeparator;
dataURL += dataRow;
}
});
window.location.href = 'data:text/csv;charset=utf-8;base64,' + btoa(dataURL);
}
The download is done bye this line as far as I can tell :
window.location.href = 'data:text/csv;charset=utf-8;base64,' + btoa(dataURL);
I would like to be able to have it download(upload/saved) to a shared google drive folder instead.
I have seen similar questions on the forum but can't seem to see how to point the download to a shared google-drive folder.
What must code must be added/changed in order to achieve this ?
Thank you
EDIT: Nevermind, just realised they say it does not support data URIs:
Data URIs and file:// URLs are not supported
I will keep this answer in case anyone else searches for non-data URI uploading
Having a quick look, I came upon Save to Drive
While this might not be exactly what you want, it looks like an easy way to add the ability to save the contents of any URI (hopefully a data URI too) to Google Drive, like so:
<script src="https://apis.google.com/js/platform.js" async defer></script>
<div class="g-savetodrive"
data-src="//example.com/path/to/myfile.pdf"
data-filename="My Statement.pdf"
data-sitename="My Company Name">
</div>
I am using a script to print a spreadsheet to PDF.I would like to print it to a location on the drive "PDF Folder". Anyone know how to do this?
Heres is my code :
function printpdf(){
var spreadsheet_id="0AkcI3cOVJXI3dHg3Nnk3Y2JUakViTkUzQzdXSUdLNEE";
var spreadsheetFile = DocsList.getFileById(spreadsheet_id);
var blob = spreadsheetFile.getAs('application/pdf');
DocsList.createFile(blob);
}
just add it to the folder like this :
(I reproduce the whole code)
function printpdf(){
var spreadsheet_id="0AkcI3cOVJXI3dHg3Nnk3Y2JUakViTkUzQzdXSUdLNEE";
var spreadsheetFile = DocsList.getFileById(spreadsheet_id);
var blob = spreadsheetFile.getAs('application/pdf');
var folder = DocsList.getFolder('PDF Folder'); //get the folder by its path
var pdf = DocsList.createFile(blob).addToFolder(folder);
}
I want to unzip a file that contains an html page, css, and js directories. I want to unzip this temporarily and view the html in an iFrame, preferrably. I am using jszip which is working. I got the html to load, but how do I add the image, js, and css folders into the iFrame?
Here is what I have so far...
<div id="jszip_utils"></div>
<iframe id="iframe"></iframe>
<script type="text/javascript">
function showError(elt, err) {
elt.innerHTML = "<p class='alert alert-danger'>" + err + "</p>";
}
function showContent(elt, content) {
elt.innerHTML = "<p class='alert alert-success'>loaded !<br/>" +
"Content = " + content + "</p>";
}
var htmltext = JSZipUtils.getBinaryContent("/zip/myWebsite.zip", function (err, data) {
var elt = document.getElementById('jszip_utils');
if (err) {
showError(elt, err);
return;
}
try {
JSZip.loadAsync(data)
.then(function (zip) {
for(var name in zip.files) {
if (name.substring(name.lastIndexOf('.') + 1) === "html") {
return zip.file(name).async("string");
}
}
return zip.file("").async("string");
})
.then(function success(text) {
$('#iframe').contents().find('html').html(text);
showContent(elt, text);
}, function error(e) {
showError(elt, e);
});
} catch(e) {
showError(elt, e);
}
});
</script>
This gets the html, but the js css and image files are not showing up. I believe I need to do some sort of fake routing, but I'm not sure how I would be able to do that. Thanks for your help.
If the html/js in the zip is not too complicated, for instance an AngularJS app that has routes for partials, this is possible.
The trick is to replace css,js,img src/href urls that point to a file in the zip with either:
Object Url: URL.createObjectURL(Blob or File object);
Data Url: data:[<mediatype>][;base64],<data>
Or in the case of js and css inject the content directly into the appropriate element
After replacing the src/href references than just inject the new html into the iframe.
Step 1: Parse the html so you can manipulate it
//html from a call like zip.file("index.html").async("string")
let parser = new DOMParser;
let doc = parser.parseFromString(html,"text/html");
Step 2: Find all elements with a relative path (e.g. /imgs/img.jpg) as they are easier to deal with as you can then use that path for zip.file
//Simply finds all resource elements, then filters all that dont start with '/'
var elements = jQuery("link[href],script[src],img[src]",doc).filter(function(){
return /^\//.test(this.href || this.src);
});
Step 3: Replace src,href with object url, data url, or direct content
//assume element is the html element: <script src="/js/main.js"></script>
zip.file(element.src).async("string").then(jsText=>{
element.src = "data:text/javascript,"+encodeURIComponent(jsText);
});
Step 4: Get the new html text and inject it into the iframe
let newHTML = doc.documentElement.outerHTML;
var viewer = document.querySelector('#iframeID');
viewer = viewer.contentWindow || viewer.contentDocument.document || viewer.contentDocument;
viewer.document.open();
viewer.document.write(html);
viewer.document.close();
JSFiddle Demo - Demonstrates replacing the src/href urls
As a security note, if you are using zip files that you do not know the contents of, you should run the whole app in a protected iframe