Didacticiel : créer un complément de composition de message Outlook

Ce didacticiel vous apprend à créer un complément Outlook qui peut être utilisé pour dans le mode composer un message pour insérer du contenu dans le corps d’un message.

Dans ce didacticiel, vous allez :

  • Créer un projet de complément Outlook
  • Définir les boutons qui s’affichent dans la fenêtre de rédaction d’un message
  • Implémenter une expérience de première exécution qui collecte des informations de l’utilisateur et extrait les données à partir d’un service externe
  • Implémenter un bouton de l’interface utilisateur qui appelle une fonction
  • Implémenter un volet des tâches qui insère du contenu dans le corps d’un message

Conseil

Si vous souhaitez obtenir une version complète de ce didacticiel, accédez au référentiel d’exemples de compléments Office sur GitHub.

Configuration requise

  • Node.js (la dernière version LTS) Visitez le siteNode.js pour télécharger et installer la version appropriée pour votre système d’exploitation.

  • La dernière version deYeoman et du Générateur Yeoman Générateur de compléments Office. Pour installer ces outils globalement, exécutez la commande suivante via l’invite de commande.

    npm install -g yo generator-office
    

    Remarque

    Même si vous avez précédemment installé le générateur Yeoman, nous vous recommandons de mettre à jour votre package vers la dernière version de npm.

  • Office connecté à un abonnement Microsoft 365 (y compris Office on the web).

    Remarque

    Si vous n’avez pas encore Office, vous pouvez bénéficier d’un abonnement Microsoft 365 E5 développeur par le biais du Programme pour les développeurs Microsoft 365. Pour plus d’informations, consultez le FAQ. Vous pouvez également vous inscrire à un essai gratuit de 1 mois ou acheter un plan Microsoft 365.

Configuration

Le complément que vous allez créer dans ce didacticiel lit lesgists à partir du compte utilisateur GitHub et ajoute le gist sélectionné dans le corps d’un message. Procédez comme suit pour créer deux nouveaux gists que vous pouvez utiliser pour tester le complément que vous allez créer.

  1. Connectez-vous à GitHub.

  2. Créer une nouveau gist.

    • Dans la zoneDescription gist..., entrez Hello World Markdown.

    • Dans la zoneNom de fichier incluant l’extension... , entrez test.md.

    • Ajoutez la démarque suivante à la zone de texte multiligne.

      # Hello World
      
      This is content converted from Markdown!
      
      Here's a JSON sample:
      
        ```json
        {
          "foo": "bar"
        }
        ```
      
    • Sélectionnez le boutoncréer un gist public.

  3. Créer un nouveau gist.

    • Dans la zoneDescription gist..., entrez Hello World Html.

    • Dans la zoneNom de fichier incluant l’extension..., entrez test.html.

    • Ajoutez la démarque suivante à la zone de texte multiligne.

      <html>
        <head>
          <style>
          h1 {
            font-family: Calibri;
          }
          </style>
        </head>
        <body>
          <h1>Hello World!</h1>
          <p>This is a test</p>
        </body>
      </html>
      
    • Sélectionnez le boutoncréer un gist public.

Créer un projet de complément Outlook

  1. Exécutez la commande suivante pour créer un projet de complément à l’aide du générateur Yeoman. Un dossier qui contient le projet est ajouté au répertoire actif.

    yo office
    

    Remarque

    Lorsque vous exécutez la commande yo office, il est possible que vous receviez des messages d’invite sur les règles de collecte de données de Yeoman et les outils CLI de complément Office. Utilisez les informations fournies pour répondre aux invites comme vous l’entendez.

    Lorsque vous y êtes invité, fournissez les informations suivantes pour créer votre projet de complément.

    • Sélectionnez un type de projet - Office Add-in Task Pane project

    • Sélectionnez un type de script - JavaScript

    • Comment souhaitez-vous nommer votre complément ? - Git the gist

    • Quelle application client Office voulez-vous prendre en charge ? - Outlook

    Les invites et les réponses du générateur Yeoman dans une interface de ligne de commande.

    Après avoir exécuté l’assistant, le générateur crée le projet et installe les composants Node de prise en charge.

    Remarque

    Si vous utilisez Node.js version 20.0.0 ou ultérieure, un avertissement peut s’afficher lorsque le générateur exécute l’installation indiquant que vous disposez d’un moteur non pris en charge. Nous travaillons sur un correctif pour cela. En attendant, l’avertissement n’affecte pas le générateur ou le projet que vous générez. Il peut donc être ignoré.

    Conseil

    Vous pouvez ignorer les instructions suivantes fournies par le générateur Yeoman une fois que le complément a été créé. Les instructions détaillées de cet article fournissent tous les conseils nécessaires à l’exécution de ce didacticiel.

  2. Accédez au registre racine du projet.

    cd "Git the gist"
    
  3. Ce complément utilise les bibliothèques suivantes.

    Pour installer ces outils pour votre projet, exécutez la commande suivante dans le répertoire racine du projet.

    npm install showdown urijs jquery --save
    
  4. Ouvrez votre projet dans VS Code ou votre éditeur de code préféré.

    Conseil

    Dans Windows, vous pouvez accéder au répertoire racine du projet via la ligne de commande, puis entrer code . pour ouvrir ce dossier dans VS Code. Sur Mac, vous devez ajouter la commande code au chemin d’accès avant de pouvoir utiliser cette commande pour ouvrir le dossier de projet dans VS Code.

Mise à jour du manifeste

Le manifeste d’un complément contrôle la manière dont il apparaît dans Outlook. Il définit la façon dont le complément est affiché dans la liste des compléments, les boutons qui apparaissent sur le ruban, et il configure les URL pour les fichiers HTML et JavaScript utilisés par le complément.

Spécifiez les informations de base

Effectuez les mises à jour suivantes dans le fichier manifest.xml pour spécifier les informations de base du complément.

  1. Recherchez l’élément <ProviderName> et remplacez la valeur par défaut par le nom de votre société.

    <ProviderName>Contoso</ProviderName>
    
  2. Recherchez l’élément <Description> , remplacez la valeur par défaut par une description du complément, puis enregistrez le fichier.

    <Description DefaultValue="Allows users to access their GitHub gists."/>
    

Tester le complément généré

Avant d’aller plus loin, nous allons tester le complément base créé par le générateur pour confirmer que le projet est correctement configuré.

Remarque

Les compléments Office doivent utiliser HTTPS, et non HTTP, même lorsque vous développez. Si vous êtes invité à installer un certificat après avoir exécuté l’une des commandes suivantes, acceptez l’invite pour installer le certificat fourni par le générateur Yeoman. Il se peut également que vous deviez exécuter votre invite de commande ou votre terminal en tant qu'administrateur pour que les modifications soient effectuées.

  1. Exécutez la commande suivante dans le répertoire racine de votre projet. Lorsque vous exécutez cette commande, le serveur web local démarre et votre complément est chargé de manière indépendante.

    npm start
    

    Remarque

    Si votre complément n’a pas été automatiquement chargé de manière indépendante, suivez les instructions fournies dans Charger une version test des compléments Outlook pour charger manuellement une version test du complément dans Outlook.

  2. Dans Outlook, ouvrez un message existant et sélectionnez le bouton Afficher le volet Office.

  3. Lorsque la boîte de dialogue WebView Stop On Load apparaît, sélectionnez OK.

    Remarque

    Si vous sélectionnez Annuler, la boîte de dialogue ne s’affiche plus lors de l’exécution de cette instance du complément. Toutefois, si vous redémarrez votre complément, la boîte de dialogue s’affichera à nouveau.

    Si tout a été correctement configuré, le volet Office s’ouvre et affiche la page d’accueil du complément.

    Le bouton Show Taskpane et Git le volet des tâches gist ajouté par l'échantillon.

Définir des boutons

À présent que vous avez vérifié que le complément base fonctionne, vous pouvez le personnaliser pour ajouter davantage de fonctionnalités. Par défaut, le manifeste définit uniquement les boutons de la fenêtre de lecture de message. Nous allons mettre à jour le manifeste pour supprimer les boutons de la fenêtre de lecture de message et définir deux nouveaux boutons pour la fenêtre composer un message :

  • Insérer un gist: bouton qui ouvre un le volet des tâches

  • Insérer gist par défaut: bouton qui appelle une fonction

Supprimer le point d’extension MessageReadCommandSurface

  1. Ouvrez le fichier manifest.xml.

  2. Recherchez l’élément <ExtensionPoint> de type MessageReadCommandSurface et supprimez-le (y compris sa balise de fermeture). Cela supprime les boutons du complément de la fenêtre de lecture du message.

Supprimer le point d’extension MessageComposeCommandSurface

  1. Dans manifest.xml, recherchez la ligne dans le manifeste qui indique </DesktopFormFactor>.

  2. Situé immédiatement avant cette ligne, insérez le balisage XML suivant. Notez les points suivants concernant ce balisage.

    • ExtensionPoint<> avec xsi:type="MessageComposeCommandSurface" indique que vous définissez des boutons à ajouter à la fenêtre de rédaction de message.

    • En utilisant un <élément OfficeTab> avec id="TabDefault", vous indiquez que vous souhaitez ajouter les boutons à l’onglet par défaut du ruban.

    • L’élément <Group> définit le regroupement des nouveaux boutons, avec une étiquette définie par la ressource groupLabel .

    • Le premier <élément Control> contient un <élément Action> avec xsi:type="ShowTaskPane", ce bouton ouvre donc un volet Office.

    • Le deuxième <élément Control> contient un <élément Action> avec xsi:type="ExecuteFunction", de sorte que ce bouton appelle une fonction JavaScript contenue dans le fichier de fonction.

    <!-- 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>
    

Ressources de mise à jour dans le fichier manifeste

Le code précédent fait référence à des étiquettes, des info-bulles et des URL que vous devez définir avant que le manifeste ne soit valide. Vous allez spécifier ces informations dans la <section Ressources> du manifeste.

  1. Dans manifest.xml, recherchez l’élément <Resources> dans le fichier manifeste et supprimez l’élément entier (y compris sa balise de fermeture).

  2. Dans ce même emplacement, ajoutez le balisage suivant pour remplacer l’élément <Resources> que vous venez de supprimer.

    <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. Enregistrez les modifications dans le manifeste.

Réinstallez le complément.

Vous devez réinstaller le complément pour que les modifications du manifeste prennent effet.

  1. Si le serveur web est en cours d’exécution, exécutez la commande suivante.

    npm stop
    
  2. Exécutez la commande suivante pour démarrer le serveur web local et charger automatiquement votre complément.

    npm start
    

Une fois le complément réinstallé, vous pouvez vérifier qu’il a été correctement installé en consultant les commandes Insérer gist et Insérer gist par défaut dans le fenêtre de composition du message. Notez que rien ne se produit si vous sélectionnez un des ces éléments, car vous n’avez pas encore terminé de générer ce complément.

  • Si vous exécutez ce complément dans Outlook 2016 ou une version ultérieure sur Windows, vous devriez voir deux nouveaux boutons sur le ruban de la fenêtre de rédaction du message : Insérer un gist et Insérer un gist par défaut.

    Menu de dépassement de ruban dans Outlook sur Windows avec les boutons du complément mis en évidence

  • Si vous exécutez ce complément dans Outlook sur le web ou un nouvel Outlook sur Windows (préversion), sélectionnez Applications dans le ruban de la fenêtre de rédaction de message, puis sélectionnez Git le gist pour afficher les options Insérer un gist et Insérer un gist par défaut.

    Le formulaire de composition de message dans Outlook sur le web avec le bouton complément et menu contextuel mis en évidence

Mettre en œuvre une expérience de première exécution

Ce complément doit être en mesure de lire les gists du compte d’utilisateur GitHub et d’identifier lequel l’utilisateur a choisi en tant que gist par défaut. Pour atteindre ces objectifs, le complément doit inviter l’utilisateur à fournir son nom d’utilisateur GitHub et choisir un gist par défaut parmi leur collection de gists existants. Suivez les étapes de cette section pour implémenter une expérience de première exécution qui affiche une boîte de dialogue pour collecter ces informations auprès de l’utilisateur.

Créer l’interface utilisateur de la boîte de dialogue

Commençons par créer l’interface utilisateur pour la boîte de dialogue.

  1. Dans le dossier ./src, créez un sous-dossier nommé settings.

  2. Dans le dossier ./src/settings , créez un fichier nommé dialog.html.

  3. Dans dialog.html, ajoutez le balisage suivant pour définir un formulaire de base avec une entrée de texte pour un nom d’utilisateur GitHub et une liste vide pour gists qui sera remplie via JavaScript.

    <!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>
    

    Vous avez peut-être remarqué que le fichier HTML fait référence à un fichier JavaScript, gist-api.js, qui n'existe pas encore. Ce fichier sera créé dans la section Extraire les données de GitHub ci-dessous.

  4. Enregistrez vos modifications.

  5. Ensuite, créez un fichier dans le dossier ./src/settings nommé dialog.css.

  6. Dans dialog.css, ajoutez le code suivant pour spécifier les styles utilisés par dialog.html.

    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;
    }
    
  7. Enregistrez vos modifications.

Développer les fonctionnalités du dialogue

Maintenant que vous avez défini la boîte de dialogue interface utilisateur, vous pouvez écrire du code pour l’utiliser.

  1. Dans le dossier ./src/settings , créez un fichier nommé dialog.js.

  2. Ajoutez le code suivant. Notez que ce code utilise jQuery pour enregistrer les événements et utilise la méthode messageParent pour renvoyer les choix de l'utilisateur à l'appelant.

    (function() {
      'use strict';
    
      // The onReady function must be run each time a new page is loaded.
      Office.onReady(function() {
        $(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, " "));
      }
    })();
    
  3. Enregistrez vos modifications.

Mettre à jour les paramètres de configuration webapck

Enfin, ouvrez le fichier webpack.config.js qui se trouve dans le répertoire racine du projet et effectuez les étapes suivantes.

  1. Recherchez l’objet entry dans l’objet config et ajoutez une nouvelle entrée pour dialog.

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

    Lorsque c’est chose faite, le nouvel objet entry se présente comme suit :

    entry: {
      polyfill: ["core-js/stable", "regenerator-runtime/runtime"],
      taskpane: ["./src/taskpane/taskpane.js", "./src/taskpane/taskpane.html"],
      commands: "./src/commands/commands.js",
      dialog: "./src/settings/dialog.js",
    },
    
  2. Recherchez la matrice plugins au sein de l’objet config. Dans patternsle tableau de new CopyWebpackPluginl'objet, ajoutez de nouvelles entrées pour taskpane.css et dialog.css.

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

    Lorsque c’est chose faite, l’objet new CopyWebpackPlugin se présente comme suit :

    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]" + "[ext]",
        transform(content) {
          if (dev) {
            return content;
          } else {
            return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
          }
        },
      },
    ]}),
    
  3. Dans le même tableau à pluginsl'intérieur de configl'objet, ajoutez ce nouvel objet à la fin du tableau.

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

    Lorsque c’est chose faite, la nouvelle matrice plugins se présente comme suit :

    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"]
      })
    ],
    

Récupérer des données à partir de GitHub

Le fichier dialog.js que vous venez de créer spécifie que le module complémentaire doit charger les gists lorsque l'événement de modification se déclenche pour le champ du nom d'utilisateur GitHub. Pour récupérer les gists de l’utilisateur à partir de GitHub, vous utiliserez le API GitHub Gists.

  1. Dans le dossier ./src, créez un nouveau sous-dossier nommé helpers.

  2. Dans le dossier ./src/helpers, créez un fichier nommé gist-api.js.

  3. Dans gist-api.js, ajoutez le code suivant pour récupérer les gists de l’utilisateur à partir de GitHub et créer la liste des gists.

    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 descPrimary = $('<span/>')
          .addClass('ms-ListItem-primaryText')
          .text(gist.description)
          .appendTo(listItem);
    
        const descSecondary = $('<span/>')
          .addClass('ms-ListItem-secondaryText')
          .text(' - ' + buildFileList(gist.files))
          .appendTo(listItem);
    
        const updated = new Date(gist.updated_at);
    
        const descTertiary = $('<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;
    }
    
  4. Enregistrez vos modifications.

  5. Exécutez la commande suivante pour regénérer le projet.

    npm run build
    

Implémentation d’un bouton sans interface utilisateur

Le bouton Insérer un gist par défaut de ce complément est un bouton sans interface utilisateur qui appelle une fonction JavaScript, au lieu d’ouvrir un volet Office comme le font de nombreux boutons de complément. Lorsque l’utilisateur sélectionne le bouton Insérer un gist par défaut , la fonction JavaScript correspondante vérifie si le complément a été configuré.

  • Si le complément a déjà été configuré, la fonction charge le contenu du gist que l’utilisateur a sélectionné par défaut et l’insère dans le corps du message.

  • Si le complément n’a pas encore été configuré, la boîte de dialogue paramètres invite l’utilisateur à fournir les informations requises.

Mettre à jour le fichier de fonction (HTML)

Une fonction appelée par un bouton sans interface utilisateur doit être définie dans le fichier spécifié par l’élément <FunctionFile> dans le manifeste pour le facteur de forme correspondant. Le manifeste de ce complément spécifie https://localhost:3000/commands.html comme fichier de fonction.

  1. Ouvrez ./src/commands/commands.html et remplacez l’intégralité du contenu par le balisage suivant.

    <!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 on purpose. Since functions in commands.js are
           invoked via a button, there is no UI to render. -->
    </body>
    
    </html>
    

    Vous avez peut-être remarqué que le fichier HTML fait référence à un fichier JavaScript, addin-config.js , qui n'existe pas encore. Ce fichier sera créé dans la section Créer un fichier pour gérer les paramètres de configuration, plus loin dans ce tutoriel.

  2. Enregistrez vos modifications.

Mettre à jour le fichier de fonction (JavaScript)

  1. Ouvrez le fichier ./src/commands/commands.js et remplacez tout le contenu par le code suivant. Notez que si la fonction insertDefaultGist détermine que le complément n’a pas encore été configuré, elle ajoute le ?warn=1 paramètre à l’URL de la boîte de dialogue. Ainsi, la boîte de dialogue des paramètres rendra la barre de message définie dans ./src/settings/dialog.html , afin d'indiquer à l'utilisateur pourquoi il voit la boîte de dialogue.

    let config;
    let btnEvent;
    
    // The onReady function must be run each time a new page is loaded.
    Office.onReady();
    
    function showError(error) {
      Office.context.mailbox.item.notificationMessages.replaceAsync('github-error', {
        type: 'errorMessage',
        message: error
      });
    }
    
    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('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(Office.EventType.DialogMessageReceived, receiveMessage);
          settingsDialog.addEventHandler(Office.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;
    }
    
  2. Enregistrez vos modifications.

Créer un fichier pour gérer les paramètres de configuration

  1. Dans le dossier ./src/helpers, créez un fichier nommé addin-config.js et ajoutez le code suivant. Ce code utilise l’objet RoamingSettings pour obtenir et définir les valeurs de configuration.

    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);
    }
    
  2. Enregistrez vos modifications.

Créer de nouvelles fonctions pour traiter les gists

  1. Ouvrez le fichier ./src/helpers/gist-api.js et ajoutez les fonctions suivantes. Veuillez prendre en compte les éléments suivants:

    • Si le gist contient du code HTML, le complément insère le code HTML tel qu’il est dans le corps du message.

    • Si le gist contient Markdown, le complément utilise la bibliothèque Showdown pour convertir le Markdown au format HTML, puis insère le code HTML obtenu dans le corps du message.

    • Si le gist contient autre chose que du HTML ou Markdown, le complément l’insère dans le corps du message comme un extrait de code.

    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');
    }
    
  2. Enregistrez vos modifications.

Tester le bouton d'insertion par défaut du gist

  1. Si le serveur web local n’est pas déjà en cours d’exécution, exécutez npm start à partir de l’invite de commandes.

  2. Ouvrez Outlook et rédigez un nouveau message.

  3. Dans la fenêtre composer un message, sélectionnez le boutonInsérer gist par défaut. Vous devriez voir une boîte de dialogue dans laquelle vous pouvez configurer le complément, en commençant par l’invite de définition de votre nom d’utilisateur GitHub.

    L’invite de la boîte de dialogue permettant de configurer le complément

  4. Dans la boîte de dialogue des paramètres, entrez votre nom d’utilisateur GitHub, puis appuyez sur Tab ou cliquez ailleurs dans la boîte de dialogue pour appeler l’événement de modification , qui doit charger votre liste de gists publics. Sélectionnez un gist par défaut, puis cliquez surTerminer.

    La boîte de dialogue paramètres du complément

  5. Cliquez de nouveau sur le bouton Insérer un gist par défaut. Cette fois, le contenu du gist est inséré dans le corps du courrier électronique.

    Remarque

    Outlook sur Windows : pour récupérer les paramètres les plus récents, vous devrez peut-être fermer et rouvrir la fenêtre de composition d’un message.

Implémentation d’un volet de tâches

Le bouton Insérer un gist de ce complément ouvre un volet Office et affiche les gists de l’utilisateur. L’utilisateur peut sélectionner un des gists à insérer dans le corps du message. Si l’utilisateur n’a pas encore configuré le complément, il sera invité à le faire.

Spécifier le code HTML pour le volet de tâches

  1. Dans le projet que vous avez créé, le code HTML du volet de tâches est spécifié dans le fichier ./src/taskpane/taskpane.html. Ouvrez ce fichier et remplacez l’intégralité de son contenu par le balisage suivant.

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Contoso Task Pane Add-in</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="taskpane.css" rel="stylesheet" type="text/css" />
    </head>
    
    <body class="ms-font-l ms-landing-page">
      <main class="ms-landing-page__main">
        <section class="ms-landing-page__content ms-font-m ms-fontColor-neutralPrimary">
          <div id="not-configured" style="display: none;">
            <div class="centered ms-font-xxl ms-u-textAlignCenter">Welcome!</div>
            <div class="ms-font-xl" id="settings-prompt">Please choose the <strong>Settings</strong> icon at the bottom of this window to configure this add-in.</div>
          </div>
          <div id="gist-list-container" style="display: none;">
            <form>
              <div id="gist-list">
              </div>
            </form>
          </div>
          <div id="error-display" style="display: none;" class="ms-u-borderBase ms-fontColor-error ms-font-m ms-bgColor-error ms-borderColor-error">
          </div>
        </section>
        <button class="ms-Button ms-Button--primary" id="insert-button" tabindex=0 disabled>
          <span class="ms-Button-label">Insert</span>
        </button>
      </main>
      <footer class="ms-landing-page__footer ms-bgColor-themePrimary">
        <div class="ms-landing-page__footer--left">
          <img src="../../assets/logo-filled.png" />
          <h1 class="ms-font-xl ms-fontWeight-semilight ms-fontColor-white">Git the gist</h1>
        </div>
        <div id="settings-icon" class="ms-landing-page__footer--right" aria-label="Settings" tabindex=0>
          <i class="ms-Icon enlarge ms-Icon--Settings ms-fontColor-white"></i>
        </div>
      </footer>
      <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>
      <script type="text/javascript" src="taskpane.js"></script>
    </body>
    
    </html>
    
  2. Enregistrez vos modifications.

Spécifier le style CSS pour le volet de tâches

  1. Dans le projet que vous avez créé, le style CSS du volet de tâches est spécifié dans le fichier ./src/taskpane/taskpane.css. Ouvrez ce fichier et remplacez l’intégralité de son contenu par le code suivant.

    /* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license in root of repo. */
    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      overflow: auto; }
    
    body {
      position: relative;
      font-size: 16px; }
    
    main {
      height: 100%;
      overflow-y: auto; }
    
    footer {
      width: 100%;
      position: relative;
      bottom: 0;
      margin-top: 10px;}
    
    p, h1, h2, h3, h4, h5, h6 {
      margin: 0;
      padding: 0; }
    
    ul {
      padding: 0; }
    
    #settings-prompt {
      margin: 10px 0;
    }
    
    #error-display {
      padding: 10px;
    }
    
    #insert-button {
      margin: 0 10px;
    }
    
    .clearfix {
      display: block;
      clear: both;
      height: 0; }
    
    .pointerCursor {
      cursor: pointer; }
    
    .invisible {
      visibility: hidden; }
    
    .undisplayed {
      display: none; }
    
    .ms-Icon.enlarge {
      position: relative;
      font-size: 20px;
      top: 4px; }
    
    .ms-ListItem-secondaryText,
    .ms-ListItem-tertiaryText {
      padding-left: 15px;
    }
    
    .ms-landing-page {
      display: -webkit-flex;
      display: flex;
      -webkit-flex-direction: column;
              flex-direction: column;
      -webkit-flex-wrap: nowrap;
              flex-wrap: nowrap;
      height: 100%; }
    
    .ms-landing-page__main {
      display: -webkit-flex;
      display: flex;
      -webkit-flex-direction: column;
              flex-direction: column;
      -webkit-flex-wrap: nowrap;
              flex-wrap: nowrap;
      -webkit-flex: 1 1 0;
              flex: 1 1 0;
      height: 100%; }
    
    .ms-landing-page__content {
      display: -webkit-flex;
      display: flex;
      -webkit-flex-direction: column;
              flex-direction: column;
      -webkit-flex-wrap: nowrap;
              flex-wrap: nowrap;
      height: 100%;
      -webkit-flex: 1 1 0;
              flex: 1 1 0;
      padding: 20px; }
    
    .ms-landing-page__content h2 {
      margin-bottom: 20px; }
    
    .ms-landing-page__footer {
      display: -webkit-inline-flex;
      display: inline-flex;
      -webkit-justify-content: center;
              justify-content: center;
      -webkit-align-items: center;
              align-items: center; }
    
    .ms-landing-page__footer--left {
      transition: background ease 0.1s, color ease 0.1s;
      display: -webkit-inline-flex;
      display: inline-flex;
      -webkit-justify-content: flex-start;
              justify-content: flex-start;
      -webkit-align-items: center;
              align-items: center;
      -webkit-flex: 1 0 0px;
              flex: 1 0 0px;
      padding: 20px; }
    
    .ms-landing-page__footer--left:active {
      cursor: default; }
    
    .ms-landing-page__footer--left--disabled {
      opacity: 0.6;
      pointer-events: none;
      cursor: not-allowed; }
    
    .ms-landing-page__footer--left--disabled:active, .ms-landing-page__footer--left--disabled:hover {
      background: transparent; }
    
    .ms-landing-page__footer--left img {
      width: 40px;
      height: 40px; }
    
    .ms-landing-page__footer--left h1 {
      -webkit-flex: 1 0 0px;
              flex: 1 0 0px;
      margin-left: 15px;
      text-align: left;
      width: auto;
      max-width: auto;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis; }
    
    .ms-landing-page__footer--right {
      transition: background ease 0.1s, color ease 0.1s;
      padding: 29px 20px; }
    
    .ms-landing-page__footer--right:active, .ms-landing-page__footer--right:hover {
      background: #005ca4;
      cursor: pointer; }
    
    .ms-landing-page__footer--right:active {
      background: #005ca4; }
    
    .ms-landing-page__footer--right--disabled {
      opacity: 0.6;
      pointer-events: none;
      cursor: not-allowed; }
    
    .ms-landing-page__footer--right--disabled:active, .ms-landing-page__footer--right--disabled:hover {
      background: transparent; }
    
  2. Enregistrez vos modifications.

Spécifier le code JavaScript pour le volet de tâches

  1. Dans le projet que vous avez créé, le code JavaScript du volet de tâches est spécifié dans le fichier ./src/taskpane/taskpane.js. Ouvrez ce fichier et remplacez l’intégralité de son contenu par le code suivant.

    (function() {
      'use strict';
    
      let config;
      let settingsDialog;
    
      Office.onReady(function() {
        $(document).ready(function() {
          config = getConfig();
    
          // Check if add-in is configured.
          if (config && config.gitHubUserName) {
            // If configured, load the gist list.
            loadGists(config.gitHubUserName);
          } else {
            // Not configured yet.
            $('#not-configured').show();
          }
    
          // When insert button is selected, build the content
          // and insert into the body.
          $('#insert-button').on('click', function() {
            const gistId = $('.ms-ListItem.is-selected').val();
            getGist(gistId, 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) {
                        if (result.status === Office.AsyncResultStatus.Failed) {
                          showError("Could not insert gist: " + result.error.message);
                        }
                      }
                    );
                  } else {
                    showError('Could not create insertable content: ' + error);
                  }
                });
              } else {
                showError('Could not retrieve gist: ' + error);
              }
            });
          });
    
          // When the settings icon is selected, open the settings dialog.
          $('#settings-icon').on('click', function() {
            // Display settings dialog.
            let url = new URI('dialog.html').absoluteTo(window.location).toString();
            if (config) {
              // If the add-in has already been configured, pass the existing values
              // to the dialog.
              url = url + '?gitHubUserName=' + config.gitHubUserName + '&defaultGistId=' + config.defaultGistId;
            }
    
            const dialogOptions = { width: 20, height: 40, displayInIframe: true };
    
            Office.context.ui.displayDialogAsync(url, dialogOptions, function(result) {
              settingsDialog = result.value;
              settingsDialog.addEventHandler(Office.EventType.DialogMessageReceived, receiveMessage);
              settingsDialog.addEventHandler(Office.EventType.DialogEventReceived, dialogClosed);
            });
          })
        });
      });
    
      function loadGists(user) {
        $('#error-display').hide();
        $('#not-configured').hide();
        $('#gist-list-container').show();
    
        getUserGists(user, function(gists, error) {
          if (error) {
    
          } else {
            $('#gist-list').empty();
            buildGistList($('#gist-list'), gists, onGistSelected);
          }
        });
      }
    
      function onGistSelected() {
        $('#insert-button').removeAttr('disabled');
        $('.ms-ListItem').removeClass('is-selected').removeAttr('checked');
        $(this).children('.ms-ListItem').addClass('is-selected').attr('checked', 'checked');
      }
    
      function showError(error) {
        $('#not-configured').hide();
        $('#gist-list-container').hide();
        $('#error-display').text(error);
        $('#error-display').show();
      }
    
      function receiveMessage(message) {
        config = JSON.parse(message.message);
        setConfig(config, function(result) {
          settingsDialog.close();
          settingsDialog = null;
          loadGists(config.gitHubUserName);
        });
      }
    
      function dialogClosed(message) {
        settingsDialog = null;
      }
    })();
    
  2. Enregistrez vos modifications.

Testez le bouton insérer le gist

  1. Si le serveur web local n’est pas déjà en cours d’exécution, exécutez npm start à partir de l’invite de commandes.

  2. Ouvrez Outlook et rédigez un nouveau message.

  3. Dans la fenêtre composer un message, sélectionnez le boutonInsérer gist. Vous devriez voir un volet des tâches qui s’ouvre à droite du formulaire Composer.

  4. Dans le volet des tâches, sélectionnez le gistHello World Html, puis sélectionnez insérer pour insérer ce gist dans le corps du message.

Le volet Office Complément et du contenu du gist sélectionné qui s’affiche dans le corps du message

Étapes suivantes

Ce didacticiel vous a appris à créer un complément Outlook qui peut être utilisé pour dans le mode composer un message pour insérer du contenu dans le corps d’un message. Pour en savoir plus sur le développement des compléments Outlook, passez à l’article suivant :

Exemples de code

Voir aussi