I have created an app script to get list of all files available in Gdrive. While executing I m unable to pass the file names which are generated during the execution to tag.
My goal is to list the file names which are generated to be populated in HTML
Code.gs
var gSheetName;
var sheet = SpreadsheetApp.openById('1XyZ2m_knnyM7cLN-DtLcHyLX0pKOt5uASCcV8');
var sheets= sheet.getSheetByName('FileList');
var Fname, CountofFiles;
var sessionuser = Session.getActiveUser().getEmail();
function doGet(e) {
return HtmlService.createTemplateFromFile('params').evaluate();
}
function Start() {
try {
gSheetName=sheet.getId();
listFolders(DriveApp.getRootFolder());
return Fname;
}
catch(error) { return error.toString();}
}
function listFolders(folder) {
var folder = folder || DriveApp.getRootFolder();
var files = folder.getFiles();
var data;
while ( files.hasNext() ) {
var file1 = files.next();
var file1 = file1.getId();
var file=DriveApp.getFileById(file1);
var value = Math.floor((file.getLastUpdated()-file.getDateCreated())/(24*3600*1000));
var value1;
var emailid = Session.getActiveUser().getEmail();
Fname = file.getName(); //I want to list this file name in HTML one by one
fileList(Fname);
data = [
file.getName(),
file.getDateCreated(),
file.getLastUpdated(),
folder.getName(),
folder.getId(),
file.getSize()
];
sheets.appendRow(data);
data=[];
}
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
listFolders(subfolders.next());
}
}
function fileList(fileName) {
var Fname1 = Fname;
return Fname1;
}
params.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form id="myForm">
<a class="waves-effect waves-light btn-large" onclick="google.script.run.withSuccessHandler(execute).Start();Showhide();">
<i class="material-icons left">cloud</i> Execute
</a>
</form>
<div id="output" style="display:none">
<p>Please wait while we are extracting records...</p>
<img src="https://media.giphy.com/media/3oEjI6SIIHBdRxXI40/giphy.gif">
</div>
<div id="Flist"></div>
<script>
function execute(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('Flist').innerHTML = execute();
document.getElementById('output').innerHTML = 'Completed';
}
function Showhide() {
var x = document.getElementById("output");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
I Need to display list of files which are generated by "Fname = file.getName();" this is where the file names are stored to the variable Fname. Is there a way i can populate these file names in HTML. I tried logging the records which is giving me the names in log but unfortunately i m unable to list in HTML tag. Please help me to solve this.
When you use google.script.run.withSuccessHandler(function) and the server function returns a value, the API passes the value to the new function as a parameter.
Which means when you call google.script.run.withSuccessHandler(execute).Start(), the return value of your Start() will be passed as an argument in your execute().
I noticed that you are trying to call your execute() to get your Flist here:
function execute(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('Flist').innerHTML = execute();
document.getElementById('output').innerHTML = 'Completed';
}
Sample Code Modification:
(code.gs - modified part only)
var Fname = [], CountofFiles;
function Start() {
try {
gSheetName=sheet.getId();
//Clear sheet
sheets.clear();
listFolders(DriveApp.getRootFolder());
return Fname;
}
catch(error) { return error.toString();}
}
function listFolders(folder) {
var folder = folder || DriveApp.getRootFolder();
var files = folder.getFiles();
var data;
while ( files.hasNext() ) {
var file1 = files.next();
var file1 = file1.getId();
var file=DriveApp.getFileById(file1);
var value = Math.floor((file.getLastUpdated()-file.getDateCreated())/(24*3600*1000));
var value1;
var emailid = Session.getActiveUser().getEmail();
//var fileFname = file.getName(); //I want to list this file name in HTML one by one
//fileList(file.getName());
Fname.push(file.getName());
data = [
file.getName(),
file.getDateCreated(),
file.getLastUpdated(),
folder.getName(),
folder.getId(),
file.getSize()
];
sheets.appendRow(data);
data=[];
}
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
listFolders(subfolders.next());
}
}
(params.html - modified part only)
function execute(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('Flist').innerHTML = status;
document.getElementById('output').innerHTML = 'Completed';
}
Changes done:
Clear FileList sheet every time you click Execute in your html page
I changed Fname to an array and push all file names found.
The array of file names returned by Start() will be passed as argument in your execute(status) hence you can access that in your status variable.
Output:
Related
Yo,
I would like to create a script where the user can choose a folder and then by getting the id of the folder I display the size of the folder.
I manage to retrieve the ID but I don't know how from this id I can calculate the size and display it.
here is the code to show the picker google drive :
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<script type="text/javascript">
var DIALOG_DIMENSIONS = {
width: 600,
height: 425
};
var pickerApiLoaded = false;
function onApiLoad() {
gapi.load('picker', {
'callback': function() {
pickerApiLoaded = true;
}
});
google.script.run.withSuccessHandler(createPicker)
.withFailureHandler(showError).getOAuthToken();
}
function createPicker(token) {
if (pickerApiLoaded && token) {
var docsView = new google.picker.DocsView()
.setIncludeFolders(true)
.setMimeTypes('application/vnd.google-apps.folder')
.setSelectFolderEnabled(true);
var picker = new google.picker.PickerBuilder()
.addView(docsView)
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.hideTitleBar()
.setSize(DIALOG_DIMENSIONS.width - 2, DIALOG_DIMENSIONS.height - 2)
.setOAuthToken(token)
.setCallback(pickerCallback)
.setOrigin('https://docs.google.com')
.build();
picker.setVisible(true);
} else {
showError('Unable to load the file picker.');
}
}
/**
* A callback function that extracts the chosen document's metadata from the
* response object. For details on the response object, see
* https://developers.google.com/picker/docs/result
*
* #param {object} data The response object.
*/
function pickerCallback(data) {
var action = data[google.picker.Response.ACTION];
if (action == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
var id = doc[google.picker.Document.ID];
// Show the ID of the Google Drive folder
document.getElementById('result').innerHTML = id;
} else if (action == google.picker.Action.CANCEL) {
google.script.host.close();
}
}
function showError(message) {
document.getElementById('result').innerHTML = 'Error: ' + message;
}
</script>
</head>
<body>
<div>
<p id='result'></p>
</div>
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>
function onOpen() {
SpreadsheetApp.getUi().createMenu('Google Picker')
.addItem('Choose Folder', 'showPicker')
.addToUi();
}
/**
* Displays an HTML-service dialog in Google Sheets that contains client-side
* JavaScript code for the Google Picker API.
*/
function showPicker() {
var html = HtmlService.createHtmlOutputFromFile('Picker.html')
.setWidth(600)
.setHeight(425)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi().showModalDialog(html, 'Select Folder');
}
function getOAuthToken() {
DriveApp.getRootFolder();
return ScriptApp.getOAuthToken();
}
I would like to merge the two code.gs file with the id of picker.html
function test(){
var root = DriveApp.getFolderById("1fl7XeqwelnlJJnSQjjvDmdxYudfCwQAR");
var list = [];
var list = recurseFolder(root, list);
//Logger.log(JSON.stringify(list));
//This is just how I am testing the outputed list. You can do what you need.
var sheet = SpreadsheetApp.getActiveSheet();
//list.forEach(function (row){
// sheet.appendRow(row);
//});
Logger.log("test !\n")
}
var fileCounter = folderCounter = fileSize = 0;
function recurseFolder(folder, list){
var files = folder.getFiles();
var subfolders = folder.getFolders();
while (files.hasNext()){ //add all the files to our list first.
var file = files.next();
var row = [];
fileCounter++;
fileSize+=file.getSize();
//Logger.log("File: " + folder.getName());
//row.push(folder.getName(),file.getName(),file.getId(),file.getUrl(),file.getSize(),file.getDateCreated(),file.getLastUpdated())
//list.push(row);
}
while (subfolders.hasNext()){ //Recurse through child folders.
subfolder = subfolders.next();
folderCounter++;
//Logger.log("Folder: " + subfolder.getName());
list = recurseFolder(subfolder, list); //Past the original list in so it stays a 2D Array suitible for inserting into a range.
}
Logger.log ("file : " + fileCounter + " folderCounter : " + folderCounter + " fileSize : " + fileSize);
}
You can use gapi to use the Drive API and use it to do the exact same logic as you did in Apps Script. You can read the official quickstart and modify it to query the size of files instead of simply listing the names.
Note that you'll have to load auth, client, and picker. Also you'll have to integrate the picker with it.
References
The Google Picker API (Picker API guide)
JavaScript (Browser) Quickstart (Google Drive API guide)
Files: get (Google Drive API reference)
Files resource (Google Drive API reference)
This is a continuation of previous question I made in this forum.
I made some changes in the code by adding else condition. What I'm trying to work out is to show the current status as the page loads. the current code shows the status only if the button get clicked.
How can I get the current status appear as the page loads and the status get updated when button get clicked.
CODE.GS
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Index');
}
function checkStatus(notify) {
var employee = "John Peter";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var mainSheet = ss.getSheetByName("MAIN");
var data = mainSheet.getDataRange().getValues();
for (var j = 0; j < data.length; j++){
var row = data[j];
var mainSheet2 = row[4];
var mainSheet3 = row[0];
var status = (mainSheet2 =="IN" && mainSheet3 == employee) ;
if (status == true){
var notify = employee +" You Are In"
return notify;
}
else{
var status = (mainSheet2 =="OUT" && mainSheet3 == employee) ;
if (status == true){
var notify2 = employee +" You Are Out"
return notify2;
}
}
}
}
Index.html
<body>
<div>
<button onclick="onStatus()">Check Status</button>
<font color='Green' id="status" onbeforeprint="onStatus" ></font>
</div>
<script>
function onStatus() {
google.script.run.withSuccessHandler(updateStatus) // Send the backend result to updateStatus()
.checkStatus(); // Call the backend function
}
function updateStatus(notify) {
document.getElementById('status').innerHTML= notify;
}
</script>
</body>
You can invoke this function at page load like below. Add this script at then end, just before your body tag ends.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
// The code in this function runs when the page is loaded.
$(function() {
google.script.run.withSuccessHandler(updateStatus)
.checkStatus();
});
</script>
My file downloading function takes more than 6 minutes. Therefore, I couldn't download the whole files. Is there anyway to complete the download within 6 minutes? Or any other solution ?
Html
<html>
<form id="downloadpdf">
<input id="urlclass" type="text" name="urlname" />
</form>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
var urllink = []; //this value assigned by another function. But let us assign statics variable as example urllink={“url1,url2,url3”}
$(document).ready(function() {
$("#downloadpdf").submit(function() {
$("#urlclass").val(urllink);
google.script.run.withSuccessHandler(function(retsearch){
}).downloadthefile(this);
});
});
</script>
</html>
code.gs
function downloadthefile(urlpass) {
var timezone = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
var now = Utilities.formatDate(new Date(),timezone, "EEE MMM d yyyy HH:mm:ss");
var dest_folder = DriveApp.createFolder(now);
var dest_folder_id = DriveApp.getFoldersByName(dest_folder).next().getId();
var source_folder = DriveApp.getFolderById(“the source folder id");
var dest_folder = DriveApp.getFolderById(dest_folder_id );
// The url that is passed to the function as string
var urlstring = urlpass.urlname;
// Make array of url
var resultarray = urlstring.split(',');
for(var i=0; i < resultarray.length; i++){
var fileurl = resultarray[i];
// Retrieve the url Id
var fileid = fileurl.match(/[-\w]{25,}/);
var file = DriveApp.getFileById(fileid);
var filecopy = file.makeCopy(file.getName());
dest_folder.addFile(filecopy);
}
}
Workaround for not hitting Google Apps Script execution time limit is to run copy requests in your modal window code (plain JavaScript with XHR requests to Google Drive API) instead of doing it in GAS script.
Edited [adapted for Deploy as web app]:
Code.gs:
function doGet(){
var template = HtmlService.createTemplateFromFile('copyDriveFiles')
// need to have next line of text somewhere (even commented out) to trigger correct scopes for script and token:
// DriveApp.getFiles() // <- DO NOT DELETE THIS COMMENT
// pass token
template.data = {
token: ScriptApp.getOAuthToken()
};
var html = template.evaluate().setTitle('Download');
return html;
}
copyDriveFiles.html:
<html>
<head>
</head>
<body>
<form id="downloadform">
<input id="downloadpdf" type="submit" value="download">
</form>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
// this value assigned by another function. But let us assign statics variable as example urllink = '{“url1,url2,url3”}'
var urllink = 'https://docs.google.com/document/d/XXXXXX/edit,https://docs.google.com/document/d/ZZZZZZ/edit';
// download files
$(document).ready(function(){
$("#downloadform").submit(function(e){
downloadFiles(urllink);
return false;
});
});
function downloadFiles(urllink)
{
<?
// create destination folder
var timezone = Session.getScriptTimeZone();
var now = Utilities.formatDate(new Date(), timezone, "EEE MMM d yyyy HH:mm:ss");
var folder = DriveApp.createFolder(now);
var folderId = folder.getId();
?>
// get folder id
var folderId = <?=folderId?>;
var resultArray = urllink.split(',');
// loop file urls
for (var i = 0; i < resultArray.length; i++)
{
// retrieve the file id from url
var fileId = resultArray[i].match(/[-\w]{25,}/);
// copy file to folder
copyFileToFolder(fileId, folderId);
}
}
function copyFileToFolder(fileId, folderId)
{
var xhr = new XMLHttpRequest();
// request payload - set parents
// here you can specify file name etc: https://developers.google.com/drive/v3/reference/files/copy
var requestBody = {
parents: [folderId]
};
xhr.open('POST', 'https://www.googleapis.com/drive/v3/files/'+fileId+'/copy');
xhr.setRequestHeader('Authorization', 'Bearer <?=data.token?>');
xhr.setRequestHeader('Content-type', 'application/json');
// send request
xhr.send(JSON.stringify(requestBody));
}
</script>
</body>
</html>
Result:
I have tried several things but its not working. Can someone help me to understan the problem with this code. This is a file upload script. I'm using it with codeigniter. My requirement is after user upload files(works right now) those file names should added to the hidden field.
<input type="hidden" name="extra_images" value="" />
<label for="deal_duration">Deal Extra Images</label>
<div id="uploads"></div>
<div class="dropzone" id="dropzone">Drop files here to upload</div>
<script type="text/javascript">
(function(){
var dropzone = document.getElementById('dropzone');
var uploads = new Array();
var hidden = document.getElementsByName('extra_images');
var displayUploads = function(data){
var uploads = document.getElementById('uploads'),
anchor,
x;
var errors = new Array();
for(x=0;x<data.length;x=x+1){
if((typeof(data[x].file) === 'undefined') && (typeof(data[x].error) != 'undefined'))
{
errors.push(data[x].error);
}
else
{
anchor = document.createElement('a');
anchor.href = 'http://localhost/project-cg/'+ data[x].file;
anchor.innerText = data[x].name;
anchor.target = '_blank';
uploads.appendChild(anchor);
uploads.push(data[x].data[x].name);
}
}
if(errors.length > 0){
alert(errors);
}
if(uploads.length > 0){
//This is what I tried so far.But its not working
hidden.value = uploads.join("|");
}
}
var upload = function(files){
var formData = new FormData(),
xhr = new XMLHttpRequest(),
x;
for(x=0;x<files.length;x=x+1){
formData.append('file[]',files[x]);
}
xhr.onload = function(){
var data = JSON.parse(this.responseText);
displayUploads(data);
}
xhr.open('post','http://localhost/project-cg/image_upload');
xhr.send(formData);
}
dropzone.ondrop = function(e){
e.preventDefault();
this.className = 'dropzone';
upload(e.dataTransfer.files);
}
dropzone.ondragover = function(){
this.className = 'dropzone dragover';
return false;
}
dropzone.ondragleave = function(){
this.className = 'dropzone';
return false;
}
}());
</script>
After I post data hidden field is still empty.
I saw your error:
You have 2 variables called uploads. One is an instance of the div and the other is the array.
What you are basically doing is assigning it a new type whenever you launch the function and in the end you have no array to pull data from. Try renaming them.
var hidden = document.getElementsByName('extra_images'); // returns a list of nodes
Try something like this :
hidden[0].value = uploads.join("|");
see mdn
I've written some code to display my favorites in IE8 but for an unknown reason I have no output on the screen despite the fact that my page is accepted by IE and that the test text 'this is a test' is displayed.
my code :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso 8859-1" />
<script type="text/javascript">
var i = 0;
var favString = "";
var fso;
function GetFavourites(Folder) {
var FavFolder = fso.GetFolder(Folder);
//Gets Favourite Names & URL's for given folder.
var files = new Enumerator(FavFolder.Files);
for (; !files.atEnd(); files.moveNext()) {
var fil = files.item();
if (fil.Type == "Internet Shortcut") {
var textReader = fso.OpenTextFile(fil.Path, 1, false, -2);
var favtext = textReader.ReadAll();
var start = favtext.indexOf("URL", 16);
var stop = favtext.indexOf("\n", start);
favString += fil.Name.replace(/.url/, "");
favString += ":URL:";
//to separate favourite name & favorite URL
favString += favtext.substring(start + 4, stop - 1);
favorites.innerHTML += favString; // Not working !
favorites.innerHTML += 'test'; // Not working too !
favString += ":NEXT:"; //to separate favorites.
i++;
}
}
//Checks any subfolder exists
var subfolders = new Enumerator(FavFolder.SubFolders);
for (; !subfolders.atEnd(); subfolders.moveNext()) {
var folder = subfolders.item();
GetFavourites(folder.Path);
}
}
function Import() {
try {
fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso !== null) {
//Create windows script shell object to access Favorites folder in user system.
var object = new ActiveXObject("WScript.Shell");
var favfolderName = object.SpecialFolders("Favorites");
if (favString === "") {
GetFavourites(favfolderName);
}
}
}
catch (err) {
alert("Security settings to be modified in your browser ");
}
}
</script>
</head>
<body onload="Import()">
<p>this is a test</p> <!-- Working ! -->
<div id="favorites">
</div>
</body>
</html>
The following works for me:
var fso, favs = [];
function GetFavourites(Folder) {
var FavFolder = fso.GetFolder(Folder);
//Gets Favourite Names & URL's for given folder.
var files = new Enumerator(FavFolder.Files);
for (; !files.atEnd(); files.moveNext()) {
var fil = files.item();
if (fil.Type == "Internet Shortcut") {
var textReader = fso.OpenTextFile(fil.Path, 1, false, -2);
var favtext = textReader.ReadAll();
var start = favtext.indexOf("URL", 16);
var stop = favtext.indexOf("\n", start);
favString = fil.Name.replace(/.url/, "");
favString += ":URL:";
//to separate favourite name & favorite URL
favString += favtext.substring(start + 4, stop - 1);
favs.push(favString);
}
}
//Checks any subfolder exists
var subfolders = new Enumerator(FavFolder.SubFolders);
for (; !subfolders.atEnd(); subfolders.moveNext()) {
var folder = subfolders.item();
GetFavourites(folder.Path);
}
}
function Import() {
try {
fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso !== null) {
//Create windows script shell object to access Favorites folder in user system.
var object = new ActiveXObject("WScript.Shell");
var favfolderName = object.SpecialFolders("Favorites");
if (favString === "") {
GetFavourites(favfolderName);
}
}
}
catch (err) {
alert("Security settings to be modified in your browser ");
}
}
Note that all I changed was the output from an element to an array named favs. I also removed the i variable, because it wasn't used. After running the script, I checked the array in the developer tools console and it contained all my favourites.
If you're getting no output at all, then either fso is null in the Import method or files.AtEnd() always evaluates to false. Since you're focusing on IE here, you might consider placing alert methods in various places with values to debug (such as alert(fso);) throughout your expected code path.