ניווט בכרטיסים

רוב התוספים המבוססים על כרטיסים נוצרים באמצעות מספר תוספים כרטיסים שמייצגים 'דפים' שונים של ממשק משתמש להוספה. כדי לספק חוויית משתמש יעילה, צריך להשתמש בניווט פשוט וטבעי בין כרטיסים בתוסף.

במקור, בתוספים ל-Gmail, המעברים בין כרטיסים שונים בממשק המשתמש מטופל על ידי דחיפה והקפצה של כרטיסים אל ערימת קלפים אחת וממנו, את הכרטיס העליון של המקבץ שמוצג על ידי Gmail.

ניווט בכרטיסים בדף הבית

תוספים ל-Google Workspace – חדש דף הבית וגם כרטיסים ללא הקשר. כדי להוסיף כרטיסים לפי הקשר או לא לפי הקשר: לתוספים ל-Google Workspace יש מקבץ כרטיסים פנימי לכל אחד מהם. כשתוסף נפתח במארח, ה-homepageTrigger התואם מופעל כדי ליצור בכרטיס של דף הבית במקבץ (כרטיס 'דף הבית' בצבע כחול כהה בתרשים שלמטה). אם לא מוגדר homepageTrigger, נוצר ומוצג כרטיס ברירת מחדל, והועברו למקבץ ללא הקשר. הכרטיס הראשון הזה הוא כרטיס רמה בסיסית.

התוסף יכול ליצור כרטיסים נוספים ללא הקשר ולהעביר אותם אל מקבץ (ה"כרטיסים שנדחפו" הכחולים בתרשים) בזמן שהמשתמש מנווט בתוסף שלכם. בממשק המשתמש של התוסף מוצג הכרטיס העליון במקבץ, כך כרטיסים למקבץ משנים את התצוגה, וכרטיסים קופצים מחוץ למקבץ חוזרים את התצוגה לכרטיסים הקודמים.

אם לתוסף שלכם יש טריגר לפי הקשר, כשהמשתמש נכנס להקשר הזה, הטריגר מופעל. פונקציית הטריגר יוצר את כרטיס ההקשר, אבל התצוגה של ממשק המשתמש מתעדכנת בהתאם DisplayStyle של הכרטיס החדש:

  • אם DisplayStyle הוא REPLACE (ברירת המחדל), הכרטיס לפי הקשר (כתום כהה לפי הקשר מחליף את הכרטיס המוצג. הפעולה הזו מפעילה ביעילות מקבץ כרטיסים חדש לפי הקשר. של מקבץ הכרטיסים ללא הקשר, וכרטיס ההקשר הזה הוא הרמה הבסיסית (root) של ערימת ההקשר.
  • אם DisplayStyle הוא PEEK, ממשק המשתמש במקום זאת יוצר כותרת הצצה שמופיעה בחלק התחתון של סרגל הצד של התוסף, מעל הכרטיס הנוכחי. כותרת הצצה מציגה את כותרת הכרטיס החדש ומספקת את פקדי המשתמש, שמאפשרים ולהחליט אם לצפות בכרטיס החדש או לא. אם הוא לוחץ על הצגה הלחצן, הכרטיס מחליף את הכרטיס הנוכחי (כפי שמתואר למעלה עם REPLACE).

אפשר ליצור כרטיסים לפי הקשר נוספים דוחפים אותם למקבץ (ה"קלפים הנדחפים" הצהובים בתרשים). מתבצע עדכון מקבץ הכרטיסים משנה את ממשק המשתמש של התוסף ומציג את הכרטיס בראש המסך. אם המשתמש שומר הקשר, כרטיסי ההקשר במקבץ מוסרים והתצוגה מתעדכנת בכרטיס או בדף הבית ברמה העליונה ביותר שאינם לפי הקשר.

אם המשתמש מזין הקשר שהתוסף לא מגדיר הפעלה לפי הקשר, לא נוצר כרטיס חדש, הכרטיס הנוכחי נשאר מוצג.

הפעולות Navigation שמתוארים בהמשך פועלים רק על כרטיסים מאותו הקשר. לדוגמה, popToRoot() בכרטיס הקשרי קופץ רק כל הכרטיסים האחרים לפי הקשר, לא תשפיע על כרטיסים בדף הבית.

לעומת זאת, הלחצן למשתמש תמיד יש אפשרות לעבור מכרטיסים לפי הקשר אל כרטיסים ללא הקשר.

אפשר ליצור מעברים בין כרטיסים על ידי הוספה או הסרה של כרטיסים מתוך ערימות הכרטיסים. Navigation class - מספק פונקציות להעברת קלפים מהמקבצים. כדי ליצור ניווט יעיל בכרטיס, אתה מגדיר את ווידג'טים לשימוש בניווט פעולות. אפשר לדחוף או לקפוץ כמה כרטיסים בו-זמנית, אבל אי אפשר להסיר את הכרטיס הראשוני של דף הבית שמוצמד למקבץ כשהתוסף מתחיל.

כדי לנווט לכרטיס חדש בתגובה לאינטראקציה של משתמש עם ווידג'ט: יש לבצע את השלבים הבאים:

  1. יצירת אובייקט Action ולשייך אותו פונקציית קריאה חוזרת שאתם מגדירים.
  2. קוראים לווידג'ט המתאים פונקציית ה-handler של הווידג'טים כדי להגדיר את Action בווידג'ט הזה.
  3. מטמיעים את פונקציית הקריאה החוזרת שמבצעת את הניווט. הפונקציה הזו מקבל אובייקט של אירוע פעולה כארגומנט ועליו לבצע את הפעולות הבאות:
    1. יצירת Navigation כדי להגדיר את השינוי בכרטיס. אובייקט Navigation יחיד יכול לכלול שלבי ניווט מרובים, המסודרים לפי הסדר הם נוספים לאובייקט.
    2. יצירת ActionResponse באמצעות הפונקציה ActionResponseBuilder הכיתה וה-Navigation. לאובייקט.
    3. החזרת ה-build ActionResponse

כדי ליצור פקדי ניווט, צריך להשתמש באפשרויות הבאות Navigation פונקציות של אובייקטים:

פעולה תיאור
Navigation.pushCard(Card) דוחף כרטיס למקבץ הנוכחי. כדי לעשות את זה, קודם צריך לבנות את הכרטיס לגמרי.
Navigation.popCard() הסרת כרטיס אחד מהחלק העליון של הערימה. זהה ללחיצה על חץ החזרה בשורת הכותרת של התוסף. הפעולה הזו לא מסירה כרטיסים בסיסיים.
Navigation.popToRoot() הסרת כל הכרטיסים מהמקבץ חוץ מכרטיס הרמה הבסיסית (root). למעשה מאפס את ערימת הכרטיסים הזו.
Navigation.popToNamedCard(String) הקשה על כרטיסים מהמקבץ עד שהיא תגיע לכרטיס עם השם הנתון או לכרטיס הבסיס של המקבץ. אפשר להקצות שמות לכרטיסים באמצעות הפונקציה CardBuilder.setName(String).
Navigation.updateCard(Card) מבצע החלפה של הכרטיס הנוכחי במקום, ורענון התצוגה בממשק המשתמש.

אם אינטראקציה או אירוע של משתמש אמורים לגרום לעיבוד מחדש של הכרטיסים באותו אופן הקשר, שימוש Navigation.pushCard(), Navigation.popCard(), ו-Navigation.updateCard() שיטות להחלפת הכרטיסים הקיימים. אם אינטראקציה או אירוע של משתמש צריכים תגרום לרינדור מחדש של כרטיסים בהקשר אחר, השתמשו ActionResponseBuilder.setStateChanged() כדי לאלץ ביצוע מחדש של התוסף שלכם בהקשרים האלה.

דוגמאות לניווט:

  • אם אינטראקציה או אירוע משנים את המצב של הכרטיס הנוכחי (לדוגמה, כדי להוסיף משימה לרשימת משימות, updateCard()
  • אם אינטראקציה או אירוע מספקים פרטים נוספים או מבקשים מהמשתמש פעולה נוספת (לדוגמה, לחיצה על שם של פריט כדי לראות פרטים נוספים, או כשלוחצים על לחצן כדי ליצור אירוע חדש ביומן), משתמשים pushCard() כדי להציג את הדף החדש ובמקביל לאפשר למשתמש לצאת מהדף החדש באמצעות לחצן 'הקודם'.
  • אם המצב של אינטראקציה או אירוע מתעדכן בכרטיס קודם (לדוגמה, כדי לעדכן שם של פריט בתצוגת הפרטים), אפשר לכתוב משהו כמו popCard(), popCard(), pushCard(previous), וגם pushCard(current) כדי לעדכן את הכרטיס הקודם ואת הכרטיס הנוכחי.

הכרטיסים בתהליך רענון

התוספים ל-Google Workspace מאפשרים למשתמשים כדאי לרענן את הכרטיס על ידי הרצה מחדש של פונקציית הטריגר של Apps Script שרשומה ב- את המניפסט. המשתמשים מפעילים את הרענון הזה דרך אפשרות בתפריט של התוסף:

סרגל הצד של התוספים ל-Google Workspace

הפעולה הזו תתווסף באופן אוטומטי לכרטיסים שנוצרו על ידי homepageTrigger או פונקציות טריגר contextualTrigger, כפי שמצוין במניפסט של התוסף ('שורשים' של ערימות הכרטיסים לפי הקשר ולא לפי הקשר).

החזרה של מספר כרטיסים

דוגמה לכרטיס תוסף

פונקציות הטריגר של דף הבית או לפי ההקשר משמשות ליצירה ולהחזרה אחד או יותר אובייקט Card או מערך של Card אובייקטים ממשק המשתמש של האפליקציה.

אם יש רק כרטיס אחד, הוא יתווסף למקבץ התמונות לפי הקשר או לפי הקשר שכרטיס הבסיס וממשק המשתמש של האפליקציה המארח מציגים אותו.

אם המערך המוחזר כולל יותר ממערך אחד Card האובייקט המארח מציג במקום זאת כרטיס חדש, שמכיל והכותרת של כל כרטיס. כשהמשתמש ילחץ על אחת מהכותרות האלה, ממשק המשתמש מציג את הכרטיס התואם.

כשהמשתמש בוחר כרטיס מהרשימה, הכרטיס מועבר. המחסנית הנוכחית והאפליקציה המארחת תציג אותה. הלחצן מחזיר את המשתמש אל רשימת כותרות של כרטיסים.

מישור סידור הכרטיסים יכול להיות תקין אם התוסף לא צריך מעברים בין כרטיסים שאתם יוצרים. עם זאת, ברוב המקרים עדיף להגדרה ישירה של מעברים בין כרטיסים, והגדרת דף הבית פונקציות טריגר לפי הקשר מחזירות אובייקט יחיד בכרטיס.

דוגמה

כאן יש דוגמה שממחישה איך ליצור כמה כרטיסים באמצעות ניווט הלחצנים שעוברים ביניהם. אפשר להוסיף את הכרטיסים האלה ערימה לפי הקשר או לא לפי הקשר על ידי דחיפת הכרטיס שהוחזר מאת createNavigationCard() בהקשר מסוים או מחוץ לו.

  /**
   *  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();
  }