merge fx-team to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-07-20 11:17:45 +02:00
Родитель 668b63cbb9 b81eed1658
Коммит ac3f25cbe3
89 изменённых файлов: 1731 добавлений и 587 удалений

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

@ -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

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

До

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

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

До

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

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

До

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

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

До

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

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

До

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

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

До

Ширина:  |  Высота:  |  Размер: 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><!--
-->=&quot;<!--
--><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;