diff --git a/toolkit/components/social/FrameWorker.jsm b/toolkit/components/social/FrameWorker.jsm index 795221c6248b..6ec2623870ad 100644 --- a/toolkit/components/social/FrameWorker.jsm +++ b/toolkit/components/social/FrameWorker.jsm @@ -71,24 +71,39 @@ function FrameWorker(url, name) { this.loaded = false; this.frame = makeHiddenFrame(); - - var self = this; - Services.obs.addObserver(function injectController(doc, topic, data) { - if (!doc.defaultView || doc.defaultView != self.frame.contentWindow) { - return; - } - Services.obs.removeObserver(injectController, "document-element-inserted", false); - try { - self.createSandbox(); - } catch (e) { - Cu.reportError("FrameWorker: failed to create sandbox for " + url + ". " + e); - } - }, "document-element-inserted", false); - - this.frame.setAttribute("src", url); + this.load(); } FrameWorker.prototype = { + load: function FrameWorker_loadWorker() { + var self = this; + Services.obs.addObserver(function injectController(doc, topic, data) { + if (!doc.defaultView || doc.defaultView != self.frame.contentWindow) { + return; + } + Services.obs.removeObserver(injectController, "document-element-inserted", false); + try { + self.createSandbox(); + } catch (e) { + Cu.reportError("FrameWorker: failed to create sandbox for " + url + ". " + e); + } + }, "document-element-inserted", false); + + this.frame.setAttribute("src", this.url); + }, + + reload: function FrameWorker_reloadWorker() { + // push all the ports into pending ports, they will be re-entangled + // during the call to createSandbox after the document is reloaded + for (let [portid, port] in Iterator(this.ports)) { + port._window = null; + this.pendingPorts.push(port); + } + this.ports = {}; + this.loaded = false; + this.load(); + }, + createSandbox: function createSandbox() { let workerWindow = this.frame.contentWindow; let sandbox = new Cu.Sandbox(workerWindow); @@ -139,10 +154,10 @@ FrameWorker.prototype = { // and we delegate ononline and onoffline events to the worker. // See http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#workerglobalscope - this.frame.addEventListener('offline', function fw_onoffline(event) { + workerWindow.addEventListener('offline', function fw_onoffline(event) { Cu.evalInSandbox("onoffline();", sandbox); }, false); - this.frame.addEventListener('online', function fw_ononline(event) { + workerWindow.addEventListener('online', function fw_ononline(event) { Cu.evalInSandbox("ononline();", sandbox); }, false); @@ -248,15 +263,12 @@ function makeHiddenFrame() { return iframe; } +// public methods on WorkerHandle should conform to the SharedWorker api function WorkerHandle(port, worker) { this.port = port; this._worker = worker; } WorkerHandle.prototype = { - get document() { - return this._worker.frame.contentDocument; - }, - // XXX - workers have no .close() method, but *do* have a .terminate() // method which we should implement. However, the worker spec doesn't define // a callback to be made in the worker when this happens - it all just dies. diff --git a/toolkit/components/social/WorkerAPI.jsm b/toolkit/components/social/WorkerAPI.jsm index 6d5b1868b961..398d69c846e4 100644 --- a/toolkit/components/social/WorkerAPI.jsm +++ b/toolkit/components/social/WorkerAPI.jsm @@ -27,9 +27,6 @@ function WorkerAPI(provider, port) { // used for the api. // later we might even include an API version - version 0 for now! this._port.postMessage({topic: "social.initialize"}); - - // backwards compat, remove after Aug 1. - this._port.postMessage({topic: "social.cookie-changed"}); } WorkerAPI.prototype = { @@ -52,6 +49,13 @@ WorkerAPI.prototype = { }, handlers: { + "social.reload-worker": function(data) { + getFrameWorkerHandle(this._provider.workerURL, null)._worker.reload(); + // the frameworker is going to be reloaded, send the initialization + // so it can have the same startup sequence as if it were loaded + // the first time. This will be queued until the frameworker is ready. + this._port.postMessage({topic: "social.initialize"}); + }, "social.user-profile": function (data) { this._provider.updateUserProfile(data); }, @@ -59,7 +63,8 @@ WorkerAPI.prototype = { this._provider.setAmbientNotification(data); }, "social.cookies-get": function(data) { - let document = getFrameWorkerHandle(this._provider.workerURL, null).document; + let document = getFrameWorkerHandle(this._provider.workerURL, null). + _worker.frame.contentDocument; let cookies = document.cookie.split(";"); let results = []; cookies.forEach(function(aCookie) { diff --git a/toolkit/components/social/test/browser/browser_workerAPI.js b/toolkit/components/social/test/browser/browser_workerAPI.js index 5f68d19d6e66..6079bc3347d8 100644 --- a/toolkit/components/social/test/browser/browser_workerAPI.js +++ b/toolkit/components/social/test/browser/browser_workerAPI.js @@ -102,6 +102,43 @@ let tests = { Services.cookies.add('.example.com', '/', 'cheez', 'burger', false, false, true, MAX_EXPIRY); port.postMessage({topic: "test-initialization"}); port.postMessage({topic: "test.cookies-get"}); - } + }, + testWorkerReload: function(next) { + let fw = {}; + Cu.import("resource://gre/modules/FrameWorker.jsm", fw); + + // get a real handle to the worker so we can watch the unload event + // we watch for the unload of the worker to know it is infact being + // unloaded, after that if we get worker.connected we know that + // the worker was loaded again and ports reconnected + let reloading = false; + let worker = fw.getFrameWorkerHandle(provider.workerURL, undefined, "testWorkerReload"); + let win = worker._worker.frame.contentWindow; + win.addEventListener("unload", function workerUnload(e) { + win.removeEventListener("unload", workerUnload); + ok(true, "worker unload event has fired"); + reloading = true; + }); + let port = provider.getWorkerPort(); + ok(port, "provider has a port"); + port.onmessage = function (e) { + let topic = e.data.topic; + switch (topic) { + case "test-initialization-complete": + // tell the worker to send the reload msg + port.postMessage({topic: "test-reload-init"}); + break; + case "worker.connected": + // we'll get this message from the worker on every load of the worker, + // so we need to ignore it unless we have requested the reload. + if (reloading) { + ok(true, "worker reloaded and testPort was reconnected"); + next(); + } + break; + } + } + port.postMessage({topic: "test-initialization"}); + } }; diff --git a/toolkit/components/social/test/browser/worker_social.js b/toolkit/components/social/test/browser/worker_social.js index efc26240b799..da2ff34f4fd9 100644 --- a/toolkit/components/social/test/browser/worker_social.js +++ b/toolkit/components/social/test/browser/worker_social.js @@ -33,6 +33,17 @@ onconnect = function(e) { break; case "social.cookies-get-response": testerPort.postMessage({topic: "test.cookies-get-response", data: data}); + break; + case "test-reload-init": + // browser_social_sidebar.js started test, tell the sidebar to + // start + apiPort.postMessage({topic: 'social.reload-worker'}); + break; } } + // used for "test-reload-worker" + if (apiPort && apiPort != port) { + port.postMessage({topic: "worker.connected"}) + } + }