בנוסף לממשק שמבוסס על כרטיסים כשמשתמש קורא הודעה ב-Gmail, תוספים של Google Workspace שמרחיבים את Gmail יכולים לספק ממשק אחר כשהמשתמש יוצר הודעות חדשות או משיב להודעות קיימות. כך תוספים של Google Workspace יכולים ליצור אימיילים באופן אוטומטי בשביל המשתמש.
גישה לממשק המשתמש של התוסף לכתיבה
יש שתי דרכים להציג את ממשק המשתמש לכתיבה של תוסף. הדרך הראשונה היא להתחיל לכתוב טיוטה או תשובה חדשה כשהתוסף כבר פתוח. הדרך השנייה היא להפעיל את התוסף בזמן כתיבת טיוטה.
בכל מקרה, התוסף יבצע את פונקציית הטריגר של ה-Compose המתאימה, שהוגדרה במניפסט של התוסף. פונקציית הטריגר של כתיבת האימייל יוצרת את ממשק המשתמש של כתיבת האימייל עבור פעולת כתיבת האימייל הזו, ואז Gmail מציג אותו למשתמש.
פיתוח תוסף לכתיבה
כדי להוסיף פונקציונליות של כתיבת אימייל לתוסף, פועלים לפי השלבים הכלליים הבאים:
- מוסיפים את השדה
gmail.composeTrigger
למניפסט של פרויקט הסקריפט של התוסף ומעדכנים את ההיקפים של המניפסט כך שיכללו את אלה שנדרשים לפעולות הכתיבה. - הטמעת פונקציית טריגר של compose שיוצרת ממשק משתמש של compose כשהטריגר מופעל. פונקציות הטריגר של Compose מחזירות אובייקט
Card
יחיד או מערך של אובייקטיםCard
שמרכיבים את ממשק המשתמש של Compose עבור פעולת ה-Compose. - מטמיעים פונקציות קריאה חוזרת משויכות שנדרשות כדי להגיב לאינטראקציות של המשתמש בממשק המשתמש של כתיבת האימייל. הפונקציות האלה הן לא פעולת הכתיבה עצמה (שגורמת רק להופעת ממשק המשתמש לכתיבה), אלא הפונקציות הנפרדות שקובעות מה יקרה כשבוחרים רכיבים שונים בממשק המשתמש לכתיבה. לדוגמה, לכרטיס UI שמכיל לחצן בדרך כלל יש פונקציית קריאה חוזרת (callback) משויכת שפועלת כשמשתמש לוחץ על הלחצן הזה. פונקציית ההתקשרות חזרה של ווידג'טים שמעדכנים את תוכן טיוטת ההודעה צריכה להחזיר אובייקט
UpdateDraftActionResponse
.
כתיבת פונקציית טריגר
ממשק המשתמש לכתיבה של תוסף נבנה באותו אופן שבו נבנה ממשק המשתמש להודעות של התוסף – באמצעות שירות הכרטיסים של Apps Script כדי ליצור כרטיסים ולמלא אותם בווידג'טים.
עליכם להטמיע את gmail.composeTrigger.selectActions[].runFunction
שהגדרתם במניפסט. פונקציית הטריגר של ה-Compose חייבת להחזיר אובייקט Card
יחיד או מערך של אובייקטים מסוג Card
שמרכיבים את ממשק המשתמש של ה-Compose לפעולה הזו. הפונקציות האלה דומות מאוד לפונקציות טריגר לפי הקשר, וצריכות ליצור כרטיסים באותו אופן.
הרכבת אובייקטים של אירועי טריגר
כשבוחרים פעולת compose, היא מבצעת את פונקציית הטריגר המתאימה של compose ומעבירה לפונקציה אובייקט אירוע כפרמטר. אובייקט האירוע יכול לשאת מידע על ההקשר של התוסף ועל הטיוטה שנוצרת לפונקציית הטריגר.
במאמר מבנה של אובייקט אירוע מוסבר איך המידע מסודר באובייקט האירוע. המידע שמכיל אובייקט האירוע נשלט באופן חלקי על ידי הערך של שדה המניפסט gmail.composeTrigger.draftAccess
:
אם השדה
gmail.composeTrigger.draftAccess
במניפסט הואNONE
או לא נכלל, אובייקט האירוע מכיל רק מידע מינימלי.אם הערך של
gmail.composeTrigger.draftAccess
מוגדר כ-METADATA
, אובייקט האירוע שמוענק לפונקציית הטריגר של כתיבת האימייל מאוכלס ברשימות של הנמענים של האימייל שנכתב.
הוספת תוכן לטיוטות פעילות
בדרך כלל, ממשק המשתמש לכתיבה בתוסף של Google Workspace מספק למשתמשים את האפשרויות ואת אמצעי הבקרה שיעזרו להם לכתוב הודעה. בתרחישי השימוש האלה, אחרי שהמשתמש מבצע בחירות בממשק המשתמש, התוסף מפרש את הבחירות ומעדכן את טיוטת האימייל הקיימת בהתאם.
כדי שיהיה קל יותר לעדכן את טיוטת האימייל הנוכחית, הוספנו לשירות הכרטיסים את הכיתות הבאות:
ContentType
– משתנה מוגדר מראש שמגדיר אם להוסיף HTML שניתן לשינוי, HTML שלא ניתן לשינוי (משתמשי Gmail לא יכולים לערוך אותו) או תוכן טקסט פשוט.UpdateDraftActionResponse
– מייצגת תגובה לפעולה שמעדכנת את טיוטת האימייל הנוכחית.UpdateDraftActionResponseBuilder
– ה-builder של אובייקטים מסוגUpdateDraftActionResponse
.UpdateDraftBodyAction
– מייצג פעולה שמעדכנת את גוף טיוטת האימייל הנוכחית.UpdateDraftBodyType
– enum שמגדיר את אופן השינוי של הגוף.UpdateDraftSubjectAction
– הפעולה הזו מייצגת עדכון של שדה הנושא בטיוטת האימייל הנוכחית.UpdateDraftToRecipientsAction
– מייצגת פעולה שמעדכנת את הנמענים בשדה 'אל' של טיוטת האימייל הנוכחית.UpdateDraftCcRecipientsAction
– הפעולה מייצגת עדכון של הנמענים בשדה 'עותק' בטיוטה הנוכחית של הודעת האימייל.UpdateDraftBccRecipientsAction
– מייצגת פעולה שמעדכנת את הנמענים בשדה 'עותק מוסתר' בטיוטה הנוכחית של הודעת האימייל.
בדרך כלל, ממשק המשתמש ליצירת אימייל של התוסף כולל ווידג'ט של 'שמירה' או 'הוספה', שעליו המשתמש יכול ללחוץ כדי לציין שהוא סיים לבצע בחירות בממשק המשתמש ושהוא רוצה שהבחירות שלו יתווספו לאימייל שהוא יוצר. כדי להוסיף את האינטראקטיביות הזו, צריך לשייך לווידג'ט אובייקט Action
שמורה לתוסף להריץ פונקציית קריאה חוזרת ספציפית כאשר לוחצים על הווידג'ט. צריך להטמיע את פונקציות הקריאה החוזרת האלה. כל פונקציית קריאה חוזרת צריכה להחזיר אובייקט 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;
}