зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c a=merge CLOSED TREE
--HG-- extra : commitid : 8cnDWzxc5CW
This commit is contained in:
Коммит
5c5db39163
|
@ -66,23 +66,36 @@ AlertsService.prototype = {
|
|||
},
|
||||
|
||||
// nsIAlertsService
|
||||
showAlert: function(aAlert, aAlertListener) {
|
||||
if (!aAlert) {
|
||||
return;
|
||||
}
|
||||
cpmm.sendAsyncMessage(kMessageAlertNotificationSend, {
|
||||
imageURL: aAlert.imageURL,
|
||||
title: aAlert.title,
|
||||
text: aAlert.text,
|
||||
clickable: aAlert.textClickable,
|
||||
cookie: aAlert.cookie,
|
||||
listener: aAlertListener,
|
||||
id: aAlert.name,
|
||||
dir: aAlert.dir,
|
||||
lang: aAlert.lang,
|
||||
dataStr: aAlert.data,
|
||||
inPrivateBrowsing: aAlert.inPrivateBrowsing
|
||||
});
|
||||
},
|
||||
|
||||
showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable,
|
||||
aCookie, aAlertListener, aName, aBidi,
|
||||
aLang, aDataStr, aPrincipal,
|
||||
aInPrivateBrowsing) {
|
||||
cpmm.sendAsyncMessage(kMessageAlertNotificationSend, {
|
||||
imageURL: aImageUrl,
|
||||
title: aTitle,
|
||||
text: aText,
|
||||
clickable: aTextClickable,
|
||||
cookie: aCookie,
|
||||
listener: aAlertListener,
|
||||
id: aName,
|
||||
dir: aBidi,
|
||||
lang: aLang,
|
||||
dataStr: aDataStr,
|
||||
inPrivateBrowsing: aInPrivateBrowsing
|
||||
});
|
||||
let alert = Cc["@mozilla.org/alert-notification;1"].
|
||||
createInstance(Ci.nsIAlertNotification);
|
||||
|
||||
alert.init(aName, aImageUrl, aTitle, aText, aTextClickable, aCookie,
|
||||
aBidi, aLang, aDataStr, aPrincipal, aInPrivateBrowsing);
|
||||
|
||||
this.showAlert(alert, aAlertListener);
|
||||
},
|
||||
|
||||
closeAlert: function(aName) {
|
||||
|
|
|
@ -739,8 +739,6 @@ HistoryMenu.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
let enabled = PlacesUIUtils.shouldEnableTabsFromOtherComputersMenuitem();
|
||||
menuitem.setAttribute("disabled", !enabled);
|
||||
menuitem.setAttribute("hidden", false);
|
||||
},
|
||||
|
||||
|
|
|
@ -803,6 +803,15 @@ BrowserGlue.prototype = {
|
|||
this._sanitizer.onStartup();
|
||||
// check if we're in safe mode
|
||||
if (Services.appinfo.inSafeMode) {
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1231112#c7 . We need to
|
||||
// register the observer early if we have to migrate tab groups
|
||||
let currentUIVersion = 0;
|
||||
try {
|
||||
currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
|
||||
} catch(ex) {}
|
||||
if (currentUIVersion < 35) {
|
||||
this._maybeMigrateTabGroups();
|
||||
}
|
||||
Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul",
|
||||
"_blank", "chrome,centerscreen,modal,resizable=no", null);
|
||||
}
|
||||
|
@ -2241,7 +2250,8 @@ BrowserGlue.prototype = {
|
|||
this._notifyNotificationsUpgrade().catch(Cu.reportError);
|
||||
}
|
||||
|
||||
if (currentUIVersion < 35) {
|
||||
// Only do this outside of safe mode, because in safe mode we do this earlier.
|
||||
if (currentUIVersion < 35 && !Services.appinfo.inSafeMode) {
|
||||
this._maybeMigrateTabGroups();
|
||||
}
|
||||
|
||||
|
|
|
@ -556,7 +556,8 @@ var WindowListener = {
|
|||
buttonNode.accessKey = paused ? this._getString("infobar_button_resume_accesskey") :
|
||||
this._getString("infobar_button_pause_accesskey");
|
||||
return true;
|
||||
}
|
||||
},
|
||||
type: "pause"
|
||||
},
|
||||
{
|
||||
label: this._getString("infobar_button_stop_label"),
|
||||
|
@ -565,7 +566,8 @@ var WindowListener = {
|
|||
callback: () => {
|
||||
this._hideBrowserSharingInfoBar();
|
||||
LoopUI.MozLoopService.hangupAllChatWindows();
|
||||
}
|
||||
},
|
||||
type: "stop"
|
||||
}]
|
||||
);
|
||||
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Hide Pause/Resume button until the functionality is complete */
|
||||
notification[value="loop-sharing-notification"] .notification-button[type="pause"] {
|
||||
display:none;
|
||||
}
|
||||
|
||||
notification[value="loop-sharing-notification"].paused .notification-button {
|
||||
background: #57bd35;
|
||||
}
|
||||
|
|
|
@ -192,6 +192,11 @@
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
/* Hide Pause/Resume button until the functionality is complete */
|
||||
notification[value="loop-sharing-notification"] .notification-button[type="pause"] {
|
||||
display:none;
|
||||
}
|
||||
|
||||
notification[value="loop-sharing-notification"].paused .notification-button {
|
||||
background-color: #57bd35;
|
||||
color: #fff;
|
||||
|
|
|
@ -1440,6 +1440,10 @@ richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon
|
|||
background-color: Window;
|
||||
}
|
||||
|
||||
#sidebar-header > .close-icon:not(:hover):-moz-lwtheme-brighttext {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
|
||||
}
|
||||
|
||||
.browserContainer > findbar {
|
||||
background-color: -moz-dialog;
|
||||
color: -moz-DialogText;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
%include ../shared/devedition.inc.css
|
||||
|
||||
:root[devtoolstheme="dark"] .findbar-closebutton:not(:hover),
|
||||
:root[devtoolstheme="dark"] #sidebar-header > .close-icon:not(:hover),
|
||||
.tab-close-button[visuallyselected]:not(:hover) {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
|
||||
}
|
||||
|
@ -76,8 +78,9 @@
|
|||
border-top-width: 0 !important;
|
||||
}
|
||||
|
||||
/* Prevent devedition foreground color from seeping into the sidebar-box (since
|
||||
* its background colors aren't affected by the devedition theme) */
|
||||
#sidebar-box {
|
||||
color: initial;
|
||||
/* Fix the bad-looking text-shadow in the sidebar header: */
|
||||
.sidebar-header,
|
||||
#sidebar-header {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,8 +52,8 @@
|
|||
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
.sidebar-header,
|
||||
#sidebar-header {
|
||||
.sidebar-header:not(:-moz-lwtheme),
|
||||
#sidebar-header:not(:-moz-lwtheme) {
|
||||
background-color: #EEF3FA;
|
||||
}
|
||||
|
||||
|
|
|
@ -1872,6 +1872,18 @@ richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon
|
|||
border: none;
|
||||
}
|
||||
|
||||
@media not all and (min-resolution: 1.1dppx) {
|
||||
#sidebar-header > .close-icon:-moz-lwtheme-brighttext {
|
||||
list-style-image: url("chrome://global/skin/icons/close-inverted.png");
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
#sidebar-header > .close-icon:-moz-lwtheme-brighttext {
|
||||
list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-xp),
|
||||
(-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
}
|
||||
|
||||
:root[devtoolstheme="dark"] .findbar-closebutton,
|
||||
:root[devtoolstheme="dark"] #sidebar-header > .close-icon,
|
||||
/* Tab styling - make sure to use an inverted icon for the selected tab
|
||||
(brighttext only covers the unselected tabs) */
|
||||
.tab-close-button[visuallyselected=true] {
|
||||
|
@ -115,6 +116,7 @@
|
|||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
:root[devtoolstheme="dark"] .findbar-closebutton,
|
||||
:root[devtoolstheme="dark"] #sidebar-header > .close-icon,
|
||||
.tab-close-button[visuallyselected=true] {
|
||||
list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png");
|
||||
}
|
||||
|
@ -254,6 +256,14 @@
|
|||
border-right: none !important;
|
||||
}
|
||||
|
||||
/* The sidebar header has no background now that the background of the #browser-panel
|
||||
* has no image and is transparent. Fix: */
|
||||
.sidebar-header:-moz-lwtheme,
|
||||
#sidebar-header {
|
||||
background-color: var(--chrome-background-color);
|
||||
color: var(--chrome-color);
|
||||
}
|
||||
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7),
|
||||
(-moz-os-version: windows-win8) {
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
// Helper to listen to a key on all windows
|
||||
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
|
||||
let keyListener = function (event) {
|
||||
if (event.ctrlKey == !!ctrlKey &&
|
||||
event.altKey == !!altKey &&
|
||||
event.keyCode === keyCode) {
|
||||
callback(event);
|
||||
|
||||
// Call preventDefault to avoid duplicated events when
|
||||
// doing the key stroke within a tab.
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
let observer = function (window, topic, data) {
|
||||
// Listen on keyup to call keyListener only once per stroke
|
||||
if (topic === "domwindowopened") {
|
||||
window.addEventListener("keyup", keyListener);
|
||||
} else {
|
||||
window.removeEventListener("keyup", keyListener);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
start: function () {
|
||||
// Automatically process already opened windows
|
||||
let e = Services.ww.getWindowEnumerator();
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
observer(window, "domwindowopened", null);
|
||||
}
|
||||
// And listen for new ones to come
|
||||
Services.ww.registerNotification(observer);
|
||||
},
|
||||
|
||||
stop: function () {
|
||||
Services.ww.unregisterNotification(observer);
|
||||
let e = Services.ww.getWindowEnumerator();
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
observer(window, "domwindowclosed", null);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
let getTopLevelWindow = function (window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
};
|
||||
|
||||
function reload(event) {
|
||||
// We automatically reload the toolbox if we are on a browser tab
|
||||
// with a toolbox already opened
|
||||
let top = getTopLevelWindow(event.view)
|
||||
let isBrowser = top.location.href.includes("/browser.xul") && top.gDevToolsBrowser;
|
||||
let reloadToolbox = false;
|
||||
if (isBrowser && top.gDevToolsBrowser.hasToolboxOpened) {
|
||||
reloadToolbox = top.gDevToolsBrowser.hasToolboxOpened(top);
|
||||
}
|
||||
dump("Reload DevTools. (reload-toolbox:"+reloadToolbox+")\n");
|
||||
|
||||
// Invalidate xul cache in order to see changes made to chrome:// files
|
||||
Services.obs.notifyObservers(null, "startupcache-invalidate", null);
|
||||
|
||||
// Ask the loader to update itself and reopen the toolbox if needed
|
||||
const {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
devtools.reload(reloadToolbox);
|
||||
}
|
||||
|
||||
let listener;
|
||||
function startup() {
|
||||
dump("DevTools addon started.\n");
|
||||
listener = new MultiWindowKeyListener({
|
||||
keyCode: Ci.nsIDOMKeyEvent.DOM_VK_R, ctrlKey: true, altKey: true,
|
||||
callback: reload
|
||||
});
|
||||
listener.start();
|
||||
}
|
||||
function shutdown() {
|
||||
listener.stop();
|
||||
listener = null;
|
||||
}
|
||||
function install() {}
|
||||
function uninstall() {}
|
|
@ -0,0 +1,6 @@
|
|||
content devtools client/
|
||||
skin devtools classic/1.0 client/themes/
|
||||
resource devtools .
|
||||
|
||||
content webide client/webide/content/
|
||||
skin webide classic/1.0 client/webide/themes/
|
|
@ -18,7 +18,7 @@ const CALL_STACK_PAGE_SIZE = 25; // frames
|
|||
const EVENTS = {
|
||||
// When the debugger's source editor instance finishes loading or unloading.
|
||||
EDITOR_LOADED: "Debugger:EditorLoaded",
|
||||
EDITOR_UNLOADED: "Debugger:EditorUnoaded",
|
||||
EDITOR_UNLOADED: "Debugger:EditorUnloaded",
|
||||
|
||||
// When new sources are received from the debugger server.
|
||||
NEW_SOURCE: "Debugger:NewSource",
|
||||
|
|
|
@ -1161,6 +1161,16 @@ var gDevToolsBrowser = {
|
|||
};
|
||||
},
|
||||
|
||||
hasToolboxOpened: function(win) {
|
||||
let tab = win.gBrowser.selectedTab;
|
||||
for (let [target, toolbox] of gDevTools._toolboxes) {
|
||||
if (target.tab == tab) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the "Toggle Tools" checkbox in the developer tools menu. This is
|
||||
* called when a toolbox is created or destroyed.
|
||||
|
@ -1168,13 +1178,7 @@ var gDevToolsBrowser = {
|
|||
_updateMenuCheckbox: function DT_updateMenuCheckbox() {
|
||||
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
|
||||
|
||||
let hasToolbox = false;
|
||||
if (TargetFactory.isKnownTab(win.gBrowser.selectedTab)) {
|
||||
let target = TargetFactory.forTab(win.gBrowser.selectedTab);
|
||||
if (gDevTools._toolboxes.has(target)) {
|
||||
hasToolbox = true;
|
||||
}
|
||||
}
|
||||
let hasToolbox = gDevToolsBrowser.hasToolboxOpened(win);
|
||||
|
||||
let broadcaster = win.document.getElementById("devtoolsMenuBroadcaster_DevToolbox");
|
||||
if (hasToolbox) {
|
||||
|
|
|
@ -51,9 +51,8 @@ var TreeView = React.createClass({
|
|||
}
|
||||
|
||||
return (
|
||||
DOM.div({className: "domTable", cellPadding: 0, cellSpacing: 0,
|
||||
onClick: this.onClick},
|
||||
children
|
||||
DOM.div({className: "domTable", cellPadding: 0, cellSpacing: 0},
|
||||
children
|
||||
)
|
||||
);
|
||||
},
|
||||
|
@ -151,8 +150,9 @@ var TreeNode = React.createFactory(React.createClass({
|
|||
}
|
||||
|
||||
return (
|
||||
DOM.div({className: classNames.join(" "), onClick: this.onClick},
|
||||
DOM.span({className: "memberLabelCell"},
|
||||
DOM.div({className: classNames.join(" ")},
|
||||
DOM.span({className: "memberLabelCell", onClick: this.onClick},
|
||||
DOM.span({className: "memberIcon"}),
|
||||
DOM.span({className: "memberLabel " + member.type + "Label"},
|
||||
member.name)
|
||||
),
|
||||
|
|
|
@ -22,7 +22,6 @@ const CONTRACT_ID = "@mozilla.org/devtools/jsonview-sniffer;1";
|
|||
const CLASS_ID = "{4148c488-dca1-49fc-a621-2a0097a62422}";
|
||||
const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
|
||||
const JSON_VIEW_TYPE = "JSON View";
|
||||
const JSON_EXTENSION = "json";
|
||||
const CONTENT_SNIFFER_CATEGORY = "net-content-sniffers";
|
||||
|
||||
/**
|
||||
|
@ -64,10 +63,6 @@ var Sniffer = Class({
|
|||
if (aRequest.contentType == JSON_TYPE) {
|
||||
return JSON_VIEW_MIME_TYPE;
|
||||
}
|
||||
|
||||
if (NetworkHelper.getFileExtension(aRequest.name) == JSON_EXTENSION) {
|
||||
return JSON_VIEW_MIME_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.6 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 2.0 KiB |
|
@ -20,7 +20,6 @@
|
|||
|
||||
.memberLabelCell {
|
||||
padding: 2px 0 2px 0px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.memberValueCell {
|
||||
|
@ -31,7 +30,6 @@
|
|||
.memberLabel {
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
padding-left: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
@ -60,6 +58,11 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
.memberRow.hasChildren > .memberLabelCell > .memberIcon:hover,
|
||||
.memberRow.cropped > .memberLabelCell > .memberIcon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.memberRow.hasChildren > .memberLabelCell > .memberLabel:hover,
|
||||
.memberRow.cropped > .memberLabelCell > .memberLabel:hover {
|
||||
cursor: pointer;
|
||||
|
@ -71,6 +74,10 @@
|
|||
background-color: #EFEFEF;
|
||||
}
|
||||
|
||||
.memberRow {
|
||||
padding: 3px 0 3px 0;
|
||||
}
|
||||
|
||||
.panelNode-dom .memberRow td,
|
||||
.panelNode-domSide .memberRow td {
|
||||
border-bottom: 1px solid #EFEFEF;
|
||||
|
@ -116,19 +123,38 @@
|
|||
/******************************************************************************/
|
||||
/* Twisties */
|
||||
|
||||
.memberRow.hasChildren > .memberLabelCell > .memberLabel,
|
||||
.memberRow.cropped > .memberLabelCell > .memberLabel {
|
||||
background-image: url(twisty-closed.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px calc(0.5em - 3px);
|
||||
min-height: 12px;
|
||||
.memberRow > .memberLabelCell > .memberIcon {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
display: inline-block;
|
||||
line-height: 15px;
|
||||
vertical-align: bottom;
|
||||
padding-right: 2px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,
|
||||
.memberRow.cropped.opened > .memberLabelCell > .memberLabel {
|
||||
background-image: url(twisty-open.svg);
|
||||
.memberRow.hasChildren > .memberLabelCell > .memberIcon,
|
||||
.memberRow.cropped > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./twisty-closed.svg");
|
||||
background-repeat: no-repeat;
|
||||
min-height: 12px;
|
||||
}
|
||||
|
||||
.memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
|
||||
.memberRow.cropped.opened > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./twisty-open.svg");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.memberRow.hasChildren > .memberLabelCell > .memberIcon,
|
||||
.memberRow.cropped > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./controls@2x.png");
|
||||
}
|
||||
|
||||
.memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
|
||||
.memberRow.cropped.opened > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./controls@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -140,7 +166,6 @@
|
|||
|
||||
.memberLabelCell,
|
||||
.memberValueCell {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.memberLabelCell {
|
||||
|
@ -150,3 +175,42 @@
|
|||
.memberRow:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Themes */
|
||||
|
||||
.theme-light .memberRow.hasChildren > .memberLabelCell > .memberIcon,
|
||||
.theme-light .memberRow.cropped > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./controls.png");
|
||||
background-size: 56px 28px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 -14px;
|
||||
}
|
||||
|
||||
.theme-light .memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
|
||||
.theme-light .memberRow.cropped.opened > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./controls.png");
|
||||
background-size: 56px 28px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: -14px -14px;
|
||||
}
|
||||
|
||||
.theme-dark .memberRow.hasChildren > .memberLabelCell > .memberIcon,
|
||||
.theme-dark .memberRow.cropped > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./controls.png");
|
||||
background-size: 56px 28px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: -28px -14px;
|
||||
}
|
||||
|
||||
.theme-dark .memberRow.hasChildren.opened > .memberLabelCell > .memberIcon,
|
||||
.theme-dark .memberRow.cropped.opened > .memberLabelCell > .memberIcon {
|
||||
background-image: url("./controls.png");
|
||||
background-size: 56px 28px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: -42px -14px;
|
||||
}
|
||||
|
||||
.theme-dark .memberRow:hover {
|
||||
background-color: var(--theme-selection-background-semitransparent);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
|
||||
DevToolsModules(
|
||||
'controls.png',
|
||||
'controls@2x.png',
|
||||
'dom-tree.css',
|
||||
'general.css',
|
||||
'headers-panel.css',
|
||||
|
|
|
@ -175,7 +175,7 @@
|
|||
|
||||
.theme-dark .domLabel,
|
||||
.theme-light .domLabel {
|
||||
color: var(--theme-highlight-bluegrey);
|
||||
color: var(--theme-highlight-blue);
|
||||
}
|
||||
|
||||
.theme-dark .objectBox-array .length,
|
||||
|
@ -207,7 +207,7 @@
|
|||
.theme-light .objectBox-object {
|
||||
font-family: Lucida Grande, sans-serif;
|
||||
font-weight: normal;
|
||||
color: var(--theme-highlight-bluegrey);
|
||||
color: var(--theme-highlight-blue);
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
|
@ -215,5 +215,5 @@
|
|||
.theme-light .caption {
|
||||
font-family: Lucida Grande, Tahoma, sans-serif;
|
||||
font-weight: normal;
|
||||
color: var(--theme-highlight-bluegrey);
|
||||
color: var(--theme-highlight-blue);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ Services.prefs.setBoolPref("devtools.memory.enabled", true);
|
|||
var { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
var { require } = Cu.import("resource://gre/modules/devtools/shared/Loader.jsm", {});
|
||||
var { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
var { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
var { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
var { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
|
||||
var { DebuggerServer } = require("devtools/server/main");
|
||||
var { DebuggerClient } = require("devtools/shared/client/main");
|
||||
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
var { TargetFactory } = require("devtools/client/framework/target");
|
||||
var { Toolbox } = require("devtools/client/framework/toolbox");
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ body {
|
|||
.devtools-toolbar,
|
||||
.devtools-sidebar-tabs tabs,
|
||||
.devtools-sidebar-alltabs,
|
||||
.CodeMirror-dialog { /* General toolbar styling */
|
||||
.cm-s-mozilla .CodeMirror-dialog { /* General toolbar styling */
|
||||
color: var(--theme-body-color-alt);
|
||||
background-color: var(--theme-toolbar-background);
|
||||
border-color: hsla(210,8%,5%,.6);
|
||||
|
|
|
@ -171,7 +171,7 @@ body {
|
|||
.devtools-toolbar,
|
||||
.devtools-sidebar-tabs tabs,
|
||||
.devtools-sidebar-alltabs,
|
||||
.CodeMirror-dialog { /* General toolbar styling */
|
||||
.cm-s-mozilla .CodeMirror-dialog { /* General toolbar styling */
|
||||
color: var(--theme-body-color-alt);
|
||||
background-color: var(--theme-toolbar-background);
|
||||
border-color: var(--theme-splitter-color);
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
# 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/.
|
||||
-->
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest"
|
||||
em:id="devtools@mozilla.org"
|
||||
em:name="Developer Tools (local version)"
|
||||
em:description="Add-on to load DevTools from local sources and easily reload them with Ctrl+Alt+r shortcut"
|
||||
em:version="44.0a1"
|
||||
em:type="2"
|
||||
em:creator="Mozilla">
|
||||
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>44.0a1</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
|
@ -803,36 +803,6 @@ var NetworkHelper = {
|
|||
let uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
|
||||
aStore.set(aUrl, uri);
|
||||
return uri;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns extension for file URLs (e.g. 'json').
|
||||
* Not everyURL has an extension and this method works as follows:
|
||||
* 1) Remove query string
|
||||
* 2) Get part after the last slash (a file name)
|
||||
* 3) Look for the last dot (an extension)
|
||||
*/
|
||||
getFileExtension: function(aUrl) {
|
||||
if (!aUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove query string from the URL if any.
|
||||
let queryString = aUrl.indexOf("?");
|
||||
if (queryString != -1) {
|
||||
aUrl = aUrl.substr(0, queryString);
|
||||
}
|
||||
|
||||
// Look for the part after last slash
|
||||
var lastSlash = aUrl.lastIndexOf("/");
|
||||
var fileName = aUrl.substr(lastSlash + 1);
|
||||
if (!fileName) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now get the file extension.
|
||||
var lastDot = fileName.lastIndexOf(".");
|
||||
return fileName.substr(lastDot + 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4415,25 +4415,26 @@ ContentParent::HasNotificationPermission(const IPC::Principal& aPrincipal)
|
|||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
|
||||
const nsString& aText, const bool& aTextClickable,
|
||||
const nsString& aCookie, const nsString& aName,
|
||||
const nsString& aBidi, const nsString& aLang,
|
||||
const nsString& aData,
|
||||
const IPC::Principal& aPrincipal,
|
||||
const bool& aInPrivateBrowsing)
|
||||
ContentParent::RecvShowAlert(const AlertNotificationType& aAlert)
|
||||
{
|
||||
if (!HasNotificationPermission(aPrincipal)) {
|
||||
nsCOMPtr<nsIAlertNotification> alert(dont_AddRef(aAlert));
|
||||
if (NS_WARN_IF(!alert)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = alert->GetPrincipal(getter_AddRefs(principal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) ||
|
||||
!HasNotificationPermission(IPC::Principal(principal))) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID));
|
||||
if (sysAlerts) {
|
||||
sysAlerts->ShowAlertNotification(aImageUrl, aTitle, aText, aTextClickable,
|
||||
aCookie, this, aName, aBidi, aLang,
|
||||
aData, aPrincipal, aInPrivateBrowsing);
|
||||
}
|
||||
return true;
|
||||
sysAlerts->ShowAlert(alert, this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -901,14 +901,7 @@ private:
|
|||
|
||||
bool HasNotificationPermission(const IPC::Principal& aPrincipal);
|
||||
|
||||
virtual bool
|
||||
RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
|
||||
const nsString& aText, const bool& aTextClickable,
|
||||
const nsString& aCookie, const nsString& aName,
|
||||
const nsString& aBidi, const nsString& aLang,
|
||||
const nsString& aData,
|
||||
const IPC::Principal& aPrincipal,
|
||||
const bool& aInPrivateBrowsing) override;
|
||||
virtual bool RecvShowAlert(const AlertNotificationType& aAlert) override;
|
||||
|
||||
virtual bool RecvCloseAlert(const nsString& aName,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
|
|
|
@ -74,6 +74,7 @@ include ProfilerTypes;
|
|||
include "mozilla/dom/PContentBridgeParent.h";
|
||||
|
||||
using GeoPosition from "nsGeoPositionIPCSerialiser.h";
|
||||
using AlertNotificationType from "mozilla/AlertNotificationIPCSerializer.h";
|
||||
|
||||
using struct ChromePackage from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
using struct SubstitutionMapping from "mozilla/chrome/RegistryMessageUtils.h";
|
||||
|
@ -881,17 +882,7 @@ parent:
|
|||
CpowEntry[] aCpows, Principal aPrincipal)
|
||||
returns (StructuredCloneData[] retval);
|
||||
|
||||
ShowAlertNotification(nsString imageUrl,
|
||||
nsString title,
|
||||
nsString text,
|
||||
bool textClickable,
|
||||
nsString cookie,
|
||||
nsString name,
|
||||
nsString bidi,
|
||||
nsString lang,
|
||||
nsString data,
|
||||
Principal principal,
|
||||
bool inPrivateBrowsing);
|
||||
ShowAlert(AlertNotificationType alert);
|
||||
|
||||
CloseAlert(nsString name, Principal principal);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/dom/DesktopNotificationBinding.h"
|
||||
#include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/dom/PBrowserChild.h"
|
||||
|
@ -114,16 +115,20 @@ DesktopNotification::PostDesktopNotification()
|
|||
nsIPrincipal* principal = doc->NodePrincipal();
|
||||
nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
|
||||
bool inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
|
||||
return alerts->ShowAlertNotification(mIconURL, mTitle, mDescription,
|
||||
true,
|
||||
uniqueName,
|
||||
mObserver,
|
||||
uniqueName,
|
||||
NS_LITERAL_STRING("auto"),
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
principal,
|
||||
inPrivateBrowsing);
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||
nsresult rv = alert->Init(uniqueName, mIconURL, mTitle,
|
||||
mDescription,
|
||||
true,
|
||||
uniqueName,
|
||||
NS_LITERAL_STRING("auto"),
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
principal,
|
||||
inPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return alerts->ShowAlert(alert, mObserver);
|
||||
}
|
||||
|
||||
DesktopNotification::DesktopNotification(const nsAString & title,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
|
||||
|
||||
#include "nsAlertsUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCRTGlue.h"
|
||||
|
@ -1787,11 +1788,19 @@ Notification::ShowInternal()
|
|||
|
||||
nsAutoString alertName;
|
||||
GetAlertName(alertName);
|
||||
alertService->ShowAlertNotification(iconUrl, mTitle, mBody, true,
|
||||
uniqueCookie, alertObserver, alertName,
|
||||
DirectionToString(mDir), mLang,
|
||||
mDataAsBase64, GetPrincipal(),
|
||||
inPrivateBrowsing);
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE_VOID(alert);
|
||||
rv = alert->Init(alertName, iconUrl, mTitle, mBody,
|
||||
true,
|
||||
uniqueCookie,
|
||||
DirectionToString(mDir),
|
||||
mLang,
|
||||
mDataAsBase64,
|
||||
GetPrincipal(),
|
||||
inPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
alertService->ShowAlert(alert, alertObserver);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
|
|
@ -98,15 +98,15 @@ function testNonDefaultContentToolbars(toolbars) {
|
|||
function testNonDefaultChromeToolbars(toolbars) {
|
||||
// None of the toolbars should be visible if hidden with chrome privileges
|
||||
ok(!toolbars.locationbar,
|
||||
"locationbar should be visible on default window.open()");
|
||||
"locationbar should not be visible with location=no");
|
||||
ok(!toolbars.menubar,
|
||||
"menubar be visible on default window.open()");
|
||||
"menubar should not be visible with menubar=no");
|
||||
ok(!toolbars.personalbar,
|
||||
"personalbar should be visible on default window.open()");
|
||||
"personalbar should not be visible with personalbar=no");
|
||||
ok(!toolbars.statusbar,
|
||||
"statusbar should be visible on default window.open()");
|
||||
"statusbar should not be visible with status=no");
|
||||
ok(!toolbars.toolbar,
|
||||
"toolbar should be visible on default window.open()");
|
||||
"toolbar should not be visible with toolbar=no");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,7 +147,42 @@ add_task(function*() {
|
|||
let popupToolbars = yield getToolbarsFromBrowserContent(popupBrowser);
|
||||
testNonDefaultContentToolbars(popupToolbars);
|
||||
|
||||
// Cleanup
|
||||
// Ensure that chrome toolbars agree with content
|
||||
let chromeToolbars = getToolbarsFromWindowChrome(popupWindow);
|
||||
testNonDefaultContentToolbars(chromeToolbars);
|
||||
|
||||
// Close the new window
|
||||
yield BrowserTestUtils.closeWindow(popupWindow);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensure that toolbars of a window opened to about:blank in the content context
|
||||
* have the correct visibility.
|
||||
*
|
||||
* A window opened with "location=no, personalbar=no, toolbar=no, scrollbars=no,
|
||||
* menubar=no, status=no", should only have location visible.
|
||||
*/
|
||||
add_task(function*() {
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: CONTENT_PAGE,
|
||||
}, function*(browser) {
|
||||
// Open a blank window with toolbars hidden
|
||||
let winPromise = BrowserTestUtils.waitForNewWindow();
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter("#winOpenNoURLNonDefault", {}, browser);
|
||||
let popupWindow = yield winPromise;
|
||||
|
||||
// No need to wait for this window to load, since it's loading about:blank
|
||||
let popupBrowser = popupWindow.gBrowser.selectedBrowser;
|
||||
let popupToolbars = yield getToolbarsFromBrowserContent(popupBrowser);
|
||||
testNonDefaultContentToolbars(popupToolbars);
|
||||
|
||||
// Ensure that chrome toolbars agree with content
|
||||
let chromeToolbars = getToolbarsFromWindowChrome(popupWindow);
|
||||
testNonDefaultContentToolbars(chromeToolbars);
|
||||
|
||||
// Close the new window
|
||||
yield BrowserTestUtils.closeWindow(popupWindow);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<p><a id="winOpenDefault" href="#" onclick="return openWindow();">Open a new window via window.open with default features.</a></p>
|
||||
<p><a id="winOpenNonDefault" href="#" onclick="return openWindow('resizable=no, location=no, personalbar=no, toolbar=no, scrollbars=no, menubar=no, status=no, directories=no, height=100, width=500');">Open a new window via window.open with non-default features.</a></p>
|
||||
<p><a id="winOpenDialog" href="#" onclick="return openWindow('dialog=yes');">Open a new window via window.open with dialog=1.</a></p>
|
||||
<p><a id="winOpenNoURLNonDefault" href="#" onclick="return openBlankWindow('location=no, toolbar=no, height=100, width=100');">Open a blank new window via window.open with non-default features.</a></p>
|
||||
<p><a id="targetBlank" href="about:robots" target="_blank">Open a new window via target="_blank".</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -16,4 +17,9 @@ function openWindow(aFeatures="") {
|
|||
window.open("about:robots", "_blank", aFeatures);
|
||||
return false;
|
||||
}
|
||||
|
||||
function openBlankWindow(aFeatures="") {
|
||||
window.open("", "_blank", aFeatures);
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -29,26 +29,34 @@ var MockServices = (function () {
|
|||
});
|
||||
|
||||
var mockAlertsService = {
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name) {
|
||||
showAlert: function(alert, alertListener) {
|
||||
var listener = SpecialPowers.wrap(alertListener);
|
||||
activeAlertNotifications[name] = {
|
||||
activeAlertNotifications[alert.name] = {
|
||||
listener: listener,
|
||||
cookie: cookie,
|
||||
title: title
|
||||
cookie: alert.cookie,
|
||||
title: alert.title
|
||||
};
|
||||
|
||||
// fake async alert show event
|
||||
if (listener) {
|
||||
setTimeout(function () {
|
||||
listener.observe(null, "alertshow", cookie);
|
||||
listener.observe(null, "alertshow", alert.cookie);
|
||||
}, 100);
|
||||
setTimeout(function () {
|
||||
listener.observe(null, "alertclickcallback", cookie);
|
||||
listener.observe(null, "alertclickcallback", alert.cookie);
|
||||
}, 100);
|
||||
}
|
||||
},
|
||||
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name) {
|
||||
this.showAlert({
|
||||
name: name,
|
||||
cookie: cookie,
|
||||
title: title
|
||||
}, alertListener);
|
||||
},
|
||||
|
||||
showAppNotification: function(aImageUrl, aTitle, aText, aAlertListener, aDetails) {
|
||||
var listener = aAlertListener || (activeAlertNotifications[aDetails.id] ? activeAlertNotifications[aDetails.id].listener : undefined);
|
||||
activeAppNotifications[aDetails.id] = {
|
||||
|
|
|
@ -8,17 +8,23 @@ var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager.
|
|||
QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar);
|
||||
|
||||
var mockAlertsService = {
|
||||
showAlert: function(alert, alertListener) {
|
||||
// probably should do this async....
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertshow", alert.cookie);
|
||||
|
||||
if (SpecialPowers.getBoolPref("notification.prompt.testing.click_on_notification") == true) {
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", alert.cookie);
|
||||
}
|
||||
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertfinished", alert.cookie);
|
||||
},
|
||||
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name, bidi,
|
||||
lang, data) {
|
||||
// probably should do this async....
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertshow", cookie);
|
||||
|
||||
if (SpecialPowers.getBoolPref("notification.prompt.testing.click_on_notification") == true) {
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertclickcallback", cookie);
|
||||
}
|
||||
|
||||
SpecialPowers.wrap(alertListener).observe(null, "alertfinished", cookie);
|
||||
return this.showAlert({
|
||||
cookie: cookie
|
||||
}, alertListener);
|
||||
},
|
||||
|
||||
showAppNotification: function(imageUrl, title, text, alertListener, details) {
|
||||
|
|
|
@ -23,15 +23,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=782211
|
|||
const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1";
|
||||
|
||||
var mockAlertsService = {
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name, dir,
|
||||
lang, data) {
|
||||
notificationsCreated.push(name);
|
||||
showAlert: function(alert, alertListener) {
|
||||
notificationsCreated.push(alert.name);
|
||||
if (notificationsCreated.length == 3) {
|
||||
checkNotifications();
|
||||
}
|
||||
},
|
||||
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name, dir,
|
||||
lang, data) {
|
||||
this.showAlert({ name: name });
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
|
||||
SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIAlertsService)) {
|
||||
|
|
|
@ -23,13 +23,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=874090
|
|||
const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1";
|
||||
|
||||
var mockAlertsService = {
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name, dir, lang, data) {
|
||||
ok(true, "System principal was granted permission and is able to call showAlertNotification.");
|
||||
showAlert: function(alert, alertListener) {
|
||||
ok(true, "System principal was granted permission and is able to call showAlert.");
|
||||
unregisterMock();
|
||||
SimpleTest.finish();
|
||||
},
|
||||
|
||||
showAlertNotification: function(imageUrl, title, text, textClickable,
|
||||
cookie, alertListener, name, dir, lang, data) {
|
||||
this.showAlert();
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Components.interfaces.nsISupports) ||
|
||||
aIID.equals(Components.interfaces.nsIAlertsService)) {
|
||||
|
|
|
@ -117,6 +117,9 @@ var AlertsService = {
|
|||
"", ALERTS_SERVICE_CONTRACT_ID, null);
|
||||
},
|
||||
|
||||
showAlert: function() {
|
||||
},
|
||||
|
||||
showAlertNotification: function() {
|
||||
},
|
||||
};
|
||||
|
|
|
@ -2170,13 +2170,21 @@ public class BrowserApp extends GeckoApp
|
|||
|
||||
final Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
final String userRequested = tab.getUserRequested();
|
||||
final String userSearchTerm = tab.getUserRequested();
|
||||
|
||||
// Check to see if there's a user-entered search term,
|
||||
// which we save whenever the user performs a search.
|
||||
url = (TextUtils.isEmpty(userRequested) ? tab.getURL() : userRequested);
|
||||
}
|
||||
final String telemetryMsg;
|
||||
if (!TextUtils.isEmpty(userSearchTerm)) {
|
||||
url = userSearchTerm;
|
||||
telemetryMsg = "urlbar-userentered";
|
||||
} else {
|
||||
url = tab.getURL();
|
||||
telemetryMsg = url.isEmpty() ? "urlbar-empty" : "urlbar-url";
|
||||
}
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.ACTIONBAR, telemetryMsg);
|
||||
}
|
||||
enterEditingMode(url);
|
||||
}
|
||||
|
||||
|
@ -2210,7 +2218,12 @@ public class BrowserApp extends GeckoApp
|
|||
|
||||
mBrowserToolbar.startEditing(url, animator);
|
||||
|
||||
showHomePagerWithAnimator(panelId, animator);
|
||||
final boolean isUserSearchTerm = !TextUtils.isEmpty(selectedTab.getUserRequested());
|
||||
if (isUserSearchTerm && AppConstants.NIGHTLY_BUILD) {
|
||||
showBrowserSearchAfterAnimation(animator);
|
||||
} else {
|
||||
showHomePagerWithAnimator(panelId, animator);
|
||||
}
|
||||
|
||||
animator.start();
|
||||
Telemetry.startUISession(TelemetryContract.Session.AWESOMESCREEN);
|
||||
|
@ -2622,6 +2635,24 @@ public class BrowserApp extends GeckoApp
|
|||
refreshToolbarHeight();
|
||||
}
|
||||
|
||||
private void showBrowserSearchAfterAnimation(PropertyAnimator animator) {
|
||||
if (animator == null) {
|
||||
showBrowserSearch();
|
||||
return;
|
||||
}
|
||||
|
||||
animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
|
||||
@Override
|
||||
public void onPropertyAnimationStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyAnimationEnd() {
|
||||
showBrowserSearch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showBrowserSearch() {
|
||||
if (mBrowserSearch.getUserVisibleHint()) {
|
||||
return;
|
||||
|
@ -2672,7 +2703,7 @@ public class BrowserApp extends GeckoApp
|
|||
|
||||
// To prevent overdraw, the HomePager is hidden when BrowserSearch is displayed:
|
||||
// reverse that.
|
||||
mHomePagerContainer.setVisibility(View.VISIBLE);
|
||||
showHomePager(Tabs.getInstance().getSelectedTab().getMostRecentHomePanel());
|
||||
|
||||
mBrowserSearchContainer.setVisibility(View.INVISIBLE);
|
||||
|
||||
|
|
|
@ -87,6 +87,11 @@ public class DownloadAction extends BaseAction {
|
|||
|
||||
temporaryFile = createTemporaryFile(context, content);
|
||||
|
||||
if (!canWrite(temporaryFile, destinationFile)) {
|
||||
throw new RecoverableDownloadContentException(RecoverableDownloadContentException.DISK_IO,
|
||||
"Temporary or destination file not writeable");
|
||||
}
|
||||
|
||||
if (!hasEnoughDiskSpace(content, destinationFile, temporaryFile)) {
|
||||
Log.d(LOGTAG, "Not enough disk space to save content. Skipping download.");
|
||||
continue;
|
||||
|
@ -125,7 +130,7 @@ public class DownloadAction extends BaseAction {
|
|||
temporaryFile.delete();
|
||||
}
|
||||
} catch (RecoverableDownloadContentException e) {
|
||||
Log.w(LOGTAG, "Downloading content failed (Recoverable): " + content , e);
|
||||
Log.w(LOGTAG, "Downloading content failed (Recoverable): " + content, e);
|
||||
|
||||
if (e.shouldBeCountedAsFailure()) {
|
||||
catalog.rememberFailure(content, e.getErrorType());
|
||||
|
@ -336,4 +341,14 @@ public class DownloadAction extends BaseAction {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean canWrite(File... files) {
|
||||
for (File file : files) {
|
||||
if (!file.canWrite()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,6 +168,7 @@ public class TestDownloadAction {
|
|||
doReturn(file).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
|
||||
doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
|
||||
|
||||
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
|
||||
doReturn(false).when(action).verify(eq(file), anyString());
|
||||
doNothing().when(action).download(any(HttpClient.class), anyString(), eq(file));
|
||||
doReturn(true).when(action).verify(eq(file), anyString());
|
||||
|
@ -202,6 +203,7 @@ public class TestDownloadAction {
|
|||
|
||||
DownloadAction action = spy(new DownloadAction(null));
|
||||
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
|
||||
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
|
||||
|
||||
File temporaryFile = mockFileWithSize(1337L);
|
||||
doReturn(temporaryFile).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
|
||||
|
@ -301,6 +303,7 @@ public class TestDownloadAction {
|
|||
File destinationFile = mockNotExistingFile();
|
||||
doReturn(destinationFile).when(action).getDestinationFile(RuntimeEnvironment.application, content);
|
||||
|
||||
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
|
||||
doReturn(true).when(action).verify(eq(temporaryFile), anyString());
|
||||
doNothing().when(action).extract(eq(temporaryFile), eq(destinationFile), anyString());
|
||||
|
||||
|
@ -333,6 +336,7 @@ public class TestDownloadAction {
|
|||
|
||||
DownloadAction action = spy(new DownloadAction(null));
|
||||
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
|
||||
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
|
||||
doNothing().when(action).download(any(HttpClient.class), anyString(), any(File.class));
|
||||
doReturn(false).when(action).verify(any(File.class), anyString());
|
||||
|
||||
|
@ -443,6 +447,7 @@ public class TestDownloadAction {
|
|||
doReturn(mockNotExistingFile()).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
|
||||
doReturn(mockNotExistingFile()).when(action).getDestinationFile(RuntimeEnvironment.application, content);
|
||||
doReturn(true).when(action).hasEnoughDiskSpace(eq(content), any(File.class), any(File.class));
|
||||
doReturn(true).when(action).canWrite(any(File.class), any(File.class));
|
||||
|
||||
HttpClient client = mock(HttpClient.class);
|
||||
doThrow(IOException.class).when(client).execute(any(HttpUriRequest.class));
|
||||
|
@ -499,6 +504,32 @@ public class TestDownloadAction {
|
|||
verify(catalog, times(11)).rememberFailure(eq(content), anyInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario: Temporary or destination file is not writable.
|
||||
*
|
||||
* Verify that:
|
||||
* * No download is performed
|
||||
* * Error is counted as failure
|
||||
*/
|
||||
@Test
|
||||
public void testNoDownIsPerformedIfFilesAreNotWritable() throws Exception{
|
||||
DownloadContent content = createFont();
|
||||
DownloadContentCatalog catalog = mockCatalogWithScheduledDownloads(content);
|
||||
|
||||
DownloadAction action = spy(new DownloadAction(null));
|
||||
doReturn(true).when(action).isConnectedToNetwork(RuntimeEnvironment.application);
|
||||
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
|
||||
doReturn(mockNotExistingFile()).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
|
||||
doReturn(mockNotExistingFile()).when(action).getDestinationFile(RuntimeEnvironment.application, content);
|
||||
doReturn(false).when(action).canWrite(any(File.class), any(File.class));
|
||||
|
||||
action.perform(RuntimeEnvironment.application, catalog);
|
||||
|
||||
verify(action).canWrite(any(File.class), any(File.class));
|
||||
verify(action, never()).download(any(HttpClient.class), anyString(), any(File.class));
|
||||
verify(catalog).rememberFailure(eq(content), anyInt());
|
||||
}
|
||||
|
||||
private DownloadContent createFont() {
|
||||
return createFontWithSize(102400L);
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ public class AppMenuComponent extends BaseComponent {
|
|||
* This method is dependent on not having two views with equivalent contentDescription / text.
|
||||
*/
|
||||
private View findAppMenuItemView(String text) {
|
||||
mSolo.waitForText(text, 1, MAX_WAITTIME_FOR_MENU_UPDATE_IN_MS);
|
||||
mSolo.waitForText(String.format("^%s$", text), 1, MAX_WAITTIME_FOR_MENU_UPDATE_IN_MS);
|
||||
|
||||
final List<View> views = mSolo.getViews();
|
||||
|
||||
|
@ -298,7 +298,8 @@ public class AppMenuComponent extends BaseComponent {
|
|||
|
||||
private boolean isLegacyMoreMenuOpen() {
|
||||
// Check if the first menu option is visible.
|
||||
return mSolo.searchText(mSolo.getString(R.string.share), true);
|
||||
final String shareTitle = mSolo.getString(R.string.share);
|
||||
return mSolo.searchText(String.format("^%s$", shareTitle), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -310,7 +311,7 @@ public class AppMenuComponent extends BaseComponent {
|
|||
*/
|
||||
private boolean isMenuOpen(String menuItemTitle) {
|
||||
final View menuItemView = findAppMenuItemView(menuItemTitle);
|
||||
return isMenuOpen(menuItemView) ? true : mSolo.searchText(menuItemTitle, true);
|
||||
return isMenuOpen(menuItemView) ? true : mSolo.searchText(String.format("^%s$", menuItemTitle), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Pub
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with t
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/AlertNotification.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(AlertNotification, mPrincipal)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AlertNotification)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAlertNotification)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAlertNotification)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(AlertNotification)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(AlertNotification)
|
||||
|
||||
AlertNotification::AlertNotification()
|
||||
: mTextClickable(false)
|
||||
, mPrincipal(nullptr)
|
||||
, mInPrivateBrowsing(false)
|
||||
{}
|
||||
|
||||
AlertNotification::~AlertNotification()
|
||||
{}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::Init(const nsAString& aName, const nsAString& aImageURL,
|
||||
const nsAString& aTitle, const nsAString& aText,
|
||||
bool aTextClickable, const nsAString& aCookie,
|
||||
const nsAString& aDir, const nsAString& aLang,
|
||||
const nsAString& aData, nsIPrincipal* aPrincipal,
|
||||
bool aInPrivateBrowsing)
|
||||
{
|
||||
mName = aName;
|
||||
mImageURL = aImageURL;
|
||||
mTitle = aTitle;
|
||||
mText = aText;
|
||||
mTextClickable = aTextClickable;
|
||||
mCookie = aCookie;
|
||||
mDir = aDir;
|
||||
mLang = aLang;
|
||||
mData = aData;
|
||||
mPrincipal = aPrincipal;
|
||||
mInPrivateBrowsing = aInPrivateBrowsing;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetName(nsAString& aName)
|
||||
{
|
||||
aName = mName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetImageURL(nsAString& aImageURL)
|
||||
{
|
||||
aImageURL = mImageURL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetTitle(nsAString& aTitle)
|
||||
{
|
||||
aTitle = mTitle;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetText(nsAString& aText)
|
||||
{
|
||||
aText = mText;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetTextClickable(bool* aTextClickable)
|
||||
{
|
||||
*aTextClickable = mTextClickable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetCookie(nsAString& aCookie)
|
||||
{
|
||||
aCookie = mCookie;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetDir(nsAString& aDir)
|
||||
{
|
||||
aDir = mDir;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetLang(nsAString& aLang)
|
||||
{
|
||||
aLang = mLang;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetData(nsAString& aData)
|
||||
{
|
||||
aData = mData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetPrincipal(nsIPrincipal** aPrincipal)
|
||||
{
|
||||
NS_IF_ADDREF(*aPrincipal = mPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AlertNotification::GetInPrivateBrowsing(bool* aInPrivateBrowsing)
|
||||
{
|
||||
*aInPrivateBrowsing = mInPrivateBrowsing;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,44 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_AlertNotification_h__
|
||||
#define mozilla_AlertNotification_h__
|
||||
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AlertNotification final : public nsIAlertNotification
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(AlertNotification,
|
||||
nsIAlertNotification)
|
||||
NS_DECL_NSIALERTNOTIFICATION
|
||||
AlertNotification();
|
||||
|
||||
protected:
|
||||
virtual ~AlertNotification();
|
||||
|
||||
private:
|
||||
nsString mName;
|
||||
nsString mImageURL;
|
||||
nsString mTitle;
|
||||
nsString mText;
|
||||
bool mTextClickable;
|
||||
nsString mCookie;
|
||||
nsString mDir;
|
||||
nsString mLang;
|
||||
nsString mData;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
bool mInPrivateBrowsing;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_AlertNotification_h__ */
|
|
@ -0,0 +1,119 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_AlertNotificationIPCSerializer_h__
|
||||
#define mozilla_AlertNotificationIPCSerializer_h__
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
|
||||
typedef nsIAlertNotification* AlertNotificationType;
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<AlertNotificationType>
|
||||
{
|
||||
typedef AlertNotificationType paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
bool isNull = !aParam;
|
||||
if (isNull) {
|
||||
WriteParam(aMsg, isNull);
|
||||
return;
|
||||
}
|
||||
|
||||
nsString name, imageURL, title, text, cookie, dir, lang, data;
|
||||
bool textClickable, inPrivateBrowsing;
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aParam->GetName(name))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetImageURL(imageURL))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetTitle(title))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetText(text))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetTextClickable(&textClickable))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetCookie(cookie))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetDir(dir))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetLang(lang))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetData(data))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetPrincipal(getter_AddRefs(principal)))) ||
|
||||
NS_WARN_IF(NS_FAILED(aParam->GetInPrivateBrowsing(&inPrivateBrowsing)))) {
|
||||
|
||||
// Write a `null` object if any getter returns an error. Otherwise, the
|
||||
// receiver will try to deserialize an incomplete object and crash.
|
||||
WriteParam(aMsg, /* isNull */ true);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteParam(aMsg, isNull);
|
||||
WriteParam(aMsg, name);
|
||||
WriteParam(aMsg, imageURL);
|
||||
WriteParam(aMsg, title);
|
||||
WriteParam(aMsg, text);
|
||||
WriteParam(aMsg, textClickable);
|
||||
WriteParam(aMsg, cookie);
|
||||
WriteParam(aMsg, dir);
|
||||
WriteParam(aMsg, lang);
|
||||
WriteParam(aMsg, data);
|
||||
WriteParam(aMsg, IPC::Principal(principal));
|
||||
WriteParam(aMsg, inPrivateBrowsing);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
bool isNull;
|
||||
NS_ENSURE_TRUE(ReadParam(aMsg, aIter, &isNull), false);
|
||||
if (isNull) {
|
||||
*aResult = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsString name, imageURL, title, text, cookie, dir, lang, data;
|
||||
bool textClickable, inPrivateBrowsing;
|
||||
IPC::Principal principal;
|
||||
|
||||
if (!ReadParam(aMsg, aIter, &name) ||
|
||||
!ReadParam(aMsg, aIter, &imageURL) ||
|
||||
!ReadParam(aMsg, aIter, &title) ||
|
||||
!ReadParam(aMsg, aIter, &text) ||
|
||||
!ReadParam(aMsg, aIter, &textClickable) ||
|
||||
!ReadParam(aMsg, aIter, &cookie) ||
|
||||
!ReadParam(aMsg, aIter, &dir) ||
|
||||
!ReadParam(aMsg, aIter, &lang) ||
|
||||
!ReadParam(aMsg, aIter, &data) ||
|
||||
!ReadParam(aMsg, aIter, &principal) ||
|
||||
!ReadParam(aMsg, aIter, &inPrivateBrowsing)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
if (NS_WARN_IF(!alert)) {
|
||||
*aResult = nullptr;
|
||||
return true;
|
||||
}
|
||||
nsresult rv = alert->Init(name, imageURL, title, text, textClickable,
|
||||
cookie, dir, lang, data, principal,
|
||||
inPrivateBrowsing);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
*aResult = nullptr;
|
||||
return true;
|
||||
}
|
||||
alert.forget(aResult);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif /* mozilla_AlertNotificationIPCSerializer_h__ */
|
|
@ -16,7 +16,13 @@ EXPORTS += [
|
|||
'nsAlertsUtils.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'AlertNotification.h',
|
||||
'AlertNotificationIPCSerializer.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AlertNotification.cpp',
|
||||
'nsAlertsService.cpp',
|
||||
'nsAlertsUtils.cpp',
|
||||
'nsXULAlerts.cpp',
|
||||
|
|
|
@ -73,40 +73,66 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
|
|||
nsIPrincipal * aPrincipal,
|
||||
bool aInPrivateBrowsing)
|
||||
{
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
|
||||
aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aBidi, aLang, aData,
|
||||
aPrincipal, aInPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return ShowAlert(alert, aAlertListener);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert,
|
||||
nsIObserver * aAlertListener)
|
||||
{
|
||||
NS_ENSURE_ARG(aAlert);
|
||||
|
||||
nsAutoString cookie;
|
||||
nsresult rv = aAlert->GetCookie(cookie);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
ContentChild* cpc = ContentChild::GetSingleton();
|
||||
|
||||
if (aAlertListener)
|
||||
cpc->AddRemoteAlertObserver(PromiseFlatString(aAlertCookie), aAlertListener);
|
||||
cpc->AddRemoteAlertObserver(cookie, aAlertListener);
|
||||
|
||||
cpc->SendShowAlertNotification(PromiseFlatString(aImageUrl),
|
||||
PromiseFlatString(aAlertTitle),
|
||||
PromiseFlatString(aAlertText),
|
||||
aAlertTextClickable,
|
||||
PromiseFlatString(aAlertCookie),
|
||||
PromiseFlatString(aAlertName),
|
||||
PromiseFlatString(aBidi),
|
||||
PromiseFlatString(aLang),
|
||||
PromiseFlatString(aData),
|
||||
IPC::Principal(aPrincipal),
|
||||
aInPrivateBrowsing);
|
||||
cpc->SendShowAlert(aAlert);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString imageUrl;
|
||||
rv = aAlert->GetImageURL(imageUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString title;
|
||||
rv = aAlert->GetTitle(title);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString text;
|
||||
rv = aAlert->GetText(text);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString name;
|
||||
rv = aAlert->GetName(name);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = aAlert->GetPrincipal(getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
mozilla::AndroidBridge::Bridge()->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertCookie,
|
||||
aAlertListener, aAlertName, aPrincipal);
|
||||
mozilla::AndroidBridge::Bridge()->ShowAlertNotification(imageUrl, title, text, cookie,
|
||||
aAlertListener, name, principal);
|
||||
return NS_OK;
|
||||
#else
|
||||
// Check if there is an optional service that handles system-level notifications
|
||||
nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
|
||||
nsresult rv;
|
||||
if (sysAlerts) {
|
||||
rv = sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aAlertListener, aAlertName,
|
||||
aBidi, aLang, aData,
|
||||
IPC::Principal(aPrincipal),
|
||||
aInPrivateBrowsing);
|
||||
rv = sysAlerts->ShowAlert(aAlert, aAlertListener);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -114,14 +140,30 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
|
|||
if (!ShouldShowAlert()) {
|
||||
// Do not display the alert. Instead call alertfinished and get out.
|
||||
if (aAlertListener)
|
||||
aAlertListener->Observe(nullptr, "alertfinished", PromiseFlatString(aAlertCookie).get());
|
||||
aAlertListener->Observe(nullptr, "alertfinished", cookie.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool textClickable;
|
||||
rv = aAlert->GetTextClickable(&textClickable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString bidi;
|
||||
rv = aAlert->GetDir(bidi);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString lang;
|
||||
rv = aAlert->GetLang(lang);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool inPrivateBrowsing;
|
||||
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Use XUL notifications as a fallback if above methods have failed.
|
||||
rv = mXULAlerts.ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aAlertListener, aAlertName,
|
||||
aBidi, aLang, aPrincipal, aInPrivateBrowsing);
|
||||
rv = mXULAlerts.ShowAlertNotification(imageUrl, title, text, textClickable,
|
||||
cookie, aAlertListener, name,
|
||||
bidi, lang, principal, inPrivateBrowsing);
|
||||
return rv;
|
||||
#endif // !MOZ_WIDGET_ANDROID
|
||||
}
|
||||
|
|
|
@ -8,9 +8,96 @@
|
|||
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, uuid(9d0284bf-db40-42da-8f0d-c2769dbde7aa)]
|
||||
%{C++
|
||||
#define ALERT_NOTIFICATION_CONTRACTID "@mozilla.org/alert-notification;1"
|
||||
%}
|
||||
|
||||
[scriptable, uuid(b26b4a67-81b0-4270-8311-1e00a097ef92)]
|
||||
interface nsIAlertNotification : nsISupports
|
||||
{
|
||||
/** Initializes an alert notification. */
|
||||
void init([optional] in AString name,
|
||||
[optional] in AString imageURL,
|
||||
[optional] in AString title,
|
||||
[optional] in AString text,
|
||||
[optional] in boolean textClickable,
|
||||
[optional] in AString cookie,
|
||||
[optional] in AString dir,
|
||||
[optional] in AString lang,
|
||||
[optional] in AString data,
|
||||
[optional] in nsIPrincipal principal,
|
||||
[optional] in boolean inPrivateBrowsing);
|
||||
|
||||
/**
|
||||
* The name of the notification. This is currently only used on Android and
|
||||
* OS X. On Android, the name is hashed and used as a notification ID.
|
||||
* Notifications will replace previous notifications with the same name.
|
||||
*/
|
||||
readonly attribute AString name;
|
||||
|
||||
/**
|
||||
* A URL identifying the image to put in the alert. The OS X backend limits
|
||||
* the amount of time it will wait for the image to load to six seconds. After
|
||||
* that time, the alert will show without an image.
|
||||
*/
|
||||
readonly attribute AString imageURL;
|
||||
|
||||
/** The title for the alert. */
|
||||
readonly attribute AString title;
|
||||
|
||||
/** The contents of the alert. */
|
||||
readonly attribute AString text;
|
||||
|
||||
/**
|
||||
* Controls the click behavior. If true, the alert listener will be notified
|
||||
* when the user clicks on the alert.
|
||||
*/
|
||||
readonly attribute boolean textClickable;
|
||||
|
||||
/**
|
||||
* An opaque cookie that will be passed to the alert listener for each
|
||||
* callback.
|
||||
*/
|
||||
readonly attribute AString cookie;
|
||||
|
||||
/**
|
||||
* Bidi override for the title and contents. Valid values are "auto", "ltr",
|
||||
* or "rtl". Ignored if the backend doesn't support localization.
|
||||
*/
|
||||
readonly attribute AString dir;
|
||||
|
||||
/**
|
||||
* Language of the title and text. Ignored if the backend doesn't support
|
||||
* localization.
|
||||
*/
|
||||
readonly attribute AString lang;
|
||||
|
||||
/**
|
||||
* A Base64-encoded structured clone buffer containing data associated with
|
||||
* this alert. Only used for web notifications. Chrome callers should use a
|
||||
* cookie instead.
|
||||
*/
|
||||
readonly attribute AString data;
|
||||
|
||||
/**
|
||||
* The principal of the page that created the alert. Used for IPC security
|
||||
* checks, and to determine whether the alert should show the source string
|
||||
* and action buttons.
|
||||
*/
|
||||
readonly attribute nsIPrincipal principal;
|
||||
|
||||
/**
|
||||
* Controls the image loading behavior. If true, the image URL will be loaded
|
||||
* in private browsing mode.
|
||||
*/
|
||||
readonly attribute boolean inPrivateBrowsing;
|
||||
};
|
||||
|
||||
[scriptable, uuid(f7a36392-d98b-4141-a7d7-4e46642684e3)]
|
||||
interface nsIAlertsService : nsISupports
|
||||
{
|
||||
void showAlert(in nsIAlertNotification alert,
|
||||
[optional] in nsIObserver alertListener);
|
||||
/**
|
||||
* Displays a sliding notification window.
|
||||
*
|
||||
|
|
|
@ -97,6 +97,9 @@
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ALERT_NOTIFICATION_CID \
|
||||
{ 0x9a7b7a41, 0x0b47, 0x47f7, { 0xb6, 0x1b, 0x15, 0xa2, 0x10, 0xd6, 0xf0, 0x20 } }
|
||||
|
||||
// {A0CCAAF8-09DA-44D8-B250-9AC3E93C8117}
|
||||
#define NS_ALERTSSERVICE_CID \
|
||||
{ 0xa0ccaaf8, 0x9da, 0x44d8, { 0xb2, 0x50, 0x9a, 0xc3, 0xe9, 0x3c, 0x81, 0x17 } }
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "nsParentalControlsService.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/AlertNotification.h"
|
||||
#include "nsAlertsService.h"
|
||||
|
||||
#include "nsDownloadManager.h"
|
||||
|
@ -82,6 +83,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsFindService)
|
|||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsParentalControlsService)
|
||||
#endif
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AlertNotification)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAlertsService)
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsDownloadManager,
|
||||
|
@ -138,6 +140,7 @@ NS_DEFINE_NAMED_CID(NS_TOOLKIT_PERFORMANCESTATSSERVICE_CID);
|
|||
NS_DEFINE_NAMED_CID(NS_TOOLKIT_TERMINATOR_CID);
|
||||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_USERINFO_CID);
|
||||
NS_DEFINE_NAMED_CID(ALERT_NOTIFICATION_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_ALERTSSERVICE_CID);
|
||||
#if !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
|
||||
NS_DEFINE_NAMED_CID(NS_PARENTALCONTROLSSERVICE_CID);
|
||||
|
@ -173,6 +176,7 @@ static const Module::CIDEntry kToolkitCIDs[] = {
|
|||
{ &kNS_TOOLKIT_PERFORMANCESTATSSERVICE_CID, false, nullptr, nsPerformanceStatsServiceConstructor },
|
||||
#endif // defined (MOZ_HAS_PERFSTATS)
|
||||
{ &kNS_USERINFO_CID, false, nullptr, nsUserInfoConstructor },
|
||||
{ &kALERT_NOTIFICATION_CID, false, nullptr, AlertNotificationConstructor },
|
||||
{ &kNS_ALERTSSERVICE_CID, false, nullptr, nsAlertsServiceConstructor },
|
||||
#if !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
|
||||
{ &kNS_PARENTALCONTROLSSERVICE_CID, false, nullptr, nsParentalControlsServiceConstructor },
|
||||
|
@ -210,6 +214,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = {
|
|||
{ NS_TOOLKIT_PERFORMANCESTATSSERVICE_CONTRACTID, &kNS_TOOLKIT_PERFORMANCESTATSSERVICE_CID },
|
||||
#endif // defined (MOZ_HAS_PERFSTATS)
|
||||
{ NS_USERINFO_CONTRACTID, &kNS_USERINFO_CID },
|
||||
{ ALERT_NOTIFICATION_CONTRACTID, &kALERT_NOTIFICATION_CID },
|
||||
{ NS_ALERTSERVICE_CONTRACTID, &kNS_ALERTSSERVICE_CID },
|
||||
#if !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
|
||||
{ NS_PARENTALCONTROLSSERVICE_CONTRACTID, &kNS_PARENTALCONTROLSSERVICE_CID },
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "imgIRequest.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIAlertsService.h"
|
||||
#include "nsIImageToPixbuf.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
@ -186,6 +187,11 @@ nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf)
|
|||
if (!mNotification)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (obsServ)
|
||||
obsServ->AddObserver(this, "quit-application", true);
|
||||
|
||||
if (aPixbuf)
|
||||
notify_notification_set_icon_from_pixbuf(mNotification, aPixbuf);
|
||||
|
||||
|
@ -277,13 +283,8 @@ nsAlertsIconListener::Observe(nsISupports *aSubject, const char *aTopic,
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsAlertsIconListener::InitAlertAsync(const nsAString & aImageUrl,
|
||||
const nsAString & aAlertTitle,
|
||||
const nsAString & aAlertText,
|
||||
bool aAlertTextClickable,
|
||||
const nsAString & aAlertCookie,
|
||||
nsIObserver * aAlertListener,
|
||||
bool aInPrivateBrowsing)
|
||||
nsAlertsIconListener::InitAlertAsync(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener)
|
||||
{
|
||||
if (!libNotifyHandle)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -335,27 +336,38 @@ nsAlertsIconListener::InitAlertAsync(const nsAString & aImageUrl,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!gHasActions && aAlertTextClickable)
|
||||
nsresult rv = aAlert->GetTextClickable(&mAlertHasAction);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!gHasActions && mAlertHasAction)
|
||||
return NS_ERROR_FAILURE; // No good, fallback to XUL
|
||||
|
||||
nsCOMPtr<nsIObserverService> obsServ =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (obsServ)
|
||||
obsServ->AddObserver(this, "quit-application", true);
|
||||
|
||||
nsAutoString title;
|
||||
rv = aAlert->GetTitle(title);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Workaround for a libnotify bug - blank titles aren't dealt with
|
||||
// properly so we use a space
|
||||
if (aAlertTitle.IsEmpty()) {
|
||||
if (title.IsEmpty()) {
|
||||
mAlertTitle = NS_LITERAL_CSTRING(" ");
|
||||
} else {
|
||||
mAlertTitle = NS_ConvertUTF16toUTF8(aAlertTitle);
|
||||
mAlertTitle = NS_ConvertUTF16toUTF8(title);
|
||||
}
|
||||
|
||||
mAlertText = NS_ConvertUTF16toUTF8(aAlertText);
|
||||
mAlertHasAction = aAlertTextClickable;
|
||||
nsAutoString text;
|
||||
rv = aAlert->GetText(text);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mAlertText = NS_ConvertUTF16toUTF8(text);
|
||||
|
||||
mAlertListener = aAlertListener;
|
||||
mAlertCookie = aAlertCookie;
|
||||
|
||||
return StartRequest(aImageUrl, aInPrivateBrowsing);
|
||||
rv = aAlert->GetCookie(mAlertCookie);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString imageUrl;
|
||||
rv = aAlert->GetImageURL(imageUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
bool inPrivateBrowsing;
|
||||
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return StartRequest(imageUrl, inPrivateBrowsing);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
class imgIRequest;
|
||||
class nsIAlertNotification;
|
||||
|
||||
struct NotifyNotification;
|
||||
|
||||
|
@ -29,13 +30,8 @@ public:
|
|||
|
||||
nsAlertsIconListener();
|
||||
|
||||
nsresult InitAlertAsync(const nsAString & aImageUrl,
|
||||
const nsAString & aAlertTitle,
|
||||
const nsAString & aAlertText,
|
||||
bool aAlertTextClickable,
|
||||
const nsAString & aAlertCookie,
|
||||
nsIObserver * aAlertListener,
|
||||
bool aInPrivateBrowsing);
|
||||
nsresult InitAlertAsync(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener);
|
||||
|
||||
void SendCallback();
|
||||
void SendClosed();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* 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/. */
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsSystemAlertsService.h"
|
||||
#include "nsAlertsIconListener.h"
|
||||
|
@ -40,12 +41,27 @@ NS_IMETHODIMP nsSystemAlertsService::ShowAlertNotification(const nsAString & aIm
|
|||
nsIPrincipal * aPrincipal,
|
||||
bool aInPrivateBrowsing)
|
||||
{
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
|
||||
aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aBidi, aLang, aData,
|
||||
aPrincipal, aInPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return ShowAlert(alert, aAlertListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsSystemAlertsService::ShowAlert(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener)
|
||||
{
|
||||
NS_ENSURE_ARG(aAlert);
|
||||
|
||||
RefPtr<nsAlertsIconListener> alertListener = new nsAlertsIconListener();
|
||||
if (!alertListener)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return alertListener->InitAlertAsync(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aAlertListener, aInPrivateBrowsing);
|
||||
return alertListener->InitAlertAsync(aAlert, aAlertListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsSystemAlertsService::CloseAlert(const nsAString& aAlertName,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "nsNetUtil.h"
|
||||
#include "imgLoader.h"
|
||||
#import "nsCocoaUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsString.h"
|
||||
|
@ -240,15 +241,39 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
|
|||
const nsAString & aData,
|
||||
nsIPrincipal * aPrincipal,
|
||||
bool aInPrivateBrowsing)
|
||||
{
|
||||
nsCOMPtr<nsIAlertNotification> alert =
|
||||
do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
|
||||
NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
|
||||
nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
|
||||
aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aBidi, aLang, aData,
|
||||
aPrincipal, aInPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return ShowAlert(alert, aAlertListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OSXNotificationCenter::ShowAlert(nsIAlertNotification* aAlert,
|
||||
nsIObserver* aAlertListener)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
NS_ENSURE_ARG(aAlert);
|
||||
|
||||
Class unClass = NSClassFromString(@"NSUserNotification");
|
||||
id<FakeNSUserNotification> notification = [[unClass alloc] init];
|
||||
notification.title = nsCocoaUtils::ToNSString(aAlertTitle);
|
||||
|
||||
nsAutoString title;
|
||||
nsresult rv = aAlert->GetTitle(title);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
notification.title = nsCocoaUtils::ToNSString(title);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = aAlert->GetPrincipal(getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoString hostPort;
|
||||
nsAlertsUtils::GetSourceHostPort(aPrincipal, hostPort);
|
||||
nsAlertsUtils::GetSourceHostPort(principal, hostPort);
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
sbs->CreateBundle("chrome://alerts/locale/alert.properties", getter_AddRefs(bundle));
|
||||
|
@ -263,12 +288,16 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
|
|||
notification.subtitle = nsCocoaUtils::ToNSString(notificationSource);
|
||||
}
|
||||
|
||||
notification.informativeText = nsCocoaUtils::ToNSString(aAlertText);
|
||||
nsAutoString text;
|
||||
rv = aAlert->GetText(text);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
notification.informativeText = nsCocoaUtils::ToNSString(text);
|
||||
|
||||
notification.soundName = NSUserNotificationDefaultSoundName;
|
||||
notification.hasActionButton = NO;
|
||||
|
||||
// If this is not an application/extension alert, show additional actions dealing with permissions.
|
||||
if (nsAlertsUtils::IsActionablePrincipal(aPrincipal)) {
|
||||
if (nsAlertsUtils::IsActionablePrincipal(principal)) {
|
||||
if (bundle) {
|
||||
nsXPIDLString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle;
|
||||
bundle->GetStringFromName(MOZ_UTF16("closeButton.title"),
|
||||
|
@ -307,24 +336,39 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
|
|||
}
|
||||
}
|
||||
}
|
||||
NSString *alertName = nsCocoaUtils::ToNSString(aAlertName);
|
||||
nsAutoString name;
|
||||
rv = aAlert->GetName(name);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NSString *alertName = nsCocoaUtils::ToNSString(name);
|
||||
if (!alertName) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
notification.userInfo = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:alertName, nil]
|
||||
forKeys:[NSArray arrayWithObjects:@"name", nil]];
|
||||
|
||||
OSXNotificationInfo *osxni = new OSXNotificationInfo(alertName, aAlertListener, aAlertCookie);
|
||||
nsAutoString cookie;
|
||||
rv = aAlert->GetCookie(cookie);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
OSXNotificationInfo *osxni = new OSXNotificationInfo(alertName, aAlertListener, cookie);
|
||||
|
||||
nsAutoString imageUrl;
|
||||
rv = aAlert->GetImageURL(imageUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool inPrivateBrowsing;
|
||||
rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Show the notification without waiting for an image if there is no icon URL or
|
||||
// notification icons are not supported on this version of OS X.
|
||||
if (aImageUrl.IsEmpty() || ![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
|
||||
if (imageUrl.IsEmpty() || ![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
|
||||
CloseAlertCocoaString(alertName);
|
||||
mActiveAlerts.AppendElement(osxni);
|
||||
[GetNotificationCenter() deliverNotification:notification];
|
||||
[notification release];
|
||||
if (aAlertListener) {
|
||||
aAlertListener->Observe(nullptr, "alertshow", PromiseFlatString(aAlertCookie).get());
|
||||
aAlertListener->Observe(nullptr, "alertshow", cookie.get());
|
||||
}
|
||||
} else {
|
||||
mPendingAlerts.AppendElement(osxni);
|
||||
|
@ -332,17 +376,17 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
|
|||
RefPtr<imgLoader> il = imgLoader::GetInstance();
|
||||
if (il) {
|
||||
nsCOMPtr<nsIURI> imageUri;
|
||||
NS_NewURI(getter_AddRefs(imageUri), aImageUrl);
|
||||
NS_NewURI(getter_AddRefs(imageUri), imageUrl);
|
||||
if (imageUri) {
|
||||
nsresult rv = il->LoadImage(imageUri, nullptr, nullptr,
|
||||
mozilla::net::RP_Default,
|
||||
aPrincipal, nullptr,
|
||||
this, nullptr,
|
||||
aInPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS :
|
||||
nsIRequest::LOAD_NORMAL,
|
||||
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
|
||||
EmptyString(),
|
||||
getter_AddRefs(osxni->mIconRequest));
|
||||
rv = il->LoadImage(imageUri, nullptr, nullptr,
|
||||
mozilla::net::RP_Default,
|
||||
principal, nullptr,
|
||||
this, nullptr,
|
||||
inPrivateBrowsing ? nsIRequest::LOAD_ANONYMOUS :
|
||||
nsIRequest::LOAD_NORMAL,
|
||||
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
|
||||
EmptyString(),
|
||||
getter_AddRefs(osxni->mIconRequest));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Set a timer for six seconds. If we don't have an icon by the time this
|
||||
// goes off then we go ahead without an icon.
|
||||
|
|
Загрузка…
Ссылка в новой задаче