2
votes

I've got a stand-alone script deployed as a Web App. My code is working exactly as it should as a Web App. However, my goal is to use that code in a Spreadsheet Project.

I copied and pasted the code into a Spreadsheet Script and made a few alterations to make it work in a pop-up Modal dialog window, but it does not work as it does as a deployed web app. The code seems to not return any data to Code.gs. After running alerts at various points along the code path I have discovered the point of failure but am not sure how to address it.

Code from the working WebApp (2 files: Code.gs & form.html):

## Code.gs file ##
function doGet() {
  return HtmlService.createHtmlOutputFromFile('form')
    .setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

function uploadFileToDrive(base64Data, fileName, totalFiles, finalCount) {
  try{
    var splitBase = base64Data.split(','),
        type = splitBase[0].split(';')[0].replace('data:','');

    var byteCharacters = Utilities.base64Decode(splitBase[1]);
    var ss = Utilities.newBlob(byteCharacters, type);
    ss.setName(fileName);

    var dropbox = "stuff"; // Folder Name
    var folder, folders = DriveApp.getFoldersByName(dropbox); // Get folders by name

    if (folders.hasNext()) {
      folder = folders.next();
    } else {
      folder = DriveApp.createFolder(dropbox);
    }
    var file  = folder.createFile(ss);

    // BEGIN LOGGING FILE NAMES AND IDs
    var dropboxId = "SOME_FOLDER_ID_HERE" // Folder ID
    var theFolder = DriveApp.getFolderById(dropboxId); // Get folder by ID
    var list     = [];
    var theBlobs = [];
    if (totalFiles == finalCount) {
      var files = theFolder.getFiles();
      while (files.hasNext()) {
        var theFile = files.next();
        list.push(theFile.getId());
      }
      for (var i = 0; i < list.length; i++) {
        Logger.log(DriveApp.getFileById(list[i]).getName() + " : " + list[i]);
        theBlobs.push(DriveApp.getFileById(list[i]).getBlob());
      }
      Logger.log(theBlobs);
      // END LOGGING FILE NAMES AND IDs


      // BEGIN ZIPPING UP FILES
        var newZip = theFolder.createFile(Utilities.zip(theBlobs, 'zippedFiles.zip'));
        var zipId  = newZip.getId();
        Logger.log("Zip Id: " + zipId);
      // END ZIPPING UP FILES


      // BEGIN TRASHING UPLOADED FILES
      for (var i = 0; i < list.length; i++) {
        DriveApp.getFileById(list[i]).setTrashed(true);
      }
      // END TRASHING UPLOADED FILES
    }

    return file.getName();
  }catch(e){
    return 'Error: ' + e.toString();
  }
}


## form.html ##
<body>
  <div id="formcontainer">

    <form id="myForm">

      <label for="myFile">Upload File(s):</label><br />

      <input type="file" name="filename" id="myFile" multiple />

      <input type="button" class="blue" value="Submit" onclick="iteratorFileUpload()" /><br /><br />

    </form>
  </div>

  <div id="output"></div>

  <div id="progressbar">
    <div class="progress-label"></div>
  </div>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="https://googledrive.com/host/0By0COpjNTZPnZTBvVGZOSFRhREE/add-ons.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

<script>
var numUploads   = {};
numUploads.done  = 0 ;
numUploads.total = 0 ;

// Upload the files into a folder in drive...set to send them all to one folder (specificed in the .gs file)
function iteratorFileUpload() {
    var allFiles = document.getElementById('myFile').files;

    if (allFiles.length == 0) {
        alert('No file selected!');
    } else { // Show Progress Bar
        var myCount = 0; // Begin count to compare loops through
        numUploads.total = allFiles.length;
        $('#progressbar').progressbar({
        value : false
        });
        $(".progress-label").html('Preparing files..');
        // Send a file at a time
        for (var i = 0; i < allFiles.length; i++) {
            myCount++; // Increment count each time before sending the file to drive
            sendFileToDrive(allFiles[i], allFiles.length, myCount);
        }
    }
}

function sendFileToDrive(file, totalFiles, newCount) {
    var reader = new FileReader();
    reader.onload = function (e) {
        var content = reader.result;
        google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, totalFiles, newCount);
    }
    reader.readAsDataURL(file);
}

function updateProgressbar( idUpdate ){
   numUploads.done++;
   var porc = Math.ceil((numUploads.done / numUploads.total)*100);
   $("#progressbar").progressbar({value: porc });
   $(".progress-label").text(numUploads.done +'/'+ numUploads.total);
   if( numUploads.done == numUploads.total ){
      numUploads.done = 0;
   };
}

function fileUploaded(status) {
  document.getElementById('myForm').style.display = 'none';
  document.getElementById('output').innerHTML = status;
}
</script>

  <style>
    body {
      max-width: 400px;
      padding: 20px;
      margin: auto;
    }
    input {
      display: inline-block;
      width: 100%;
      padding: 5px 0px 5px 5px;
      margin-bottom: 10px;
      -webkit-box-sizing: border-box;
      ‌​ -moz-box-sizing: border-box;
      box-sizing: border-box;
    }
    select {
      margin: 5px 0px 15px 0px;
    }
    input[type="submit"] {
      width: auto !important;
      display: block !important;
    }
    input[type="file"] {
      padding: 5px 0px 15px 0px !important;
    }
#progressbar{
    width: 100%;
    text-align: center;
    overflow: hidden;
    position: relative;
    vertical-align: middle;

}
.progress-label {
      float: left;
margin-top: 5px;
      font-weight: bold;
      text-shadow: 1px 1px 0 #fff;
          width: 100%;
    height: 100%;
    position: absolute;
    vertical-align: middle;
    }
  </style>
</body>

When deploying as a Spreadsheet container bound app the code is as follows (2 files: Code.gs & form.html):

## Code.gs ##
function uploadFiles() {

  function doGet() {
    return SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutputFromFile('form').setSandboxMode(HtmlService.SandboxMode.IFRAME), "Upload Files");
  }

  doGet();

  function uploadFileToDrive(base64Data, fileName, totalFiles, finalCount) {
    try{
      var splitBase = base64Data.split(','),
          type = splitBase[0].split(';')[0].replace('data:','');

      var byteCharacters = Utilities.base64Decode(splitBase[1]);
      var ss = Utilities.newBlob(byteCharacters, type);
      ss.setName(fileName);

      var dropbox = "stuff"; // Folder Name
      var folder, folders = DriveApp.getFoldersByName(dropbox); // Get folders by name

      if (folders.hasNext()) {
        folder = folders.next();
      } else {
        folder = DriveApp.createFolder(dropbox);
      }
      var file  = folder.createFile(ss);

      // BEGIN LOGGING FILE NAMES AND IDs
      var dropboxId = "SOME_FOLDER_ID_HERE" // Folder ID
      var theFolder = DriveApp.getFolderById(dropboxId); // Get folder by ID
      var list     = [];
      var theBlobs = [];
      if (totalFiles == finalCount) {
        var files = theFolder.getFiles();
        while (files.hasNext()) {
          var theFile = files.next();
          list.push(theFile.getId());
        }
        for (var i = 0; i < list.length; i++) {
          Logger.log(DriveApp.getFileById(list[i]).getName() + " : " + list[i]);
          theBlobs.push(DriveApp.getFileById(list[i]).getBlob());
        }
        Logger.log(theBlobs);
        // END LOGGING FILE NAMES AND IDs


        // BEGIN ZIPPING UP FILES
          var newZip = theFolder.createFile(Utilities.zip(theBlobs, 'zippedFiles.zip'));
          var zipId  = newZip.getId();
          Logger.log("Zip Id: " + zipId);
        // END ZIPPING UP FILES


        // BEGIN TRASHING UPLOADED FILES
        for (var i = 0; i < list.length; i++) {
          DriveApp.getFileById(list[i]).setTrashed(true);
        }
        // END TRASHING UPLOADED FILES
      }

      return file.getName();
    }catch(e){
      return 'Error: ' + e.toString();
    }
  }
}


## form.html ##
<body>
  <div id="formcontainer">

    <form id="myForm">

      <label for="myFile">Upload File(s):</label><br />

      <input type="file" name="filename" id="myFile" multiple />

      <input type="button" class="blue" value="Submit" onclick="iteratorFileUpload()" /><br /><br />

    </form>
  </div>

  <div id="output"></div>

  <div id="progressbar">
    <div class="progress-label"></div>
  </div>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="https://googledrive.com/host/0By0COpjNTZPnZTBvVGZOSFRhREE/add-ons.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

<script>
var numUploads   = {};
numUploads.done  = 0 ;
numUploads.total = 0 ;

// Upload the files into a folder in drive...set to send them all to one folder (specificed in the .gs file)
function iteratorFileUpload() {
    var allFiles = document.getElementById('myFile').files;

    if (allFiles.length == 0) {
        alert('No file selected!');
    } else { // Show Progress Bar
        var myCount = 0; // Begin count to compare loops through
        numUploads.total = allFiles.length;
        $('#progressbar').progressbar({
        value : false
        });
        $(".progress-label").html('Preparing files..');
        // Send a file at a time
        for (var i = 0; i < allFiles.length; i++) {
            myCount++; // Increment count each time before sending the file to drive
            sendFileToDrive(allFiles[i], allFiles.length, myCount);
        }
    }
}

function sendFileToDrive(file, totalFiles, newCount) {
    var reader = new FileReader();
    reader.onload = function (e) {
        var content = reader.result;
        google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, totalFiles, newCount);
    }
    reader.readAsDataURL(file);
}

function updateProgressbar( idUpdate ){
   numUploads.done++;
   var porc = Math.ceil((numUploads.done / numUploads.total)*100);
   $("#progressbar").progressbar({value: porc });
   $(".progress-label").text(numUploads.done +'/'+ numUploads.total);
   if( numUploads.done == numUploads.total ){
      numUploads.done = 0;
   };
}

/*
function updateProgressbar( idUpdate ){
   numUploads.done++;
   var porc = Math.ceil((numUploads.done / numUploads.total)*100);
   $("#progressbar").progressbar({value: porc });
   $(".progress-label").text(numUploads.done +'/'+ numUploads.total);
   if( numUploads.done == numUploads.total ){
      numUploads.done = 0;
   };
}
*/

function fileUploaded(status) {
  document.getElementById('myForm').style.display = 'none';
  document.getElementById('output').innerHTML = status;
}
</script>

  <style>
    body {
      max-width: 400px;
      padding: 20px;
      margin: auto;
    }
    input {
      display: inline-block;
      width: 100%;
      padding: 5px 0px 5px 5px;
      margin-bottom: 10px;
      -webkit-box-sizing: border-box;
      ‌​ -moz-box-sizing: border-box;
      box-sizing: border-box;
    }
    select {
      margin: 5px 0px 15px 0px;
    }
    input[type="submit"] {
      width: auto !important;
      display: block !important;
    }
    input[type="file"] {
      padding: 5px 0px 15px 0px !important;
    }
#progressbar{
    width: 100%;
    text-align: center;
    overflow: hidden;
    position: relative;
    vertical-align: middle;

}
.progress-label {
      float: left;
margin-top: 5px;
      font-weight: bold;
      text-shadow: 1px 1px 0 #fff;
          width: 100%;
    height: 100%;
    position: absolute;
    vertical-align: middle;
    }
  </style>
</body>

The non-working code stops at this point: google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, totalFiles, newCount);.

Up to that point everything moves along nicely and info is passed from function to function.

In the Spreadsheet script the files never get uploaded to Drive and the counter for the files that displays on the html page never increments...it just stalls.

The closest articles I've come across that may aid in resolving this are: how to use google.script.run as if it was a function that was originally proposed as a solution to this question Google Apps Script HTML Service: Passing variables and Returning a value using Date picker in HTMLService / Google Apps Script.

Thank you for your help in advance!!

1

1 Answers

0
votes

The solution was rather simple since the underlying code already functioned as a stand-alone Web App.

The only changes needed made were to the Code.gs file.

Pulled out the beginning of the code and kept it in it's own top-level function:

function uploadFiles() {

  function doGet() {
    return SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutputFromFile('form').setSandboxMode(HtmlService.SandboxMode.IFRAME), "Upload Files");
  }

  doGet();
}

Then put the remainder in it's own top-level function as well:

function uploadFileToDrive(base64Data, fileName, totalFiles, finalCount) {
  try{
    var splitBase = base64Data.split(','),
    type = splitBase[0].split(';')[0].replace('data:','');

    var byteCharacters = Utilities.base64Decode(splitBase[1]);
    var ss = Utilities.newBlob(byteCharacters, type);
    ss.setName(fileName);

    var dropbox = "stuff"; // Folder Name
    var folder, folders = DriveApp.getFoldersByName(dropbox); // Get folders by name

    if (folders.hasNext()) {
      folder = folders.next();
    } else {
      folder = DriveApp.createFolder(dropbox);
    }
    var file  = folder.createFile(ss);

    // BEGIN LOGGING FILE NAMES AND IDs
    var dropboxId = "SOME_FOLDER_ID_HERE" // Folder ID
    var theFolder = DriveApp.getFolderById(dropboxId); // Get folder by ID
    var list     = [];
    var theBlobs = [];
    if (totalFiles == finalCount) {
      var files = theFolder.getFiles();
      while (files.hasNext()) {
        var theFile = files.next();
        list.push(theFile.getId());
      }
      for (var i = 0; i < list.length; i++) {
        Logger.log(DriveApp.getFileById(list[i]).getName() + " : " + list[i]);
        theBlobs.push(DriveApp.getFileById(list[i]).getBlob());
      }
      Logger.log(theBlobs);
      // END LOGGING FILE NAMES AND IDs


      // BEGIN ZIPPING UP FILES
        var newZip = theFolder.createFile(Utilities.zip(theBlobs, 'zippedFiles.zip'));
        var zipId  = newZip.getId();
        Logger.log("Zip Id: " + zipId);
      // END ZIPPING UP FILES


      // BEGIN TRASHING UPLOADED FILES
      for (var i = 0; i < list.length; i++) {
        DriveApp.getFileById(list[i]).setTrashed(true);
      }
      // END TRASHING UPLOADED FILES
    }

    return file.getName();
  }catch(e){
    return 'Error: ' + e.toString();
  }
}

It now works perfectly as a script attached to a Spreadsheet!