3
So you've got a website, and want to integrate your site with the Ubuntu using the webapps API. This is great. You should review the API docs, https://chinstrap.canonical.com/~racarr/unity-web-api-docs/unity-web-api-reference.html. This guide is for people who want to write a userscript to integrate your page without putting the code right into a site. I'll be using firefox as my browser for this tutorial. Feel free to use chromium but you might have to do some translation of the bits where I'm doing debuggging. This is meant to be an introduction to the webapps API, not a full api reference.
6
What integration points are you going to use?
7
---------------------------------------------
8
Unity webapps offer a solid list of integration points for your web app.
12
* Launcher quicklist actions
13
* Launcher icon count emblem
14
* Launcher icon progress bar
20
Writing our userscript
21
-----------------------
22
For this tutorial I'm going to write an integration script for tumblr.com. Both the dashboard and tumblr blogs. Tumblr is pretty cool example as it's a simple site that offers lots of chances for integration. Just off the top of my head I can see tumblr using:
23
* HUD Actions for making a new post, liking, reblogging, and following
24
* Launcher icon count emblems for unread new posts
25
* Quicklist action for returning to the Dashboard
26
* Messaging menu integration for new questions and fanmail
27
* Soundmenu integration for sound posts and videos.
28
A pretty rockin' list if you ask me.
31
Step zero. Getting the code and the bits you need to write your script.
32
----------------------------------------------------------------------
33
This isn't a real step, this is prerequisite and numbering from 0 is always a fun programmer joke. You laughed right?
35
A great way of exploring this API is in the developer console. Ctrl+Shift+K in Firefox will open it, and allow you to test these code snippets without having to reinstall the script and restart your browser.
38
Step one half. Getting an Icon ready.
39
-------------------------------------
40
You'll need a 128px, a 64px and a 52px icon. Run the build-icon-list script to add your icons to the iconlist.mk file so that they'll be installed. This script only finds svg icons. If you've got .png files (svg preferred!) Add them to the list manually. You can also use a remote url if there's a suitable icon on the site you're trying to integrate.
43
Step one. Integrate. Get a Launcher Icon and Switcher Icon going.
44
------------------------------------------------------------------------
46
// @name tumblr-unity-integration
47
// @include https://tumblr.com/dashboard
49
// @author WebApps Team
53
window.Unity = external.getUnityObject(1.0);
55
Unity.init({ name: "Tumblr",
56
iconUrl: "icon://Tumblr",
59
That's it. The // bits are boilerplate for the manifest file. The important bit that does the integration are getting the unity object into your DOM. window.Unity = external.getUnityObject and Unity.init. Here you establish the name of your webapp (the name parameter), the icon (the iconUrl parameter), and what to do once the page is loaded (the onInit parameter).
61
Want to test this? Open up tumblr in firefox, and then open the developer console and enter the bits from above. You can leave out the parts that are preceeded by //.
63
BAM. Should now have an icon in your launcher and switcher.
64
In our scripts it's commonplace to add some code like this to filter out pages that don't have the DOM elements we need.
66
function isCorrectPage() {
67
var i, ids = ['content', 'tabs_outter_container'];;
69
for (i = 0; i < ids.length; i++) {
70
if (!document.getElementById(ids[i])) {
78
if (isCorrectPage()) {
79
Unity.init({ name: "Tumblr",
80
iconUrl: "icon://Tumblr",
84
NICE. Now let's start getting integrating tumblr deeper into our desktop.
85
First thing we're going to do is change our onInit to a callback that will setup our integration.
87
function setupTumblr()
91
if (isCorrectPage()) {
92
Unity.init({ name: "Tumblr",
93
iconUrl: "icon://Tumblr",
94
onInit: wrapCallback(setupTumblr) });
97
A little note: there are some convenience functions in utils.js.in that we use in these scripts. wrapCallback is one of them. You'll see others used. Refer to utils.js.in for more information.
102
Tumblr lets us post Text, Photos, Quotes, Videos, Links, Chat, and Audio.
103
These are all really easy, they are just links.
105
function setupTumblr()
107
Unity.addAction('/Post/Text', makeRedirector('http://tumblr.com/new/text'));
108
Unity.addAction('/Post/Link', makeRedirector('http://tumblr.com/new/link'));
109
Unity.addAction('/Post/Chat', makeRedirector('http://tumblr.com/new/chat'));
110
Unity.addAction('/Post/Photo', makeRedirector('http://tumblr.com/new/photo'));
111
Unity.addAction('/Post/Quote', makeRedirector('http://tumblr.com/new/quote'));
112
Unity.addAction('/Post/Audio', makeRedirector('http://tumblr.com/new/audio'));
113
Unity.addAction('/Post/Video', makeRedirector('http://tumblr.com/new/video'));
116
Voila! Now we've got HUD integration for posting any type. Simply summon the HUD and type 'post photo' and you'll be taken to a new photo post page. Rockin'.
120
Getting a count on the launcher icon
121
------------------------------------
122
Very simple. We just need to parse the page for the count, and then set the count. The API for this is very simple.
124
function setupTumblr()
126
function setLauncherCount() {
127
// we want the total count for new posts and messages on the launcher, so we sum the two.
128
var i, total =0 , elements = document.getElementsByClassName("tab_notice_value");
129
for (i = 0; i < elements.length; i++) {
130
var count = elements[i].innerHTML;
132
total += parseInt(count);
136
Unity.Launcher.setLauncherCount(total);
138
Unity.Launcher.clearCount();
145
setInterval(wrapCallback(checkLauncherCount), 5000);
148
Note that we do this on a timer. every 5000 ms (5 seconds) we check the count, and reset it when it's empty.
151
Putting questions and fanmail into the messaging menu
152
------------------------------------------------------
153
Tumblr alerts you when you've got a new question, similar to the unread post count.
155
function checkNewMessageCount() {
156
var ib = document.getElementById("inbox_button");
157
var count = document.evaluate('a//span', ib, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
161
count = parseInt(count.innerHTML);
163
Unity.MessagingIndicator.showIndicator(_("Inbox"),
165
onIndicatorActivated: makeRedirector("http://tumblr.com/inbox");
170
This will make an indicator under the tumblr subheading with a count for new messages that when clicked, will take our user to the inbox page.
173
Integrating with tumblr blogs
174
------------------------------
175
We're going to do a little bit of refactoring. Tumblr has two components, the dashboard and blogs. Our integration this far has been with the dashboard, but there are some nice things we can do on blogs.
176
So let's start by differentiating the two. Tumblr blogs have tumblr controls on the top right hand corner.
178
function isDashboard() {
179
var i, ids = ['content', 'tabs_outter_container'];;
181
for (i = 0; i < ids.length; i++) {
182
if (!document.getElementById(ids[i])) {
190
function isTumblrBlog() {
191
return document.getElementById("tumblr_controls");
194
if (isDashboard() || isTumblrBlog()) {
195
Unity.init({ name: "Tumblr",
196
iconUrl: "icon://Tumblr",
197
onInit: wrapCallback(setupTumblr),
198
domain: "tumblr.com" });
201
Next we'll need to rework our setupTumblr function to take the two cases into account. Let's move what used to be setupTumblr into a new function, integrateDashboard and rework setupTumblr to look like this,
203
function setupTumblr()
206
integrateDashboard();
207
} else if (isTumblrBlog()) {
208
integrateTumblrblog();
212
And what's left is to integrate the blogs.
215
Adding quicklist actions to the launcher icon
216
----------------------------------------------
218
function integrateTumblrblog()
220
Unity.Launcher.addAction(_("Dashboard"), makeRedirector("http://tumblr.com/dashboard"));
226
As always proper automated tested is imperative! Most of the test is setup boiler plate. Check the source !!!LINK!!! to see the full test.
228
Tumblr requires authorization so we need some code to log in. The username and password get stored in a password file. in the scripts/ folder, where the test runner is. You'll see passwords.example. Copy it to a file names passwords, then modify it with valid usernames and passwords for the scripts you want to test, like so,
231
"Tumblr.user.js.in": {
232
"login": "cooltumblrdude@coolemail.xxx",
233
"password": "webappsrcool4u"
237
we then need to modify our test script to insert the values into the login form
239
onLoad: function () {
240
function authorize(login, pass) {
241
var name = document.getElementById("signup_email");
242
var password = document.getElementById("signup_password");
244
password.value = pass;
245
password.form.submit();
251
Next we validate our call log. This is how we test. TODO: How to get the call log for matching up log indices.
253
validateCallLog: function (log) {
254
assertEquals(log[0].func, "Unity.init");
255
assertEquals(log[0].args[0].name, "Tumblr");
256
assertEquals(log[3].func, "Unity.MessagingIndicator.showIndicator");
258
var i, actionsCount = 0;
259
for (i = 0; i < log.length; i++) {
260
if (log[i].func === 'Unity.addAction') {
264
assertEquals(actionsCount, 7);
267
scriptName: 'Tumblr.user.js.in'