Bug 773530: make additions to the social WorkerAPI module to support the toolbar UI, r=gavin

--HG--
extra : transplant_source : 9%EF%EE%2A3g%3C%85%03%92%CC%1Ek%F3vKaD%1D%9F
This commit is contained in:
Shane Caraveo 2012-07-14 16:35:19 -07:00
parent 4aeece54fc
commit 720197f7a2
6 changed files with 141 additions and 12 deletions

View File

@ -27,8 +27,10 @@ function SocialProvider(input, enabled) {
throw new Error("SocialProvider must be passed an origin");
this.name = input.name;
this.iconURL = input.iconURL;
this.workerURL = input.workerURL;
this.origin = input.origin;
this.ambientNotificationIcons = {};
// If enabled is |undefined|, default to true.
this._enabled = !(enabled == false);
@ -65,13 +67,46 @@ SocialProvider.prototype = {
// no FrameWorker, or is disabled.
workerAPI: null,
// Contains information related to the user's profile. Populated by the
// workerAPI via updateUserProfile. Null if the provider has no FrameWorker.
// Properties:
// iconURL, portrait, userName, displayName, profileURL
// See https://github.com/mozilla/socialapi-dev/blob/develop/docs/socialAPI.md
profile: null,
// Map of objects describing the provider's notification icons, whose
// properties include:
// name, iconURL, counter, contentPanel
// See https://github.com/mozilla/socialapi-dev/blob/develop/docs/socialAPI.md
ambientNotificationIcons: null,
// Called by the workerAPI to update our profile information.
updateUserProfile: function(profile) {
this.profile = profile;
if (profile.iconURL)
this.iconURL = profile.iconURL;
if (!profile.displayName)
profile.displayName = profile.userName;
Services.obs.notifyObservers(null, "social:profile-changed", this.origin);
},
// Called by the workerAPI to add/update a notification icon.
setAmbientNotification: function(notification) {
this.ambientNotificationIcons[notification.name] = notification;
Services.obs.notifyObservers(null, "social:ambient-notification-changed", this.origin);
},
// Internal helper methods
_activate: function _activate() {
// Initialize the workerAPI and its port first, so that its initialization
// occurs before any other messages are processed by other ports.
let workerAPIPort = this._getWorkerPort();
if (workerAPIPort)
this.workerAPI = new WorkerAPI(workerAPIPort);
this.workerAPI = new WorkerAPI(this, workerAPIPort);
this.port = this._getWorkerPort();
},

View File

@ -7,13 +7,15 @@
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
const EXPORTED_SYMBOLS = ["WorkerAPI"];
function WorkerAPI(port) {
function WorkerAPI(provider, port) {
if (!port)
throw new Error("Can't initialize WorkerAPI with a null port");
this._provider = provider;
this._port = port;
this._port.onmessage = this._handleMessage.bind(this);
@ -43,6 +45,41 @@ WorkerAPI.prototype = {
handlers: {
"social.initialize-response": function (data) {
this.initialized = true;
},
"social.user-profile": function (data) {
this._provider.updateUserProfile(data);
},
"social.ambient-notification": function (data) {
this._provider.setAmbientNotification(data);
},
// XXX backwards compat for existing providers, remove these eventually
"social.ambient-notification-area": function (data) {
// replaced with social.user-profile
// handle the provider icon and user profile for the primary provider menu
if (data.background) {
// backwards compat
try {
data.iconURL = /url\((['"]?)(.*)(\1)\)/.exec(data.background)[2];
} catch(e) {
data.iconURL = data.background;
}
}
this._provider.updateUserProfile(data);
},
"social.ambient-notification-update": function (data) {
// replaced with social.ambient-notification
// handle the provider icon and user profile for the primary provider menu
if (data.background) {
// backwards compat
try {
data.iconURL = /url\((['"]?)(.*)(\1)\)/.exec(data.background)[2];
} catch(e) {
data.iconURL = data.background;
}
}
this._provider.setAmbientNotification(data);
}
}
}

View File

@ -8,9 +8,12 @@ function makeWorkerUrl(runner) {
var getFrameWorkerHandle;
function test() {
waitForExplicitFinish();
let scope = {};
Cu.import("resource://gre/modules/FrameWorker.jsm", scope);
getFrameWorkerHandle = scope.getFrameWorkerHandle;
runTests(tests);
}

View File

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
let provider;
function test() {
waitForExplicitFinish();
@ -13,7 +15,16 @@ function test() {
ensureSocialEnabled();
SocialService.addProvider(manifest, function (provider) {
SocialService.addProvider(manifest, function (p) {
provider = p;
runTests(tests, undefined, undefined, function () {
SocialService.removeProvider(provider.origin, finish);
});
});
}
let tests = {
testInitializeWorker: function(next) {
ok(provider.workerAPI, "provider has a workerAPI");
is(provider.workerAPI.initialized, false, "workerAPI is not yet initialized");
@ -24,9 +35,47 @@ function test() {
let {topic, data} = event.data;
if (topic == "test-initialization-complete") {
is(provider.workerAPI.initialized, true, "workerAPI is now initialized");
SocialService.removeProvider(provider.origin, finish);
next();
}
}
port.postMessage({topic: "test-initialization"});
});
}
},
testProfile: function(next) {
let expect = {
portrait: "chrome://branding/content/icon48.png",
userName: "trickster",
displayName: "Kuma Lisa",
profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
}
function ob(aSubject, aTopic, aData) {
Services.obs.removeObserver(ob, "social:profile-changed", false);
is(aData, provider.origin, "update of profile from our provider");
let profile = provider.profile;
is(profile.portrait, expect.portrait, "portrait is set");
is(profile.userName, expect.userName, "userName is set");
is(profile.displayName, expect.displayName, "displayName is set");
is(profile.profileURL, expect.profileURL, "profileURL is set");
next();
}
Services.obs.addObserver(ob, "social:profile-changed", false);
provider.workerAPI._port.postMessage({topic: "test-profile", data: expect});
},
testAmbientNotification: function(next) {
let expect = {
name: "test-ambient"
}
function ob(aSubject, aTopic, aData) {
Services.obs.removeObserver(ob, "social:ambient-notification-changed", false);
is(aData, provider.origin, "update is from our provider");
let notif = provider.ambientNotificationIcons[expect.name];
is(notif.name, expect.name, "ambientNotification reflected");
next();
}
Services.obs.addObserver(ob, "social:ambient-notification-changed", false);
provider.workerAPI._port.postMessage({topic: "test-ambient", data: expect});
}
};

View File

@ -20,8 +20,7 @@ function ensureSocialEnabled() {
// test = {
// foo: function(cbnext) {... cbnext();}
// }
function runTests(tests, cbPreTest, cbPostTest) {
waitForExplicitFinish();
function runTests(tests, cbPreTest, cbPostTest, cbFinish) {
let testIter = Iterator(tests);
if (cbPreTest === undefined) {
@ -31,18 +30,18 @@ function runTests(tests, cbPreTest, cbPostTest) {
cbPostTest = function(cb) {cb()};
}
let runNextTest = function() {
function runNextTest() {
let name, func;
try {
[name, func] = testIter.next();
} catch (err if err instanceof StopIteration) {
// out of items:
finish();
(cbFinish || finish)();
return;
}
// We run on a timeout as the frameworker also makes use of timeouts, so
// this helps keep the debug messages sane.
window.setTimeout(function() {
executeSoon(function() {
function cleanupAndRunNextTest() {
info("sub-test " + name + " complete");
cbPostTest(runNextTest);
@ -56,7 +55,7 @@ function runTests(tests, cbPreTest, cbPostTest) {
cleanupAndRunNextTest();
}
})
}, 0)
});
}
runNextTest();
}

View File

@ -13,6 +13,12 @@ onconnect = function(e) {
case "test-initialization":
port.postMessage({topic: "test-initialization-complete"});
break;
case "test-profile":
port.postMessage({topic: "social.user-profile", data: data});
break;
case "test-ambient":
port.postMessage({topic: "social.ambient-notification", data: data});
break;
}
}
}