mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 04:27:41 +00:00
Merge autoland to mozilla-central a=merge
This commit is contained in:
commit
90035255ae
@ -1086,6 +1086,10 @@ pref("security.sandbox.gpu.level", 0);
|
||||
pref("security.sandbox.content.level", 3);
|
||||
#endif
|
||||
|
||||
#if defined(NIGHTLY_BUILD) && defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
pref("security.sandbox.mac.flash.enabled", false);
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
// This pref is introduced as part of bug 742434, the naming is inspired from
|
||||
// its Windows/Mac counterpart, but on Linux it's an integer which means:
|
||||
|
@ -137,8 +137,10 @@ appUpdater.prototype =
|
||||
|
||||
// true when updating is disabled by an administrator.
|
||||
get updateDisabledAndLocked() {
|
||||
return !this.updateEnabled &&
|
||||
Services.prefs.prefIsLocked("app.update.enabled");
|
||||
return (!this.updateEnabled &&
|
||||
Services.prefs.prefIsLocked("app.update.enabled")) ||
|
||||
(Services.policies &&
|
||||
!Services.policies.isAllowed("appUpdate"));
|
||||
},
|
||||
|
||||
// true when updating is enabled.
|
||||
|
@ -30,6 +30,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
|
||||
FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
|
||||
LanguagePrompt: "resource://gre/modules/LanguagePrompt.jsm",
|
||||
LightweightThemeConsumer: "resource://gre/modules/LightweightThemeConsumer.jsm",
|
||||
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
LoginManagerParent: "resource://gre/modules/LoginManagerParent.jsm",
|
||||
@ -1313,6 +1314,7 @@ var gBrowserInit = {
|
||||
}
|
||||
|
||||
// Misc. inits.
|
||||
new LightweightThemeConsumer(document);
|
||||
TabletModeUpdater.init();
|
||||
CombinedStopReload.ensureInitialized();
|
||||
gPrivateBrowsingUI.init();
|
||||
|
@ -51,7 +51,6 @@
|
||||
tabsintitlebar="true"
|
||||
#endif
|
||||
titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
|
||||
lightweightthemes="true"
|
||||
windowtype="navigator:browser"
|
||||
macanimationtype="document"
|
||||
screenX="4" screenY="4"
|
||||
|
@ -105,7 +105,7 @@ function openSelectPopup(selectPopup, mode = "key", selector = "select", win = w
|
||||
return Promise.all([popupShownPromise, mousePromise]);
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true, code: "ArrowDown" }, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {altKey: true}, win);
|
||||
return popupShownPromise;
|
||||
}
|
||||
|
||||
@ -144,15 +144,15 @@ async function doSelectTests(contentType, content) {
|
||||
is(selectPopup.childNodes[1].localName, "menuitem", "option is menuitem");
|
||||
is(selectPopup.childNodes[1].getAttribute("label"), "One", "option label");
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
is(menulist.menuBoxObject.activeChild, menulist.getItemAtIndex(2), "Select item 2");
|
||||
is(menulist.selectedIndex, isWindows ? 2 : 1, "Select item 2 selectedIndex");
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
is(menulist.menuBoxObject.activeChild, menulist.getItemAtIndex(3), "Select item 3");
|
||||
is(menulist.selectedIndex, isWindows ? 3 : 1, "Select item 3 selectedIndex");
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
|
||||
// On Windows, one can navigate on disabled menuitems
|
||||
is(menulist.menuBoxObject.activeChild, menulist.getItemAtIndex(9),
|
||||
@ -163,7 +163,7 @@ async function doSelectTests(contentType, content) {
|
||||
is(menulist.getItemAtIndex(i).disabled, i >= 4 && i <= 7, "item " + i + " disabled");
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
is(menulist.menuBoxObject.activeChild, menulist.getItemAtIndex(3), "Select item 3 again");
|
||||
is(menulist.selectedIndex, isWindows ? 3 : 1, "Select item 3 selectedIndex");
|
||||
|
||||
@ -205,7 +205,7 @@ async function doSelectTests(contentType, content) {
|
||||
is((await getClickEvents()), 1, "Tab away from select with no change - number of click events");
|
||||
|
||||
await openSelectPopup(selectPopup, "click");
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
await hideSelectPopup(selectPopup, "escape");
|
||||
is((await getInputEvents()), isWindows ? 2 : 1, "Open and close with change - number of input events");
|
||||
is((await getChangeEvents()), isWindows ? 2 : 1, "Open and close with change - number of change events");
|
||||
@ -435,7 +435,7 @@ add_task(async function test_event_order() {
|
||||
});
|
||||
});
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
await hideSelectPopup(selectPopup, mode);
|
||||
await eventsPromise;
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ function testOptionColors(index, item, menulist) {
|
||||
|
||||
// Press Down to move the selected item to the next item in the
|
||||
// list and check the colors of this item when it's not selected.
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
|
||||
if (expected.end) {
|
||||
return;
|
||||
|
@ -6,9 +6,9 @@ function hideSelectPopup(selectPopup, mode = "enter", win = window) {
|
||||
});
|
||||
|
||||
if (mode == "escape") {
|
||||
EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" }, win);
|
||||
EventUtils.synthesizeKey("KEY_Escape", {}, win);
|
||||
} else if (mode == "enter") {
|
||||
EventUtils.synthesizeKey("KEY_Enter", { code: "Enter" }, win);
|
||||
EventUtils.synthesizeKey("KEY_Enter", {}, win);
|
||||
} else if (mode == "click") {
|
||||
EventUtils.synthesizeMouseAtCenter(selectPopup.lastChild, { }, win);
|
||||
}
|
||||
|
@ -19,14 +19,14 @@ add_task(async function test_content_and_chrome_selection() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, testPage);
|
||||
await BrowserTestUtils.synthesizeMouse("#textarea", 0, 0, {}, gBrowser.selectedBrowser);
|
||||
await BrowserTestUtils.synthesizeKey("KEY_ArrowRight",
|
||||
{shiftKey: true, ctrlKey: true, code: "ArrowRight"}, gBrowser.selectedBrowser);
|
||||
{shiftKey: true, ctrlKey: true}, gBrowser.selectedBrowser);
|
||||
selectedText = DOMWindowUtils.GetSelectionAsPlaintext();
|
||||
is(selectedText, "Write something here", "The macOS services got the selected content text");
|
||||
|
||||
gURLBar.value = "test.mozilla.org";
|
||||
await gURLBar.focus();
|
||||
await BrowserTestUtils.synthesizeKey("KEY_ArrowRight",
|
||||
{shiftKey: true, ctrlKey: true, code: "ArrowRight"}, gBrowser.selectedBrowser);
|
||||
{shiftKey: true, ctrlKey: true}, gBrowser.selectedBrowser);
|
||||
selectedText = DOMWindowUtils.GetSelectionAsPlaintext();
|
||||
is(selectedText, "test.mozilla.org", "The macOS services got the selected chrome text");
|
||||
|
||||
@ -51,12 +51,12 @@ add_task(async function test_active_selection_switches_properly() {
|
||||
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, testPage1);
|
||||
await BrowserTestUtils.synthesizeMouse("#textarea", 0, 0, {}, gBrowser.selectedBrowser);
|
||||
await BrowserTestUtils.synthesizeKey("KEY_ArrowRight",
|
||||
{shiftKey: true, ctrlKey: true, code: "ArrowRight"}, gBrowser.selectedBrowser);
|
||||
{shiftKey: true, ctrlKey: true}, gBrowser.selectedBrowser);
|
||||
|
||||
let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, testPage2);
|
||||
await BrowserTestUtils.synthesizeMouse("#textarea", 0, 0, {}, gBrowser.selectedBrowser);
|
||||
await BrowserTestUtils.synthesizeKey("KEY_ArrowRight",
|
||||
{shiftKey: true, ctrlKey: true, code: "ArrowRight"}, gBrowser.selectedBrowser);
|
||||
{shiftKey: true, ctrlKey: true}, gBrowser.selectedBrowser);
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, tab1);
|
||||
selectedText = DOMWindowUtils.GetSelectionAsPlaintext();
|
||||
|
@ -54,7 +54,7 @@ add_task(async function() {
|
||||
resolve();
|
||||
}, true);
|
||||
|
||||
sendAsyncMessage("Test:SendKey", { key: "c", code: "KeyC" });
|
||||
sendAsyncMessage("Test:SendKey", {key: "c"});
|
||||
});
|
||||
|
||||
selection.modify("move", "right", "line");
|
||||
@ -73,7 +73,7 @@ add_task(async function() {
|
||||
resolve();
|
||||
}, true);
|
||||
|
||||
sendAsyncMessage("Test:SendKey", {key: "v", code: "KeyV"});
|
||||
sendAsyncMessage("Test:SendKey", {key: "v"});
|
||||
});
|
||||
|
||||
Assert.equal(main.innerHTML, "Test <b>Bold</b> After Textt <b>Bold</b>", "Copy and paste html");
|
||||
@ -92,7 +92,7 @@ add_task(async function() {
|
||||
resolve();
|
||||
}, true);
|
||||
|
||||
sendAsyncMessage("Test:SendKey", {key: "x", code: "KeyX"});
|
||||
sendAsyncMessage("Test:SendKey", {key: "x"});
|
||||
});
|
||||
|
||||
selection.modify("move", "left", "line");
|
||||
@ -111,7 +111,7 @@ add_task(async function() {
|
||||
resolve();
|
||||
}, true);
|
||||
|
||||
sendAsyncMessage("Test:SendKey", {key: "v", code: "KeyV"});
|
||||
sendAsyncMessage("Test:SendKey", {key: "v"});
|
||||
});
|
||||
|
||||
Assert.equal(main.innerHTML, "<i>Italic</i> Test <b>Bold</b> After<b></b>",
|
||||
@ -155,7 +155,7 @@ add_task(async function() {
|
||||
resolve();
|
||||
}, true);
|
||||
|
||||
sendAsyncMessage("Test:SendKey", {key: "v", code: "KeyV"});
|
||||
sendAsyncMessage("Test:SendKey", {key: "v"});
|
||||
});
|
||||
|
||||
// The new content should now include an image.
|
||||
|
@ -77,7 +77,7 @@ if (!navigator.platform.includes("Mac")) {
|
||||
let filePopup = document.getElementById("menu_FilePopup");
|
||||
popupShown = BrowserTestUtils.waitForEvent(filePopup, "popupshown");
|
||||
if (navigator.platform.includes("Win")) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
}
|
||||
await popupShown;
|
||||
|
||||
|
@ -122,10 +122,7 @@ add_task(async function() {
|
||||
// the message and adds its event listener before synthesizing the key.
|
||||
let keydownPromises = promiseEvent("keydown");
|
||||
await keydownPromises[0];
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {
|
||||
type: "keydown",
|
||||
code: "ArrowDown",
|
||||
});
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {type: "keydown"});
|
||||
await keydownPromises[1];
|
||||
|
||||
// urlbar.getPanelHeight
|
||||
|
15
browser/branding/aurora/locales/en-US/brand.ftl
Normal file
15
browser/branding/aurora/locales/en-US/brand.ftl
Normal file
@ -0,0 +1,15 @@
|
||||
# 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/.
|
||||
|
||||
## Firefox Brand
|
||||
##
|
||||
## Firefox must be treated as a brand, and kept in English.
|
||||
## It cannot be:
|
||||
## - Declined to adapt to grammatical case.
|
||||
## - Transliterated.
|
||||
## - Translated.
|
||||
##
|
||||
## Reference: https://www.mozilla.org/styleguide/communications/translation/
|
||||
|
||||
-brand-short-name = Firefox Developer Edition
|
@ -3,6 +3,8 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
[localization] @AB_CD@.jar:
|
||||
branding (en-US/**/*.ftl)
|
||||
|
||||
@AB_CD@.jar:
|
||||
% locale branding @AB_CD@ %locale/branding/
|
||||
|
15
browser/branding/nightly/locales/en-US/brand.ftl
Normal file
15
browser/branding/nightly/locales/en-US/brand.ftl
Normal file
@ -0,0 +1,15 @@
|
||||
# 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/.
|
||||
|
||||
## Firefox Brand
|
||||
##
|
||||
## Firefox must be treated as a brand, and kept in English.
|
||||
## It cannot be:
|
||||
## - Declined to adapt to grammatical case.
|
||||
## - Transliterated.
|
||||
## - Translated.
|
||||
##
|
||||
## Reference: https://www.mozilla.org/styleguide/communications/translation/
|
||||
|
||||
-brand-short-name = Nightly
|
@ -3,6 +3,8 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
[localization] @AB_CD@.jar:
|
||||
branding (en-US/**/*.ftl)
|
||||
|
||||
@AB_CD@.jar:
|
||||
% locale branding @AB_CD@ %locale/branding/
|
||||
|
15
browser/branding/official/locales/en-US/brand.ftl
Normal file
15
browser/branding/official/locales/en-US/brand.ftl
Normal file
@ -0,0 +1,15 @@
|
||||
# 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/.
|
||||
|
||||
## Firefox Brand
|
||||
##
|
||||
## Firefox must be treated as a brand, and kept in English.
|
||||
## It cannot be:
|
||||
## - Declined to adapt to grammatical case.
|
||||
## - Transliterated.
|
||||
## - Translated.
|
||||
##
|
||||
## Reference: https://www.mozilla.org/styleguide/communications/translation/
|
||||
|
||||
-brand-short-name = Firefox
|
@ -3,6 +3,8 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
[localization] @AB_CD@.jar:
|
||||
branding (%*.ftl)
|
||||
|
||||
@AB_CD@.jar:
|
||||
% locale branding @AB_CD@ %locale/branding/
|
||||
|
15
browser/branding/unofficial/locales/en-US/brand.ftl
Normal file
15
browser/branding/unofficial/locales/en-US/brand.ftl
Normal file
@ -0,0 +1,15 @@
|
||||
# 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/.
|
||||
|
||||
## Firefox Brand
|
||||
##
|
||||
## Firefox must be treated as a brand, and kept in English.
|
||||
## It cannot be:
|
||||
## - Declined to adapt to grammatical case.
|
||||
## - Transliterated.
|
||||
## - Translated.
|
||||
##
|
||||
## Reference: https://www.mozilla.org/styleguide/communications/translation/
|
||||
|
||||
-brand-short-name = Nightly
|
@ -3,6 +3,8 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
[localization] @AB_CD@.jar:
|
||||
branding (en-US/**/*.ftl)
|
||||
|
||||
@AB_CD@.jar:
|
||||
% locale branding @AB_CD@ %locale/branding/
|
||||
|
@ -17,12 +17,12 @@ add_task(async function testUpDownKeys() {
|
||||
for (let button of buttons) {
|
||||
if (button.disabled)
|
||||
continue;
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
Assert.equal(document.commandDispatcher.focusedElement, button,
|
||||
"The correct button should be focused after navigating downward");
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
Assert.equal(document.commandDispatcher.focusedElement, buttons[0],
|
||||
"Pressing upwards should cycle around and select the first button again");
|
||||
|
||||
@ -30,7 +30,7 @@ add_task(async function testUpDownKeys() {
|
||||
let button = buttons[i];
|
||||
if (button.disabled)
|
||||
continue;
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
Assert.equal(document.commandDispatcher.focusedElement, button,
|
||||
"The first button should be focused after navigating upward");
|
||||
}
|
||||
@ -48,7 +48,7 @@ add_task(async function testEnterKeyBehaviors() {
|
||||
let buttons = PanelView.forNode(PanelUI.mainView).getNavigableElements();
|
||||
|
||||
// Navigate to the 'Help' button, which points to a subview.
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
let focusedElement = document.commandDispatcher.focusedElement;
|
||||
Assert.equal(focusedElement, buttons[buttons.length - 1],
|
||||
"The last button should be focused after navigating upward");
|
||||
@ -56,10 +56,10 @@ add_task(async function testEnterKeyBehaviors() {
|
||||
promise = BrowserTestUtils.waitForEvent(PanelUI.helpView, "ViewShown");
|
||||
// Make sure the Help button is in focus.
|
||||
while (!focusedElement || !focusedElement.id || focusedElement.id != kHelpButtonId) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
focusedElement = document.commandDispatcher.focusedElement;
|
||||
}
|
||||
EventUtils.synthesizeKey("VK_RETURN", { code: "Enter" });
|
||||
EventUtils.synthesizeKey("KEY_Enter", {});
|
||||
await promise;
|
||||
|
||||
let helpButtons = PanelView.forNode(PanelUI.helpView).getNavigableElements();
|
||||
@ -71,33 +71,33 @@ add_task(async function testEnterKeyBehaviors() {
|
||||
let button = helpButtons[i];
|
||||
if (button.disabled)
|
||||
continue;
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
focusedElement = document.commandDispatcher.focusedElement;
|
||||
Assert.equal(focusedElement, button, "The first button should be focused after navigating upward");
|
||||
}
|
||||
|
||||
// Make sure the back button is in focus again.
|
||||
while (focusedElement != helpButtons[0]) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
focusedElement = document.commandDispatcher.focusedElement;
|
||||
}
|
||||
|
||||
// The first button is the back button. Hittin Enter should navigate us back.
|
||||
promise = BrowserTestUtils.waitForEvent(PanelUI.mainView, "ViewShown");
|
||||
EventUtils.synthesizeKey("VK_RETURN", { code: "Enter" });
|
||||
EventUtils.synthesizeKey("KEY_Enter", {});
|
||||
await promise;
|
||||
|
||||
// Let's test a 'normal' command button.
|
||||
focusedElement = document.commandDispatcher.focusedElement;
|
||||
const kFindButtonId = "appMenu-find-button";
|
||||
while (!focusedElement || !focusedElement.id || focusedElement.id != kFindButtonId) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
focusedElement = document.commandDispatcher.focusedElement;
|
||||
}
|
||||
Assert.equal(focusedElement.id, kFindButtonId, "Find button should be selected");
|
||||
|
||||
promise = promisePanelHidden(window);
|
||||
EventUtils.synthesizeKey("VK_RETURN", { code: "Enter" });
|
||||
EventUtils.synthesizeKey("KEY_Enter", {});
|
||||
await promise;
|
||||
|
||||
Assert.ok(!gFindBar.hidden, "Findbar should have opened");
|
||||
@ -112,7 +112,7 @@ add_task(async function testLeftRightKeys() {
|
||||
// Navigate to the 'Help' button, which points to a subview.
|
||||
let focusedElement = document.commandDispatcher.focusedElement;
|
||||
while (!focusedElement || !focusedElement.id || focusedElement.id != kHelpButtonId) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
focusedElement = document.commandDispatcher.focusedElement;
|
||||
}
|
||||
Assert.equal(focusedElement.id, kHelpButtonId, "The last button should be focused after navigating upward");
|
||||
@ -120,12 +120,12 @@ add_task(async function testLeftRightKeys() {
|
||||
// Hitting ArrowRight on a button that points to a subview should navigate us
|
||||
// there.
|
||||
promise = BrowserTestUtils.waitForEvent(PanelUI.helpView, "ViewShown");
|
||||
EventUtils.synthesizeKey("KEY_ArrowRight", { code: "ArrowRight" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowRight", {});
|
||||
await promise;
|
||||
|
||||
// Hitting ArrowLeft should navigate us back.
|
||||
promise = BrowserTestUtils.waitForEvent(PanelUI.mainView, "ViewShown");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", { code: "ArrowLeft" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {});
|
||||
await promise;
|
||||
|
||||
focusedElement = document.commandDispatcher.focusedElement;
|
||||
@ -147,12 +147,12 @@ add_task(async function testTabKey() {
|
||||
for (let button of buttons) {
|
||||
if (button.disabled)
|
||||
continue;
|
||||
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
|
||||
EventUtils.synthesizeKey("KEY_Tab", {});
|
||||
Assert.equal(document.commandDispatcher.focusedElement, button,
|
||||
"The correct button should be focused after tabbing");
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
|
||||
EventUtils.synthesizeKey("KEY_Tab", {});
|
||||
Assert.equal(document.commandDispatcher.focusedElement, buttons[0],
|
||||
"Pressing tab should cycle around and select the first button again");
|
||||
|
||||
@ -160,12 +160,12 @@ add_task(async function testTabKey() {
|
||||
let button = buttons[i];
|
||||
if (button.disabled)
|
||||
continue;
|
||||
EventUtils.synthesizeKey("Tab", { code: "Tab", shiftKey: true });
|
||||
EventUtils.synthesizeKey("Tab", {shiftKey: true});
|
||||
Assert.equal(document.commandDispatcher.focusedElement, button,
|
||||
"The correct button should be focused after shift + tabbing");
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab", shiftKey: true });
|
||||
EventUtils.synthesizeKey("KEY_Tab", {shiftKey: true});
|
||||
Assert.equal(document.commandDispatcher.focusedElement, buttons[buttons.length - 1],
|
||||
"Pressing shift + tab should cycle around and select the last button again");
|
||||
|
||||
@ -186,9 +186,9 @@ add_task(async function testInterleavedTabAndArrowKeys() {
|
||||
if (button.disabled)
|
||||
continue;
|
||||
if (tab) {
|
||||
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
|
||||
EventUtils.synthesizeKey("KEY_Tab", {});
|
||||
} else {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
}
|
||||
tab = !tab;
|
||||
}
|
||||
@ -212,7 +212,7 @@ add_task(async function testSpaceDownAfterTabNavigation() {
|
||||
for (button of buttons) {
|
||||
if (button.disabled)
|
||||
continue;
|
||||
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
|
||||
EventUtils.synthesizeKey("KEY_Tab", {});
|
||||
if (button.id == kHelpButtonId) {
|
||||
break;
|
||||
}
|
||||
@ -224,7 +224,7 @@ add_task(async function testSpaceDownAfterTabNavigation() {
|
||||
// Pressing down space on a button that points to a subview should navigate us
|
||||
// there, before keyup.
|
||||
promise = BrowserTestUtils.waitForEvent(PanelUI.helpView, "ViewShown");
|
||||
EventUtils.synthesizeKey(" ", { code: "Space", type: "keydown" });
|
||||
EventUtils.synthesizeKey(" ", {type: "keydown"});
|
||||
await promise;
|
||||
|
||||
promise = promisePanelHidden(window);
|
||||
|
@ -20,6 +20,12 @@ const POLICIES_FILENAME = "policies.json";
|
||||
// and set PREF_ALTERNATE_PATH in firefox.js as:
|
||||
// /your/repo/browser/components/enterprisepolicies/helpers/sample.json
|
||||
const PREF_ALTERNATE_PATH = "browser.policies.alternatePath";
|
||||
// For testing, we may want to set PREF_ALTERNATE_PATH to point to a file
|
||||
// relative to the test root directory. In order to enable this, the string
|
||||
// below may be placed at the beginning of that preference value and it will
|
||||
// be replaced with the path to the test root directory.
|
||||
const MAGIC_TEST_ROOT_PREFIX = "<test-root>";
|
||||
const PREF_TEST_ROOT = "mochitest.testRoot";
|
||||
|
||||
// This pref is meant to be temporary: it will only be used while we're
|
||||
// testing this feature without rolling it out officially. When the
|
||||
@ -319,6 +325,18 @@ class JSONPoliciesProvider {
|
||||
// the admin-provided policies by changing the user-controlled prefs.
|
||||
// This pref is only meant for tests, so it's fine to use this extra
|
||||
// synchronous configFile.exists() above.
|
||||
if (alternatePath.startsWith(MAGIC_TEST_ROOT_PREFIX)) {
|
||||
// Intentionally not using a default value on this pref lookup. If no
|
||||
// test root is set, we are not currently testing and this function
|
||||
// should throw rather than returning something.
|
||||
let testRoot = Services.prefs.getStringPref(PREF_TEST_ROOT);
|
||||
let relativePath = alternatePath.substring(MAGIC_TEST_ROOT_PREFIX.length);
|
||||
if (AppConstants.platform == "win") {
|
||||
relativePath = relativePath.replace(/\//g, "\\");
|
||||
}
|
||||
alternatePath = testRoot + relativePath;
|
||||
}
|
||||
|
||||
configFile = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsIFile);
|
||||
configFile.initWithPath(alternatePath);
|
||||
|
@ -37,6 +37,14 @@ this.Policies = {
|
||||
}
|
||||
},
|
||||
|
||||
"DisableAppUpdate": {
|
||||
onBeforeAddons(manager, param) {
|
||||
if (param == true) {
|
||||
manager.disallowFeature("appUpdate");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"display_menu_bar": {
|
||||
onBeforeUIStartup(manager, param) {
|
||||
if (param == true) {
|
||||
|
@ -10,6 +10,15 @@
|
||||
"enum": [true]
|
||||
},
|
||||
|
||||
"DisableAppUpdate": {
|
||||
"description": "Prevent the browser from updating.",
|
||||
"first_available": "60.0",
|
||||
"enterprise_only": true,
|
||||
|
||||
"type": "boolean",
|
||||
"enum": [true]
|
||||
},
|
||||
|
||||
"display_menu_bar": {
|
||||
"description": "Causes the menu bar to be displayed by default.",
|
||||
"first_available": "60.0",
|
||||
|
@ -11,6 +11,7 @@ support-files =
|
||||
[browser_policies_setAndLockPref_API.js]
|
||||
[browser_policies_simple_policies.js]
|
||||
[browser_policies_validate_and_parse_API.js]
|
||||
[browser_policy_app_update.js]
|
||||
[browser_policy_block_set_desktop_background.js]
|
||||
[browser_policy_default_browser_check.js]
|
||||
[browser_policy_disable_fxscreenshots.js]
|
||||
|
@ -0,0 +1,19 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
var updateService = Cc["@mozilla.org/updates/update-service;1"].
|
||||
getService(Ci.nsIApplicationUpdateService);
|
||||
|
||||
// This test is intended to ensure that nsIUpdateService::canCheckForUpdates
|
||||
// is true before the "DisableAppUpdate" policy is applied. Testing that
|
||||
// nsIUpdateService::canCheckForUpdates is false after the "DisableAppUpdate"
|
||||
// policy is applied needs to occur in a different test since the policy does
|
||||
// not properly take effect unless it is applied during application startup.
|
||||
add_task(async function test_updates_pre_policy() {
|
||||
is(Services.policies.isAllowed("appUpdate"), true,
|
||||
"Since no policies have been set, appUpdate should be allowed by default");
|
||||
|
||||
is(updateService.canCheckForUpdates, true,
|
||||
"Should be able to check for updates before any policies are in effect.");
|
||||
});
|
@ -0,0 +1,8 @@
|
||||
[DEFAULT]
|
||||
prefs =
|
||||
browser.policies.enabled=true
|
||||
browser.policies.alternatePath='<test-root>/browser/components/enterprisepolicies/tests/browser/disable_app_update/config_disable_app_update.json'
|
||||
support-files =
|
||||
config_disable_app_update.json
|
||||
|
||||
[browser_policy_disable_app_update.js]
|
@ -0,0 +1,14 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
var updateService = Cc["@mozilla.org/updates/update-service;1"].
|
||||
getService(Ci.nsIApplicationUpdateService);
|
||||
|
||||
add_task(async function test_updates_post_policy() {
|
||||
is(Services.policies.isAllowed("appUpdate"), false,
|
||||
"appUpdate should be disabled by policy.");
|
||||
|
||||
is(updateService.canCheckForUpdates, false,
|
||||
"Should not be able to check for updates with DisableAppUpdate enabled.");
|
||||
});
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"policies": {
|
||||
"DisableAppUpdate": true
|
||||
}
|
||||
}
|
@ -8,5 +8,6 @@ with Files("**"):
|
||||
BUG_COMPONENT = ("Firefox", "General")
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'browser/browser.ini'
|
||||
'browser/browser.ini',
|
||||
'browser/disable_app_update/browser.ini'
|
||||
]
|
||||
|
@ -22,9 +22,9 @@ async function testContextmenu(menuitem) {
|
||||
EventUtils.synthesizeMouseAtCenter(menuitem, {type: "contextmenu", button: 2});
|
||||
await promiseEvent;
|
||||
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, null);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
BrowserTestUtils.waitForEvent(menuitem, "DOMMenuItemActive");
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {});
|
||||
BrowserTestUtils.waitForEvent(menuitem, "DOMMenuItemActive");
|
||||
EventUtils.sendKey("return");
|
||||
let newTab = await promiseTabOpened;
|
||||
|
@ -379,7 +379,8 @@
|
||||
label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
|
||||
onsyncfrompreference="return gMainPane.updateButtons('translateButton',
|
||||
'browser.translation.detectLanguage');"/>
|
||||
<hbox id="bingAttribution" hidden="true">
|
||||
<hbox id="bingAttribution" hidden="true" align="center">
|
||||
<separator orient="vertical" class="thin"/>
|
||||
<label>&translation.options.attribution.beforeLogo;</label>
|
||||
<separator orient="vertical" class="thin"/>
|
||||
<image id="translationAttributionImage" aria-label="Microsoft Translator"
|
||||
|
@ -114,7 +114,7 @@ add_task(async function test_nested() {
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
// Modify the input field's value.
|
||||
await BrowserTestUtils.synthesizeKey("m", {code: "KeyM"}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("m", {}, browser);
|
||||
|
||||
// Remove the tab and check that we stored form data correctly.
|
||||
await promiseRemoveTab(tab);
|
||||
@ -151,7 +151,7 @@ add_task(async function test_design_mode() {
|
||||
await promiseBrowserLoaded(browser);
|
||||
|
||||
// Modify the document content.
|
||||
await BrowserTestUtils.synthesizeKey("m", {code: "KeyM"}, browser);
|
||||
await BrowserTestUtils.synthesizeKey("m", {}, browser);
|
||||
|
||||
// Close and restore the tab.
|
||||
await promiseRemoveTab(tab);
|
||||
|
@ -119,7 +119,7 @@ function triggerAutofillAndCheckProfile(profile) {
|
||||
promises.push(checkFieldAutofilled);
|
||||
}
|
||||
// Press Enter key and trigger form autofill.
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
@ -243,10 +243,10 @@ function initPopupListener() {
|
||||
|
||||
async function triggerPopupAndHoverItem(fieldSelector, selectIndex) {
|
||||
await focusAndWaitForFieldsIdentified(fieldSelector);
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
for (let i = 0; i <= selectIndex; i++) {
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
}
|
||||
await notifySelectedIndex(selectIndex);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ async function setupAddressStorage() {
|
||||
|
||||
add_task(async function check_autocomplete_on_autofocus_field() {
|
||||
await setupAddressStorage();
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
|
||||
|
@ -54,7 +54,7 @@ add_task(async function history_only_menu_checking() {
|
||||
await setupFormHistory();
|
||||
|
||||
await setInput("#tel", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["+1234567890"], false);
|
||||
});
|
||||
@ -67,7 +67,7 @@ add_task(async function all_saved_fields_less_than_threshold() {
|
||||
});
|
||||
|
||||
await setInput("#email", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["foo@mozilla.com"], false);
|
||||
|
||||
@ -79,7 +79,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
await setupAddressStorage();
|
||||
|
||||
await setInput("#organization", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({
|
||||
@ -89,7 +89,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
));
|
||||
|
||||
await setInput("#street-address", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({
|
||||
@ -99,7 +99,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
));
|
||||
|
||||
await setInput("#tel", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({
|
||||
@ -109,7 +109,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
));
|
||||
|
||||
await setInput("#address-line1", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({
|
||||
@ -122,7 +122,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
// Display history search result if no matched data in addresses.
|
||||
add_task(async function check_fallback_for_mismatched_field() {
|
||||
await setInput("#email", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["foo@mozilla.com"], false);
|
||||
});
|
||||
@ -134,7 +134,7 @@ add_task(async function check_search_result_for_pref_off() {
|
||||
});
|
||||
|
||||
await setInput("#tel", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["+1234567890"], false);
|
||||
|
||||
@ -144,7 +144,7 @@ add_task(async function check_search_result_for_pref_off() {
|
||||
// Autofill the address from dropdown menu.
|
||||
add_task(async function check_fields_after_form_autofill() {
|
||||
const focusedInput = await setInput("#organization", "Moz");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({
|
||||
@ -152,16 +152,16 @@ add_task(async function check_fields_after_form_autofill() {
|
||||
secondary: FormAutofillUtils.toOneLineAddress(address["street-address"]),
|
||||
})
|
||||
).slice(1));
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await triggerAutofillAndCheckProfile(MOCK_STORAGE[1]);
|
||||
synthesizeKey("KEY_Escape", {code: "Escape"});
|
||||
synthesizeKey("KEY_Escape", {});
|
||||
is(focusedInput.value, "Mozilla", "Filled field shouldn't be reverted by ESC key");
|
||||
});
|
||||
|
||||
// Fallback to history search after autofill address.
|
||||
add_task(async function check_fallback_after_form_autofill() {
|
||||
await setInput("#tel", "", true);
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["+1234567890"], false);
|
||||
});
|
||||
@ -171,7 +171,7 @@ add_task(async function check_form_autofill_resume() {
|
||||
document.querySelector("#tel").blur();
|
||||
document.querySelector("#form1").reset();
|
||||
await setInput("#tel", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({
|
||||
|
@ -62,7 +62,7 @@ add_task(async function history_only_menu_checking() {
|
||||
await setupFormHistory();
|
||||
|
||||
await setInput("#cc-exp-year", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["2023"], false);
|
||||
});
|
||||
@ -72,7 +72,7 @@ add_task(async function all_saved_fields_less_than_threshold() {
|
||||
await addCreditCard(reducedMockRecord);
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries([reducedMockRecord].map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
@ -87,7 +87,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
await setupCreditCardStorage();
|
||||
|
||||
await setInput("#cc-number", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primaryAffix: cc.ccNumberFmt.affix,
|
||||
@ -96,7 +96,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
})));
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
@ -104,7 +104,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
})));
|
||||
|
||||
await setInput("#cc-exp-year", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-exp-year"],
|
||||
@ -112,7 +112,7 @@ add_task(async function check_menu_when_both_existed() {
|
||||
})));
|
||||
|
||||
await setInput("#cc-exp-month", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-exp-month"],
|
||||
@ -127,7 +127,7 @@ add_task(async function check_fallback_for_mismatched_field() {
|
||||
await addCreditCard(reducedMockRecord);
|
||||
|
||||
await setInput("#cc-exp-year", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["2023"], false);
|
||||
|
||||
@ -143,7 +143,7 @@ add_task(async function check_search_result_for_pref_off() {
|
||||
});
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["John Smith"], false);
|
||||
|
||||
@ -154,21 +154,21 @@ add_task(async function check_search_result_for_pref_off() {
|
||||
add_task(async function check_fields_after_form_autofill() {
|
||||
await setInput("#cc-exp-year", 202);
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.slice(1).map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-exp-year"],
|
||||
secondary: cc.ccNumberFmt.affix + cc.ccNumberFmt.label,
|
||||
})));
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await triggerAutofillAndCheckProfile(MOCK_STORAGE[1]);
|
||||
});
|
||||
|
||||
// Fallback to history search after autofill address.
|
||||
add_task(async function check_fallback_after_form_autofill() {
|
||||
await setInput("#cc-name", "", true);
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["John Smith"], false);
|
||||
});
|
||||
@ -179,7 +179,7 @@ add_task(async function check_form_autofill_resume() {
|
||||
document.querySelector("#form1").reset();
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
|
@ -71,7 +71,7 @@ add_task(async function simple_clear() {
|
||||
await triggerAutofillAndCheckProfile(MOCK_ADDR_STORAGE[0]);
|
||||
|
||||
await triggerPopupAndHoverItem("#tel", 0);
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
checkIsFormCleared();
|
||||
});
|
||||
|
||||
@ -80,7 +80,7 @@ add_task(async function clear_adapted_record() {
|
||||
await triggerAutofillAndCheckProfile(MOCK_ADDR_STORAGE[0]);
|
||||
|
||||
await triggerPopupAndHoverItem("#street-address", 0);
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
checkIsFormCleared();
|
||||
});
|
||||
|
||||
@ -91,7 +91,7 @@ add_task(async function clear_modified_form() {
|
||||
await setInput("#tel", "+1111111111", true);
|
||||
|
||||
await triggerPopupAndHoverItem("#street-address", 0);
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
checkIsFormCleared({tel: "+1111111111"});
|
||||
});
|
||||
|
||||
@ -103,7 +103,7 @@ add_task(async function clear_distinct_section() {
|
||||
await triggerPopupAndHoverItem("#organization", 0);
|
||||
await triggerAutofillAndCheckProfile(MOCK_ADDR_STORAGE[0]);
|
||||
await triggerPopupAndHoverItem("#street-address", 0);
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
|
||||
for (const [id, val] of Object.entries(MOCK_CC_STORAGE[0])) {
|
||||
const element = document.getElementById(id);
|
||||
@ -115,7 +115,7 @@ add_task(async function clear_distinct_section() {
|
||||
}
|
||||
|
||||
await triggerPopupAndHoverItem("#cc-name", 0);
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
checkIsFormCleared();
|
||||
});
|
||||
|
||||
|
@ -51,12 +51,12 @@ add_task(async function history_only_menu_checking() {
|
||||
await setupFormHistory();
|
||||
|
||||
await setInput("#cc-number", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(["1234000056780000"], false);
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await notExpectPopup();
|
||||
});
|
||||
|
||||
@ -65,7 +65,7 @@ add_task(async function check_menu_when_both_with_autocomplete_off() {
|
||||
await setupCreditCardStorage();
|
||||
|
||||
await setInput("#cc-number", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primaryAffix: cc.ccNumberFmt.affix,
|
||||
@ -74,7 +74,7 @@ add_task(async function check_menu_when_both_with_autocomplete_off() {
|
||||
})));
|
||||
|
||||
await setInput("#cc-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(patchRecordCCNumber).map(cc => JSON.stringify({
|
||||
primary: cc["cc-name"],
|
||||
|
@ -50,7 +50,7 @@ function addInputField(form, className) {
|
||||
async function checkFormChangeHappened(formId) {
|
||||
info("expecting form changed");
|
||||
await focusAndWaitForFieldsIdentified(`#${formId} input[name=tel]`);
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address.tel, secondary: address.name})
|
||||
@ -60,7 +60,7 @@ async function checkFormChangeHappened(formId) {
|
||||
addInputField(document.querySelector(`#${formId}`), "address-level2");
|
||||
|
||||
await focusAndWaitForFieldsIdentified(`#${formId} input[name=name]`);
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address.name, secondary: address["address-level2"]})
|
||||
@ -71,7 +71,7 @@ async function checkFormChangeHappened(formId) {
|
||||
addInputField(document.querySelector(`#${formId}`), "address-level2");
|
||||
|
||||
await focusAndWaitForFieldsIdentified(`#${formId} input[name=address-level2]`, true);
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(MOCK_STORAGE.map(address =>
|
||||
JSON.stringify({primary: address["address-level2"], secondary: address.name})
|
||||
|
@ -55,22 +55,22 @@ add_task(async function setup_storage() {
|
||||
add_task(async function check_preview() {
|
||||
const focusedInput = await setInput("#organization", "");
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkFormFieldsStyle(null);
|
||||
|
||||
for (let i = 0; i < MOCK_STORAGE.length; i++) {
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await notifySelectedIndex(i);
|
||||
checkFormFieldsStyle(MOCK_STORAGE[i]);
|
||||
}
|
||||
|
||||
// Navigate to the footer
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await notifySelectedIndex(MOCK_STORAGE.length);
|
||||
checkFormFieldsStyle(null);
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await notifySelectedIndex(-1);
|
||||
checkFormFieldsStyle(null);
|
||||
|
||||
|
@ -89,7 +89,7 @@ function checkFormFilled(selector, address) {
|
||||
promises.push(...checkElementFilled(element, converted));
|
||||
}
|
||||
}
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
@ -106,19 +106,19 @@ add_task(async function autofill_with_level1_code() {
|
||||
await setupAddressStorage();
|
||||
|
||||
await setInput("#organization-en", "Mozilla Toronto");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
// Replace address level 1 code with full name in English for test result
|
||||
let result = Object.assign({}, MOCK_STORAGE[1], {"address-level1": "Ontario"});
|
||||
await checkFormFilled("#form-en", result);
|
||||
|
||||
await setInput("#organization-fr", "Mozilla Vancouver");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
// Replace address level 1 code with full name in French for test result
|
||||
result = Object.assign({}, MOCK_STORAGE[0], {"address-level1": "Colombie-Britannique"});
|
||||
await checkFormFilled("#form-fr", result);
|
||||
@ -129,19 +129,19 @@ add_task(async function autofill_with_level1_code() {
|
||||
// Autofill the address with address level 1 full name.
|
||||
add_task(async function autofill_with_level1_full_name() {
|
||||
await setInput("#organization-en", "ExpoCité");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
// Replace address level 1 code with full name in French for test result
|
||||
let result = Object.assign({}, MOCK_STORAGE[3], {"address-level1": "Quebec"});
|
||||
await checkFormFilled("#form-en", result);
|
||||
|
||||
await setInput("#organization-fr", "Prince of Wales Northern Heritage");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
// Replace address level 1 code with full name in English for test result
|
||||
result = Object.assign({}, MOCK_STORAGE[2], {"address-level1": "Territoires du Nord-Ouest"});
|
||||
await checkFormFilled("#form-fr", result);
|
||||
|
@ -33,19 +33,19 @@ add_task(async function setupStorage() {
|
||||
|
||||
add_task(async function check_switch_form_popup() {
|
||||
await setInput("#additional-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
|
||||
// We need an intentional wait here before switching form.
|
||||
await sleep();
|
||||
await setInput("#organization", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
const {open: popupOpen} = await getPopupState();
|
||||
is(popupOpen, false);
|
||||
|
||||
await sleep();
|
||||
await setInput("#given-name", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
});
|
||||
|
||||
|
@ -75,7 +75,7 @@ add_task(async function check_storage_after_another_address_submitted() {
|
||||
ok(matching, "New address saved as expected");
|
||||
|
||||
await setInput("#organization", "");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
checkMenuEntries(addressesInMenu.map(address =>
|
||||
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
|
||||
@ -110,10 +110,10 @@ add_task(async function check_storage_after_form_submitted() {
|
||||
TEST_ADDRESSES[1].country = "US";
|
||||
|
||||
await setInput("#organization", "Moz");
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
await expectPopup();
|
||||
synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
|
||||
synthesizeKey("KEY_Enter", {code: "Enter"});
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
clickOnElement("input[type=submit]");
|
||||
|
||||
let expectedAddresses = TEST_ADDRESSES.slice(0);
|
||||
|
@ -382,7 +382,7 @@ this.PreferenceExperiments = {
|
||||
const newValue = getPref(UserPreferences, preferenceName, preferenceType);
|
||||
if (newValue !== preferenceValue) {
|
||||
PreferenceExperiments.stop(experimentName, {
|
||||
didResetValue: false,
|
||||
resetValue: false,
|
||||
reason: "user-preference-changed",
|
||||
}).catch(Cu.reportError);
|
||||
}
|
||||
|
@ -1043,3 +1043,38 @@ decorate_task(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Should send the correct event telemetry when a study ends because
|
||||
// the user changed preferences during a browser run.
|
||||
decorate_task(
|
||||
withMockPreferences,
|
||||
withStub(TelemetryEvents, "sendEvent"),
|
||||
async function testPrefChangeEventTelemetry(mockPreferences, sendEventStub) {
|
||||
is(Preferences.get("fake.preference"), null, "preference should start unset");
|
||||
|
||||
await PreferenceExperiments.start({
|
||||
name: "test",
|
||||
branch: "branch",
|
||||
preferenceName: "fake.preference",
|
||||
preferenceValue: "experimentvalue",
|
||||
preferenceBranchType: "default",
|
||||
preferenceType: "string",
|
||||
});
|
||||
|
||||
// setting the preference on the user branch should trigger the observer to stop the experiment
|
||||
mockPreferences.set("fake.preference", "uservalue", "user");
|
||||
|
||||
// let the event loop tick to run the observer
|
||||
await Promise.resolve();
|
||||
|
||||
is(sendEventStub.getCall(0).args[0], "enroll", "There is an enrollment event from start()");
|
||||
Assert.deepEqual(
|
||||
sendEventStub.getCall(1).args,
|
||||
["unenroll", "preference_study", "test", {
|
||||
didResetValue: "false",
|
||||
reason: "user-preference-changed",
|
||||
}],
|
||||
"stop should send a telemetry event indicating the user unenrolled manually",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -779,21 +779,26 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
|
||||
# doesn't match the target C compiler.
|
||||
# As a special case, since clang supports all kinds of targets in the same
|
||||
# executable, when cross compiling with clang, default to the same compiler
|
||||
# as the target compiler, resetting flags.
|
||||
# as the target compiler, resetting flags. However, Android NDK clangs do
|
||||
# not function as host compilers -- they're target compilers only -- so
|
||||
# don't use clang target as host if the target OS is Android.
|
||||
if host_or_target == host:
|
||||
if other_c_compiler is not None:
|
||||
args = (c_compiler, other_c_compiler)
|
||||
else:
|
||||
args = ()
|
||||
|
||||
@depends(provided_compiler, other_compiler, cross_compiling, *args)
|
||||
def provided_compiler(value, other_compiler, cross_compiling, *args):
|
||||
@depends(provided_compiler, other_compiler, cross_compiling,
|
||||
target, *args)
|
||||
def provided_compiler(value, other_compiler, cross_compiling,
|
||||
target, *args):
|
||||
if value:
|
||||
return value
|
||||
c_compiler, other_c_compiler = args if args else (None, None)
|
||||
if not cross_compiling and c_compiler == other_c_compiler:
|
||||
return other_compiler
|
||||
if cross_compiling and other_compiler.type == 'clang':
|
||||
if cross_compiling and other_compiler.type == 'clang' and \
|
||||
target.os != 'Android':
|
||||
return namespace(**{
|
||||
k: [] if k == 'flags' else v
|
||||
for k, v in other_compiler.__dict__.iteritems()
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
const {
|
||||
UPDATE_PREVIEW_TEXT,
|
||||
UPDATE_SHOW_ALL_FONTS,
|
||||
} = require("./index");
|
||||
|
||||
module.exports = {
|
||||
@ -21,14 +20,4 @@ module.exports = {
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Update whether to show all fonts in the font inspector
|
||||
*/
|
||||
updateShowAllFonts(showAllFonts) {
|
||||
return {
|
||||
type: UPDATE_SHOW_ALL_FONTS,
|
||||
showAllFonts,
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
|
@ -13,10 +13,11 @@ module.exports = {
|
||||
/**
|
||||
* Update the list of fonts in the font inspector
|
||||
*/
|
||||
updateFonts(fonts) {
|
||||
updateFonts(fonts, otherFonts) {
|
||||
return {
|
||||
type: UPDATE_FONTS,
|
||||
fonts,
|
||||
otherFonts,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,4 @@ createEnum([
|
||||
// Update the preview text.
|
||||
"UPDATE_PREVIEW_TEXT",
|
||||
|
||||
// Update whether to show all fonts.
|
||||
"UPDATE_SHOW_ALL_FONTS",
|
||||
|
||||
], module.exports);
|
||||
|
@ -4,84 +4,123 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const FontPreview = createFactory(require("./FontPreview"));
|
||||
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
class Font extends PureComponent {
|
||||
static get propTypes() {
|
||||
return PropTypes.shape(Types.font).isRequired;
|
||||
return {
|
||||
font: PropTypes.shape(Types.font).isRequired,
|
||||
fontOptions: PropTypes.shape(Types.fontOptions).isRequired,
|
||||
onPreviewFonts: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.renderFontCSS = this.renderFontCSS.bind(this);
|
||||
this.renderFontCSSCode = this.renderFontCSSCode.bind(this);
|
||||
this.renderFontFormatURL = this.renderFontFormatURL.bind(this);
|
||||
this.renderFontName = this.renderFontName.bind(this);
|
||||
this.renderFontPreview = this.renderFontPreview.bind(this);
|
||||
|
||||
this.state = {
|
||||
isFontExpanded: false,
|
||||
isFontFaceRuleExpanded: false,
|
||||
};
|
||||
|
||||
this.onFontToggle = this.onFontToggle.bind(this);
|
||||
this.onFontFaceRuleToggle = this.onFontFaceRuleToggle.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps) {
|
||||
if (this.props.font.name === newProps.font.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isFontExpanded: false,
|
||||
isFontFaceRuleExpanded: false,
|
||||
});
|
||||
}
|
||||
|
||||
onFontToggle() {
|
||||
this.setState({
|
||||
isFontExpanded: !this.state.isFontExpanded
|
||||
});
|
||||
}
|
||||
|
||||
onFontFaceRuleToggle() {
|
||||
this.setState({
|
||||
isFontFaceRuleExpanded: !this.state.isFontFaceRuleExpanded
|
||||
});
|
||||
}
|
||||
|
||||
renderFontCSS(cssFamilyName) {
|
||||
return dom.p(
|
||||
{
|
||||
className: "font-css"
|
||||
className: "font-css-name"
|
||||
},
|
||||
dom.span(
|
||||
{},
|
||||
getStr("fontinspector.usedAs")
|
||||
),
|
||||
" \"",
|
||||
dom.span(
|
||||
{
|
||||
className: "font-css-name"
|
||||
},
|
||||
cssFamilyName
|
||||
),
|
||||
"\""
|
||||
`${getStr("fontinspector.usedAs")} "${cssFamilyName}"`
|
||||
);
|
||||
}
|
||||
|
||||
renderFontCSSCode(ruleText) {
|
||||
renderFontCSSCode(rule, ruleText) {
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Cut the rule text in 3 parts: the selector, the declarations, the closing brace.
|
||||
// This way we can collapse the declarations by default and display an expander icon
|
||||
// to expand them again.
|
||||
let leading = ruleText.substring(0, ruleText.indexOf("{") + 1);
|
||||
let body = ruleText.substring(ruleText.indexOf("{") + 1, ruleText.lastIndexOf("}"));
|
||||
let trailing = ruleText.substring(ruleText.lastIndexOf("}"));
|
||||
|
||||
let { isFontFaceRuleExpanded } = this.state;
|
||||
|
||||
return dom.pre(
|
||||
{
|
||||
className: "font-css-code"
|
||||
className: "font-css-code",
|
||||
},
|
||||
ruleText
|
||||
this.renderFontCSSCodeTwisty(),
|
||||
leading,
|
||||
isFontFaceRuleExpanded ?
|
||||
null
|
||||
:
|
||||
dom.span(
|
||||
{
|
||||
className: "font-css-code-expander"
|
||||
}
|
||||
),
|
||||
isFontFaceRuleExpanded ? body : null,
|
||||
trailing
|
||||
);
|
||||
}
|
||||
|
||||
renderFontFormatURL(url, format) {
|
||||
renderFontTypeAndURL(url, format) {
|
||||
if (!url) {
|
||||
return dom.p(
|
||||
{
|
||||
className: "font-format-url"
|
||||
},
|
||||
getStr("fontinspector.system")
|
||||
);
|
||||
}
|
||||
|
||||
return dom.p(
|
||||
{
|
||||
className: "font-format-url"
|
||||
},
|
||||
dom.input(
|
||||
getStr("fontinspector.remote"),
|
||||
dom.a(
|
||||
{
|
||||
className: "font-url",
|
||||
readOnly: "readonly",
|
||||
value: url
|
||||
}
|
||||
),
|
||||
" ",
|
||||
format ?
|
||||
dom.span(
|
||||
{
|
||||
className: "font-format"
|
||||
},
|
||||
format
|
||||
)
|
||||
:
|
||||
dom.span(
|
||||
{
|
||||
className: "font-format",
|
||||
hidden: "true"
|
||||
},
|
||||
format
|
||||
)
|
||||
href: url
|
||||
},
|
||||
format
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -89,27 +128,43 @@ class Font extends PureComponent {
|
||||
return dom.h1(
|
||||
{
|
||||
className: "font-name",
|
||||
onClick: this.onFontToggle,
|
||||
},
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
renderFontPreview(previewUrl) {
|
||||
return dom.div(
|
||||
{
|
||||
className: "font-preview-container",
|
||||
},
|
||||
dom.img(
|
||||
{
|
||||
className: "font-preview",
|
||||
src: previewUrl
|
||||
}
|
||||
)
|
||||
);
|
||||
renderFontTwisty() {
|
||||
let { isFontExpanded } = this.state;
|
||||
return this.renderTwisty(isFontExpanded, this.onFontToggle);
|
||||
}
|
||||
|
||||
renderFontCSSCodeTwisty() {
|
||||
let { isFontFaceRuleExpanded } = this.state;
|
||||
return this.renderTwisty(isFontFaceRuleExpanded, this.onFontFaceRuleToggle);
|
||||
}
|
||||
|
||||
renderTwisty(isExpanded, onClick) {
|
||||
let attributes = {
|
||||
className: "theme-twisty",
|
||||
onClick,
|
||||
};
|
||||
if (isExpanded) {
|
||||
attributes.open = "true";
|
||||
}
|
||||
|
||||
return dom.span(attributes);
|
||||
}
|
||||
|
||||
render() {
|
||||
let { font } = this.props;
|
||||
let {
|
||||
font,
|
||||
fontOptions,
|
||||
onPreviewFonts,
|
||||
} = this.props;
|
||||
|
||||
let { previewText } = fontOptions;
|
||||
|
||||
let {
|
||||
CSSFamilyName,
|
||||
format,
|
||||
@ -120,16 +175,23 @@ class Font extends PureComponent {
|
||||
URI,
|
||||
} = font;
|
||||
|
||||
let { isFontExpanded } = this.state;
|
||||
|
||||
return dom.li(
|
||||
{
|
||||
className: "font",
|
||||
className: "font" + (isFontExpanded ? " expanded" : ""),
|
||||
},
|
||||
this.renderFontPreview(previewUrl),
|
||||
this.renderFontTwisty(),
|
||||
this.renderFontName(name),
|
||||
" " + (URI ? getStr("fontinspector.remote") : getStr("fontinspector.system")),
|
||||
URI ? this.renderFontFormatURL(URI, format) : null,
|
||||
this.renderFontCSS(CSSFamilyName),
|
||||
rule ? this.renderFontCSSCode(ruleText) : null
|
||||
FontPreview({ previewText, previewUrl, onPreviewFonts }),
|
||||
dom.div(
|
||||
{
|
||||
className: "font-details"
|
||||
},
|
||||
this.renderFontTypeAndURL(URI, format),
|
||||
this.renderFontCSSCode(rule, ruleText),
|
||||
this.renderFontCSS(CSSFamilyName)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -15,26 +15,29 @@ const Types = require("../types");
|
||||
class FontList extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired
|
||||
fontOptions: PropTypes.shape(Types.fontOptions).isRequired,
|
||||
fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired,
|
||||
onPreviewFonts: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
let { fonts } = this.props;
|
||||
let {
|
||||
fonts,
|
||||
fontOptions,
|
||||
onPreviewFonts
|
||||
} = this.props;
|
||||
|
||||
return dom.div(
|
||||
return dom.ul(
|
||||
{
|
||||
id: "font-container"
|
||||
className: "fonts-list"
|
||||
},
|
||||
dom.ul(
|
||||
{
|
||||
id: "all-fonts"
|
||||
},
|
||||
fonts.map((font, i) => Font({
|
||||
key: i,
|
||||
font
|
||||
}))
|
||||
)
|
||||
fonts.map((font, i) => Font({
|
||||
key: i,
|
||||
font,
|
||||
fontOptions,
|
||||
onPreviewFonts,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
93
devtools/client/inspector/fonts/components/FontPreview.js
Normal file
93
devtools/client/inspector/fonts/components/FontPreview.js
Normal file
@ -0,0 +1,93 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const Types = require("../types");
|
||||
|
||||
class FontPreview extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
previewText: Types.fontOptions.previewText.isRequired,
|
||||
previewUrl: Types.font.previewUrl.isRequired,
|
||||
onPreviewFonts: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
// Is the text preview input field currently focused?
|
||||
isFocused: false,
|
||||
};
|
||||
|
||||
this.onBlur = this.onBlur.bind(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.isFocused) {
|
||||
let input = this.fontPreviewInput;
|
||||
input.focus();
|
||||
input.selectionStart = input.selectionEnd = input.value.length;
|
||||
}
|
||||
}
|
||||
|
||||
onBlur() {
|
||||
this.setState({ isFocused: false });
|
||||
}
|
||||
|
||||
onClick() {
|
||||
this.setState({ isFocused: true });
|
||||
}
|
||||
|
||||
onChange(event) {
|
||||
this.props.onPreviewFonts(event.target.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
previewText,
|
||||
previewUrl,
|
||||
} = this.props;
|
||||
|
||||
let { isFocused } = this.state;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "font-preview-container",
|
||||
},
|
||||
isFocused ?
|
||||
dom.input(
|
||||
{
|
||||
type: "search",
|
||||
className: "font-preview-input devtools-searchinput",
|
||||
value: previewText,
|
||||
onBlur: this.onBlur,
|
||||
onChange: this.onChange,
|
||||
ref: input => {
|
||||
this.fontPreviewInput = input;
|
||||
}
|
||||
}
|
||||
)
|
||||
:
|
||||
null,
|
||||
dom.img(
|
||||
{
|
||||
className: "font-preview",
|
||||
src: previewUrl,
|
||||
onClick: this.onClick,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FontPreview;
|
@ -9,30 +9,73 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
const SearchBox = createFactory(require("devtools/client/shared/components/SearchBox"));
|
||||
const Accordion = createFactory(require("devtools/client/inspector/layout/components/Accordion"));
|
||||
const FontList = createFactory(require("./FontList"));
|
||||
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
const PREVIEW_UPDATE_DELAY = 150;
|
||||
|
||||
class FontsApp extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
fonts: PropTypes.arrayOf(PropTypes.shape(Types.font)).isRequired,
|
||||
fontData: PropTypes.shape(Types.fontData).isRequired,
|
||||
fontOptions: PropTypes.shape(Types.fontOptions).isRequired,
|
||||
onPreviewFonts: PropTypes.func.isRequired,
|
||||
onShowAllFont: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
renderElementFonts() {
|
||||
let {
|
||||
fonts,
|
||||
fontData,
|
||||
fontOptions,
|
||||
onPreviewFonts,
|
||||
onShowAllFont,
|
||||
} = this.props;
|
||||
let { fonts } = fontData;
|
||||
|
||||
return fonts.length ?
|
||||
FontList({
|
||||
fonts,
|
||||
fontOptions,
|
||||
onPreviewFonts
|
||||
})
|
||||
:
|
||||
dom.div(
|
||||
{
|
||||
className: "devtools-sidepanel-no-result"
|
||||
},
|
||||
getStr("fontinspector.noFontsOnSelectedElement")
|
||||
);
|
||||
}
|
||||
|
||||
renderOtherFonts() {
|
||||
let {
|
||||
fontData,
|
||||
onPreviewFonts,
|
||||
fontOptions,
|
||||
} = this.props;
|
||||
let { otherFonts } = fontData;
|
||||
|
||||
if (!otherFonts.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Accordion({
|
||||
items: [
|
||||
{
|
||||
header: getStr("fontinspector.otherFontsInPageHeader"),
|
||||
component: FontList,
|
||||
componentProps: {
|
||||
fontOptions,
|
||||
fonts: otherFonts,
|
||||
onPreviewFonts
|
||||
},
|
||||
opened: false
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return dom.div(
|
||||
{
|
||||
className: "theme-sidebar inspector-tabpanel",
|
||||
@ -40,33 +83,11 @@ class FontsApp extends PureComponent {
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
className: "devtools-toolbar"
|
||||
id: "font-container"
|
||||
},
|
||||
SearchBox({
|
||||
delay: PREVIEW_UPDATE_DELAY,
|
||||
placeholder: getStr("fontinspector.previewText"),
|
||||
type: "text",
|
||||
onChange: onPreviewFonts,
|
||||
}),
|
||||
dom.label(
|
||||
{
|
||||
id: "font-showall",
|
||||
className: "theme-link",
|
||||
title: getStr("fontinspector.seeAll.tooltip"),
|
||||
onClick: onShowAllFont,
|
||||
},
|
||||
getStr("fontinspector.seeAll")
|
||||
)
|
||||
),
|
||||
fonts.length ?
|
||||
FontList({ fonts })
|
||||
:
|
||||
dom.div(
|
||||
{
|
||||
className: "devtools-sidepanel-no-result"
|
||||
},
|
||||
getStr("fontinspector.noFontsOnSelectedElement")
|
||||
)
|
||||
this.renderElementFonts(),
|
||||
this.renderOtherFonts()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,5 +7,6 @@
|
||||
DevToolsModules(
|
||||
'Font.js',
|
||||
'FontList.js',
|
||||
'FontPreview.js',
|
||||
'FontsApp.js',
|
||||
)
|
||||
|
@ -20,7 +20,7 @@ const INSPECTOR_L10N =
|
||||
new LocalizationHelper("devtools/client/locales/inspector.properties");
|
||||
|
||||
const { updateFonts } = require("./actions/fonts");
|
||||
const { updatePreviewText, updateShowAllFonts } = require("./actions/font-options");
|
||||
const { updatePreviewText } = require("./actions/font-options");
|
||||
|
||||
class FontInspector {
|
||||
constructor(inspector, window) {
|
||||
@ -33,7 +33,6 @@ class FontInspector {
|
||||
|
||||
this.onNewNode = this.onNewNode.bind(this);
|
||||
this.onPreviewFonts = this.onPreviewFonts.bind(this);
|
||||
this.onShowAllFont = this.onShowAllFont.bind(this);
|
||||
this.onThemeChanged = this.onThemeChanged.bind(this);
|
||||
|
||||
this.init();
|
||||
@ -46,7 +45,6 @@ class FontInspector {
|
||||
|
||||
let fontsApp = FontsApp({
|
||||
onPreviewFonts: this.onPreviewFonts,
|
||||
onShowAllFont: this.onShowAllFont,
|
||||
});
|
||||
|
||||
let provider = createElement(Provider, {
|
||||
@ -66,10 +64,26 @@ class FontInspector {
|
||||
gDevTools.on("theme-switched", this.onThemeChanged);
|
||||
|
||||
this.store.dispatch(updatePreviewText(""));
|
||||
this.store.dispatch(updateShowAllFonts(false));
|
||||
this.update(false, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given all fonts on the page, and given the fonts used in given node, return all fonts
|
||||
* not from the page not used in this node.
|
||||
*
|
||||
* @param {Array} allFonts
|
||||
* All fonts used on the entire page
|
||||
* @param {Array} nodeFonts
|
||||
* Fonts used only in one of the nodes
|
||||
* @return {Array}
|
||||
* All fonts, except the ones used in the current node
|
||||
*/
|
||||
excludeNodeFonts(allFonts, nodeFonts) {
|
||||
return allFonts.filter(font => {
|
||||
return !nodeFonts.some(nodeFont => nodeFont.name === font.name);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Destruction function called when the inspector is destroyed. Removes event listeners
|
||||
* and cleans up references.
|
||||
@ -85,6 +99,34 @@ class FontInspector {
|
||||
this.store = null;
|
||||
}
|
||||
|
||||
async getFontsForNode(node, options) {
|
||||
// In case we've been destroyed in the meantime
|
||||
if (!this.document) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let fonts = await this.pageStyle.getUsedFontFaces(node, options).catch(console.error);
|
||||
if (!fonts) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
async getFontsNotInNode(nodeFonts, options) {
|
||||
// In case we've been destroyed in the meantime
|
||||
if (!this.document) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let allFonts = await this.pageStyle.getAllUsedFontFaces(options).catch(console.error);
|
||||
if (!allFonts) {
|
||||
allFonts = [];
|
||||
}
|
||||
|
||||
return this.excludeNodeFonts(allFonts, nodeFonts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the font inspector panel is visible, and false otherwise.
|
||||
*/
|
||||
@ -98,7 +140,6 @@ class FontInspector {
|
||||
*/
|
||||
onNewNode() {
|
||||
if (this.isPanelVisible()) {
|
||||
this.store.dispatch(updateShowAllFonts(false));
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
@ -111,14 +152,6 @@ class FontInspector {
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for click on show all fonts button.
|
||||
*/
|
||||
onShowAllFont() {
|
||||
this.store.dispatch(updateShowAllFonts(true));
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the "theme-switched" event.
|
||||
*/
|
||||
@ -135,20 +168,22 @@ class FontInspector {
|
||||
}
|
||||
|
||||
let node = this.inspector.selection.nodeFront;
|
||||
|
||||
let fonts = [];
|
||||
let otherFonts = [];
|
||||
|
||||
let { fontOptions } = this.store.getState();
|
||||
let { showAllFonts, previewText } = fontOptions;
|
||||
let { previewText } = fontOptions;
|
||||
|
||||
// Clear the list of fonts if the currently selected node is not connected or a text
|
||||
// or element node unless all fonts are supposed to be shown.
|
||||
let isElementOrTextNode = this.inspector.selection.isElementNode() ||
|
||||
this.inspector.selection.isTextNode();
|
||||
if (!showAllFonts &&
|
||||
(!node ||
|
||||
!this.isPanelVisible() ||
|
||||
!this.inspector.selection.isConnected() ||
|
||||
!isElementOrTextNode)) {
|
||||
this.store.dispatch(updateFonts(fonts));
|
||||
if (!node ||
|
||||
!this.isPanelVisible() ||
|
||||
!this.inspector.selection.isConnected() ||
|
||||
!isElementOrTextNode) {
|
||||
this.store.dispatch(updateFonts(fonts, otherFonts));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -158,23 +193,18 @@ class FontInspector {
|
||||
previewFillStyle: getColor("body-color")
|
||||
};
|
||||
|
||||
if (showAllFonts) {
|
||||
fonts = await this.pageStyle.getAllUsedFontFaces(options)
|
||||
.catch(console.error);
|
||||
} else {
|
||||
fonts = await this.pageStyle.getUsedFontFaces(node, options)
|
||||
.catch(console.error);
|
||||
}
|
||||
fonts = await this.getFontsForNode(node, options);
|
||||
otherFonts = await this.getFontsNotInNode(fonts, options);
|
||||
|
||||
if (!fonts || !fonts.length) {
|
||||
if (!fonts.length && !otherFonts.length) {
|
||||
// No fonts to display. Clear the previously shown fonts.
|
||||
if (this.store) {
|
||||
this.store.dispatch(updateFonts(fonts));
|
||||
this.store.dispatch(updateFonts(fonts, otherFonts));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (let font of fonts) {
|
||||
for (let font of [...fonts, ...otherFonts]) {
|
||||
font.previewUrl = await font.preview.data.string();
|
||||
}
|
||||
|
||||
@ -183,7 +213,7 @@ class FontInspector {
|
||||
return;
|
||||
}
|
||||
|
||||
this.store.dispatch(updateFonts(fonts));
|
||||
this.store.dispatch(updateFonts(fonts, otherFonts));
|
||||
|
||||
this.inspector.emit("fontinspector-updated");
|
||||
}
|
||||
|
@ -6,12 +6,10 @@
|
||||
|
||||
const {
|
||||
UPDATE_PREVIEW_TEXT,
|
||||
UPDATE_SHOW_ALL_FONTS
|
||||
} = require("../actions/index");
|
||||
|
||||
const INITIAL_FONT_OPTIONS = {
|
||||
previewText: "Abc",
|
||||
showAllFonts: false,
|
||||
};
|
||||
|
||||
let reducers = {
|
||||
@ -20,10 +18,6 @@ let reducers = {
|
||||
return Object.assign({}, fontOptions, { previewText });
|
||||
},
|
||||
|
||||
[UPDATE_SHOW_ALL_FONTS](fontOptions, { showAllFonts }) {
|
||||
return Object.assign({}, fontOptions, { showAllFonts });
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = function (fontOptions = INITIAL_FONT_OPTIONS, action) {
|
||||
|
@ -8,20 +8,23 @@ const {
|
||||
UPDATE_FONTS,
|
||||
} = require("../actions/index");
|
||||
|
||||
const INITIAL_FONTS = [];
|
||||
const INITIAL_FONT_DATA = {
|
||||
fonts: [],
|
||||
otherFonts: []
|
||||
};
|
||||
|
||||
let reducers = {
|
||||
|
||||
[UPDATE_FONTS](_, { fonts }) {
|
||||
return fonts;
|
||||
[UPDATE_FONTS](_, { fonts, otherFonts }) {
|
||||
return { fonts, otherFonts };
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = function (fonts = INITIAL_FONTS, action) {
|
||||
module.exports = function (fontData = INITIAL_FONT_DATA, action) {
|
||||
let reducer = reducers[action.type];
|
||||
if (!reducer) {
|
||||
return fonts;
|
||||
return fontData;
|
||||
}
|
||||
return reducer(fonts, action);
|
||||
return reducer(fontData, action);
|
||||
};
|
||||
|
@ -16,6 +16,8 @@ support-files =
|
||||
|
||||
[browser_fontinspector.js]
|
||||
[browser_fontinspector_edit-previews.js]
|
||||
[browser_fontinspector_edit-previews-show-all.js]
|
||||
[browser_fontinspector_expand-css-code.js]
|
||||
[browser_fontinspector_expand-details.js]
|
||||
[browser_fontinspector_other-fonts.js]
|
||||
[browser_fontinspector_text-node.js]
|
||||
[browser_fontinspector_theme-change.js]
|
||||
|
@ -40,33 +40,40 @@ add_task(function* () {
|
||||
|
||||
yield testBodyFonts(inspector, viewDoc);
|
||||
yield testDivFonts(inspector, viewDoc);
|
||||
yield testShowAllFonts(inspector, viewDoc);
|
||||
});
|
||||
|
||||
function isRemote(fontLiEl) {
|
||||
return fontLiEl.querySelectorAll(".font-format-url").length === 1;
|
||||
function isRemote(fontLi) {
|
||||
return fontLi.querySelectorAll(".font-format-url a").length === 1;
|
||||
}
|
||||
|
||||
function getFormat(fontLi) {
|
||||
let link = fontLi.querySelector(".font-format-url a");
|
||||
if (!link) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return link.textContent;
|
||||
}
|
||||
|
||||
function getCSSName(fontLi) {
|
||||
let text = fontLi.querySelector(".font-css-name").textContent;
|
||||
|
||||
return text.substring(text.indexOf('"') + 1, text.lastIndexOf('"'));
|
||||
}
|
||||
|
||||
function* testBodyFonts(inspector, viewDoc) {
|
||||
let lis = viewDoc.querySelectorAll("#all-fonts > li");
|
||||
let lis = getUsedFontsEls(viewDoc);
|
||||
is(lis.length, 5, "Found 5 fonts");
|
||||
|
||||
for (let i = 0; i < FONTS.length; i++) {
|
||||
let li = lis[i];
|
||||
let font = FONTS[i];
|
||||
is(li.querySelector(".font-name").textContent, font.name,
|
||||
"font " + i + " right font name");
|
||||
|
||||
is(isRemote(li), font.remote,
|
||||
"font " + i + " remote value correct");
|
||||
is(li.querySelector(".font-url").value, font.url,
|
||||
"font " + i + " url correct");
|
||||
is(li.querySelector(".font-format").hidden, !font.format,
|
||||
"font " + i + " format hidden value correct");
|
||||
is(li.querySelector(".font-format").textContent,
|
||||
font.format, "font " + i + " format correct");
|
||||
is(li.querySelector(".font-css-name").textContent,
|
||||
font.cssName, "font " + i + " css name correct");
|
||||
is(getName(li), font.name, "font " + i + " right font name");
|
||||
is(isRemote(li), font.remote, "font " + i + " remote value correct");
|
||||
is(li.querySelector(".font-url").href, font.url, "font " + i + " url correct");
|
||||
is(getFormat(li), font.format, "font " + i + " format correct");
|
||||
is(getCSSName(li), font.cssName, "font " + i + " css name correct");
|
||||
}
|
||||
|
||||
// test that the bold and regular fonts have different previews
|
||||
@ -75,8 +82,8 @@ function* testBodyFonts(inspector, viewDoc) {
|
||||
isnot(regSrc, boldSrc, "preview for bold font is different from regular");
|
||||
|
||||
// test system font
|
||||
let localFontName = lis[4].querySelector(".font-name").textContent;
|
||||
let localFontCSSName = lis[4].querySelector(".font-css-name").textContent;
|
||||
let localFontName = getName(lis[4]);
|
||||
let localFontCSSName = getCSSName(lis[4]);
|
||||
|
||||
// On Linux test machines, the Arial font doesn't exist.
|
||||
// The fallback is "Liberation Sans"
|
||||
@ -92,22 +99,7 @@ function* testDivFonts(inspector, viewDoc) {
|
||||
yield selectNode("div", inspector);
|
||||
yield updated;
|
||||
|
||||
let lis = viewDoc.querySelectorAll("#all-fonts > li");
|
||||
let lis = getUsedFontsEls(viewDoc);
|
||||
is(lis.length, 1, "Found 1 font on DIV");
|
||||
is(lis[0].querySelector(".font-name").textContent,
|
||||
"Ostrich Sans Medium",
|
||||
"The DIV font has the right name");
|
||||
}
|
||||
|
||||
function* testShowAllFonts(inspector, viewDoc) {
|
||||
info("testing showing all fonts");
|
||||
|
||||
let updated = inspector.once("fontinspector-updated");
|
||||
viewDoc.querySelector("#font-showall").click();
|
||||
yield updated;
|
||||
|
||||
// shouldn't change the node selection
|
||||
is(inspector.selection.nodeFront.nodeName, "DIV", "Show all fonts selected");
|
||||
let lis = viewDoc.querySelectorAll("#all-fonts > li");
|
||||
is(lis.length, 6, "Font inspector shows 6 fonts (1 from iframe)");
|
||||
is(getName(lis[0]), "Ostrich Sans Medium", "The DIV font has the right name");
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that correct previews are shown if the text is edited after 'Show all'
|
||||
// button is pressed.
|
||||
|
||||
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
|
||||
|
||||
add_task(function* () {
|
||||
let { inspector, view } = yield openFontInspectorForURL(TEST_URI);
|
||||
let viewDoc = view.document;
|
||||
|
||||
info("Selecting a node that doesn't contain all document fonts.");
|
||||
yield selectNode(".normal-text", inspector);
|
||||
|
||||
let normalTextNumPreviews =
|
||||
viewDoc.querySelectorAll("#all-fonts .font-preview").length;
|
||||
|
||||
let onUpdated = inspector.once("fontinspector-updated");
|
||||
|
||||
info("Clicking 'Select all' button.");
|
||||
viewDoc.getElementById("font-showall").click();
|
||||
|
||||
info("Waiting for font-inspector to update.");
|
||||
yield onUpdated;
|
||||
|
||||
let allFontsNumPreviews =
|
||||
viewDoc.querySelectorAll("#all-fonts .font-preview").length;
|
||||
|
||||
// Sanity check. If this fails all fonts apply also to the .normal-text node
|
||||
// meaning we won't detect if preview editing causes the panel not to show all
|
||||
// fonts.
|
||||
isnot(allFontsNumPreviews, normalTextNumPreviews,
|
||||
"The .normal-text didn't show all fonts.");
|
||||
|
||||
info("Editing the preview text.");
|
||||
yield updatePreviewText(view, "The quick brown");
|
||||
|
||||
let numPreviews = viewDoc.querySelectorAll("#all-fonts .font-preview").length;
|
||||
is(numPreviews, allFontsNumPreviews,
|
||||
"All fonts are still shown after the preview text was edited.");
|
||||
});
|
@ -13,7 +13,7 @@ add_task(function* () {
|
||||
let {view} = yield openFontInspectorForURL(TEST_URI);
|
||||
let viewDoc = view.document;
|
||||
|
||||
let previews = viewDoc.querySelectorAll("#all-fonts .font-preview");
|
||||
let previews = viewDoc.querySelectorAll("#font-container .font-preview");
|
||||
let initialPreviews = [...previews].map(p => p.src);
|
||||
|
||||
info("Typing 'Abc' to check that the reference previews are correct.");
|
||||
@ -42,7 +42,7 @@ add_task(function* () {
|
||||
* URI's are different.
|
||||
*/
|
||||
function checkPreviewImages(viewDoc, originalURIs, assertIdentical) {
|
||||
let previews = viewDoc.querySelectorAll("#all-fonts .font-preview");
|
||||
let previews = viewDoc.querySelectorAll("#font-container .font-preview");
|
||||
let newURIs = [...previews].map(p => p.src);
|
||||
|
||||
is(newURIs.length, originalURIs.length,
|
||||
|
@ -0,0 +1,36 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the font-face css rule code is collapsed by default, and can be expanded.
|
||||
|
||||
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
|
||||
|
||||
add_task(function* () {
|
||||
let { view } = yield openFontInspectorForURL(TEST_URI);
|
||||
let viewDoc = view.document;
|
||||
|
||||
info("Expanding the details section of the first font");
|
||||
let fontEl = getUsedFontsEls(viewDoc)[0];
|
||||
yield expandFontDetails(fontEl);
|
||||
|
||||
info("Checking that the css font-face rule is collapsed by default");
|
||||
let codeEl = fontEl.querySelector(".font-css-code");
|
||||
is(codeEl.textContent, "@font-face {}", "The font-face rule is collapsed");
|
||||
|
||||
info("Expanding the rule by clicking on the expander icon");
|
||||
let onExpanded = BrowserTestUtils.waitForCondition(() => {
|
||||
return codeEl.textContent === `@font-face {
|
||||
font-family: "bar";
|
||||
src: url("bad/font/name.ttf"), url("ostrich-regular.ttf") format("truetype");
|
||||
}`;
|
||||
}, "Waiting for the font-face rule");
|
||||
|
||||
let expander = fontEl.querySelector(".font-css-code .theme-twisty");
|
||||
expander.click();
|
||||
yield onExpanded;
|
||||
|
||||
ok(true, "Font-face rule is now expanded");
|
||||
});
|
@ -0,0 +1,38 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that fonts are collapsed by default, and can be expanded.
|
||||
|
||||
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
|
||||
|
||||
add_task(function* () {
|
||||
let { inspector, view } = yield openFontInspectorForURL(TEST_URI);
|
||||
let viewDoc = view.document;
|
||||
|
||||
info("Checking all font are collapsed by default");
|
||||
let fonts = getUsedFontsEls(viewDoc);
|
||||
checkAllFontsCollapsed(fonts);
|
||||
|
||||
info("Clicking on the first one to expand the font details");
|
||||
yield expandFontDetails(fonts[0]);
|
||||
|
||||
ok(fonts[0].querySelector(".theme-twisty").hasAttribute("open"), `Twisty is open`);
|
||||
ok(isFontDetailsVisible(fonts[0]), `Font details is shown`);
|
||||
|
||||
info("Selecting a node with different fonts and checking that all fonts are collapsed");
|
||||
yield selectNode(".black-text", inspector);
|
||||
fonts = getUsedFontsEls(viewDoc);
|
||||
checkAllFontsCollapsed(fonts);
|
||||
});
|
||||
|
||||
function checkAllFontsCollapsed(fonts) {
|
||||
fonts.forEach((el, i) => {
|
||||
let twisty = el.querySelector(".theme-twisty");
|
||||
ok(twisty, `Twisty ${i} exists`);
|
||||
ok(!twisty.hasAttribute("open"), `Twisty ${i} is closed`);
|
||||
ok(!isFontDetailsVisible(el), `Font details ${i} is hidden`);
|
||||
});
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Check that the font inspector has a section for "other fonts" and that section contains
|
||||
// the fonts *not* used in the currently selected element.
|
||||
// Check that it's collapsed by default, but can be expanded. That it does not contain
|
||||
// the fonts listed in the previous section.
|
||||
|
||||
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
|
||||
|
||||
add_task(function* () {
|
||||
const { inspector, view } = yield openFontInspectorForURL(TEST_URI);
|
||||
const viewDoc = view.document;
|
||||
|
||||
let otherFontsAccordion = viewDoc.querySelector("#font-container .accordion");
|
||||
ok(otherFontsAccordion, "There's an accordion in the panel");
|
||||
is(otherFontsAccordion.textContent, "Other fonts in page", "It has the right title");
|
||||
|
||||
yield expandOtherFontsAccordion(viewDoc);
|
||||
let otherFontsEls = getOtherFontsEls(viewDoc);
|
||||
|
||||
is(otherFontsEls.length, 1, "There is one font listed in the other fonts section");
|
||||
// On Linux Times New Roman does not exist, Liberation Serif is used instead
|
||||
let name = getName(otherFontsEls[0]);
|
||||
ok(name === "Times New Roman" || name === "Liberation Serif",
|
||||
"The other font listed is the right one");
|
||||
|
||||
info("Checking that fonts of the current element aren't listed");
|
||||
yield selectNode(".bold-text", inspector);
|
||||
yield expandOtherFontsAccordion(viewDoc);
|
||||
otherFontsEls = getOtherFontsEls(viewDoc);
|
||||
|
||||
for (let otherFontEl of otherFontsEls) {
|
||||
ok(![...getUsedFontsEls(viewDoc)].some(el => getName(el) === getName(otherFontEl)),
|
||||
"Other font isn't listed in the main fonts section");
|
||||
}
|
||||
});
|
@ -17,6 +17,6 @@ add_task(function* () {
|
||||
let { nodes } = yield inspector.walker.children(bodyNode);
|
||||
yield selectNode(nodes[0], inspector);
|
||||
|
||||
let sections = viewDoc.querySelectorAll("#all-fonts > li");
|
||||
is(sections.length, 1, "Font inspector shows 1 font");
|
||||
let lis = getUsedFontsEls(viewDoc);
|
||||
is(lis.length, 1, "Font inspector shows 1 font");
|
||||
});
|
||||
|
@ -24,17 +24,17 @@ add_task(function* () {
|
||||
yield selectNode(".normal-text", inspector);
|
||||
|
||||
// Store the original preview URI for later comparison.
|
||||
let originalURI = doc.querySelector("#all-fonts .font-preview").src;
|
||||
let originalURI = doc.querySelector("#font-container .font-preview").src;
|
||||
let newTheme = originalTheme === "light" ? "dark" : "light";
|
||||
|
||||
info(`Original theme was '${originalTheme}'.`);
|
||||
|
||||
yield setThemeAndWaitForUpdate(newTheme, inspector);
|
||||
isnot(doc.querySelector("#all-fonts .font-preview").src, originalURI,
|
||||
isnot(doc.querySelector("#font-container .font-preview").src, originalURI,
|
||||
"The preview image changed with the theme.");
|
||||
|
||||
yield setThemeAndWaitForUpdate(originalTheme, inspector);
|
||||
is(doc.querySelector("#all-fonts .font-preview").src, originalURI,
|
||||
is(doc.querySelector("#font-container .font-preview").src, originalURI,
|
||||
"The preview image is correct after the original theme was restored.");
|
||||
});
|
||||
|
||||
|
@ -51,7 +51,7 @@ var openFontInspectorForURL = Task.async(function* (url) {
|
||||
});
|
||||
|
||||
/**
|
||||
* Clears the preview input field, types new text into it and waits for the
|
||||
* Focus one of the preview inputs, clear it, type new text into it and wait for the
|
||||
* preview images to be updated.
|
||||
*
|
||||
* @param {FontInspector} view - The FontInspector instance.
|
||||
@ -61,25 +61,95 @@ function* updatePreviewText(view, text) {
|
||||
info(`Changing the preview text to '${text}'`);
|
||||
|
||||
let doc = view.document;
|
||||
let input = doc.querySelector("#sidebar-panel-fontinspector .devtools-textinput");
|
||||
let update = view.inspector.once("fontinspector-updated");
|
||||
let previewImg = doc.querySelector("#sidebar-panel-fontinspector .font-preview");
|
||||
|
||||
info("Focusing the input field.");
|
||||
input.focus();
|
||||
info("Clicking the font preview element to turn it to edit mode");
|
||||
let onClick = once(doc, "click");
|
||||
previewImg.click();
|
||||
yield onClick;
|
||||
|
||||
let input = previewImg.parentNode.querySelector("input");
|
||||
is(doc.activeElement, input, "The input was focused.");
|
||||
|
||||
info("Blanking the input field.");
|
||||
for (let i = input.value.length; i >= 0; i--) {
|
||||
while (input.value.length) {
|
||||
let update = view.inspector.once("fontinspector-updated");
|
||||
EventUtils.sendKey("BACK_SPACE", doc.defaultView);
|
||||
yield update;
|
||||
}
|
||||
|
||||
is(input.value, "", "The input is now blank.");
|
||||
if (text) {
|
||||
info("Typing the specified text to the input field.");
|
||||
let update = waitForNEvents(view.inspector, "fontinspector-updated", text.length);
|
||||
EventUtils.sendString(text, doc.defaultView);
|
||||
yield update;
|
||||
}
|
||||
|
||||
info("Typing the specified text to the input field.");
|
||||
EventUtils.sendString(text, doc.defaultView);
|
||||
is(input.value, text, "The input now contains the correct text.");
|
||||
|
||||
info("Waiting for the font-inspector to update.");
|
||||
yield update;
|
||||
}
|
||||
|
||||
async function expandFontDetails(fontEl) {
|
||||
info("Expanding a font details section");
|
||||
|
||||
let onExpanded = BrowserTestUtils.waitForCondition(() => isFontDetailsVisible(fontEl),
|
||||
"Waiting for font details");
|
||||
let twisty = fontEl.querySelector(".theme-twisty");
|
||||
twisty.click();
|
||||
await onExpanded;
|
||||
}
|
||||
|
||||
function isFontDetailsVisible(fontEl) {
|
||||
return [...fontEl.querySelectorAll(".font-css-name, .font-css-code, .font-format-url")]
|
||||
.every(el => el.getBoxQuads().length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the <li> elements for the fonts used on the currently selected element.
|
||||
*
|
||||
* @param {document} viewDoc
|
||||
* @return {Array}
|
||||
*/
|
||||
function getUsedFontsEls(viewDoc) {
|
||||
return viewDoc.querySelectorAll("#font-container > .fonts-list > li");
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the other fonts accordion.
|
||||
*/
|
||||
async function expandOtherFontsAccordion(viewDoc) {
|
||||
info("Expanding the other fonts section");
|
||||
|
||||
let accordion = viewDoc.querySelector("#font-container .accordion");
|
||||
let isExpanded = () => accordion.querySelector(".fonts-list");
|
||||
|
||||
if (isExpanded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let onExpanded = BrowserTestUtils.waitForCondition(isExpanded,
|
||||
"Waiting for other fonts section");
|
||||
accordion.querySelector(".theme-twisty").click();
|
||||
await onExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the <li> elements for the fonts used elsewhere in the document.
|
||||
*
|
||||
* @param {document} viewDoc
|
||||
* @return {Array}
|
||||
*/
|
||||
function getOtherFontsEls(viewDoc) {
|
||||
return viewDoc.querySelectorAll("#font-container .accordion .fonts-list > li");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a font element, return its name.
|
||||
*
|
||||
* @param {DOMNode} fontEl
|
||||
* The font element.
|
||||
* @return {String}
|
||||
* The name of the font as shown in the UI.
|
||||
*/
|
||||
function getName(fontEl) {
|
||||
return fontEl.querySelector(".font-name").textContent;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
/**
|
||||
* A single font.
|
||||
*/
|
||||
exports.font = {
|
||||
const font = exports.font = {
|
||||
// The name of the font family
|
||||
CSSFamilyName: PropTypes.string,
|
||||
|
||||
@ -31,3 +31,19 @@ exports.font = {
|
||||
// The URI of the font file
|
||||
URI: PropTypes.string,
|
||||
};
|
||||
|
||||
exports.fontOptions = {
|
||||
// The current preview text
|
||||
previewText: PropTypes.string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Font data
|
||||
*/
|
||||
exports.fontData = {
|
||||
// The fonts used in the current element.
|
||||
fonts: PropTypes.arrayOf(PropTypes.shape(font)),
|
||||
|
||||
// Fonts used elsewhere.
|
||||
otherFonts: PropTypes.arrayOf(PropTypes.shape(font)),
|
||||
};
|
||||
|
@ -14,6 +14,6 @@ exports.events = require("devtools/client/inspector/events/reducers/events");
|
||||
exports.extensionsSidebar = require("devtools/client/inspector/extensions/reducers/sidebar");
|
||||
exports.flexbox = require("devtools/client/inspector/flexbox/reducers/flexbox");
|
||||
exports.fontOptions = require("devtools/client/inspector/fonts/reducers/font-options");
|
||||
exports.fonts = require("devtools/client/inspector/fonts/reducers/fonts");
|
||||
exports.fontData = require("devtools/client/inspector/fonts/reducers/fonts");
|
||||
exports.grids = require("devtools/client/inspector/grids/reducers/grids");
|
||||
exports.highlighterSettings = require("devtools/client/inspector/grids/reducers/highlighter-settings");
|
||||
|
@ -5,13 +5,6 @@
|
||||
# LOCALIZATION NOTE This file contains the Font Inspector strings.
|
||||
# The Font Inspector is a panel accessible in the Inspector sidebar.
|
||||
|
||||
# LOCALIZATION NOTE (fontinspector.seeAll) This is the label of a link that will show all
|
||||
# the fonts used in the page, instead of the ones related to the inspected element.
|
||||
fontinspector.seeAll=Show all fonts used
|
||||
|
||||
# LOCALIZATION NOTE (fontinspector.seeAll.tooltip) see fontinspector.seeAll.
|
||||
fontinspector.seeAll.tooltip=See all the fonts used in the page
|
||||
|
||||
# LOCALIZATION NOTE (fontinspector.usedAs) This label introduces the name used to refer to
|
||||
# the font in a stylesheet.
|
||||
fontinspector.usedAs=Used as:
|
||||
@ -24,10 +17,10 @@ fontinspector.system=system
|
||||
# font.
|
||||
fontinspector.remote=remote
|
||||
|
||||
# LOCALIZATION NOTE (fontinspector.previewText):
|
||||
# This is the label shown as the placeholder in font inspector preview text box.
|
||||
fontinspector.previewText=Preview Text
|
||||
|
||||
# LOCALIZATION NOTE (fontinspector.noFontsOnSelectedElement): This label is shown when
|
||||
# no fonts found on the selected element.
|
||||
fontinspector.noFontsOnSelectedElement=No fonts were found for the current element.
|
||||
|
||||
# LOCALIZATION NOTE (fontinspector.otherFontsInPageHeader): This is the text for the
|
||||
# header of a collapsible section containing other fonts used in the page.
|
||||
fontinspector.otherFontsInPageHeader=Other fonts in page
|
@ -18,17 +18,10 @@ const { getToplevelWindow } = require("../utils/window");
|
||||
|
||||
const FRAME_SCRIPT = "resource://devtools/client/responsive.html/browser/content.js";
|
||||
|
||||
// Allow creation of HTML fragments without automatic sanitization, even
|
||||
// though we're in a chrome-privileged document.
|
||||
// This is, unfortunately, necessary in order to React to function
|
||||
// correctly.
|
||||
document.allowUnsafeHTML = true;
|
||||
|
||||
class Browser extends PureComponent {
|
||||
/**
|
||||
* This component is not allowed to depend directly on frequently changing
|
||||
* data (width, height) due to the use of `dangerouslySetInnerHTML` below.
|
||||
* Any changes in props will cause the <iframe> to be removed and added again,
|
||||
* This component is not allowed to depend directly on frequently changing data (width,
|
||||
* height). Any changes in props would cause the <iframe> to be removed and added again,
|
||||
* throwing away the current state of the page.
|
||||
*/
|
||||
static get propTypes() {
|
||||
@ -54,8 +47,7 @@ class Browser extends PureComponent {
|
||||
componentWillMount() {
|
||||
this.browserShown = new Promise(resolve => {
|
||||
let handler = frameLoader => {
|
||||
let browser = this.refs.browserContainer.querySelector("iframe.browser");
|
||||
if (frameLoader.ownerElement != browser) {
|
||||
if (frameLoader.ownerElement != this.browser) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(handler, "remote-browser-shown");
|
||||
@ -105,8 +97,10 @@ class Browser extends PureComponent {
|
||||
}
|
||||
|
||||
async startFrameScript() {
|
||||
let { onContentResize } = this;
|
||||
let browser = this.refs.browserContainer.querySelector("iframe.browser");
|
||||
let {
|
||||
browser,
|
||||
onContentResize,
|
||||
} = this;
|
||||
let mm = browser.frameLoader.messageManager;
|
||||
|
||||
// Notify tests when the content has received a resize event. This is not
|
||||
@ -131,8 +125,10 @@ class Browser extends PureComponent {
|
||||
}
|
||||
|
||||
async stopFrameScript() {
|
||||
let { onContentResize } = this;
|
||||
let browser = this.refs.browserContainer.querySelector("iframe.browser");
|
||||
let {
|
||||
browser,
|
||||
onContentResize,
|
||||
} = this;
|
||||
let mm = browser.frameLoader.messageManager;
|
||||
|
||||
e10s.off(mm, "OnContentResize", onContentResize);
|
||||
@ -141,31 +137,27 @@ class Browser extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
return dom.div(
|
||||
// In the case of @remote and @remoteType, the attribute must be set before the
|
||||
// element is added to the DOM to have any effect, which we are able to do with this
|
||||
// approach.
|
||||
//
|
||||
// @noisolation and @allowfullscreen are needed so that these frames have the same
|
||||
// access to browser features as regular browser tabs. The `swapFrameLoaders` platform
|
||||
// API we use compares such features before allowing the swap to proceed.
|
||||
return dom.iframe(
|
||||
{
|
||||
ref: "browserContainer",
|
||||
className: "browser-container",
|
||||
|
||||
/**
|
||||
* React uses a whitelist for attributes, so we need some way to set
|
||||
* attributes it does not know about, such as @mozbrowser. If this were
|
||||
* the only issue, we could use componentDidMount or ref: node => {} to
|
||||
* set the atttibutes. In the case of @remote and @remoteType, the
|
||||
* attribute must be set before the element is added to the DOM to have
|
||||
* any effect, which we are able to do with this approach.
|
||||
*
|
||||
* @noisolation and @allowfullscreen are needed so that these frames
|
||||
* have the same access to browser features as regular browser tabs.
|
||||
* The `swapFrameLoaders` platform API we use compares such features
|
||||
* before allowing the swap to proceed.
|
||||
*/
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: `<iframe class="browser" mozbrowser="true"
|
||||
remote="true" remoteType="web"
|
||||
noisolation="true" allowfullscreen="true"
|
||||
src="about:blank" width="100%" height="100%">
|
||||
</iframe>`
|
||||
}
|
||||
allowFullScreen: "true",
|
||||
className: "browser",
|
||||
height: "100%",
|
||||
mozbrowser: "true",
|
||||
noisolation: "true",
|
||||
remote: "true",
|
||||
remotetype: "web",
|
||||
src: "about:blank",
|
||||
width: "100%",
|
||||
ref: browser => {
|
||||
this.browser = browser;
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -268,11 +268,6 @@ select > option.divider {
|
||||
* Viewport Browser
|
||||
*/
|
||||
|
||||
.browser-container {
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
.browser {
|
||||
display: block;
|
||||
border: 0;
|
||||
|
@ -44,9 +44,10 @@ async function waitStartup(ui) {
|
||||
async function testDefaults(ui) {
|
||||
info("Test Defaults");
|
||||
|
||||
await testDevicePixelRatio(ui, window.devicePixelRatio);
|
||||
let dppx = await getViewportDevicePixelRatio(ui);
|
||||
is(dppx, DEFAULT_DPPX, "Content has expected devicePixelRatio");
|
||||
testViewportDevicePixelRatioSelect(ui, {
|
||||
value: window.devicePixelRatio,
|
||||
value: DEFAULT_DPPX,
|
||||
disabled: false,
|
||||
});
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
@ -55,12 +56,12 @@ async function testDefaults(ui) {
|
||||
async function testChangingDevice(ui) {
|
||||
info("Test Changing Device");
|
||||
|
||||
let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
|
||||
|
||||
let reloaded = waitForViewportLoad(ui);
|
||||
await selectDevice(ui, testDevice.name);
|
||||
await reloaded;
|
||||
await waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
|
||||
await waitPixelRatioChange;
|
||||
await testDevicePixelRatio(ui, testDevice.pixelRatio);
|
||||
let dppx = await waitForDevicePixelRatio(ui, testDevice.pixelRatio);
|
||||
is(dppx, testDevice.pixelRatio, "Content has expected devicePixelRatio");
|
||||
testViewportDevicePixelRatioSelect(ui, {
|
||||
value: testDevice.pixelRatio,
|
||||
disabled: true,
|
||||
@ -71,18 +72,17 @@ async function testChangingDevice(ui) {
|
||||
async function testResetWhenResizingViewport(ui) {
|
||||
info("Test reset when resizing the viewport");
|
||||
|
||||
let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
|
||||
|
||||
let deviceRemoved = once(ui, "device-association-removed");
|
||||
let reloaded = waitForViewportLoad(ui);
|
||||
await testViewportResize(ui, ".viewport-vertical-resize-handle",
|
||||
[-10, -10], [testDevice.width, testDevice.height - 10], [0, -10], ui);
|
||||
await deviceRemoved;
|
||||
await Promise.all([ deviceRemoved, reloaded ]);
|
||||
|
||||
await waitPixelRatioChange;
|
||||
await testDevicePixelRatio(ui, window.devicePixelRatio);
|
||||
let dppx = await waitForDevicePixelRatio(ui, DEFAULT_DPPX);
|
||||
is(dppx, DEFAULT_DPPX, "Content has expected devicePixelRatio");
|
||||
|
||||
testViewportDevicePixelRatioSelect(ui, {
|
||||
value: window.devicePixelRatio,
|
||||
value: DEFAULT_DPPX,
|
||||
disabled: false,
|
||||
});
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
@ -91,11 +91,9 @@ async function testResetWhenResizingViewport(ui) {
|
||||
async function testChangingDevicePixelRatio(ui) {
|
||||
info("Test changing device pixel ratio");
|
||||
|
||||
let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
|
||||
|
||||
await selectDevicePixelRatio(ui, VIEWPORT_DPPX);
|
||||
await waitPixelRatioChange;
|
||||
await testDevicePixelRatio(ui, VIEWPORT_DPPX);
|
||||
let dppx = await waitForDevicePixelRatio(ui, VIEWPORT_DPPX);
|
||||
is(dppx, VIEWPORT_DPPX, "Content has expected devicePixelRatio");
|
||||
testViewportDevicePixelRatioSelect(ui, {
|
||||
value: VIEWPORT_DPPX,
|
||||
disabled: false,
|
||||
@ -114,33 +112,22 @@ function testViewportDevicePixelRatioSelect(ui, expected) {
|
||||
`DevicePixelRatio Select should be ${expected.disabled ? "disabled" : "enabled"}.`);
|
||||
}
|
||||
|
||||
async function testDevicePixelRatio(ui, expected) {
|
||||
info("Test device pixel ratio");
|
||||
|
||||
let dppx = await getViewportDevicePixelRatio(ui);
|
||||
is(dppx, expected, `devicePixelRatio should be: ${expected}`);
|
||||
}
|
||||
|
||||
function onceDevicePixelRatioChange(ui) {
|
||||
return ContentTask.spawn(ui.getViewportBrowser(), {}, async function () {
|
||||
info(`Listening for a pixel ratio change (current: ${content.devicePixelRatio}dppx)`);
|
||||
|
||||
let pixelRatio = content.devicePixelRatio;
|
||||
let mql = content.matchMedia(`(resolution: ${pixelRatio}dppx)`);
|
||||
|
||||
function waitForDevicePixelRatio(ui, expected) {
|
||||
return ContentTask.spawn(ui.getViewportBrowser(), { expected }, function (args) {
|
||||
let initial = content.devicePixelRatio;
|
||||
info(`Listening for pixel ratio change ` +
|
||||
`(current: ${initial}, expected: ${args.expected})`);
|
||||
return new Promise(resolve => {
|
||||
const onWindowCreated = () => {
|
||||
if (pixelRatio !== content.devicePixelRatio) {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
addEventListener("DOMWindowCreated", onWindowCreated, {once: true});
|
||||
|
||||
let mql = content.matchMedia(`(resolution: ${args.expected}dppx)`);
|
||||
if (mql.matches) {
|
||||
info(`Ratio already changed to ${args.expected}dppx`);
|
||||
resolve(content.devicePixelRatio);
|
||||
return;
|
||||
}
|
||||
mql.addListener(function listener() {
|
||||
info(`Ratio changed to ${args.expected}dppx`);
|
||||
mql.removeListener(listener);
|
||||
removeEventListener("DOMWindowCreated", onWindowCreated, {once: true});
|
||||
resolve();
|
||||
resolve(content.devicePixelRatio);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -45,7 +45,7 @@ async function setViewportSizeWithInputKeys(ui) {
|
||||
resized = waitForViewportResizeTo(ui, 420, height);
|
||||
dimensions[0].focus();
|
||||
for (let i = 1; i <= 100; i++) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowUp", {});
|
||||
}
|
||||
await resized;
|
||||
|
||||
@ -53,20 +53,20 @@ async function setViewportSizeWithInputKeys(ui) {
|
||||
resized = waitForViewportResizeTo(ui, width, height);
|
||||
dimensions[0].focus();
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { shiftKey: true, code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {shiftKey: true});
|
||||
}
|
||||
await resized;
|
||||
|
||||
// Increase height value to 600 by using `PageUp + Shift` key
|
||||
resized = waitForViewportResizeTo(ui, width, 600);
|
||||
dimensions[1].focus();
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { shiftKey: true });
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", {shiftKey: true});
|
||||
await resized;
|
||||
|
||||
// Resetting height value back to 500 by using `PageDown + Shift` key
|
||||
resized = waitForViewportResizeTo(ui, width, height);
|
||||
dimensions[1].focus();
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { shiftKey: true });
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", {shiftKey: true});
|
||||
await resized;
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,7 @@ function waitForViewportResizeTo(ui, width, height) {
|
||||
// If the viewport has already the expected size, we resolve the promise immediately.
|
||||
let size = await getContentSize(ui);
|
||||
if (isSizeMatching(size)) {
|
||||
info(`Content already resized to ${width} x ${height}`);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
info("Pressing down key to select next item");
|
||||
event = defer();
|
||||
tree.once("select", pass);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
|
||||
let [name, data, attachment] = await event.promise;
|
||||
is(name, "select", "Select event was fired after pressing down");
|
||||
is(data[0], "level1", "Correct item was selected after pressing down");
|
||||
@ -119,7 +119,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
info("Pressing down key again to select next item");
|
||||
event = defer();
|
||||
tree.once("select", pass);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
|
||||
[name, data, attachment] = await event.promise;
|
||||
is(data.length, 2, "Correct level item was selected after second down keypress");
|
||||
is(data[0], "level1", "Correct parent level");
|
||||
@ -128,7 +128,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
info("Pressing down key again to select next item");
|
||||
event = defer();
|
||||
tree.once("select", pass);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
|
||||
[name, data, attachment] = await event.promise;
|
||||
is(data.length, 3, "Correct level item was selected after third down keypress");
|
||||
is(data[0], "level1", "Correct parent level");
|
||||
@ -138,7 +138,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
info("Pressing down key again to select next item");
|
||||
event = defer();
|
||||
tree.once("select", pass);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
|
||||
[name, data, attachment] = await event.promise;
|
||||
is(data.length, 2, "Correct level item was selected after fourth down keypress");
|
||||
is(data[0], "level1", "Correct parent level");
|
||||
@ -155,7 +155,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
event = defer();
|
||||
node = tree._selectedLabel;
|
||||
ok(node.hasAttribute("expanded"), "Item is expanded before left keypress");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {code: "ArrowLeft"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win);
|
||||
await event.promise;
|
||||
|
||||
ok(!node.hasAttribute("expanded"), "Item is not expanded after left keypress");
|
||||
@ -168,7 +168,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
// parent node should have no effect of this keypress
|
||||
node = tree.root.children.firstChild.nextSibling.firstChild;
|
||||
ok(node.hasAttribute("expanded"), "Parent is expanded");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {code: "ArrowLeft"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win);
|
||||
[name, data] = await event.promise;
|
||||
is(data.length, 3, "Correct level item was selected after second left keypress");
|
||||
is(data[0], "level1", "Correct parent level");
|
||||
@ -181,7 +181,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
info("Pressing down key to select next item");
|
||||
event = defer();
|
||||
tree.once("select", pass);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
|
||||
[name, data, attachment] = await event.promise;
|
||||
is(data.length, 2, "Correct level item was selected after fifth down keypress");
|
||||
is(data[0], "level1", "Correct parent level");
|
||||
@ -196,7 +196,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
event = defer();
|
||||
node = tree._selectedLabel;
|
||||
ok(node.hasAttribute("expanded"), "Item is expanded before left keypress");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {code: "ArrowLeft"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {}, win);
|
||||
await event.promise;
|
||||
ok(!node.hasAttribute("expanded"), "Item is collapsed after left keypress");
|
||||
|
||||
@ -209,7 +209,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
event = defer();
|
||||
node = tree._selectedLabel;
|
||||
ok(!node.hasAttribute("expanded"), "Item is collapsed before right keypress");
|
||||
EventUtils.synthesizeKey("KEY_ArrowRight", {code: "ArrowRight"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowRight", {}, win);
|
||||
await event.promise;
|
||||
ok(node.hasAttribute("expanded"), "Item is expanded after right keypress");
|
||||
|
||||
@ -223,7 +223,7 @@ async function testKeyboardInteraction(tree, win) {
|
||||
executeSoon(() => event.resolve(null));
|
||||
}, {once: true});
|
||||
info("Pressing down key on last item of the tree");
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"}, win);
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", {}, win);
|
||||
await event.promise;
|
||||
|
||||
ok(tree.isSelected(["level1.1", "level2", "level3"]),
|
||||
|
@ -10,101 +10,144 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#sidebar-panel-fontinspector > .devtools-toolbar {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#font-container {
|
||||
overflow: auto;
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
#all-fonts {
|
||||
.fonts-list {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#font-showall {
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#font-showall:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.font-format::before {
|
||||
content: "(";
|
||||
}
|
||||
|
||||
.font-format::after {
|
||||
content: ")";
|
||||
}
|
||||
|
||||
.preview-input-toolbar {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.font-preview-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#font-preview-text-input {
|
||||
margin-top: 1px;
|
||||
margin-bottom: 1px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
flex: 1;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.font {
|
||||
padding: 10px 10px;
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
border-width: 0 1px 1px 0;
|
||||
display: grid;
|
||||
grid-template-columns: 14px auto 1fr;
|
||||
grid-template-rows: 50px;
|
||||
grid-column-gap: 10px;
|
||||
padding: 0 10px 0 5px;
|
||||
}
|
||||
|
||||
.theme-dark .font {
|
||||
border-bottom: 1px solid #444;
|
||||
#font-container .theme-twisty {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
place-self: center;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.theme-light .font {
|
||||
border-bottom: 1px solid #DDD;
|
||||
}
|
||||
|
||||
.font:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.theme-light .font:nth-child(even) {
|
||||
background: #F4F4F4;
|
||||
.font-preview-container {
|
||||
grid-column: 3 / -1;
|
||||
grid-row: 1;
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
place-items: center end;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.font-preview {
|
||||
margin-left: -4px;
|
||||
height: 60px;
|
||||
height: 50px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.font-preview:hover {
|
||||
cursor: text;
|
||||
background-image: linear-gradient(to right,
|
||||
var(--grey-40) 3px, transparent 3px, transparent);
|
||||
background-size: 6px 1px;
|
||||
background-repeat: repeat-x;
|
||||
background-position-y: 45px;
|
||||
}
|
||||
|
||||
.font-preview-input {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: calc(100% - 5px);
|
||||
height: calc(100% - 2px);
|
||||
background: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.font-preview-input::-moz-selection {
|
||||
background: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.font-name {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
white-space: nowrap;
|
||||
grid-column: 2;
|
||||
place-self: center start;
|
||||
}
|
||||
|
||||
.font-details {
|
||||
grid-column: 2 / 4;
|
||||
padding-inline-end: 14px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.font-css-code {
|
||||
max-width: 100%;
|
||||
direction: ltr;
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: 5px;
|
||||
direction: ltr;
|
||||
color: var(--theme-toolbar-color);
|
||||
}
|
||||
|
||||
.theme-light .font-css-code,
|
||||
.theme-light .font-url {
|
||||
border: 1px solid #CCC;
|
||||
background: white;
|
||||
.font-css-code-expander::before {
|
||||
content: "\2026";
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 8px;
|
||||
margin: 0 2px;
|
||||
line-height: 3px;
|
||||
color: var(--theme-body-color-inactive);
|
||||
border-radius: 3px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.theme-dark .font-css-code,
|
||||
.theme-dark .font-url {
|
||||
border: 1px solid #333;
|
||||
background: black;
|
||||
color: white;
|
||||
.font-format-url {
|
||||
text-transform: capitalize;
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
.font-url {
|
||||
margin-inline-start: 1em;
|
||||
text-transform: uppercase;
|
||||
text-decoration: underline;
|
||||
color: var(--theme-highlight-blue);
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.font-url::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 13px;
|
||||
width: 13px;
|
||||
margin: -.3rem .15rem 0 0.25rem;
|
||||
vertical-align: middle;
|
||||
background-image: url(chrome://devtools-shim/content/aboutdevtools/images/external-link.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 13px 13px;
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--blue-60);
|
||||
}
|
||||
|
||||
|
||||
.font:not(.expanded) .font-css-name,
|
||||
.font:not(.expanded) .font-css-code,
|
||||
.font:not(.expanded) .font-format-url {
|
||||
display: none;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<!-- 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/. -->
|
||||
|
@ -166,31 +166,31 @@ support-files =
|
||||
!/devtools/client/shared/test/test-actor-registry.js
|
||||
|
||||
[browser_console.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437806
|
||||
[browser_console_addonsdk_loader_exception.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437807
|
||||
[browser_console_clear_method.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437843
|
||||
[browser_console_consolejsm_output.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437844
|
||||
[browser_console_dead_objects.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437845
|
||||
[browser_console_error_source_click.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437847
|
||||
[browser_console_filters.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437848
|
||||
[browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437849
|
||||
[browser_console_nsiconsolemessage.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437850
|
||||
[browser_console_open_or_focus.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437851
|
||||
[browser_console_restore.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437852
|
||||
[browser_console_webconsole_ctrlw_close_tab.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437854
|
||||
[browser_console_webconsole_iframe_messages.js]
|
||||
skip-if = true # Bug 1406060
|
||||
skip-if = true # Bug 1437855
|
||||
[browser_console_webconsole_private_browsing.js]
|
||||
skip-if = true # Bug 1403188
|
||||
# old console skip-if = e10s # Bug 1042253 - webconsole e10s tests
|
||||
@ -336,8 +336,6 @@ subsuite = clipboard
|
||||
skip-if = true # Bug 1403450
|
||||
[browser_webconsole_sandbox_update_after_navigation.js]
|
||||
[browser_webconsole_script_errordoc_urls.js]
|
||||
skip-if = true # Bug 1403454
|
||||
# old console skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
|
||||
[browser_webconsole_scroll.js]
|
||||
[browser_webconsole_select_all.js]
|
||||
[browser_webconsole_show_subresource_security_errors.js]
|
||||
|
@ -3,12 +3,15 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* import-globals-from head.js */
|
||||
|
||||
// Ensure that [Learn More] links appear alongside any errors listed
|
||||
// in "errordocs.js". Note: this only tests script execution.
|
||||
|
||||
"use strict";
|
||||
|
||||
const ErrorDocs = require("devtools/server/actors/errordocs");
|
||||
const TEST_URI = "data:text/html;charset=utf8,errordoc tests";
|
||||
|
||||
function makeURIData(script) {
|
||||
return `data:text/html;charset=utf8,<script>${script}</script>`;
|
||||
@ -19,49 +22,51 @@ const TestData = [
|
||||
jsmsg: "JSMSG_READ_ONLY",
|
||||
script: "'use strict'; (Object.freeze({name: 'Elsa', score: 157})).score = 0;",
|
||||
isException: true,
|
||||
expected: 'TypeError: "score" is read-only',
|
||||
},
|
||||
{
|
||||
jsmsg: "JSMSG_STMT_AFTER_RETURN",
|
||||
script: "function a() { return; 1 + 1; };",
|
||||
isException: false,
|
||||
expected: "unreachable code after return statement",
|
||||
}
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
yield loadTab("data:text/html;charset=utf8,errordoc tests");
|
||||
add_task(async function () {
|
||||
let hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
let hud = yield openConsole();
|
||||
|
||||
for (let i = 0; i < TestData.length; i++) {
|
||||
yield testScriptError(hud, TestData[i]);
|
||||
for (let data of TestData) {
|
||||
await testScriptError(hud, data);
|
||||
}
|
||||
});
|
||||
|
||||
function* testScriptError(hud, testData) {
|
||||
if (testData.isException === true) {
|
||||
async function testScriptError(hud, testData) {
|
||||
let isE10s = Services.appinfo.browserTabsRemoteAutostart;
|
||||
if (testData.isException && !isE10s) {
|
||||
expectUncaughtException();
|
||||
}
|
||||
|
||||
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, makeURIData(testData.script));
|
||||
await loadDocument(makeURIData(testData.script));
|
||||
|
||||
yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [
|
||||
{
|
||||
category: CATEGORY_JS
|
||||
}
|
||||
]
|
||||
});
|
||||
let msg = "the expected error message was displayed";
|
||||
info(`waiting for ${msg} to be displayed`);
|
||||
await waitFor(() => findMessage(hud, testData.expected));
|
||||
ok(true, msg);
|
||||
|
||||
// grab the most current error doc URL
|
||||
let url = ErrorDocs.GetURL({ errorMessageName: testData.jsmsg });
|
||||
// grab the most current error doc URL.
|
||||
let urlObj = new URL(ErrorDocs.GetURL({ errorMessageName: testData.jsmsg }));
|
||||
|
||||
let hrefs = {};
|
||||
for (let link of hud.jsterm.outputNode.querySelectorAll("a")) {
|
||||
hrefs[link.href] = true;
|
||||
// strip all params from the URL.
|
||||
let url = `${urlObj.origin}${urlObj.pathname}`;
|
||||
|
||||
// Gather all URLs displayed in the console. [Learn More] links have no href
|
||||
// but have the URL in the title attribute.
|
||||
let hrefs = new Set();
|
||||
for (let link of hud.ui.outputNode.querySelectorAll("a")) {
|
||||
hrefs.add(link.title);
|
||||
}
|
||||
|
||||
ok(url in hrefs, `Expected a link to ${url}.`);
|
||||
ok(hrefs.has(url), `Expected a link to ${url}.`);
|
||||
|
||||
hud.jsterm.clearOutput();
|
||||
}
|
||||
|
@ -31,14 +31,14 @@ const STATUS_CODES_GA_PARAMS = `?${new URLSearchParams({
|
||||
"utm_campaign": "default"
|
||||
})}`;
|
||||
|
||||
Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true);
|
||||
registerCleanupFunction(function* () {
|
||||
Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
|
||||
Services.prefs.setBoolPref("devtools.browserconsole.new-frontend-enabled", true);
|
||||
registerCleanupFunction(async function () {
|
||||
Services.prefs.clearUserPref("devtools.browserconsole.new-frontend-enabled");
|
||||
Services.prefs.clearUserPref("devtools.webconsole.ui.filterbar");
|
||||
|
||||
// Reset all filter prefs between tests. First flushPrefEnv in case one of the
|
||||
// filter prefs has been pushed for the test
|
||||
yield SpecialPowers.flushPrefEnv();
|
||||
await SpecialPowers.flushPrefEnv();
|
||||
Services.prefs.getChildList("devtools.webconsole.filter").forEach(pref => {
|
||||
Services.prefs.clearUserPref(pref);
|
||||
});
|
||||
@ -47,7 +47,7 @@ registerCleanupFunction(function* () {
|
||||
if (browserConsole.jsterm) {
|
||||
browserConsole.jsterm.clearOutput(true);
|
||||
}
|
||||
yield HUDService.toggleBrowserConsole();
|
||||
await HUDService.toggleBrowserConsole();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -62,7 +62,7 @@ add_task(async function() {
|
||||
|
||||
// Alt + D is a shortcut key to move focus to the URL bar and selects its text.
|
||||
info("Pressing Alt + D in the search bar...");
|
||||
EventUtils.synthesizeKey("d", {code: "KeyD", altKey: true});
|
||||
EventUtils.synthesizeKey("d", {altKey: true});
|
||||
|
||||
await promiseURLBarHasFocus();
|
||||
await promiseURLBarSelectsAllText();
|
||||
@ -74,7 +74,7 @@ add_task(async function() {
|
||||
gURLBar.inputField.value.length;
|
||||
|
||||
info("Pressing Alt + D in the URL bar...");
|
||||
EventUtils.synthesizeKey("d", {code: "KeyD", altKey: true});
|
||||
EventUtils.synthesizeKey("d", {altKey: true});
|
||||
await promiseURLBarHasFocus();
|
||||
await promiseURLBarSelectsAllText();
|
||||
|
||||
|
@ -38,7 +38,7 @@ function setTabFocus() {
|
||||
|
||||
var doc = document;
|
||||
function tab_to(id) {
|
||||
synthesizeKey("KEY_Tab", {code: "Tab"});
|
||||
synthesizeKey("KEY_Tab", {});
|
||||
is(doc.activeElement.id, id, "element with id=" + id + " should have focus");
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=238987
|
||||
|
||||
function tab() {
|
||||
// Send tab key events.
|
||||
synthesizeKey("KEY_Tab", {code: "Tab", shiftKey: activateShift});
|
||||
synthesizeKey("KEY_Tab", {shiftKey: activateShift});
|
||||
if (shouldStop) {
|
||||
// Did focus handling succeed
|
||||
is(forwardFocusArray.length, 0,
|
||||
|
@ -119,7 +119,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=409604
|
||||
}
|
||||
|
||||
function pressAccessKey(key) {
|
||||
synthesizeKey(key.key, {code: key.code, altKey: true, shiftKey: true});
|
||||
synthesizeKey(key.key, {altKey: true, shiftKey: true});
|
||||
}
|
||||
|
||||
function testFocusableElements() {
|
||||
@ -128,7 +128,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=409604
|
||||
if (code == "b".charCodeAt(0))
|
||||
continue;
|
||||
var accessChar = String.fromCharCode(code).toUpperCase();
|
||||
pressAccessKey({key: accessChar, code: "Key" + accessChar});
|
||||
pressAccessKey({key: accessChar});
|
||||
}
|
||||
ok(focusArray.length == 0, "(focus) unhandled elements remaining: " + focusArray.join(","));
|
||||
}
|
||||
@ -187,7 +187,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=409604
|
||||
var i, e;
|
||||
for (i = 0; i < unfocusableTags.length; ++ i) {
|
||||
createUnfocusableElement(unfocusableTags[i], "z");
|
||||
pressAccessKey({key: "Z", code:"KeyZ"});
|
||||
pressAccessKey({key: "Z"});
|
||||
destroyUnfocusableElement();
|
||||
}
|
||||
for (i = 0; i < invalidElements.length; ++ i) {
|
||||
@ -196,7 +196,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=409604
|
||||
e.setAttribute("accesskey", "z");
|
||||
e.setAttribute("onclick", "handleClick(event.target); event.preventDefault();");
|
||||
e.setAttribute("onfocus", "handleInvalid(event.target);");
|
||||
pressAccessKey({key: "Z", code:"KeyZ"});
|
||||
pressAccessKey({key: "Z"});
|
||||
e.removeAttribute("accesskey");
|
||||
e.removeAttribute("onclick");
|
||||
e.removeAttribute("onfocus");
|
||||
|
@ -25,7 +25,7 @@ function doTest() {
|
||||
document.getElementById('a').focus();
|
||||
is(document.activeElement, document.getElementById('a'), "link should have focus");
|
||||
is(document.hasFocus(), true, "document should be focused");
|
||||
synthesizeKey("KEY_Tab", {code: "Tab"});
|
||||
synthesizeKey("KEY_Tab", {});
|
||||
is(document.activeElement, document.getElementById('a'), "body element should be focused");
|
||||
is(document.hasFocus(), false, "document should not be focused");
|
||||
|
||||
|
@ -98,14 +98,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=493251
|
||||
function(e) { dumpEvent(e); ++mouseClick; }, true);
|
||||
|
||||
ok(true, "doTest #1...");
|
||||
synthesizeKey("a", {code: "KeyA"}, win);
|
||||
synthesizeKey("a", {}, win);
|
||||
is(keyDown, 1, "Wrong number events (1)");
|
||||
is(keyPress, 1, "Wrong number events (2)");
|
||||
is(keyUp, 1, "Wrong number events (3)");
|
||||
|
||||
ok(true, "doTest #2...");
|
||||
suppressEventHandling(true);
|
||||
synthesizeKey("a", {code: "KeyA"}, win);
|
||||
synthesizeKey("a", {}, win);
|
||||
is(keyDown, 1, "Wrong number events (4)");
|
||||
is(keyPress, 1, "Wrong number events (5)");
|
||||
is(keyUp, 1, "Wrong number events (6)");
|
||||
@ -120,7 +120,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=493251
|
||||
function continueTest1() {
|
||||
ok(true, "continueTest1...");
|
||||
win.addEventListener("keydown", () => { suppressEventHandling(true); }, {once: true});
|
||||
synthesizeKey("a", {code: "KeyA"}, win);
|
||||
synthesizeKey("a", {}, win);
|
||||
is(keyDown, 2, "Wrong number events (10)");
|
||||
is(keyPress, 1, "Wrong number events (11)");
|
||||
is(keyUp, 1, "Wrong number events (12)");
|
||||
|
@ -46,7 +46,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=545268
|
||||
subwin.addEventListener("mouseup", function(e) { ++mouseUp; }, true);
|
||||
subwin.addEventListener("click", function(e) { ++mouseClick; }, true);
|
||||
|
||||
synthesizeKey("a", {code: "KeyA"}, subwin);
|
||||
synthesizeKey("a", {}, subwin);
|
||||
is(keyDown, 1, "Wrong number events (1)");
|
||||
is(keyPress, 1, "Wrong number events (2)");
|
||||
is(keyUp, 1, "Wrong number events (3)");
|
||||
@ -54,7 +54,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=545268
|
||||
// Test that suppressing events on the parent window prevents key
|
||||
// events in the subdocument window
|
||||
utils.suppressEventHandling(true);
|
||||
synthesizeKey("a", {code: "KeyA"}, subwin);
|
||||
synthesizeKey("a", {}, subwin);
|
||||
is(keyDown, 1, "Wrong number events (4)");
|
||||
is(keyPress, 1, "Wrong number events (5)");
|
||||
is(keyUp, 1, "Wrong number events (6)");
|
||||
@ -69,7 +69,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=545268
|
||||
function continueTest1() {
|
||||
var utils = SpecialPowers.getDOMWindowUtils(win);
|
||||
subwin.addEventListener("keydown", () => { utils.suppressEventHandling(true); }, {once: true});
|
||||
synthesizeKey("a", {code: "KeyA"}, subwin);
|
||||
synthesizeKey("a", {}, subwin);
|
||||
is(keyDown, 2, "Wrong number events (10)");
|
||||
is(keyPress, 1, "Wrong number events (11)");
|
||||
is(keyUp, 1, "Wrong number events (12)");
|
||||
|
@ -84,9 +84,9 @@ async function runTests()
|
||||
iframe.contentWindow.addEventListener("scroll", onScroll, { once: true });
|
||||
|
||||
if (aVertical) {
|
||||
synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
|
||||
synthesizeKey("KEY_ArrowDown", {});
|
||||
} else {
|
||||
synthesizeKey("KEY_ArrowRight", { code: "ArrowRight" });
|
||||
synthesizeKey("KEY_ArrowRight", {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ if (observers.hasMoreElements()) {
|
||||
"control used for the submission");
|
||||
var c = document.getElementById('c');
|
||||
c.focus();
|
||||
synthesizeKey("KEY_Enter", { code: "Enter" });
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
});
|
||||
|
||||
document.getElementById('c').addEventListener("invalid", function(aEvent) {
|
||||
|
@ -210,11 +210,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=851780
|
||||
if (isDesktop) { // up/down arrow keys not supported on android/b2g
|
||||
number.value = "";
|
||||
number.focus();
|
||||
synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
|
||||
synthesizeKey("KEY_ArrowUp", {});
|
||||
is(numberInput, 1, "input event should be dispatched for up/down arrow key keypress");
|
||||
is(number.value, "1", "sanity check value of number control after keypress");
|
||||
|
||||
synthesizeKey("KEY_ArrowDown", { code: "ArrowDown", repeat: 3 });
|
||||
synthesizeKey("KEY_ArrowDown", {repeat: 3});
|
||||
is(numberInput, 4, "input event should be dispatched for each up/down arrow key keypress event, even when rapidly repeated");
|
||||
is(number.value, "-2", "sanity check value of number control after multiple keydown events");
|
||||
|
||||
|
@ -47,7 +47,7 @@ document.forms[1].addEventListener("submit", function(aEvent) {
|
||||
ok(true, "novalidate has been correctly used for second form");
|
||||
var c = document.getElementById('c');
|
||||
c.focus();
|
||||
synthesizeKey("KEY_Enter", { code: "Enter" });
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
}, {once: true});
|
||||
|
||||
document.forms[2].addEventListener("submit", function(aEvent) {
|
||||
|
@ -54,15 +54,15 @@ function runTests() {
|
||||
});
|
||||
|
||||
number.focus();
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown", code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown", code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keyup", code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keyup"});
|
||||
number.blur();
|
||||
range.focus();
|
||||
waiting_event_idx = 0;
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown", code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown", code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keyup", code: "ArrowDown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keydown"});
|
||||
synthesizeKey("KEY_ArrowDown", {type: "keyup"});
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ function runTest()
|
||||
document.getElementById('b').click();
|
||||
var c = document.getElementById('c');
|
||||
c.focus();
|
||||
synthesizeKey("KEY_Enter", { code: "Enter" });
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
document.getElementById('s2').click();
|
||||
}
|
||||
|
||||
|
@ -1543,25 +1543,9 @@ StartMacOSContentSandbox()
|
||||
MOZ_CRASH("Error resolving child process path");
|
||||
}
|
||||
|
||||
// During sandboxed content process startup, before reaching
|
||||
// this point, NS_OS_TEMP_DIR is modified to refer to a sandbox-
|
||||
// writable temporary directory
|
||||
nsCOMPtr<nsIFile> tempDir;
|
||||
nsresult rv = nsDirectoryService::gService->Get(NS_OS_TEMP_DIR,
|
||||
NS_GET_IID(nsIFile), getter_AddRefs(tempDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_CRASH("Failed to get NS_OS_TEMP_DIR");
|
||||
}
|
||||
|
||||
nsAutoCString tempDirPath;
|
||||
tempDir->Normalize();
|
||||
rv = tempDir->GetNativePath(tempDirPath);
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
|
||||
}
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIFile> profileDir;
|
||||
cc->GetProfileDir(getter_AddRefs(profileDir));
|
||||
nsCString profileDirPath;
|
||||
@ -1584,7 +1568,6 @@ StartMacOSContentSandbox()
|
||||
info.appPath.assign(appPath.get());
|
||||
info.appBinaryPath.assign(appBinaryPath.get());
|
||||
info.appDir.assign(appDir.get());
|
||||
info.appTempDir.assign(tempDirPath.get());
|
||||
info.hasAudio = !Preferences::GetBool("media.cubeb.sandbox");
|
||||
|
||||
// These paths are used to whitelist certain directories used by the testing
|
||||
|
@ -46,28 +46,16 @@ SetTmpEnvironmentVariable(nsIFile* aValue)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
static void
|
||||
SetTmpEnvironmentVariable(nsIFile* aValue)
|
||||
{
|
||||
nsAutoCString fullTmpPath;
|
||||
nsresult rv = aValue->GetNativePath(fullTmpPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
Unused << NS_WARN_IF(setenv("TMPDIR", fullTmpPath.get(), 1) != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
static void
|
||||
SetUpSandboxEnvironment()
|
||||
{
|
||||
MOZ_ASSERT(nsDirectoryService::gService,
|
||||
"SetUpSandboxEnvironment relies on nsDirectoryService being initialized");
|
||||
|
||||
// On macOS and Windows, a sandbox-writable temp directory is used whenever
|
||||
// the sandbox is enabled.
|
||||
// On Windows, a sandbox-writable temp directory is used whenever the sandbox
|
||||
// is enabled.
|
||||
if (!IsContentSandboxEnabled()) {
|
||||
return;
|
||||
}
|
||||
@ -247,7 +235,7 @@ ContentProcess::Init(int aArgc, char* aArgv[])
|
||||
mContent.SetProfileDir(profileDir);
|
||||
#endif
|
||||
|
||||
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
SetUpSandboxEnvironment();
|
||||
#endif
|
||||
|
||||
|
@ -235,6 +235,7 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
|
||||
mFullPath(aPluginInfo->fFullPath),
|
||||
mLastModifiedTime(aLastModifiedTime),
|
||||
mSandboxLevel(0),
|
||||
mIsSandboxLoggingEnabled(false),
|
||||
mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
|
||||
mCachedBlocklistStateValid(false),
|
||||
mIsFromExtension(fromExtension)
|
||||
@ -270,6 +271,7 @@ nsPluginTag::nsPluginTag(const char* aName,
|
||||
mFullPath(aFullPath),
|
||||
mLastModifiedTime(aLastModifiedTime),
|
||||
mSandboxLevel(0),
|
||||
mIsSandboxLoggingEnabled(false),
|
||||
mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
|
||||
mCachedBlocklistStateValid(false),
|
||||
mIsFromExtension(fromExtension)
|
||||
@ -306,6 +308,7 @@ nsPluginTag::nsPluginTag(uint32_t aId,
|
||||
mSupportsAsyncRender(aSupportsAsyncRender),
|
||||
mLastModifiedTime(aLastModifiedTime),
|
||||
mSandboxLevel(aSandboxLevel),
|
||||
mIsSandboxLoggingEnabled(false),
|
||||
mNiceFileName(),
|
||||
mCachedBlocklistState(aBlocklistState),
|
||||
mCachedBlocklistStateValid(true),
|
||||
@ -421,6 +424,30 @@ nsPluginTag::InitSandboxLevel()
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
// At present, the Mac Flash NPAPI plugin sandbox is controlled via
|
||||
// a boolean with no support for different levels. When the sandbox
|
||||
// is enabled, we set the level to 1.
|
||||
if (mIsFlashPlugin) {
|
||||
// Allow enabling the sandbox via the pref
|
||||
// security.sandbox.mac.flash.enabled or via the environment variable
|
||||
// MOZ_SANDBOX_MAC_FLASH_FORCE (which is useful while the sandbox is
|
||||
// off by default).
|
||||
if (Preferences::GetBool("security.sandbox.mac.flash.enabled") ||
|
||||
PR_GetEnv("MOZ_SANDBOX_MAC_FLASH_FORCE")) {
|
||||
mSandboxLevel = 1;
|
||||
|
||||
// Enable sandbox logging in the plugin process if it has
|
||||
// been turned on via prefs or environment variables.
|
||||
if (Preferences::GetBool("security.sandbox.logging.enabled") ||
|
||||
PR_GetEnv("MOZ_SANDBOX_LOGGING") ||
|
||||
PR_GetEnv("MOZ_SANDBOX_MAC_FLASH_LOGGING")) {
|
||||
mIsSandboxLoggingEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(XP_WIN) && !defined(XP_MACOSX)
|
||||
|
@ -173,6 +173,7 @@ public:
|
||||
int64_t mLastModifiedTime;
|
||||
nsCOMPtr<nsITimer> mUnloadTimer;
|
||||
int32_t mSandboxLevel;
|
||||
bool mIsSandboxLoggingEnabled;
|
||||
|
||||
void InvalidateBlocklistState();
|
||||
|
||||
|
@ -54,6 +54,10 @@
|
||||
#include "ChildProfilerController.h"
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::plugins;
|
||||
@ -99,6 +103,10 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome)
|
||||
, mGlobalCallWndProcHook(nullptr)
|
||||
, mAsyncRenderSupport(false)
|
||||
#endif
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
, mEnableFlashSandbox(false)
|
||||
, mEnableFlashSandboxLogging(false)
|
||||
#endif
|
||||
{
|
||||
memset(&mFunctions, 0, sizeof(mFunctions));
|
||||
if (mIsChrome) {
|
||||
@ -191,6 +199,15 @@ PluginModuleChild::RecvDisableFlashProtectedMode()
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
void
|
||||
PluginModuleChild::EnableFlashSandbox(bool aShouldEnableLogging)
|
||||
{
|
||||
mEnableFlashSandbox = true;
|
||||
mEnableFlashSandboxLogging = aShouldEnableLogging;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
|
||||
base::ProcessId aParentPid,
|
||||
@ -282,6 +299,22 @@ PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
|
||||
|
||||
# error Please copy the initialization code from nsNPAPIPlugin.cpp
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
||||
if (mEnableFlashSandbox) {
|
||||
MacSandboxInfo flashSandboxInfo;
|
||||
flashSandboxInfo.type = MacSandboxType_Plugin;
|
||||
flashSandboxInfo.pluginInfo.type = MacSandboxPluginType_Flash;
|
||||
flashSandboxInfo.pluginInfo.pluginBinaryPath = aPluginFilename;
|
||||
flashSandboxInfo.shouldLog = mEnableFlashSandboxLogging;
|
||||
|
||||
std::string sbError;
|
||||
if (!mozilla::StartMacSandbox(flashSandboxInfo, sbError)) {
|
||||
fprintf(stderr, "Failed to start sandbox:\n%s\n", sbError.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
@ -313,7 +313,17 @@ public: // called by PluginInstanceChild
|
||||
return mFunctions.destroy(instance->GetNPP(), 0);
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && defined(MOZ_SANDBOX)
|
||||
void EnableFlashSandbox(bool aShouldEnableLogging);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#if defined(OS_MACOSX) && defined(MOZ_SANDBOX)
|
||||
bool mEnableFlashSandbox;
|
||||
bool mEnableFlashSandboxLogging;
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
virtual void EnteredCall() override;
|
||||
virtual void ExitedCall() override;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user