Übung – Hinzufügen von Schaltflächen und Befehlen

Abgeschlossen

In dieser Übung fügen Sie dem Add-In, das Sie in einer vorherigen Übung erstellt haben, zusätzliche Funktionen hinzu. Sie erstellen zwei neue Schaltflächen, die einen bestimmten GIST oder einen Standard-GIST in eine Nachricht einfügen. Sie implementieren auch einen ersten Durchlauf, bei dem Sie nach Ihrem GitHub-Benutzernamen gefragt werden, um Ihre Gists abzurufen.

Wichtig

In diesem Beispiel wird davon ausgegangen, dass Sie das Outlook-Add-In-Projekt mit dem Yeoman-Generator erstellt haben und in einer vorangegangenen Übung dieses Moduls in Outlook getestet haben, ob es funktioniert.

Definieren von Schaltflächen

Das Add-In-Manifest definiert standardmäßig lediglich Schaltflächen für das Nachrichten-Lesefenster. Wir aktualisieren das Manifest so, dass die Schaltflächen aus dem Fenster zum Lesen von Nachrichten entfernt und zwei neue Schaltflächen für das Fenster zum Verfassen von Nachrichten definiert werden:

  • Insert gist: Eine Add-In-Befehlsschaltfläche, mit der eine Aufgabenbereich geöffnet wird.
  • Insert default gist: Eine Schaltfläche, die eine Funktion aufruft.

Entfernen des MessageReadCommandSurface-Erweiterungspunkts

Öffnen Sie die Datei manifest.xml, und suchen Sie nach dem ExtensionPoint-Element mit dem Typ MessageReadCommandSurface. Löschen Sie dieses ExtensionPoint-Element (einschließlich des schließenden Tags), um die Schaltflächen aus dem Fenster zum Lesen von Nachrichten zu entfernen.

Hinzufügen des MessageReadCommandSurface-Erweiterungspunkts

Suchen Sie die Zeile im Manifest, die </DesktopFormFactor> lautet. Fügen Sie unmittelbar vor dieser Zeile die folgende XML-Markup hinzu.

<!-- Message Compose -->
<ExtensionPoint xsi:type="MessageComposeCommandSurface">
  <OfficeTab id="TabDefault">
    <Group id="msgComposeCmdGroup">
      <Label resid="GroupLabel"/>
      <Control xsi:type="Button" id="msgComposeInsertGist">
        <Label resid="TaskpaneButton.Label"/>
        <Supertip>
          <Title resid="TaskpaneButton.Title"/>
          <Description resid="TaskpaneButton.Tooltip"/>
        </Supertip>
        <Icon>
          <bt:Image size="16" resid="Icon.16x16"/>
          <bt:Image size="32" resid="Icon.32x32"/>
          <bt:Image size="80" resid="Icon.80x80"/>
        </Icon>
        <Action xsi:type="ShowTaskpane">
          <SourceLocation resid="Taskpane.Url"/>
        </Action>
      </Control>
      <Control xsi:type="Button" id="msgComposeInsertDefaultGist">
        <Label resid="FunctionButton.Label"/>
        <Supertip>
          <Title resid="FunctionButton.Title"/>
          <Description resid="FunctionButton.Tooltip"/>
        </Supertip>
        <Icon>
          <bt:Image size="16" resid="Icon.16x16"/>
          <bt:Image size="32" resid="Icon.32x32"/>
          <bt:Image size="80" resid="Icon.80x80"/>
        </Icon>
        <Action xsi:type="ExecuteFunction">
          <FunctionName>insertDefaultGist</FunctionName>
        </Action>
      </Control>
    </Group>
  </OfficeTab>
</ExtensionPoint>

Hinweis

  • Das ExtensionPoint mit xsi:type="MessageComposeCommandSurface" zeigt an, dass Sie Schaltflächen definieren, die dem Fenster zum Verfassen von Nachrichten hinzugefügt werden sollen.
  • Mithilfe eines OfficeTab-Elements mit id="TabDefault" geben Sie an, dass Sie die Schaltflächen zu der Standardregisterkarte auf dem Menüband hinzufügen möchten.
  • Das Group-Element definiert die Gruppierung für die neuen Schaltflächen, mit einer Bezeichnung, die von der groupLabel-Ressource festgelegt wird.
  • Das erste Control-Element enthält ein Action-Element mit xsi:type="ShowTaskPane", sodass diese Schaltfläche einen Aufgabenbereich öffnet.
  • Das zweite Control-Element enthält ein Action-Element mit xsi:type="ExecuteFunction", sodass diese Schaltfläche eine JavaScript-Funktion aufruft, die in der Funktionsdatei enthalten ist.

Aktualisieren von Ressourcen im Manifest

Der Code oben verwies auf Bezeichnungen, QuickInfos und URLs, die definiert werden müssen, damit das Manifest gültig ist. Diese Informationen geben Sie im Abschnitt Resources des Manifests an.

  1. Suchen Sie das Resources-Element in der Manifestdatei, und löschen Sie das gesamte Element (einschließlich seiner Endtags).

  2. Fügen Sie an der gleichen Stelle das folgende Markup hinzu, um das Resources-Element zu ersetzen, das Sie entfernt haben:

    <Resources>
      <bt:Images>
        <bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/>
        <bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/>
        <bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/>
      </bt:Images>
      <bt:Urls>
        <bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
        <bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
      </bt:Urls>
      <bt:ShortStrings>
        <bt:String id="GroupLabel" DefaultValue="Git the gist"/>
        <bt:String id="TaskpaneButton.Label" DefaultValue="Insert gist"/>
        <bt:String id="TaskpaneButton.Title" DefaultValue="Insert gist"/>
        <bt:String id="FunctionButton.Label" DefaultValue="Insert default gist"/>
        <bt:String id="FunctionButton.Title" DefaultValue="Insert default gist"/>
      </bt:ShortStrings>
      <bt:LongStrings>
        <bt:String id="TaskpaneButton.Tooltip" DefaultValue="Displays a list of your gists and allows you to insert their contents into the current message."/>
        <bt:String id="FunctionButton.Tooltip" DefaultValue="Inserts the content of the gist you mark as default into the current message."/>
      </bt:LongStrings>
    </Resources>
    
  3. Speichern Sie die Änderungen im Manifest.

Erneutes Installieren des Add-Ins

Da Sie Änderungen am Manifest vorgenommen haben, müssen Sie das Add-In neu installieren, damit die Änderungen wirksam werden.

  1. Wenn der Webserver ausgeführt wird, schließen Sie das Knotenbefehlsfenster.

  2. Führen Sie den folgenden Befehl aus, um den lokalen Webserver zu starten und Ihr Add-In automatisch querzuladen.

    npm start
    

Nachdem Sie das Add-In erneut installiert haben, können Sie überprüfen, ob es erfolgreich installiert wurden, indem Sie nach den Befehlen Insert gist und Insert default gist im Fenster zum Verfassen von Nachrichten suchen. Es passiert nichts, wenn Sie eines der folgenden Elemente auswählen, da Sie das Erstellen dieses Add-Ins noch nicht abgeschlossen haben.

  • Wenn Sie dieses Add-In in Outlook 2016 oder höher für Windows ausführen, sollten zwei neue Schaltflächen im Menüband des Fensters zum Verfassen von Nachrichten angezeigt werden: Insert gist und Insert default gist.

    Screenshot von Outlook unter Windows mit hervorgehobenen Add-In-Schaltflächen im Menübandüberlaufmenü.

  • Wenn Sie dieses Add-In in Outlook im Web ausführen, sollte unten im Fenster zum Verfassen von Nachrichten eine neue Schaltfläche angezeigt werden. Klicken Sie auf diese Schaltfläche, um die Optionen Insert gist und Insert default gist anzuzeigen.

    Screenshot des Formulars zum Verfassen von Nachrichten in Outlook im Web mit hervorgehobener Add-In-Schaltfläche und hervorgehobenem Popupmenü.

Implementieren einer ersten Ausführung

Dieses Add-In muss in der Lage sein, GISTs aus dem GitHub-Konto des Benutzers zu lesen und zu identifizieren, welchen der Benutzer als Standard-GIST ausgewählt hat. Um diese Ziele zu erreichen, muss das Add-In den Benutzer auffordern, seinen GitHub-Benutzernamen einzugeben und einen Standard-GIST aus der Sammlung vorhandener GISTs auszuwählen. Führen Sie die Schritte in diesem Abschnitt aus, um eine erste Ausführung zu implementieren, in der ein Dialogfeld zum Erfassen von Informationen vom Benutzer angezeigt wird.

Erfassen von Daten vom Benutzer

Beginnen wir mit dem Erstellen der Benutzeroberfläche für das Dialogfeld selbst. Erstellen Sie im Ordner ./src einen neuen Unterordner mit dem Namen settings. Erstellen Sie im Ordner ./src/settings eine Datei mit dem Namen dialog.html und fügen Sie das folgende Markup hinzu, um ein sehr einfaches Formular mit einer Texteingabe für einen GitHub-Benutzernamen sowie eine leere Liste für GISTs zu definieren, die über JavaScript aufgefüllt wird.

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
  <title>Settings</title>

  <!-- Office JavaScript API -->
  <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>

  <!-- For more information on Fluent UI, visit https://developer.microsoft.com/fluentui. -->
  <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/9.6.1/css/fabric.min.css"/>

  <!-- Template styles -->
  <link href="dialog.css" rel="stylesheet" type="text/css" />
</head>

<body class="ms-font-l">
  <main>
    <section class="ms-font-m ms-fontColor-neutralPrimary">
      <div class="not-configured-warning ms-MessageBar ms-MessageBar--warning">
        <div class="ms-MessageBar-content">
          <div class="ms-MessageBar-icon">
            <i class="ms-Icon ms-Icon--Info"></i>
          </div>
          <div class="ms-MessageBar-text">
            Oops! It looks like you haven't configured <strong>Git the gist</strong> yet.
            <br/>
            Please configure your GitHub username and select a default gist, then try that action again!
          </div>
        </div>
      </div>
      <div class="ms-font-xxl">Settings</div>
      <div class="ms-Grid">
        <div class="ms-Grid-row">
          <div class="ms-TextField">
            <label class="ms-Label">GitHub Username</label>
            <input class="ms-TextField-field" id="github-user" type="text" value="" placeholder="Please enter your GitHub username">
          </div>
        </div>
        <div class="error-display ms-Grid-row">
          <div class="ms-font-l ms-fontWeight-semibold">An error occurred:</div>
          <pre><code id="error-text"></code></pre>
        </div>
        <div class="gist-list-container ms-Grid-row">
          <div class="list-title ms-font-xl ms-fontWeight-regular">Choose Default Gist</div>
          <form>
            <div id="gist-list">
            </div>
          </form>
        </div>
      </div>
      <div class="ms-Dialog-actions">
        <div class="ms-Dialog-actionsRight">
          <button class="ms-Dialog-action ms-Button ms-Button--primary" id="settings-done" disabled>
            <span class="ms-Button-label">Done</span>
          </button>
        </div>
      </div>
    </section>
  </main>
  <script type="text/javascript" src="../../node_modules/jquery/dist/jquery.js"></script>
  <script type="text/javascript" src="../helpers/gist-api.js"></script>
  <script type="text/javascript" src="dialog.js"></script>
</body>

</html>

Möglicherweise haben Sie bemerkt, dass die HTML-Datei auf eine JavaScript-Datei verweist, gist-api.js, die noch nicht vorhanden ist. Diese Datei wird im Abschnitt Daten von GitHub abrufen weiter unten erstellt.

Als Nächstes erstellen Sie eine Datei im Ordner ./src/settings mit dem Namen dialog.css, und fügen Sie den folgenden Code hinzu, um die Formatvorlagen anzugeben, die von dialog.html verwendet werden.

section {
  margin: 10px 20px;
}

.not-configured-warning {
  display: none;
}

.error-display {
  display: none;
}

.gist-list-container {
  margin: 10px -8px;
  display: none;
}

.list-title {
  border-bottom: 1px solid #a6a6a6;
  padding-bottom: 5px;
}

ul {
  margin-top: 10px;
}

.ms-ListItem-secondaryText,
.ms-ListItem-tertiaryText {
  padding-left: 15px;
}

Da Sie nun die Benutzeroberfläche des Dialogfelds definiert haben, können Sie den Code schreiben, der dazu führt, dass eine Aktion ausgeführt wird. Erstellen Sie eine Datei im Ordner .src/settings mit dem Namen dialog.js, und fügen Sie den folgenden Code hinzu. Dieser Code verwendet jQuery, um Ereignisse zu registrieren, und die Funktion messageParent, um die Auswahl des Benutzers an den Aufrufer zurückzusenden.

(function(){
  'use strict';

  // The Office initialize function must be run each time a new page is loaded.
  Office.initialize = function(reason){
    jQuery(document).ready(function(){
      if (window.location.search) {
        // Check if warning should be displayed.
        const warn = getParameterByName('warn');
        if (warn) {
          $('.not-configured-warning').show();
        } else {
          // See if the config values were passed.
          // If so, pre-populate the values.
          const user = getParameterByName('gitHubUserName');
          const gistId = getParameterByName('defaultGistId');

          $('#github-user').val(user);
          loadGists(user, function(success){
            if (success) {
              $('.ms-ListItem').removeClass('is-selected');
              $('input').filter(function() {
                return this.value === gistId;
              }).addClass('is-selected').attr('checked', 'checked');
              $('#settings-done').removeAttr('disabled');
            }
          });
        }
      }

      // When the GitHub username changes,
      // try to load gists.
      $('#github-user').on('change', function(){
        $('#gist-list').empty();
        const ghUser = $('#github-user').val();
        if (ghUser.length > 0) {
          loadGists(ghUser);
        }
      });

      // When the Done button is selected, send the
      // values back to the caller as a serialized
      // object.
      $('#settings-done').on('click', function() {
        const settings = {};

        settings.gitHubUserName = $('#github-user').val();

        const selectedGist = $('.ms-ListItem.is-selected');
        if (selectedGist) {
          settings.defaultGistId = selectedGist.val();

          sendMessage(JSON.stringify(settings));
        }
      });
    });
  };

  // Load gists for the user using the GitHub API
  // and build the list.
  function loadGists(user, callback) {
    getUserGists(user, function(gists, error){
      if (error) {
        $('.gist-list-container').hide();
        $('#error-text').text(JSON.stringify(error, null, 2));
        $('.error-display').show();
        if (callback) callback(false);
      } else {
        $('.error-display').hide();
        buildGistList($('#gist-list'), gists, onGistSelected);
        $('.gist-list-container').show();
        if (callback) callback(true);
      }
    });
  }

  function onGistSelected() {
    $('.ms-ListItem').removeClass('is-selected').removeAttr('checked');
    $(this).children('.ms-ListItem').addClass('is-selected').attr('checked', 'checked');
    $('.not-configured-warning').hide();
    $('#settings-done').removeAttr('disabled');
  }

  function sendMessage(message) {
    Office.context.ui.messageParent(message);
  }

  function getParameterByName(name, url) {
    if (!url) {
      url = window.location.href;
    }
    name = name.replace(/[\[\]]/g, "\\$&");
    const regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
      results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
  }
})();

Aktualisieren der Webpack-Konfigurationseinstellungen

Öffnen Sie schließlich die Datei webpack.config.js im Stammverzeichnis des Projekts, und führen Sie die folgenden Schritte aus.

  1. Suchen Sie das entry-Objekt innerhalb des config-Objekts, und fügen Sie einen neuen Eintrag für dialog hinzu.

    dialog: "./src/settings/dialog.js"
    

    Danach sieht das neue entry-Objekt folgendermaßen aus:

    entry: {
      polyfill: ["core-js/stable", "regenerator-runtime/runtime"],
      taskpane: "./src/taskpane/taskpane.js",
      commands: "./src/commands/commands.js",
      dialog: "./src/settings/dialog.js"
    },
    
  2. Suchen Sie das Array pluginsinnerhalb des Objekts config. Fügen Sie im patterns-Array des new CopyWebpackPlugin-Objekts neue Einträge für taskpane.css und dialog.css hinzu.

    {
      from: "./src/taskpane/taskpane.css",
      to: "taskpane.css",
    },
    {
      from: "./src/settings/dialog.css",
      to: "dialog.css",
    },
    

    Danach sieht das neue Objekt new CopyWebpackPlugin folgendermaßen aus:

    new CopyWebpackPlugin({
      patterns: [
      {
        from: "./src/taskpane/taskpane.css",
        to: "taskpane.css",
      },
      {
        from: "./src/settings/dialog.css",
        to: "dialog.css",
      },
      {
        from: "assets/*",
        to: "assets/[name][ext][query]",
      },
      {
        from: "manifest*.xml",
        to: "[name]." + buildType + "[ext]",
        transform(content) {
          if (dev) {
            return content;
          } else {
            return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
          }
        },
      },
    ]}),
    
  3. Fügen Sie im gleichen plugins-Array innerhalb des config-Objekts dieses neue Objekt am Ende des Arrays hinzu.

    new HtmlWebpackPlugin({
      filename: "dialog.html",
      template: "./src/settings/dialog.html",
      chunks: ["polyfill", "dialog"]
    })
    

    Danach sieht das neue plugins-Array folgendermaßen aus:

    plugins: [
      new HtmlWebpackPlugin({
        filename: "taskpane.html",
        template: "./src/taskpane/taskpane.html",
        chunks: ["polyfill", "taskpane"],
      }),
      new CopyWebpackPlugin({
        patterns: [
        {
          from: "./src/taskpane/taskpane.css",
          to: "taskpane.css",
        },
        {
          from: "./src/settings/dialog.css",
          to: "dialog.css",
        },
        {
          from: "assets/*",
          to: "assets/[name][ext][query]",
        },
        {
          from: "manifest*.xml",
          to: "[name]." + buildType + "[ext]",
          transform(content) {
            if (dev) {
              return content;
            } else {
              return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
            }
          },
        },
      ]}),
      new HtmlWebpackPlugin({
        filename: "commands.html",
        template: "./src/commands/commands.html",
        chunks: ["polyfill", "commands"],
      }),
      new HtmlWebpackPlugin({
        filename: "dialog.html",
        template: "./src/settings/dialog.html",
        chunks: ["polyfill", "dialog"]
      })
    ],
    

Abrufen von Daten aus GitHub

Die Datei dialog.js, die Sie erstellt haben, gibt an, dass das Add-In Gists laden soll, wenn die Änderungs-Ereignis für das GitHub-Benutzernamenfeld ausgelöst wird. Um die Gists des Benutzers aus GitHub abzurufen, verwenden Sie die GitHub-Gists-API.

Erstellen Sie im Ordner ./src einen neuen Unterordner mit dem Namen helpers. Erstellen Sie im Ordner ./src/helpers eine Datei mit dem Namen gist-api.js, und fügen Sie den folgenden Code hinzu, um die Gists des Benutzers aus GitHub abzurufen und die Liste von Gists zu erstellen.

function getUserGists(user, callback) {
  const requestUrl = 'https://api.github.com/users/' + user + '/gists';

  $.ajax({
    url: requestUrl,
    dataType: 'json'
  }).done(function(gists){
    callback(gists);
  }).fail(function(error){
    callback(null, error);
  });
}

function buildGistList(parent, gists, clickFunc) {
  gists.forEach(function(gist) {

    const listItem = $('<div/>')
      .appendTo(parent);

    const radioItem = $('<input>')
      .addClass('ms-ListItem')
      .addClass('is-selectable')
      .attr('type', 'radio')
      .attr('name', 'gists')
      .attr('tabindex', 0)
      .val(gist.id)
      .appendTo(listItem);

    const desc = $('<span/>')
      .addClass('ms-ListItem-primaryText')
      .text(gist.description)
      .appendTo(listItem);

    const desc = $('<span/>')
      .addClass('ms-ListItem-secondaryText')
      .text(' - ' + buildFileList(gist.files))
      .appendTo(listItem);

    const updated = new Date(gist.updated_at);

    const desc = $('<span/>')
      .addClass('ms-ListItem-tertiaryText')
      .text(' - Last updated ' + updated.toLocaleString())
      .appendTo(listItem);

    listItem.on('click', clickFunc);
  });
}

function buildFileList(files) {

  let fileList = '';

  for (let file in files) {
    if (files.hasOwnProperty(file)) {
      if (fileList.length > 0) {
        fileList = fileList + ', ';
      }

      fileList = fileList + files[file].filename + ' (' + files[file].language + ')';
    }
  }

  return fileList;
}

Führen Sie den folgenden Befehl aus, um das Projekt erneut zu erstellen.

npm run build

Implementieren einer Schaltfläche ohne Benutzeroberfläche

Die Schaltfläche Insert default gist des Add-Ins ist eine Schaltfläche ohne Benutzeroberfläche, die eine JavaScript-Funktion aufruft; es wird kein Aufgabenbereich geöffnet, wie das bei vielen Add-Ins der Fall ist. Wenn der Benutzer die Schaltfläche Insert default gist auswählt, überprüft die entsprechende JavaScript-Funktion, ob das Add-In konfiguriert wurde.

  • Wenn das Add-In bereits konfiguriert wurde, lädt die Funktion den Inhalt des Gists, den der Benutzer als Standard ausgewählt hat und fügt diesen in den Text der Nachricht ein.
  • Wenn das Add-In nicht noch nicht konfiguriert wurde, fordert das Dialogfeld „Einstellungen“ den Benutzer auf, die erforderlichen Informationen einzugeben.

Aktualisieren der Funktionsdatei (HTML)

Eine Funktion, die von einer Schaltfläche ohne Benutzeroberfläche aufgerufen wird, muss in der Datei definiert werden, die vom FunctionFile-Element im Manifest für den entsprechenden Formfaktor angegeben ist. Das Manifest dieses Add-Ins gibt https://localhost:3000/commands.html als Funktionsdatei an.

Öffnen Sie die Datei ./src/commands/commands.html, und ersetzen Sie den gesamten Inhalt durch das folgende Markup.

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=Edge" />

  <!-- Office JavaScript API -->
  <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>

  <script type="text/javascript" src="../../node_modules/jquery/dist/jquery.js"></script>
  <script type="text/javascript" src="../../node_modules/showdown/dist/showdown.min.js"></script>
  <script type="text/javascript" src="../../node_modules/urijs/src/URI.min.js"></script>
  <script type="text/javascript" src="../helpers/addin-config.js"></script>
  <script type="text/javascript" src="../helpers/gist-api.js"></script>
</head>

<body>
  <!-- NOTE: The body is empty by design. Since functions in commands.js are invoked using a button, there is no UI to render. -->
</body>

</html>

Möglicherweise haben Sie bemerkt, dass die HTML-Datei auf eine JavaScript-Datei verweist, addin-config.js, die noch nicht vorhanden ist. Diese Datei wird im Abschnitt Erstellen einer Datei zum Verwalten von Konfigurationseinstellungen weiter unten in dieser Übung erstellt.

Aktualisieren der Funktionsdatei (JavaScript)

Öffnen Sie die Datei ./src/commands/commands.js, und ersetzen Sie den gesamten Inhalt durch den folgenden Code. Wenn die Funktion insertDefaultGist() feststellt, dass das Add-In noch nicht konfiguriert wurde, fügt sie den Parameter ?warn=1 zu der Dialog-URL hinzu. Dadurch wird im Dialogfeld „Einstellungen“ die Nachrichtenleiste gerendert, die in ./settings/dialog.html definiert wurde, um dem Benutzer mitzuteilen, warum das Dialogfeld angezeigt wird.

let config;
let btnEvent;

// The initialize function must be run each time a new page is loaded.
Office.initialize = function (reason) {
};

// Add any UI-less function here.
function showError(error) {
  Office.context.mailbox.item.notificationMessages.replaceAsync('github-error', {
    type: 'errorMessage',
    message: error
  }, function(result){
  });
}

let settingsDialog;

function insertDefaultGist(event) {

  config = getConfig();

  // Check if the add-in has been configured.
  if (config && config.defaultGistId) {
    // Get the default gist content and insert.
    try {
      getGist(config.defaultGistId, function(gist, error) {
        if (gist) {
          buildBodyContent(gist, function (content, error) {
            if (content) {
              Office.context.mailbox.item.body.setSelectedDataAsync(content,
                {coercionType: Office.CoercionType.Html}, function(result) {
                  event.completed();
              });
            } else {
              showError(error);
              event.completed();
            }
          });
        } else {
          showError(error);
          event.completed();
        }
      });
    } catch (err) {
      showError(err);
      event.completed();
    }

  } else {
    // Save the event object so we can finish up later.
    btnEvent = event;
    // Not configured yet, display settings dialog with
    // warn=1 to display warning.
    const url = new URI('../src/settings/dialog.html?warn=1').absoluteTo(window.location).toString();
    const dialogOptions = { width: 20, height: 40, displayInIframe: true };

    Office.context.ui.displayDialogAsync(url, dialogOptions, function(result) {
      settingsDialog = result.value;
      settingsDialog.addEventHandler(Microsoft.Office.WebExtension.EventType.DialogMessageReceived, receiveMessage);
      settingsDialog.addEventHandler(Microsoft.Office.WebExtension.EventType.DialogEventReceived, dialogClosed);
    });
  }
}

// Register the function.
Office.actions.associate("insertDefaultGist", insertDefaultGist);

function receiveMessage(message) {
  config = JSON.parse(message.message);
  setConfig(config, function(result) {
    settingsDialog.close();
    settingsDialog = null;
    btnEvent.completed();
    btnEvent = null;
  });
}

function dialogClosed(message) {
  settingsDialog = null;
  btnEvent.completed();
  btnEvent = null;
}

Erstellen einer Datei zum Verwalten von Konfigurationseinstellungen

Die HTML-Funktionsdatei verweist auf eine Datei mit dem Namen addin-config.js, die nicht noch nicht vorhanden ist. Erstellen Sie im Ordner ./src/helpers eine Datei namens addin-config.js, und fügen Sie den folgenden Code hinzu. Dieser Code verwendet das RoamingSettings-Objekt, um die Konfigurationswerte abzurufen und festzulegen.

function getConfig() {
  const config = {};

  config.gitHubUserName = Office.context.roamingSettings.get('gitHubUserName');
  config.defaultGistId = Office.context.roamingSettings.get('defaultGistId');

  return config;
}

function setConfig(config, callback) {
  Office.context.roamingSettings.set('gitHubUserName', config.gitHubUserName);
  Office.context.roamingSettings.set('defaultGistId', config.defaultGistId);

  Office.context.roamingSettings.saveAsync(callback);
}

Erstellen neuer Funktionen zum Verarbeiten von Gists

Öffnen Sie die Datei ./src/helpers/gist-api.js, und fügen Sie die folgenden Funktionen hinzu.

function getGist(gistId, callback) {
  const requestUrl = 'https://api.github.com/gists/' + gistId;

  $.ajax({
    url: requestUrl,
    dataType: 'json'
  }).done(function(gist){
    callback(gist);
  }).fail(function(error){
    callback(null, error);
  });
}

function buildBodyContent(gist, callback) {
  // Find the first non-truncated file in the gist
  // and use it.
  for (let filename in gist.files) {
    if (gist.files.hasOwnProperty(filename)) {
      const file = gist.files[filename];
      if (!file.truncated) {
        // We have a winner.
        switch (file.language) {
          case 'HTML':
            // Insert as-is.
            callback(file.content);
            break;
          case 'Markdown':
            // Convert Markdown to HTML.
            const converter = new showdown.Converter();
            const html = converter.makeHtml(file.content);
            callback(html);
            break;
          default:
            // Insert contents as a <code> block.
            let codeBlock = '<pre><code>';
            codeBlock = codeBlock + file.content;
            codeBlock = codeBlock + '</code></pre>';
            callback(codeBlock);
        }
        return;
      }
    }
  }
  callback(null, 'No suitable file found in the gist');
}

Hinweis

  • Wenn der Gist HTML enthält, fügt das Add-In den HTML-Code unverändert in den Text der Nachricht ein.
  • Wenn der Gist Markdown enthält, verwendet das Add-In die Showdown-Bibliothek, um das Markdown in HTML zu konvertieren, und fügt dann den resultierenden HTML-Code in den Text der Nachricht ein.
  • Wenn der Gist etwas anderes als HTML oder Markdown enthält, fügt das Add-In diese Elemente als Codeausschnitt in den Text der Nachricht ein.

Testen der Schaltfläche "Standardgist einfügen"

Wenn der Server noch nicht ausgeführt wird, speichern Sie alle Änderungen, und führen Sie npm start an der Eingabeaufforderung aus. Führen Sie die folgenden Schritte zum Testen der Schaltfläche Insert default gist aus.

  1. Öffnen Sie Outlook, und verfassen Sie eine neue Nachricht.

  2. Klicken Sie im Fenster zum Verfassen der Nachricht auf die Schaltfläche Insert default gist. Sie werden aufgefordert, das Add-In zu konfigurieren.

    Screenshot der Eingabeaufforderung des Add-Ins zum Konfigurieren

  3. Geben Sie im Dialogfeld „Einstellungen“ Ihren GitHub-Benutzernamen an, und tippen oder klicken Sie dann auf eine andere Stelle im Dialogfeld, um das change-Ereignis aufzurufen, das die Liste von Gists lädt. Wählen Sie einen Gist als Standard aus, und klicken Sie auf Done.

    Screenshot des Dialogfelds

  4. Klicken Sie erneut auf die Schaltfläche Insert Default Gist. Dieses Mal sollten Sie den Inhalt des Gists sehen, der in den Textkörper der E-Mail eingefügt wurde.

    Hinweis

    Outlook für Windows: damit die neuesten Einstellungen in Kraft treten, müssen Sie das Nachrichtenfenster ggfs. schließen und neu öffnen.

Zusammenfassung

In dieser Übung haben Sie dem Add-In, das Sie in einer vorherigen Übung erstellt haben, zusätzliche Funktionen hinzugefügt. Sie haben zwei neue Schaltflächen, die einen bestimmten GIST oder einen Standard-GIST in eine Nachricht einfügen, erstellt. Sie haben außerdem einen ersten Durchlauf implementiert, bei dem Sie nach Ihrem GitHub-Benutzernamen gefragt wurden, um Ihre Gists abzurufen.

Testen Sie Ihr Wissen

1.

Um eine Schaltfläche zu einem Add-In für das Verfassen von Outlook-Nachrichten hinzuzufügen, müssen Sie das Steuerelement zu welchem Erweiterungspunkttyp in der Manifestdatei des Add-Ins hinzufügen?

2.

Welche der folgenden Aktionen müssen Sie ausführen, um eine JavaScript-Funktion über eine Schaltfläche in der Menüleiste der Office-Anwendung aufzurufen, die im Manifest des Add-Ins definiert ist