зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
3e816e5942
|
@ -1598,15 +1598,6 @@ pref("browser.contentblocking.fingerprinting.preferences.ui.enabled", true);
|
|||
// One value from each section must be included in the browser.contentblocking.features.strict pref.
|
||||
pref("browser.contentblocking.features.strict", "tp,tpPrivate,cookieBehavior4,cm,fp");
|
||||
|
||||
// Enable the Report Breakage UI on Nightly and Beta but not on Release yet.
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
pref("browser.contentblocking.reportBreakage.enabled", true);
|
||||
#else
|
||||
pref("browser.contentblocking.reportBreakage.enabled", false);
|
||||
#endif
|
||||
// Show report breakage for tracking cookies in all channels.
|
||||
pref("browser.contentblocking.rejecttrackers.reportBreakage.enabled", true);
|
||||
|
||||
pref("browser.contentblocking.reportBreakage.url", "https://tracking-protection-issues.herokuapp.com/new");
|
||||
|
||||
// Enable Protections report's Lockwise card by default.
|
||||
|
|
|
@ -535,8 +535,6 @@ var TrackingProtection = {
|
|||
|
||||
var ThirdPartyCookies = {
|
||||
PREF_ENABLED: "network.cookie.cookieBehavior",
|
||||
PREF_REPORT_BREAKAGE_ENABLED:
|
||||
"browser.contentblocking.rejecttrackers.reportBreakage.enabled",
|
||||
PREF_ENABLED_VALUES: [
|
||||
// These values match the ones exposed under the Content Blocking section
|
||||
// of the Preferences UI.
|
||||
|
@ -650,12 +648,6 @@ var ThirdPartyCookies = {
|
|||
Ci.nsICookieService.BEHAVIOR_ACCEPT,
|
||||
this.updateCategoryLabel.bind(this)
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"reportBreakageEnabled",
|
||||
this.PREF_REPORT_BREAKAGE_ENABLED,
|
||||
false
|
||||
);
|
||||
this.updateCategoryLabel();
|
||||
},
|
||||
|
||||
|
@ -907,8 +899,6 @@ var ThirdPartyCookies = {
|
|||
*/
|
||||
var gProtectionsHandler = {
|
||||
PREF_ANIMATIONS_ENABLED: "toolkit.cosmeticAnimations.enabled",
|
||||
PREF_REPORT_BREAKAGE_ENABLED:
|
||||
"browser.contentblocking.reportBreakage.enabled",
|
||||
PREF_REPORT_BREAKAGE_URL: "browser.contentblocking.reportBreakage.url",
|
||||
PREF_CB_CATEGORY: "browser.contentblocking.category",
|
||||
PREF_SHOW_ALLOWED_LABELS:
|
||||
|
@ -969,18 +959,18 @@ var gProtectionsHandler = {
|
|||
"protections-popup-tp-switch-breakage-link"
|
||||
));
|
||||
},
|
||||
get _protectionsPopupTPSwitchSection() {
|
||||
delete this._protectionsPopupTPSwitchSection;
|
||||
return (this._protectionsPopupTPSwitchSection = document.getElementById(
|
||||
"protections-popup-tp-switch-section"
|
||||
));
|
||||
},
|
||||
get _protectionsPopupTPSwitch() {
|
||||
delete this._protectionsPopupTPSwitch;
|
||||
return (this._protectionsPopupTPSwitch = document.getElementById(
|
||||
"protections-popup-tp-switch"
|
||||
));
|
||||
},
|
||||
get _breakageLink() {
|
||||
delete this._breakageLink;
|
||||
return (this._breakageLink = document.getElementById(
|
||||
"protections-popup-tp-switch-breakage-link"
|
||||
));
|
||||
},
|
||||
get _protectionPopupSettingsButton() {
|
||||
delete this._protectionPopupSettingsButton;
|
||||
return (this._protectionPopupSettingsButton = document.getElementById(
|
||||
|
@ -1110,12 +1100,6 @@ var gProtectionsHandler = {
|
|||
}
|
||||
}
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"reportBreakageEnabled",
|
||||
this.PREF_REPORT_BREAKAGE_ENABLED,
|
||||
false
|
||||
);
|
||||
|
||||
for (let blocker of this.blockers) {
|
||||
if (blocker.init) {
|
||||
|
@ -1453,10 +1437,19 @@ var gProtectionsHandler = {
|
|||
tpSwitch.toggleAttribute("enabled", currentlyEnabled);
|
||||
}
|
||||
|
||||
// Display the breakage link according to the current enable state.
|
||||
// The display state of the breakage link will be fixed once the protections
|
||||
// panel opened no matter how the TP switch state is.
|
||||
this._protectionsPopupTPSwitchBreakageLink.hidden = !currentlyEnabled;
|
||||
// Toggle the breakage link according to the current enable state.
|
||||
this.toggleBreakageLink();
|
||||
|
||||
// Display a short TP switch section depending on the enable state. We need
|
||||
// to use a separate attribute here since the 'hasException' attribute will
|
||||
// be toggled as well as the TP switch, we cannot rely on that to decide the
|
||||
// height of TP switch section, or it will change when toggling the switch,
|
||||
// which is not desirable for us. So, we need to use a different attribute
|
||||
// here.
|
||||
this._protectionsPopupTPSwitchSection.toggleAttribute(
|
||||
"short",
|
||||
!currentlyEnabled
|
||||
);
|
||||
|
||||
// Set the counter of the 'Trackers blocked This Week'.
|
||||
// We need to get the statistics of trackers. So far, we haven't implemented
|
||||
|
@ -1500,6 +1493,9 @@ var gProtectionsHandler = {
|
|||
tpSwitch.toggleAttribute("enabled", !newExceptionState);
|
||||
}
|
||||
|
||||
// Toggle the breakage link if needed.
|
||||
this.toggleBreakageLink();
|
||||
|
||||
// Indicating that we need to show a toast after refreshing the page.
|
||||
// And caching the current URI and window ID in order to only show the mini
|
||||
// panel if it's still on the same page.
|
||||
|
@ -1570,10 +1566,6 @@ var gProtectionsHandler = {
|
|||
);
|
||||
}
|
||||
|
||||
// Adjust "site not working?" visibility based on whether we're
|
||||
// blocking something or not.
|
||||
gProtectionsHandler.toggleBreakageLink();
|
||||
|
||||
// Check the panel state of the identity panel. Hide it if needed.
|
||||
if (gIdentityHandler._identityPopup.state != "closed") {
|
||||
PanelMultiView.hidePopup(gIdentityHandler._identityPopup);
|
||||
|
@ -1611,18 +1603,18 @@ var gProtectionsHandler = {
|
|||
},
|
||||
|
||||
toggleBreakageLink() {
|
||||
// For release (due to the large volume) we only want to receive reports
|
||||
// for breakage that is directly related to third party cookie blocking.
|
||||
if (
|
||||
this.reportBreakageEnabled ||
|
||||
(ThirdPartyCookies.reportBreakageEnabled &&
|
||||
ThirdPartyCookies.activated &&
|
||||
!TrackingProtection.activated)
|
||||
) {
|
||||
this._breakageLink.removeAttribute("hidden");
|
||||
} else {
|
||||
this._breakageLink.setAttribute("hidden", "true");
|
||||
}
|
||||
// The breakage link will only be shown if tracking protection is enabled
|
||||
// for the site and the TP toggle state is on. And we won't show the
|
||||
// link as toggling TP switch to On from Off. In order to do so, we need to
|
||||
// know the previous TP state. We check the ContentBlockingAllowList instead
|
||||
// of 'hasException' attribute of the protection popup for the previous
|
||||
// since the 'hasException' will also be toggled as well as toggling the TP
|
||||
// switch. We won't be able to know the previous TP state through the
|
||||
// 'hasException' attribute. So we fallback to check the
|
||||
// ContentBlockingAllowList here.
|
||||
this._protectionsPopupTPSwitchBreakageLink.hidden =
|
||||
ContentBlockingAllowList.includes(gBrowser.selectedBrowser) ||
|
||||
!this._protectionsPopupTPSwitch.hasAttribute("enabled");
|
||||
},
|
||||
|
||||
submitBreakageReport(uri) {
|
||||
|
|
|
@ -309,7 +309,10 @@ var gURLBarHandler = {
|
|||
get urlbar() {
|
||||
if (!this._urlbar) {
|
||||
let textbox = document.getElementById("urlbar");
|
||||
this._urlbar = new UrlbarInput({ textbox });
|
||||
this._urlbar = new UrlbarInput({
|
||||
textbox,
|
||||
eventTelemetryCategory: "urlbar",
|
||||
});
|
||||
if (this._lastValue) {
|
||||
this._urlbar.value = this._lastValue;
|
||||
delete this._lastValue;
|
||||
|
|
|
@ -204,7 +204,7 @@ var gSanitizePromptDialog = {
|
|||
var prefs = this._getItemPrefs();
|
||||
for (let i = 0; i < prefs.length; ++i) {
|
||||
var p = prefs[i];
|
||||
Services.prefs.setBoolPref(p.name, p.value);
|
||||
Services.prefs.setBoolPref(p.id, p.value);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -332,16 +332,20 @@
|
|||
gBrowser.selectedTab = lastSelectedTab;
|
||||
|
||||
// Make sure selection is cleared when tab-switch doesn't happen.
|
||||
gBrowser.clearMultiSelectedTabs(false);
|
||||
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
|
||||
}
|
||||
gBrowser.addRangeToMultiSelectedTabs(lastSelectedTab, this);
|
||||
} else if (accelKey) {
|
||||
// Ctrl (Cmd for mac) key is pressed
|
||||
eventMaySelectTab = false;
|
||||
if (this.multiselected) {
|
||||
gBrowser.removeFromMultiSelectedTabs(this, true);
|
||||
gBrowser.removeFromMultiSelectedTabs(this, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
} else if (this != gBrowser.selectedTab) {
|
||||
gBrowser.addToMultiSelectedTabs(this, false);
|
||||
gBrowser.addToMultiSelectedTabs(this, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
gBrowser.lastMultiSelectedTab = this;
|
||||
}
|
||||
} else if (!this.selected && this.multiselected) {
|
||||
|
@ -382,9 +386,9 @@
|
|||
|
||||
// Force positional attributes to update when the
|
||||
// target (of the click) is the "active" tab.
|
||||
let updatePositionalAttr = gBrowser.selectedTab == this;
|
||||
let isLastMultiSelectChange = gBrowser.selectedTab == this;
|
||||
|
||||
gBrowser.clearMultiSelectedTabs(updatePositionalAttr);
|
||||
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange });
|
||||
}
|
||||
|
||||
if (
|
||||
|
|
|
@ -342,13 +342,13 @@
|
|||
case KeyEvent.DOM_VK_SPACE:
|
||||
if (visibleTabs[lastFocusedTabIndex].multiselected) {
|
||||
gBrowser.removeFromMultiSelectedTabs(
|
||||
visibleTabs[lastFocusedTabIndex]
|
||||
visibleTabs[lastFocusedTabIndex],
|
||||
{ isLastMultiSelectChange: false }
|
||||
);
|
||||
} else {
|
||||
gBrowser.addToMultiSelectedTabs(
|
||||
visibleTabs[lastFocusedTabIndex],
|
||||
false
|
||||
);
|
||||
gBrowser.addToMultiSelectedTabs(visibleTabs[lastFocusedTabIndex], {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1201,7 +1201,7 @@
|
|||
|
||||
this._startMultiSelectChange();
|
||||
this._multiSelectChangeSelected = true;
|
||||
this.clearMultiSelectedTabs(true);
|
||||
this.clearMultiSelectedTabs({ isLastMultiSelectChange: true });
|
||||
|
||||
if (oldBrowser != newBrowser && oldBrowser.getInPermitUnload) {
|
||||
oldBrowser.getInPermitUnload(inPermitUnload => {
|
||||
|
@ -4364,7 +4364,7 @@
|
|||
return SessionStore.duplicateTab(window, aTab, 0, aRestoreTabImmediately);
|
||||
},
|
||||
|
||||
addToMultiSelectedTabs(aTab, multiSelectMayChangeMore) {
|
||||
addToMultiSelectedTabs(aTab, { isLastMultiSelectChange = false } = {}) {
|
||||
if (aTab.multiselected) {
|
||||
return;
|
||||
}
|
||||
|
@ -4379,10 +4379,12 @@
|
|||
this._multiSelectChangeAdditions.add(aTab);
|
||||
}
|
||||
|
||||
if (!multiSelectMayChangeMore) {
|
||||
if (isLastMultiSelectChange) {
|
||||
let { selectedTab } = this;
|
||||
if (!selectedTab.multiselected) {
|
||||
this.addToMultiSelectedTabs(selectedTab, true);
|
||||
this.addToMultiSelectedTabs(selectedTab, {
|
||||
isLastMultiSelectChange: false,
|
||||
});
|
||||
}
|
||||
this.tabContainer._setPositionalAttributes();
|
||||
}
|
||||
|
@ -4406,12 +4408,17 @@
|
|||
: [indexOfTab2, indexOfTab1];
|
||||
|
||||
for (let i = lowerIndex; i <= higherIndex; i++) {
|
||||
this.addToMultiSelectedTabs(tabs[i], true);
|
||||
this.addToMultiSelectedTabs(tabs[i], {
|
||||
isLastMultiSelectChange: false,
|
||||
});
|
||||
}
|
||||
this.tabContainer._setPositionalAttributes();
|
||||
},
|
||||
|
||||
removeFromMultiSelectedTabs(aTab, isLastMultiSelectChange) {
|
||||
removeFromMultiSelectedTabs(
|
||||
aTab,
|
||||
{ isLastMultiSelectChange = false } = {}
|
||||
) {
|
||||
if (!aTab.multiselected) {
|
||||
return;
|
||||
}
|
||||
|
@ -4433,7 +4440,7 @@
|
|||
}
|
||||
},
|
||||
|
||||
clearMultiSelectedTabs(isLastMultiSelectChange) {
|
||||
clearMultiSelectedTabs({ isLastMultiSelectChange = false } = {}) {
|
||||
if (this._clearMultiSelectionLocked) {
|
||||
if (this._clearMultiSelectionLockedOnce) {
|
||||
this._clearMultiSelectionLockedOnce = false;
|
||||
|
@ -4447,7 +4454,9 @@
|
|||
}
|
||||
|
||||
for (let tab of this.selectedTabs) {
|
||||
this.removeFromMultiSelectedTabs(tab, false);
|
||||
this.removeFromMultiSelectedTabs(tab, {
|
||||
isLastMultiSelectChange: false,
|
||||
});
|
||||
}
|
||||
this._lastMultiSelectedTabRef = null;
|
||||
if (isLastMultiSelectChange) {
|
||||
|
@ -4508,7 +4517,7 @@
|
|||
*/
|
||||
avoidSingleSelectedTab() {
|
||||
if (this.multiSelectedTabsCount == 1) {
|
||||
this.clearMultiSelectedTabs();
|
||||
this.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -4535,11 +4544,13 @@
|
|||
},
|
||||
|
||||
set selectedTabs(tabs) {
|
||||
this.clearMultiSelectedTabs(false);
|
||||
this.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
|
||||
this.selectedTab = tabs[0];
|
||||
if (tabs.length > 1) {
|
||||
for (let tab of tabs) {
|
||||
this.addToMultiSelectedTabs(tab, true);
|
||||
this.addToMultiSelectedTabs(tab, {
|
||||
isLastMultiSelectChange: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
this.tabContainer._setPositionalAttributes();
|
||||
|
|
|
@ -714,7 +714,7 @@ add_task(async function sendToDevice_title() {
|
|||
// Add the other tab to the selection.
|
||||
gBrowser.addToMultiSelectedTabs(
|
||||
gBrowser.getTabForBrowser(otherBrowser),
|
||||
false
|
||||
{ isLastMultiSelectChange: true }
|
||||
);
|
||||
|
||||
// Open the panel again. Now the action's title should be "Send 2 Tabs to
|
||||
|
|
|
@ -25,6 +25,15 @@ add_task(async function testToggleSwitch() {
|
|||
"https://example.com"
|
||||
);
|
||||
await openProtectionsPanel();
|
||||
|
||||
// Check the visibility of the "Site not working?" link.
|
||||
ok(
|
||||
BrowserTestUtils.is_visible(
|
||||
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
|
||||
),
|
||||
"The 'Site not working?' link should be visible."
|
||||
);
|
||||
|
||||
ok(
|
||||
gProtectionsHandler._protectionsPopupTPSwitch.hasAttribute("enabled"),
|
||||
"TP Switch should be enabled"
|
||||
|
@ -35,6 +44,15 @@ add_task(async function testToggleSwitch() {
|
|||
);
|
||||
let browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
gProtectionsHandler._protectionsPopupTPSwitch.click();
|
||||
|
||||
// The 'Site not working?' link should be hidden after clicking the TP switch.
|
||||
ok(
|
||||
BrowserTestUtils.is_hidden(
|
||||
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
|
||||
),
|
||||
"The 'Site not working?' link should be hidden after TP switch turns to off."
|
||||
);
|
||||
|
||||
await popuphiddenPromise;
|
||||
|
||||
// We need to wait toast's popup shown and popup hidden events. It won't fire
|
||||
|
@ -60,6 +78,30 @@ add_task(async function testToggleSwitch() {
|
|||
!gProtectionsHandler._protectionsPopupTPSwitch.hasAttribute("enabled"),
|
||||
"TP Switch should be disabled"
|
||||
);
|
||||
|
||||
// The 'Site not working?' link should be hidden if the TP is off.
|
||||
ok(
|
||||
BrowserTestUtils.is_hidden(
|
||||
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
|
||||
),
|
||||
"The 'Site not working?' link should be hidden if TP is off."
|
||||
);
|
||||
|
||||
// Click the TP switch again and check the visibility of the 'Site not
|
||||
// Working?'. It should be hidden after toggling the TP switch.
|
||||
browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
gProtectionsHandler._protectionsPopupTPSwitch.click();
|
||||
|
||||
ok(
|
||||
BrowserTestUtils.is_hidden(
|
||||
gProtectionsHandler._protectionsPopupTPSwitchBreakageLink
|
||||
),
|
||||
`The 'Site not working?' link should be still hidden after toggling TP
|
||||
switch to on from off.`
|
||||
);
|
||||
|
||||
await browserLoadedPromise;
|
||||
|
||||
ContentBlockingAllowList.remove(tab.linkedBrowser);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
|
|
@ -51,7 +51,7 @@ add_task(async function withAMultiSelectedTab() {
|
|||
is(gBrowser.multiSelectedTabsCount, 2, "Two multiselected tabs");
|
||||
is(gBrowser.selectedTab, initialTab, "InitialTab is still the active tab");
|
||||
|
||||
gBrowser.clearMultiSelectedTabs(false);
|
||||
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
|
||||
BrowserTestUtils.removeTab(tab1);
|
||||
BrowserTestUtils.removeTab(tab4);
|
||||
});
|
||||
|
|
|
@ -142,63 +142,85 @@ add_task(async function clickWithPrefSet() {
|
|||
"Unmultiselection tab with removeFromMultiSelectedTabs should trigger event"
|
||||
);
|
||||
await expectEvent(async () => {
|
||||
gBrowser.removeFromMultiSelectedTabs(tab3, true);
|
||||
gBrowser.removeFromMultiSelectedTabs(tab3, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1, tab2]);
|
||||
|
||||
info("Expect no event if the tab is not multiselected");
|
||||
await expectNoEvent(async () => {
|
||||
gBrowser.removeFromMultiSelectedTabs(tab3, true);
|
||||
gBrowser.removeFromMultiSelectedTabs(tab3, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1, tab2]);
|
||||
|
||||
info(
|
||||
"Clearing multiselection with clearMultiSelectedTabs should trigger event"
|
||||
);
|
||||
await expectEvent(async () => {
|
||||
gBrowser.clearMultiSelectedTabs(tab3, true);
|
||||
gBrowser.clearMultiSelectedTabs(tab3, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1]);
|
||||
|
||||
info("Expect no event if there is no multiselection to clear");
|
||||
await expectNoEvent(async () => {
|
||||
gBrowser.clearMultiSelectedTabs(tab3, true);
|
||||
gBrowser.clearMultiSelectedTabs(tab3, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1]);
|
||||
|
||||
info(
|
||||
"Expect no event if clearMultiSelectedTabs counteracts addToMultiSelectedTabs"
|
||||
);
|
||||
await expectNoEvent(async () => {
|
||||
gBrowser.addToMultiSelectedTabs(tab3, true);
|
||||
gBrowser.clearMultiSelectedTabs(true);
|
||||
gBrowser.addToMultiSelectedTabs(tab3, {
|
||||
isLastMultiSelectChange: false,
|
||||
});
|
||||
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: true });
|
||||
}, [tab1]);
|
||||
|
||||
info(
|
||||
"Multiselecting tab with gBrowser.addToMultiSelectedTabs should trigger event"
|
||||
);
|
||||
await expectEvent(async () => {
|
||||
gBrowser.addToMultiSelectedTabs(tab2, false);
|
||||
gBrowser.addToMultiSelectedTabs(tab2, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1, tab2]);
|
||||
|
||||
info(
|
||||
"Expect no event if addToMultiSelectedTabs counteracts clearMultiSelectedTabs"
|
||||
);
|
||||
await expectNoEvent(async () => {
|
||||
gBrowser.clearMultiSelectedTabs(false);
|
||||
gBrowser.addToMultiSelectedTabs(tab2, false);
|
||||
gBrowser.clearMultiSelectedTabs({ isLastMultiSelectChange: false });
|
||||
gBrowser.addToMultiSelectedTabs(tab2, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1, tab2]);
|
||||
|
||||
info(
|
||||
"Expect no event if removeFromMultiSelectedTabs counteracts addToMultiSelectedTabs"
|
||||
);
|
||||
await expectNoEvent(async () => {
|
||||
gBrowser.addToMultiSelectedTabs(tab3, true);
|
||||
gBrowser.removeFromMultiSelectedTabs(tab3, true);
|
||||
gBrowser.addToMultiSelectedTabs(tab3, {
|
||||
isLastMultiSelectChange: false,
|
||||
});
|
||||
gBrowser.removeFromMultiSelectedTabs(tab3, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1, tab2]);
|
||||
|
||||
info(
|
||||
"Expect no event if addToMultiSelectedTabs counteracts removeFromMultiSelectedTabs"
|
||||
);
|
||||
await expectNoEvent(async () => {
|
||||
gBrowser.removeFromMultiSelectedTabs(tab2, false);
|
||||
gBrowser.addToMultiSelectedTabs(tab2, false);
|
||||
gBrowser.removeFromMultiSelectedTabs(tab2, {
|
||||
isLastMultiSelectChange: false,
|
||||
});
|
||||
gBrowser.addToMultiSelectedTabs(tab2, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}, [tab1, tab2]);
|
||||
|
||||
info("Multiselection with addRangeToMultiSelectedTabs should trigger event");
|
||||
|
|
|
@ -15,8 +15,6 @@ const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled";
|
|||
const TP_PREF = "privacy.trackingprotection.enabled";
|
||||
const CB_PREF = "network.cookie.cookieBehavior";
|
||||
|
||||
const PREF_REPORT_BREAKAGE_ENABLED =
|
||||
"browser.contentblocking.reportBreakage.enabled";
|
||||
const PREF_REPORT_BREAKAGE_URL = "browser.contentblocking.reportBreakage.url";
|
||||
|
||||
let { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
|
@ -34,7 +32,6 @@ add_task(async function setup() {
|
|||
Services.prefs.clearUserPref(CB_PREF);
|
||||
Services.prefs.clearUserPref(FP_PREF);
|
||||
Services.prefs.clearUserPref(CM_PREF);
|
||||
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_ENABLED);
|
||||
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_URL);
|
||||
|
||||
UrlClassifierTestUtils.cleanupTestTrackers();
|
||||
|
@ -64,93 +61,8 @@ add_task(async function setup() {
|
|||
});
|
||||
});
|
||||
|
||||
add_task(async function testReportBreakageVisibility() {
|
||||
let scenarios = [
|
||||
{
|
||||
url: TRACKING_PAGE,
|
||||
prefs: {
|
||||
"privacy.trackingprotection.enabled": true,
|
||||
"browser.contentblocking.reportBreakage.enabled": true,
|
||||
},
|
||||
buttonVisible: true,
|
||||
},
|
||||
{
|
||||
url: TRACKING_PAGE,
|
||||
hasException: true,
|
||||
prefs: {
|
||||
"privacy.trackingprotection.enabled": true,
|
||||
"browser.contentblocking.reportBreakage.enabled": true,
|
||||
},
|
||||
buttonVisible: true,
|
||||
},
|
||||
{
|
||||
url: TRACKING_PAGE,
|
||||
prefs: {
|
||||
"privacy.trackingprotection.enabled": true,
|
||||
"browser.contentblocking.reportBreakage.enabled": false,
|
||||
},
|
||||
buttonVisible: false,
|
||||
},
|
||||
{
|
||||
url: BENIGN_PAGE,
|
||||
prefs: {
|
||||
"privacy.trackingprotection.enabled": true,
|
||||
"browser.contentblocking.reportBreakage.enabled": true,
|
||||
},
|
||||
buttonVisible: false,
|
||||
},
|
||||
{
|
||||
url: COOKIE_PAGE,
|
||||
prefs: {
|
||||
"privacy.trackingprotection.enabled": false,
|
||||
"network.cookie.cookieBehavior":
|
||||
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
|
||||
"browser.contentblocking.reportBreakage.enabled": false,
|
||||
"browser.contentblocking.rejecttrackers.reportBreakage.enabled": true,
|
||||
},
|
||||
buttonVisible: true,
|
||||
},
|
||||
];
|
||||
|
||||
for (let scenario of scenarios) {
|
||||
for (let pref in scenario.prefs) {
|
||||
Preferences.set(pref, scenario.prefs[pref]);
|
||||
}
|
||||
|
||||
let uri = Services.io.newURI(scenario.url);
|
||||
if (scenario.hasException) {
|
||||
Services.perms.add(
|
||||
uri,
|
||||
"trackingprotection",
|
||||
Services.perms.ALLOW_ACTION
|
||||
);
|
||||
}
|
||||
|
||||
await BrowserTestUtils.withNewTab(scenario.url, async function() {
|
||||
await openProtectionsPopup();
|
||||
|
||||
let reportBreakageButton = document.getElementById(
|
||||
"protections-popup-tp-switch-breakage-link"
|
||||
);
|
||||
await TestUtils.waitForCondition(
|
||||
() =>
|
||||
BrowserTestUtils.is_visible(reportBreakageButton) ==
|
||||
scenario.buttonVisible,
|
||||
"waiting for correct visibility"
|
||||
);
|
||||
ok(true, "report breakage button has the correct visibility");
|
||||
});
|
||||
|
||||
Services.perms.remove(uri, "trackingprotection");
|
||||
for (let pref in scenario.prefs) {
|
||||
Services.prefs.clearUserPref(pref);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function testReportBreakageCancel() {
|
||||
Services.prefs.setBoolPref(TP_PREF, true);
|
||||
Services.prefs.setBoolPref(PREF_REPORT_BREAKAGE_ENABLED, true);
|
||||
|
||||
await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function() {
|
||||
await openProtectionsPopup();
|
||||
|
@ -195,7 +107,6 @@ add_task(async function testReportBreakageCancel() {
|
|||
});
|
||||
|
||||
Services.prefs.clearUserPref(TP_PREF);
|
||||
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_ENABLED);
|
||||
});
|
||||
|
||||
add_task(async function testTP() {
|
||||
|
@ -265,7 +176,6 @@ async function testReportBreakage(url, tags) {
|
|||
let path =
|
||||
i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort + "/";
|
||||
|
||||
Services.prefs.setBoolPref(PREF_REPORT_BREAKAGE_ENABLED, true);
|
||||
Services.prefs.setStringPref(PREF_REPORT_BREAKAGE_URL, path);
|
||||
|
||||
await openProtectionsPopup();
|
||||
|
@ -384,6 +294,5 @@ async function testReportBreakage(url, tags) {
|
|||
// Stop the server.
|
||||
await new Promise(r => server.stop(r));
|
||||
|
||||
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_ENABLED);
|
||||
Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_URL);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ function openProtectionsPopup() {
|
|||
let mainView = document.getElementById("protections-popup-mainView");
|
||||
let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
|
||||
// TODO: This should click on the icon once we have it.
|
||||
gProtectionsHandler.showProtectionsPopup();
|
||||
gIdentityHandler._trackingProtectionIconContainer.click();
|
||||
return viewShown;
|
||||
}
|
||||
|
||||
|
|
|
@ -829,7 +829,9 @@ this.tabs = class extends ExtensionAPI {
|
|||
}
|
||||
if (updateProperties.highlighted) {
|
||||
if (!nativeTab.selected && !nativeTab.multiselected) {
|
||||
tabbrowser.addToMultiSelectedTabs(nativeTab, false);
|
||||
tabbrowser.addToMultiSelectedTabs(nativeTab, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
// Select the highlighted tab unless active:false is provided.
|
||||
// Note that Chrome selects it even in that case.
|
||||
if (updateProperties.active !== false) {
|
||||
|
@ -838,7 +840,9 @@ this.tabs = class extends ExtensionAPI {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
tabbrowser.removeFromMultiSelectedTabs(nativeTab, true);
|
||||
tabbrowser.removeFromMultiSelectedTabs(nativeTab, {
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (updateProperties.muted !== null) {
|
||||
|
|
|
@ -156,23 +156,23 @@
|
|||
<vbox flex="1">
|
||||
<!-- by design, no tooltip for bookmarks or history -->
|
||||
<checkbox data-l10n-id="sync-engine-bookmarks"
|
||||
preference="engine.bookmarks"/>
|
||||
preference="services.sync.engine.bookmarks"/>
|
||||
<checkbox data-l10n-id="sync-engine-history"
|
||||
preference="engine.history"/>
|
||||
preference="services.sync.engine.history"/>
|
||||
<checkbox data-l10n-id="sync-engine-tabs"
|
||||
preference="engine.tabs"/>
|
||||
preference="services.sync.engine.tabs"/>
|
||||
<checkbox data-l10n-id="sync-engine-logins"
|
||||
preference="engine.passwords"/>
|
||||
preference="services.sync.engine.passwords"/>
|
||||
</vbox>
|
||||
<vbox flex="1">
|
||||
<checkbox data-l10n-id="sync-engine-addresses"
|
||||
preference="engine.addresses"/>
|
||||
preference="services.sync.engine.addresses"/>
|
||||
<checkbox data-l10n-id="sync-engine-creditcards"
|
||||
preference="engine.creditcards"/>
|
||||
preference="services.sync.engine.creditcards"/>
|
||||
<checkbox data-l10n-id="sync-engine-addons"
|
||||
preference="engine.addons"/>
|
||||
preference="services.sync.engine.addons"/>
|
||||
<checkbox data-l10n-id="sync-engine-prefs"
|
||||
preference="engine.prefs"/>
|
||||
preference="services.sync.engine.prefs"/>
|
||||
</vbox>
|
||||
<spacer/>
|
||||
</hbox>
|
||||
|
|
|
@ -31,30 +31,14 @@ const FXA_LOGIN_UNVERIFIED = 1;
|
|||
const FXA_LOGIN_FAILED = 2;
|
||||
|
||||
Preferences.addAll([
|
||||
{ id: "engine.addons", name: "services.sync.engine.addons", type: "bool" },
|
||||
{
|
||||
id: "engine.bookmarks",
|
||||
name: "services.sync.engine.bookmarks",
|
||||
type: "bool",
|
||||
},
|
||||
{ id: "engine.history", name: "services.sync.engine.history", type: "bool" },
|
||||
{ id: "engine.tabs", name: "services.sync.engine.tabs", type: "bool" },
|
||||
{ id: "engine.prefs", name: "services.sync.engine.prefs", type: "bool" },
|
||||
{
|
||||
id: "engine.passwords",
|
||||
name: "services.sync.engine.passwords",
|
||||
type: "bool",
|
||||
},
|
||||
{
|
||||
id: "engine.addresses",
|
||||
name: "services.sync.engine.addresses",
|
||||
type: "bool",
|
||||
},
|
||||
{
|
||||
id: "engine.creditcards",
|
||||
name: "services.sync.engine.creditcards",
|
||||
type: "bool",
|
||||
},
|
||||
{ id: "services.sync.engine.addons", type: "bool" },
|
||||
{ id: "services.sync.engine.bookmarks", type: "bool" },
|
||||
{ id: "services.sync.engine.history", type: "bool" },
|
||||
{ id: "services.sync.engine.tabs", type: "bool" },
|
||||
{ id: "services.sync.engine.prefs", type: "bool" },
|
||||
{ id: "services.sync.engine.passwords", type: "bool" },
|
||||
{ id: "services.sync.engine.addresses", type: "bool" },
|
||||
{ id: "services.sync.engine.creditcards", type: "bool" },
|
||||
]);
|
||||
|
||||
var gSyncPane = {
|
||||
|
@ -111,8 +95,14 @@ var gSyncPane = {
|
|||
// These 2 engines are unique in that there are prefs that make the
|
||||
// entire engine unavailable (which is distinct from "disabled").
|
||||
let enginePrefs = [
|
||||
["services.sync.engine.addresses.available", "engine.addresses"],
|
||||
["services.sync.engine.creditcards.available", "engine.creditcards"],
|
||||
[
|
||||
"services.sync.engine.addresses.available",
|
||||
"services.sync.engine.addresses",
|
||||
],
|
||||
[
|
||||
"services.sync.engine.creditcards.available",
|
||||
"services.sync.engine.creditcards",
|
||||
],
|
||||
];
|
||||
let numHidden = 0;
|
||||
for (let [availablePref, prefName] of enginePrefs) {
|
||||
|
@ -128,8 +118,12 @@ var gSyncPane = {
|
|||
// the second column. (If we only moved one, it's still unbalanced, but
|
||||
// there's an odd number of engines so that can't be avoided)
|
||||
if (numHidden == 2) {
|
||||
let history = document.querySelector('[preference="engine.history"]');
|
||||
let addons = document.querySelector('[preference="engine.addons"]');
|
||||
let history = document.querySelector(
|
||||
'[preference="services.sync.engine.history"]'
|
||||
);
|
||||
let addons = document.querySelector(
|
||||
'[preference="services.sync.engine.addons"]'
|
||||
);
|
||||
addons.parentNode.insertBefore(history, addons);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -369,7 +369,7 @@ const gPrefCache = new Map();
|
|||
function cache_preferences(win) {
|
||||
let prefs = win.Preferences.getAll();
|
||||
for (let pref of prefs) {
|
||||
gPrefCache.set(pref.name, pref.value);
|
||||
gPrefCache.set(pref.id, pref.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,8 +377,8 @@ function reset_preferences(win) {
|
|||
let prefs = win.Preferences.getAll();
|
||||
// Avoid assigning undefined, which means clearing a "user"/test pref value
|
||||
for (let pref of prefs) {
|
||||
if (gPrefCache.has(pref.name)) {
|
||||
pref.value = gPrefCache.get(pref.name);
|
||||
if (gPrefCache.has(pref.id)) {
|
||||
pref.value = gPrefCache.get(pref.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,9 @@ add_task(async function test_movePendingTabToNewWindow() {
|
|||
newWindowTabs[1].hasAttribute("pending"),
|
||||
"Second tab in new window should still be pending"
|
||||
);
|
||||
newWindow.gBrowser.clearMultiSelectedTabs(true);
|
||||
newWindow.gBrowser.clearMultiSelectedTabs({
|
||||
isLastMultiSelectChange: true,
|
||||
});
|
||||
ok(
|
||||
newWindowTabs.every(t => !t.multiselected),
|
||||
"No multiselection should be present"
|
||||
|
|
|
@ -65,6 +65,8 @@ class UrlbarController {
|
|||
|
||||
this._listeners = new Set();
|
||||
this._userSelectionBehavior = "none";
|
||||
|
||||
this.engagementEvent = new TelemetryEvent(options.eventTelemetryCategory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -339,6 +341,7 @@ class UrlbarController {
|
|||
}
|
||||
if (executeAction) {
|
||||
this.userSelectionBehavior = "arrow";
|
||||
this.engagementEvent.start(event);
|
||||
this.input.startQuery({ searchString: this.input.textValue });
|
||||
}
|
||||
}
|
||||
|
@ -581,3 +584,196 @@ class UrlbarController {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks and records telemetry events for the given category, if provided,
|
||||
* otherwise it's a no-op.
|
||||
* It is currently designed around the "urlbar" category, even if it can
|
||||
* potentially be extended to other categories.
|
||||
* To record an event, invoke start() with a starting event, then either
|
||||
* invoke record() with a final event, or discard() to drop the recording.
|
||||
* @see Events.yaml
|
||||
*/
|
||||
class TelemetryEvent {
|
||||
constructor(category) {
|
||||
this._category = category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start measuring the elapsed time from an input event.
|
||||
* After this has been invoked, any subsequent calls to start() are ignored,
|
||||
* until either record() or discard() are invoked. Thus, it is safe to keep
|
||||
* invoking this on every input event.
|
||||
* @param {event} event A DOM input event.
|
||||
* @note This should never throw, or it may break the urlbar.
|
||||
*/
|
||||
start(event) {
|
||||
// Start is invoked at any input, but we only count the first one.
|
||||
// Once an engagement or abandoment happens, we clear the _startEventInfo.
|
||||
if (!this._category || this._startEventInfo) {
|
||||
return;
|
||||
}
|
||||
if (!event) {
|
||||
Cu.reportError("Must always provide an event");
|
||||
return;
|
||||
}
|
||||
if (!["input", "drop", "mousedown", "keydown"].includes(event.type)) {
|
||||
Cu.reportError("Can't start recording from event type: " + event.type);
|
||||
return;
|
||||
}
|
||||
|
||||
// "typed" is used when the user types something, while "pasted" and
|
||||
// "dropped" are used when the text is inserted at once, by a paste or drop
|
||||
// operation. "topsites" is a bit special, it is used when the user opens
|
||||
// the empty search dropdown, that is supposed to show top sites. That
|
||||
// happens by clicking on the urlbar dropmarker, or pressing DOWN with an
|
||||
// empty input field. Even if the user later types something, we still
|
||||
// report "topsites", with a positive numChars.
|
||||
let interactionType = "topsites";
|
||||
if (event.type == "input") {
|
||||
interactionType = UrlbarUtils.isPasteEvent(event) ? "pasted" : "typed";
|
||||
} else if (event.type == "drop") {
|
||||
interactionType = "dropped";
|
||||
}
|
||||
|
||||
this._startEventInfo = {
|
||||
timeStamp: event.timeStamp || Cu.now(),
|
||||
interactionType,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an engagement telemetry event.
|
||||
* When the user picks a result from a search through the mouse or keyboard,
|
||||
* an engagement event is recorded. If instead the user abandons a search, by
|
||||
* blurring the input field, an abandonment event is recorded.
|
||||
* @param {event} [event] A DOM event.
|
||||
* @param {object} details An object describing action details.
|
||||
* @param {string} details.numChars Number of input characters.
|
||||
* @param {string} details.selIndex Index of the selected result, undefined
|
||||
* for "blur".
|
||||
* @param {string} details.selType type of the selected element, undefined
|
||||
* for "blur". One of "none", "autofill", "visit", "bookmark",
|
||||
* "history", "keyword", "search", "searchsuggestion", "switchtab",
|
||||
* "remotetab", "extension", "oneoff".
|
||||
* @note event can be null, that usually happens for paste&go or drop&go.
|
||||
* If there's no _startEventInfo this is a no-op.
|
||||
*/
|
||||
record(event, details) {
|
||||
// This should never throw, or it may break the urlbar.
|
||||
try {
|
||||
this._internalRecord(event, details);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Could not record event: " + ex);
|
||||
} finally {
|
||||
this._startEventInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
_internalRecord(event, details) {
|
||||
if (!this._category || !this._startEventInfo) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!event &&
|
||||
this._startEventInfo.interactionType != "pasted" &&
|
||||
this._startEventInfo.interactionType != "dropped"
|
||||
) {
|
||||
// If no event is passed, we must be executing either paste&go or drop&go.
|
||||
throw new Error("Event must be defined, unless input was pasted/dropped");
|
||||
}
|
||||
if (!details) {
|
||||
throw new Error("Invalid event details: " + details);
|
||||
}
|
||||
|
||||
let endTime = (event && event.timeStamp) || Cu.now();
|
||||
let startTime = this._startEventInfo.timeStamp || endTime;
|
||||
// Synthesized events in tests may have a bogus timeStamp, causing a
|
||||
// subtraction between monotonic and non-monotonic timestamps; that's why
|
||||
// abs is necessary here. It should only happen in tests, anyway.
|
||||
let elapsed = Math.abs(Math.round(endTime - startTime));
|
||||
|
||||
let action;
|
||||
if (!event) {
|
||||
action =
|
||||
this._startEventInfo.interactionType == "dropped"
|
||||
? "drop_go"
|
||||
: "paste_go";
|
||||
} else if (event.type == "blur") {
|
||||
action = "blur";
|
||||
} else {
|
||||
action = event instanceof MouseEvent ? "click" : "enter";
|
||||
}
|
||||
let method = action == "blur" ? "abandonment" : "engagement";
|
||||
let value = this._startEventInfo.interactionType;
|
||||
|
||||
// Rather than listening to the pref, just update status when we record an
|
||||
// event, if the pref changed from the last time.
|
||||
let recordingEnabled = UrlbarPrefs.get("eventTelemetry.enabled");
|
||||
if (this._eventRecordingEnabled != recordingEnabled) {
|
||||
this._eventRecordingEnabled = recordingEnabled;
|
||||
Services.telemetry.setEventRecordingEnabled("urlbar", recordingEnabled);
|
||||
}
|
||||
|
||||
let extra = {
|
||||
elapsed: elapsed.toString(),
|
||||
numChars: details.numChars.toString(),
|
||||
};
|
||||
if (method == "engagement") {
|
||||
extra.selIndex = details.selIndex.toString();
|
||||
extra.selType = details.selType;
|
||||
}
|
||||
|
||||
// We invoke recordEvent regardless, if recording is disabled this won't
|
||||
// report the events remotely, but will count it in the event_counts scalar.
|
||||
Services.telemetry.recordEvent(
|
||||
this._category,
|
||||
method,
|
||||
action,
|
||||
value,
|
||||
extra
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the currently tracked input event, that was registered via start(),
|
||||
* so it won't be recorded.
|
||||
* If there's no tracked input event, this is a no-op.
|
||||
*/
|
||||
discard() {
|
||||
this._startEventInfo = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a type from a result, to be used in the telemetry event.
|
||||
* @param {UrlbarResult} result The result to analyze.
|
||||
* @returns {string} a string type for the telemetry event.
|
||||
*/
|
||||
typeFromResult(result) {
|
||||
if (result) {
|
||||
switch (result.type) {
|
||||
case UrlbarUtils.RESULT_TYPE.TAB_SWITCH:
|
||||
return "switchtab";
|
||||
case UrlbarUtils.RESULT_TYPE.SEARCH:
|
||||
return result.payload.suggestion ? "searchsuggestion" : "search";
|
||||
case UrlbarUtils.RESULT_TYPE.URL:
|
||||
if (result.autofill) {
|
||||
return "autofill";
|
||||
}
|
||||
if (result.heuristic) {
|
||||
return "visit";
|
||||
}
|
||||
return result.source == UrlbarUtils.RESULT_SOURCE.BOOKMARKS
|
||||
? "bookmark"
|
||||
: "history";
|
||||
case UrlbarUtils.RESULT_TYPE.KEYWORD:
|
||||
return "keyword";
|
||||
case UrlbarUtils.RESULT_TYPE.OMNIBOX:
|
||||
return "extension";
|
||||
case UrlbarUtils.RESULT_TYPE.REMOTE_TAB:
|
||||
return "remotetab";
|
||||
}
|
||||
}
|
||||
return "none";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ class UrlbarInput {
|
|||
options.controller ||
|
||||
new UrlbarController({
|
||||
browserWindow: this.window,
|
||||
eventTelemetryCategory: options.eventTelemetryCategory,
|
||||
});
|
||||
this.controller.setInput(this);
|
||||
this.view = new UrlbarView(this);
|
||||
|
@ -207,6 +208,10 @@ class UrlbarInput {
|
|||
this.view.panel.addEventListener("popupshowing", this);
|
||||
this.view.panel.addEventListener("popuphidden", this);
|
||||
|
||||
// This is used to detect commands launched from the panel, to avoid
|
||||
// recording abandonment events when the command causes a blur event.
|
||||
this.view.panel.addEventListener("command", this, true);
|
||||
|
||||
this._copyCutController = new CopyCutController(this);
|
||||
this.inputField.controllers.insertControllerAt(0, this._copyCutController);
|
||||
|
||||
|
@ -363,7 +368,7 @@ class UrlbarInput {
|
|||
/**
|
||||
* Handles an event which would cause a url or text to be opened.
|
||||
*
|
||||
* @param {Event} event The event triggering the open.
|
||||
* @param {Event} [event] The event triggering the open.
|
||||
* @param {string} [openWhere] Where we expect the result to be opened.
|
||||
* @param {object} [openParams]
|
||||
* The parameters related to where the result will be opened.
|
||||
|
@ -390,6 +395,7 @@ class UrlbarInput {
|
|||
}
|
||||
// Do the command of the selected one-off if it's not an engine.
|
||||
if (selectedOneOff && !selectedOneOff.engine) {
|
||||
this.controller.engagementEvent.discard();
|
||||
selectedOneOff.doCommand();
|
||||
return;
|
||||
}
|
||||
|
@ -404,7 +410,11 @@ class UrlbarInput {
|
|||
}
|
||||
|
||||
let url;
|
||||
let selType = this.controller.engagementEvent.typeFromResult(result);
|
||||
let numChars = this.textValue.length;
|
||||
if (selectedOneOff) {
|
||||
selType = "oneoff";
|
||||
numChars = this._lastSearchString.length;
|
||||
// If there's a selected one-off button then load a search using
|
||||
// the button's engine.
|
||||
result = this._resultForCurrentValue;
|
||||
|
@ -436,6 +446,12 @@ class UrlbarInput {
|
|||
openParams.allowInheritPrincipal = false;
|
||||
url = this._maybeCanonizeURL(event, url) || url.trim();
|
||||
|
||||
this.controller.engagementEvent.record(event, {
|
||||
numChars,
|
||||
selIndex: this.view.selectedIndex,
|
||||
selType,
|
||||
});
|
||||
|
||||
try {
|
||||
new URL(url);
|
||||
} catch (ex) {
|
||||
|
@ -479,6 +495,7 @@ class UrlbarInput {
|
|||
allowInheritPrincipal: false,
|
||||
};
|
||||
|
||||
let selIndex = this.view.selectedIndex;
|
||||
if (!result.payload.isKeywordOffer) {
|
||||
this.view.close();
|
||||
}
|
||||
|
@ -486,6 +503,11 @@ class UrlbarInput {
|
|||
this.controller.recordSelectedResult(event, result);
|
||||
|
||||
if (isCanonized) {
|
||||
this.controller.engagementEvent.record(event, {
|
||||
numChars: this._lastSearchString.length,
|
||||
selIndex,
|
||||
selType: "canonized",
|
||||
});
|
||||
this._loadURL(this.value, where, openParams);
|
||||
return;
|
||||
}
|
||||
|
@ -514,14 +536,18 @@ class UrlbarInput {
|
|||
),
|
||||
};
|
||||
|
||||
if (
|
||||
this.window.switchToTabHavingURI(
|
||||
Services.io.newURI(url),
|
||||
false,
|
||||
loadOpts
|
||||
) &&
|
||||
prevTab.isEmpty
|
||||
) {
|
||||
this.controller.engagementEvent.record(event, {
|
||||
numChars: this._lastSearchString.length,
|
||||
selIndex,
|
||||
selType: "tabswitch",
|
||||
});
|
||||
|
||||
let switched = this.window.switchToTabHavingURI(
|
||||
Services.io.newURI(url),
|
||||
false,
|
||||
loadOpts
|
||||
);
|
||||
if (switched && prevTab.isEmpty) {
|
||||
this.window.gBrowser.removeTab(prevTab);
|
||||
}
|
||||
return;
|
||||
|
@ -533,6 +559,12 @@ class UrlbarInput {
|
|||
// the user can directly start typing a query string at that point.
|
||||
this.selectionStart = this.selectionEnd = this.value.length;
|
||||
|
||||
this.controller.engagementEvent.record(event, {
|
||||
numChars: this._lastSearchString.length,
|
||||
selIndex,
|
||||
selType: "keywordoffer",
|
||||
});
|
||||
|
||||
// Picking a keyword offer just fills it in the input and doesn't
|
||||
// visit anything. The user can then type a search string. Also
|
||||
// start a new search so that the offer appears in the view by itself
|
||||
|
@ -549,6 +581,12 @@ class UrlbarInput {
|
|||
break;
|
||||
}
|
||||
case UrlbarUtils.RESULT_TYPE.OMNIBOX: {
|
||||
this.controller.engagementEvent.record(event, {
|
||||
numChars: this._lastSearchString.length,
|
||||
selIndex,
|
||||
selType: "extension",
|
||||
});
|
||||
|
||||
// The urlbar needs to revert to the loaded url when a command is
|
||||
// handled by the extension.
|
||||
this.handleRevert();
|
||||
|
@ -578,6 +616,12 @@ class UrlbarInput {
|
|||
);
|
||||
}
|
||||
|
||||
this.controller.engagementEvent.record(event, {
|
||||
numChars: this._lastSearchString.length,
|
||||
selIndex,
|
||||
selType: this.controller.engagementEvent.typeFromResult(result),
|
||||
});
|
||||
|
||||
this._loadURL(url, where, openParams, {
|
||||
source: result.source,
|
||||
type: result.type,
|
||||
|
@ -1393,7 +1437,23 @@ class UrlbarInput {
|
|||
|
||||
// Event handlers below.
|
||||
|
||||
_on_command(event) {
|
||||
// Something is executing a command, likely causing a focus change. This
|
||||
// should not be recorded as an abandonment.
|
||||
this.controller.engagementEvent.discard();
|
||||
}
|
||||
|
||||
_on_blur(event) {
|
||||
// We cannot count every blur events after a missed engagement as abandoment
|
||||
// because the user may have clicked on some view element that executes
|
||||
// a command causing a focus change. For example opening preferences from
|
||||
// the oneoff settings button, or from a contextual tip button.
|
||||
// For now we detect that case by discarding the event on command, but we
|
||||
// may want to figure out a more robust way to detect abandonment.
|
||||
this.controller.engagementEvent.record(event, {
|
||||
numChars: this._lastSearchString.length,
|
||||
});
|
||||
|
||||
this.removeAttribute("focused");
|
||||
this.formatValue();
|
||||
this._resetSearchState();
|
||||
|
@ -1469,6 +1529,7 @@ class UrlbarInput {
|
|||
this.editor.selectAll();
|
||||
event.preventDefault();
|
||||
} else if (this.openViewOnFocus && !this.view.isOpen) {
|
||||
this.controller.engagementEvent.start(event);
|
||||
this.startQuery({
|
||||
allowAutofill: false,
|
||||
});
|
||||
|
@ -1481,6 +1542,7 @@ class UrlbarInput {
|
|||
this.view.close();
|
||||
} else {
|
||||
this.focus();
|
||||
this.controller.engagementEvent.start(event);
|
||||
this.startQuery({
|
||||
allowAutofill: false,
|
||||
});
|
||||
|
@ -1534,12 +1596,13 @@ class UrlbarInput {
|
|||
return;
|
||||
}
|
||||
|
||||
this.controller.engagementEvent.start(event);
|
||||
|
||||
// Autofill only when text is inserted (i.e., event.data is not empty) and
|
||||
// it's not due to pasting.
|
||||
let allowAutofill =
|
||||
!!event.data &&
|
||||
!event.inputType.startsWith("insertFromPaste") &&
|
||||
event.inputType != "insertFromYank" &&
|
||||
!UrlbarUtils.isPasteEvent(event) &&
|
||||
this._maybeAutofillOnInput(value);
|
||||
|
||||
this.startQuery({
|
||||
|
@ -1754,6 +1817,9 @@ class UrlbarInput {
|
|||
this.value = droppedURL;
|
||||
this.window.SetPageProxyState("invalid");
|
||||
this.focus();
|
||||
// To simplify tracking of events, register an initial event for event
|
||||
// telemetry, to replace the missing input event.
|
||||
this.controller.engagementEvent.start(event);
|
||||
this.handleCommand(null, undefined, undefined, principal);
|
||||
// For safety reasons, in the drop case we don't want to immediately show
|
||||
// the the dropped value, instead we want to keep showing the current page
|
||||
|
|
|
@ -66,6 +66,9 @@ const PREF_URLBAR_DEFAULTS = new Map([
|
|||
// clipboard on systems that support it.
|
||||
["doubleClickSelectsAll", false],
|
||||
|
||||
// Whether telemetry events should be recorded.
|
||||
["eventTelemetry.enabled", false],
|
||||
|
||||
// When true, `javascript:` URLs are not included in search results.
|
||||
["filter.javascript", true],
|
||||
|
||||
|
@ -102,6 +105,7 @@ const PREF_URLBAR_DEFAULTS = new Map([
|
|||
// should be opened in new tabs by default.
|
||||
["openintab", false],
|
||||
|
||||
// Whether to open the urlbar view when the input field is focused by the user.
|
||||
["openViewOnFocus", false],
|
||||
|
||||
// Whether the quantum bar is enabled.
|
||||
|
|
|
@ -434,6 +434,19 @@ var UrlbarUtils = {
|
|||
);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether the passed-in input event is paste event.
|
||||
* @param {DOMEvent} event an input DOM event.
|
||||
* @returns {boolean} Whether the event is a paste event.
|
||||
*/
|
||||
isPasteEvent(event) {
|
||||
return (
|
||||
event.inputType &&
|
||||
(event.inputType.startsWith("insertFromPaste") ||
|
||||
event.inputType == "insertFromYank")
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(UrlbarUtils.ICON, "DEFAULT", () => {
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
[DEFAULT]
|
||||
prefs=browser.urlbar.quantumbar=true
|
||||
tags=quantumbar
|
||||
support-files =
|
||||
dummy_page.html
|
||||
head.js
|
||||
|
@ -119,6 +117,10 @@ support-files =
|
|||
[browser_urlbar_content_opener.js]
|
||||
[browser_urlbar_display_selectedAction_Extensions.js]
|
||||
[browser_urlbar_empty_search.js]
|
||||
[browser_urlbar_event_telemetry.js]
|
||||
support-files =
|
||||
searchSuggestionEngine.xml
|
||||
searchSuggestionEngine.sjs
|
||||
[browser_urlbar_locationchange_urlbar_edit_dos.js]
|
||||
support-files =
|
||||
file_urlbar_edit_dos.html
|
||||
|
|
|
@ -206,7 +206,7 @@ add_task(async function test_keyword_with_question_mark() {
|
|||
UrlbarUtils.RESULT_TYPE.SEARCH,
|
||||
"Result should be a search"
|
||||
);
|
||||
Assert.equal(result.searchParams.query, "question", "Check search query");
|
||||
Assert.equal(result.searchParams.query, "question?", "Check search query");
|
||||
|
||||
result = await promise_first_result("question? something");
|
||||
Assert.equal(
|
||||
|
|
|
@ -0,0 +1,579 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
function copyToClipboard(str) {
|
||||
return new Promise((resolve, reject) => {
|
||||
waitForClipboard(
|
||||
str,
|
||||
() => {
|
||||
Cc["@mozilla.org/widget/clipboardhelper;1"]
|
||||
.getService(Ci.nsIClipboardHelper)
|
||||
.copyString(str);
|
||||
},
|
||||
resolve,
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Each test is a function that executes an urlbar action and returns the
|
||||
// expected event object, or null if no event is expected.
|
||||
const tests = [
|
||||
/*
|
||||
* Engagement tests.
|
||||
*/
|
||||
async function() {
|
||||
info("Type something, press Enter.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("x", window, true);
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "1",
|
||||
selIndex: "0",
|
||||
selType: "search",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Paste something, press Enter.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await copyToClipboard("test");
|
||||
document.commandDispatcher
|
||||
.getControllerForCommand("cmd_paste")
|
||||
.doCommand("cmd_paste");
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "pasted",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "4",
|
||||
selIndex: "0",
|
||||
selType: "search",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type something, click one-off.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("moz", window, true);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true });
|
||||
UrlbarTestUtils.getOneOffSearchButtons(window).selectedButton.click();
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "click",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "3",
|
||||
selIndex: "0",
|
||||
selType: "oneoff",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type something, select one-off, Enter.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("moz", window, true);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true });
|
||||
Assert.ok(UrlbarTestUtils.getOneOffSearchButtons(window).selectedButton);
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "3",
|
||||
selIndex: "0",
|
||||
selType: "oneoff",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type something, ESC, type something else, press Enter.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
EventUtils.synthesizeKey("x");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE");
|
||||
EventUtils.synthesizeKey("y");
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "1",
|
||||
selIndex: "0",
|
||||
selType: "search",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type a keyword, Enter.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("kw test", window, true);
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "7",
|
||||
selIndex: "0",
|
||||
selType: "keyword",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type something and canonize");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("example", window, true);
|
||||
EventUtils.synthesizeKey("VK_RETURN", { ctrlKey: true });
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "7",
|
||||
selIndex: "0",
|
||||
selType: "canonized",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type something, click on bookmark entry.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("exa", window, true);
|
||||
while (gURLBar.value != "http://example.com/?q=%s") {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
}
|
||||
let element = UrlbarTestUtils.getSelectedElement(window);
|
||||
EventUtils.synthesizeMouseAtCenter(element, {});
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "click",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "3",
|
||||
selIndex: val => parseInt(val) > 0,
|
||||
selType: "bookmark",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type an autofilled string, Enter.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("exa", window, true);
|
||||
// Check it's autofilled.
|
||||
Assert.equal(gURLBar.selectionStart, 3);
|
||||
Assert.equal(gURLBar.selectionEnd, 12);
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "3",
|
||||
selIndex: "0",
|
||||
selType: "autofill",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type something, select bookmark entry, Enter.");
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await promiseAutocompleteResultPopup("exa", window, true);
|
||||
while (gURLBar.value != "http://example.com/?q=%s") {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
}
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "3",
|
||||
selIndex: val => parseInt(val) > 0,
|
||||
selType: "bookmark",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type @, Enter on a keywordoffer");
|
||||
gURLBar.select();
|
||||
await promiseAutocompleteResultPopup("@", window, true);
|
||||
while (gURLBar.value != "@test ") {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
}
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await UrlbarTestUtils.promiseSearchComplete(window);
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "1",
|
||||
selIndex: val => parseInt(val) > 0,
|
||||
selType: "keywordoffer",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Drop something.");
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
EventUtils.synthesizeDrop(
|
||||
document.getElementById("home-button"),
|
||||
gURLBar.inputField,
|
||||
[[{ type: "text/plain", data: "www.example.com" }]],
|
||||
"copy",
|
||||
window
|
||||
);
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "drop_go",
|
||||
value: "dropped",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "15",
|
||||
selIndex: "-1",
|
||||
selType: "none",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Paste & Go something.");
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await copyToClipboard("www.example.com");
|
||||
let inputBox = gURLBar.querySelector("moz-input-box");
|
||||
let cxmenu = inputBox.menupopup;
|
||||
let cxmenuPromise = BrowserTestUtils.waitForEvent(cxmenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
});
|
||||
await cxmenuPromise;
|
||||
let menuitem = inputBox.getMenuItem("paste-and-go");
|
||||
EventUtils.synthesizeMouseAtCenter(menuitem, {});
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "paste_go",
|
||||
value: "pasted",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "15",
|
||||
selIndex: "-1",
|
||||
selType: "none",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Open the panel with DOWN, select with DOWN, Enter.");
|
||||
gURLBar.value = "";
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await UrlbarTestUtils.promisePopupOpen(window, () => {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
});
|
||||
await UrlbarTestUtils.promiseSearchComplete(window);
|
||||
while (gURLBar.value != "http://mochi.test:8888/") {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
}
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "topsites",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "0",
|
||||
selType: "history",
|
||||
selIndex: val => parseInt(val) >= 0,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Open the panel with DOWN, click on entry.");
|
||||
gURLBar.value = "";
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await UrlbarTestUtils.promisePopupOpen(window, () => {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
});
|
||||
while (gURLBar.value != "http://mochi.test:8888/") {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
}
|
||||
let element = UrlbarTestUtils.getSelectedElement(window);
|
||||
EventUtils.synthesizeMouseAtCenter(element, {});
|
||||
await promise;
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "click",
|
||||
value: "topsites",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "0",
|
||||
selType: "history",
|
||||
selIndex: "0",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Open the panel with dropmarker, type something, Enter.");
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:blank" },
|
||||
async browser => {
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
await UrlbarTestUtils.promisePopupOpen(window, () => {
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.dropmarker, {}, window);
|
||||
});
|
||||
await promiseAutocompleteResultPopup("x", window, true);
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
}
|
||||
);
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "engagement",
|
||||
object: "enter",
|
||||
value: "topsites",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "1",
|
||||
selType: "search",
|
||||
selIndex: "0",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/*
|
||||
* Abandonment tests.
|
||||
*/
|
||||
|
||||
async function() {
|
||||
info("Type something, blur.");
|
||||
gURLBar.select();
|
||||
EventUtils.synthesizeKey("x");
|
||||
gURLBar.blur();
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "abandonment",
|
||||
object: "blur",
|
||||
value: "typed",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "1",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Open the panel with DOWN, don't type, blur it.");
|
||||
gURLBar.value = "";
|
||||
gURLBar.select();
|
||||
await UrlbarTestUtils.promisePopupOpen(window, () => {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
});
|
||||
gURLBar.blur();
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "abandonment",
|
||||
object: "blur",
|
||||
value: "topsites",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "0",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Open the panel with dropmarker, type something, blur it.");
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:blank" },
|
||||
async browser => {
|
||||
gURLBar.select();
|
||||
await UrlbarTestUtils.promisePopupOpen(window, () => {
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar.dropmarker, {}, window);
|
||||
});
|
||||
EventUtils.synthesizeKey("x");
|
||||
gURLBar.blur();
|
||||
}
|
||||
);
|
||||
return {
|
||||
category: "urlbar",
|
||||
method: "abandonment",
|
||||
object: "blur",
|
||||
value: "topsites",
|
||||
extra: {
|
||||
elapsed: val => parseInt(val) > 0,
|
||||
numChars: "1",
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
/*
|
||||
* No event tests.
|
||||
*/
|
||||
|
||||
async function() {
|
||||
info("Type something, click on search settings.");
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:blank" },
|
||||
async browser => {
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(browser);
|
||||
await promiseAutocompleteResultPopup("x", window, true);
|
||||
UrlbarTestUtils.getOneOffSearchButtons(window).settingsButton.click();
|
||||
await promise;
|
||||
}
|
||||
);
|
||||
return null;
|
||||
},
|
||||
|
||||
async function() {
|
||||
info("Type something, Up, Enter on search settings.");
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{ gBrowser, url: "about:blank" },
|
||||
async browser => {
|
||||
gURLBar.select();
|
||||
let promise = BrowserTestUtils.browserLoaded(browser);
|
||||
await promiseAutocompleteResultPopup("x", window, true);
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp");
|
||||
Assert.ok(
|
||||
UrlbarTestUtils.getOneOffSearchButtons(
|
||||
window
|
||||
).selectedButton.classList.contains("search-setting-button-compact"),
|
||||
"Should have selected the settings button"
|
||||
);
|
||||
EventUtils.synthesizeKey("VK_RETURN");
|
||||
await promise;
|
||||
}
|
||||
);
|
||||
return null;
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.urlbar.eventTelemetry.enabled", true],
|
||||
["browser.urlbar.suggest.searches", true],
|
||||
],
|
||||
});
|
||||
// Create a new search engine and mark it as default
|
||||
let engine = await SearchTestUtils.promiseNewSearchEngine(
|
||||
getRootDirectory(gTestPath) + "searchSuggestionEngine.xml"
|
||||
);
|
||||
let oldDefaultEngine = await Services.search.getDefault();
|
||||
await Services.search.setDefault(engine);
|
||||
await Services.search.moveEngine(engine, 0);
|
||||
|
||||
let aliasEngine = await Services.search.addEngineWithDetails("Test", {
|
||||
alias: "@test",
|
||||
template: "http://example.com/?search={searchTerms}",
|
||||
});
|
||||
|
||||
// Add a bookmark and a keyword.
|
||||
let bm = await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: "http://example.com/?q=%s",
|
||||
title: "test",
|
||||
});
|
||||
await PlacesUtils.keywords.insert({
|
||||
keyword: "kw",
|
||||
url: "http://example.com/?q=%s",
|
||||
});
|
||||
await PlacesTestUtils.addVisits([
|
||||
{
|
||||
uri: "http://mochi.test:8888/",
|
||||
transition: PlacesUtils.history.TRANSITIONS.TYPED,
|
||||
},
|
||||
]);
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
await Services.search.setDefault(oldDefaultEngine);
|
||||
await Services.search.removeEngine(aliasEngine);
|
||||
await PlacesUtils.keywords.remove("kw");
|
||||
await PlacesUtils.bookmarks.remove(bm);
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
||||
|
||||
// This is not necessary after each loop, because assertEvents does it.
|
||||
Services.telemetry.clearEvents();
|
||||
|
||||
for (let testFn of tests) {
|
||||
let expectedEvents = [await testFn()].filter(e => !!e);
|
||||
// Always blur to ensure it's not accounted as an additional abandonment.
|
||||
gURLBar.blur();
|
||||
TelemetryTestUtils.assertEvents(expectedEvents);
|
||||
}
|
||||
});
|
|
@ -620,13 +620,6 @@ description#identity-popup-content-verifier,
|
|||
box-shadow: var(--focus-ring-box-shadow);
|
||||
}
|
||||
|
||||
/* Hide the "report breakage" button if we have not detected any trackers
|
||||
* (except if the user added an exception, in which case they might still
|
||||
* (especially!) want to report the breakage). */
|
||||
#protections-popup:not([blocking]):not([hasException]) #protections-popup-tp-switch-breakage-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* PERMISSIONS */
|
||||
|
||||
#identity-popup-permissions-content {
|
||||
|
@ -803,6 +796,13 @@ description#identity-popup-content-verifier,
|
|||
position: relative;
|
||||
}
|
||||
|
||||
/* This is needed in order to show a correct height if the 'Site not working?'
|
||||
link is not displaying. */
|
||||
#protections-popup-tp-switch-section[short] > .protections-popup-tp-switch-label-box,
|
||||
#protections-popup-tp-switch-section[short] > .protections-popup-tp-switch-box {
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.protections-popup-tp-switch-on-header,
|
||||
.protections-popup-tp-switch-off-header {
|
||||
font-weight: 600;
|
||||
|
|
|
@ -49,6 +49,9 @@ async function testReloadAboutDevToolsToolbox(toolId) {
|
|||
const toolbox = getToolbox(devtoolsWindow);
|
||||
await toolbox.selectTool(toolId);
|
||||
|
||||
info("Wait for requests to settle before reloading");
|
||||
await toolbox.target.client.waitForRequestsToSettle();
|
||||
|
||||
info("Reload about:devtools-toolbox page");
|
||||
devtoolsBrowser.reload();
|
||||
await gDevTools.once("toolbox-ready");
|
||||
|
|
|
@ -24,6 +24,10 @@ Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-mocks.js", this);
|
|||
|
||||
// Make sure the ADB addon is removed and ADB is stopped when the test ends.
|
||||
registerCleanupFunction(async function() {
|
||||
// Reset the selected tool in case we opened about:devtools-toolbox to
|
||||
// avoid side effects between tests.
|
||||
Services.prefs.clearUserPref("devtools.toolbox.selectedTool");
|
||||
|
||||
try {
|
||||
const { adbAddon } = require("devtools/shared/adb/adb-addon");
|
||||
await adbAddon.uninstall();
|
||||
|
@ -118,6 +122,12 @@ async function closeAboutDevtoolsToolbox(
|
|||
devtoolsTab,
|
||||
win
|
||||
) {
|
||||
// Wait for all requests to settle on the opened about:devtools toolbox.
|
||||
const devtoolsBrowser = devtoolsTab.linkedBrowser;
|
||||
const devtoolsWindow = devtoolsBrowser.contentWindow;
|
||||
const toolbox = getToolbox(devtoolsWindow);
|
||||
await toolbox.target.client.waitForRequestsToSettle();
|
||||
|
||||
info("Close about:devtools-toolbox page");
|
||||
const onToolboxDestroyed = gDevTools.once("toolbox-destroyed");
|
||||
|
||||
|
|
|
@ -1,13 +1,63 @@
|
|||
|
||||
.book .book-summary ul.summary li {
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.book .book-body .page-wrapper .page-inner section.normal p,
|
||||
.book .book-body .page-wrapper .page-inner section.normal pre {
|
||||
margin: .85em 0;
|
||||
margin: 0.85em 0;
|
||||
}
|
||||
|
||||
.book .book-body .page-wrapper .page-inner section.normal pre {
|
||||
line-height: 1.25em;
|
||||
}
|
||||
line-height: 1.25em;
|
||||
}
|
||||
|
||||
/* Resets default style on the main page container */
|
||||
.page-inner {
|
||||
max-width: unset !important;
|
||||
margin: 0 10px !important;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sections are displayed on the grid. By default everything goes into the
|
||||
* second column, and we use left and right columns to expand content when needed,
|
||||
* for example for images, diagrams, code example, …
|
||||
*/
|
||||
.normal.markdown-section {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr minmax(min-content, 800px) 1fr;
|
||||
margin: 0 50px;
|
||||
}
|
||||
|
||||
.normal.markdown-section > * {
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
|
||||
/* Hero element take the whole row */
|
||||
.normal.markdown-section > .hero {
|
||||
grid-column: 1 / -1;
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.diagram,
|
||||
pre.diagram {
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
background-color: #f9f9fa;
|
||||
border: 3px solid #d7d7db;
|
||||
margin: 0 auto !important;
|
||||
padding: 2em;
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
max-width: 800px;
|
||||
font-size: 0.85em !important;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
margin: 10px auto 0;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
|
Двоичные данные
devtools/docs/tools/console-panel-architecture.png
Двоичные данные
devtools/docs/tools/console-panel-architecture.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 38 KiB |
|
@ -7,28 +7,140 @@ The Console panel is responsible for rendering all logs coming from the current
|
|||
Internal architecture of the Console panel (the client side) is described
|
||||
on the following diagram.
|
||||
|
||||
![Console panel architecture](console-panel-architecture.png)
|
||||
|
||||
## Entry points
|
||||
|
||||
There are two ways to load the Console panel. It can either run on top
|
||||
of the Launchpad (inside a browser tab) or within the DevTools Toolbox.
|
||||
|
||||
There are different entry points for these scenarios:
|
||||
* Launchpad - uses `index.js` file as the entry point
|
||||
* Toolbox - uses `panel.js` file as the entry point
|
||||
<figure class="hero">
|
||||
<pre class="diagram">
|
||||
┌───────────────────────────────────┐ ┌───────────────────────────────────┐
|
||||
│ DevTools │ │ WebConsolePanel │
|
||||
│ [client/framework/devtools.js] │ ┌ ─ ─ ─ ─ ─ ─│ [panel.js] │
|
||||
└───────────────────────────────────┘ └───────────────────────────────────┘
|
||||
│ │ │
|
||||
│
|
||||
openBrowserConsole() openWebConsole() │
|
||||
│
|
||||
│ │ │
|
||||
▼ │
|
||||
│ ┌───────────────────────────────────┐ │
|
||||
│ HUDService │ │
|
||||
└ ─ ─ ─ ─ ─ ▶│ [hudservice.js] │ {hud}
|
||||
└───────────────────────────────────┘ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
┌─────────────{consoles}────────────┐ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
▼ n ▼ n ▼ 1
|
||||
┌────────────────────────┐ ┌────────────────────────┐
|
||||
│ BrowserConsole │ │ WebConsole │
|
||||
│ [browser-console.js] │─ ─ ─ ─ ─extends─ ─ ─ ▶│ [webconsole.js] │
|
||||
└────────────────────────┘ └────────────────────────┘
|
||||
│
|
||||
{ui}
|
||||
│
|
||||
▼ 1
|
||||
┌────────────────────────┐ ┌─────────────────────────────────┐
|
||||
│ WebConsoleUI │ 1│ WebConsoleConnectionProxy │
|
||||
│ [webconsole-ui.js] │─────{proxy}────────▶│[webconsole-connection-proxy.js] │
|
||||
└────────────────────────┘ └─────────────────────────────────┘
|
||||
│ │
|
||||
│
|
||||
{wrapper} │
|
||||
│
|
||||
│ │
|
||||
▼ 1
|
||||
┌────────────────────────┐ │
|
||||
│ WebConsoleWrapper │
|
||||
│[webconsole-wrapper.js] │◀ ─ ─ ─ ─ ─ ─ calls methods from─ ─ ─ ┘
|
||||
└────────────────────────┘
|
||||
│
|
||||
<renders>
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ App │
|
||||
└────────────────────────┘
|
||||
</pre>
|
||||
<figcaption>Elements between curly bracket on arrows represent the property name of the reference (for example, the WebConsolePanel as a `hud` property that is a reference to the WebConsole instance)</figcaption>
|
||||
</figure>
|
||||
|
||||
## Components
|
||||
|
||||
The Console panel UI is built on top of [React](../frontend/react.md). It defines set of React components in `components` directory
|
||||
The React architecture is described on the following diagram.
|
||||
|
||||
<figure class="hero">
|
||||
<pre class="diagram">
|
||||
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
WebConsole React components │
|
||||
│ [/components] ┌────────────────────────┐
|
||||
│ App │ │
|
||||
│ └────────────────────────┘
|
||||
│ │
|
||||
│ │
|
||||
┌───────────────────┬──────────────────────┬───────────────────┬───────────┴─────────┬───────────────────────┬────────────────────┬─────────────────┐ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │ ┌────────────────────────────────────────┐
|
||||
│ ┌──────────┐ ┌────────────────┐ ┌────────────────┐ ┌───────────┐ ┌────────────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────┐ │ Editor │
|
||||
│ SideBar │ │NotificationBox │ │ ConfirmDialog │ │ FilterBar │ │ ReverseSearchInput │ │ConsoleOutput │ │EditorToolbar │ │ JSTerm │──{editor}──▶│ (CodeMirror) │
|
||||
│ └──────────┘ └────────────────┘ │ (portal) │ └───────────┘ └────────────────────┘ └──────────────┘ └──────────────┘ └─────────┘ │ [client/shared/sourceeditor/editor.js] │
|
||||
│ └────────────────┘ │ │ │ └────────────────────────────────────────┘
|
||||
│ │ ┌─────────┴─────────────┐ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ ▼ ▼
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ │ FilterButton │ │ FilterCheckbox │ │ MessageContainer │
|
||||
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ │ ┌──────────────────┐
|
||||
│ │ Message │ │
|
||||
│ │ └──────────────────┘
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ┌─────────────────────┬─────────────────────┬─────────────────────┬───────┴─────────────┬─────────────────────┬─────────────┼─────────────────────┬───────────────────────────────────────────┐
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ ▼ ▼ ▼ ▼ ▼ ▼ │ ▼ ▼
|
||||
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌─────────────────────────────────────┐ ┌────────────────────────────────────────┐
|
||||
│ │ MessageIndent │ │ MessageIcon │ │ CollapseButton │ │ GripMessageBody │ │ ConsoleTable │ │ MessageRepeat │ │ │ Frame │ │ SmartTrace │
|
||||
│ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ [client/shared/components/Frame.js] │ │[client/shared/components/SmartTrace.js]│
|
||||
│ │ │ │ └─────────────────────────────────────┘ └────────────────────────────────────────┘
|
||||
└ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
│ │ │
|
||||
│ ├─────────────────────┘
|
||||
│ │
|
||||
│ ▼
|
||||
│ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
│ Reps ┌──────────────────────┐ │
|
||||
│ │ [client/shared/components/reps/reps.js] │ ObjectInspector │
|
||||
│ └──────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ │ ┌──────────────────────┐
|
||||
│ │ ObjectInspectorItem │ │
|
||||
│ │ └──────────────────────┘
|
||||
└───────────────────────────────────────────────────────────────▶ │ │
|
||||
│ ▼
|
||||
┌──────────────────────┐ │
|
||||
│ ┌─▶│ Rep │
|
||||
│ └──────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ └──────────────┘
|
||||
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
|
||||
</pre>
|
||||
</figure>
|
||||
|
||||
## Actions
|
||||
|
||||
The Console panel implements a set of actions divided into several groups.
|
||||
|
||||
* **Filters** Actions related to content filtering.
|
||||
* **Messages** Actions related to list of messages rendered in the panel.
|
||||
* **UI** Actions related to the UI state.
|
||||
- **Filters** Actions related to content filtering.
|
||||
- **Messages** Actions related to list of messages rendered in the panel.
|
||||
- **UI** Actions related to the UI state.
|
||||
|
||||
### State
|
||||
|
||||
|
@ -36,7 +148,7 @@ The Console panel manages the app state via [Redux](../frontend/redux.md).
|
|||
|
||||
There are following reducers defining the panel state:
|
||||
|
||||
* `reducers/filters.js` state for panel filters. These filters can be set from within the panel's toolbar (e.g. error, info, log, css, etc.)
|
||||
* `reducers/messages.js` state of all messages rendered within the panel.
|
||||
* `reducers/prefs.js` Preferences associated with the Console panel (e.g. logLimit)
|
||||
* `reducers/ui.js` UI related state (sometimes also called a presentation state). This state contains state of the filter bar (visible/hidden), state of the time-stamp (visible/hidden), etc.
|
||||
- `reducers/filters.js` state for panel filters. These filters can be set from within the panel's toolbar (e.g. error, info, log, css, etc.)
|
||||
- `reducers/messages.js` state of all messages rendered within the panel.
|
||||
- `reducers/prefs.js` Preferences associated with the Console panel (e.g. logLimit)
|
||||
- `reducers/ui.js` UI related state (sometimes also called a presentation state). This state contains state of the filter bar (visible/hidden), state of the time-stamp (visible/hidden), etc.
|
||||
|
|
|
@ -3366,13 +3366,9 @@ nsresult nsContentUtils::LoadImage(
|
|||
|
||||
// XXXbz using "documentURI" for the initialDocumentURI is not quite
|
||||
// right, but the best we can do here...
|
||||
nsCOMPtr<nsIURI> referrer = aReferrerInfo->GetOriginalReferrer();
|
||||
auto referrerPolicy = static_cast<mozilla::net::ReferrerPolicy>(
|
||||
aReferrerInfo->GetReferrerPolicy());
|
||||
return imgLoader->LoadImage(aURI, /* uri to load */
|
||||
documentURI, /* initialDocumentURI */
|
||||
referrer, /* referrerInfo */
|
||||
referrerPolicy, /* referrer policy */
|
||||
aReferrerInfo, /* referrerInfo */
|
||||
aLoadingPrincipal, /* loading principal */
|
||||
aRequestContextID, /* request context ID */
|
||||
loadGroup, /* loadgroup */
|
||||
|
|
|
@ -40,6 +40,7 @@ skip-if = android_version == '18' # Android, bug 1147974
|
|||
[test_input_datetime_focus_blur_events.html]
|
||||
[test_input_datetime_focus_state.html]
|
||||
[test_input_datetime_hidden.html]
|
||||
[test_input_datetime_reset_button.html]
|
||||
[test_input_datetime_reset_default_value_input_change_event.html]
|
||||
[test_input_datetime_tabindex.html]
|
||||
[test_input_defaultValue.html]
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1479708
|
||||
-->
|
||||
<head>
|
||||
<title>Test required date/time input can't be reset</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1479708">Mozilla Bug 1479708</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<input type="date" id="id_date" value="2017-06-08">
|
||||
<input type="time" id="id_time" value="10:30">
|
||||
<input type="date" id="id_date_required" value="2017-06-08" required>
|
||||
<input type="time" id="id_time_required" value="10:30" required>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody">
|
||||
|
||||
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
|
||||
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
if (isDesktop) {
|
||||
// Initial load.
|
||||
assert_reset_visible("id_date");
|
||||
assert_reset_visible("id_time");
|
||||
assert_reset_hidden("id_date_required");
|
||||
assert_reset_hidden("id_time_required");
|
||||
|
||||
// Dynamic toggling.
|
||||
test_make_required("id_date");
|
||||
test_make_required("id_time");
|
||||
test_make_optional("id_date_required");
|
||||
test_make_optional("id_time_required");
|
||||
} else {
|
||||
ok(true, "Mobile and tablet don’t show reset button");
|
||||
}
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function test_make_required(id) {
|
||||
const input = document.getElementById(id);
|
||||
is(input.required, false, `Precondition: input #${id} is optional`);
|
||||
|
||||
input.required = true;
|
||||
assert_reset_hidden(id);
|
||||
}
|
||||
|
||||
function test_make_optional(id) {
|
||||
const input = document.getElementById(id);
|
||||
is(input.required, true, `Precondition: input #${id} is required`);
|
||||
|
||||
input.required = false;
|
||||
assert_reset_visible(id);
|
||||
}
|
||||
|
||||
function assert_reset_visible(id) {
|
||||
const resetButton = get_reset_button(id);
|
||||
is(resetButton.style.visibility, "", `Reset button is visible on #${id}`);
|
||||
}
|
||||
|
||||
function assert_reset_hidden(id) {
|
||||
const resetButton = get_reset_button(id);
|
||||
is(resetButton.style.visibility, "hidden", `Reset button is hidden on #${id}`);
|
||||
}
|
||||
|
||||
function get_reset_button(id) {
|
||||
const input = document.getElementById(id);
|
||||
const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
|
||||
return shadowRoot.getElementById("reset-button");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -273,9 +273,7 @@ skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator)
|
|||
[test_peerConnection_callbacks.html]
|
||||
skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_replaceTrack.html]
|
||||
skip-if =
|
||||
toolkit == 'android' || # Bug 1189784
|
||||
(fission && debug) # Intermittently times out under Fission.
|
||||
skip-if = toolkit == 'android' # Bug 1189784
|
||||
[test_peerConnection_syncSetDescription.html]
|
||||
skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||
[test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
|
||||
|
|
|
@ -14,6 +14,7 @@ interface nsILoadGroup;
|
|||
interface nsIPrincipal;
|
||||
interface nsIStreamListener;
|
||||
interface nsIURI;
|
||||
interface nsIReferrerInfo;
|
||||
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
|
@ -40,10 +41,7 @@ interface imgILoader : nsISupports
|
|||
* @param aURI the URI to load
|
||||
* @param aInitialDocumentURI the URI that 'initiated' the load -- used for
|
||||
* 3rd party cookie blocking
|
||||
* @param aReferrerURI the 'referring' URI
|
||||
* @param aReferrerPolicy the policy to apply to sending referrers.
|
||||
* examples: "default", "never", "always", "origin"
|
||||
* (see W3C referrer-policy spec for valid policy strings)
|
||||
* @param aReferrerInfo the referrer info to compute sending referrer.
|
||||
* @param aLoadingPrincipal the principal of the loading document
|
||||
* @param aLoadGroup Loadgroup to put the image load into
|
||||
* @param aObserver the observer (may be null)
|
||||
|
@ -63,8 +61,7 @@ interface imgILoader : nsISupports
|
|||
*/
|
||||
imgIRequest loadImageXPCOM(in nsIURI aURI,
|
||||
in nsIURI aInitialDocumentURL,
|
||||
in nsIURI aReferrerURI,
|
||||
in AString aReferrerPolicy,
|
||||
in nsIReferrerInfo aReferrerInfo,
|
||||
in nsIPrincipal aLoadingPrincipal,
|
||||
in nsILoadGroup aLoadGroup,
|
||||
in imgINotificationObserver aObserver,
|
||||
|
|
|
@ -716,12 +716,26 @@ static bool ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
|
|||
nsIPrincipal* triggeringPrincipal,
|
||||
nsISupports* aCX,
|
||||
nsContentPolicyType aPolicyType,
|
||||
ReferrerPolicy referrerPolicy) {
|
||||
// If the entry's Referrer Policy doesn't match, we can't use this request.
|
||||
nsIReferrerInfo* aReferrerInfo) {
|
||||
// If the referrer policy doesn't match, we can't use this request.
|
||||
// XXX: Note that we only validate referrer policy, not referrerInfo object.
|
||||
// We should do with referrerInfo object, but it will cause us to use more
|
||||
// resources in the common case (the same policies but diferrent original
|
||||
// referrers).
|
||||
// XXX: this will return false if an image has different referrer attributes,
|
||||
// i.e. we currently don't use the cached image but reload the image with
|
||||
// the new referrer policy bug 1174921
|
||||
if (referrerPolicy != request->GetReferrerPolicy()) {
|
||||
uint32_t referrerPolicy = RP_Unset;
|
||||
if (aReferrerInfo) {
|
||||
referrerPolicy = aReferrerInfo->GetReferrerPolicy();
|
||||
}
|
||||
|
||||
uint32_t requestReferrerPolicy = RP_Unset;
|
||||
if (request->GetReferrerInfo()) {
|
||||
requestReferrerPolicy = request->GetReferrerInfo()->GetReferrerPolicy();
|
||||
}
|
||||
|
||||
if (referrerPolicy != requestReferrerPolicy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -762,8 +776,8 @@ static nsresult NewImageChannel(
|
|||
// be set to true if this channel ends up depending on
|
||||
// aTriggeringPrincipal and false otherwise.
|
||||
bool* aForcePrincipalCheckForCacheEntry, nsIURI* aURI,
|
||||
nsIURI* aInitialDocumentURI, int32_t aCORSMode, nsIURI* aReferringURI,
|
||||
ReferrerPolicy aReferrerPolicy, nsILoadGroup* aLoadGroup,
|
||||
nsIURI* aInitialDocumentURI, int32_t aCORSMode,
|
||||
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
|
||||
const nsCString& aAcceptHeader, nsLoadFlags aLoadFlags,
|
||||
nsContentPolicyType aPolicyType, nsIPrincipal* aTriggeringPrincipal,
|
||||
nsISupports* aRequestingContext, bool aRespectPrivacy) {
|
||||
|
@ -885,10 +899,10 @@ static nsresult NewImageChannel(
|
|||
NS_ENSURE_TRUE(httpChannelInternal, NS_ERROR_UNEXPECTED);
|
||||
rv = httpChannelInternal->SetDocumentURI(aInitialDocumentURI);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
nsCOMPtr<nsIReferrerInfo> referrerInfo =
|
||||
new ReferrerInfo(aReferringURI, aReferrerPolicy);
|
||||
rv = newHttpChannel->SetReferrerInfoWithoutClone(referrerInfo);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (aReferrerInfo) {
|
||||
DebugOnly<nsresult> rv = newHttpChannel->SetReferrerInfo(aReferrerInfo);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
}
|
||||
|
||||
// Image channels are loaded by default with reduced priority.
|
||||
|
@ -1649,9 +1663,9 @@ void imgLoader::CheckCacheLimits(imgCacheTable& cache, imgCacheQueue& queue) {
|
|||
|
||||
bool imgLoader::ValidateRequestWithNewChannel(
|
||||
imgRequest* request, nsIURI* aURI, nsIURI* aInitialDocumentURI,
|
||||
nsIURI* aReferrerURI, ReferrerPolicy aReferrerPolicy,
|
||||
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
|
||||
nsISupports* aCX, Document* aLoadingDocument, nsLoadFlags aLoadFlags,
|
||||
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver, nsISupports* aCX,
|
||||
Document* aLoadingDocument, nsLoadFlags aLoadFlags,
|
||||
nsContentPolicyType aLoadPolicyType, imgRequestProxy** aProxyRequest,
|
||||
nsIPrincipal* aTriggeringPrincipal, int32_t aCORSMode,
|
||||
bool* aNewChannelCreated) {
|
||||
|
@ -1691,10 +1705,9 @@ bool imgLoader::ValidateRequestWithNewChannel(
|
|||
nsCOMPtr<nsIChannel> newChannel;
|
||||
bool forcePrincipalCheck;
|
||||
rv = NewImageChannel(getter_AddRefs(newChannel), &forcePrincipalCheck, aURI,
|
||||
aInitialDocumentURI, aCORSMode, aReferrerURI,
|
||||
aReferrerPolicy, aLoadGroup, mAcceptHeader, aLoadFlags,
|
||||
aLoadPolicyType, aTriggeringPrincipal, aCX,
|
||||
mRespectPrivacy);
|
||||
aInitialDocumentURI, aCORSMode, aReferrerInfo,
|
||||
aLoadGroup, mAcceptHeader, aLoadFlags, aLoadPolicyType,
|
||||
aTriggeringPrincipal, aCX, mRespectPrivacy);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1756,9 +1769,9 @@ bool imgLoader::ValidateRequestWithNewChannel(
|
|||
|
||||
bool imgLoader::ValidateEntry(
|
||||
imgCacheEntry* aEntry, nsIURI* aURI, nsIURI* aInitialDocumentURI,
|
||||
nsIURI* aReferrerURI, ReferrerPolicy aReferrerPolicy,
|
||||
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
|
||||
nsISupports* aCX, Document* aLoadingDocument, nsLoadFlags aLoadFlags,
|
||||
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver, nsISupports* aCX,
|
||||
Document* aLoadingDocument, nsLoadFlags aLoadFlags,
|
||||
nsContentPolicyType aLoadPolicyType, bool aCanMakeNewChannel,
|
||||
bool* aNewChannelCreated, imgRequestProxy** aProxyRequest,
|
||||
nsIPrincipal* aTriggeringPrincipal, int32_t aCORSMode) {
|
||||
|
@ -1799,7 +1812,7 @@ bool imgLoader::ValidateEntry(
|
|||
|
||||
if (!ValidateSecurityInfo(request, aEntry->ForcePrincipalCheck(), aCORSMode,
|
||||
aTriggeringPrincipal, aCX, aLoadPolicyType,
|
||||
aReferrerPolicy))
|
||||
aReferrerInfo))
|
||||
return false;
|
||||
|
||||
// data URIs are immutable and by their nature can't leak data, so we can
|
||||
|
@ -1877,10 +1890,9 @@ bool imgLoader::ValidateEntry(
|
|||
LOG_SCOPE(gImgLog, "imgLoader::ValidateRequest |cache hit| must validate");
|
||||
|
||||
return ValidateRequestWithNewChannel(
|
||||
request, aURI, aInitialDocumentURI, aReferrerURI, aReferrerPolicy,
|
||||
aLoadGroup, aObserver, aCX, aLoadingDocument, aLoadFlags,
|
||||
aLoadPolicyType, aProxyRequest, aTriggeringPrincipal, aCORSMode,
|
||||
aNewChannelCreated);
|
||||
request, aURI, aInitialDocumentURI, aReferrerInfo, aLoadGroup,
|
||||
aObserver, aCX, aLoadingDocument, aLoadFlags, aLoadPolicyType,
|
||||
aProxyRequest, aTriggeringPrincipal, aCORSMode, aNewChannelCreated);
|
||||
}
|
||||
|
||||
return !validateRequest;
|
||||
|
@ -2030,37 +2042,38 @@ bool imgLoader::PreferLoadFromCache(nsIURI* aURI) const {
|
|||
nsIRequest::VALIDATE_ONCE_PER_SESSION)
|
||||
|
||||
NS_IMETHODIMP
|
||||
imgLoader::LoadImageXPCOM(
|
||||
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
|
||||
const nsAString& aReferrerPolicy, nsIPrincipal* aTriggeringPrincipal,
|
||||
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
|
||||
nsISupports* aCX, nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
|
||||
nsContentPolicyType aContentPolicyType, imgIRequest** _retval) {
|
||||
imgLoader::LoadImageXPCOM(nsIURI* aURI, nsIURI* aInitialDocumentURI,
|
||||
nsIReferrerInfo* aReferrerInfo,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver, nsISupports* aCX,
|
||||
nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
imgIRequest** _retval) {
|
||||
// Optional parameter, so defaults to 0 (== TYPE_INVALID)
|
||||
if (!aContentPolicyType) {
|
||||
aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
|
||||
}
|
||||
imgRequestProxy* proxy;
|
||||
ReferrerPolicy refpol = ReferrerPolicyFromString(aReferrerPolicy);
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aCX);
|
||||
nsCOMPtr<Document> doc = do_QueryInterface(aCX);
|
||||
nsresult rv =
|
||||
LoadImage(aURI, aInitialDocumentURI, aReferrerURI, refpol,
|
||||
aTriggeringPrincipal, 0, aLoadGroup, aObserver, node, doc,
|
||||
aLoadFlags, aCacheKey, aContentPolicyType, EmptyString(),
|
||||
LoadImage(aURI, aInitialDocumentURI, aReferrerInfo, aTriggeringPrincipal,
|
||||
0, aLoadGroup, aObserver, node, doc, aLoadFlags, aCacheKey,
|
||||
aContentPolicyType, EmptyString(),
|
||||
/* aUseUrgentStartForChannel */ false, &proxy);
|
||||
*_retval = proxy;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult imgLoader::LoadImage(
|
||||
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
|
||||
ReferrerPolicy aReferrerPolicy, nsIPrincipal* aTriggeringPrincipal,
|
||||
uint64_t aRequestContextID, nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver, nsINode* aContext,
|
||||
Document* aLoadingDocument, nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
|
||||
nsContentPolicyType aContentPolicyType, const nsAString& initiatorType,
|
||||
bool aUseUrgentStartForChannel, imgRequestProxy** _retval) {
|
||||
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIReferrerInfo* aReferrerInfo,
|
||||
nsIPrincipal* aTriggeringPrincipal, uint64_t aRequestContextID,
|
||||
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
|
||||
nsINode* aContext, Document* aLoadingDocument, nsLoadFlags aLoadFlags,
|
||||
nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType,
|
||||
const nsAString& initiatorType, bool aUseUrgentStartForChannel,
|
||||
imgRequestProxy** _retval) {
|
||||
VerifyCacheSizes();
|
||||
|
||||
NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer");
|
||||
|
@ -2154,11 +2167,11 @@ nsresult imgLoader::LoadImage(
|
|||
|
||||
if (cache.Get(key, getter_AddRefs(entry)) && entry) {
|
||||
bool newChannelCreated = false;
|
||||
if (ValidateEntry(
|
||||
entry, aURI, aInitialDocumentURI, aReferrerURI, aReferrerPolicy,
|
||||
aLoadGroup, aObserver, ToSupports(aLoadingDocument),
|
||||
aLoadingDocument, requestFlags, aContentPolicyType, true,
|
||||
&newChannelCreated, _retval, aTriggeringPrincipal, corsmode)) {
|
||||
if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerInfo,
|
||||
aLoadGroup, aObserver, ToSupports(aLoadingDocument),
|
||||
aLoadingDocument, requestFlags, aContentPolicyType, true,
|
||||
&newChannelCreated, _retval, aTriggeringPrincipal,
|
||||
corsmode)) {
|
||||
request = entry->GetRequest();
|
||||
|
||||
// If this entry has no proxies, its request has no reference to the
|
||||
|
@ -2206,10 +2219,10 @@ nsresult imgLoader::LoadImage(
|
|||
|
||||
bool forcePrincipalCheck;
|
||||
rv = NewImageChannel(getter_AddRefs(newChannel), &forcePrincipalCheck, aURI,
|
||||
aInitialDocumentURI, corsmode, aReferrerURI,
|
||||
aReferrerPolicy, aLoadGroup, mAcceptHeader,
|
||||
requestFlags, aContentPolicyType, aTriggeringPrincipal,
|
||||
aContext, mRespectPrivacy);
|
||||
aInitialDocumentURI, corsmode, aReferrerInfo,
|
||||
aLoadGroup, mAcceptHeader, requestFlags,
|
||||
aContentPolicyType, aTriggeringPrincipal, aContext,
|
||||
mRespectPrivacy);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2246,7 +2259,7 @@ nsresult imgLoader::LoadImage(
|
|||
rv = request->Init(aURI, aURI, /* aHadInsecureRedirect = */ false,
|
||||
channelLoadGroup, newChannel, entry,
|
||||
ToSupports(aLoadingDocument), aTriggeringPrincipal,
|
||||
corsmode, aReferrerPolicy);
|
||||
corsmode, aReferrerInfo);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2414,9 +2427,9 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
|
|||
// default to the internal image type
|
||||
nsContentPolicyType policyType = loadInfo->InternalContentPolicyType();
|
||||
|
||||
if (ValidateEntry(entry, uri, nullptr, nullptr, RP_Unset, nullptr,
|
||||
aObserver, aCX, doc, requestFlags, policyType, false,
|
||||
nullptr, nullptr, nullptr, imgIRequest::CORS_NONE)) {
|
||||
if (ValidateEntry(entry, uri, nullptr, nullptr, nullptr, aObserver, aCX,
|
||||
doc, requestFlags, policyType, false, nullptr, nullptr,
|
||||
nullptr, imgIRequest::CORS_NONE)) {
|
||||
request = entry->GetRequest();
|
||||
} else {
|
||||
nsCOMPtr<nsICacheInfoChannel> cacheChan(do_QueryInterface(channel));
|
||||
|
@ -2511,7 +2524,7 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
|
|||
// can set aHadInsecureRedirect to false here.
|
||||
rv = request->Init(originalURI, uri, /* aHadInsecureRedirect = */ false,
|
||||
channel, channel, entry, aCX, nullptr,
|
||||
imgIRequest::CORS_NONE, RP_Unset);
|
||||
imgIRequest::CORS_NONE, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<ProxyListener> pl =
|
||||
|
@ -2886,7 +2899,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest) {
|
|||
"uri", uri);
|
||||
|
||||
int32_t corsmode = mRequest->GetCORSMode();
|
||||
ReferrerPolicy refpol = mRequest->GetReferrerPolicy();
|
||||
nsCOMPtr<nsIReferrerInfo> referrerInfo = mRequest->GetReferrerInfo();
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal =
|
||||
mRequest->GetTriggeringPrincipal();
|
||||
|
||||
|
@ -2898,7 +2911,7 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest) {
|
|||
channel->GetOriginalURI(getter_AddRefs(originalURI));
|
||||
nsresult rv = mNewRequest->Init(originalURI, uri, mHadInsecureRedirect,
|
||||
aRequest, channel, mNewEntry, context,
|
||||
triggeringPrincipal, corsmode, refpol);
|
||||
triggeringPrincipal, corsmode, referrerInfo);
|
||||
if (NS_FAILED(rv)) {
|
||||
UpdateProxies(/* aCancelRequest */ true, /* aSyncNotify */ true);
|
||||
return rv;
|
||||
|
|
|
@ -191,7 +191,6 @@ class imgLoader final : public imgILoader,
|
|||
typedef nsRefPtrHashtable<nsGenericHashKey<ImageCacheKey>, imgCacheEntry>
|
||||
imgCacheTable;
|
||||
typedef nsTHashtable<nsPtrHashKey<imgRequest>> imgSet;
|
||||
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -241,15 +240,14 @@ class imgLoader final : public imgILoader,
|
|||
imgLoader();
|
||||
nsresult Init();
|
||||
|
||||
MOZ_MUST_USE nsresult
|
||||
LoadImage(nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
|
||||
ReferrerPolicy aReferrerPolicy, nsIPrincipal* aLoadingPrincipal,
|
||||
uint64_t aRequestContextID, nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver, nsINode* aContext,
|
||||
mozilla::dom::Document* aLoadingDocument, nsLoadFlags aLoadFlags,
|
||||
nsISupports* aCacheKey, nsContentPolicyType aContentPolicyType,
|
||||
const nsAString& initiatorType, bool aUseUrgentStartForChannel,
|
||||
imgRequestProxy** _retval);
|
||||
MOZ_MUST_USE nsresult LoadImage(
|
||||
nsIURI* aURI, nsIURI* aInitialDocumentURI, nsIReferrerInfo* aReferrerInfo,
|
||||
nsIPrincipal* aLoadingPrincipal, uint64_t aRequestContextID,
|
||||
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
|
||||
nsINode* aContext, mozilla::dom::Document* aLoadingDocument,
|
||||
nsLoadFlags aLoadFlags, nsISupports* aCacheKey,
|
||||
nsContentPolicyType aContentPolicyType, const nsAString& initiatorType,
|
||||
bool aUseUrgentStartForChannel, imgRequestProxy** _retval);
|
||||
|
||||
MOZ_MUST_USE nsresult
|
||||
LoadImageWithChannel(nsIChannel* channel, imgINotificationObserver* aObserver,
|
||||
|
@ -347,8 +345,8 @@ class imgLoader final : public imgILoader,
|
|||
bool PreferLoadFromCache(nsIURI* aURI) const;
|
||||
|
||||
bool ValidateEntry(imgCacheEntry* aEntry, nsIURI* aKey,
|
||||
nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
|
||||
ReferrerPolicy aReferrerPolicy, nsILoadGroup* aLoadGroup,
|
||||
nsIURI* aInitialDocumentURI,
|
||||
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver, nsISupports* aCX,
|
||||
mozilla::dom::Document* aLoadingDocument,
|
||||
nsLoadFlags aLoadFlags,
|
||||
|
@ -359,12 +357,12 @@ class imgLoader final : public imgILoader,
|
|||
|
||||
bool ValidateRequestWithNewChannel(
|
||||
imgRequest* request, nsIURI* aURI, nsIURI* aInitialDocumentURI,
|
||||
nsIURI* aReferrerURI, ReferrerPolicy aReferrerPolicy,
|
||||
nsILoadGroup* aLoadGroup, imgINotificationObserver* aObserver,
|
||||
nsISupports* aCX, mozilla::dom::Document* aLoadingDocument,
|
||||
nsLoadFlags aLoadFlags, nsContentPolicyType aContentPolicyType,
|
||||
imgRequestProxy** aProxyRequest, nsIPrincipal* aLoadingPrincipal,
|
||||
int32_t aCORSMode, bool* aNewChannelCreated);
|
||||
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver, nsISupports* aCX,
|
||||
mozilla::dom::Document* aLoadingDocument, nsLoadFlags aLoadFlags,
|
||||
nsContentPolicyType aContentPolicyType, imgRequestProxy** aProxyRequest,
|
||||
nsIPrincipal* aLoadingPrincipal, int32_t aCORSMode,
|
||||
bool* aNewChannelCreated);
|
||||
|
||||
nsresult CreateNewProxyForRequest(imgRequest* aRequest,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
|
|
|
@ -59,7 +59,6 @@ imgRequest::imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey)
|
|||
mValidator(nullptr),
|
||||
mInnerWindowId(0),
|
||||
mCORSMode(imgIRequest::CORS_NONE),
|
||||
mReferrerPolicy(mozilla::net::RP_Unset),
|
||||
mImageErrorCode(NS_OK),
|
||||
mImageAvailable(false),
|
||||
mMutex("imgRequest"),
|
||||
|
@ -86,7 +85,7 @@ nsresult imgRequest::Init(nsIURI* aURI, nsIURI* aFinalURI,
|
|||
bool aHadInsecureRedirect, nsIRequest* aRequest,
|
||||
nsIChannel* aChannel, imgCacheEntry* aCacheEntry,
|
||||
nsISupports* aCX, nsIPrincipal* aTriggeringPrincipal,
|
||||
int32_t aCORSMode, ReferrerPolicy aReferrerPolicy) {
|
||||
int32_t aCORSMode, nsIReferrerInfo* aReferrerInfo) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Cannot use nsIURI off main thread!");
|
||||
|
||||
LOG_FUNC(gImgLog, "imgRequest::Init");
|
||||
|
@ -105,7 +104,7 @@ nsresult imgRequest::Init(nsIURI* aURI, nsIURI* aFinalURI,
|
|||
mTimedChannel = do_QueryInterface(mChannel);
|
||||
mTriggeringPrincipal = aTriggeringPrincipal;
|
||||
mCORSMode = aCORSMode;
|
||||
mReferrerPolicy = aReferrerPolicy;
|
||||
mReferrerInfo = aReferrerInfo;
|
||||
|
||||
// If the original URI and the final URI are different, check whether the
|
||||
// original URI is secure. We deliberately don't take the final URI into
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "nsError.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "ImageCacheKey.h"
|
||||
|
||||
class imgCacheValidator;
|
||||
|
@ -31,6 +30,7 @@ class nsIProperties;
|
|||
class nsIRequest;
|
||||
class nsITimedChannel;
|
||||
class nsIURI;
|
||||
class nsIReferrerInfo;
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
@ -49,7 +49,6 @@ class imgRequest final : public nsIStreamListener,
|
|||
typedef mozilla::image::Image Image;
|
||||
typedef mozilla::image::ImageCacheKey ImageCacheKey;
|
||||
typedef mozilla::image::ProgressTracker ProgressTracker;
|
||||
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
|
||||
|
||||
public:
|
||||
imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey);
|
||||
|
@ -67,7 +66,7 @@ class imgRequest final : public nsIStreamListener,
|
|||
nsIChannel* aChannel, imgCacheEntry* aCacheEntry,
|
||||
nsISupports* aCX,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
int32_t aCORSMode, ReferrerPolicy aReferrerPolicy);
|
||||
int32_t aCORSMode, nsIReferrerInfo* aReferrerInfo);
|
||||
|
||||
void ClearLoader();
|
||||
|
||||
|
@ -113,8 +112,8 @@ class imgRequest final : public nsIStreamListener,
|
|||
// The CORS mode for which we loaded this image.
|
||||
int32_t GetCORSMode() const { return mCORSMode; }
|
||||
|
||||
// The Referrer Policy in effect when loading this image.
|
||||
ReferrerPolicy GetReferrerPolicy() const { return mReferrerPolicy; }
|
||||
// The ReferrerInfo in effect when loading this image.
|
||||
nsIReferrerInfo* GetReferrerInfo() const { return mReferrerInfo; }
|
||||
|
||||
// The principal for the document that loaded this image. Used when trying to
|
||||
// validate a CORS image load.
|
||||
|
@ -264,8 +263,8 @@ class imgRequest final : public nsIStreamListener,
|
|||
// default, imgIRequest::CORS_NONE.
|
||||
int32_t mCORSMode;
|
||||
|
||||
// The Referrer Policy (defined in ReferrerPolicy.h) used for this image.
|
||||
ReferrerPolicy mReferrerPolicy;
|
||||
// The ReferrerInfo used for this image.
|
||||
nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
|
||||
|
||||
nsresult mImageErrorCode;
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
|
||||
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
const ReferrerInfo = Components.Constructor(
|
||||
"@mozilla.org/referrer-info;1",
|
||||
"nsIReferrerInfo",
|
||||
"init"
|
||||
);
|
||||
|
||||
var server = new HttpServer();
|
||||
server.registerDirectory("/", do_get_file(""));
|
||||
|
@ -94,12 +99,16 @@ function checkSecondLoad() {
|
|||
var outer = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools)
|
||||
.createScriptedObserver(listener);
|
||||
var referrerInfo = new ReferrerInfo(
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
|
||||
true,
|
||||
null
|
||||
);
|
||||
requests.push({
|
||||
request: gCurrentLoader.loadImageXPCOM(
|
||||
uri,
|
||||
null,
|
||||
null,
|
||||
"default",
|
||||
referrerInfo,
|
||||
null,
|
||||
null,
|
||||
outer,
|
||||
|
@ -207,12 +216,16 @@ function startImageCallback(otherCb) {
|
|||
var outer = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools)
|
||||
.createScriptedObserver(listener2);
|
||||
var referrerInfo = new ReferrerInfo(
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
|
||||
true,
|
||||
null
|
||||
);
|
||||
requests.push({
|
||||
request: gCurrentLoader.loadImageXPCOM(
|
||||
uri,
|
||||
null,
|
||||
null,
|
||||
"default",
|
||||
referrerInfo,
|
||||
null,
|
||||
null,
|
||||
outer,
|
||||
|
@ -257,11 +270,15 @@ function run_test() {
|
|||
var outer = Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(Ci.imgITools)
|
||||
.createScriptedObserver(listener);
|
||||
var referrerInfo = new ReferrerInfo(
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
|
||||
true,
|
||||
null
|
||||
);
|
||||
var req = gCurrentLoader.loadImageXPCOM(
|
||||
uri,
|
||||
null,
|
||||
null,
|
||||
"default",
|
||||
referrerInfo,
|
||||
null,
|
||||
null,
|
||||
outer,
|
||||
|
|
|
@ -2,6 +2,12 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
|
||||
const ReferrerInfo = Components.Constructor(
|
||||
"@mozilla.org/referrer-info;1",
|
||||
"nsIReferrerInfo",
|
||||
"init"
|
||||
);
|
||||
|
||||
var server = new HttpServer();
|
||||
server.registerPathHandler("/image.png", imageHandler);
|
||||
server.start(-1);
|
||||
|
@ -84,12 +90,16 @@ function loadImage(isPrivate, callback) {
|
|||
? privateLoadContext
|
||||
: nonPrivateLoadContext;
|
||||
var loader = isPrivate ? gPrivateLoader : gPublicLoader;
|
||||
var referrerInfo = new ReferrerInfo(
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
|
||||
true,
|
||||
null
|
||||
);
|
||||
requests.push(
|
||||
loader.loadImageXPCOM(
|
||||
uri,
|
||||
null,
|
||||
null,
|
||||
"default",
|
||||
referrerInfo,
|
||||
null,
|
||||
loadGroup,
|
||||
outer,
|
||||
|
|
|
@ -184,7 +184,11 @@ static_assert(
|
|||
(JSVAL_SHIFTED_TAG_NULL ^ JSVAL_SHIFTED_TAG_OBJECT) == ValueObjectOrNullBit,
|
||||
"ValueObjectOrNullBit must be consistent with object and null tags");
|
||||
|
||||
constexpr uint64_t ValuePrivateDoubleBit = 0x8000'0000'0000'0000;
|
||||
constexpr uint64_t IsValidUserModePointer(uint64_t bits) {
|
||||
// All 64-bit platforms that we support actually have a 48-bit address space
|
||||
// for user-mode pointers, with the top 16 bits all set to zero.
|
||||
return (bits & 0xFFFF'0000'0000'0000) == 0;
|
||||
}
|
||||
|
||||
#endif /* JS_PUNBOX64 */
|
||||
|
||||
|
@ -837,7 +841,7 @@ union alignas(8) Value {
|
|||
s_.tag_ = JSValueTag(0);
|
||||
s_.payload_.ptr_ = ptr;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
MOZ_ASSERT((uintptr_t(ptr) & detail::ValuePrivateDoubleBit) == 0);
|
||||
MOZ_ASSERT(detail::IsValidUserModePointer(uintptr_t(ptr)));
|
||||
asBits_ = uintptr_t(ptr);
|
||||
#endif
|
||||
MOZ_ASSERT(isDouble());
|
||||
|
@ -848,7 +852,7 @@ union alignas(8) Value {
|
|||
#if defined(JS_NUNBOX32)
|
||||
return s_.payload_.ptr_;
|
||||
#elif defined(JS_PUNBOX64)
|
||||
MOZ_ASSERT((asBits_ & detail::ValuePrivateDoubleBit) == 0);
|
||||
MOZ_ASSERT(detail::IsValidUserModePointer(asBits_));
|
||||
return reinterpret_cast<void*>(asBits_);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -160,7 +160,7 @@ DefaultJitOptions::DefaultJitOptions() {
|
|||
// How many invocations or loop iterations are needed before functions
|
||||
// are compiled with the baseline compiler.
|
||||
// Duplicated in all.js - ensure both match.
|
||||
SET_DEFAULT(baselineJitWarmUpThreshold, 50);
|
||||
SET_DEFAULT(baselineJitWarmUpThreshold, 100);
|
||||
|
||||
// How many invocations or loop iterations are needed before functions
|
||||
// are compiled with the Ion compiler at OptimizationLevel::Normal.
|
||||
|
|
|
@ -233,7 +233,8 @@ nsresult nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
|
|||
// nsGkAtoms::disabled is handled by SyncDisabledState
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::readonly ||
|
||||
aAttribute == nsGkAtoms::tabindex) {
|
||||
aAttribute == nsGkAtoms::tabindex ||
|
||||
aAttribute == nsGkAtoms::required) {
|
||||
MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::input), "bad cast");
|
||||
auto contentAsInputElem =
|
||||
static_cast<dom::HTMLInputElement*>(GetContent());
|
||||
|
|
|
@ -2397,7 +2397,7 @@ nsresult nsImageFrame::LoadIcon(const nsAString& aSpec,
|
|||
relevant for cookies, so does not
|
||||
apply to icons. */
|
||||
nullptr, /* referrer (not relevant for icons) */
|
||||
mozilla::net::RP_Unset, nullptr, /* principal (not relevant for icons) */
|
||||
nullptr, /* principal (not relevant for icons) */
|
||||
0, loadGroup, gIconLoad, nullptr, /* No context */
|
||||
nullptr, /* Not associated with any particular document */
|
||||
loadFlags, nullptr, contentPolicyType, EmptyString(),
|
||||
|
|
|
@ -3453,6 +3453,11 @@ class nsDisplayList {
|
|||
*/
|
||||
template <typename Item, typename Comparator>
|
||||
void Sort(const Comparator& aComparator) {
|
||||
if (Count() < 2) {
|
||||
// Only sort lists with more than one item.
|
||||
return;
|
||||
}
|
||||
|
||||
// Some casual local browsing testing suggests that a local preallocated
|
||||
// array of 20 items should be able to avoid a lot of dynamic allocations
|
||||
// here.
|
||||
|
|
|
@ -477,13 +477,13 @@ DEFINE_GLOBAL(size_t) gPageSizeMask = gPageSize - 1;
|
|||
// Number of pages in a chunk.
|
||||
DEFINE_GLOBAL(size_t) gChunkNumPages = kChunkSize >> gPageSize2Pow;
|
||||
|
||||
// Number of pages necessary for a chunk header.
|
||||
// Number of pages necessary for a chunk header plus a guard page.
|
||||
DEFINE_GLOBAL(size_t)
|
||||
gChunkHeaderNumPages =
|
||||
((sizeof(arena_chunk_t) + sizeof(arena_chunk_map_t) * (gChunkNumPages - 1) +
|
||||
gPageSizeMask) &
|
||||
~gPageSizeMask) >>
|
||||
gPageSize2Pow;
|
||||
1 + (((sizeof(arena_chunk_t) +
|
||||
sizeof(arena_chunk_map_t) * (gChunkNumPages - 1) + gPageSizeMask) &
|
||||
~gPageSizeMask) >>
|
||||
gPageSize2Pow);
|
||||
|
||||
// One chunk, minus the header, minus a guard page
|
||||
DEFINE_GLOBAL(size_t)
|
||||
|
@ -2300,31 +2300,40 @@ void arena_t::InitChunk(arena_chunk_t* aChunk, bool aZeroed) {
|
|||
aChunk->ndirty = 0;
|
||||
|
||||
// Initialize the map to contain one maximal free untouched run.
|
||||
#ifdef MALLOC_DECOMMIT
|
||||
arena_run_t* run = (arena_run_t*)(uintptr_t(aChunk) +
|
||||
(gChunkHeaderNumPages << gPageSize2Pow));
|
||||
#endif
|
||||
|
||||
for (i = 0; i < gChunkHeaderNumPages; i++) {
|
||||
// Clear the bits for the real header pages.
|
||||
for (i = 0; i < gChunkHeaderNumPages - 1; i++) {
|
||||
aChunk->map[i].bits = 0;
|
||||
}
|
||||
aChunk->map[i].bits = gMaxLargeClass | flags;
|
||||
for (i++; i < gChunkNumPages - 2; i++) {
|
||||
// Mark the leading guard page (last header page) as decommitted.
|
||||
aChunk->map[i++].bits = CHUNK_MAP_DECOMMITTED;
|
||||
|
||||
// Mark the area usable for runs as available, note size at start and end
|
||||
aChunk->map[i++].bits = gMaxLargeClass | flags;
|
||||
for (; i < gChunkNumPages - 2; i++) {
|
||||
aChunk->map[i].bits = flags;
|
||||
}
|
||||
aChunk->map[gChunkNumPages - 2].bits = gMaxLargeClass | flags;
|
||||
// Mark the guard page as decommited.
|
||||
|
||||
// Mark the trailing guard page as decommitted.
|
||||
aChunk->map[gChunkNumPages - 1].bits = CHUNK_MAP_DECOMMITTED;
|
||||
|
||||
#ifdef MALLOC_DECOMMIT
|
||||
// Start out decommitted, in order to force a closer correspondence
|
||||
// between dirty pages and committed untouched pages.
|
||||
pages_decommit(run, gMaxLargeClass + gPageSize);
|
||||
// between dirty pages and committed untouched pages. This includes
|
||||
// leading and trailing guard pages.
|
||||
pages_decommit((void*)(uintptr_t(run) - gPageSize),
|
||||
gMaxLargeClass + 2 * gPageSize);
|
||||
#else
|
||||
// Only decommit the last page as a guard.
|
||||
// Decommit the last header page (=leading page) as a guard.
|
||||
pages_decommit((void*)(uintptr_t(run) - gPageSize), gPageSize);
|
||||
// Decommit the last page as a guard.
|
||||
pages_decommit((void*)(uintptr_t(aChunk) + kChunkSize - gPageSize),
|
||||
gPageSize);
|
||||
#endif
|
||||
|
||||
mStats.committed += gChunkHeaderNumPages;
|
||||
|
||||
// Insert the run into the tree of available runs.
|
||||
|
|
|
@ -1215,7 +1215,7 @@ pref("javascript.options.blinterp", true);
|
|||
pref("javascript.options.blinterp.threshold", 10);
|
||||
pref("javascript.options.baselinejit", true);
|
||||
// Duplicated in JitOptions - ensure both match.
|
||||
pref("javascript.options.baselinejit.threshold", 50);
|
||||
pref("javascript.options.baselinejit.threshold", 100);
|
||||
pref("javascript.options.ion", true);
|
||||
// Duplicated in JitOptions - ensure both match.
|
||||
pref("javascript.options.ion.threshold", 1000);
|
||||
|
|
|
@ -152,6 +152,12 @@ def get_paths(os_name):
|
|||
return (mozbuild_path, sdk_path, ndk_path)
|
||||
|
||||
|
||||
def sdkmanager_tool(sdk_path):
|
||||
# sys.platform is win32 even if Python/Win64.
|
||||
sdkmanager = 'sdkmanager.bat' if sys.platform.startswith('win') else 'sdkmanager'
|
||||
return os.path.join(sdk_path, 'tools', 'bin', sdkmanager)
|
||||
|
||||
|
||||
def ensure_dir(dir):
|
||||
'''Ensures the given directory exists'''
|
||||
if dir and not os.path.exists(dir):
|
||||
|
@ -191,8 +197,8 @@ def ensure_android(os_name, artifact_mode=False, ndk_only=False, no_interactive=
|
|||
|
||||
# We expect the |sdkmanager| tool to be at
|
||||
# ~/.mozbuild/android-sdk-$OS_NAME/tools/bin/sdkmanager.
|
||||
sdkmanager_tool = os.path.join(sdk_path, 'tools', 'bin', 'sdkmanager')
|
||||
ensure_android_packages(sdkmanager_tool=sdkmanager_tool, no_interactive=no_interactive)
|
||||
ensure_android_packages(sdkmanager_tool=sdkmanager_tool(sdk_path),
|
||||
no_interactive=no_interactive)
|
||||
|
||||
|
||||
def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_path, ndk_url,
|
||||
|
@ -221,7 +227,7 @@ def ensure_android_sdk_and_ndk(mozbuild_path, os_name, sdk_path, sdk_url, ndk_pa
|
|||
# |sdkmanager| tool to install additional parts of the Android
|
||||
# toolchain. If we overwrite, we lose whatever Android packages
|
||||
# the user may have already installed.
|
||||
if os.path.isfile(os.path.join(sdk_path, 'tools', 'bin', 'sdkmanager')):
|
||||
if os.path.isfile(sdkmanager_tool(sdk_path)):
|
||||
print(ANDROID_SDK_EXISTS % sdk_path)
|
||||
elif os.path.isdir(sdk_path):
|
||||
raise NotImplementedError(ANDROID_SDK_TOO_OLD % sdk_path)
|
||||
|
|
|
@ -70,7 +70,30 @@ class MozillaBuildBootstrapper(BaseBootstrapper):
|
|||
pass
|
||||
|
||||
def install_mobile_android_artifact_mode_packages(self):
|
||||
pass
|
||||
self.ensure_mobile_android_packages(artifact_mode=True)
|
||||
|
||||
def ensure_mobile_android_packages(self, artifact_mode=False):
|
||||
# Get java path from registry key
|
||||
import _winreg
|
||||
|
||||
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
|
||||
r'SOFTWARE\JavaSoft\Java Development Kit\1.8')
|
||||
java_path, regtype = _winreg.QueryValueEx(key, 'JavaHome')
|
||||
_winreg.CloseKey(key)
|
||||
os.environ['PATH'] = \
|
||||
'{}{}{}'.format(os.path.join(java_path, 'bin'), os.pathsep, os.environ['PATH'])
|
||||
self.ensure_java()
|
||||
|
||||
from mozboot import android
|
||||
android.ensure_android('windows', artifact_mode=artifact_mode,
|
||||
no_interactive=self.no_interactive)
|
||||
|
||||
def suggest_mobile_android_mozconfig(self, artifact_mode=False):
|
||||
from mozboot import android
|
||||
android.suggest_mozconfig('windows', artifact_mode=artifact_mode)
|
||||
|
||||
def suggest_mobile_android_artifact_mode_mozconfig(self):
|
||||
self.suggest_mobile_android_mozconfig(artifact_mode=True)
|
||||
|
||||
def ensure_clang_static_analysis_package(self, state_dir, checkout_root):
|
||||
from mozboot import static_analysis
|
||||
|
|
|
@ -79,6 +79,10 @@ class StaticAnalysisMonitor(object):
|
|||
self._warnings_database = WarningsDatabase()
|
||||
|
||||
def on_warning(warning):
|
||||
|
||||
# Output paths relative to repository root
|
||||
warning['filename'] = os.path.relpath(warning['filename'], srcdir)
|
||||
|
||||
self._warnings_database.insert(warning)
|
||||
|
||||
self._warnings_collector = WarningsCollector(on_warning, objdir=objdir)
|
||||
|
@ -1971,7 +1975,9 @@ class StaticAnalysis(MachCommandBase):
|
|||
try:
|
||||
output = check_output(args + l)
|
||||
if output and output_format == 'json':
|
||||
patches[original_path] = self._parse_xml_output(original_path, output)
|
||||
# Output a relative path in json patch list
|
||||
relative_path = os.path.relpath(original_path, self.topsrcdir)
|
||||
patches[relative_path] = self._parse_xml_output(original_path, output)
|
||||
except CalledProcessError as e:
|
||||
# Something wrong happend
|
||||
print("clang-format: An error occured while running clang-format.")
|
||||
|
|
|
@ -111,7 +111,7 @@ def make_task_description(config, jobs):
|
|||
'implementation': 'docker-worker',
|
||||
'docker-image': {'in-tree': 'funsize-update-generator'},
|
||||
'os': 'linux',
|
||||
'max-run-time': 3600 if 'asan' in dep_job.label else 600,
|
||||
'max-run-time': 3600 if 'asan' in dep_job.label else 900,
|
||||
'chain-of-trust': True,
|
||||
'taskcluster-proxy': True,
|
||||
'env': {
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
|
||||
[iceConnectionState changes at the right time, with bundle policy max-bundle]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1307996
|
||||
|
||||
[iceConnectionState changes at the right time, with bundle policy max-compat]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1307996
|
||||
|
||||
[iceConnectionState changes at the right time, with bundle policy balanced]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1307996
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
[RTCPeerConnection-onicecandidateerror.html]
|
||||
expected: TIMEOUT
|
||||
[Surfacing onicecandidateerror]
|
||||
expected: TIMEOUT
|
||||
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1561441
|
||||
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
[candidate-exchange.https.html]
|
||||
[Adding only caller -> callee candidates gives a connection]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
|
||||
|
||||
[Adding only callee -> caller candidates gives a connection]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
|
||||
|
||||
[Explicit offer/answer exchange gives a connection]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
|
||||
|
||||
[Adding callee -> caller candidates from end-of-candidates gives a connection]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1278299
|
||||
|
||||
|
|
|
@ -291,10 +291,9 @@ nsresult AlertImageRequest::Start() {
|
|||
int32_t loadFlags =
|
||||
mInPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS : nsIRequest::LOAD_NORMAL;
|
||||
|
||||
rv = il->LoadImageXPCOM(mURI, nullptr, nullptr, NS_LITERAL_STRING("default"),
|
||||
mPrincipal, nullptr, this, nullptr, loadFlags,
|
||||
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
|
||||
getter_AddRefs(mRequest));
|
||||
rv = il->LoadImageXPCOM(
|
||||
mURI, nullptr, nullptr, mPrincipal, nullptr, this, nullptr, loadFlags,
|
||||
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, getter_AddRefs(mRequest));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NotifyMissing();
|
||||
}
|
||||
|
|
|
@ -33,11 +33,204 @@ export const updateSelectedItem = (() => {
|
|||
};
|
||||
})();
|
||||
|
||||
const createEntryItem = (label, info) => {
|
||||
return {
|
||||
label,
|
||||
info,
|
||||
};
|
||||
};
|
||||
|
||||
const adjustCertInformation = cert => {
|
||||
let certItems = [];
|
||||
|
||||
// Subject Name section
|
||||
certItems.push({
|
||||
sectionTitle: "Subject Name",
|
||||
sectionItems: cert.subject.entries.map(entry =>
|
||||
createEntryItem(entry[0], entry[1])
|
||||
),
|
||||
Critical: false,
|
||||
});
|
||||
|
||||
// Issuer Name section
|
||||
certItems.push({
|
||||
sectionTitle: "Issuer Name",
|
||||
sectionItems: cert.issuer.entries.map(entry =>
|
||||
createEntryItem(entry[0], entry[1])
|
||||
),
|
||||
Critical: false,
|
||||
});
|
||||
|
||||
// Validity section
|
||||
certItems.push({
|
||||
sectionTitle: "Validity",
|
||||
sectionItems: [
|
||||
createEntryItem("Not Before", cert.notBefore),
|
||||
createEntryItem("Not After", cert.notAfter),
|
||||
],
|
||||
Critical: false,
|
||||
});
|
||||
|
||||
// Subject Alt Names section
|
||||
certItems.push({
|
||||
sectionTitle: "Subject Alt Names",
|
||||
sectionItems: cert.ext.san.altNames.map(entry =>
|
||||
createEntryItem(entry[0], entry[1])
|
||||
),
|
||||
Critical: cert.ext.san.critical || false,
|
||||
});
|
||||
|
||||
// Public Key Info section
|
||||
certItems.push({
|
||||
sectionTitle: "Public Key Info",
|
||||
sectionItems: [
|
||||
createEntryItem("Algorithm", cert.subjectPublicKeyInfo.kty),
|
||||
createEntryItem("Key size", cert.subjectPublicKeyInfo.keysize),
|
||||
createEntryItem("Curve", cert.subjectPublicKeyInfo.crv),
|
||||
createEntryItem("Public Value", cert.subjectPublicKeyInfo.xy),
|
||||
createEntryItem("Exponent", cert.subjectPublicKeyInfo.e),
|
||||
createEntryItem("Modulus", cert.subjectPublicKeyInfo.n),
|
||||
],
|
||||
Critical: false,
|
||||
});
|
||||
|
||||
// Miscellaneous section
|
||||
certItems.push({
|
||||
sectionTitle: "Miscellaneous",
|
||||
sectionItems: [
|
||||
createEntryItem("Serial Number", cert.serialNumber),
|
||||
createEntryItem("Signature Algorithm", cert.signature.name),
|
||||
createEntryItem("Version", cert.version),
|
||||
createEntryItem("Download", cert.files.pem),
|
||||
],
|
||||
Critical: false,
|
||||
});
|
||||
|
||||
// Fingerprints section
|
||||
certItems.push({
|
||||
sectionTitle: "Fingerprints",
|
||||
sectionItems: [
|
||||
createEntryItem("SHA-256", cert.fingerprint.sha256),
|
||||
createEntryItem("SHA-1", cert.fingerprint.sha1),
|
||||
],
|
||||
Critical: false,
|
||||
});
|
||||
|
||||
// Basic Constraints section
|
||||
certItems.push({
|
||||
sectionTitle: "Basic Constraints",
|
||||
sectionItems: [
|
||||
createEntryItem("Certificate Authority", cert.ext.basicConstraintscA),
|
||||
],
|
||||
Critical: cert.ext.basicConstraints.critical || false,
|
||||
});
|
||||
|
||||
// Key Usages section
|
||||
certItems.push({
|
||||
sectionTitle: "Key Usages",
|
||||
sectionItems: [createEntryItem("Purposes", cert.ext.keyUsages.purposes)],
|
||||
Critical: cert.ext.keyUsages.critical || false,
|
||||
});
|
||||
|
||||
// Extended Key Usages section
|
||||
certItems.push({
|
||||
sectionTitle: "Extended Key Usages",
|
||||
sectionItems: [createEntryItem("Purposes", cert.ext.eKeyUsages.purposes)],
|
||||
Critical: cert.ext.eKeyUsages.critical || false,
|
||||
});
|
||||
|
||||
// OCSP Stapling section
|
||||
certItems.push({
|
||||
sectionTitle: "OCSP Stapling",
|
||||
sectionItems: [createEntryItem("Required", cert.ext.ocspStaple.critical)],
|
||||
Critical: cert.ext.ocspStaple.critical || false,
|
||||
});
|
||||
|
||||
// Subject Key ID section
|
||||
certItems.push({
|
||||
sectionTitle: "Subject Key ID",
|
||||
sectionItems: [createEntryItem("Key ID", cert.ext.sKID.id)],
|
||||
Critical: cert.ext.sKID.critical || false,
|
||||
});
|
||||
|
||||
// Authority Key ID section
|
||||
certItems.push({
|
||||
sectionTitle: "Authority Key ID",
|
||||
sectionItems: [createEntryItem("Key ID", cert.ext.aKID.id)],
|
||||
Critical: cert.ext.aKID.critical || false,
|
||||
});
|
||||
|
||||
// CRL Endpoints section
|
||||
certItems.push({
|
||||
sectionTitle: "CRL Endpoints",
|
||||
sectionItems: cert.ext.crlPoints.points.map(entry => {
|
||||
let label = "Distribution Point";
|
||||
return createEntryItem(label, entry);
|
||||
}),
|
||||
Critical: cert.ext.crlPoints.critical || false,
|
||||
});
|
||||
|
||||
// // Authority Info (AIA) section
|
||||
let items = [];
|
||||
cert.ext.aia.descriptions.forEach(entry => {
|
||||
items.push(createEntryItem("Location", entry.location));
|
||||
items.push(createEntryItem("Method", entry.method));
|
||||
});
|
||||
certItems.push({
|
||||
sectionTitle: "Authority Info (AIA)",
|
||||
sectionItems: items,
|
||||
Critical: cert.ext.aia.critical || false,
|
||||
});
|
||||
|
||||
// Certificate Policies section
|
||||
items = [];
|
||||
cert.ext.cp.policies.forEach(entry => {
|
||||
items.push(createEntryItem("Policy", entry.name + " ( " + entry.id + " )"));
|
||||
items.push(createEntryItem("Value", entry.value));
|
||||
if (entry.qualifiers) {
|
||||
entry.qualifiers.forEach(qualifier => {
|
||||
items.push(
|
||||
createEntryItem(
|
||||
"Qualifier",
|
||||
qualifier.name + " ( " + qualifier.id + " )"
|
||||
)
|
||||
);
|
||||
items.push(createEntryItem("Value", qualifier.value));
|
||||
});
|
||||
}
|
||||
});
|
||||
certItems.push({
|
||||
sectionTitle: "Certificate Policies",
|
||||
sectionItems: items,
|
||||
Critical: cert.ext.cp.critical || false,
|
||||
});
|
||||
|
||||
// Embedded SCTs section
|
||||
items = [];
|
||||
cert.ext.scts.timestamps.forEach(entry => {
|
||||
for (let key of Object.keys(entry)) {
|
||||
items.push(createEntryItem(key, entry[key]));
|
||||
}
|
||||
});
|
||||
certItems.push({
|
||||
sectionTitle: "Embedded SCTs",
|
||||
sectionItems: items,
|
||||
Critical: cert.ext.scts.critical || false,
|
||||
});
|
||||
|
||||
certItems.push({
|
||||
tabName: cert.subject.cn,
|
||||
});
|
||||
|
||||
return certItems;
|
||||
};
|
||||
|
||||
const buildChain = async () => {
|
||||
let chain = [derString];
|
||||
let builtChain = chain.map(cert => {
|
||||
return stringToArrayBuffer(cert);
|
||||
});
|
||||
let certs = await Promise.all(builtChain.map(cert => parse(cert)));
|
||||
console.log("certs ", certs);
|
||||
let adjustedCerts = certs.map(adjustCertInformation);
|
||||
console.log("adjustedCerts ", adjustedCerts);
|
||||
};
|
||||
|
|
|
@ -647,7 +647,6 @@ function Search(
|
|||
|
||||
// This allows to handle leading or trailing restriction characters specially.
|
||||
this._leadingRestrictionToken = null;
|
||||
this._trailingRestrictionToken = null;
|
||||
if (tokens.length > 0) {
|
||||
if (
|
||||
UrlbarTokenizer.isRestrictionToken(tokens[0]) &&
|
||||
|
@ -656,13 +655,6 @@ function Search(
|
|||
) {
|
||||
this._leadingRestrictionToken = tokens[0].value;
|
||||
}
|
||||
if (
|
||||
UrlbarTokenizer.isRestrictionToken(tokens[tokens.length - 1]) &&
|
||||
(tokens.length > 1 ||
|
||||
tokens[tokens.length - 1].type == UrlbarTokenizer.TYPE.RESTRICT_SEARCH)
|
||||
) {
|
||||
this._trailingRestrictionToken = tokens[tokens.length - 1].value;
|
||||
}
|
||||
|
||||
// Check if the first token has a strippable prefix and remove it, but don't
|
||||
// create an empty token.
|
||||
|
@ -1739,17 +1731,14 @@ Search.prototype = {
|
|||
if (!engine || !this.pending) {
|
||||
return false;
|
||||
}
|
||||
// Strip a leading or trailing restriction char.
|
||||
// Strip a leading search restriction char, because we prepend it to text
|
||||
// when the search shortcut is used and it's not user typed. Don't strip
|
||||
// other restriction chars, so that it's possible to search for things
|
||||
// including one of those (e.g. "c#").
|
||||
let query = this._trimmedOriginalSearchString;
|
||||
if (this._leadingRestrictionToken) {
|
||||
if (this._leadingRestrictionToken === UrlbarTokenizer.RESTRICT.SEARCH) {
|
||||
query = substringAfter(query, this._leadingRestrictionToken).trim();
|
||||
}
|
||||
if (this._trailingRestrictionToken) {
|
||||
query = query.substring(
|
||||
0,
|
||||
query.lastIndexOf(this._trailingRestrictionToken)
|
||||
);
|
||||
}
|
||||
this._addSearchEngineMatch({ engine, query });
|
||||
return true;
|
||||
},
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Test that restriction tokens are not removed from the search string, apart
|
||||
* from a leading search restriction token.
|
||||
*/
|
||||
|
||||
add_task(async function test_searchstring() {
|
||||
for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
|
||||
for (let search of [`${token} query`, `query ${token}`]) {
|
||||
let searchQuery =
|
||||
token == UrlbarTokenizer.RESTRICT.SEARCH &&
|
||||
search.startsWith(UrlbarTokenizer.RESTRICT.SEARCH)
|
||||
? search.substring(2)
|
||||
: search;
|
||||
info(`Searching for "${search}", expecting "${searchQuery}"`);
|
||||
await check_autocomplete({
|
||||
search,
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch(search, {
|
||||
engineName: "MozSearch",
|
||||
searchQuery,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
|
@ -111,15 +111,20 @@ add_task(async function basicGetAndPost() {
|
|||
// be recognized. It should be treated as part of the search string. Try
|
||||
// all the restriction tokens to test that. We should get a single "search
|
||||
// with" heuristic result without an alias.
|
||||
for (let restrictToken in UrlbarTokenizer.RESTRICT) {
|
||||
let search = `${restrictToken} ${alias} query string`;
|
||||
for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
|
||||
let search = `${token} ${alias} query string`;
|
||||
let searchQuery =
|
||||
token == UrlbarTokenizer.RESTRICT.SEARCH &&
|
||||
search.startsWith(UrlbarTokenizer.RESTRICT.SEARCH)
|
||||
? search.substring(2)
|
||||
: search;
|
||||
await check_autocomplete({
|
||||
search,
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch(search, {
|
||||
engineName: "MozSearch",
|
||||
searchQuery: search,
|
||||
searchQuery,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
|
|
|
@ -224,7 +224,7 @@ add_task(async function test_tab_matches() {
|
|||
matches: [
|
||||
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE + " abc", {
|
||||
heuristic: true,
|
||||
searchQuery: "abc",
|
||||
searchQuery: UrlbarTokenizer.RESTRICT.OPENPAGE + " abc",
|
||||
}),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
],
|
||||
|
@ -247,7 +247,7 @@ add_task(async function test_tab_matches() {
|
|||
matches: [
|
||||
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla", {
|
||||
heuristic: true,
|
||||
searchQuery: "mozilla",
|
||||
searchQuery: UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla",
|
||||
}),
|
||||
makeSwitchToTabMatch("about:mozilla"),
|
||||
],
|
||||
|
|
|
@ -43,6 +43,7 @@ skip-if = appname == "thunderbird"
|
|||
[test_query_url.js]
|
||||
[test_remote_tab_matches.js]
|
||||
skip-if = !sync
|
||||
[test_restrict_searchstring.js]
|
||||
[test_search_engine_alias.js]
|
||||
[test_search_engine_default.js]
|
||||
[test_search_engine_host.js]
|
||||
|
|
|
@ -249,9 +249,9 @@ addonsManager:
|
|||
An abuse report submitted by a user for a given extension. The object of the event
|
||||
represent the report entry point, the value is the id of the addon being reported.
|
||||
objects:
|
||||
- menu
|
||||
- toolbar_context_menu
|
||||
- uninstall
|
||||
- menu
|
||||
- toolbar_context_menu
|
||||
- uninstall
|
||||
extra_keys:
|
||||
addon_type: The type of the add-on being reported (missing on ERROR_ADDON_NOT_FOUND).
|
||||
error_type: >
|
||||
|
@ -317,6 +317,52 @@ navigation:
|
|||
extra_keys:
|
||||
engine: The id of the search engine used.
|
||||
|
||||
urlbar:
|
||||
engagement:
|
||||
objects: ["click", "enter", "paste_go", "drop_go"]
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
- "firefox"
|
||||
record_in_processes: ["main"]
|
||||
description: >
|
||||
This is recorded on urlbar engagement, that is when the user picks a
|
||||
search result.
|
||||
The value field records the initial interaction type. One of:
|
||||
"typed", "dropped", "pasted", "topsites"
|
||||
bug_numbers: [1559136]
|
||||
notification_emails:
|
||||
- "rharter@mozilla.com"
|
||||
- "fx-search@mozilla.com"
|
||||
expiry_version: never
|
||||
extra_keys:
|
||||
elapsed: engagement time in milliseconds.
|
||||
numChars: number of input characters.
|
||||
selIndex: index of the selected result in the urlbar panel, or -1.
|
||||
selType: >
|
||||
type of the selected result in the urlbar panel. One of:
|
||||
"autofill", "visit", "bookmark", "history", "keyword", "search",
|
||||
"searchsuggestion", "switchtab", "remotetab", "extension", "oneoff",
|
||||
"keywordoffer", "canonized", "none"
|
||||
abandonment:
|
||||
objects: ["blur"]
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
- "firefox"
|
||||
record_in_processes: ["main"]
|
||||
description: >
|
||||
This is recorded on urlbar search abandon, that is when the user starts
|
||||
an interaction but then blurs the urlbar.
|
||||
The value field records the initial interaction type. One of:
|
||||
"typed", "dropped", "pasted", "topsites"
|
||||
bug_numbers: [1559136]
|
||||
notification_emails:
|
||||
- "rharter@mozilla.com"
|
||||
- "fx-search@mozilla.com"
|
||||
expiry_version: never
|
||||
extra_keys:
|
||||
elapsed: abandonement time in milliseconds.
|
||||
numChars: number of input characters.
|
||||
|
||||
normandy:
|
||||
enroll:
|
||||
objects: ["preference_study", "addon_study", "preference_rollout"]
|
||||
|
@ -505,7 +551,6 @@ pwmgr:
|
|||
]
|
||||
bug_numbers:
|
||||
- 1548463
|
||||
description: An action was taken on the about:logins page
|
||||
expiry_version: "74"
|
||||
notification_emails: ["loines@mozilla.com", "passwords-dev@mozilla.org", "jaws@mozilla.com"]
|
||||
release_channel_collection: opt-out
|
||||
|
@ -554,7 +599,7 @@ fxa_avatar_menu:
|
|||
"sync_tabs_sidebar",
|
||||
"toolbar_icon",
|
||||
"unver_sync_settings"
|
||||
]
|
||||
]
|
||||
methods: ["click"]
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
|
@ -583,7 +628,7 @@ fxa_app_menu:
|
|||
"sync_tabs",
|
||||
"sync_tabs_sidebar",
|
||||
"toolbar_icon"
|
||||
]
|
||||
]
|
||||
methods: ["click"]
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
|
@ -707,10 +752,6 @@ telemetry.test:
|
|||
objects: ["object1"]
|
||||
bug_numbers: [1452552]
|
||||
notification_emails: ["telemetry-client-dev@mozilla.com"]
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes: ["main"]
|
||||
description: This event is used to test desktop-only main recording.
|
||||
expiry_version: never
|
||||
|
@ -719,10 +760,6 @@ telemetry.test:
|
|||
objects: ["object1"]
|
||||
bug_numbers: [1452552]
|
||||
notification_emails: ["telemetry-client-dev@mozilla.com"]
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes: ["main"]
|
||||
description: This event is used to test multiproduct main recording.
|
||||
expiry_version: never
|
||||
|
@ -731,10 +768,6 @@ telemetry.test:
|
|||
objects: ["object1"]
|
||||
bug_numbers: [1452552]
|
||||
notification_emails: ["telemetry-client-dev@mozilla.com"]
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes: ["main"]
|
||||
description: This event is used to test mobile-only main recording.
|
||||
expiry_version: never
|
||||
|
@ -1379,10 +1412,6 @@ security.ui.certerror:
|
|||
- rtestard@mozilla.com
|
||||
- seceng-telemetry@mozilla.com
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes: ["main", "content"]
|
||||
products:
|
||||
- firefox
|
||||
|
@ -1413,10 +1442,6 @@ security.ui.certerror:
|
|||
- rtestard@mozilla.com
|
||||
- seceng-telemetry@mozilla.com
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes: ["content"]
|
||||
products:
|
||||
- firefox
|
||||
|
@ -1442,10 +1467,6 @@ security.ui.identitypopup:
|
|||
- pdol@mozilla.com
|
||||
- seceng-telemetry@mozilla.com
|
||||
release_channel_collection: opt-in
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes:
|
||||
- main
|
||||
products:
|
||||
|
@ -1468,10 +1489,6 @@ security.ui.identitypopup:
|
|||
- pdol@mozilla.com
|
||||
- seceng-telemetry@mozilla.com
|
||||
release_channel_collection: opt-in
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes:
|
||||
- main
|
||||
products:
|
||||
|
@ -1541,10 +1558,6 @@ intl.ui.browserLanguage:
|
|||
- flod@mozilla.com
|
||||
- mstriemer@mozilla.com
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes: ["main"]
|
||||
bug_numbers: [1486507, 1553311]
|
||||
|
||||
|
@ -1567,10 +1580,6 @@ security.ui.permissionprompt:
|
|||
- ehsan@mozilla.com
|
||||
- seceng-telemetry@mozilla.com
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes:
|
||||
- main
|
||||
extra_keys:
|
||||
|
@ -1607,10 +1616,6 @@ security.ui.permissionprompt:
|
|||
- ehsan@mozilla.com
|
||||
- seceng-telemetry@mozilla.com
|
||||
release_channel_collection: opt-out
|
||||
products:
|
||||
- "firefox"
|
||||
- "fennec"
|
||||
- "geckoview"
|
||||
record_in_processes:
|
||||
- main
|
||||
extra_keys:
|
||||
|
|
|
@ -430,7 +430,7 @@ browser.usage:
|
|||
- 1381591
|
||||
description: >-
|
||||
The number of plugin instances that were created.
|
||||
expires: never # Jan-2021 but we don't have a version number for that
|
||||
expires: never # Jan-2021 but we don't have a version number for that
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- bsmedberg@mozilla.com
|
||||
|
@ -2225,83 +2225,83 @@ devtools.toolbox:
|
|||
devtools.webreplay:
|
||||
new_recording:
|
||||
bug_numbers:
|
||||
- 1495910
|
||||
- 1495910
|
||||
description: >
|
||||
Number of times a blank recording tab was created.
|
||||
expires: never
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- bhackett@mozilla.com
|
||||
- bhackett@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
- 'main'
|
||||
|
||||
reload_recording:
|
||||
bug_numbers:
|
||||
- 1495910
|
||||
- 1495910
|
||||
description: >
|
||||
Number of times a non-recording tab was reloaded to create a recording tab.
|
||||
expires: never
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- bhackett@mozilla.com
|
||||
- bhackett@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
- 'main'
|
||||
|
||||
stop_recording:
|
||||
bug_numbers:
|
||||
- 1495910
|
||||
- 1495910
|
||||
description: >
|
||||
Number of times a recording tab was reloaded to create a non-recording tab.
|
||||
expires: never
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- bhackett@mozilla.com
|
||||
- bhackett@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
- 'main'
|
||||
|
||||
save_recording:
|
||||
bug_numbers:
|
||||
- 1495910
|
||||
- 1495910
|
||||
description: >
|
||||
Number of times a recording was saved.
|
||||
expires: never
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- bhackett@mozilla.com
|
||||
- bhackett@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
- 'main'
|
||||
|
||||
load_recording:
|
||||
bug_numbers:
|
||||
- 1495910
|
||||
- 1495910
|
||||
description: >
|
||||
Number of times a recording was loaded.
|
||||
expires: never
|
||||
kind: uint
|
||||
notification_emails:
|
||||
- bhackett@mozilla.com
|
||||
- bhackett@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'main'
|
||||
- 'main'
|
||||
|
||||
devtools.changesview:
|
||||
opened_count:
|
||||
|
@ -4853,10 +4853,6 @@ telemetry.test:
|
|||
kind: uint
|
||||
notification_emails:
|
||||
- telemetry-client-dev@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'all'
|
||||
products:
|
||||
|
@ -4871,10 +4867,6 @@ telemetry.test:
|
|||
keyed: true
|
||||
notification_emails:
|
||||
- telemetry-client-dev@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'all'
|
||||
products:
|
||||
|
@ -4888,10 +4880,6 @@ telemetry.test:
|
|||
kind: uint
|
||||
notification_emails:
|
||||
- telemetry-client-dev@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'all'
|
||||
products:
|
||||
|
@ -4907,10 +4895,6 @@ telemetry.test:
|
|||
kind: uint
|
||||
notification_emails:
|
||||
- telemetry-client-dev@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'all'
|
||||
products:
|
||||
|
@ -4925,10 +4909,6 @@ telemetry.test:
|
|||
kind: uint
|
||||
notification_emails:
|
||||
- telemetry-client-dev@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'all'
|
||||
products:
|
||||
|
@ -4943,10 +4923,6 @@ telemetry.test:
|
|||
keyed: true
|
||||
notification_emails:
|
||||
- telemetry-client-dev@mozilla.com
|
||||
products:
|
||||
- 'firefox'
|
||||
- 'fennec'
|
||||
- 'geckoview'
|
||||
record_in_processes:
|
||||
- 'all'
|
||||
products:
|
||||
|
|
|
@ -344,7 +344,7 @@ const Preferences = (window.Preferences = (function() {
|
|||
window.addEventListener("unload", Preferences, { once: true });
|
||||
|
||||
class Preference extends EventEmitter {
|
||||
constructor({ id, name, type, inverted, disabled }) {
|
||||
constructor({ id, type, inverted, disabled }) {
|
||||
super();
|
||||
this.on("change", this.onChange.bind(this));
|
||||
|
||||
|
@ -354,17 +354,10 @@ const Preferences = (window.Preferences = (function() {
|
|||
this.batching = false;
|
||||
|
||||
this.id = id;
|
||||
this._name = name || this.id;
|
||||
this.type = type;
|
||||
this.inverted = !!inverted;
|
||||
this._disabled = !!disabled;
|
||||
|
||||
// if the element has been inserted without the name attribute set,
|
||||
// we have nothing to do here
|
||||
if (!this.name) {
|
||||
throw new Error(`preference with id '${id}' doesn't have name`);
|
||||
}
|
||||
|
||||
// In non-instant apply mode, we must try and use the last saved state
|
||||
// from any previous opens of a child dialog instead of the value from
|
||||
// preferences, to pick up any edits a user may have made.
|
||||
|
@ -376,7 +369,7 @@ const Preferences = (window.Preferences = (function() {
|
|||
window.opener.document.nodePrincipal.isSystemPrincipal
|
||||
) {
|
||||
// Try to find the preference in the parent window.
|
||||
const preference = window.opener.Preferences.get(this.name);
|
||||
const preference = window.opener.Preferences.get(this.id);
|
||||
|
||||
// Don't use the value setter here, we don't want updateElements to be
|
||||
// prematurely fired.
|
||||
|
@ -392,9 +385,9 @@ const Preferences = (window.Preferences = (function() {
|
|||
}
|
||||
|
||||
_reportUnknownType() {
|
||||
const msg = `Preference with id=${this.id} and name=${
|
||||
this.name
|
||||
} has unknown type ${this.type}.`;
|
||||
const msg = `Preference with id=${this.id} has unknown type ${
|
||||
this.type
|
||||
}.`;
|
||||
Services.console.logStringMessage(msg);
|
||||
}
|
||||
|
||||
|
@ -530,20 +523,6 @@ const Preferences = (window.Preferences = (function() {
|
|||
this.updateElements();
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
set name(val) {
|
||||
if (val == this.name) {
|
||||
return val;
|
||||
}
|
||||
|
||||
this._name = val;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
|
@ -560,7 +539,7 @@ const Preferences = (window.Preferences = (function() {
|
|||
}
|
||||
|
||||
get locked() {
|
||||
return Services.prefs.prefIsLocked(this.name);
|
||||
return Services.prefs.prefIsLocked(this.id);
|
||||
}
|
||||
|
||||
get disabled() {
|
||||
|
@ -589,7 +568,7 @@ const Preferences = (window.Preferences = (function() {
|
|||
|
||||
get hasUserValue() {
|
||||
return (
|
||||
Services.prefs.prefHasUserValue(this.name) && this.value !== undefined
|
||||
Services.prefs.prefHasUserValue(this.id) && this.value !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -609,28 +588,28 @@ const Preferences = (window.Preferences = (function() {
|
|||
// Force a resync of value with preferences.
|
||||
switch (this.type) {
|
||||
case "int":
|
||||
return this._branch.getIntPref(this.name);
|
||||
return this._branch.getIntPref(this.id);
|
||||
case "bool": {
|
||||
const val = this._branch.getBoolPref(this.name);
|
||||
const val = this._branch.getBoolPref(this.id);
|
||||
return this.inverted ? !val : val;
|
||||
}
|
||||
case "wstring":
|
||||
return this._branch.getComplexValue(
|
||||
this.name,
|
||||
this.id,
|
||||
Ci.nsIPrefLocalizedString
|
||||
).data;
|
||||
case "string":
|
||||
case "unichar":
|
||||
return this._branch.getStringPref(this.name);
|
||||
return this._branch.getStringPref(this.id);
|
||||
case "fontname": {
|
||||
const family = this._branch.getStringPref(this.name);
|
||||
const family = this._branch.getStringPref(this.id);
|
||||
const fontEnumerator = Cc[
|
||||
"@mozilla.org/gfx/fontenumerator;1"
|
||||
].createInstance(Ci.nsIFontEnumerator);
|
||||
return fontEnumerator.getStandardFamilyName(family);
|
||||
}
|
||||
case "file": {
|
||||
const f = this._branch.getComplexValue(this.name, Ci.nsIFile);
|
||||
const f = this._branch.getComplexValue(this.id, Ci.nsIFile);
|
||||
return f;
|
||||
}
|
||||
default:
|
||||
|
@ -648,17 +627,17 @@ const Preferences = (window.Preferences = (function() {
|
|||
|
||||
// The special value undefined means 'reset preference to default'.
|
||||
if (val === undefined) {
|
||||
Services.prefs.clearUserPref(this.name);
|
||||
Services.prefs.clearUserPref(this.id);
|
||||
return val;
|
||||
}
|
||||
|
||||
// Force a resync of preferences with value.
|
||||
switch (this.type) {
|
||||
case "int":
|
||||
Services.prefs.setIntPref(this.name, val);
|
||||
Services.prefs.setIntPref(this.id, val);
|
||||
break;
|
||||
case "bool":
|
||||
Services.prefs.setBoolPref(this.name, this.inverted ? !val : val);
|
||||
Services.prefs.setBoolPref(this.id, this.inverted ? !val : val);
|
||||
break;
|
||||
case "wstring": {
|
||||
const pls = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(
|
||||
|
@ -666,7 +645,7 @@ const Preferences = (window.Preferences = (function() {
|
|||
);
|
||||
pls.data = val;
|
||||
Services.prefs.setComplexValue(
|
||||
this.name,
|
||||
this.id,
|
||||
Ci.nsIPrefLocalizedString,
|
||||
pls
|
||||
);
|
||||
|
@ -675,7 +654,7 @@ const Preferences = (window.Preferences = (function() {
|
|||
case "string":
|
||||
case "unichar":
|
||||
case "fontname":
|
||||
Services.prefs.setStringPref(this.name, val);
|
||||
Services.prefs.setStringPref(this.id, val);
|
||||
break;
|
||||
case "file": {
|
||||
let lf;
|
||||
|
@ -688,7 +667,7 @@ const Preferences = (window.Preferences = (function() {
|
|||
} else {
|
||||
lf = val.QueryInterface(Ci.nsIFile);
|
||||
}
|
||||
Services.prefs.setComplexValue(this.name, Ci.nsIFile, lf);
|
||||
Services.prefs.setComplexValue(this.id, Ci.nsIFile, lf);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -337,7 +337,7 @@ this.DateTimeInputBaseImplWidget = class {
|
|||
}
|
||||
|
||||
updateResetButtonVisibility() {
|
||||
if (this.isAnyFieldAvailable(false)) {
|
||||
if (this.isAnyFieldAvailable(false) && !this.isRequired()) {
|
||||
this.mResetButton.style.visibility = "";
|
||||
} else {
|
||||
this.mResetButton.style.visibility = "hidden";
|
||||
|
@ -438,6 +438,7 @@ this.DateTimeInputBaseImplWidget = class {
|
|||
}
|
||||
|
||||
this.mResetButton.disabled = this.mInputElement.disabled;
|
||||
this.updateResetButtonVisibility();
|
||||
}
|
||||
|
||||
isEmpty(aValue) {
|
||||
|
@ -513,6 +514,10 @@ this.DateTimeInputBaseImplWidget = class {
|
|||
return this.mInputElement.hasAttribute("readonly");
|
||||
}
|
||||
|
||||
isRequired() {
|
||||
return this.mInputElement.hasAttribute("required");
|
||||
}
|
||||
|
||||
handleEvent(aEvent) {
|
||||
this.log("handleEvent: " + aEvent.type);
|
||||
|
||||
|
|
|
@ -99,8 +99,8 @@ nsresult nsIconLoaderService::LoadIcon(nsIURI* aIconURI) {
|
|||
}
|
||||
|
||||
nsresult rv = loader->LoadImage(
|
||||
aIconURI, nullptr, nullptr, mozilla::net::RP_Unset, mContent->NodePrincipal(), 0, loadGroup,
|
||||
this, mContent, document, nsIRequest::LOAD_NORMAL, nullptr, mContentType, EmptyString(),
|
||||
aIconURI, nullptr, nullptr, mContent->NodePrincipal(), 0, loadGroup, this, mContent, document,
|
||||
nsIRequest::LOAD_NORMAL, nullptr, mContentType, EmptyString(),
|
||||
/* aUseUrgentStartForChannel */ false, getter_AddRefs(mIconRequest));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
|
Загрузка…
Ссылка в новой задаче