הרחבה של ממשק המשתמש של הכתיבה באמצעות פעולות כתיבה

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

איך ניגשים לממשק הכתיבה של התוסף

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

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

יצירה של תוסף 'אימייל חדש'

כדי להוסיף פונקציונליות של 'כתיבה' לתוסף, צריך לבצע את השלבים הכלליים הבאים:

  1. מוסיפים את השדה gmail.composeTrigger למניפסט של פרויקט הסקריפט של התוסף, ומעדכנים את ההיקפים של המניפסט כך שיכללו את הפעולות שנדרשות לפעולות הכתיבה.
  2. מטמיעים פונקציית טריגר לכתיבה, שיוצרת ממשק משתמש של כתיבת ההודעה כשהטריגר מופעל. הפונקציה של יצירת טריגרים מחזירה אובייקט Card יחיד או מערך של Card אובייקטים שמרכיבים את ממשק המשתמש של כתיבת הפקודה, של פעולת הכתיבה.
  3. מטמיעים פונקציות קריאה חוזרת (callback) משויכות שנחוצות כדי להגיב לאינטראקציות של המשתמשים עם תוכן בממשק המשתמש. הפונקציות האלה הן לא פעולת הכתיבה עצמה (שגורמת רק להופעת ממשק המשתמש של כתיבת ההודעה), אלא הפונקציות הנפרדות שקובעות מה קורה כשבוחרים אלמנטים שונים בממשק המשתמש של הכתיבה. לדוגמה, לכרטיס ממשק המשתמש שמכיל לחצן בדרך כלל משויכת פונקציית קריאה חוזרת שמופעלת כשמשתמש לוחץ על הלחצן. פונקציית הקריאה החוזרת לווידג'טים שמעדכנים את תוכן טיוטת ההודעה אמורה להחזיר אובייקט UpdateDraftActionResponse.

כתיבת פונקציית טריגר

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

עליכם להטמיע את gmail.composeTrigger.selectActions[].runFunction שהגדרתם במניפסט. הפונקציה של פונקציית ה-build חייבת להחזיר אובייקט Card יחיד או מערך של אובייקטים של Card שמרכיבים את ממשק המשתמש של כתיבת ההודעה. הפונקציות האלה דומות מאוד לפונקציות טריגר לפי הקשר, ועליהן ליצור כרטיסים באותו אופן.

יצירת אובייקטים של אירועי טריגר

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

פרטים על האופן שבו המידע מאורגן באובייקט האירוע מופיעים בקטע מבנה אובייקט האירוע. המידע שכלול באובייקט האירוע נשלט באופן חלקי על ידי הערך של שדה המניפסט gmail.composeTrigger.draftAccess:

  • אם שדה המניפסט gmail.composeTrigger.draftAccess הוא NONE או לא כלול, אובייקט האירוע מכיל רק מידע מינימלי.

  • אם הערך של gmail.composeTrigger.draftAccess הוא METADATA, אובייקט האירוע שהועבר לפונקציית הטריגר של כתיבת האימייל יאוכלס ברשימות של הנמענים של הודעת האימייל שאתם כותבים.

הוספת תוכן לטיוטות פעילות

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

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

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

דוגמה 1

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

    /**
     * Compose trigger function that fires when the compose UI is
     * requested. Builds and returns a compose UI for inserting images.
     *
     * @param {event} e The compose trigger event object. Not used in
     *         this example.
     * @return {Card[]}
     */
    function getComposeUI(e) {
      return [buildComposeCard()];
    }

    /**
     * Build a card to display interactive buttons to allow the user to
     * update the subject, and To, Cc, Bcc recipients.
     *
     * @return {Card}
     */
    function buildComposeCard() {

      var card = CardService.newCardBuilder();
      var cardSection = CardService.newCardSection().setHeader('Update email');
      cardSection.addWidget(
          CardService.newTextButton()
              .setText('Update subject')
              .setOnClickAction(CardService.newAction()
                  .setFunctionName('applyUpdateSubjectAction')));
      cardSection.addWidget(
          CardService.newTextButton()
              .setText('Update To recipients')
              .setOnClickAction(CardService.newAction()
                  .setFunctionName('updateToRecipients')));
      cardSection.addWidget(
          CardService.newTextButton()
              .setText('Update Cc recipients')
              .setOnClickAction(CardService.newAction()
                  .setFunctionName('updateCcRecipients')));
      cardSection.addWidget(
          CardService.newTextButton()
              .setText('Update Bcc recipients')
              .setOnClickAction(CardService.newAction()
                  .setFunctionName('updateBccRecipients')));
      return card.addSection(cardSection).build();
    }

    /**
     * Updates the subject field of the current email when the user clicks
     * on "Update subject" in the compose UI.
     *
     * Note: This is not the compose action that builds a compose UI, but
     * rather an action taken when the user interacts with the compose UI.
     *
     * @return {UpdateDraftActionResponse}
     */
    function applyUpdateSubjectAction() {
      // Get the new subject field of the email.
      // This function is not shown in this example.
      var subject = getSubject();
      var response = CardService.newUpdateDraftActionResponseBuilder()
          .setUpdateDraftSubjectAction(CardService.newUpdateDraftSubjectAction()
              .addUpdateSubject(subject))
          .build();
      return response;
    }

    /**
     * Updates the To recipients of the current email when the user clicks
     * on "Update To recipients" in the compose UI.
     *
     * Note: This is not the compose action that builds a compose UI, but
     * rather an action taken when the user interacts with the compose UI.
     *
     * @return {UpdateDraftActionResponse}
     */
    function applyUpdateToRecipientsAction() {
      // Get the new To recipients of the email.
      // This function is not shown in this example.
      var toRecipients = getToRecipients();
      var response = CardService.newUpdateDraftActionResponseBuilder()
          .setUpdateDraftToRecipientsAction(CardService.newUpdateDraftToRecipientsAction()
              .addUpdateToRecipients(toRecipients))
          .build();
      return response;
    }

    /**
     * Updates the Cc recipients  of the current email when the user clicks
     * on "Update Cc recipients" in the compose UI.
     *
     * Note: This is not the compose action that builds a compose UI, but
     * rather an action taken when the user interacts with the compose UI.
     *
     * @return {UpdateDraftActionResponse}
     */
    function applyUpdateCcRecipientsAction() {
      // Get the new Cc recipients of the email.
      // This function is not shown in this example.
      var ccRecipients = getCcRecipients();
      var response = CardService.newUpdateDraftActionResponseBuilder()
          .setUpdateDraftCcRecipientsAction(CardService.newUpdateDraftCcRecipientsAction()
              .addUpdateToRecipients(ccRecipients))
          .build();
      return response;
    }

    /**
     * Updates the Bcc recipients  of the current email when the user clicks
     * on "Update Bcc recipients" in the compose UI.
     *
     * Note: This is not the compose action that builds a compose UI, but
     * rather an action taken when the user interacts with the compose UI.
     *
     * @return {UpdateDraftActionResponse}
     */
    function applyUpdateBccRecipientsAction() {
      // Get the new Bcc recipients of the email.
      // This function is not shown in this example.
      var bccRecipients = getBccRecipients();
      var response = CardService.newUpdateDraftActionResponseBuilder()
          .setUpdateDraftBccRecipientsAction(CardService.newUpdateDraftBccRecipientsAction()
              .addUpdateToRecipients(bccRecipients))
          .build();
      return response;
    }

דוגמה 2

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

    /**
     * Compose trigger function that fires when the compose UI is
     * requested. Builds and returns a compose UI for inserting images.
     *
     * @param {event} e The compose trigger event object. Not used in
     *         this example.
     * @return {Card[]}
     */
    function getInsertImageComposeUI(e) {
      return [buildImageComposeCard()];
    }

    /**
     * Build a card to display images from a third-party source.
     *
     * @return {Card}
     */
    function buildImageComposeCard() {
      // Get a short list of image URLs to display in the UI.
      // This function is not shown in this example.
      var imageUrls = getImageUrls();

      var card = CardService.newCardBuilder();
      var cardSection = CardService.newCardSection().setHeader('My Images');
      for (var i = 0; i < imageUrls.length; i++) {
        var imageUrl = imageUrls[i];
        cardSection.addWidget(
            CardService.newImage()
                .setImageUrl(imageUrl)
                .setOnClickAction(CardService.newAction()
                      .setFunctionName('applyInsertImageAction')
                      .setParameters({'url' : imageUrl})));
      }
      return card.addSection(cardSection).build();
    }

    /**
     * Adds an image to the current draft email when the image is clicked
     * in the compose UI. The image is inserted at the current cursor
     * location. If any content of the email draft is currently selected,
     * it is deleted and replaced with the image.
     *
     * Note: This is not the compose action that builds a compose UI, but
     * rather an action taken when the user interacts with the compose UI.
     *
     * @param {event} e The incoming event object.
     * @return {UpdateDraftActionResponse}
     */
    function applyInsertImageAction(e) {
      var imageUrl = e.parameters.url;
      var imageHtmlContent = '<img style=\"display: block\" src=\"'
           + imageUrl + '\"/>';
      var response = CardService.newUpdateDraftActionResponseBuilder()
          .setUpdateDraftBodyAction(CardService.newUpdateDraftBodyAction()
              .addUpdateContent(
                  imageHtmlContent,
                  CardService.ContentType.MUTABLE_HTML)
              .setUpdateType(
                  CardService.UpdateDraftBodyType.IN_PLACE_INSERT))
          .build();
      return response;
    }