Dienstag, 11. Januar 2011

Eigene Dialog-Box mit Google Apps Script erstellen

Die Möglichkeiten bei der Interaktion mit dem Benutzer sind bei der Verwendung von Message- und Eingabe-Boxen für viele Fälle vollkommen ausreichend. Doch gibt es auch Anwendungsgebiete, in denen man zum Beispiel die Breite und Höhe der Box selber bestimmen möchte (damit der enthaltene Text nicht umbricht) oder man Buttons mit Texten versehen möchte, die standardmäßig nicht zur Verfügung stehen.

Um nun all das umzusetzen, bietet Google Apps Script die Ui Services an. Mit diesen lassen sich fast alle Elemente erstellen, die man in die Google Anwendungen sieht.

Das folgende Beispiel zeigt eine ganz einfache eigene Anwendung innerhalb eines Tabellen-Dokuments, welche nur eine Box erstellt und der Titel der Box definiert wird.

function myDialogBox({
  var spreadsheet SpreadsheetApp.getActiveSpreadsheet();
  var app UiApp.createApplication();
  
  app.setTitle("Dialogbox");
  
  spreadsheet.show(app);
}

Führt man diese Funktion aus, erhält man eine solche Dialog-Box:


Einer solchen Box kann man nun verschiedene Elemente hinzufügen. Texte, Eingabefelder, Checkboxen, Buttons usw. Je nach Bedarf. Die Werte dieser Elemente kann man dann übrigens auch in die Tabelle übertragen oder anhand der Werte Aktionen mit der Tabelle durchführen. Aber das würde für den Anfang an dieser Stelle etwas zu weit führen. Um es gemütlich angehen zu lassen, zeigt das folgende Beispiel zunächst einmal nur, wie man die Höhe und Breite der Box festlegt sowie einen Text und einen Button zum Schließen der Box hinzufügt.

function myDialogBox({
  var spreadsheet SpreadsheetApp.getActiveSpreadsheet();
  var app UiApp.createApplication();

  app.setHeight(100);
  app.setWidth(300);
  app.setTitle("Dialogbox");
  
  var text app.createLabel("Hier steht der Text.");
  app.add(text);
  
  var closeButton app.createButton("Schließen");
  app.add(closeButton);
  
  var handler app.createServerClickHandler("closeDialogBox");
  closeButton.addClickHandler(handler);
  
  spreadsheet.show(app);
}

function closeDialogBox(e{
  var app UiApp.getActiveApplication();
  app.close();
  return app;
}

Führt man diese Funktion ("myDialogBox") aus, erhält man eine solche Dialog-Box:


Wie man dann Eingabeelemente in einer solchen Box erstellt und mit den Werten weiterarbeitet ... das gibt es in einem kommenden Artikel.

Freitag, 7. Januar 2011

Automatischer Funktionsaufruf beim Bearbeiten einer Tabelle

Möchte man automatisch eine Google Apps Script Funktion aufrufen, sobald eine Tabelle bearbeitet wurde, hat man dafür zwei Möglichkeiten:
  1. Einfache Event Handler
  2. Installierbare Event Handler
Einfacher Event Handler sind bereits in Google Apps Script eingebaut. Um sie zu nutzen, muss man nur eine Funktion mit einem speziellen Namen (onOpen(), onEdit() oder onInstall()) erstellen. Der Inhalt der Funktion wird dann beim Eintreten des entsprechenden Events ausgeführt.

Um nun eine Funktion nach dem Bearbeiten einer Tabelle auszuführen, erstellt man eine Funktion mit dem Namen “onEdit”. Dieser wird ein Parameter "event" übergeben, der ein Objekt mit dem aktuellen Tabellen-Dokument enthält. Um das alles einmal auszuprobieren erstellt an ein neues Tabellen-Dokument, öffnet den Skripteditor (Tools -> Skripte -> Skripteditor) und erstellt folgende Funktion:

function onEdit(event{
  Browser.msgBox("Tabelle wurde bearbeitet.");
}

Nun noch die Funktion unter einem beliebigen Namen speichern und eine Änderung an der aktuellen Tabelle vornehmen. Voilà, eine Message-Box erscheint.

Doch warum die Übergabe des Parameters "event"? Was kann man damit machen? Ganz einfach. Der Inhalt dieses Parameters ist, wie bereits weiter oben geschrieben - aber hier sicherheitshalber ein zweites Mal, ein Objekt, welches das Tabellen-Dokument (Spreadsheet) enthält. Aus diesem Objekt kann man nun zum Beispiel die Information auslesen, welche Tabellenzelle gerade aktiv ist.

function onEdit(event{
  var rowIndex event.source.getActiveCell().getRowIndex();
  var columnIndex event.source.getActiveCell().getColumnIndex();

  Browser.msgBox("Spalte: "+String(rowIndex));
  Browser.msgBox("Zeile: " String(columnIndex));
}

Sind mehrere Tabellenzellen aktiv, wird übrigens immer die oberste linke zurückgegeben. Ach noch was: Führt man diese Funktion innerhalb des Skripteditors aus, erhält man eine Fehlermeldung wie diese hier: TypeError: Cannot read property "source" from undefined. (line 2). Keine Sorge. Es ist alles in Ordnung mit der Funktion. Funktion speichern, zur Tabelle wechseln und eine Änderung vornehmen. Geht!

So, nun zur zweiten Möglichkeit: Installierbare Event Handler. Komischer Name, aber etwas Besseres als Übersetzung für "Installable Event Handlers" wollte mir einfach nicht einfallen.

Hierbei ist der Name der Funktion nicht ausschlaggebend. Zum Ausprobieren erstellt man einfach eine Funktion mit dem Namen "myOnEdit":

function myOnEdit(event{
  Browser.msgBox("Tabelle wurde bearbeitet.");
}

Nun wählt man im Skripteditor den Menüpunkt Triggers -> All your Triggers aus und klickt in der angezeigten Dialogbox auf den Link "No triggers set up. Click here to add one now." (wenn man noch keinen Trigger angelegt hat) beziehungsweise "Add a new trigger" (wenn man bereits einen Trigger angelegt hat). In der Spalte "Run" wählt man aus der Select-Box die Option "myOnEdit" aus und in der Spalte "Events" wählt man bei der ersten Select-Box die Option "From spreadsheet" und bei der zweiten Select-Box die Option "On edit" aus. Speichern.

Zum Testen kann man nun Änderungen an der Tabelle durchführen und es erscheint nach jeder Änderung die Message-Box.

Fertig!

Donnerstag, 6. Januar 2011

Debugging-Logs von Google Apps Script nutzen

Beim Erstellen eines Scripts kann es mitunter nützlich sein, wenn man als Entwickler im Verlauf des Scripts einige Werte überprüft. Dazu könnte man zum Beispiel die Message-Box verwenden. Dies würde aber den Ablauf des Scripts etwas stören. Praktischer ist es, auf die zur Verfügung stehenden Debugging-Logs zurückzugreifen. In diese kann man im Verlauf eines Scripts beliebig Daten schreiben und sich dann am Ende alles in Ruhe ansehen.

In der folgenden einfachen Beispiel-Funktion wird eine for-Schleife durchlaufen. Bei jedem Schleifendurchlauf wird der Zählerwert mit der Methode log() der Klasse Logger ins Log geschrieben:

function myLogger({
  for (var 0<= 10i++{
    Logger.log("i = " String(i));
  }
}

Nach dem Ausführen der Funktion kann man sich das Debugging-Log über Ansicht -> Protokolle... ansehen.



Den Inhalt des Debugging-Logs kann man aber auch per Script abrufen, wenn man dies möchte. Google Apps Script stellt dafür die Methode getLog() der Klasse Logger zu Verfügung. Das folgende Beispiel zeigt, wie man den Inhalt des Debugging-Logs über eine Message-Box ausgibt:

function myLogger({
  for (var 0<= 10i++{
    Logger.log("i = " String(i));
  }
  
  Browser.msgBox(Logger.getLog());
}

Und so schaut es dann aus:

Eigene Menüs einem Tabellen-Dokument hinzufügen

Vorhandene Google Apps Scripte eine Tabellen-Dokuments über das Menü Tools -> Skripte -> Verwalten von... zu starten ist zwar nicht allzu schwer, aber nicht sonderlich komfortabel. Um den Weg für den Aufruf eines Scripts zu verkürzen und auch den nicht so technisch versierten Nutzern etwas unter die Arme zu greifen, kann man mittels Google Apps Script über die Methode addMenu() eigene neue Menüeinträge erstellen und mit beliebigen Funktionen verknüpfen.

Damit die neuen Menüpunkte beim Öffnen des Tabellen-Dokuments automatisch hinzugefügt werden, erstellt man eine Funktion mit dem Namen onOpen() (siehe Events). Diese wird durch das System selbständig gestartet, sobald das Tabellen-Dokument geöffnet wird.

Das folgende Beispiel zeigt, wie man der Menüleiste einen neuen eigenen Hauptmenüpunkt "Mein Menü" mit drei Untermenüpunkten ("Eintrag 1", "Eintrag 2", "Eintrag 3") hinzufügt. Jeder Untermenüpunkt wird dabei mit einer eigenen Funktion verknüpft. Dies wird aufgerufen, sobald der Benutzer auf diesen klickt.

function onOpen({
  var spreadsheet SpreadsheetApp.getActiveSpreadsheet();
  
  spreadsheet.addMenu(
    "Mein Menü",
    [
      {name"Eintrag 1"functionName"function1"},
      {name"Eintrag 2"functionName"function2"},
      {name"Eintrag 3"functionName"function3"},
    ]
  )
}

function function1({
  Browser.msgBox("Eintrag 1 geklickt");
}

function function2({
  Browser.msgBox("Eintrag 2 geklickt");
}

function function3({
  Browser.msgBox("Eintrag 3 geklickt");
}

Führt man nun die Funktion onOpen() zum Test einmal aus, dann sieht man, wie nach dem letzten Standard-Menüpunkt "Hilfe" der neue Menüpunkt "Mein Menü" hinzugefügt wurde.


Möchte man die Untermenüpunkte etwas gruppieren, kann man zwischen diesen auch Trennlinien einfügen. Das folgende Beispiel zeigt, wie man eine solche Trennlinie zwischen dem zweiten und dritten Untermenüpunkt einfügt.

function onOpen({
  var spreadsheet SpreadsheetApp.getActiveSpreadsheet();
  
  spreadsheet.addMenu(
    "Mein Menü",
    [
      {name"Eintrag 1"functionName"function1"},
      {name"Eintrag 2"functionName"function2"},
      null,
      {name"Eintrag 3"functionName"function3"},
    ]
  )
}

function function1({
  Browser.msgBox("Eintrag 1 geklickt");
}

function function2({
  Browser.msgBox("Eintrag 2 geklickt");
}

function function3({
  Browser.msgBox("Eintrag 3 geklickt");
}

Im Tabellen-Dokument sieht dies nun so aus:

Mittwoch, 5. Januar 2011

Inhaltsänderung einer Webseite automatisch überwachen

Möchte man automatisch per E-Mail informiert werden, wenn sich der Inhalt einer bestimmten Webseite ändert, kann man dies mittels Google Apps Script realisieren. Dazu benötigt man zunächst eine beliebige App, die Google Apps Script unterstützt - zum Beispiel Text & Tabellen oder Sites. Hier erstellt man eine Funktion, die den Inhalt (also den HTML-Quelltext) einer Webseite abruft, mit dem bei einem vorherigen Funktionsaufruf gespeicherten Inhalt vergleicht und dann innerhalb des Dokuments speichert. Hat sich der Inhalt geändert, wird eine E-Mail verschickt. Diese Funktion lässt man nun über einen zeitbasierten Trigger automatisch in einem beliebigen Intervall aufrufen. Fertig.

Um es etwas anschaulicher zu gestalten habe ich mal eine solche Funktion erstellt, welche innerhalb einer Tabelle ausgeführt wird. Bitte zum Ausprobieren die eingetragene E-Mail-Adresse "max@mustermann.de" in die eigene ändern!

function checkWebContent({
  var url "http://www.apple.com/de/iphone/";

  var response UrlFetchApp.fetch(url);
  var newContent response.getContentText();

  var sheet SpreadsheetApp.getActiveSheet();
  var cell sheet.getRange("A1");
  var oldContent cell.getValue();

  if (oldContent != newContent{
    sheet.getRange("A1").setValue(newContent);
    MailApp.sendEmail(
      "max@mustermann.de",
      "Geänderter Inhalt",
      "Der Inhalt der Seite " url " hat sich geändert."
    );
  }
}

Funktion unter dem Namen "checkWebContent" speichern.

Für einen ersten Test, kann man diese Funktion mal im Skripteditor starten. Man sollte hierbei bereits eine E-Mail erhalten.

Nun geht es an den zeitbasierten Trigger zur automatischen Ausführung. Hierzu wählt man im Skripteditor den Menüpunkt Triggers -> All your Triggers aus und klickt in der angezeigten Dialogbox auf den Link "No triggers set up. Click here to add one now." (wenn man noch keinen Trigger angelegt hat) beziehungsweise "Add a new trigger" (wenn man bereits einen Trigger angelegt hat). In der Spalte "Run" wählt man den Namen der Funktion aus, in der Spalte "Events" wählt man "Time-driven" aus und definiert einen Intervall. Der folgende Screenshot zeigt einen zeitbasierten Trigger, welcher die Funktion checkWebContent jede Minute ausführt. Speichern.


Scripteditor schließen, Tabelle speichern, Tabelle schließen. Fertig. Nun kann man den Posteingang beobachten und geduldig auf die Benachrichtigungen warten. Die im oben genannten Beispielcode genannte Website wird sich sicher nicht so häufig ändern ... für mehr Benachrichtigungen einfach mal den URL "http://news.google.de/" einsetzen. Die E-Mails sollten dann im Minutentakt im Posteingang landen.