mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 935815 - [Australis] UITour: Allow adding a button with an action to the info panel. r=MattN
This commit is contained in:
parent
892809e3fa
commit
cd86b382d5
@ -202,8 +202,16 @@
|
||||
align="start"
|
||||
orient="vertical"
|
||||
role="alert">
|
||||
<label id="UITourTooltipTitle" flex="1"/>
|
||||
<description id="UITourTooltipDescription" flex="1"/>
|
||||
<hbox>
|
||||
<vbox>
|
||||
<image id="UITourTooltipIcon"/>
|
||||
</vbox>
|
||||
<vbox flex="1">
|
||||
<label id="UITourTooltipTitle" flex="1"/>
|
||||
<description id="UITourTooltipDescription" flex="1"/>
|
||||
<hbox id="UITourTooltipButtons" flex="1" align="end"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</panel>
|
||||
<panel id="UITourHighlightContainer"
|
||||
hidden="true"
|
||||
|
@ -22,6 +22,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||
|
||||
const UITOUR_PERMISSION = "uitour";
|
||||
const PREF_PERM_BRANCH = "browser.uitour.";
|
||||
const MAX_BUTTONS = 4;
|
||||
|
||||
|
||||
this.UITour = {
|
||||
@ -125,7 +126,34 @@ this.UITour = {
|
||||
Cu.reportError("UITour: Target could not be resolved: " + data.target);
|
||||
return;
|
||||
}
|
||||
this.showInfo(target, data.title, data.text);
|
||||
|
||||
let iconURL = null;
|
||||
if (typeof data.icon == "string")
|
||||
iconURL = this.resolveURL(contentDocument, data.icon);
|
||||
|
||||
let buttons = [];
|
||||
if (Array.isArray(data.buttons) && data.buttons.length > 0) {
|
||||
for (let buttonData of data.buttons) {
|
||||
if (typeof buttonData == "object" &&
|
||||
typeof buttonData.label == "string" &&
|
||||
typeof buttonData.callbackID == "string") {
|
||||
let button = {
|
||||
label: buttonData.label,
|
||||
callbackID: buttonData.callbackID,
|
||||
};
|
||||
|
||||
if (typeof buttonData.icon == "string")
|
||||
button.iconURL = this.resolveURL(contentDocument, buttonData.icon);
|
||||
|
||||
buttons.push(button);
|
||||
|
||||
if (buttons.length == MAX_BUTTONS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.showInfo(contentDocument, target, data.title, data.text, iconURL, buttons);
|
||||
}).then(null, Cu.reportError);
|
||||
break;
|
||||
}
|
||||
@ -303,11 +331,7 @@ this.UITour = {
|
||||
if (uri.schemeIs("chrome"))
|
||||
return true;
|
||||
|
||||
let allowedSchemes = new Set(["https"]);
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
|
||||
allowedSchemes.add("http");
|
||||
|
||||
if (!allowedSchemes.has(uri.scheme))
|
||||
if (!this.isSafeScheme(uri))
|
||||
return false;
|
||||
|
||||
this.importPermissions();
|
||||
@ -315,6 +339,50 @@ this.UITour = {
|
||||
return permission == Services.perms.ALLOW_ACTION;
|
||||
},
|
||||
|
||||
isSafeScheme: function(aURI) {
|
||||
let allowedSchemes = new Set(["https"]);
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
|
||||
allowedSchemes.add("http");
|
||||
|
||||
if (!allowedSchemes.has(aURI.scheme))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
resolveURL: function(aDocument, aURL) {
|
||||
try {
|
||||
let uri = Services.io.newURI(aURL, null, aDocument.documentURIObject);
|
||||
|
||||
if (!this.isSafeScheme(uri))
|
||||
return null;
|
||||
|
||||
return uri.spec;
|
||||
} catch (e) {}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
sendPageCallback: function(aDocument, aCallbackID, aData = {}) {
|
||||
let detail = Cu.createObjectIn(aDocument.defaultView);
|
||||
detail.data = Cu.createObjectIn(detail);
|
||||
|
||||
for (let key of Object.keys(aData))
|
||||
detail.data[key] = aData[key];
|
||||
|
||||
Cu.makeObjectPropsNormal(detail.data);
|
||||
Cu.makeObjectPropsNormal(detail);
|
||||
|
||||
detail.callbackID = aCallbackID;
|
||||
|
||||
let event = new aDocument.defaultView.CustomEvent("mozUITourResponse", {
|
||||
bubbles: true,
|
||||
detail: detail
|
||||
});
|
||||
|
||||
aDocument.dispatchEvent(event);
|
||||
},
|
||||
|
||||
getTarget: function(aWindow, aTargetName, aSticky = false) {
|
||||
let deferred = Promise.defer();
|
||||
if (typeof aTargetName != "string" || !aTargetName) {
|
||||
@ -506,7 +574,7 @@ this.UITour = {
|
||||
this._setAppMenuStateForAnnotation(aWindow, "highlight", false);
|
||||
},
|
||||
|
||||
showInfo: function(aAnchor, aTitle, aDescription) {
|
||||
showInfo: function(aContentDocument, aAnchor, aTitle = "", aDescription = "", aIconURL = "", aButtons = []) {
|
||||
function showInfoPanel(aAnchorEl) {
|
||||
aAnchorEl.focus();
|
||||
|
||||
@ -514,6 +582,8 @@ this.UITour = {
|
||||
let tooltip = document.getElementById("UITourTooltip");
|
||||
let tooltipTitle = document.getElementById("UITourTooltipTitle");
|
||||
let tooltipDesc = document.getElementById("UITourTooltipDescription");
|
||||
let tooltipIcon = document.getElementById("UITourTooltipIcon");
|
||||
let tooltipButtons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
if (tooltip.state == "open") {
|
||||
tooltip.hidePopup();
|
||||
@ -521,6 +591,28 @@ this.UITour = {
|
||||
|
||||
tooltipTitle.textContent = aTitle;
|
||||
tooltipDesc.textContent = aDescription;
|
||||
tooltipIcon.src = aIconURL;
|
||||
tooltipIcon.hidden = !aIconURL;
|
||||
|
||||
while (tooltipButtons.firstChild)
|
||||
tooltipButtons.firstChild.remove();
|
||||
|
||||
for (let button of aButtons) {
|
||||
let el = document.createElement("button");
|
||||
el.setAttribute("label", button.label);
|
||||
if (button.iconURL)
|
||||
el.setAttribute("image", button.iconURL);
|
||||
|
||||
let callbackID = button.callbackID;
|
||||
el.addEventListener("command", event => {
|
||||
tooltip.hidePopup();
|
||||
this.sendPageCallback(aContentDocument, callbackID);
|
||||
});
|
||||
|
||||
tooltipButtons.appendChild(el);
|
||||
}
|
||||
|
||||
tooltipButtons.hidden = !aButtons.length;
|
||||
|
||||
tooltip.hidden = false;
|
||||
let alignment = "bottomcenter topright";
|
||||
@ -533,9 +625,15 @@ this.UITour = {
|
||||
},
|
||||
|
||||
hideInfo: function(aWindow) {
|
||||
let tooltip = aWindow.document.getElementById("UITourTooltip");
|
||||
let document = aWindow.document;
|
||||
|
||||
let tooltip = document.getElementById("UITourTooltip");
|
||||
tooltip.hidePopup();
|
||||
this._setAppMenuStateForAnnotation(aWindow, "info", false);
|
||||
|
||||
let tooltipButtons = document.getElementById("UITourTooltipButtons");
|
||||
while (tooltipButtons.firstChild)
|
||||
tooltipButtons.firstChild.remove();
|
||||
},
|
||||
|
||||
showMenu: function(aWindow, aMenuName, aOpenCallback = null) {
|
||||
|
@ -5,6 +5,6 @@ support-files =
|
||||
[browser_NetworkPrioritizer.js]
|
||||
[browser_SignInToWebsite.js]
|
||||
[browser_UITour.js]
|
||||
support-files = uitour.*
|
||||
support-files = uitour.* image.png
|
||||
[browser_taskbar_preview.js]
|
||||
run-if = os == "win"
|
||||
|
@ -4,6 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
let gTestTab;
|
||||
let gContentWindow;
|
||||
let gContentAPI;
|
||||
|
||||
Components.utils.import("resource:///modules/UITour.jsm");
|
||||
@ -66,10 +67,10 @@ function loadTestPage(callback, host = "https://example.com/") {
|
||||
gTestTab.linkedBrowser.addEventListener("load", function onLoad() {
|
||||
gTestTab.linkedBrowser.removeEventListener("load", onLoad);
|
||||
|
||||
let contentWindow = Components.utils.waiveXrays(gTestTab.linkedBrowser.contentDocument.defaultView);
|
||||
gContentAPI = contentWindow.Mozilla.UITour;
|
||||
gContentWindow = Components.utils.waiveXrays(gTestTab.linkedBrowser.contentDocument.defaultView);
|
||||
gContentAPI = gContentWindow.Mozilla.UITour;
|
||||
|
||||
waitForFocus(callback, contentWindow);
|
||||
waitForFocus(callback, gContentWindow);
|
||||
}, true);
|
||||
}
|
||||
|
||||
@ -82,6 +83,7 @@ function test() {
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
delete window.UITour;
|
||||
delete window.gContentWindow;
|
||||
delete window.gContentAPI;
|
||||
if (gTestTab)
|
||||
gBrowser.removeTab(gTestTab);
|
||||
@ -285,11 +287,16 @@ let tests = [
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
|
||||
is(title.textContent, "test title", "Popup should have correct title");
|
||||
is(desc.textContent, "test text", "Popup should have correct description text");
|
||||
is(icon.src, "", "Popup should have no icon");
|
||||
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
|
||||
|
||||
popup.addEventListener("popuphidden", function onPopupHidden() {
|
||||
popup.removeEventListener("popuphidden", onPopupHidden);
|
||||
@ -311,11 +318,16 @@ let tests = [
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
|
||||
is(title.textContent, "urlbar title", "Popup should have correct title");
|
||||
is(desc.textContent, "urlbar text", "Popup should have correct description text");
|
||||
is(icon.src, "", "Popup should have no icon");
|
||||
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
|
||||
|
||||
gContentAPI.showInfo("search", "search title", "search text");
|
||||
executeSoon(function() {
|
||||
@ -377,6 +389,114 @@ let tests = [
|
||||
}, "Info should be shown after showInfo() for fixed menu panel items");
|
||||
});
|
||||
},
|
||||
function test_info_icon(done) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
|
||||
is(title.textContent, "a title", "Popup should have correct title");
|
||||
is(desc.textContent, "some text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
gContentAPI.showInfo("urlbar", "a title", "some text", "image.png");
|
||||
},
|
||||
function test_info_buttons_1(done) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
|
||||
is(title.textContent, "another title", "Popup should have correct title");
|
||||
is(desc.textContent, "moar text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
is(buttons.childElementCount, 2, "Popup should have two buttons");
|
||||
|
||||
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
|
||||
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
|
||||
|
||||
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
|
||||
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
|
||||
|
||||
popup.addEventListener("popuphidden", function onPopupHidden() {
|
||||
popup.removeEventListener("popuphidden", onPopupHidden);
|
||||
ok(true, "Popup should close automatically");
|
||||
|
||||
executeSoon(function() {
|
||||
is(gContentWindow.callbackResult, "button1", "Correct callback should have been called");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[0], {}, window);
|
||||
});
|
||||
|
||||
let buttons = gContentWindow.makeButtons();
|
||||
gContentAPI.showInfo("urlbar", "another title", "moar text", "./image.png", buttons);
|
||||
},
|
||||
function test_info_buttons_2(done) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
let icon = document.getElementById("UITourTooltipIcon");
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
|
||||
is(title.textContent, "another title", "Popup should have correct title");
|
||||
is(desc.textContent, "moar text", "Popup should have correct description text");
|
||||
|
||||
let imageURL = getRootDirectory(gTestPath) + "image.png";
|
||||
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
is(icon.src, imageURL, "Popup should have correct icon shown");
|
||||
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
is(buttons.childElementCount, 2, "Popup should have two buttons");
|
||||
|
||||
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
|
||||
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
|
||||
|
||||
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
|
||||
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
|
||||
|
||||
popup.addEventListener("popuphidden", function onPopupHidden() {
|
||||
popup.removeEventListener("popuphidden", onPopupHidden);
|
||||
ok(true, "Popup should close automatically");
|
||||
|
||||
executeSoon(function() {
|
||||
is(gContentWindow.callbackResult, "button2", "Correct callback should have been called");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[1], {}, window);
|
||||
});
|
||||
|
||||
let buttons = gContentWindow.makeButtons();
|
||||
gContentAPI.showInfo("urlbar", "another title", "moar text", "./image.png", buttons);
|
||||
},
|
||||
function test_pinnedTab(done) {
|
||||
is(UITour.pinnedTabs.get(window), null, "Should not already have a pinned tab");
|
||||
|
||||
|
BIN
browser/modules/test/image.png
Normal file
BIN
browser/modules/test/image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
@ -5,6 +5,22 @@
|
||||
<title>UITour test</title>
|
||||
<script type="application/javascript" src="uitour.js">
|
||||
</script>
|
||||
<script type="application/javascript">
|
||||
var callbackResult;
|
||||
function makeCallback(name) {
|
||||
return (function() {
|
||||
callbackResult = name;
|
||||
});
|
||||
}
|
||||
|
||||
// Defined in content to avoid weird issues when crossing between chrome/content.
|
||||
function makeButtons() {
|
||||
return [
|
||||
{label: "Button 1", callback: makeCallback("button1")},
|
||||
{label: "Button 2", callback: makeCallback("button2"), icon: "image.png"}
|
||||
];
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>UITour tests</h1>
|
||||
|
@ -25,7 +25,6 @@ if (typeof Mozilla == 'undefined') {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _sendEvent(action, data) {
|
||||
var event = new CustomEvent('mozUITour', {
|
||||
bubbles: true,
|
||||
@ -34,10 +33,31 @@ if (typeof Mozilla == 'undefined') {
|
||||
data: data || {}
|
||||
}
|
||||
});
|
||||
console.log("Sending mozUITour event: ", event);
|
||||
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function _generateCallbackID() {
|
||||
return Math.random().toString(36).replace(/[^a-z]+/g, '');
|
||||
}
|
||||
|
||||
function _waitForCallback(callback) {
|
||||
var id = _generateCallbackID();
|
||||
|
||||
function listener(event) {
|
||||
if (typeof event.detail != "object")
|
||||
return;
|
||||
if (event.detail.callbackID != id)
|
||||
return;
|
||||
|
||||
document.removeEventListener("mozUITourResponse", listener);
|
||||
callback(event.detail.data);
|
||||
}
|
||||
document.addEventListener("mozUITourResponse", listener);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY = 10 * 1000;
|
||||
|
||||
Mozilla.UITour.showHighlight = function(target, effect) {
|
||||
@ -51,11 +71,24 @@ if (typeof Mozilla == 'undefined') {
|
||||
_sendEvent('hideHighlight');
|
||||
};
|
||||
|
||||
Mozilla.UITour.showInfo = function(target, title, text) {
|
||||
Mozilla.UITour.showInfo = function(target, title, text, icon, buttons) {
|
||||
var buttonData = [];
|
||||
if (Array.isArray(buttons)) {
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
buttonData.push({
|
||||
label: buttons[i].label,
|
||||
icon: buttons[i].icon,
|
||||
callbackID: _waitForCallback(buttons[i].callback)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_sendEvent('showInfo', {
|
||||
target: target,
|
||||
title: title,
|
||||
text: text
|
||||
text: text,
|
||||
icon: icon,
|
||||
buttons: buttonData
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -22,8 +22,10 @@
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
#UITourTooltip {
|
||||
max-width: 20em;
|
||||
#UITourTooltipIcon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#UITourTooltipTitle {
|
||||
@ -35,3 +37,13 @@
|
||||
#UITourTooltipDescription {
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
#UITourTooltipButtons {
|
||||
height: 5em;
|
||||
}
|
||||
|
||||
#UITourTooltipButtons > button[image] > .button-box > .button-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user