From a9523dbb947974e112f0796a789e75cbb98532fd Mon Sep 17 00:00:00 2001
From: Justin Dolske
Date: Tue, 16 Dec 2014 18:30:34 -0800
Subject: [PATCH 01/24] Bug 984140 - UITour: Info panels with no image are
missing a left margin. r=mattn
---
browser/modules/UITour.jsm | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/browser/modules/UITour.jsm b/browser/modules/UITour.jsm
index 48448e8c337..23547aadd8f 100644
--- a/browser/modules/UITour.jsm
+++ b/browser/modules/UITour.jsm
@@ -1159,6 +1159,7 @@ this.UITour = {
let tooltipTitle = document.getElementById("UITourTooltipTitle");
let tooltipDesc = document.getElementById("UITourTooltipDescription");
let tooltipIcon = document.getElementById("UITourTooltipIcon");
+ let tooltipIconContainer = document.getElementById("UITourTooltipIconContainer");
let tooltipButtons = document.getElementById("UITourTooltipButtons");
if (tooltip.state == "showing" || tooltip.state == "open") {
@@ -1168,7 +1169,7 @@ this.UITour = {
tooltipTitle.textContent = aTitle || "";
tooltipDesc.textContent = aDescription || "";
tooltipIcon.src = aIconURL || "";
- tooltipIcon.hidden = !aIconURL;
+ tooltipIconContainer.hidden = !aIconURL;
while (tooltipButtons.firstChild)
tooltipButtons.firstChild.remove();
From b7aeea798cac2cc5cdd11ea6de552d60f9307b97 Mon Sep 17 00:00:00 2001
From: Mark Hammond
Date: Wed, 17 Dec 2014 15:18:07 +1100
Subject: [PATCH 02/24] Bug 1098661 - Update sync in-content preferences UI to
match FxA migration flows. r=adw
---
.../components/preferences/in-content/sync.js | 81 +++++++++++++++++--
.../preferences/in-content/sync.xul | 25 ++++++
.../en-US/chrome/browser/accounts.properties | 3 +
.../en-US/chrome/browser/preferences/sync.dtd | 3 +
.../shared/incontentprefs/preferences.inc.css | 17 ++++
5 files changed, 123 insertions(+), 6 deletions(-)
diff --git a/browser/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js
index c558c8ec7ae..0e17a73b4c1 100644
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -9,6 +9,12 @@ XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () {
return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
});
+XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
+ "resource://gre/modules/FxAccounts.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "fxaMigrator",
+ "resource://services-sync/FxaMigrator.jsm");
+
const PAGE_NO_ACCOUNT = 0;
const PAGE_HAS_ACCOUNT = 1;
const PAGE_NEEDS_UPDATE = 2;
@@ -25,7 +31,6 @@ const FXA_LOGIN_UNVERIFIED = 1;
const FXA_LOGIN_FAILED = 2;
let gSyncPane = {
- _stringBundle: null,
prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
"engine.tabs", "engine.history"],
@@ -91,6 +96,7 @@ let gSyncPane = {
"weave:service:setup-complete",
"weave:service:logout:finish",
FxAccountsCommon.ONVERIFIED_NOTIFICATION];
+ let migrateTopic = "fxa-migration:state-changed";
// Add the observers now and remove them on unload
//XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
@@ -98,14 +104,30 @@ let gSyncPane = {
topics.forEach(function (topic) {
Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
}, this);
+ // The FxA migration observer is a special case.
+ Weave.Svc.Obs.add(migrateTopic, this.updateMigrationState, this);
+
window.addEventListener("unload", function() {
topics.forEach(function (topic) {
Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
}, gSyncPane);
+ Weave.Svc.Obs.remove(migrateTopic, this.updateMigrationState, this);
}, false);
- this._stringBundle =
- Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
+ // ask the migration module to broadcast its current state (and nothing will
+ // happen if it's not loaded - which is good, as that means no migration
+ // is pending/necessary) - we don't want to suck that module in just to
+ // find there's nothing to do.
+ Services.obs.notifyObservers(null, "fxa-migration:state-request", null);
+
+ 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");
+ }),
+
this.updateWeavePrefs();
},
@@ -192,6 +214,17 @@ let gSyncPane = {
});
setEventListener("tosPP-small-ToS", "click", gSyncPane.openToS);
setEventListener("tosPP-small-PP", "click", gSyncPane.openPrivacyPolicy);
+ setEventListener("sync-migrate-upgrade", "click", function () {
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ fxaMigrator.createFxAccount(win);
+ });
+ setEventListener("sync-migrate-forget", "click", function () {
+ fxaMigrator.forgetFxAccount();
+ });
+ setEventListener("sync-migrate-resend", "click", function () {
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ fxaMigrator.resendVerificationMail(win);
+ });
},
updateWeavePrefs: function () {
@@ -203,7 +236,6 @@ let gSyncPane = {
if (service.fxAccountsEnabled) {
// determine the fxa status...
this.page = PAGE_PLEASE_WAIT;
- Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.getSignedInUser().then(data => {
if (!data) {
this.page = FXA_PAGE_LOGGED_OUT;
@@ -262,6 +294,45 @@ let gSyncPane = {
}
},
+ updateMigrationState: function(subject, state) {
+ let selIndex;
+ switch (state) {
+ case fxaMigrator.STATE_USER_FXA: {
+ let sb = this._accountsStringBundle;
+ let button = document.getElementById("sync-migrate-upgrade");
+ button.setAttribute("label", sb.GetStringFromName("upgradeToFxA.label"));
+ button.setAttribute("accesskey", sb.GetStringFromName("upgradeToFxA.accessKey"));
+ selIndex = 0;
+ break;
+ }
+ case fxaMigrator.STATE_USER_FXA_VERIFIED: {
+ let sb = this._accountsStringBundle;
+ let email = subject.QueryInterface(Components.interfaces.nsISupportsString).data;
+ let label = sb.formatStringFromName("needVerifiedUserLong", [email], 1);
+ let elt = document.getElementById("sync-migrate-verify-label");
+ elt.setAttribute("value", label);
+ // The "resend" button.
+ let button = document.getElementById("sync-migrate-resend");
+ button.setAttribute("label", sb.GetStringFromName("resendVerificationEmail.label"));
+ button.setAttribute("accesskey", sb.GetStringFromName("resendVerificationEmail.accessKey"));
+ // The "forget" button.
+ button = document.getElementById("sync-migrate-forget");
+ button.setAttribute("label", sb.GetStringFromName("forgetMigration.label"));
+ button.setAttribute("accesskey", sb.GetStringFromName("forgetMigration.accessKey"));
+ selIndex = 1;
+ break;
+ }
+ default:
+ if (state) { // |null| is expected, but everything else is not.
+ Cu.reportError("updateMigrationState has unknown state: " + state);
+ }
+ document.getElementById("sync-migration").hidden = true;
+ return;
+ }
+ document.getElementById("sync-migration").hidden = false;
+ document.getElementById("sync-migration-deck").selectedIndex = selIndex;
+ },
+
startOver: function (showDialog) {
if (showDialog) {
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
@@ -375,7 +446,6 @@ let gSyncPane = {
},
verifyFirefoxAccount: function() {
- Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.resendVerificationEmail().then(() => {
fxAccounts.getSignedInUser().then(data => {
let sb = this._stringBundle;
@@ -430,7 +500,6 @@ let gSyncPane = {
return;
}
}
- Cu.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.signOut().then(() => {
this.updateWeavePrefs();
});
diff --git a/browser/components/preferences/in-content/sync.xul b/browser/components/preferences/in-content/sync.xul
index 649c8e7f3c4..d23e8a778cf 100644
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -37,6 +37,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/locales/en-US/chrome/browser/accounts.properties b/browser/locales/en-US/chrome/browser/accounts.properties
index 18dff0aaa66..edbcd0f31c7 100644
--- a/browser/locales/en-US/chrome/browser/accounts.properties
+++ b/browser/locales/en-US/chrome/browser/accounts.properties
@@ -17,3 +17,6 @@ needVerifiedUserLong = Please click the verification link in the email sent to %
resendVerificationEmail.label = Resend
resendVerificationEmail.accessKey = R
+
+forgetMigration.label = Forget
+forgetMigration.accessKey = F
diff --git a/browser/locales/en-US/chrome/browser/preferences/sync.dtd b/browser/locales/en-US/chrome/browser/preferences/sync.dtd
index b8a9d600f60..ffa94b8eec1 100644
--- a/browser/locales/en-US/chrome/browser/preferences/sync.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/sync.dtd
@@ -78,3 +78,6 @@ both, to better adapt this sentence to their language.
+
+
+
diff --git a/browser/themes/shared/incontentprefs/preferences.inc.css b/browser/themes/shared/incontentprefs/preferences.inc.css
index 36d54d45c80..c344a75e9aa 100644
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -293,3 +293,20 @@ description > html|a {
/**
* End Dialog
*/
+
+/**
+ * Sync migration
+ */
+#sync-migration {
+ border: 1px solid rgba(0, 0, 0, 0.32);
+ background-color: InfoBackground;
+ color: InfoText;
+ text-shadow: none;
+ margin: 5px 0 0 0;
+ animation: fadein 3000ms;
+}
+
+@keyframes fadein {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
From fa63867018e3621ac2dc2e640348b0f345b027af Mon Sep 17 00:00:00 2001
From: Mark Hammond
Date: Wed, 17 Dec 2014 15:18:07 +1100
Subject: [PATCH 03/24] Bug 1109430 - Sync migrator module should show
confirmation after resending verification email. r=adw
---
browser/base/content/browser-fxaccounts.js | 4 ++-
.../components/preferences/in-content/sync.js | 8 +++---
browser/components/preferences/sync.js | 8 +++---
.../en-US/chrome/browser/accounts.properties | 11 ++++++++
.../preferences/preferences.properties | 6 -----
services/sync/modules/FxaMigrator.jsm | 27 +++++++++++++++++--
6 files changed, 47 insertions(+), 17 deletions(-)
diff --git a/browser/base/content/browser-fxaccounts.js b/browser/base/content/browser-fxaccounts.js
index 5dcdbcb12c3..5873206bc89 100644
--- a/browser/base/content/browser-fxaccounts.js
+++ b/browser/base/content/browser-fxaccounts.js
@@ -331,7 +331,9 @@ let gFxAccounts = {
fxaMigrator.createFxAccount(window);
break;
case "migrate-verify":
- fxaMigrator.resendVerificationMail();
+ // Instead of using the migrator module directly here the UX calls for
+ // us to open prefs which has a "resend" button.
+ this.openPreferences();
break;
default:
this.openAccountsPage(null, { entryPoint: "menupanel" });
diff --git a/browser/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js
index 0e17a73b4c1..96b8de42664 100644
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -448,11 +448,11 @@ let gSyncPane = {
verifyFirefoxAccount: function() {
fxAccounts.resendVerificationEmail().then(() => {
fxAccounts.getSignedInUser().then(data => {
- let sb = this._stringBundle;
- let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
- let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
+ let sb = this._accountsStringBundle;
+ let title = sb.GetStringFromName("verificationSentTitle");
+ let heading = sb.formatStringFromName("verificationSentHeading",
[data.email], 1);
- let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
+ let description = sb.GetStringFromName("verificationSentDescription");
let factory = Cc["@mozilla.org/prompter;1"]
.getService(Ci.nsIPromptFactory);
diff --git a/browser/components/preferences/sync.js b/browser/components/preferences/sync.js
index 3133cc04250..80e74b1ed05 100644
--- a/browser/components/preferences/sync.js
+++ b/browser/components/preferences/sync.js
@@ -285,11 +285,11 @@ let gSyncPane = {
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.resendVerificationEmail().then(() => {
fxAccounts.getSignedInUser().then(data => {
- let sb = this._stringBundle;
- let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
- let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
+ let sb = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
+ let title = sb.GetStringFromName("verificationSentTitle");
+ let heading = sb.formatStringFromName("verificationSentHeading",
[data.email], 1);
- let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
+ let description = sb.GetStringFromName("verificationSentDescription");
Services.prompt.alert(window, title, heading + "\n\n" + description);
});
diff --git a/browser/locales/en-US/chrome/browser/accounts.properties b/browser/locales/en-US/chrome/browser/accounts.properties
index edbcd0f31c7..b2e94ccec18 100644
--- a/browser/locales/en-US/chrome/browser/accounts.properties
+++ b/browser/locales/en-US/chrome/browser/accounts.properties
@@ -20,3 +20,14 @@ resendVerificationEmail.accessKey = R
forgetMigration.label = Forget
forgetMigration.accessKey = F
+
+# These strings are used in a dialog we display after the user requests we resend
+# a verification email.
+verificationSentTitle = Verification Sent
+# LOCALIZATION NOTE (verificationSentHeading) - %S = Email address of user's Firefox Account
+verificationSentHeading = A verification link has been sent to %S
+verificationSentDescription = Please check your email and click the link to begin syncing.
+
+verificationNotSentTitle = Unable to Send Verification
+verificationNotSentHeading = We are unable to send a verification mail at this time
+verificationNotSentDescription = Please try again later.
diff --git a/browser/locales/en-US/chrome/browser/preferences/preferences.properties b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
index 00acacf1937..619e015e041 100644
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -137,9 +137,3 @@ syncUnlinkConfirm.label=Unlink
featureEnableRequiresRestart=%S must restart to enable this feature.
featureDisableRequiresRestart=%S must restart to disable this feature.
shouldRestartTitle=Restart %S
-
-###Preferences::Sync::Firefox Accounts
-firefoxAccountsVerificationSentTitle=Verification Sent
-# LOCALIZATION NOTE: %S = user's email address.
-firefoxAccountsVerificationSentHeading=A verification link has been sent to %S
-firefoxAccountVerificationSentDescription=Please check your email and click the link to begin syncing.
diff --git a/services/sync/modules/FxaMigrator.jsm b/services/sync/modules/FxaMigrator.jsm
index a99d766803e..68269025c29 100644
--- a/services/sync/modules/FxaMigrator.jsm
+++ b/services/sync/modules/FxaMigrator.jsm
@@ -350,12 +350,35 @@ Migrator.prototype = {
// STATE_USER_FXA_VERIFIED state. When the user clicks on the link in
// the mail we should see an ONVERIFIED_NOTIFICATION which will cause us
// to complete the migration.
- resendVerificationMail: Task.async(function * () {
+ resendVerificationMail: Task.async(function * (win) {
// warn if we aren't in the expected state - but go ahead anyway!
if (this._state != this.STATE_USER_FXA_VERIFIED) {
this.log.warn("createFxAccount called in an unexpected state: ${}", this._state);
}
- return fxAccounts.resendVerificationEmail();
+ let ok = true;
+ try {
+ yield fxAccounts.resendVerificationEmail();
+ } catch (ex) {
+ this.log.error("Failed to resend verification mail: ${}", ex);
+ ok = false;
+ }
+ let fxauser = yield fxAccounts.getSignedInUser();
+ let sb = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
+
+ let heading = ok ?
+ sb.formatStringFromName("verificationSentHeading", [fxauser.email], 1) :
+ sb.GetStringFromName("verificationNotSentHeading");
+ let title = sb.GetStringFromName(ok ? "verificationSentTitle" : "verificationNotSentTitle");
+ let description = sb.GetStringFromName(ok ? "verificationSentDescription"
+ : "verificationNotSentDescription");
+
+ let factory = Cc["@mozilla.org/prompter;1"]
+ .getService(Ci.nsIPromptFactory);
+ let prompt = factory.getPrompt(win, Ci.nsIPrompt);
+ let bag = prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
+ bag.setPropertyAsBool("allowTabModal", true);
+
+ prompt.alert(title, heading + "\n\n" + description);
}),
// "forget" about the current Firefox account. This should only be called
From 533195ed7cf105c0f674e9979fdd1d9b302bfd2e Mon Sep 17 00:00:00 2001
From: Phil Ringnalda
Date: Tue, 16 Dec 2014 23:57:10 -0800
Subject: [PATCH 04/24] Backed out 2 changesets (bug 1098661, bug 1109430) for
leaking prefs windows CLOSED TREE
Backed out changeset 1b8f23ce8a7a (bug 1109430)
Backed out changeset 069da43ec3be (bug 1098661)
---
browser/base/content/browser-fxaccounts.js | 4 +-
.../components/preferences/in-content/sync.js | 89 +++----------------
.../preferences/in-content/sync.xul | 25 ------
browser/components/preferences/sync.js | 8 +-
.../en-US/chrome/browser/accounts.properties | 14 ---
.../preferences/preferences.properties | 6 ++
.../en-US/chrome/browser/preferences/sync.dtd | 3 -
.../shared/incontentprefs/preferences.inc.css | 17 ----
services/sync/modules/FxaMigrator.jsm | 27 +-----
9 files changed, 23 insertions(+), 170 deletions(-)
diff --git a/browser/base/content/browser-fxaccounts.js b/browser/base/content/browser-fxaccounts.js
index 5873206bc89..5dcdbcb12c3 100644
--- a/browser/base/content/browser-fxaccounts.js
+++ b/browser/base/content/browser-fxaccounts.js
@@ -331,9 +331,7 @@ let gFxAccounts = {
fxaMigrator.createFxAccount(window);
break;
case "migrate-verify":
- // Instead of using the migrator module directly here the UX calls for
- // us to open prefs which has a "resend" button.
- this.openPreferences();
+ fxaMigrator.resendVerificationMail();
break;
default:
this.openAccountsPage(null, { entryPoint: "menupanel" });
diff --git a/browser/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js
index 96b8de42664..c558c8ec7ae 100644
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -9,12 +9,6 @@ XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () {
return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
});
-XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
- "resource://gre/modules/FxAccounts.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "fxaMigrator",
- "resource://services-sync/FxaMigrator.jsm");
-
const PAGE_NO_ACCOUNT = 0;
const PAGE_HAS_ACCOUNT = 1;
const PAGE_NEEDS_UPDATE = 2;
@@ -31,6 +25,7 @@ const FXA_LOGIN_UNVERIFIED = 1;
const FXA_LOGIN_FAILED = 2;
let gSyncPane = {
+ _stringBundle: null,
prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
"engine.tabs", "engine.history"],
@@ -96,7 +91,6 @@ let gSyncPane = {
"weave:service:setup-complete",
"weave:service:logout:finish",
FxAccountsCommon.ONVERIFIED_NOTIFICATION];
- let migrateTopic = "fxa-migration:state-changed";
// Add the observers now and remove them on unload
//XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
@@ -104,30 +98,14 @@ let gSyncPane = {
topics.forEach(function (topic) {
Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
}, this);
- // The FxA migration observer is a special case.
- Weave.Svc.Obs.add(migrateTopic, this.updateMigrationState, this);
-
window.addEventListener("unload", function() {
topics.forEach(function (topic) {
Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
}, gSyncPane);
- Weave.Svc.Obs.remove(migrateTopic, this.updateMigrationState, this);
}, false);
- // ask the migration module to broadcast its current state (and nothing will
- // happen if it's not loaded - which is good, as that means no migration
- // is pending/necessary) - we don't want to suck that module in just to
- // find there's nothing to do.
- Services.obs.notifyObservers(null, "fxa-migration:state-request", null);
-
- 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");
- }),
-
+ this._stringBundle =
+ Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
this.updateWeavePrefs();
},
@@ -214,17 +192,6 @@ let gSyncPane = {
});
setEventListener("tosPP-small-ToS", "click", gSyncPane.openToS);
setEventListener("tosPP-small-PP", "click", gSyncPane.openPrivacyPolicy);
- setEventListener("sync-migrate-upgrade", "click", function () {
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- fxaMigrator.createFxAccount(win);
- });
- setEventListener("sync-migrate-forget", "click", function () {
- fxaMigrator.forgetFxAccount();
- });
- setEventListener("sync-migrate-resend", "click", function () {
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- fxaMigrator.resendVerificationMail(win);
- });
},
updateWeavePrefs: function () {
@@ -236,6 +203,7 @@ let gSyncPane = {
if (service.fxAccountsEnabled) {
// determine the fxa status...
this.page = PAGE_PLEASE_WAIT;
+ Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.getSignedInUser().then(data => {
if (!data) {
this.page = FXA_PAGE_LOGGED_OUT;
@@ -294,45 +262,6 @@ let gSyncPane = {
}
},
- updateMigrationState: function(subject, state) {
- let selIndex;
- switch (state) {
- case fxaMigrator.STATE_USER_FXA: {
- let sb = this._accountsStringBundle;
- let button = document.getElementById("sync-migrate-upgrade");
- button.setAttribute("label", sb.GetStringFromName("upgradeToFxA.label"));
- button.setAttribute("accesskey", sb.GetStringFromName("upgradeToFxA.accessKey"));
- selIndex = 0;
- break;
- }
- case fxaMigrator.STATE_USER_FXA_VERIFIED: {
- let sb = this._accountsStringBundle;
- let email = subject.QueryInterface(Components.interfaces.nsISupportsString).data;
- let label = sb.formatStringFromName("needVerifiedUserLong", [email], 1);
- let elt = document.getElementById("sync-migrate-verify-label");
- elt.setAttribute("value", label);
- // The "resend" button.
- let button = document.getElementById("sync-migrate-resend");
- button.setAttribute("label", sb.GetStringFromName("resendVerificationEmail.label"));
- button.setAttribute("accesskey", sb.GetStringFromName("resendVerificationEmail.accessKey"));
- // The "forget" button.
- button = document.getElementById("sync-migrate-forget");
- button.setAttribute("label", sb.GetStringFromName("forgetMigration.label"));
- button.setAttribute("accesskey", sb.GetStringFromName("forgetMigration.accessKey"));
- selIndex = 1;
- break;
- }
- default:
- if (state) { // |null| is expected, but everything else is not.
- Cu.reportError("updateMigrationState has unknown state: " + state);
- }
- document.getElementById("sync-migration").hidden = true;
- return;
- }
- document.getElementById("sync-migration").hidden = false;
- document.getElementById("sync-migration-deck").selectedIndex = selIndex;
- },
-
startOver: function (showDialog) {
if (showDialog) {
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
@@ -446,13 +375,14 @@ let gSyncPane = {
},
verifyFirefoxAccount: function() {
+ Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.resendVerificationEmail().then(() => {
fxAccounts.getSignedInUser().then(data => {
- let sb = this._accountsStringBundle;
- let title = sb.GetStringFromName("verificationSentTitle");
- let heading = sb.formatStringFromName("verificationSentHeading",
+ let sb = this._stringBundle;
+ let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
+ let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
[data.email], 1);
- let description = sb.GetStringFromName("verificationSentDescription");
+ let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
let factory = Cc["@mozilla.org/prompter;1"]
.getService(Ci.nsIPromptFactory);
@@ -500,6 +430,7 @@ let gSyncPane = {
return;
}
}
+ Cu.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.signOut().then(() => {
this.updateWeavePrefs();
});
diff --git a/browser/components/preferences/in-content/sync.xul b/browser/components/preferences/in-content/sync.xul
index d23e8a778cf..649c8e7f3c4 100644
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -37,31 +37,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/browser/components/preferences/sync.js b/browser/components/preferences/sync.js
index 80e74b1ed05..3133cc04250 100644
--- a/browser/components/preferences/sync.js
+++ b/browser/components/preferences/sync.js
@@ -285,11 +285,11 @@ let gSyncPane = {
Components.utils.import("resource://gre/modules/FxAccounts.jsm");
fxAccounts.resendVerificationEmail().then(() => {
fxAccounts.getSignedInUser().then(data => {
- let sb = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
- let title = sb.GetStringFromName("verificationSentTitle");
- let heading = sb.formatStringFromName("verificationSentHeading",
+ let sb = this._stringBundle;
+ let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
+ let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
[data.email], 1);
- let description = sb.GetStringFromName("verificationSentDescription");
+ let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
Services.prompt.alert(window, title, heading + "\n\n" + description);
});
diff --git a/browser/locales/en-US/chrome/browser/accounts.properties b/browser/locales/en-US/chrome/browser/accounts.properties
index b2e94ccec18..18dff0aaa66 100644
--- a/browser/locales/en-US/chrome/browser/accounts.properties
+++ b/browser/locales/en-US/chrome/browser/accounts.properties
@@ -17,17 +17,3 @@ needVerifiedUserLong = Please click the verification link in the email sent to %
resendVerificationEmail.label = Resend
resendVerificationEmail.accessKey = R
-
-forgetMigration.label = Forget
-forgetMigration.accessKey = F
-
-# These strings are used in a dialog we display after the user requests we resend
-# a verification email.
-verificationSentTitle = Verification Sent
-# LOCALIZATION NOTE (verificationSentHeading) - %S = Email address of user's Firefox Account
-verificationSentHeading = A verification link has been sent to %S
-verificationSentDescription = Please check your email and click the link to begin syncing.
-
-verificationNotSentTitle = Unable to Send Verification
-verificationNotSentHeading = We are unable to send a verification mail at this time
-verificationNotSentDescription = Please try again later.
diff --git a/browser/locales/en-US/chrome/browser/preferences/preferences.properties b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
index 619e015e041..00acacf1937 100644
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -137,3 +137,9 @@ syncUnlinkConfirm.label=Unlink
featureEnableRequiresRestart=%S must restart to enable this feature.
featureDisableRequiresRestart=%S must restart to disable this feature.
shouldRestartTitle=Restart %S
+
+###Preferences::Sync::Firefox Accounts
+firefoxAccountsVerificationSentTitle=Verification Sent
+# LOCALIZATION NOTE: %S = user's email address.
+firefoxAccountsVerificationSentHeading=A verification link has been sent to %S
+firefoxAccountVerificationSentDescription=Please check your email and click the link to begin syncing.
diff --git a/browser/locales/en-US/chrome/browser/preferences/sync.dtd b/browser/locales/en-US/chrome/browser/preferences/sync.dtd
index ffa94b8eec1..b8a9d600f60 100644
--- a/browser/locales/en-US/chrome/browser/preferences/sync.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/sync.dtd
@@ -78,6 +78,3 @@ both, to better adapt this sentence to their language.
-
-
-
diff --git a/browser/themes/shared/incontentprefs/preferences.inc.css b/browser/themes/shared/incontentprefs/preferences.inc.css
index c344a75e9aa..36d54d45c80 100644
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -293,20 +293,3 @@ description > html|a {
/**
* End Dialog
*/
-
-/**
- * Sync migration
- */
-#sync-migration {
- border: 1px solid rgba(0, 0, 0, 0.32);
- background-color: InfoBackground;
- color: InfoText;
- text-shadow: none;
- margin: 5px 0 0 0;
- animation: fadein 3000ms;
-}
-
-@keyframes fadein {
- from { opacity: 0; }
- to { opacity: 1; }
-}
diff --git a/services/sync/modules/FxaMigrator.jsm b/services/sync/modules/FxaMigrator.jsm
index 68269025c29..a99d766803e 100644
--- a/services/sync/modules/FxaMigrator.jsm
+++ b/services/sync/modules/FxaMigrator.jsm
@@ -350,35 +350,12 @@ Migrator.prototype = {
// STATE_USER_FXA_VERIFIED state. When the user clicks on the link in
// the mail we should see an ONVERIFIED_NOTIFICATION which will cause us
// to complete the migration.
- resendVerificationMail: Task.async(function * (win) {
+ resendVerificationMail: Task.async(function * () {
// warn if we aren't in the expected state - but go ahead anyway!
if (this._state != this.STATE_USER_FXA_VERIFIED) {
this.log.warn("createFxAccount called in an unexpected state: ${}", this._state);
}
- let ok = true;
- try {
- yield fxAccounts.resendVerificationEmail();
- } catch (ex) {
- this.log.error("Failed to resend verification mail: ${}", ex);
- ok = false;
- }
- let fxauser = yield fxAccounts.getSignedInUser();
- let sb = Services.strings.createBundle("chrome://browser/locale/accounts.properties");
-
- let heading = ok ?
- sb.formatStringFromName("verificationSentHeading", [fxauser.email], 1) :
- sb.GetStringFromName("verificationNotSentHeading");
- let title = sb.GetStringFromName(ok ? "verificationSentTitle" : "verificationNotSentTitle");
- let description = sb.GetStringFromName(ok ? "verificationSentDescription"
- : "verificationNotSentDescription");
-
- let factory = Cc["@mozilla.org/prompter;1"]
- .getService(Ci.nsIPromptFactory);
- let prompt = factory.getPrompt(win, Ci.nsIPrompt);
- let bag = prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
- bag.setPropertyAsBool("allowTabModal", true);
-
- prompt.alert(title, heading + "\n\n" + description);
+ return fxAccounts.resendVerificationEmail();
}),
// "forget" about the current Firefox account. This should only be called
From 9eedf195813a282b298c278218d1416f07e66b8d Mon Sep 17 00:00:00 2001
From: Nicolas Perriault
Date: Wed, 17 Dec 2014 14:16:53 +0100
Subject: [PATCH 05/24] Bug 1105525 - Enlarge Loop room rename field to prevent
l10n issues. r=Standard8
---
browser/components/loop/content/js/roomViews.js | 13 ++++++++++++-
browser/components/loop/content/js/roomViews.jsx | 13 ++++++++++++-
.../loop/content/shared/css/conversation.css | 9 +++++++--
.../loop/test/desktop-local/roomViews_test.js | 4 ++--
browser/components/loop/ui/ui-showcase.js | 6 +++++-
browser/components/loop/ui/ui-showcase.jsx | 6 +++++-
6 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/browser/components/loop/content/js/roomViews.js b/browser/components/loop/content/js/roomViews.js
index eaa0caba9af..d2155ae0e13 100644
--- a/browser/components/loop/content/js/roomViews.js
+++ b/browser/components/loop/content/js/roomViews.js
@@ -81,6 +81,16 @@ loop.roomViews = (function(mozL10n) {
this.stopListening(this.props.roomStore);
},
+ handleTextareaKeyDown: function(event) {
+ // Submit the form as soon as the user press Enter in that field
+ // Note: We're using a textarea instead of a simple text input to display
+ // placeholder and entered text on two lines, to circumvent l10n
+ // rendering/UX issues for some locales.
+ if (event.which === 13) {
+ this.handleFormSubmit(event);
+ }
+ },
+
handleFormSubmit: function(event) {
event.preventDefault();
@@ -129,9 +139,10 @@ loop.roomViews = (function(mozL10n) {
mozL10n.get("rooms_name_change_failed_label")
),
React.DOM.form({onSubmit: this.handleFormSubmit},
- React.DOM.input({type: "text", className: "input-room-name",
+ React.DOM.textarea({rows: "2", type: "text", className: "input-room-name",
valueLink: this.linkState("newRoomName"),
onBlur: this.handleFormSubmit,
+ onKeyDown: this.handleTextareaKeyDown,
placeholder: mozL10n.get("rooms_name_this_room_label")})
),
React.DOM.p(null, mozL10n.get("invite_header_text")),
diff --git a/browser/components/loop/content/js/roomViews.jsx b/browser/components/loop/content/js/roomViews.jsx
index 60debab1ab0..680db543ca6 100644
--- a/browser/components/loop/content/js/roomViews.jsx
+++ b/browser/components/loop/content/js/roomViews.jsx
@@ -81,6 +81,16 @@ loop.roomViews = (function(mozL10n) {
this.stopListening(this.props.roomStore);
},
+ handleTextareaKeyDown: function(event) {
+ // Submit the form as soon as the user press Enter in that field
+ // Note: We're using a textarea instead of a simple text input to display
+ // placeholder and entered text on two lines, to circumvent l10n
+ // rendering/UX issues for some locales.
+ if (event.which === 13) {
+ this.handleFormSubmit(event);
+ }
+ },
+
handleFormSubmit: function(event) {
event.preventDefault();
@@ -129,9 +139,10 @@ loop.roomViews = (function(mozL10n) {
{mozL10n.get("rooms_name_change_failed_label")}
{mozL10n.get("invite_header_text")}
diff --git a/browser/components/loop/content/shared/css/conversation.css b/browser/components/loop/content/shared/css/conversation.css
index da6b0616814..ceaed3798b6 100644
--- a/browser/components/loop/content/shared/css/conversation.css
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -810,15 +810,20 @@ html, .fx-embedded, #main,
}
.room-invitation-overlay form {
- padding: 8em 0 2.5em 0;
+ padding: 6em 0 2em 0;
}
-.room-invitation-overlay input[type="text"] {
+.room-invitation-overlay textarea {
+ display: block;
+ background: rgba(0, 0, 0, .5);
color: #fff;
+ font-family: "Helvetica Neue", Arial, sans;
font-size: 1.2em;
border: none;
width: 200px;
margin: 0 auto;
+ padding: .2em .4em;
+ border-radius: .5em;
}
.room-invitation-overlay .btn-group {
diff --git a/browser/components/loop/test/desktop-local/roomViews_test.js b/browser/components/loop/test/desktop-local/roomViews_test.js
index e4d0e00ca17..d37e0f9ea9e 100644
--- a/browser/components/loop/test/desktop-local/roomViews_test.js
+++ b/browser/components/loop/test/desktop-local/roomViews_test.js
@@ -146,9 +146,9 @@ describe("loop.roomViews", function () {
}));
});
- it("should dispatch a RenameRoom action when enter is pressed",
+ it("should dispatch a RenameRoom action when Enter key is pressed",
function() {
- React.addons.TestUtils.Simulate.submit(roomNameBox);
+ TestUtils.Simulate.keyDown(roomNameBox, {key: "Enter", which: 13});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
diff --git a/browser/components/loop/ui/ui-showcase.js b/browser/components/loop/ui/ui-showcase.js
index 0a6653379bf..f08f524c842 100644
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -704,7 +704,11 @@
}
window.addEventListener("DOMContentLoaded", function() {
- React.renderComponent(App(null), document.body);
+ try {
+ React.renderComponent(App(null), document.body);
+ } catch(err) {
+ console.log(err);
+ }
_renderComponentsInIframes();
diff --git a/browser/components/loop/ui/ui-showcase.jsx b/browser/components/loop/ui/ui-showcase.jsx
index 2aa4b93f410..13cf01f89ba 100644
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -704,7 +704,11 @@
}
window.addEventListener("DOMContentLoaded", function() {
- React.renderComponent(, document.body);
+ try {
+ React.renderComponent(, document.body);
+ } catch(err) {
+ console.log(err);
+ }
_renderComponentsInIframes();
From 25fc750547cf4086247f82306a9ddffb8c2095fb Mon Sep 17 00:00:00 2001
From: Mike de Boer
Date: Wed, 17 Dec 2014 14:26:23 +0100
Subject: [PATCH 06/24] (no bug) convert Windows to Unix line-endings in
browser_UITour_loop.js. DONTBUILD because formatting only. r=me
---
browser/modules/test/browser_UITour_loop.js | 320 ++++++++++----------
1 file changed, 160 insertions(+), 160 deletions(-)
diff --git a/browser/modules/test/browser_UITour_loop.js b/browser/modules/test/browser_UITour_loop.js
index 25a18232a44..e314c10ade8 100644
--- a/browser/modules/test/browser_UITour_loop.js
+++ b/browser/modules/test/browser_UITour_loop.js
@@ -1,160 +1,160 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-let gTestTab;
-let gContentAPI;
-let gContentWindow;
-let loopButton;
-let loopPanel = document.getElementById("loop-notification-panel");
-
-Components.utils.import("resource:///modules/UITour.jsm");
-const { LoopRooms } = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
-
-function test() {
- UITourTest();
-}
-
-let tests = [
- taskify(function* test_menu_show_hide() {
- ise(loopButton.open, false, "Menu should initially be closed");
- gContentAPI.showMenu("loop");
-
- yield waitForConditionPromise(() => {
- return loopButton.open;
- }, "Menu should be visible after showMenu()");
-
- ok(loopPanel.hasAttribute("noautohide"), "@noautohide should be on the loop panel");
- ok(loopPanel.hasAttribute("panelopen"), "The panel should have @panelopen");
- is(loopPanel.state, "open", "The panel should be open");
- ok(loopButton.hasAttribute("open"), "Loop button should know that the menu is open");
-
- gContentAPI.hideMenu("loop");
- yield waitForConditionPromise(() => {
- return !loopButton.open;
- }, "Menu should be hidden after hideMenu()");
-
- checkLoopPanelIsHidden();
- }),
- // Test the menu was cleaned up in teardown.
- taskify(function* setup_menu_cleanup() {
- gContentAPI.showMenu("loop");
-
- yield waitForConditionPromise(() => {
- return loopButton.open;
- }, "Menu should be visible after showMenu()");
-
- // Leave it open so it gets torn down and we can test below that teardown was succesful.
- }),
- taskify(function* test_menu_cleanup() {
- // Test that the open menu from above was torn down fully.
- checkLoopPanelIsHidden();
- }),
- function test_availableTargets(done) {
- gContentAPI.showMenu("loop");
- gContentAPI.getConfiguration("availableTargets", (data) => {
- for (let targetName of ["loop-newRoom", "loop-roomList", "loop-signInUpLink"]) {
- isnot(data.targets.indexOf(targetName), -1, targetName + " should exist");
- }
- done();
- });
- },
- function test_hideMenuHidesAnnotations(done) {
- let infoPanel = document.getElementById("UITourTooltip");
- let highlightPanel = document.getElementById("UITourHighlightContainer");
-
- gContentAPI.showMenu("loop", function menuCallback() {
- gContentAPI.showHighlight("loop-roomList");
- gContentAPI.showInfo("loop-newRoom", "Make a new room", "AKA. conversation");
- UITour.getTarget(window, "loop-newRoom").then((target) => {
- waitForPopupAtAnchor(infoPanel, target.node, Task.async(function* checkPanelIsOpen() {
- isnot(loopPanel.state, "closed", "Loop panel should still be open");
- ok(loopPanel.hasAttribute("noautohide"), "@noautohide should still be on the loop panel");
- is(highlightPanel.getAttribute("targetName"), "loop-roomList", "Check highlight @targetname");
- is(infoPanel.getAttribute("targetName"), "loop-newRoom", "Check info panel @targetname");
-
- info("Close the loop menu and make sure the annotations inside disappear");
- let hiddenPromises = [promisePanelElementHidden(window, infoPanel),
- promisePanelElementHidden(window, highlightPanel)];
- gContentAPI.hideMenu("loop");
- yield Promise.all(hiddenPromises);
- isnot(infoPanel.state, "open", "Info panel should have automatically hid");
- isnot(highlightPanel.state, "open", "Highlight panel should have automatically hid");
- done();
- }), "Info panel should be anchored to the new room button");
- });
- });
- },
- function test_notifyLoopChatWindowOpenedClosed(done) {
- gContentAPI.observe((event, params) => {
- is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
- gContentAPI.observe((event, params) => {
- is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
- gContentAPI.observe((event, params) => {
- is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
- gContentAPI.observe((event, params) => {
- ok(false, "No more notifications should have arrived");
- });
- });
- done();
- });
- document.querySelector("#pinnedchats > chatbox").close();
- });
- LoopRooms.open("fakeTourRoom");
- },
- taskify(function* test_arrow_panel_position() {
- ise(loopButton.open, false, "Menu should initially be closed");
- let popup = document.getElementById("UITourTooltip");
-
- yield showMenuPromise("loop");
-
- let currentTarget = "loop-newRoom";
- yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
- is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
-
- currentTarget = "loop-roomList";
- yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
- is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
-
- currentTarget = "loop-signInUpLink";
- yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be underneath");
- is(popup.popupBoxObject.alignmentPosition, "after_end", "Check " + currentTarget + " position");
- }),
-];
-
-// End tests
-
-function checkLoopPanelIsHidden() {
- ok(!loopPanel.hasAttribute("noautohide"), "@noautohide on the loop panel should have been cleaned up");
- ok(!loopPanel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
- isnot(loopPanel.state, "open", "The panel shouldn't be open");
- is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
-}
-
-if (Services.prefs.getBoolPref("loop.enabled")) {
- loopButton = window.LoopUI.toolbarButton.node;
- // The targets to highlight only appear after getting started is launched.
- Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
- Services.prefs.setCharPref("loop.server", "http://localhost");
- Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
-
- registerCleanupFunction(() => {
- Services.prefs.clearUserPref("loop.gettingStarted.seen");
- Services.prefs.clearUserPref("loop.server");
- Services.prefs.clearUserPref("services.push.serverURL");
-
- // Copied from browser/components/loop/test/mochitest/head.js
- // Remove the iframe after each test. This also avoids mochitest complaining
- // about leaks on shutdown as we intentionally hold the iframe open for the
- // life of the application.
- let frameId = loopButton.getAttribute("notificationFrameId");
- let frame = document.getElementById(frameId);
- if (frame) {
- frame.remove();
- }
- });
-} else {
- ok(true, "Loop is disabled so skip the UITour Loop tests");
- tests = [];
-}
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let gTestTab;
+let gContentAPI;
+let gContentWindow;
+let loopButton;
+let loopPanel = document.getElementById("loop-notification-panel");
+
+Components.utils.import("resource:///modules/UITour.jsm");
+const { LoopRooms } = Components.utils.import("resource:///modules/loop/LoopRooms.jsm", {});
+
+function test() {
+ UITourTest();
+}
+
+let tests = [
+ taskify(function* test_menu_show_hide() {
+ ise(loopButton.open, false, "Menu should initially be closed");
+ gContentAPI.showMenu("loop");
+
+ yield waitForConditionPromise(() => {
+ return loopButton.open;
+ }, "Menu should be visible after showMenu()");
+
+ ok(loopPanel.hasAttribute("noautohide"), "@noautohide should be on the loop panel");
+ ok(loopPanel.hasAttribute("panelopen"), "The panel should have @panelopen");
+ is(loopPanel.state, "open", "The panel should be open");
+ ok(loopButton.hasAttribute("open"), "Loop button should know that the menu is open");
+
+ gContentAPI.hideMenu("loop");
+ yield waitForConditionPromise(() => {
+ return !loopButton.open;
+ }, "Menu should be hidden after hideMenu()");
+
+ checkLoopPanelIsHidden();
+ }),
+ // Test the menu was cleaned up in teardown.
+ taskify(function* setup_menu_cleanup() {
+ gContentAPI.showMenu("loop");
+
+ yield waitForConditionPromise(() => {
+ return loopButton.open;
+ }, "Menu should be visible after showMenu()");
+
+ // Leave it open so it gets torn down and we can test below that teardown was succesful.
+ }),
+ taskify(function* test_menu_cleanup() {
+ // Test that the open menu from above was torn down fully.
+ checkLoopPanelIsHidden();
+ }),
+ function test_availableTargets(done) {
+ gContentAPI.showMenu("loop");
+ gContentAPI.getConfiguration("availableTargets", (data) => {
+ for (let targetName of ["loop-newRoom", "loop-roomList", "loop-signInUpLink"]) {
+ isnot(data.targets.indexOf(targetName), -1, targetName + " should exist");
+ }
+ done();
+ });
+ },
+ function test_hideMenuHidesAnnotations(done) {
+ let infoPanel = document.getElementById("UITourTooltip");
+ let highlightPanel = document.getElementById("UITourHighlightContainer");
+
+ gContentAPI.showMenu("loop", function menuCallback() {
+ gContentAPI.showHighlight("loop-roomList");
+ gContentAPI.showInfo("loop-newRoom", "Make a new room", "AKA. conversation");
+ UITour.getTarget(window, "loop-newRoom").then((target) => {
+ waitForPopupAtAnchor(infoPanel, target.node, Task.async(function* checkPanelIsOpen() {
+ isnot(loopPanel.state, "closed", "Loop panel should still be open");
+ ok(loopPanel.hasAttribute("noautohide"), "@noautohide should still be on the loop panel");
+ is(highlightPanel.getAttribute("targetName"), "loop-roomList", "Check highlight @targetname");
+ is(infoPanel.getAttribute("targetName"), "loop-newRoom", "Check info panel @targetname");
+
+ info("Close the loop menu and make sure the annotations inside disappear");
+ let hiddenPromises = [promisePanelElementHidden(window, infoPanel),
+ promisePanelElementHidden(window, highlightPanel)];
+ gContentAPI.hideMenu("loop");
+ yield Promise.all(hiddenPromises);
+ isnot(infoPanel.state, "open", "Info panel should have automatically hid");
+ isnot(highlightPanel.state, "open", "Highlight panel should have automatically hid");
+ done();
+ }), "Info panel should be anchored to the new room button");
+ });
+ });
+ },
+ function test_notifyLoopChatWindowOpenedClosed(done) {
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
+ gContentAPI.observe((event, params) => {
+ ok(false, "No more notifications should have arrived");
+ });
+ });
+ done();
+ });
+ document.querySelector("#pinnedchats > chatbox").close();
+ });
+ LoopRooms.open("fakeTourRoom");
+ },
+ taskify(function* test_arrow_panel_position() {
+ ise(loopButton.open, false, "Menu should initially be closed");
+ let popup = document.getElementById("UITourTooltip");
+
+ yield showMenuPromise("loop");
+
+ let currentTarget = "loop-newRoom";
+ yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
+ is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
+
+ currentTarget = "loop-roomList";
+ yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
+ is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
+
+ currentTarget = "loop-signInUpLink";
+ yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be underneath");
+ is(popup.popupBoxObject.alignmentPosition, "after_end", "Check " + currentTarget + " position");
+ }),
+];
+
+// End tests
+
+function checkLoopPanelIsHidden() {
+ ok(!loopPanel.hasAttribute("noautohide"), "@noautohide on the loop panel should have been cleaned up");
+ ok(!loopPanel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
+ isnot(loopPanel.state, "open", "The panel shouldn't be open");
+ is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
+}
+
+if (Services.prefs.getBoolPref("loop.enabled")) {
+ loopButton = window.LoopUI.toolbarButton.node;
+ // The targets to highlight only appear after getting started is launched.
+ Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
+ Services.prefs.setCharPref("loop.server", "http://localhost");
+ Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("loop.gettingStarted.seen");
+ Services.prefs.clearUserPref("loop.server");
+ Services.prefs.clearUserPref("services.push.serverURL");
+
+ // Copied from browser/components/loop/test/mochitest/head.js
+ // Remove the iframe after each test. This also avoids mochitest complaining
+ // about leaks on shutdown as we intentionally hold the iframe open for the
+ // life of the application.
+ let frameId = loopButton.getAttribute("notificationFrameId");
+ let frame = document.getElementById(frameId);
+ if (frame) {
+ frame.remove();
+ }
+ });
+} else {
+ ok(true, "Loop is disabled so skip the UITour Loop tests");
+ tests = [];
+}
From 3f63e3add1740cc8d4a4d6c0b9aab2bfc336f554 Mon Sep 17 00:00:00 2001
From: Mike de Boer
Date: Wed, 17 Dec 2014 09:33:08 +0100
Subject: [PATCH 07/24] Bug 1080948: UITour: tell the page when a URL is copied
or emailed. r=MattN,dmose
---
browser/components/loop/LoopRooms.jsm | 21 +++++++
browser/components/loop/MozLoopAPI.jsm | 18 +++++-
.../loop/content/shared/js/roomStore.js | 2 +
browser/modules/test/browser_UITour_loop.js | 61 +++++++++++++++++++
4 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/browser/components/loop/LoopRooms.jsm b/browser/components/loop/LoopRooms.jsm
index 13afd7eb3d5..48abe5f70a3 100644
--- a/browser/components/loop/LoopRooms.jsm
+++ b/browser/components/loop/LoopRooms.jsm
@@ -570,6 +570,27 @@ this.LoopRooms = {
return LoopRoomsInternal.maybeRefresh(user);
},
+ /**
+ * This method is only useful for unit tests to set the rooms cache to contain
+ * a list of fake room data that can be asserted in tests.
+ *
+ * @param {Map} stub Stub cache containing fake rooms data
+ */
+ stubCache: function(stub) {
+ LoopRoomsInternal.rooms.clear();
+ if (stub) {
+ // Fill up the rooms cache with room objects provided in the `stub` Map.
+ for (let [key, value] of stub.entries()) {
+ LoopRoomsInternal.rooms.set(key, value);
+ }
+ gDirty = false;
+ } else {
+ // Restore the cache to not be stubbed anymore, but it'll need a refresh
+ // from the server for sure.
+ gDirty = true;
+ }
+ },
+
promise: function(method, ...params) {
return new Promise((resolve, reject) => {
this[method](...params, (error, result) => {
diff --git a/browser/components/loop/MozLoopAPI.jsm b/browser/components/loop/MozLoopAPI.jsm
index 71b97e5c153..cf99747ea96 100644
--- a/browser/components/loop/MozLoopAPI.jsm
+++ b/browser/components/loop/MozLoopAPI.jsm
@@ -23,6 +23,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "hookWindowCloseForPanelClose",
"resource://gre/modules/MozSocialAPI.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "UITour",
+ "resource:///modules/UITour.jsm");
XPCOMUtils.defineLazyGetter(this, "appInfo", function() {
return Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULAppInfo)
@@ -735,7 +737,21 @@ function injectLoopAPI(targetWindow) {
callId: callid
});
}
- }
+ },
+
+ /**
+ * Notifies the UITour module that an event occurred that it might be
+ * interested in.
+ *
+ * @param {String} subject Subject of the notification
+ */
+ notifyUITour: {
+ enumerable: true,
+ writable: true,
+ value: function(subject) {
+ UITour.notify(subject);
+ }
+ },
};
function onStatusChanged(aSubject, aTopic, aData) {
diff --git a/browser/components/loop/content/shared/js/roomStore.js b/browser/components/loop/content/shared/js/roomStore.js
index 903225ee503..ca05036a299 100644
--- a/browser/components/loop/content/shared/js/roomStore.js
+++ b/browser/components/loop/content/shared/js/roomStore.js
@@ -298,6 +298,7 @@ loop.store = loop.store || {};
*/
copyRoomUrl: function(actionData) {
this._mozLoop.copyString(actionData.roomUrl);
+ this._mozLoop.notifyUITour("Loop:RoomURLCopied");
},
/**
@@ -307,6 +308,7 @@ loop.store = loop.store || {};
*/
emailRoomUrl: function(actionData) {
loop.shared.utils.composeCallUrlEmail(actionData.roomUrl);
+ this._mozLoop.notifyUITour("Loop:RoomURLEmailed");
},
/**
diff --git a/browser/modules/test/browser_UITour_loop.js b/browser/modules/test/browser_UITour_loop.js
index e314c10ade8..b8cb4a91f8d 100644
--- a/browser/modules/test/browser_UITour_loop.js
+++ b/browser/modules/test/browser_UITour_loop.js
@@ -103,6 +103,58 @@ let tests = [
});
LoopRooms.open("fakeTourRoom");
},
+ function test_notifyLoopRoomURLCopied(done) {
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowOpened", "Loop chat window should've opened");
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
+
+ let chat = document.querySelector("#pinnedchats > chatbox");
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:RoomURLCopied", "Check Loop:RoomURLCopied notification");
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
+ });
+ chat.close();
+ done();
+ });
+ chat.content.contentDocument.querySelector(".btn-copy").click();
+ });
+ });
+ setupFakeRoom();
+ LoopRooms.open("fakeTourRoom");
+ },
+ function test_notifyLoopRoomURLEmailed(done) {
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowOpened", "Loop chat window should've opened");
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
+
+ let chat = document.querySelector("#pinnedchats > chatbox");
+ let composeEmailCalled = false;
+
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:RoomURLEmailed", "Check Loop:RoomURLEmailed notification");
+ ok(composeEmailCalled, "mozLoop.composeEmail should be called");
+ gContentAPI.observe((event, params) => {
+ is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
+ });
+ chat.close();
+ done();
+ });
+
+ let chatWin = chat.content.contentWindow;
+ let oldComposeEmail = chatWin.navigator.wrappedJSObject.mozLoop.composeEmail;
+ chatWin.navigator.wrappedJSObject.mozLoop.composeEmail = function(recipient, subject, body) {
+ ok(recipient, "composeEmail should be invoked with at least a recipient value");
+ composeEmailCalled = true;
+ chatWin.navigator.wrappedJSObject.mozLoop.composeEmail = oldComposeEmail;
+ };
+ chatWin.document.querySelector(".btn-email").click();
+ });
+ });
+ LoopRooms.open("fakeTourRoom");
+ },
taskify(function* test_arrow_panel_position() {
ise(loopButton.open, false, "Menu should initially be closed");
let popup = document.getElementById("UITourTooltip");
@@ -132,6 +184,15 @@ function checkLoopPanelIsHidden() {
is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
}
+function setupFakeRoom() {
+ let room = {};
+ for (let prop of ["roomToken", "roomName", "roomOwner", "roomUrl", "participants"])
+ room[prop] = "fakeTourRoom";
+ LoopRooms.stubCache(new Map([
+ [room.roomToken, room]
+ ]));
+}
+
if (Services.prefs.getBoolPref("loop.enabled")) {
loopButton = window.LoopUI.toolbarButton.node;
// The targets to highlight only appear after getting started is launched.
From f1910c270346e88b0acd66cc2f140c589a9433bf Mon Sep 17 00:00:00 2001
From: Michael Ratcliffe
Date: Wed, 17 Dec 2014 13:43:30 +0000
Subject: [PATCH 08/24] Bug 1111601 - Avoid using hiddenwindow in DevTools code
r=pbrosset
---
browser/devtools/eyedropper/eyedropper.js | 5 +-
.../projecteditor/lib/stores/local.js | 10 +-
.../devtools/shared/test/browser_css_color.js | 2 +-
browser/devtools/styleinspector/rule-view.js | 26 +---
toolkit/devtools/css-color.js | 130 +++++++-----------
toolkit/devtools/output-parser.js | 10 +-
6 files changed, 57 insertions(+), 126 deletions(-)
diff --git a/browser/devtools/eyedropper/eyedropper.js b/browser/devtools/eyedropper/eyedropper.js
index cb2992dbaa3..e0a3f816bd5 100644
--- a/browser/devtools/eyedropper/eyedropper.js
+++ b/browser/devtools/eyedropper/eyedropper.js
@@ -6,6 +6,7 @@ const {Cc, Ci, Cu} = require("chrome");
const {rgbToHsl} = require("devtools/css-color").colorUtils;
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
+const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
Cu.import("resource://gre/modules/Services.jsm");
@@ -546,7 +547,7 @@ Eyedropper.prototype = {
* Callback to be called when the color is in the clipboard.
*/
copyColor: function(callback) {
- Services.appShell.hiddenDOMWindow.clearTimeout(this._copyTimeout);
+ clearTimeout(this._copyTimeout);
let color = this._colorValue.value;
clipboardHelper.copyString(color);
@@ -554,7 +555,7 @@ Eyedropper.prototype = {
this._colorValue.classList.add("highlight");
this._colorValue.value = "✓ " + l10n.GetStringFromName("colorValue.copied");
- this._copyTimeout = Services.appShell.hiddenDOMWindow.setTimeout(() => {
+ this._copyTimeout = setTimeout(() => {
this._colorValue.classList.remove("highlight");
this._colorValue.value = color;
diff --git a/browser/devtools/projecteditor/lib/stores/local.js b/browser/devtools/projecteditor/lib/stores/local.js
index 0053966124a..7fdc42107bc 100644
--- a/browser/devtools/projecteditor/lib/stores/local.js
+++ b/browser/devtools/projecteditor/lib/stores/local.js
@@ -14,6 +14,7 @@ const promise = require("projecteditor/helpers/promise");
const { on, forget } = require("projecteditor/helpers/event");
const { FileResource } = require("projecteditor/stores/resource");
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
+const {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
const CHECK_LINKED_DIRECTORY_DELAY = 5000;
const SHOULD_LIVE_REFRESH = true;
@@ -35,7 +36,6 @@ var LocalStore = Class({
initialize: function(path) {
this.initStore();
- this.window = Services.appShell.hiddenDOMWindow;
this.path = OS.Path.normalize(path);
this.rootPath = this.path;
this.displayName = this.path;
@@ -46,9 +46,8 @@ var LocalStore = Class({
},
destroy: function() {
- if (this.window) {
- this.window.clearTimeout(this._refreshTimeout);
- }
+ clearTimeout(this._refreshTimeout);
+
if (this._refreshDeferred) {
this._refreshDeferred.reject("destroy");
}
@@ -58,7 +57,6 @@ var LocalStore = Class({
this._refreshTimeout = null;
this._refreshDeferred = null;
- this.window = null;
this.worker = null;
if (this.root) {
@@ -132,7 +130,7 @@ var LocalStore = Class({
// XXX: Once Bug 958280 adds a watch function, will not need to forever loop here.
this.refresh().then(() => {
if (SHOULD_LIVE_REFRESH) {
- this._refreshTimeout = this.window.setTimeout(this.refreshLoop,
+ this._refreshTimeout = setTimeout(this.refreshLoop,
CHECK_LINKED_DIRECTORY_DELAY);
}
});
diff --git a/browser/devtools/shared/test/browser_css_color.js b/browser/devtools/shared/test/browser_css_color.js
index e7efcc85150..ab498db791d 100644
--- a/browser/devtools/shared/test/browser_css_color.js
+++ b/browser/devtools/shared/test/browser_css_color.js
@@ -17,7 +17,7 @@ function test() {
waitForFocus(init, content);
}, true);
- content.location = "data:text/html,browser_css_color.js";
+ content.location = "data:text/html;charset=utf-8,browser_css_color.js";
}
function init() {
diff --git a/browser/devtools/styleinspector/rule-view.js b/browser/devtools/styleinspector/rule-view.js
index 0cfe6ec40b3..dad2872c589 100644
--- a/browser/devtools/styleinspector/rule-view.js
+++ b/browser/devtools/styleinspector/rule-view.js
@@ -2822,32 +2822,10 @@ TextPropertyEditor.prototype = {
* Validate this property. Does it make sense for this value to be assigned
* to this property name? This does not apply the property value
*
- * @param {string} [aValue]
- * The property value used for validation.
- * Defaults to the current value for this.prop
- *
* @return {bool} true if the property value is valid, false otherwise.
*/
- isValid: function(aValue) {
- let name = this.prop.name;
- let value = typeof aValue == "undefined" ? this.prop.value : aValue;
- let val = parseSingleValue(value);
-
- let style = this.doc.createElementNS(HTML_NS, "div").style;
- let prefs = Services.prefs;
-
- // We toggle output of errors whilst the user is typing a property value.
- let prefVal = prefs.getBoolPref("layout.css.report_errors");
- prefs.setBoolPref("layout.css.report_errors", false);
-
- let validValue = false;
- try {
- style.setProperty(name, val.value, val.priority);
- validValue = style.getPropertyValue(name) !== "" || val.value === "";
- } finally {
- prefs.setBoolPref("layout.css.report_errors", prefVal);
- }
- return validValue;
+ isValid: function() {
+ return domUtils.cssPropertyIsValid(this.prop.name, this.prop.value);
}
};
diff --git a/toolkit/devtools/css-color.js b/toolkit/devtools/css-color.js
index 170e2456822..da5ef242ba1 100644
--- a/toolkit/devtools/css-color.js
+++ b/toolkit/devtools/css-color.js
@@ -10,8 +10,6 @@ const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
const REGEX_JUST_QUOTES = /^""$/;
-const REGEX_RGB_3_TUPLE = /^rgb\(([\d.]+),\s*([\d.]+),\s*([\d.]+)\)$/i;
-const REGEX_RGBA_4_TUPLE = /^rgba\(([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+|1|0)\)$/i;
const REGEX_HSL_3_TUPLE = /^\bhsl\(([\d.]+),\s*([\d.]+%),\s*([\d.]+%)\)$/i;
/**
@@ -106,7 +104,7 @@ CssColor.prototype = {
},
get valid() {
- return this._validateColor(this.authored);
+ return DOMUtils.isValidCSSColor(this.authored);
},
/**
@@ -126,11 +124,9 @@ CssColor.prototype = {
},
get name() {
- if (!this.valid) {
- return "";
- }
- if (this.specialValue) {
- return this.specialValue;
+ let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
+ if (invalidOrSpecialValue !== false) {
+ return invalidOrSpecialValue;
}
try {
@@ -147,11 +143,9 @@ CssColor.prototype = {
},
get hex() {
- if (!this.valid) {
- return "";
- }
- if (this.specialValue) {
- return this.specialValue;
+ let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
+ if (invalidOrSpecialValue !== false) {
+ return invalidOrSpecialValue;
}
if (this.hasAlpha) {
return this.rgba;
@@ -167,11 +161,9 @@ CssColor.prototype = {
},
get longHex() {
- if (!this.valid) {
- return "";
- }
- if (this.specialValue) {
- return this.specialValue;
+ let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
+ if (invalidOrSpecialValue !== false) {
+ return invalidOrSpecialValue;
}
if (this.hasAlpha) {
return this.rgba;
@@ -182,11 +174,9 @@ CssColor.prototype = {
},
get rgb() {
- if (!this.valid) {
- return "";
- }
- if (this.specialValue) {
- return this.specialValue;
+ let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
+ if (invalidOrSpecialValue !== false) {
+ return invalidOrSpecialValue;
}
if (!this.hasAlpha) {
if (this.authored.startsWith("rgb(")) {
@@ -200,11 +190,9 @@ CssColor.prototype = {
},
get rgba() {
- if (!this.valid) {
- return "";
- }
- if (this.specialValue) {
- return this.specialValue;
+ let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
+ if (invalidOrSpecialValue !== false) {
+ return invalidOrSpecialValue;
}
if (this.authored.startsWith("rgba(")) {
// The color is valid and begins with rgba(. Return the authored value.
@@ -218,11 +206,9 @@ CssColor.prototype = {
},
get hsl() {
- if (!this.valid) {
- return "";
- }
- if (this.specialValue) {
- return this.specialValue;
+ let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
+ if (invalidOrSpecialValue !== false) {
+ return invalidOrSpecialValue;
}
if (this.authored.startsWith("hsl(")) {
// The color is valid and begins with hsl(. Return the authored value.
@@ -235,11 +221,9 @@ CssColor.prototype = {
},
get hsla() {
- if (!this.valid) {
- return "";
- }
- if (this.specialValue) {
- return this.specialValue;
+ let invalidOrSpecialValue = this._getInvalidOrSpecialValue();
+ if (invalidOrSpecialValue !== false) {
+ return invalidOrSpecialValue;
}
if (this.authored.startsWith("hsla(")) {
// The color is valid and begins with hsla(. Return the authored value.
@@ -252,6 +236,27 @@ CssColor.prototype = {
return this._hslNoAlpha().replace("hsl", "hsla").replace(")", ", 1)");
},
+ /**
+ * Check whether the current color value is in the special list e.g.
+ * transparent or invalid.
+ *
+ * @return {String|Boolean}
+ * - If the current color is a special value e.g. "transparent" then
+ * return the color.
+ * - If the color is invalid return an empty string.
+ * - If the color is a regular color e.g. #F06 so we return false
+ * to indicate that the color is neither invalid or special.
+ */
+ _getInvalidOrSpecialValue: function() {
+ if (this.specialValue) {
+ return this.specialValue;
+ }
+ if (!this.valid) {
+ return "";
+ }
+ return false;
+ },
+
/**
* Change color
*
@@ -298,27 +303,11 @@ CssColor.prototype = {
* appropriate.
*/
_getRGBATuple: function() {
- let win = Services.appShell.hiddenDOMWindow;
- let doc = win.document;
- let span = doc.createElement("span");
- span.style.color = this.authored;
- let computed = win.getComputedStyle(span).color;
+ let tuple = DOMUtils.colorToRGBA(this.authored);
- if (computed === "transparent") {
- return {r: 0, g: 0, b: 0, a: 0};
- }
+ tuple.a = parseFloat(tuple.a.toFixed(1));
- let rgba = computed.match(REGEX_RGBA_4_TUPLE);
-
- if (rgba) {
- let [, r, g, b, a] = rgba;
- return {r: r, g: g, b: b, a: a};
- } else {
- let rgb = computed.match(REGEX_RGB_3_TUPLE);
- let [, r, g, b] = rgb;
-
- return {r: r, g: g, b: b, a: 1};
- }
+ return tuple;
},
_hslNoAlpha: function() {
@@ -342,33 +331,6 @@ CssColor.prototype = {
valueOf: function() {
return this.rgba;
},
-
- _validateColor: function(color) {
- if (typeof color !== "string" || color === "") {
- return false;
- }
-
- let win = Services.appShell.hiddenDOMWindow;
- let doc = win.document;
-
- // Create a black span in a hidden window.
- let span = doc.createElement("span");
- span.style.color = "rgb(0, 0, 0)";
-
- // Attempt to set the color. If the color is no longer black we know that
- // color is valid.
- span.style.color = color;
- if (span.style.color !== "rgb(0, 0, 0)") {
- return true;
- }
-
- // If the color is black then the above check will have failed. We change
- // the span to white and attempt to reapply the color. If the span is not
- // white then we know that the color is valid otherwise we return invalid.
- span.style.color = "rgb(255, 255, 255)";
- span.style.color = color;
- return span.style.color !== "rgb(255, 255, 255)";
- },
};
/**
diff --git a/toolkit/devtools/output-parser.js b/toolkit/devtools/output-parser.js
index 902393ceea6..469b4e117a3 100644
--- a/toolkit/devtools/output-parser.js
+++ b/toolkit/devtools/output-parser.js
@@ -337,15 +337,7 @@ OutputParser.prototype = {
* CSS Property value to check
*/
_cssPropertySupportsValue: function(name, value) {
- let win = Services.appShell.hiddenDOMWindow;
- let doc = win.document;
-
- value = value.replace("!important", "");
-
- let div = doc.createElement("div");
- div.style.setProperty(name, value);
-
- return !!div.style.getPropertyValue(name);
+ return DOMUtils.cssPropertyIsValid(name, value);
},
/**
From 4aa070b7b422f3d87c346b7746c552e98a5cd607 Mon Sep 17 00:00:00 2001
From: Mike de Boer
Date: Wed, 17 Dec 2014 15:24:06 +0100
Subject: [PATCH 09/24] Fix marionette bustage - follow-up of bug 1080948.
CLOSED TREE. r=bustage
---
browser/components/loop/test/shared/roomStore_test.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/browser/components/loop/test/shared/roomStore_test.js b/browser/components/loop/test/shared/roomStore_test.js
index 741aef06aea..64d5f686d86 100644
--- a/browser/components/loop/test/shared/roomStore_test.js
+++ b/browser/components/loop/test/shared/roomStore_test.js
@@ -77,6 +77,7 @@ describe("loop.store.RoomStore", function () {
beforeEach(function() {
fakeMozLoop = {
copyString: function() {},
+ notifyUITour: function() {},
rooms: {
create: function() {},
getAll: function() {},
From 2961143573df170ab472d3846c57daea776e7b97 Mon Sep 17 00:00:00 2001
From: Mark Finkle
Date: Wed, 17 Dec 2014 10:04:26 -0500
Subject: [PATCH 10/24] Bug 1110607 - Enable tab mirroring by default on all
channels r=blassey
---
mobile/android/app/mobile.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js
index 3eedd7f4717..a4c81efd558 100644
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -280,13 +280,13 @@ pref("browser.search.noCurrentEngine", true);
pref("browser.search.official", true);
#endif
-// Control media casting feature
+// Control media casting & mirroring features
pref("browser.casting.enabled", true);
+pref("browser.mirroring.enabled", true);
#ifdef RELEASE_BUILD
-pref("browser.mirroring.enabled", false);
+// Roku does not yet support mirroring in production
pref("browser.mirroring.enabled.roku", false);
#else
-pref("browser.mirroring.enabled", true);
pref("browser.mirroring.enabled.roku", true);
#endif
From 21b13d4ae1b8ff0379e21801f74cb95c36bc66f6 Mon Sep 17 00:00:00 2001
From: Eugen Sawin
Date: Wed, 17 Dec 2014 16:03:04 +0100
Subject: [PATCH 11/24] Bug 991923 - Set Android SDK version in DNS resolver.
r=sworkman
---
other-licenses/android/getaddrinfo.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/other-licenses/android/getaddrinfo.c b/other-licenses/android/getaddrinfo.c
index c2267b6c095..448499b90c6 100644
--- a/other-licenses/android/getaddrinfo.c
+++ b/other-licenses/android/getaddrinfo.c
@@ -422,19 +422,38 @@ extern int
__real_getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res);
-int android_sdk_version;
-
#pragma GCC visibility pop
-int android_sdk_version = -1;
+static int get_android_sdk_version()
+{
+ char version_str[PROP_VALUE_MAX];
+ memset(version_str, 0, PROP_VALUE_MAX);
+ int len = __system_property_get("ro.build.version.sdk", version_str);
+ if (len < 1) {
+#ifdef MOZ_GETADDRINFO_LOG_VERBOSE
+ __android_log_print(ANDROID_LOG_INFO, "getaddrinfo",
+ "Failed to get Android SDK version\n");
+#endif
+
+ return len;
+ }
+
+ return (int)strtol(version_str, NULL, 10);
+}
static int honeycomb_or_later()
{
+ static int android_sdk_version = 0;
+ if (android_sdk_version == 0) {
+ android_sdk_version = get_android_sdk_version();
+ }
+
#ifdef MOZ_GETADDRINFO_LOG_VERBOSE
__android_log_print(ANDROID_LOG_INFO, "getaddrinfo",
"I am%s Honeycomb\n",
(android_sdk_version >= 11) ? "" : " not");
#endif
+
return android_sdk_version >= 11;
}
From 7ae192629da8ff0ab01cfb0d33f126f56559d78d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Qu=C3=A8ze?=
Date: Wed, 17 Dec 2014 16:20:01 +0100
Subject: [PATCH 12/24] Bug 1106559 - Improve the search preference UI,
r=felipe,dao.
---
browser/components/preferences/jar.mn | 1 -
.../components/preferences/preferences.xul | 2 +-
browser/components/preferences/search.css | 29 -
browser/components/preferences/search.js | 518 ++++++++++++++++--
browser/components/preferences/search.xul | 32 +-
browser/themes/linux/jar.mn | 1 +
browser/themes/linux/preferences/search.css | 39 ++
browser/themes/osx/jar.mn | 7 +
.../osx/preferences/checkbox-yosemite.png | Bin 0 -> 1033 bytes
.../osx/preferences/checkbox-yosemite@2x.png | Bin 0 -> 2434 bytes
browser/themes/osx/preferences/checkbox.png | Bin 0 -> 1685 bytes
.../themes/osx/preferences/checkbox@2x.png | Bin 0 -> 3699 bytes
browser/themes/osx/preferences/search.css | 54 ++
browser/themes/windows/jar.mn | 10 +
.../themes/windows/preferences/checkbox-8.png | Bin 0 -> 705 bytes
.../windows/preferences/checkbox-aero.png | Bin 0 -> 1566 bytes
.../windows/preferences/checkbox-classic.png | Bin 0 -> 284 bytes
.../windows/preferences/checkbox-xp.png | Bin 0 -> 1417 bytes
browser/themes/windows/preferences/search.css | 59 ++
19 files changed, 687 insertions(+), 65 deletions(-)
delete mode 100644 browser/components/preferences/search.css
create mode 100644 browser/themes/linux/preferences/search.css
create mode 100644 browser/themes/osx/preferences/checkbox-yosemite.png
create mode 100644 browser/themes/osx/preferences/checkbox-yosemite@2x.png
create mode 100644 browser/themes/osx/preferences/checkbox.png
create mode 100644 browser/themes/osx/preferences/checkbox@2x.png
create mode 100644 browser/themes/osx/preferences/search.css
create mode 100644 browser/themes/windows/preferences/checkbox-8.png
create mode 100644 browser/themes/windows/preferences/checkbox-aero.png
create mode 100644 browser/themes/windows/preferences/checkbox-classic.png
create mode 100644 browser/themes/windows/preferences/checkbox-xp.png
create mode 100644 browser/themes/windows/preferences/search.css
diff --git a/browser/components/preferences/jar.mn b/browser/components/preferences/jar.mn
index 384ae71c5f5..717af639044 100644
--- a/browser/components/preferences/jar.mn
+++ b/browser/components/preferences/jar.mn
@@ -45,7 +45,6 @@ browser.jar:
content/browser/preferences/sync.js
#endif
content/browser/preferences/search.xul
- content/browser/preferences/search.css
content/browser/preferences/search.js
* content/browser/preferences/tabs.xul
* content/browser/preferences/tabs.js
diff --git a/browser/components/preferences/preferences.xul b/browser/components/preferences/preferences.xul
index 8783c558aa1..984775f45c8 100644
--- a/browser/components/preferences/preferences.xul
+++ b/browser/components/preferences/preferences.xul
@@ -16,7 +16,7 @@
-->
-
+
diff --git a/browser/components/preferences/search.css b/browser/components/preferences/search.css
deleted file mode 100644
index 9866ec61897..00000000000
--- a/browser/components/preferences/search.css
+++ /dev/null
@@ -1,29 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#oneClickProvidersList richlistitem {
- -moz-binding: url("chrome://global/content/bindings/checkbox.xml#checkbox");
- -moz-padding-start: 5px;
- height: 22px; /* setting the height of checkboxes is required to let the
- window auto-sizing code work. */
-}
-
-#oneClickProvidersList {
- height: 178px;
-}
-
-.searchengine-menuitem > .menu-iconic-left {
- display: -moz-box
-}
-
-.checkbox-label-box {
- -moz-box-align: center;
- -moz-appearance: none;
- border: none;
-}
-
-.checkbox-icon {
- margin: 3px 3px;
- max-width: 16px;
-}
diff --git a/browser/components/preferences/search.js b/browser/components/preferences/search.js
index 36b06cc976c..04fcdae173d 100644
--- a/browser/components/preferences/search.js
+++ b/browser/components/preferences/search.js
@@ -4,13 +4,45 @@
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+const ENGINE_FLAVOR = "text/x-moz-search-engine";
+
+var gEngineView = null;
+
var gSearchPane = {
init: function ()
{
+ gEngineView = new EngineView(new EngineStore());
+ document.getElementById("engineList").view = gEngineView;
+ this.buildDefaultEngineDropDown();
+
+ Services.obs.addObserver(this, "browser-search-engine-modified", false);
+ window.addEventListener("unload", () => {
+ Services.obs.removeObserver(this, "browser-search-engine-modified", false);
+ });
+ },
+
+ buildDefaultEngineDropDown: function() {
+ // This is called each time something affects the list of engines.
let list = document.getElementById("defaultEngine");
- let currentEngine = Services.search.currentEngine.name;
- Services.search.getVisibleEngines().forEach(e => {
+ let currentEngine;
+
+ // First, try to preserve the current selection.
+ if (list.selectedItem)
+ currentEngine = list.selectedItem.label;
+
+ // If there's no current selection, use the current default engine.
+ if (!currentEngine)
+ currentEngine = Services.search.currentEngine.name;
+
+ // If the current engine isn't in the list any more, select the first item.
+ let engines = gEngineView._engineStore._engines;
+ if (!engines.some(e => e.name == currentEngine))
+ currentEngine = engines[0].name;
+
+ // Now clean-up and rebuild the list.
+ list.removeAllItems();
+ gEngineView._engineStore._engines.forEach(e => {
let item = list.appendItem(e.name);
item.setAttribute("class", "menuitem-iconic searchengine-menuitem menuitem-with-favicon");
if (e.iconURI)
@@ -19,50 +51,472 @@ var gSearchPane = {
if (e.name == currentEngine)
list.selectedItem = item;
});
-
- this.displayOneClickEnginesList();
-
- document.getElementById("oneClickProvidersList")
- .addEventListener("CheckboxStateChange", gSearchPane.saveOneClickEnginesList);
},
- displayOneClickEnginesList: function () {
- let richlistbox = document.getElementById("oneClickProvidersList");
- let pref = document.getElementById("browser.search.hiddenOneOffs").value;
- let hiddenList = pref ? pref.split(",") : [];
+ observe: function(aEngine, aTopic, aVerb) {
+ if (aTopic == "browser-search-engine-modified") {
+ aEngine.QueryInterface(Components.interfaces.nsISearchEngine);
+ switch (aVerb) {
+ case "engine-added":
+ gEngineView._engineStore.addEngine(aEngine);
+ gEngineView.rowCountChanged(gEngineView.lastIndex, 1);
+ gSearchPane.buildDefaultEngineDropDown();
+ break;
+ case "engine-changed":
+ gEngineView._engineStore.reloadIcons();
+ gEngineView.invalidate();
+ break;
+ case "engine-removed":
+ case "engine-current":
+ case "engine-default":
+ // Not relevant
+ break;
+ }
+ }
+ },
- while (richlistbox.firstChild)
- richlistbox.firstChild.remove();
+ onTreeSelect: function() {
+ document.getElementById("removeEngineButton").disabled =
+ gEngineView.selectedIndex == -1 || gEngineView.lastIndex == 0;
+ },
- let currentEngine = Services.search.currentEngine.name;
- Services.search.getVisibleEngines().forEach(e => {
- if (e.name == currentEngine)
- return;
+ onTreeKeyPress: function(aEvent) {
+ let index = gEngineView.selectedIndex;
+ let tree = document.getElementById("engineList");
+ if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
+ // Space toggles the checkbox.
+ let newValue = !gEngineView._engineStore.engines[index].shown;
+ gEngineView.setCellValue(index, tree.columns.getFirstColumn(),
+ newValue.toString());
+ }
+ else {
+ let isMac = Services.appinfo.OS == "Darwin";
+ if ((isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
+ (!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2))
+ tree.startEditing(index, tree.columns.getLastColumn());
+ }
+ },
- let item = document.createElement("richlistitem");
- item.setAttribute("label", e.name);
- if (hiddenList.indexOf(e.name) == -1)
- item.setAttribute("checked", "true");
- if (e.iconURI)
- item.setAttribute("src", e.iconURI.spec);
- richlistbox.appendChild(item);
- });
+ onRestoreDefaults: function() {
+ let num = gEngineView._engineStore.restoreDefaultEngines();
+ gEngineView.rowCountChanged(0, num);
+ gEngineView.invalidate();
+ },
+
+ showRestoreDefaults: function(aEnable) {
+ document.getElementById("restoreDefaultSearchEngines").disabled = !aEnable;
+ },
+
+ remove: function() {
+ gEngineView._engineStore.removeEngine(gEngineView.selectedEngine);
+ let index = gEngineView.selectedIndex;
+ gEngineView.rowCountChanged(index, -1);
+ gEngineView.invalidate();
+ gEngineView.selection.select(Math.min(index, gEngineView.lastIndex));
+ gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
+ document.getElementById("engineList").focus();
+ },
+
+ editKeyword: function(aEngine, aNewKeyword) {
+ if (aNewKeyword) {
+ let bduplicate = false;
+ let eduplicate = false;
+ let dupName = "";
+
+ try {
+ let bmserv =
+ Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"]
+ .getService(Components.interfaces.nsINavBookmarksService);
+ if (bmserv.getURIForKeyword(aNewKeyword))
+ bduplicate = true;
+ } catch(ex) {}
+
+ // Check for duplicates in changes we haven't committed yet
+ let engines = gEngineView._engineStore.engines;
+ for each (let engine in engines) {
+ if (engine.alias == aNewKeyword &&
+ engine.name != aEngine.name) {
+ eduplicate = true;
+ dupName = engine.name;
+ break;
+ }
+ }
+
+ // Notify the user if they have chosen an existing engine/bookmark keyword
+ if (eduplicate || bduplicate) {
+ let strings = document.getElementById("engineManagerBundle");
+ let dtitle = strings.getString("duplicateTitle");
+ let bmsg = strings.getString("duplicateBookmarkMsg");
+ let emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
+
+ Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
+ return false;
+ }
+ }
+
+ gEngineView._engineStore.changeEngine(aEngine, "alias", aNewKeyword);
+ gEngineView.invalidate();
+ return true;
},
saveOneClickEnginesList: function () {
- let richlistbox = document.getElementById("oneClickProvidersList");
let hiddenList = [];
- for (let child of richlistbox.childNodes) {
- if (!child.checked)
- hiddenList.push(child.getAttribute("label"));
+ for (let engine of gEngineView._engineStore.engines) {
+ if (!engine.shown)
+ hiddenList.push(engine.name);
}
document.getElementById("browser.search.hiddenOneOffs").value =
hiddenList.join(",");
},
setDefaultEngine: function () {
- Services.search.currentEngine =
- document.getElementById("defaultEngine").selectedItem.engine;
- this.displayOneClickEnginesList();
+ if (document.documentElement.instantApply) {
+ Services.search.currentEngine =
+ document.getElementById("defaultEngine").selectedItem.engine;
+ }
}
};
+
+function onDragEngineStart(event) {
+ var selectedIndex = gEngineView.selectedIndex;
+ if (selectedIndex >= 0) {
+ event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
+ event.dataTransfer.effectAllowed = "move";
+ }
+}
+
+// "Operation" objects
+function EngineMoveOp(aEngineClone, aNewIndex) {
+ if (!aEngineClone)
+ throw new Error("bad args to new EngineMoveOp!");
+ this._engine = aEngineClone.originalEngine;
+ this._newIndex = aNewIndex;
+}
+EngineMoveOp.prototype = {
+ _engine: null,
+ _newIndex: null,
+ commit: function EMO_commit() {
+ Services.search.moveEngine(this._engine, this._newIndex);
+ }
+};
+
+function EngineRemoveOp(aEngineClone) {
+ if (!aEngineClone)
+ throw new Error("bad args to new EngineRemoveOp!");
+ this._engine = aEngineClone.originalEngine;
+}
+EngineRemoveOp.prototype = {
+ _engine: null,
+ commit: function ERO_commit() {
+ Services.search.removeEngine(this._engine);
+ }
+};
+
+function EngineUnhideOp(aEngineClone, aNewIndex) {
+ if (!aEngineClone)
+ throw new Error("bad args to new EngineUnhideOp!");
+ this._engine = aEngineClone.originalEngine;
+ this._newIndex = aNewIndex;
+}
+EngineUnhideOp.prototype = {
+ _engine: null,
+ _newIndex: null,
+ commit: function EUO_commit() {
+ this._engine.hidden = false;
+ Services.search.moveEngine(this._engine, this._newIndex);
+ }
+};
+
+function EngineChangeOp(aEngineClone, aProp, aValue) {
+ if (!aEngineClone)
+ throw new Error("bad args to new EngineChangeOp!");
+
+ this._engine = aEngineClone.originalEngine;
+ this._prop = aProp;
+ this._newValue = aValue;
+}
+EngineChangeOp.prototype = {
+ _engine: null,
+ _prop: null,
+ _newValue: null,
+ commit: function ECO_commit() {
+ this._engine[this._prop] = this._newValue;
+ }
+};
+
+function EngineStore() {
+ let pref = document.getElementById("browser.search.hiddenOneOffs").value;
+ this.hiddenList = pref ? pref.split(",") : [];
+
+ this._engines = Services.search.getVisibleEngines().map(this._cloneEngine, this);
+ this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine, this);
+
+ if (document.documentElement.instantApply) {
+ this._ops = {
+ push: function(op) { op.commit(); }
+ };
+ }
+ else {
+ this._ops = [];
+ document.documentElement.addEventListener("beforeaccept", () => {
+ gEngineView._engineStore.commit();
+ });
+ }
+
+ // check if we need to disable the restore defaults button
+ var someHidden = this._defaultEngines.some(function (e) e.hidden);
+ gSearchPane.showRestoreDefaults(someHidden);
+}
+EngineStore.prototype = {
+ _engines: null,
+ _defaultEngines: null,
+ _ops: null,
+
+ get engines() {
+ return this._engines;
+ },
+ set engines(val) {
+ this._engines = val;
+ return val;
+ },
+
+ _getIndexForEngine: function ES_getIndexForEngine(aEngine) {
+ return this._engines.indexOf(aEngine);
+ },
+
+ _getEngineByName: function ES_getEngineByName(aName) {
+ for each (var engine in this._engines)
+ if (engine.name == aName)
+ return engine;
+
+ return null;
+ },
+
+ _cloneEngine: function ES_cloneEngine(aEngine) {
+ var clonedObj={};
+ for (var i in aEngine)
+ clonedObj[i] = aEngine[i];
+ clonedObj.originalEngine = aEngine;
+ clonedObj.shown = this.hiddenList.indexOf(clonedObj.name) == -1;
+ return clonedObj;
+ },
+
+ // Callback for Array's some(). A thisObj must be passed to some()
+ _isSameEngine: function ES_isSameEngine(aEngineClone) {
+ return aEngineClone.originalEngine == this.originalEngine;
+ },
+
+ commit: function ES_commit() {
+ for (op of this._ops)
+ op.commit();
+
+ Services.search.currentEngine =
+ document.getElementById("defaultEngine").selectedItem.engine;
+ },
+
+ addEngine: function ES_addEngine(aEngine) {
+ this._engines.push(this._cloneEngine(aEngine));
+ },
+
+ moveEngine: function ES_moveEngine(aEngine, aNewIndex) {
+ if (aNewIndex < 0 || aNewIndex > this._engines.length - 1)
+ throw new Error("ES_moveEngine: invalid aNewIndex!");
+ var index = this._getIndexForEngine(aEngine);
+ if (index == -1)
+ throw new Error("ES_moveEngine: invalid engine?");
+
+ if (index == aNewIndex)
+ return; // nothing to do
+
+ // Move the engine in our internal store
+ var removedEngine = this._engines.splice(index, 1)[0];
+ this._engines.splice(aNewIndex, 0, removedEngine);
+
+ this._ops.push(new EngineMoveOp(aEngine, aNewIndex));
+ },
+
+ removeEngine: function ES_removeEngine(aEngine) {
+ var index = this._getIndexForEngine(aEngine);
+ if (index == -1)
+ throw new Error("invalid engine?");
+
+ this._engines.splice(index, 1);
+ this._ops.push(new EngineRemoveOp(aEngine));
+ if (this._defaultEngines.some(this._isSameEngine, aEngine))
+ gSearchPane.showRestoreDefaults(true);
+ gSearchPane.buildDefaultEngineDropDown();
+ },
+
+ restoreDefaultEngines: function ES_restoreDefaultEngines() {
+ var added = 0;
+
+ for (var i = 0; i < this._defaultEngines.length; ++i) {
+ var e = this._defaultEngines[i];
+
+ // If the engine is already in the list, just move it.
+ if (this._engines.some(this._isSameEngine, e)) {
+ this.moveEngine(this._getEngineByName(e.name), i);
+ } else {
+ // Otherwise, add it back to our internal store
+ this._engines.splice(i, 0, e);
+ this._ops.push(new EngineUnhideOp(e, i));
+ added++;
+ }
+ }
+ gSearchPane.showRestoreDefaults(false);
+ gSearchPane.buildDefaultEngineDropDown();
+ return added;
+ },
+
+ changeEngine: function ES_changeEngine(aEngine, aProp, aNewValue) {
+ var index = this._getIndexForEngine(aEngine);
+ if (index == -1)
+ throw new Error("invalid engine?");
+
+ this._engines[index][aProp] = aNewValue;
+ this._ops.push(new EngineChangeOp(aEngine, aProp, aNewValue));
+ },
+
+ reloadIcons: function ES_reloadIcons() {
+ this._engines.forEach(function (e) {
+ e.uri = e.originalEngine.uri;
+ });
+ }
+};
+
+function EngineView(aEngineStore) {
+ this._engineStore = aEngineStore;
+}
+EngineView.prototype = {
+ _engineStore: null,
+ tree: null,
+
+ get lastIndex() {
+ return this.rowCount - 1;
+ },
+ get selectedIndex() {
+ var seln = this.selection;
+ if (seln.getRangeCount() > 0) {
+ var min = {};
+ seln.getRangeAt(0, min, {});
+ return min.value;
+ }
+ return -1;
+ },
+ get selectedEngine() {
+ return this._engineStore.engines[this.selectedIndex];
+ },
+
+ // Helpers
+ rowCountChanged: function (index, count) {
+ this.tree.rowCountChanged(index, count);
+ },
+
+ invalidate: function () {
+ this.tree.invalidate();
+ },
+
+ ensureRowIsVisible: function (index) {
+ this.tree.ensureRowIsVisible(index);
+ },
+
+ getSourceIndexFromDrag: function (dataTransfer) {
+ return parseInt(dataTransfer.getData(ENGINE_FLAVOR));
+ },
+
+ // nsITreeView
+ get rowCount() {
+ return this._engineStore.engines.length;
+ },
+
+ getImageSrc: function(index, column) {
+ if (column.id == "engineName" && this._engineStore.engines[index].iconURI)
+ return this._engineStore.engines[index].iconURI.spec;
+ return "";
+ },
+
+ getCellText: function(index, column) {
+ if (column.id == "engineName")
+ return this._engineStore.engines[index].name;
+ else if (column.id == "engineKeyword")
+ return this._engineStore.engines[index].alias;
+ return "";
+ },
+
+ setTree: function(tree) {
+ this.tree = tree;
+ },
+
+ canDrop: function(targetIndex, orientation, dataTransfer) {
+ var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
+ return (sourceIndex != -1 &&
+ sourceIndex != targetIndex &&
+ sourceIndex != targetIndex + orientation);
+ },
+
+ drop: function(dropIndex, orientation, dataTransfer) {
+ var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
+ var sourceEngine = this._engineStore.engines[sourceIndex];
+
+ const nsITreeView = Components.interfaces.nsITreeView;
+ if (dropIndex > sourceIndex) {
+ if (orientation == nsITreeView.DROP_BEFORE)
+ dropIndex--;
+ } else {
+ if (orientation == nsITreeView.DROP_AFTER)
+ dropIndex++;
+ }
+
+ this._engineStore.moveEngine(sourceEngine, dropIndex);
+ gSearchPane.showRestoreDefaults(true);
+ gSearchPane.buildDefaultEngineDropDown();
+
+ // Redraw, and adjust selection
+ this.invalidate();
+ this.selection.select(dropIndex);
+ },
+
+ selection: null,
+ getRowProperties: function(index) { return ""; },
+ getCellProperties: function(index, column) { return ""; },
+ getColumnProperties: function(column) { return ""; },
+ isContainer: function(index) { return false; },
+ isContainerOpen: function(index) { return false; },
+ isContainerEmpty: function(index) { return false; },
+ isSeparator: function(index) { return false; },
+ isSorted: function(index) { return false; },
+ getParentIndex: function(index) { return -1; },
+ hasNextSibling: function(parentIndex, index) { return false; },
+ getLevel: function(index) { return 0; },
+ getProgressMode: function(index, column) { },
+ getCellValue: function(index, column) {
+ if (column.id == "engineShown")
+ return this._engineStore.engines[index].shown;
+ return undefined;
+ },
+ toggleOpenState: function(index) { },
+ cycleHeader: function(column) { },
+ selectionChanged: function() { },
+ cycleCell: function(row, column) { },
+ isEditable: function(index, column) { return column.id != "engineName"; },
+ isSelectable: function(index, column) { return false; },
+ setCellValue: function(index, column, value) {
+ if (column.id == "engineShown") {
+ this._engineStore.engines[index].shown = value == "true";
+ gEngineView.invalidate();
+ gSearchPane.saveOneClickEnginesList();
+ }
+ },
+ setCellText: function(index, column, value) {
+ if (column.id == "engineKeyword") {
+ if (!gSearchPane.editKeyword(this._engineStore.engines[index], value)) {
+ setTimeout(() => {
+ document.getElementById("engineList").startEditing(index, column);
+ }, 0);
+ }
+ }
+ },
+ performAction: function(action) { },
+ performActionOnRow: function(action, index) { },
+ performActionOnCell: function(action, index, column) { }
+};
diff --git a/browser/components/preferences/search.xul b/browser/components/preferences/search.xul
index c9190dc154f..8e36d409171 100644
--- a/browser/components/preferences/search.xul
+++ b/browser/components/preferences/search.xul
@@ -34,6 +34,8 @@
+
+
@@ -51,8 +53,34 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn
index 90185df14f3..2f67952df47 100644
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -169,6 +169,7 @@ browser.jar:
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
+ skin/classic/browser/preferences/search.css (preferences/search.css)
skin/classic/browser/social/services-16.png (social/services-16.png)
skin/classic/browser/social/services-64.png (social/services-64.png)
skin/classic/browser/social/share-button.png (social/share-button.png)
diff --git a/browser/themes/linux/preferences/search.css b/browser/themes/linux/preferences/search.css
new file mode 100644
index 00000000000..660ec2ccd2d
--- /dev/null
+++ b/browser/themes/linux/preferences/search.css
@@ -0,0 +1,39 @@
+/* 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/. */
+
+#defaultEngine > .menulist-label-box > .menulist-icon {
+ height: 16px;
+}
+
+/* work around a display: none in Linux's menu.css, see bug 1112310 */
+.searchengine-menuitem > .menu-iconic-left {
+ display: -moz-box;
+}
+
+#engineList {
+ margin: .5em 6px;
+}
+
+#engineList treechildren::-moz-tree-checkbox(checked) {
+ list-style-image: url("chrome://global/skin/checkbox/cbox-check.gif");
+}
+
+#engineList treechildren::-moz-tree-image(engineName) {
+ -moz-margin-end: 4px;
+ -moz-margin-start: 0;
+ width: 16px;
+ height: 16px;
+}
+
+#engineList treechildren::-moz-tree-row {
+ min-height: 20px;
+}
+
+#engineList treechildren::-moz-tree-drop-feedback {
+ background-color: Highlight;
+ width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
+ we may have, overflow isn't visible. */
+ height: 2px;
+ -moz-margin-start: 0;
+}
diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn
index cefcd90d9d5..e8f3175980b 100644
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -273,6 +273,11 @@ browser.jar:
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
+ skin/classic/browser/preferences/search.css (preferences/search.css)
+ skin/classic/browser/preferences/checkbox.png (preferences/checkbox.png)
+ skin/classic/browser/preferences/checkbox@2x.png (preferences/checkbox@2x.png)
+ skin/classic/browser/yosemite/preferences/checkbox.png (preferences/checkbox-yosemite.png)
+ skin/classic/browser/yosemite/preferences/checkbox@2x.png (preferences/checkbox-yosemite@2x.png)
skin/classic/browser/social/services-16.png (social/services-16.png)
skin/classic/browser/social/services-16@2x.png (social/services-16@2x.png)
skin/classic/browser/social/services-64.png (social/services-64.png)
@@ -588,6 +593,8 @@ browser.jar:
% override chrome://browser/skin/menuPanel-help@2x.png chrome://browser/skin/yosemite/menuPanel-help@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/yosemite/menuPanel-small.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-small@2x.png chrome://browser/skin/yosemite/menuPanel-small@2x.png os=Darwin osversion>=10.10
+% override chrome://browser/skin/preferences/checkbox.png chrome://browser/skin/yosemite/preferences/checkbox.png os=Darwin osversion>=10.10
+% override chrome://browser/skin/preferences/checkbox@2x.png chrome://browser/skin/yosemite/preferences/checkbox@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/reload-stop-go.png chrome://browser/skin/yosemite/reload-stop-go.png os=Darwin osversion>=10.10
% override chrome://browser/skin/reload-stop-go@2x.png chrome://browser/skin/yosemite/reload-stop-go@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/sync-horizontalbar.png chrome://browser/skin/yosemite/sync-horizontalbar.png os=Darwin osversion>=10.10
diff --git a/browser/themes/osx/preferences/checkbox-yosemite.png b/browser/themes/osx/preferences/checkbox-yosemite.png
new file mode 100644
index 0000000000000000000000000000000000000000..1421c7d0e29cc43deab290b4d99f08c778fe3a00
GIT binary patch
literal 1033
zcmV+k1or!hP)9^+OlFdKeAmTv
zrZaiWmr&85XE)#6-@W&odE9&8e;xv$wU+7W=}}+^h=&Nv(fo4j
z57tV0$7`Kz7fwGWEM+n{>-^4l{tt((;PqaYg{4*A`06*r<2SxO_9{4k3Ko`DdFhK^
zH~dHJx&j>71AB}+ug^Rn9BEe!eRPcj;Uk_t+5~}`tloT7aqM1$S1(?}^&j3ae%BS?
z{F89*czI({Kb(FTrY_C#vlYfP3{U^T^NNe73@m}(knrLOMdH#NU#}d(RvZ1UE5OH>
zQ#>A3y!?%8^CQSwE_$qP4$guA!xC$3twS9}4Udgmto;Qd>U-*p8zbnqS~t|aOBCQb6z
z8ovh)vu_6{M$mtdw|_{{(N^}~yPX8gt$pR4bS{_M_9C~(rfVLhD>po^a2$tXu~_G|
zChgXoPDdkMymEP&53ic+YuUSD4p)~=tuJX!DW3%(*c#!?mw$5ZCq=++sk5bgmXg+0
zU-PnA^VE49(8Yjshbh($OdZt@S)G+1J-s*9_f_
zuQWqS^a#+<1M{wy$t{|p5%KUE=Fu`)X@)%3`tQeIj3$h<8X`gs00000NkvXXu0mjf
DKtT9Q
literal 0
HcmV?d00001
diff --git a/browser/themes/osx/preferences/checkbox-yosemite@2x.png b/browser/themes/osx/preferences/checkbox-yosemite@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f156f2587d396c049f98a7ff57b7e09ad419910
GIT binary patch
literal 2434
zcmV-|34Qj7P)s{NyYa8MR&ch)A)KDNHPLNU&>MFEV
zql$oN`2Z-DjR-DZPzyq>iV&(wo2oWZ1wsuKDpFHaR4GDL6^R5BRP`YNv0{O&*b3k{
zU~lX=`_
zPM`@;McQ|OFSOPtL}cK>2Om6H$W2$9f72n|ZQ%5w*@@63Me;Q`Xud!=5l0Q2J}3q8
z&EBzYL+Ar`0!<=C^0nK3;6z+AU=Ow~;Ac6&@#DwMiHV6rKyNX?0yG#3g`PZc;6N-_
z;nn8zoHn=AIfq16hp#n*6;fO(CTfESy^*k!mv3Dde_6!kdprtLDdI)8
zJt;$LY{wxMa}emYJmXe0gP*c~^ytwYz)2Bd+qP|Zz1|gp=WBL$mQ$xrp|u9+-nVbx
zdzs~#{Fas$EXyh>KN^kl*=L{S{)=vfvg9RLE7Q-+I1Oi;Vcrhnm#OVWf
z(tE=hk?8Gn(L}b_e>yrG2h6bvts_^-I1OkB-
z)j>oE1OoVcKB}s!XlQ82%LjIY8}?VKeA7mT?S*`C`KC&&_dFJcRZ~>wdlI+A5e%ya
zJZ>~i*_Jdv(*c4?DSSTPvVn!l>-D0PLMauTUzX%oR#pPw_xnr6t*xyEprWE8FJFWp
z{eX`G4K7_~TxaEne4_X}J|ittWJvpE(5-
z4J=e5lH@FStyxWeGKwt5FO|NxPPnbr4?ftq)?1
zTweU1D_6T~K>c?KUUvp#`0NbdA9#;gEcYw_YUueMgW9Sz|A(&)5q1{mmmQ!)`evKZ
z-RX}0m>uVl!H=nKY{uj9ToL{w>kW2qF|zphny6HZ^UDrU0@Yd2w=*63UwrdZ-k;Lk
z+J55|;kQ@7)Ayyj^2Ikl<^A)T+J^Qe?=3q(3G~FB2K9**|3A-6^Xxn0+}yPpxdIDo
zfS=!Evc@M_eAV2AQNRa{vI7*L-8TqLRk_P{wFviYa*r>C9UdP1h&62;_)7RC^`TCK
zuIk*2*Zu7Vd$&p!pSm`D6@~H34zPr7X%L>-BfPLjs4=t4d>%NsOH!X|o_l?S;b;Zx
zZ)hzU|K3L7m-j1PeLxYM$8Yh#v-cS!Uu>RxeT3mzi~9Pt1=}w>z!K{3h6)ol1chJh
z7R-!+_@k``P3|`){_*cges$t=wszfA(pSxA_bMtqaMKOKtNRp{89nyQ-HMia$>OW#
zu4R2aEIYswdj6eD%*@#U+|e%d-{C&8+Zu&$-{M{~H5223SB6>Jxt_|ZJaa{n`pMB5
zE++Upx(r_0?Y`&lZ4vI@Ze;OUvksqUd3anq{srD-E?pULL;_ZZw5%;5j$
zE2^6|7G=Ne087YM<7MOKTR8l|1TXyQldQ7OzYMeQ$Qe2|bd@}RAt}FA11+05d@4Vm
z#tm4iIDXjy3Q$8`9qk)7@zcMJa^&yh0B8+;hfjmIf#&NPSCt>Au7lvl+@QKHpsLc
z$>xvD;%&cu$$Jen@l3u>^D`Y_0tkk~;nY9*QY#XP03ae0If^HMpl#cjrb#FiDp^iI
zA`1w|aq{xDWuk||+xbM6C3+RnvCI1X+C=VIEvZUgx0FdDC?zOH^*^~tckkgr|7
zop4fOQP&B`u1|gAdhpaiO*4U-xgnt1dQ#N1rKlx>~nXS&Y-uzz%Pl;-B(LBle2$D=Jlgqzm8;iNQ
z{3YeXU^KQii=Q)&9Xocc8|V{}U0Um)h!nXsNjoAkk(hIHj=cXzerju&o4p%c(bh0`
z!S`-aTf>B1Xo4%+8YWDjc{ktIu(HZ3>sr?T04JQeR(xU$JOBUy07*qoM6N<$f@Oxj
A&;S4c
literal 0
HcmV?d00001
diff --git a/browser/themes/osx/preferences/checkbox.png b/browser/themes/osx/preferences/checkbox.png
new file mode 100644
index 0000000000000000000000000000000000000000..fd009385362bcef2a1bdb4f4da71307366300c58
GIT binary patch
literal 1685
zcmV;G25R|e{9s{9mikK_wK&s==H9>J9_O&OY17JM5j2HA+xv{M8hns
zi7`5sxy{A7&Q$?7wrLi{g_ZG3E!7wjH>b(SMl@+z2`$4E0YmBrizFa)rHq!Aa(8X-
z+TQoRci-pPAEnp3+DZ}s@sqrhC*MzA-{<+fpXd30p9j8-5xjjV!Nu?6TO7PzUSvEj
z1#SV{fS8^{0a4&2@V_a!>*K%HcsCl4f|!p&o0b+xWc(6C@77?%{Wu&a=|1*VK=F;Y
zzlG2qLs5!Q)ALG5q|wK~uH~f605Q?AY;aRaMpfKA*1wW+(t;I2`Ugdh}>(U0vOlG=JxgZ$7rF^5yTY
zzNPG@3cpuqVp;>0RO;uy_^sK#Kb`}~?Z4mf;o3DdLVW%0Wvi>o8dol_2$q%Rdjvu#
z)D-Uo3Z%#twiM2m}^YS65S8Ticdl
zz->#HE?rSjP_Xc7d_h6M!X-Eva5Lb_c;xc?{Wr~)_j
zSa$C+?zr`yP`(fc0Z>+{d!EM=i(4oKBO_5DMK5zgcvjgd-gQ(y@wy=RObbT43Sp-#!Vzb
zVe;n(`9u8+YgTg)S4s6Ovfmq`CReFc@O%)@SJHyU3_1Ied6OpL}!(91hk$vyrIj
zgj9ko1C&zNq%Sm70>c7B*=XGPDw@|za$tZL);-CI<0p8lVH*H->(?^3q>^ZIoS8Jh
z6p0j=(#D2gZ2@-y3|^-3m35pxbCTx2HvsU^nx}C3Di}#9kfz8oz_Kio$>gjw-Cj?n
zQkbSWE2UDYY}gtjGzMpf6n%5b*#7EkkY7NuzmLZCPryiwyH-5F;uQ~Zq+b#m8)qhY
zL!7x}a=h21Yb?MIf3_7|9%Q(mzrFG_jEzu!$GsF*uB5%w;LIfxEF;?hA;dLlYFrnu
z66iL_wZo99z<(n<8(%}qF94lAq%HnpxXr~L(4MYT8fw{J}<8&<2dbt{G4%(SuiJ9!RxO#k{2vy
z(;qj}n{=l0PP;%$#xqtxLgeOXDsXxiP`h>;!dJu-Ki$ZXsi*U~IT~0A0Wk3!
zRDhgn$Y+Ek`)93$5TBn{3F+3QD$EsP;`5?_c?%ZO^zI%)Rt~}(PY3~ST`E*UX7Zl7
zLLoIFGe+etDra;3Ul>l<(F_R)Gy(3pBF#@2Fg7qSaN6(pU+o}-&1NGM3Vi}(Y(mBc
z2M0Sn9?#VdLfC9JqS5GoGkKe3^belziUiBQ;!9d&9Ap$Rq2sVA<~hfUci13&zB^*G
zjQ+F($#}03?u``|mbg=vBGUvzIk4No>$0H>(b$HFr9Q=SFu>^?6G6VS~GcJgqvF5
zYw3<&=n5CPP(im~LPdF*ZB+C^SGe`Pz2}7yZc6u_3jOt89~`=DMtfq#KAXD1Z)ZY9
z-pO{c&xRT8iT(S?p#hSEyJ7M$;sh1~Wmnptb(x6+-N2bE?JtDaeYf7HIr1J5+1Iw$)aX*64Zh#psLkNkIy(FT$xpbfzh-VJe3FI-kEoO=o
f5XDxm+~lT1$-gT5b~P5lbLh&+4qmh
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
R&}#qy002ovPDHLkV1kYQIdlL3
literal 0
HcmV?d00001
diff --git a/browser/themes/osx/preferences/search.css b/browser/themes/osx/preferences/search.css
new file mode 100644
index 00000000000..9ac566cb112
--- /dev/null
+++ b/browser/themes/osx/preferences/search.css
@@ -0,0 +1,54 @@
+/* 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/. */
+
+#defaultEngine > .menulist-label-box > .menulist-icon {
+ height: 16px;
+}
+
+#engineList {
+ margin: .5em 6px;
+}
+
+#engineList treechildren::-moz-tree-image(engineShown) {
+ list-style-image: url("chrome://browser/skin/preferences/checkbox.png");
+ -moz-image-region: rect(0, 16px, 16px, 0);
+ -moz-margin-start: 4px;
+ -moz-margin-end: 1px;
+}
+
+#engineList treechildren::-moz-tree-image(engineShown, checked) {
+ -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+
+@media (min-resolution: 2dppx) {
+ #engineList treechildren::-moz-tree-image(engineShown) {
+ list-style-image: url("chrome://browser/skin/preferences/checkbox@2x.png");
+ -moz-image-region: rect(0, 32px, 32px, 0);
+ width: 16px;
+ height: 16px;
+ }
+
+ #engineList treechildren::-moz-tree-image(engineShown, checked) {
+ -moz-image-region: rect(0, 96px, 32px, 64px);
+ }
+}
+
+#engineList treechildren::-moz-tree-image(engineName) {
+ -moz-margin-end: 4px;
+ -moz-margin-start: 1px;
+ width: 16px;
+ height: 16px;
+}
+
+#engineList treechildren::-moz-tree-row {
+ min-height: 20px;
+}
+
+#engineList treechildren::-moz-tree-drop-feedback {
+ background-color: Highlight;
+ width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
+ we may have, overflow isn't visible. */
+ height: 2px;
+ -moz-margin-start: 0;
+}
diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn
index d889eb7d432..8a372461345 100644
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -197,6 +197,9 @@ browser.jar:
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
+ skin/classic/browser/preferences/search.css (preferences/search.css)
+ skin/classic/browser/preferences/checkbox.png (preferences/checkbox-xp.png)
+ skin/classic/browser/preferences/checkbox-classic.png (preferences/checkbox-classic.png)
skin/classic/browser/social/services-16.png (social/services-16.png)
skin/classic/browser/social/services-64.png (social/services-64.png)
skin/classic/browser/social/chat-icons.svg (../shared/social/chat-icons.svg)
@@ -645,6 +648,10 @@ browser.jar:
skin/classic/aero/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
skin/classic/aero/browser/preferences/applications.css (preferences/applications.css)
skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
+ skin/classic/aero/browser/preferences/search.css (preferences/search.css)
+ skin/classic/aero/browser/preferences/checkbox.png (preferences/checkbox-8.png)
+ skin/classic/aero/browser/preferences/checkbox-aero.png (preferences/checkbox-aero.png)
+ skin/classic/aero/browser/preferences/checkbox-classic.png (preferences/checkbox-classic.png)
skin/classic/aero/browser/social/services-16.png (social/services-16.png)
skin/classic/aero/browser/social/services-64.png (social/services-64.png)
skin/classic/aero/browser/social/chat-icons.svg (../shared/social/chat-icons.svg)
@@ -902,6 +909,9 @@ browser.jar:
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/menuPanel-small-aero.png os=WINNT osversion=6
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/menuPanel-small-aero.png os=WINNT osversion=6.1
+% override chrome://browser/skin/preferences/checkbox.png chrome://browser/skin/preferences/checkbox-aero.png os=WINNT osversion=6
+% override chrome://browser/skin/preferences/checkbox.png chrome://browser/skin/preferences/checkbox-aero.png os=WINNT osversion=6.1
+
% override chrome://browser/skin/theme-switcher-icon.png chrome://browser/skin/theme-switcher-icon-aero.png os=WINNT osversion=6
% override chrome://browser/skin/theme-switcher-icon.png chrome://browser/skin/theme-switcher-icon-aero.png os=WINNT osversion=6.1
diff --git a/browser/themes/windows/preferences/checkbox-8.png b/browser/themes/windows/preferences/checkbox-8.png
new file mode 100644
index 0000000000000000000000000000000000000000..be1747e2406e0fd75c13e4f76dbd1c5874c387cf
GIT binary patch
literal 705
zcmV;y0zUnTP)AHIP00004b3#c}2nYxW
zdN2Q=E+U5){qoSAgf!eJMsATBBAY~|
z2dcC3M_a@iUYML48S4lA0V9Hh7*mUW&_x#`@}g!mYaNYl>teHcA?xBWaca492xKQe
zSLX}o#q;p}@;nz0Y-U3v03;HLf)VU+I0S&(Qw2l5?|>ixNUwev@{y(;6~F(gV$ssl
zq6?3YkC)UJ>htce=E`*sxufzw`cQNnNS?-=c5X&HU^9Hv@>rmy1e=|Lnx^EW6k>gx7iG%Va*?HvSV51
zO?d(q7Z;bl^Z7iIB$3T#2?PRVHE+3J$mh9sS@ZsW1AZaTaKFTSE=%{7KuPn#gac4j
z6{pk574%Mpo0uv)D|
zqfsmtOIhC4>f!33=I=)%)LN}5qfx5M^v6$nI41}BHJ>B)Ai}m&D2hT|U7ar9+2y16lIDko6?X5@=Up8>I(sxP-%{AQ>(AbFS5PsMBq53-
zq9_{j=X)fMG>RNhf5m2W$GQ|bHP%m(E*Imq%;37&e500000NkvXXu0mjfyzfgI
literal 0
HcmV?d00001
diff --git a/browser/themes/windows/preferences/checkbox-aero.png b/browser/themes/windows/preferences/checkbox-aero.png
new file mode 100644
index 0000000000000000000000000000000000000000..899c39c603a41bceeb3d394375c0023aed62f7a5
GIT binary patch
literal 1566
zcmV+(2I2XMP)AHIP00004b3#c}2nYxW
zd=Qanf#Z?Ufuxkb>Gdyt5)SCuHU&c<^I);%W~4M+x~va{hlpra?&r{vLod_6Tc7w
zAtkQk;JWTG{zI=l8mPB{C~zL=1S;0PlJb8h{=%@J$dsJ!a`?O3?dR8nAKJTbe~L&+
ziBuA$6uR%yipq-ew3R%4D1GII08@gc1h$6zZb;u@HXo5`f48J}tqjTb48H1j4=h*%AVK&@TgN%rr__t0GG`Dx~`j>}TyZmN^
z7-+v9`tXEUY@h*3_L{CS3{BY3#9RJMPuUv_iUx|*5<=1?EFmnxRPfyy7w{jkD<&BI
z-wo*{&QtFr%$YHsjvV-B
zjDY$Nf26Ugm6C!8wH2krI|u4dn*cxa4Xp|3%ntgQA5vgvVW6M+md>1j5qVL@j4nVc
zMd5X$IMCR{=RX_=VBNA>B4%&_QzH)5Ba?)r%j|rIZx5bg*LR-&$z?ZThYf<#SC#Kj
zH^#w~aC?zM!>@m^tKldBPc5H=X&PJ_R6t4sl$3$y8(L)?0YT=6B}8=k`Li#A%r})F
zYWVA?luhL5$$x41?G%OAjpFaK7ud1;X8>-inn?BZ6587R`|snE;g4fY>^pFb+4&AF
z|D5BQ_dNZgs_U6kUd&Hz{vEJ>hM?v6DH;wO<@O?nmNOkZyUSab7FAE8cKQT9JDtj(
z;-<`CzS79S_V&HS}PvBvy#rP
z1e;#o%kk#30IXSBL%|3ODTFV-3uqX$_qbpv
z$%Z90w09+V@cB>py{Q#|$M3FTRMey!F^oT@IIUEm`F)M_3p0cH0Ab}nh4dNjXMQGq
zQ@n+_GfSzR7Ng@rHvn^{$GEk6vNt?3@V{{q=FKdjZd#1iUVUBpc;;7?(t*lY|K=ku
z^C~A&H=~r+^PYbG^b!_SPv##dy?$5%g3JeRf%Xeai9qwgo8$c=Pl-VD0Yb`u3e!sA
zBpp`YT|>kQVVef)?w!lvCTHS5mlSNer-}m0Am222;@&DQ4JsiM|Gx>rW6NtPutMZp
z2AfyZ((MlDhw`Tk2(1EDBF?d|g;%Ei{+f@}2}8dd^B
zLeLT%)vza?B-*>%i5ddCcjpvVf{=0p^;#=VoIFLWcpNJhlp}N_d`fgQCu*al(cX2rkbxWoD~i&YD&khp{*HeZ}}2`eWpe@X)U-f*)G?+y2|jzs|f
zH{5JvF#qDZnE<#>l4!)rO5ewy0G7-v1K^BsDJjUVO?~|FPFQ@)6aWr)^iUk~*Yqb~
z=-EiFG4yOF*BE-XlWPp+7sBgnuA7~CL(g{1-f6chi}|NY$E#rLxx-?i2Gw{^)&Zk9`2CTtz$k6*H$yE=hgCWb3P
zf^Blvo8NLvLq7lW<2t>`W%lz-o~*UMtiLy2v&w3^p4@vcqRVSdy;qsYmFNBEul+3I
z%{t4nf!)SL=s?_ufJ6qnHP&Wnzc+kOy!-KU9rwNUdJG#bto)$Vc(1A5i@BkuB9O->
zM52LzHrM;Z|C-vlm>Ia|etvq;DgU7JQbq^6JsNCsbNmYC9a}FO*7NTzllR*73_fXh
giX=1d)@STxTyda6R`-dEBG7vbp00i_>zopr0Q6LHAOHXW
literal 0
HcmV?d00001
diff --git a/browser/themes/windows/preferences/checkbox-xp.png b/browser/themes/windows/preferences/checkbox-xp.png
new file mode 100644
index 0000000000000000000000000000000000000000..cb7a5badd688ba469d19c6a53e21b3b91abc2f97
GIT binary patch
literal 1417
zcmV;41$O$0P)AHIP00004b3#c}2nYxW
zdgRONGJ_Z{
ze3MFdSNE^#`+N4U8}8w*LIJRAUwB*6M?SbG{~zT|eE!$RucEa^Ye7U1F&HC=Sd1}<
zm}Fi=BfCG$trhOy3XM5vRKcHt`V9C}P@8n4ItsI+P#pt*9Cc`CPJVFD{%dF`Y2`PXN`zv-?kSD|_Zb#Tia;h#7_
zYmHJ0r2x`n7D~m}`FX&R4;#@4Aq=8p2t*@3FNqfsK`Rw;P>>7~UaHmJ8UF5m_L=7E
z7HGv^8|YpFy-VGkcOGuk?->7#10<5sXq_&U9RRA8E{!UL4KDkuT@>~hq)!S_*!}&B
zKu{1jA}FPtB2gr3rO-+@@hG>a)*4WmK+-whDCqtC32LvOEnlF7zv)x-NP`|di>8J;
zx|ML_KA5}FF@F?1e0)1sH+`MkK5>AEL<%Uh&McyvouJB{;Lku9CS@!upUbY$cTv^^
zYYj@dXN?F(bU_&vb15-k%-^k%-#=6#{fF0*c%lsTSqPz9LeL-*;_1lv!3=8f75ALC
z7^J%+{-Fwa>}OYUoB3xPV4@6AIU~AA(gi0J6_|lAKzdA~d|uX_6Zob2d)7jtfQ~XI
zRz#ykqg86uq618%pw8`I3w)LxeJXh_*0F$~2GT{p=Yy)Fl)|by_4*85L%Y)F!iFnX
zZSoIPoi)F_kv!MTUnib0*%z0IyeGLRETnZ7{uKDr$xE&%8_5N=atC-e_mVQkV68zS
zMMMi)bdm*S4iGV{_+~u~6`-|H2`VfbOpQOX?Yl&W0>TDJ7d=Cp5vJ%;vsC=?obfMh
z+7Fe#p>m}q|7ZSu8;rsj!?M_P5mdCpH`?@J}2dVsGF0kaRoQP9x2vG@HuGk5eG+
z7OZuSFvfLaM#ObqTBkL&-~dUo;K8rfGd%eRD~FyZzlIoZ~T;1eGe7*Cnd<3IE7VG
zGSWJle;<^hHVK4@;hRfY+NG4k^K7!WYbABk)`=-*Q!^a@bbiB+dz15PyH2pEd*S>6
zmC}EeCVcwQWZtdP?rC%>kj1RFT8M+MO_0e`DYv;8RKP*pLR0yVs;cN
zqdDirYur+Kq8e)5u%5*li;2omO1?FRIB=HtEoXZ7DMx9~Fuis`Tl+J04sM)cN$(08
z+rI!HczF=(Ehe-}!0Sh8drST+dLQ7z^G^PsO~+W^_0G#b*9Ae`=a+v2%!}$65V}4;
z^j%F2YAtJiK>=%sTimz|DXr%1e6nzDsFM{8{@#(2?rk1SUxMm&s7;{z9wB`CJ-9Rk
zlOw2!GfZL=@iZXb~;7#znxCe{BNgI+-?5%aF_5e
X)s2cpW1*qZ00000NkvXXu0mjfHASGD
literal 0
HcmV?d00001
diff --git a/browser/themes/windows/preferences/search.css b/browser/themes/windows/preferences/search.css
new file mode 100644
index 00000000000..729948c9bcb
--- /dev/null
+++ b/browser/themes/windows/preferences/search.css
@@ -0,0 +1,59 @@
+/* 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/. */
+
+#defaultEngine > .menulist-label-box > .menulist-icon {
+ height: 16px;
+}
+
+#engineList {
+ margin: .5em 6px;
+}
+
+#engineList treechildren::-moz-tree-checkbox {
+ list-style-image: url("chrome://browser/skin/preferences/checkbox.png");
+ -moz-image-region: rect(0, 16px, 16px, 0);
+}
+
+#engineList treechildren::-moz-tree-checkbox(checked) {
+ -moz-image-region: rect(0, 64px, 16px, 48px);
+}
+
+@media (-moz-windows-classic) {
+ #engineList treechildren::-moz-tree-checkbox {
+ list-style-image: url("chrome://browser/skin/preferences/checkbox-classic.png");
+ }
+
+ #engineList treechildren::-moz-tree-checkbox(checked) {
+ -moz-image-region: rect(0, 48px, 16px, 32px);
+ }
+}
+
+@media not all and (-moz-windows-classic) {
+ #engineList treechildren::-moz-tree-checkbox(hover) {
+ -moz-image-region: rect(0, 48px, 16px, 32px);
+ }
+
+ #engineList treechildren::-moz-tree-checkbox(checked, hover) {
+ -moz-image-region: rect(0, 80px, 16px, 64px);
+ }
+}
+
+#engineList treechildren::-moz-tree-image(engineName) {
+ -moz-margin-end: 4px;
+ -moz-margin-start: 0;
+ width: 16px;
+ height: 16px;
+}
+
+#engineList treechildren::-moz-tree-row {
+ min-height: 20px;
+}
+
+#engineList treechildren::-moz-tree-drop-feedback {
+ background-color: Highlight;
+ width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
+ we may have, overflow isn't visible. */
+ height: 2px;
+ -moz-margin-start: 0;
+}
From d413320756e9687162dc8bc29d86bdf2635e7969 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Qu=C3=A8ze?=
Date: Wed, 17 Dec 2014 16:20:04 +0100
Subject: [PATCH 13/24] Bug 1106559 - Improve the in-content search preference
UI, r=felipe.
---
.../preferences/in-content/preferences.xul | 2 +-
.../preferences/in-content/search.js | 436 ++++++++++++++++--
.../preferences/in-content/search.xul | 30 +-
browser/themes/linux/jar.mn | 3 +
browser/themes/osx/jar.mn | 3 +
.../themes/shared/incontentprefs/check.png | Bin 0 -> 288 bytes
.../themes/shared/incontentprefs/check@2x.png | Bin 0 -> 471 bytes
.../themes/shared/incontentprefs/search.css | 54 +++
browser/themes/windows/jar.mn | 6 +
9 files changed, 501 insertions(+), 33 deletions(-)
create mode 100644 browser/themes/shared/incontentprefs/check.png
create mode 100644 browser/themes/shared/incontentprefs/check@2x.png
create mode 100644 browser/themes/shared/incontentprefs/search.css
diff --git a/browser/components/preferences/in-content/preferences.xul b/browser/components/preferences/in-content/preferences.xul
index 07adfa4155e..57f75e6bcea 100644
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -14,7 +14,7 @@
-
+
diff --git a/browser/components/preferences/in-content/search.js b/browser/components/preferences/in-content/search.js
index c69d4c75a6d..bb31356afa4 100644
--- a/browser/components/preferences/in-content/search.js
+++ b/browser/components/preferences/in-content/search.js
@@ -4,6 +4,10 @@
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+const ENGINE_FLAVOR = "text/x-moz-search-engine";
+
+var gEngineView = null;
+
var gSearchPane = {
init: function ()
@@ -15,9 +19,37 @@ var gSearchPane = {
return;
}
+ gEngineView = new EngineView(new EngineStore());
+ document.getElementById("engineList").view = gEngineView;
+ this.buildDefaultEngineDropDown();
+
+ Services.obs.addObserver(this, "browser-search-engine-modified", false);
+ window.addEventListener("unload", () => {
+ Services.obs.removeObserver(this, "browser-search-engine-modified", false);
+ });
+ },
+
+ buildDefaultEngineDropDown: function() {
+ // This is called each time something affects the list of engines.
let list = document.getElementById("defaultEngine");
- let currentEngine = Services.search.currentEngine.name;
- Services.search.getVisibleEngines().forEach(e => {
+ let currentEngine;
+
+ // First, try to preserve the current selection.
+ if (list.selectedItem)
+ currentEngine = list.selectedItem.label;
+
+ // If there's no current selection, use the current default engine.
+ if (!currentEngine)
+ currentEngine = Services.search.currentEngine.name;
+
+ // If the current engine isn't in the list any more, select the first item.
+ let engines = gEngineView._engineStore._engines;
+ if (!engines.some(e => e.name == currentEngine))
+ currentEngine = engines[0].name;
+
+ // Now clean-up and rebuild the list.
+ list.removeAllItems();
+ gEngineView._engineStore._engines.forEach(e => {
let item = list.appendItem(e.name);
item.setAttribute("class", "menuitem-iconic searchengine-menuitem menuitem-with-favicon");
if (e.iconURI)
@@ -26,42 +58,119 @@ var gSearchPane = {
if (e.name == currentEngine)
list.selectedItem = item;
});
-
- this.displayOneClickEnginesList();
-
- document.getElementById("oneClickProvidersList")
- .addEventListener("CheckboxStateChange", gSearchPane.saveOneClickEnginesList);
},
- displayOneClickEnginesList: function () {
- let richlistbox = document.getElementById("oneClickProvidersList");
- let pref = document.getElementById("browser.search.hiddenOneOffs").value;
- let hiddenList = pref ? pref.split(",") : [];
+ observe: function(aEngine, aTopic, aVerb) {
+ if (aTopic == "browser-search-engine-modified") {
+ aEngine.QueryInterface(Components.interfaces.nsISearchEngine);
+ switch (aVerb) {
+ case "engine-added":
+ gEngineView._engineStore.addEngine(aEngine);
+ gEngineView.rowCountChanged(gEngineView.lastIndex, 1);
+ gSearchPane.buildDefaultEngineDropDown();
+ break;
+ case "engine-changed":
+ gEngineView._engineStore.reloadIcons();
+ gEngineView.invalidate();
+ break;
+ case "engine-removed":
+ case "engine-current":
+ case "engine-default":
+ // Not relevant
+ break;
+ }
+ }
+ },
- while (richlistbox.firstChild)
- richlistbox.firstChild.remove();
+ onTreeSelect: function() {
+ document.getElementById("removeEngineButton").disabled =
+ gEngineView.selectedIndex == -1 || gEngineView.lastIndex == 0;
+ },
- let currentEngine = Services.search.currentEngine.name;
- Services.search.getVisibleEngines().forEach(e => {
- if (e.name == currentEngine)
- return;
+ onTreeKeyPress: function(aEvent) {
+ let index = gEngineView.selectedIndex;
+ let tree = document.getElementById("engineList");
+ if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
+ // Space toggles the checkbox.
+ let newValue = !gEngineView._engineStore.engines[index].shown;
+ gEngineView.setCellValue(index, tree.columns.getFirstColumn(),
+ newValue.toString());
+ }
+ else {
+ let isMac = Services.appinfo.OS == "Darwin";
+ if ((isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
+ (!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2))
+ tree.startEditing(index, tree.columns.getLastColumn());
+ }
+ },
- let item = document.createElement("richlistitem");
- item.setAttribute("label", e.name);
- if (hiddenList.indexOf(e.name) == -1)
- item.setAttribute("checked", "true");
- if (e.iconURI)
- item.setAttribute("src", e.iconURI.spec);
- richlistbox.appendChild(item);
- });
+ onRestoreDefaults: function() {
+ let num = gEngineView._engineStore.restoreDefaultEngines();
+ gEngineView.rowCountChanged(0, num);
+ gEngineView.invalidate();
+ },
+
+ showRestoreDefaults: function(aEnable) {
+ document.getElementById("restoreDefaultSearchEngines").disabled = !aEnable;
+ },
+
+ remove: function() {
+ gEngineView._engineStore.removeEngine(gEngineView.selectedEngine);
+ let index = gEngineView.selectedIndex;
+ gEngineView.rowCountChanged(index, -1);
+ gEngineView.invalidate();
+ gEngineView.selection.select(Math.min(index, gEngineView.lastIndex));
+ gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
+ document.getElementById("engineList").focus();
+ },
+
+ editKeyword: function(aEngine, aNewKeyword) {
+ if (aNewKeyword) {
+ let bduplicate = false;
+ let eduplicate = false;
+ let dupName = "";
+
+ try {
+ let bmserv =
+ Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"]
+ .getService(Components.interfaces.nsINavBookmarksService);
+ if (bmserv.getURIForKeyword(aNewKeyword))
+ bduplicate = true;
+ } catch(ex) {}
+
+ // Check for duplicates in changes we haven't committed yet
+ let engines = gEngineView._engineStore.engines;
+ for each (let engine in engines) {
+ if (engine.alias == aNewKeyword &&
+ engine.name != aEngine.name) {
+ eduplicate = true;
+ dupName = engine.name;
+ break;
+ }
+ }
+
+ // Notify the user if they have chosen an existing engine/bookmark keyword
+ if (eduplicate || bduplicate) {
+ let strings = document.getElementById("engineManagerBundle");
+ let dtitle = strings.getString("duplicateTitle");
+ let bmsg = strings.getString("duplicateBookmarkMsg");
+ let emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
+
+ Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
+ return false;
+ }
+ }
+
+ gEngineView._engineStore.changeEngine(aEngine, "alias", aNewKeyword);
+ gEngineView.invalidate();
+ return true;
},
saveOneClickEnginesList: function () {
- let richlistbox = document.getElementById("oneClickProvidersList");
let hiddenList = [];
- for (let child of richlistbox.childNodes) {
- if (!child.checked)
- hiddenList.push(child.getAttribute("label"));
+ for (let engine of gEngineView._engineStore.engines) {
+ if (!engine.shown)
+ hiddenList.push(engine.name);
}
document.getElementById("browser.search.hiddenOneOffs").value =
hiddenList.join(",");
@@ -70,6 +179,273 @@ var gSearchPane = {
setDefaultEngine: function () {
Services.search.currentEngine =
document.getElementById("defaultEngine").selectedItem.engine;
- this.displayOneClickEnginesList();
}
};
+
+function onDragEngineStart(event) {
+ var selectedIndex = gEngineView.selectedIndex;
+ if (selectedIndex >= 0) {
+ event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
+ event.dataTransfer.effectAllowed = "move";
+ }
+}
+
+
+function EngineStore() {
+ let pref = document.getElementById("browser.search.hiddenOneOffs").value;
+ this.hiddenList = pref ? pref.split(",") : [];
+
+ this._engines = Services.search.getVisibleEngines().map(this._cloneEngine, this);
+ this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine, this);
+
+ // check if we need to disable the restore defaults button
+ var someHidden = this._defaultEngines.some(function (e) e.hidden);
+ gSearchPane.showRestoreDefaults(someHidden);
+}
+EngineStore.prototype = {
+ _engines: null,
+ _defaultEngines: null,
+
+ get engines() {
+ return this._engines;
+ },
+ set engines(val) {
+ this._engines = val;
+ return val;
+ },
+
+ _getIndexForEngine: function ES_getIndexForEngine(aEngine) {
+ return this._engines.indexOf(aEngine);
+ },
+
+ _getEngineByName: function ES_getEngineByName(aName) {
+ for each (var engine in this._engines)
+ if (engine.name == aName)
+ return engine;
+
+ return null;
+ },
+
+ _cloneEngine: function ES_cloneEngine(aEngine) {
+ var clonedObj={};
+ for (var i in aEngine)
+ clonedObj[i] = aEngine[i];
+ clonedObj.originalEngine = aEngine;
+ clonedObj.shown = this.hiddenList.indexOf(clonedObj.name) == -1;
+ return clonedObj;
+ },
+
+ // Callback for Array's some(). A thisObj must be passed to some()
+ _isSameEngine: function ES_isSameEngine(aEngineClone) {
+ return aEngineClone.originalEngine == this.originalEngine;
+ },
+
+ addEngine: function ES_addEngine(aEngine) {
+ this._engines.push(this._cloneEngine(aEngine));
+ },
+
+ moveEngine: function ES_moveEngine(aEngine, aNewIndex) {
+ if (aNewIndex < 0 || aNewIndex > this._engines.length - 1)
+ throw new Error("ES_moveEngine: invalid aNewIndex!");
+ var index = this._getIndexForEngine(aEngine);
+ if (index == -1)
+ throw new Error("ES_moveEngine: invalid engine?");
+
+ if (index == aNewIndex)
+ return; // nothing to do
+
+ // Move the engine in our internal store
+ var removedEngine = this._engines.splice(index, 1)[0];
+ this._engines.splice(aNewIndex, 0, removedEngine);
+
+ Services.search.moveEngine(aEngine.originalEngine, aNewIndex);
+ },
+
+ removeEngine: function ES_removeEngine(aEngine) {
+ var index = this._getIndexForEngine(aEngine);
+ if (index == -1)
+ throw new Error("invalid engine?");
+
+ this._engines.splice(index, 1);
+ Services.search.removeEngine(aEngine.originalEngine);
+
+ if (this._defaultEngines.some(this._isSameEngine, aEngine))
+ gSearchPane.showRestoreDefaults(true);
+ gSearchPane.buildDefaultEngineDropDown();
+ },
+
+ restoreDefaultEngines: function ES_restoreDefaultEngines() {
+ var added = 0;
+
+ for (var i = 0; i < this._defaultEngines.length; ++i) {
+ var e = this._defaultEngines[i];
+
+ // If the engine is already in the list, just move it.
+ if (this._engines.some(this._isSameEngine, e)) {
+ this.moveEngine(this._getEngineByName(e.name), i);
+ } else {
+ // Otherwise, add it back to our internal store
+ this._engines.splice(i, 0, e);
+ let engine = e.originalEngine;
+ engine.hidden = false;
+ Services.search.moveEngine(engine, i);
+ added++;
+ }
+ }
+ gSearchPane.showRestoreDefaults(false);
+ gSearchPane.buildDefaultEngineDropDown();
+ return added;
+ },
+
+ changeEngine: function ES_changeEngine(aEngine, aProp, aNewValue) {
+ var index = this._getIndexForEngine(aEngine);
+ if (index == -1)
+ throw new Error("invalid engine?");
+
+ this._engines[index][aProp] = aNewValue;
+ aEngine.originalEngine[aProp] = aNewValue;
+ },
+
+ reloadIcons: function ES_reloadIcons() {
+ this._engines.forEach(function (e) {
+ e.uri = e.originalEngine.uri;
+ });
+ }
+};
+
+function EngineView(aEngineStore) {
+ this._engineStore = aEngineStore;
+}
+EngineView.prototype = {
+ _engineStore: null,
+ tree: null,
+
+ get lastIndex() {
+ return this.rowCount - 1;
+ },
+ get selectedIndex() {
+ var seln = this.selection;
+ if (seln.getRangeCount() > 0) {
+ var min = {};
+ seln.getRangeAt(0, min, {});
+ return min.value;
+ }
+ return -1;
+ },
+ get selectedEngine() {
+ return this._engineStore.engines[this.selectedIndex];
+ },
+
+ // Helpers
+ rowCountChanged: function (index, count) {
+ this.tree.rowCountChanged(index, count);
+ },
+
+ invalidate: function () {
+ this.tree.invalidate();
+ },
+
+ ensureRowIsVisible: function (index) {
+ this.tree.ensureRowIsVisible(index);
+ },
+
+ getSourceIndexFromDrag: function (dataTransfer) {
+ return parseInt(dataTransfer.getData(ENGINE_FLAVOR));
+ },
+
+ // nsITreeView
+ get rowCount() {
+ return this._engineStore.engines.length;
+ },
+
+ getImageSrc: function(index, column) {
+ if (column.id == "engineName" && this._engineStore.engines[index].iconURI)
+ return this._engineStore.engines[index].iconURI.spec;
+ return "";
+ },
+
+ getCellText: function(index, column) {
+ if (column.id == "engineName")
+ return this._engineStore.engines[index].name;
+ else if (column.id == "engineKeyword")
+ return this._engineStore.engines[index].alias;
+ return "";
+ },
+
+ setTree: function(tree) {
+ this.tree = tree;
+ },
+
+ canDrop: function(targetIndex, orientation, dataTransfer) {
+ var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
+ return (sourceIndex != -1 &&
+ sourceIndex != targetIndex &&
+ sourceIndex != targetIndex + orientation);
+ },
+
+ drop: function(dropIndex, orientation, dataTransfer) {
+ var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
+ var sourceEngine = this._engineStore.engines[sourceIndex];
+
+ const nsITreeView = Components.interfaces.nsITreeView;
+ if (dropIndex > sourceIndex) {
+ if (orientation == nsITreeView.DROP_BEFORE)
+ dropIndex--;
+ } else {
+ if (orientation == nsITreeView.DROP_AFTER)
+ dropIndex++;
+ }
+
+ this._engineStore.moveEngine(sourceEngine, dropIndex);
+ gSearchPane.showRestoreDefaults(true);
+ gSearchPane.buildDefaultEngineDropDown();
+
+ // Redraw, and adjust selection
+ this.invalidate();
+ this.selection.select(dropIndex);
+ },
+
+ selection: null,
+ getRowProperties: function(index) { return ""; },
+ getCellProperties: function(index, column) { return ""; },
+ getColumnProperties: function(column) { return ""; },
+ isContainer: function(index) { return false; },
+ isContainerOpen: function(index) { return false; },
+ isContainerEmpty: function(index) { return false; },
+ isSeparator: function(index) { return false; },
+ isSorted: function(index) { return false; },
+ getParentIndex: function(index) { return -1; },
+ hasNextSibling: function(parentIndex, index) { return false; },
+ getLevel: function(index) { return 0; },
+ getProgressMode: function(index, column) { },
+ getCellValue: function(index, column) {
+ if (column.id == "engineShown")
+ return this._engineStore.engines[index].shown;
+ return undefined;
+ },
+ toggleOpenState: function(index) { },
+ cycleHeader: function(column) { },
+ selectionChanged: function() { },
+ cycleCell: function(row, column) { },
+ isEditable: function(index, column) { return column.id != "engineName"; },
+ isSelectable: function(index, column) { return false; },
+ setCellValue: function(index, column, value) {
+ if (column.id == "engineShown") {
+ this._engineStore.engines[index].shown = value == "true";
+ gEngineView.invalidate();
+ gSearchPane.saveOneClickEnginesList();
+ }
+ },
+ setCellText: function(index, column, value) {
+ if (column.id == "engineKeyword") {
+ if (!gSearchPane.editKeyword(this._engineStore.engines[index], value)) {
+ setTimeout(() => {
+ document.getElementById("engineList").startEditing(index, column);
+ }, 0);
+ }
+ }
+ },
+ performAction: function(action) { },
+ performActionOnRow: function(action, index) { },
+ performActionOnCell: function(action, index, column) { }
+};
diff --git a/browser/components/preferences/in-content/search.xul b/browser/components/preferences/in-content/search.xul
index 351fa235702..f733b086c1e 100644
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -39,8 +39,34 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn
index 2f67952df47..895e211f4a6 100644
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -167,6 +167,9 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
+ skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
+ skin/classic/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
+ skin/classic/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)
diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn
index e8f3175980b..798b1014028 100644
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -271,6 +271,9 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
+ skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
+ skin/classic/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
+ skin/classic/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)
diff --git a/browser/themes/shared/incontentprefs/check.png b/browser/themes/shared/incontentprefs/check.png
new file mode 100644
index 0000000000000000000000000000000000000000..98c89d66e628dcf852fbe1774363c0efff8876ff
GIT binary patch
literal 288
zcmV+*0pI?KP)uK>R~t@+A$tisk#y
zNCFkU18bOkp#m0%^Q@h`;*
zm-P^)OuWzpmH4kb@q9ek-P13M0S$Nq6>mhfchxFprHL1IK_!1HOupc*H0k_mDF3o{
z!&Np6x5`bsBnVV=2dd~Nl>VbM;k+r%5K)ZA*GKo8sEk_P~vZGl;O!Zy1A0000KH!tvMkWBPiTfeQkisuk6NzZf$nnB~x9RygrOJ7L4mM`NU#$rqO6PQw!~Oh?slF%zdRCtMZ>`t%K&1+Ub4&WK>w
zF!4edmNfhamv@1VS%VR=Kr;yC!cAB#`KB=Gq6La$CZ7+*5;W@wMi?kl02N=yV##Y*
zp#=&8P*9-Bzf+icRf4!QJ>`NLP{RjIOU~a>o_7ooJ<;zNZ7AQ_SpGr|NAT{$07to*!I4syhm9j>m|GWY?
z6`>mb1td<*I@S?r=x;>OT*#q*MLy|b9@K(E#1@34r>sfmr;*!A005yCz>!?D9tr>e
N002ovPDHLkV1jR)%n1Mh
literal 0
HcmV?d00001
diff --git a/browser/themes/shared/incontentprefs/search.css b/browser/themes/shared/incontentprefs/search.css
new file mode 100644
index 00000000000..dae04fbdecc
--- /dev/null
+++ b/browser/themes/shared/incontentprefs/search.css
@@ -0,0 +1,54 @@
+/* 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/. */
+
+#defaultEngine > .menulist-label-box > .menulist-icon {
+ height: 16px;
+}
+
+/* work around a display: none in Linux's menu.css, see bug 1112310 */
+.searchengine-menuitem > .menu-iconic-left {
+ display: -moz-box;
+}
+
+#engineList {
+ margin: .5em 6px;
+}
+
+#engineList treechildren::-moz-tree-image(engineShown, checked) {
+ /* Unfortunately check.svg can't be used in XUL trees. */
+ list-style-image: url("check.png");
+ -moz-margin-start: 5px;
+ width: 12px;
+ height: 12px;
+}
+
+@media (min-resolution: 2dppx) {
+ #engineList treechildren::-moz-tree-image(engineShown, checked) {
+ list-style-image: url("check@2x.png");
+ }
+}
+
+#engineList treechildren::-moz-tree-image(engineName) {
+ -moz-margin-end: 10px;
+ -moz-margin-start: 1px;
+ width: 16px;
+ height: 16px;
+}
+
+#engineList treechildren::-moz-tree-row {
+ min-height: 36px;
+}
+
+#engineList treechildren::-moz-tree-cell-text {
+ /* Override to avoid text in the selected row being white on light gray. */
+ color: -moz-FieldText;
+}
+
+#engineList treechildren::-moz-tree-drop-feedback {
+ background-color: Highlight;
+ width: 10000px; /* 100% doesn't work; 10k is hopefully larger than any window
+ we may have, overflow isn't visible. */
+ height: 2px;
+ -moz-margin-start: 0;
+}
diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn
index 8a372461345..4ae5e7483ad 100644
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -195,6 +195,9 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
+ skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
+ skin/classic/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
+ skin/classic/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)
@@ -646,6 +649,9 @@ browser.jar:
skin/classic/aero/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/aero/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
skin/classic/aero/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
+ skin/classic/aero/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
+ skin/classic/aero/browser/preferences/in-content/check.png (../shared/incontentprefs/check.png)
+ skin/classic/aero/browser/preferences/in-content/check@2x.png (../shared/incontentprefs/check@2x.png)
skin/classic/aero/browser/preferences/applications.css (preferences/applications.css)
skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/aero/browser/preferences/search.css (preferences/search.css)
From 91396a9492fe251e1ebe7f7618de9af9c55b81bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Qu=C3=A8ze?=
Date: Fri, 12 Dec 2014 14:13:48 +0100
Subject: [PATCH 14/24] Bug 1107278 - Localize the new searchbar UI for Firefox
35 - remove duplicated code to match the code landed on beta, r=felipe.
---
browser/base/content/urlbarBindings.xml | 2 --
1 file changed, 2 deletions(-)
diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml
index b100b1b441b..23b1f21ff4b 100644
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1060,8 +1060,6 @@
let addEngines = gBrowser.selectedBrowser.engines;
if (addEngines && addEngines.length > 0) {
- const kBundleURI = "chrome://browser/locale/search.properties";
- let bundle = Services.strings.createBundle(kBundleURI);
for (let engine of addEngines) {
let button = document.createElementNS(kXULNS, "button");
let label = bundle.formatStringFromName("cmd_addFoundEngine",
From fc294b23df60577401b6da9ca557d994a87fb6f0 Mon Sep 17 00:00:00 2001
From: Mike Conley
Date: Tue, 16 Dec 2014 11:25:15 -0500
Subject: [PATCH 15/24] Bug 1111957 - Invalidate mDPI and mDefaultScale in
TabChild when switching displays. r=fabrice.
Bug 1107259 made TabChild cache the display DPI and default scale more aggressively, and
we need to invalidate those caches when switching displays, otherwise we can get weird
scaling behaviours when switching between displays with different DPIs and scales.
--HG--
extra : rebase_source : cccbdae40113ae1a1b76d020ddc93e7b393fce61
extra : amend_source : d2664b4ea30342476e67da2a16315be4c1920abf
---
dom/ipc/TabChild.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp
index 3404b8b08aa..b8a8266bb30 100644
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3411,6 +3411,8 @@ TabChild::RecvRequestNotifyAfterRemotePaint()
bool
TabChild::RecvUIResolutionChanged()
{
+ mDPI = 0;
+ mDefaultScale = 0;
static_cast(mWidget.get())->ClearBackingScaleCache();
nsCOMPtr document(GetDocument());
nsCOMPtr presShell = document->GetShell();
From c006280f8e3d5e79b6314124556711c0a15540aa Mon Sep 17 00:00:00 2001
From: Michael Comella
Date: Wed, 17 Dec 2014 08:52:50 -0800
Subject: [PATCH 16/24] Bug 1112397 - Go back in testSettingsMenuItems on small
tablet. r=gbrown
---
mobile/android/base/tests/testSettingsMenuItems.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mobile/android/base/tests/testSettingsMenuItems.java b/mobile/android/base/tests/testSettingsMenuItems.java
index 5064369a6e3..80d4ee65e4e 100644
--- a/mobile/android/base/tests/testSettingsMenuItems.java
+++ b/mobile/android/base/tests/testSettingsMenuItems.java
@@ -258,8 +258,9 @@ public class testSettingsMenuItems extends PixelTest {
}
}
- // Navigate back if on a phone. Tablets shouldn't do this because they use headers and fragments.
- if (mDevice.type.equals("phone")) {
+ // Navigate back if on a phone or small tablets. Large tablets
+ // shouldn't do this because they use headers and fragments.
+ if (mDevice.type.equals("phone") || HardwareUtils.isSmallTablet()) {
int menuDepth = menuPath.length;
while (menuDepth > 0) {
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
From be2b75345b6f7b6689e6564f592ec4e5c4dc319f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A3o=20Gottwald?=
Date: Wed, 17 Dec 2014 18:17:38 +0100
Subject: [PATCH 17/24] Bug 1108555 - [e10s] closing last tab does not focus
urlbar (browser.tabs.closeWindowWithLastTab = false). r=jimm,mconley
---
browser/base/content/tabbrowser.xml | 26 +++++++++++---------------
browser/base/content/utilityOverlay.js | 10 +---------
2 files changed, 12 insertions(+), 24 deletions(-)
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index d28441b1e27..b081551681c 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1190,6 +1190,10 @@
// We need to explicitly focus the new tab, because
// tabbox.xml does this only in some cases.
this.mCurrentTab.focus();
+ } else if (gMultiProcessBrowser) {
+ // Clear focus so that _adjustFocusAfterTabSwitch can detect if
+ // some element has been focused and respect that.
+ document.activeElement.blur();
}
if (!gMultiProcessBrowser)
@@ -1207,12 +1211,12 @@
Date: Wed, 17 Dec 2014 20:25:52 +0100
Subject: [PATCH 18/24] Bug 1106876 - the one-click search header isn't updated
immediately when the textfield value changes, r=felipe.
---
browser/base/content/urlbarBindings.xml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml
index 23b1f21ff4b..1b2f0129689 100644
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1035,17 +1035,17 @@
"searchbar-oneoffheader-searchtext");
let textbox = searchbar.textbox;
let self = this;
- let keyPressHandler = function() {
+ let inputHandler = function() {
headerSearchText.setAttribute("value", textbox.value);
if (textbox.value)
self.removeAttribute("showonlysettings");
};
- textbox.addEventListener("keyup", keyPressHandler);
+ textbox.addEventListener("input", inputHandler);
this.addEventListener("popuphiding", function hiding() {
- textbox.removeEventListener("keyup", keyPressHandler);
+ textbox.removeEventListener("input", inputHandler);
this.removeEventListener("popuphiding", hiding);
});
- keyPressHandler();
+ inputHandler();
// Handle opensearch items. This needs to be done before building the
// list of one off providers, as that code will return early if all the
From 025d148d80bd8f41f6bc68009e1d367cfc2a4ae7 Mon Sep 17 00:00:00 2001
From: Ryan VanderMeulen
Date: Wed, 17 Dec 2014 14:34:21 -0500
Subject: [PATCH 19/24] Backed out changeset 66cc38d90f25 (bug 1112397) for
making testSettingsMenuItems permafail on Android 4.0.
---
mobile/android/base/tests/testSettingsMenuItems.java | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/mobile/android/base/tests/testSettingsMenuItems.java b/mobile/android/base/tests/testSettingsMenuItems.java
index 80d4ee65e4e..5064369a6e3 100644
--- a/mobile/android/base/tests/testSettingsMenuItems.java
+++ b/mobile/android/base/tests/testSettingsMenuItems.java
@@ -258,9 +258,8 @@ public class testSettingsMenuItems extends PixelTest {
}
}
- // Navigate back if on a phone or small tablets. Large tablets
- // shouldn't do this because they use headers and fragments.
- if (mDevice.type.equals("phone") || HardwareUtils.isSmallTablet()) {
+ // Navigate back if on a phone. Tablets shouldn't do this because they use headers and fragments.
+ if (mDevice.type.equals("phone")) {
int menuDepth = menuPath.length;
while (menuDepth > 0) {
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
From 8de57b4f58ed9facc58fe6b251e353e232640fc8 Mon Sep 17 00:00:00 2001
From: Brad Lassey
Date: Tue, 16 Dec 2014 17:35:10 -0500
Subject: [PATCH 20/24] bug 1112337 - desktop mirroring code passes null
viewport r=mconley
---
browser/base/content/content.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/browser/base/content/content.js b/browser/base/content/content.js
index 5a7bc986845..03604c84b1a 100644
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -95,8 +95,8 @@ addMessageListener("MixedContent:ReenableProtection", function() {
addMessageListener("SecondScreen:tab-mirror", function(message) {
let app = SimpleServiceDiscovery.findAppForService(message.data.service);
if (app) {
- let width = content.scrollWidth;
- let height = content.scrollHeight;
+ let width = content.innerWidth;
+ let height = content.innerHeight;
let viewport = {cssWidth: width, cssHeight: height, width: width, height: height};
app.mirror(function() {}, content, viewport, function() {}, content);
}
From c23ee59cc4f31fdfcf3c7125f16c70c9f682d946 Mon Sep 17 00:00:00 2001
From: Brad Lassey
Date: Tue, 16 Dec 2014 17:43:23 -0500
Subject: [PATCH 21/24] bug 1112345 - Tab streaming should scroll stream with
layers and not offsets r=snorp
---
.../webrtc/MediaEngineTabVideoSource.cpp | 33 +++++++------------
1 file changed, 11 insertions(+), 22 deletions(-)
diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.cpp b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
index df56ca5f53c..0b0a44aaa11 100644
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -219,7 +219,6 @@ MediaEngineTabVideoSource::Draw() {
IntSize size(mBufW, mBufH);
nsresult rv;
- float scale = 1.0;
nsCOMPtr win = do_QueryInterface(mWindow);
@@ -240,25 +239,14 @@ MediaEngineTabVideoSource::Draw() {
return;
}
- float left, top, width, height;
- rect->GetLeft(&left);
- rect->GetTop(&top);
+ float width, height;
rect->GetWidth(&width);
rect->GetHeight(&height);
- if (mScrollWithPage) {
- nsPoint point;
- utils->GetScrollXY(false, &point.x, &point.y);
- left += point.x;
- top += point.y;
- }
-
if (width == 0 || height == 0) {
return;
}
- int32_t srcX = left;
- int32_t srcY = top;
int32_t srcW;
int32_t srcH;
@@ -279,14 +267,15 @@ MediaEngineTabVideoSource::Draw() {
if (!presContext) {
return;
}
+
nscolor bgColor = NS_RGB(255, 255, 255);
nsCOMPtr presShell = presContext->PresShell();
- uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
- nsIPresShell::RENDER_DOCUMENT_RELATIVE);
- nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
- nsPresContext::CSSPixelsToAppUnits(srcY / scale),
- nsPresContext::CSSPixelsToAppUnits(srcW / scale),
- nsPresContext::CSSPixelsToAppUnits(srcH / scale));
+ uint32_t renderDocFlags = nsIPresShell::RENDER_DOCUMENT_RELATIVE;
+ if (!mScrollWithPage) {
+ renderDocFlags |= nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING;
+ }
+ nsRect r(0, 0, nsPresContext::CSSPixelsToAppUnits((float)srcW),
+ nsPresContext::CSSPixelsToAppUnits((float)srcH));
gfxImageFormat format = gfxImageFormat::RGB24;
uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width);
@@ -302,9 +291,9 @@ MediaEngineTabVideoSource::Draw() {
return;
}
nsRefPtr context = new gfxContext(dt);
- context->SetMatrix(
- context->CurrentMatrix().Scale(scale * size.width / srcW,
- scale * size.height / srcH));
+ context->SetMatrix(context->CurrentMatrix().Scale((float)size.width/srcW,
+ (float)size.height/srcH));
+
rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
NS_ENSURE_SUCCESS_VOID(rv);
From 5f6686adceeb3247b5ca30edff9d8b43e51dc8ca Mon Sep 17 00:00:00 2001
From: Dan Mosedale
Date: Wed, 17 Dec 2014 12:27:03 -0800
Subject: [PATCH 22/24] Bug 1110507-Loop self-image can be cropped by scrolling
out of view (privacy), r=jaws
---
browser/base/content/browser.css | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
index 4f3bb6eeec1..eb4e9cc257c 100644
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -14,6 +14,30 @@
%endif
}
+/* These values are chosen to keep the Loop detached chat window from
+ * getting too small. When it's too small, three bad things happen:
+ *
+ * - It looks terrible
+ * - It's not really usable
+ * - It's possible for the user to be transmitting video that's cropped by the
+ * the edge of the window, so that they're not aware of it, which is a
+ * privacy problem
+ *
+ * Note that if the chat window grows more users than Loop who want this
+ * ability, we'll need to generalize. A partial patch for this is in
+ * bug 1112264.
+ */
+
+#chat-window {
+ /*
+ * In some ideal world, we'd have a simple way to express "block resizing
+ * along any dimension beyond the point at which an overflow event would
+ * occur". But none of -moz-{fit,max,min}-content do what we want here. So..
+ */
+ min-width: 320px;
+ min-height: 280px;
+}
+
#main-window[customize-entered] {
min-width: -moz-fit-content;
}
From afc20ecc8708a7741a6dc639b292e1e281d36738 Mon Sep 17 00:00:00 2001
From: Paolo Amadini
Date: Wed, 17 Dec 2014 20:42:29 +0000
Subject: [PATCH 23/24] Bug 1088508 - Update Loop button icon images and
rendered size. r=jaws
--HG--
rename : browser/themes/windows/loop/toolbar-XPVista7.png => browser/themes/windows/loop/toolbar-aero.png
---
browser/base/content/browser.css | 2 +-
browser/themes/linux/loop/menuPanel.png | Bin 2439 -> 2834 bytes
.../themes/linux/loop/toolbar-inverted.png | Bin 3023 -> 2731 bytes
browser/themes/linux/loop/toolbar.png | Bin 4806 -> 4421 bytes
.../themes/osx/loop/menuPanel-yosemite.png | Bin 12795 -> 5882 bytes
.../themes/osx/loop/menuPanel-yosemite@2x.png | Bin 26676 -> 11601 bytes
browser/themes/osx/loop/menuPanel.png | Bin 16828 -> 9703 bytes
browser/themes/osx/loop/menuPanel@2x.png | Bin 37656 -> 22824 bytes
browser/themes/osx/loop/toolbar-inverted.png | Bin 4446 -> 4060 bytes
.../themes/osx/loop/toolbar-inverted@2x.png | Bin 11554 -> 10967 bytes
browser/themes/osx/loop/toolbar-yosemite.png | Bin 2920 -> 2561 bytes
.../themes/osx/loop/toolbar-yosemite@2x.png | Bin 6372 -> 6047 bytes
browser/themes/osx/loop/toolbar.png | Bin 4582 -> 4307 bytes
browser/themes/osx/loop/toolbar@2x.png | Bin 13690 -> 13249 bytes
browser/themes/windows/jar.mn | 16 ++++++++++------
.../themes/windows/loop/menuPanel-aero.png | Bin 16541 -> 10263 bytes
browser/themes/windows/loop/menuPanel.png | Bin 8901 -> 2834 bytes
browser/themes/windows/loop/toolbar-XP.png | Bin 0 -> 4339 bytes
.../themes/windows/loop/toolbar-XPVista7.png | Bin 4666 -> 0 bytes
browser/themes/windows/loop/toolbar-aero.png | Bin 0 -> 4437 bytes
.../themes/windows/loop/toolbar-inverted.png | Bin 3023 -> 2731 bytes
.../windows/loop/toolbar-lunaSilver.png | Bin 4862 -> 4451 bytes
browser/themes/windows/loop/toolbar.png | Bin 1259 -> 1121 bytes
23 files changed, 11 insertions(+), 7 deletions(-)
create mode 100644 browser/themes/windows/loop/toolbar-XP.png
delete mode 100644 browser/themes/windows/loop/toolbar-XPVista7.png
create mode 100644 browser/themes/windows/loop/toolbar-aero.png
diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
index eb4e9cc257c..2e5a7cd34e7 100644
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -873,7 +873,7 @@ toolbarbutton[type="socialmark"] {
toolbarbutton.badged-button > .toolbarbutton-badge-container > .toolbarbutton-icon,
toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
- max-width: 16px;
+ max-width: 18px;
}
toolbarpaletteitem[place="palette"] > toolbarbutton.badged-button > .toolbarbutton-badge-container > .toolbarbutton-icon {
max-width: 32px;
diff --git a/browser/themes/linux/loop/menuPanel.png b/browser/themes/linux/loop/menuPanel.png
index 6e741afdd4fea47123a06c29ba9fc6c983d8e6ab..31f3671d4ce3714fcc446f8b7373234684f32be5 100644
GIT binary patch
delta 2828
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
delta 2429
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
diff --git a/browser/themes/linux/loop/toolbar-inverted.png b/browser/themes/linux/loop/toolbar-inverted.png
index cb9a93fb9d5cdad09f5c9a08ffda5589eb8e68cc..31c0256b3e321dedfdc8d11a86b982b99eb52cfd 100644
GIT binary patch
delta 2724
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
wL?N=LnK3CBU7fz
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
diff --git a/browser/themes/osx/loop/menuPanel-yosemite.png b/browser/themes/osx/loop/menuPanel-yosemite.png
index 9a1df39f1276d770d866a999dc55ef00a9efefe1..1d0cb991a657cd9110ee8de3d421a7c8bea79662 100644
GIT binary patch
literal 5882
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