Today we’ll create Gmail Contextual gadget with the help of GWT.
According to Google definition, Contextual gadget is “a gadget that is triggered by clues in Gmail, such as the contents of Subject lines and email messages. For example, Gmail already provides a YouTube contextual gadget. If the body of an email contains a link to a YouTube video, a clickable thumbnail view of the video appears at the bottom of the email.”
Gmail Contextual gadgets can work only with Google Apps for domain, you can’t set it up with your *@gmail.com account, because gadgets are available via Google Apps Marketplace only.
There are very good specs from Google about creating gadgets with pure JavaScript http://code.google.com/intl/en/apis/gmail/gadgets/contextual. I recommend to look through it, to understand, what we are doing.
GWT version has some differences with native JavaScript, we will take look at this.
Manifest
<?xml version="1.0" encoding="UTF-8" ?> <ApplicationManifest xmlns="http://schemas.google.com/ApplicationManifest/2009"> <Support> <!-- URL explaining how customers get support. --> <Link rel="support" href="http://example.com/google/support.php" /> <!-- URL that is displayed to admins during the deletion process, to specify policies such as data retention, how to claim accounts, etc. --> <Link rel="deletion-policy" href="http://example.com/google/deletion-policy.php" /> </Support> <!-- Name and description pulled from message bundles --> <Name>Demo Contextual Gadget</Name> <Description>Simple GWT gadget</Description> <!-- EXTRACTOR --> <Extension id="body" type="contextExtractor"> <Name>Email Body</Name> <Url>google.com:EmailBodyExtractor</Url> <Param name="email_body" value=".*" /> <Triggers ref="CtxDemoGadget" /> <Scope ref="bodyScope" /> <Container name="mail" /> </Extension> <!-- GADGET --> <Extension id="CtxDemoGadget" type="gadget"> <Name>Demo Gmail Contextual Gadget</Name> <!-- Public path to your main class --> <Url>http://mozgoweb.com/gadget/CtxGadgetEntryPoint.gadget.xml</Url> <Container name="mail" /> </Extension> <!-- SCOPE --> <Scope id="bodyScope"> <Url>tag:google.com,2010:auth/contextual/extractor/BODY</Url> <Reason>Body</Reason> </Scope> </ApplicationManifest>
I take only Body Extractor, you can add any other.
Now, we need to define extractors for GWT application, create Extractors.xml in the same folder, where placed your main class with following lines:
<?xml version="1.0" encoding="UTF-8"?> <Require feature="google.contentmatch"> <Param name="extractors"> google.com:EmailBodyExtractor </Param> </Require>
To add multiply extractors use:
... <Param name="extractors"> google.com:SenderEmailExtractor,google.com:RecipientEmailExtractor,google.com:EmailBodyExtractor </Param> ...
GWT application code
package com.mozgoweb.demo.client; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.gadgets.client.Gadget; import com.google.gwt.gadgets.client.Gadget.AllowHtmlQuirksMode; import com.google.gwt.gadgets.client.Gadget.InjectModulePrefs; import com.google.gwt.gadgets.client.Gadget.ModulePrefs; import com.google.gwt.gadgets.client.Gadget.UseLongManifestName; import com.google.gwt.gadgets.client.GadgetFeature; import com.google.gwt.gadgets.client.UserPreferences; import com.google.gwt.json.client.JSONObject; import com.google.gwt.user.client.ui.HTML; /** * Main entry point. * * @author Denis Lunev <den@mozgoweb.com> * * Twitter functionality based on "Cross-Site Scripting with GWT and Twitter" * http://jectbd.com/?p=406 by Alex Moffat * */ @ModulePrefs(title = "DemoGadget", author = "Denis Lunev", author_email = "den@mozogweb.com") @UseLongManifestName(false) @AllowHtmlQuirksMode(false) @GadgetFeature.FeatureName(value = "google.contentmatch") @InjectModulePrefs(files = {"Extractors.xml"}) public class CtxGadgetEntryPoint extends Gadget<UserPreferences> { public CtxGadgetEntryPoint() {} /* For gadget use init() instead of onModuleLoad */ @Override protected void init(UserPreferences preferences) { final JsArray<JavaScriptObject> matches = jsGetContentMatches(); if (matches != null) { final int numMatches = matches.length(); result = new JSONObject[numMatches]; for (int i = 0; i < numMatches; i++) { //Do something with email body matches.get(i); } } } /* Native JS method to invoke extractors */ native JsArray<JavaScriptObject> jsGetContentMatches() /*-{ return google.contentmatch.getContentMatches(); }-*/; }
Then build the project and open xml file with main class, in my case it’s build/web/com.mozgoweb.demo.gadget/CtxGadgetEntryPoint.gadget.xml
Make sure, that your extractors are presented and add view=”card” to Content tag:
...<Content type="html" view="card">...
Card view is required for Contextual gadgets.
Now you need to upload builded gadgets (all files from folder, where located CtxGadgetEntryPoint.gadget.xml) to FTP or any other web storage, which we specified in Manifest.
Apps Marketplace
Login to Marketplace:
“My Vendor Profile” -> “Create a new listing”;
Check “My product may be directly installed into Google Apps domains”;
Fill “Application Manifest” with content from our Manifest.xml.
So, you’ve created application, now we need to connect it to domain.
Hit “Add it now” button and write your domain, then login with your domain admin credentials and activate application.
Thats all! Open any email and see how it works. Remember, that gadgets have very solid cache and it can take some time for your changes to be accepted, even with ?nogadgetcache=1 parameter.
My sample application searches words, starting with “@” in email body and shows twitter info for these users.
![]()
I used Twitter + GWT example by Alex Moffat for this Demo Gadget.
You can find source code here.
Enjoy!
11 Responses
Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.
Hi Denis,
Thank you very much for the gadget example.
I’ve managed to get your example code running using gwt-gadgets 1.2.0 and GWT 2.1.1. But when using GWT 2.2 or 2.3, even with gwt-gadgets 1.2.1-rc1, the contextual gadget is not displayed. It looks like the problem is with the call to google.contentmatch.getContentMatches().
Do you know if there should be an update to the example code to make it work with the newer libraries? Thank you.
thxs !! helped alot.
mainly this part :
….
where dit you find documentation on that ?
this part
. Content type=”html” view=”card”
(filtered out in previous comment )
Hi Koen,
You can find it in official google specs – http://code.google.com/intl/en/apis/gmail/gadgets/contextual/#gadget
This is the only view available for gadgets.
Hi !
I’ve just added http://mozgoweb.com/gadget/CtxGadgetEntryPoint.gadget.xml as a gadget in gmail, but it is not visible in mails. What am I doing wrong ?
Please see my reply in email.
Hey Dennis,
Starting from this post, I am taking development of GWT gmail contextual gadget a bit further but I got stuck and no reply on the Google Groups. Desperately re-reading your article, I wonder maybe you can spot the problem. The post is here :
https://groups.google.com/forum/#!topic/google-apps-gadgets-api/gxNoIQUVI4k
Little rectification to get it work, native method should be declared like this:
native JsArray jsGetContentMatches() /*-{
return $wnd.google.contentmatch.getContentMatches();
}-*/;
Continuing the Discussion