Bug 811143 - move recommend support to the worker api and avoid dangling port if not supported by the provider. r=jaws

This commit is contained in:
Mark Hammond 2012-11-15 14:57:28 +11:00
Родитель 23a86417ce
Коммит f0ec0acb93
4 изменённых файлов: 85 добавлений и 81 удалений

Просмотреть файл

@ -12,6 +12,7 @@ let SocialUI = {
Services.obs.addObserver(this, "social:pref-changed", false);
Services.obs.addObserver(this, "social:ambient-notification-changed", false);
Services.obs.addObserver(this, "social:profile-changed", false);
Services.obs.addObserver(this, "social:recommend-info-changed", false);
Services.obs.addObserver(this, "social:frameworker-error", false);
Services.prefs.addObserver("social.sidebar.open", this, false);
@ -33,6 +34,7 @@ let SocialUI = {
Services.obs.removeObserver(this, "social:pref-changed");
Services.obs.removeObserver(this, "social:ambient-notification-changed");
Services.obs.removeObserver(this, "social:profile-changed");
Services.obs.removeObserver(this, "social:recommend-info-changed");
Services.obs.removeObserver(this, "social:frameworker-error");
Services.prefs.removeObserver("social.sidebar.open", this);
@ -74,6 +76,9 @@ let SocialUI = {
SocialShareButton.updateProfileInfo();
SocialChatBar.update();
break;
case "social:recommend-info-changed":
SocialShareButton.updateShareState();
break;
case "social:frameworker-error":
if (Social.provider) {
Social.errorState = "frameworker-error";
@ -455,12 +460,6 @@ let SocialFlyout = {
}
let SocialShareButton = {
// promptImages and promptMessages being null means we are yet to get the
// message back from the provider with the images and icons (or that we got
// the response but determined it was invalid.)
promptImages: null,
promptMessages: null,
// Called once, after window load, when the Social.provider object is initialized
init: function SSB_init() {
this.updateButtonHiddenState();
@ -470,8 +469,6 @@ let SocialShareButton = {
updateProfileInfo: function SSB_updateProfileInfo() {
let profileRow = document.getElementById("unsharePopupHeader");
let profile = Social.provider.profile;
this.promptImages = null;
this.promptMessages = null;
if (profile && profile.displayName) {
profileRow.hidden = false;
let portrait = document.getElementById("socialUserPortrait");
@ -483,63 +480,7 @@ let SocialShareButton = {
this.updateButtonHiddenState();
return;
}
// XXX - this shouldn't be done as part of updateProfileInfo, but instead
// whenever we notice the provider has changed - but the concept of
// "provider changed" will only exist once bug 774520 lands.
// get the recommend-prompt info.
let port = Social.provider.getWorkerPort();
if (port) {
port.onmessage = function(evt) {
if (evt.data.topic == "social.user-recommend-prompt-response") {
port.close();
this.acceptRecommendInfo(evt.data.data);
this.updateButtonHiddenState();
this.updateShareState();
}
}.bind(this);
port.postMessage({topic: "social.user-recommend-prompt"});
}
},
acceptRecommendInfo: function SSB_acceptRecommendInfo(data) {
// Accept *and validate* the user-recommend-prompt-response message.
let promptImages = {};
let promptMessages = {};
function reportError(reason) {
Cu.reportError("Invalid recommend data from provider: " + reason + ": sharing is disabled for this provider");
return false;
}
if (!data ||
!data.images || typeof data.images != "object" ||
!data.messages || typeof data.messages != "object") {
return reportError("data is missing valid 'images' or 'messages' elements");
}
for (let sub of ["share", "unshare"]) {
let url = data.images[sub];
if (!url || typeof url != "string" || url.length == 0) {
return reportError('images["' + sub + '"] is missing or not a non-empty string');
}
// resolve potentially relative URLs then check the scheme is acceptable.
url = Services.io.newURI(Social.provider.origin, null, null).resolve(url);
let uri = Services.io.newURI(url, null, null);
if (!uri.schemeIs("http") && !uri.schemeIs("https") && !uri.schemeIs("data")) {
return reportError('images["' + sub + '"] does not have a valid scheme');
}
promptImages[sub] = url;
}
for (let sub of ["shareTooltip", "unshareTooltip",
"sharedLabel", "unsharedLabel", "unshareLabel",
"portraitLabel",
"unshareConfirmLabel", "unshareConfirmAccessKey",
"unshareCancelLabel", "unshareCancelAccessKey"]) {
if (typeof data.messages[sub] != "string" || data.messages[sub].length == 0) {
return reportError('messages["' + sub + '"] is not a valid string');
}
promptMessages[sub] = data.messages[sub];
}
this.promptImages = promptImages;
this.promptMessages = promptMessages;
return true;
this.updateShareState();
},
get shareButton() {
@ -561,7 +502,7 @@ let SocialShareButton = {
updateButtonHiddenState: function SSB_updateButtonHiddenState() {
let shareButton = this.shareButton;
if (shareButton)
shareButton.hidden = !Social.uiVisible || this.promptImages == null ||
shareButton.hidden = !Social.uiVisible || Social.provider.recommendInfo == null ||
!SocialUI.haveLoggedInUser() ||
!this.canSharePage(gBrowser.currentURI);
},
@ -585,16 +526,17 @@ let SocialShareButton = {
}
let continueSharingButton = document.getElementById("unsharePopupContinueSharingButton");
continueSharingButton.focus();
let recommendInfo = Social.provider.recommendInfo;
updateElement("unsharePopupContinueSharingButton",
{label: this.promptMessages.unshareCancelLabel,
accesskey: this.promptMessages.unshareCancelAccessKey});
{label: recommendInfo.messages.unshareCancelLabel,
accesskey: recommendInfo.messages.unshareCancelAccessKey});
updateElement("unsharePopupStopSharingButton",
{label: this.promptMessages.unshareConfirmLabel,
accesskey: this.promptMessages.unshareConfirmAccessKey});
{label: recommendInfo.messages.unshareConfirmLabel,
accesskey: recommendInfo.messages.unshareConfirmAccessKey});
updateElement("socialUserPortrait",
{"aria-label": this.promptMessages.portraitLabel});
{"aria-label": recommendInfo.messages.portraitLabel});
updateElement("socialUserRecommendedText",
{value: this.promptMessages.unshareLabel});
{value: recommendInfo.messages.unshareLabel});
},
sharePage: function SSB_sharePage() {
@ -623,6 +565,7 @@ let SocialShareButton = {
let shareButton = this.shareButton;
let currentPageShared = shareButton && !shareButton.hidden && Social.isPageShared(gBrowser.currentURI);
let recommendInfo = Social.provider ? Social.provider.recommendInfo : null;
// Provide a11y-friendly notification of share.
let status = document.getElementById("share-button-status");
if (status) {
@ -630,10 +573,10 @@ let SocialShareButton = {
// unshared (ie, it needs to manage three-states: (1) nothing done, (2)
// shared, (3) shared then unshared)
// Note that we *do* have an appropriate string from the provider for
// this (promptMessages['unsharedLabel'] but currently lack a way of
// this (recommendInfo.messages.unsharedLabel) but currently lack a way of
// tracking this state)
let statusString = currentPageShared ?
this.promptMessages['sharedLabel'] : "";
let statusString = currentPageShared && recommendInfo ?
recommendInfo.messages.sharedLabel : "";
status.setAttribute("value", statusString);
}
@ -644,12 +587,12 @@ let SocialShareButton = {
let imageURL;
if (currentPageShared) {
shareButton.setAttribute("shared", "true");
shareButton.setAttribute("tooltiptext", this.promptMessages['unshareTooltip']);
imageURL = this.promptImages["unshare"]
shareButton.setAttribute("tooltiptext", recommendInfo.messages.unshareTooltip);
imageURL = recommendInfo.images.unshare;
} else {
shareButton.removeAttribute("shared");
shareButton.setAttribute("tooltiptext", this.promptMessages['shareTooltip']);
imageURL = this.promptImages["share"]
shareButton.setAttribute("tooltiptext", recommendInfo.messages.shareTooltip);
imageURL = recommendInfo.images.share;
}
shareButton.src = imageURL;
}

Просмотреть файл

@ -54,7 +54,7 @@ function testInitial(finishcb) {
// ensure the worker initialization and handshakes are all done and we
// have a profile and the worker has responsed to the recommend-prompt msg.
waitForCondition(function() Social.provider.profile && SocialShareButton.promptImages != null, function() {
waitForCondition(function() Social.provider.profile && Social.provider.recommendInfo != null, function() {
is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' attribute before share button is clicked");
// check dom values
let profile = Social.provider.profile;

Просмотреть файл

@ -220,6 +220,62 @@ SocialProvider.prototype = {
// values aren't to be used as the user is logged out'.
profile: undefined,
// Contains the information necessary to support our "recommend" feature.
// null means no info yet provided (which includes the case of the provider
// not supporting the feature) or the provided data is invalid. Updated via
// the 'recommendInfo' setter and returned via the getter.
_recommendInfo: null,
get recommendInfo() {
return this._recommendInfo;
},
set recommendInfo(data) {
// Accept *and validate* the user-recommend-prompt-response message from
// the provider.
let promptImages = {};
let promptMessages = {};
function reportError(reason) {
Cu.reportError("Invalid recommend data from provider: " + reason + ": sharing is disabled for this provider");
// and we explicitly reset the recommend data to null to avoid stale
// data being used and notify our observers.
this._recommendInfo = null;
Services.obs.notifyObservers(null, "social:recommend-info-changed", this.origin);
}
if (!data ||
!data.images || typeof data.images != "object" ||
!data.messages || typeof data.messages != "object") {
reportError("data is missing valid 'images' or 'messages' elements");
return;
}
for (let sub of ["share", "unshare"]) {
let url = data.images[sub];
if (!url || typeof url != "string" || url.length == 0) {
reportError('images["' + sub + '"] is missing or not a non-empty string');
return;
}
// resolve potentially relative URLs then check the scheme is acceptable.
url = Services.io.newURI(this.origin, null, null).resolve(url);
let uri = Services.io.newURI(url, null, null);
if (!uri.schemeIs("http") && !uri.schemeIs("https") && !uri.schemeIs("data")) {
reportError('images["' + sub + '"] does not have a valid scheme');
return;
}
promptImages[sub] = url;
}
for (let sub of ["shareTooltip", "unshareTooltip",
"sharedLabel", "unsharedLabel", "unshareLabel",
"portraitLabel",
"unshareConfirmLabel", "unshareConfirmAccessKey",
"unshareCancelLabel", "unshareCancelAccessKey"]) {
if (typeof data.messages[sub] != "string" || data.messages[sub].length == 0) {
reportError('messages["' + sub + '"] is not a valid string');
return;
}
promptMessages[sub] = data.messages[sub];
}
this._recommendInfo = {images: promptImages, messages: promptMessages};
Services.obs.notifyObservers(null, "social:recommend-info-changed", this.origin);
},
// Map of objects describing the provider's notification icons, whose
// properties include:
// name, iconURL, counter, contentPanel

Просмотреть файл

@ -44,7 +44,7 @@ WorkerAPI.prototype = {
try {
handler.call(this, data);
} catch (ex) {
Cu.reportError("WorkerAPI: failed to handle message '" + topic + "': " + ex);
Cu.reportError("WorkerAPI: failed to handle message '" + topic + "': " + ex + "\n" + ex.stack);
}
},
@ -58,10 +58,15 @@ WorkerAPI.prototype = {
},
"social.user-profile": function (data) {
this._provider.updateUserProfile(data);
// get the info we need for 'recommend' support.
this._port.postMessage({topic: "social.user-recommend-prompt"});
},
"social.ambient-notification": function (data) {
this._provider.setAmbientNotification(data);
},
"social.user-recommend-prompt-response": function(data) {
this._provider.recommendInfo = data;
},
"social.cookies-get": function(data) {
let document = this._port._window.document;
let cookies = document.cookie.split(";");