From 720197f7a2eafdff4f05d9cc8f6bc2ac863b5ad2 Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Sat, 14 Jul 2012 16:35:19 -0700 Subject: [PATCH] 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 --- toolkit/components/social/SocialProvider.jsm | 37 +++++++++++- toolkit/components/social/WorkerAPI.jsm | 39 ++++++++++++- .../test/browser/browser_frameworker.js | 3 + .../social/test/browser/browser_workerAPI.js | 57 +++++++++++++++++-- .../components/social/test/browser/head.js | 11 ++-- .../social/test/browser/worker_social.js | 6 ++ 6 files changed, 141 insertions(+), 12 deletions(-) diff --git a/toolkit/components/social/SocialProvider.jsm b/toolkit/components/social/SocialProvider.jsm index 759e91a63cc..20e89c96bc3 100644 --- a/toolkit/components/social/SocialProvider.jsm +++ b/toolkit/components/social/SocialProvider.jsm @@ -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(); }, diff --git a/toolkit/components/social/WorkerAPI.jsm b/toolkit/components/social/WorkerAPI.jsm index e4c00641cf1..f9fc4626fb4 100644 --- a/toolkit/components/social/WorkerAPI.jsm +++ b/toolkit/components/social/WorkerAPI.jsm @@ -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); } } } diff --git a/toolkit/components/social/test/browser/browser_frameworker.js b/toolkit/components/social/test/browser/browser_frameworker.js index 626f72a429a..5dc730da4f8 100644 --- a/toolkit/components/social/test/browser/browser_frameworker.js +++ b/toolkit/components/social/test/browser/browser_frameworker.js @@ -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); } diff --git a/toolkit/components/social/test/browser/browser_workerAPI.js b/toolkit/components/social/test/browser/browser_workerAPI.js index 9a91668f253..8c42086c98f 100644 --- a/toolkit/components/social/test/browser/browser_workerAPI.js +++ b/toolkit/components/social/test/browser/browser_workerAPI.js @@ -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}); + } +}; diff --git a/toolkit/components/social/test/browser/head.js b/toolkit/components/social/test/browser/head.js index 2f70cf4a3c9..e0708691aa7 100644 --- a/toolkit/components/social/test/browser/head.js +++ b/toolkit/components/social/test/browser/head.js @@ -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(); } diff --git a/toolkit/components/social/test/browser/worker_social.js b/toolkit/components/social/test/browser/worker_social.js index fa68d24244a..f0c3169fc64 100644 --- a/toolkit/components/social/test/browser/worker_social.js +++ b/toolkit/components/social/test/browser/worker_social.js @@ -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; } } }