зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1272256 - Adding in longpress new tab button container menu r=Gijs
MozReview-Commit-ID: 5KECDW34G8M --HG-- extra : rebase_source : 95cd57a27dc0ac76e1a0ac15afa59ba04a2e3c8a
This commit is contained in:
Родитель
13d2c8e67f
Коммит
b55bb2b76f
|
@ -90,6 +90,15 @@
|
|||
);
|
||||
} else {
|
||||
SimpleTest.ok(true, "Testing Firefox tabbrowser UI.");
|
||||
let newTabChildren = [];
|
||||
if (SpecialPowers.getBoolPref("privacy.userContext.enabled")) {
|
||||
newTabChildren = [
|
||||
{
|
||||
role: ROLE_MENUPOPUP,
|
||||
children: []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// NB: The (3) buttons are not visible, unless manually hovered,
|
||||
// probably due to size reduction in this test.
|
||||
|
@ -119,7 +128,7 @@
|
|||
{
|
||||
// xul:toolbarbutton ("Open a new tab")
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: []
|
||||
children: newTabChildren
|
||||
}
|
||||
// "List all tabs" dropdown
|
||||
// XXX: This child(?) is not present in this test.
|
||||
|
|
|
@ -119,6 +119,16 @@ tabbrowser {
|
|||
visibility: hidden; /* temporary space to keep a tab's close button under the cursor */
|
||||
}
|
||||
|
||||
.tabs-newtab-button > .toolbarbutton-menu-dropmarker,
|
||||
#new-tab-button > .toolbarbutton-menu-dropmarker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tabs-newtab-button > .toolbarbutton-icon,
|
||||
#new-tab-button > .toolbarbutton-icon {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
.tabbrowser-tab {
|
||||
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
|
||||
}
|
||||
|
@ -177,6 +187,7 @@ tabbrowser {
|
|||
transition: transform 200ms ease-out;
|
||||
}
|
||||
|
||||
.new-tab-popup,
|
||||
#alltabs-popup {
|
||||
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
|
||||
}
|
||||
|
|
|
@ -263,15 +263,26 @@ function UpdateBackForwardCommands(aWebNavigation) {
|
|||
* XXXmano: should this live in toolbarbutton.xml?
|
||||
*/
|
||||
function SetClickAndHoldHandlers() {
|
||||
var timer;
|
||||
// Bug 414797: Clone the back/forward buttons' context menu into both buttons.
|
||||
let popup = document.getElementById("backForwardMenu").cloneNode(true);
|
||||
popup.removeAttribute("id");
|
||||
// Prevent the back/forward buttons' context attributes from being inherited.
|
||||
popup.setAttribute("context", "");
|
||||
|
||||
function openMenu(aButton) {
|
||||
cancelHold(aButton);
|
||||
aButton.firstChild.hidden = false;
|
||||
aButton.open = true;
|
||||
let backButton = document.getElementById("back-button");
|
||||
backButton.setAttribute("type", "menu");
|
||||
backButton.appendChild(popup);
|
||||
addClickAndHoldListenersOnElement(backButton);
|
||||
|
||||
let forwardButton = document.getElementById("forward-button");
|
||||
popup = popup.cloneNode(true);
|
||||
forwardButton.setAttribute("type", "menu");
|
||||
forwardButton.appendChild(popup);
|
||||
addClickAndHoldListenersOnElement(forwardButton);
|
||||
}
|
||||
|
||||
function mousedownHandler(aEvent) {
|
||||
let holdTimersMap = new Map();
|
||||
function holdMousedownHandler(aEvent) {
|
||||
if (aEvent.button != 0 ||
|
||||
aEvent.currentTarget.open ||
|
||||
aEvent.currentTarget.disabled)
|
||||
|
@ -280,32 +291,12 @@ function SetClickAndHoldHandlers() {
|
|||
// Prevent the menupopup from opening immediately
|
||||
aEvent.currentTarget.firstChild.hidden = true;
|
||||
|
||||
aEvent.currentTarget.addEventListener("mouseout", mouseoutHandler, false);
|
||||
aEvent.currentTarget.addEventListener("mouseup", mouseupHandler, false);
|
||||
timer = setTimeout(openMenu, 500, aEvent.currentTarget);
|
||||
aEvent.currentTarget.addEventListener("mouseout", holdMouseoutHandler, false);
|
||||
aEvent.currentTarget.addEventListener("mouseup", holdMouseupHandler, false);
|
||||
holdTimersMap.set(aEvent.currentTarget, setTimeout(holdOpenMenu, 500, aEvent.currentTarget));
|
||||
}
|
||||
|
||||
function mouseoutHandler(aEvent) {
|
||||
let buttonRect = aEvent.currentTarget.getBoundingClientRect();
|
||||
if (aEvent.clientX >= buttonRect.left &&
|
||||
aEvent.clientX <= buttonRect.right &&
|
||||
aEvent.clientY >= buttonRect.bottom)
|
||||
openMenu(aEvent.currentTarget);
|
||||
else
|
||||
cancelHold(aEvent.currentTarget);
|
||||
}
|
||||
|
||||
function mouseupHandler(aEvent) {
|
||||
cancelHold(aEvent.currentTarget);
|
||||
}
|
||||
|
||||
function cancelHold(aButton) {
|
||||
clearTimeout(timer);
|
||||
aButton.removeEventListener("mouseout", mouseoutHandler, false);
|
||||
aButton.removeEventListener("mouseup", mouseupHandler, false);
|
||||
}
|
||||
|
||||
function clickHandler(aEvent) {
|
||||
function holdClickHandler(aEvent) {
|
||||
if (aEvent.button == 0 &&
|
||||
aEvent.target == aEvent.currentTarget &&
|
||||
!aEvent.currentTarget.open &&
|
||||
|
@ -316,29 +307,48 @@ function SetClickAndHoldHandlers() {
|
|||
aEvent.metaKey, null);
|
||||
aEvent.currentTarget.dispatchEvent(cmdEvent);
|
||||
}
|
||||
// This is here to cancel the XUL default event
|
||||
// dom.click() triggers a command even if there is a click handler
|
||||
// however this can now be prevented with preventDefault().
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
|
||||
function _addClickAndHoldListenersOnElement(aElm) {
|
||||
aElm.addEventListener("mousedown", mousedownHandler, true);
|
||||
aElm.addEventListener("click", clickHandler, true);
|
||||
function holdOpenMenu(aButton) {
|
||||
cancelHold(aButton);
|
||||
aButton.firstChild.hidden = false;
|
||||
aButton.open = true;
|
||||
}
|
||||
|
||||
// Bug 414797: Clone the back/forward buttons' context menu into both buttons.
|
||||
let popup = document.getElementById("backForwardMenu").cloneNode(true);
|
||||
popup.removeAttribute("id");
|
||||
// Prevent the back/forward buttons' context attributes from being inherited.
|
||||
popup.setAttribute("context", "");
|
||||
function holdMouseoutHandler(aEvent) {
|
||||
let buttonRect = aEvent.currentTarget.getBoundingClientRect();
|
||||
if (aEvent.clientX >= buttonRect.left &&
|
||||
aEvent.clientX <= buttonRect.right &&
|
||||
aEvent.clientY >= buttonRect.bottom)
|
||||
holdOpenMenu(aEvent.currentTarget);
|
||||
else
|
||||
cancelHold(aEvent.currentTarget);
|
||||
}
|
||||
|
||||
let backButton = document.getElementById("back-button");
|
||||
backButton.setAttribute("type", "menu");
|
||||
backButton.appendChild(popup);
|
||||
_addClickAndHoldListenersOnElement(backButton);
|
||||
function holdMouseupHandler(aEvent) {
|
||||
cancelHold(aEvent.currentTarget);
|
||||
}
|
||||
|
||||
let forwardButton = document.getElementById("forward-button");
|
||||
popup = popup.cloneNode(true);
|
||||
forwardButton.setAttribute("type", "menu");
|
||||
forwardButton.appendChild(popup);
|
||||
_addClickAndHoldListenersOnElement(forwardButton);
|
||||
function cancelHold(aButton) {
|
||||
clearTimeout(holdTimersMap.get(aButton));
|
||||
aButton.removeEventListener("mouseout", holdMouseoutHandler, false);
|
||||
aButton.removeEventListener("mouseup", holdMouseupHandler, false);
|
||||
}
|
||||
|
||||
function removeClickAndHoldListenersOnElement(aElm) {
|
||||
aElm.removeEventListener("mousedown", holdMousedownHandler, true);
|
||||
aElm.removeEventListener("click", holdClickHandler, true);
|
||||
}
|
||||
|
||||
function addClickAndHoldListenersOnElement(aElm) {
|
||||
holdTimersMap.delete(aElm);
|
||||
|
||||
aElm.addEventListener("mousedown", holdMousedownHandler, true);
|
||||
aElm.addEventListener("click", holdClickHandler, true);
|
||||
}
|
||||
|
||||
const gSessionHistoryObserver = {
|
||||
|
|
|
@ -4939,7 +4939,7 @@
|
|||
</xul:arrowscrollbox>
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIDOMEventListener">
|
||||
<implementation implements="nsIDOMEventListener, nsIObserver">
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
|
||||
|
@ -4958,9 +4958,21 @@
|
|||
this._tabAnimationLoggingEnabled = false;
|
||||
}
|
||||
this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
|
||||
this.observe(null, "nsPref:changed", "privacy.userContext.enabled");
|
||||
Services.prefs.addObserver("privacy.userContext.enabled", this, false);
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<destructor>
|
||||
<![CDATA[
|
||||
Services.prefs.removeObserver("privacy.userContext.enabled", this);
|
||||
]]>
|
||||
</destructor>
|
||||
|
||||
<field name="newtabUndoCloseTab" readonly="true">
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "newtab_undoCloseTab");
|
||||
</field>
|
||||
|
||||
<field name="tabbrowser" readonly="true">
|
||||
document.getElementById(this.getAttribute("tabbrowser"));
|
||||
</field>
|
||||
|
@ -4986,6 +4998,54 @@
|
|||
<field name="_afterHoveredTab">null</field>
|
||||
<field name="_hoveredTab">null</field>
|
||||
|
||||
<method name="observe">
|
||||
<parameter name="aSubject"/>
|
||||
<parameter name="aTopic"/>
|
||||
<parameter name="aData"/>
|
||||
<body><![CDATA[
|
||||
switch (aTopic) {
|
||||
case "nsPref:changed":
|
||||
// This is the only pref observed.
|
||||
let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
|
||||
|
||||
const newTab = document.getElementById("new-tab-button");
|
||||
const newTab2 = document.getAnonymousElementByAttribute(this, "anonid", "tabs-newtab-button")
|
||||
|
||||
if (containersEnabled) {
|
||||
for (let parent of [newTab, newTab2]) {
|
||||
if (!parent)
|
||||
continue;
|
||||
let popup = document.createElementNS(
|
||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||
"menupopup");
|
||||
if (parent.id) {
|
||||
popup.id = "newtab-popup";
|
||||
} else {
|
||||
popup.setAttribute("anonid", "newtab-popup");
|
||||
}
|
||||
popup.oncommand="event.stopPropagation();";
|
||||
popup.className = "new-tab-popup";
|
||||
popup.setAttribute("position", "after_end");
|
||||
parent.appendChild(popup);
|
||||
|
||||
addClickAndHoldListenersOnElement(parent);
|
||||
parent.setAttribute("type", "menu");
|
||||
}
|
||||
} else {
|
||||
for (let parent of [newTab, newTab2]) {
|
||||
if (!parent)
|
||||
continue;
|
||||
removeClickAndHoldListenersOnElement(parent);
|
||||
parent.removeAttribute("type");
|
||||
parent.firstChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<property name="_isCustomizing" readonly="true">
|
||||
<getter>
|
||||
let root = document.documentElement;
|
||||
|
@ -6673,6 +6733,11 @@
|
|||
}
|
||||
|
||||
let containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
|
||||
|
||||
if (event.target.getAttribute('anonid') == "newtab-popup" ||
|
||||
event.target.id == "newtab-popup") {
|
||||
createUserContextMenu(event);
|
||||
} else {
|
||||
document.getElementById("alltabs-popup-separator-1").hidden = !containersEnabled;
|
||||
let containersTab = document.getElementById("alltabs_containersTab");
|
||||
|
||||
|
@ -6697,6 +6762,7 @@
|
|||
this._createTabMenuItem(tabs[i]);
|
||||
}
|
||||
this._updateTabsVisibilityStatus();
|
||||
}
|
||||
]]></handler>
|
||||
|
||||
<handler event="popuphidden">
|
||||
|
@ -6712,6 +6778,9 @@
|
|||
menuItem.tab.mCorrespondingMenuitem = null;
|
||||
this.removeChild(menuItem);
|
||||
}
|
||||
if (menuItem.hasAttribute("usercontextid")) {
|
||||
this.removeChild(menuItem);
|
||||
}
|
||||
}
|
||||
var tabcontainer = gBrowser.tabContainer;
|
||||
tabcontainer.mTabstrip.removeEventListener("scroll", this, false);
|
||||
|
|
|
@ -13,6 +13,7 @@ skip-if = (debug && (os == "win" || os == "linux")) # intermittent negative leak
|
|||
[browser_eme.js]
|
||||
[browser_favicon.js]
|
||||
[browser_forgetaboutsite.js]
|
||||
[browser_newtabButton.js]
|
||||
[browser_usercontext.js]
|
||||
[browser_usercontextid_tabdrop.js]
|
||||
skip-if = os == "mac" || os == "win" # Intermittent failure - bug 1268276
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
// Testing that when the user opens the add tab menu and clicks menu items
|
||||
// the correct context id is opened
|
||||
|
||||
add_task(function* test() {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true]
|
||||
]});
|
||||
|
||||
let newTab = document.getElementById('tabbrowser-tabs');
|
||||
let newTabButton = document.getAnonymousElementByAttribute(newTab, "anonid", "tabs-newtab-button");
|
||||
ok(newTabButton, "New tab button exists");
|
||||
ok(!newTabButton.hidden, "New tab button is visible");
|
||||
let popup = document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
|
||||
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(newTabButton, {type: "mousedown"});
|
||||
|
||||
yield popupShownPromise;
|
||||
let contextIdItem = popup.querySelector(`menuitem[usercontextid="${i}"]`);
|
||||
|
||||
ok(contextIdItem, `User context id ${i} exists`);
|
||||
|
||||
let waitForTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
|
||||
EventUtils.synthesizeMouseAtCenter(contextIdItem, {});
|
||||
|
||||
let tab = yield waitForTabPromise;
|
||||
|
||||
is(tab.getAttribute('usercontextid'), i, `New tab has UCI equal ${i}`);
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
});
|
Загрузка…
Ссылка в новой задаче