Bee Tee
Bee Tee

Reputation: 129

How do you pass prompted data as a variable into a google docs bound script?

I have a rather large Google Doc (text file) that is divided into many chapters. It's a book that I am writing and from time to time, as I add chapters (often non-sequentially) I need to renumber all of the chapters. I do so in a two-step process: set all chapter numbers to a dummy placeholder, than replace all of those placeholders with the correct sequential numbers. I have been hard-coding the upper limit of the number of chapters, but now I'd like to change the process and take in a number of chapters from the user. I have written a prompt that does that. What I cannot get to work is passing that number as a variable back into my script that is bound to the document. I tried to hack some code I have used successfully in a web app using Google script. But it doesn't work in this situation (bound script versus web app) and I can't debug where it is failing as it originates in the index html and Google's debugger won't track that (or I don't know how to make it track it). I have been unable to find any questions at stackoverflow that address the issue of how to pass a prompted variable back into a bound script in a Google Doc. I'm sure it will be obvious to any real programmers that I am "painting by the numbers" with Google script, but I do invest a lot of time trying to teach myself how to do this and your help is much appreciated. I really need to get this to work. The idea of having to manually renumber all these chapters every time I add ten or so is pretty depressing!

My code so far is:

function onOpen() {
  var ui = DocumentApp.getUi();
  ui.createMenu('Custom')
      .addItem('Renumber Chapters', 'showDialog')
      .addToUi();
}

function showDialog() {
  var html = HtmlService.createHtmlOutputFromFile('Index')
      .setWidth(400)
      .setHeight(300);
  DocumentApp.getUi()
      .showModalDialog(html, 'Data Entry');
}
//Finds all numbered chapters and replaces with a placeholder "Chapter_"
function reChapter1(uObj){
  var body = DocumentApp.getActiveDocument().getBody();
  var numChaps = uObj.numChaps;
  var n = numChaps;
  var replaceTerm = "Chapter [0-9]+"
  for (i = 0; i < n; i++) { 
    num = i+1
    newText = "Chapter_";
    Logger.log(newText);
    replaceIt(replaceTerm, body);
  }
}
function replaceIt(replaceTerm, body) {    
  var found = body.findText(replaceTerm);
  if (found) {
   var start = found.getStartOffset();
    var end = found.getEndOffsetInclusive();
    var text = found.getElement().asText();
  text.deleteText(start, end);
  text.insertText(start, newText);
  }
}
//Finds placeholders and renumbers chapters
function reChapter2(uObj){
  var numChaps = uObj.numChaps;
  var n = numChaps;
  var replaceTerm = "Chapter_"
  var body = DocumentApp.getActiveDocument().getBody();
  for (i = 0; i < n; i++) { 
    num = i+1
    Logger.log(i);
    newText = "Chapter "+num+"";
    replaceIt(replaceTerm, body);
  }
}
function replaceIt(replaceTerm, body) {    
  var found = body.findText(replaceTerm);
  if (found) {
   var start = found.getStartOffset();
    var end = found.getEndOffsetInclusive();
    var text = found.getElement().asText();
  text.deleteText(start, end);
  text.insertText(start, newText);
  }
}

The html is:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body><center>
Enter the estimated number of current chapters plus ten*<br><br>  
      <input id="numChaps" type="text" placeholder="##"><br><br>
      <button onclick="saveUserInput()">Click to Renumber Chapters.</button><br><br>
            <font color=red><center><font size = "2">Click "X" icon on top right hand side of this dialog box to close it.</font><br><br>
      <left><font color=black><font size = "2">*For instance, if your book currently has about 30 chapters that you want to renumber, enter 40. The extra ten are just in case you have a bunch of non-sequential chapter numbers and you are not totally sure how many current chapters you have.</font></left> 

      
  <script>
   function saveUserInput() {
     var numChaps = document.getElementById('numChaps').value;

         console.log('numChaps: ' + numChaps);
         
         google.script.run
         .withSuccessHandler(openNewDoc)
         .reChapter1({numChaps:numChaps});
         .reChapter2({numChaps:numChaps});
   }

        function openNewDoc(results){
           window.open(results.url, '_blank').focus();//this opens the html input page
}
  </script>   
  </body>
</html>

The working scripts, without the attempt to prompt a user entry of the expected number of chapters is as follows:

function onOpen() {
  var ui = DocumentApp.getUi();
  ui.createMenu('Renumber Chapters')
      .addItem('Run First', 'reChapter2')
      .addItem('Run Second', 'reChapter')
      .addToUi();
}
function reChapter(){
  var n = 30;
  var replaceTerm = "Chapter_"
  var body = DocumentApp.getActiveDocument().getBody();
  for (i = 0; i < n; i++) { 
    num = i+1
    Logger.log(i);
    newText = "Chapter "+num+"";
    replaceIt(replaceTerm, body);
  }
}
// replaces the occurrences
function replaceIt(replaceTerm, body) {    
  var found = body.findText(replaceTerm);
  if (found) {
   var start = found.getStartOffset();
    var end = found.getEndOffsetInclusive();
    var text = found.getElement().asText();
  text.deleteText(start, end);
  text.insertText(start, newText);
  }
}
function reChapter2(){
  var n = 30;
  var replaceTerm = "Chapter [0-9]+"
  var body = DocumentApp.getActiveDocument().getBody();
  for (i = 0; i < n; i++) { 
    num = i+1
    newText = "Chapter_";
    Logger.log(newText);
    replaceIt2(replaceTerm, body);
  }
}
// replaces the occurrences
function replaceIt2(replaceTerm, body) {    
  var found = body.findText(replaceTerm);
  if (found) {
   var start = found.getStartOffset();
    var end = found.getEndOffsetInclusive();
    var text = found.getElement().asText();
  text.deleteText(start, end);
  text.insertText(start, newText);
  }
}

I run "Run First" from the "Renumber Chapters" menu and then "Run Second" and that approach works fine as long as I have less than the number of chapters (in the case of this code, 30) hardcoded in the GS.

Upvotes: 1

Views: 182

Answers (1)

Cooper
Cooper

Reputation: 64100

I have several scripts which I use when I'm writing and I store most of the data in Properties Service. You can access the scripts through a menu and prompt for the data and pass it to PS or you can build a dialog or use the sidebar to enter the data and save in PS.

Upvotes: 1

Related Questions