merge fx-team to mozilla-central a=merge
|
@ -3785,11 +3785,6 @@
|
|||
this.getTabState(this.requestedTab) == this.STATE_LOADED) {
|
||||
// After this point the tab has switched from the content thread's point of view.
|
||||
// The changes will be visible after the next refresh driver tick + composite.
|
||||
let event = new CustomEvent("TabSwitched", {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
this.tabbrowser.dispatchEvent(event);
|
||||
let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
|
||||
if (time != -1) {
|
||||
TelemetryStopwatch.finish("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
|
||||
|
|
|
@ -504,8 +504,8 @@ const CustomizableWidgets = [
|
|||
shortcutId: "key_privatebrowsing",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(e) {
|
||||
let win = e.target && e.target.ownerGlobal;
|
||||
if (win && typeof win.OpenBrowserWindow == "function") {
|
||||
let win = e.target.ownerGlobal;
|
||||
if (typeof win.OpenBrowserWindow == "function") {
|
||||
win.OpenBrowserWindow({private: true});
|
||||
}
|
||||
}
|
||||
|
@ -515,9 +515,8 @@ const CustomizableWidgets = [
|
|||
tooltiptext: "save-page-button.tooltiptext3",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
let win = aEvent.target &&
|
||||
aEvent.target.ownerGlobal;
|
||||
if (win && typeof win.saveBrowser == "function") {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
if (typeof win.saveBrowser == "function") {
|
||||
win.saveBrowser(win.gBrowser.selectedBrowser);
|
||||
}
|
||||
}
|
||||
|
@ -527,9 +526,8 @@ const CustomizableWidgets = [
|
|||
tooltiptext: "find-button.tooltiptext3",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
let win = aEvent.target &&
|
||||
aEvent.target.ownerGlobal;
|
||||
if (win && win.gFindBar) {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
if (win.gFindBar) {
|
||||
win.gFindBar.onFindCommand();
|
||||
}
|
||||
}
|
||||
|
@ -539,9 +537,8 @@ const CustomizableWidgets = [
|
|||
tooltiptext: "open-file-button.tooltiptext3",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
let win = aEvent.target
|
||||
&& aEvent.target.ownerGlobal;
|
||||
if (win && typeof win.BrowserOpenFileWindow == "function") {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
if (typeof win.BrowserOpenFileWindow == "function") {
|
||||
win.BrowserOpenFileWindow();
|
||||
}
|
||||
}
|
||||
|
@ -617,9 +614,8 @@ const CustomizableWidgets = [
|
|||
tooltiptext: "add-ons-button.tooltiptext3",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
let win = aEvent.target &&
|
||||
aEvent.target.ownerGlobal;
|
||||
if (win && typeof win.BrowserOpenAddonsMgr == "function") {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
if (typeof win.BrowserOpenAddonsMgr == "function") {
|
||||
win.BrowserOpenAddonsMgr();
|
||||
}
|
||||
}
|
||||
|
@ -1154,9 +1150,8 @@ let preferencesButton = {
|
|||
id: "preferences-button",
|
||||
defaultArea: CustomizableUI.AREA_PANEL,
|
||||
onCommand: function(aEvent) {
|
||||
let win = aEvent.target &&
|
||||
aEvent.target.ownerGlobal;
|
||||
if (win && typeof win.openPreferences == "function") {
|
||||
let win = aEvent.target.ownerGlobal;
|
||||
if (typeof win.openPreferences == "function") {
|
||||
win.openPreferences();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,10 +77,12 @@ CommandList.prototype = {
|
|||
for (let name of Object.keys(manifest.commands)) {
|
||||
let command = manifest.commands[name];
|
||||
let shortcut = command.suggested_key[os] || command.suggested_key.default;
|
||||
commands.set(name, {
|
||||
description: command.description,
|
||||
shortcut: shortcut.replace(/\s+/g, ""),
|
||||
});
|
||||
if (shortcut) {
|
||||
commands.set(name, {
|
||||
description: command.description,
|
||||
shortcut: shortcut.replace(/\s+/g, ""),
|
||||
});
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
|
@ -124,7 +126,7 @@ CommandList.prototype = {
|
|||
// therefore the listeners for these elements will be garbage collected.
|
||||
keyElement.addEventListener("command", (event) => {
|
||||
if (name == "_execute_page_action") {
|
||||
let win = event.target.ownerGlobal;
|
||||
let win = event.target.ownerDocument.defaultView;
|
||||
pageActionFor(this.extension).triggerAction(win);
|
||||
} else {
|
||||
this.emit("command", name);
|
||||
|
|
|
@ -2,32 +2,185 @@
|
|||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
add_task(function* test_user_defined_commands() {
|
||||
const testCommands = [
|
||||
// Ctrl Shortcuts
|
||||
{
|
||||
name: "toggle-ctrl-a",
|
||||
shortcut: "Ctrl+A",
|
||||
key: "A",
|
||||
modifiers: {
|
||||
accelKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-ctrl-up",
|
||||
shortcut: "Ctrl+Up",
|
||||
key: "VK_UP",
|
||||
modifiers: {
|
||||
accelKey: true,
|
||||
},
|
||||
},
|
||||
// Alt Shortcuts
|
||||
{
|
||||
name: "toggle-alt-1",
|
||||
shortcut: "Alt+1",
|
||||
key: "1",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-alt-a",
|
||||
shortcut: "Alt+A",
|
||||
key: "A",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-alt-down",
|
||||
shortcut: "Alt+Down",
|
||||
key: "VK_DOWN",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
},
|
||||
},
|
||||
// Mac Shortcuts
|
||||
{
|
||||
name: "toggle-command-shift-page-up",
|
||||
shortcutMac: "Command+Shift+PageUp",
|
||||
key: "VK_PAGE_UP",
|
||||
modifiers: {
|
||||
accelKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-mac-control-b",
|
||||
shortcut: "Ctrl+B",
|
||||
shortcutMac: "MacCtrl+B",
|
||||
key: "B",
|
||||
modifiers: {
|
||||
ctrlKey: true,
|
||||
},
|
||||
},
|
||||
// Ctrl+Shift Shortcuts
|
||||
{
|
||||
name: "toggle-ctrl-shift-1",
|
||||
shortcut: "Ctrl+Shift+1",
|
||||
key: "1",
|
||||
modifiers: {
|
||||
accelKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-ctrl-shift-i",
|
||||
shortcut: "Ctrl+Shift+I",
|
||||
key: "I",
|
||||
modifiers: {
|
||||
accelKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-ctrl-shift-left",
|
||||
shortcut: "Ctrl+Shift+Left",
|
||||
key: "VK_LEFT",
|
||||
modifiers: {
|
||||
accelKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
// Alt+Shift Shortcuts
|
||||
{
|
||||
name: "toggle-alt-shift-1",
|
||||
shortcut: "Alt+Shift+1",
|
||||
key: "1",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-alt-shift-a",
|
||||
shortcut: "Alt+Shift+A",
|
||||
key: "A",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toggle-alt-shift-right",
|
||||
shortcut: "Alt+Shift+Right",
|
||||
key: "VK_RIGHT",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
// Misc Shortcuts
|
||||
{
|
||||
name: "unrecognized-property-name",
|
||||
shortcut: "Alt+Shift+3",
|
||||
key: "3",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
unrecognized_property: "with-a-random-value",
|
||||
},
|
||||
{
|
||||
name: "spaces-in-shortcut-name",
|
||||
shortcut: " Alt + Shift + 2 ",
|
||||
key: "2",
|
||||
modifiers: {
|
||||
altKey: true,
|
||||
shiftKey: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Create a window before the extension is loaded.
|
||||
let win1 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots");
|
||||
yield BrowserTestUtils.browserLoaded(win1.gBrowser.selectedBrowser);
|
||||
|
||||
let commands = {};
|
||||
let isMac = AppConstants.platform == "macosx";
|
||||
let totalMacOnlyCommands = 0;
|
||||
|
||||
for (let testCommand of testCommands) {
|
||||
let command = {
|
||||
suggested_key: {},
|
||||
};
|
||||
|
||||
if (testCommand.shortcut) {
|
||||
command.suggested_key.default = testCommand.shortcut;
|
||||
}
|
||||
|
||||
if (testCommand.shortcutMac) {
|
||||
command.suggested_key.mac = testCommand.shortcutMac;
|
||||
}
|
||||
|
||||
if (testCommand.shortcutMac && !testCommand.shortcut) {
|
||||
totalMacOnlyCommands++;
|
||||
}
|
||||
|
||||
if (testCommand.unrecognized_property) {
|
||||
command.unrecognized_property = testCommand.unrecognized_property;
|
||||
}
|
||||
|
||||
commands[testCommand.name] = command;
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"commands": {
|
||||
"toggle-feature-using-alt-shift-3": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+3",
|
||||
},
|
||||
},
|
||||
"toggle-feature-using-alt-shift-comma": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+Comma",
|
||||
},
|
||||
"unrecognized_property": "with-a-random-value",
|
||||
},
|
||||
"toggle-feature-with-whitespace-in-suggested-key": {
|
||||
"suggested_key": {
|
||||
"default": " Alt + Shift + 2 ",
|
||||
},
|
||||
},
|
||||
},
|
||||
"commands": commands,
|
||||
},
|
||||
|
||||
background: function() {
|
||||
|
@ -38,7 +191,6 @@ add_task(function* test_user_defined_commands() {
|
|||
},
|
||||
});
|
||||
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
let waitForConsole = new Promise(resolve => {
|
||||
SimpleTest.monitorConsole(resolve, [{
|
||||
|
@ -49,35 +201,41 @@ add_task(function* test_user_defined_commands() {
|
|||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
function* runTest() {
|
||||
for (let testCommand of testCommands) {
|
||||
if (testCommand.shortcutMac && !isMac) {
|
||||
continue;
|
||||
}
|
||||
EventUtils.synthesizeKey(testCommand.key, testCommand.modifiers);
|
||||
let message = yield extension.awaitMessage("oncommand");
|
||||
is(message, testCommand.name, "Expected onCommand listener to fire with the correct command name");
|
||||
}
|
||||
}
|
||||
|
||||
// Create another window after the extension is loaded.
|
||||
let win2 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield BrowserTestUtils.loadURI(win2.gBrowser.selectedBrowser, "about:config");
|
||||
yield BrowserTestUtils.browserLoaded(win2.gBrowser.selectedBrowser);
|
||||
|
||||
let totalTestCommands = Object.keys(testCommands).length;
|
||||
let expectedCommandsRegistered = isMac ? totalTestCommands : totalTestCommands - totalMacOnlyCommands;
|
||||
|
||||
// Confirm the keysets have been added to both windows.
|
||||
let keysetID = `ext-keyset-id-${makeWidgetId(extension.id)}`;
|
||||
let keyset = win1.document.getElementById(keysetID);
|
||||
ok(keyset != null, "Expected keyset to exist");
|
||||
is(keyset.childNodes.length, 3, "Expected keyset to have 3 children");
|
||||
is(keyset.childNodes.length, expectedCommandsRegistered, "Expected keyset to have the correct number of children");
|
||||
|
||||
keyset = win2.document.getElementById(keysetID);
|
||||
ok(keyset != null, "Expected keyset to exist");
|
||||
is(keyset.childNodes.length, 3, "Expected keyset to have 3 children");
|
||||
is(keyset.childNodes.length, expectedCommandsRegistered, "Expected keyset to have the correct number of children");
|
||||
|
||||
// Confirm that the commands are registered to both windows.
|
||||
yield focusWindow(win1);
|
||||
EventUtils.synthesizeKey("3", {altKey: true, shiftKey: true});
|
||||
let message = yield extension.awaitMessage("oncommand");
|
||||
is(message, "toggle-feature-using-alt-shift-3", "Expected onCommand listener to fire with correct message");
|
||||
yield runTest();
|
||||
|
||||
yield focusWindow(win2);
|
||||
EventUtils.synthesizeKey("VK_COMMA", {altKey: true, shiftKey: true});
|
||||
message = yield extension.awaitMessage("oncommand");
|
||||
is(message, "toggle-feature-using-alt-shift-comma", "Expected onCommand listener to fire with correct message");
|
||||
|
||||
EventUtils.synthesizeKey("2", {altKey: true, shiftKey: true});
|
||||
message = yield extension.awaitMessage("oncommand");
|
||||
is(message, "toggle-feature-with-whitespace-in-suggested-key", "Expected onCommand listener to fire with correct message");
|
||||
yield runTest();
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
|
@ -94,5 +252,3 @@ add_task(function* test_user_defined_commands() {
|
|||
SimpleTest.endMonitorConsole();
|
||||
yield waitForConsole;
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -125,14 +125,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "TabCrashHandler",
|
||||
"resource:///modules/ContentCrashHandlers.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluginCrashReporter",
|
||||
"resource:///modules/ContentCrashHandlers.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
|
||||
"resource://gre/modules/CrashSubmit.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
|
||||
|
@ -2482,8 +2481,12 @@ BrowserGlue.prototype = {
|
|||
} else {
|
||||
title = bundle.GetStringFromName("tabsArrivingNotification.title");
|
||||
const tabArrivingBody = URIs.every(URI => URI.clientId == URIs[0].clientId) ?
|
||||
"tabsArrivingNotification.body" : "tabsArrivingNotificationMultiple.body";
|
||||
body = bundle.formatStringFromName(tabArrivingBody, [URIs.length, deviceName], 2);
|
||||
"unnamedTabsArrivingNotification.body" :
|
||||
"unnamedTabsArrivingNotificationMultiple.body";
|
||||
body = bundle.GetStringFromName(tabArrivingBody);
|
||||
body = PluralForm.get(URIs.length, body);
|
||||
body = body.replace("#1", URIs.length);
|
||||
body = body.replace("#2", deviceName);
|
||||
}
|
||||
|
||||
const clickCallback = (subject, topic, data) => {
|
||||
|
|
|
@ -370,11 +370,11 @@ var ScrollPositionListener = {
|
|||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
let frame = event.target && event.target.defaultView;
|
||||
let frame = event.target.defaultView;
|
||||
|
||||
// Don't collect scroll data for frames created at or after the load event
|
||||
// as SessionStore can't restore scroll data for those.
|
||||
if (frame && gFrameTree.contains(frame)) {
|
||||
if (gFrameTree.contains(frame)) {
|
||||
MessageQueue.push("scroll", () => this.collect());
|
||||
}
|
||||
},
|
||||
|
@ -417,12 +417,11 @@ var FormDataListener = {
|
|||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
let frame = event.target &&
|
||||
event.target.ownerGlobal;
|
||||
let frame = event.target.ownerGlobal;
|
||||
|
||||
// Don't collect form data for frames created at or after the load event
|
||||
// as SessionStore can't restore form data for those.
|
||||
if (frame && gFrameTree.contains(frame)) {
|
||||
if (gFrameTree.contains(frame)) {
|
||||
MessageQueue.push("formdata", () => this.collect());
|
||||
}
|
||||
},
|
||||
|
|
|
@ -47,9 +47,13 @@ tabArrivingNotification.title = Tab received
|
|||
tabArrivingNotification.body = “%1$S” has arrived from %2$S.
|
||||
|
||||
tabsArrivingNotification.title = Multiple tabs received
|
||||
# LOCALIZATION NOTE (tabsArrivingNotification.body) %1 is the number of tabs received and %2 is the device name.
|
||||
tabsArrivingNotification.body = %1$S tabs have arrived from %2$S.
|
||||
# LOCALIZATION NOTE (tabsArrivingNotificationMultiple.body)
|
||||
# This string is used in a notification shown when we're opening tab(s) that several devices sent us to display.
|
||||
# %S is the number of tabs received
|
||||
tabsArrivingNotificationMultiple.body = %S tabs have arrived from your connected devices.
|
||||
# LOCALIZATION NOTE (unnamedTabsArrivingNotification.body):
|
||||
# Semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 is the number of tabs received and #2 is the device name.
|
||||
unnamedTabsArrivingNotification.body = #1 tab has arrived from #2.;#1 tabs have arrived from #2.
|
||||
# LOCALIZATION NOTE (unnamedTabsArrivingNotificationMultiple.body):
|
||||
# Semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 is the number of tabs received.
|
||||
unnamedTabsArrivingNotificationMultiple.body = #1 tab has arrived from your connected devices.;#1 tabs have arrived from your connected devices.
|
||||
|
|
|
@ -5,15 +5,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="16" height="16" viewBox="0 0 16 16">
|
||||
<defs>
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
.style-icon-notification {
|
||||
fill: #999;
|
||||
}
|
||||
</style>
|
||||
<path id="shape-notifications-addons" d="M10,15c0.5,0,1-0.4,1-1v-3c0,0,0-0.8,0.8-0.8c0.6,0,0.6,0.8,1.8,0.8c0.6,0,1.5-0.2,1.5-2c0-1.8-0.9-2-1.5-2 c-1.1,0-1.1,0.7-1.8,0.7C11,7.7,11,7,11,7V6c0-0.6-0.5-1-1-1H8c0,0-0.8,0-0.8-0.8C7.2,3.6,8,3.6,8,2.5C8,1.9,7.8,1,6,1 C4.2,1,4,1.9,4,2.5c0,1.1,0.8,1.1,0.8,1.8C4.8,5,4,5,4,5H2C1.5,5,1,5.4,1,6l0,1.5c0,0-0.1,1,1.1,1c0.8,0,0.9-1,1.9-1 C4.5,7.4,5,8,5,9c0,1-0.5,1.6-1,1.6c-1,0-1.1-1.1-1.9-1.1C0.9,9.5,1,10.8,1,10.8V14c0,0.6,0.5,1,1,1l2.6,0c0,0,1.1,0,1.1-1 c0-0.8-1-0.1-1-1.1c0-0.5,0.7-1.2,1.8-1.2s1.8,0.7,1.8,1.2c0,1-1.1,0.3-1.1,1.1c0,1,1.2,1,1.2,1H10z"/>
|
||||
</defs>
|
||||
<use id="default" xlink:href="#shape-notifications-addons" class="style-icon-notification"/>
|
||||
<use id="default" xlink:href="#shape-notifications-addons" />
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 1.2 KiB После Ширина: | Высота: | Размер: 1.0 KiB |
|
@ -66,7 +66,7 @@
|
|||
skin/classic/browser/identity-mixed-passive-loaded.svg (../shared/identity-block/identity-mixed-passive-loaded.svg)
|
||||
skin/classic/browser/identity-mixed-active-loaded.svg (../shared/identity-block/identity-mixed-active-loaded.svg)
|
||||
skin/classic/browser/info.svg (../shared/info.svg)
|
||||
skin/classic/browser/permissions.svg (../shared/permissions.svg)
|
||||
skin/classic/browser/notification-icons.svg (../shared/notification-icons.svg)
|
||||
skin/classic/browser/tracking-protection-16.svg (../shared/identity-block/tracking-protection-16.svg)
|
||||
skin/classic/browser/tracking-protection-disabled-16.svg (../shared/identity-block/tracking-protection-disabled-16.svg)
|
||||
skin/classic/browser/newtab/close.png (../shared/newtab/close.png)
|
||||
|
@ -127,12 +127,6 @@
|
|||
skin/classic/browser/reader-tour.png (../shared/reader/reader-tour.png)
|
||||
skin/classic/browser/reader-tour@2x.png (../shared/reader/reader-tour@2x.png)
|
||||
skin/classic/browser/readerMode.svg (../shared/reader/readerMode.svg)
|
||||
skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png)
|
||||
skin/classic/browser/notification-pluginNormal@2x.png (../shared/plugins/notification-pluginNormal@2x.png)
|
||||
skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png)
|
||||
skin/classic/browser/notification-pluginAlert@2x.png (../shared/plugins/notification-pluginAlert@2x.png)
|
||||
skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png)
|
||||
skin/classic/browser/notification-pluginBlocked@2x.png (../shared/plugins/notification-pluginBlocked@2x.png)
|
||||
skin/classic/browser/webRTC-camera-white-16.png (../shared/webrtc/camera-white-16.png)
|
||||
skin/classic/browser/webRTC-microphone-white-16.png (../shared/webrtc/microphone-white-16.png)
|
||||
skin/classic/browser/webRTC-screen-white-16.png (../shared/webrtc/screen-white-16.png)
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
margin-inline-end: 10px;
|
||||
}
|
||||
|
||||
#notification-popup-box > .notification-anchor-icon:hover {
|
||||
fill: #606060;
|
||||
}
|
||||
|
||||
/* INDIVIDUAL NOTIFICATIONS */
|
||||
|
||||
/* For the moment we apply the color filter only on the icons listed here.
|
||||
|
@ -50,8 +54,10 @@
|
|||
.camera-icon,
|
||||
.geo-icon,
|
||||
.indexedDB-icon,
|
||||
.install-icon,
|
||||
.login-icon,
|
||||
.microphone-icon,
|
||||
.plugin-icon,
|
||||
.pointerLock-icon,
|
||||
.popup-icon,
|
||||
.screen-icon,
|
||||
|
@ -81,58 +87,58 @@
|
|||
|
||||
.popup-notification-icon[popupid="web-notifications"],
|
||||
.desktop-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#desktop-notification);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification);
|
||||
}
|
||||
|
||||
.desktop-notification-icon.blocked {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#desktop-notification-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#desktop-notification-blocked);
|
||||
}
|
||||
|
||||
.geo-icon {
|
||||
%ifdef XP_MACOSX
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-osx);
|
||||
%elif defined(MOZ_WIDGET_GTK)
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-linux);
|
||||
%else
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-windows);
|
||||
%endif
|
||||
}
|
||||
|
||||
.geo-icon.blocked {
|
||||
%ifdef XP_MACOSX
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-osx-blocked);
|
||||
%elif defined(MOZ_WIDGET_GTK)
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-linux-blocked);
|
||||
%else
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-windows-blocked);
|
||||
%endif
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
%ifdef XP_MACOSX
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-osx);
|
||||
%elif defined(MOZ_WIDGET_GTK)
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-detailed);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-linux-detailed);
|
||||
%else
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-detailed);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#geo-windows-detailed);
|
||||
%endif
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.indexedDB-icon {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#indexedDB);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#indexedDB);
|
||||
}
|
||||
|
||||
.indexedDB-icon.blocked {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#indexedDB-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#indexedDB-blocked);
|
||||
}
|
||||
|
||||
.login-icon {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#login);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#login);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password"] {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#login-detailed);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#login-detailed);
|
||||
}
|
||||
|
||||
#login-fill-notification-icon {
|
||||
|
@ -145,50 +151,50 @@
|
|||
.camera-icon,
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#camera);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#camera);
|
||||
}
|
||||
|
||||
.camera-icon.blocked {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#camera-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#camera-blocked);
|
||||
}
|
||||
|
||||
/* The first selector is used by socialchat.xml (bug 1275558). */
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
.microphone-icon {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#microphone);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone);
|
||||
}
|
||||
|
||||
.microphone-icon.blocked {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#microphone-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-blocked);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#microphone-detailed);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#microphone-detailed);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.screen-icon {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#screen);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#screen);
|
||||
}
|
||||
|
||||
.screen-icon.blocked {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#screen-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#screen-blocked);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"],
|
||||
.pointerLock-icon {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#pointerLock);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#pointerLock);
|
||||
}
|
||||
|
||||
.pointerLock-icon.blocked {
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#pointerLock-blocked);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#pointerLock-blocked);
|
||||
}
|
||||
|
||||
/* This icon has a block sign in it, so we don't need a blocked version. */
|
||||
.popup-icon {
|
||||
list-style-image: url("chrome://browser/skin/permissions.svg#popup");
|
||||
list-style-image: url("chrome://browser/skin/notification-icons.svg#popup");
|
||||
}
|
||||
|
||||
/* EME */
|
||||
|
@ -263,41 +269,14 @@
|
|||
/* PLUGINS */
|
||||
|
||||
.plugin-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
||||
.plugin-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#plugin);
|
||||
}
|
||||
|
||||
.plugin-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
list-style-image: url(chrome://browser/skin/notification-icons.svg#plugin-blocked);
|
||||
fill: #d92215;
|
||||
}
|
||||
|
||||
.plugin-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.plugin-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png);
|
||||
}
|
||||
|
||||
.plugin-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png);
|
||||
}
|
||||
|
||||
.plugin-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png);
|
||||
}
|
||||
|
||||
.plugin-icon {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
<path id="login-detailed-icon" d="m 1,27 0,3.5 a 0.5,0.5 0 0 0 0.5,0.5 l 5,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1.5 1.5,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1.5 1,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-1 1,0 a 0.5,0.5 0 0 0 0.5,-0.5 l 0,-2 2,0 2.5,-2.5 q 0.5,-0.5 1,0 l 1,1 c 0.5,0.5 1,0.5 1.5,-0.5 l 1,-2 a 9,9 0 1 0 -8,-8 l -2,1 c -1,0.5 -1,1 -0.5,1.5 l 1.5,1.5 q 0.5,0.5 0,1 z m 21,-19.1 a 2,2 0 1 1 0,0.2 z" />
|
||||
<path id="microphone-icon" d="m 8,14 0,4 a 8,8 0 0 0 6,7.7 l 0,2.3 -2,0 a 2,2 0 0 0 -2,2 l 12,0 a 2,2 0 0 0 -2,-2 l -2,0 0,-2.3 a 8,8 0 0 0 6,-7.7 l 0,-4 -2,0 0,4 a 6,6 0 0 1 -12,0 l 0,-4 z m 4,4 a 4,4 0 0 0 8,0 l 0,-12 a 4,4 0 0 0 -8,0 z" />
|
||||
<path id="microphone-detailed-icon" d="m 8,18 a 8,8 0 0 0 6,7.7 l 0,2.3 -1,0 a 3,2 0 0 0 -3,2 l 12,0 a 3,2 0 0 0 -3,-2 l -1,0 0,-2.3 a 8,8 0 0 0 6,-7.7 l 0,-4 a 1,1 0 0 0 -2,0 l 0,4 a 6,6 0 0 1 -12,0 l 0,-4 a 1,1 0 0 0 -2,0 z m 4,0 a 4,4 0 0 0 8,0 l 0,-12 a 4,4 0 0 0 -8,0 z" />
|
||||
<path id="plugin-icon" d="m 2,26 a 2,2 0 0 0 2,2 l 24,0 a 2,2 0 0 0 2,-2 l 0,-16 a 2,2 0 0 0 -2,-2 l -24,0 a 2,2 0 0 0 -2,2 z m 2,-20 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z m 14,0 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z" />
|
||||
<path id="pointerLock-icon" d="m 8,24 6,-5 5,10 4,-2 -5,-10 7,-1 -17,-14 z" />
|
||||
<path id="popup-icon" d="m 2,24 a 4,4 0 0 0 4,4 l 8,0 a 10,10 0 0 1 -2,-4 l -4,0 a 2,2 0 0 1 -2,-2 l 0,-12 18,0 0,2 a 10,10 0 0 1 4,2 l 0,-8 a 4,4 0 0 0 -4,-4 l -18,0 a 4,4 0 0 0 -4,4 z m 12,-2.1 a 8,8 0 1 1 0,0.2 m 10.7,-4.3 a 5,5 0 0 0 -6.9,6.9 z m -5.4,8.4 a 5,5 0 0 0 6.9,-6.9 z" />
|
||||
<path id="screen-icon" d="m 2,18 a 2,2 0 0 0 2,2 l 2,0 0,-6 a 4,4 0 0 1 4,-4 l 14,0 0,-6 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z m 6,10 a 2,2 0 0 0 2,2 l 18,0 a 2,2 0 0 0 2,-2 l 0,-14 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z" />
|
||||
|
@ -61,6 +62,8 @@
|
|||
<use id="microphone" xlink:href="#microphone-icon" />
|
||||
<use id="microphone-blocked" class="blocked" xlink:href="#microphone-icon" />
|
||||
<use id="microphone-detailed" xlink:href="#microphone-detailed-icon" />
|
||||
<use id="plugin" xlink:href="#plugin-icon" />
|
||||
<use id="plugin-blocked" class="blocked" xlink:href="#plugin-icon" />
|
||||
<use id="pointerLock" xlink:href="#pointerLock-icon" />
|
||||
<use id="pointerLock-blocked" class="blocked" xlink:href="#pointerLock-icon" />
|
||||
<use id="popup" xlink:href="#popup-icon" />
|
До Ширина: | Высота: | Размер: 5.7 KiB После Ширина: | Высота: | Размер: 6.1 KiB |
Двоичные данные
browser/themes/shared/plugins/notification-pluginAlert.png
До Ширина: | Высота: | Размер: 648 B |
Двоичные данные
browser/themes/shared/plugins/notification-pluginAlert@2x.png
До Ширина: | Высота: | Размер: 1.2 KiB |
Двоичные данные
browser/themes/shared/plugins/notification-pluginBlocked.png
До Ширина: | Высота: | Размер: 968 B |
Двоичные данные
browser/themes/shared/plugins/notification-pluginBlocked@2x.png
До Ширина: | Высота: | Размер: 2.0 KiB |
Двоичные данные
browser/themes/shared/plugins/notification-pluginNormal.png
До Ширина: | Высота: | Размер: 340 B |
Двоичные данные
browser/themes/shared/plugins/notification-pluginNormal@2x.png
До Ширина: | Высота: | Размер: 469 B |
|
@ -114,15 +114,15 @@
|
|||
}
|
||||
|
||||
.tab-sharing-icon-overlay[sharing="camera"] {
|
||||
list-style-image: url("chrome://browser/skin/permissions.svg#camera");
|
||||
list-style-image: url("chrome://browser/skin/notification-icons.svg#camera");
|
||||
}
|
||||
|
||||
.tab-sharing-icon-overlay[sharing="microphone"] {
|
||||
list-style-image: url("chrome://browser/skin/permissions.svg#microphone");
|
||||
list-style-image: url("chrome://browser/skin/notification-icons.svg#microphone");
|
||||
}
|
||||
|
||||
.tab-sharing-icon-overlay[sharing="screen"] {
|
||||
list-style-image: url("chrome://browser/skin/permissions.svg#screen");
|
||||
list-style-image: url("chrome://browser/skin/notification-icons.svg#screen");
|
||||
}
|
||||
|
||||
.tab-sharing-icon-overlay[sharing] {
|
||||
|
|
|
@ -1023,49 +1023,114 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
|||
|
||||
/* ::::: fullscreen window controls ::::: */
|
||||
|
||||
#window-controls {
|
||||
margin-inline-start: 4px;
|
||||
}
|
||||
|
||||
#minimize-button,
|
||||
#restore-button,
|
||||
#close-button {
|
||||
list-style-image: url("chrome://global/skin/icons/windowControls.png");
|
||||
padding: 0;
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
margin: 0 !important;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
#minimize-button {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
#minimize-button:hover {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0);
|
||||
}
|
||||
#minimize-button:hover:active {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0);
|
||||
}
|
||||
#restore-button {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
#restore-button:hover {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
#restore-button:hover:active {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
#close-button {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
-moz-appearance: none;
|
||||
border-style: none;
|
||||
margin: 2px;
|
||||
}
|
||||
#close-button:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
#close-button:hover:active {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize);
|
||||
}
|
||||
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
#restore-button {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore);
|
||||
}
|
||||
|
||||
#minimize-button:hover,
|
||||
#restore-button:hover {
|
||||
background-color: hsla(0, 0%, 0%, .12);
|
||||
}
|
||||
|
||||
#minimize-button:hover:active,
|
||||
#restore-button:hover:active {
|
||||
background-color: hsla(0, 0%, 0%, .22);
|
||||
}
|
||||
|
||||
#close-button {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close);
|
||||
}
|
||||
|
||||
#close-button:hover {
|
||||
background-color: hsl(355, 86%, 49%);
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
|
||||
}
|
||||
|
||||
#close-button:hover:active {
|
||||
background-color: hsl(355, 82%, 69%);
|
||||
}
|
||||
|
||||
toolbar[brighttext] #minimize-button {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-white);
|
||||
}
|
||||
|
||||
toolbar[brighttext] #restore-button {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-white);
|
||||
}
|
||||
|
||||
toolbar[brighttext] #close-button {
|
||||
list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
#window-controls {
|
||||
margin-inline-start: 4px;
|
||||
}
|
||||
|
||||
#minimize-button,
|
||||
#restore-button,
|
||||
#close-button {
|
||||
list-style-image: url("chrome://global/skin/icons/windowControls.png");
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#minimize-button {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#minimize-button:hover {
|
||||
-moz-image-region: rect(16px, 16px, 32px, 0);
|
||||
}
|
||||
|
||||
#minimize-button:hover:active {
|
||||
-moz-image-region: rect(32px, 16px, 48px, 0);
|
||||
}
|
||||
|
||||
#restore-button {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#restore-button:hover {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
|
||||
#restore-button:hover:active {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
|
||||
#close-button {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
-moz-appearance: none;
|
||||
border-style: none;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#close-button:hover {
|
||||
-moz-image-region: rect(16px, 48px, 32px, 32px);
|
||||
}
|
||||
|
||||
#close-button:hover:active {
|
||||
-moz-image-region: rect(32px, 48px, 48px, 32px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
#window-controls {
|
||||
-moz-box-align: start;
|
||||
}
|
||||
|
@ -1077,12 +1142,15 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
|||
border-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#close-button {
|
||||
-moz-image-region: rect(0, 49px, 16px, 32px);
|
||||
}
|
||||
|
||||
#close-button:hover {
|
||||
-moz-image-region: rect(16px, 49px, 32px, 32px);
|
||||
}
|
||||
|
||||
#close-button:hover:active {
|
||||
-moz-image-region: rect(32px, 49px, 48px, 32px);
|
||||
}
|
||||
|
|
|
@ -181,6 +181,9 @@ https://tracking.example.com:443
|
|||
https://not-tracking.example.com:443
|
||||
https://tracking.example.org:443
|
||||
|
||||
# Bug 1281083
|
||||
http://bug1281083.example.com:80
|
||||
|
||||
# Bug 483437, 484111
|
||||
https://www.bank1.com:443 privileged,cert=escapeattack1
|
||||
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci} = require("chrome");
|
||||
const Services = require("Services");
|
||||
|
||||
loader.lazyGetter(this, "osString", () => Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS);
|
||||
const osString = Services.appinfo.OS;
|
||||
|
||||
// Panels
|
||||
loader.lazyGetter(this, "OptionsPanel", () => require("devtools/client/framework/toolbox-options").OptionsPanel);
|
||||
|
|
|
@ -32,10 +32,6 @@ loader.lazyGetter(this, "DOMUtils", function () {
|
|||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
});
|
||||
|
||||
loader.lazyGetter(this, "XULRuntime", function () {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
|
||||
});
|
||||
|
||||
loader.lazyGetter(this, "l10n", () => Services.strings
|
||||
.createBundle("chrome://devtools/locale/eyedropper.properties"));
|
||||
|
||||
|
@ -117,7 +113,7 @@ function Eyedropper(chromeWindow, opts = { copyOnSelect: true, context: "other"
|
|||
this._chromeWindow = chromeWindow;
|
||||
this._chromeDocument = chromeWindow.document;
|
||||
|
||||
this._OS = XULRuntime.OS;
|
||||
this._OS = Services.appinfo.OS;
|
||||
|
||||
this._dragging = true;
|
||||
this.loaded = false;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -474,3 +475,17 @@ function pushPref(preferenceName, value) {
|
|||
SpecialPowers.pushPrefEnv(options, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the provided dotted path ("prop1.subprop2.myProp") in the provided object.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* Object to expand.
|
||||
* @param {String} path
|
||||
* Dotted path to use to expand the object.
|
||||
* @return {?} anything that is found at the provided path in the object.
|
||||
*/
|
||||
function lookupPath(obj, path) {
|
||||
let segments = path.split(".");
|
||||
return segments.reduce((prev, current) => prev[current], obj);
|
||||
}
|
||||
|
|
|
@ -70,9 +70,6 @@ loader.lazyRequireGetter(this, "KeyShortcuts",
|
|||
loader.lazyRequireGetter(this, "ZoomKeys",
|
||||
"devtools/client/shared/zoom-keys");
|
||||
|
||||
loader.lazyGetter(this, "osString", () => {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
});
|
||||
loader.lazyGetter(this, "registerHarOverlay", () => {
|
||||
return require("devtools/client/netmonitor/har/toolbox-overlay").register;
|
||||
});
|
||||
|
@ -495,7 +492,8 @@ Toolbox.prototype = {
|
|||
this._telemetry.toolOpened("toolbox");
|
||||
|
||||
this._telemetry.logOncePerBrowserVersion(OS_HISTOGRAM, system.getOSCPU());
|
||||
this._telemetry.logOncePerBrowserVersion(OS_IS_64_BITS, system.is64Bit ? 1 : 0);
|
||||
this._telemetry.logOncePerBrowserVersion(OS_IS_64_BITS,
|
||||
Services.appinfo.is64Bit ? 1 : 0);
|
||||
this._telemetry.logOncePerBrowserVersion(SCREENSIZE_HISTOGRAM, system.getScreenDimensions());
|
||||
},
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ loader.lazyRequireGetter(this, "StyleInspectorMenu",
|
|||
"devtools/client/inspector/shared/style-inspector-menu");
|
||||
loader.lazyRequireGetter(this, "KeyShortcuts",
|
||||
"devtools/client/shared/key-shortcuts", true);
|
||||
loader.lazyRequireGetter(this, "LayoutView",
|
||||
"devtools/client/inspector/layout/layout", true);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
|
@ -169,7 +171,6 @@ function CssComputedView(inspector, document, pageStyle) {
|
|||
this._onFilterTextboxContextMenu.bind(this);
|
||||
|
||||
let doc = this.styleDocument;
|
||||
this.root = doc.getElementById("root");
|
||||
this.element = doc.getElementById("propertyContainer");
|
||||
this.searchField = doc.getElementById("computedview-searchbox");
|
||||
this.searchClearButton = doc.getElementById("computedview-searchinput-clear");
|
||||
|
@ -777,7 +778,6 @@ CssComputedView.prototype = {
|
|||
this._onIncludeBrowserStyles);
|
||||
|
||||
// Nodes used in templating
|
||||
this.root = null;
|
||||
this.element = null;
|
||||
this.panel = null;
|
||||
this.searchField = null;
|
||||
|
@ -1407,8 +1407,9 @@ function ComputedViewTool(inspector, window) {
|
|||
this.inspector = inspector;
|
||||
this.document = window.document;
|
||||
|
||||
this.view = new CssComputedView(this.inspector, this.document,
|
||||
this.computedView = new CssComputedView(this.inspector, this.document,
|
||||
this.inspector.pageStyle);
|
||||
this.layoutView = new LayoutView(this.inspector, this.document);
|
||||
|
||||
this.onSelected = this.onSelected.bind(this);
|
||||
this.refresh = this.refresh.bind(this);
|
||||
|
@ -1424,14 +1425,14 @@ function ComputedViewTool(inspector, window) {
|
|||
this.inspector.walker.on("mutations", this.onMutations);
|
||||
this.inspector.walker.on("resize", this.onResized);
|
||||
|
||||
this.view.selectElement(null);
|
||||
this.computedView.selectElement(null);
|
||||
|
||||
this.onSelected();
|
||||
}
|
||||
|
||||
ComputedViewTool.prototype = {
|
||||
isSidebarActive: function () {
|
||||
if (!this.view) {
|
||||
if (!this.computedView) {
|
||||
return false;
|
||||
}
|
||||
return this.inspector.sidebar.getCurrentTabID() == "computedview";
|
||||
|
@ -1442,7 +1443,7 @@ ComputedViewTool.prototype = {
|
|||
// But only if the current selection isn't null. If it's been set to null,
|
||||
// let the update go through as this is needed to empty the view on
|
||||
// navigation.
|
||||
if (!this.view) {
|
||||
if (!this.computedView) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1452,17 +1453,17 @@ ComputedViewTool.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
this.view.setPageStyle(this.inspector.pageStyle);
|
||||
this.computedView.setPageStyle(this.inspector.pageStyle);
|
||||
|
||||
if (!this.inspector.selection.isConnected() ||
|
||||
!this.inspector.selection.isElementNode()) {
|
||||
this.view.selectElement(null);
|
||||
this.computedView.selectElement(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!event || event == "new-node-front") {
|
||||
let done = this.inspector.updating("computed-view");
|
||||
this.view.selectElement(this.inspector.selection.nodeFront).then(() => {
|
||||
this.computedView.selectElement(this.inspector.selection.nodeFront).then(() => {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
@ -1470,12 +1471,12 @@ ComputedViewTool.prototype = {
|
|||
|
||||
refresh: function () {
|
||||
if (this.isSidebarActive()) {
|
||||
this.view.refreshPanel();
|
||||
this.computedView.refreshPanel();
|
||||
}
|
||||
},
|
||||
|
||||
onPanelSelected: function () {
|
||||
if (this.inspector.selection.nodeFront === this.view._viewedElement) {
|
||||
if (this.inspector.selection.nodeFront === this.computedView._viewedElement) {
|
||||
this.refresh();
|
||||
} else {
|
||||
this.onSelected();
|
||||
|
@ -1516,9 +1517,10 @@ ComputedViewTool.prototype = {
|
|||
this.inspector.pageStyle.off("stylesheet-updated", this.refresh);
|
||||
}
|
||||
|
||||
this.view.destroy();
|
||||
this.computedView.destroy();
|
||||
this.layoutView.destroy();
|
||||
|
||||
this.view = this.document = this.inspector = null;
|
||||
this.computedView = this.layoutView = this.document = this.inspector = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ function* checkColorCycling(container, view) {
|
|||
function* checkSwatchShiftClick(container, win, expectedValue, comment) {
|
||||
let swatch = container.querySelector(".computedview-colorswatch");
|
||||
let valueNode = container.querySelector(".computedview-color");
|
||||
swatch.scrollIntoView();
|
||||
|
||||
let onUnitChange = swatch.once("unit-change");
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {
|
||||
|
|
|
@ -25,6 +25,7 @@ add_task(function* () {
|
|||
let matchedExpander = propView.element;
|
||||
|
||||
info("Focusing the property");
|
||||
matchedExpander.scrollIntoView();
|
||||
let onMatchedExpanderFocus = once(matchedExpander, "focus", true);
|
||||
EventUtils.synthesizeMouseAtCenter(matchedExpander, {}, view.styleWindow);
|
||||
yield onMatchedExpanderFocus;
|
||||
|
|
|
@ -30,7 +30,7 @@ function* testExpandOnTwistyClick({styleDocument, styleWindow}, inspector) {
|
|||
info("Testing that a property expands on twisty click");
|
||||
|
||||
info("Getting twisty element");
|
||||
let twisty = styleDocument.querySelector(".expandable");
|
||||
let twisty = styleDocument.querySelector("#propertyContainer .expandable");
|
||||
ok(twisty, "Twisty found");
|
||||
|
||||
let onExpand = inspector.once("computed-view-property-expanded");
|
||||
|
@ -49,7 +49,7 @@ function* testCollapseOnTwistyClick({styleDocument, styleWindow}, inspector) {
|
|||
info("Testing that a property collapses on twisty click");
|
||||
|
||||
info("Getting twisty element");
|
||||
let twisty = styleDocument.querySelector(".expandable");
|
||||
let twisty = styleDocument.querySelector("#propertyContainer .expandable");
|
||||
ok(twisty, "Twisty found");
|
||||
|
||||
let onCollapse = inspector.once("computed-view-property-collapsed");
|
||||
|
@ -71,6 +71,8 @@ function* testExpandOnDblClick({styleDocument, styleWindow}, inspector) {
|
|||
let container = styleDocument.querySelector(".property-view");
|
||||
ok(container, "Container found");
|
||||
|
||||
container.scrollIntoView();
|
||||
|
||||
let onExpand = inspector.once("computed-view-property-expanded");
|
||||
info("Dbl-clicking on the container");
|
||||
EventUtils.synthesizeMouseAtCenter(container, {clickCount: 2}, styleWindow);
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
|
||||
// Tests that properties can be selected and copied from the computed view.
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "osString", function () {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
});
|
||||
const osString = Services.appinfo.OS;
|
||||
|
||||
const TEST_URI = `
|
||||
<style type="text/css">
|
||||
|
|
|
@ -132,7 +132,7 @@ function getComputedViewPropertyValue(view, name, propertyName) {
|
|||
*/
|
||||
function expandComputedViewPropertyByIndex(view, index) {
|
||||
info("Expanding property " + index + " in the computed view");
|
||||
let expandos = view.styleDocument.querySelectorAll(".expandable");
|
||||
let expandos = view.styleDocument.querySelectorAll("#propertyContainer .expandable");
|
||||
if (!expandos.length || !expandos[index]) {
|
||||
return promise.reject();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ loader.lazyRequireGetter(this, "ComputedViewTool", "devtools/client/inspector/co
|
|||
loader.lazyRequireGetter(this, "FontInspector", "devtools/client/inspector/fonts/fonts", true);
|
||||
loader.lazyRequireGetter(this, "HTMLBreadcrumbs", "devtools/client/inspector/breadcrumbs", true);
|
||||
loader.lazyRequireGetter(this, "InspectorSearch", "devtools/client/inspector/inspector-search", true);
|
||||
loader.lazyRequireGetter(this, "LayoutView", "devtools/client/inspector/layout/layout", true);
|
||||
loader.lazyRequireGetter(this, "MarkupView", "devtools/client/inspector/markup/markup", true);
|
||||
loader.lazyRequireGetter(this, "RuleViewTool", "devtools/client/inspector/rules/rules", true);
|
||||
loader.lazyRequireGetter(this, "ToolSidebar", "devtools/client/inspector/toolsidebar", true);
|
||||
|
@ -423,11 +422,6 @@ InspectorPanel.prototype = {
|
|||
strings.GetStringFromName("inspector.sidebar.computedViewTitle"),
|
||||
defaultTab == "computedview");
|
||||
|
||||
this.sidebar.addExistingTab(
|
||||
"layoutview",
|
||||
strings.GetStringFromName("inspector.sidebar.layoutViewTitle"),
|
||||
defaultTab == "layoutview");
|
||||
|
||||
this._setDefaultSidebar = (event, toolId) => {
|
||||
Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId);
|
||||
};
|
||||
|
@ -436,7 +430,6 @@ InspectorPanel.prototype = {
|
|||
|
||||
this.ruleview = new RuleViewTool(this, this.panelWin);
|
||||
this.computedview = new ComputedViewTool(this, this.panelWin);
|
||||
this.layoutview = new LayoutView(this, this.panelWin);
|
||||
|
||||
if (this.target.form.animationsActor) {
|
||||
this.sidebar.addFrameTab(
|
||||
|
@ -752,10 +745,6 @@ InspectorPanel.prototype = {
|
|||
this.fontInspector.destroy();
|
||||
}
|
||||
|
||||
if (this.layoutview) {
|
||||
this.layoutview.destroy();
|
||||
}
|
||||
|
||||
let cssPropertiesDestroyer = this._cssPropertiesLoaded.then(({front}) => {
|
||||
if (front) {
|
||||
front.destroy();
|
||||
|
|
|
@ -107,59 +107,64 @@
|
|||
label="&browserStylesLabel;"/>&browserStylesLabel;</html:label>
|
||||
</html:div>
|
||||
|
||||
<html:div id="propertyContainer">
|
||||
</html:div>
|
||||
<html:div id="computedview-container">
|
||||
<html:div id="layout-wrapper" class="theme-separator" tabindex="0">
|
||||
<html:div id="layout-header">
|
||||
<html:div id="layout-expander" class="expander theme-twisty expandable" open=""></html:div>
|
||||
<html:span>&layoutViewTitle;</html:span>
|
||||
<html:button class="devtools-button" id="layout-geometry-editor" title="&geometry.button.tooltip;"></html:button>
|
||||
</html:div>
|
||||
|
||||
<html:div id="computedview-no-results" hidden="">
|
||||
&noPropertiesFound;
|
||||
</html:div>
|
||||
</html:div>
|
||||
|
||||
<html:div id="sidebar-panel-layoutview" class="devtools-monospace theme-sidebar inspector-tabpanel">
|
||||
<html:div id="layout-wrapper">
|
||||
<html:div id="layout-container">
|
||||
<html:p id="layout-header">
|
||||
<html:span id="layout-element-size"></html:span>
|
||||
<html:section id="layout-position-group">
|
||||
<html:button class="devtools-button" id="layout-geometry-editor" title="&geometry.button.tooltip;"></html:button>
|
||||
<html:span id="layout-element-position"></html:span>
|
||||
</html:section>
|
||||
</html:p>
|
||||
|
||||
<html:div id="layout-main">
|
||||
<html:span class="layout-legend" data-box="margin" title="&margin.tooltip;">&margin.tooltip;</html:span>
|
||||
<html:div id="layout-margins" data-box="margin" title="&margin.tooltip;">
|
||||
<html:span class="layout-legend" data-box="border" title="&border.tooltip;">&border.tooltip;</html:span>
|
||||
<html:div id="layout-borders" data-box="border" title="&border.tooltip;">
|
||||
<html:span class="layout-legend" data-box="padding" title="&padding.tooltip;">&padding.tooltip;</html:span>
|
||||
<html:div id="layout-padding" data-box="padding" title="&padding.tooltip;">
|
||||
<html:div id="layout-content" data-box="content" title="&content.tooltip;">
|
||||
<html:div id="layout-container">
|
||||
<html:div id="layout-main">
|
||||
<html:span class="layout-legend" data-box="margin" title="&margin.tooltip;">&margin.tooltip;</html:span>
|
||||
<html:div id="layout-margins" data-box="margin" title="&margin.tooltip;">
|
||||
<html:span class="layout-legend" data-box="border" title="&border.tooltip;">&border.tooltip;</html:span>
|
||||
<html:div id="layout-borders" data-box="border" title="&border.tooltip;">
|
||||
<html:span class="layout-legend" data-box="padding" title="&padding.tooltip;">&padding.tooltip;</html:span>
|
||||
<html:div id="layout-padding" data-box="padding" title="&padding.tooltip;">
|
||||
<html:div id="layout-content" data-box="content" title="&content.tooltip;">
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
|
||||
<html:p class="layout-margin layout-top"><html:span data-box="margin" class="layout-editable" title="margin-top"></html:span></html:p>
|
||||
<html:p class="layout-margin layout-right"><html:span data-box="margin" class="layout-editable" title="margin-right"></html:span></html:p>
|
||||
<html:p class="layout-margin layout-bottom"><html:span data-box="margin" class="layout-editable" title="margin-bottom"></html:span></html:p>
|
||||
<html:p class="layout-margin layout-left"><html:span data-box="margin" class="layout-editable" title="margin-left"></html:span></html:p>
|
||||
|
||||
<html:p class="layout-border layout-top"><html:span data-box="border" class="layout-editable" title="border-top"></html:span></html:p>
|
||||
<html:p class="layout-border layout-right"><html:span data-box="border" class="layout-editable" title="border-right"></html:span></html:p>
|
||||
<html:p class="layout-border layout-bottom"><html:span data-box="border" class="layout-editable" title="border-bottom"></html:span></html:p>
|
||||
<html:p class="layout-border layout-left"><html:span data-box="border" class="layout-editable" title="border-left"></html:span></html:p>
|
||||
|
||||
<html:p class="layout-padding layout-top"><html:span data-box="padding" class="layout-editable" title="padding-top"></html:span></html:p>
|
||||
<html:p class="layout-padding layout-right"><html:span data-box="padding" class="layout-editable" title="padding-right"></html:span></html:p>
|
||||
<html:p class="layout-padding layout-bottom"><html:span data-box="padding" class="layout-editable" title="padding-bottom"></html:span></html:p>
|
||||
<html:p class="layout-padding layout-left"><html:span data-box="padding" class="layout-editable" title="padding-left"></html:span></html:p>
|
||||
|
||||
<html:p class="layout-size"><html:span data-box="content" title="&content.tooltip;"></html:span></html:p>
|
||||
</html:div>
|
||||
|
||||
<html:p class="layout-border layout-top"><html:span data-box="border" class="layout-editable" title="border-top"></html:span></html:p>
|
||||
<html:p class="layout-border layout-right"><html:span data-box="border" class="layout-editable" title="border-right"></html:span></html:p>
|
||||
<html:p class="layout-border layout-bottom"><html:span data-box="border" class="layout-editable" title="border-bottom"></html:span></html:p>
|
||||
<html:p class="layout-border layout-left"><html:span data-box="border" class="layout-editable" title="border-left"></html:span></html:p>
|
||||
<html:div id="layout-info">
|
||||
<html:span id="layout-element-size"></html:span>
|
||||
<html:section id="layout-position-group">
|
||||
<html:span id="layout-element-position"></html:span>
|
||||
</html:section>
|
||||
</html:div>
|
||||
|
||||
<html:p class="layout-margin layout-top"><html:span data-box="margin" class="layout-editable" title="margin-top"></html:span></html:p>
|
||||
<html:p class="layout-margin layout-right"><html:span data-box="margin" class="layout-editable" title="margin-right"></html:span></html:p>
|
||||
<html:p class="layout-margin layout-bottom"><html:span data-box="margin" class="layout-editable" title="margin-bottom"></html:span></html:p>
|
||||
<html:p class="layout-margin layout-left"><html:span data-box="margin" class="layout-editable" title="margin-left"></html:span></html:p>
|
||||
|
||||
<html:p class="layout-padding layout-top"><html:span data-box="padding" class="layout-editable" title="padding-top"></html:span></html:p>
|
||||
<html:p class="layout-padding layout-right"><html:span data-box="padding" class="layout-editable" title="padding-right"></html:span></html:p>
|
||||
<html:p class="layout-padding layout-bottom"><html:span data-box="padding" class="layout-editable" title="padding-bottom"></html:span></html:p>
|
||||
<html:p class="layout-padding layout-left"><html:span data-box="padding" class="layout-editable" title="padding-left"></html:span></html:p>
|
||||
|
||||
<html:p class="layout-size"><html:span data-box="content" title="&content.tooltip;"></html:span></html:p>
|
||||
<html:div style="display: none">
|
||||
<html:p id="layout-dummy"></html:p>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
|
||||
<html:div style="display: none">
|
||||
<html:p id="layout-dummy"></html:p>
|
||||
</html:div>
|
||||
<html:div id="propertyContainer" class="theme-separator" tabindex="0">
|
||||
</html:div>
|
||||
|
||||
<html:div id="computedview-no-results" hidden="">
|
||||
&noPropertiesFound;
|
||||
</html:div>
|
||||
</html:div>
|
||||
</html:div>
|
||||
|
|
|
@ -68,7 +68,7 @@ EditingSession.prototype = {
|
|||
// Create a hidden element for getPropertyFromRule to use
|
||||
let div = this._doc.createElement("div");
|
||||
div.setAttribute("style", "display: none");
|
||||
this._doc.getElementById("sidebar-panel-layoutview").appendChild(div);
|
||||
this._doc.getElementById("sidebar-panel-computedview").appendChild(div);
|
||||
this._element = this._doc.createElement("p");
|
||||
div.appendChild(this._element);
|
||||
|
||||
|
@ -183,13 +183,17 @@ EditingSession.prototype = {
|
|||
|
||||
/**
|
||||
* The layout-view panel
|
||||
* @param {InspectorPanel} inspector An instance of the inspector-panel
|
||||
* currently loaded in the toolbox
|
||||
* @param {Window} win The window containing the panel
|
||||
* @param {InspectorPanel} inspector
|
||||
* An instance of the inspector-panel currently loaded in the toolbox
|
||||
* @param {Document} document
|
||||
* The document that will contain the layout view.
|
||||
*/
|
||||
function LayoutView(inspector, win) {
|
||||
function LayoutView(inspector, document) {
|
||||
this.inspector = inspector;
|
||||
this.doc = win.document;
|
||||
this.doc = document;
|
||||
this.wrapper = this.doc.getElementById("layout-wrapper");
|
||||
this.container = this.doc.getElementById("layout-container");
|
||||
this.expander = this.doc.getElementById("layout-expander");
|
||||
this.sizeLabel = this.doc.querySelector(".layout-size > span");
|
||||
this.sizeHeadingLabel = this.doc.getElementById("layout-element-size");
|
||||
this._geometryEditorHighlighter = null;
|
||||
|
@ -205,11 +209,16 @@ LayoutView.prototype = {
|
|||
this.inspector.selection.on("new-node-front", this.onNewSelection);
|
||||
|
||||
this.onNewNode = this.onNewNode.bind(this);
|
||||
this.inspector.sidebar.on("layoutview-selected", this.onNewNode);
|
||||
this.inspector.sidebar.on("computedview-selected", this.onNewNode);
|
||||
|
||||
this.onSidebarSelect = this.onSidebarSelect.bind(this);
|
||||
this.inspector.sidebar.on("select", this.onSidebarSelect);
|
||||
|
||||
this.onToggleExpander = this.onToggleExpander.bind(this);
|
||||
this.expander.addEventListener("click", this.onToggleExpander);
|
||||
let header = this.doc.getElementById("layout-header");
|
||||
header.addEventListener("dblclick", this.onToggleExpander);
|
||||
|
||||
this.onPickerStarted = this.onPickerStarted.bind(this);
|
||||
this.onMarkupViewLeave = this.onMarkupViewLeave.bind(this);
|
||||
this.onMarkupViewNodeHover = this.onMarkupViewNodeHover.bind(this);
|
||||
|
@ -313,7 +322,6 @@ LayoutView.prototype = {
|
|||
container.setAttribute("dir", dir ? "rtl" : "ltr");
|
||||
|
||||
let nodeGeometry = this.doc.getElementById("layout-geometry-editor");
|
||||
|
||||
this.onGeometryButtonClick = this.onGeometryButtonClick.bind(this);
|
||||
nodeGeometry.addEventListener("click", this.onGeometryButtonClick);
|
||||
},
|
||||
|
@ -415,7 +423,7 @@ LayoutView.prototype = {
|
|||
*/
|
||||
isViewVisible: function () {
|
||||
return this.inspector &&
|
||||
this.inspector.sidebar.getCurrentTabID() == "layoutview";
|
||||
this.inspector.sidebar.getCurrentTabID() == "computedview";
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -440,6 +448,10 @@ LayoutView.prototype = {
|
|||
element.removeEventListener("mouseout", this.onHighlightMouseOut, true);
|
||||
}
|
||||
|
||||
this.expander.removeEventListener("click", this.onToggleExpander);
|
||||
let header = this.doc.getElementById("layout-header");
|
||||
header.removeEventListener("dblclick", this.onToggleExpander);
|
||||
|
||||
let nodeGeometry = this.doc.getElementById("layout-geometry-editor");
|
||||
nodeGeometry.removeEventListener("click", this.onGeometryButtonClick);
|
||||
|
||||
|
@ -453,15 +465,18 @@ LayoutView.prototype = {
|
|||
this.inspector.markup.off("node-hover", this.onMarkupViewNodeHover);
|
||||
}
|
||||
|
||||
this.inspector.sidebar.off("layoutview-selected", this.onNewNode);
|
||||
this.inspector.sidebar.off("computedview-selected", this.onNewNode);
|
||||
this.inspector.selection.off("new-node-front", this.onNewSelection);
|
||||
this.inspector.sidebar.off("select", this.onSidebarSelect);
|
||||
this.inspector._target.off("will-navigate", this.onWillNavigate);
|
||||
|
||||
this.sizeHeadingLabel = null;
|
||||
this.sizeLabel = null;
|
||||
this.inspector = null;
|
||||
this.doc = null;
|
||||
this.wrapper = null;
|
||||
this.container = null;
|
||||
this.expander = null;
|
||||
this.sizeLabel = null;
|
||||
this.sizeHeadingLabel = null;
|
||||
|
||||
if (this.reflowFront) {
|
||||
this.untrackReflows();
|
||||
|
@ -471,14 +486,14 @@ LayoutView.prototype = {
|
|||
},
|
||||
|
||||
onSidebarSelect: function (e, sidebar) {
|
||||
this.setActive(sidebar === "layoutview");
|
||||
this.setActive(sidebar === "computedview");
|
||||
},
|
||||
|
||||
/**
|
||||
* Selection 'new-node-front' event handler.
|
||||
*/
|
||||
onNewSelection: function () {
|
||||
let done = this.inspector.updating("layoutview");
|
||||
let done = this.inspector.updating("computed-view");
|
||||
this.onNewNode()
|
||||
.then(() => this.hideGeometryEditor())
|
||||
.then(done, (err) => {
|
||||
|
@ -526,6 +541,18 @@ LayoutView.prototype = {
|
|||
this.hideGeometryEditor();
|
||||
},
|
||||
|
||||
onToggleExpander: function () {
|
||||
let isOpen = this.expander.hasAttribute("open");
|
||||
|
||||
if (isOpen) {
|
||||
this.container.hidden = true;
|
||||
this.expander.removeAttribute("open");
|
||||
} else {
|
||||
this.container.hidden = false;
|
||||
this.expander.setAttribute("open", "");
|
||||
}
|
||||
},
|
||||
|
||||
onMarkupViewLeave: function () {
|
||||
this.showGeometryEditor(true);
|
||||
},
|
||||
|
@ -550,9 +577,6 @@ LayoutView.prototype = {
|
|||
}
|
||||
this.isActive = isActive;
|
||||
|
||||
let panel = this.doc.getElementById("sidebar-panel-layoutview");
|
||||
panel.classList.toggle("inactive", !isActive);
|
||||
|
||||
if (isActive) {
|
||||
this.trackReflows();
|
||||
} else {
|
||||
|
@ -562,12 +586,14 @@ LayoutView.prototype = {
|
|||
|
||||
/**
|
||||
* Compute the dimensions of the node and update the values in
|
||||
* the layoutview/view.xhtml document.
|
||||
* the inspector.xul document.
|
||||
* @return a promise that will be resolved when complete.
|
||||
*/
|
||||
update: function () {
|
||||
let lastRequest = Task.spawn((function* () {
|
||||
if (!this.isViewVisibleAndNodeValid()) {
|
||||
this.wrapper.hidden = true;
|
||||
this.inspector.emit("layoutview-updated");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -593,12 +619,6 @@ LayoutView.prototype = {
|
|||
this.sizeHeadingLabel.textContent = newLabel;
|
||||
}
|
||||
|
||||
// If the view isn't active, no need to do anything more.
|
||||
if (!this.isActive) {
|
||||
this.inspector.emit("layoutview-updated");
|
||||
return null;
|
||||
}
|
||||
|
||||
for (let i in this.map) {
|
||||
let property = this.map[i].property;
|
||||
if (!(property in layout)) {
|
||||
|
@ -656,8 +676,10 @@ LayoutView.prototype = {
|
|||
|
||||
this.elementRules = styleEntries.map(e => e.rule);
|
||||
|
||||
this.wrapper.hidden = false;
|
||||
|
||||
this.inspector.emit("layoutview-updated");
|
||||
return undefined;
|
||||
return null;
|
||||
}).bind(this)).catch(console.error);
|
||||
|
||||
this._lastRequest = lastRequest;
|
||||
|
|
|
@ -55,7 +55,7 @@ function selectAndHighlightNode(nodeOrSelector, inspector) {
|
|||
* view is visible and ready
|
||||
*/
|
||||
function openLayoutView() {
|
||||
return openInspectorSidebarTab("layoutview").then(data => {
|
||||
return openInspectorSidebarTab("computedview").then(data => {
|
||||
// The actual highligher show/hide methods are mocked in layoutview tests.
|
||||
// The highlighter is tested in devtools/inspector/test.
|
||||
function mockHighlighter({highlighter}) {
|
||||
|
@ -71,7 +71,7 @@ function openLayoutView() {
|
|||
return {
|
||||
toolbox: data.toolbox,
|
||||
inspector: data.inspector,
|
||||
view: data.inspector.layoutview,
|
||||
view: data.inspector.computedview.layoutView,
|
||||
testActor: data.testActor
|
||||
};
|
||||
});
|
||||
|
|
|
@ -53,6 +53,7 @@ const {PrefObserver} = require("devtools/client/styleeditor/utils");
|
|||
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
|
||||
const {template} = require("devtools/shared/gcli/templater");
|
||||
const nodeConstants = require("devtools/shared/dom-node-constants");
|
||||
const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
loader.lazyRequireGetter(this, "CSS", "CSS");
|
||||
|
@ -632,14 +633,14 @@ MarkupView.prototype = {
|
|||
_selectionWalker: function (start) {
|
||||
let walker = this.doc.createTreeWalker(
|
||||
start || this._elt,
|
||||
Ci.nsIDOMNodeFilter.SHOW_ELEMENT,
|
||||
nodeFilterConstants.SHOW_ELEMENT,
|
||||
function (element) {
|
||||
if (element.container &&
|
||||
element.container.elt === element &&
|
||||
element.container.visible) {
|
||||
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
|
||||
return nodeFilterConstants.FILTER_ACCEPT;
|
||||
}
|
||||
return Ci.nsIDOMNodeFilter.FILTER_SKIP;
|
||||
return nodeFilterConstants.FILTER_SKIP;
|
||||
}
|
||||
);
|
||||
walker.currentNode = this._selectedContainer.elt;
|
||||
|
@ -3193,6 +3194,7 @@ ElementEditor.prototype = {
|
|||
// Create the template editor, which will save some variables here.
|
||||
let data = {
|
||||
attrName: attribute.name,
|
||||
tabindex: this.container.canFocus ? "0" : "-1",
|
||||
};
|
||||
this.template("attribute", data);
|
||||
let {attr, inner, name, val} = data;
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
data-value="${attrValue}"
|
||||
class="attreditor"
|
||||
style="display:none"> <!--
|
||||
--><span class="editable" save="${inner}" tabindex="-1"><!--
|
||||
--><span class="editable" save="${inner}" tabindex="${tabindex}"><!--
|
||||
--><span save="${name}" class="attr-name theme-fg-color2"></span><!--
|
||||
-->="<!--
|
||||
--><span save="${val}" class="attr-value theme-fg-color6"></span><!--
|
||||
|
|
|
@ -34,6 +34,7 @@ support-files =
|
|||
head.js
|
||||
helper_attributes_test_runner.js
|
||||
helper_events_test_runner.js
|
||||
helper_markup_accessibility_navigation.js
|
||||
helper_outerhtml_test_runner.js
|
||||
helper_style_attr_test_runner.js
|
||||
lib_jquery_1.0.js
|
||||
|
@ -55,6 +56,8 @@ support-files =
|
|||
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
|
||||
[browser_markup_accessibility_navigation.js]
|
||||
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
|
||||
[browser_markup_accessibility_navigation_after_edit.js]
|
||||
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
|
||||
[browser_markup_accessibility_semantics.js]
|
||||
[browser_markup_anonymous_01.js]
|
||||
[browser_markup_anonymous_02.js]
|
||||
|
@ -90,6 +93,7 @@ subsuite = clipboard
|
|||
[browser_markup_events_jquery_2.1.1.js]
|
||||
[browser_markup_events-overflow.js]
|
||||
skip-if = true # Bug 1177550
|
||||
[browser_markup_events-windowed-host.js]
|
||||
[browser_markup_links_01.js]
|
||||
[browser_markup_links_02.js]
|
||||
[browser_markup_links_03.js]
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
/* 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/. */
|
||||
/* import-globals-from helper_markup_accessibility_navigation.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* global getContainerForSelector, openInspectorForURL */
|
||||
|
||||
// Test keyboard navigation accessibility of inspector's markup view.
|
||||
|
||||
loadHelperScript("helper_markup_accessibility_navigation.js");
|
||||
|
||||
/**
|
||||
* Test data has the format of:
|
||||
* {
|
||||
|
@ -237,15 +238,12 @@ const TESTS = [
|
|||
},
|
||||
];
|
||||
|
||||
let elms = {};
|
||||
let containerID = 0;
|
||||
let elms = {};
|
||||
|
||||
add_task(function* () {
|
||||
let { inspector } = yield openInspectorForURL(`data:text/html;charset=utf-8,
|
||||
<h1 id="some-id" class="some-class">foo<span>Child span<span></h1>`);
|
||||
let markup = inspector.markup;
|
||||
let doc = markup.doc;
|
||||
let win = doc.defaultView;
|
||||
|
||||
// Record containers that are created after inspector is initialized to be
|
||||
// useful in testing.
|
||||
|
@ -254,48 +252,26 @@ add_task(function* () {
|
|||
inspector.off("container-created", memorizeContainer);
|
||||
});
|
||||
|
||||
elms.docBody = doc.body;
|
||||
elms.root = markup.getContainer(markup._rootNode);
|
||||
elms.docBody = inspector.markup.doc.body;
|
||||
elms.root = inspector.markup.getContainer(inspector.markup._rootNode);
|
||||
elms.header = yield getContainerForSelector("h1", inspector);
|
||||
elms.body = yield getContainerForSelector("body", inspector);
|
||||
|
||||
// Initial focus is on root element and active descendant should be set on
|
||||
// body tag line.
|
||||
testNavigationState(doc, elms.docBody, elms.body.tagLine);
|
||||
testNavigationState(inspector, elms, elms.docBody, elms.body.tagLine);
|
||||
|
||||
// Focus on the tree element.
|
||||
elms.root.elt.focus();
|
||||
|
||||
for (let {desc, waitFor, focused, activedescendant, key, options} of TESTS) {
|
||||
info(desc);
|
||||
let updated;
|
||||
if (waitFor) {
|
||||
updated = waitFor === "inspector-updated" ?
|
||||
inspector.once(waitFor) : markup.once(waitFor);
|
||||
} else {
|
||||
updated = Promise.resolve();
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey(key, options, win);
|
||||
yield updated;
|
||||
testNavigationState(doc, getElm(focused), getElm(activedescendant));
|
||||
for (let testData of TESTS) {
|
||||
yield runAccessibilityNavigationTest(inspector, elms, testData);
|
||||
}
|
||||
|
||||
elms = null;
|
||||
});
|
||||
|
||||
// Record all containers that are created dynamically into elms object.
|
||||
function memorizeContainer(event, container) {
|
||||
elms[`container-${containerID++}`] = container;
|
||||
}
|
||||
|
||||
// Parse and lookup an element from elms object based on dotted path.
|
||||
function getElm(path) {
|
||||
let segments = path.split(".");
|
||||
return segments.reduce((prev, current) => prev[current], elms);
|
||||
}
|
||||
|
||||
function testNavigationState(doc, focused, activedescendant) {
|
||||
let id = activedescendant.getAttribute("id");
|
||||
is(doc.activeElement, focused, `Keyboard focus should be set to ${focused}`);
|
||||
is(elms.root.elt.getAttribute("aria-activedescendant"), id,
|
||||
`Active descendant should be set to ${id}`);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/* 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/. */
|
||||
/* import-globals-from helper_markup_accessibility_navigation.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test keyboard navigation accessibility is preserved after editing attributes.
|
||||
|
||||
loadHelperScript("helper_markup_accessibility_navigation.js");
|
||||
|
||||
const TEST_URI = '<div id="some-id" class="some-class"></div>';
|
||||
|
||||
/**
|
||||
* Test data has the format of:
|
||||
* {
|
||||
* desc {String} description for better logging
|
||||
* key {String} key event's key
|
||||
* options {?Object} optional event data such as shiftKey, etc
|
||||
* focused {String} path to expected focused element relative to
|
||||
* its container
|
||||
* activedescendant {String} path to expected aria-activedescendant element
|
||||
* relative to its container
|
||||
* waitFor {String} optional event to wait for if keyboard actions
|
||||
* result in asynchronous updates
|
||||
* }
|
||||
*/
|
||||
const TESTS = [
|
||||
{
|
||||
desc: "Select header container",
|
||||
focused: "root.elt",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_DOWN",
|
||||
options: { },
|
||||
waitFor: "inspector-updated"
|
||||
},
|
||||
{
|
||||
desc: "Focus on header tag",
|
||||
focused: "div.focusableElms.0",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_RETURN",
|
||||
options: { }
|
||||
},
|
||||
{
|
||||
desc: "Activate header tag editor",
|
||||
focused: "div.editor.tag.inplaceEditor.input",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_RETURN",
|
||||
options: { }
|
||||
},
|
||||
{
|
||||
desc: "Activate header id attribute editor",
|
||||
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_TAB",
|
||||
options: { }
|
||||
},
|
||||
{
|
||||
desc: "Deselect text in header id attribute editor",
|
||||
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_TAB",
|
||||
options: { }
|
||||
},
|
||||
{
|
||||
desc: "Move the cursor to the left",
|
||||
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_LEFT",
|
||||
options: { }
|
||||
},
|
||||
{
|
||||
desc: "Modify the attribute",
|
||||
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "A",
|
||||
options: { }
|
||||
},
|
||||
{
|
||||
desc: "Commit the attribute change",
|
||||
focused: "div.focusableElms.1",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_RETURN",
|
||||
options: { },
|
||||
waitFor: "inspector-updated"
|
||||
},
|
||||
{
|
||||
desc: "Tab and focus on header class attribute",
|
||||
focused: "div.focusableElms.2",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_TAB",
|
||||
options: { }
|
||||
},
|
||||
{
|
||||
desc: "Tab and focus on header new attribute node",
|
||||
focused: "div.focusableElms.3",
|
||||
activedescendant: "div.tagLine",
|
||||
key: "VK_TAB",
|
||||
options: { }
|
||||
},
|
||||
];
|
||||
|
||||
let elms = {};
|
||||
|
||||
add_task(function* () {
|
||||
let url = `data:text/html;charset=utf-8,${TEST_URI}`;
|
||||
let { inspector } = yield openInspectorForURL(url);
|
||||
|
||||
elms.docBody = inspector.markup.doc.body;
|
||||
elms.root = inspector.markup.getContainer(inspector.markup._rootNode);
|
||||
elms.div = yield getContainerForSelector("div", inspector);
|
||||
elms.body = yield getContainerForSelector("body", inspector);
|
||||
|
||||
// Initial focus is on root element and active descendant should be set on
|
||||
// body tag line.
|
||||
testNavigationState(inspector, elms, elms.docBody, elms.body.tagLine);
|
||||
|
||||
// Focus on the tree element.
|
||||
elms.root.elt.focus();
|
||||
|
||||
for (let testData of TESTS) {
|
||||
yield runAccessibilityNavigationTest(inspector, elms, testData);
|
||||
}
|
||||
|
||||
elms = null;
|
||||
});
|
|
@ -0,0 +1,61 @@
|
|||
/* 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 event details tooltip can be hidden by clicking outside of the tooltip
|
||||
* after switching hosts.
|
||||
*/
|
||||
|
||||
const TEST_URL = URL_ROOT + "doc_markup_events-overflow.html";
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
// Restore the default Toolbox host position after the test.
|
||||
Services.prefs.clearUserPref("devtools.toolbox.host");
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
let { inspector, toolbox } = yield openInspectorForURL(TEST_URL);
|
||||
yield runTests(inspector);
|
||||
|
||||
yield toolbox.switchHost("window");
|
||||
yield runTests(inspector);
|
||||
|
||||
yield toolbox.switchHost("bottom");
|
||||
yield runTests(inspector);
|
||||
|
||||
yield toolbox.destroy();
|
||||
});
|
||||
|
||||
function* runTests(inspector) {
|
||||
let markupContainer = yield getContainerForSelector("#events", inspector);
|
||||
let evHolder = markupContainer.elt.querySelector(".markupview-events");
|
||||
let tooltip = inspector.markup.eventDetailsTooltip;
|
||||
|
||||
info("Clicking to open event tooltip.");
|
||||
|
||||
let onInspectorUpdated = inspector.once("inspector-updated");
|
||||
let onTooltipShown = tooltip.once("shown");
|
||||
EventUtils.synthesizeMouseAtCenter(evHolder, {}, inspector.markup.doc.defaultView);
|
||||
|
||||
yield onTooltipShown;
|
||||
// New node is selected when clicking on the events bubble, wait for inspector-updated.
|
||||
yield onInspectorUpdated;
|
||||
|
||||
ok(tooltip.isVisible(), "EventTooltip visible.");
|
||||
|
||||
onInspectorUpdated = inspector.once("inspector-updated");
|
||||
let onTooltipHidden = tooltip.once("hidden");
|
||||
|
||||
info("Click on another tag to hide the event tooltip");
|
||||
let h1 = yield getContainerForSelector("h1", inspector);
|
||||
let tag = h1.elt.querySelector(".tag");
|
||||
EventUtils.synthesizeMouseAtCenter(tag, {}, inspector.markup.doc.defaultView);
|
||||
|
||||
yield onTooltipHidden;
|
||||
// New node is selected, wait for inspector-updated.
|
||||
yield onInspectorUpdated;
|
||||
|
||||
ok(!tooltip.isVisible(), "EventTooltip hidden.");
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* 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/. */
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
/* import-globals-from head.js */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Execute a keyboard event and check that the state is as expected (focused element, aria
|
||||
* attribute etc...).
|
||||
*
|
||||
* @param {InspectorPanel} inspector
|
||||
* Current instance of the inspector being tested.
|
||||
* @param {Object} elms
|
||||
* Map of elements that will be used to retrieve live references to children
|
||||
* elements
|
||||
* @param {Element} focused
|
||||
* Element expected to be focused
|
||||
* @param {Element} activedescendant
|
||||
* Element expected to be the aria activedescendant of the root node
|
||||
*/
|
||||
function testNavigationState(inspector, elms, focused, activedescendant) {
|
||||
let doc = inspector.markup.doc;
|
||||
let id = activedescendant.getAttribute("id");
|
||||
is(doc.activeElement, focused, `Keyboard focus should be set to ${focused}`);
|
||||
is(elms.root.elt.getAttribute("aria-activedescendant"), id,
|
||||
`Active descendant should be set to ${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a keyboard event and check that the state is as expected (focused element, aria
|
||||
* attribute etc...).
|
||||
*
|
||||
* @param {InspectorPanel} inspector
|
||||
* Current instance of the inspector being tested.
|
||||
* @param {Object} elms
|
||||
* MarkupContainers/Elements that will be used to retrieve references to other
|
||||
* elements based on objects' paths.
|
||||
* @param {Object} testData
|
||||
* - {String} desc: description for better logging.
|
||||
* - {String} key: keyboard event's key.
|
||||
* - {Object} options, optional: event data such as shiftKey, etc.
|
||||
* - {String} focused: path to expected focused element in elms map.
|
||||
* - {String} activedescendant: path to expected aria-activedescendant element in
|
||||
* elms map.
|
||||
* - {String} waitFor, optional: markupview event to wait for if keyboard actions
|
||||
* result in async updates. Also accepts the inspector event "inspector-updated".
|
||||
*/
|
||||
function* runAccessibilityNavigationTest(inspector, elms,
|
||||
{desc, key, options, focused, activedescendant, waitFor}) {
|
||||
info(desc);
|
||||
|
||||
let markup = inspector.markup;
|
||||
let doc = markup.doc;
|
||||
let win = doc.defaultView;
|
||||
|
||||
let updated;
|
||||
if (waitFor) {
|
||||
updated = waitFor === "inspector-updated" ?
|
||||
inspector.once(waitFor) : markup.once(waitFor);
|
||||
} else {
|
||||
updated = Promise.resolve();
|
||||
}
|
||||
EventUtils.synthesizeKey(key, options, win);
|
||||
yield updated;
|
||||
|
||||
let focusedElement = lookupPath(elms, focused);
|
||||
let activeDescendantElement = lookupPath(elms, activedescendant);
|
||||
testNavigationState(inspector, elms, focusedElement, activeDescendantElement);
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci} = require("chrome");
|
||||
const {Ci} = require("chrome");
|
||||
const promise = require("promise");
|
||||
const CssLogic = require("devtools/shared/inspector/css-logic");
|
||||
const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
|
||||
|
@ -14,11 +14,7 @@ const {TextProperty} =
|
|||
require("devtools/client/inspector/rules/models/text-property");
|
||||
const {promiseWarn} = require("devtools/client/inspector/shared/utils");
|
||||
const {parseDeclarations} = require("devtools/shared/css-parsing-utils");
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "osString", function () {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
});
|
||||
const Services = require("Services");
|
||||
|
||||
/**
|
||||
* Rule is responsible for the following:
|
||||
|
@ -660,7 +656,7 @@ Rule.prototype = {
|
|||
stringifyRule: function () {
|
||||
let selectorText = this.selectorText;
|
||||
let cssText = "";
|
||||
let terminator = osString === "WINNT" ? "\r\n" : "\n";
|
||||
let terminator = Services.appinfo.OS === "WINNT" ? "\r\n" : "\n";
|
||||
|
||||
for (let textProp of this.textProps) {
|
||||
if (!textProp.invisible) {
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
* view.
|
||||
*/
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "osString", function () {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
});
|
||||
const osString = Services.appinfo.OS;
|
||||
|
||||
const TEST_URI = URL_ROOT + "doc_copystyles.html";
|
||||
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
|
||||
// Tests that properties can be selected and copied from the rule view
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "osString", function () {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
});
|
||||
const osString = Services.appinfo.OS;
|
||||
|
||||
const TEST_URI = `
|
||||
<style type="text/css">
|
||||
|
|
|
@ -24,7 +24,7 @@ function* testView(viewId, inspector) {
|
|||
info("Testing " + viewId);
|
||||
|
||||
yield inspector.sidebar.select(viewId);
|
||||
let view = inspector[viewId].view;
|
||||
let view = inspector[viewId].view || inspector[viewId].computedView;
|
||||
yield selectNode("div", inspector);
|
||||
|
||||
testIsColorValueNode(view);
|
||||
|
|
|
@ -20,7 +20,7 @@ add_task(function* () {
|
|||
is(getRuleViewPropertyValue(view, "element", "color"), "red",
|
||||
"The rule-view shows the properties for test node one");
|
||||
|
||||
let cView = inspector.computedview.view;
|
||||
let cView = inspector.computedview.computedView;
|
||||
let prop = getComputedViewProperty(cView, "color");
|
||||
ok(!prop, "The computed-view doesn't show the properties for test node one");
|
||||
|
||||
|
|
|
@ -297,7 +297,7 @@ function openComputedView() {
|
|||
toolbox: data.toolbox,
|
||||
inspector: data.inspector,
|
||||
testActor: data.testActor,
|
||||
view: data.inspector.computedview.view
|
||||
view: data.inspector.computedview.computedView
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ function selectRuleView(inspector) {
|
|||
*/
|
||||
function selectComputedView(inspector) {
|
||||
inspector.sidebar.select("computedview");
|
||||
return inspector.computedview.view;
|
||||
return inspector.computedview.computedView;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
- The text appears on the bottom right corner of the layout view when
|
||||
- the corresponding box is hovered. -->
|
||||
|
||||
<!ENTITY layoutViewTitle "Box Model">
|
||||
<!ENTITY margin.tooltip "margin">
|
||||
<!ENTITY border.tooltip "border">
|
||||
<!ENTITY padding.tooltip "padding">
|
||||
|
|
|
@ -3,16 +3,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { Ci, Cc } = require("chrome");
|
||||
const { defer, all } = require("promise");
|
||||
const { LocalizationHelper } = require("devtools/client/shared/l10n");
|
||||
const Services = require("Services");
|
||||
const appInfo = Services.appinfo;
|
||||
|
||||
loader.lazyRequireGetter(this, "NetworkHelper", "devtools/shared/webconsole/network-helper");
|
||||
|
||||
loader.lazyGetter(this, "appInfo", () => {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
|
||||
});
|
||||
|
||||
loader.lazyGetter(this, "L10N", () => {
|
||||
return new LocalizationHelper("chrome://devtools/locale/har.properties");
|
||||
});
|
||||
|
|
|
@ -102,6 +102,7 @@ support-files =
|
|||
[browser_perf-tree-abstract-02.js]
|
||||
[browser_perf-tree-abstract-03.js]
|
||||
[browser_perf-tree-abstract-04.js]
|
||||
[browser_perf-tree-abstract-05.js]
|
||||
[browser_perf-tree-view-01.js]
|
||||
[browser_perf-tree-view-02.js]
|
||||
[browser_perf-tree-view-03.js]
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if the abstract tree base class for the profiler's tree view
|
||||
* supports PageUp/PageDown/Home/End keys.
|
||||
*/
|
||||
|
||||
const { appendAndWaitForPaint } = require("devtools/client/performance/test/helpers/dom-utils");
|
||||
const { synthesizeCustomTreeClass } = require("devtools/client/performance/test/helpers/synth-utils");
|
||||
const { once } = require("devtools/client/performance/test/helpers/event-utils");
|
||||
|
||||
add_task(function* () {
|
||||
let { MyCustomTreeItem } = synthesizeCustomTreeClass();
|
||||
|
||||
let container = document.createElement("vbox");
|
||||
container.style.height = '100%';
|
||||
container.style.overflow = 'scroll';
|
||||
yield appendAndWaitForPaint(gBrowser.selectedBrowser.parentNode, container);
|
||||
|
||||
let myDataSrc = {
|
||||
label: "root",
|
||||
children: []
|
||||
};
|
||||
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
myDataSrc.children.push({
|
||||
label: "child-" + i,
|
||||
children: []
|
||||
});
|
||||
}
|
||||
|
||||
let treeRoot = new MyCustomTreeItem(myDataSrc, { parent: null });
|
||||
treeRoot.attachTo(container);
|
||||
treeRoot.focus();
|
||||
treeRoot.expand();
|
||||
|
||||
is(document.commandDispatcher.focusedElement, treeRoot.target,
|
||||
"The root node is focused.");
|
||||
|
||||
// Test HOME and END
|
||||
|
||||
key("VK_END");
|
||||
is(document.commandDispatcher.focusedElement,
|
||||
treeRoot.getChild(myDataSrc.children.length - 1).target,
|
||||
"The last node is focused.");
|
||||
|
||||
key("VK_HOME");
|
||||
is(document.commandDispatcher.focusedElement, treeRoot.target,
|
||||
"The first (root) node is focused.");
|
||||
|
||||
// Test PageUp and PageDown
|
||||
|
||||
let nodesPerPageSize = treeRoot._getNodesPerPageSize();
|
||||
|
||||
key("VK_PAGE_DOWN");
|
||||
is(document.commandDispatcher.focusedElement,
|
||||
treeRoot.getChild(nodesPerPageSize - 1).target,
|
||||
"The first node in the second page is focused.");
|
||||
|
||||
key("VK_PAGE_DOWN");
|
||||
is(document.commandDispatcher.focusedElement,
|
||||
treeRoot.getChild(nodesPerPageSize * 2 - 1).target,
|
||||
"The first node in the third page is focused.");
|
||||
|
||||
key("VK_PAGE_UP");
|
||||
is(document.commandDispatcher.focusedElement,
|
||||
treeRoot.getChild(nodesPerPageSize - 1).target,
|
||||
"The first node in the second page is focused.");
|
||||
|
||||
key("VK_PAGE_UP");
|
||||
is(document.commandDispatcher.focusedElement, treeRoot.target,
|
||||
"The first (root) node is focused.");
|
||||
|
||||
// Test PageUp in the middle of the first page
|
||||
|
||||
let middleIndex = Math.floor(nodesPerPageSize / 2);
|
||||
|
||||
treeRoot.getChild(middleIndex).target.focus();
|
||||
is(document.commandDispatcher.focusedElement,
|
||||
treeRoot.getChild(middleIndex).target,
|
||||
"The middle node in the first page is focused.");
|
||||
|
||||
key("VK_PAGE_UP");
|
||||
is(document.commandDispatcher.focusedElement, treeRoot.target,
|
||||
"The first (root) node is focused.");
|
||||
|
||||
// Test PageDown in the middle of the last page
|
||||
|
||||
middleIndex = Math.ceil(myDataSrc.children.length - middleIndex);
|
||||
|
||||
treeRoot.getChild(middleIndex).target.focus();
|
||||
is(document.commandDispatcher.focusedElement,
|
||||
treeRoot.getChild(middleIndex).target,
|
||||
"The middle node in the last page is focused.");
|
||||
|
||||
key("VK_PAGE_DOWN");
|
||||
is(document.commandDispatcher.focusedElement,
|
||||
treeRoot.getChild(myDataSrc.children.length - 1).target,
|
||||
"The last node is focused.");
|
||||
|
||||
container.remove();
|
||||
});
|
|
@ -147,7 +147,7 @@ var openInspectorSideBar = Task.async(function* (id) {
|
|||
return {
|
||||
toolbox: toolbox,
|
||||
inspector: inspector,
|
||||
view: inspector[id].view
|
||||
view: inspector[id].view || inspector[id].computedView
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DOMHelpers"];
|
||||
|
||||
|
@ -103,7 +105,7 @@ DOMHelpers.prototype = {
|
|||
|
||||
getFirstChild: function Helpers_getFirstChild(node)
|
||||
{
|
||||
let SHOW_ALL = Components.interfaces.nsIDOMNodeFilter.SHOW_ALL;
|
||||
let SHOW_ALL = nodeFilterConstants.SHOW_ALL;
|
||||
this.treeWalker = node.ownerDocument.createTreeWalker(node,
|
||||
SHOW_ALL, null);
|
||||
return this.treeWalker.firstChild();
|
||||
|
|
|
@ -60,7 +60,7 @@ define(function (require, exports, module) {
|
|||
}
|
||||
}
|
||||
|
||||
if (array.length > max + 1) {
|
||||
if (array.length > max) {
|
||||
items.pop();
|
||||
|
||||
let objectLink = this.props.objectLink || DOM.span;
|
||||
|
|
|
@ -87,7 +87,7 @@ define(function (require, exports, module) {
|
|||
}
|
||||
}
|
||||
|
||||
if (array.length > max + 1) {
|
||||
if (array.length > max) {
|
||||
items.pop();
|
||||
let objectLink = this.props.objectLink || span;
|
||||
items.push(Caption({
|
||||
|
|
|
@ -19,13 +19,18 @@ window.onload = Task.async(function* () {
|
|||
let { ArrayRep } = browserRequire("devtools/client/shared/components/reps/array");
|
||||
|
||||
let componentUnderTest = ArrayRep;
|
||||
const maxLength = {
|
||||
short: 3,
|
||||
long: 300
|
||||
};
|
||||
|
||||
try {
|
||||
yield testBasic();
|
||||
|
||||
// Test property iterator
|
||||
yield testMaxProps();
|
||||
yield testMoreThanMaxProps();
|
||||
yield testMoreThanShortMaxProps();
|
||||
yield testMoreThanLongMaxProps();
|
||||
yield testRecursiveArray();
|
||||
|
||||
// Test that properties are rendered as expected by ItemRep
|
||||
|
@ -93,26 +98,53 @@ window.onload = Task.async(function* () {
|
|||
testRepRenderModes(modeTests, "testMaxProps", componentUnderTest, stub);
|
||||
}
|
||||
|
||||
function testMoreThanMaxProps() {
|
||||
const stub = Array(302).fill("foo");
|
||||
const defaultOutput = `["foo", "foo", "foo", more…]`;
|
||||
function testMoreThanShortMaxProps() {
|
||||
const stub = Array(maxLength.short + 1).fill("foo");
|
||||
const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, more…]`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultOutput,
|
||||
expectedOutput: defaultShortOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `[302]`,
|
||||
expectedOutput: `[${maxLength.short + 1}]`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultOutput,
|
||||
expectedOutput: defaultShortOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: `[${Array(300).fill("\"foo\"").join(", ")}, more…]`,
|
||||
expectedOutput: `[${Array(maxLength.short + 1).fill("\"foo\"").join(", ")}]`,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
|
||||
}
|
||||
|
||||
function testMoreThanLongMaxProps() {
|
||||
const stub = Array(maxLength.long + 1).fill("foo");
|
||||
const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, more…]`;
|
||||
const defaultLongOutput = `[${Array(maxLength.long).fill("\"foo\"").join(", ")}, more…]`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultShortOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `[${maxLength.long + 1}]`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultShortOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultLongOutput,
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -19,13 +19,18 @@ window.onload = Task.async(function* () {
|
|||
let { GripArray } = browserRequire("devtools/client/shared/components/reps/grip-array");
|
||||
|
||||
let componentUnderTest = GripArray;
|
||||
const maxLength = {
|
||||
short: 3,
|
||||
long: 300
|
||||
};
|
||||
|
||||
try {
|
||||
yield testBasic();
|
||||
|
||||
// Test property iterator
|
||||
yield testMaxProps();
|
||||
yield testMoreThanMaxProps();
|
||||
yield testMoreThanShortMaxProps();
|
||||
yield testMoreThanLongMaxProps();
|
||||
yield testRecursiveArray();
|
||||
} catch(e) {
|
||||
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
|
||||
|
@ -95,11 +100,11 @@ window.onload = Task.async(function* () {
|
|||
testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
|
||||
}
|
||||
|
||||
function testMoreThanMaxProps() {
|
||||
// Test array = `["test string"…] //301 items`
|
||||
const testName = "testMoreThanMaxProps";
|
||||
function testMoreThanShortMaxProps() {
|
||||
// Test array = `["test string"…] //4 items`
|
||||
const testName = "testMoreThanShortMaxProps";
|
||||
|
||||
const defaultOutput = `[${Array(3).fill("\"test string\"").join(", ")}, more…]`;
|
||||
const defaultOutput = `[${Array(maxLength.short).fill("\"test string\"").join(", ")}, more…]`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
|
@ -108,7 +113,7 @@ window.onload = Task.async(function* () {
|
|||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `[302]`,
|
||||
expectedOutput: `[${maxLength.short + 1}]`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
|
@ -116,7 +121,36 @@ window.onload = Task.async(function* () {
|
|||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: `[${Array(300).fill("\"test string\"").join(", ")}, more…]`,
|
||||
expectedOutput: `[${Array(maxLength.short + 1).fill("\"test string\"").join(", ")}]`,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
|
||||
}
|
||||
|
||||
function testMoreThanLongMaxProps() {
|
||||
// Test array = `["test string"…] //301 items`
|
||||
const testName = "testMoreThanLongMaxProps";
|
||||
|
||||
const defaultShortOutput = `[${Array(maxLength.short).fill("\"test string\"").join(", ")}, more…]`;
|
||||
const defaultLongOutput = `[${Array(maxLength.long).fill("\"test string\"").join(", ")}, more…]`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultShortOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `[${maxLength.long + 1}]`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultShortOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultLongOutput
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -200,8 +234,8 @@ window.onload = Task.async(function* () {
|
|||
}
|
||||
};
|
||||
|
||||
case "testMoreThanMaxProps":
|
||||
let grip = {
|
||||
case "testMoreThanShortMaxProps":
|
||||
let shortArrayGrip = {
|
||||
"type": "object",
|
||||
"class": "Array",
|
||||
"actor": "server1.conn1.obj35",
|
||||
|
@ -211,18 +245,42 @@ window.onload = Task.async(function* () {
|
|||
"ownPropertyLength": 4,
|
||||
"preview": {
|
||||
"kind": "ArrayLike",
|
||||
"length": 302,
|
||||
"length": maxLength.short + 1,
|
||||
"items": []
|
||||
}
|
||||
};
|
||||
|
||||
// Generate 101 properties, which is more that the maximum
|
||||
// limit in case of the 'long' mode.
|
||||
for (let i = 0; i < 302; i++) {
|
||||
grip.preview.items.push("test string");
|
||||
// Generate array grip with length 4, which is more that the maximum
|
||||
// limit in case of the 'short' mode.
|
||||
for (let i = 0; i < maxLength.short + 1; i++) {
|
||||
shortArrayGrip.preview.items.push("test string");
|
||||
}
|
||||
|
||||
return grip;
|
||||
return shortArrayGrip;
|
||||
|
||||
case "testMoreThanLongMaxProps":
|
||||
let longArrayGrip = {
|
||||
"type": "object",
|
||||
"class": "Array",
|
||||
"actor": "server1.conn1.obj35",
|
||||
"extensible": true,
|
||||
"frozen": false,
|
||||
"sealed": false,
|
||||
"ownPropertyLength": 4,
|
||||
"preview": {
|
||||
"kind": "ArrayLike",
|
||||
"length": maxLength.long + 1,
|
||||
"items": []
|
||||
}
|
||||
};
|
||||
|
||||
// Generate array grip with length 301, which is more that the maximum
|
||||
// limit in case of the 'long' mode.
|
||||
for (let i = 0; i < maxLength.long + 1; i++) {
|
||||
longArrayGrip.preview.items.push("test string");
|
||||
}
|
||||
|
||||
return longArrayGrip;
|
||||
|
||||
case "testRecursiveArray":
|
||||
return {
|
||||
|
|
|
@ -223,15 +223,10 @@ exports.CommandUtils = CommandUtils;
|
|||
* to using panels.
|
||||
*/
|
||||
loader.lazyGetter(this, "isLinux", function () {
|
||||
return OS == "Linux";
|
||||
return Services.appinfo.OS == "Linux";
|
||||
});
|
||||
loader.lazyGetter(this, "isMac", function () {
|
||||
return OS == "Darwin";
|
||||
});
|
||||
|
||||
loader.lazyGetter(this, "OS", function () {
|
||||
let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
return os;
|
||||
return Services.appinfo.OS == "Darwin";
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -1010,7 +1005,7 @@ OutputPanel.prototype._resize = function () {
|
|||
// We'd like to put this in CSS but we can't:
|
||||
// body { width: calc(min(-5px, max-content)); }
|
||||
// #_panel { max-width: -5px; }
|
||||
switch (OS) {
|
||||
switch (Services.appinfo.OS) {
|
||||
case "Linux":
|
||||
maxWidth -= 5;
|
||||
break;
|
||||
|
|
|
@ -465,6 +465,42 @@ const Services = {
|
|||
* by devtools is implemented here.
|
||||
*/
|
||||
prefs: new PrefBranch(null, "", ""),
|
||||
|
||||
/**
|
||||
* An implementation of Services.appinfo that holds just the
|
||||
* properties needed by devtools.
|
||||
*/
|
||||
appinfo: {
|
||||
get OS() {
|
||||
const os = window.navigator.userAgent;
|
||||
if (os) {
|
||||
if (os.includes("Linux")) {
|
||||
return "Linux";
|
||||
} else if (os.includes("Windows")) {
|
||||
return "WINNT";
|
||||
} else if (os.includes("Mac")) {
|
||||
return "Darwin";
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
},
|
||||
|
||||
// It's fine for this to be an approximation.
|
||||
get name() {
|
||||
return window.navigator.userAgent;
|
||||
},
|
||||
|
||||
// It's fine for this to be an approximation.
|
||||
get version() {
|
||||
return window.navigator.appVersion;
|
||||
},
|
||||
|
||||
// This is only used by telemetry, which is disabled for the
|
||||
// content case. So, being totally wrong is ok.
|
||||
get is64Bit() {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
support-files =
|
||||
prefs-wrapper.js
|
||||
|
||||
[test_service_appinfo.html]
|
||||
[test_service_prefs.html]
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1265802
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1265802 - replace Services.appinfo</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
"use strict";
|
||||
var exports = {};
|
||||
</script>
|
||||
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="resource://devtools/client/shared/shim/Services.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.8">
|
||||
"use strict";
|
||||
|
||||
is(Services.appinfo.OS, SpecialPowers.Services.appinfo.OS,
|
||||
"check that Services.appinfo.OS shim matches platform");
|
||||
</script>
|
||||
</body>
|
|
@ -56,9 +56,7 @@ this.Telemetry = function () {
|
|||
|
||||
module.exports = Telemetry;
|
||||
|
||||
var {Cc, Ci, Cu} = require("chrome");
|
||||
var Services = require("Services");
|
||||
var {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
|
||||
Telemetry.prototype = {
|
||||
_histograms: {
|
||||
|
@ -97,11 +95,6 @@ Telemetry.prototype = {
|
|||
userHistogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
layoutview: {
|
||||
histogram: "DEVTOOLS_LAYOUTVIEW_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_LAYOUTVIEW_OPENED_PER_USER_FLAG",
|
||||
timerHistogram: "DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS"
|
||||
},
|
||||
fontinspector: {
|
||||
histogram: "DEVTOOLS_FONTINSPECTOR_OPENED_COUNT",
|
||||
userHistogram: "DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG",
|
||||
|
@ -362,7 +355,7 @@ Telemetry.prototype = {
|
|||
* Histogram in which the data is to be stored.
|
||||
*/
|
||||
logOncePerBrowserVersion: function (perUserHistogram, value) {
|
||||
let currentVersion = appInfo.version;
|
||||
let currentVersion = Services.appinfo.version;
|
||||
let latest = Services.prefs.getCharPref(TOOLS_OPENED_PREF);
|
||||
let latestObj = JSON.parse(latest);
|
||||
|
||||
|
@ -383,7 +376,3 @@ Telemetry.prototype = {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "appInfo", function () {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ function* testSidebar(toolbox) {
|
|||
|
||||
let inspector = toolbox.getCurrentPanel();
|
||||
let sidebarTools = ["ruleview", "computedview", "fontinspector",
|
||||
"layoutview", "animationinspector"];
|
||||
"animationinspector"];
|
||||
|
||||
// Concatenate the array with itself so that we can open each tool twice.
|
||||
sidebarTools.push.apply(sidebarTools, sidebarTools);
|
||||
|
|
|
@ -478,7 +478,48 @@ AbstractTreeItem.prototype = {
|
|||
_getSiblingAtDelta: function (delta) {
|
||||
let childNodes = this._containerNode.childNodes;
|
||||
let indexOfSelf = Array.indexOf(childNodes, this._targetNode);
|
||||
return childNodes[indexOfSelf + delta];
|
||||
if (indexOfSelf + delta >= 0) {
|
||||
return childNodes[indexOfSelf + delta];
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
_getNodesPerPageSize: function() {
|
||||
let childNodes = this._containerNode.childNodes;
|
||||
let nodeHeight = this._getHeight(childNodes[childNodes.length - 1]);
|
||||
let containerHeight = this.bounds.height;
|
||||
return Math.ceil(containerHeight / nodeHeight);
|
||||
},
|
||||
|
||||
_getHeight: function(elem) {
|
||||
let win = this.document.defaultView;
|
||||
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
return utils.getBoundsWithoutFlushing(elem).height;
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the first item in this tree.
|
||||
*/
|
||||
_focusFirstNode: function () {
|
||||
let childNodes = this._containerNode.childNodes;
|
||||
// The root node of the tree may be hidden in practice, so uses for-loop
|
||||
// here to find the next visible node.
|
||||
for (let i = 0; i < childNodes.length; i++) {
|
||||
// The height will be 0 if an element is invisible.
|
||||
if (this._getHeight(childNodes[i])) {
|
||||
childNodes[i].focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the last item in this tree.
|
||||
*/
|
||||
_focusLastNode: function () {
|
||||
let childNodes = this._containerNode.childNodes;
|
||||
childNodes[childNodes.length - 1].focus();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -570,6 +611,36 @@ AbstractTreeItem.prototype = {
|
|||
this._focusNextNode();
|
||||
}
|
||||
return;
|
||||
|
||||
case e.DOM_VK_PAGE_UP:
|
||||
let pageUpElement =
|
||||
this._getSiblingAtDelta(-this._getNodesPerPageSize());
|
||||
// There's a chance that the root node is hidden. In this case, its
|
||||
// height will be 0.
|
||||
if (pageUpElement && this._getHeight(pageUpElement)) {
|
||||
pageUpElement.focus();
|
||||
} else {
|
||||
this._focusFirstNode();
|
||||
}
|
||||
return;
|
||||
|
||||
case e.DOM_VK_PAGE_DOWN:
|
||||
let pageDownElement =
|
||||
this._getSiblingAtDelta(this._getNodesPerPageSize());
|
||||
if (pageDownElement) {
|
||||
pageDownElement.focus();
|
||||
} else {
|
||||
this._focusLastNode();
|
||||
}
|
||||
return;
|
||||
|
||||
case e.DOM_VK_HOME:
|
||||
this._focusFirstNode();
|
||||
return;
|
||||
|
||||
case e.DOM_VK_END:
|
||||
this._focusLastNode();
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -927,7 +927,9 @@ FlameGraph.prototype = {
|
|||
_onKeyDown: function (e) {
|
||||
ViewHelpers.preventScrolling(e);
|
||||
|
||||
if (!this._keysPressed[e.keyCode]) {
|
||||
const hasModifier = e.ctrlKey || e.shiftKey || e.altKey || e.metaKey;
|
||||
|
||||
if (!hasModifier && !this._keysPressed[e.keyCode]) {
|
||||
this._keysPressed[e.keyCode] = true;
|
||||
this._userInputStack++;
|
||||
this._shouldRedraw = true;
|
||||
|
|
|
@ -222,10 +222,11 @@ function HTMLTooltip(toolbox, {
|
|||
this.consumeOutsideClicks = consumeOutsideClicks;
|
||||
this.useXulWrapper = this._isXUL() && useXulWrapper;
|
||||
|
||||
this._position = null;
|
||||
// The top window is used to attach click event listeners to close the tooltip if the
|
||||
// user clicks on the content page.
|
||||
this.topWindow = this._getTopWindow();
|
||||
|
||||
// Use the topmost window to listen for click events to close the tooltip
|
||||
this.topWindow = this.doc.defaultView.top;
|
||||
this._position = null;
|
||||
|
||||
this._onClick = this._onClick.bind(this);
|
||||
|
||||
|
@ -382,6 +383,8 @@ HTMLTooltip.prototype = {
|
|||
this.doc.defaultView.clearTimeout(this.attachEventsTimer);
|
||||
this.attachEventsTimer = this.doc.defaultView.setTimeout(() => {
|
||||
this._maybeFocusTooltip();
|
||||
// Updated the top window reference each time in case the host changes.
|
||||
this.topWindow = this._getTopWindow();
|
||||
this.topWindow.addEventListener("click", this._onClick, true);
|
||||
this.emit("shown");
|
||||
}, 0);
|
||||
|
@ -550,6 +553,10 @@ HTMLTooltip.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_getTopWindow: function () {
|
||||
return this.doc.defaultView.top;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the tooltip's owner document is a XUL document.
|
||||
*/
|
||||
|
|
|
@ -32,11 +32,17 @@
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
#computedview-container {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#propertyContainer {
|
||||
-moz-user-select: text;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
flex: auto;
|
||||
border-top-width: 1px;
|
||||
border-top-style: dotted;
|
||||
}
|
||||
|
||||
.row-striped {
|
||||
|
@ -59,7 +65,9 @@
|
|||
}
|
||||
|
||||
.property-value-container {
|
||||
width: 168px;
|
||||
display: flex;
|
||||
flex: 1 1 168px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.property-name-container > *,
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
.theme-firebug #sources-toolbar image,
|
||||
.theme-firebug [id$="pane-toggle"] > image,
|
||||
.theme-firebug [id$="pane-toggle"]::before,
|
||||
.theme-firebug #global-toolbar .devtools-button::before,
|
||||
.theme-firebug .sidebar-toggle::before,
|
||||
.theme-firebug #element-picker::before,
|
||||
.theme-firebug #rewind-timeline::before,
|
||||
.theme-firebug #pause-resume-timeline::before,
|
||||
.theme-firebug #debugger-controls .toolbarbutton-icon,
|
||||
.theme-firebug #filter-button .toolbarbutton-icon {
|
||||
filter: none !important;
|
||||
|
|
|
@ -2,66 +2,34 @@
|
|||
* 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/ */
|
||||
|
||||
#sidebar-panel-layoutview {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#layout-wrapper {
|
||||
/* The sidebar-panel is not focusable, this wrapper will catch click events in
|
||||
all the empty area around the layout-container */
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#layout-container {
|
||||
/* The view will grow bigger as the window gets resized, until 400px */
|
||||
max-width: 400px;
|
||||
margin: 0px auto;
|
||||
padding: 0;
|
||||
/* "Contain" the absolutely positioned #layout-main element */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Header: contains the position and size of the element */
|
||||
/* Header */
|
||||
|
||||
#layout-header {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 4px 14px;
|
||||
display: -moz-box;
|
||||
vertical-align: top;
|
||||
#layout-header,
|
||||
#layout-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 17px;
|
||||
}
|
||||
|
||||
#layout-header:dir(rtl) {
|
||||
-moz-box-direction: reverse;
|
||||
#layout-geometry-editor {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#layout-header > span {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#layout-element-size {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#layout-element-size:dir(rtl) {
|
||||
-moz-box-pack: end;
|
||||
}
|
||||
|
||||
@media (max-height: 250px) {
|
||||
#layout-header {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
#layout-geometry-editor::before {
|
||||
background: url(images/geometry-editor.svg) no-repeat center center / 16px 16px;
|
||||
}
|
||||
|
||||
/* Main: contains the box-model regions */
|
||||
|
||||
#layout-main {
|
||||
position: absolute;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
/* The regions are semi-transparent, so the white background is partly
|
||||
visible */
|
||||
|
@ -316,7 +284,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Legend, displayed inside regions */
|
||||
/* Legend: displayed inside regions */
|
||||
|
||||
.layout-legend {
|
||||
position: absolute;
|
||||
|
@ -356,23 +324,13 @@
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
/* Hide all values when the view is inactive */
|
||||
/* Layout info: contains the position and size of the element */
|
||||
|
||||
#layout-container.inactive > #layout-header > #layout-element-position,
|
||||
#layout-container.inactive > #layout-header > #layout-element-size,
|
||||
#layout-container.inactive > #layout-main > p {
|
||||
visibility: hidden;
|
||||
#layout-element-size {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#layout-position-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#layout-geometry-editor {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#layout-geometry-editor::before {
|
||||
background: url(images/geometry-editor.svg) no-repeat center center / 16px 16px;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
|
||||
#ruleview-toolbar {
|
||||
display: flex;
|
||||
height: 23px;
|
||||
}
|
||||
|
||||
#ruleview-toolbar > .devtools-searchbox:first-child {
|
||||
|
@ -256,11 +255,9 @@
|
|||
.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-namecontainer,
|
||||
.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-namecontainer *,
|
||||
.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-propertyvaluecontainer,
|
||||
.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-propertyvaluecontainer * {
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-computedlist * {
|
||||
.theme-firebug .ruleview-enableproperty:not([checked]) ~ .ruleview-propertyvaluecontainer *,
|
||||
.theme-firebug .ruleview-overridden > * > .ruleview-computed:not(.ruleview-overridden),
|
||||
.theme-firebug .ruleview-overridden > * > .ruleview-computed:not(.ruleview-overridden) * {
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
|
|
|
@ -390,6 +390,7 @@
|
|||
.devtools-searchbox {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
height: 23px;
|
||||
position: relative;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ const {
|
|||
} = require("devtools/shared/layout/utils");
|
||||
const {getLayoutChangesObserver, releaseLayoutChangesObserver} =
|
||||
require("devtools/server/actors/layout");
|
||||
const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
|
||||
|
||||
loader.lazyRequireGetter(this, "CSS", "CSS");
|
||||
|
||||
|
@ -2768,13 +2769,13 @@ function isNodeDead(node) {
|
|||
*
|
||||
* @param {DOMNode} node
|
||||
* @param {Window} rootWin
|
||||
* @param {Int} whatToShow See Ci.nsIDOMNodeFilter / inIDeepTreeWalker for
|
||||
* @param {Int} whatToShow See nodeFilterConstants / inIDeepTreeWalker for
|
||||
* options.
|
||||
* @param {Function} filter A custom filter function Taking in a DOMNode
|
||||
* and returning an Int. See WalkerActor.nodeFilter for an example.
|
||||
*/
|
||||
function DocumentWalker(node, rootWin,
|
||||
whatToShow = Ci.nsIDOMNodeFilter.SHOW_ALL,
|
||||
whatToShow = nodeFilterConstants.SHOW_ALL,
|
||||
filter = standardTreeWalkerFilter) {
|
||||
if (!rootWin.location) {
|
||||
throw new Error("Got an invalid root window in DocumentWalker");
|
||||
|
@ -2793,7 +2794,7 @@ function DocumentWalker(node, rootWin,
|
|||
// causes currentNode to be updated.
|
||||
this.walker.currentNode = node;
|
||||
while (node &&
|
||||
this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
|
||||
this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
|
||||
node = this.walker.parentNode();
|
||||
}
|
||||
}
|
||||
|
@ -2824,7 +2825,7 @@ DocumentWalker.prototype = {
|
|||
|
||||
let nextNode = this.walker.nextNode();
|
||||
while (nextNode &&
|
||||
this.filter(nextNode) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
|
||||
this.filter(nextNode) === nodeFilterConstants.FILTER_SKIP) {
|
||||
nextNode = this.walker.nextNode();
|
||||
}
|
||||
|
||||
|
@ -2839,7 +2840,7 @@ DocumentWalker.prototype = {
|
|||
|
||||
let firstChild = this.walker.firstChild();
|
||||
while (firstChild &&
|
||||
this.filter(firstChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
|
||||
this.filter(firstChild) === nodeFilterConstants.FILTER_SKIP) {
|
||||
firstChild = this.walker.nextSibling();
|
||||
}
|
||||
|
||||
|
@ -2854,7 +2855,7 @@ DocumentWalker.prototype = {
|
|||
|
||||
let lastChild = this.walker.lastChild();
|
||||
while (lastChild &&
|
||||
this.filter(lastChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
|
||||
this.filter(lastChild) === nodeFilterConstants.FILTER_SKIP) {
|
||||
lastChild = this.walker.previousSibling();
|
||||
}
|
||||
|
||||
|
@ -2863,7 +2864,7 @@ DocumentWalker.prototype = {
|
|||
|
||||
previousSibling: function () {
|
||||
let node = this.walker.previousSibling();
|
||||
while (node && this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
|
||||
while (node && this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
|
||||
node = this.walker.previousSibling();
|
||||
}
|
||||
return node;
|
||||
|
@ -2871,7 +2872,7 @@ DocumentWalker.prototype = {
|
|||
|
||||
nextSibling: function () {
|
||||
let node = this.walker.nextSibling();
|
||||
while (node && this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
|
||||
while (node && this.filter(node) === nodeFilterConstants.FILTER_SKIP) {
|
||||
node = this.walker.nextSibling();
|
||||
}
|
||||
return node;
|
||||
|
@ -2895,13 +2896,13 @@ function standardTreeWalkerFilter(node) {
|
|||
// want to show them
|
||||
if (node.nodeName === "_moz_generated_content_before" ||
|
||||
node.nodeName === "_moz_generated_content_after") {
|
||||
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
|
||||
return nodeFilterConstants.FILTER_ACCEPT;
|
||||
}
|
||||
|
||||
// Ignore empty whitespace text nodes.
|
||||
if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
|
||||
!/[^\s]/.exec(node.nodeValue)) {
|
||||
return Ci.nsIDOMNodeFilter.FILTER_SKIP;
|
||||
return nodeFilterConstants.FILTER_SKIP;
|
||||
}
|
||||
|
||||
// Ignore all native and XBL anonymous content inside a non-XUL document
|
||||
|
@ -2911,10 +2912,10 @@ function standardTreeWalkerFilter(node) {
|
|||
// that's XUL content injected in an HTML document, but we need to because
|
||||
// this also skips many other elements that need to be skipped - like form
|
||||
// controls, scrollbars, video controls, etc (see bug 1187482).
|
||||
return Ci.nsIDOMNodeFilter.FILTER_SKIP;
|
||||
return nodeFilterConstants.FILTER_SKIP;
|
||||
}
|
||||
|
||||
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
|
||||
return nodeFilterConstants.FILTER_ACCEPT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2925,9 +2926,9 @@ function allAnonymousContentTreeWalkerFilter(node) {
|
|||
// Ignore empty whitespace text nodes.
|
||||
if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
|
||||
!/[^\s]/.exec(node.nodeValue)) {
|
||||
return Ci.nsIDOMNodeFilter.FILTER_SKIP;
|
||||
return nodeFilterConstants.FILTER_SKIP;
|
||||
}
|
||||
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
|
||||
return nodeFilterConstants.FILTER_ACCEPT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,11 +12,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=777674
|
|||
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
window.onload = function() {
|
||||
const Ci = Components.interfaces;
|
||||
const {InspectorFront} =
|
||||
require("devtools/shared/fronts/inspector");
|
||||
const {_documentWalker} =
|
||||
require("devtools/server/actors/inspector");
|
||||
const nodeFilterConstants =
|
||||
require("devtools/shared/dom-node-filter-constants");
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
|
@ -76,9 +77,9 @@ window.onload = function() {
|
|||
let docwalker = new _documentWalker(
|
||||
gInspectee.querySelector("select"),
|
||||
gInspectee.defaultView,
|
||||
Ci.nsIDOMNodeFilter.SHOW_ALL,
|
||||
nodeFilterConstants.SHOW_ALL,
|
||||
() => {
|
||||
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT
|
||||
return nodeFilterConstants.FILTER_ACCEPT
|
||||
}
|
||||
);
|
||||
let scrollbar = docwalker.lastChild();
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
FILTER_ACCEPT: 1,
|
||||
FILTER_REJECT: 2,
|
||||
FILTER_SKIP: 3,
|
||||
|
||||
SHOW_ALL: 0xFFFFFFFF,
|
||||
SHOW_ELEMENT: 0x00000001,
|
||||
SHOW_ATTRIBUTE: 0x00000002,
|
||||
SHOW_TEXT: 0x00000004,
|
||||
SHOW_CDATA_SECTION: 0x00000008,
|
||||
SHOW_ENTITY_REFERENCE: 0x00000010,
|
||||
SHOW_ENTITY: 0x00000020,
|
||||
SHOW_PROCESSING_INSTRUCTION: 0x00000040,
|
||||
SHOW_COMMENT: 0x00000080,
|
||||
SHOW_DOCUMENT: 0x00000100,
|
||||
SHOW_DOCUMENT_TYPE: 0x00000200,
|
||||
SHOW_DOCUMENT_FRAGMENT: 0x00000400,
|
||||
SHOW_NOTATION: 0x00000800
|
||||
};
|
|
@ -40,7 +40,6 @@
|
|||
* @constructor
|
||||
*/
|
||||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const Services = require("Services");
|
||||
|
||||
// This should be ok because none of the functions that use this should be used
|
||||
|
@ -144,7 +143,7 @@ const TAB_CHARS = "\t";
|
|||
*/
|
||||
function prettifyCSS(text, ruleCount) {
|
||||
if (prettifyCSS.LINE_SEPARATOR == null) {
|
||||
let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||
let os = Services.appinfo.OS;
|
||||
prettifyCSS.LINE_SEPARATOR = (os === "WINNT" ? "\r\n" : "\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
const { Ci, Cc } = require("chrome");
|
||||
const { memoize } = require("sdk/lang/functional");
|
||||
const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
|
||||
|
||||
loader.lazyRequireGetter(this, "setIgnoreLayoutChanges", "devtools/server/actors/layout", true);
|
||||
exports.setIgnoreLayoutChanges = (...args) =>
|
||||
|
@ -377,7 +378,7 @@ function safelyGetContentWindow(frame) {
|
|||
.createInstance(Ci.inIDeepTreeWalker);
|
||||
walker.showSubDocuments = true;
|
||||
walker.showDocumentsAsNodes = true;
|
||||
walker.init(frame, Ci.nsIDOMNodeFilter.SHOW_ALL);
|
||||
walker.init(frame, nodeFilterConstants.SHOW_ALL);
|
||||
walker.currentNode = frame;
|
||||
|
||||
let document = walker.nextNode();
|
||||
|
|
|
@ -49,6 +49,7 @@ DevToolsModules(
|
|||
'deprecated-sync-thenables.js',
|
||||
'DevToolsUtils.js',
|
||||
'dom-node-constants.js',
|
||||
'dom-node-filter-constants.js',
|
||||
'event-emitter.js',
|
||||
'event-parsers.js',
|
||||
'indentation.js',
|
||||
|
|
|
@ -331,7 +331,6 @@ function getSetting(name) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
exports.is64Bit = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).is64Bit;
|
||||
exports.getSystemInfo = Task.async(getSystemInfo);
|
||||
exports.getAppIniString = getAppIniString;
|
||||
exports.getSetting = getSetting;
|
||||
|
|
|
@ -76,7 +76,13 @@ ClientEngine.prototype = {
|
|||
},
|
||||
|
||||
get remoteClients() {
|
||||
return Object.values(this._store._remoteClients);
|
||||
// return all non-stale clients for external consumption.
|
||||
return Object.values(this._store._remoteClients).filter(v => !v.stale);
|
||||
},
|
||||
|
||||
remoteClientExists(id) {
|
||||
let client = this._store._remoteClients[id];
|
||||
return !!(client && !client.stale);
|
||||
},
|
||||
|
||||
// Aggregate some stats on the composition of clients on this account
|
||||
|
@ -88,10 +94,12 @@ ClientEngine.prototype = {
|
|||
};
|
||||
|
||||
for (let id in this._store._remoteClients) {
|
||||
let {name, type} = this._store._remoteClients[id];
|
||||
stats.hasMobile = stats.hasMobile || type == DEVICE_TYPE_MOBILE;
|
||||
stats.names.push(name);
|
||||
stats.numClients++;
|
||||
let {name, type, stale} = this._store._remoteClients[id];
|
||||
if (!stale) {
|
||||
stats.hasMobile = stats.hasMobile || type == DEVICE_TYPE_MOBILE;
|
||||
stats.names.push(name);
|
||||
stats.numClients++;
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
|
@ -109,6 +117,9 @@ ClientEngine.prototype = {
|
|||
|
||||
for (let id in this._store._remoteClients) {
|
||||
let record = this._store._remoteClients[id];
|
||||
if (record.stale) {
|
||||
continue; // pretend "stale" records don't exist.
|
||||
}
|
||||
let type = record.type;
|
||||
if (!counts.has(type)) {
|
||||
counts.set(type, 0);
|
||||
|
@ -157,10 +168,6 @@ ClientEngine.prototype = {
|
|||
Svc.Prefs.set("client.type", value);
|
||||
},
|
||||
|
||||
remoteClientExists(id) {
|
||||
return !!this._store._remoteClients[id];
|
||||
},
|
||||
|
||||
getClientName(id) {
|
||||
if (id == this.localID) {
|
||||
return this.localName;
|
||||
|
@ -202,8 +209,10 @@ ClientEngine.prototype = {
|
|||
}
|
||||
}
|
||||
// Bug 1264498: Mobile clients don't remove themselves from the clients
|
||||
// collection when the user disconnects Sync, so we filter out clients
|
||||
// collection when the user disconnects Sync, so we mark as stale clients
|
||||
// with the same name that haven't synced in over a week.
|
||||
// (Note we can't simply delete them, or we re-apply them next sync - see
|
||||
// bug 1287687)
|
||||
delete this._incomingClients[this.localID];
|
||||
let names = new Set([this.localName]);
|
||||
for (let id in this._incomingClients) {
|
||||
|
@ -215,7 +224,7 @@ ClientEngine.prototype = {
|
|||
let remoteAge = AsyncResource.serverTime - this._incomingClients[id];
|
||||
if (remoteAge > STALE_CLIENT_REMOTE_AGE) {
|
||||
this._log.info(`Hiding stale client ${id} with age ${remoteAge}`);
|
||||
this._removeRemoteClient(id);
|
||||
record.stale = true;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
@ -345,6 +354,9 @@ ClientEngine.prototype = {
|
|||
if (!client) {
|
||||
throw new Error("Unknown remote client ID: '" + clientId + "'.");
|
||||
}
|
||||
if (client.stale) {
|
||||
throw new Error("Stale remote client ID: '" + clientId + "'.");
|
||||
}
|
||||
|
||||
let action = {
|
||||
command: command,
|
||||
|
@ -454,8 +466,10 @@ ClientEngine.prototype = {
|
|||
if (clientId) {
|
||||
this._sendCommandToClient(command, args, clientId);
|
||||
} else {
|
||||
for (let id in this._store._remoteClients) {
|
||||
this._sendCommandToClient(command, args, id);
|
||||
for (let [id, record] in Iterator(this._store._remoteClients)) {
|
||||
if (!record.stale) {
|
||||
this._sendCommandToClient(command, args, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -609,6 +623,12 @@ ClientStore.prototype = {
|
|||
// record.formfactor = ""; // Bug 1100722
|
||||
} else {
|
||||
record.cleartext = this._remoteClients[id];
|
||||
if (record.cleartext.stale) {
|
||||
// It's almost certainly a logic error for us to upload a record we
|
||||
// consider stale, so make log noise, but still remove the flag.
|
||||
this._log.error(`Preparing to upload record ${id} that we consider stale`);
|
||||
delete record.cleartext.stale;
|
||||
}
|
||||
}
|
||||
|
||||
return record;
|
||||
|
|
|
@ -568,9 +568,41 @@ add_test(function test_filter_duplicate_names() {
|
|||
deepEqual(user.collection("clients").keys().sort(),
|
||||
[recentID, dupeID, oldID, engine.localID].sort(),
|
||||
"Our record should be uploaded on first sync");
|
||||
|
||||
deepEqual(Object.keys(store.getAllIDs()).sort(),
|
||||
[recentID, oldID, engine.localID].sort(),
|
||||
"Fresh clients should be downloaded on first sync");
|
||||
[recentID, dupeID, oldID, engine.localID].sort(),
|
||||
"Duplicate ID should remain in getAllIDs");
|
||||
ok(engine._store.itemExists(dupeID), "Dupe ID should be considered as existing for Sync methods.");
|
||||
ok(!engine.remoteClientExists(dupeID), "Dupe ID should not be considered as existing for external methods.");
|
||||
|
||||
// dupe desktop should not appear in .deviceTypes.
|
||||
equal(engine.deviceTypes.get("desktop"), 2);
|
||||
equal(engine.deviceTypes.get("mobile"), 1);
|
||||
|
||||
// dupe desktop should not appear in stats
|
||||
deepEqual(engine.stats, {
|
||||
hasMobile: 1,
|
||||
names: [engine.localName, "My Phone", "My old desktop"],
|
||||
numClients: 3,
|
||||
});
|
||||
|
||||
ok(engine.remoteClientExists(oldID), "non-dupe ID should exist.");
|
||||
ok(!engine.remoteClientExists(dupeID), "dupe ID should not exist");
|
||||
equal(engine.remoteClients.length, 2, "dupe should not be in remoteClients");
|
||||
|
||||
// Check that a subsequent Sync doesn't report anything as being processed.
|
||||
let counts;
|
||||
Svc.Obs.add("weave:engine:sync:applied", function observe(subject, data) {
|
||||
Svc.Obs.remove("weave:engine:sync:applied", observe);
|
||||
counts = subject;
|
||||
});
|
||||
|
||||
engine._sync();
|
||||
equal(counts.applied, 0); // We didn't report applying any records.
|
||||
equal(counts.reconciled, 4); // We reported reconcilliation for all records
|
||||
equal(counts.succeeded, 0);
|
||||
equal(counts.failed, 0);
|
||||
equal(counts.newFailed, 0);
|
||||
|
||||
_("Broadcast logout to all clients");
|
||||
engine.sendCommand("logout", []);
|
||||
|
@ -605,6 +637,22 @@ add_test(function test_filter_duplicate_names() {
|
|||
deepEqual(Object.keys(store.getAllIDs()).sort(),
|
||||
[recentID, oldID, dupeID, engine.localID].sort(),
|
||||
"Stale client synced, so it should no longer be marked as a dupe");
|
||||
|
||||
ok(engine.remoteClientExists(dupeID), "Dupe ID should appear as it synced.");
|
||||
|
||||
// Recently synced dupe desktop should appear in .deviceTypes.
|
||||
equal(engine.deviceTypes.get("desktop"), 3);
|
||||
|
||||
// Recently synced dupe desktop should now appear in stats
|
||||
deepEqual(engine.stats, {
|
||||
hasMobile: 1,
|
||||
names: [engine.localName, "My Phone", engine.localName, "My old desktop"],
|
||||
numClients: 4,
|
||||
});
|
||||
|
||||
ok(engine.remoteClientExists(dupeID), "recently synced dupe ID should now exist");
|
||||
equal(engine.remoteClients.length, 3, "recently synced dupe should now be in remoteClients");
|
||||
|
||||
} finally {
|
||||
Svc.Prefs.resetBranch("");
|
||||
Service.recordManager.clearCache();
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
type: testharness
|
||||
[test SelectionStart offset for input]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1287655
|
||||
|
||||
[test SelectionStart offset for textarea]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1287655
|
||||
|
||||
[test SelectionEnd offset for input]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1287655
|
||||
|
||||
[test SelectionEnd offset for textarea]
|
||||
expected: FAIL
|
||||
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1287655
|
||||
|
|
|
@ -6321,14 +6321,6 @@
|
|||
"description": "Number of times the DevTools Computed View has been opened.",
|
||||
"releaseChannelCollection": "opt-out"
|
||||
},
|
||||
"DEVTOOLS_LAYOUTVIEW_OPENED_COUNT": {
|
||||
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "count",
|
||||
"bug_numbers": [1247985],
|
||||
"description": "Number of times the DevTools Layout View has been opened.",
|
||||
"releaseChannelCollection": "opt-out"
|
||||
},
|
||||
"DEVTOOLS_FONTINSPECTOR_OPENED_COUNT": {
|
||||
"alert_emails": ["dev-developer-tools@lists.mozilla.org"],
|
||||
"expires_in_version": "never",
|
||||
|
@ -6602,11 +6594,6 @@
|
|||
"kind": "flag",
|
||||
"description": "Number of users that have opened the DevTools Computed View."
|
||||
},
|
||||
"DEVTOOLS_LAYOUTVIEW_OPENED_PER_USER_FLAG": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "flag",
|
||||
"description": "Number of users that have opened the DevTools Layout View."
|
||||
},
|
||||
"DEVTOOLS_FONTINSPECTOR_OPENED_PER_USER_FLAG": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "flag",
|
||||
|
@ -6813,13 +6800,6 @@
|
|||
"n_buckets": 100,
|
||||
"description": "How long has the computed view been active (seconds)"
|
||||
},
|
||||
"DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 10000000,
|
||||
"n_buckets": 100,
|
||||
"description": "How long has the layout view been active (seconds)"
|
||||
},
|
||||
"DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
|
|
@ -46,14 +46,15 @@ function getLists(prefName) {
|
|||
.map(function(value) { return value.trim(); });
|
||||
}
|
||||
|
||||
// These may be a comma-separated lists of tables.
|
||||
const phishingLists = getLists("urlclassifier.phishTable");
|
||||
const malwareLists = getLists("urlclassifier.malwareTable");
|
||||
const downloadBlockLists = getLists("urlclassifier.downloadBlockTable");
|
||||
const downloadAllowLists = getLists("urlclassifier.downloadAllowTable");
|
||||
const trackingProtectionLists = getLists("urlclassifier.trackingTable");
|
||||
const trackingProtectionWhitelists = getLists("urlclassifier.trackingWhitelistTable");
|
||||
const blockedLists = getLists("urlclassifier.blockedTable");
|
||||
const tablePreferences = [
|
||||
"urlclassifier.phishTable",
|
||||
"urlclassifier.malwareTable",
|
||||
"urlclassifier.downloadBlockTable",
|
||||
"urlclassifier.downloadAllowTable",
|
||||
"urlclassifier.trackingTable",
|
||||
"urlclassifier.trackingWhitelistTable",
|
||||
"urlclassifier.blockedTable"
|
||||
];
|
||||
|
||||
this.SafeBrowsing = {
|
||||
|
||||
|
@ -65,6 +66,8 @@ this.SafeBrowsing = {
|
|||
|
||||
Services.prefs.addObserver("browser.safebrowsing", this.readPrefs.bind(this), false);
|
||||
Services.prefs.addObserver("privacy.trackingprotection", this.readPrefs.bind(this), false);
|
||||
Services.prefs.addObserver("urlclassifier", this.readPrefs.bind(this), false);
|
||||
|
||||
this.readPrefs();
|
||||
this.addMozEntries();
|
||||
|
||||
|
@ -91,26 +94,26 @@ this.SafeBrowsing = {
|
|||
},
|
||||
|
||||
registerTables: function() {
|
||||
for (let i = 0; i < phishingLists.length; ++i) {
|
||||
this.registerTableWithURLs(phishingLists[i]);
|
||||
for (let i = 0; i < this.phishingLists.length; ++i) {
|
||||
this.registerTableWithURLs(this.phishingLists[i]);
|
||||
}
|
||||
for (let i = 0; i < malwareLists.length; ++i) {
|
||||
this.registerTableWithURLs(malwareLists[i]);
|
||||
for (let i = 0; i < this.malwareLists.length; ++i) {
|
||||
this.registerTableWithURLs(this.malwareLists[i]);
|
||||
}
|
||||
for (let i = 0; i < downloadBlockLists.length; ++i) {
|
||||
this.registerTableWithURLs(downloadBlockLists[i]);
|
||||
for (let i = 0; i < this.downloadBlockLists.length; ++i) {
|
||||
this.registerTableWithURLs(this.downloadBlockLists[i]);
|
||||
}
|
||||
for (let i = 0; i < downloadAllowLists.length; ++i) {
|
||||
this.registerTableWithURLs(downloadAllowLists[i]);
|
||||
for (let i = 0; i < this.downloadAllowLists.length; ++i) {
|
||||
this.registerTableWithURLs(this.downloadAllowLists[i]);
|
||||
}
|
||||
for (let i = 0; i < trackingProtectionLists.length; ++i) {
|
||||
this.registerTableWithURLs(trackingProtectionLists[i]);
|
||||
for (let i = 0; i < this.trackingProtectionLists.length; ++i) {
|
||||
this.registerTableWithURLs(this.trackingProtectionLists[i]);
|
||||
}
|
||||
for (let i = 0; i < trackingProtectionWhitelists.length; ++i) {
|
||||
this.registerTableWithURLs(trackingProtectionWhitelists[i]);
|
||||
for (let i = 0; i < this.trackingProtectionWhitelists.length; ++i) {
|
||||
this.registerTableWithURLs(this.trackingProtectionWhitelists[i]);
|
||||
}
|
||||
for (let i = 0; i < blockedLists.length; ++i) {
|
||||
this.registerTableWithURLs(blockedLists[i]);
|
||||
for (let i = 0; i < this.blockedLists.length; ++i) {
|
||||
this.registerTableWithURLs(this.blockedLists[i]);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -121,6 +124,14 @@ this.SafeBrowsing = {
|
|||
trackingEnabled: false,
|
||||
blockedEnabled: false,
|
||||
|
||||
phishingLists: [],
|
||||
malwareLists: [],
|
||||
downloadBlockLists: [],
|
||||
downloadAllowLists: [],
|
||||
trackingProtectionLists: [],
|
||||
trackingProtectionWhitelists: [],
|
||||
blockedLists: [],
|
||||
|
||||
updateURL: null,
|
||||
gethashURL: null,
|
||||
|
||||
|
@ -166,6 +177,15 @@ this.SafeBrowsing = {
|
|||
this.malwareEnabled = Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled");
|
||||
this.trackingEnabled = Services.prefs.getBoolPref("privacy.trackingprotection.enabled") || Services.prefs.getBoolPref("privacy.trackingprotection.pbmode.enabled");
|
||||
this.blockedEnabled = Services.prefs.getBoolPref("browser.safebrowsing.blockedURIs.enabled");
|
||||
|
||||
[this.phishingLists,
|
||||
this.malwareLists,
|
||||
this.downloadBlockLists,
|
||||
this.downloadAllowLists,
|
||||
this.trackingProtectionLists,
|
||||
this.trackingProtectionWhitelists,
|
||||
this.blockedLists] = tablePreferences.map(getLists);
|
||||
|
||||
this.updateProviderURLs();
|
||||
this.registerTables();
|
||||
|
||||
|
@ -247,53 +267,53 @@ this.SafeBrowsing = {
|
|||
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
|
||||
getService(Ci.nsIUrlListManager);
|
||||
|
||||
for (let i = 0; i < phishingLists.length; ++i) {
|
||||
for (let i = 0; i < this.phishingLists.length; ++i) {
|
||||
if (this.phishingEnabled) {
|
||||
listManager.enableUpdate(phishingLists[i]);
|
||||
listManager.enableUpdate(this.phishingLists[i]);
|
||||
} else {
|
||||
listManager.disableUpdate(phishingLists[i]);
|
||||
listManager.disableUpdate(this.phishingLists[i]);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < malwareLists.length; ++i) {
|
||||
for (let i = 0; i < this.malwareLists.length; ++i) {
|
||||
if (this.malwareEnabled) {
|
||||
listManager.enableUpdate(malwareLists[i]);
|
||||
listManager.enableUpdate(this.malwareLists[i]);
|
||||
} else {
|
||||
listManager.disableUpdate(malwareLists[i]);
|
||||
listManager.disableUpdate(this.malwareLists[i]);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < downloadBlockLists.length; ++i) {
|
||||
for (let i = 0; i < this.downloadBlockLists.length; ++i) {
|
||||
if (this.malwareEnabled) {
|
||||
listManager.enableUpdate(downloadBlockLists[i]);
|
||||
listManager.enableUpdate(this.downloadBlockLists[i]);
|
||||
} else {
|
||||
listManager.disableUpdate(downloadBlockLists[i]);
|
||||
listManager.disableUpdate(this.downloadBlockLists[i]);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < downloadAllowLists.length; ++i) {
|
||||
for (let i = 0; i < this.downloadAllowLists.length; ++i) {
|
||||
if (this.malwareEnabled) {
|
||||
listManager.enableUpdate(downloadAllowLists[i]);
|
||||
listManager.enableUpdate(this.downloadAllowLists[i]);
|
||||
} else {
|
||||
listManager.disableUpdate(downloadAllowLists[i]);
|
||||
listManager.disableUpdate(this.downloadAllowLists[i]);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < trackingProtectionLists.length; ++i) {
|
||||
for (let i = 0; i < this.trackingProtectionLists.length; ++i) {
|
||||
if (this.trackingEnabled) {
|
||||
listManager.enableUpdate(trackingProtectionLists[i]);
|
||||
listManager.enableUpdate(this.trackingProtectionLists[i]);
|
||||
} else {
|
||||
listManager.disableUpdate(trackingProtectionLists[i]);
|
||||
listManager.disableUpdate(this.trackingProtectionLists[i]);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < trackingProtectionWhitelists.length; ++i) {
|
||||
for (let i = 0; i < this.trackingProtectionWhitelists.length; ++i) {
|
||||
if (this.trackingEnabled) {
|
||||
listManager.enableUpdate(trackingProtectionWhitelists[i]);
|
||||
listManager.enableUpdate(this.trackingProtectionWhitelists[i]);
|
||||
} else {
|
||||
listManager.disableUpdate(trackingProtectionWhitelists[i]);
|
||||
listManager.disableUpdate(this.trackingProtectionWhitelists[i]);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < blockedLists.length; ++i) {
|
||||
for (let i = 0; i < this.blockedLists.length; ++i) {
|
||||
if (this.blockedEnabled) {
|
||||
listManager.enableUpdate(blockedLists[i]);
|
||||
listManager.enableUpdate(this.blockedLists[i]);
|
||||
} else {
|
||||
listManager.disableUpdate(blockedLists[i]);
|
||||
listManager.disableUpdate(this.blockedLists[i]);
|
||||
}
|
||||
}
|
||||
listManager.maybeToggleUpdateChecking();
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var scriptItem = "untouched";
|
||||
|
||||
function checkLoads() {
|
||||
// Make sure the javascript did not load.
|
||||
window.parent.is(scriptItem, "untouched", "Should not load bad javascript");
|
||||
|
||||
// Call parent.loadTestFrame again to test classification metadata in HTTP
|
||||
// cache entries.
|
||||
if (window.parent.firstLoad) {
|
||||
window.parent.info("Reloading from cache...");
|
||||
window.parent.firstLoad = false;
|
||||
window.parent.loadTestFrame();
|
||||
return;
|
||||
}
|
||||
|
||||
// End (parent) test.
|
||||
window.parent.SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- Try loading from a malware javascript URI -->
|
||||
<script type="text/javascript" src="http://bug1281083.example.com/tests/toolkit/components/url-classifier/tests/mochitest/evil.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="checkLoads()">
|
||||
</body>
|
||||
</html>
|
|
@ -4,6 +4,7 @@ support-files =
|
|||
allowlistAnnotatedFrame.html
|
||||
classifiedAnnotatedFrame.html
|
||||
classifiedAnnotatedPBFrame.html
|
||||
bug_1281083.html
|
||||
|
||||
[test_lookup_system_principal.html]
|
||||
[test_classified_annotations.html]
|
||||
|
@ -18,3 +19,4 @@ tags = trackingprotection
|
|||
[test_trackingprotection_whitelist.html]
|
||||
tags = trackingprotection
|
||||
[test_donottrack.html]
|
||||
[test_classifier_changetablepref.html]
|
||||
|
|
|
@ -22,6 +22,7 @@ support-files =
|
|||
basic.vtt
|
||||
dnt.html
|
||||
dnt.sjs
|
||||
update.sjs
|
||||
|
||||
[test_classifier.html]
|
||||
skip-if = (os == 'linux' && debug) #Bug 1199778
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1281083 - Changing the urlclassifier.*Table prefs doesn't take effect before the next browser restart.</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="classifierHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const testTable = "moz-track-digest256";
|
||||
const UPDATE_URL = "http://mochi.test:8888/tests/toolkit/components/url-classifier/tests/mochitest/update.sjs";
|
||||
|
||||
var Cc = SpecialPowers.Cc;
|
||||
var Ci = SpecialPowers.Ci;
|
||||
|
||||
var prefService = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefService);
|
||||
|
||||
var timer = Cc["@mozilla.org/timer;1"]
|
||||
.createInstance(Ci.nsITimer);
|
||||
|
||||
// If default preference contain the table we want to test,
|
||||
// We should change test table to a different one.
|
||||
var trackingTables = SpecialPowers.getCharPref("urlclassifier.trackingTable").split(",");
|
||||
ok(!trackingTables.includes(testTable), "test table should not be in the preference");
|
||||
|
||||
var listmanager = Cc["@mozilla.org/url-classifier/listmanager;1"].
|
||||
getService(Ci.nsIUrlListManager);
|
||||
|
||||
is(listmanager.getGethashUrl(testTable), "",
|
||||
"gethash url for test table should be empty before setting to preference");
|
||||
|
||||
function loadTestFrame() {
|
||||
// gethash url of test table "moz-track-digest256" should be updated
|
||||
// after setting preference.
|
||||
var url = listmanager.getGethashUrl(testTable);
|
||||
var expected = SpecialPowers.getCharPref("browser.safebrowsing.provider.mozilla.gethashURL");
|
||||
|
||||
is(url, expected, testTable + " matches its gethash url");
|
||||
|
||||
// Trigger update
|
||||
listmanager.disableUpdate(testTable);
|
||||
listmanager.enableUpdate(testTable);
|
||||
listmanager.maybeToggleUpdateChecking();
|
||||
|
||||
// We wait until "nextupdattime" was set as a signal that update is complete.
|
||||
waitForUpdateSuccess(function() {
|
||||
document.getElementById("testFrame").src = "bug_1281083.html";
|
||||
});
|
||||
}
|
||||
|
||||
function waitForUpdateSuccess(callback) {
|
||||
let nextupdatetime =
|
||||
SpecialPowers.getCharPref("browser.safebrowsing.provider.mozilla.nextupdatetime");
|
||||
|
||||
if (nextupdatetime !== "1") {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
timer.initWithCallback(function() {
|
||||
waitForUpdateSuccess(callback);
|
||||
}, 10, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
function addCompletionToServer(list, url) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var listParam = "list=" + list;
|
||||
var fullhashParam = "fullhash=" + hash(url);
|
||||
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open("PUT", UPDATE_URL + "?" +
|
||||
listParam + "&" +
|
||||
fullhashParam, true);
|
||||
xhr.setRequestHeader("Content-Type", "text/plain");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
function hash(str) {
|
||||
function bytesFromString(str) {
|
||||
var converter =
|
||||
SpecialPowers.Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(SpecialPowers.Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
return converter.convertToByteArray(str);
|
||||
}
|
||||
|
||||
var hasher = SpecialPowers.Cc["@mozilla.org/security/hash;1"]
|
||||
.createInstance(SpecialPowers.Ci.nsICryptoHash);
|
||||
|
||||
var data = bytesFromString(str);
|
||||
hasher.init(hasher.SHA256);
|
||||
hasher.update(data, data.length);
|
||||
|
||||
return hasher.finish(true);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
/**
|
||||
* In this test we try to modify only urlclassifier.*Table preference to see if
|
||||
* url specified in the table will be blocked after update.
|
||||
*/
|
||||
var pushPrefPromise = SpecialPowers.pushPrefEnv(
|
||||
{"set" : [["urlclassifier.trackingTable", testTable]]});
|
||||
|
||||
// To make sure url is not blocked by an already blocked url.
|
||||
// Here we use non-tracking.example.com as a tracked url.
|
||||
// Since this table is only used in this bug, so it won't affect other testcases.
|
||||
var addCompletePromise =
|
||||
addCompletionToServer(testTable, "bug1281083.example.com/");
|
||||
|
||||
Promise.all([pushPrefPromise, addCompletePromise])
|
||||
.then(() => {
|
||||
loadTestFrame();
|
||||
});
|
||||
}
|
||||
|
||||
// Set nextupdatetime to 1 to trigger an update
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{"set" : [["privacy.trackingprotection.enabled", true],
|
||||
["channelclassifier.allowlist_example", true],
|
||||
["browser.safebrowsing.provider.mozilla.nextupdatetime", "1"],
|
||||
["browser.safebrowsing.provider.mozilla.lists", testTable],
|
||||
["browser.safebrowsing.provider.mozilla.updateURL", UPDATE_URL]]},
|
||||
runTest);
|
||||
|
||||
// Expected finish() call is in "bug_1281083.html".
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
<iframe id="testFrame" width="100%" height="100%" onload=""></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
const CC = Components.Constructor;
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream");
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var query = {};
|
||||
request.queryString.split('&').forEach(function (val) {
|
||||
var idx = val.indexOf('=');
|
||||
query[val.slice(0, idx)] = unescape(val.slice(idx + 1));
|
||||
});
|
||||
|
||||
// Store fullhash in the server side.
|
||||
if ("list" in query && "fullhash" in query) {
|
||||
// In the server side we will store:
|
||||
// 1. All the full hashes for a given list
|
||||
// 2. All the lists we have right now
|
||||
// data is separate by '\n'
|
||||
let list = query["list"];
|
||||
let hashes = getState(list);
|
||||
|
||||
let hash = base64ToString(query["fullhash"]);
|
||||
hashes += hash + "\n";
|
||||
setState(list, hashes);
|
||||
|
||||
let lists = getState("lists");
|
||||
if (lists.indexOf(list) == -1) {
|
||||
lists += list + "\n";
|
||||
setState("lists", lists);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var body = new BinaryInputStream(request.bodyInputStream);
|
||||
var avail;
|
||||
var bytes = [];
|
||||
|
||||
while ((avail = body.available()) > 0) {
|
||||
Array.prototype.push.apply(bytes, body.readByteArray(avail));
|
||||
}
|
||||
|
||||
var responseBody = parseV2Request(bytes);
|
||||
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.write(responseBody);
|
||||
}
|
||||
|
||||
function parseV2Request(bytes) {
|
||||
var table = String.fromCharCode.apply(this, bytes).slice(0,-2);
|
||||
|
||||
var ret = "";
|
||||
getState("lists").split("\n").forEach(function(list) {
|
||||
if (list == table) {
|
||||
var completions = getState(list).split("\n");
|
||||
ret += "n:1000\n"
|
||||
ret += "i:" + list + "\n";
|
||||
ret += "a:1:32:" + 32*(completions.length - 1) + "\n";
|
||||
|
||||
for (var completion of completions) {
|
||||
ret += completion;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Convert Base64 data to a string */
|
||||
const toBinaryTable = [
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
|
||||
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
|
||||
];
|
||||
const base64Pad = '=';
|
||||
|
||||
function base64ToString(data) {
|
||||
var result = '';
|
||||
var leftbits = 0; // number of bits decoded, but yet to be appended
|
||||
var leftdata = 0; // bits decoded, but yet to be appended
|
||||
|
||||
// Convert one by one.
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
|
||||
var padding = (data[i] == base64Pad);
|
||||
// Skip illegal characters and whitespace
|
||||
if (c == -1) continue;
|
||||
|
||||
// Collect data into leftdata, update bitcount
|
||||
leftdata = (leftdata << 6) | c;
|
||||
leftbits += 6;
|
||||
|
||||
// If we have 8 or more bits, append 8 bits to the result
|
||||
if (leftbits >= 8) {
|
||||
leftbits -= 8;
|
||||
// Append if not padding.
|
||||
if (!padding)
|
||||
result += String.fromCharCode((leftdata >> leftbits) & 0xff);
|
||||
leftdata &= (1 << leftbits) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any bits left, the base64 string was corrupted
|
||||
if (leftbits)
|
||||
throw Components.Exception('Corrupted base64 string');
|
||||
|
||||
return result;
|
||||
}
|
|
@ -316,27 +316,35 @@
|
|||
}
|
||||
]]></handler>
|
||||
<handler event="popuphidden"><![CDATA[
|
||||
function doFocus() {
|
||||
// Focus was set on an element inside this panel,
|
||||
// so we need to move it back to where it was previously
|
||||
try {
|
||||
let fm = Components.classes["@mozilla.org/focus-manager;1"]
|
||||
.getService(Components.interfaces.nsIFocusManager);
|
||||
fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
|
||||
} catch(e) {
|
||||
prevFocus.focus();
|
||||
}
|
||||
}
|
||||
var currentFocus = this._currentFocus;
|
||||
var prevFocus = this._prevFocus ? this._prevFocus.get() : null;
|
||||
this._currentFocus = null;
|
||||
this._prevFocus = null;
|
||||
if (prevFocus && currentFocus && this.getAttribute("norestorefocus") != "true") {
|
||||
if (prevFocus && this.getAttribute("norestorefocus") != "true") {
|
||||
// Try to restore focus
|
||||
try {
|
||||
if (document.commandDispatcher.focusedWindow != window)
|
||||
return; // Focus has already been set to a window outside of this panel
|
||||
} catch(ex) {}
|
||||
|
||||
if (!currentFocus) {
|
||||
doFocus();
|
||||
return;
|
||||
}
|
||||
while (currentFocus) {
|
||||
if (currentFocus == this) {
|
||||
// Focus was set on an element inside this panel,
|
||||
// so we need to move it back to where it was previously
|
||||
try {
|
||||
let fm = Components.classes["@mozilla.org/focus-manager;1"]
|
||||
.getService(Components.interfaces.nsIFocusManager);
|
||||
fm.setFocus(prevFocus, fm.FLAG_NOSCROLL);
|
||||
} catch(e) {
|
||||
prevFocus.focus();
|
||||
}
|
||||
doFocus();
|
||||
return;
|
||||
}
|
||||
currentFocus = currentFocus.parentNode;
|
||||
|
|