bug 853151 refactoring recommend into SocialMark, r=felipe

--HG--
rename : browser/base/content/test/social/social_share_image.png => browser/base/content/test/social/social_mark_image.png
This commit is contained in:
Shane Caraveo 2013-04-24 12:58:36 -07:00
Родитель f6494f1354
Коммит c1591385ae
22 изменённых файлов: 503 добавлений и 783 удалений

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

@ -37,6 +37,10 @@
label="&bookmarkThisLinkCmd.label;"
accesskey="&bookmarkThisLinkCmd.accesskey;"
oncommand="gContextMenu.bookmarkLink();"/>
<menuitem id="context-marklink"
label="&social.marklink.label;"
accesskey="&social.marklink.accesskey;"
oncommand="gContextMenu.markLink();"/>
<menuitem id="context-savelink"
label="&saveLinkCmd.label;"
accesskey="&saveLinkCmd.accesskey;"
@ -222,6 +226,10 @@
label="&bookmarkPageCmd2.label;"
accesskey="&bookmarkPageCmd2.accesskey;"
oncommand="gContextMenu.bookmarkThisPage();"/>
<menuitem id="context-markpage"
label="&social.markpage.label;"
accesskey="&social.markpage.accesskey;"
command="Social:TogglePageMark"/>
<menuitem id="context-savepage"
label="&savePageCmd.label;"
accesskey="&savePageCmd.accesskey2;"

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

@ -109,8 +109,7 @@
<command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
<command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
<command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
<command id="Social:SharePage" oncommand="SocialShareButton.sharePage();" disabled="true"/>
<command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
<command id="Social:TogglePageMark" oncommand="SocialMark.togglePageMark();" disabled="true"/>
<command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
<command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
<command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/>
@ -350,8 +349,8 @@
# overridden for other purposes there.
<key id="viewBookmarksSidebarWinKb" key="&bookmarksWinCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
#endif
<key id="sharePage" key="&sharePageCmd.commandkey;" command="Social:SharePage" modifiers="accel,shift"/>
<key id="markPage" key="&markPageCmd.commandkey;" command="Social:TogglePageMark" modifiers="accel,shift"/>
<key id="focusChatBar" key="&social.chatBar.commandkey;" command="Social:FocusChat" modifiers="accel,shift"/>
<key id="key_stop" keycode="VK_ESCAPE" command="Browser:Stop"/>

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

@ -6,7 +6,7 @@
let SocialUI,
SocialChatBar,
SocialFlyout,
SocialShareButton,
SocialMark,
SocialMenu,
SocialToolbar,
SocialSidebar;
@ -25,7 +25,7 @@ SocialUI = {
init: function SocialUI_init() {
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:page-mark-config", false);
Services.obs.addObserver(this, "social:frameworker-error", false);
Services.obs.addObserver(this, "social:provider-set", false);
Services.obs.addObserver(this, "social:providers-changed", false);
@ -42,7 +42,7 @@ SocialUI = {
});
SocialChatBar.init();
SocialShareButton.init();
SocialMark.init();
SocialMenu.init();
SocialToolbar.init();
SocialSidebar.init();
@ -61,7 +61,7 @@ SocialUI = {
uninit: function SocialUI_uninit() {
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:page-mark-config");
Services.obs.removeObserver(this, "social:frameworker-error");
Services.obs.removeObserver(this, "social:provider-set");
Services.obs.removeObserver(this, "social:providers-changed");
@ -88,7 +88,7 @@ SocialUI = {
SocialFlyout.unload();
SocialChatBar.update();
SocialSidebar.update();
SocialShareButton.update();
SocialMark.update();
SocialToolbar.update();
SocialMenu.populate();
break;
@ -109,13 +109,13 @@ SocialUI = {
case "social:profile-changed":
if (this._matchesCurrentProvider(data)) {
SocialToolbar.updateProfile();
SocialShareButton.update();
SocialMark.update();
SocialChatBar.update();
}
break;
case "social:recommend-info-changed":
case "social:page-mark-config":
if (this._matchesCurrentProvider(data)) {
SocialShareButton.updateShareState();
SocialMark.updateMarkState();
}
break;
case "social:frameworker-error":
@ -566,146 +566,81 @@ SocialFlyout = {
}
}
SocialShareButton = {
SocialMark = {
// Called once, after window load, when the Social.provider object is initialized
init: function SSB_init() {
},
// Called when the Social.provider changes
update: function() {
this._updateButtonHiddenState();
let profileRow = document.getElementById("unsharePopupHeader");
let profile = SocialUI.enabled ? Social.provider.profile : null;
if (profile && profile.displayName) {
profileRow.hidden = false;
let portrait = document.getElementById("socialUserPortrait");
if (profile.portrait) {
portrait.setAttribute("src", profile.portrait);
} else {
portrait.removeAttribute("src");
}
let displayName = document.getElementById("socialUserDisplayName");
displayName.setAttribute("label", profile.displayName);
} else {
profileRow.hidden = true;
}
get button() {
return document.getElementById("social-mark-button");
},
get shareButton() {
return document.getElementById("share-button");
},
get unsharePopup() {
return document.getElementById("unsharePopup");
},
dismissUnsharePopup: function SSB_dismissUnsharePopup() {
this.unsharePopup.hidePopup();
},
canSharePage: function SSB_canSharePage(aURI) {
canMarkPage: function SSB_canMarkPage(aURI) {
// We only allow sharing of http or https
return aURI && (aURI.schemeIs('http') || aURI.schemeIs('https'));
},
_updateButtonHiddenState: function SSB_updateButtonHiddenState() {
let shareButton = this.shareButton;
if (shareButton)
shareButton.hidden = !SocialUI.enabled || Social.provider.recommendInfo == null ||
!Social.haveLoggedInUser() ||
!this.canSharePage(gBrowser.currentURI);
// Called when the Social.provider changes
update: function SSB_updateButtonState() {
let markButton = this.button;
// always show button if provider supports marks
markButton.hidden = !SocialUI.enabled || Social.provider.pageMarkInfo == null;
markButton.disabled = markButton.hidden || !this.canMarkPage(gBrowser.currentURI);
// also update the relevent command's disabled state so the keyboard
// shortcut only works when available.
let cmd = document.getElementById("Social:SharePage");
cmd.setAttribute("disabled", shareButton.hidden ? "true" : "false");
let cmd = document.getElementById("Social:TogglePageMark");
cmd.setAttribute("disabled", markButton.disabled ? "true" : "false");
},
onClick: function SSB_onClick(aEvent) {
if (aEvent.button != 0)
togglePageMark: function(aCallback) {
if (this.button.disabled)
return;
// Don't bubble to the textbox, to avoid unwanted selection of the address.
aEvent.stopPropagation();
this.sharePage();
this.toggleURIMark(gBrowser.currentURI, aCallback)
},
toggleURIMark: function(aURI, aCallback) {
let update = function(marked) {
this._updateMarkState(marked);
if (aCallback)
aCallback(marked);
}.bind(this);
Social.isURIMarked(aURI, function(marked) {
if (marked) {
Social.unmarkURI(aURI, update);
} else {
Social.markURI(aURI, update);
}
});
},
panelShown: function SSB_panelShown(aEvent) {
function updateElement(id, attrs) {
let el = document.getElementById(id);
Object.keys(attrs).forEach(function(attr) {
el.setAttribute(attr, attrs[attr]);
});
}
let continueSharingButton = document.getElementById("unsharePopupContinueSharingButton");
continueSharingButton.focus();
let recommendInfo = Social.provider.recommendInfo;
updateElement("unsharePopupContinueSharingButton",
{label: recommendInfo.messages.unshareCancelLabel,
accesskey: recommendInfo.messages.unshareCancelAccessKey});
updateElement("unsharePopupStopSharingButton",
{label: recommendInfo.messages.unshareConfirmLabel,
accesskey: recommendInfo.messages.unshareConfirmAccessKey});
updateElement("socialUserPortrait",
{"aria-label": recommendInfo.messages.portraitLabel});
updateElement("socialUserRecommendedText",
{value: recommendInfo.messages.unshareLabel});
updateMarkState: function SSB_updateMarkState() {
this.update();
Social.isURIMarked(gBrowser.currentURI, this._updateMarkState.bind(this));
},
sharePage: function SSB_sharePage() {
this.unsharePopup.hidden = false;
_updateMarkState: function(currentPageMarked) {
// callback for isURIMarked
let markButton = this.button;
let pageMarkInfo = SocialUI.enabled ? Social.provider.pageMarkInfo : null;
let uri = gBrowser.currentURI;
if (!Social.isPageShared(uri)) {
Social.sharePage(uri);
this.updateShareState();
} else {
this.unsharePopup.openPopup(this.shareButton, "bottomcenter topright");
}
},
unsharePage: function SSB_unsharePage() {
Social.unsharePage(gBrowser.currentURI);
this.updateShareState();
this.dismissUnsharePopup();
},
updateShareState: function SSB_updateShareState() {
this._updateButtonHiddenState();
let shareButton = this.shareButton;
let currentPageShared = shareButton && !shareButton.hidden && Social.isPageShared(gBrowser.currentURI);
let recommendInfo = SocialUI.enabled ? Social.provider.recommendInfo : null;
// Provide a11y-friendly notification of share.
let status = document.getElementById("share-button-status");
if (status) {
// XXX - this should also be capable of reflecting that the page was
// 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 (recommendInfo.messages.unsharedLabel) but currently lack a way of
// tracking this state)
let statusString = currentPageShared && recommendInfo ?
recommendInfo.messages.sharedLabel : "";
status.setAttribute("value", statusString);
}
// Update the share button, if present
if (!shareButton || shareButton.hidden)
// Update the mark button, if present
if (!markButton || markButton.hidden || !pageMarkInfo)
return;
let imageURL;
if (currentPageShared) {
shareButton.setAttribute("shared", "true");
shareButton.setAttribute("tooltiptext", recommendInfo.messages.unshareTooltip);
imageURL = recommendInfo.images.unshare;
if (!markButton.disabled && currentPageMarked) {
markButton.setAttribute("marked", "true");
markButton.setAttribute("label", pageMarkInfo.messages.markedLabel);
markButton.setAttribute("tooltiptext", pageMarkInfo.messages.markedTooltip);
imageURL = pageMarkInfo.images.marked;
} else {
shareButton.removeAttribute("shared");
shareButton.setAttribute("tooltiptext", recommendInfo.messages.shareTooltip);
imageURL = recommendInfo.images.share;
markButton.removeAttribute("marked");
markButton.setAttribute("label", pageMarkInfo.messages.unmarkedLabel);
markButton.setAttribute("tooltiptext", pageMarkInfo.messages.unmarkedTooltip);
imageURL = pageMarkInfo.images.unmarked;
}
shareButton.src = imageURL;
markButton.style.listStyleImage = "url(" + imageURL + ")";
}
};
@ -794,8 +729,12 @@ SocialToolbar = {
let tbi = document.getElementById("social-toolbar-item");
if (tbi) {
while (tbi.lastChild != tbi.firstChild)
tbi.removeChild(tbi.lastChild);
// SocialMark is the last button allways
let next = SocialMark.button.previousSibling;
while (next != tbi.firstChild) {
tbi.removeChild(next);
next = SocialMark.button.previousSibling;
}
}
}
},
@ -943,7 +882,7 @@ SocialToolbar = {
toolbarButton.setAttribute("aria-label", ariaLabel);
}
let socialToolbarItem = document.getElementById("social-toolbar-item");
socialToolbarItem.appendChild(toolbarButtons);
socialToolbarItem.insertBefore(toolbarButtons, SocialMark.button);
for (let frame of createdFrames) {
if (frame.socialErrorListener) {

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

@ -3405,7 +3405,7 @@ function BrowserToolboxCustomizeDone(aToolboxChanged) {
URLBarSetURI();
XULBrowserWindow.asyncUpdateUI();
BookmarksMenuButton.updateStarState();
SocialShareButton.updateShareState();
SocialMark.updateMarkState();
}
TabsInTitlebar.allowedBy("customizing-toolbars", true);
@ -3879,7 +3879,7 @@ var XULBrowserWindow = {
// Update starring UI
BookmarksMenuButton.updateStarState();
SocialShareButton.updateShareState();
SocialMark.updateMarkState();
}
// Show or hide browser chrome based on the whitelist

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

@ -205,52 +205,6 @@
</vbox>
</panel>
<panel id="unsharePopup"
type="arrow"
orient="vertical"
ignorekeys="true"
hidden="true"
onpopupshown="SocialShareButton.panelShown(event);"
consumeoutsideclicks="true"
level="top">
<!-- Note that 'label', 'accesskey', 'value' and 'aria-label' attributes
for many of these elements are supplied by the provider and filled
in at runtime
-->
<row id="unsharePopupHeader" align="center">
<vbox align="center">
<image id="socialUserPortrait" onclick="SocialUI.showProfile();"/>
</vbox>
<vbox id="unsharePopupText">
<button id="socialUserDisplayName" pack="start"
oncommand="SocialUI.showProfile();"/>
<spacer flex="1"/>
<label id="socialUserRecommendedText"/>
</vbox>
</row>
<hbox id="unsharePopupBottomButtons" pack="end">
#ifdef XP_UNIX
<button id="unsharePopupStopSharingButton"
class="unsharePopupBottomButton"
command="Social:UnsharePage"/>
<button id="unsharePopupContinueSharingButton"
class="unsharePopupBottomButton"
default="true"
autofocus="autofocus"
oncommand="SocialShareButton.dismissUnsharePopup();"/>
#else
<button id="unsharePopupContinueSharingButton"
class="unsharePopupBottomButton"
default="true"
autofocus="autofocus"
oncommand="SocialShareButton.dismissUnsharePopup();"/>
<button id="unsharePopupStopSharingButton"
class="unsharePopupBottomButton"
command="Social:UnsharePage"/>
#endif
</hbox>
</panel>
<panel id="social-notification-panel"
class="social-panel"
type="arrow"
@ -613,13 +567,6 @@
hidden="true"
tooltiptext="&pageReportIcon.tooltip;"
onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
<label id="share-button-status" collapsed="true" role="status"/>
<image id="share-button"
class="urlbar-icon"
hidden="true"
onclick="SocialShareButton.onClick(event);"/>
<image id="go-button"
class="urlbar-icon"
tooltiptext="&goEndCap.tooltip;"
@ -802,6 +749,9 @@
oncommand="SocialUI.showLearnMore();"/>
</menupopup>
</toolbarbutton>
<toolbarbutton id="social-mark-button"
class="toolbarbutton-1"
command="Social:TogglePageMark"/>
</toolbaritem>
<hbox id="window-controls" hidden="true" pack="end">

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

@ -292,6 +292,32 @@ nsContextMenu.prototype = {
this.onTextInput && top.gBidiUI);
this.showItem("context-bidi-page-direction-toggle",
!this.onTextInput && top.gBidiUI);
// SocialMarks
let marksEnabled = SocialUI.enabled && Social.provider.pageMarkInfo;
let enablePageMark = marksEnabled && !(this.isContentSelected ||
this.onTextInput || this.onLink || this.onImage ||
this.onVideo || this.onAudio || this.onSocial);
let enableLinkMark = marksEnabled && ((this.onLink && !this.onMailtoLink &&
!this.onSocial) || this.onPlainTextLink)
if (enablePageMark) {
Social.isURIMarked(gBrowser.currentURI, function(marked) {
let label = marked ? "social.unmarkpage.label" : "social.markpage.label";
let provider = Social.provider || Social.defaultProvider;
let menuLabel = gNavigatorBundle.getFormattedString(label, [provider.name]);
this.setItemAttr("context-markpage", "label", menuLabel);
}.bind(this));
}
this.showItem("context-markpage", enablePageMark);
if (enableLinkMark) {
Social.isURIMarked(this.linkURI, function(marked) {
let label = marked ? "social.unmarklink.label" : "social.marklink.label";
let provider = Social.provider || Social.defaultProvider;
let menuLabel = gNavigatorBundle.getFormattedString(label, [provider.name]);
this.setItemAttr("context-marklink", "label", menuLabel);
}.bind(this));
}
this.showItem("context-marklink", enableLinkMark);
},
initSpellingItems: function() {
@ -1468,6 +1494,11 @@ nsContextMenu.prototype = {
}
},
markLink: function CM_markLink() {
// send link to social
SocialMark.toggleURIMark(this.linkURI);
},
savePageAs: function CM_savePageAs() {
saveDocument(this.browser.contentDocument);
},

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

@ -20,7 +20,7 @@ _BROWSER_FILES = \
browser_social_activation.js \
browser_social_perwindowPB.js \
browser_social_toolbar.js \
browser_social_shareButton.js \
browser_social_markButton.js \
browser_social_sidebar.js \
browser_social_flyout.js \
browser_social_mozSocial_API.js \
@ -33,7 +33,7 @@ _BROWSER_FILES = \
social_activate.html \
social_activate_iframe.html \
social_panel.html \
social_share_image.png \
social_mark_image.png \
social_sidebar.html \
social_chat.html \
social_flyout.html \

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

@ -0,0 +1,215 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 prefName = "social.enabled",
gFinishCB;
function test() {
waitForExplicitFinish();
// Need to load a http/https/ftp/ftps page for the social mark button to appear
let tab = gBrowser.selectedTab = gBrowser.addTab("https://example.com", {skipAnimation: true});
tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
tab.linkedBrowser.removeEventListener("load", tabLoad, true);
executeSoon(tabLoaded);
}, true);
registerCleanupFunction(function() {
Services.prefs.clearUserPref(prefName);
gBrowser.removeTab(tab);
});
}
function tabLoaded() {
ok(Social, "Social module loaded");
let manifest = { // normal provider
name: "provider 1",
origin: "https://example.com",
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
};
runSocialTestWithProvider(manifest, function (finishcb) {
gFinishCB = finishcb;
testInitial();
});
}
function testInitial(finishcb) {
ok(Social.provider, "Social provider is active");
ok(Social.provider.enabled, "Social provider is enabled");
let port = Social.provider.getWorkerPort();
ok(port, "Social provider has a port to its FrameWorker");
port.close();
let markButton = SocialMark.button;
ok(markButton, "mark button exists");
// ensure the worker initialization and handshakes are all done and we
// have a profile and the worker has sent a page-mark-config msg.
waitForCondition(function() Social.provider.pageMarkInfo != null, function() {
is(markButton.hasAttribute("marked"), false, "SocialMark button should not have 'marked' attribute before mark button is clicked");
// Check the strings from our worker actually ended up on the button.
is(markButton.getAttribute("tooltiptext"), "Mark this page", "check tooltip text is correct");
// Check the relative URL was resolved correctly (note this image has offsets of zero...)
is(markButton.style.listStyleImage, 'url("https://example.com/browser/browser/base/content/test/social/social_mark_image.png")', "check image url is correct");
// Test the mark button command handler
SocialMark.togglePageMark(function() {
is(markButton.hasAttribute("marked"), true, "mark button should have 'marked' attribute after mark button is clicked");
is(markButton.getAttribute("tooltiptext"), "Unmark this page", "check tooltip text is correct");
// Check the URL and offsets were applied correctly
is(markButton.style.listStyleImage, 'url("https://example.com/browser/browser/base/content/test/social/social_mark_image.png")', "check image url is correct");
SocialMark.togglePageMark(function() {
executeSoon(function() {
testStillMarkedIn2Tabs();
});
});
});
markButton.click();
}, "provider didn't provide page-mark-config");
}
function testStillMarkedIn2Tabs() {
let toMark = "http://example.com";
let markUri = Services.io.newURI(toMark, null, null);
let markButton = SocialMark.button;
let initialTab = gBrowser.selectedTab;
if (markButton.hasAttribute("marked")) {
SocialMark.togglePageMark(testStillMarkedIn2Tabs);
return;
}
is(markButton.hasAttribute("marked"), false, "SocialMark button should not have 'marked' for the initial tab");
let tab1 = gBrowser.selectedTab = gBrowser.addTab(toMark);
let tab1b = gBrowser.getBrowserForTab(tab1);
tab1b.addEventListener("load", function tabLoad(event) {
tab1b.removeEventListener("load", tabLoad, true);
let tab2 = gBrowser.selectedTab = gBrowser.addTab(toMark);
let tab2b = gBrowser.getBrowserForTab(tab2);
tab2b.addEventListener("load", function tabLoad(event) {
tab2b.removeEventListener("load", tabLoad, true);
// should start without either page being marked.
is(markButton.hasAttribute("marked"), false, "SocialMark button should not have 'marked' before we've done anything");
Social.isURIMarked(markUri, function(marked) {
ok(!marked, "page is unmarked in annotations");
markButton.click();
waitForCondition(function() markButton.hasAttribute("marked"), function() {
Social.isURIMarked(markUri, function(marked) {
ok(marked, "page is marked in annotations");
// and switching to the first tab (with the same URL) should still reflect marked.
gBrowser.selectedTab = tab1;
is(markButton.hasAttribute("marked"), true, "SocialMark button should reflect the marked state");
// but switching back the initial one should reflect not marked.
gBrowser.selectedTab = initialTab;
waitForCondition(function() !markButton.hasAttribute("marked"), function() {
gBrowser.selectedTab = tab1;
SocialMark.togglePageMark(function() {
Social.isURIMarked(gBrowser.currentURI, function(marked) {
ok(!marked, "page is unmarked in annotations");
waitForCondition(function() !markButton.hasAttribute("marked"), function() {
is(markButton.hasAttribute("marked"), false, "SocialMark button should reflect the marked state");
gBrowser.removeTab(tab1);
gBrowser.removeTab(tab2);
executeSoon(testStillMarkedAfterReopen);
}, "button has been unmarked");
});
});
}, "button has been unmarked");
});
}, "button has been marked");
});
}, true);
}, true);
}
function testStillMarkedAfterReopen() {
let toMark = "http://example.com";
let markButton = SocialMark.button;
is(markButton.hasAttribute("marked"), false, "Reopen: SocialMark button should not have 'marked' for the initial tab");
let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
let tabb = gBrowser.getBrowserForTab(tab);
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
SocialMark.togglePageMark(function() {
is(markButton.hasAttribute("marked"), true, "SocialMark button should reflect the marked state");
gBrowser.removeTab(tab);
// should be on the initial unmarked tab now.
waitForCondition(function() !markButton.hasAttribute("marked"), function() {
// now open the same URL - should be back to Marked.
tab = gBrowser.selectedTab = gBrowser.addTab(toMark, {skipAnimation: true});
tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
tab.linkedBrowser.removeEventListener("load", tabLoad, true);
executeSoon(function() {
is(markButton.hasAttribute("marked"), true, "New tab to previously marked URL should reflect marked state");
SocialMark.togglePageMark(function() {
gBrowser.removeTab(tab);
executeSoon(testOnlyMarkCertainUrlsTabSwitch);
});
});
}, true);
}, "button is now unmarked");
});
}, true);
}
function testOnlyMarkCertainUrlsTabSwitch() {
let toMark = "http://example.com";
let notSharable = "about:blank";
let markButton = SocialMark.button;
let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
let tabb = gBrowser.getBrowserForTab(tab);
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(!markButton.hidden, "SocialMark button not hidden for http url");
let tab2 = gBrowser.selectedTab = gBrowser.addTab(notSharable);
let tabb2 = gBrowser.getBrowserForTab(tab2);
tabb2.addEventListener("load", function tabLoad(event) {
tabb2.removeEventListener("load", tabLoad, true);
ok(markButton.disabled, "SocialMark button disabled for about:blank");
gBrowser.selectedTab = tab;
ok(!markButton.disabled, "SocialMark button re-shown when switching back to http: url");
gBrowser.selectedTab = tab2;
ok(markButton.disabled, "SocialMark button re-hidden when switching back to about:blank");
gBrowser.removeTab(tab);
gBrowser.removeTab(tab2);
executeSoon(testOnlyMarkCertainUrlsSameTab);
}, true);
}, true);
}
function testOnlyMarkCertainUrlsSameTab() {
let toMark = "http://example.com";
let notSharable = "about:blank";
let markButton = SocialMark.button;
let tab = gBrowser.selectedTab = gBrowser.addTab(toMark);
let tabb = gBrowser.getBrowserForTab(tab);
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(!markButton.disabled, "SocialMark button not disabled for http url");
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(markButton.disabled, "SocialMark button disabled for about:blank");
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(!markButton.disabled, "SocialMark button re-enabled http url");
gBrowser.removeTab(tab);
executeSoon(testDisable);
}, true);
tabb.loadURI(toMark);
}, true);
tabb.loadURI(notSharable);
}, true);
}
function testDisable() {
let markButton = SocialMark.button;
Services.prefs.setBoolPref(prefName, false);
is(markButton.hidden, true, "SocialMark button should be hidden when pref is disabled");
gFinishCB();
}

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

@ -59,10 +59,6 @@ var tests = {
function checkUIStateMatchesProvider(provider) {
let profileData = getExpectedProfileData(provider);
// Bug 789863 - share button uses 'displayName', toolbar uses 'userName'
// Check the "share button"
let displayNameEl = document.getElementById("socialUserDisplayName");
is(displayNameEl.getAttribute("label"), profileData.displayName, "display name matches provider profile");
// The toolbar
let loginStatus = document.getElementsByClassName("social-statusarea-loggedInStatus");
for (let label of loginStatus) {

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

@ -1,328 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 prefName = "social.enabled",
gFinishCB;
function test() {
waitForExplicitFinish();
// Need to load a http/https/ftp/ftps page for the social share button to appear
let tab = gBrowser.selectedTab = gBrowser.addTab("https://example.com", {skipAnimation: true});
tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
tab.linkedBrowser.removeEventListener("load", tabLoad, true);
executeSoon(tabLoaded);
}, true);
registerCleanupFunction(function() {
Services.prefs.clearUserPref(prefName);
gBrowser.removeTab(tab);
});
}
function tabLoaded() {
ok(Social, "Social module loaded");
let manifest = { // normal provider
name: "provider 1",
origin: "https://example.com",
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
};
runSocialTestWithProvider(manifest, function (finishcb) {
gFinishCB = finishcb;
testInitial();
});
}
function testInitial(finishcb) {
ok(Social.provider, "Social provider is active");
ok(Social.provider.enabled, "Social provider is enabled");
let port = Social.provider.getWorkerPort();
ok(port, "Social provider has a port to its FrameWorker");
port.close();
let {shareButton, unsharePopup} = SocialShareButton;
ok(shareButton, "share button exists");
ok(unsharePopup, "share popup exists");
let okButton = document.getElementById("unsharePopupContinueSharingButton");
let undoButton = document.getElementById("unsharePopupStopSharingButton");
let shareStatusLabel = document.getElementById("share-button-status");
// 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 && 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;
let portrait = document.getElementById("socialUserPortrait").getAttribute("src");
is(profile.portrait, portrait, "portrait is set");
let displayName = document.getElementById("socialUserDisplayName");
is(displayName.label, profile.displayName, "display name is set");
ok(!document.getElementById("unsharePopupHeader").hidden, "user profile is visible");
// Check the strings from our worker actually ended up on the button.
is(shareButton.getAttribute("tooltiptext"), "Share this page", "check tooltip text is correct");
is(shareStatusLabel.getAttribute("value"), "", "check status label text is blank");
// Check the relative URL was resolved correctly (note this image has offsets of zero...)
is(shareButton.src, 'https://example.com/browser/browser/base/content/test/social/social_share_image.png', "check image url is correct");
// Test clicking the share button
shareButton.addEventListener("click", function listener() {
shareButton.removeEventListener("click", listener);
is(shareButton.hasAttribute("shared"), true, "Share button should have 'shared' attribute after share button is clicked");
is(shareButton.getAttribute("tooltiptext"), "Unshare this page", "check tooltip text is correct");
is(shareStatusLabel.getAttribute("value"), "This page has been shared", "check status label text is correct");
// Check the URL and offsets were applied correctly
is(shareButton.src, 'https://example.com/browser/browser/base/content/test/social/social_share_image.png', "check image url is correct");
executeSoon(testSecondClick.bind(window, testPopupOKButton));
});
shareButton.click();
}, "provider didn't provide user-recommend-prompt response");
}
function testSecondClick(nextTest) {
let {shareButton, unsharePopup} = SocialShareButton;
unsharePopup.addEventListener("popupshown", function listener() {
unsharePopup.removeEventListener("popupshown", listener);
ok(true, "popup was shown after second click");
executeSoon(nextTest);
});
shareButton.click();
}
function testPopupOKButton() {
let {shareButton, unsharePopup} = SocialShareButton;
let okButton = document.getElementById("unsharePopupContinueSharingButton");
unsharePopup.addEventListener("popuphidden", function listener() {
unsharePopup.removeEventListener("popuphidden", listener);
is(shareButton.hasAttribute("shared"), true, "Share button should still have 'shared' attribute after OK button is clicked");
executeSoon(testSecondClick.bind(window, testPopupUndoButton));
});
okButton.click();
}
function testPopupUndoButton() {
let {shareButton, unsharePopup} = SocialShareButton;
let undoButton = document.getElementById("unsharePopupStopSharingButton");
unsharePopup.addEventListener("popuphidden", function listener() {
unsharePopup.removeEventListener("popuphidden", listener);
is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' attribute after Undo button is clicked");
executeSoon(testShortcut);
});
undoButton.click();
}
function testShortcut() {
let keyTarget = window;
keyTarget.addEventListener("keyup", function listener() {
keyTarget.removeEventListener("keyup", listener);
executeSoon(checkShortcutWorked.bind(window, keyTarget));
});
EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
}
function checkShortcutWorked(keyTarget) {
let {unsharePopup, shareButton} = SocialShareButton;
is(shareButton.hasAttribute("shared"), true, "Share button should be in the 'shared' state after keyboard shortcut is used");
// Test a second invocation of the shortcut
unsharePopup.addEventListener("popupshown", function listener() {
unsharePopup.removeEventListener("popupshown", listener);
ok(true, "popup was shown after second use of keyboard shortcut");
executeSoon(checkOKButton);
});
EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
}
function checkOKButton() {
let okButton = document.getElementById("unsharePopupContinueSharingButton");
let undoButton = document.getElementById("unsharePopupStopSharingButton");
is(document.activeElement, okButton, "ok button should be focused by default");
// the undo button text, label text, access keys, etc should be as
// specified by the provider.
function isEltAttr(eltid, attr, expected) {
is(document.getElementById(eltid).getAttribute(attr), expected,
"element '" + eltid + "' has correct value for attribute '" + attr + "'");
}
isEltAttr("socialUserRecommendedText", "value", "You have already shared this page");
isEltAttr("unsharePopupContinueSharingButton", "label", "Got it!");
isEltAttr("unsharePopupContinueSharingButton", "accesskey", "G");
isEltAttr("unsharePopupStopSharingButton", "label", "Unshare it!");
isEltAttr("unsharePopupStopSharingButton", "accesskey", "U");
isEltAttr("socialUserPortrait", "aria-label", "Your pretty face");
// This rest of particular test doesn't really apply on Mac, since buttons
// aren't focusable by default.
if (navigator.platform.contains("Mac")) {
executeSoon(testCloseBySpace);
return;
}
let displayName = document.getElementById("socialUserDisplayName");
// Linux has the buttons in the [unshare] [ok] order, so displayName will come first.
if (navigator.platform.contains("Linux")) {
checkNextInTabOrder(displayName, function () {
checkNextInTabOrder(undoButton, function () {
checkNextInTabOrder(okButton, testCloseBySpace);
});
});
} else {
checkNextInTabOrder(undoButton, function () {
checkNextInTabOrder(displayName, function () {
checkNextInTabOrder(okButton, testCloseBySpace);
});
});
}
}
function checkNextInTabOrder(element, next) {
function listener() {
element.removeEventListener("focus", listener);
is(document.activeElement, element, element.id + " should be next in tab order");
executeSoon(next);
}
element.addEventListener("focus", listener);
// Register a cleanup function to remove the listener in case this test fails
registerCleanupFunction(function () {
element.removeEventListener("focus", listener);
});
EventUtils.synthesizeKey("VK_TAB", {});
}
function testCloseBySpace() {
let unsharePopup = SocialShareButton.unsharePopup;
is(document.activeElement.id, "unsharePopupContinueSharingButton", "testCloseBySpace, the ok button should be focused");
unsharePopup.addEventListener("popuphidden", function listener() {
unsharePopup.removeEventListener("popuphidden", listener);
ok(true, "space closed the share popup");
executeSoon(testStillSharedIn2Tabs);
});
EventUtils.synthesizeKey("VK_SPACE", {});
}
function testStillSharedIn2Tabs() {
let toShare = "http://example.com";
let {shareButton} = SocialShareButton;
let initialTab = gBrowser.selectedTab;
if (shareButton.hasAttribute("shared")) {
SocialShareButton.unsharePage();
}
is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' for the initial tab");
let tab1 = gBrowser.selectedTab = gBrowser.addTab(toShare);
let tab1b = gBrowser.getBrowserForTab(tab1);
tab1b.addEventListener("load", function tabLoad(event) {
tab1b.removeEventListener("load", tabLoad, true);
let tab2 = gBrowser.selectedTab = gBrowser.addTab(toShare);
let tab2b = gBrowser.getBrowserForTab(tab2);
tab2b.addEventListener("load", function tabLoad(event) {
tab2b.removeEventListener("load", tabLoad, true);
// should start without either page being shared.
is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' before we've done anything");
shareButton.click();
is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
// and switching to the first tab (with the same URL) should still reflect shared.
gBrowser.selectedTab = tab1;
is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
// but switching back the initial one should reflect not shared.
gBrowser.selectedTab = initialTab;
is(shareButton.hasAttribute("shared"), false, "Initial tab should not reflect shared");
gBrowser.selectedTab = tab1;
SocialShareButton.unsharePage();
gBrowser.removeTab(tab1);
gBrowser.removeTab(tab2);
executeSoon(testStillSharedAfterReopen);
}, true);
}, true);
}
function testStillSharedAfterReopen() {
let toShare = "http://example.com";
let {shareButton} = SocialShareButton;
is(shareButton.hasAttribute("shared"), false, "Reopen: Share button should not have 'shared' for the initial tab");
let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
let tabb = gBrowser.getBrowserForTab(tab);
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
SocialShareButton.sharePage();
is(shareButton.hasAttribute("shared"), true, "Share button should reflect the share");
gBrowser.removeTab(tab);
// should be on the initial unshared tab now.
is(shareButton.hasAttribute("shared"), false, "Initial tab should be selected and be unshared.");
// now open the same URL - should be back to shared.
tab = gBrowser.selectedTab = gBrowser.addTab(toShare, {skipAnimation: true});
tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
tab.linkedBrowser.removeEventListener("load", tabLoad, true);
executeSoon(function() {
is(shareButton.hasAttribute("shared"), true, "New tab to previously shared URL should reflect shared");
SocialShareButton.unsharePage();
gBrowser.removeTab(tab);
executeSoon(testOnlyShareCertainUrlsTabSwitch);
});
}, true);
}, true);
}
function testOnlyShareCertainUrlsTabSwitch() {
let toShare = "http://example.com";
let notSharable = "about:blank";
let {shareButton} = SocialShareButton;
let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
let tabb = gBrowser.getBrowserForTab(tab);
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(!shareButton.hidden, "share button not hidden for http url");
let tab2 = gBrowser.selectedTab = gBrowser.addTab(notSharable);
let tabb2 = gBrowser.getBrowserForTab(tab2);
tabb2.addEventListener("load", function tabLoad(event) {
tabb2.removeEventListener("load", tabLoad, true);
ok(shareButton.hidden, "share button hidden for about:blank");
gBrowser.selectedTab = tab;
ok(!shareButton.hidden, "share button re-shown when switching back to http: url");
gBrowser.selectedTab = tab2;
ok(shareButton.hidden, "share button re-hidden when switching back to about:blank");
gBrowser.removeTab(tab);
gBrowser.removeTab(tab2);
executeSoon(testOnlyShareCertainUrlsSameTab);
}, true);
}, true);
}
function testOnlyShareCertainUrlsSameTab() {
let toShare = "http://example.com";
let notSharable = "about:blank";
let {shareButton} = SocialShareButton;
let tab = gBrowser.selectedTab = gBrowser.addTab(toShare);
let tabb = gBrowser.getBrowserForTab(tab);
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(!shareButton.hidden, "share button not hidden for http url");
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(shareButton.hidden, "share button hidden for about:blank");
tabb.addEventListener("load", function tabLoad(event) {
tabb.removeEventListener("load", tabLoad, true);
ok(!shareButton.hidden, "share button re-enabled http url");
gBrowser.removeTab(tab);
executeSoon(testDisable);
}, true);
tabb.loadURI(toShare);
}, true);
tabb.loadURI(notSharable);
}, true);
}
function testDisable() {
let shareButton = SocialShareButton.shareButton;
Services.prefs.setBoolPref(prefName, false);
is(shareButton.hidden, true, "Share button should be hidden when pref is disabled");
gFinishCB();
}

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

@ -185,8 +185,10 @@ function checkSocialUI(win) {
isbool(win.SocialChatBar.isAvailable, enabled && Social.haveLoggedInUser(), "chatbar available?");
isbool(!win.SocialChatBar.chatbar.hidden, enabled && Social.haveLoggedInUser(), "chatbar visible?");
let canShare = enabled && provider.recommendInfo && Social.haveLoggedInUser() && win.SocialShareButton.canSharePage(win.gBrowser.currentURI)
isbool(!win.SocialShareButton.shareButton.hidden, canShare, "share button visible?");
let markVisible = enabled && provider.pageMarkInfo;
let canMark = markVisible && win.SocialMark.canMarkPage(win.gBrowser.currentURI);
isbool(!win.SocialMark.button.hidden, markVisible, "SocialMark button visible?");
isbool(!win.SocialMark.button.disabled, canMark, "SocialMark button enabled?");
isbool(!doc.getElementById("social-toolbar-item").hidden, active, "toolbar items visible?");
if (active)
is(win.SocialToolbar.button.style.listStyleImage, 'url("' + Social.defaultProvider.iconURL + '")', "toolbar button has provider icon");
@ -201,7 +203,7 @@ function checkSocialUI(win) {
isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
isbool(!doc.getElementById("Social:FocusChat").hidden, enabled && Social.haveLoggedInUser(), "Social:FocusChat visible?");
isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
is(doc.getElementById("Social:SharePage").getAttribute("disabled"), canShare ? "false" : "true", "Social:SharePage visible?");
is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
// broadcasters.
isbool(!doc.getElementById("socialActiveBroadcaster").hidden, active, "socialActiveBroadcaster hidden?");

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

До

Ширина:  |  Высота:  |  Размер: 934 B

После

Ширина:  |  Высота:  |  Размер: 934 B

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

@ -100,6 +100,23 @@ onconnect = function(e) {
};
}
port.postMessage({topic: "social.user-profile", data: profile});
port.postMessage({
topic: "social.page-mark-config",
data: {
images: {
// this one is relative to test we handle relative ones.
marked: "/browser/browser/base/content/test/social/social_mark_image.png",
// absolute to check we handle them too.
unmarked: "https://example.com/browser/browser/base/content/test/social/social_mark_image.png"
},
messages: {
unmarkedTooltip: "Mark this page",
markedTooltip: "Unmark this page",
unmarkedLabel: "Mark",
markedLabel: "Unmark",
}
}
});
break;
case "test-ambient-notification":
let icon = {
@ -116,31 +133,6 @@ onconnect = function(e) {
case "test-isVisible-response":
testPort.postMessage({topic: "got-isVisible-response", result: event.data.result});
break;
case "social.user-recommend-prompt":
port.postMessage({
topic: "social.user-recommend-prompt-response",
data: {
images: {
// this one is relative to test we handle relative ones.
share: "browser/browser/base/content/test/social/social_share_image.png",
// absolute to check we handle them too.
unshare: "https://example.com/browser/browser/base/content/test/social/social_share_image.png"
},
messages: {
shareTooltip: "Share this page",
unshareTooltip: "Unshare this page",
sharedLabel: "This page has been shared",
unsharedLabel: "This page is no longer shared",
unshareLabel: "You have already shared this page",
portraitLabel: "Your pretty face",
unshareConfirmLabel: "Unshare it!",
unshareConfirmAccessKey: "U",
unshareCancelLabel: "Got it!",
unshareCancelAccessKey: "G"
}
}
});
break;
}
}
}

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

@ -308,6 +308,7 @@ function runTest(testNum) {
"context-openlink", true,
"---", null,
"context-bookmarklink", true,
"context-marklink", true,
"context-savelink", true,
"context-copylink", true
].concat(inspectItems));
@ -808,6 +809,7 @@ function runTest(testNum) {
"context-openlink", true,
"---", null,
"context-bookmarklink", true,
"context-marklink", true,
"context-savelink", true,
"context-copy", true,
"context-selectall", true,
@ -849,6 +851,7 @@ function runTest(testNum) {
"context-openlink", true,
"---", null,
"context-bookmarklink", true,
"context-marklink", true,
"context-savelink", true,
"context-copylink", true,
"---", null,

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

@ -115,7 +115,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY bookmarksMenu.accesskey "B">
<!ENTITY bookmarkThisPageCmd.label "Bookmark This Page">
<!ENTITY bookmarkThisPageCmd.commandkey "d">
<!ENTITY sharePageCmd.commandkey "l">
<!ENTITY markPageCmd.commandkey "l">
<!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
<!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
<!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
@ -643,6 +643,11 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY social.chatBar.label "Focus chats">
<!ENTITY social.chatBar.accesskey "c">
<!ENTITY social.markpage.label "Mark This Page">
<!ENTITY social.markpage.accesskey "m">
<!ENTITY social.marklink.label "Unmark This Page">
<!ENTITY social.marklink.accesskey "M">
<!ENTITY getUserMedia.selectCamera.label "Camera to share:">
<!ENTITY getUserMedia.selectCamera.accesskey "C">
<!ENTITY getUserMedia.selectMicrophone.label "Microphone to share:">

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

@ -386,6 +386,13 @@ social.turnOff.accesskey=T
social.turnOn.label=Turn on %S
social.turnOn.accesskey=T
# LOCALIZATION NOTE (social.markpage.label): %S is the name of the social provider
social.markpage.label=Send Page to %S
social.unmarkpage.label=Remove Page from %S
# LOCALIZATION NOTE (social.marklink.label): %S is the name of the social provider
social.marklink.label=Send Link to %S
social.unmarklink.label=Remove Link from %S
# LOCALIZATION NOTE (social.error.message): %1$S is brandShortName (e.g. Firefox), %2$S is the name of the social provider
social.error.message=%1$S is unable to connect with %2$S right now.
social.error.tryAgain.label=Try Again

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

@ -15,6 +15,10 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
"resource://gre/modules/SocialService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
// Add a pref observer for the enabled state
function prefObserver(subject, topic, data) {
@ -32,6 +36,46 @@ Services.obs.addObserver(function xpcomShutdown() {
Services.prefs.removeObserver("social.enabled", prefObserver);
}, "xpcom-shutdown", false);
function promiseSetAnnotation(aURI, providerList) {
let deferred = Promise.defer();
// Delaying to catch issues with asynchronous behavior while waiting
// to implement asynchronous annotations in bug 699844.
Services.tm.mainThread.dispatch(function() {
try {
if (providerList && providerList.length > 0) {
PlacesUtils.annotations.setPageAnnotation(
aURI, "social/mark", JSON.stringify(providerList), 0,
PlacesUtils.annotations.EXPIRE_WITH_HISTORY);
} else {
PlacesUtils.annotations.removePageAnnotation(aURI, "social/mark");
}
} catch(e) {
Cu.reportError("SocialAnnotation failed: " + e);
}
deferred.resolve();
}, Ci.nsIThread.DISPATCH_NORMAL);
return deferred.promise;
}
function promiseGetAnnotation(aURI) {
let deferred = Promise.defer();
// Delaying to catch issues with asynchronous behavior while waiting
// to implement asynchronous annotations in bug 699844.
Services.tm.mainThread.dispatch(function() {
let val = null;
try {
val = PlacesUtils.annotations.getPageAnnotation(aURI, "social/mark");
} catch (ex) { }
deferred.resolve(val);
}, Ci.nsIThread.DISPATCH_NORMAL);
return deferred.promise;
}
this.Social = {
initialized: false,
lastEventReceived: 0,
@ -213,8 +257,8 @@ this.Social = {
SocialService.removeProvider(origin);
},
// Sharing functionality
_getShareablePageUrl: function Social_getShareablePageUrl(aURI) {
// Page Marking functionality
_getMarkablePageUrl: function Social_getMarkablePageUrl(aURI) {
let uri = aURI.clone();
try {
// Setting userPass on about:config throws.
@ -223,52 +267,96 @@ this.Social = {
return uri.spec;
},
isPageShared: function Social_isPageShared(aURI) {
let url = this._getShareablePageUrl(aURI);
return this._sharedUrls.hasOwnProperty(url);
isURIMarked: function(aURI, aCallback) {
promiseGetAnnotation(aURI).then(function(val) {
if (val) {
let providerList = JSON.parse(val);
val = providerList.indexOf(this.provider.origin) >= 0;
}
aCallback(!!val);
}.bind(this));
},
sharePage: function Social_sharePage(aURI) {
markURI: function(aURI, aCallback) {
// this should not be called if this.provider or the port is null
if (!this.provider) {
Cu.reportError("Can't share a page when no provider is current");
Cu.reportError("Can't mark a page when no provider is current");
return;
}
let port = this.provider.getWorkerPort();
if (!port) {
Cu.reportError("Can't share page as no provider port is available");
Cu.reportError("Can't mark page as no provider port is available");
return;
}
let url = this._getShareablePageUrl(aURI);
this._sharedUrls[url] = true;
port.postMessage({
topic: "social.user-recommend",
data: { url: url }
});
port.close();
},
unsharePage: function Social_unsharePage(aURI) {
// update or set our annotation
promiseGetAnnotation(aURI).then(function(val) {
let providerList = val ? JSON.parse(val) : [];
let marked = providerList.indexOf(this.provider.origin) >= 0;
if (marked)
return;
providerList.push(this.provider.origin);
// we allow marking links in a page that may not have been visited yet.
// make sure there is a history entry for the uri, then annotate it.
let place = {
uri: aURI,
visits: [{
visitDate: Date.now() + 1000,
transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
}]
};
PlacesUtils.asyncHistory.updatePlaces(place, {
handleError: function () Cu.reportError("couldn't update history for socialmark annotation"),
handleResult: function () {},
handleCompletion: function () {
promiseSetAnnotation(aURI, providerList).then();
// post to the provider
let url = this._getMarkablePageUrl(aURI);
port.postMessage({
topic: "social.page-mark",
data: { url: url, 'marked': true }
});
port.close();
if (aCallback)
aCallback(true);
}.bind(this)
});
}.bind(this));
},
unmarkURI: function(aURI, aCallback) {
// this should not be called if this.provider or the port is null
if (!this.provider) {
Cu.reportError("Can't unshare a page when no provider is current");
Cu.reportError("Can't mark a page when no provider is current");
return;
}
let port = this.provider.getWorkerPort();
if (!port) {
Cu.reportError("Can't unshare page as no provider port is available");
Cu.reportError("Can't mark page as no provider port is available");
return;
}
let url = this._getShareablePageUrl(aURI);
delete this._sharedUrls[url];
port.postMessage({
topic: "social.user-unrecommend",
data: { url: url }
});
port.close();
},
_sharedUrls: {},
// set our annotation
promiseGetAnnotation(aURI).then(function(val) {
let providerList = val ? JSON.parse(val) : [];
let marked = providerList.indexOf(this.provider.origin) >= 0;
if (marked) {
// remove the annotation
providerList.splice(providerList.indexOf(this.provider.origin), 1);
promiseSetAnnotation(aURI, providerList).then();
}
// post to the provider regardless
let url = this._getMarkablePageUrl(aURI);
port.postMessage({
topic: "social.page-mark",
data: { url: url, 'marked': false }
});
port.close();
if (aCallback)
aCallback(false);
}.bind(this));
},
setErrorListener: function(iframe, errorHandler) {
if (iframe.socialErrorListener)

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

@ -1434,80 +1434,10 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
/* social recommending panel */
#share-button {
#social-mark-button {
-moz-image-region: rect(0, 16px, 16px, 0);
}
#socialUserPortrait {
width: 48px;
height: 48px;
list-style-image:url("chrome://global/skin/icons/information-32.png");
}
#socialUserDisplayName,
#socialUserPortrait {
cursor: pointer;
}
#socialUserDisplayName {
-moz-appearance: none;
border: none;
background-color: transparent;
margin-top: 0;
padding-top: 0;
font-size: 130%;
font-weight: bold;
}
#socialUserDisplayName > .button-box {
-moz-padding-start: 0;
padding-top: 0;
border-top-width: 0;
}
#socialUserDisplayName:hover {
color: -moz-nativehyperlinktext;
text-decoration: underline;
}
#unsharePopupText {
height: 48px;
}
#unsharePopupBottomButtons {
margin-top: 1em;
}
/* bookmarks menu-button */
#bookmarks-menu-button {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0px 216px 24px 192px);
}
#bookmarks-menu-button[starred] {
-moz-image-region: rect(24px 216px 48px 192px);
}
toolbar[iconsize="small"] #bookmarks-menu-button,
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-moz-image-region: rect(0px 144px 16px 128px);
}
toolbar[iconsize="small"] #bookmarks-menu-button[starred],
#bookmarks-menu-button.bookmark-item[starred] {
-moz-image-region: rect(16px 144px 32px 128px);
}
#bookmarks-menu-button[disabled] > .toolbarbutton-icon,
#bookmarks-menu-button[disabled] > .toolbarbutton-menu-dropmarker,
#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-dropmarker,
#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
#bookmarks-menu-button > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
opacity: .4;
}
/* Bookmarking panel */
#editBookmarkPanelStarIcon {
list-style-image: url("chrome://browser/skin/places/starred48.png");

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

@ -1657,65 +1657,10 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
/* social recommending panel */
#share-button {
#social-mark-button {
-moz-image-region: rect(0, 16px, 16px, 0);
}
#socialUserPortrait {
width: 48px;
height: 48px;
list-style-image:url("chrome://global/skin/icons/information-32.png");
}
#socialUserDisplayName,
#socialUserPortrait {
cursor: pointer;
}
#socialUserDisplayName {
-moz-appearance: none;
border: none;
background-color: transparent;
margin: 1px;
padding: 0;
font-size: 130%;
font-weight: bold;
}
#socialUserDisplayName > .button-box {
-moz-padding-start: 0;
padding-top: 0;
border-top-width: 0;
}
#socialUserDisplayName:hover {
color: -moz-nativehyperlinktext;
text-decoration: underline;
}
#unsharePopupText {
height: 48px;
}
#unsharePopupBottomButtons {
margin-top: 1em;
}
/* bookmarks menu-button */
#bookmarks-menu-button {
-moz-image-region: rect(0px 500px 20px 480px);
}
#bookmarks-menu-button[starred] {
-moz-image-region: rect(20px 500px 40px 480px);
}
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/places/star-icons.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#bookmarks-menu-button.bookmark-item[starred] {
-moz-image-region: rect(0px 32px 16px 16px);
}

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

@ -1706,65 +1706,10 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
/* social recommending panel */
#share-button {
#social-mark-button {
-moz-image-region: rect(0, 16px, 16px, 0);
}
#socialUserPortrait {
width: 48px;
height: 48px;
list-style-image:url("chrome://global/skin/icons/information-32.png");
}
#socialUserDisplayName,
#socialUserPortrait {
cursor: pointer;
}
#socialUserDisplayName {
-moz-appearance: none;
border: none;
background-color: transparent;
margin-top: 0;
padding-top: 0;
font-size: 130%;
font-weight: bold;
}
#socialUserDisplayName > .button-box {
-moz-padding-start: 0;
padding-top: 0;
border-top-width: 0;
}
#socialUserDisplayName:hover {
color: -moz-nativehyperlinktext;
text-decoration: underline;
}
#unsharePopupText {
height: 48px;
}
#unsharePopupBottomButtons {
margin-top: 1em;
}
/* bookmarks menu-button */
#bookmarks-menu-button {
-moz-image-region: rect(0px 378px 18px 360px);
}
#bookmarks-menu-button[starred] {
-moz-image-region: rect(18px 378px 36px 360px);
}
#bookmarks-menu-button.bookmark-item {
list-style-image: url("chrome://browser/skin/places/bookmark.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#bookmarks-menu-button.bookmark-item[starred] {
-moz-image-region: rect(0px 48px 16px 32px);
}

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

@ -627,25 +627,24 @@ 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.
// Contains the information necessary to support our page mark 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;
// the 'pageMarkInfo' setter and returned via the getter.
_pageMarkInfo: null,
get pageMarkInfo() {
return this._pageMarkInfo;
},
set recommendInfo(data) {
// Accept *and validate* the user-recommend-prompt-response message from
// the provider.
set pageMarkInfo(data) {
// Accept *and validate* the page-mark-config 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
Cu.reportError("Invalid page-mark data from provider: " + reason + ": marking is disabled for this provider");
// and we explicitly reset the page-mark 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);
this._pageMarkInfo = null;
Services.obs.notifyObservers(null, "social:page-mark-config", this.origin);
}
if (!data ||
!data.images || typeof data.images != "object" ||
@ -653,10 +652,10 @@ SocialProvider.prototype = {
reportError("data is missing valid 'images' or 'messages' elements");
return;
}
for (let sub of ["share", "unshare"]) {
for (let sub of ["marked", "unmarked"]) {
let url = data.images[sub];
if (!url || typeof url != "string" || url.length == 0) {
reportError('images["' + sub + '"] is missing or not a non-empty string');
reportError('images["' + sub + '"] is not a valid string');
return;
}
// resolve potentially relative URLs but there is no same-origin check
@ -670,19 +669,15 @@ SocialProvider.prototype = {
}
promptImages[sub] = imgUri.spec;
}
for (let sub of ["shareTooltip", "unshareTooltip",
"sharedLabel", "unsharedLabel", "unshareLabel",
"portraitLabel",
"unshareConfirmLabel", "unshareConfirmAccessKey",
"unshareCancelLabel", "unshareCancelAccessKey"]) {
for (let sub of ["markedTooltip", "unmarkedTooltip", "markedLabel", "unmarkedLabel"]) {
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);
this._pageMarkInfo = {images: promptImages, messages: promptMessages};
Services.obs.notifyObservers(null, "social:page-mark-config", this.origin);
},
// Map of objects describing the provider's notification icons, whose

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

@ -58,14 +58,12 @@ 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.page-mark-config": function(data) {
this._provider.pageMarkInfo = data;
},
"social.cookies-get": function(data) {
let document = this._port._window.document;