Javascript, HTML, CSS e... !
0 commenti

Menu e funzioni personalizzate in Google Docs

Aggiungere funzionalità avanzate ad un Documento con Google Apps Script

Tramite l'inserimento di codice Google Apps Script all'interno di un file Google Docs è possibile andare ad aggiungere funzionalità utili, non previste nativamente, che possono agevolare le operazioni lato utente durante le loro interazioni con i Documenti.

Nell'esempio di questo tutorial verranno utilizzati alcuni servizi di Apps Script per i quali ho inserito contestualmente un link alla relativa risorsa interna dove sarà possibile accedere a casi d'uso dedicati ed informazioni aggiuntive per chiunque volesse approfondire l'argomento.

Obiettivo della funzionalità aggiuntiva:
La funzionalità aggiuntiva oggetto di questo esempio prevederà l'inserimento di una nuova voce di menu (nella barra dei menu del documento) la quale sarà composta da un solo elemento che, se cliccato, lancerà una funziona il cui scopo è quello di recuperare nel testo presente all'interno del corpo del documento la parola selezionata e, tramite uno scraping su un sito che mette a disposizione un dizionario italiano online, estrarne il significato e visualizzarlo all'interno della barra laterale del documento.
Di seguito uno screenshot del risultato, Fig. 1, dove è evidenziato il menu e dove è possibile vedere la selezione su un termine all'interno del documento ed il relativo significato nella colonna laterale:



funzionalità aggiuntiva per la visualizzazione del significato del termine selezionato

Fig. 1 - Funzionalità aggiuntiva per Google Docs per la visualizzazione del significato dei termini selezionati


Il codice dovrà essere incorporato all'interno di un Documento Google, si parla quindi di bound-script, e per poterlo inserire è necessario selezionare dalla barra dei menu del documento la voce "Tools -> Script editor...".
Si aprirà a questo punto un editor di Apps Script nel quale dovrà essere incollato il seguente script:

function onOpen() {
  DocumentApp.getUi().createMenu('Nuove funzionalità')
  .addItem("Dimmi il significato del termine...", 'dimmiSignificato' )
  .addToUi();    
}

function dimmiSignificato () {
  var doc = DocumentApp.getActiveDocument();
  var selection = doc.getSelection();
  var ui = DocumentApp.getUi();
  
  if (!selection) {
    ui.alert('Attenzione! Nessuna parola selezionata.');
    return false;
  }
  else {
    var elements = selection.getSelectedElements();
    if (elements.length == 1) {
      var element = elements[0].getElement();
      var startOffset = elements[0].getStartOffset();
      var endOffset = elements[0].getEndOffsetInclusive();
      var selectedText = element.asText().getText();
      if (elements[0].isPartial()) {
        selectedText = selectedText.substring(startOffset,endOffset+1);
        selectedText = selectedText.trim();
      }
    }
  }
  if (selectedText.indexOf(" ") > 0) {
    ui.alert('Attenzione! Devi selezionare una sola parola.');
    return false;
  }
  
  var fonte_vocabolario = 'dizionari.corriere.it';
  
  var firstWordChar = selectedText.substring(0, 1);
  var firstWordCharUpper = firstWordChar.toUpperCase();
  var url = 'http://dizionari.corriere.it/dizionario_italiano/'+ firstWordCharUpper + '/' + selectedText + '.shtml';
  try {
    var content = UrlFetchApp.fetch(url);
  } catch(e) {
    ui.alert('Richiesta non andata a buon fine per il termine selezionato!\nProbabilmente non esiste un significato associato nel vocabolario di ' + fonte_vocabolario);
    return false;
  }
  
  var content = content.getBlob().getDataAsString('ISO-8859-1');
  var string_find_start = '<div id="defin-dx" class="clearfix left">';
  var string_find_end = '</div>';
  var string_find_start_length = string_find_start.length;
  var string_find_start_position = content.indexOf(string_find_start);
  var string_find_start_position_content = string_find_start_position + string_find_start_length;
  var string_find_end_position = content.indexOf(string_find_end, string_find_start_position);
  var result = content.substring(string_find_start_position_content, string_find_end_position);
  
  var html = HtmlService.createHtmlOutput(result)
  .setTitle('Dimmi il significato di...')
  .setWidth(350)
  .append('<p style="font-size:12px;"><strong>Fonte:</strong> <i><a href="http://' + fonte_vocabolario + '/" target="_blank">' + fonte_vocabolario + '</a></i></p>');
  
  ui.showSidebar(html);
}

Come è possibile notare è presente la funzione onOpen (che fa parte di quel gruppo di trigger definiti 'semplici') il cui ruolo è quello di eseguire il codice al suo interno nel momento in cui il documento viene aperto.
Non a caso all'apertura del file viene subito delegato al trigger in questione la creazione di una nuova voce di menu con una funzione associata al clic sul suo unico elemento. Per maggiori informazioni sulla creazione dei menu fare riferimento all'articolo "Menu personalizzati in SpreadsheetApp e DocumentApp con Google Apps Script".

function onOpen() {
  DocumentApp.getUi().createMenu('Nuove funzionalità')
  .addItem("Dimmi il significato del termine...", 'dimmiSignificato' )
  .addToUi();    
}

La funzione principale, dimmiSignificato(), recupera l'istanza del documento attivo e dell'interfaccia utente e salva in una variabile l'oggetto della selezione (intesa come porzione di testo selezionata, ad esempio, con il mouse):

  var doc = DocumentApp.getActiveDocument();
  var selection = doc.getSelection();
  var ui = DocumentApp.getUi();

Successivamente viene verificato se esiste effettivamente una selezione e se questa è limitata ad una sola parola, negli altri casi mostra un messaggio di avvisio all'utente:

  if (!selection) {
    ui.alert('Attenzione! Nessuna parola selezionata.');
    return false;
  }
  else {
    var elements = selection.getSelectedElements();
    if (elements.length == 1) {
      var element = elements[0].getElement();
      var startOffset = elements[0].getStartOffset();
      var endOffset = elements[0].getEndOffsetInclusive();
      var selectedText = element.asText().getText();
      if (elements[0].isPartial()) {
        selectedText = selectedText.substring(startOffset,endOffset+1);
        selectedText = selectedText.trim();
      }
    }
  }
  if (selectedText.indexOf(" ") > 0) {
    ui.alert('Attenzione! Devi selezionare una sola parola.');
    return false;
  }

A questo punto viene effettuata una chiamata, nel formato atteso, all'indirizzo web di dizionari.corriere.it (il sito interrogato tramite UrlFetchApp per il recupero della porzione di testo relativa al significato del termine selezionato) sfruttando un blocco try-catch (per maggiori informazioni consultare l'articolo "Gestire le eccezioni negli script di Google Apps Script con Try e Catch") per mostrare all'utente un messaggio di avviso in caso di termine non disponibile nella risorsa web interrogata:

  var fonte_vocabolario = 'dizionari.corriere.it';
  
  var firstWordChar = selectedText.substring(0, 1);
  var firstWordCharUpper = firstWordChar.toUpperCase();
  var url = 'http://dizionari.corriere.it/dizionario_italiano/'+ firstWordCharUpper + '/' + selectedText + '.shtml';
  try {
    var content = UrlFetchApp.fetch(url);
  } catch(e) {
    ui.alert('Richiesta non andata a buon fine per il termine selezionato!\nProbabilmente non esiste un significato associato nel vocabolario di ' + fonte_vocabolario);
    return false;
  }

Qualora la chiamata restituisse un risultato atteso viene effettuato un parsing HTML sulla risposta ottenuta forzando la conversione in UTF-8 ed indicando i tag HTML, iniziale e finale, che contengono la parte di contenuto di nostro interesse, Fig. 2:



pagina del sito sorgente sul quale effettuare lo scraping per il recupero del contenuto

Fig. 2 - Pagina del sito sorgente sul quale effettuare lo scraping per il recupero del contenuto desiderato


Di seguito la parte di codice che effettua il parsing (per maggiori dettagli su questa porzione di codice fare riferimento all'articolo "Parsing HTML di una pagina web con Google Apps Script"):

  var content = content.getBlob().getDataAsString('ISO-8859-1');
  var string_find_start = '<div id="defin-dx" class="clearfix left">';
  var string_find_end = '</div>';
  var string_find_start_length = string_find_start.length;
  var string_find_start_position = content.indexOf(string_find_start);
  var string_find_start_position_content = string_find_start_position + string_find_start_length;
  var string_find_end_position = content.indexOf(string_find_end, string_find_start_position);
  var result = content.substring(string_find_start_position_content, string_find_end_position);

Ed infine non rimane altro che aprire la colonna laterale e visualizzare al suo interno il contenuto:

  var html = HtmlService.createHtmlOutput(result)
  .setTitle('Dimmi il significato di...')
  .setWidth(350)
  .append('<p style="font-size:12px;"><strong>Fonte:</strong> <i><a href="http://' + fonte_vocabolario + '/" target="_blank">' + fonte_vocabolario + '</a></i></p>');
  
  ui.showSidebar(html);

In questo modo abbiamo arricchito un Google Docs con una funzione utile al lettore che, qualora non conoscesse la definizione di un termine all'interno del testo durante la sua lettura, potrà comodamente visualizzarla all'interno del documento senza doverla andare a cercare online o su un dizionario tradizionale.

Uno dei passi successive potrebbe essere quello di pubblicare questo tipo di servizio come Add-on per i Docs all'interno del G Suite Marketplace app.

Tags

Michele Pisani

Michele Pisani

Sviluppatore Javascript ed esperto in Digital Analytics

L'esperienza nel settore Digital Analytics unita ad anni di sviluppo in Javascript ha trovato la massima espressione in Google Apps Script che mi ha permesso, con estrema facilità e poche righe di codice, di realizzare potenti applicazioni interattive e processi automatizzati integrati con i prodotti della G Suite.

Come contattarmi
scrivi un commento

0 Commenti

Non ci sono commenti

Nessuno ha ancora commentato questo articolo, fallo tu per primo!

scrivi un commento

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato.I campi contrassegnati da un * sono obbligatori
Puoi utilizzare i seguenti tag nei commenti:
[bold]testo[/bold] se vuoi evidenziare un testo con il grassetto[code]function helloworld() { }[/code] se vuoi pubblicare una porzione di codice[url]http://www.appsscript.it[/url] se devi riferirti ad un indirizzo web