mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge fx-team to mozilla-central a=merge
This commit is contained in:
commit
44392ef17a
@ -37,7 +37,6 @@ All changes need a review by someone on the Jetpack review crew:
|
||||
- [@mossop]
|
||||
- [@gozala]
|
||||
- [@ZER0]
|
||||
- [@erikvold]
|
||||
- [@jsantell]
|
||||
- [@zombie]
|
||||
|
||||
@ -61,6 +60,5 @@ For API and developer ergonomics review, ask [@gozala].
|
||||
[@mossop]:https://github.com/mossop/
|
||||
[@gozala]:https://github.com/Gozala/
|
||||
[@ZER0]:https://github.com/ZER0/
|
||||
[@erikvold]:https://github.com/erikvold/
|
||||
[@jsantell]:https://github.com/jsantell
|
||||
[@zombie]:https://github.com/zombie
|
||||
|
@ -3,7 +3,6 @@ github
|
||||
stackoverflow
|
||||
bugzilla
|
||||
irc
|
||||
erikvold
|
||||
jsantell
|
||||
mossop
|
||||
gozala
|
||||
|
@ -2,6 +2,7 @@
|
||||
support-files =
|
||||
file_dom_notifications.html
|
||||
|
||||
[browser_notification_do_not_disturb.js]
|
||||
[browser_notification_open_settings.js]
|
||||
[browser_notification_remove_permission.js]
|
||||
skip-if = e10s
|
||||
|
@ -0,0 +1,91 @@
|
||||
"use strict";
|
||||
|
||||
var tab;
|
||||
var notification;
|
||||
var notification2;
|
||||
var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
|
||||
|
||||
const ALERT_SERVICE = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
|
||||
|
||||
function test () {
|
||||
waitForExplicitFinish();
|
||||
|
||||
try {
|
||||
// Only run the test if the do-not-disturb
|
||||
// interface has been implemented.
|
||||
ALERT_SERVICE.manualDoNotDisturb;
|
||||
ok(true, "Alert service implements do-not-disturb interface");
|
||||
} catch (e) {
|
||||
ok(true, "Alert service doesn't implement do-not-disturb interface, exiting test");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
let pm = Services.perms;
|
||||
registerCleanupFunction(function() {
|
||||
ALERT_SERVICE.manualDoNotDisturb = false;
|
||||
pm.remove(makeURI(notificationURL), "desktop-notification");
|
||||
gBrowser.removeTab(tab);
|
||||
window.restore();
|
||||
});
|
||||
|
||||
pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION);
|
||||
|
||||
// Make sure that do-not-disturb is not enabled.
|
||||
ok(!ALERT_SERVICE.manualDoNotDisturb, "Alert service should not be disabled when test starts");
|
||||
ALERT_SERVICE.manualDoNotDisturb = false;
|
||||
|
||||
tab = gBrowser.addTab(notificationURL);
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.linkedBrowser.addEventListener("load", onLoad, true);
|
||||
}
|
||||
|
||||
function onLoad() {
|
||||
tab.linkedBrowser.removeEventListener("load", onLoad, true);
|
||||
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
notification = win.showNotification2();
|
||||
notification.addEventListener("show", onAlertShowing);
|
||||
}
|
||||
|
||||
function onAlertShowing() {
|
||||
info("Notification alert showing");
|
||||
notification.removeEventListener("show", onAlertShowing);
|
||||
|
||||
let alertWindow = Services.wm.getMostRecentWindow("alert:alert");
|
||||
if (!alertWindow) {
|
||||
ok(true, "Notifications don't use XUL windows on all platforms.");
|
||||
notification.close();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
let doNotDisturbMenuItem = alertWindow.document.getElementById("doNotDisturbMenuItem");
|
||||
is(doNotDisturbMenuItem.localName, "menuitem", "menuitem found");
|
||||
alertWindow.addEventListener("beforeunload", onAlertClosing);
|
||||
doNotDisturbMenuItem.click();
|
||||
info("Clicked on do-not-disturb menuitem")
|
||||
}
|
||||
|
||||
function onAlertClosing(event) {
|
||||
event.target.removeEventListener("beforeunload", onAlertClosing);
|
||||
|
||||
ok(ALERT_SERVICE.manualDoNotDisturb, "Alert service should be disabled after clicking menuitem");
|
||||
let win = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
notification2 = win.showNotification2();
|
||||
notification2.addEventListener("show", onAlert2Showing);
|
||||
|
||||
// The notification should not appear, but there is
|
||||
// no way from the client-side to know that it was
|
||||
// blocked, except for waiting some time and realizing
|
||||
// that the "onshow" event never fired.
|
||||
setTimeout(function() {
|
||||
notification2.removeEventListener("show", onAlert2Showing);
|
||||
finish();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function onAlert2Showing() {
|
||||
ok(false, "the second alert should not have been shown");
|
||||
notification2.close();
|
||||
}
|
@ -2,6 +2,19 @@
|
||||
* 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/. */
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function () {
|
||||
try {
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
|
||||
// This will throw if manualDoNotDisturb isn't implemented.
|
||||
alertsService.manualDoNotDisturb;
|
||||
return alertsService;
|
||||
} catch (ex) {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
var gContentPane = {
|
||||
init: function ()
|
||||
{
|
||||
@ -30,6 +43,18 @@ var gContentPane = {
|
||||
}
|
||||
}
|
||||
|
||||
let doNotDisturbAlertsEnabled = false;
|
||||
if (AlertsServiceDND) {
|
||||
let notificationsDoNotDisturbRow =
|
||||
document.getElementById("notificationsDoNotDisturbRow");
|
||||
notificationsDoNotDisturbRow.removeAttribute("hidden");
|
||||
if (AlertsServiceDND.manualDoNotDisturb) {
|
||||
let notificationsDoNotDisturb =
|
||||
document.getElementById("notificationsDoNotDisturb");
|
||||
notificationsDoNotDisturb.setAttribute("checked", true);
|
||||
}
|
||||
}
|
||||
|
||||
setEventListener("font.language.group", "change",
|
||||
gContentPane._rebuildFonts);
|
||||
setEventListener("notificationsPolicyButton", "command",
|
||||
@ -46,6 +71,8 @@ var gContentPane = {
|
||||
gContentPane.openTranslationProviderAttribution);
|
||||
setEventListener("translateButton", "command",
|
||||
gContentPane.showTranslationExceptions);
|
||||
setEventListener("notificationsDoNotDisturb", "command",
|
||||
gContentPane.toggleDoNotDisturbNotifications);
|
||||
|
||||
let drmInfoURL =
|
||||
Services.urlFormatter.formatURLPref("app.support.baseURL") + "drm-content";
|
||||
@ -253,5 +280,10 @@ var gContentPane = {
|
||||
{
|
||||
Components.utils.import("resource:///modules/translation/Translation.jsm");
|
||||
Translation.openProviderAttribution();
|
||||
}
|
||||
},
|
||||
|
||||
toggleDoNotDisturbNotifications: function (event)
|
||||
{
|
||||
AlertsServiceDND.manualDoNotDisturb = event.target.checked;
|
||||
},
|
||||
};
|
||||
|
@ -77,6 +77,15 @@
|
||||
accesskey="¬ificationsPolicyButton.accesskey;"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row id="notificationsDoNotDisturbRow" hidden="true">
|
||||
<vbox align="start">
|
||||
<checkbox id="notificationsDoNotDisturb" label="¬ificationsDoNotDisturb.label;"
|
||||
accesskey="¬ificationsDoNotDisturb.accesskey;"/>
|
||||
<label id="notificationsDoNotDisturbDetails"
|
||||
class="indent"
|
||||
value="¬ificationsDoNotDisturbDetails.value;"/>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
|
@ -20,6 +20,7 @@ skip-if = os != "win" # This test tests the windows-specific app selection dialo
|
||||
[browser_cookies_exceptions.js]
|
||||
[browser_healthreport.js]
|
||||
skip-if = !healthreport || (os == 'linux' && debug)
|
||||
[browser_notifications_do_not_disturb.js]
|
||||
[browser_permissions.js]
|
||||
[browser_proxy_backup.js]
|
||||
[browser_privacypane_1.js]
|
||||
|
@ -0,0 +1,44 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
while (gBrowser.tabs[1])
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
});
|
||||
|
||||
add_task(function() {
|
||||
let prefs = yield openPreferencesViaOpenPreferencesAPI("paneContent", undefined, {leaveOpen: true});
|
||||
is(prefs.selectedPane, "paneContent", "Content pane was selected");
|
||||
|
||||
let doc = gBrowser.contentDocument;
|
||||
let notificationsDoNotDisturbRow = doc.getElementById("notificationsDoNotDisturbRow");
|
||||
if (notificationsDoNotDisturbRow.hidden) {
|
||||
todo(false, "Do not disturb is not available on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
let alertService;
|
||||
try {
|
||||
alertService = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
|
||||
} catch (ex) {
|
||||
ok(true, "Do not disturb is not available on this platform: " + ex.message);
|
||||
return;
|
||||
}
|
||||
|
||||
let checkbox = doc.getElementById("notificationsDoNotDisturb");
|
||||
ok(!checkbox.checked, "Checkbox should not be checked by default");
|
||||
ok(!alertService.manualDoNotDisturb, "Do not disturb should be off by default");
|
||||
|
||||
let checkboxChanged = waitForEvent(checkbox, "command")
|
||||
checkbox.click();
|
||||
yield checkboxChanged;
|
||||
ok(alertService.manualDoNotDisturb, "Do not disturb should be enabled when checked");
|
||||
|
||||
checkboxChanged = waitForEvent(checkbox, "command")
|
||||
checkbox.click();
|
||||
yield checkboxChanged;
|
||||
ok(!alertService.manualDoNotDisturb, "Do not disturb should be disabled when unchecked");
|
||||
});
|
@ -79,6 +79,32 @@
|
||||
current node -->
|
||||
<!ENTITY inspectorHTMLDelete.label "Delete Node">
|
||||
<!ENTITY inspectorHTMLDelete.accesskey "D">
|
||||
<!-- LOCALIZATION NOTE (inspectorAttributeSubmenu.label): This is the label
|
||||
shown in the inspector contextual-menu for the sub-menu of the other
|
||||
attribute items, which allow to:
|
||||
- add new attribute
|
||||
- edit attribute
|
||||
- remove attribute -->
|
||||
<!ENTITY inspectorAttributeSubmenu.label "Attribute">
|
||||
<!ENTITY inspectorAttributeSubmenu.accesskey "A">
|
||||
|
||||
<!-- LOCALIZATION NOTE (inspectorAddAttribute.label): This is the label shown in
|
||||
the inspector contextual-menu for the item that lets users add attribute
|
||||
to current node -->
|
||||
<!ENTITY inspectorAddAttribute.label "Add Attribute">
|
||||
<!ENTITY inspectorAddAttribute.accesskey "A">
|
||||
|
||||
<!-- LOCALIZATION NOTE (inspectorEditAttribute.label): This is the label shown in
|
||||
the inspector contextual-menu for the item that lets users edit attribute
|
||||
for current node -->
|
||||
<!ENTITY inspectorEditAttribute.label "Edit Attribute">
|
||||
<!ENTITY inspectorEditAttribute.accesskey "E">
|
||||
|
||||
<!-- LOCALIZATION NOTE (inspectorRemoveAttribute.label): This is the label shown in
|
||||
the inspector contextual-menu for the item that lets users delete attribute
|
||||
from current node -->
|
||||
<!ENTITY inspectorRemoveAttribute.label "Remove Attribute">
|
||||
<!ENTITY inspectorRemoveAttribute.accesskey "R">
|
||||
|
||||
<!ENTITY inspector.selectButton.tooltip "Select element with mouse">
|
||||
|
||||
|
@ -104,3 +104,15 @@ inspector.menu.copyUrlToClipboard.label=Copy Link Address
|
||||
# element in the DOM (like with <label for="input-id">), and that allows to
|
||||
# select that element in the inspector.
|
||||
inspector.menu.selectElement.label=Select Element #%S
|
||||
|
||||
# LOCALIZATION NOTE (inspector.menu.editAttribute.label): This is the label of a
|
||||
# sub-menu "Attribute" in the inspector contextual-menu that appears
|
||||
# when the user right-clicks on the node in the inspector, and that allows
|
||||
# to edit an attribute on this node.
|
||||
inspector.menu.editAttribute.label=Edit Attribute %S
|
||||
|
||||
# LOCALIZATION NOTE (inspector.menu.removeAttribute.label): This is the label of a
|
||||
# sub-menu "Attribute" in the inspector contextual-menu that appears
|
||||
# when the user right-clicks on the attribute of a node in the inspector,
|
||||
# and that allows to remove this attribute.
|
||||
inspector.menu.removeAttribute.label=Remove Attribute %S
|
||||
|
@ -11,6 +11,9 @@
|
||||
<!ENTITY notificationsPolicyDesc.label "Choose which sites are allowed to show notifications">
|
||||
<!ENTITY notificationsPolicyButton.accesskey "h">
|
||||
<!ENTITY notificationsPolicyButton.label "Choose…">
|
||||
<!ENTITY notificationsDoNotDisturb.label "Do not disturb me">
|
||||
<!ENTITY notificationsDoNotDisturb.accesskey "n">
|
||||
<!ENTITY notificationsDoNotDisturbDetails.value "No notification will be shown until you restart &brandShortName;">
|
||||
|
||||
<!ENTITY popupExceptions.label "Exceptions…">
|
||||
<!ENTITY popupExceptions.accesskey "E">
|
||||
|
@ -271,7 +271,9 @@ description > html|a {
|
||||
}
|
||||
|
||||
.indent {
|
||||
-moz-margin-start: 33px;
|
||||
/* !important needed to override -moz-margin-start:0 !important; rule
|
||||
define in common.css for labels */
|
||||
-moz-margin-start: 33px !important;
|
||||
}
|
||||
|
||||
.text-link {
|
||||
|
@ -77,6 +77,7 @@ function InspectorPanel(iframeWindow, toolbox) {
|
||||
this.panelWin = iframeWindow;
|
||||
this.panelWin.inspector = this;
|
||||
|
||||
this.nodeMenuTriggerInfo = null;
|
||||
this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
|
||||
this._target.on("will-navigate", this._onBeforeNavigate);
|
||||
|
||||
@ -647,9 +648,14 @@ InspectorPanel.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable the delete item if needed. Update the pseudo classes.
|
||||
* Update, enable, disable, hide, show any menu item depending on the current
|
||||
* element.
|
||||
*/
|
||||
_setupNodeMenu: function() {
|
||||
_setupNodeMenu: function(event) {
|
||||
let markupContainer = this.markup.getContainer(this.selection.nodeFront);
|
||||
this.nodeMenuTriggerInfo =
|
||||
markupContainer.editor.getInfoAtNode(event.target.triggerNode);
|
||||
|
||||
let isSelectionElement = this.selection.isElementNode() &&
|
||||
!this.selection.isPseudoElementNode();
|
||||
let isEditableElement = isSelectionElement &&
|
||||
@ -696,9 +702,8 @@ InspectorPanel.prototype = {
|
||||
expandAll.setAttribute("disabled", "true");
|
||||
collapse.setAttribute("disabled", "true");
|
||||
|
||||
let markUpContainer = this.markup.importNode(this.selection.nodeFront, false);
|
||||
if (this.selection.isNode() && markUpContainer.hasChildren) {
|
||||
if (markUpContainer.expanded) {
|
||||
if (this.selection.isNode() && markupContainer.hasChildren) {
|
||||
if (markupContainer.expanded) {
|
||||
collapse.removeAttribute("disabled");
|
||||
}
|
||||
expandAll.removeAttribute("disabled");
|
||||
@ -784,12 +789,52 @@ InspectorPanel.prototype = {
|
||||
// Enable the "copy image data-uri" item if the selection is previewable
|
||||
// which essentially checks if it's an image or canvas tag
|
||||
let copyImageData = this.panelDoc.getElementById("node-menu-copyimagedatauri");
|
||||
let markupContainer = this.markup.getContainer(this.selection.nodeFront);
|
||||
if (isSelectionElement && markupContainer && markupContainer.isPreviewable()) {
|
||||
copyImageData.removeAttribute("disabled");
|
||||
} else {
|
||||
copyImageData.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
// Enable / disable "Add Attribute", "Edit Attribute"
|
||||
// and "Remove Attribute" items
|
||||
this._setupAttributeMenu(isEditableElement);
|
||||
},
|
||||
|
||||
_setupAttributeMenu: function(isEditableElement) {
|
||||
let addAttribute = this.panelDoc.getElementById("node-menu-add-attribute");
|
||||
let editAttribute = this.panelDoc.getElementById("node-menu-edit-attribute");
|
||||
let removeAttribute = this.panelDoc.getElementById("node-menu-remove-attribute");
|
||||
let nodeInfo = this.nodeMenuTriggerInfo;
|
||||
|
||||
// Enable "Add Attribute" for all editable elements
|
||||
if (isEditableElement) {
|
||||
addAttribute.removeAttribute("disabled");
|
||||
} else {
|
||||
addAttribute.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
// Enable "Edit Attribute" and "Remove Attribute" only on attribute click
|
||||
if (isEditableElement && nodeInfo && nodeInfo.type === "attribute") {
|
||||
editAttribute.removeAttribute("disabled");
|
||||
editAttribute.setAttribute("label",
|
||||
strings.formatStringFromName(
|
||||
"inspector.menu.editAttribute.label", [`"${nodeInfo.name}"`], 1));
|
||||
|
||||
removeAttribute.removeAttribute("disabled");
|
||||
removeAttribute.setAttribute("label",
|
||||
strings.formatStringFromName(
|
||||
"inspector.menu.removeAttribute.label", [`"${nodeInfo.name}"`], 1));
|
||||
} else {
|
||||
editAttribute.setAttribute("disabled", "true");
|
||||
editAttribute.setAttribute("label",
|
||||
strings.formatStringFromName(
|
||||
"inspector.menu.editAttribute.label", [''], 1));
|
||||
|
||||
removeAttribute.setAttribute("disabled", "true");
|
||||
removeAttribute.setAttribute("label",
|
||||
strings.formatStringFromName(
|
||||
"inspector.menu.removeAttribute.label", [''], 1));
|
||||
}
|
||||
},
|
||||
|
||||
_resetNodeMenu: function() {
|
||||
@ -1224,6 +1269,33 @@ InspectorPanel.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add attribute to node.
|
||||
* Used for node context menu and shouldn't be called directly.
|
||||
*/
|
||||
onAddAttribute: function() {
|
||||
let container = this.markup.getContainer(this.selection.nodeFront);
|
||||
container.addAttribute();
|
||||
},
|
||||
|
||||
/**
|
||||
* Edit attribute for node.
|
||||
* Used for node context menu and shouldn't be called directly.
|
||||
*/
|
||||
onEditAttribute: function() {
|
||||
let container = this.markup.getContainer(this.selection.nodeFront);
|
||||
container.editAttribute(this.nodeMenuTriggerInfo.name);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove attribute from node.
|
||||
* Used for node context menu and shouldn't be called directly.
|
||||
*/
|
||||
onRemoveAttribute: function() {
|
||||
let container = this.markup.getContainer(this.selection.nodeFront);
|
||||
container.removeAttribute(this.nodeMenuTriggerInfo.name);
|
||||
},
|
||||
|
||||
expandNode: function() {
|
||||
this.markup.expandAll(this.selection.nodeFront);
|
||||
},
|
||||
|
@ -110,6 +110,23 @@
|
||||
label="&inspectorHTMLDelete.label;"
|
||||
accesskey="&inspectorHTMLDelete.accesskey;"
|
||||
oncommand="inspector.deleteNode()"/>
|
||||
<menu label="&inspectorAttributeSubmenu.label;"
|
||||
accesskey="&inspectorAttributeSubmenu.accesskey;">
|
||||
<menupopup>
|
||||
<menuitem id="node-menu-add-attribute"
|
||||
label="&inspectorAddAttribute.label;"
|
||||
accesskey="&inspectorAddAttribute.accesskey;"
|
||||
oncommand="inspector.onAddAttribute()"/>
|
||||
<menuitem id="node-menu-edit-attribute"
|
||||
label="&inspectorEditAttribute.label;"
|
||||
accesskey="&inspectorEditAttribute.accesskey;"
|
||||
oncommand="inspector.onEditAttribute()"/>
|
||||
<menuitem id="node-menu-remove-attribute"
|
||||
label="&inspectorRemoveAttribute.label;"
|
||||
accesskey="&inspectorRemoveAttribute.accesskey;"
|
||||
oncommand="inspector.onRemoveAttribute()"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator id="node-menu-link-separator"/>
|
||||
<menuitem id="node-menu-link-follow"
|
||||
oncommand="inspector.onFollowLink()"/>
|
||||
|
@ -86,7 +86,8 @@ skip-if = e10s # GCLI isn't e10s compatible. See bug 1128988.
|
||||
[browser_inspector_menu-02-copy-items.js]
|
||||
[browser_inspector_menu-03-paste-items.js]
|
||||
[browser_inspector_menu-04-use-in-console.js]
|
||||
[browser_inspector_menu-05-other.js]
|
||||
[browser_inspector_menu-05-attribute-items.js]
|
||||
[browser_inspector_menu-06-other.js]
|
||||
[browser_inspector_navigation.js]
|
||||
[browser_inspector_pane-toggle-01.js]
|
||||
[browser_inspector_pane-toggle-02.js]
|
||||
|
@ -32,12 +32,24 @@ const ALL_MENU_ITEMS = [
|
||||
"node-menu-pseudo-active",
|
||||
"node-menu-pseudo-focus",
|
||||
"node-menu-scrollnodeintoview",
|
||||
"node-menu-screenshotnode"
|
||||
"node-menu-screenshotnode",
|
||||
"node-menu-add-attribute",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
].concat(PASTE_MENU_ITEMS, ACTIVE_ON_DOCTYPE_ITEMS);
|
||||
|
||||
const INACTIVE_ON_DOCTYPE_ITEMS =
|
||||
ALL_MENU_ITEMS.filter(item => ACTIVE_ON_DOCTYPE_ITEMS.indexOf(item) === -1);
|
||||
|
||||
/**
|
||||
* Test cases, each item of this array may define the following properties:
|
||||
* desc: string that will be logged
|
||||
* selector: selector of the node to be selected
|
||||
* disabled: items that should have disabled state
|
||||
* clipboardData: clipboard content
|
||||
* clipboardDataType: clipboard content type
|
||||
* attributeTrigger: attribute that will be used as context menu trigger
|
||||
*/
|
||||
const TEST_CASES = [
|
||||
{
|
||||
desc: "doctype node with empty clipboard",
|
||||
@ -55,7 +67,11 @@ const TEST_CASES = [
|
||||
desc: "element node HTML on the clipboard",
|
||||
clipboardData: "<p>some text</p>",
|
||||
clipboardDataType: "html",
|
||||
disabled: ["node-menu-copyimagedatauri"],
|
||||
disabled: [
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
],
|
||||
selector: "#sensitivity",
|
||||
},
|
||||
{
|
||||
@ -69,6 +85,8 @@ const TEST_CASES = [
|
||||
"node-menu-pasteafter",
|
||||
"node-menu-pastefirstchild",
|
||||
"node-menu-pastelastchild",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -80,6 +98,8 @@ const TEST_CASES = [
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-pastebefore",
|
||||
"node-menu-pasteafter",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -87,7 +107,10 @@ const TEST_CASES = [
|
||||
clipboardData: "<p>some text</p>",
|
||||
clipboardDataType: "html",
|
||||
selector: "img",
|
||||
disabled: []
|
||||
disabled: [
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]
|
||||
},
|
||||
{
|
||||
desc: "<head> with HTML on clipboard",
|
||||
@ -99,6 +122,8 @@ const TEST_CASES = [
|
||||
"node-menu-pastebefore",
|
||||
"node-menu-pasteafter",
|
||||
"node-menu-screenshotnode",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -107,6 +132,8 @@ const TEST_CASES = [
|
||||
disabled: PASTE_MENU_ITEMS.concat([
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-screenshotnode",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]),
|
||||
},
|
||||
{
|
||||
@ -114,7 +141,11 @@ const TEST_CASES = [
|
||||
clipboardData: "some text",
|
||||
clipboardDataType: undefined,
|
||||
selector: "#paste-area",
|
||||
disabled: ["node-menu-copyimagedatauri"],
|
||||
disabled: [
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]
|
||||
},
|
||||
{
|
||||
desc: "<element> with base64 encoded image data uri on clipboard",
|
||||
@ -123,21 +154,33 @@ const TEST_CASES = [
|
||||
"AAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==",
|
||||
clipboardDataType: undefined,
|
||||
selector: "#paste-area",
|
||||
disabled: PASTE_MENU_ITEMS.concat(["node-menu-copyimagedatauri"]),
|
||||
disabled: PASTE_MENU_ITEMS.concat([
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]),
|
||||
},
|
||||
{
|
||||
desc: "<element> with empty string on clipboard",
|
||||
clipboardData: "",
|
||||
clipboardDataType: undefined,
|
||||
selector: "#paste-area",
|
||||
disabled: PASTE_MENU_ITEMS.concat(["node-menu-copyimagedatauri"]),
|
||||
disabled: PASTE_MENU_ITEMS.concat([
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]),
|
||||
},
|
||||
{
|
||||
desc: "<element> with whitespace only on clipboard",
|
||||
clipboardData: " \n\n\t\n\n \n",
|
||||
clipboardDataType: undefined,
|
||||
selector: "#paste-area",
|
||||
disabled: PASTE_MENU_ITEMS.concat(["node-menu-copyimagedatauri"]),
|
||||
disabled: PASTE_MENU_ITEMS.concat([
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]),
|
||||
},
|
||||
{
|
||||
desc: "<element> that isn't visible on the page, empty clipboard",
|
||||
@ -145,6 +188,8 @@ const TEST_CASES = [
|
||||
disabled: PASTE_MENU_ITEMS.concat([
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-screenshotnode",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]),
|
||||
},
|
||||
{
|
||||
@ -153,7 +198,15 @@ const TEST_CASES = [
|
||||
disabled: PASTE_MENU_ITEMS.concat([
|
||||
"node-menu-copyimagedatauri",
|
||||
"node-menu-screenshotnode",
|
||||
"node-menu-edit-attribute",
|
||||
"node-menu-remove-attribute"
|
||||
]),
|
||||
},
|
||||
{
|
||||
desc: "<element> with context menu triggered on attribute, empty clipboard",
|
||||
selector: "#attributes",
|
||||
disabled: PASTE_MENU_ITEMS.concat(["node-menu-copyimagedatauri"]),
|
||||
attributeTrigger: "data-edit"
|
||||
}
|
||||
];
|
||||
|
||||
@ -165,7 +218,7 @@ registerCleanupFunction(() => {
|
||||
add_task(function *() {
|
||||
let { inspector } = yield openInspectorForURL(TEST_URL);
|
||||
for (let test of TEST_CASES) {
|
||||
let { desc, disabled, selector } = test;
|
||||
let { desc, disabled, selector, attributeTrigger } = test;
|
||||
|
||||
info(`Test ${desc}`);
|
||||
setupClipboard(test.clipboardData, test.clipboardDataType);
|
||||
@ -176,7 +229,11 @@ add_task(function *() {
|
||||
yield selectNode(front, inspector);
|
||||
|
||||
info("Simulating context menu click on the selected node container.");
|
||||
contextMenuClick(getContainerForNodeFront(front, inspector).tagLine);
|
||||
let nodeFrontContainer = getContainerForNodeFront(front, inspector);
|
||||
let contextMenuTrigger = attributeTrigger
|
||||
? nodeFrontContainer.tagLine.querySelector(`[data-attr="${attributeTrigger}"]`)
|
||||
: nodeFrontContainer.tagLine;
|
||||
contextMenuClick(contextMenuTrigger);
|
||||
|
||||
for (let menuitem of ALL_MENU_ITEMS) {
|
||||
let elt = inspector.panelDoc.getElementById(menuitem);
|
||||
|
@ -0,0 +1,75 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Test that attribute items work in the context menu
|
||||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_inspector_menu.html";
|
||||
|
||||
add_task(function* () {
|
||||
let { inspector, toolbox, testActor } = yield openInspectorForURL(TEST_URL);
|
||||
yield selectNode("#attributes", inspector);
|
||||
|
||||
yield testAddAttribute();
|
||||
yield testEditAttribute();
|
||||
yield testRemoveAttribute();
|
||||
|
||||
function* testAddAttribute() {
|
||||
info("Testing 'Add Attribute' menu item");
|
||||
let addAttribute = getMenuItem("node-menu-add-attribute");
|
||||
|
||||
info("Triggering 'Add Attribute' and waiting for mutation to occur");
|
||||
dispatchCommandEvent(addAttribute);
|
||||
EventUtils.synthesizeKey('class="u-hidden"', {});
|
||||
let onMutation = inspector.once("markupmutation");
|
||||
EventUtils.synthesizeKey('VK_RETURN', {});
|
||||
yield onMutation;
|
||||
|
||||
let hasAttribute = testActor.hasNode("#attributes.u-hidden");
|
||||
ok(hasAttribute, "attribute was successfully added");
|
||||
}
|
||||
|
||||
function* testEditAttribute() {
|
||||
info("Testing 'Edit Attribute' menu item");
|
||||
let editAttribute = getMenuItem("node-menu-edit-attribute");
|
||||
|
||||
info("Triggering 'Edit Attribute' and waiting for mutation to occur");
|
||||
inspector.nodeMenuTriggerInfo = {
|
||||
type: "attribute",
|
||||
name: "data-edit"
|
||||
};
|
||||
dispatchCommandEvent(editAttribute);
|
||||
EventUtils.synthesizeKey("data-edit='edited'", {});
|
||||
let onMutation = inspector.once("markupmutation");
|
||||
EventUtils.synthesizeKey('VK_RETURN', {});
|
||||
yield onMutation;
|
||||
|
||||
let isAttributeChanged =
|
||||
yield testActor.hasNode("#attributes[data-edit='edited']");
|
||||
ok(isAttributeChanged, "attribute was successfully edited");
|
||||
}
|
||||
|
||||
function* testRemoveAttribute() {
|
||||
info("Testing 'Remove Attribute' menu item");
|
||||
let removeAttribute = getMenuItem("node-menu-remove-attribute");
|
||||
|
||||
info("Triggering 'Remove Attribute' and waiting for mutation to occur");
|
||||
inspector.nodeMenuTriggerInfo = {
|
||||
type: "attribute",
|
||||
name: "data-remove"
|
||||
};
|
||||
let onMutation = inspector.once("markupmutation");
|
||||
dispatchCommandEvent(removeAttribute);
|
||||
yield onMutation;
|
||||
|
||||
let hasAttribute = yield testActor.hasNode("#attributes[data-remove]")
|
||||
ok(!hasAttribute, "attribute was successfully removed");
|
||||
}
|
||||
|
||||
function getMenuItem(id) {
|
||||
let attribute = inspector.panelDoc.getElementById(id);
|
||||
ok(attribute, "Menu item '" + id + "' found");
|
||||
return attribute;
|
||||
}
|
||||
});
|
@ -23,6 +23,7 @@
|
||||
</div>
|
||||
<p id="console-var">Paragraph for testing console variables</p>
|
||||
<p id="console-var-multi">Paragraph for testing multiple console variables</p>
|
||||
<p id="attributes" data-edit="original" data-remove="thing">Attributes are going to be changed here</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -2305,6 +2305,36 @@ MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, {
|
||||
clearSingleTextChild: function() {
|
||||
this.singleTextChild = undefined;
|
||||
this.editor.updateTextEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger new attribute field for input.
|
||||
*/
|
||||
addAttribute: function() {
|
||||
this.editor.newAttr.editMode();
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger attribute field for editing.
|
||||
*/
|
||||
editAttribute: function(attrName) {
|
||||
this.editor.attrElements.get(attrName).editMode();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove attribute from container.
|
||||
* This is an undoable action.
|
||||
*/
|
||||
removeAttribute: function(attrName) {
|
||||
let doMods = this.editor._startModifyingAttributes();
|
||||
let undoMods = this.editor._startModifyingAttributes();
|
||||
this.editor._saveAttribute(attrName, undoMods);
|
||||
doMods.removeAttribute(attrName);
|
||||
this.undo.do(() => {
|
||||
doMods.apply();
|
||||
}, () => {
|
||||
undoMods.apply();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -2361,6 +2391,13 @@ function GenericEditor(aContainer, aNode) {
|
||||
GenericEditor.prototype = {
|
||||
destroy: function() {
|
||||
this.elt.remove();
|
||||
},
|
||||
|
||||
/**
|
||||
* Stub method for consistency with ElementEditor.
|
||||
*/
|
||||
getInfoAtNode: function() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@ -2443,7 +2480,14 @@ TextEditor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {}
|
||||
destroy: function() {},
|
||||
|
||||
/**
|
||||
* Stub method for consistency with ElementEditor.
|
||||
*/
|
||||
getInfoAtNode: function() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2497,18 +2541,14 @@ function ElementEditor(aContainer, aNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let doMods = this._startModifyingAttributes();
|
||||
let undoMods = this._startModifyingAttributes();
|
||||
this._applyAttributes(aVal, null, doMods, undoMods);
|
||||
this.container.undo.do(() => {
|
||||
doMods.apply();
|
||||
}, function() {
|
||||
undoMods.apply();
|
||||
});
|
||||
} catch(x) {
|
||||
console.error(x);
|
||||
}
|
||||
let doMods = this._startModifyingAttributes();
|
||||
let undoMods = this._startModifyingAttributes();
|
||||
this._applyAttributes(aVal, null, doMods, undoMods);
|
||||
this.container.undo.do(() => {
|
||||
doMods.apply();
|
||||
}, function() {
|
||||
undoMods.apply();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -2540,6 +2580,35 @@ ElementEditor.prototype = {
|
||||
flashElementOff(this.getAttributeElement(attrName));
|
||||
}, this.markup.CONTAINER_FLASHING_DURATION);
|
||||
},
|
||||
/**
|
||||
* Returns information about node in the editor.
|
||||
*
|
||||
* @param {DOMNode} node
|
||||
* The node to get information from.
|
||||
*
|
||||
* @return {Object}
|
||||
* An object literal with the following information:
|
||||
* {type: "attribute", name: "rel", value: "index", el: node}
|
||||
*/
|
||||
getInfoAtNode: function(node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let type = null;
|
||||
let name = null;
|
||||
let value = null;
|
||||
|
||||
// Attribute
|
||||
let attribute = node.closest('.attreditor');
|
||||
if (attribute) {
|
||||
type = "attribute";
|
||||
name = attribute.querySelector('.attr-name').textContent;
|
||||
value = attribute.querySelector('.attr-value').textContent;
|
||||
}
|
||||
|
||||
return {type, name, value, el: node};
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the state of the editor from the node.
|
||||
@ -2697,19 +2766,15 @@ ElementEditor.prototype = {
|
||||
// Remove the attribute stored in this editor and re-add any attributes
|
||||
// parsed out of the input element. Restore original attribute if
|
||||
// parsing fails.
|
||||
try {
|
||||
this.refocusOnEdit(aAttr.name, attr, direction);
|
||||
this._saveAttribute(aAttr.name, undoMods);
|
||||
doMods.removeAttribute(aAttr.name);
|
||||
this._applyAttributes(aVal, attr, doMods, undoMods);
|
||||
this.container.undo.do(() => {
|
||||
doMods.apply();
|
||||
}, () => {
|
||||
undoMods.apply();
|
||||
});
|
||||
} catch(ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
this.refocusOnEdit(aAttr.name, attr, direction);
|
||||
this._saveAttribute(aAttr.name, undoMods);
|
||||
doMods.removeAttribute(aAttr.name);
|
||||
this._applyAttributes(aVal, attr, doMods, undoMods);
|
||||
this.container.undo.do(() => {
|
||||
doMods.apply();
|
||||
}, () => {
|
||||
undoMods.apply();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -209,7 +209,6 @@ public class BrowserApp extends GeckoApp
|
||||
private static class MenuItemInfo {
|
||||
public int id;
|
||||
public String label;
|
||||
public String icon;
|
||||
public boolean checkable;
|
||||
public boolean checked;
|
||||
public boolean enabled = true;
|
||||
@ -1763,7 +1762,6 @@ public class BrowserApp extends GeckoApp
|
||||
final MenuItemInfo info = new MenuItemInfo();
|
||||
info.label = message.getString("name");
|
||||
info.id = message.getInt("id") + ADDON_MENU_OFFSET;
|
||||
info.icon = message.optString("icon", null);
|
||||
info.checked = message.optBoolean("checked", false);
|
||||
info.enabled = message.optBoolean("enabled", true);
|
||||
info.visible = message.optBoolean("visible", true);
|
||||
|
@ -2317,9 +2317,9 @@ var NativeWindow = {
|
||||
if (arguments.length == 1) {
|
||||
options = arguments[0];
|
||||
} else if (arguments.length == 3) {
|
||||
Log.w("Browser", "This menu addon API has been deprecated. Instead, use the options object API.");
|
||||
options = {
|
||||
name: arguments[0],
|
||||
icon: arguments[1],
|
||||
callback: arguments[2]
|
||||
};
|
||||
} else {
|
||||
@ -5842,6 +5842,8 @@ var HealthReportStatusListener = {
|
||||
|
||||
var XPInstallObserver = {
|
||||
init: function() {
|
||||
Services.obs.addObserver(this, "addon-install-origin-blocked", false);
|
||||
Services.obs.addObserver(this, "addon-install-disabled", false);
|
||||
Services.obs.addObserver(this, "addon-install-blocked", false);
|
||||
Services.obs.addObserver(this, "addon-install-started", false);
|
||||
Services.obs.addObserver(this, "xpi-signature-changed", false);
|
||||
@ -5851,76 +5853,103 @@ var XPInstallObserver = {
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
let installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
|
||||
let tab = BrowserApp.getTabForBrowser(installInfo.browser);
|
||||
let strings = Strings.browser;
|
||||
|
||||
let host = null;
|
||||
if (installInfo.originatingURI) {
|
||||
host = installInfo.originatingURI.host;
|
||||
}
|
||||
|
||||
let brandShortName = Strings.brand.GetStringFromName("brandShortName");
|
||||
|
||||
switch (aTopic) {
|
||||
case "addon-install-started":
|
||||
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertAddonsDownloading"), "short");
|
||||
NativeWindow.toast.show(strings.GetStringFromName("alertAddonsDownloading"), "short");
|
||||
break;
|
||||
case "addon-install-blocked": {
|
||||
let installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
|
||||
let tab = BrowserApp.getTabForBrowser(installInfo.browser);
|
||||
case "addon-install-disabled": {
|
||||
if (!tab)
|
||||
return;
|
||||
|
||||
let host = null;
|
||||
if (installInfo.originatingURI) {
|
||||
host = installInfo.originatingURI.host;
|
||||
}
|
||||
|
||||
let brandShortName = Strings.brand.GetStringFromName("brandShortName");
|
||||
let notificationName, buttons, message;
|
||||
let strings = Strings.browser;
|
||||
let enabled = true;
|
||||
try {
|
||||
enabled = Services.prefs.getBoolPref("xpinstall.enabled");
|
||||
}
|
||||
catch (e) {}
|
||||
} catch (e) {}
|
||||
|
||||
let buttons, message, callback;
|
||||
if (!enabled) {
|
||||
notificationName = "xpinstall-disabled";
|
||||
if (Services.prefs.prefIsLocked("xpinstall.enabled")) {
|
||||
message = strings.GetStringFromName("xpinstallDisabledMessageLocked");
|
||||
buttons = [];
|
||||
} else {
|
||||
message = strings.formatStringFromName("xpinstallDisabledMessage2", [brandShortName, host], 2);
|
||||
buttons = [{
|
||||
label: strings.GetStringFromName("xpinstallDisabledButton"),
|
||||
callback: function editPrefs() {
|
||||
Services.prefs.setBoolPref("xpinstall.enabled", true);
|
||||
return false;
|
||||
}
|
||||
}];
|
||||
}
|
||||
message = strings.GetStringFromName("xpinstallDisabledMessageLocked");
|
||||
buttons = [strings.GetStringFromName("unsignedAddonsDisabled.dismiss")];
|
||||
callback: (data) => {};
|
||||
} else {
|
||||
notificationName = "xpinstall";
|
||||
if (host) {
|
||||
// We have a host which asked for the install.
|
||||
message = strings.formatStringFromName("xpinstallPromptWarning2", [brandShortName, host], 2);
|
||||
} else {
|
||||
// Without a host we address the add-on as the initiator of the install.
|
||||
let addon = null;
|
||||
if (installInfo.installs.length > 0) {
|
||||
addon = installInfo.installs[0].name;
|
||||
message = strings.formatStringFromName("xpinstallDisabledMessage2", [brandShortName, host], 2);
|
||||
buttons = [
|
||||
strings.GetStringFromName("xpinstallDisabledButton"),
|
||||
strings.GetStringFromName("unsignedAddonsDisabled.dismiss")
|
||||
];
|
||||
callback: (data) => {
|
||||
if (data.button === 1) {
|
||||
Services.prefs.setBoolPref("xpinstall.enabled", true)
|
||||
}
|
||||
if (addon) {
|
||||
// We have an addon name, show the regular message.
|
||||
message = strings.formatStringFromName("xpinstallPromptWarningLocal", [brandShortName, addon], 2);
|
||||
} else {
|
||||
// We don't have an addon name, show an alternative message.
|
||||
message = strings.formatStringFromName("xpinstallPromptWarningDirect", [brandShortName], 1);
|
||||
}
|
||||
}
|
||||
|
||||
buttons = [{
|
||||
label: strings.GetStringFromName("xpinstallPromptAllowButton"),
|
||||
callback: function() {
|
||||
// Kick off the install
|
||||
installInfo.install();
|
||||
return false;
|
||||
},
|
||||
positive: true
|
||||
}];
|
||||
};
|
||||
}
|
||||
NativeWindow.doorhanger.show(message, aTopic, buttons, tab.id);
|
||||
|
||||
new Prompt({
|
||||
title: Strings.browser.GetStringFromName("addonError.titleError"),
|
||||
message: message,
|
||||
buttons: buttons
|
||||
}).show(callback);
|
||||
break;
|
||||
}
|
||||
case "addon-install-blocked": {
|
||||
if (!tab)
|
||||
return;
|
||||
|
||||
let message;
|
||||
if (host) {
|
||||
// We have a host which asked for the install.
|
||||
message = strings.formatStringFromName("xpinstallPromptWarning2", [brandShortName, host], 2);
|
||||
} else {
|
||||
// Without a host we address the add-on as the initiator of the install.
|
||||
let addon = null;
|
||||
if (installInfo.installs.length > 0) {
|
||||
addon = installInfo.installs[0].name;
|
||||
}
|
||||
if (addon) {
|
||||
// We have an addon name, show the regular message.
|
||||
message = strings.formatStringFromName("xpinstallPromptWarningLocal", [brandShortName, addon], 2);
|
||||
} else {
|
||||
// We don't have an addon name, show an alternative message.
|
||||
message = strings.formatStringFromName("xpinstallPromptWarningDirect", [brandShortName], 1);
|
||||
}
|
||||
}
|
||||
|
||||
let buttons = [
|
||||
strings.GetStringFromName("xpinstallPromptAllowButton"),
|
||||
strings.GetStringFromName("unsignedAddonsDisabled.dismiss")
|
||||
];
|
||||
new Prompt({
|
||||
title: Strings.browser.GetStringFromName("addonError.titleBlocked"),
|
||||
message: message,
|
||||
buttons: buttons
|
||||
}).show((data) => {
|
||||
if (data.button === 0) {
|
||||
// Kick off the install
|
||||
installInfo.install();
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "addon-install-origin-blocked": {
|
||||
if (!tab)
|
||||
return;
|
||||
|
||||
new Prompt({
|
||||
title: Strings.browser.GetStringFromName("addonError.titleBlocked"),
|
||||
message: strings.formatStringFromName("xpinstallPromptWarningDirect", [brandShortName], 1),
|
||||
buttons: [strings.GetStringFromName("unsignedAddonsDisabled.dismiss")]
|
||||
}).show((data) => {});
|
||||
break;
|
||||
}
|
||||
case "xpi-signature-changed": {
|
||||
|
@ -44,11 +44,19 @@ function prefillAlertInfo() {
|
||||
let hostPort = window.arguments[10];
|
||||
const ALERT_BUNDLE = Services.strings.createBundle(
|
||||
"chrome://alerts/locale/alert.properties");
|
||||
const BRAND_BUNDLE = Services.strings.createBundle(
|
||||
"chrome://branding/locale/brand.properties");
|
||||
const BRAND_NAME = BRAND_BUNDLE.GetStringFromName("brandShortName");
|
||||
let label = document.getElementById("alertSourceLabel");
|
||||
label.setAttribute("value",
|
||||
ALERT_BUNDLE.formatStringFromName("source.label",
|
||||
[hostPort],
|
||||
1));
|
||||
let doNotDisturbMenuItem = document.getElementById("doNotDisturbMenuItem");
|
||||
doNotDisturbMenuItem.setAttribute("label",
|
||||
ALERT_BUNDLE.formatStringFromName("doNotDisturb.label",
|
||||
[BRAND_NAME],
|
||||
1));
|
||||
let disableForOrigin = document.getElementById("disableForOriginMenuItem");
|
||||
disableForOrigin.setAttribute("label",
|
||||
ALERT_BUNDLE.formatStringFromName("webActions.disableForOrigin.label",
|
||||
@ -62,12 +70,12 @@ function prefillAlertInfo() {
|
||||
gReplacedWindow = window.arguments[8];
|
||||
case 8:
|
||||
if (window.arguments[7]) {
|
||||
document.getElementById('alertTitleLabel').setAttribute('lang', window.arguments[7]);
|
||||
document.getElementById('alertTextLabel').setAttribute('lang', window.arguments[7]);
|
||||
document.getElementById("alertTitleLabel").setAttribute("lang", window.arguments[7]);
|
||||
document.getElementById("alertTextLabel").setAttribute("lang", window.arguments[7]);
|
||||
}
|
||||
case 7:
|
||||
if (window.arguments[6]) {
|
||||
document.getElementById('alertNotification').style.direction = window.arguments[6];
|
||||
document.getElementById("alertNotification").style.direction = window.arguments[6];
|
||||
}
|
||||
case 6:
|
||||
gOrigin = window.arguments[5];
|
||||
@ -76,20 +84,20 @@ function prefillAlertInfo() {
|
||||
case 4:
|
||||
gAlertTextClickable = window.arguments[3];
|
||||
if (gAlertTextClickable) {
|
||||
document.getElementById('alertNotification').setAttribute('clickable', true);
|
||||
document.getElementById('alertTextLabel').setAttribute('clickable', true);
|
||||
document.getElementById("alertNotification").setAttribute("clickable", true);
|
||||
document.getElementById("alertTextLabel").setAttribute("clickable", true);
|
||||
}
|
||||
case 3:
|
||||
if (window.arguments[2]) {
|
||||
document.getElementById('alertBox').setAttribute('hasBodyText', true);
|
||||
document.getElementById('alertTextLabel').textContent = window.arguments[2];
|
||||
document.getElementById("alertBox").setAttribute("hasBodyText", true);
|
||||
document.getElementById("alertTextLabel").textContent = window.arguments[2];
|
||||
}
|
||||
case 2:
|
||||
document.getElementById('alertTitleLabel').textContent = window.arguments[1];
|
||||
document.getElementById("alertTitleLabel").textContent = window.arguments[1];
|
||||
case 1:
|
||||
if (window.arguments[0]) {
|
||||
document.getElementById('alertBox').setAttribute('hasImage', true);
|
||||
document.getElementById('alertImage').setAttribute('src', window.arguments[0]);
|
||||
document.getElementById("alertBox").setAttribute("hasImage", true);
|
||||
document.getElementById("alertImage").setAttribute("src", window.arguments[0]);
|
||||
}
|
||||
case 0:
|
||||
break;
|
||||
@ -142,7 +150,7 @@ function moveWindowToReplace(aReplacedAlert) {
|
||||
|
||||
// Move windows that come after the replaced alert if the height is different.
|
||||
if (heightDelta != 0) {
|
||||
let windows = Services.wm.getEnumerator('alert:alert');
|
||||
let windows = Services.wm.getEnumerator("alert:alert");
|
||||
while (windows.hasMoreElements()) {
|
||||
let alertWindow = windows.getNext();
|
||||
// boolean to determine if the alert window is after the replaced alert.
|
||||
@ -172,7 +180,7 @@ function moveWindowToEnd() {
|
||||
screen.availTop + screen.availHeight - window.outerHeight;
|
||||
|
||||
// Position the window at the end of all alerts.
|
||||
let windows = Services.wm.getEnumerator('alert:alert');
|
||||
let windows = Services.wm.getEnumerator("alert:alert");
|
||||
while (windows.hasMoreElements()) {
|
||||
let alertWindow = windows.getNext();
|
||||
if (alertWindow != window) {
|
||||
@ -195,7 +203,7 @@ function onAlertBeforeUnload() {
|
||||
if (!gIsReplaced) {
|
||||
// Move other alert windows to fill the gap left by closing alert.
|
||||
let heightDelta = window.outerHeight + WINDOW_MARGIN;
|
||||
let windows = Services.wm.getEnumerator('alert:alert');
|
||||
let windows = Services.wm.getEnumerator("alert:alert");
|
||||
while (windows.hasMoreElements()) {
|
||||
let alertWindow = windows.getNext();
|
||||
if (alertWindow != window) {
|
||||
@ -231,6 +239,14 @@ function onAlertClick() {
|
||||
}
|
||||
}
|
||||
|
||||
function doNotDisturb() {
|
||||
const alertService = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService)
|
||||
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
|
||||
alertService.manualDoNotDisturb = true;
|
||||
onAlertClose();
|
||||
}
|
||||
|
||||
function disableForOrigin() {
|
||||
gAlertListener.observe(null, "alertdisablecallback", gAlertCookie);
|
||||
onAlertClose();
|
||||
|
@ -46,6 +46,9 @@
|
||||
<button type="menu" id="alertSettings" tooltiptext="&settings.label;"
|
||||
onclick="event.stopPropagation();">
|
||||
<menupopup position="after_end">
|
||||
<menuitem id="doNotDisturbMenuItem"
|
||||
oncommand="doNotDisturb();"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="disableForOriginMenuItem"
|
||||
oncommand="disableForOrigin();"/>
|
||||
</menupopup>
|
||||
|
@ -17,3 +17,7 @@ webActions.disableForOrigin.label = Disable notifications from %S
|
||||
# and port.
|
||||
source.label=via %1$S
|
||||
webActions.settings.label = Notification settings
|
||||
|
||||
# LOCALIZATION NOTE(doNotDisturb.label): %S is replaced with the
|
||||
# brandShortName of the application.
|
||||
doNotDisturb.label = Do not disturb me until I restart %S
|
||||
|
Loading…
Reference in New Issue
Block a user