Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kindy/0cfebd20a9b87129c40177515328c500 to your computer and use it in GitHub Desktop.
Save kindy/0cfebd20a9b87129c40177515328c500 to your computer and use it in GitHub Desktop.

Google Apps Script Document Utilities

  • getAllLinks.js

  • getAllLinks(element) - returns array of all UrlLinks in Document

  • findAndReplaceLinks(searchPattern,replacement) - changes all matching links in Document

  • changeCase.js - Document add-in, provides case-change operations in the add-in Menu.

  • onOpen - installs "Change Case" menu

  • _changeCase - worker function to locate selected text and change text case. Case conversion is managed via callback to a function that accepts a string as a parameter and returns the converted string.

  • helper functions for five cases

  • UPPER CASE

  • lower case

  • Title Case

  • Sentence case

  • camelCase

  • Fountain-lite, screenplay formatting - see http://fountain.io/

/**
* Copyright (c) 2014 by Mogsdad (David Bingham)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Google Doc add-on menu will inherit the name of the script project.
*/
function onOpen() {
DocumentApp.getUi().createAddonMenu()
.addItem("UPPER CASE", 'toUpperCase' )
.addItem("lower case", 'toLowerCase' )
.addItem("Title Case", 'toTitleCase' )
.addItem("Sentence case", 'toSentenceCase' )
.addItem("camelCase", 'toCamelCase' )
.addSeparator()
.addItem("Fountain-lite", 'fountainLite')
.addToUi();
}
/**
* Dispatcher functions to provide case-specific
* callback functions to generic _changeCase().
*/
function toUpperCase() {
_changeCase(_toUpperCase);
}
function toLowerCase() {
_changeCase(_toLowerCase);
}
function toSentenceCase() {
_changeCase(_toSentenceCase);
}
function toTitleCase() {
_changeCase(_toTitleCase);
}
function toCamelCase() {
_changeCase(_toCamelCase);
}
/**
* Generic function to implement case change function in Google Docs.
* In case of error, alert window is opened in Google Docs UI with an
* explanation for the user. Exceptions are not caught, but pass through
* to Google Doc UI.
*
* Caveat: formatting is lost, due to operation of replaceText().
*
* @parameter {function} newCase Callback function, reflects an input
* string after case change.
*/
function _changeCase(newCase) {
newCase = newCase || _toUpperCase;
var doc = DocumentApp.getActiveDocument();
var selection = doc.getSelection();
var ui = DocumentApp.getUi();
var report = ""; // Assume success
if (!selection) {
report = "Select text to be modified.";
}
else {
var elements = selection.getSelectedElements();
if (elements.length > 1) {
report = "Select text in one paragraph only.";
}
else {
var element = elements[0].getElement();
//Logger.log( element.getType() );
var startOffset = elements[0].getStartOffset(); // -1 if whole element
var endOffset = elements[0].getEndOffsetInclusive(); // -1 if whole element
var elementText = element.asText().getText(); // All text from element
// Is only part of the element selected?
if (elements[0].isPartial())
var selectedText = elementText.substring(startOffset,endOffset+1);
else
selectedText = elementText;
// Google Doc UI "word selection" (double click)
// selects trailing spaces - trim them
selectedText = selectedText.trim();
//endOffset = startOffset + selectedText.length - 1; // Not necessary w/ replaceText
// Convert case of selected text.
var convertedText = newCase(selectedText);
var regexEscaped = selectedText.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); // http://stackoverflow.com/a/3561711/1677912
element.replaceText(regexEscaped, convertedText);
}
}
if (report !== '') ui.alert( report );
}
/**
* Case change callbacks for customization of generic _changeCase().
* Source credits as noted.
*/
function _toUpperCase(str) {
return str.toUpperCase();
}
function _toLowerCase(str) {
return str.toLowerCase();
}
// http://stackoverflow.com/a/196991/1677912
function _toTitleCase(str)
{
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}
// http://stackoverflow.com/a/19089667/1677912
function _toSentenceCase (str) {
var rg = /(^\s*\w{1}|\.\s*\w{1})/gi;
return str.toLowerCase().replace(rg, function(toReplace) {
return toReplace.toUpperCase();
});
}
// http://stackoverflow.com/a/2970667/1677912
function _toCamelCase(str) {
return str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function(match, index) {
if (+match === 0) return ""; // or if (/\s+/.test(match)) for white spaces
return index == 0 ? match.toLowerCase() : match.toUpperCase();
});
}
/**
* Scan Google doc, applying fountain syntax rules.
* Caveat: this is a partial implementation.
*
* Supported:
* Character names ahead of speech.
*
* Not supported:
* Everything else. See http://fountain.io/syntax
*/
function fountainLite() {
// Private helper function; find text length of paragraph
function paragraphLen( par ) {
return par.asText().getText().length;
}
var doc = DocumentApp.getActiveDocument();
var paragraphs = doc.getBody().getParagraphs();
var numParagraphs = paragraphs.length;
// Scan document
for (var i=0; i<numParagraphs; i++) {
/*
** Character names are in UPPERCASE.
** Dialogue comes right after Character.
*/
if (paragraphLen(paragraphs[i]) > 0) {
// This paragraph has text. If the preceeding one was blank and the following
// one has text, then this paragraph might be a character name.
if ((i==0 || paragraphLen(paragraphs[i-1]) == 0) && (i < numParagraphs && paragraphLen(paragraphs[i+1]) > 0)) {
var paragraphText = paragraphs[i].asText().getText();
// If no power-user overrides, convert Character to UPPERCASE
if (paragraphText.charAt(0) != '!' && paragraphText.charAt(0) != '@') {
var convertedText = _toUpperCase(paragraphText);
var regexEscaped = paragraphText.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); // http://stackoverflow.com/a/3561711/1677912
paragraphs[i].replaceText(regexEscaped, convertedText);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment