|
/** |
|
* Creates a menu entry in the Google Docs UI when the document is opened. |
|
* |
|
* @param {object} e The event parameter for a simple onOpen trigger. To |
|
* determine which authorization mode (ScriptApp.AuthMode) the trigger is |
|
* running in, inspect e.authMode. |
|
*/ |
|
function onOpen(e) { |
|
DocumentApp.getUi().createAddonMenu() |
|
.addItem('Start', 'showSidebar') |
|
.addToUi(); |
|
} |
|
|
|
/** |
|
* Runs when the add-on is installed. |
|
* |
|
* @param {object} e The event parameter for a simple onInstall trigger. To |
|
* determine which authorization mode (ScriptApp.AuthMode) the trigger is |
|
* running in, inspect e.authMode. (In practice, onInstall triggers always |
|
* run in AuthMode.FULL, but onOpen triggers may be AuthMode.LIMITED or |
|
* AuthMode.NONE.) |
|
*/ |
|
function onInstall(e) { |
|
onOpen(e); |
|
} |
|
|
|
/** |
|
* Opens a sidebar in the document containing the add-on's user interface. |
|
*/ |
|
function showSidebar() { |
|
var ui = HtmlService.createHtmlOutputFromFile('Sidebar') |
|
.setTitle('Synonyms') |
|
.setSandboxMode(HtmlService.SandboxMode.IFRAME); |
|
DocumentApp.getUi().showSidebar(ui); |
|
} |
|
|
|
/** |
|
* Gets the text the user has selected. If there is no selection, |
|
* this function displays an error message. |
|
* |
|
* @return {Array.<string>} The selected text. |
|
*/ |
|
function getSelectedText() { |
|
var selection = DocumentApp.getActiveDocument().getSelection(); |
|
if (selection) { |
|
var text = []; |
|
var elements = selection.getSelectedElements(); |
|
for (var i = 0; i < elements.length; i++) { |
|
if (elements[i].isPartial()) { |
|
var element = elements[i].getElement().asText(); |
|
var startIndex = elements[i].getStartOffset(); |
|
var endIndex = elements[i].getEndOffsetInclusive(); |
|
|
|
text.push(element.getText().substring(startIndex, endIndex + 1)); |
|
} else { |
|
var element = elements[i].getElement(); |
|
// Only translate elements that can be edited as text; skip images and |
|
// other non-text elements. |
|
if (element.editAsText) { |
|
var elementText = element.asText().getText(); |
|
// This check is necessary to exclude images, which return a blank |
|
// text element. |
|
if (elementText != '') { |
|
text.push(elementText); |
|
} |
|
} |
|
} |
|
} |
|
if (text.length == 0) { |
|
throw 'Please select some text.'; |
|
} |
|
return text; |
|
} else { |
|
throw 'Please select some text.'; |
|
} |
|
} |
|
|
|
/** |
|
* Gets the user-selected text and provides some synonyms |
|
* |
|
* @return {object} The result of the translation |
|
*/ |
|
function getSynonyms() { |
|
var word = getSelectedText(); |
|
var response = UrlFetchApp.fetch("http://words.bighugelabs.com/api/2/9f04fb6c0ad64879bcc2cfd437844c34/"+ word +"/json"); |
|
if (response.getResponseCode() !== 200) return JSON.parse('Sorry, no synonyms found :('); |
|
return JSON.parse(response.getContentText("UTF-8")); |
|
} |
|
|
|
/** |
|
* Replaces the text of the current selection with the provided text, or |
|
* inserts text at the current cursor location. (There will always be either |
|
* a selection or a cursor.) If multiple elements are selected, only inserts the |
|
* translated text in the first element that can contain text and removes the |
|
* other elements. |
|
* |
|
* @param {string} newText The text with which to replace the current selection. |
|
*/ |
|
function insertText(newText) { |
|
var selection = DocumentApp.getActiveDocument().getSelection(); |
|
if (selection) { |
|
var replaced = false; |
|
var elements = selection.getSelectedElements(); |
|
if (elements.length == 1 && |
|
elements[0].getElement().getType() == |
|
DocumentApp.ElementType.INLINE_IMAGE) { |
|
throw "Can't insert text into an image."; |
|
} |
|
for (var i = 0; i < elements.length; i++) { |
|
if (elements[i].isPartial()) { |
|
var element = elements[i].getElement().asText(); |
|
var startIndex = elements[i].getStartOffset(); |
|
var endIndex = elements[i].getEndOffsetInclusive(); |
|
|
|
var remainingText = element.getText().substring(endIndex + 1); |
|
element.deleteText(startIndex, endIndex); |
|
if (!replaced) { |
|
element.insertText(startIndex, newText); |
|
replaced = true; |
|
} else { |
|
// This block handles a selection that ends with a partial element. We |
|
// want to copy this partial text to the previous element so we don't |
|
// have a line-break before the last partial. |
|
var parent = element.getParent(); |
|
parent.getPreviousSibling().asText().appendText(remainingText); |
|
// We cannot remove the last paragraph of a doc. If this is the case, |
|
// just remove the text within the last paragraph instead. |
|
if (parent.getNextSibling()) { |
|
parent.removeFromParent(); |
|
} else { |
|
element.removeFromParent(); |
|
} |
|
} |
|
} else { |
|
var element = elements[i].getElement(); |
|
if (!replaced && element.editAsText) { |
|
// Only translate elements that can be edited as text, removing other |
|
// elements. |
|
element.clear(); |
|
element.asText().setText(newText); |
|
replaced = true; |
|
} else { |
|
// We cannot remove the last paragraph of a doc. If this is the case, |
|
// just clear the element. |
|
if (element.getNextSibling()) { |
|
element.removeFromParent(); |
|
} else { |
|
element.clear(); |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
var cursor = DocumentApp.getActiveDocument().getCursor(); |
|
var surroundingText = cursor.getSurroundingText().getText(); |
|
var surroundingTextOffset = cursor.getSurroundingTextOffset(); |
|
|
|
// If the cursor follows or preceds a non-space character, insert a space |
|
// between the character and the translation. Otherwise, just insert the |
|
// translation. |
|
if (surroundingTextOffset > 0) { |
|
if (surroundingText.charAt(surroundingTextOffset - 1) != ' ') { |
|
newText = ' ' + newText; |
|
} |
|
} |
|
if (surroundingTextOffset < surroundingText.length) { |
|
if (surroundingText.charAt(surroundingTextOffset) != ' ') { |
|
newText += ' '; |
|
} |
|
} |
|
cursor.insertText(newText); |
|
} |
|
} |