Reputation: 129
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
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