diff --git a/browser/base/content/browser-tabsintitlebar-stub.js b/browser/base/content/browser-tabsintitlebar-stub.js
deleted file mode 100644
index 7276cc4751b8..000000000000
--- a/browser/base/content/browser-tabsintitlebar-stub.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * 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/. */
-
-// This file is used as a stub object for platforms which
-// don't have CAN_DRAW_IN_TITLEBAR defined.
-
-var TabsInTitlebar = {
- init() {},
- whenWindowLayoutReady() {},
- uninit() {},
- allowedBy() {},
- update() {},
- enabled: false,
-};
diff --git a/browser/base/content/browser-tabsintitlebar.js b/browser/base/content/browser-tabsintitlebar.js
index 70eeeeaab51f..c1cb43de4213 100644
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -3,19 +3,11 @@
* 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/. */
-// Note: the file browser-tabsintitlebar-stub.js is used instead of
-// this one on platforms which don't have CAN_DRAW_IN_TITLEBAR defined.
-
var TabsInTitlebar = {
init() {
this._readPref();
Services.prefs.addObserver(this._prefName, this);
- // Always disable on unsupported GTK versions.
- if (AppConstants.MOZ_WIDGET_TOOLKIT == "gtk3") {
- this.allowedBy("gtk", window.matchMedia("(-moz-gtk-csd-available)"));
- }
-
// We need to update the appearance of the titlebar when the menu changes
// from the active to the inactive state. We can't, however, rely on
// DOMMenuBarInactive, because the menu fires this event and then removes
@@ -66,6 +58,21 @@ var TabsInTitlebar = {
}
},
+ get systemSupported() {
+ let isSupported = false;
+ switch (AppConstants.MOZ_WIDGET_TOOLKIT) {
+ case "windows":
+ case "cocoa":
+ isSupported = true;
+ break;
+ case "gtk3":
+ isSupported = window.matchMedia("(-moz-gtk-csd-available)");
+ break;
+ }
+ delete this.systemSupported;
+ return this.systemSupported = isSupported;
+ },
+
get enabled() {
return document.documentElement.getAttribute("tabsintitlebar") == "true";
},
@@ -134,7 +141,8 @@ var TabsInTitlebar = {
return;
}
- let allowed = (Object.keys(this._disallowed)).length == 0;
+ let allowed = this.systemSupported &&
+ (Object.keys(this._disallowed)).length == 0;
if (allowed) {
document.documentElement.setAttribute("tabsintitlebar", "true");
if (AppConstants.platform == "macosx") {
diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
index b08f72ad0d5e..de5229667b67 100644
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -277,7 +277,6 @@ window:not([chromehidden~="toolbar"]) #nav-bar[nonemptyoverflow] > .overflow-but
}
-%ifdef CAN_DRAW_IN_TITLEBAR
%ifdef MENUBAR_CAN_AUTOHIDE
#toolbar-menubar:not([autohide=true]) + #TabsToolbar > .titlebar-placeholder,
%endif
@@ -347,8 +346,6 @@ toolbarpaletteitem {
}
%endif
-%endif
-
#main-window[inFullscreen][inDOMFullscreen] #navigator-toolbox,
#main-window[inFullscreen][inDOMFullscreen] #fullscr-toggler,
#main-window[inFullscreen][inDOMFullscreen] #sidebar-box,
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 5f069e03bb8f..d6d770d121fb 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -46,14 +46,12 @@
titlemodifier_normal="&mainWindow.titlemodifier;"
titlemodifier_privatebrowsing="&mainWindow.titlemodifier; &mainWindow.titlePrivateBrowsingSuffix;"
#endif
-#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef XP_WIN
chromemargin="0,2,2,2"
#else
chromemargin="0,-1,-1,-1"
#endif
tabsintitlebar="true"
-#endif
titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
windowtype="navigator:browser"
macanimationtype="document"
@@ -598,7 +596,6 @@
Performing a GET or POST request
+ + +diff --git a/devtools/client/inspector/animation/test/head.js b/devtools/client/inspector/animation/test/head.js index 3679bea9874d..78f130161ffd 100644 --- a/devtools/client/inspector/animation/test/head.js +++ b/devtools/client/inspector/animation/test/head.js @@ -84,6 +84,16 @@ addTab = async function(url) { return tab; }; +/** + * Remove animated elements from document except given selectors. + * + * @param {Array} selectors + * @return {Promise} + */ +const removeAnimatedElementsExcept = async function(selectors) { + return executeInContent("Test:RemoveAnimatedElementsExcept", { selectors }); +}; + /** * Click on an animation in the timeline to select it. * @@ -96,14 +106,24 @@ addTab = async function(url) { const clickOnAnimation = async function(animationInspector, panel, index) { info("Click on animation " + index + " in the timeline"); const summaryGraphEl = panel.querySelectorAll(".animation-summary-graph")[index]; - // Scroll to show the timeBlock since the element may be out of displayed area. - summaryGraphEl.scrollIntoView(false); - const bounds = summaryGraphEl.getBoundingClientRect(); - const x = bounds.width / 2; - const y = bounds.height / 2; - EventUtils.synthesizeMouse(summaryGraphEl, x, y, {}, summaryGraphEl.ownerGlobal); + await clickOnSummaryGraph(animationInspector, panel, summaryGraphEl); +}; - await waitForAnimationDetail(animationInspector); +/** + * Click on an animation by given selector of node which is target element of animation. + * + * @param {AnimationInspector} animationInspector. + * @param {AnimationsPanel} panel + * The panel instance. + * @param {String} selector + * Selector of node which is target element of animation. + */ +const clickOnAnimationByTargetSelector = async function(animationInspector, + panel, selector) { + info(`Click on animation whose selector of target element is '${ selector }'`); + const animationItemEl = findAnimationItemElementsByTargetSelector(panel, selector); + const summaryGraphEl = animationItemEl.querySelector(".animation-summary-graph"); + await clickOnSummaryGraph(animationInspector, panel, summaryGraphEl); }; /** @@ -202,6 +222,25 @@ const clickOnPlaybackRateSelector = async function(animationInspector, panel, ra await waitForSummaryAndDetail(animationInspector); }; +/** + * Click on given summary graph element. + * + * @param {AnimationInspector} animationInspector + * @param {AnimationsPanel} panel + * @param {Element} summaryGraphEl + */ +const clickOnSummaryGraph = async function(animationInspector, panel, summaryGraphEl) { + // Disable pointer-events of the scrubber in order to avoid to click accidently. + const scrubberEl = panel.querySelector(".current-time-scrubber"); + scrubberEl.style.pointerEvents = "none"; + // Scroll to show the timeBlock since the element may be out of displayed area. + summaryGraphEl.scrollIntoView(false); + EventUtils.synthesizeMouseAtCenter(summaryGraphEl, {}, summaryGraphEl.ownerGlobal); + await waitForAnimationDetail(animationInspector); + // Restore the scrubber style. + scrubberEl.style.pointerEvents = "unset"; +}; + /** * Drag on the scrubber to update the animation current time. * @@ -590,22 +629,21 @@ function isPassingThrough(pathSegList, x, y) { } /** - * Return animation item element by target node class. - * This function compares betweem animation-target textContent and given className. - * Also, this function premises one class name. + * Return animation item element by target node selector. + * This function compares betweem animation-target textContent and given selector. + * Then returns matched first item. * * @param {Element} panel - root element of animation inspector. - * @param {String} targetClassName - class name of tested element. + * @param {String} selector - selector of tested element. * @return {Element} animation item element. */ -function findAnimationItemElementsByTargetClassName(panel, targetClassName) { - const animationTargetEls = panel.querySelectorAll(".animation-target"); +function findAnimationItemElementsByTargetSelector(panel, selector) { + const attrNameEls = panel.querySelectorAll(".animation-target .attrName"); + const regexp = new RegExp(`\\${ selector }(\\.|$)`, "gi"); - for (const animationTargetEl of animationTargetEls) { - const className = animationTargetEl.textContent.split(".")[1]; - - if (className === targetClassName) { - return animationTargetEl.closest(".animation-item"); + for (const attrNameEl of attrNameEls) { + if (regexp.exec(attrNameEl.textContent)) { + return attrNameEl.closest(".animation-item"); } } diff --git a/devtools/client/inspector/rules/rules.js b/devtools/client/inspector/rules/rules.js index 5ae98b51441f..7f8646c8b898 100644 --- a/devtools/client/inspector/rules/rules.js +++ b/devtools/client/inspector/rules/rules.js @@ -1750,6 +1750,7 @@ function RuleViewTool(inspector, window) { this.refresh = this.refresh.bind(this); this.onDetachedFront = this.onDetachedFront.bind(this); this.onPanelSelected = this.onPanelSelected.bind(this); + this.onDetachedFront = this.onDetachedFront.bind(this); this.onSelected = this.onSelected.bind(this); this.onViewRefreshed = this.onViewRefreshed.bind(this); diff --git a/devtools/client/netmonitor/src/utils/firefox/open-request-in-tab.js b/devtools/client/netmonitor/src/utils/firefox/open-request-in-tab.js index 80f52c6f74c6..50939d863a58 100644 --- a/devtools/client/netmonitor/src/utils/firefox/open-request-in-tab.js +++ b/devtools/client/netmonitor/src/utils/firefox/open-request-in-tab.js @@ -12,9 +12,9 @@ const { gDevTools } = require("devtools/client/framework/devtools"); /** * Opens given request in a new tab. */ -function openRequestInTab(request) { +function openRequestInTab(url, requestPostData) { let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); - let rawData = request.requestPostData ? request.requestPostData.postData : null; + let rawData = requestPostData ? requestPostData.postData : null; let postData; if (rawData && rawData.text) { @@ -25,7 +25,7 @@ function openRequestInTab(request) { postData.setData(stringStream); } - win.gBrowser.selectedTab = win.gBrowser.addTab(request.url, null, null, postData); + win.gBrowser.selectedTab = win.gBrowser.addTab(url, null, null, postData); } function getInputStreamFromString(data) { diff --git a/devtools/client/netmonitor/src/utils/open-request-in-tab.js b/devtools/client/netmonitor/src/utils/open-request-in-tab.js index 3004241ffcdb..3b713c3ee384 100644 --- a/devtools/client/netmonitor/src/utils/open-request-in-tab.js +++ b/devtools/client/netmonitor/src/utils/open-request-in-tab.js @@ -10,26 +10,23 @@ const { gDevTools } = require("devtools/client/framework/devtools"); /** * Opens given request in a new tab. */ -function openRequestInTab(request) { +function openRequestInTab(url, requestPostData) { let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); - if (request.method.toLowerCase() !== "get") { - win.openUILinkIn(this.selectedRequest.url, "tab", { - relatedToCurrent: true - }); + if (!requestPostData) { + win.openUILinkIn(url, "tab", {relatedToCurrent: true}); } else { - openRequestInTabHelper({ - url: request.url, - method: request.method, - data: request.requestPostData ? request.requestPostData.postData : null, + openPostRequestInTabHelper({ + url, + data: requestPostData.postData }); } } -function openRequestInTabHelper({url, method, data}) { +function openPostRequestInTabHelper({url, data}) { let form = document.createElement("form"); form.target = "_blank"; form.action = url; - form.method = method; + form.method = "post"; if (data) { for (let key in data) { diff --git a/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js b/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js index c4bb53087baa..7d0d926d7e60 100644 --- a/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js +++ b/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js @@ -194,7 +194,7 @@ class RequestListContextMenu { label: L10N.getStr("netmonitor.context.newTab"), accesskey: L10N.getStr("netmonitor.context.newTab.accesskey"), visible: !!selectedRequest, - click: () => this.openRequestInTab(selectedRequest), + click: () => this.openRequestInTab(id, url, requestPostData), }); menu.push({ @@ -229,8 +229,10 @@ class RequestListContextMenu { /** * Opens selected item in a new tab. */ - openRequestInTab(selectedRequest) { - openRequestInTab(selectedRequest); + async openRequestInTab(id, url, requestPostData) { + requestPostData = requestPostData || + await this.props.connector.requestData(id, "requestPostData"); + openRequestInTab(url, requestPostData); } /** diff --git a/devtools/client/netmonitor/test/browser.ini b/devtools/client/netmonitor/test/browser.ini index e477eb1d45f0..5b970e45e7be 100644 --- a/devtools/client/netmonitor/test/browser.ini +++ b/devtools/client/netmonitor/test/browser.ini @@ -40,11 +40,13 @@ support-files = html_api-calls-test-page.html html_copy-as-curl.html html_curl-utils.html + html_open-request-in-tab.html sjs_content-type-test-server.sjs sjs_cors-test-server.sjs sjs_https-redirect-test-server.sjs sjs_hsts-test-server.sjs sjs_json-test-server.sjs + sjs_method-test-server.sjs sjs_simple-test-server.sjs sjs_simple-unsorted-cookies-test-server.sjs sjs_sorting-test-server.sjs diff --git a/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js b/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js index 549edbde690d..55edd29c7b63 100644 --- a/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js +++ b/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js @@ -8,33 +8,69 @@ */ add_task(async function() { - let { tab, monitor } = await initNetMonitor(CUSTOM_GET_URL); + let { tab, monitor } = await initNetMonitor(OPEN_REQUEST_IN_TAB_URL); info("Starting test..."); let { document, store, windowRequire } = monitor.panelWin; let contextMenuDoc = monitor.panelWin.parent.document; let Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); + let newTab; store.dispatch(Actions.batchEnable(false)); - // Execute requests. - await performRequests(monitor, tab, 1); + // Post data may be fetched by the Header panel, + // so set the Timings panel as the new default. + store.getState().ui.detailsPanelSelectedTab = "timings"; - wait = waitForDOM(contextMenuDoc, "#request-list-context-newtab"); - EventUtils.sendMouseEvent({ type: "mousedown" }, - document.querySelectorAll(".request-list-item")[0]); - EventUtils.sendMouseEvent({ type: "contextmenu" }, - document.querySelectorAll(".request-list-item")[0]); - await wait; + // Open GET request in new tab + await performRequest("GET"); - let onTabOpen = once(gBrowser.tabContainer, "TabOpen", false); - monitor.panelWin.parent.document - .querySelector("#request-list-context-newtab").click(); - await onTabOpen; + newTab = await openLastRequestInTab(); + await checkTabResponse(newTab, "GET"); - ok(true, "A new tab has been opened"); + // Open POST request in new tab + await performRequest("POST"); + newTab = await openLastRequestInTab(); + await checkTabResponse(newTab, "POST"); await teardown(monitor); gBrowser.removeCurrentTab(); + + async function openLastRequestInTab() { + let wait = waitForDOM(contextMenuDoc, "#request-list-context-newtab"); + let requestItems = document.querySelectorAll(".request-list-item"); + let lastRequest = requestItems[requestItems.length - 1]; + EventUtils.sendMouseEvent({ type: "mousedown" }, lastRequest); + EventUtils.sendMouseEvent({ type: "contextmenu" }, lastRequest); + await wait; + + let onTabOpen = once(gBrowser.tabContainer, "TabOpen", false); + monitor.panelWin.parent.document + .querySelector("#request-list-context-newtab").click(); + await onTabOpen; + ok(true, "A new tab has been opened"); + + let awaitedTab = gBrowser.selectedTab; + await BrowserTestUtils.browserLoaded(awaitedTab.linkedBrowser); + info("The tab load completed"); + + return awaitedTab; + } + + async function performRequest(method) { + let wait = waitForNetworkEvents(monitor, 1); + await ContentTask.spawn(tab.linkedBrowser, method, async function(meth) { + content.wrappedJSObject.performRequest(meth); + }); + await wait; + } + + async function checkTabResponse(checkedTab, method) { + await ContentTask.spawn(checkedTab.linkedBrowser, method, async function(met) { + let { body } = content.wrappedJSObject.document; + let responseRE = RegExp(met + (met == "POST" ? "\n*\s*foo\=bar\&baz\=42" : "")); + ok(body.innerHTML.match(responseRE), "Tab method and data match original request"); + }); + } }); diff --git a/devtools/client/netmonitor/test/head.js b/devtools/client/netmonitor/test/head.js index d6d6aeb77405..46515cb8150d 100644 --- a/devtools/client/netmonitor/test/head.js +++ b/devtools/client/netmonitor/test/head.js @@ -63,6 +63,7 @@ const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html"; const SEND_BEACON_URL = EXAMPLE_URL + "html_send-beacon.html"; const CORS_URL = EXAMPLE_URL + "html_cors-test-page.html"; const PAUSE_URL = EXAMPLE_URL + "html_pause-test-page.html"; +const OPEN_REQUEST_IN_TAB_URL = EXAMPLE_URL + "html_open-request-in-tab.html"; const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs"; const SIMPLE_UNSORTED_COOKIES_SJS = EXAMPLE_URL + "sjs_simple-unsorted-cookies-test-server.sjs"; @@ -73,6 +74,7 @@ const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs"; const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs"; const CORS_SJS_PATH = "/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs"; const HSTS_SJS = EXAMPLE_URL + "sjs_hsts-test-server.sjs"; +const METHOD_SJS = EXAMPLE_URL + "sjs_method-test-server.sjs"; const HSTS_BASE_URL = EXAMPLE_URL; const HSTS_PAGE_URL = CUSTOM_GET_URL; diff --git a/devtools/client/netmonitor/test/html_open-request-in-tab.html b/devtools/client/netmonitor/test/html_open-request-in-tab.html new file mode 100644 index 000000000000..819efbff8b21 --- /dev/null +++ b/devtools/client/netmonitor/test/html_open-request-in-tab.html @@ -0,0 +1,31 @@ + + + + +
+ + + + +
+ + +
+