Merge m-c to graphics

MozReview-Commit-ID: 5zsIClrx1FB
This commit is contained in:
Kartikaya Gupta 2017-04-21 10:01:47 -04:00
commit 2e1380aecf
1928 changed files with 131826 additions and 75643 deletions

View File

@ -21,6 +21,16 @@ jobs:
mozilla-aurora: [{hour: 7, minute: 45}] # Buildbot uses minute 40 mozilla-aurora: [{hour: 7, minute: 45}] # Buildbot uses minute 40
# No default # No default
- name: nightly-desktop-osx
job:
type: decision-task
treeherder-symbol: Nd-OSX
triggered-by: nightly
target-tasks-method: nightly_macosx
run-on-projects:
- date
when: [] # never (hook only)
- name: nightly-android - name: nightly-android
job: job:
type: decision-task type: decision-task

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla-config.h"
#include "AccessibleHandler.h" #include "AccessibleHandler.h"
import "ocidl.idl"; import "ocidl.idl";

View File

@ -20,7 +20,7 @@ export:: $(MIDL_GENERATED_FILES)
$(MIDL_GENERATED_FILES): midl_done $(MIDL_GENERATED_FILES): midl_done
midl_done: HandlerData.acf HandlerData.idl midl_done: HandlerData.acf HandlerData.idl
$(MIDL) $(MIDL_FLAGS) $(DEFINES) -I $(IA2DIR) -I $(MSAADIR) -Oicf -acf $(srcdir)/HandlerData.acf $(srcdir)/HandlerData.idl $(MIDL) $(MIDL_FLAGS) $(DEFINES) -I $(topobjdir) -I $(DIST)/include -I $(IA2DIR) -I $(MSAADIR) -Oicf -acf $(srcdir)/HandlerData.acf $(srcdir)/HandlerData.idl
touch $@ touch $@
INSTALL_TARGETS += midl INSTALL_TARGETS += midl

View File

@ -1613,6 +1613,9 @@ pref("browser.formautofill.experimental", false);
pref("browser.formautofill.enabled", false); pref("browser.formautofill.enabled", false);
pref("browser.formautofill.loglevel", "Warn"); pref("browser.formautofill.loglevel", "Warn");
// Whether or not to restore a session with lazy-browser tabs.
pref("browser.sessionstore.restore_tabs_lazily", true);
// Enable safebrowsing v4 tables (suffixed by "-proto") update. // Enable safebrowsing v4 tables (suffixed by "-proto") update.
#ifdef NIGHTLY_BUILD #ifdef NIGHTLY_BUILD
pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,goog-malware-proto,goog-unwanted-proto,test-malware-simple,test-unwanted-simple"); pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,goog-malware-proto,goog-unwanted-proto,test-malware-simple,test-unwanted-simple");

View File

@ -636,7 +636,8 @@ var FullScreen = {
} }
} }
ToolbarIconColor.inferFromText(); ToolbarIconColor.inferFromText("fullscreen", aEnterFS);
// For Lion fullscreen, all fullscreen controls are hidden, don't // For Lion fullscreen, all fullscreen controls are hidden, don't
// bother to touch them. If we don't stop here, the following code // bother to touch them. If we don't stop here, the following code

View File

@ -247,7 +247,8 @@ var TabsInTitlebar = {
menubar.style.paddingBottom = ""; menubar.style.paddingBottom = "";
} }
ToolbarIconColor.inferFromText(); ToolbarIconColor.inferFromText("tabsintitlebar", TabsInTitlebar.enabled);
if (CustomizationHandler.isCustomizing()) { if (CustomizationHandler.isCustomizing()) {
gCustomizeMode.updateLWTStyling(); gCustomizeMode.updateLWTStyling();
} }

View File

@ -5408,8 +5408,6 @@ function setToolbarVisibility(toolbar, isVisible, persist = true) {
PlacesToolbarHelper.init(); PlacesToolbarHelper.init();
BookmarkingUI.onToolbarVisibilityChange(); BookmarkingUI.onToolbarVisibilityChange();
if (isVisible)
ToolbarIconColor.inferFromText();
} }
var TabletModeUpdater = { var TabletModeUpdater = {
@ -7686,7 +7684,7 @@ var gIdentityHandler = {
let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip"); let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip");
button.setAttribute("tooltiptext", tooltiptext); button.setAttribute("tooltiptext", tooltiptext);
button.addEventListener("command", () => { button.addEventListener("command", () => {
let browser = gBrowser.selectedBrowser; let browser = gBrowser.selectedBrowser;
// Only resize the window if the reload hint was previously hidden. // Only resize the window if the reload hint was previously hidden.
this._handleHeightChange(() => this._permissionList.removeChild(container), this._handleHeightChange(() => this._permissionList.removeChild(container),
this._permissionReloadHint.hasAttribute("hidden")); this._permissionReloadHint.hasAttribute("hidden"));
@ -8219,8 +8217,8 @@ var MousePosTracker = {
handleEvent(event) { handleEvent(event) {
var fullZoom = this._windowUtils.fullZoom; var fullZoom = this._windowUtils.fullZoom;
this._x = event.clientX / fullZoom; this._x = event.screenX / fullZoom - window.mozInnerScreenX;
this._y = event.clientY / fullZoom; this._y = event.screenY / fullZoom - window.mozInnerScreenY;
this._listeners.forEach(function(listener) { this._listeners.forEach(function(listener) {
try { try {
@ -8253,18 +8251,25 @@ var MousePosTracker = {
}; };
var ToolbarIconColor = { var ToolbarIconColor = {
_windowState: {
"active": false,
"fullscreen": false,
"tabsintitlebar": false
},
init() { init() {
this._initialized = true; this._initialized = true;
window.addEventListener("activate", this); window.addEventListener("activate", this);
window.addEventListener("deactivate", this); window.addEventListener("deactivate", this);
window.addEventListener("toolbarvisibilitychange", this);
Services.obs.addObserver(this, "lightweight-theme-styling-update"); Services.obs.addObserver(this, "lightweight-theme-styling-update");
// If the window isn't active now, we assume that it has never been active // If the window isn't active now, we assume that it has never been active
// before and will soon become active such that inferFromText will be // before and will soon become active such that inferFromText will be
// called from the initial activate event. // called from the initial activate event.
if (Services.focus.activeWindow == window) if (Services.focus.activeWindow == window) {
this.inferFromText(); this.inferFromText("activate");
}
}, },
uninit() { uninit() {
@ -8272,14 +8277,18 @@ var ToolbarIconColor = {
window.removeEventListener("activate", this); window.removeEventListener("activate", this);
window.removeEventListener("deactivate", this); window.removeEventListener("deactivate", this);
window.removeEventListener("toolbarvisibilitychange", this);
Services.obs.removeObserver(this, "lightweight-theme-styling-update"); Services.obs.removeObserver(this, "lightweight-theme-styling-update");
}, },
handleEvent(event) { handleEvent(event) {
switch (event.type) { switch (event.type) {
case "activate": case "activate": // falls through
case "deactivate": case "deactivate":
this.inferFromText(); this.inferFromText(event.type);
break;
case "toolbarvisibilitychange":
this.inferFromText(event.type, event.visible);
break; break;
} }
}, },
@ -8289,32 +8298,66 @@ var ToolbarIconColor = {
case "lightweight-theme-styling-update": case "lightweight-theme-styling-update":
// inferFromText needs to run after LightweightThemeConsumer.jsm's // inferFromText needs to run after LightweightThemeConsumer.jsm's
// lightweight-theme-styling-update observer. // lightweight-theme-styling-update observer.
setTimeout(() => { this.inferFromText(); }, 0); setTimeout(() => {
this.inferFromText(aTopic);
}, 0);
break; break;
} }
}, },
inferFromText() { // a cache of luminance values for each toolbar
// to avoid unnecessary calls to getComputedStyle
_toolbarLuminanceCache: new Map(),
inferFromText(reason, reasonValue) {
if (!this._initialized) if (!this._initialized)
return; return;
function parseRGB(aColorString) { function parseRGB(aColorString) {
let rgb = aColorString.match(/^rgba?\((\d+), (\d+), (\d+)/); let rgb = aColorString.match(/^rgba?\((\d+), (\d+), (\d+)/);
rgb.shift(); rgb.shift();
return rgb.map(x => parseInt(x)); return rgb.map(x => parseInt(x));
} }
switch (reason) {
case "activate": // falls through
case "deactivate":
this._windowState.active = (reason === "activate");
break;
case "fullscreen":
this._windowState.fullscreen = reasonValue;
break;
case "lightweight-theme-styling-update":
// theme change, we'll need to recalculate all color values
this._toolbarLuminanceCache.clear();
break;
case "toolbarvisibilitychange":
// toolbar changes dont require reset of the cached color values
break;
case "tabsintitlebar":
this._windowState.tabsintitlebar = reasonValue;
break;
}
let toolbarSelector = "#navigator-toolbox > toolbar:not([collapsed=true]):not(#addon-bar)"; let toolbarSelector = "#navigator-toolbox > toolbar:not([collapsed=true]):not(#addon-bar)";
if (AppConstants.platform == "macosx") if (AppConstants.platform == "macosx")
toolbarSelector += ":not([type=menubar])"; toolbarSelector += ":not([type=menubar])";
// The getComputedStyle calls and setting the brighttext are separated in // The getComputedStyle calls and setting the brighttext are separated in
// two loops to avoid flushing layout and making it dirty repeatedly. // two loops to avoid flushing layout and making it dirty repeatedly.
let cachedLuminances = this._toolbarLuminanceCache;
let luminances = new Map; let luminances = new Map();
for (let toolbar of document.querySelectorAll(toolbarSelector)) { for (let toolbar of document.querySelectorAll(toolbarSelector)) {
let [r, g, b] = parseRGB(getComputedStyle(toolbar).color); // toolbars *should* all have ids, but guard anyway to avoid blowing up
let luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b; let cacheKey = toolbar.id && toolbar.id + JSON.stringify(this._windowState);
// lookup cached luminance value for this toolbar in this window state
let luminance = cacheKey && cachedLuminances.get(cacheKey);
if (isNaN(luminance)) {
let [r, g, b] = parseRGB(getComputedStyle(toolbar).color);
luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b;
if (cacheKey) {
cachedLuminances.set(cacheKey, luminance);
}
}
luminances.set(toolbar, luminance); luminances.set(toolbar, luminance);
} }

View File

@ -2034,7 +2034,8 @@
"addProgressListener", "removeProgressListener", "audioPlaybackStarted", "addProgressListener", "removeProgressListener", "audioPlaybackStarted",
"audioPlaybackStopped", "adjustPriority", "pauseMedia", "stopMedia", "audioPlaybackStopped", "adjustPriority", "pauseMedia", "stopMedia",
"blockMedia", "resumeMedia", "mute", "unmute", "blockedPopups", "lastURI", "blockMedia", "resumeMedia", "mute", "unmute", "blockedPopups", "lastURI",
"purgeSessionHistory", "stopScroll", "startScroll" "purgeSessionHistory", "stopScroll", "startScroll",
"userTypedValue", "userTypedClear"
]</field> ]</field>
<method name="_createLazyBrowser"> <method name="_createLazyBrowser">
@ -2052,11 +2053,51 @@
switch (name) { switch (name) {
case "permitUnload": case "permitUnload":
getter = () => { getter = () => {
return function() { return () => {
return { permitUnload: true, timedOut: false }; return { permitUnload: true, timedOut: false };
}; };
}; };
break; break;
case "reload":
case "reloadWithFlags":
getter = () => {
return (params) => {
// Wait for load handler to be instantiated before
// initializing the reload.
aTab.addEventListener("SSTabRestoring", () => {
browser[name](params);
}, { once: true });
gBrowser._insertBrowser(aTab);
};
};
break;
case "isRemoteBrowser":
getter = () => {
return browser.getAttribute("remote") == "true";
};
break;
case "audioMuted":
getter = () => {
return false;
};
break;
case "currentURI":
getter = () => {
let url = SessionStore.getLazyTabValue(aTab, "url");
return Services.io.newURI(url);
};
break;
case "contentTitle":
getter = () => {
return SessionStore.getLazyTabValue(aTab, "title");
};
break;
case "userTypedValue":
case "userTypedClear":
getter = () => {
return SessionStore.getLazyTabValue(aTab, name);
};
break;
default: default:
getter = () => { getter = () => {
this._insertBrowser(aTab); this._insertBrowser(aTab);
@ -2084,9 +2125,8 @@
<![CDATA[ <![CDATA[
"use strict"; "use strict";
// If browser is already inserted, or aTab doesn't have a // If browser is already inserted don't do anything.
// browser, don't do anything. if (aTab.linkedPanel) {
if (aTab.linkedPanel || !aTab.linkedBrowser) {
return; return;
} }
@ -4876,7 +4916,8 @@
tab.linkedBrowser && tab.linkedBrowser &&
tab.linkedBrowser.isRemoteBrowser) { tab.linkedBrowser.isRemoteBrowser) {
label += " - e10s"; label += " - e10s";
if (Services.appinfo.maxWebProcessCount > 1) { if (tab.linkedBrowser.frameLoader &&
Services.appinfo.maxWebProcessCount > 1) {
label += " (" + tab.linkedBrowser.frameLoader.tabParent.osPid + ")"; label += " (" + tab.linkedBrowser.frameLoader.tabParent.osPid + ")";
} }
} }
@ -7245,6 +7286,11 @@
<parameter name="aMuteReason"/> <parameter name="aMuteReason"/>
<body> <body>
<![CDATA[ <![CDATA[
// Do not attempt to toggle mute state if browser is lazy.
if (!this.linkedPanel) {
return;
}
let tabContainer = this.parentNode; let tabContainer = this.parentNode;
let browser = this.linkedBrowser; let browser = this.linkedBrowser;
let modifiedAttrs = []; let modifiedAttrs = [];

View File

@ -254,8 +254,6 @@ var whitelist = new Set([
{file: "resource://gre/modules/addons/AddonLogging.jsm"}, {file: "resource://gre/modules/addons/AddonLogging.jsm"},
// Bug 1351637 // Bug 1351637
{file: "resource://gre/modules/sdk/bootstrap.js"}, {file: "resource://gre/modules/sdk/bootstrap.js"},
// Bug 1351657
{file: "resource://gre/res/langGroups.properties", platforms: ["macosx"]},
].filter(item => ].filter(item =>
("isFromDevTools" in item) == isDevtools && ("isFromDevTools" in item) == isDevtools &&

View File

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"plugin:mozilla/browser-test"
]
};

View File

@ -0,0 +1,2 @@
[DEFAULT]
[browser_toolbariconcolor_restyles.js]

View File

@ -0,0 +1,43 @@
"use strict";
/**
* Ensure redundant style flushes are not triggered when switching between windows
*/
add_task(function* test_toolbar_element_restyles_on_activation() {
let restyles = {
win1: {},
win2: {}
};
// create a window and snapshot the elementsStyled
let win1 = yield BrowserTestUtils.openNewBrowserWindow();
yield new Promise(resolve => waitForFocus(resolve, win1));
// create a 2nd window and snapshot the elementsStyled
let win2 = yield BrowserTestUtils.openNewBrowserWindow();
yield new Promise(resolve => waitForFocus(resolve, win2));
let utils1 = SpecialPowers.getDOMWindowUtils(win1);
restyles.win1.initial = utils1.elementsRestyled;
let utils2 = SpecialPowers.getDOMWindowUtils(win2);
restyles.win2.initial = utils2.elementsRestyled;
// switch back to 1st window, and snapshot elementsStyled
win1.focus();
restyles.win1.activate = utils1.elementsRestyled;
restyles.win2.deactivate = utils2.elementsRestyled;
// switch back to 2nd window, and snapshot elementsStyled
win2.focus();
restyles.win2.activate = utils2.elementsRestyled;
restyles.win1.deactivate = utils1.elementsRestyled;
is(restyles.win1.activate - restyles.win1.deactivate, 0,
"No elements restyled when re-activating/deactivating a window");
is(restyles.win2.activate - restyles.win2.deactivate, 0,
"No elements restyled when re-activating/deactivating a window");
yield BrowserTestUtils.closeWindow(win1);
yield BrowserTestUtils.closeWindow(win2);
});

View File

@ -35,6 +35,7 @@ BROWSER_CHROME_MANIFESTS += [
'content/test/urlbar/browser.ini', 'content/test/urlbar/browser.ini',
'content/test/webextensions/browser.ini', 'content/test/webextensions/browser.ini',
'content/test/webrtc/browser.ini', 'content/test/webrtc/browser.ini',
'content/test/windows/browser.ini',
] ]
if CONFIG['MOZ_UPDATER']: if CONFIG['MOZ_UPDATER']:

View File

@ -1492,7 +1492,8 @@ var CustomizableUIInternal = {
let anchor = aNode; let anchor = aNode;
if (area != CustomizableUI.AREA_PANEL) { if (area != CustomizableUI.AREA_PANEL) {
let wrapper = this.wrapWidget(aWidget.id).forWindow(ownerWindow); let wrapper = this.wrapWidget(aWidget.id).forWindow(ownerWindow);
if (wrapper && wrapper.anchor) {
if (wrapper && !wrapper.overflowed && wrapper.anchor) {
this.hidePanelForNode(aNode); this.hidePanelForNode(aNode);
anchor = wrapper.anchor; anchor = wrapper.anchor;
} }
@ -4118,7 +4119,9 @@ OverflowableToolbar.prototype = {
return new Promise(resolve => { return new Promise(resolve => {
let doc = this._panel.ownerDocument; let doc = this._panel.ownerDocument;
this._panel.hidden = false; this._panel.hidden = false;
let contextMenu = doc.getElementById(this._panel.getAttribute("context")); let mainViewId = this._panel.querySelector("panelmultiview").getAttribute("mainViewId");
let mainView = doc.getElementById(mainViewId);
let contextMenu = doc.getElementById(mainView.getAttribute("context"));
gELS.addSystemEventListener(contextMenu, "command", this, true); gELS.addSystemEventListener(contextMenu, "command", this, true);
let anchor = doc.getAnonymousElementByAttribute(this._chevron, "class", "toolbarbutton-icon"); let anchor = doc.getAnonymousElementByAttribute(this._chevron, "class", "toolbarbutton-icon");
this._panel.openPopup(anchor || this._chevron); this._panel.openPopup(anchor || this._chevron);

View File

@ -377,13 +377,17 @@
role="group" role="group"
type="arrow" type="arrow"
noautofocus="true" noautofocus="true"
context="toolbar-context-menu"
position="bottomcenter topright" position="bottomcenter topright"
hidden="true"> hidden="true">
<vbox id="widget-overflow-scroller"> <panelmultiview mainViewId="widget-overflow-mainView">
<vbox id="widget-overflow-list" class="widget-overflow-list" <panelview id="widget-overflow-mainView"
overflowfortoolbar="nav-bar"/> context="toolbar-context-menu">
</vbox> <vbox id="widget-overflow-scroller">
<vbox id="widget-overflow-list" class="widget-overflow-list"
overflowfortoolbar="nav-bar"/>
</vbox>
</panelview>
</panelmultiview>
</panel> </panel>
<panel id="customization-tipPanel" <panel id="customization-tipPanel"

View File

@ -431,8 +431,9 @@ const PanelUI = {
return; return;
} }
if (aPlacementArea == CustomizableUI.AREA_PANEL) { let container = aAnchor.closest("panelmultiview");
this.multiView.showSubView(aViewId, aAnchor); if (container) {
container.showSubView(aViewId, aAnchor);
} else if (!aAnchor.open) { } else if (!aAnchor.open) {
aAnchor.open = true; aAnchor.open = true;

View File

@ -178,6 +178,14 @@
<body><![CDATA[ <body><![CDATA[
Task.spawn(function*() { Task.spawn(function*() {
let viewNode = this.querySelector("#" + aViewId); let viewNode = this.querySelector("#" + aViewId);
if (!viewNode) {
viewNode = document.getElementById(aViewId);
if (viewNode) {
this._subViews.appendChild(viewNode);
} else {
throw new Error(`Subview ${aViewId} doesn't exist!`);
}
}
viewNode.setAttribute("current", true); viewNode.setAttribute("current", true);
// Emit the ViewShowing event so that the widget definition has a chance // Emit the ViewShowing event so that the widget definition has a chance
// to lazily populate the subview with things. // to lazily populate the subview with things.

View File

@ -149,6 +149,7 @@ skip-if = os == "mac"
[browser_bootstrapped_custom_toolbar.js] [browser_bootstrapped_custom_toolbar.js]
[browser_customizemode_contextmenu_menubuttonstate.js] [browser_customizemode_contextmenu_menubuttonstate.js]
[browser_exit_background_customize_mode.js] [browser_exit_background_customize_mode.js]
[browser_overflow_use_subviews.js]
[browser_panel_toggle.js] [browser_panel_toggle.js]
[browser_panelUINotifications.js] [browser_panelUINotifications.js]
[browser_switch_to_customize_mode.js] [browser_switch_to_customize_mode.js]

View File

@ -0,0 +1,69 @@
"use strict";
const kOverflowPanel = document.getElementById("widget-overflow");
var gOriginalWidth;
registerCleanupFunction(function*() {
kOverflowPanel.removeAttribute("animate");
window.resizeTo(gOriginalWidth, window.outerHeight);
CustomizableUI.reset();
});
/**
* This checks that subview-compatible items show up as subviews rather than
* re-anchored panels. If we ever remove the character encoding widget, please
* replace this test with another subview - don't remove it.
*/
add_task(async function check_character_encoding_subview_in_overflow() {
kOverflowPanel.setAttribute("animate", "false");
gOriginalWidth = window.outerWidth;
CustomizableUI.addWidgetToArea("developer-button", CustomizableUI.AREA_NAVBAR);
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
window.resizeTo(400, window.outerHeight);
await waitForCondition(() => navbar.hasAttribute("overflowing"));
let chevron = document.getElementById("nav-bar-overflow-button");
let shownPanelPromise = promisePanelElementShown(window, kOverflowPanel);
chevron.click();
await shownPanelPromise;
let developerView = document.getElementById("PanelUI-developer");
let button = document.getElementById("developer-button");
let subviewShownPromise = subviewShown(developerView);
button.click();
await subviewShownPromise;
is(developerView.closest("panel"), kOverflowPanel, "Should be inside the panel");
kOverflowPanel.hidePopup();
await Promise.resolve(); // wait for popup to hide fully.
CustomizableUI.reset();
});
/**
* This checks that non-subview-compatible items still work correctly.
* Ideally we should make the downloads panel and bookmarks/library item
* proper subview items, then this test can go away, and potentially we can
* simplify some of the subview anchoring code.
*/
add_task(async function check_downloads_panel_in_overflow() {
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
ok(navbar.hasAttribute("overflowing"), "Should still be overflowing");
let chevron = document.getElementById("nav-bar-overflow-button");
let shownPanelPromise = promisePanelElementShown(window, kOverflowPanel);
chevron.click();
await shownPanelPromise;
let button = document.getElementById("downloads-button");
button.click();
await waitForCondition(() => {
let panel = document.getElementById("downloadsPanel");
return panel && panel.state != "closed";
});
let downloadsPanel = document.getElementById("downloadsPanel");
isnot(downloadsPanel.state, "closed", "Should be attempting to show the downloads panel.");
downloadsPanel.hidePopup();
});

View File

@ -1859,7 +1859,7 @@ BrowserGlue.prototype = {
Services.prefs.clearUserPref("browser.tabs.animate"); Services.prefs.clearUserPref("browser.tabs.animate");
Services.prefs.clearUserPref("browser.fullscreen.animate"); Services.prefs.clearUserPref("browser.fullscreen.animate");
Services.prefs.clearUserPref("browser.tabs.animate"); Services.prefs.clearUserPref("alerts.disableSlidingEffect");
} }
// Update the migration version. // Update the migration version.

View File

@ -334,6 +334,10 @@ this.SessionStore = {
SessionStoreInternal.deleteTabValue(aTab, aKey); SessionStoreInternal.deleteTabValue(aTab, aKey);
}, },
getLazyTabValue(aTab, aKey) {
return SessionStoreInternal.getLazyTabValue(aTab, aKey);
},
getGlobalValue: function ss_getGlobalValue(aKey) { getGlobalValue: function ss_getGlobalValue(aKey) {
return SessionStoreInternal.getGlobalValue(aKey); return SessionStoreInternal.getGlobalValue(aKey);
}, },
@ -1871,6 +1875,15 @@ var SessionStoreInternal = {
if (browser.frameLoader) { if (browser.frameLoader) {
this._lastKnownFrameLoader.set(browser.permanentKey, browser.frameLoader); this._lastKnownFrameLoader.set(browser.permanentKey, browser.frameLoader);
} }
// Only restore if browser has been lazy.
if (aTab.__SS_lazyData && !browser.__SS_restoreState && TabStateCache.get(browser)) {
let tabState = TabState.clone(aTab);
this.restoreTab(aTab, tabState);
}
// The browser has been inserted now, so lazy data is no longer relevant.
delete aTab.__SS_lazyData;
}, },
/** /**
@ -2545,6 +2558,19 @@ var SessionStoreInternal = {
} }
}, },
/**
* Retrieves data specific to lazy-browser tabs. If tab is not lazy,
* will return undefined.
*
* @param aTab (xul:tab)
* The tabbrowser-tab the data is for.
* @param aKey (string)
* The key which maps to the desired data.
*/
getLazyTabValue(aTab, aKey) {
return (aTab.__SS_lazyData || {})[aKey];
},
getGlobalValue: function ssi_getGlobalValue(aKey) { getGlobalValue: function ssi_getGlobalValue(aKey) {
return this._globalState.get(aKey); return this._globalState.get(aKey);
}, },
@ -3272,6 +3298,9 @@ var SessionStoreInternal = {
let numVisibleTabs = 0; let numVisibleTabs = 0;
let createLazyBrowser = this._prefBranch.getBoolPref("sessionstore.restore_tabs_lazily") &&
this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
for (var t = 0; t < newTabCount; t++) { for (var t = 0; t < newTabCount; t++) {
// When trying to restore into existing tab, we also take the userContextId // When trying to restore into existing tab, we also take the userContextId
// into account if present. // into account if present.
@ -3280,7 +3309,8 @@ var SessionStoreInternal = {
(tabbrowser.tabs[t].getAttribute("usercontextid") == (userContextId || "")); (tabbrowser.tabs[t].getAttribute("usercontextid") == (userContextId || ""));
let tab = reuseExisting ? this._maybeUpdateBrowserRemoteness(tabbrowser.tabs[t]) let tab = reuseExisting ? this._maybeUpdateBrowserRemoteness(tabbrowser.tabs[t])
: tabbrowser.addTab("about:blank", : tabbrowser.addTab("about:blank",
{ skipAnimation: true, { createLazyBrowser,
skipAnimation: true,
userContextId, userContextId,
skipBackgroundNotify: true }); skipBackgroundNotify: true });
@ -3595,9 +3625,7 @@ var SessionStoreInternal = {
tabbrowser.selectedBrowser == browser || tabbrowser.selectedBrowser == browser ||
loadArguments; loadArguments;
if (!willRestoreImmediately && !forceOnDemand) { let isBrowserInserted = browser.isConnected;
TabRestoreQueue.add(tab);
}
// Increase the busy state counter before modifying the tab. // Increase the busy state counter before modifying the tab.
this._setWindowStateBusy(window); this._setWindowStateBusy(window);
@ -3665,14 +3693,6 @@ var SessionStoreInternal = {
// Save the index in case we updated it above. // Save the index in case we updated it above.
tabData.index = activeIndex + 1; tabData.index = activeIndex + 1;
// Start a new epoch to discard all frame script messages relating to a
// previous epoch. All async messages that are still on their way to chrome
// will be ignored and don't override any tab data set when restoring.
let epoch = this.startNextEpoch(browser);
// keep the data around to prevent dataloss in case
// a tab gets closed before it's been properly restored
browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
browser.setAttribute("pending", "true"); browser.setAttribute("pending", "true");
tab.setAttribute("pending", "true"); tab.setAttribute("pending", "true");
@ -3700,26 +3720,57 @@ var SessionStoreInternal = {
userTypedClear: tabData.userTypedClear || 0 userTypedClear: tabData.userTypedClear || 0
}); });
this._sendRestoreHistory(browser, {tabData, epoch, loadArguments});
// Update tab label and icon to show something
// while we wait for the messages to be processed.
this.updateTabLabelAndIcon(tab, tabData);
// Restore tab attributes. // Restore tab attributes.
if ("attributes" in tabData) { if ("attributes" in tabData) {
TabAttributes.set(tab, tabData.attributes); TabAttributes.set(tab, tabData.attributes);
} }
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but if (isBrowserInserted) {
// it ensures each window will have its selected tab loaded. // Start a new epoch to discard all frame script messages relating to a
if (willRestoreImmediately) { // previous epoch. All async messages that are still on their way to chrome
this.restoreTabContent(tab, loadArguments, reloadInFreshProcess, // will be ignored and don't override any tab data set when restoring.
restoreContentReason); let epoch = this.startNextEpoch(browser);
} else if (!forceOnDemand) {
this.restoreNextTab(); // Ensure that the tab will get properly restored in the event the tab
// crashes while restoring. But don't set this on lazy browsers as
// restoreTab will get called again when the browser is instantiated.
browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
this._sendRestoreHistory(browser, {tabData, epoch, loadArguments});
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
// it ensures each window will have its selected tab loaded.
if (willRestoreImmediately) {
this.restoreTabContent(tab, loadArguments, reloadInFreshProcess,
restoreContentReason);
} else if (!forceOnDemand) {
TabRestoreQueue.add(tab);
this.restoreNextTab();
}
} else {
// __SS_lazyData holds data for lazy-browser tabs to proxy for
// data unobtainable from the unbound browser. This only applies to lazy
// browsers and will be removed once the browser is inserted in the document.
// This must preceed `updateTabLabelAndIcon` call for required data to be present.
let url = "about:blank";
let title = "";
if (activeIndex in tabData.entries) {
url = tabData.entries[activeIndex].url;
title = tabData.entries[activeIndex].title || url;
}
tab.__SS_lazyData = {
url,
title,
userTypedValue: tabData.userTypedValue || "",
userTypedClear: tabData.userTypedClear || 0
};
} }
// Update tab label and icon to show something
// while we wait for the messages to be processed.
this.updateTabLabelAndIcon(tab, tabData);
// Decrease the busy state counter after we're done. // Decrease the busy state counter after we're done.
this._setWindowStateReady(window); this._setWindowStateReady(window);
}, },

View File

@ -32,11 +32,27 @@ function test() {
"We still know that no load is ongoing"); "We still know that no load is ongoing");
is(gURLBar.value, "example.com", is(gURLBar.value, "example.com",
"Address bar's value correctly restored"); "Address bar's value correctly restored");
// Change tabs to make sure address bar value gets updated
gBrowser.selectedTab = gBrowser.tabContainer.getItemAtIndex(0); // Change tabs to make sure address bar value gets updated. If tab is
is(gURLBar.value, "about:mozilla", // lazy, wait for SSTabRestored to ensure address bar has time to update.
"Address bar's value correctly updated"); let tabToSelect = gBrowser.tabContainer.getItemAtIndex(0);
runNextTest(); if (tabToSelect.linkedBrowser.isConnected) {
gBrowser.selectedTab = tabToSelect;
is(gURLBar.value, "about:mozilla",
"Address bar's value correctly updated");
runNextTest();
} else {
gBrowser.tabContainer.addEventListener("SSTabRestored",
function SSTabRestored(event) {
if (event.target == tabToSelect) {
gBrowser.tabContainer.removeEventListener("SSTabRestored", SSTabRestored, true);
is(gURLBar.value, "about:mozilla",
"Address bar's value correctly updated");
runNextTest();
}
}, true);
gBrowser.selectedTab = tabToSelect;
}
}); });
} }
@ -60,15 +76,34 @@ function test() {
"No history entries still sets currentURI to about:blank"); "No history entries still sets currentURI to about:blank");
is(browser.userTypedValue, "example.org", is(browser.userTypedValue, "example.org",
"userTypedValue was correctly restored"); "userTypedValue was correctly restored");
ok(!browser.didStartLoadSinceLastUserTyping(), // didStartLoadSinceLastUserTyping does not exist on lazy tabs.
"We still know that no load is ongoing"); if (browser.didStartLoadSinceLastUserTyping) {
ok(!browser.didStartLoadSinceLastUserTyping(),
"We still know that no load is ongoing");
}
is(gURLBar.value, "about:mozilla", is(gURLBar.value, "about:mozilla",
"Address bar's value correctly restored"); "Address bar's value correctly restored");
// Change tabs to make sure address bar value gets updated
gBrowser.selectedTab = gBrowser.tabContainer.getItemAtIndex(1); // Change tabs to make sure address bar value gets updated. If tab is
is(gURLBar.value, "example.org", // lazy, wait for SSTabRestored to ensure address bar has time to update.
"Address bar's value correctly updated"); let tabToSelect = gBrowser.tabContainer.getItemAtIndex(1);
runNextTest(); if (tabToSelect.linkedBrowser.isConnected) {
gBrowser.selectedTab = tabToSelect;
is(gURLBar.value, "example.org",
"Address bar's value correctly updated");
runNextTest();
} else {
gBrowser.tabContainer.addEventListener("SSTabRestored",
function SSTabRestored(event) {
if (event.target == tabToSelect) {
gBrowser.tabContainer.removeEventListener("SSTabRestored", SSTabRestored, true);
is(gURLBar.value, "example.org",
"Address bar's value correctly updated");
runNextTest();
}
}, true);
gBrowser.selectedTab = tabToSelect;
}
}); });
} }

View File

@ -5,10 +5,9 @@
var stateBackup = ss.getBrowserState(); var stateBackup = ss.getBrowserState();
function cleanup() { function cleanup() {
// Reset the pref // Reset the prefs
try { Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand"); Services.prefs.clearUserPref("browser.sessionstore.restore_tabs_lazily");
} catch (e) {}
ss.setBrowserState(stateBackup); ss.setBrowserState(stateBackup);
executeSoon(finish); executeSoon(finish);
} }
@ -20,6 +19,8 @@ function test() {
// Set the pref to true so we know exactly how many tabs should be restoring at // Set the pref to true so we know exactly how many tabs should be restoring at
// any given time. This guarantees that a finishing load won't start another. // any given time. This guarantees that a finishing load won't start another.
Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true); Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);
// Don't restore tabs lazily.
Services.prefs.setBoolPref("browser.sessionstore.restore_tabs_lazily", false);
let state = { windows: [{ tabs: [ let state = { windows: [{ tabs: [
{ entries: [{ url: "http://example.org/#1", triggeringPrincipal_base64 }] }, { entries: [{ url: "http://example.org/#1", triggeringPrincipal_base64 }] },

View File

@ -9,6 +9,8 @@ add_task(function* () {
// Set the pref to true so we know exactly how many tabs should be restoring at // Set the pref to true so we know exactly how many tabs should be restoring at
// any given time. This guarantees that a finishing load won't start another. // any given time. This guarantees that a finishing load won't start another.
Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true); Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);
// Don't restore tabs lazily.
Services.prefs.setBoolPref("browser.sessionstore.restore_tabs_lazily", false);
let state = { windows: [{ tabs: [ let state = { windows: [{ tabs: [
{ entries: [{ url: "http://example.org#1", triggeringPrincipal_base64 }], extData: { "uniq": r() } }, { entries: [{ url: "http://example.org#1", triggeringPrincipal_base64 }], extData: { "uniq": r() } },
@ -92,5 +94,7 @@ add_task(function* () {
yield progressCallback(); yield progressCallback();
// Cleanup. // Cleanup.
Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
Services.prefs.clearUserPref("browser.sessionstore.restore_tabs_lazily");
yield promiseBrowserState(stateBackup); yield promiseBrowserState(stateBackup);
}); });

View File

@ -97,22 +97,26 @@ function test_setTabState() {
ss.setTabValue(tab, "baz", "qux"); ss.setTabValue(tab, "baz", "qux");
} }
function onSSTabRestored(aEvent) { function onSSTabRestoring(aEvent) {
is(busyEventCount, 1); if (aEvent.target == tab) {
is(readyEventCount, 1); is(busyEventCount, 1);
is(ss.getTabValue(tab, "baz"), "qux"); is(readyEventCount, 1);
is(tab.linkedBrowser.currentURI.spec, "http://example.org/"); is(ss.getTabValue(tab, "baz"), "qux");
is(tab.linkedBrowser.currentURI.spec, "http://example.org/");
window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy); window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy);
window.removeEventListener("SSWindowStateReady", onSSWindowStateReady); window.removeEventListener("SSWindowStateReady", onSSWindowStateReady);
gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored); gBrowser.tabContainer.removeEventListener("SSTabRestoring", onSSTabRestoring);
runNextTest(); runNextTest();
}
} }
window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy); window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy);
window.addEventListener("SSWindowStateReady", onSSWindowStateReady); window.addEventListener("SSWindowStateReady", onSSWindowStateReady);
gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored); gBrowser.tabContainer.addEventListener("SSTabRestoring", onSSTabRestoring);
// Browser must be inserted in order to restore.
gBrowser._insertBrowser(tab);
ss.setTabState(tab, newTabState); ss.setTabState(tab, newTabState);
} }
@ -137,23 +141,26 @@ function test_duplicateTab() {
ss.setTabValue(newTab, "baz", "qux"); ss.setTabValue(newTab, "baz", "qux");
} }
function onSSTabRestored(aEvent) { function onSSTabRestoring(aEvent) {
is(busyEventCount, 1); if (aEvent.target == newTab) {
is(readyEventCount, 1); is(busyEventCount, 1);
is(ss.getTabValue(newTab, "baz"), "qux"); is(readyEventCount, 1);
is(newTab.linkedBrowser.currentURI.spec, "about:rights"); is(ss.getTabValue(newTab, "baz"), "qux");
is(newTab.linkedBrowser.currentURI.spec, "about:rights");
window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy); window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy);
window.removeEventListener("SSWindowStateReady", onSSWindowStateReady); window.removeEventListener("SSWindowStateReady", onSSWindowStateReady);
gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored); gBrowser.tabContainer.removeEventListener("SSTabRestoring", onSSTabRestoring);
runNextTest(); runNextTest();
}
} }
window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy); window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy);
window.addEventListener("SSWindowStateReady", onSSWindowStateReady); window.addEventListener("SSWindowStateReady", onSSWindowStateReady);
gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored); gBrowser.tabContainer.addEventListener("SSTabRestoring", onSSTabRestoring);
gBrowser._insertBrowser(tab);
newTab = ss.duplicateTab(window, tab); newTab = ss.duplicateTab(window, tab);
} }

View File

@ -147,7 +147,6 @@ add_task(function* test_scroll_background_tabs() {
// The second tab should be the one we loaded URL at still // The second tab should be the one we loaded URL at still
tab = newWin.gBrowser.tabs[1]; tab = newWin.gBrowser.tabs[1];
yield promiseTabRestoring(tab);
ok(tab.hasAttribute("pending"), "Tab should be pending"); ok(tab.hasAttribute("pending"), "Tab should be pending");
browser = tab.linkedBrowser; browser = tab.linkedBrowser;

View File

@ -47,7 +47,6 @@ add_task(function* test_scroll_background_about_reader_tabs() {
// The second tab should be the one we loaded URL at still // The second tab should be the one we loaded URL at still
tab = newWin.gBrowser.tabs[1]; tab = newWin.gBrowser.tabs[1];
yield promiseTabRestoring(tab);
ok(tab.hasAttribute("pending"), "Tab should be pending"); ok(tab.hasAttribute("pending"), "Tab should be pending");
browser = tab.linkedBrowser; browser = tab.linkedBrowser;

View File

@ -94,18 +94,24 @@ function waitForBrowserState(aState, aSetStateCallback) {
let windowObserving = false; let windowObserving = false;
let restoreHiddenTabs = Services.prefs.getBoolPref( let restoreHiddenTabs = Services.prefs.getBoolPref(
"browser.sessionstore.restore_hidden_tabs"); "browser.sessionstore.restore_hidden_tabs");
let restoreTabsLazily = Services.prefs.getBoolPref(
"browser.sessionstore.restore_tabs_lazily");
aState.windows.forEach(function(winState) { aState.windows.forEach(function(winState) {
winState.tabs.forEach(function(tabState) { winState.tabs.forEach(function(tabState) {
if (restoreHiddenTabs || !tabState.hidden) if (!restoreTabsLazily && (restoreHiddenTabs || !tabState.hidden))
expectedTabsRestored++; expectedTabsRestored++;
}); });
}); });
// There must be only hidden tabs and restoreHiddenTabs = false. We still // If there are only hidden tabs and restoreHiddenTabs = false, we still
// expect one of them to be restored because it gets shown automatically. // expect one of them to be restored because it gets shown automatically.
if (!expectedTabsRestored) // Otherwise if lazy tab restore there will only be one tab restored per window.
if (!expectedTabsRestored) {
expectedTabsRestored = 1; expectedTabsRestored = 1;
} else if (restoreTabsLazily) {
expectedTabsRestored = aState.windows.length;
}
function onSSTabRestored(aEvent) { function onSSTabRestored(aEvent) {
if (++tabsRestored == expectedTabsRestored) { if (++tabsRestored == expectedTabsRestored) {
@ -376,11 +382,11 @@ var gProgressListener = {
for (let win of BrowserWindowIterator()) { for (let win of BrowserWindowIterator()) {
for (let i = 0; i < win.gBrowser.tabs.length; i++) { for (let i = 0; i < win.gBrowser.tabs.length; i++) {
let browser = win.gBrowser.tabs[i].linkedBrowser; let browser = win.gBrowser.tabs[i].linkedBrowser;
if (!browser.__SS_restoreState) if (browser.isConnected && !browser.__SS_restoreState)
wasRestored++; wasRestored++;
else if (browser.__SS_restoreState == TAB_STATE_RESTORING) else if (browser.__SS_restoreState == TAB_STATE_RESTORING)
isRestoring++; isRestoring++;
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE || !browser.isConnected)
needsRestore++; needsRestore++;
} }
} }

View File

@ -127,6 +127,7 @@ function defineCohort() {
setCohort("optedOut"); setCohort("optedOut");
} else if (userOptedIn.e10s) { } else if (userOptedIn.e10s) {
setCohort("optedIn"); setCohort("optedIn");
inMultiExperiment = true;
} else if (temporaryDisqualification != "") { } else if (temporaryDisqualification != "") {
// Users who are disqualified by the backend (from multiprocessBlockPolicy) // Users who are disqualified by the backend (from multiprocessBlockPolicy)
// can be put into either the test or control groups, because e10s will // can be put into either the test or control groups, because e10s will
@ -185,7 +186,7 @@ function defineCohort() {
let multiUserSample = getUserSample(true); let multiUserSample = getUserSample(true);
for (let sampleName of Object.getOwnPropertyNames(BUCKETS)) { for (let sampleName of Object.getOwnPropertyNames(BUCKETS)) {
if (multiUserSample < BUCKETS[sampleName]) { if (multiUserSample < BUCKETS[sampleName]) {
setCohort(`${cohortPrefix}multiBucket${sampleName}`); setCohort(`multiBucket${sampleName}`);
Preferences.set(PREF_E10S_PROCESSCOUNT + ".web", sampleName); Preferences.set(PREF_E10S_PROCESSCOUNT + ".web", sampleName);
break; break;
} }

View File

@ -10,7 +10,8 @@
- loaded as a stacked subdialog. --> - loaded as a stacked subdialog. -->
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" /> <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
<link rel="stylesheet" href="chrome://browser/skin/preferences/in-content/dialog.css" /> <link rel="stylesheet" href="chrome://browser/skin/preferences/in-content/dialog.css" />
<link rel="stylesheet" href="chrome://formautofill/content/editProfile.css" /> <link rel="stylesheet" href="chrome://formautofill-shared/skin/editProfile.css" />
<link rel="stylesheet" href="chrome://formautofill/skin/editProfile.css" />
<script src="chrome://formautofill/content/editProfile.js"></script> <script src="chrome://formautofill/content/editProfile.js"></script>
</head> </head>
<body> <body>

View File

@ -0,0 +1,5 @@
/* 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/. */
/* Linux specific rules */

View File

@ -0,0 +1,5 @@
/* 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/. */
/* OSX specific rules */

View File

@ -0,0 +1,12 @@
/* 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/. */
/* The save button should be on the left and cancel on the right for Windows */
#save {
order: 0;
}
#cancel {
order: 1;
}

View File

@ -1,3 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.8.229 Current extension version is: 1.8.243

View File

@ -90,7 +90,7 @@ var PdfjsChromeUtils = {
this._mmg.addMessageListener("PDFJS:Parent:removeEventListener", this); this._mmg.addMessageListener("PDFJS:Parent:removeEventListener", this);
this._mmg.addMessageListener("PDFJS:Parent:updateControlState", this); this._mmg.addMessageListener("PDFJS:Parent:updateControlState", this);
// observer to handle shutdown // Observer to handle shutdown.
Services.obs.addObserver(this, "quit-application"); Services.obs.addObserver(this, "quit-application");
} }
}, },

View File

@ -45,6 +45,7 @@ var PdfjsContentUtils = {
this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"]. this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].
getService(Ci.nsISyncMessageSender); getService(Ci.nsISyncMessageSender);
this._mm.addMessageListener("PDFJS:Child:refreshSettings", this); this._mm.addMessageListener("PDFJS:Child:refreshSettings", this);
Services.obs.addObserver(this, "quit-application"); Services.obs.addObserver(this, "quit-application");
} }
}, },

View File

@ -961,12 +961,12 @@ var createBlob = function createBlob(data, contentType) {
if (typeof Blob !== 'undefined') { if (typeof Blob !== 'undefined') {
return new Blob([data], { type: contentType }); return new Blob([data], { type: contentType });
} }
warn('The "Blob" constructor is not supported.'); throw new Error('The "Blob" constructor is not supported.');
}; };
var createObjectURL = function createObjectURLClosure() { var createObjectURL = function createObjectURLClosure() {
var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
return function createObjectURL(data, contentType, forceDataSchema) { return function createObjectURL(data, contentType, forceDataSchema = false) {
if (!forceDataSchema && typeof URL !== 'undefined' && URL.createObjectURL) { if (!forceDataSchema) {
var blob = createBlob(data, contentType); var blob = createBlob(data, contentType);
return URL.createObjectURL(blob); return URL.createObjectURL(blob);
} }
@ -3391,8 +3391,8 @@ var _UnsupportedManager = function UnsupportedManagerClosure() {
}(); }();
var version, build; var version, build;
{ {
exports.version = version = '1.8.229'; exports.version = version = '1.8.243';
exports.build = build = '5ad3611c'; exports.build = build = '96cb599e';
} }
exports.getDocument = getDocument; exports.getDocument = getDocument;
exports.PDFDataRangeTransport = PDFDataRangeTransport; exports.PDFDataRangeTransport = PDFDataRangeTransport;
@ -4394,8 +4394,8 @@ if (!_util.globalScope.PDFJS) {
} }
var PDFJS = _util.globalScope.PDFJS; var PDFJS = _util.globalScope.PDFJS;
{ {
PDFJS.version = '1.8.229'; PDFJS.version = '1.8.243';
PDFJS.build = '5ad3611c'; PDFJS.build = '96cb599e';
} }
PDFJS.pdfBug = false; PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) { if (PDFJS.verbosity !== undefined) {
@ -6709,8 +6709,8 @@ exports.TilingPattern = TilingPattern;
"use strict"; "use strict";
var pdfjsVersion = '1.8.229'; var pdfjsVersion = '1.8.243';
var pdfjsBuild = '5ad3611c'; var pdfjsBuild = '96cb599e';
var pdfjsSharedUtil = __w_pdfjs_require__(0); var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(8); var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
var pdfjsDisplayAPI = __w_pdfjs_require__(3); var pdfjsDisplayAPI = __w_pdfjs_require__(3);

View File

@ -961,12 +961,12 @@ var createBlob = function createBlob(data, contentType) {
if (typeof Blob !== 'undefined') { if (typeof Blob !== 'undefined') {
return new Blob([data], { type: contentType }); return new Blob([data], { type: contentType });
} }
warn('The "Blob" constructor is not supported.'); throw new Error('The "Blob" constructor is not supported.');
}; };
var createObjectURL = function createObjectURLClosure() { var createObjectURL = function createObjectURLClosure() {
var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
return function createObjectURL(data, contentType, forceDataSchema) { return function createObjectURL(data, contentType, forceDataSchema = false) {
if (!forceDataSchema && typeof URL !== 'undefined' && URL.createObjectURL) { if (!forceDataSchema) {
var blob = createBlob(data, contentType); var blob = createBlob(data, contentType);
return URL.createObjectURL(blob); return URL.createObjectURL(blob);
} }
@ -36565,8 +36565,8 @@ exports.Type1Parser = Type1Parser;
"use strict"; "use strict";
var pdfjsVersion = '1.8.229'; var pdfjsVersion = '1.8.243';
var pdfjsBuild = '5ad3611c'; var pdfjsBuild = '96cb599e';
var pdfjsCoreWorker = __w_pdfjs_require__(17); var pdfjsCoreWorker = __w_pdfjs_require__(17);
; ;
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler; exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;

View File

@ -315,9 +315,18 @@ function getVisibleElements(scrollEl, views, sortByVisibility) {
function noContextMenuHandler(e) { function noContextMenuHandler(e) {
e.preventDefault(); e.preventDefault();
} }
function getPDFFileNameFromURL(url, defaultFilename) { function isDataSchema(url) {
if (typeof defaultFilename === 'undefined') { var i = 0,
defaultFilename = 'document.pdf'; ii = url.length;
while (i < ii && url[i].trim() === '') {
i++;
}
return url.substr(i, 5).toLowerCase() === 'data:';
}
function getPDFFileNameFromURL(url, defaultFilename = 'document.pdf') {
if (isDataSchema(url)) {
console.warn('getPDFFileNameFromURL: ' + 'ignoring "data:" URL for performance reasons.');
return defaultFilename;
} }
var reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/; var reURI = /^(?:(?:[^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i; var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
@ -3869,11 +3878,14 @@ var PDFAttachmentViewer = function PDFAttachmentViewerClosure() {
}); });
this._renderedCapability.resolve(); this._renderedCapability.resolve();
}, },
_bindPdfLink: function PDFAttachmentViewer_bindPdfLink(button, content, filename) { _bindPdfLink(button, content, filename) {
if (_pdfjs.PDFJS.disableCreateObjectURL) {
throw new Error('bindPdfLink: ' + 'Unsupported "PDFJS.disableCreateObjectURL" value.');
}
var blobUrl; var blobUrl;
button.onclick = function () { button.onclick = function () {
if (!blobUrl) { if (!blobUrl) {
blobUrl = (0, _pdfjs.createObjectURL)(content, 'application/pdf', _pdfjs.PDFJS.disableCreateObjectURL); blobUrl = (0, _pdfjs.createObjectURL)(content, 'application/pdf');
} }
var viewerUrl; var viewerUrl;
viewerUrl = blobUrl + '?' + encodeURIComponent(filename); viewerUrl = blobUrl + '?' + encodeURIComponent(filename);
@ -3911,7 +3923,7 @@ var PDFAttachmentViewer = function PDFAttachmentViewerClosure() {
div.className = 'attachmentsItem'; div.className = 'attachmentsItem';
var button = document.createElement('button'); var button = document.createElement('button');
button.textContent = filename; button.textContent = filename;
if (/\.pdf$/i.test(filename)) { if (/\.pdf$/i.test(filename) && !_pdfjs.PDFJS.disableCreateObjectURL) {
this._bindPdfLink(button, item.content, filename); this._bindPdfLink(button, item.content, filename);
} else { } else {
this._bindLink(button, item.content, filename); this._bindLink(button, item.content, filename);
@ -7630,7 +7642,7 @@ var pdfjsWebApp;
pdfjsWebApp = __webpack_require__(4); pdfjsWebApp = __webpack_require__(4);
} }
{ {
window.FirefoxCom = __webpack_require__(10).FirefoxCom; __webpack_require__(10);
__webpack_require__(9); __webpack_require__(9);
} }
; ;

View File

@ -696,10 +696,6 @@
@RESPATH@/res/fonts/* @RESPATH@/res/fonts/*
@RESPATH@/res/dtd/* @RESPATH@/res/dtd/*
@RESPATH@/res/html/* @RESPATH@/res/html/*
#if defined(XP_MACOSX)
; For SafariProfileMigrator.js.
@RESPATH@/res/langGroups.properties
#endif
@RESPATH@/res/language.properties @RESPATH@/res/language.properties
@RESPATH@/res/entityTables/* @RESPATH@/res/entityTables/*
#ifdef XP_MACOSX #ifdef XP_MACOSX

View File

@ -98,8 +98,7 @@ let customizationListener = {
}; };
customizationListener.onWidgetAdded = customizationListener.onWidgetAdded =
customizationListener.onWidgetRemoved = customizationListener.onWidgetRemoved =
customizationListener.onWidgetMoved = customizationListener.onWidgetMoved = function(aWidgetId) {
customizationListener.onWidgetInstanceRemoved = function(aWidgetId) {
if (aWidgetId == "zoom-controls") { if (aWidgetId == "zoom-controls") {
for (let window of CustomizableUI.windows) { for (let window of CustomizableUI.windows) {
updateZoomUI(window.gBrowser.selectedBrowser); updateZoomUI(window.gBrowser.selectedBrowser);

View File

@ -92,12 +92,22 @@ var BrowserHelper = {
}, },
increasePriority: function NP_BH_increasePriority(aBrowser) { increasePriority: function NP_BH_increasePriority(aBrowser) {
// Ignore if browser is lazy. Once the browser is instantiated, this will
// get taken care of by TabBrowserInserted and TabSelect handlers.
if (!aBrowser.isConnected) {
return;
}
aBrowser.adjustPriority(PRIORITY_DELTA); aBrowser.adjustPriority(PRIORITY_DELTA);
_priorityBackup.set(aBrowser.permanentKey, _priorityBackup.set(aBrowser.permanentKey,
_priorityBackup.get(aBrowser.permanentKey) + PRIORITY_DELTA); _priorityBackup.get(aBrowser.permanentKey) + PRIORITY_DELTA);
}, },
decreasePriority: function NP_BH_decreasePriority(aBrowser) { decreasePriority: function NP_BH_decreasePriority(aBrowser) {
// Ignore if browser is lazy. Once the browser is instantiated, this will
// get taken care of by TabBrowserInserted and TabSelect handlers.
if (!aBrowser.isConnected) {
return;
}
aBrowser.adjustPriority(PRIORITY_DELTA * -1); aBrowser.adjustPriority(PRIORITY_DELTA * -1);
_priorityBackup.set(aBrowser.permanentKey, _priorityBackup.set(aBrowser.permanentKey,
_priorityBackup.get(aBrowser.permanentKey) - PRIORITY_DELTA); _priorityBackup.get(aBrowser.permanentKey) - PRIORITY_DELTA);

View File

@ -34,6 +34,7 @@ run-if = crashreporter
[browser_UsageTelemetry.js] [browser_UsageTelemetry.js]
[browser_UsageTelemetry_private_and_restore.js] [browser_UsageTelemetry_private_and_restore.js]
[browser_UsageTelemetry_urlbar.js] [browser_UsageTelemetry_urlbar.js]
skip-if = (os == 'linux' && bits == 32 && debug) # bug 1356758
support-files = support-files =
usageTelemetrySearchSuggestions.sjs usageTelemetrySearchSuggestions.sjs
usageTelemetrySearchSuggestions.xml usageTelemetrySearchSuggestions.xml

View File

@ -553,7 +553,7 @@ menuitem.bookmark-item {
/* Menu panel buttons */ /* Menu panel buttons */
%include ../shared/toolbarbuttons.inc.css %include ../shared/toolbarbutton-icons.inc.css
%include ../shared/menupanel.inc.css %include ../shared/menupanel.inc.css
#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon, #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon,

View File

@ -726,7 +726,7 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
-moz-box-align: center; -moz-box-align: center;
} }
%include ../shared/toolbarbuttons.inc.css %include ../shared/toolbarbutton-icons.inc.css
%include ../shared/menupanel.inc.css %include ../shared/menupanel.inc.css
@media not all and (min-resolution: 1.1dppx) { @media not all and (min-resolution: 1.1dppx) {

View File

@ -578,7 +578,7 @@ menuitem.bookmark-item {
/* ::::: primary toolbar buttons ::::: */ /* ::::: primary toolbar buttons ::::: */
%include ../shared/toolbarbuttons.inc.css %include ../shared/toolbarbutton-icons.inc.css
#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon, #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker, #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,

View File

@ -7,7 +7,7 @@ console.assert(false, "Failing mozscreenshots assertion");
console.group("Grouped Message"); console.group("Grouped Message");
console.log("group message 1"); console.log("group message 1");
console.groupEnd("Grouped Message"); console.groupEnd();
console.count("counter"); console.count("counter");
console.count("counter"); console.count("counter");

View File

@ -504,6 +504,13 @@ set_config('HAVE_64BIT_BUILD', have_64_bit)
set_define('HAVE_64BIT_BUILD', have_64_bit) set_define('HAVE_64BIT_BUILD', have_64_bit)
add_old_configure_assignment('HAVE_64BIT_BUILD', have_64_bit) add_old_configure_assignment('HAVE_64BIT_BUILD', have_64_bit)
@depends(host)
def host_os_kernel_major_version(host):
versions = host.raw_os.split('.')
version = ''.join(x for x in versions[0] if x.isdigit())
return version
set_config('HOST_MAJOR_VERSION', host_os_kernel_major_version)
# Autoconf needs these set # Autoconf needs these set
@depends(host) @depends(host)

View File

@ -61,6 +61,9 @@ check_and_add_gcc_warning('-Wc++14-compat', cxx_compiler)
check_and_add_gcc_warning('-Wc++14-compat-pedantic', cxx_compiler) check_and_add_gcc_warning('-Wc++14-compat-pedantic', cxx_compiler)
check_and_add_gcc_warning('-Wc++1z-compat', cxx_compiler) check_and_add_gcc_warning('-Wc++1z-compat', cxx_compiler)
# catches possible misuse of the comma operator
check_and_add_gcc_warning('-Wcomma', cxx_compiler)
# catches unintentional switch case fallthroughs # catches unintentional switch case fallthroughs
check_and_add_gcc_warning('-Wimplicit-fallthrough', cxx_compiler) check_and_add_gcc_warning('-Wimplicit-fallthrough', cxx_compiler)

View File

@ -40,6 +40,10 @@ elif CONFIG['OS_TARGET'] in ('FreeBSD', 'OpenBSD', 'NetBSD'):
SOURCES += ['/nsprpub/pr/src/md/unix/%s.c' % CONFIG['OS_TARGET'].lower()] SOURCES += ['/nsprpub/pr/src/md/unix/%s.c' % CONFIG['OS_TARGET'].lower()]
elif CONFIG['OS_TARGET'] == 'Darwin': elif CONFIG['OS_TARGET'] == 'Darwin':
OS_LIBS += ['-framework CoreServices'] OS_LIBS += ['-framework CoreServices']
if CONFIG['HOST_MAJOR_VERSION'] == '15':
DEFINES.update(
HAS_CONNECTX=True,
)
DEFINES.update( DEFINES.update(
DARWIN=True, DARWIN=True,
HAVE_BSD_FLOCK=True, HAVE_BSD_FLOCK=True,

View File

@ -26,7 +26,7 @@ module.exports = createClass({
displayName: "multiE10SWarning", displayName: "multiE10SWarning",
onUpdatePreferenceClick() { onUpdatePreferenceClick() {
let message = Strings.GetStringFromName("multiProcessWarningConfirmUpdate"); let message = Strings.GetStringFromName("multiProcessWarningConfirmUpdate2");
if (window.confirm(message)) { if (window.confirm(message)) {
// Disable multi until at least the next experiment. // Disable multi until at least the next experiment.
Services.prefs.setIntPref(MULTI_OPT_OUT_PREF, Services.prefs.setIntPref(MULTI_OPT_OUT_PREF,
@ -48,14 +48,14 @@ module.exports = createClass({
), ),
dom.div( dom.div(
{}, {},
Strings.GetStringFromName("multiProcessWarningMessage") Strings.GetStringFromName("multiProcessWarningMessage2")
), ),
dom.button( dom.button(
{ {
className: "update-button", className: "update-button",
onClick: this.onUpdatePreferenceClick, onClick: this.onUpdatePreferenceClick,
}, },
Strings.GetStringFromName("multiProcessWarningUpdateLink") Strings.GetStringFromName("multiProcessWarningUpdateLink2")
) )
); );
}, },

View File

@ -31,6 +31,7 @@ const Strings = Services.strings.createBundle(
const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg"; const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg";
const MORE_INFO_URL = "https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging"; const MORE_INFO_URL = "https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging";
const PROCESS_COUNT_PREF = "dom.ipc.processCount"; const PROCESS_COUNT_PREF = "dom.ipc.processCount";
const MULTI_OPTOUT_PREF = "dom.ipc.multiOptOut";
module.exports = createClass({ module.exports = createClass({
displayName: "WorkersPanel", displayName: "WorkersPanel",
@ -58,7 +59,20 @@ module.exports = createClass({
client.addListener("processListChanged", this.updateWorkers); client.addListener("processListChanged", this.updateWorkers);
client.addListener("registration-changed", this.updateWorkers); client.addListener("registration-changed", this.updateWorkers);
// Some notes about these observers:
// - nsIPrefBranch.addObserver observes prefixes. In reality, watching
// PROCESS_COUNT_PREF watches two separate prefs:
// dom.ipc.processCount *and* dom.ipc.processCount.web. Because these
// are the two ways that we control the number of content processes,
// that works perfectly fine.
// - The user might opt in or out of multi by setting the multi opt out
// pref. That affects whether we need to show our warning, so we need to
// update our state when that pref changes.
// - In all cases, we don't have to manually check which pref changed to
// what. The platform code in nsIXULRuntime.maxWebProcessCount does all
// of that for us.
Services.prefs.addObserver(PROCESS_COUNT_PREF, this.updateMultiE10S); Services.prefs.addObserver(PROCESS_COUNT_PREF, this.updateMultiE10S);
Services.prefs.addObserver(MULTI_OPTOUT_PREF, this.updateMultiE10S);
this.updateMultiE10S(); this.updateMultiE10S();
this.updateWorkers(); this.updateWorkers();
@ -72,11 +86,12 @@ module.exports = createClass({
client.removeListener("registration-changed", this.updateWorkers); client.removeListener("registration-changed", this.updateWorkers);
Services.prefs.removeObserver(PROCESS_COUNT_PREF, this.updateMultiE10S); Services.prefs.removeObserver(PROCESS_COUNT_PREF, this.updateMultiE10S);
Services.prefs.removeObserver(MULTI_OPTOUT_PREF, this.updateMultiE10S);
}, },
updateMultiE10S() { updateMultiE10S() {
// We watch the pref but set the state based on // We watch the pref but set the state based on
// nsIXULRuntime::maxWebProcessCount. // nsIXULRuntime.maxWebProcessCount.
let processCount = Services.appinfo.maxWebProcessCount; let processCount = Services.appinfo.maxWebProcessCount;
this.setState({ processCount }); this.setState({ processCount });
}, },

View File

@ -79,7 +79,6 @@ function loadTelemetryAndRecordLogs() {
info("Mock the Telemetry log function to record logged information"); info("Mock the Telemetry log function to record logged information");
let Telemetry = require("devtools/client/shared/telemetry"); let Telemetry = require("devtools/client/shared/telemetry");
Telemetry.prototype.telemetryInfo = {}; Telemetry.prototype.telemetryInfo = {};
Telemetry.prototype._oldlog = Telemetry.prototype.log; Telemetry.prototype._oldlog = Telemetry.prototype.log;
Telemetry.prototype.log = function (histogramId, value) { Telemetry.prototype.log = function (histogramId, value) {
@ -94,6 +93,8 @@ function loadTelemetryAndRecordLogs() {
this.telemetryInfo[histogramId].push(value); this.telemetryInfo[histogramId].push(value);
} }
}; };
Telemetry.prototype._oldlogScalar = Telemetry.prototype.logScalar;
Telemetry.prototype.logScalar = Telemetry.prototype.log;
Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed; Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed;
Telemetry.prototype.logKeyed = function (histogramId, key, value) { Telemetry.prototype.logKeyed = function (histogramId, key, value) {
this.log(`${histogramId}|${key}`, value); this.log(`${histogramId}|${key}`, value);
@ -110,8 +111,10 @@ function loadTelemetryAndRecordLogs() {
function stopRecordingTelemetryLogs(Telemetry) { function stopRecordingTelemetryLogs(Telemetry) {
info("Stopping Telemetry"); info("Stopping Telemetry");
Telemetry.prototype.log = Telemetry.prototype._oldlog; Telemetry.prototype.log = Telemetry.prototype._oldlog;
Telemetry.prototype.logScalar = Telemetry.prototype._oldlogScalar;
Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed; Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed;
delete Telemetry.prototype._oldlog; delete Telemetry.prototype._oldlog;
delete Telemetry.prototype._oldlogScalar;
delete Telemetry.prototype._oldlogKeyed; delete Telemetry.prototype._oldlogKeyed;
delete Telemetry.prototype.telemetryInfo; delete Telemetry.prototype.telemetryInfo;
} }

View File

@ -95,7 +95,7 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
this._preferredSourceURL = null; this._preferredSourceURL = null;
this._unnamedSourceIndex = 0; this._unnamedSourceIndex = 0;
this.emptyText = L10N.getStr("noSourcesText"); this.emptyText = L10N.getStr("noSourcesText");
this._blackBoxCheckboxTooltip = L10N.getStr("blackBoxCheckboxTooltip"); this._blackBoxCheckboxTooltip = L10N.getStr("blackboxCheckboxTooltip2");
this._commandset = document.getElementById("debuggerCommands"); this._commandset = document.getElementById("debuggerCommands");
this._popupset = document.getElementById("debuggerPopupset"); this._popupset = document.getElementById("debuggerPopupset");

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,6 @@ DevToolsModules(
'debugger.css', 'debugger.css',
'debugger.js', 'debugger.js',
'panel.js', 'panel.js',
'parser-worker.js',
'pretty-print-worker.js', 'pretty-print-worker.js',
'source-map-worker.js'
) )

View File

@ -4,7 +4,7 @@
"use strict"; "use strict";
const { Task } = require("devtools/shared/task"); const { Task } = require("devtools/shared/task");
var {LocalizationHelper} = require("devtools/shared/l10n"); var { LocalizationHelper } = require("devtools/shared/l10n");
const DBG_STRINGS_URI = "devtools/client/locales/debugger.properties"; const DBG_STRINGS_URI = "devtools/client/locales/debugger.properties";
var L10N = new LocalizationHelper(DBG_STRINGS_URI); var L10N = new LocalizationHelper(DBG_STRINGS_URI);
@ -16,38 +16,46 @@ function DebuggerPanel(iframeWindow, toolbox) {
} }
DebuggerPanel.prototype = { DebuggerPanel.prototype = {
open: Task.async(function* () { open: async function() {
if (!this.toolbox.target.isRemote) { if (!this.toolbox.target.isRemote) {
yield this.toolbox.target.makeRemote(); await this.toolbox.target.makeRemote();
} }
yield this.panelWin.Debugger.bootstrap({ const {
actions,
store,
selectors,
client
} = await this.panelWin.Debugger.bootstrap({
threadClient: this.toolbox.threadClient, threadClient: this.toolbox.threadClient,
tabTarget: this.toolbox.target tabTarget: this.toolbox.target,
debuggerClient: this.toolbox.target._client,
sourceMaps: this.toolbox.sourceMapService
}); });
this._actions = actions;
this._store = store;
this._selectors = selectors;
this._client = client;
this.isReady = true; this.isReady = true;
return this; return this;
}),
_store: function () {
return this.panelWin.Debugger.store;
}, },
_getState: function () { getVarsForTests() {
return this._store().getState(); return {
store: this._store,
selectors: this._selectors,
actions: this._actions,
client: this._client
};
}, },
_actions: function () { _getState: function() {
return this.panelWin.Debugger.actions; return this._store.getState();
}, },
_selectors: function () { getFrames: function() {
return this.panelWin.Debugger.selectors; let frames = this._selectors.getFrames(this._getState());
},
getFrames: function () {
let frames = this._selectors().getFrames(this._getState());
// Frames is null when the debugger is not paused. // Frames is null when the debugger is not paused.
if (!frames) { if (!frames) {
@ -58,7 +66,7 @@ DebuggerPanel.prototype = {
} }
frames = frames.toJS(); frames = frames.toJS();
const selectedFrame = this._selectors().getSelectedFrame(this._getState()); const selectedFrame = this._selectors.getSelectedFrame(this._getState());
const selected = frames.findIndex(frame => frame.id == selectedFrame.id); const selected = frames.findIndex(frame => frame.id == selectedFrame.id);
frames.forEach(frame => { frames.forEach(frame => {
@ -68,7 +76,15 @@ DebuggerPanel.prototype = {
return { frames, selected }; return { frames, selected };
}, },
destroy: function () { selectSource(sourceURL, sourceLine) {
this._actions.selectSourceURL(sourceURL, { line: sourceLine });
},
getSource(sourceURL) {
return this._selectors.getSourceByURL(this._getState(), sourceURL);
},
destroy: function() {
this.panelWin.Debugger.destroy(); this.panelWin.Debugger.destroy();
this.emit("destroyed"); this.emit("destroyed");
} }

File diff suppressed because one or more lines are too long

View File

@ -55,7 +55,7 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ 0: /***/ 0:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(801); module.exports = __webpack_require__(964);
/***/ }, /***/ },
@ -75,76 +75,6 @@ return /******/ (function(modules) { // webpackBootstrap
/***/ }, /***/ },
/***/ 801:
/***/ function(module, exports, __webpack_require__) {
"use strict";
var prettyFast = __webpack_require__(802);
var assert = __webpack_require__(223);
function prettyPrint(_ref) {
var url = _ref.url,
indent = _ref.indent,
source = _ref.source;
try {
var prettified = prettyFast(source, {
url: url,
indent: " ".repeat(indent)
});
return {
code: prettified.code,
mappings: prettified.map._mappings
};
} catch (e) {
throw new Error(`${e.message}\n${e.stack}`);
}
}
function invertMappings(mappings) {
return mappings._array.map(m => {
var mapping = {
generated: {
line: m.originalLine,
column: m.originalColumn
}
};
if (m.source) {
mapping.source = m.source;
mapping.original = {
line: m.generatedLine,
column: m.generatedColumn
};
mapping.name = m.name;
}
return mapping;
});
}
self.onmessage = function (msg) {
var _msg$data = msg.data,
id = _msg$data.id,
args = _msg$data.args;
assert(msg.data.method === "prettyPrint", "Method must be `prettyPrint`");
try {
var _prettyPrint = prettyPrint(args[0]),
code = _prettyPrint.code,
mappings = _prettyPrint.mappings;
self.postMessage({ id, response: {
code, mappings: invertMappings(mappings)
} });
} catch (e) {
self.postMessage({ id, error: e });
}
};
/***/ },
/***/ 802: /***/ 802:
/***/ function(module, exports, __webpack_require__) { /***/ function(module, exports, __webpack_require__) {
@ -5918,6 +5848,80 @@ return /******/ (function(modules) { // webpackBootstrap
}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/***/ 964:
/***/ function(module, exports, __webpack_require__) {
"use strict";
var prettyFast = __webpack_require__(802);
var assert = __webpack_require__(223);
function prettyPrint(_ref) {
var url = _ref.url,
indent = _ref.indent,
source = _ref.source;
try {
var prettified = prettyFast(source, {
url: url,
indent: " ".repeat(indent)
});
return {
code: prettified.code,
mappings: prettified.map._mappings
};
} catch (e) {
throw new Error(`${e.message}\n${e.stack}`);
}
}
function invertMappings(mappings) {
return mappings._array.map(m => {
var mapping = {
generated: {
line: m.originalLine,
column: m.originalColumn
}
};
if (m.source) {
mapping.source = m.source;
mapping.original = {
line: m.generatedLine,
column: m.generatedColumn
};
mapping.name = m.name;
}
return mapping;
});
}
self.onmessage = function (msg) {
var _msg$data = msg.data,
id = _msg$data.id,
args = _msg$data.args;
assert(msg.data.method === "prettyPrint", "Method must be `prettyPrint`");
try {
var _prettyPrint = prettyPrint(args[0]),
code = _prettyPrint.code,
mappings = _prettyPrint.mappings;
self.postMessage({
id,
response: {
code,
mappings: invertMappings(mappings)
}
});
} catch (e) {
self.postMessage({ id, error: e });
}
};
/***/ } /***/ }
/******/ }) /******/ })

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@ support-files =
[browser_dbg-breakpoints.js] [browser_dbg-breakpoints.js]
[browser_dbg-breakpoints-cond.js] [browser_dbg-breakpoints-cond.js]
[browser_dbg-call-stack.js] [browser_dbg-call-stack.js]
[browser_dbg-expressions.js]
[browser_dbg-scopes.js] [browser_dbg-scopes.js]
[browser_dbg-chrome-create.js] [browser_dbg-chrome-create.js]
[browser_dbg-chrome-debugging.js] [browser_dbg-chrome-debugging.js]

View File

@ -54,6 +54,6 @@ add_task(function* () {
button = toggleButton(dbg); button = toggleButton(dbg);
frames = findAllElements(dbg, "frames"); frames = findAllElements(dbg, "frames");
is(button.innerText, "Collapse Rows", "toggle button should be collapse"); is(button.innerText, "Collapse Rows", "toggle button should be collapsed");
is(frames.length, 22, "All of the frames should be shown"); is(frames.length, 22, "All of the frames should be shown");
}); });

View File

@ -18,7 +18,9 @@ add_task(function* () {
// Wait for the source text to load and make sure we're in the right // Wait for the source text to load and make sure we're in the right
// place. // place.
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
assertHighlightLocation(dbg, "long.js", 66);
// TODO: revisit highlighting lines when the debugger opens
//assertHighlightLocation(dbg, "long.js", 66);
// Jump to line 16 and make sure the editor scrolled. // Jump to line 16 and make sure the editor scrolled.
yield selectSource(dbg, "long.js", 16); yield selectSource(dbg, "long.js", 16);

View File

@ -50,5 +50,5 @@ add_task(function* () {
invokeInTab("testModel"); invokeInTab("testModel");
yield waitForPaused(dbg); yield waitForPaused(dbg);
assertPausedLocation(dbg, longSrc, 66); assertPausedLocation(dbg, longSrc, 66);
// ok(isElementVisible(dbg, "breakpoint"), "Breakpoint is visible"); ok(isElementVisible(dbg, "breakpoint"), "Breakpoint is visible");
}); });

View File

@ -1,12 +1,56 @@
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */ * http://creativecommons.org/publicdomain/zero/1.0/ */
const { /**
setupTestRunner, * tests the watch expressions component
expressions * 1. add watch expressions
} = require("devtools/client/debugger/new/integration-tests"); * 2. edit watch expressions
* 3. delete watch expressions
*/
const expressionSelectors = {
input: "input.input-expression"
};
function getLabel(dbg, index) {
return findElement(dbg, "expressionNode", index).innerText;
}
function getValue(dbg, index) {
return findElement(dbg, "expressionValue", index).innerText;
}
async function addExpression(dbg, input) {
info("Adding an expression");
findElementWithSelector(dbg, expressionSelectors.input).focus();
type(dbg, input);
pressKey(dbg, "Enter");
await waitForDispatch(dbg, "EVALUATE_EXPRESSION");
}
async function editExpression(dbg, input) {
info("updating the expression");
dblClickElement(dbg, "expressionNode", 1);
type(dbg, input);
pressKey(dbg, "Enter");
await waitForDispatch(dbg, "EVALUATE_EXPRESSION");
}
add_task(function*() { add_task(function*() {
setupTestRunner(this); const dbg = yield initDebugger("doc-script-switching.html");
yield expressions(this);
invokeInTab("firstCall");
yield waitForPaused(dbg);
yield addExpression(dbg, "f");
is(getLabel(dbg, 1), "f");
is(getValue(dbg, 1), "ReferenceError");
yield editExpression(dbg, "oo");
is(getLabel(dbg, 1), "foo()");
is(getValue(dbg, 1), "");
yield deleteExpression(dbg, "foo");
is(findAllElements(dbg, "expressionNodes").length, 0);
}); });

View File

@ -20,7 +20,6 @@ add_task(function* () {
const dbg = yield initDebugger("doc-exceptions.html"); const dbg = yield initDebugger("doc-exceptions.html");
// test skipping an uncaught exception // test skipping an uncaught exception
yield togglePauseOnExceptions(dbg, false, false);
yield uncaughtException(); yield uncaughtException();
ok(!isPaused(dbg)); ok(!isPaused(dbg));

View File

@ -3,7 +3,7 @@
// Tests basic pretty-printing functionality. // Tests basic pretty-printing functionality.
add_task(function* () { add_task(function*() {
const dbg = yield initDebugger("doc-minified.html"); const dbg = yield initDebugger("doc-minified.html");
yield selectSource(dbg, "math.min.js"); yield selectSource(dbg, "math.min.js");

View File

@ -19,4 +19,13 @@ add_task(function* () {
is(getLabel(dbg, 1), "secondCall"); is(getLabel(dbg, 1), "secondCall");
is(getLabel(dbg, 2), "<this>"); is(getLabel(dbg, 2), "<this>");
is(getLabel(dbg, 4), "foo()");
toggleNode(dbg, 4);
yield waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
is(getLabel(dbg, 5), "prototype");
yield stepOver(dbg);
is(getLabel(dbg, 4), "foo()");
is(getLabel(dbg, 5), "prototype");
}); });

View File

@ -4,7 +4,10 @@
// Test that an error while loading a sourcemap does not break // Test that an error while loading a sourcemap does not break
// debugging. // debugging.
add_task(function* () { add_task(function*() {
// NOTE: the CORS call makes the test run times inconsistent
requestLongerTimeout(2);
const dbg = yield initDebugger("doc-sourcemap-bogus.html"); const dbg = yield initDebugger("doc-sourcemap-bogus.html");
const { selectors: { getSources }, getState } = dbg; const { selectors: { getSources }, getState } = dbg;

View File

@ -4,7 +4,10 @@
// Tests loading sourcemapped sources, setting breakpoints, and // Tests loading sourcemapped sources, setting breakpoints, and
// stepping in them. // stepping in them.
add_task(function* () { add_task(function*() {
// NOTE: the CORS call makes the test run times inconsistent
requestLongerTimeout(2);
const dbg = yield initDebugger("doc-sourcemaps.html"); const dbg = yield initDebugger("doc-sourcemaps.html");
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg; const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
@ -13,21 +16,27 @@ add_task(function* () {
const entrySrc = findSource(dbg, "entry.js"); const entrySrc = findSource(dbg, "entry.js");
yield selectSource(dbg, entrySrc); yield selectSource(dbg, entrySrc);
ok(dbg.win.cm.getValue().includes("window.keepMeAlive"), ok(
"Original source text loaded correctly"); dbg.win.cm.getValue().includes("window.keepMeAlive"),
"Original source text loaded correctly"
);
// Test that breakpoint sliding is not attempted. The breakpoint // Test that breakpoint sliding is not attempted. The breakpoint
// should not move anywhere. // should not move anywhere.
yield addBreakpoint(dbg, entrySrc, 13); yield addBreakpoint(dbg, entrySrc, 13);
is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
ok(getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }), ok(
"Breakpoint has correct line"); getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
"Breakpoint has correct line"
);
// Test breaking on a breakpoint // Test breaking on a breakpoint
yield addBreakpoint(dbg, "entry.js", 15); yield addBreakpoint(dbg, "entry.js", 15);
is(getBreakpoints(getState()).size, 2, "Two breakpoints exist"); is(getBreakpoints(getState()).size, 2, "Two breakpoints exist");
ok(getBreakpoint(getState(), { sourceId: entrySrc.id, line: 15 }), ok(
"Breakpoint has correct line"); getBreakpoint(getState(), { sourceId: entrySrc.id, line: 15 }),
"Breakpoint has correct line"
);
invokeInTab("keepMeAlive"); invokeInTab("keepMeAlive");
yield waitForPaused(dbg); yield waitForPaused(dbg);

View File

@ -6,7 +6,10 @@
// This source map does not have source contents, so it's fetched separately // This source map does not have source contents, so it's fetched separately
add_task(function* () { add_task(function*() {
// NOTE: the CORS call makes the test run times inconsistent
requestLongerTimeout(2);
const dbg = yield initDebugger("doc-sourcemaps2.html"); const dbg = yield initDebugger("doc-sourcemaps2.html");
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg; const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
@ -20,8 +23,10 @@ add_task(function* () {
// Test that breakpoint is not off by a line. // Test that breakpoint is not off by a line.
yield addBreakpoint(dbg, mainSrc, 4); yield addBreakpoint(dbg, mainSrc, 4);
is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
ok(getBreakpoint(getState(), { sourceId: mainSrc.id, line: 4 }), ok(
"Breakpoint has correct line"); getBreakpoint(getState(), { sourceId: mainSrc.id, line: 4 }),
"Breakpoint has correct line"
);
invokeInTab("logMessage"); invokeInTab("logMessage");

View File

@ -6,6 +6,7 @@
<body> <body>
<script> <script>
debugger; debugger;
// This inline script allows this HTML page to show up as a // This inline script allows this HTML page to show up as a
// source. It also needs to introduce a new global variable so // source. It also needs to introduce a new global variable so
// it's not immediately garbage collected. // it's not immediately garbage collected.

View File

@ -33,13 +33,14 @@
*/ */
// shared-head.js handles imports, constants, and utility functions // shared-head.js handles imports, constants, and utility functions
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js", this); Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
this
);
var { Toolbox } = require("devtools/client/framework/toolbox"); var { Toolbox } = require("devtools/client/framework/toolbox");
const EXAMPLE_URL = "http://example.com/browser/devtools/client/debugger/new/test/mochitest/examples/"; const EXAMPLE_URL = "http://example.com/browser/devtools/client/debugger/new/test/mochitest/examples/";
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", true); Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", true);
Services.prefs.clearUserPref("devtools.debugger.tabs")
Services.prefs.clearUserPref("devtools.debugger.pending-selected-location")
registerCleanupFunction(() => { registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend"); Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
@ -76,9 +77,9 @@ function _afterDispatchDone(store, type) {
type: "@@service/waitUntil", type: "@@service/waitUntil",
predicate: action => { predicate: action => {
if (action.type === type) { if (action.type === type) {
return action.status ? return action.status
(action.status === "done" || action.status === "error") : ? action.status === "done" || action.status === "error"
true; : true;
} }
}, },
run: (dispatch, getState, action) => { run: (dispatch, getState, action) => {
@ -102,7 +103,7 @@ function _afterDispatchDone(store, type) {
function waitForDispatch(dbg, type, eventRepeat = 1) { function waitForDispatch(dbg, type, eventRepeat = 1) {
let count = 0; let count = 0;
return Task.spawn(function* () { return Task.spawn(function*() {
info("Waiting for " + type + " to dispatch " + eventRepeat + " time(s)"); info("Waiting for " + type + " to dispatch " + eventRepeat + " time(s)");
while (count < eventRepeat) { while (count < eventRepeat) {
yield _afterDispatchDone(dbg.store, type); yield _afterDispatchDone(dbg.store, type);
@ -170,21 +171,23 @@ function waitForSources(dbg, ...sources) {
info("Waiting on sources: " + sources.join(", ")); info("Waiting on sources: " + sources.join(", "));
const { selectors: { getSources }, store } = dbg; const { selectors: { getSources }, store } = dbg;
return Promise.all(sources.map(url => { return Promise.all(
function sourceExists(state) { sources.map(url => {
return getSources(state).some(s => { function sourceExists(state) {
return s.get("url").includes(url); return getSources(state).some(s => {
}); return s.get("url").includes(url);
} });
}
if (!sourceExists(store.getState())) { if (!sourceExists(store.getState())) {
return waitForState(dbg, sourceExists); return waitForState(dbg, sourceExists);
} }
})); })
);
} }
function waitForElement(dbg, selector) { function waitForElement(dbg, selector) {
return waitUntil(() => findElementWithSelector(dbg, selector)) return waitUntil(() => findElementWithSelector(dbg, selector));
} }
/** /**
@ -209,8 +212,10 @@ function assertPausedLocation(dbg, source, line) {
is(location.get("line"), line); is(location.get("line"), line);
// Check the debug line // Check the debug line
ok(dbg.win.cm.lineInfo(line - 1).wrapClass.includes("debug-line"), ok(
"Line is highlighted as paused"); dbg.win.cm.lineInfo(line - 1).wrapClass.includes("debug-line"),
"Line is highlighted as paused"
);
} }
/** /**
@ -232,10 +237,14 @@ function assertHighlightLocation(dbg, source, line) {
// Check the highlight line // Check the highlight line
const lineEl = findElement(dbg, "highlightLine"); const lineEl = findElement(dbg, "highlightLine");
ok(lineEl, "Line is highlighted"); ok(lineEl, "Line is highlighted");
// ok(isVisibleWithin(findElement(dbg, "codeMirror"), lineEl), ok(
// "Highlighted line is visible"); isVisibleWithin(findElement(dbg, "codeMirror"), lineEl),
ok(dbg.win.cm.lineInfo(line - 1).wrapClass.includes("highlight-line"), "Highlighted line is visible"
"Line is highlighted"); );
ok(
dbg.win.cm.lineInfo(line - 1).wrapClass.includes("highlight-line"),
"Line is highlighted"
);
} }
/** /**
@ -258,12 +267,11 @@ function isPaused(dbg) {
* @static * @static
*/ */
function waitForPaused(dbg) { function waitForPaused(dbg) {
return Task.spawn(function* () { return Task.spawn(function*() {
// We want to make sure that we get both a real paused event and // We want to make sure that we get both a real paused event and
// that the state is fully populated. The client may do some more // that the state is fully populated. The client may do some more
// work (call other client methods) before populating the state. // work (call other client methods) before populating the state.
yield waitForThreadEvents(dbg, "paused"), yield waitForThreadEvents(dbg, "paused"), yield waitForState(dbg, state => {
yield waitForState(dbg, state => {
const pause = dbg.selectors.getPause(state); const pause = dbg.selectors.getPause(state);
// Make sure we have the paused state. // Make sure we have the paused state.
if (!pause) { if (!pause) {
@ -279,15 +287,16 @@ function waitForPaused(dbg) {
} }
function createDebuggerContext(toolbox) { function createDebuggerContext(toolbox) {
const win = toolbox.getPanel("jsdebugger").panelWin; const panel = toolbox.getPanel("jsdebugger");
const store = win.Debugger.store; const win = panel.panelWin;
const { store, client, selectors, actions } = panel.getVarsForTests();
return { return {
actions: win.Debugger.actions, actions: actions,
selectors: win.Debugger.selectors, selectors: selectors,
getState: store.getState, getState: store.getState,
store: store, store: store,
client: win.Debugger.client, client: client,
toolbox: toolbox, toolbox: toolbox,
win: win win: win
}; };
@ -303,9 +312,13 @@ function createDebuggerContext(toolbox) {
* @static * @static
*/ */
function initDebugger(url, ...sources) { function initDebugger(url, ...sources) {
return Task.spawn(function* () { return Task.spawn(function*() {
Services.prefs.clearUserPref("devtools.debugger.tabs") Services.prefs.clearUserPref("devtools.debugger.pause-on-exceptions");
Services.prefs.clearUserPref("devtools.debugger.pending-selected-location") Services.prefs.clearUserPref("devtools.debugger.ignore-caught-exceptions");
Services.prefs.clearUserPref("devtools.debugger.tabs");
Services.prefs.clearUserPref("devtools.debugger.pending-selected-location");
Services.prefs.clearUserPref("devtools.debugger.pending-breakpoints");
Services.prefs.clearUserPref("devtools.debugger.expressions");
const toolbox = yield openNewTabAndToolbox(EXAMPLE_URL + url, "jsdebugger"); const toolbox = yield openNewTabAndToolbox(EXAMPLE_URL + url, "jsdebugger");
return createDebuggerContext(toolbox); return createDebuggerContext(toolbox);
}); });
@ -429,6 +442,11 @@ function resume(dbg) {
return waitForThreadEvents(dbg, "resumed"); return waitForThreadEvents(dbg, "resumed");
} }
function deleteExpression(dbg, input) {
info("Resuming");
return dbg.actions.deleteExpression({ input });
}
/** /**
* Reloads the debuggee. * Reloads the debuggee.
* *
@ -500,8 +518,11 @@ function removeBreakpoint(dbg, sourceId, line, col) {
* @return {Promise} * @return {Promise}
* @static * @static
*/ */
function togglePauseOnExceptions(dbg, function togglePauseOnExceptions(
pauseOnExceptions, ignoreCaughtExceptions) { dbg,
pauseOnExceptions,
ignoreCaughtExceptions
) {
const command = dbg.actions.pauseOnExceptions( const command = dbg.actions.pauseOnExceptions(
pauseOnExceptions, pauseOnExceptions,
ignoreCaughtExceptions ignoreCaughtExceptions
@ -526,7 +547,7 @@ function togglePauseOnExceptions(dbg,
*/ */
function invokeInTab(fnc) { function invokeInTab(fnc) {
info(`Invoking function ${fnc} in tab`); info(`Invoking function ${fnc} in tab`);
return ContentTask.spawn(gBrowser.selectedBrowser, fnc, function* (fnc) { return ContentTask.spawn(gBrowser.selectedBrowser, fnc, function*(fnc) {
content.wrappedJSObject[fnc](); // eslint-disable-line mozilla/no-cpows-in-tests, max-len content.wrappedJSObject[fnc](); // eslint-disable-line mozilla/no-cpows-in-tests, max-len
}); });
} }
@ -534,18 +555,21 @@ function invokeInTab(fnc) {
const isLinux = Services.appinfo.OS === "Linux"; const isLinux = Services.appinfo.OS === "Linux";
const cmdOrCtrl = isLinux ? { ctrlKey: true } : { metaKey: true }; const cmdOrCtrl = isLinux ? { ctrlKey: true } : { metaKey: true };
const keyMappings = { const keyMappings = {
sourceSearch: { code: "p", modifiers: cmdOrCtrl}, sourceSearch: { code: "p", modifiers: cmdOrCtrl },
fileSearch: { code: "f", modifiers: cmdOrCtrl}, fileSearch: { code: "f", modifiers: cmdOrCtrl },
"Enter": { code: "VK_RETURN" }, Enter: { code: "VK_RETURN" },
"Up": { code: "VK_UP" }, Up: { code: "VK_UP" },
"Down": { code: "VK_DOWN" }, Down: { code: "VK_DOWN" },
"Tab": { code: "VK_TAB" }, Tab: { code: "VK_TAB" },
"Escape": { code: "VK_ESCAPE" }, Escape: { code: "VK_ESCAPE" },
pauseKey: { code: "VK_F8" }, pauseKey: { code: "VK_F8" },
resumeKey: { code: "VK_F8" }, resumeKey: { code: "VK_F8" },
stepOverKey: { code: "VK_F10" }, stepOverKey: { code: "VK_F10" },
stepInKey: { code: "VK_F11", modifiers: { ctrlKey: isLinux }}, stepInKey: { code: "VK_F11", modifiers: { ctrlKey: isLinux } },
stepOutKey: { code: "VK_F11", modifiers: { ctrlKey: isLinux, shiftKey: true }} stepOutKey: {
code: "VK_F11",
modifiers: { ctrlKey: isLinux, shiftKey: true }
}
}; };
/** /**
@ -561,11 +585,7 @@ function pressKey(dbg, keyName) {
let keyEvent = keyMappings[keyName]; let keyEvent = keyMappings[keyName];
const { code, modifiers } = keyEvent; const { code, modifiers } = keyEvent;
return EventUtils.synthesizeKey( return EventUtils.synthesizeKey(code, modifiers || {}, dbg.win);
code,
modifiers || {},
dbg.win
);
} }
function type(dbg, string) { function type(dbg, string) {
@ -577,14 +597,19 @@ function type(dbg, string) {
function isVisibleWithin(outerEl, innerEl) { function isVisibleWithin(outerEl, innerEl) {
const innerRect = innerEl.getBoundingClientRect(); const innerRect = innerEl.getBoundingClientRect();
const outerRect = outerEl.getBoundingClientRect(); const outerRect = outerEl.getBoundingClientRect();
return innerRect.top > outerRect.top && innerRect.bottom < outerRect.bottom;
return innerRect.top > outerRect.top &&
innerRect.bottom < outerRect.bottom;
} }
const selectors = { const selectors = {
callStackHeader: ".call-stack-pane ._header", callStackHeader: ".call-stack-pane ._header",
callStackBody: ".call-stack-pane .pane", callStackBody: ".call-stack-pane .pane",
expressionNode: i =>
`.expressions-list .tree-node:nth-child(${i}) .object-label`,
expressionValue: i =>
`.expressions-list .tree-node:nth-child(${i}) .object-value`,
expressionClose: i =>
`.expressions-list .expression-container:nth-child(${i}) .close`,
expressionNodes: ".expressions-list .tree-node",
scopesHeader: ".scopes-pane ._header", scopesHeader: ".scopes-pane ._header",
breakpointItem: i => `.breakpoints-list .breakpoint:nth-child(${i})`, breakpointItem: i => `.breakpoints-list .breakpoint:nth-child(${i})`,
scopeNode: i => `.scopes-list .tree-node:nth-child(${i}) .object-label`, scopeNode: i => `.scopes-list .tree-node:nth-child(${i}) .object-label`,
@ -605,7 +630,7 @@ const selectors = {
sourceFooter: ".source-footer", sourceFooter: ".source-footer",
sourceNode: i => `.sources-list .tree-node:nth-child(${i})`, sourceNode: i => `.sources-list .tree-node:nth-child(${i})`,
sourceNodes: ".sources-list .tree-node", sourceNodes: ".sources-list .tree-node",
sourceArrow: i => `.sources-list .tree-node:nth-child(${i}) .arrow`, sourceArrow: i => `.sources-list .tree-node:nth-child(${i}) .arrow`
}; };
function getSelector(elementName, ...args) { function getSelector(elementName, ...args) {
@ -647,6 +672,9 @@ function findAllElements(dbg, elementName, ...args) {
*/ */
function clickElement(dbg, elementName, ...args) { function clickElement(dbg, elementName, ...args) {
const selector = getSelector(elementName, ...args); const selector = getSelector(elementName, ...args);
const el = findElement(dbg, elementName, ...args);
el.scrollIntoView();
return EventUtils.synthesizeMouseAtCenter( return EventUtils.synthesizeMouseAtCenter(
findElementWithSelector(dbg, selector), findElementWithSelector(dbg, selector),
{}, {},
@ -654,12 +682,22 @@ function clickElement(dbg, elementName, ...args) {
); );
} }
function dblClickElement(dbg, elementName, ...args) {
const selector = getSelector(elementName, ...args);
return EventUtils.synthesizeMouseAtCenter(
findElementWithSelector(dbg, selector),
{ clickCount: 2 },
dbg.win
);
}
function rightClickElement(dbg, elementName, ...args) { function rightClickElement(dbg, elementName, ...args) {
const selector = getSelector(elementName, ...args); const selector = getSelector(elementName, ...args);
const doc = dbg.win.document; const doc = dbg.win.document;
return EventUtils.synthesizeMouseAtCenter( return EventUtils.synthesizeMouseAtCenter(
doc.querySelector(selector), doc.querySelector(selector),
{type: "contextmenu"}, { type: "contextmenu" },
dbg.win dbg.win
); );
} }
@ -669,10 +707,10 @@ function selectMenuItem(dbg, index) {
const doc = dbg.toolbox.win.document; const doc = dbg.toolbox.win.document;
// there are several context menus, we want the one with the menu-api // there are several context menus, we want the one with the menu-api
const popup = doc.querySelector("menupopup[menu-api=\"true\"]"); const popup = doc.querySelector('menupopup[menu-api="true"]');
const item = popup.querySelector(`menuitem:nth-child(${index})`); const item = popup.querySelector(`menuitem:nth-child(${index})`);
return EventUtils.synthesizeMouseAtCenter(item, {}, dbg.toolbox.win ); return EventUtils.synthesizeMouseAtCenter(item, {}, dbg.toolbox.win);
} }
/** /**

View File

@ -584,6 +584,8 @@ function loadTelemetryAndRecordLogs() {
this.telemetryInfo[histogramId].push(value); this.telemetryInfo[histogramId].push(value);
} }
}; };
Telemetry.prototype._oldlogScalar = Telemetry.prototype.logScalar;
Telemetry.prototype.logScalar = Telemetry.prototype.log;
Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed; Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed;
Telemetry.prototype.logKeyed = function (histogramId, key, value) { Telemetry.prototype.logKeyed = function (histogramId, key, value) {
this.log(`${histogramId}|${key}`, value); this.log(`${histogramId}|${key}`, value);
@ -600,8 +602,10 @@ function loadTelemetryAndRecordLogs() {
function stopRecordingTelemetryLogs(Telemetry) { function stopRecordingTelemetryLogs(Telemetry) {
info("Stopping Telemetry"); info("Stopping Telemetry");
Telemetry.prototype.log = Telemetry.prototype._oldlog; Telemetry.prototype.log = Telemetry.prototype._oldlog;
Telemetry.prototype.logScalar = Telemetry.prototype._oldlogScalar;
Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed; Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed;
delete Telemetry.prototype._oldlog; delete Telemetry.prototype._oldlog;
delete Telemetry.prototype._oldlogScalar;
delete Telemetry.prototype._oldlogKeyed; delete Telemetry.prototype._oldlogKeyed;
delete Telemetry.prototype.telemetryInfo; delete Telemetry.prototype.telemetryInfo;
} }

View File

@ -6,6 +6,8 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that the various copy items in the context menu works correctly. // Test that the various copy items in the context menu works correctly.
const TEST_URL = URL_ROOT + "doc_inspector_menu.html"; const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
const SELECTOR_UNIQUE = "devtools.copy.unique.css.selector.opened";
const SELECTOR_FULL = "devtools.copy.full.css.selector.opened";
const COPY_ITEMS_TEST_DATA = [ const COPY_ITEMS_TEST_DATA = [
{ {
desc: "copy inner html", desc: "copy inner html",
@ -26,7 +28,7 @@ const COPY_ITEMS_TEST_DATA = [
text: "body > div:nth-child(1) > p:nth-child(2)", text: "body > div:nth-child(1) > p:nth-child(2)",
}, },
{ {
desc: "copy css path", desc: "copy CSS path",
id: "node-menu-copycsspath", id: "node-menu-copycsspath",
selector: "[data-id=\"copy\"]", selector: "[data-id=\"copy\"]",
text: "html body div p", text: "html body div p",
@ -41,7 +43,9 @@ const COPY_ITEMS_TEST_DATA = [
]; ];
add_task(function* () { add_task(function* () {
let Telemetry = loadTelemetryAndRecordLogs();
let { inspector } = yield openInspectorForURL(TEST_URL); let { inspector } = yield openInspectorForURL(TEST_URL);
for (let {desc, id, selector, text} of COPY_ITEMS_TEST_DATA) { for (let {desc, id, selector, text} of COPY_ITEMS_TEST_DATA) {
info("Testing " + desc); info("Testing " + desc);
yield selectNode(selector, inspector); yield selectNode(selector, inspector);
@ -52,4 +56,32 @@ add_task(function* () {
yield waitForClipboardPromise(() => item.click(), text); yield waitForClipboardPromise(() => item.click(), text);
} }
checkTelemetryResults(Telemetry);
stopRecordingTelemetryLogs(Telemetry);
}); });
function checkTelemetryResults(Telemetry) {
let data = Telemetry.prototype.telemetryInfo;
let results = new Map();
for (let key in data) {
if (key.toLowerCase() === key) {
let pings = data[key].length;
results.set(key, pings);
}
}
is(results.size, 2, "The correct number of scalars were logged");
let pings = checkPings(SELECTOR_UNIQUE, results);
is(pings, 1, `${SELECTOR_UNIQUE} has just 1 ping`);
pings = checkPings(SELECTOR_FULL, results);
is(pings, 1, `${SELECTOR_FULL} has just 1 ping`);
}
function checkPings(scalarId, results) {
return results.get(scalarId);
}

View File

@ -128,14 +128,14 @@ multiProcessWarningTitle = Service Worker debugging is not compatible with multi
# LOCALIZATION NOTE (multiProcessWarningMessage): # LOCALIZATION NOTE (multiProcessWarningMessage):
# This string is displayed in the warning section for multi-e10s in # This string is displayed in the warning section for multi-e10s in
# about:debugging#workers # about:debugging#workers
multiProcessWarningMessage = The preference “dom.ipc.processCount” can be set to 1 to force a single content process. multiProcessWarningMessage2 = The preference “dom.ipc.multiOptOut” can be modified to force a single content process for the current version.
# LOCALIZATION NOTE (multiProcessWarningLink): # LOCALIZATION NOTE (multiProcessWarningLink):
# This string is the text content of a link in the warning section for multi-e10s in # This string is the text content of a link in the warning section for multi-e10s in
# about:debugging#workers. The link updates the pref and restarts the browser. # about:debugging#workers. The link updates the pref and restarts the browser.
multiProcessWarningUpdateLink = Set dom.ipc.processCount to 1 multiProcessWarningUpdateLink2 = Opt out of multiple content processes
# LOCALIZATION NOTE (multiProcessWarningConfirmUpdate): # LOCALIZATION NOTE (multiProcessWarningConfirmUpdate):
# This string is displayed as a confirmation message when the user clicks on # This string is displayed as a confirmation message when the user clicks on
# the multiProcessWarningUpdateLink in about:debugging#workers # the multiProcessWarningUpdateLink in about:debugging#workers
multiProcessWarningConfirmUpdate = Set “dom.ipc.processCount” to 1 and restart the browser? multiProcessWarningConfirmUpdate2 = Opt out of multiple processes?

View File

@ -115,15 +115,19 @@ timeEvents=Time
touchEvents=Touch touchEvents=Touch
otherEvents=Other otherEvents=Other
# LOCALIZATION NOTE (blackBoxCheckboxTooltip): The tooltip text to display when # LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when
# the user hovers over the checkbox used to toggle black boxing its associated # the user hovers over the checkbox used to toggle blackboxing its associated
# source. # source.
blackBoxCheckboxTooltip=Toggle black boxing blackboxCheckboxTooltip2=Toggle blackboxing
# LOCALIZATION NOTE (sources.search.key): Key shortcut to open the search for # LOCALIZATION NOTE (sources.search.key): Key shortcut to open the search for
# searching all the source files the debugger has seen. # searching all the source files the debugger has seen.
sources.search.key=P sources.search.key=P
# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger
# does not have any sources.
sources.noSourcesAvailable=This page has no sources
# LOCALIZATION NOTE (sources.searchAlt.key): Alternate key shortcut to open # LOCALIZATION NOTE (sources.searchAlt.key): Alternate key shortcut to open
# the search for searching all the source files the debugger has seen. # the search for searching all the source files the debugger has seen.
sources.searchAlt.key=O sources.searchAlt.key=O
@ -235,10 +239,17 @@ callStack.expand=Expand Rows
# for the summarizing the selected search result. e.g. 5 of 10 results. # for the summarizing the selected search result. e.g. 5 of 10 results.
editor.searchResults=%d of %d results editor.searchResults=%d of %d results
# LOCALIZATION NOTE (sourceSearch.singleResult): Copy shown when there is one result.
editor.singleResult=1 result
# LOCALIZATION NOTE (editor.noResults): Editor Search bar message # LOCALIZATION NOTE (editor.noResults): Editor Search bar message
# for when no results found. # for when no results found.
editor.noResults=no results editor.noResults=no results
# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for
# toggling search type buttons(function search, variable search)
editor.searchTypeToggleTitle=Search for:
# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item # LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item
# for adding a breakpoint on a line. # for adding a breakpoint on a line.
editor.addBreakpoint=Add Breakpoint editor.addBreakpoint=Add Breakpoint
@ -341,6 +352,22 @@ sourceTabs.prettyPrint=Pretty Print Source
# the editor context menu. # the editor context menu.
sourceTabs.prettyPrint.accesskey=p sourceTabs.prettyPrint.accesskey=p
# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated
# with the blackbox button
sourceFooter.blackbox=Blackbox Source
# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated
# with the blackbox button
sourceFooter.unblackbox=Unblackbox Source
# LOCALIZATION NOTE (sourceFooter.blackbox.accesskey): Access key to blackbox
# an associated source
sourceFooter.blackbox.accesskey=b
# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated
# with a blackboxed source
sourceFooter.blackboxed=Blackboxed Source
# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed # LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed
# for close tab button in source tabs. # for close tab button in source tabs.
sourceTabs.closeTabButtonTooltip=Close tab sourceTabs.closeTabButtonTooltip=Close tab
@ -393,10 +420,6 @@ sourceSearch.search=Search Sources…
# message when the query did not match any of the sources. # message when the query did not match any of the sources.
sourceSearch.noResults=No files matching %S found sourceSearch.noResults=No files matching %S found
# LOCALIZATION NOTE (sourceFooter.debugBtnTooltip): Tooltip text associated
# with the pretty-print button
sourceFooter.debugBtnTooltip=Prettify Source
# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip # LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip
# when the debugger will not pause on exceptions. # when the debugger will not pause on exceptions.
ignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions ignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions
@ -508,8 +531,30 @@ watchExpressionsSeparatorLabel2=\u0020→
# in the functions search panel as a separator between function's inferred name # in the functions search panel as a separator between function's inferred name
# and its real name (if available). # and its real name (if available).
functionSearchSeparatorLabel= functionSearchSeparatorLabel=
functionSearch.search.placeholder=Search Functions…
functionSearch.search.key=O # LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder
# text displayed when the user searches for functions in a file
symbolSearch.search.functionsPlaceholder=Search functions…
# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder
# text displayed when the user searches for variables in a file
symbolSearch.search.variablesPlaceholder=Search variables…
# LOCALIZATION NOTE(symbolSearch.search.key): The shortcut (cmd+shift+o) for
# searching for a function or variable
symbolSearch.search.key=O
# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option
# when searching text in a file
symbolSearch.searchModifier.regex=Regex
# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option
# when searching text in a file
symbolSearch.searchModifier.caseSensitive=Case sensitive
# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option
# when searching text in a file
symbolSearch.searchModifier.wholeWord=Whole word
# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears # LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears
# as a description in the notification panel popup, when multiple debuggers are # as a description in the notification panel popup, when multiple debuggers are
@ -577,3 +622,7 @@ whyPaused.debugCommand=Paused on debugged function
# in a info block explaining how the debugger is currently paused on an event # in a info block explaining how the debugger is currently paused on an event
# listener breakpoint set # listener breakpoint set
whyPaused.other=Debugger paused whyPaused.other=Debugger paused
# LOCALIZATION NOTE (ctrl): The text that is used for documenting
# keyboard shortcuts that use the control key
ctrl=Ctrl

View File

@ -11,7 +11,6 @@
# A good criteria is the language in which you'd find the best # A good criteria is the language in which you'd find the best
# documentation on web development on the web. # documentation on web development on the web.
# LOCALIZATION NOTE (responsiveUI.rotate2): tooltip of the rotate button. # LOCALIZATION NOTE (responsiveUI.rotate2): tooltip of the rotate button.
responsiveUI.rotate2=Rotate responsiveUI.rotate2=Rotate
@ -67,3 +66,13 @@ responsiveUI.notificationReload=Reload
responsiveUI.notificationReload_accesskey=R responsiveUI.notificationReload_accesskey=R
responsiveUI.dontShowReloadNotification=Never show again responsiveUI.dontShowReloadNotification=Never show again
responsiveUI.dontShowReloadNotification_accesskey=N responsiveUI.dontShowReloadNotification_accesskey=N
# LOCALIZATION NOTE (responsiveUI.newVersionUserDisabled): notification that appears
# when old RDM is displayed because the user has disabled new RDM.
responsiveUI.newVersionUserDisabled=A new version of Responsive Design Mode is available, but it appears to be disabled. Please enable it and provide feedback, as this version will be removed.
# LOCALIZATION NOTE (responsiveUI.newVersionE10sDisabled): notification that appears
# when old RDM is displayed because e10s is disabled.
responsiveUI.newVersionE10sDisabled=A new version of Responsive Design Mode is available, but it requires multi-process mode, which is currently disabled. Please enable it and provide feedback, as this version will be removed.
# LOCALIZATION NOTE (responsiveUI.newVersionEnableAndRestart): button text in notification
# to enable new RDM itself or e10s as a prerequisite for new RDM.
responsiveUI.newVersionEnableAndRestart=Enable and Restart

View File

@ -1,7 +1,5 @@
# -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /* Any copyright is dedicated to the Public Domain.
# This Source Code Form is subject to the terms of the Mozilla Public * http://creativecommons.org/publicdomain/zero/1.0/ */
# 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/.
#ifdef RELEASE_OR_BETA #ifdef RELEASE_OR_BETA
pref("devtools.debugger.new-debugger-frontend", false); pref("devtools.debugger.new-debugger-frontend", false);
@ -17,7 +15,7 @@ pref("devtools.debugger.chrome-debugging-websocket", false);
pref("devtools.debugger.remote-host", "localhost"); pref("devtools.debugger.remote-host", "localhost");
pref("devtools.debugger.remote-timeout", 20000); pref("devtools.debugger.remote-timeout", 20000);
pref("devtools.debugger.pause-on-exceptions", false); pref("devtools.debugger.pause-on-exceptions", false);
pref("devtools.debugger.ignore-caught-exceptions", true); pref("devtools.debugger.ignore-caught-exceptions", false);
pref("devtools.debugger.source-maps-enabled", true); pref("devtools.debugger.source-maps-enabled", true);
pref("devtools.debugger.client-source-maps-enabled", true); pref("devtools.debugger.client-source-maps-enabled", true);
pref("devtools.debugger.pretty-print-enabled", true); pref("devtools.debugger.pretty-print-enabled", true);
@ -38,4 +36,5 @@ pref("devtools.debugger.start-panel-collapsed", false);
pref("devtools.debugger.end-panel-collapsed", false); pref("devtools.debugger.end-panel-collapsed", false);
pref("devtools.debugger.tabs", "[]"); pref("devtools.debugger.tabs", "[]");
pref("devtools.debugger.pending-selected-location", "{}"); pref("devtools.debugger.pending-selected-location", "{}");
pref("devtools.debugger.pending-breakpoints", "[]");
pref("devtools.debugger.expressions", "[]");

View File

@ -14,6 +14,8 @@ const EventEmitter = require("devtools/shared/event-emitter");
loader.lazyImporter(this, "SystemAppProxy", loader.lazyImporter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm"); "resource://gre/modules/SystemAppProxy.jsm");
loader.lazyImporter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry"); loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
loader.lazyRequireGetter(this, "showDoorhanger", loader.lazyRequireGetter(this, "showDoorhanger",
"devtools/client/shared/doorhanger", true); "devtools/client/shared/doorhanger", true);
@ -27,9 +29,12 @@ loader.lazyRequireGetter(this, "DebuggerClient",
"devtools/shared/client/main", true); "devtools/shared/client/main", true);
loader.lazyRequireGetter(this, "DebuggerServer", loader.lazyRequireGetter(this, "DebuggerServer",
"devtools/server/main", true); "devtools/server/main", true);
loader.lazyRequireGetter(this, "system", "devtools/shared/system");
this.EXPORTED_SYMBOLS = ["ResponsiveUIManager"]; this.EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
const NEW_RDM_ENABLED = "devtools.responsive.html.enabled";
const MIN_WIDTH = 50; const MIN_WIDTH = 50;
const MIN_HEIGHT = 50; const MIN_HEIGHT = 50;
@ -136,7 +141,7 @@ EventEmitter.decorate(Manager);
// the new HTML RDM UI to function), delegate the ResponsiveUIManager API over to that // the new HTML RDM UI to function), delegate the ResponsiveUIManager API over to that
// tool instead. Performing this delegation here allows us to contain the pref check to a // tool instead. Performing this delegation here allows us to contain the pref check to a
// single place. // single place.
if (Services.prefs.getBoolPref("devtools.responsive.html.enabled") && if (Services.prefs.getBoolPref(NEW_RDM_ENABLED) &&
Services.appinfo.browserTabsRemoteAutostart) { Services.appinfo.browserTabsRemoteAutostart) {
let { ResponsiveUIManager } = let { ResponsiveUIManager } =
require("devtools/client/responsive.html/manager"); require("devtools/client/responsive.html/manager");
@ -266,6 +271,8 @@ ResponsiveUI.prototype = {
anchor: this.chromeDoc.querySelector("#content") anchor: this.chromeDoc.querySelector("#content")
}); });
this.showNewUINotification();
// Notify that responsive mode is on. // Notify that responsive mode is on.
this._telemetry.toolOpened("responsive"); this._telemetry.toolOpened("responsive");
ResponsiveUIManager.emit("on", { tab: this.tab }); ResponsiveUIManager.emit("on", { tab: this.tab });
@ -399,12 +406,14 @@ ResponsiveUI.prototype = {
this._telemetry.toolClosed("responsive"); this._telemetry.toolClosed("responsive");
if (this.tab.linkedBrowser.messageManager) { if (this.tab.linkedBrowser && this.tab.linkedBrowser.messageManager) {
let stopped = this.waitForMessage("ResponsiveMode:Stop:Done"); let stopped = this.waitForMessage("ResponsiveMode:Stop:Done");
this.tab.linkedBrowser.messageManager.sendAsyncMessage("ResponsiveMode:Stop"); this.tab.linkedBrowser.messageManager.sendAsyncMessage("ResponsiveMode:Stop");
yield stopped; yield stopped;
} }
this.hideNewUINotification();
this.inited = null; this.inited = null;
ResponsiveUIManager.emit("off", { tab: this.tab }); ResponsiveUIManager.emit("off", { tab: this.tab });
}), }),
@ -683,6 +692,69 @@ ResponsiveUI.prototype = {
this.container.appendChild(bottomToolbar); this.container.appendChild(bottomToolbar);
}, },
showNewUINotification() {
let nbox = this.mainWindow.gBrowser.getNotificationBox(this.browser);
// One reason we might be using old RDM is that the user explcitly disabled new RDM.
// We should encourage them to use the new one, since the old one will be removed.
if (Services.prefs.prefHasUserValue(NEW_RDM_ENABLED) &&
!Services.prefs.getBoolPref(NEW_RDM_ENABLED)) {
let buttons = [{
label: this.strings.GetStringFromName("responsiveUI.newVersionEnableAndRestart"),
callback: () => {
Services.prefs.setBoolPref(NEW_RDM_ENABLED, true);
BrowserUtils.restartApplication();
},
}];
nbox.appendNotification(
this.strings.GetStringFromName("responsiveUI.newVersionUserDisabled"),
"responsive-ui-new-version-user-disabled",
null,
nbox.PRIORITY_INFO_LOW,
buttons
);
return;
}
// Only show a notification about the new RDM UI on channels where there is an e10s
// switch in the preferences UI (Dev. Ed, Nightly). On other channels, it is less
// clear how a user would proceed here, so don't show a message.
if (!system.constants.E10S_TESTING_ONLY) {
return;
}
let buttons = [{
label: this.strings.GetStringFromName("responsiveUI.newVersionEnableAndRestart"),
callback: () => {
Services.prefs.setBoolPref("browser.tabs.remote.autostart", true);
Services.prefs.setBoolPref("browser.tabs.remote.autostart.2", true);
BrowserUtils.restartApplication();
},
}];
nbox.appendNotification(
this.strings.GetStringFromName("responsiveUI.newVersionE10sDisabled"),
"responsive-ui-new-version-e10s-disabled",
null,
nbox.PRIORITY_INFO_LOW,
buttons
);
},
hideNewUINotification() {
if (!this.mainWindow.gBrowser || !this.mainWindow.gBrowser.getNotificationBox) {
return;
}
let nbox = this.mainWindow.gBrowser.getNotificationBox(this.browser);
let n = nbox.getNotificationWithValue("responsive-ui-new-version-user-disabled");
if (n) {
n.close();
}
n = nbox.getNotificationWithValue("responsive-ui-new-version-e10s-disabled");
if (n) {
n.close();
}
},
/** /**
* Validate and apply any user input on the editable menulist * Validate and apply any user input on the editable menulist
*/ */

File diff suppressed because it is too large Load Diff

View File

@ -69,7 +69,3 @@ function testRepRenderModes(modeTests, testName, componentUnderTest, gripStub,
is(rendered.textContent, expectedOutput, message); is(rendered.textContent, expectedOutput, message);
}); });
} }
function getStubAttachedActorIds(gripStubs) {
return gripStubs.map(gripStub => gripStub.actor);
}

View File

@ -20,8 +20,12 @@ Test ArrayRep rep
/* import-globals-from head.js */ /* import-globals-from head.js */
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, ArrayRep } = REPS; REPS,
MODE,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { ArrayRep } = REPS;
let componentUnderTest = ArrayRep; let componentUnderTest = ArrayRep;
const maxLength = { const maxLength = {
@ -52,9 +56,7 @@ window.onload = Task.async(function* () {
function testBasic() { function testBasic() {
// Test that correct rep is chosen // Test that correct rep is chosen
const stub = []; const stub = [];
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), ArrayRep.rep, "Rep correctly selects Array Rep");
is(renderedRep.type, ArrayRep.rep,
`Rep correctly selects ${ArrayRep.rep.displayName}`);
// Test rendering // Test rendering

View File

@ -17,8 +17,11 @@ Test Attribute rep
<script src="head.js" type="application/javascript"></script> <script src="head.js" type="application/javascript"></script>
<script type="application/javascript"> <script type="application/javascript">
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, Attribute } = REPS; REPS,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { Attribute } = REPS;
try { try {
testBasic(); testBasic();
@ -31,8 +34,7 @@ window.onload = Task.async(function* () {
function testBasic() { function testBasic() {
// Test that correct rep is chosen // Test that correct rep is chosen
const renderedRep = shallowRenderComponent(Rep, { object: getStub() }); is(getRep(getStub()), Attribute.rep, "Rep correctly selects Attribute Rep");
is(renderedRep.type, Attribute.rep, `Rep correctly selects ${Attribute.rep.displayName}`);
// Test rendering // Test rendering
const renderedComponent = renderComponent(Attribute.rep, { object: getStub() }); const renderedComponent = renderComponent(Attribute.rep, { object: getStub() });

View File

@ -20,8 +20,12 @@ Test comment-node rep
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
try { try {
const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, CommentNode } = REPS; REPS,
MODE,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { CommentNode } = REPS;
let gripStub = { let gripStub = {
"type": "object", "type": "object",
@ -40,9 +44,7 @@ window.onload = Task.async(function* () {
}; };
// Test that correct rep is chosen. // Test that correct rep is chosen.
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), CommentNode.rep, "Rep correctly selects CommentNode Rep");
is(renderedRep.type, CommentNode.rep,
`Rep correctly selects ${CommentNode.rep.displayName}`);
// Test rendering. // Test rendering.
const renderedComponent = renderComponent(CommentNode.rep, { object: gripStub }); const renderedComponent = renderComponent(CommentNode.rep, { object: gripStub });

View File

@ -17,8 +17,11 @@ Test DateTime rep
<script src="head.js" type="application/javascript"></script> <script src="head.js" type="application/javascript"></script>
<script type="application/javascript"> <script type="application/javascript">
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, DateTime } = REPS; REPS,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { DateTime } = REPS;
try { try {
testValid(); testValid();
@ -45,12 +48,11 @@ window.onload = Task.async(function* () {
}; };
// Test that correct rep is chosen // Test that correct rep is chosen
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), DateTime.rep, "Rep correctly selects DateTime Rep");
is(renderedRep.type, DateTime.rep, `Rep correctly selects ${DateTime.rep.displayName}`);
// Test rendering // Test rendering
const renderedComponent = renderComponent(DateTime.rep, { object: gripStub }); const renderedComponent = renderComponent(DateTime.rep, { object: gripStub });
is(renderedComponent.textContent, "2016-03-30T21:17:24.859Z", "DateTime rep has expected text content for valid date"); is(renderedComponent.textContent, "Date 2016-03-30T21:17:24.859Z", "DateTime rep has expected text content for valid date");
} }
function testInvalid() { function testInvalid() {

View File

@ -17,8 +17,11 @@ Test Document rep
<script src="head.js" type="application/javascript"></script> <script src="head.js" type="application/javascript"></script>
<script type="application/javascript"> <script type="application/javascript">
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, Document } = REPS; REPS,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { Document } = REPS;
try { try {
testBasic(); testBasic();
@ -31,12 +34,11 @@ window.onload = Task.async(function* () {
function testBasic() { function testBasic() {
// Test that correct rep is chosen // Test that correct rep is chosen
const renderedRep = shallowRenderComponent(Rep, { object: getStub() }); is(getRep(getStub()), Document.rep, "Rep correctly selects Document Rep");
is(renderedRep.type, Document.rep, `Rep correctly selects ${Document.rep.displayName}`);
// Test rendering // Test rendering
const renderedComponent = renderComponent(Document.rep, { object: getStub() }); const renderedComponent = renderComponent(Document.rep, { object: getStub() });
is(renderedComponent.textContent, "https://www.mozilla.org/en-US/firefox/new/", is(renderedComponent.textContent, "HTMLDocument https://www.mozilla.org/en-US/firefox/new/",
"Document rep has expected text content"); "Document rep has expected text content");
} }

View File

@ -22,9 +22,10 @@ window.onload = Task.async(function* () {
const { const {
REPS, REPS,
MODE, MODE,
getRep,
getSelectableInInspectorGrips, getSelectableInInspectorGrips,
} = browserRequire("devtools/client/shared/components/reps/reps"); } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, ElementNode } = REPS; let { ElementNode } = REPS;
try { try {
yield testBodyNode(); yield testBodyNode();
@ -48,9 +49,8 @@ window.onload = Task.async(function* () {
function testBodyNode() { function testBodyNode() {
const stub = getGripStub("testBodyNode"); const stub = getGripStub("testBodyNode");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), ElementNode.rep,
is(renderedRep.type, ElementNode.rep, "Rep correctly selects ElementNode Rep for body node");
`Rep correctly selects ${ElementNode.rep.displayName} for body node`);
const renderedComponent = renderComponent(ElementNode.rep, { object: stub }); const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
is(renderedComponent.textContent, `<body id="body-id" class="body-class">`, is(renderedComponent.textContent, `<body id="body-id" class="body-class">`,
@ -64,9 +64,8 @@ window.onload = Task.async(function* () {
function testDocumentElement() { function testDocumentElement() {
const stub = getGripStub("testDocumentElement"); const stub = getGripStub("testDocumentElement");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), ElementNode.rep,
is(renderedRep.type, ElementNode.rep, "Rep correctly selects ElementNode Rep for document element node");
`Rep correctly selects ${ElementNode.rep.displayName} for document element node`);
const renderedComponent = renderComponent(ElementNode.rep, { object: stub }); const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
is(renderedComponent.textContent, `<html dir="ltr" lang="en-US">`, is(renderedComponent.textContent, `<html dir="ltr" lang="en-US">`,
@ -80,9 +79,8 @@ window.onload = Task.async(function* () {
function testNode() { function testNode() {
const stub = getGripStub("testNode"); const stub = getGripStub("testNode");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), ElementNode.rep,
is(renderedRep.type, ElementNode.rep, "Rep correctly selects ElementNode Rep for element node");
`Rep correctly selects ${ElementNode.rep.displayName} for element node`);
const renderedComponent = renderComponent(ElementNode.rep, { object: stub }); const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -99,9 +97,8 @@ window.onload = Task.async(function* () {
function testNodeWithLeadingAndTrailingSpacesClassName() { function testNodeWithLeadingAndTrailingSpacesClassName() {
const stub = getGripStub("testNodeWithLeadingAndTrailingSpacesClassName"); const stub = getGripStub("testNodeWithLeadingAndTrailingSpacesClassName");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), ElementNode.rep,
is(renderedRep.type, ElementNode.rep, "Rep correctly selects ElementNode Rep for element node");
`Rep correctly selects ${ElementNode.rep.displayName} for element node`);
const renderedComponent = renderComponent(ElementNode.rep, { object: stub }); const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -119,8 +116,7 @@ window.onload = Task.async(function* () {
function testNodeWithoutAttributes() { function testNodeWithoutAttributes() {
const stub = getGripStub("testNodeWithoutAttributes"); const stub = getGripStub("testNodeWithoutAttributes");
const renderedComponent = renderComponent(ElementNode.rep, { object: stub }); is(getRep(stub), ElementNode.rep,
is(renderedComponent.textContent, "<p>",
"Element node rep has expected text content for element node without attributes"); "Element node rep has expected text content for element node without attributes");
const tinyRenderedComponent = renderComponent( const tinyRenderedComponent = renderComponent(
@ -147,8 +143,7 @@ window.onload = Task.async(function* () {
function testSvgNode() { function testSvgNode() {
const stub = getGripStub("testSvgNode"); const stub = getGripStub("testSvgNode");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), ElementNode.rep,
is(renderedRep.type, ElementNode.rep,
`Rep correctly selects ${ElementNode.rep.displayName} for SVG element node`); `Rep correctly selects ${ElementNode.rep.displayName} for SVG element node`);
const renderedComponent = renderComponent(ElementNode.rep, { object: stub }); const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
@ -165,8 +160,7 @@ window.onload = Task.async(function* () {
function testSvgNodeInXHTML() { function testSvgNodeInXHTML() {
const stub = getGripStub("testSvgNodeInXHTML"); const stub = getGripStub("testSvgNodeInXHTML");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), ElementNode.rep,
is(renderedRep.type, ElementNode.rep,
`Rep correctly selects ${ElementNode.rep.displayName} for XHTML SVG element node`); `Rep correctly selects ${ElementNode.rep.displayName} for XHTML SVG element node`);
const renderedComponent = renderComponent(ElementNode.rep, { object: stub }); const renderedComponent = renderComponent(ElementNode.rep, { object: stub });
@ -182,12 +176,9 @@ window.onload = Task.async(function* () {
function testOnMouseOver() { function testOnMouseOver() {
const stub = getGripStub("testNode"); const stub = getGripStub("testNode");
debugger;
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 1, "the stub has one node grip"); is(grips.length, 1, "the stub has one node grip");
const attachedActorIds = getStubAttachedActorIds(grips);
let mouseOverValue; let mouseOverValue;
let onDOMNodeMouseOver = (object) => { let onDOMNodeMouseOver = (object) => {
mouseOverValue = object; mouseOverValue = object;
@ -195,7 +186,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(ElementNode.rep, { const renderedComponent = renderComponent(ElementNode.rep, {
object: stub, object: stub,
onDOMNodeMouseOver, onDOMNodeMouseOver,
attachedActorIds,
}); });
TestUtils.Simulate.mouseOver(renderedComponent); TestUtils.Simulate.mouseOver(renderedComponent);
@ -209,8 +199,6 @@ window.onload = Task.async(function* () {
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 1, "the stub has one node grip"); is(grips.length, 1, "the stub has one node grip");
const attachedActorIds = getStubAttachedActorIds(grips);
let called = false; let called = false;
let onDOMNodeMouseOut = (object) => { let onDOMNodeMouseOut = (object) => {
called = true; called = true;
@ -218,7 +206,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(ElementNode.rep, { const renderedComponent = renderComponent(ElementNode.rep, {
object: stub, object: stub,
onDOMNodeMouseOut, onDOMNodeMouseOut,
attachedActorIds,
}); });
TestUtils.Simulate.mouseOut(renderedComponent); TestUtils.Simulate.mouseOut(renderedComponent);
@ -231,8 +218,6 @@ window.onload = Task.async(function* () {
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 1, "the stub has one node grip"); is(grips.length, 1, "the stub has one node grip");
const attachedActorIds = getStubAttachedActorIds(grips);
let inspectIconClickedValue = null; let inspectIconClickedValue = null;
let inspectIconClickedEvent = null; let inspectIconClickedEvent = null;
@ -242,28 +227,18 @@ window.onload = Task.async(function* () {
}; };
const renderedComponentWithoutInspectIcon = renderComponent(ElementNode.rep, { const renderedComponentWithoutInspectIcon = renderComponent(ElementNode.rep, {
object: stub, object: getGripStub("testDisconnectedNode"),
onInspectIconClick, onInspectIconClick,
attachedActorIds: ["someOtherId"]
}); });
is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null, is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
"There isn't an inspect icon when actor is not in attachedActorIds"); "There isn't an inspect icon when the node is not in the DOM tree");
let renderedComponent = renderComponent(ElementNode.rep, { const renderedComponent = renderComponent(ElementNode.rep, {
object: stub, object: stub,
onInspectIconClick, onInspectIconClick,
}); });
let inspectIconNode = renderedComponent.querySelector(".open-inspector");
ok(inspectIconNode !== null,
"There is an inspect icon when attachedActorIds is not specified");
renderedComponent = renderComponent(ElementNode.rep, { const inspectIconNode = renderedComponent.querySelector(".open-inspector");
object: stub,
onInspectIconClick,
attachedActorIds,
});
inspectIconNode = renderedComponent.querySelector(".open-inspector");
ok(inspectIconNode !== null, "There is an inspect icon as expected"); ok(inspectIconNode !== null, "There is an inspect icon as expected");
TestUtils.Simulate.click(inspectIconNode); TestUtils.Simulate.click(inspectIconNode);
@ -345,6 +320,32 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "input", "nodeName": "input",
"isConnected": true,
"attributes": {
"id": "newtab-customize-button",
"dir": "ltr",
"title": "Customize your New Tab page",
"class": "bar baz",
"value": "foo",
"type": "button"
},
"attributesLength": 6
}
};
case "testDisconnectedNode":
return {
"type": "object",
"actor": "server1.conn2.child1/obj116",
"class": "HTMLInputElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "input",
"isConnected": false,
"attributes": { "attributes": {
"id": "newtab-customize-button", "id": "newtab-customize-button",
"dir": "ltr", "dir": "ltr",

View File

@ -19,8 +19,12 @@ Test Error rep
"use strict"; "use strict";
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, ErrorRep } = REPS; REPS,
MODE,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { ErrorRep } = REPS;
try { try {
// Test errors with different properties // Test errors with different properties
@ -47,9 +51,7 @@ window.onload = Task.async(function* () {
function testSimpleError() { function testSimpleError() {
// Test object = `new Error("Error message")` // Test object = `new Error("Error message")`
const stub = getGripStub("testSimpleError"); const stub = getGripStub("testSimpleError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep, "Rep correctly selects Error Rep for Error object");
is(renderedRep.type, ErrorRep.rep,
`Rep correctly selects ${ErrorRep.rep.displayName} for Error object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -77,9 +79,8 @@ window.onload = Task.async(function* () {
* errorFoo();` * errorFoo();`
*/ */
const stub = getGripStub("testMultilineStackError"); const stub = getGripStub("testMultilineStackError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for Error object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for Error object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -99,9 +100,8 @@ window.onload = Task.async(function* () {
function testErrorWithoutStacktrace() { function testErrorWithoutStacktrace() {
const stub = getGripStub("testErrorWithoutStacktrace"); const stub = getGripStub("testErrorWithoutStacktrace");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for Error object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for Error object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -118,9 +118,8 @@ window.onload = Task.async(function* () {
function testEvalError() { function testEvalError() {
// Test object = `new EvalError("EvalError message")` // Test object = `new EvalError("EvalError message")`
const stub = getGripStub("testEvalError"); const stub = getGripStub("testEvalError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for EvalError object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for EvalError object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -139,9 +138,8 @@ window.onload = Task.async(function* () {
function testInternalError() { function testInternalError() {
// Test object = `new InternalError("InternalError message")` // Test object = `new InternalError("InternalError message")`
const stub = getGripStub("testInternalError"); const stub = getGripStub("testInternalError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for InternalError object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for InternalError object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -160,9 +158,8 @@ window.onload = Task.async(function* () {
function testRangeError() { function testRangeError() {
// Test object = `new RangeError("RangeError message")` // Test object = `new RangeError("RangeError message")`
const stub = getGripStub("testRangeError"); const stub = getGripStub("testRangeError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for RangeError object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for RangeError object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -181,9 +178,8 @@ window.onload = Task.async(function* () {
function testReferenceError() { function testReferenceError() {
// Test object = `new ReferenceError("ReferenceError message"` // Test object = `new ReferenceError("ReferenceError message"`
const stub = getGripStub("testReferenceError"); const stub = getGripStub("testReferenceError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for ReferenceError object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for ReferenceError object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -202,9 +198,8 @@ window.onload = Task.async(function* () {
function testSyntaxError() { function testSyntaxError() {
// Test object = `new SyntaxError("SyntaxError message"` // Test object = `new SyntaxError("SyntaxError message"`
const stub = getGripStub("testSyntaxError"); const stub = getGripStub("testSyntaxError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for SyntaxError object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for SyntaxError object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -223,9 +218,8 @@ window.onload = Task.async(function* () {
function testTypeError() { function testTypeError() {
// Test object = `new TypeError("TypeError message"` // Test object = `new TypeError("TypeError message"`
const stub = getGripStub("testTypeError"); const stub = getGripStub("testTypeError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for TypeError`);
`Rep correctly selects ${ErrorRep.rep.displayName} for TypeError`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,
@ -244,9 +238,8 @@ window.onload = Task.async(function* () {
function testURIError() { function testURIError() {
// Test object = `new URIError("URIError message")` // Test object = `new URIError("URIError message")`
const stub = getGripStub("testURIError"); const stub = getGripStub("testURIError");
const renderedRep = shallowRenderComponent(Rep, {object: stub}); is(getRep(stub), ErrorRep.rep,
is(renderedRep.type, ErrorRep.rep, `Rep correctly selects Error Rep for URIError object`);
`Rep correctly selects ${ErrorRep.rep.displayName} for URIError object`);
const renderedComponent = renderComponent(ErrorRep.rep, {object: stub}); const renderedComponent = renderComponent(ErrorRep.rep, {object: stub});
is(renderedComponent.textContent, is(renderedComponent.textContent,

View File

@ -20,14 +20,14 @@ window.onload = Task.async(function* () {
const { const {
REPS, REPS,
MODE, MODE,
getRep,
getSelectableInInspectorGrips, getSelectableInInspectorGrips,
} = browserRequire("devtools/client/shared/components/reps/reps"); } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, Event } = REPS; let { Event } = REPS;
try { try {
// Test that correct rep is chosen // Test that correct rep is chosen
const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testEvent") }); is(getRep(getGripStub("testEvent")), Event.rep, "Rep correctly selects Event Rep");
is(renderedRep.type, Event.rep, `Rep correctly selects ${Event.rep.displayName}`);
yield testEvent(); yield testEvent();
yield testMouseEvent(); yield testMouseEvent();
@ -129,8 +129,6 @@ window.onload = Task.async(function* () {
is(grips.length, 1, "the stub has one node grip"); is(grips.length, 1, "the stub has one node grip");
const attachedActorIds = getStubAttachedActorIds(grips);
let mouseOverValue; let mouseOverValue;
let onDOMNodeMouseOver = (object) => { let onDOMNodeMouseOver = (object) => {
mouseOverValue = object; mouseOverValue = object;
@ -138,7 +136,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(Event.rep, { const renderedComponent = renderComponent(Event.rep, {
object: stub, object: stub,
onDOMNodeMouseOver, onDOMNodeMouseOver,
attachedActorIds,
}); });
const node = renderedComponent.querySelector(".objectBox-node"); const node = renderedComponent.querySelector(".objectBox-node");
@ -153,8 +150,6 @@ window.onload = Task.async(function* () {
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 1, "the stub has one node grip"); is(grips.length, 1, "the stub has one node grip");
const attachedActorIds = getStubAttachedActorIds(grips);
let called = false; let called = false;
let onDOMNodeMouseOut = (object) => { let onDOMNodeMouseOut = (object) => {
called = true; called = true;
@ -162,7 +157,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(Event.rep, { const renderedComponent = renderComponent(Event.rep, {
object: stub, object: stub,
onDOMNodeMouseOut, onDOMNodeMouseOut,
attachedActorIds
}); });
const node = renderedComponent.querySelector(".objectBox-node"); const node = renderedComponent.querySelector(".objectBox-node");
@ -176,34 +170,19 @@ window.onload = Task.async(function* () {
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 1, "the stub has one node grip"); is(grips.length, 1, "the stub has one node grip");
const attachedActorIds = getStubAttachedActorIds(grips);
let inspectIconClickedValue = null; let inspectIconClickedValue = null;
let onInspectIconClick = (object) => { let onInspectIconClick = (object) => {
inspectIconClickedValue = object; inspectIconClickedValue = object;
}; };
let renderedComponentWithoutInspectIcon = renderComponent(Event.rep, {
object: stub,
onInspectIconClick,
attachedActorIds: ["someOtherId"]
});
is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
"There isn't an inspect icon when the actor is not in attachedActorIds");
is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
"There isn't an inspect icon when attachedActorIds does not have keys " +
"matching grip event's target item");
const renderedComponent = renderComponent(Event.rep, { const renderedComponent = renderComponent(Event.rep, {
object: stub, object: stub,
onInspectIconClick, onInspectIconClick,
attachedActorIds
}); });
const icon = renderedComponent.querySelector(".open-inspector"); const icon = renderedComponent.querySelector(".open-inspector");
ok(icon !== null, "There is an icon as expected when passing a matching " + ok(icon !== null,
"attachedActorIds item"); "There is an inspect icon when the node is connected to the DOM tree");
TestUtils.Simulate.click(icon); TestUtils.Simulate.click(icon);
@ -344,6 +323,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "div", "nodeName": "div",
"isConnected": true,
"attributes": { "attributes": {
"id": "test" "id": "test"
}, },

View File

@ -18,8 +18,11 @@ Test fallback for rep rendering when a rep fails to render.
<script type="application/javascript"> <script type="application/javascript">
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
try { try {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, ArrayRep, RegExp } = REPS; REPS,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { ArrayRep, RegExp } = REPS;
// Force the RegExp rep to crash by creating RegExp grip that throws when accessing // Force the RegExp rep to crash by creating RegExp grip that throws when accessing
// the displayString property // the displayString property
@ -37,8 +40,7 @@ window.onload = Task.async(function* () {
}; };
// Test that correct rep is chosen. // Test that correct rep is chosen.
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), RegExp.rep, "Rep correctly selects RegExp Rep");
is(renderedRep.type, RegExp.rep, `Rep correctly selects ${RegExp.rep.displayName}`);
// Test fallback message is displayed when rendering bad rep directly. // Test fallback message is displayed when rendering bad rep directly.
let renderedComponent = renderComponent(RegExp.rep, { object: gripStub }); let renderedComponent = renderComponent(RegExp.rep, { object: gripStub });

View File

@ -17,16 +17,19 @@ Test Func rep
<script src="head.js" type="application/javascript"></script> <script src="head.js" type="application/javascript"></script>
<script type="application/javascript"> <script type="application/javascript">
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, Func } = REPS; REPS,
MODE,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { Func } = REPS;
const componentUnderTest = Func; const componentUnderTest = Func;
try { try {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub("testNamed"); const gripStub = getGripStub("testNamed");
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Func.rep, "Rep correctly selects Func Rep");
is(renderedRep.type, Func.rep, `Rep correctly selects ${Func.rep.displayName}`);
yield testNamed(); yield testNamed();
yield testVarNamed(); yield testVarNamed();

View File

@ -20,9 +20,10 @@ window.onload = Task.async(function* () {
const { const {
REPS, REPS,
MODE, MODE,
getRep,
getSelectableInInspectorGrips, getSelectableInInspectorGrips,
} = browserRequire("devtools/client/shared/components/reps/reps"); } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, GripArray } = REPS; let { GripArray } = REPS;
let componentUnderTest = GripArray; let componentUnderTest = GripArray;
const maxLength = { const maxLength = {
@ -60,8 +61,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub("testBasic"); const gripStub = getGripStub("testBasic");
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), GripArray.rep, "Rep correctly selects GripArray Rep");
is(renderedRep.type, GripArray.rep, `Rep correctly selects ${GripArray.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `Array []`; const defaultOutput = `Array []`;
@ -328,8 +328,6 @@ window.onload = Task.async(function* () {
is(grips.length, 3, "the stub has three node grips"); is(grips.length, 3, "the stub has three node grips");
const attachedActorIds = getStubAttachedActorIds(grips);
let mouseOverValue; let mouseOverValue;
let onDOMNodeMouseOver = (object) => { let onDOMNodeMouseOver = (object) => {
mouseOverValue = object; mouseOverValue = object;
@ -337,7 +335,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(GripArray.rep, { const renderedComponent = renderComponent(GripArray.rep, {
object: stub, object: stub,
onDOMNodeMouseOver, onDOMNodeMouseOver,
attachedActorIds,
}); });
const nodes = renderedComponent.querySelectorAll(".objectBox-node"); const nodes = renderedComponent.querySelectorAll(".objectBox-node");
@ -357,8 +354,6 @@ window.onload = Task.async(function* () {
is(grips.length, 3, "the stub has three node grips"); is(grips.length, 3, "the stub has three node grips");
const attachedActorIds = getStubAttachedActorIds(grips);
let called = 0; let called = 0;
let onDOMNodeMouseOut = (object) => { let onDOMNodeMouseOut = (object) => {
called++; called++;
@ -366,7 +361,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(GripArray.rep, { const renderedComponent = renderComponent(GripArray.rep, {
object: stub, object: stub,
onDOMNodeMouseOut, onDOMNodeMouseOut,
attachedActorIds,
}); });
const nodes = renderedComponent.querySelectorAll(".objectBox-node"); const nodes = renderedComponent.querySelectorAll(".objectBox-node");
@ -377,35 +371,30 @@ window.onload = Task.async(function* () {
} }
function testOnDomNodeInspectIconClick() { function testOnDomNodeInspectIconClick() {
const stub = getGripStub("testNodeList");
const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 3, "the stub has three node grips");
const attachedActorIds = getStubAttachedActorIds(grips);
let inspectIconClickedValue = null; let inspectIconClickedValue = null;
let onInspectIconClick = (object) => { let onInspectIconClick = (object) => {
inspectIconClickedValue = object; inspectIconClickedValue = object;
}; };
let renderedComponentWithoutInspectIcon = renderComponent(GripArray.rep, { let renderedComponentWithoutInspectIcon = renderComponent(GripArray.rep, {
object: stub, object: getGripStub("testDisconnectedNodeList"),
onInspectIconClick, onInspectIconClick,
attachedActorIds: ["someOtherId"],
}); });
is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null, is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
"There isn't an inspect icon when the actor is not in attachedActorIds"); "There isn't an inspect icon when the nodes are not connected to the DOM tree");
const stub = getGripStub("testNodeList");
const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 3, "the stub has three node grips");
const renderedComponent = renderComponent(GripArray.rep, { const renderedComponent = renderComponent(GripArray.rep, {
object: stub, object: stub,
onInspectIconClick, onInspectIconClick,
attachedActorIds,
}); });
const icons = renderedComponent.querySelectorAll(".open-inspector"); const icons = renderedComponent.querySelectorAll(".open-inspector");
is(icons.length, grips.length, is(icons.length, grips.length,
"There is an icon for each grip array item with a matching attachedNodeFront"); "There is an icon for each node connected to the DOM tree");
icons.forEach((icon, index) => { icons.forEach((icon, index) => {
TestUtils.Simulate.click(icon); TestUtils.Simulate.click(icon);
@ -678,6 +667,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-1", "id": "btn-1",
"class": "btn btn-log", "class": "btn btn-log",
@ -698,6 +688,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-2", "id": "btn-2",
"class": "btn btn-err", "class": "btn btn-err",
@ -718,6 +709,87 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": {
"id": "btn-3",
"class": "btn btn-count",
"type": "button"
},
"attributesLength": 3
}
}
]
}
};
case "testDisconnectedNodeList":
return {
"type": "object",
"actor": "server1.conn1.child1/obj51",
"class": "NodeList",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 3,
"preview": {
"kind": "ArrayLike",
"length": 3,
"items": [
{
"type": "object",
"actor": "server1.conn1.child1/obj52",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": false,
"attributes": {
"id": "btn-1",
"class": "btn btn-log",
"type": "button"
},
"attributesLength": 3
}
},
{
"type": "object",
"actor": "server1.conn1.child1/obj53",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": false,
"attributes": {
"id": "btn-2",
"class": "btn btn-err",
"type": "button"
},
"attributesLength": 3
}
},
{
"type": "object",
"actor": "server1.conn1.child1/obj54",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": false,
"attributes": { "attributes": {
"id": "btn-3", "id": "btn-3",
"class": "btn btn-count", "class": "btn btn-count",

View File

@ -22,9 +22,10 @@ window.onload = Task.async(function* () {
const { const {
REPS, REPS,
MODE, MODE,
getRep,
getSelectableInInspectorGrips, getSelectableInInspectorGrips,
} = browserRequire("devtools/client/shared/components/reps/reps"); } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, GripMap } = REPS; let { GripMap } = REPS;
const componentUnderTest = GripMap; const componentUnderTest = GripMap;
@ -55,8 +56,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub("testEmptyMap"); const gripStub = getGripStub("testEmptyMap");
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), GripMap.rep, "Rep correctly selects GripMap Rep");
is(renderedRep.type, GripMap.rep, `Rep correctly selects ${GripMap.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `Map { }`; const defaultOutput = `Map { }`;
@ -118,8 +118,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub("testWeakMap"); const gripStub = getGripStub("testWeakMap");
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), GripMap.rep, "Rep correctly selects GripMap Rep");
is(renderedRep.type, GripMap.rep, `Rep correctly selects ${GripMap.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `WeakMap { Object: "value-a" }`; const defaultOutput = `WeakMap { Object: "value-a" }`;
@ -254,11 +253,9 @@ window.onload = Task.async(function* () {
const valuesGrips = getSelectableInInspectorGrips(nodeValuedStub); const valuesGrips = getSelectableInInspectorGrips(nodeValuedStub);
is(valuesGrips.length, 3, "the stub has three node grips"); is(valuesGrips.length, 3, "the stub has three node grips");
const valuesattachedActorIds = getStubAttachedActorIds(valuesGrips);
const keysGrips = getSelectableInInspectorGrips(nodeKeyedStub); const keysGrips = getSelectableInInspectorGrips(nodeKeyedStub);
is(keysGrips.length, 3, "the stub has three node grips"); is(keysGrips.length, 3, "the stub has three node grips");
const keysAttachedActorIds = getStubAttachedActorIds(keysGrips);
let mouseOverValue; let mouseOverValue;
let onDOMNodeMouseOver = (object) => { let onDOMNodeMouseOver = (object) => {
@ -269,7 +266,6 @@ window.onload = Task.async(function* () {
const nodeValuedRenderedComponent = renderComponent(GripMap.rep, { const nodeValuedRenderedComponent = renderComponent(GripMap.rep, {
object: nodeValuedStub, object: nodeValuedStub,
onDOMNodeMouseOver, onDOMNodeMouseOver,
attachedActorIds: valuesattachedActorIds,
}); });
let nodes = nodeValuedRenderedComponent.querySelectorAll(".objectBox-node"); let nodes = nodeValuedRenderedComponent.querySelectorAll(".objectBox-node");
@ -284,7 +280,6 @@ window.onload = Task.async(function* () {
const nodeKeyedRenderedComponent = renderComponent(GripMap.rep, { const nodeKeyedRenderedComponent = renderComponent(GripMap.rep, {
object: nodeKeyedStub, object: nodeKeyedStub,
onDOMNodeMouseOver, onDOMNodeMouseOver,
attachedActorIds: keysAttachedActorIds,
}); });
nodes = nodeKeyedRenderedComponent.querySelectorAll(".objectBox-node"); nodes = nodeKeyedRenderedComponent.querySelectorAll(".objectBox-node");
@ -302,11 +297,9 @@ window.onload = Task.async(function* () {
const valuesGrips = getSelectableInInspectorGrips(nodeValuedStub); const valuesGrips = getSelectableInInspectorGrips(nodeValuedStub);
is(valuesGrips.length, 3, "the stub has three node grips"); is(valuesGrips.length, 3, "the stub has three node grips");
const valuesattachedActorIds = getStubAttachedActorIds(valuesGrips);
const keysGrips = getSelectableInInspectorGrips(nodeKeyedStub); const keysGrips = getSelectableInInspectorGrips(nodeKeyedStub);
is(keysGrips.length, 3, "the stub has three node grips"); is(keysGrips.length, 3, "the stub has three node grips");
const keysAttachedActorIds = getStubAttachedActorIds(keysGrips);
let called = 0; let called = 0;
let onDOMNodeMouseOut = (object) => { let onDOMNodeMouseOut = (object) => {
@ -317,7 +310,6 @@ window.onload = Task.async(function* () {
const nodeValuedRenderedComponent = renderComponent(GripMap.rep, { const nodeValuedRenderedComponent = renderComponent(GripMap.rep, {
object: nodeValuedStub, object: nodeValuedStub,
onDOMNodeMouseOut, onDOMNodeMouseOut,
attachedActorIds: valuesattachedActorIds,
}); });
let nodes = nodeValuedRenderedComponent.querySelectorAll(".objectBox-node"); let nodes = nodeValuedRenderedComponent.querySelectorAll(".objectBox-node");
@ -330,7 +322,6 @@ window.onload = Task.async(function* () {
const nodeKeyedRenderedComponent = renderComponent(GripMap.rep, { const nodeKeyedRenderedComponent = renderComponent(GripMap.rep, {
object: nodeKeyedStub, object: nodeKeyedStub,
onDOMNodeMouseOut, onDOMNodeMouseOut,
attachedActorIds: keysAttachedActorIds,
}); });
nodes = nodeKeyedRenderedComponent.querySelectorAll(".objectBox-node"); nodes = nodeKeyedRenderedComponent.querySelectorAll(".objectBox-node");
@ -348,11 +339,9 @@ window.onload = Task.async(function* () {
const valuesGrips = getSelectableInInspectorGrips(nodeValuedStub); const valuesGrips = getSelectableInInspectorGrips(nodeValuedStub);
is(valuesGrips.length, 3, "the stub has three node grips"); is(valuesGrips.length, 3, "the stub has three node grips");
const valuesattachedActorIds = getStubAttachedActorIds(valuesGrips);
const keysGrips = getSelectableInInspectorGrips(nodeKeyedStub); const keysGrips = getSelectableInInspectorGrips(nodeKeyedStub);
is(keysGrips.length, 3, "the stub has three node grips"); is(keysGrips.length, 3, "the stub has three node grips");
const keysAttachedActorIds = getStubAttachedActorIds(keysGrips);
let inspectIconClickedValue = null; let inspectIconClickedValue = null;
let onInspectIconClick = (object) => { let onInspectIconClick = (object) => {
@ -360,23 +349,21 @@ window.onload = Task.async(function* () {
}; };
const renderedComponentWithoutInspectIcon = renderComponent(GripMap.rep, { const renderedComponentWithoutInspectIcon = renderComponent(GripMap.rep, {
object: nodeValuedStub, object: getGripStub("testDisconnectedNodeValuedMap"),
onInspectIconClick, onInspectIconClick,
attachedActorIds: [],
}); });
is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null, is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
"There isn't an inspect icon when the actor is not in attachedActorIds"); "There isn't an inspect icon when nodes are not connected to the DOM tree");
info("Testing onInspectIconClick on node valued Map"); info("Testing onInspectIconClick on node valued Map");
const nodeValuedRenderedComponent = renderComponent(GripMap.rep, { const nodeValuedRenderedComponent = renderComponent(GripMap.rep, {
object: nodeValuedStub, object: nodeValuedStub,
onInspectIconClick, onInspectIconClick,
attachedActorIds: valuesattachedActorIds,
}); });
let icons = nodeValuedRenderedComponent.querySelectorAll(".open-inspector"); let icons = nodeValuedRenderedComponent.querySelectorAll(".open-inspector");
is(icons.length, valuesGrips.length, is(icons.length, valuesGrips.length,
"There is an icon for each map value with a matching attachedNodeFront"); "There is an icon for each node connected to the DOM tree");
icons.forEach((icon, index) => { icons.forEach((icon, index) => {
TestUtils.Simulate.click(icon); TestUtils.Simulate.click(icon);
@ -388,12 +375,11 @@ window.onload = Task.async(function* () {
const nodeKeyedRenderedComponent = renderComponent(GripMap.rep, { const nodeKeyedRenderedComponent = renderComponent(GripMap.rep, {
object: nodeKeyedStub, object: nodeKeyedStub,
onInspectIconClick, onInspectIconClick,
attachedActorIds: keysAttachedActorIds,
}); });
icons = nodeKeyedRenderedComponent.querySelectorAll(".open-inspector"); icons = nodeKeyedRenderedComponent.querySelectorAll(".open-inspector");
is(icons.length, keysGrips.length, is(icons.length, keysGrips.length,
"There is an icon for each map key with a matching attachedNodeFront"); "There is an icon for each node connected to the DOM tree");
icons.forEach((icon, index) => { icons.forEach((icon, index) => {
TestUtils.Simulate.click(icon); TestUtils.Simulate.click(icon);
@ -607,6 +593,92 @@ window.onload = Task.async(function* () {
} }
}; };
case "testDisconnectedNodeValuedMap":
return {
"type": "object",
"actor": "server1.conn1.child1/obj213",
"class": "Map",
"ownPropertyLength": 0,
"preview": {
"kind": "MapLike",
"size": 3,
"entries": [
[
"item-0",
{
"type": "object",
"actor": "server1.conn1.child1/obj214",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": false,
"attributes": {
"id": "btn-1",
"class": "btn btn-log",
"type": "button"
},
"attributesLength": 3
}
}
],
[
"item-1",
{
"type": "object",
"actor": "server1.conn1.child1/obj215",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": false,
"attributes": {
"id": "btn-2",
"class": "btn btn-err",
"type": "button"
},
"attributesLength": 3
}
}
],
[
"item-2",
{
"type": "object",
"actor": "server1.conn1.child1/obj216",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": false,
"attributes": {
"id": "btn-3",
"class": "btn btn-count",
"type": "button"
},
"attributesLength": 3
}
}
]
]
}
};
case "testNodeValuedMap": case "testNodeValuedMap":
return { return {
"type": "object", "type": "object",
@ -631,6 +703,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-1", "id": "btn-1",
"class": "btn btn-log", "class": "btn btn-log",
@ -654,6 +727,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-2", "id": "btn-2",
"class": "btn btn-err", "class": "btn btn-err",
@ -677,6 +751,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-3", "id": "btn-3",
"class": "btn btn-count", "class": "btn btn-count",
@ -713,6 +788,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-1", "id": "btn-1",
"class": "btn btn-log", "class": "btn btn-log",
@ -736,6 +812,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-3", "id": "btn-3",
"class": "btn btn-count", "class": "btn btn-count",
@ -759,6 +836,7 @@ window.onload = Task.async(function* () {
"kind": "DOMNode", "kind": "DOMNode",
"nodeType": 1, "nodeType": 1,
"nodeName": "button", "nodeName": "button",
"isConnected": true,
"attributes": { "attributes": {
"id": "btn-2", "id": "btn-2",
"class": "btn btn-err", "class": "btn btn-err",

View File

@ -20,9 +20,10 @@ window.onload = Task.async(function* () {
const { const {
REPS, REPS,
MODE, MODE,
getRep,
getSelectableInInspectorGrips, getSelectableInInspectorGrips,
} = browserRequire("devtools/client/shared/components/reps/reps"); } = browserRequire("devtools/client/shared/components/reps/reps");
let { Rep, Grip } = REPS; let { Grip } = REPS;
const componentUnderTest = Grip; const componentUnderTest = Grip;
@ -66,8 +67,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub("testBasic"); const gripStub = getGripStub("testBasic");
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `Object { }`; const defaultOutput = `Object { }`;
@ -100,8 +100,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub(testName); const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `Boolean { true }`; const defaultOutput = `Boolean { true }`;
@ -134,8 +133,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub(testName); const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `Number { 42 }`; const defaultOutput = `Number { 42 }`;
@ -168,8 +166,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub(testName); const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `String { "foo" }`; const defaultOutput = `String { "foo" }`;
@ -202,8 +199,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub(testName); const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `Proxy { <target>: Object, <handler>: [3] }`; const defaultOutput = `Proxy { <target>: Object, <handler>: [3] }`;
@ -236,8 +232,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub(testName); const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `ArrayBuffer { byteLength: 10 }`; const defaultOutput = `ArrayBuffer { byteLength: 10 }`;
@ -270,8 +265,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub(testName); const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `SharedArrayBuffer { byteLength: 5 }`; const defaultOutput = `SharedArrayBuffer { byteLength: 5 }`;
@ -304,8 +298,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub(testName); const gripStub = getGripStub(testName);
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = const defaultOutput =
@ -412,8 +405,7 @@ window.onload = Task.async(function* () {
// Test that correct rep is chosen // Test that correct rep is chosen
const gripStub = getGripStub("testNonEnumerableProps"); const gripStub = getGripStub("testNonEnumerableProps");
const renderedRep = shallowRenderComponent(Rep, { object: gripStub }); is(getRep(gripStub), Grip.rep, "Rep correctly selects Grip Rep");
is(renderedRep.type, Grip.rep, `Rep correctly selects ${Grip.rep.displayName}`);
// Test rendering // Test rendering
const defaultOutput = `Object { }`; const defaultOutput = `Object { }`;
@ -537,7 +529,6 @@ window.onload = Task.async(function* () {
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 2, "the stub has two node grips"); is(grips.length, 2, "the stub has two node grips");
const attachedActorIds = getStubAttachedActorIds(grips);
let mouseOverValue; let mouseOverValue;
let called = 0; let called = 0;
@ -549,7 +540,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(Grip.rep, { const renderedComponent = renderComponent(Grip.rep, {
object: stub, object: stub,
onDOMNodeMouseOver, onDOMNodeMouseOver,
attachedActorIds,
}); });
const nodes = renderedComponent.querySelectorAll(".objectBox-node"); const nodes = renderedComponent.querySelectorAll(".objectBox-node");
@ -568,7 +558,6 @@ window.onload = Task.async(function* () {
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 2, "the stub has two node grips"); is(grips.length, 2, "the stub has two node grips");
const attachedActorIds = getStubAttachedActorIds(grips);
let called = 0; let called = 0;
let onDOMNodeMouseOut = (object) => { let onDOMNodeMouseOut = (object) => {
@ -578,7 +567,6 @@ window.onload = Task.async(function* () {
const renderedComponent = renderComponent(Grip.rep, { const renderedComponent = renderComponent(Grip.rep, {
object: stub, object: stub,
onDOMNodeMouseOut, onDOMNodeMouseOut,
attachedActorIds,
}); });
const nodes = renderedComponent.querySelectorAll(".objectBox-node"); const nodes = renderedComponent.querySelectorAll(".objectBox-node");
@ -593,7 +581,6 @@ window.onload = Task.async(function* () {
const grips = getSelectableInInspectorGrips(stub); const grips = getSelectableInInspectorGrips(stub);
is(grips.length, 2, "the stub has two node grips"); is(grips.length, 2, "the stub has two node grips");
const attachedActorIds = getStubAttachedActorIds(grips);
let inspectIconClickedValue = null; let inspectIconClickedValue = null;
let onInspectIconClick = (object) => { let onInspectIconClick = (object) => {
@ -601,26 +588,20 @@ window.onload = Task.async(function* () {
}; };
let renderedComponentWithoutInspectIcon = renderComponent(Grip.rep, { let renderedComponentWithoutInspectIcon = renderComponent(Grip.rep, {
object: stub, object: getGripStub("testObjectWithDisconnectedNodes"),
onInspectIconClick, onInspectIconClick,
attachedActorIds: ["someOtherId"],
}); });
is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null, is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
"There isn't an inspect icon when the actor is not in attachedActorIds"); "There isn't an inspect icon when the node is not connected to the DOM tree");
is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
"There isn't an inspect icon when attachedActorIds does not have keys " +
"matching grip properties");
const renderedComponent = renderComponent(Grip.rep, { const renderedComponent = renderComponent(Grip.rep, {
object: stub, object: stub,
onInspectIconClick, onInspectIconClick,
attachedActorIds,
}); });
const icons = renderedComponent.querySelectorAll(".open-inspector"); const icons = renderedComponent.querySelectorAll(".open-inspector");
is(icons.length, 2, is(icons.length, 2,
"There is an icon for each grip property matching an attachedNodeFront"); "There is an icon for each node connected to the DOM tree");
icons.forEach((icon, index) => { icons.forEach((icon, index) => {
TestUtils.Simulate.click(icon); TestUtils.Simulate.click(icon);
@ -1169,6 +1150,72 @@ window.onload = Task.async(function* () {
} }
}; };
case "testObjectWithNodes": case "testObjectWithNodes":
return {
"type": "object",
"actor": "server1.conn1.child1/obj214",
"class": "Object",
"ownPropertyLength": 2,
"preview": {
"kind": "Object",
"ownProperties": {
"foo": {
"configurable": true,
"enumerable": true,
"writable": true,
"value": {
"type": "object",
"actor": "server1.conn1.child1/obj215",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": true,
"attributes": {
"id": "btn-1",
"class": "btn btn-log",
"type": "button"
},
"attributesLength": 3
}
}
},
"bar": {
"configurable": true,
"enumerable": true,
"writable": true,
"value": {
"type": "object",
"actor": "server1.conn1.child1/obj216",
"class": "HTMLButtonElement",
"extensible": true,
"frozen": false,
"sealed": false,
"ownPropertyLength": 0,
"preview": {
"kind": "DOMNode",
"nodeType": 1,
"nodeName": "button",
"isConnected": true,
"attributes": {
"id": "btn-2",
"class": "btn btn-err",
"type": "button"
},
"attributesLength": 3
}
}
}
},
"ownPropertiesLength": 2,
"safeGetterValues": {}
}
};
case "testObjectWithDisconnectedNodes":
return { return {
"type": "object", "type": "object",
"actor": "server1.conn1.child1/obj214", "actor": "server1.conn1.child1/obj214",

View File

@ -19,8 +19,11 @@ Test Infinity rep
"use strict"; "use strict";
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, InfinityRep } = REPS; REPS,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { InfinityRep } = REPS;
try { try {
yield testInfinity(); yield testInfinity();
@ -33,9 +36,7 @@ window.onload = Task.async(function* () {
function testInfinity() { function testInfinity() {
const stub = getGripStub("testInfinity"); const stub = getGripStub("testInfinity");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), InfinityRep.rep, "Rep correctly selects Infinity Rep");
is(renderedRep.type, InfinityRep.rep,
`Rep correctly selects ${InfinityRep.rep.displayName} for Infinity value`);
const renderedComponent = renderComponent(InfinityRep.rep, { object: stub }); const renderedComponent = renderComponent(InfinityRep.rep, { object: stub });
is(renderedComponent.textContent, "Infinity", is(renderedComponent.textContent, "Infinity",
@ -44,9 +45,7 @@ window.onload = Task.async(function* () {
function testNegativeInfinity() { function testNegativeInfinity() {
const stub = getGripStub("testNegativeInfinity"); const stub = getGripStub("testNegativeInfinity");
const renderedRep = shallowRenderComponent(Rep, { object: stub }); is(getRep(stub), InfinityRep.rep, "Rep correctly selects Infinity Rep");
is(renderedRep.type, InfinityRep.rep,
`Rep correctly selects ${InfinityRep.rep.displayName} for negative Infinity value`);
const renderedComponent = renderComponent(InfinityRep.rep, { object: stub }); const renderedComponent = renderComponent(InfinityRep.rep, { object: stub });
is(renderedComponent.textContent, "-Infinity", is(renderedComponent.textContent, "-Infinity",

View File

@ -17,14 +17,16 @@ Test LongString rep
<script src="head.js" type="application/javascript"></script> <script src="head.js" type="application/javascript"></script>
<script type="application/javascript"> <script type="application/javascript">
window.onload = Task.async(function* () { window.onload = Task.async(function* () {
const { REPS } = browserRequire("devtools/client/shared/components/reps/reps"); const {
let { Rep, LongStringRep } = REPS; REPS,
getRep,
} = browserRequire("devtools/client/shared/components/reps/reps");
let { LongStringRep } = REPS;
try { try {
// Test that correct rep is chosen // Test that correct rep is chosen
const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testMultiline") }); is(getRep(getGripStub("testMultiline")), LongStringRep.rep,
is(renderedRep.type, LongStringRep.rep, "Rep correctly selects LongString Rep");
`Rep correctly selects ${LongStringRep.rep.displayName}`);
// Test rendering // Test rendering
yield testMultiline(); yield testMultiline();

Some files were not shown because too many files have changed in this diff Show More