Navigation dans les fiches

La plupart des modules complémentaires basés sur des fiches sont créés à l'aide de plusieurs fiches représentant différentes "pages" de l'interface du module complémentaire. Pour offrir une expérience utilisateur efficace, vous devez utiliser une navigation simple et naturelle entre les cartes de votre module complémentaire.

À l'origine, dans les modules complémentaires Gmail, les transitions entre les différentes cartes de l'interface utilisateur étaient gérées en poussant et en faisant glisser des cartes vers et depuis une pile de cartes unique, la carte supérieure de la pile étant affichée par Gmail.

Fiche de navigation de la page d'accueil

Les modules complémentaires Google Workspace proposent des pages d'accueil et des fiches non contextuelles. Pour gérer les fiches contextuelles et non contextuelles, les modules complémentaires Google Workspace disposent d'une pile de fiches interne pour chacune d'elles. Lorsqu'un module complémentaire est ouvert dans un hôte, le homepageTrigger correspondant se déclenche pour créer la première fiche de la page d'accueil de la pile (carte "Page d'accueil" bleu foncé dans le schéma ci-dessous). Si aucun élément homepageTrigger n'est défini, une carte par défaut est créée, affichée et transférée vers la pile non contextuelle. Cette première carte est une carte racine.

Votre module complémentaire peut créer d'autres cartes non contextuelles et les placer sur la pile (les "cartes transmises" bleues dans le diagramme) lorsque l'utilisateur parcourt votre module complémentaire. L'interface utilisateur du module complémentaire affiche la carte supérieure de la pile. Ainsi, le fait d'ajouter de nouvelles cartes dans la pile modifie l'affichage, et le fait de faire sortir des cartes de la pile rétablit l'affichage des cartes précédentes.

Si votre module complémentaire dispose d'un déclencheur contextuel défini, le déclencheur s'active lorsque l'utilisateur entre dans ce contexte. La fonction du déclencheur crée la fiche contextuelle, mais l'affichage de l'UI est mis à jour en fonction de la DisplayStyle de la nouvelle fiche:

  • Si DisplayStyle est REPLACE (valeur par défaut), la carte contextuelle (la carte "contextuelle" orange foncé dans le diagramme) remplace la carte actuellement affichée. Cela lance efficacement une nouvelle pile de cartes contextuelle au-dessus de la pile de cartes non contextuelle, et cette carte contextuelle est la carte racine de la pile contextuelle.
  • Si DisplayStyle est défini sur PEEK, l'UI crée un en-tête d'aperçu qui apparaît en bas de la barre latérale du module complémentaire, en superposition sur la carte actuelle. L'en-tête d'aperçu affiche le titre de la nouvelle fiche et fournit à l'utilisateur des boutons qui lui permettent de décider s'il doit afficher ou non la nouvelle fiche. S'il clique sur le bouton Afficher, la fiche remplace la carte actuelle (comme décrit ci-dessus par REPLACE).

Vous pouvez créer des fiches contextuelles supplémentaires et les insérer dans la pile (les "cartes transmises" jaunes sur le schéma). La mise à jour de la pile de cartes modifie l'UI du module complémentaire pour afficher la carte la plus élevée. Si l'utilisateur quitte un contexte, les fiches contextuelles de la pile sont supprimées et l'affichage est mis à jour vers la fiche ou la page d'accueil non contextuelle la plus élevée.

Si l'utilisateur saisit un contexte pour lequel votre module complémentaire ne définit pas de déclencheur contextuel, aucune fiche n'est créée et la carte actuelle reste affichée.

Les actions Navigation décrites ci-dessous n'agissent que sur les fiches du même contexte. Par exemple, popToRoot() à partir d'une fiche contextuelle n'affiche que toutes les autres fiches contextuelles et n'affecte pas les fiches de la page d'accueil.

En revanche, le bouton est toujours disponible pour que l'utilisateur puisse passer de vos fiches contextuelles à vos fiches non contextuelles.

Vous pouvez créer des transitions entre les cartes en ajoutant ou en supprimant des cartes dans les piles de cartes. La classe Navigation fournit des fonctions pour transférer et insérer des cartes depuis les piles. Pour créer une navigation par carte efficace, vous devez configurer vos widgets pour qu'ils utilisent des actions de navigation. Vous pouvez insérer ou insérer plusieurs cartes simultanément, mais vous ne pouvez pas supprimer la fiche de la page d'accueil initiale qui est insérée pour la première fois dans la pile au démarrage du module complémentaire.

Pour accéder à une nouvelle fiche en réponse à une interaction de l'utilisateur avec un widget, procédez comme suit:

  1. Créez un objet Action et associez-le à une fonction de rappel que vous définissez.
  2. Appelez la fonction de gestionnaire de widgets appropriée pour définir l'Action sur ce widget.
  3. Implémentez la fonction de rappel qui effectue la navigation. Cette fonction reçoit un objet d'événement d'action en tant qu'argument et doit effectuer les opérations suivantes :
    1. Créez un objet Navigation pour définir le changement de carte. Un seul objet Navigation peut contenir plusieurs étapes de navigation, qui sont effectuées dans l'ordre dans lequel elles ont été ajoutées à l'objet.
    2. Créez un objet ActionResponse à l'aide de la classe ActionResponseBuilder et de l'objet Navigation.
    3. Renvoyez le ActionResponse compilé.

Lorsque vous créez des commandes de navigation, vous utilisez les fonctions d'objet Navigation suivantes:

Fonction Description
Navigation.pushCard(Card) Ajoute une carte à la pile actuelle. Pour cela, vous devez d'abord créer la carte.
Navigation.popCard() Supprime une carte du haut de la pile. Équivaut à cliquer sur la flèche de retour dans la ligne d'en-tête du module complémentaire. Cela ne supprime pas les cartes racine.
Navigation.popToRoot() Supprime toutes les cartes de la pile, à l'exception de la carte racine. En bref, cette pile de cartes est réinitialisée.
Navigation.popToNamedCard(String) Fait sortir les cartes de la pile jusqu'à ce qu'elles atteignent une carte portant le nom donné ou la carte racine de la pile. Vous pouvez attribuer des noms aux fiches à l'aide de la fonction CardBuilder.setName(String).
Navigation.updateCard(Card) Effectue un remplacement sur place de la carte actuelle, en rafraîchissant son affichage dans l'interface utilisateur.

Si une interaction ou un événement utilisateur doit entraîner un nouvel affichage des fiches dans le même contexte, remplacez les fiches existantes à l'aide des méthodes Navigation.pushCard(), Navigation.popCard() et Navigation.updateCard(). Si une interaction ou un événement utilisateur doit entraîner un nouvel affichage des cartes dans un contexte différent, utilisez ActionResponseBuilder.setStateChanged() pour forcer la réexécution de votre module complémentaire dans ces contextes.

Voici des exemples de navigation:

  • Si une interaction ou un événement modifie l'état de la fiche actuelle (par exemple, en ajoutant une tâche à une liste de tâches), utilisez updateCard().
  • Si une interaction ou un événement fournit plus de détails ou invite l'utilisateur à effectuer une action supplémentaire (par exemple, cliquer sur le titre d'un élément pour afficher plus de détails ou appuyer sur un bouton pour créer un événement d'agenda), utilisez pushCard() pour afficher la nouvelle page tout en permettant à l'utilisateur de la quitter à l'aide du bouton "Retour".
  • Si une interaction ou un événement modifie l'état d'une fiche précédente (par exemple, en modifiant le titre d'un élément avec la vue détaillée), utilisez des éléments comme popCard(), popCard(), pushCard(previous) et pushCard(current) pour mettre à jour la fiche précédente et la carte actuelle.

Actualisation des fiches...

Les modules complémentaires Google Workspace permettent aux utilisateurs d'actualiser votre fiche en exécutant à nouveau la fonction de déclencheur Apps Script enregistrée dans votre fichier manifeste. Les utilisateurs déclenchent cette actualisation via un élément de menu du module complémentaire:

Barre latérale du module complémentaire Google Workspace

Cette action est automatiquement ajoutée aux fiches générées par les fonctions de déclenchement homepageTrigger ou contextualTrigger, comme spécifié dans le fichier manifeste du module complémentaire (les "racines" des piles de cartes contextuelles et non contextuelles).

Retourner plusieurs cartes

Exemple de carte complémentaire

Les fonctions de page d'accueil ou de déclencheur contextuel permettent de créer et de renvoyer un seul objet Card ou un tableau d'objets Card affichés par l'interface utilisateur de l'application.

S'il n'y a qu'une seule fiche, elle est ajoutée à la pile non contextuelle ou contextuelle en tant que carte racine et l'UI de l'application hôte l'affiche.

Si le tableau renvoyé inclut plusieurs objets Card compilés, l'application hôte affiche à la place une nouvelle carte contenant une liste de l'en-tête de chaque carte. Lorsque l'utilisateur clique sur l'un de ces en-têtes, l'UI affiche la fiche correspondante.

Lorsque l'utilisateur sélectionne une carte dans la liste, cette carte est placée dans la pile actuelle, et l'application hôte l'affiche. Le bouton renvoie l'utilisateur à la liste des en-têtes de la carte.

Cette disposition "plate" des fiches peut s'avérer efficace si votre module complémentaire n'a pas besoin de transitions entre les fiches que vous créez. Toutefois, dans la plupart des cas, il est préférable de définir directement des transitions de fiches, et de faire en sorte que votre page d'accueil et les fonctions de déclenchement contextuel renvoient un seul objet Card.

Exemple

Voici un exemple qui montre comment créer plusieurs cartes avec des boutons de navigation qui passent de l'une à l'autre. Vous pouvez ajouter ces cartes à la pile contextuelle ou non contextuelle en transférant la carte renvoyée par createNavigationCard() dans ou en dehors d'un contexte particulier.

  /**
   *  Create the top-level card, with buttons leading to each of three
   *  'children' cards, as well as buttons to backtrack and return to the
   *  root card of the stack.
   *  @return {Card}
   */
  function createNavigationCard() {
    // Create a button set with actions to navigate to 3 different
    // 'children' cards.
    var buttonSet = CardService.newButtonSet();
    for(var i = 1; i <= 3; i++) {
      buttonSet.addButton(createToCardButton(i));
    }

    // Build the card with all the buttons (two rows)
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle('Navigation'))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()));
    return card.build();
  }

  /**
   *  Create a button that navigates to the specified child card.
   *  @return {TextButton}
   */
  function createToCardButton(id) {
    var action = CardService.newAction()
        .setFunctionName('gotoChildCard')
        .setParameters({'id': id.toString()});
    var button = CardService.newTextButton()
        .setText('Card ' + id)
        .setOnClickAction(action);
    return button;
  }

  /**
   *  Create a ButtonSet with two buttons: one that backtracks to the
   *  last card and another that returns to the original (root) card.
   *  @return {ButtonSet}
   */
  function buildPreviousAndRootButtonSet() {
    var previousButton = CardService.newTextButton()
        .setText('Back')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoPreviousCard'));
    var toRootButton = CardService.newTextButton()
        .setText('To Root')
        .setOnClickAction(CardService.newAction()
            .setFunctionName('gotoRootCard'));

    // Return a new ButtonSet containing these two buttons.
    return CardService.newButtonSet()
        .addButton(previousButton)
        .addButton(toRootButton);
  }

  /**
   *  Create a child card, with buttons leading to each of the other
   *  child cards, and then navigate to it.
   *  @param {Object} e object containing the id of the card to build.
   *  @return {ActionResponse}
   */
  function gotoChildCard(e) {
    var id = parseInt(e.parameters.id);  // Current card ID
    var id2 = (id==3) ? 1 : id + 1;      // 2nd card ID
    var id3 = (id==1) ? 3 : id - 1;      // 3rd card ID
    var title = 'CARD ' + id;

    // Create buttons that go to the other two child cards.
    var buttonSet = CardService.newButtonSet()
      .addButton(createToCardButton(id2))
      .addButton(createToCardButton(id3));

    // Build the child card.
    var card = CardService.newCardBuilder()
        .setHeader(CardService.newCardHeader().setTitle(title))
        .addSection(CardService.newCardSection()
            .addWidget(buttonSet)
            .addWidget(buildPreviousAndRootButtonSet()))
        .build();

    // Create a Navigation object to push the card onto the stack.
    // Return a built ActionResponse that uses the navigation object.
    var nav = CardService.newNavigation().pushCard(card);
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Pop a card from the stack.
   *  @return {ActionResponse}
   */
  function gotoPreviousCard() {
    var nav = CardService.newNavigation().popCard();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }

  /**
   *  Return to the initial add-on card.
   *  @return {ActionResponse}
   */
  function gotoRootCard() {
    var nav = CardService.newNavigation().popToRoot();
    return CardService.newActionResponseBuilder()
        .setNavigation(nav)
        .build();
  }