Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-12-03 12:11:24 +01:00
Родитель bc529ded47 df451fe7b0
Коммит 4f04da8f11
834 изменённых файлов: 13126 добавлений и 12494 удалений

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

@ -57,7 +57,11 @@ xulrunner/**
# browser/ exclusions
browser/app/**
browser/base/**
browser/base/content/browser-social.js
browser/base/content/nsContextMenu.js
browser/base/content/sanitizeDialog.js
browser/base/content/test/**
browser/base/content/newtab/**
browser/components/customizableui/**
browser/components/downloads/**
browser/components/feeds/**

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

@ -716,11 +716,6 @@
@RESPATH@/components/PrivateBrowsing.manifest
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
; GNOME hooks
#ifdef MOZ_ENABLE_GNOME_COMPONENT
@RESPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
#endif
; Signed Packaged Content
@RESPATH@/components/InstallPackagedWebapp.manifest
@RESPATH@/components/InstallPackagedWebapp.js

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

@ -1,6 +1,5 @@
{
// When adding items to this file please check for effects on sub-directories.
"rules": {
"eol-last": 2,
}
"extends": [
"../toolkit/.eslintrc"
]
}

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

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1447879967000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1449088954000">
<emItems>
<emItem blockID="i58" id="webmaster@buzzzzvideos.info">
<versionRange minVersion="0" maxVersion="*">
@ -122,6 +122,12 @@
<prefs>
<pref>browser.search.defaultenginename</pref>
</prefs>
</emItem>
<emItem blockID="i1058" id="amo-validator-bypass@example.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
<prefs>
</prefs>
</emItem>
<emItem blockID="i140" id="mozillahmpg@mozilla.org">
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -449,7 +455,7 @@
</prefs>
</emItem>
<emItem blockID="i1056" id="{82AF8DCA-6DE9-405D-BD5E-43525BDAD38A}">
<versionRange minVersion="0" maxVersion="7.5.0.9082" severity="1">
<versionRange minVersion="0" maxVersion="*" severity="1">
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
<versionRange minVersion="43.0a1" maxVersion="*" />
</targetApplication>
@ -463,7 +469,7 @@
<prefs>
</prefs>
</emItem>
<emItem blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
<emItem blockID="i748" id="{32da2f20-827d-40aa-a3b4-2fc4a294352e}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
<prefs>
@ -2386,7 +2392,7 @@
<pref>browser.search.defaultenginename</pref>
</prefs>
</emItem>
<emItem blockID="i748" id="{32da2f20-827d-40aa-a3b4-2fc4a294352e}">
<emItem blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
<prefs>
@ -3309,6 +3315,30 @@
<match name="filename" exp="DirectorShockwave\.plugin" /> <versionRange minVersion="0" maxVersion="12.2.0.162" severity="0" vulnerabilitystatus="1"></versionRange>
<infoURL>https://get.adobe.com/shockwave/</infoURL>
</pluginItem>
<pluginItem blockID="p1059">
<match name="filename" exp="JavaAppletPlugin\.plugin" /> <versionRange minVersion="Java 7 Update 81" maxVersion="Java 7 Update 90" severity="0" vulnerabilitystatus="1"></versionRange>
<infoURL>https://java.com/</infoURL>
</pluginItem>
<pluginItem blockID="p1060">
<match name="filename" exp="JavaAppletPlugin\.plugin" /> <versionRange minVersion="Java 8 Update 46" maxVersion="Java 8 Update 64" severity="0" vulnerabilitystatus="1"></versionRange>
<infoURL>https://java.com/</infoURL>
</pluginItem>
<pluginItem blockID="p1061">
<match name="name" exp="Java\(TM\) Platform SE 7 U(8[1-9]|90)(\s[^\d\._U]|$)" /> <match name="filename" exp="npjp2\.dll" /> <versionRange severity="0" vulnerabilitystatus="1"></versionRange>
<infoURL>https://java.com/</infoURL>
</pluginItem>
<pluginItem blockID="p1062">
<match name="name" exp="Java\(TM\) Platform SE 8 U(4[6-9]|5\d|6[0-4])(\s[^\d\._U]|$)" /> <match name="filename" exp="npjp2\.dll" /> <versionRange severity="0" vulnerabilitystatus="1"></versionRange>
<infoURL>https://java.com/</infoURL>
</pluginItem>
<pluginItem blockID="p1063">
<match name="name" exp="Java(\(TM\))? Plug-in 10\.(8[1-9]|90)(\.[0-9]+)?([^\d\._]|$)" /> <match name="filename" exp="libnpjp2\.so" /> <versionRange severity="0" vulnerabilitystatus="1"></versionRange>
<infoURL>https://java.com/</infoURL>
</pluginItem>
<pluginItem blockID="p1064">
<match name="name" exp="Java(\(TM\))? Plug-in 11\.(4[6-9]|5\d|6[0-4])(\.[0-9]+)?([^\d\._]|$)" /> <match name="filename" exp="libnpjp2\.so" /> <versionRange severity="0" vulnerabilitystatus="1"></versionRange>
<infoURL>https://java.com/</infoURL>
</pluginItem>
</pluginItems>
<gfxItems>

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

@ -1471,6 +1471,11 @@ pref("identity.fxaccounts.profile_image.enabled", true);
// Token server used by the FxA Sync identity.
pref("identity.sync.tokenserver.uri", "https://token.services.mozilla.com/1.0/sync/1.5");
// URLs for promo links to mobile browsers. Note that consumers are expected to
// append a value for utm_campaign.
pref("identity.mobilepromo.android", "https://www.mozilla.org/firefox/android/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=");
pref("identity.mobilepromo.ios", "https://www.mozilla.org/firefox/ios/?utm_source=firefox-browser&utm_medium=firefox-browser&utm_campaign=");
// Migrate any existing Firefox Account data from the default profile to the
// Developer Edition profile.
#ifdef MOZ_DEV_EDITION

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

@ -109,14 +109,25 @@
function showCertificateErrorReporting() {
// Display error reporting UI
document.getElementById('certificateErrorReporting').style.display = 'block';
}
function showAdvancedButton(allowOverride) {
// Display weak crypto advanced UI
document.getElementById("buttonContainer").style.display = "flex";
document.getElementById("advancedButton").style.display = "block";
document.getElementById("errorTryAgain").style.display = "none";
// Get the hostname and add it to the panel
document.getElementById('hostname').textContent = document.location.hostname;
var panel = document.getElementById("weakCryptoAdvancedPanel");
for (var span of panel.querySelectorAll("span.hostname")) {
span.textContent = document.location.hostname;
}
panel.replaceChild(document.getElementById("errorLongDesc"),
document.getElementById("advancedLongDesc"));
// Register click handler for the certificateErrorReportingPanel
document.getElementById('showCertificateErrorReportingPanel')
.addEventListener('click', function togglePanelVisibility() {
var panel = document.getElementById('certificateErrorReportingPanel');
// Register click handler for the weakCryptoAdvancedPanel
document.getElementById("advancedButton")
.addEventListener("click", function togglePanelVisibility() {
toggleDisplay(panel);
if (panel.style.display == "block") {
@ -125,24 +136,12 @@
document.dispatchEvent(event);
}
});
}
function showWeakCryptoAdvanced() {
// Display weak crypto advanced UI
document.getElementById("weakCryptoAdvanced").style.display = "block";
// Get the hostname and add it to the panel
var panel = document.getElementById("weakCryptoAdvancedPanel");
for (var span of panel.querySelectorAll("span.hostname")) {
span.textContent = document.location.hostname;
if (allowOverride) {
document.getElementById("overrideWeakCryptoPanel").style.display = "flex";
var overrideLink = document.getElementById("overrideWeakCrypto");
overrideLink.addEventListener("click", () => doOverride(overrideLink), false);
}
// Register click handler for the weakCryptoAdvancedPanel
document.getElementById("showWeakCryptoAdvancedPanel")
.addEventListener("click", () => toggleDisplay(panel));
var overrideLink = document.getElementById("overrideWeakCrypto");
overrideLink.addEventListener("click", () => doOverride(overrideLink), false);
}
function sendErrorReport() {
@ -186,23 +185,16 @@
}
if (err == "sslv3Used") {
var learnMoreText = document.getElementById("learn_more_ssl3");
document.getElementById("errorTitle").setAttribute("sslv3", "true");
var retryBtn = document.getElementById("errorTryAgain");
retryBtn.textContent = learnMoreText.textContent;
retryBtn.setAttribute("onclick", "learnMoreSSLV3()");
document.getElementById("errorTryAgain").style.display = "none";
document.getElementById("learnMoreContainer").style.display = "block";
var learnMoreLink = document.getElementById("learnMoreLink");
learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-sslv3-error-messages-firefox";
document.getElementById("buttonContainer").style.display = "flex";
}
if (err == "weakCryptoUsed") {
var learnMoreText = document.getElementById("learn_more_weak_crypto");
document.getElementById("errorTitle").setAttribute("weakCrypto", "true");
var retryBtn = document.getElementById("errorTryAgain");
retryBtn.textContent = learnMoreText.textContent;
retryBtn.setAttribute("onclick", "learnMoreWeakCrypto()");
}
// remove undisplayed errors to avoid bug 39098
@ -243,13 +235,17 @@
window.addEventListener("AboutNetErrorOptions", function(evt) {
// Pinning errors are of type nssFailure2
if (getErrorCode() == "nssFailure2") {
if (getErrorCode() == "nssFailure2" || getErrorCode() == "weakCryptoUsed") {
document.getElementById("learnMoreContainer").style.display = "block";
var learnMoreLink = document.getElementById("learnMoreLink");
// nssFailure2 also gets us other non-overrideable errors. Choose
// a "learn more" link based on description:
if (getDescription().includes("mozilla_pkix_error_key_pinning_failure")) {
learnMoreLink.href = "https://support.mozilla.org/kb/certificate-pinning-reports";
}
if (getErrorCode() == "weakCryptoUsed") {
learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-weak-crypto-error-messages-firefox";
}
var options = JSON.parse(evt.detail);
if (options && options.enabled) {
@ -264,6 +260,9 @@
var event = new CustomEvent("AboutNetErrorSetAutomatic",
{bubbles:true, detail:evt.target.checked});
document.dispatchEvent(event);
if (evt.target.checked && reportBtn.style.display != "none") {
sendErrorReport();
}
}, false);
var reportBtn = document.getElementById('reportCertificateError');
@ -273,8 +272,8 @@
retryBtn.addEventListener('click', sendErrorReport, false);
}
}
if (getErrorCode() == "weakCryptoUsed") {
showWeakCryptoAdvanced();
if (getErrorCode() == "weakCryptoUsed" || getErrorCode() == "sslv3Used") {
showAdvancedButton(getErrorCode() == "weakCryptoUsed");
}
}.bind(this), true, true);
@ -381,18 +380,6 @@
function endsWith(haystack, needle) {
return haystack.slice(-needle.length) == needle;
}
function learnMoreSSLV3() {
location.href = "https://support.mozilla.org/kb/how-resolve-sslv3-error-messages-firefox";
// Ensure users don't re-click the button:
e.target.disabled = true;
}
function learnMoreWeakCrypto() {
location.href = "https://support.mozilla.org/kb/how-resolve-weak-crypto-error-messages-firefox";
// Ensure users don't re-click the button:
e.target.disabled = true;
}
]]></script>
</head>
@ -458,9 +445,7 @@
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
<div id="ed_sslv3Used">&sslv3Used.longDesc;</div>
<div id="learn_more_ssl3">&sslv3Used.learnMore;</div>
<div id="ed_weakCryptoUsed">&weakCryptoUsed.longDesc;</div>
<div id="learn_more_weak_crypto">&weakCryptoUsed.learnMore;</div>
</div>
</div>
@ -490,9 +475,17 @@
<div id="securityOverrideContent" style="display: none;">&securityOverride.warningContent;</div>
</div>
<div id="learnMoreContainer">
<p><a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&errorReporting.learnMore;</a></p>
</div>
<div id="buttonContainer">
<button id="returnButton" autocomplete="off" autofocus="true">&returnToPreviousPage.label;</button>
<div id="buttonSpacer"></div>
<button id="advancedButton" autocomplete="off" autofocus="true">&advanced.label;</button>
</div>
</div>
<!-- Retry Button -->
<button id="errorTryAgain" autocomplete="off" onclick="retryThis(this);">&retry.label;</button>
<script>
// Only do autofocus if we're the toplevel frame; otherwise we
@ -513,38 +506,24 @@
<!-- UI for option to report certificate errors to Mozilla. Removed on
init for other error types .-->
<div id="certificateErrorReporting">
<a id="showCertificateErrorReportingPanel" href="#">&errorReporting.title;<span class="downArrow"></span></a>
</div>
<p>
<input type="checkbox" id="automaticallyReportInFuture" />
<label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
<div id="certificateErrorReportingPanel">
<div id="certificateErrorReportingDescription">
<p>&errorReporting.longDesc;</p>
<p>
<input type="checkbox" id="automaticallyReportInFuture" />
<label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label>
</p>
</div>
<div id="errorStatePanel">
<a href="https://support.mozilla.org/kb/tls-error-reports" id="learnMoreLink" target="new">&errorReporting.learnMore;</a>
<span id="reportingState">
<button id="reportCertificateError">&errorReporting.report;</button>
<button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
<span id="reportSendingMessage">&errorReporting.sending;</span>
<span id="reportSentMessage">&errorReporting.sent;</span>
</span>
</div>
</div>
<!-- UI for option to override weak crypto errors. Removed on
init for other error types .-->
<div id="weakCryptoAdvanced">
<a id="showWeakCryptoAdvancedPanel" href="#">&weakCryptoAdvanced.title;<span class="downArrow"> &#x25bc;</span></a>
</p>
</div>
<div id="weakCryptoAdvancedPanel">
<div id="weakCryptoAdvancedDescription">
<p>&weakCryptoAdvanced.longDesc;</p>
</div>
<div id="advancedLongDesc" />
<div id="overrideWeakCryptoPanel">
<a id="overrideWeakCrypto" href="#">&weakCryptoAdvanced.override;</a>
</div>

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

@ -255,4 +255,4 @@ var AboutTabCrashed = {
},
};
AboutTabCrashed.init();
AboutTabCrashed.init();

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

@ -255,7 +255,7 @@ var gGestureSupport = {
* Source array containing any number of elements
* @yield Array that is a subset of the input array from full set to empty
*/
_power: function GS__power(aArray) {
_power: function* GS__power(aArray) {
// Create a bitmask based on the length of the array
let num = 1 << aArray.length;
while (--num >= 0) {

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

@ -367,9 +367,9 @@
<menuseparator id="sanitizeSeparator"/>
<menuitem id="sync-tabs-menuitem"
class="syncTabsMenuItem"
label="&syncTabsMenu2.label;"
label="&syncTabsMenu3.label;"
oncommand="BrowserOpenSyncTabs();"
disabled="true"/>
hidden="true"/>
<menuitem id="historyRestoreLastSession"
label="&historyRestoreLastSession.label;"
command="Browser:RestoreLastSession"/>

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

@ -177,6 +177,14 @@
<broadcaster id="isFrameImage"/>
<broadcaster id="singleFeedMenuitemState" disabled="true"/>
<broadcaster id="multipleFeedsMenuState" hidden="true"/>
<!-- Sync broadcasters -->
<!-- A broadcaster of a number of attributes suitable for "sync now" UI -
A 'syncstatus' attribute is set while actively syncing, and the label
attribute which changes from "sync now" to "syncing" etc. -->
<broadcaster id="sync-status"/>
<!-- broadcasters of the "hidden" attribute to reflect setup state for
menus -->
<broadcaster id="sync-setup-state"/>
<broadcaster id="sync-syncnow-state" hidden="true"/>
<broadcaster id="sync-reauth-state" hidden="true"/>

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

@ -77,6 +77,10 @@ var gSyncUI = {
Services.obs.addObserver(this, topic, true);
}, this);
// initial label for the sync buttons.
let broadcaster = document.getElementById("sync-status");
broadcaster.setAttribute("label", this._stringBundle.GetStringFromName("syncnow.label"));
this.updateUI();
},
@ -176,14 +180,10 @@ var gSyncUI = {
this.log.debug("onActivityStart with numActive", this._numActiveSyncTasks);
if (++this._numActiveSyncTasks == 1) {
let button = document.getElementById("sync-button");
if (button) {
button.setAttribute("status", "active");
}
let container = document.getElementById("PanelUI-footer-fxa");
if (container) {
container.setAttribute("syncstatus", "active");
}
let broadcaster = document.getElementById("sync-status");
broadcaster.setAttribute("syncstatus", "active");
broadcaster.setAttribute("label", this._stringBundle.GetStringFromName("syncing.label"));
broadcaster.setAttribute("disabled", "true");
}
this.updateUI();
},
@ -203,14 +203,10 @@ var gSyncUI = {
return; // active tasks are still ongoing...
}
let syncButton = document.getElementById("sync-button");
if (syncButton) {
syncButton.removeAttribute("status");
}
let fxaContainer = document.getElementById("PanelUI-footer-fxa");
if (fxaContainer) {
fxaContainer.removeAttribute("syncstatus");
}
let broadcaster = document.getElementById("sync-status");
broadcaster.removeAttribute("syncstatus");
broadcaster.removeAttribute("disabled");
broadcaster.setAttribute("label", this._stringBundle.GetStringFromName("syncnow.label"));
this.updateUI();
},
@ -313,8 +309,25 @@ var gSyncUI = {
gFxAccounts.openSignInAgainPage(entryPoint);
},
/* Update the tooltip for the Sync Toolbar button and the Sync spinner in the
FxA hamburger area.
openSyncedTabsPanel() {
let placement = CustomizableUI.getPlacementOfWidget("sync-button");
let area = placement ? placement.area : CustomizableUI.AREA_NAVBAR;
let anchor = document.getElementById("sync-button") ||
document.getElementById("PanelUI-menu-button");
if (area == CustomizableUI.AREA_PANEL) {
// The button is in the panel, so we need to show the panel UI, then our
// subview.
PanelUI.show().then(() => {
PanelUI.showSubView("PanelUI-remotetabs", anchor, area);
}).catch(Cu.reportError);
} else {
// It is placed somewhere else - just try and show it.
PanelUI.showSubView("PanelUI-remotetabs", anchor, area);
}
},
/* Update the tooltip for the sync-status broadcaster (which will update the
Sync Toolbar button and the Sync spinner in the FxA hamburger area.)
If Sync is configured, the tooltip is when the last sync occurred,
otherwise the tooltip reflects the fact that Sync needs to be
(re-)configured.
@ -364,16 +377,13 @@ var gSyncUI = {
// sure it hasn't been torn down since we started.
if (!gBrowser)
return;
let syncButton = document.getElementById("sync-button");
let statusButton = document.getElementById("PanelUI-fxa-icon");
for (let button of [syncButton, statusButton]) {
if (button) {
if (tooltiptext) {
button.setAttribute("tooltiptext", tooltiptext);
} else {
button.removeAttribute("tooltiptext");
}
let broadcaster = document.getElementById("sync-status");
if (broadcaster) {
if (tooltiptext) {
broadcaster.setAttribute("tooltiptext", tooltiptext);
} else {
broadcaster.removeAttribute("tooltiptext");
}
}
}),

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

@ -218,7 +218,7 @@ var TrackingProtection = {
];
let panelTarget = yield UITour.getTarget(window, "trackingProtection");
UITour.initForBrowser(gBrowser.selectedBrowser);
UITour.initForBrowser(gBrowser.selectedBrowser, window);
UITour.showInfo(window, mm, panelTarget,
gNavigatorBundle.getString("trackingProtection.intro.title"),
gNavigatorBundle.getFormattedString("trackingProtection.intro.description",

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

@ -1136,6 +1136,7 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
/* Apply crisp rendering for favicons at exactly 2dppx resolution */
@media (resolution: 2dppx) {
#PanelUI-remotetabs-tabslist > toolbarbutton > .toolbarbutton-icon,
#PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon,
#PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon,
#PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon {

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

@ -2663,6 +2663,7 @@ var BrowserOnClick = {
mm.addMessageListener("Browser:SetSSLErrorReportAuto", this);
mm.addMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.addMessageListener("Browser:OverrideWeakCrypto", this);
mm.addMessageListener("Browser:SSLErrorGoBack", this);
},
uninit: function () {
@ -2674,6 +2675,7 @@ var BrowserOnClick = {
mm.removeMessageListener("Browser:SetSSLErrorReportAuto", this);
mm.removeMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.removeMessageListener("Browser:OverrideWeakCrypto", this);
mm.removeMessageListener("Browser:SSLErrorGoBack", this);
},
handleEvent: function (event) {
@ -2738,6 +2740,9 @@ var BrowserOnClick = {
msg.data.location.hostname,
PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser));
break;
case "Browser:SSLErrorGoBack":
goBackFromErrorPage();
break;
}
},
@ -4456,8 +4461,11 @@ var XULBrowserWindow = {
try {
gCrashReporter.annotateCrashReport("URL", uri.spec);
} catch (ex if ex.result == Components.results.NS_ERROR_NOT_INITIALIZED) {
} catch (ex) {
// Don't make noise when the crash reporter is built but not enabled.
if (ex.result != Components.results.NS_ERROR_NOT_INITIALIZED) {
throw ex;
}
}
}
},
@ -5459,7 +5467,7 @@ function handleLinkClick(event, href, linkNode) {
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
linkNode) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(linkNode.
getAttribute("referrer"));
getAttribute("referrerpolicy"));
if (referrerAttrValue != Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
@ -6471,7 +6479,7 @@ function isTabEmpty(aTab) {
}
function BrowserOpenSyncTabs() {
switchToTabHavingURI("about:sync-tabs", true);
gSyncUI.openSyncedTabsPanel();
}
/**

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

@ -1038,11 +1038,6 @@
type="checkbox"
label="&fullScreenCmd.label;"
tooltip="dynamic-shortcut-tooltip"/>
<toolbarbutton id="sync-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&syncToolbarButton.label;"
oncommand="gSyncUI.handleToolbarButton()"/>
</toolbarpalette>
</toolbox>

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

@ -114,7 +114,7 @@ var handleContentContextMenu = function (event) {
// the document wide referrer
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer")) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(event.target.
getAttribute("referrer"));
getAttribute("referrerpolicy"));
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
@ -389,7 +389,7 @@ var ClickEventHandler = {
if (Services.prefs.getBoolPref("network.http.enablePerElementReferrer") &&
node) {
let referrerAttrValue = Services.netUtils.parseAttributePolicyString(node.
getAttribute("referrer"));
getAttribute("referrerpolicy"));
if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT) {
referrerPolicy = referrerAttrValue;
}
@ -473,6 +473,10 @@ var ClickEventHandler = {
onAboutNetError: function (event, documentURI) {
let elmId = event.originalTarget.getAttribute("id");
if (elmId == "returnButton") {
sendAsyncMessage("Browser:SSLErrorGoBack", {});
return;
}
if (elmId != "errorTryAgain" || !/e=netOffline/.test(documentURI)) {
return;
}

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

@ -31,7 +31,6 @@
<script type="application/javascript" src="chrome://browser/content/browser-social.js"/>
<script type="application/javascript" src="chrome://browser/content/browser-syncui.js"/>
<script type="application/javascript" src="chrome://browser/content/browser-tabsintitlebar.js"/>
<script type="application/javascript" src="chrome://browser/content/browser-tabview.js"/>
<script type="application/javascript" src="chrome://browser/content/browser-thumbnails.js"/>
<script type="application/javascript" src="chrome://browser/content/browser-trackingprotection.js"/>

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

@ -297,14 +297,13 @@ function initPluginsRow() {
}
}
let entries = [{name: item[1], permission: item[0]} for (item of permissionMap)];
let entries = Array.from(permissionMap, item => ({ name: item[1], permission: item[0] }));
entries.sort(function(a, b) {
return a.name < b.name ? -1 : (a.name == b.name ? 0 : 1);
});
let permissionEntries = [
fillInPluginPermissionTemplate(p.name, p.permission) for (p of entries)
];
let permissionEntries = entries.map(p => fillInPluginPermissionTemplate(p.name, p.permission));
let permPluginsRow = document.getElementById("perm-plugins-row");
clearPluginPermissionTemplate();

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

@ -450,7 +450,7 @@ Sanitizer.prototype = {
{
let refObj = {};
TelemetryStopwatch.start("FX_SANITIZE_DOWNLOADS", refObj);
Task.spawn(function () {
Task.spawn(function*() {
let filterByTime = null;
if (this.range) {
// Convert microseconds back to milliseconds for date comparisons.

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

@ -472,6 +472,7 @@ skip-if = os == "linux" || e10s # Bug 1073339 - Investigate autocomplete test un
[browser_urlbarSearchSingleWordNotification.js]
[browser_urlbarSearchSuggestions.js]
[browser_urlbarSearchSuggestionsNotification.js]
[browser_urlbarSearchTelemetry.js]
[browser_urlbarStop.js]
[browser_urlbarTrimURLs.js]
[browser_urlbar_autoFill_backspaced.js]

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

@ -114,7 +114,7 @@ var gTests = [
// Get the current number of recorded searches.
let searchStr = "a search";
getNumberOfSearches(engineName).then(num => {
getNumberOfSearchesInFHR(engineName, "abouthome").then(num => {
numSearchesBefore = num;
info("Perform a search.");
@ -126,7 +126,7 @@ var gTests = [
getSubmission(searchStr, null, "homepage").
uri.spec;
let loadPromise = waitForDocLoadAndStopIt(expectedURL).then(() => {
getNumberOfSearches(engineName).then(num => {
getNumberOfSearchesInFHR(engineName, "abouthome").then(num => {
is(num, numSearchesBefore + 1, "One more search recorded.");
searchEventDeferred.resolve();
});
@ -601,58 +601,6 @@ function promiseSetupSnippetsMap(aTab, aSetupFn)
return deferred.promise;
}
/**
* Retrieves the number of about:home searches recorded for the current day.
*
* @param aEngineName
* name of the setup search engine.
*
* @return {Promise} Returns a promise resolving to the number of searches.
*/
function getNumberOfSearches(aEngineName) {
let reporter = Components.classes["@mozilla.org/datareporting/service;1"]
.getService()
.wrappedJSObject
.healthReporter;
ok(reporter, "Health Reporter instance available.");
return reporter.onInit().then(function onInit() {
let provider = reporter.getProvider("org.mozilla.searches");
ok(provider, "Searches provider is available.");
let m = provider.getMeasurement("counts", 3);
return m.getValues().then(data => {
let now = new Date();
let yday = new Date(now);
yday.setDate(yday.getDate() - 1);
// Add the number of searches recorded yesterday to the number of searches
// recorded today. This makes the test not fail intermittently when it is
// run at midnight and we accidentally compare the number of searches from
// different days. Tests are always run with an empty profile so there
// are no searches from yesterday, normally. Should the test happen to run
// past midnight we make sure to count them in as well.
return getNumberOfSearchesByDate(aEngineName, data, now) +
getNumberOfSearchesByDate(aEngineName, data, yday);
});
});
}
function getNumberOfSearchesByDate(aEngineName, aData, aDate) {
if (aData.days.hasDay(aDate)) {
let id = Services.search.getEngineByName(aEngineName).identifier;
let day = aData.days.getDay(aDate);
let field = id + ".abouthome";
if (day.has(field)) {
return day.get(field) || 0;
}
}
return 0; // No records found.
}
function waitForLoad(cb) {
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function listener() {

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

@ -53,7 +53,7 @@ function promiseObserver(topic) {
}
function checkButtonTooltips(stringPrefix) {
for (let butId of ["sync-button", "PanelUI-fxa-icon"]) {
for (let butId of ["PanelUI-remotetabs-syncnow", "PanelUI-fxa-icon"]) {
let text = document.getElementById(butId).getAttribute("tooltiptext");
let desc = `Text is "${text}", expecting it to start with "${stringPrefix}"`
Assert.ok(text.startsWith(stringPrefix), desc);
@ -89,6 +89,8 @@ add_task(function* prepare() {
// and a notification to have the state change away from "needs setup"
yield notifyAndPromiseUIUpdated("weave:service:login:finish");
checkBroadcasterVisible("sync-syncnow-state");
// open the sync-button panel so we can check elements in that.
document.getElementById("sync-button").click();
});
add_task(function* testSyncNeedsVerification() {
@ -128,14 +130,17 @@ add_task(function* testSyncLoginError() {
});
function checkButtonsStatus(shouldBeActive) {
let button = document.getElementById("sync-button");
let fxaContainer = document.getElementById("PanelUI-footer-fxa");
if (shouldBeActive) {
Assert.equal(button.getAttribute("status"), "active");
Assert.equal(fxaContainer.getAttribute("syncstatus"), "active");
} else {
Assert.ok(!button.hasAttribute("status"));
Assert.ok(!fxaContainer.hasAttribute("syncstatus"));
for (let eid of [
"sync-status", // the broadcaster itself.
"sync-button", // the main sync button which observes the broadcaster
"PanelUI-fxa-icon", // the sync icon in the fxa footer that observes it.
]) {
let elt = document.getElementById(eid);
if (shouldBeActive) {
Assert.equal(elt.getAttribute("syncstatus"), "active", `${eid} should be active`);;
} else {
Assert.ok(!elt.hasAttribute("syncstatus"), `${eid} should have no status attr`);
}
}
}

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

@ -0,0 +1,177 @@
"use strict";
Cu.import("resource:///modules/BrowserUITelemetry.jsm");
const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
// Must run first.
add_task(function* prepare() {
Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
let oldCurrentEngine = Services.search.currentEngine;
Services.search.currentEngine = engine;
registerCleanupFunction(function* () {
Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
Services.search.currentEngine = oldCurrentEngine;
// Clicking urlbar results causes visits to their associated pages, so clear
// that history now.
yield PlacesTestUtils.clearHistory();
// Make sure the popup is closed for the next test.
gURLBar.blur();
Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
});
});
add_task(function* heuristicResult() {
yield compareCounts(function* () {
yield promiseAutocompleteResultPopup("heuristicResult");
let action = getActionAtIndex(0);
Assert.ok(!!action, "there should be an action at index 0");
Assert.equal(action.type, "searchengine", "type should be searchengine");
let item = gURLBar.popup.richlistbox.getItemAtIndex(0);
let loadPromise = promiseTabLoaded(gBrowser.selectedTab);
item.click();
yield loadPromise;
});
});
add_task(function* searchSuggestion() {
yield compareCounts(function* () {
yield promiseAutocompleteResultPopup("searchSuggestion");
let idx = getFirstSuggestionIndex();
Assert.ok(idx >= 0, "there should be a first suggestion");
let item = gURLBar.popup.richlistbox.getItemAtIndex(idx);
let loadPromise = promiseTabLoaded(gBrowser.selectedTab);
item.click();
yield loadPromise;
});
});
/**
* This does three things: gets current telemetry/FHR counts, calls
* clickCallback, gets telemetry/FHR counts again to compare them to the old
* counts.
*
* @param clickCallback Use this to open the urlbar popup and choose and click a
* result.
*/
function* compareCounts(clickCallback) {
// Search events triggered by clicks (not the Return key in the urlbar) are
// recorded in three places:
// * BrowserUITelemetry
// * Telemetry histogram named "SEARCH_COUNTS"
// * FHR
let engine = Services.search.currentEngine;
let engineID = "org.mozilla.testsearchsuggestions";
// First, get the current counts.
// BrowserUITelemetry
let uiTelemCount = 0;
let bucket = BrowserUITelemetry.currentBucket;
let events = BrowserUITelemetry.getToolbarMeasures().countableEvents;
if (events[bucket] &&
events[bucket].search &&
events[bucket].search.urlbar) {
uiTelemCount = events[bucket].search.urlbar;
}
// telemetry histogram SEARCH_COUNTS
let histogramCount = 0;
let histogramKey = engineID + ".urlbar";
let histogram;
try {
histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
} catch (ex) {
// No searches performed yet, not a problem.
}
if (histogram) {
let snapshot = histogram.snapshot();
if (histogramKey in snapshot) {
histogramCount = snapshot[histogramKey].sum;
}
}
// FHR -- first make sure the engine has an identifier so that FHR is happy.
Object.defineProperty(engine.wrappedJSObject, "identifier",
{ value: engineID });
let fhrCount = yield getNumberOfSearchesInFHR(engine.name, "urlbar");
gURLBar.focus();
yield clickCallback();
// Now get the new counts and compare them to the old.
// BrowserUITelemetry
events = BrowserUITelemetry.getToolbarMeasures().countableEvents;
Assert.ok(bucket in events, "bucket should be recorded");
events = events[bucket];
Assert.ok("search" in events, "search should be recorded");
events = events.search;
Assert.ok("urlbar" in events, "urlbar should be recorded");
Assert.equal(events.urlbar, uiTelemCount + 1,
"clicked suggestion should be recorded");
// telemetry histogram SEARCH_COUNTS
histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
let snapshot = histogram.snapshot();
Assert.ok(histogramKey in snapshot, "histogram with key should be recorded");
Assert.equal(snapshot[histogramKey].sum, histogramCount + 1,
"histogram sum should be incremented");
// FHR
let newFHRCount = yield getNumberOfSearchesInFHR(engine.name, "urlbar");
Assert.equal(newFHRCount, fhrCount + 1, "should be recorded in FHR");
}
/**
* Returns the "action" object at the given index in the urlbar results:
* { type, params: {}}
*
* @param index The index in the urlbar results.
* @return An action object, or null if index >= number of results.
*/
function getActionAtIndex(index) {
let controller = gURLBar.popup.input.controller;
if (controller.matchCount <= index) {
return null;
}
let url = controller.getValueAt(index);
let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
if (!mozActionMatch) {
let msg = "result at index " + index + " is not a moz-action: " + url;
Assert.ok(false, msg);
throw new Error(msg);
}
let [, type, paramStr] = mozActionMatch;
return {
type: type,
params: JSON.parse(paramStr),
};
}
/**
* Returns the index of the first search suggestion in the urlbar results.
*
* @return An index, or -1 if there are no search suggestions.
*/
function getFirstSuggestionIndex() {
let controller = gURLBar.popup.input.controller;
let matchCount = controller.matchCount;
for (let i = 0; i < matchCount; i++) {
let url = controller.getValueAt(i);
let mozActionMatch = url.match(/^moz-action:([^,]+),(.*)$/);
if (mozActionMatch) {
let [, type, paramStr] = mozActionMatch;
let params = JSON.parse(paramStr);
if (type == "searchengine" && "searchSuggestion" in params) {
return i;
}
}
}
return -1;
}

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

@ -1202,3 +1202,61 @@ function promiseCrashReport(expectedExtra) {
}
});
}
/**
* Retrieves the number of searches recorded in FHR for the current day.
*
* @param aEngineName
* name of the setup search engine.
* @param aSource
* The FHR "source" name for the search, like "abouthome" or "urlbar".
*
* @return {Promise} Returns a promise resolving to the number of searches.
*/
function getNumberOfSearchesInFHR(aEngineName, aSource) {
let reporter = Components.classes["@mozilla.org/datareporting/service;1"]
.getService()
.wrappedJSObject
.healthReporter;
ok(reporter, "Health Reporter instance available.");
return reporter.onInit().then(function onInit() {
let provider = reporter.getProvider("org.mozilla.searches");
ok(provider, "Searches provider is available.");
let m = provider.getMeasurement("counts", 3);
return m.getValues().then(data => {
let now = new Date();
let yday = new Date(now);
yday.setDate(yday.getDate() - 1);
// Add the number of searches recorded yesterday to the number of searches
// recorded today. This makes the test not fail intermittently when it is
// run at midnight and we accidentally compare the number of searches from
// different days. Tests are always run with an empty profile so there
// are no searches from yesterday, normally. Should the test happen to run
// past midnight we make sure to count them in as well.
return getNumberOfSearchesInFHRByDate(aEngineName, aSource, data, now) +
getNumberOfSearchesInFHRByDate(aEngineName, aSource, data, yday);
});
});
}
/**
* Helper for getNumberOfSearchesInFHR. You probably don't want to call this
* directly.
*/
function getNumberOfSearchesInFHRByDate(aEngineName, aSource, aData, aDate) {
if (aData.days.hasDay(aDate)) {
let id = Services.search.getEngineByName(aEngineName).identifier;
let day = aData.days.getDay(aDate);
let field = id + "." + aSource;
if (day.has(field)) {
return day.get(field) || 0;
}
}
return 0; // No records found.
}

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

@ -1,6 +1,7 @@
[DEFAULT]
support-files =
file_referrer_policyserver.sjs
file_referrer_policyserver_attr.sjs
file_referrer_testserver.sjs
head.js

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

@ -0,0 +1,36 @@
/**
* Renders a link with the provided referrer policy.
* Used in browser_referrer_*.js, bug 1113431.
* Arguments: ?scheme=http://&policy=origin&rel=noreferrer
*/
function handleRequest(request, response)
{
Components.utils.importGlobalProperties(["URLSearchParams"]);
let query = new URLSearchParams(request.queryString);
let scheme = query.get("scheme");
let policy = query.get("policy");
let rel = query.get("rel");
let linkUrl = scheme +
"test1.example.com/browser/browser/base/content/test/referrer/" +
"file_referrer_testserver.sjs";
let referrerPolicy =
policy ? `referrerpolicy="${policy}"` : "";
let html = `<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'>
<title>Test referrer</title>
</head>
<body>
<a id='testlink' href='${linkUrl}' ${referrerPolicy} ${rel ? ` rel='${rel}'` : ""}>
referrer test link</a>
</body>
</html>`;
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/html", false);
response.write(html);
}

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

@ -10,8 +10,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "ContentTask",
const REFERRER_URL_BASE = "/browser/browser/base/content/test/referrer/";
const REFERRER_POLICYSERVER_URL =
"test1.example.com" + REFERRER_URL_BASE + "file_referrer_policyserver.sjs";
const REFERRER_POLICYSERVER_URL_ATTRIBUTE =
"test1.example.com" + REFERRER_URL_BASE + "file_referrer_policyserver_attr.sjs";
SpecialPowers.pushPrefEnv({"set": [['network.http.enablePerElementReferrer', true]]});
var gTestWindow = null;
var rounds = 0;
// We test that the UI code propagates three pieces of state - the referrer URI
// itself, the referrer policy, and the triggering principal. After that, we
@ -49,20 +54,21 @@ var _referrerTests = [
rel: "noreferrer",
result: "" // rel=noreferrer trumps meta-referrer
},
// 3. Origin-when-cross-origin policy - this depends on the triggering
// 3. XXX: using no-referrer here until we support all attribute values (bug 1178337)
// Origin-when-cross-origin policy - this depends on the triggering
// principal. We expect full referrer for same-origin requests,
// and origin referrer for cross-origin requests.
{
fromScheme: "https://",
toScheme: "https://",
policy: "origin-when-cross-origin",
result: "https://test1.example.com/browser" // same origin
policy: "no-referrer",
result: "" // same origin https://test1.example.com/browser
},
{
fromScheme: "http://",
toScheme: "https://",
policy: "origin-when-cross-origin",
result: "http://test1.example.com" // cross origin
policy: "no-referrer",
result: "" // cross origin http://test1.example.com
},
];
@ -191,7 +197,9 @@ function doContextMenuCommand(aWindow, aMenu, aItemId) {
*/
function referrerTestCaseLoaded(aTestNumber) {
let test = getReferrerTest(aTestNumber);
let url = test.fromScheme + REFERRER_POLICYSERVER_URL +
let server = rounds == 0 ? REFERRER_POLICYSERVER_URL :
REFERRER_POLICYSERVER_URL_ATTRIBUTE;
let url = test.fromScheme + server +
"?scheme=" + escape(test.toScheme) +
"&policy=" + escape(test.policy || "") +
"&rel=" + escape(test.rel || "");
@ -227,6 +235,12 @@ function checkReferrerAndStartNextTest(aTestNumber, aNewWindow, aNewTab,
referrerTestCaseLoaded(nextTestNumber).then(function() {
aStartTestCase(nextTestNumber);
});
} else if (rounds == 0) {
nextTestNumber = 0;
rounds = 1;
referrerTestCaseLoaded(nextTestNumber).then(function() {
aStartTestCase(nextTestNumber);
});
} else {
finish();
}

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

@ -361,13 +361,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
} else if (action.type == "keyword") {
url = action.params.url;
} else if (action.type == "searchengine") {
let engine = Services.search.getEngineByName(action.params.engineName);
let query = action.params.searchSuggestion ||
action.params.searchQuery;
let submission = engine.getSubmission(query, null, "keyword");
url = submission.uri.spec;
postData = submission.postData;
[url, postData] = this._parseAndRecordSearchEngineAction(action);
} else if (action.type == "visiturl") {
url = action.params.url;
}
@ -455,6 +449,19 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
]]></body>
</method>
<method name="_parseAndRecordSearchEngineAction">
<parameter name="action"/>
<body><![CDATA[
let engine =
Services.search.getEngineByName(action.params.engineName);
BrowserSearch.recordSearchInHealthReport(engine, "urlbar");
let query = action.params.searchSuggestion ||
action.params.searchQuery;
let submission = engine.getSubmission(query, null, "keyword");
return [submission.uri.spec, submission.postData];
]]></body>
</method>
<method name="_canonizeURL">
<parameter name="aTriggeringEvent"/>
<parameter name="aCallback"/>
@ -1455,12 +1462,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
break;
}
case "searchengine": {
let engine = Services.search.getEngineByName(action.params.engineName);
let query = action.params.searchSuggestion ||
action.params.searchQuery;
let submission = engine.getSubmission(query, null, "keyword");
url = submission.uri.spec;
options.postData = submission.postData;
[url, options.postData] =
this._parseAndRecordSearchEngineAction(action);
break;
}
default: {

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

@ -20,7 +20,7 @@
# The installer's certificate name and issuer expected by the stub installer
!define CertNameDownload "Mozilla Corporation"
!define CertIssuerDownload "DigiCert Assured ID Code Signing CA-1"
!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
# Dialog units are used so the UI displays correctly with the system's DPI
# settings.

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

@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
JS_PREFERENCE_FILES += [
'pref/firefox-branding.js',
'/%s/pref/firefox-branding.js' % CONFIG['MOZ_BRANDING_DIRECTORY'],
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':

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

@ -19,7 +19,7 @@
# The installer's certificate name and issuer expected by the stub installer
!define CertNameDownload "Mozilla Corporation"
!define CertIssuerDownload "DigiCert Assured ID Code Signing CA-1"
!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
# Dialog units are used so the UI displays correctly with the system's DPI
# settings.

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

@ -24,7 +24,7 @@
# The installer's certificate name and issuer expected by the stub installer
!define CertNameDownload "Mozilla Corporation"
!define CertIssuerDownload "DigiCert Assured ID Code Signing CA-1"
!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
# Dialog units are used so the UI displays correctly with the system's DPI
# settings.

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

@ -19,7 +19,7 @@
# The installer's certificate name and issuer expected by the stub installer
!define CertNameDownload "Mozilla Corporation"
!define CertIssuerDownload "Thawte Code Signing CA - G2"
!define CertIssuerDownload "DigiCert SHA2 Assured ID Code Signing CA"
# Dialog units are used so the UI displays correctly with the system's DPI
# settings.

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

@ -53,14 +53,16 @@ const kSubviewEvents = [
* The current version. We can use this to auto-add new default widgets as necessary.
* (would be const but isn't because of testing purposes)
*/
var kVersion = 4;
var kVersion = 5;
/**
* Buttons removed from built-ins by version they were removed. kVersion must be
* bumped any time a new id is added to this. Use the button id as key, and
* version the button is removed in as the value. e.g. "pocket-button": 5
*/
var ObsoleteBuiltinButtons = {};
var ObsoleteBuiltinButtons = {
"loop-button": 5
};
/**
* gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed
@ -178,6 +180,7 @@ var CustomizableUIInternal = {
#ifndef MOZ_DEV_EDITION
"developer-button",
#endif
"sync-button",
];
#ifdef E10S_TESTING_ONLY

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

@ -30,6 +30,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
"resource://gre/modules/SocialService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SyncedTabs",
"resource://services-sync/SyncedTabs.jsm");
XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() {
const kCharsetBundle = "chrome://global/locale/charsetMenu.properties";
@ -249,12 +251,6 @@ const CustomizableWidgets = [
tabsFromOtherComputers.setAttribute("hidden", true);
}
if (PlacesUIUtils.shouldEnableTabsFromOtherComputersMenuitem()) {
tabsFromOtherComputers.removeAttribute("disabled");
} else {
tabsFromOtherComputers.setAttribute("disabled", true);
}
let utils = RecentlyClosedTabsAndWindowsMenuUtils;
let tabsFragment = utils.getTabsFragment(doc.defaultView, "toolbarbutton", true,
"menuRestoreAllTabsSubview.label");
@ -292,6 +288,207 @@ const CustomizableWidgets = [
onViewHiding: function(aEvent) {
LOG("History view is being hidden!");
}
}, {
id: "sync-button",
label: "remotetabs-panelmenu.label",
tooltiptext: "remotetabs-panelmenu.tooltiptext",
type: "view",
viewId: "PanelUI-remotetabs",
defaultArea: CustomizableUI.AREA_PANEL,
deckIndices: {
DECKINDEX_TABS: 0,
DECKINDEX_TABSDISABLED: 1,
DECKINDEX_FETCHING: 2,
DECKINDEX_NOCLIENTS: 3,
},
onCreated(aNode) {
// Add an observer to the button so we get the animation during sync.
// (Note the observer sets many attributes, including label and
// tooltiptext, but we only want the 'syncstatus' attribute for the
// animation)
let doc = aNode.ownerDocument;
let obnode = doc.createElementNS(kNSXUL, "observes");
obnode.setAttribute("element", "sync-status");
obnode.setAttribute("attribute", "syncstatus");
aNode.appendChild(obnode);
// A somewhat complicated dance to format the mobilepromo label.
let bundle = doc.getElementById("bundle_browser");
let formatArgs = ["android", "ios"].map(os => {
let link = doc.createElement("label");
link.textContent = bundle.getString(`appMenuRemoteTabs.mobilePromo.${os}`)
link.href = Services.prefs.getCharPref(`identity.mobilepromo.${os}`) + "synced-tabs";
link.className = "text-link remotetabs-promo-link";
return link.outerHTML;
});
// Put it all together...
let contents = bundle.getFormattedString("appMenuRemoteTabs.mobilePromo", formatArgs);
doc.getElementById("PanelUI-remotetabs-mobile-promo").innerHTML = contents;
},
onViewShowing(aEvent) {
let doc = aEvent.target.ownerDocument;
this._tabsList = doc.getElementById("PanelUI-remotetabs-tabslist");
Services.obs.addObserver(this, SyncedTabs.TOPIC_TABS_CHANGED, false);
let deck = doc.getElementById("PanelUI-remotetabs-deck");
if (SyncedTabs.isConfiguredToSyncTabs) {
if (SyncedTabs.hasSyncedThisSession) {
deck.selectedIndex = this.deckIndices.DECKINDEX_TABS;
} else {
// Sync hasn't synced tabs yet, so show the "fetching" panel.
deck.selectedIndex = this.deckIndices.DECKINDEX_FETCHING;
}
// force a background sync.
SyncedTabs.syncTabs().catch(ex => {
Cu.reportError(ex);
});
// show the current list - it will be updated by our observer.
this._showTabs();
} else {
// not configured to sync tabs, so no point updating the list.
deck.selectedIndex = this.deckIndices.DECKINDEX_TABSDISABLED;
}
},
onViewHiding() {
Services.obs.removeObserver(this, SyncedTabs.TOPIC_TABS_CHANGED);
this._tabsList = null;
},
_tabsList: null,
observe(subject, topic, data) {
switch (topic) {
case SyncedTabs.TOPIC_TABS_CHANGED:
this._showTabs();
break;
default:
break;
}
},
_showTabsPromise: Promise.resolve(),
// Update the tab list after any existing in-flight updates are complete.
_showTabs() {
this._showTabsPromise = this._showTabsPromise.then(() => {
return this.__showTabs();
});
},
// Return a new promise to update the tab list.
__showTabs() {
let doc = this._tabsList.ownerDocument;
let deck = doc.getElementById("PanelUI-remotetabs-deck");
return SyncedTabs.getTabClients().then(clients => {
// The view may have been hidden while the promise was resolving.
if (!this._tabsList) {
return;
}
if (clients.length === 0 && !SyncedTabs.hasSyncedThisSession) {
// the "fetching tabs" deck is being shown - let's leave it there.
// When that first sync completes we'll be notified and update.
return;
}
if (clients.length === 0) {
deck.selectedIndex = this.deckIndices.DECKINDEX_NOCLIENTS;
return;
}
deck.selectedIndex = this.deckIndices.DECKINDEX_TABS;
this._clearTabList();
this._sortFilterClientsAndTabs(clients);
let fragment = doc.createDocumentFragment();
for (let client of clients) {
// add a menu separator for all clients other than the first.
if (fragment.lastChild) {
let separator = doc.createElementNS(kNSXUL, "menuseparator");
fragment.appendChild(separator);
}
this._appendClient(client, fragment);
}
this._tabsList.appendChild(fragment);
}).catch(err => {
Cu.reportError(err);
}).then(() => {
// an observer for tests.
Services.obs.notifyObservers(null, "synced-tabs-menu:test:tabs-updated", null);
});
},
_clearTabList () {
let list = this._tabsList;
while (list.lastChild) {
list.lastChild.remove();
}
},
_showNoClientMessage() {
this._appendMessageLabel("notabslabel");
},
_appendMessageLabel(messageAttr, appendTo = null) {
if (!appendTo) {
appendTo = this._tabsList;
}
let message = this._tabsList.getAttribute(messageAttr);
let doc = this._tabsList.ownerDocument;
let messageLabel = doc.createElementNS(kNSXUL, "label");
messageLabel.textContent = message;
appendTo.appendChild(messageLabel);
return messageLabel;
},
_appendClient: function (client, attachFragment) {
let doc = attachFragment.ownerDocument;
// Create the element for the remote client.
let clientItem = doc.createElementNS(kNSXUL, "label");
clientItem.setAttribute("itemtype", "client");
clientItem.textContent = client.name;
attachFragment.appendChild(clientItem);
if (client.tabs.length == 0) {
let label = this._appendMessageLabel("notabsforclientlabel", attachFragment);
label.setAttribute("class", "PanelUI-remotetabs-notabsforclient-label");
} else {
for (let tab of client.tabs) {
let tabEnt = this._createTabElement(doc, tab);
attachFragment.appendChild(tabEnt);
}
}
},
_createTabElement(doc, tabInfo) {
let win = doc.defaultView;
let item = doc.createElementNS(kNSXUL, "toolbarbutton");
item.setAttribute("itemtype", "tab");
item.setAttribute("class", "subviewbutton");
item.setAttribute("targetURI", tabInfo.url);
item.setAttribute("label", tabInfo.title != "" ? tabInfo.title : tabInfo.url);
item.setAttribute("image", tabInfo.icon);
// We need to use "click" instead of "command" here so openUILink
// respects different buttons (eg, to open in a new tab).
item.addEventListener("click", e => {
doc.defaultView.openUILink(tabInfo.url, e);
CustomizableUI.hidePanelForNode(item);
});
return item;
},
_sortFilterClientsAndTabs(clients) {
// First sort and filter the list of tabs for each client. Note that the
// SyncedTabs module promises that the objects it returns are never
// shared, so we are free to mutate those objects directly.
const maxTabs = 15;
for (let client of clients) {
let tabs = client.tabs;
tabs.sort((a, b) => b.lastUsed - a.lastUsed);
client.tabs = tabs.slice(0, maxTabs);
}
// Now sort the clients - the clients are sorted in the order of the
// most recent tab for that client (ie, it is important the tabs for
// each client are already sorted.)
clients.sort((a, b) => {
if (a.tabs.length == 0) {
return 1; // b comes first.
}
if (b.tabs.length == 0) {
return -1; // a comes first.
}
return b.tabs[0].lastUsed - a.tabs[0].lastUsed;
});
},
}, {
id: "privatebrowsing-button",
shortcutId: "key_privatebrowsing",

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

@ -34,7 +34,10 @@
<toolbarseparator/>
<toolbarbutton id="PanelUI-fxa-icon"
oncommand="gSyncUI.doSync();"
closemenu="none"/>
closemenu="none">
<observes element="sync-status" attribute="syncstatus"/>
<observes element="sync-status" attribute="tooltiptext"/>
</toolbarbutton>
</hbox>
<hbox id="PanelUI-footer-inner">
@ -83,7 +86,7 @@
command="Tools:Sanitize"/>
<toolbarbutton id="sync-tabs-menuitem2"
class="syncTabsMenuItem subviewbutton"
label="&syncTabsMenu2.label;"
label="&syncTabsMenu3.label;"
oncommand="BrowserOpenSyncTabs();"
disabled="true"/>
<toolbarbutton id="appMenuRestoreLastSession"
@ -103,6 +106,83 @@
oncommand="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/>
</panelview>
<panelview id="PanelUI-remotetabs" flex="1" class="PanelUI-subView">
<label value="&appMenuRemoteTabs.label;" class="panel-subview-header"/>
<vbox class="panel-subview-body">
<!-- this widget has 3 boxes in the body, but only 1 is ever visible -->
<!-- When Sync is ready to sync -->
<vbox id="PanelUI-remotetabs-main" observes="sync-syncnow-state">
<toolbarbutton id="PanelUI-remotetabs-syncnow"
observes="sync-status"
class="subviewbutton"
oncommand="gSyncUI.doSync();"
closemenu="none"/>
<menuseparator id="PanelUI-remotetabs-separator"/>
<deck id="PanelUI-remotetabs-deck">
<!-- Sync is ready to Sync and the "tabs" engine is enabled -->
<vbox id="PanelUI-remotetabs-tabspane">
<vbox id="PanelUI-remotetabs-tabslist"
notabsforclientlabel="&appMenuRemoteTabs.notabs.label;"
/>
</vbox>
<!-- Sync is ready to Sync but the "tabs" engine isn't enabled-->
<vbox id="PanelUI-remotetabs-tabsdisabledpane"
class="PanelUI-remotetabs-instruction-box">
<hbox pack="center">
<image class="fxaSyncIllustration" alt=""/>
</hbox>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.tabsnotsyncing.label;</label>
<hbox pack="center">
<toolbarbutton class="PanelUI-remotetabs-prefs-button"
label="&appMenuRemoteTabs.openprefs.label;"
oncommand="gSyncUI.openSetup();"/>
</hbox>
</vbox>
<!-- Sync is ready to Sync but we are still fetching the tabs to show -->
<vbox id="PanelUI-remotetabs-fetching">
<label>&appMenuRemoteTabs.fetching.label;</label>
</vbox>
<!-- Sync has only 1 (ie, this) device connected -->
<vbox id="PanelUI-remotetabs-nodevicespane"
class="PanelUI-remotetabs-instruction-box">
<hbox pack="center">
<image class="fxaSyncIllustration" alt=""/>
</hbox>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.noclients.label;</label>
<!-- The inner HTML for PanelUI-remotetabs-mobile-promo is built at runtime -->
<label id="PanelUI-remotetabs-mobile-promo"/>
</vbox>
</deck>
</vbox>
<!-- When Sync is not configured -->
<vbox id="PanelUI-remotetabs-setupsync"
flex="1"
align="center"
class="PanelUI-remotetabs-instruction-box"
observes="sync-setup-state">
<image class="fxaSyncIllustration" alt=""/>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
<toolbarbutton class="PanelUI-remotetabs-prefs-button"
label="&appMenuRemoteTabs.signin.label;"
oncommand="gSyncUI.openSetup();"/>
</vbox>
<!-- When Sync needs re-authentication. This uses the exact same messaging
as "Sync is not configured" but remains a separate box so we get
the goodness of observing broadcasters to manage the hidden states -->
<vbox id="PanelUI-remotetabs-reauthsync"
flex="1"
align="center"
class="PanelUI-remotetabs-instruction-box"
observes="sync-reauth-state">
<image class="fxaSyncIllustration" alt=""/>
<label class="PanelUI-remotetabs-instruction-label">&appMenuRemoteTabs.notsignedin.label;</label>
<toolbarbutton class="PanelUI-remotetabs-prefs-button"
label="&appMenuRemoteTabs.signin.label;"
oncommand="gSyncUI.openSetup();"/>
</vbox>
</vbox>
</panelview>
<panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView">
<label value="&bookmarksMenu.label;" class="panel-subview-header"/>
<vbox class="panel-subview-body">

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

@ -4,7 +4,7 @@
"use strict";
const kXULWidgetId = "sync-button";
const kXULWidgetId = "a-test-button"; // we'll create a button with this ID.
const kAPIWidgetId = "feed-button";
const kPanel = CustomizableUI.AREA_PANEL;
const kToolbar = CustomizableUI.AREA_NAVBAR;
@ -141,6 +141,16 @@ function checkPalette(id, method) {
checkWrapper(id);
}
// This test needs a XUL button that's in the palette by default. No such
// button currently exists, so we create a simple one.
function createXULButtonForWindow(win) {
createDummyXULButton(kXULWidgetId, "test-button", win);
}
function removeXULButtonForWindow(win) {
win.gNavToolbox.palette.querySelector(`#${kXULWidgetId}`).remove();
}
var otherWin;
// Moving widgets in two windows, one with customize mode and one without, should work.
@ -148,6 +158,9 @@ add_task(function MoveWidgetsInTwoWindows() {
yield startCustomizing();
otherWin = yield openAndLoadWindow(null, true);
yield otherWin.PanelUI.ensureReady();
// Create the XUL button to use in the test in both windows.
createXULButtonForWindow(window);
createXULButtonForWindow(otherWin);
ok(CustomizableUI.inDefaultState, "Should start in default state");
for (let widgetId of [kXULWidgetId, kAPIWidgetId]) {
@ -164,6 +177,7 @@ add_task(function MoveWidgetsInTwoWindows() {
yield promiseWindowClosed(otherWin);
otherWin = null;
yield endCustomizing();
removeXULButtonForWindow(window);
});
add_task(function asyncCleanup() {

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

@ -27,7 +27,10 @@ add_task(function testWrapUnwrap() {
// Creating and destroying a widget should correctly deal with panel placeholders
add_task(function testPanelPlaceholders() {
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
let expectedPlaceholders = 2 + (isInDevEdition() ? 1 : 0);
// The value of expectedPlaceholders depends on the default palette layout.
// Bug 1229236 is for these tests to be smarter so the test doesn't need to
// change when the default placements change.
let expectedPlaceholders = 1 + (isInDevEdition() ? 1 : 0);
is(panel.querySelectorAll(".panel-customization-placeholder").length, expectedPlaceholders, "The number of placeholders should be correct.");
CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
let elem = document.getElementById(kTestWidget2);
@ -36,7 +39,7 @@ add_task(function testPanelPlaceholders() {
ok(wrapper, "There should be a wrapper");
is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget");
is(wrapper.parentNode, panel, "Wrapper should be in panel");
expectedPlaceholders = 1 + (isInDevEdition() ? 1 : 0);
expectedPlaceholders = isInDevEdition() ? 1 : 3;
is(panel.querySelectorAll(".panel-customization-placeholder").length, expectedPlaceholders, "The number of placeholders should be correct.");
CustomizableUI.destroyWidget(kTestWidget2);
wrapper = document.getElementById("wrapper-" + kTestWidget2);

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

@ -22,7 +22,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(zoomControls, printButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -48,7 +50,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(zoomControls, savePageButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -72,7 +76,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(zoomControls, newWindowButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -95,7 +101,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(zoomControls, historyPanelMenu);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -122,7 +130,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(zoomControls, preferencesButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -149,7 +159,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterInsert);
simulateItemDrag(openFileButton, zoomControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
@ -188,7 +200,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterInsert);
simulateItemDrag(openFileButton, editControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
@ -224,7 +238,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(editControls, zoomControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -248,7 +264,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(editControls, newWindowButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -275,7 +293,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(editControls, privateBrowsingButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -302,7 +322,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(editControls, savePageButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -328,7 +350,9 @@ add_task(function() {
"preferences-button",
"add-ons-button",
"edit-controls",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(editControls, panel);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@ -353,7 +377,9 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
"developer-button"];
"developer-button",
"sync-button",
];
removeDeveloperButtonIfDevEdition(placementsAfterMove);
let paletteChildElementCount = palette.childElementCount;
simulateItemDrag(editControls, palette);
@ -379,6 +405,12 @@ add_task(function() {
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
let numPlaceholders = 2;
for (let i = 0; i < numPlaceholders; i++) {
// This test relies on there being a specific number of widgets in the
// panel. The addition of sync-button screwed this up, so we remove it
// here. We should either fix the tests to not rely on the specific layout,
// or fix bug 1007910 which would change the placeholder logic in different
// ways. Bug 1229236 is for these tests to be smarter.
CustomizableUI.removeWidgetFromArea("sync-button");
// NB: We can't just iterate over all of the placeholders
// because each drag-drop action recreates them.
let placeholder = panel.getElementsByClassName("panel-customization-placeholder")[i];
@ -399,6 +431,7 @@ add_task(function() {
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
let zoomControls = document.getElementById("zoom-controls");
simulateItemDrag(editControls, zoomControls);
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should still be in default state.");
}
});
@ -420,6 +453,10 @@ add_task(function() {
// Dragging a small button onto the last big button should work.
add_task(function() {
// Bug 1007910 requires there be a placeholder on the final row for this
// test to work as written. The addition of sync-button meant that's not true
// so we remove it from here. Bug 1229236 is for these tests to be smarter.
CustomizableUI.removeWidgetFromArea("sync-button");
yield startCustomizing();
let editControls = document.getElementById("edit-controls");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
@ -439,7 +476,7 @@ add_task(function() {
removeDeveloperButtonIfDevEdition(placementsAfterMove);
simulateItemDrag(editControls, target);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
let itemToDrag = "sync-button";
let itemToDrag = "email-link-button"; // any button in the palette by default.
let button = document.getElementById(itemToDrag);
placementsAfterMove.splice(11, 0, itemToDrag);
simulateItemDrag(button, editControls);
@ -450,6 +487,7 @@ add_task(function() {
let zoomControls = document.getElementById("zoom-controls");
simulateItemDrag(button, palette);
simulateItemDrag(editControls, zoomControls);
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
});

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

@ -20,7 +20,9 @@ add_task(function() {
ok(!CustomizableUI.inDefaultState, "Should not be in default state if on DevEdition.");
}
let btn = document.getElementById("open-file-button");
// This test relies on an exact number of widgets being in the panel.
// Remove the sync-button to satisfy that. (bug 1229236)
CustomizableUI.removeWidgetFromArea("sync-button");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
@ -35,6 +37,7 @@ add_task(function() {
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
}
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
});
@ -46,6 +49,10 @@ add_task(function() {
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
}
// This test relies on an exact number of widgets being in the panel.
// Remove the sync-button to satisfy that. (bug 1229236)
CustomizableUI.removeWidgetFromArea("sync-button");
let btn = document.getElementById("open-file-button");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
@ -74,7 +81,8 @@ add_task(function() {
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
}
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
});
// Two orphaned items should have one placeholder next to them (case 2).
@ -84,6 +92,9 @@ add_task(function() {
if (isInDevEdition()) {
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
}
// This test relies on an exact number of widgets being in the panel.
// Remove the sync-button to satisfy that. (bug 1229236)
CustomizableUI.removeWidgetFromArea("sync-button");
let btn = document.getElementById("add-ons-button");
let btn2 = document.getElementById("developer-button");
@ -112,6 +123,7 @@ add_task(function() {
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
}
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
});
@ -123,6 +135,10 @@ add_task(function() {
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_PANEL);
}
// This test relies on an exact number of widgets being in the panel.
// Remove the sync-button to satisfy that. (bug 1229236)
CustomizableUI.removeWidgetFromArea("sync-button");
let btn = document.getElementById("edit-controls");
let btn2 = document.getElementById("developer-button");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
@ -151,6 +167,7 @@ add_task(function() {
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR, 2);
}
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
});
@ -167,12 +184,18 @@ add_task(function() {
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state.");
// This test relies on an exact number of widgets being in the panel.
// Remove the sync-button to satisfy that. (bug 1229236)
CustomizableUI.removeWidgetFromArea("sync-button");
is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting");
yield endCustomizing();
yield startCustomizing();
is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders after re-entering");
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should still be in default state.");
});

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

@ -2,16 +2,51 @@
* 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/. */
// The test expects the about:accounts page to open in the current tab
"use strict";
let {SyncedTabs} = Cu.import("resource://services-sync/SyncedTabs.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "UITour", "resource:///modules/UITour.jsm");
// These are available on the widget implementation, but it seems impossible
// to grab that impl at runtime.
const DECKINDEX_TABS = 0;
const DECKINDEX_TABSDISABLED = 1;
const DECKINDEX_FETCHING = 2;
const DECKINDEX_NOCLIENTS = 3;
var initialLocation = gBrowser.currentURI.spec;
var newTab = null;
function openAboutAccountsFromMenuPanel(entryPoint) {
// A helper to notify there are new tabs. Returns a promise that is resolved
// once the UI has been updated.
function updateTabsPanel() {
let promiseTabsUpdated = promiseObserverNotified("synced-tabs-menu:test:tabs-updated");
Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED, null);
return promiseTabsUpdated;
}
// This is the mock we use for SyncedTabs.jsm - tests may override various
// functions.
let mockedInternal = {
get isConfiguredToSyncTabs() { return true; },
getTabClients() { return []; },
syncTabs() {},
hasSyncedThisSession: false,
};
add_task(function* setup() {
let oldInternal = SyncedTabs._internal;
SyncedTabs._internal = mockedInternal;
registerCleanupFunction(() => {
SyncedTabs._internal = oldInternal;
});
});
// The test expects the about:preferences#sync page to open in the current tab
function openPrefsFromMenuPanel(expectedPanelId, entryPoint) {
info("Check Sync button functionality");
Services.prefs.setCharPref("identity.fxaccounts.remote.signup.uri", "http://example.com/");
@ -29,6 +64,18 @@ function openAboutAccountsFromMenuPanel(entryPoint) {
let syncButton = document.getElementById("sync-button");
ok(syncButton, "The Sync button was added to the Panel Menu");
syncButton.click();
let syncPanel = document.getElementById("PanelUI-remotetabs");
ok(syncPanel.getAttribute("current"), "Sync Panel is in view");
// Sync is not configured - verify that state is reflected.
let subpanel = document.getElementById(expectedPanelId)
ok(!subpanel.hidden, "sync setup element is visible");
// Find and click the "setup" button.
let setupButton = subpanel.querySelector(".PanelUI-remotetabs-prefs-button");
setupButton.click();
let deferred = Promise.defer();
let handler = (e) => {
if (e.originalTarget != gBrowser.selectedBrowser.contentDocument ||
@ -41,7 +88,6 @@ function openAboutAccountsFromMenuPanel(entryPoint) {
}
gBrowser.selectedBrowser.addEventListener("load", handler, true);
syncButton.click();
yield deferred.promise;
newTab = gBrowser.selectedTab;
@ -68,8 +114,162 @@ function asyncCleanup() {
UITour.tourBrowsersByWindow.delete(window);
}
add_task(() => openAboutAccountsFromMenuPanel("syncbutton"));
// When Sync is not setup.
add_task(() => openPrefsFromMenuPanel("PanelUI-remotetabs-setupsync", "syncbutton"));
add_task(asyncCleanup);
// Test that uitour is in progress, the entrypoint is `uitour` and not `menupanel`
add_task(() => openAboutAccountsFromMenuPanel("uitour"));
add_task(() => openPrefsFromMenuPanel("PanelUI-remotetabs-setupsync", "uitour"));
add_task(asyncCleanup);
// When Sync is configured in a "needs reauthentication" state.
add_task(function* () {
// configure our broadcasters so we are in the right state.
document.getElementById("sync-reauth-state").hidden = false;
document.getElementById("sync-setup-state").hidden = true;
document.getElementById("sync-syncnow-state").hidden = true;
yield openPrefsFromMenuPanel("PanelUI-remotetabs-reauthsync", "syncbutton")
});
// Test the "Sync Now" button
add_task(function* () {
let nSyncs = 0;
mockedInternal.getTabClients = () => [];
mockedInternal.syncTabs = () => {
nSyncs++;
return Promise.resolve();
}
// configure our broadcasters so we are in the right state.
document.getElementById("sync-reauth-state").hidden = true;
document.getElementById("sync-setup-state").hidden = true;
document.getElementById("sync-syncnow-state").hidden = false;
// add the Sync button to the panel
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
yield PanelUI.show();
document.getElementById("sync-button").click();
let syncPanel = document.getElementById("PanelUI-remotetabs");
ok(syncPanel.getAttribute("current"), "Sync Panel is in view");
let subpanel = document.getElementById("PanelUI-remotetabs-main")
ok(!subpanel.hidden, "main pane is visible");
let deck = document.getElementById("PanelUI-remotetabs-deck");
// The widget is still fetching tabs, as we've neutered everything that
// provides them
is(deck.selectedIndex, DECKINDEX_FETCHING, "first deck entry is visible");
let syncNowButton = document.getElementById("PanelUI-remotetabs-syncnow");
let didSync = false;
let oldDoSync = gSyncUI.doSync;
gSyncUI.doSync = function() {
didSync = true;
mockedInternal.hasSyncedThisSession = true;
gSyncUI.doSync = oldDoSync;
}
syncNowButton.click();
ok(didSync, "clicking the button called the correct function");
// Tell the widget there are tabs available, but with zero clients.
mockedInternal.getTabClients = () => {
return Promise.resolve([]);
}
yield updateTabsPanel();
// The UI should be showing the "no clients" pane.
is(deck.selectedIndex, DECKINDEX_NOCLIENTS, "no-clients deck entry is visible");
// Tell the widget there are tabs available - we have 3 clients, one with no
// tabs.
mockedInternal.getTabClients = () => {
return Promise.resolve([
{
id: "guid_mobile",
type: "client",
name: "My Phone",
tabs: [],
},
{
id: "guid_desktop",
type: "client",
name: "My Desktop",
tabs: [
{
title: "http://example.com/10",
lastUsed: 10, // the most recent
},
{
title: "http://example.com/1",
lastUsed: 1, // the least recent.
},
{
title: "http://example.com/5",
lastUsed: 5,
},
],
},
{
id: "guid_second_desktop",
name: "My Other Desktop",
tabs: [
{
title: "http://example.com/6",
lastUsed: 6,
}
],
},
]);
};
yield updateTabsPanel();
// The UI should be showing tabs!
is(deck.selectedIndex, DECKINDEX_TABS, "no-clients deck entry is visible");
let tabList = document.getElementById("PanelUI-remotetabs-tabslist");
let node = tabList.firstChild;
// First entry should be the client with the most-recent tab.
is(node.getAttribute("itemtype"), "client", "node is a client entry");
is(node.textContent, "My Desktop", "correct client");
// Next entry is the most-recent tab
node = node.nextSibling;
is(node.getAttribute("itemtype"), "tab", "node is a tab");
is(node.getAttribute("label"), "http://example.com/10");
// Next entry is the next-most-recent tab
node = node.nextSibling;
is(node.getAttribute("itemtype"), "tab", "node is a tab");
is(node.getAttribute("label"), "http://example.com/5");
// Next entry is the least-recent tab from the first client.
node = node.nextSibling;
is(node.getAttribute("itemtype"), "tab", "node is a tab");
is(node.getAttribute("label"), "http://example.com/1");
// Next is a menuseparator between the clients.
node = node.nextSibling;
is(node.nodeName, "menuseparator");
// Next is the client with 1 tab.
node = node.nextSibling;
is(node.getAttribute("itemtype"), "client", "node is a client entry");
is(node.textContent, "My Other Desktop", "correct client");
// Its single tab
node = node.nextSibling;
is(node.getAttribute("itemtype"), "tab", "node is a tab");
is(node.getAttribute("label"), "http://example.com/6");
// Next is a menuseparator between the clients.
node = node.nextSibling;
is(node.nodeName, "menuseparator");
// Next is the client with no tab.
node = node.nextSibling;
is(node.getAttribute("itemtype"), "client", "node is a client entry");
is(node.textContent, "My Phone", "correct client");
// There is a single node saying there's no tabs for the client.
node = node.nextSibling;
is(node.nodeName, "label", "node is a label");
is(node.getAttribute("itemtype"), "", "node is neither a tab nor a client");
node = node.nextSibling;
is(node, null, "no more entries");
});

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

@ -4,6 +4,13 @@
"use strict";
const kXULWidgetId = "a-test-button"; // we'll create a button with this ID.
add_task(function setup() {
// create a XUL button and add it to the palette.
createDummyXULButton(kXULWidgetId, "test-button");
});
add_task(function customizeToolbarAndKeepIt() {
ok(gNavToolbox.toolbarset, "There should be a toolbarset");
let toolbarID = "testAustralisCustomToolbar";
@ -97,11 +104,11 @@ add_task(function resetShouldDealWithCustomToolbars() {
return;
}
ok(!CustomizableUI.getWidgetIdsInArea(toolbarDOMID).length, "There should be no widgets in the area yet.");
CustomizableUI.addWidgetToArea("sync-button", toolbarDOMID, 0);
CustomizableUI.addWidgetToArea(kXULWidgetId, toolbarDOMID, 0);
ok(toolbarElement.hasChildNodes(), "Toolbar should now have a button.");
assertAreaPlacements(toolbarDOMID, ["sync-button"]);
assertAreaPlacements(toolbarDOMID, [kXULWidgetId]);
gNavToolbox.toolbarset.setAttribute("toolbar2", toolbarID + ":sync-button");
gNavToolbox.toolbarset.setAttribute("toolbar2", `${toolbarID}:${kXULWidgetId}`);
document.persist(gNavToolbox.toolbarset.id, "toolbar2");
let newWindow = yield openAndLoadWindow({}, true);
@ -118,9 +125,9 @@ add_task(function resetShouldDealWithCustomToolbars() {
yield promiseWindowClosed(newWindow);
ok(CustomizableUI.inDefaultState, "Should be in default state after reset.");
let syncButton = document.getElementById("sync-button");
ok(!syncButton, "Sync button shouldn't be in the document anymore.");
ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button should be in the palette");
let xulButton = document.getElementById(kXULWidgetId);
ok(!xulButton, "XUL button shouldn't be in the document anymore.");
ok(gNavToolbox.palette.querySelector(`#${kXULWidgetId}`), "XUL button should be in the palette");
ok(!toolbarElement.hasChildNodes(), "Toolbar should have no more child nodes.");
ok(!toolbarElement.parentNode, "Toolbar should no longer be in the DOM.");
cuiAreaType = CustomizableUI.getAreaType(toolbarDOMID);

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

@ -26,7 +26,15 @@ add_task(function* testSyncButtonFunctionality() {
let syncButton = document.getElementById("sync-button");
ok(syncButton, "The Sync button was added to the Panel Menu");
// click the button - the panel should open.
syncButton.click();
let syncPanel = document.getElementById("PanelUI-remotetabs");
ok(syncPanel.getAttribute("current"), "Sync Panel is in view");
// Find and click the "setup" button.
let syncNowButton = document.getElementById("PanelUI-remotetabs-syncnow");
syncNowButton.click();
info("The sync button was clicked");
yield waitForCondition(() => syncWasCalled);

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

@ -6,33 +6,36 @@
const TOOLBARID = "test-toolbar-added-during-customize-mode";
// The ID of a button that is not placed (ie, is in the palette) by default
const kNonPlacedWidgetId = "open-file-button";
add_task(function*() {
yield startCustomizing();
let toolbar = createToolbarWithPlacements(TOOLBARID, []);
CustomizableUI.addWidgetToArea("sync-button", TOOLBARID);
let syncButton = document.getElementById("sync-button");
ok(syncButton, "Sync button should exist.");
is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should be a wrapper.");
CustomizableUI.addWidgetToArea(kNonPlacedWidgetId, TOOLBARID);
let button = document.getElementById(kNonPlacedWidgetId);
ok(button, "Button should exist.");
is(button.parentNode.localName, "toolbarpaletteitem", "Button's parent node should be a wrapper.");
simulateItemDrag(syncButton, gNavToolbox.palette);
ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
simulateItemDrag(button, gNavToolbox.palette);
ok(!CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId), "Button moved to the palette");
ok(gNavToolbox.palette.querySelector(`#${kNonPlacedWidgetId}`), "Button really is in palette.");
syncButton.scrollIntoView();
simulateItemDrag(syncButton, toolbar);
ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
button.scrollIntoView();
simulateItemDrag(button, toolbar);
ok(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId), "Button moved out of palette");
is(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId).area, TOOLBARID, "Button's back on toolbar");
ok(toolbar.querySelector(`#${kNonPlacedWidgetId}`), "Button really is on toolbar.");
yield endCustomizing();
isnot(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should not be a wrapper outside customize mode.");
isnot(button.parentNode.localName, "toolbarpaletteitem", "Button's parent node should not be a wrapper outside customize mode.");
yield startCustomizing();
is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should be a wrapper back in customize mode.");
is(button.parentNode.localName, "toolbarpaletteitem", "Button's parent node should be a wrapper back in customize mode.");
simulateItemDrag(syncButton, gNavToolbox.palette);
ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
simulateItemDrag(button, gNavToolbox.palette);
ok(!CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId), "Button moved to the palette");
ok(gNavToolbox.palette.querySelector(`#${kNonPlacedWidgetId}`), "Button really is in palette.");
ok(!CustomizableUI.inDefaultState, "Not in default state while toolbar is not collapsed yet.");
setToolbarVisibility(toolbar, false);
@ -50,11 +53,11 @@ add_task(function*() {
ok(!CustomizableUI.inDefaultState, "Now that the toolbar is registered again, should no longer be in default state.");
ok(gCustomizeMode.areas.has(toolbar), "Toolbar should be known to customize mode again.");
syncButton.scrollIntoView();
simulateItemDrag(syncButton, toolbar);
ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
button.scrollIntoView();
simulateItemDrag(button, toolbar);
ok(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId), "Button moved out of palette");
is(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId).area, TOOLBARID, "Button's back on toolbar");
ok(toolbar.querySelector(`#${kNonPlacedWidgetId}`), "Button really is on toolbar.");
let otherWin = yield openAndLoadWindow({}, true);
let otherTB = otherWin.document.createElementNS(kNSXUL, "toolbar");
@ -73,19 +76,19 @@ add_task(function*() {
ok(wasInformedCorrectlyOfAreaAppearing, "Should have been told area was registered.");
CustomizableUI.removeListener(listener);
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
ok(otherTB.querySelector(`#${kNonPlacedWidgetId}`), "Button is on other toolbar, too.");
simulateItemDrag(syncButton, gNavToolbox.palette);
ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
ok(!otherTB.querySelector("#sync-button"), "Sync button is in palette in other window, too.");
simulateItemDrag(button, gNavToolbox.palette);
ok(!CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId), "Button moved to the palette");
ok(gNavToolbox.palette.querySelector(`#${kNonPlacedWidgetId}`), "Button really is in palette.");
ok(!otherTB.querySelector(`#${kNonPlacedWidgetId}`), "Button is in palette in other window, too.");
syncButton.scrollIntoView();
simulateItemDrag(syncButton, toolbar);
ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
button.scrollIntoView();
simulateItemDrag(button, toolbar);
ok(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId), "Button moved out of palette");
is(CustomizableUI.getPlacementOfWidget(kNonPlacedWidgetId).area, TOOLBARID, "Button's back on toolbar");
ok(toolbar.querySelector(`#${kNonPlacedWidgetId}`), "Button really is on toolbar.");
ok(otherTB.querySelector(`#${kNonPlacedWidgetId}`), "Button is on other toolbar, too.");
let wasInformedCorrectlyOfAreaDisappearing = false;
//XXXgijs So we could be using promiseWindowClosed here. However, after
@ -120,7 +123,7 @@ add_task(function*() {
is(windowClosed, otherWin, "Window should have sent onWindowClosed notification.");
ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
// Closing the other window should not be counted against this window's customize mode:
is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should still be a wrapper.");
is(button.parentNode.localName, "toolbarpaletteitem", "Button's parent node should still be a wrapper.");
ok(gCustomizeMode.areas.has(toolbar), "Toolbar should still be a customizable area for this customize mode instance.");
yield gCustomizeMode.reset();

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

@ -26,12 +26,12 @@ var {synthesizeDragStart, synthesizeDrop} = ChromeUtils;
const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const kTabEventFailureTimeoutInMs = 20000;
function createDummyXULButton(id, label) {
function createDummyXULButton(id, label, win = window) {
let btn = document.createElementNS(kNSXUL, "toolbarbutton");
btn.id = id;
btn.setAttribute("label", label || id);
btn.className = "toolbarbutton-1 chromeclass-toolbar-additional";
window.gNavToolbox.palette.appendChild(btn);
win.gNavToolbox.palette.appendChild(btn);
return btn;
}

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

@ -32,6 +32,8 @@ function BrowserAction(options, extension)
this.id = makeWidgetId(extension.id) + "-browser-action";
this.widget = null;
this.tabManager = TabManager.for(extension);
let title = extension.localize(options.default_title || "");
let popup = extension.localize(options.default_popup || "");
if (popup) {
@ -74,6 +76,7 @@ BrowserAction.prototype = {
node.addEventListener("command", event => {
let tab = tabbrowser.selectedTab;
let popup = this.getProperty(tab, "popup");
this.tabManager.addActiveTabPermission(tab);
if (popup) {
this.togglePopup(node, popup);
} else {

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

@ -43,8 +43,11 @@ var menuBuilder = {
for (let [ext, menuItemMap] of contextMenuMap) {
let parentMap = new Map();
let topLevelItems = new Set();
for (let [id, item] of menuItemMap) {
dump(id + " : " + item + "\n");
for (let entry of menuItemMap) {
// We need a closure over |item|, and we don't currently get a
// fresh binding per loop if we declare it in the loop head.
let [id, item] = entry;
if (item.enabledForContext(contextData)) {
let element;
if (item.isMenu) {
@ -79,15 +82,13 @@ var menuBuilder = {
topLevelItems.add(element);
}
if (item.onclick) {
function clickHandlerForItem(item) {
return event => {
let clickData = item.getClickData(contextData, event);
runSafe(item.extContext, item.onclick, clickData);
}
element.addEventListener("command", event => {
item.tabManager.addActiveTabPermission();
if (item.onclick) {
let clickData = item.getClickData(contextData, event);
runSafe(item.extContext, item.onclick, clickData);
}
element.addEventListener("command", clickHandlerForItem(item));
}
});
}
}
if (topLevelItems.size > 1) {
@ -166,6 +167,8 @@ function MenuItem(extension, extContext, createProperties)
this.extension = extension;
this.extContext = extContext;
this.tabManager = TabManager.for(extension);
this.init(createProperties);
}

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

@ -20,6 +20,8 @@ function PageAction(options, extension)
this.extension = extension;
this.id = makeWidgetId(extension.id) + "-page-action";
this.tabManager = TabManager.for(extension);
let title = extension.localize(options.default_title || "");
let popup = extension.localize(options.default_popup || "");
if (popup) {
@ -139,6 +141,8 @@ PageAction.prototype = {
let tab = window.gBrowser.selectedTab;
let popup = this.tabContext.get(tab).popup;
this.tabManager.addActiveTabPermission(tab);
if (popup) {
openPanel(this.getButton(window), popup, this.extension);
} else {

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

@ -457,13 +457,8 @@ extensions.registerAPI((extension, context) => {
}
let result = [];
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
let window = e.getNext();
if (window.document.readyState != "complete") {
continue;
}
let tabs = TabManager.getTabs(extension, window);
for (let window of WindowListManager.browserWindows()) {
let tabs = TabManager.for(extension).getTabs(window);
for (let tab of tabs) {
if (matches(window, tab)) {
result.push(tab);
@ -477,12 +472,38 @@ extensions.registerAPI((extension, context) => {
let tab = tabId ? TabManager.getTab(tabId) : TabManager.activeTab;
let mm = tab.linkedBrowser.messageManager;
let options = {js: [], css: []};
let options = {
js: [],
css: [],
// We need to send the inner window ID to make sure we only
// execute the script if the window is currently navigated to
// the document that we expect.
//
// TODO: When we add support for callbacks, non-matching
// window IDs and insufficient permissions need to result in a
// callback with |lastError| set.
innerWindowID: tab.linkedBrowser.innerWindowID,
};
if (TabManager.for(extension).hasActiveTabPermission(tab)) {
// If we have the "activeTab" permission for this tab, ignore
// the host whitelist.
options.matchesHost = ["<all_urls>"];
} else {
options.matchesHost = extension.whiteListedHosts.serialize();
}
if (details.code) {
options[kind + 'Code'] = details.code;
}
if (details.file) {
options[kind].push(extension.baseURI.resolve(details.file));
let url = context.uri.resolve(details.file);
if (extension.isExtensionURL(url)) {
// We should really set |lastError| here, and go straight to
// the callback, but we don't have |lastError| yet.
options[kind].push(url);
}
}
if (details.allFrames) {
options.all_frames = details.allFrames;

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

@ -267,7 +267,87 @@ TabContext.prototype = {
},
};
// Manages mapping between XUL tabs and extension tab IDs.
// Manages tab mappings and permissions for a specific extension.
function ExtensionTabManager(extension) {
this.extension = extension;
// A mapping of tab objects to the inner window ID the extension currently has
// the active tab permission for. The active permission for a given tab is
// valid only for the inner window that was active when the permission was
// granted. If the tab navigates, the inner window ID changes, and the
// permission automatically becomes stale.
//
// WeakMap[tab => inner-window-id<int>]
this.hasTabPermissionFor = new WeakMap();
}
ExtensionTabManager.prototype = {
addActiveTabPermission(tab = TabManager.activeTab) {
if (this.extension.hasPermission("activeTab")) {
// Note that, unlike Chrome, we don't currently clear this permission with
// the tab navigates. If the inner window is revived from BFCache before
// we've granted this permission to a new inner window, the extension
// maintains its permissions for it.
this.hasTabPermissionFor.set(tab, tab.linkedBrowser.innerWindowID);
}
},
// Returns true if the extension has the "activeTab" permission for this tab.
// This is somewhat more permissive than the generic "tabs" permission, as
// checked by |hasTabPermission|, in that it also allows programmatic script
// injection without an explicit host permission.
hasActiveTabPermission(tab) {
// This check is redundant with addTabPermission, but cheap.
if (this.extension.hasPermission("activeTab")) {
return (this.hasTabPermissionFor.has(tab) &&
this.hasTabPermissionFor.get(tab) === tab.linkedBrowser.innerWindowID);
}
return false;
},
hasTabPermission(tab) {
return this.extension.hasPermission("tabs") || this.hasActiveTabPermission(tab);
},
convert(tab) {
let window = tab.ownerDocument.defaultView;
let windowActive = window == WindowManager.topWindow;
let result = {
id: TabManager.getId(tab),
index: tab._tPos,
windowId: WindowManager.getId(window),
selected: tab.selected,
highlighted: tab.selected,
active: tab.selected,
pinned: tab.pinned,
status: TabManager.getStatus(tab),
incognito: PrivateBrowsingUtils.isBrowserPrivate(tab.linkedBrowser),
width: tab.linkedBrowser.clientWidth,
height: tab.linkedBrowser.clientHeight,
};
if (this.hasTabPermission(tab)) {
result.url = tab.linkedBrowser.currentURI.spec;
if (tab.linkedBrowser.contentTitle) {
result.title = tab.linkedBrowser.contentTitle;
}
let icon = window.gBrowser.getIcon(tab);
if (icon) {
result.favIconUrl = icon;
}
}
return result;
},
getTabs(window) {
return Array.from(window.gBrowser.tabs, tab => this.convert(tab));
},
};
// Manages global mappings between XUL tabs and extension tab IDs.
global.TabManager = {
_tabs: new WeakMap(),
_nextId: 1,
@ -322,44 +402,26 @@ global.TabManager = {
},
convert(extension, tab) {
let window = tab.ownerDocument.defaultView;
let windowActive = window == WindowManager.topWindow;
let result = {
id: this.getId(tab),
index: tab._tPos,
windowId: WindowManager.getId(window),
selected: tab.selected,
highlighted: tab.selected,
active: tab.selected,
pinned: tab.pinned,
status: this.getStatus(tab),
incognito: PrivateBrowsingUtils.isBrowserPrivate(tab.linkedBrowser),
width: tab.linkedBrowser.clientWidth,
height: tab.linkedBrowser.clientHeight,
};
if (extension.hasPermission("tabs")) {
result.url = tab.linkedBrowser.currentURI.spec;
if (tab.linkedBrowser.contentTitle) {
result.title = tab.linkedBrowser.contentTitle;
}
let icon = window.gBrowser.getIcon(tab);
if (icon) {
result.favIconUrl = icon;
}
}
return result;
},
getTabs(extension, window) {
if (!window.gBrowser) {
return [];
}
return Array.map(window.gBrowser.tabs, tab => this.convert(extension, tab));
return TabManager.for(extension).convert(tab);
},
};
// WeakMap[Extension -> ExtensionTabManager]
let tabManagers = new WeakMap();
// Returns the extension-specific tab manager for the given extension, or
// creates one if it doesn't already exist.
TabManager.for = function (extension) {
if (!tabManagers.has(extension)) {
tabManagers.set(extension, new ExtensionTabManager(extension));
}
return tabManagers.get(extension);
};
extensions.on("shutdown", (type, extension) => {
tabManagers.delete(extension);
});
// Manages mapping between XUL windows and extension window IDs.
global.WindowManager = {
_windows: new WeakMap(),
@ -411,7 +473,7 @@ global.WindowManager = {
};
if (getInfo && getInfo.populate) {
results.tabs = TabManager.getTabs(extension, window);
results.tabs = TabManager.for(extension).getTabs(window);
}
return result;

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

@ -20,7 +20,8 @@ support-files =
[browser_ext_popup_api_injection.js]
[browser_ext_contextMenus.js]
[browser_ext_getViews.js]
[browser_ext_tabs_executeScript.js]
[browser_ext_tabs_executeScript_good.js]
[browser_ext_tabs_executeScript_bad.js]
[browser_ext_tabs_query.js]
[browser_ext_tabs_getCurrent.js]
[browser_ext_tabs_update.js]

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

@ -3,7 +3,7 @@ add_task(function* () {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["http://mochi.test/"]
},
background: function() {

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

@ -1,32 +0,0 @@
add_task(function* () {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
},
background: function() {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "script ran", "script ran");
browser.test.notifyPass("executeScript");
});
browser.tabs.executeScript({
file: "script.js"
});
},
files: {
"script.js": function() {
browser.runtime.sendMessage("script ran");
}
}
});
yield extension.startup();
yield extension.awaitFinish("executeScript");
yield extension.unload();
yield BrowserTestUtils.removeTab(tab);
});

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

@ -0,0 +1,110 @@
"use strict";
// This is a pretty terrible hack, but it's the best we can do until we
// support |executeScript| callbacks and |lastError|.
function* testHasNoPermission(params) {
let contentSetup = params.contentSetup || (() => Promise.resolve());
let extension = ExtensionTestUtils.loadExtension({
manifest: params.manifest,
background: `(${function(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "second script ran", "second script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
browser.tabs.query({ activeWindow: true }, tabs => {
browser.tabs.executeScript({
file: "script.js"
});
// Execute a script we know we have permissions for in the
// second tab, in the hopes that it will execute after the
// first one. This has intermittent failure written all over
// it, but it's just about the best we can do until we
// support callbacks for executeScript.
browser.tabs.executeScript(tabs[1].id, {
file: "second-script.js"
});
});
});
contentSetup().then(() => {
browser.test.sendMessage("ready");
});
}})(${contentSetup})`,
files: {
"script.js": function() {
browser.runtime.sendMessage("first script ran");
},
"second-script.js": function() {
browser.runtime.sendMessage("second script ran");
}
}
});
yield extension.startup();
yield extension.awaitMessage("ready");
if (params.setup) {
yield params.setup(extension);
}
extension.sendMessage("execute-script");
yield extension.awaitFinish("executeScript");
yield extension.unload();
}
add_task(function* testBadPermissions() {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
info("Test no special permissions");
yield testHasNoPermission({
manifest: { "permissions": ["http://example.com/"] }
});
info("Test tabs permissions");
yield testHasNoPermission({
manifest: { "permissions": ["http://example.com/", "tabs"] }
});
info("Test active tab, browser action, no click");
yield testHasNoPermission({
manifest: {
"permissions": ["http://example.com/", "activeTab"],
"browser_action": {},
},
});
info("Test active tab, page action, no click");
yield testHasNoPermission({
manifest: {
"permissions": ["http://example.com/", "activeTab"],
"page_action": {},
},
contentSetup() {
return new Promise(resolve => {
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
browser.pageAction.show(tabs[0].id);
resolve();
});
});
}
});
yield BrowserTestUtils.removeTab(tab2);
yield BrowserTestUtils.removeTab(tab1);
});
// TODO: Test that |executeScript| fails if the tab has navigated to a
// new page, and no longer matches our expected state. This involves
// intentionally trying to trigger a race condition, and is probably not
// even worth attempting until we have proper |executeScript| callbacks.

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

@ -0,0 +1,151 @@
"use strict";
function* testHasPermission(params) {
let contentSetup = params.contentSetup || (() => Promise.resolve());
let extension = ExtensionTestUtils.loadExtension({
manifest: params.manifest,
background: `(${function(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "script ran", "script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
browser.tabs.executeScript({
file: "script.js"
});
});
contentSetup().then(() => {
browser.test.sendMessage("ready");
});
}})(${contentSetup})`,
files: {
"script.js": function() {
browser.runtime.sendMessage("script ran");
}
}
});
yield extension.startup();
yield extension.awaitMessage("ready");
if (params.setup) {
yield params.setup(extension);
}
extension.sendMessage("execute-script");
yield extension.awaitFinish("executeScript");
yield extension.unload();
}
add_task(function* testGoodPermissions() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true);
info("Test explicit host permission");
yield testHasPermission({
manifest: { "permissions": ["http://mochi.test/"] }
});
info("Test explicit host subdomain permission");
yield testHasPermission({
manifest: { "permissions": ["http://*.mochi.test/"] }
});
info("Test explicit <all_urls> permission");
yield testHasPermission({
manifest: { "permissions": ["<all_urls>"] }
});
info("Test activeTab permission with a browser action click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab"],
"browser_action": {},
},
contentSetup() {
browser.browserAction.onClicked.addListener(() => {
browser.test.log("Clicked.");
});
return Promise.resolve();
},
setup: clickBrowserAction,
});
info("Test activeTab permission with a page action click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab"],
"page_action": {},
},
contentSetup() {
return new Promise(resolve => {
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
browser.pageAction.show(tabs[0].id);
resolve();
});
});
},
setup: clickPageAction,
});
info("Test activeTab permission with a browser action w/popup click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab"],
"browser_action": { "default_popup": "_blank.html" },
},
setup: clickBrowserAction,
});
info("Test activeTab permission with a page action w/popup click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab"],
"page_action": { "default_popup": "_blank.html" },
},
contentSetup() {
return new Promise(resolve => {
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
browser.pageAction.show(tabs[0].id);
resolve();
});
});
},
setup: clickPageAction,
});
info("Test activeTab permission with a context menu click");
yield testHasPermission({
manifest: {
"permissions": ["activeTab", "contextMenus"],
},
contentSetup() {
browser.contextMenus.create({ title: "activeTab", contexts: ["all"] });
return Promise.resolve();
},
setup: function* (extension) {
let contextMenu = document.getElementById("contentAreaContextMenu");
let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
yield BrowserTestUtils.synthesizeMouseAtCenter("a[href]", { type: "contextmenu", button: 2 },
gBrowser.selectedBrowser);
yield awaitPopupShown;
let item = contextMenu.querySelector("[label=activeTab]");
yield EventUtils.synthesizeMouseAtCenter(item, {}, window);
yield awaitPopupHidden;
},
});
yield BrowserTestUtils.removeTab(tab);
});

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

@ -44,6 +44,6 @@ function clickPageAction(extension, win = window) {
let pageActionId = makeWidgetId(extension.id) + "-page-action";
let elem = win.document.getElementById(pageActionId);
EventUtils.synthesizeMouse(elem, 8, 8, {}, win);
EventUtils.synthesizeMouseAtCenter(elem, {}, win);
return new Promise(SimpleTest.executeSoon);
}

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

@ -422,39 +422,16 @@ BrowserGlue.prototype = {
this._dispose();
break;
case "keyword-search":
// This is very similar to code in
// browser.js:BrowserSearch.recordSearchInHealthReport(). The code could
// be consolidated if there is will. We need the observer in
// nsBrowserGlue to prevent double counting.
let win = RecentWindow.getMostRecentBrowserWindow();
BrowserUITelemetry.countSearchEvent("urlbar", win.gURLBar.value);
// This notification is broadcast by the docshell when it "fixes up" a
// URI that it's been asked to load into a keyword search.
let engine = null;
try {
engine = subject.QueryInterface(Ci.nsISearchEngine);
} catch (ex) {
Cu.reportError(ex);
}
win.BrowserSearch.recordSearchInTelemetry(engine, "urlbar");
#ifdef MOZ_SERVICES_HEALTHREPORT
let reporter = Cc["@mozilla.org/datareporting/service;1"]
.getService()
.wrappedJSObject
.healthReporter;
if (!reporter) {
return;
}
reporter.onInit().then(function record() {
try {
reporter.getProvider("org.mozilla.searches").recordSearch(engine, "urlbar");
} catch (ex) {
Cu.reportError(ex);
}
});
#endif
let win = RecentWindow.getMostRecentBrowserWindow();
win.BrowserSearch.recordSearchInHealthReport(engine, "urlbar");
break;
case "browser-search-engine-modified":
// Ensure we cleanup the hiddenOneOffs pref when removing

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

@ -1223,16 +1223,7 @@ this.PlacesUIUtils = {
shouldShowTabsFromOtherComputersMenuitem: function() {
let weaveOK = Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED &&
Weave.Svc.Prefs.get("firstSync", "") != "notReady";
let cloudSyncOK = CloudSync && CloudSync.ready && CloudSync().tabsReady && CloudSync().tabs.hasRemoteTabs();
return weaveOK || cloudSyncOK;
},
shouldEnableTabsFromOtherComputersMenuitem: function() {
let weaveEnabled = Weave.Service.isLoggedIn &&
Weave.Service.engineManager.get("tabs") &&
Weave.Service.engineManager.get("tabs").enabled;
let cloudSyncEnabled = CloudSync && CloudSync.ready && CloudSync().tabsReady && CloudSync().tabs.hasRemoteTabs();
return weaveEnabled || cloudSyncEnabled;
return weaveOK;
},
/**

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

@ -134,11 +134,16 @@ var gSyncPane = {
XPCOMUtils.defineLazyGetter(this, '_stringBundle', () => {
return Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
}),
});
XPCOMUtils.defineLazyGetter(this, '_accountsStringBundle', () => {
return Services.strings.createBundle("chrome://browser/locale/accounts.properties");
}),
});
let url = Services.prefs.getCharPref("identity.mobilepromo.android") + "sync-preferences";
document.getElementById("fxaMobilePromo-android").setAttribute("href", url);
url = Services.prefs.getCharPref("identity.mobilepromo.ios") + "sync-preferences";
document.getElementById("fxaMobilePromo-ios").setAttribute("href", url);
this.updateWeavePrefs();

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

@ -214,12 +214,12 @@
</hbox>
<label class="fxaMobilePromo">
&mobilePromo2.start;<!-- We put these comments to avoid inserting white spaces
--><label class="androidLink text-link"
href="https://www.mozilla.org/firefox/android/?utm_source=firefox-browser&amp;utm_medium=firefox-browser&amp;utm_campaign=sync-preferences"><!--
--><label id="fxaMobilePromo-android"
class="androidLink text-link"><!--
-->&mobilePromo2.androidLink;</label><!--
-->&mobilePromo2.iOSBefore;<!--
--><label class="iOSLink text-link"
href="https://www.mozilla.org/firefox/ios/?utm_source=firefox-browser&amp;utm_medium=firefox-browser&amp;utm_campaign=sync-preferences"><!--
--><label id="fxaMobilePromo-ios"
class="iOSLink text-link"><!--
-->&mobilePromo2.iOSLink;</label><!--
-->&mobilePromo2.end;
</label>

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

@ -47,6 +47,8 @@ var gTests = [
searchForm: "http://mochi.test:8888/browser/browser/components/search/test/"
},
run: function () {
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml",
null, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC",
false);
@ -72,6 +74,12 @@ var gTests = [
gSS.removeEngine(engine);
},
removed: function (engine) {
// Remove the observer before calling the currentEngine getter,
// as that getter will set the currentEngine to the original default
// which will trigger a notification causing the test to loop over all
// engines.
Services.obs.removeObserver(observer, "browser-search-engine-modified");
let currentEngine = gSS.currentEngine;
ok(currentEngine, "An engine is present.");
isnot(currentEngine.name, this.engine.name, "Current engine reset after removal");
@ -93,12 +101,5 @@ function nextTest() {
function test() {
waitForExplicitFinish();
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
registerCleanupFunction(cleanup);
nextTest();
}
function cleanup() {
Services.obs.removeObserver(observer, "browser-search-engine-modified");
}

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

@ -735,13 +735,12 @@ this.UITour = {
}
}
this.initForBrowser(browser);
this.initForBrowser(browser, window);
return true;
},
initForBrowser(aBrowser) {
let window = aBrowser.ownerDocument.defaultView;
initForBrowser(aBrowser, window) {
let gBrowser = window.gBrowser;
if (gBrowser) {

70
browser/extensions/loop/bootstrap.js поставляемый
Просмотреть файл

@ -11,6 +11,7 @@ const kPrefBrowserSharingInfoBar = "browserSharing.showInfoBar";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
@ -39,7 +40,8 @@ var WindowListener = {
var LoopUI = {
/**
* @var {XULWidgetSingleWrapper} toolbarButton Getter for the Loop toolbarbutton
* instance for this window.
* instance for this window. This should
* not be used in the hidden window.
*/
get toolbarButton() {
delete this.toolbarButton;
@ -262,18 +264,10 @@ var WindowListener = {
},
/**
* Triggers the initialization of the loop service. Called by
* delayedStartup.
* Triggers the initialization of the loop service if necessary.
* Also adds appropraite observers for the UI.
*/
init: function() {
// Cleanup when the window unloads.
window.addEventListener("unload", () => {
this.uninit();
});
// Add observer notifications before the service is initialized
Services.obs.addObserver(this, "loop-status-changed", false);
// This is a promise for test purposes, but we don't want to be logging
// expected errors to the console, so we catch them here.
this.MozLoopService.initialize().catch(ex => {
@ -283,11 +277,21 @@ var WindowListener = {
console.error(ex);
}
});
this.updateToolbarState();
},
uninit: function() {
Services.obs.removeObserver(this, "loop-status-changed");
// Don't do the rest if this is for the hidden window - we don't
// have a toolbar there.
if (window == Services.appShell.hiddenDOMWindow) {
return;
}
// Cleanup when the window unloads.
window.addEventListener("unload", () => {
Services.obs.removeObserver(this, "loop-status-changed");
});
Services.obs.addObserver(this, "loop-status-changed", false);
this.updateToolbarState();
},
// Implements nsIObserver
@ -299,7 +303,8 @@ var WindowListener = {
},
/**
* Updates the toolbar/menu-button state to reflect Loop status.
* Updates the toolbar/menu-button state to reflect Loop status. This should
* not be called from the hidden window.
*
* @param {string} [aReason] Some states are only shown if
* a related reason is provided.
@ -351,7 +356,8 @@ var WindowListener = {
},
/**
* Updates the tootltiptext to reflect Loop status.
* Updates the tootltiptext to reflect Loop status. This should not be called
* from the hidden window.
*
* @param {string} [mozL10nId] l10n ID that refelct the current
* Loop status.
@ -758,15 +764,17 @@ function startup() {
createLoopButton();
// Attach to hidden window (for OS X).
try {
WindowListener.setupBrowserUI(Services.appShell.hiddenDOMWindow);
} catch (ex) {
// Hidden window didn't exist, so wait until startup is done.
let topic = "browser-delayed-startup-finished";
Services.obs.addObserver(function observer() {
Services.obs.removeObserver(observer, topic);
if (AppConstants.platform == "macosx") {
try {
WindowListener.setupBrowserUI(Services.appShell.hiddenDOMWindow);
}, topic, false);
} catch (ex) {
// Hidden window didn't exist, so wait until startup is done.
let topic = "browser-delayed-startup-finished";
Services.obs.addObserver(function observer() {
Services.obs.removeObserver(observer, topic);
WindowListener.setupBrowserUI(Services.appShell.hiddenDOMWindow);
}, topic, false);
}
}
// Attach to existing browser windows, for modifying UI.
@ -783,8 +791,12 @@ function startup() {
// Load our stylesheets.
let styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"]
.getService(Components.interfaces.nsIStyleSheetService);
let sheets = ["chrome://loop-shared/skin/loop.css",
"chrome://loop/skin/platform.css"];
let sheets = ["chrome://loop-shared/skin/loop.css"];
if (AppConstants.platform != "linux") {
sheets.push("chrome://loop/skin/platform.css");
}
for (let sheet of sheets) {
let styleSheetURI = Services.io.newURI(sheet, null, null);
// XXX We would love to specify AUTHOR_SHEET here and in shutdown, however
@ -809,7 +821,9 @@ function shutdown() {
});
// Detach from hidden window (for OS X).
WindowListener.tearDownBrowserUI(Services.appShell.hiddenDOMWindow);
if (AppConstants.platform == "macosx") {
WindowListener.tearDownBrowserUI(Services.appShell.hiddenDOMWindow);
}
// Detach from browser windows.
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);

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

@ -24,10 +24,6 @@ ifdef MOZ_DEBUG
DEFINES += -DMOZ_DEBUG=1
endif
ifdef MOZ_ENABLE_GNOME_COMPONENT
DEFINES += -DMOZ_ENABLE_GNOME_COMPONENT=1
endif
ifdef MOZ_WIDGET_GTK
DEFINES += -DMOZ_GTK=1
ifdef MOZ_ENABLE_GTK3

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

@ -495,12 +495,6 @@
#ifdef XP_MACOSX
@RESPATH@/browser/components/SafariProfileMigrator.js
#endif
#ifdef MOZ_ENABLE_GNOME_COMPONENT
@RESPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@
#endif
#if defined(MOZ_ENABLE_DBUS) || defined(MOZ_ENABLE_GNOME_COMPONENT)
@RESPATH@/components/components.manifest
#endif
@RESPATH@/components/nsINIProcessor.manifest
@RESPATH@/components/nsINIProcessor.js
@RESPATH@/components/nsPrompter.manifest

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

@ -37,7 +37,7 @@
!define BrandFullName "${BrandFullNameInternal}"
!define CERTIFICATE_NAME "Mozilla Corporation"
!define CERTIFICATE_ISSUER "DigiCert Assured ID Code Signing CA-1"
!define CERTIFICATE_ISSUER "DigiCert SHA2 Assured ID Code Signing CA"
# LSP_CATEGORIES is the permitted LSP categories for the application. Each LSP
# category value is ANDed together to set multiple permitted categories.

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

@ -220,7 +220,7 @@ Section "MaintenanceService"
; These keys are used to bypass the installation dir is a valid installation
; check from the service so that tests can be run.
; WriteRegStr HKLM "${FallbackKey}\0" "name" "Mozilla Corporation"
; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "DigiCert Assured ID Code Signing CA-1"
; WriteRegStr HKLM "${FallbackKey}\0" "issuer" "DigiCert SHA2 Assured ID Code Signing CA"
${If} ${RunningX64}
SetRegView lastused
${EndIf}

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

@ -2,7 +2,6 @@
- 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/. -->
<!-- LOCALIZATION NOTE (tabs.otherDevices.label): Keep this in sync with syncTabsMenu2.label from browser.dtd -->
<!ENTITY tabs.otherDevices.label "Tabs From Other Devices">
<!ENTITY tabs.searchText.label "Type here to find tabs…">

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

@ -410,6 +410,22 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY appMenuHistory.viewSidebar.label "View History Sidebar">
<!ENTITY appMenuHelp.tooltip "Open Help Menu">
<!ENTITY appMenuRemoteTabs.label "Synced Tabs">
<!ENTITY appMenuRemoteTabs.fetching.label "Fetching Synced Tabs…">
<!-- LOCALIZATION NOTE (appMenuRemoteTabs.notabs.label): This is shown beneath
the name of a device when that device has no open tabs -->
<!ENTITY appMenuRemoteTabs.notabs.label "No open tabs">
<!-- LOCALIZATION NOTE (appMenuRemoteTabs.tabsnotsyncing.label): This is shown
when Sync is configured but syncing tabs is disabled. -->
<!ENTITY appMenuRemoteTabs.tabsnotsyncing.label "Turn on tab syncing to view a list of tabs from your other devices.">
<!-- LOCALIZATION NOTE (appMenuRemoteTabs.noclients.label): This is shown
when Sync is configured but this appears to be the only device attached to
the account. We also show links to download Firefox for android/ios. -->
<!ENTITY appMenuRemoteTabs.noclients.label "Sign in to Firefox from your other devices to view their tabs here.">
<!ENTITY appMenuRemoteTabs.openprefs.label "Sync Preferences">
<!ENTITY appMenuRemoteTabs.notsignedin.label "Sign in to view a list of tabs from your other devices.">
<!ENTITY appMenuRemoteTabs.signin.label "Sign in to Sync">
<!ENTITY customizeMenu.addToToolbar.label "Add to Toolbar">
<!ENTITY customizeMenu.addToToolbar.accesskey "A">
<!ENTITY customizeMenu.addToPanel.label "Add to Menu">
@ -771,8 +787,8 @@ you can use these alternative items. Otherwise, their values should be empty. -
The word "toolbar" is appended automatically and should not be contained below! -->
<!ENTITY tabsToolbar.label "Browser tabs">
<!-- LOCALIZATION NOTE (syncTabsMenu2.label): This appears in the history menu -->
<!ENTITY syncTabsMenu2.label "Tabs From Other Devices">
<!-- LOCALIZATION NOTE (syncTabsMenu3.label): This appears in the history menu and history panel -->
<!ENTITY syncTabsMenu3.label "Synced Tabs">
<!ENTITY syncBrand.shortName.label "Sync">

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

@ -728,6 +728,17 @@ appmenu.downloadUpdateButton.label = Download Update
readingList.promo.firstUse.readerView.title = Reader View
readingList.promo.firstUse.readerView.body = Remove clutter so you can focus exactly on what you want to read.
# LOCALIZATION NOTE (appMenuRemoteTabs.mobilePromo):
# %1$S will be replaced with a link, the text of which is
# appMenuRemoteTabs.mobilePromo.android and the link will be to
# https://www.mozilla.org/firefox/android/.
# %2$S will be replaced with a link, the text of which is
# appMenuRemoteTabs.mobilePromo.ios
# and the link will be to https://www.mozilla.org/firefox/ios/.
appMenuRemoteTabs.mobilePromo = Get %1$S or %2$S.
appMenuRemoteTabs.mobilePromo.android = Firefox for Android
appMenuRemoteTabs.mobilePromo.ios = Firefox for iOS
# LOCALIZATION NOTE (e10s.offerPopup.mainMessage
# e10s.offerPopup.highlight1
# e10s.offerPopup.highlight2

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

@ -6,6 +6,9 @@ history-panelmenu.label = History
# LOCALIZATION NOTE(history-panelmenu.tooltiptext2): %S is the keyboard shortcut
history-panelmenu.tooltiptext2 = Show your history (%S)
remotetabs-panelmenu.label = Synced Tabs
remotetabs-panelmenu.tooltiptext = Show your synced tabs from other devices
privatebrowsing-button.label = New Private Window
# LOCALIZATION NOTE(privatebrowsing-button.tooltiptext): %S is the keyboard shortcut
privatebrowsing-button.tooltiptext = Open a new Private Browsing window (%S)

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

@ -7,6 +7,8 @@
<!ENTITY loadError.label "Problem loading page">
<!ENTITY retry.label "Try Again">
<!ENTITY returnToPreviousPage.label "Go Back">
<!ENTITY advanced.label "Advanced">
<!-- Specific error messages -->
@ -202,9 +204,7 @@ functionality specific to firefox. -->
<button id='exceptionDialogButton'>&securityOverride.exceptionButtonLabel;</button>
">
<!ENTITY errorReporting.title "Report this error">
<!ENTITY errorReporting.longDesc "Reporting the address and certificate information for <span id='hostname'></span> will help us identify and block malicious sites. Thanks for helping create a safer web!">
<!ENTITY errorReporting.automatic "Automatically report errors in the future">
<!ENTITY errorReporting.automatic2 "Report errors like this to help Mozilla identify and block malicious sites">
<!ENTITY errorReporting.learnMore "Learn more…">
<!ENTITY errorReporting.sending "Sending report">
<!ENTITY errorReporting.sent "Report sent">
@ -218,13 +218,11 @@ functionality specific to firefox. -->
<!-- LOCALIZATION NOTE (sslv3Used.longDesc) - Do not translate
"ssl_error_unsupported_version". -->
<!ENTITY sslv3Used.longDesc "Advanced info: ssl_error_unsupported_version">
<!ENTITY sslv3Used.learnMore "Learn More…">
<!ENTITY weakCryptoUsed.title "Your connection is not secure">
<!-- LOCALIZATION NOTE (weakCryptoUsed.longDesc) - Do not translate
"ssl_error_no_cypher_overlap". -->
<!ENTITY weakCryptoUsed.longDesc "Advanced info: ssl_error_no_cypher_overlap">
<!ENTITY weakCryptoUsed.learnMore "Learn More…">
<!ENTITY weakCryptoAdvanced.title "Advanced">
<!ENTITY weakCryptoAdvanced.longDesc "<span class='hostname'></span> uses security technology that is outdated and vulnerable to attack. An attacker could easily reveal information which you thought to be safe.">
<!ENTITY weakCryptoAdvanced.override "(Not secure) Try loading <span class='hostname'></span> using outdated security">

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

@ -5,3 +5,4 @@ google
twitter
wikipedia
yahoo
yahoo-en-CA:hidden

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -162,7 +162,7 @@ this.TabGroupsMigrator = {
let groupFolder = yield PlacesUtils.bookmarks.insert({
parentGuid: tabgroupsFolder.guid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: group.title ||
title: group.tabGroupsMigrationTitle ||
gBrowserBundle.formatStringFromName("tabgroups.migration.anonGroup", [group.anonGroupID], 1),
}).catch(Cu.reportError);

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

@ -146,6 +146,29 @@ add_task(function* test_selfSupport() {
uitourAPI.ping(resolve);
});
yield pingPromise;
info("Ping succeeded");
let observePromise = ContentTask.spawn(selfSupportBrowser, null, function* checkObserve() {
yield new Promise(resolve => {
let win = Cu.waiveXrays(content);
win.Mozilla.UITour.observe((event, data) => {
if (event != "Heartbeat:Engaged") {
return;
}
is(data.flowId, "myFlowID", "Check flowId");
ok(!!data.timestamp, "Check timestamp");
resolve(data);
}, () => {});
});
});
info("Notifying Heartbeat:Engaged");
UITour.notify("Heartbeat:Engaged", {
flowId: "myFlowID",
timestamp: Date.now(),
});
yield observePromise;
info("Observed in the hidden frame");
// Close SelfSupport from content.
contentWindow.close();

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

@ -78,7 +78,9 @@ add_task(function* gatherGroupDataTest() {
});
add_task(function* bookmarkingTest() {
let groupInfo = TabGroupsMigrator._gatherGroupData(TEST_STATES.TWO_GROUPS);
let stateClone = JSON.parse(JSON.stringify(TEST_STATES.TWO_GROUPS));
let groupInfo = TabGroupsMigrator._gatherGroupData(stateClone);
let removedGroups = TabGroupsMigrator._removeHiddenTabGroupsFromState(stateClone, groupInfo);
yield TabGroupsMigrator._bookmarkAllGroupsFromState(groupInfo);
let bmCounter = 0;
let bmParents = {};

Двоичные данные
browser/themes/linux/Toolbar-inverted.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/linux/Toolbar.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/linux/menuPanel.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/linux/menuPanel@2x.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/Toolbar-inverted.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/Toolbar-inverted@2x.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/Toolbar-yosemite.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/Toolbar-yosemite@2x.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/Toolbar.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/Toolbar@2x.png

Двоичный файл не отображается.

До

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

После

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

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

@ -811,8 +811,8 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
-moz-image-region: rect(18px, 252px, 36px, 234px);
}
#sync-button@toolbarButtonPressed@:not([status="active"]) {
-moz-image-region: rect(18px, 270px, 36px, 252px);
#sync-button@toolbarButtonPressed@ {
-moz-image-region: rect(18px, 792px, 36px, 774px);
}
#feed-button@toolbarButtonPressed@ {
@ -974,8 +974,8 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
-moz-image-region: rect(36px, 504px, 72px, 468px);
}
#sync-button@toolbarButtonPressed@:not([status="active"]) {
-moz-image-region: rect(36px, 540px, 72px, 504px);
#sync-button@toolbarButtonPressed@ {
-moz-image-region: rect(36px, 1584px, 72px, 1548px);
}
#feed-button@toolbarButtonPressed@ {

Двоичные данные
browser/themes/osx/menuPanel-yosemite.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/menuPanel-yosemite@2x.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/menuPanel.png

Двоичный файл не отображается.

До

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

После

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

Двоичные данные
browser/themes/osx/menuPanel@2x.png

Двоичный файл не отображается.

До

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

После

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

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

@ -51,7 +51,7 @@ ul {
#errorTitle[sslv3=true],
#errorTitle[weakCrypto=true] {
background-image: url("aboutNetError_alert.svg");
background-image: url("cert-error.svg");
}
#errorTryAgain {
@ -79,7 +79,46 @@ button:disabled {
cursor: pointer;
}
div#certificateErrorReporting,
#learnMoreContainer {
display: none;
}
#buttonContainer {
display: none;
flex-flow: row wrap;
}
#buttonSpacer {
flex: 1;
}
#returnButton {
background-color: var(--in-content-primary-button-background);
border: none;
color: var(--in-content-selected-text);
min-width: 250px;
margin-inline-start: 0;
}
#returnButton:hover {
background-color: var(--in-content-primary-button-background-hover) !important;
}
#returnButton:hover:active {
background-color: var(--in-content-primary-button-background-active) !important;
}
#advancedButton {
display: none;
min-width: 150px;
}
#certificateErrorReporting,
#reportCertificateError,
#reportSentMessage {
display: none;
}
div#weakCryptoAdvanced {
display: none;
float: right;
@ -88,12 +127,10 @@ div#weakCryptoAdvanced {
-moz-margin-end: 24px;
}
div#certificateErrorReporting a,
div#weakCryptoAdvanced a {
text-decoration: none;
}
div#certificateErrorReporting a:hover,
div#weakCryptoAdvanced a:hover {
text-decoration: underline;
}
@ -106,7 +143,6 @@ span.downArrow {
transform: scaleY(0.7);
}
div#certificateErrorReportingPanel,
div#weakCryptoAdvancedPanel {
/* Hidden until the link is clicked */
display: none;
@ -118,28 +154,16 @@ div#weakCryptoAdvancedPanel {
box-shadow: 0 0 4px #ddd;
font-size: 0.9em;
position: absolute;
width: 75%;
margin-top: 10px;
}
div#certificateErrorReportingPanel:-moz-dir(ltr),
div#weakCryptoAdvancedPanel:-moz-dir(ltr) {
left: 34%;
}
div#certificateErrorReportingPanel:-moz-dir(rtl),
div#weakCryptoAdvancedPanel:-moz-dir(rtl) {
right: 0;
}
#errorStatePanel,
#overrideWeakCryptoPanel {
display: flex;
display: none;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-content: space-between;
align-items: flex-start;
margin-top: 1em;
}
span#hostname {

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

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40">
<defs>
<linearGradient id="gradient1" gradientUnits="userSpaceOnUse" x1="20" y1="4" x2="20" y2="36">
<stop offset="0" style="stop-color: #e63b2e"/>
<stop offset="1" style="stop-color: #c33931"/>
</linearGradient>
<linearGradient id="gradient2" gradientUnits="userSpaceOnUse" x1="20" y1="0" x2="20" y2="40">
<stop offset="0" style="stop-color: #e63b2e"/>
<stop offset="1" style="stop-color: #c33931"/>
</linearGradient>
</defs>
<path fill="url(#gradient1)" d="M13.373,4L4,13.372v13.256L13.373,36h13.255L36,26.628V13.372L26.627,4H13.373z M22.176,8.704 l-0.48,14.304h-3.424L17.76,8.704H22.176z M20,31.296c-1.44,0-2.592-1.184-2.592-2.592c0-1.44,1.152-2.592,2.592-2.592 c1.472,0,2.592,1.152,2.592,2.592C22.592,30.112,21.472,31.296,20,31.296z"/>
<path fill="url(#gradient2)" d="M28.284,0H11.716L0,11.716v16.569L11.716,40h16.569L40,28.284V11.716L28.284,0z M38,27.456 L27.456,38H12.544L2,27.456V12.544L12.544,2h14.911L38,12.544V27.456z"/>
</svg>

До

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

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

@ -634,6 +634,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
#PanelUI-update-status > .toolbarbutton-icon,
#PanelUI-fxa-label > .toolbarbutton-icon,
#PanelUI-fxa-icon > .toolbarbutton-icon,
#PanelUI-remotetabs-syncnow > .toolbarbutton-icon,
#PanelUI-customize > .toolbarbutton-icon,
#PanelUI-help > .toolbarbutton-icon,
#PanelUI-quit > .toolbarbutton-icon {
@ -667,12 +668,92 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
list-style-image: url(chrome://branding/content/icon16.png);
}
#PanelUI-remotetabs-syncnow,
#PanelUI-fxa-label,
#PanelUI-fxa-icon {
list-style-image: url(chrome://browser/skin/sync-horizontalbar.png);
}
#PanelUI-footer-fxa[syncstatus="active"] > #PanelUI-fxa-icon {
.PanelUI-remotetabs-instruction-label,
#PanelUI-remotetabs-mobile-promo {
margin: 15px;
text-align: center;
text-shadow: none;
max-width: 15em;
color: GrayText;
}
/* The boxes with "instructions" get extra padding for space around the
illustration and buttons */
.PanelUI-remotetabs-instruction-box {
padding: 30px 15px 15px 15px;
}
.PanelUI-remotetabs-prefs-button {
-moz-appearance: none;
background-color: #0096dd;
color: white;
border-radius: 2px;
margin: 10px;
padding: 8px;
text-shadow: none;
min-width: 200px;
}
.PanelUI-remotetabs-prefs-button:hover,
.PanelUI-remotetabs-prefs-button:hover:active {
background-color: #018acb;
}
.remotetabs-promo-link {
margin: 0;
}
.PanelUI-remotetabs-notabsforclient-label {
color: GrayText;
/* This margin is to line this label up with the labels in toolbarbuttons. */
margin-left: 28px;
}
.fxaSyncIllustration {
width: 180px;
list-style-image: url(chrome://browser/skin/fxa/sync-illustration.svg);
}
.PanelUI-remotetabs-prefs-button > .toolbarbutton-text {
/* !important to override ".cui-widget-panel toolbarbutton > .toolbarbutton-text" above. */
text-align: center !important;
text-shadow: none;
}
#PanelUI-remotetabs[mainview] { /* panel anchored to toolbar button might be too skinny */
min-width: 19em;
}
/* Work around bug 1224412 - these boxes will cause scrollbars to appear when
the panel is anchored to a toolbar button.
*/
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync,
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-reauthsync,
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-nodevicespane,
#PanelUI-remotetabs[mainview] #PanelUI-remotetabs-tabsdisabledpane {
min-height: 30em;
}
#PanelUI-remotetabs-tabslist > label[itemtype="client"] {
color: GrayText;
}
/* Collapse the non-active vboxes in the remotetabs deck to use only the
height the active box needs */
#PanelUI-remotetabs-deck:not([selectedIndex="1"]) > #PanelUI-remotetabs-tabsdisabledpane,
#PanelUI-remotetabs-deck:not([selectedIndex="2"]) > #PanelUI-remotetabs-fetching,
#PanelUI-remotetabs-deck:not([selectedIndex="3"]) > #PanelUI-remotetabs-nodevicespane {
visibility: collapse;
}
#PanelUI-remotetabs-syncnow[syncstatus="active"],
#PanelUI-fxa-icon[syncstatus="active"] {
list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar.png);
}
@ -701,6 +782,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
#PanelUI-fxa-label,
#PanelUI-fxa-icon,
#PanelUI-remotetabs-syncnow,
#PanelUI-customize,
#PanelUI-help,
#PanelUI-quit {
@ -1070,10 +1152,19 @@ menuitem.panel-subview-footer@menuStateActive@,
color: GrayText;
}
#PanelUI-remotetabs-tabslist > toolbarbutton,
#PanelUI-historyItems > toolbarbutton {
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
}
@media (min-resolution: 1.1dppx) {
#PanelUI-remotetabs-tabslist > toolbarbutton,
#PanelUI-historyItems > toolbarbutton {
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
}
}
#PanelUI-remotetabs-tabslist > toolbarbutton > .toolbarbutton-icon,
#PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon,
#PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon,
#PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon {
@ -1531,11 +1622,13 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
}
#PanelUI-fxa-label,
#PanelUI-remotetabs-syncnow,
#PanelUI-fxa-icon {
list-style-image: url(chrome://browser/skin/sync-horizontalbar@2x.png);
}
#PanelUI-footer-fxa[syncstatus="active"] > #PanelUI-fxa-icon {
#PanelUI-remotetabs-syncnow[syncstatus="active"],
#PanelUI-fxa-icon[syncstatus="active"] {
list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar@2x.png);
}
@ -1557,6 +1650,7 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
#PanelUI-fxa-label,
#PanelUI-fxa-icon,
#PanelUI-remotetabs-syncnow,
#PanelUI-customize,
#PanelUI-help,
#PanelUI-quit {
@ -1566,6 +1660,7 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
#PanelUI-update-status > .toolbarbutton-icon,
#PanelUI-fxa-label > .toolbarbutton-icon,
#PanelUI-fxa-icon > .toolbarbutton-icon,
#PanelUI-remotetabs-syncnow > .toolbarbutton-icon,
#PanelUI-customize > .toolbarbutton-icon,
#PanelUI-help > .toolbarbutton-icon,
#PanelUI-quit > .toolbarbutton-icon {

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

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="320" height="280" viewBox="0 0 320 280">
<g fill="#cdcdcd">
<path d="M46.352,148.919 L46.352,148.919 L44.938,150.333 L43.523,148.919 L43.523,148.919 L37.866,143.262 L39.281,141.848 L44.938,147.505 L50.594,141.848 L52.009,143.262 L46.352,148.919 ZM43.937,134.000 L45.938,134.000 L45.938,142.000 L43.937,142.000 L43.937,134.000 ZM43.937,122.000 L45.938,122.000 L45.938,130.000 L43.937,130.000 L43.937,122.000 Z"/>
<path d="M306.641,132.110 L300.984,126.453 L295.328,132.110 L293.913,130.696 L300.984,123.625 L308.055,130.696 L306.641,132.110 ZM302.000,223.969 L300.000,223.969 L300.000,215.969 L302.000,215.969 L302.000,223.969 ZM302.000,211.969 L300.000,211.969 L300.000,203.969 L302.000,203.969 L302.000,211.969 ZM302.000,199.969 L300.000,199.969 L300.000,191.969 L302.000,191.969 L302.000,199.969 ZM302.000,187.969 L300.000,187.969 L300.000,179.969 L302.000,179.969 L302.000,187.969 ZM302.000,175.969 L300.000,175.969 L300.000,167.969 L302.000,167.969 L302.000,175.969 ZM302.000,163.969 L300.000,163.969 L300.000,155.969 L302.000,155.969 L302.000,163.969 ZM300.000,131.969 L302.000,131.969 L302.000,139.969 L300.000,139.969 L300.000,131.969 ZM302.000,151.969 L300.000,151.969 L300.000,143.969 L302.000,143.969 L302.000,151.969 ZM300.000,227.969 L302.000,227.969 L302.000,232.000 L302.000,234.000 L300.000,234.000 L292.000,234.000 L292.000,232.000 L300.000,232.000 L300.000,227.969 Z"/>
<path d="M101.335,236.009 L99.921,234.594 L105.578,228.938 L99.921,223.281 L101.335,221.866 L108.406,228.938 L101.335,236.009 ZM100.000,229.938 L92.000,229.938 L92.000,227.937 L100.000,227.937 L100.000,229.938 ZM80.000,227.937 L88.000,227.937 L88.000,229.938 L80.000,229.938 L80.000,227.937 Z"/>
<path d="M182.000,54.000 L182.000,52.000 L190.000,52.000 L190.000,54.000 L182.000,54.000 ZM170.000,52.000 L178.000,52.000 L178.000,54.000 L170.000,54.000 L170.000,52.000 ZM168.488,60.071 L161.417,53.000 L168.488,45.929 L169.902,47.343 L164.245,53.000 L169.902,58.657 L168.488,60.071 Z"/>
<path d="M297.688,276.000 L102.312,276.000 C97.721,276.000 94.000,272.279 94.000,267.688 L94.000,260.000 L306.000,260.000 L306.000,267.688 C306.000,272.279 302.279,276.000 297.688,276.000 ZM117.906,150.312 C117.906,145.721 121.628,142.000 126.218,142.000 L273.688,142.000 C278.279,142.000 282.000,145.721 282.000,150.312 L282.000,256.000 L117.906,256.000 L117.906,150.312 ZM132.000,242.000 L270.000,242.000 L270.000,156.000 L132.000,156.000 L132.000,242.000 Z"/>
<path d="M307.074,115.969 L206.926,115.969 C203.101,115.969 200.000,112.868 200.000,109.042 L200.000,38.926 C200.000,35.101 203.101,32.000 206.926,32.000 L307.074,32.000 C310.899,32.000 314.000,35.101 314.000,38.926 L314.000,109.042 C314.000,112.868 310.899,115.969 307.074,115.969 ZM210.000,65.875 C210.000,64.770 209.105,63.875 208.000,63.875 C206.895,63.875 206.000,64.770 206.000,65.875 L206.000,82.000 C206.000,83.105 206.895,84.000 208.000,84.000 C209.105,84.000 210.000,83.105 210.000,82.000 L210.000,65.875 ZM302.000,42.000 L216.000,42.000 L216.000,106.000 L302.000,106.000 L302.000,42.000 Z"/>
<path d="M65.844,240.000 L26.156,240.000 C23.861,240.000 22.000,238.139 22.000,235.844 L22.000,162.156 C22.000,159.861 23.861,158.000 26.156,158.000 L65.844,158.000 C68.139,158.000 70.000,159.861 70.000,162.156 L70.000,235.844 C70.000,238.139 68.139,240.000 65.844,240.000 ZM46.000,236.000 C48.287,236.000 50.141,234.195 50.141,231.969 C50.141,229.742 48.287,227.938 46.000,227.938 C43.713,227.938 41.859,229.742 41.859,231.969 C41.859,234.195 43.713,236.000 46.000,236.000 ZM66.000,168.000 L26.000,168.000 L26.000,224.000 L66.000,224.000 L66.000,168.000 Z"/>
<path d="M171.906,86.156 C171.906,102.329 159.026,115.469 143.017,115.797 L143.039,115.955 L28.850,115.955 L28.869,115.797 C12.872,115.475 -0.000,102.333 -0.000,86.156 C-0.000,71.661 10.336,59.603 23.994,57.019 C23.620,55.457 23.401,53.834 23.401,52.156 C23.401,40.714 32.606,31.438 43.962,31.438 C47.561,31.438 50.941,32.375 53.884,34.012 C53.883,33.930 53.878,33.848 53.878,33.766 C53.878,17.137 67.301,3.656 83.858,3.656 C97.763,3.656 109.453,13.164 112.843,26.059 C116.677,23.334 121.343,21.719 126.393,21.719 C139.394,21.719 149.933,32.331 149.933,45.422 C149.933,49.572 148.868,53.468 147.007,56.861 C161.114,59.082 171.906,71.351 171.906,86.156 Z"/>
</g>
</svg>

После

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

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

@ -9,7 +9,6 @@
skin/classic/browser/aboutCertError.css (../shared/aboutCertError.css)
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
skin/classic/browser/aboutNetError_alert.svg (../shared/aboutNetError_alert.svg)
* skin/classic/browser/aboutProviderDirectory.css (../shared/aboutProviderDirectory.css)
* skin/classic/browser/aboutSessionRestore.css (../shared/aboutSessionRestore.css)
skin/classic/browser/aboutSocialError.css (../shared/aboutSocialError.css)
@ -79,6 +78,7 @@
skin/classic/browser/fxa/logo@2x.png (../shared/fxa/logo@2x.png)
skin/classic/browser/fxa/sync-illustration.png (../shared/fxa/sync-illustration.png)
skin/classic/browser/fxa/sync-illustration@2x.png (../shared/fxa/sync-illustration@2x.png)
skin/classic/browser/fxa/sync-illustration.svg (../shared/fxa/sync-illustration.svg)
skin/classic/browser/fxa/android.png (../shared/fxa/android.png)
skin/classic/browser/fxa/android@2x.png (../shared/fxa/android@2x.png)
skin/classic/browser/search-pref.png (../shared/search/search-pref.png)

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

@ -60,12 +60,7 @@
#sync-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #sync-button {
-moz-image-region: rect(0px, 384px, 32px, 352px);
}
#sync-button[cui-areatype="menu-panel"][status="active"] {
list-style-image: url(chrome://browser/skin/syncProgress-menuPanel.png);
-moz-image-region: rect(0px, 32px, 32px, 0px);
-moz-image-region: rect(0px, 1024px, 32px, 992px);
}
#feed-button[cui-areatype="menu-panel"],
@ -279,12 +274,7 @@
#sync-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #sync-button {
-moz-image-region: rect(0px, 768px, 64px, 704px);
}
#sync-button[cui-areatype="menu-panel"][status="active"] {
list-style-image: url(chrome://browser/skin/syncProgress-menuPanel@2x.png);
-moz-image-region: rect(0px, 64px, 64px, 0px);
-moz-image-region: rect(0px, 2048px, 64px, 1984px);
}
#feed-button[cui-areatype="menu-panel"],

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

@ -53,16 +53,7 @@ toolbar[brighttext] #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarke
}
#sync-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 270px, 18px, 252px);
}
#sync-button[cui-areatype="toolbar"][status="active"] {
list-style-image: url("chrome://browser/skin/syncProgress-toolbar.png");
-moz-image-region: rect(0, 18px, 18px, 0px);
}
toolbar[brighttext] #sync-button[status="active"] {
list-style-image: url("chrome://browser/skin/syncProgress-toolbar-inverted.png");
-moz-image-region: rect(0, 792px, 18px, 774px);
}
#feed-button[cui-areatype="toolbar"] {
@ -253,16 +244,7 @@ toolbar[brighttext] #sync-button[status="active"] {
}
#sync-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 540px, 36px, 504px);
}
#sync-button[cui-areatype="toolbar"][status="active"] {
list-style-image: url("chrome://browser/skin/syncProgress-toolbar@2x.png");
-moz-image-region: rect(0, 36px, 36px, 0px);
}
toolbar[brighttext] #sync-button[cui-areatype="toolbar"][status="active"] {
list-style-image: url("chrome://browser/skin/syncProgress-toolbar-inverted@2x.png");
-moz-image-region: rect(0, 1584px, 36px, 1548px);
}
#feed-button[cui-areatype="toolbar"] {

Двоичные данные
browser/themes/windows/Toolbar-XP.png

Двоичный файл не отображается.

До

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

После

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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше