зеркало из https://github.com/mozilla/gecko-dev.git
merge autoland to mozilla-central. r=merge a=merge
MozReview-Commit-ID: Fsg3B4nCNMh
This commit is contained in:
Коммит
f324d0cfb7
|
@ -88,6 +88,7 @@ MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_A
|
|||
|
||||
.PHONY: repackage
|
||||
tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME)
|
||||
rm -rf $(dist_dest)
|
||||
$(MKDIR) -p $(dist_dest)/Contents/MacOS
|
||||
$(MKDIR) -p $(dist_dest)/$(LPROJ)
|
||||
rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
|
||||
|
|
|
@ -115,6 +115,17 @@ pref("app.update.backgroundMaxErrors", 10);
|
|||
// Whether or not app updates are enabled
|
||||
pref("app.update.enabled", true);
|
||||
|
||||
// Whether or not to use the doorhanger application update UI.
|
||||
pref("app.update.doorhanger", true);
|
||||
|
||||
// How many times we should let downloads fail before prompting the user to
|
||||
// download a fresh installer.
|
||||
pref("app.update.download.promptMaxAttempts", 2);
|
||||
|
||||
// How many times we should let an elevation prompt fail before prompting the user to
|
||||
// download a fresh installer.
|
||||
pref("app.update.elevation.promptMaxAttempts", 2);
|
||||
|
||||
// If set to true, the Update Service will automatically download updates when
|
||||
// app updates are enabled per the app.update.enabled preference and if the user
|
||||
// can apply updates.
|
||||
|
@ -123,12 +134,6 @@ pref("app.update.auto", true);
|
|||
// If set to true, the Update Service will present no UI for any event.
|
||||
pref("app.update.silent", false);
|
||||
|
||||
// If set to true, the hamburger button will show badges for update events.
|
||||
#ifndef RELEASE_OR_BETA
|
||||
pref("app.update.badge", true);
|
||||
#else
|
||||
pref("app.update.badge", false);
|
||||
#endif
|
||||
// app.update.badgeWaitTime is in branding section
|
||||
|
||||
// If set to true, the Update Service will apply updates in the background
|
||||
|
|
|
@ -504,10 +504,9 @@ const gExtensionsNotifications = {
|
|||
let sideloaded = ExtensionsUI.sideloaded;
|
||||
let updates = ExtensionsUI.updates;
|
||||
if (sideloaded.size + updates.size == 0) {
|
||||
gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_ADDONS);
|
||||
PanelUI.removeNotification("addon-alert");
|
||||
} else {
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_ADDONS,
|
||||
"addon-alert");
|
||||
PanelUI.showBadgeOnlyNotification("addon-alert");
|
||||
}
|
||||
|
||||
let container = document.getElementById("PanelUI-footer-addons");
|
||||
|
|
|
@ -537,7 +537,8 @@ var FullScreen = {
|
|||
// e.g. we wouldn't want the autoscroll icon firing this event, so when the user
|
||||
// toggles chrome when moving mouse to the top, it doesn't go away again.
|
||||
if (aEvent.type == "popupshown" && !FullScreen._isChromeCollapsed &&
|
||||
aEvent.target.localName != "tooltip" && aEvent.target.localName != "window")
|
||||
aEvent.target.localName != "tooltip" && aEvent.target.localName != "window" &&
|
||||
aEvent.target.getAttribute("nopreventnavboxhide") != "true")
|
||||
FullScreen._isPopupOpen = true;
|
||||
else if (aEvent.type == "popuphidden" && aEvent.target.localName != "tooltip" &&
|
||||
aEvent.target.localName != "window") {
|
||||
|
@ -547,6 +548,10 @@ var FullScreen = {
|
|||
}
|
||||
},
|
||||
|
||||
get navToolboxHidden() {
|
||||
return this._isChromeCollapsed;
|
||||
},
|
||||
|
||||
// Autohide helpers for the context menu item
|
||||
getAutohide(aItem) {
|
||||
aItem.setAttribute("checked", gPrefService.getBoolPref("browser.fullscreen.autohide"));
|
||||
|
@ -579,6 +584,7 @@ var FullScreen = {
|
|||
}
|
||||
|
||||
this._isChromeCollapsed = false;
|
||||
Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "shown");
|
||||
},
|
||||
|
||||
hideNavToolbox(aAnimate = false) {
|
||||
|
@ -602,6 +608,8 @@ var FullScreen = {
|
|||
gNavToolbox.style.marginTop =
|
||||
-gNavToolbox.getBoundingClientRect().height + "px";
|
||||
this._isChromeCollapsed = true;
|
||||
Services.obs.notifyObservers(null, "fullscreen-nav-toolbox", "hidden");
|
||||
|
||||
MousePosTracker.removeListener(this);
|
||||
},
|
||||
|
||||
|
|
|
@ -217,9 +217,9 @@ var gFxAccounts = {
|
|||
}
|
||||
}
|
||||
if (showErrorBadge) {
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_FXA, "fxa-needs-authentication");
|
||||
PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
|
||||
} else {
|
||||
gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_FXA);
|
||||
PanelUI.removeNotification("fxa-needs-authentication");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1183,7 +1183,7 @@ toolbarpaletteitem[place="palette"][hidden] {
|
|||
max-width: 10em;
|
||||
}
|
||||
|
||||
#main-window[customizing=true] #PanelUI-update-status {
|
||||
#main-window[customizing=true] .PanelUI-notification-menu-item {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -1515,8 +1515,6 @@ var gBrowserInit = {
|
|||
|
||||
gBrowserThumbnails.init();
|
||||
|
||||
gMenuButtonBadgeManager.init();
|
||||
|
||||
gMenuButtonUpdateBadge.init();
|
||||
|
||||
gExtensionsNotifications.init();
|
||||
|
@ -1693,8 +1691,6 @@ var gBrowserInit = {
|
|||
|
||||
gMenuButtonUpdateBadge.uninit();
|
||||
|
||||
gMenuButtonBadgeManager.uninit();
|
||||
|
||||
SidebarUI.uninit();
|
||||
|
||||
// Now either cancel delayedStartup, or clean up the services initialized from
|
||||
|
@ -2749,185 +2745,217 @@ function PageProxyClickHandler(aEvent) {
|
|||
middleMousePaste(aEvent);
|
||||
}
|
||||
|
||||
var gMenuButtonBadgeManager = {
|
||||
BADGEID_APPUPDATE: "update",
|
||||
BADGEID_DOWNLOAD: "download",
|
||||
BADGEID_FXA: "fxa",
|
||||
BADGEID_ADDONS: "addons",
|
||||
|
||||
fxaBadge: null,
|
||||
downloadBadge: null,
|
||||
appUpdateBadge: null,
|
||||
addonsBadge: null,
|
||||
|
||||
init() {
|
||||
PanelUI.panel.addEventListener("popupshowing", this, true);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
PanelUI.panel.removeEventListener("popupshowing", this, true);
|
||||
},
|
||||
|
||||
handleEvent(e) {
|
||||
if (e.type === "popupshowing") {
|
||||
this.clearBadges();
|
||||
}
|
||||
},
|
||||
|
||||
_showBadge() {
|
||||
let badgeToShow = this.downloadBadge || this.appUpdateBadge || this.fxaBadge || this.addonsBadge;
|
||||
|
||||
if (badgeToShow) {
|
||||
PanelUI.menuButton.setAttribute("badge-status", badgeToShow);
|
||||
} else {
|
||||
PanelUI.menuButton.removeAttribute("badge-status");
|
||||
}
|
||||
},
|
||||
|
||||
_changeBadge(badgeId, badgeStatus = null) {
|
||||
if (badgeId == this.BADGEID_APPUPDATE) {
|
||||
this.appUpdateBadge = badgeStatus;
|
||||
} else if (badgeId == this.BADGEID_DOWNLOAD) {
|
||||
this.downloadBadge = badgeStatus;
|
||||
} else if (badgeId == this.BADGEID_FXA) {
|
||||
this.fxaBadge = badgeStatus;
|
||||
} else if (badgeId == this.BADGEID_ADDONS) {
|
||||
this.addonsBadge = badgeStatus;
|
||||
} else {
|
||||
Cu.reportError("The badge ID '" + badgeId + "' is unknown!");
|
||||
}
|
||||
this._showBadge();
|
||||
},
|
||||
|
||||
addBadge(badgeId, badgeStatus) {
|
||||
if (!badgeStatus) {
|
||||
Cu.reportError("badgeStatus must be defined");
|
||||
return;
|
||||
}
|
||||
this._changeBadge(badgeId, badgeStatus);
|
||||
},
|
||||
|
||||
removeBadge(badgeId) {
|
||||
this._changeBadge(badgeId);
|
||||
},
|
||||
|
||||
clearBadges() {
|
||||
this.appUpdateBadge = null;
|
||||
this.downloadBadge = null;
|
||||
this.fxaBadge = null;
|
||||
this._showBadge();
|
||||
}
|
||||
};
|
||||
|
||||
// Setup the hamburger button badges for updates, if enabled.
|
||||
var gMenuButtonUpdateBadge = {
|
||||
enabled: false,
|
||||
badgeWaitTime: 0,
|
||||
timer: null,
|
||||
cancelObserverRegistered: false,
|
||||
kTopics: [
|
||||
"update-staged",
|
||||
"update-downloaded",
|
||||
"update-available",
|
||||
"update-error",
|
||||
],
|
||||
|
||||
timeouts: [],
|
||||
|
||||
get enabled() {
|
||||
return Services.prefs.getBoolPref("app.update.doorhanger", false);
|
||||
},
|
||||
|
||||
get badgeWaitTime() {
|
||||
return Services.prefs.getIntPref("app.update.badgeWaitTime", 4 * 24 * 3600); // 4 days
|
||||
},
|
||||
|
||||
init() {
|
||||
this.enabled = Services.prefs.getBoolPref("app.update.badge", false);
|
||||
if (this.enabled) {
|
||||
this.badgeWaitTime = Services.prefs.getIntPref("app.update.badgeWaitTime",
|
||||
345600); // 4 days
|
||||
Services.obs.addObserver(this, "update-staged", false);
|
||||
Services.obs.addObserver(this, "update-downloaded", false);
|
||||
this.kTopics.forEach(t => {
|
||||
Services.obs.addObserver(this, t, false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
if (this.timer)
|
||||
this.timer.cancel();
|
||||
if (this.enabled) {
|
||||
Services.obs.removeObserver(this, "update-staged");
|
||||
Services.obs.removeObserver(this, "update-downloaded");
|
||||
this.enabled = false;
|
||||
this.kTopics.forEach(t => {
|
||||
Services.obs.removeObserver(this, t);
|
||||
});
|
||||
}
|
||||
if (this.cancelObserverRegistered) {
|
||||
Services.obs.removeObserver(this, "update-canceled");
|
||||
this.cancelObserverRegistered = false;
|
||||
|
||||
this.reset();
|
||||
},
|
||||
|
||||
reset() {
|
||||
PanelUI.removeNotification(/^update-/);
|
||||
this.clearCallbacks();
|
||||
},
|
||||
|
||||
clearCallbacks() {
|
||||
this.timeouts.forEach(t => clearTimeout(t));
|
||||
this.timeouts = [];
|
||||
},
|
||||
|
||||
addTimeout(time, callback) {
|
||||
this.timeouts.push(setTimeout(() => {
|
||||
this.clearCallbacks();
|
||||
callback();
|
||||
}, time));
|
||||
},
|
||||
|
||||
replaceReleaseNotes(update, whatsNewId) {
|
||||
let whatsNewLink = document.getElementById(whatsNewId);
|
||||
if (update && update.detailsURL) {
|
||||
whatsNewLink.href = update.detailsURL;
|
||||
} else {
|
||||
whatsNewLink.href = Services.urlFormatter.formatURLPref("app.update.url.details");
|
||||
}
|
||||
},
|
||||
|
||||
onMenuPanelCommand(event) {
|
||||
if (event.originalTarget.getAttribute("update-status") === "succeeded") {
|
||||
// restart the app
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||
requestRestart() {
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
|
||||
|
||||
if (!cancelQuit.data) {
|
||||
Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart);
|
||||
if (!cancelQuit.data) {
|
||||
Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart);
|
||||
}
|
||||
},
|
||||
|
||||
openManualUpdateUrl() {
|
||||
let manualUpdateUrl = Services.urlFormatter.formatURLPref("app.update.url.manual");
|
||||
openUILinkIn(manualUpdateUrl, "tab");
|
||||
},
|
||||
|
||||
showUpdateNotification(type, dismissed, mainAction) {
|
||||
let action = {
|
||||
callback(fromDoorhanger) {
|
||||
if (fromDoorhanger) {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_DOORHANGER").add(type);
|
||||
} else {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_MENU").add(type);
|
||||
}
|
||||
mainAction();
|
||||
}
|
||||
} else {
|
||||
// open the page for manual update
|
||||
let url = Services.urlFormatter.formatURLPref("app.update.url.manual");
|
||||
openUILinkIn(url, "tab");
|
||||
};
|
||||
|
||||
let secondaryAction = {
|
||||
callback() {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_DISMISSED").add(type);
|
||||
},
|
||||
dismiss: true
|
||||
};
|
||||
|
||||
PanelUI.showNotification("update-" + type, action, [secondaryAction], { dismissed });
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_SHOWN").add(type);
|
||||
},
|
||||
|
||||
showRestartNotification(dismissed) {
|
||||
this.showUpdateNotification("restart", dismissed, () => gMenuButtonUpdateBadge.requestRestart());
|
||||
},
|
||||
|
||||
showUpdateAvailableNotification(update, dismissed) {
|
||||
this.replaceReleaseNotes(update, "update-available-whats-new");
|
||||
this.showUpdateNotification("available", dismissed, () => {
|
||||
let updateService = Cc["@mozilla.org/updates/update-service;1"]
|
||||
.getService(Ci.nsIApplicationUpdateService);
|
||||
updateService.downloadUpdate(update, true);
|
||||
});
|
||||
},
|
||||
|
||||
showManualUpdateNotification(update, dismissed) {
|
||||
this.replaceReleaseNotes(update, "update-manual-whats-new");
|
||||
|
||||
this.showUpdateNotification("manual", dismissed, () => gMenuButtonUpdateBadge.openManualUpdateUrl());
|
||||
},
|
||||
|
||||
handleUpdateError(update, status) {
|
||||
switch (status) {
|
||||
case "download-attempt-failed":
|
||||
this.clearCallbacks();
|
||||
this.showUpdateAvailableNotification(update, false);
|
||||
break;
|
||||
case "download-attempts-exceeded":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
case "elevation-attempt-failed":
|
||||
this.clearCallbacks();
|
||||
this.showRestartNotification(update, false);
|
||||
break;
|
||||
case "elevation-attempts-exceeded":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
case "check-attempts-exceeded":
|
||||
case "unknown":
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateStagedOrDownloaded(update, status) {
|
||||
switch (status) {
|
||||
case "applied":
|
||||
case "pending":
|
||||
case "applied-service":
|
||||
case "pending-service":
|
||||
case "success":
|
||||
this.clearCallbacks();
|
||||
|
||||
let badgeWaitTimeMs = this.badgeWaitTime * 1000;
|
||||
let doorhangerWaitTimeMs = update.promptWaitTime * 1000;
|
||||
|
||||
if (badgeWaitTimeMs < doorhangerWaitTimeMs) {
|
||||
this.addTimeout(badgeWaitTimeMs, () => {
|
||||
this.showRestartNotification(true);
|
||||
|
||||
// doorhangerWaitTimeMs is relative to when we initially received
|
||||
// the event. Since we've already waited badgeWaitTimeMs, subtract
|
||||
// that from doorhangerWaitTimeMs.
|
||||
let remainingTime = doorhangerWaitTimeMs - badgeWaitTimeMs;
|
||||
this.addTimeout(remainingTime, () => {
|
||||
this.showRestartNotification(false);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.addTimeout(doorhangerWaitTimeMs, () => {
|
||||
this.showRestartNotification(false);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateAvailable(update, status) {
|
||||
switch (status) {
|
||||
case "show-prompt":
|
||||
// If an update is available and had the showPrompt flag set, then
|
||||
// show an update available doorhanger.
|
||||
this.clearCallbacks();
|
||||
this.showUpdateAvailableNotification(update, false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, status) {
|
||||
if (topic == "update-canceled") {
|
||||
this.reset();
|
||||
return;
|
||||
}
|
||||
if (status == "failed") {
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this.uninit();
|
||||
this.displayBadge(false);
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Give the user badgeWaitTime seconds to react before prompting.
|
||||
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this.timer.initWithCallback(this, this.badgeWaitTime * 1000,
|
||||
this.timer.TYPE_ONE_SHOT);
|
||||
// The timer callback will call uninit() when it completes.
|
||||
},
|
||||
let update = subject && subject.QueryInterface(Ci.nsIUpdate);
|
||||
|
||||
notify() {
|
||||
// If the update is successfully applied, or if the updater has fallen back
|
||||
// to non-staged updates, add a badge to the hamburger menu to indicate an
|
||||
// update will be applied once the browser restarts.
|
||||
this.uninit();
|
||||
this.displayBadge(true);
|
||||
},
|
||||
|
||||
displayBadge(succeeded) {
|
||||
let status = succeeded ? "succeeded" : "failed";
|
||||
let badgeStatus = "update-" + status;
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_APPUPDATE, badgeStatus);
|
||||
|
||||
let stringId;
|
||||
let updateButtonText;
|
||||
if (succeeded) {
|
||||
let brandBundle = document.getElementById("bundle_brand");
|
||||
let brandShortName = brandBundle.getString("brandShortName");
|
||||
stringId = "appmenu.restartNeeded.description";
|
||||
updateButtonText = gNavigatorBundle.getFormattedString(stringId,
|
||||
[brandShortName]);
|
||||
Services.obs.addObserver(this, "update-canceled", false);
|
||||
this.cancelObserverRegistered = true;
|
||||
} else {
|
||||
stringId = "appmenu.updateFailed.description";
|
||||
updateButtonText = gNavigatorBundle.getString(stringId);
|
||||
switch (topic) {
|
||||
case "update-available":
|
||||
this.handleUpdateAvailable(update, status);
|
||||
break;
|
||||
case "update-staged":
|
||||
case "update-downloaded":
|
||||
this.handleUpdateStagedOrDownloaded(update, status);
|
||||
break;
|
||||
case "update-error":
|
||||
this.handleUpdateError(update, status);
|
||||
break;
|
||||
}
|
||||
|
||||
let updateButton = document.getElementById("PanelUI-update-status");
|
||||
updateButton.setAttribute("label", updateButtonText);
|
||||
updateButton.setAttribute("update-status", status);
|
||||
updateButton.hidden = false;
|
||||
},
|
||||
|
||||
reset() {
|
||||
gMenuButtonBadgeManager.removeBadge(
|
||||
gMenuButtonBadgeManager.BADGEID_APPUPDATE);
|
||||
let updateButton = document.getElementById("PanelUI-update-status");
|
||||
updateButton.hidden = true;
|
||||
this.uninit();
|
||||
this.init();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/ContentWebRTC.jsm");
|
||||
Cu.import("resource://gre/modules/InlineSpellChecker.jsm");
|
||||
Cu.import("resource://gre/modules/InlineSpellCheckerContent.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
|
||||
|
@ -23,6 +20,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
|
|||
"resource://gre/modules/BrowserUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ContentLinkHandler",
|
||||
"resource:///modules/ContentLinkHandler.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ContentWebRTC",
|
||||
"resource:///modules/ContentWebRTC.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SpellCheckHelper",
|
||||
"resource://gre/modules/InlineSpellChecker.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "InlineSpellCheckerContent",
|
||||
"resource://gre/modules/InlineSpellCheckerContent.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
|
||||
"resource://gre/modules/LoginManagerContent.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LoginFormFactory",
|
||||
|
@ -702,19 +705,15 @@ addEventListener("DOMWindowFocus", function(event) {
|
|||
sendAsyncMessage("DOMWindowFocus", {});
|
||||
}, false);
|
||||
|
||||
ContentWebRTC.init();
|
||||
addMessageListener("rtcpeer:Allow", ContentWebRTC);
|
||||
addMessageListener("rtcpeer:Deny", ContentWebRTC);
|
||||
addMessageListener("webrtc:Allow", ContentWebRTC);
|
||||
addMessageListener("webrtc:Deny", ContentWebRTC);
|
||||
addMessageListener("webrtc:StopSharing", ContentWebRTC);
|
||||
addMessageListener("webrtc:StartBrowserSharing", () => {
|
||||
let windowID = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
|
||||
sendAsyncMessage("webrtc:response:StartBrowserSharing", {
|
||||
windowID
|
||||
});
|
||||
});
|
||||
// We use this shim so that ContentWebRTC.jsm will not be loaded until
|
||||
// it is actually needed.
|
||||
var ContentWebRTCShim = message => ContentWebRTC.receiveMessage(message);
|
||||
|
||||
addMessageListener("rtcpeer:Allow", ContentWebRTCShim);
|
||||
addMessageListener("rtcpeer:Deny", ContentWebRTCShim);
|
||||
addMessageListener("webrtc:Allow", ContentWebRTCShim);
|
||||
addMessageListener("webrtc:Deny", ContentWebRTCShim);
|
||||
addMessageListener("webrtc:StopSharing", ContentWebRTCShim);
|
||||
|
||||
addEventListener("pageshow", function(event) {
|
||||
if (event.target == content.document) {
|
||||
|
|
|
@ -5614,11 +5614,12 @@
|
|||
|
||||
<handlers>
|
||||
<handler event="underflow" phase="capturing"><![CDATA[
|
||||
if (event.target != this)
|
||||
if (event.originalTarget != this._scrollbox)
|
||||
return;
|
||||
|
||||
// Ignore vertical events
|
||||
if (event.detail == 0)
|
||||
return; // Ignore vertical events
|
||||
return;
|
||||
|
||||
var tabs = document.getBindingParent(this);
|
||||
tabs.removeAttribute("overflow");
|
||||
|
@ -5632,11 +5633,12 @@
|
|||
tabs._positionPinnedTabs();
|
||||
]]></handler>
|
||||
<handler event="overflow"><![CDATA[
|
||||
if (event.target != this)
|
||||
if (event.originalTarget != this._scrollbox)
|
||||
return;
|
||||
|
||||
// Ignore vertical events
|
||||
if (event.detail == 0)
|
||||
return; // Ignore vertical events
|
||||
return;
|
||||
|
||||
var tabs = document.getBindingParent(this);
|
||||
tabs.setAttribute("overflow", "true");
|
||||
|
@ -6073,16 +6075,19 @@
|
|||
|
||||
let scrollButtonWidth = this.mTabstrip._scrollButtonDown.getBoundingClientRect().width;
|
||||
let paddingStart = this.mTabstrip.scrollboxPaddingStart;
|
||||
let pinnedTabWidth;
|
||||
let width = 0;
|
||||
|
||||
for (let i = numPinned - 1; i >= 0; i--) {
|
||||
let tab = this.childNodes[i];
|
||||
width += tab.getBoundingClientRect().width;
|
||||
if (!pinnedTabWidth) {
|
||||
pinnedTabWidth = tab.getBoundingClientRect().width;
|
||||
}
|
||||
width += pinnedTabWidth;
|
||||
tab.style.marginInlineStart = -(width + scrollButtonWidth + paddingStart) + "px";
|
||||
}
|
||||
|
||||
this.style.paddingInlineStart = width + paddingStart + "px";
|
||||
|
||||
} else {
|
||||
this.removeAttribute("positionpinnedtabs");
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/browser-test"
|
||||
]
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
[DEFAULT]
|
||||
tags = appupdate
|
||||
support-files =
|
||||
head.js
|
||||
downloadPage.html
|
||||
testConstants.js
|
||||
|
||||
[browser_updatesBasicPrompt.js]
|
||||
skip-if = asan
|
||||
reason = Bug 1168003
|
||||
[browser_updatesBasicPromptNoStaging.js]
|
||||
[browser_updatesCompleteAndPartialPatchesWithBadCompleteSize.js]
|
||||
[browser_updatesCompleteAndPartialPatchesWithBadPartialSize.js]
|
||||
[browser_updatesCompleteAndPartialPatchesWithBadSizes.js]
|
||||
[browser_updatesCompletePatchApplyFailure.js]
|
||||
[browser_updatesCompletePatchWithBadCompleteSize.js]
|
||||
[browser_updatesDownloadFailures.js]
|
||||
[browser_updatesMalformedXml.js]
|
||||
[browser_updatesPartialPatchApplyFailure.js]
|
||||
[browser_updatesPartialPatchApplyFailureWithCompleteAvailable.js]
|
||||
[browser_updatesPartialPatchApplyFailureWithCompleteValidationFailure.js]
|
||||
[browser_updatesPartialPatchWithBadPartialSize.js]
|
|
@ -0,0 +1,28 @@
|
|||
add_task(function* testBasicPrompt() {
|
||||
SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_STAGING_ENABLED, true]]});
|
||||
let updateParams = "showPrompt=1&promptWaitTime=0";
|
||||
gUseTestUpdater = true;
|
||||
|
||||
// Open a new window to make sure that it doesn't get in the way
|
||||
// of the notification management.
|
||||
let extraWindow = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
notificationId: "update-available",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-available-whats-new");
|
||||
}
|
||||
},
|
||||
{
|
||||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
*cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
yield BrowserTestUtils.closeWindow(extraWindow);
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
add_task(function* testBasicPromptNoStaging() {
|
||||
SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_STAGING_ENABLED, false]]});
|
||||
|
||||
let updateParams = "showPrompt=1&promptWaitTime=0";
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
notificationId: "update-available",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-available-whats-new");
|
||||
}
|
||||
},
|
||||
{
|
||||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
add_task(function* testCompleteAndPartialPatchesWithBadCompleteSize() {
|
||||
let updateParams = "invalidCompleteSize=1&promptWaitTime=0";
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
add_task(function* testCompleteAndPartialPatchesWithBadPartialSize() {
|
||||
let updateParams = "invalidPartialSize=1&promptWaitTime=0";
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
add_task(function* testCompleteAndPartialPatchesWithBadSizes() {
|
||||
SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2]]});
|
||||
let updateParams = "invalidPartialSize=1&invalidCompleteSize=1";
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
// if we fail maxBackgroundErrors download attempts, then we want to
|
||||
// first show the user an update available prompt.
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
// if we have only an invalid patch, then something's wrong and we don't
|
||||
// have an automatic way to fix it, so show the manual update
|
||||
// doorhanger.
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-manual-whats-new");
|
||||
},
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
add_task(function* testCompletePatchApplyFailure() {
|
||||
let patches = getLocalPatchString("complete", null, null, null, null, null,
|
||||
STATE_PENDING);
|
||||
let updates = getLocalUpdateString(patches, null, null, null,
|
||||
Services.appinfo.version, null);
|
||||
|
||||
yield runUpdateProcessingTest(updates, [
|
||||
{
|
||||
// if we have only an invalid patch, then something's wrong and we don't
|
||||
// have an automatic way to fix it, so show the manual update
|
||||
// doorhanger.
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-manual-whats-new");
|
||||
},
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
add_task(function* testCompletePatchWithBadCompleteSize() {
|
||||
SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2]]});
|
||||
|
||||
let updateParams = "completePatchOnly=1&invalidCompleteSize=1";
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
// if we fail maxBackgroundErrors download attempts, then we want to
|
||||
// first show the user an update available prompt.
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
// if we have only an invalid patch, then something's wrong and we don't
|
||||
// have an automatic way to fix it, so show the manual update
|
||||
// doorhanger.
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-manual-whats-new");
|
||||
},
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
add_task(function* testDownloadFailures() {
|
||||
const maxBackgroundErrors = 5;
|
||||
SpecialPowers.pushPrefEnv({set: [
|
||||
[PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
|
||||
[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2]
|
||||
]});
|
||||
let updateParams = "badURL=1";
|
||||
|
||||
// Open a new window to make sure that our pref management isn't duplicated.
|
||||
let extraWindow = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
// if we fail maxBackgroundErrors download attempts, then we want to
|
||||
// first show the user an update available prompt.
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gMenuButtonUpdateBadge.reset();
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
yield BrowserTestUtils.closeWindow(extraWindow);
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
add_task(function* testMalformedXml() {
|
||||
const updateDetailsUrl = "http://example.com/details";
|
||||
const maxBackgroundErrors = 10;
|
||||
SpecialPowers.pushPrefEnv({set: [
|
||||
[PREF_APP_UPDATE_BACKGROUNDMAXERRORS, maxBackgroundErrors],
|
||||
[PREF_APP_UPDATE_URL_DETAILS, updateDetailsUrl]
|
||||
]});
|
||||
|
||||
let updateParams = "xmlMalformed=1";
|
||||
|
||||
yield runUpdateTest(updateParams, maxBackgroundErrors, [
|
||||
{
|
||||
// if we fail 10 check attempts, then we want to just show the user a manual update
|
||||
// workflow.
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-manual-whats-new", updateDetailsUrl);
|
||||
},
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gMenuButtonUpdateBadge.reset();
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
add_task(function* testPartialPatchApplyFailure() {
|
||||
let patches = getLocalPatchString("partial", null, null, null, null, null,
|
||||
STATE_PENDING);
|
||||
let updates = getLocalUpdateString(patches, null, null, null,
|
||||
Services.appinfo.version, null,
|
||||
null, null, null, null, "false");
|
||||
|
||||
yield runUpdateProcessingTest(updates, [
|
||||
{
|
||||
// if we have only an invalid patch, then something's wrong and we don't
|
||||
// have an automatic way to fix it, so show the manual update
|
||||
// doorhanger.
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-manual-whats-new");
|
||||
},
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
add_task(function* testPartialPatchApplyFailureWithCompleteAvailable() {
|
||||
let patches = getLocalPatchString("partial", null, null, null, null, null,
|
||||
STATE_PENDING) +
|
||||
getLocalPatchString("complete", null, null, null,
|
||||
null, "false");
|
||||
|
||||
let promptWaitTime = "0";
|
||||
let updates = getLocalUpdateString(patches, null, null, null,
|
||||
Services.appinfo.version, null,
|
||||
null, null, null, null, "false",
|
||||
null, null, null, null, promptWaitTime);
|
||||
|
||||
yield runUpdateProcessingTest(updates, [
|
||||
{
|
||||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
add_task(function* testPartialPatchApplyFailureWithCompleteValidationFailure() {
|
||||
// because of the way we're simulating failure, we have to just pretend we've already
|
||||
// retried.
|
||||
SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 0]]});
|
||||
let patches = getLocalPatchString("partial", null, null, null, null, null,
|
||||
STATE_PENDING) +
|
||||
getLocalPatchString("complete", null, "MD5",
|
||||
null, "1234",
|
||||
"false");
|
||||
|
||||
let updates = getLocalUpdateString(patches, null, null, null,
|
||||
Services.appinfo.version, null,
|
||||
null, null, null, null, "false");
|
||||
|
||||
yield runUpdateProcessingTest(updates, [
|
||||
{
|
||||
// if we have only an invalid patch, then something's wrong and we don't
|
||||
// have an automatic way to fix it, so show the manual update
|
||||
// doorhanger.
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-manual-whats-new");
|
||||
},
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
add_task(function* testPartialPatchWithBadPartialSize() {
|
||||
SpecialPowers.pushPrefEnv({set: [[PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS, 2]]});
|
||||
let updateParams = "partialPatchOnly=1&invalidPartialSize=1";
|
||||
|
||||
yield runUpdateTest(updateParams, 1, [
|
||||
{
|
||||
// if we fail maxBackgroundErrors download attempts, then we want to
|
||||
// first show the user an update available prompt.
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
notificationId: "update-available",
|
||||
button: "button"
|
||||
},
|
||||
{
|
||||
// if we have only an invalid patch, then something's wrong and we don't
|
||||
// have an automatic way to fix it, so show the manual update
|
||||
// doorhanger.
|
||||
notificationId: "update-manual",
|
||||
button: "button",
|
||||
beforeClick() {
|
||||
checkWhatsNewLink("update-manual-whats-new");
|
||||
},
|
||||
*cleanup() {
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
},
|
||||
]);
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Download page</title>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<!-- just use simple.mar since we have it available and it will result in a download dialog -->
|
||||
<a id="download-link" href="http://example.com/browser/browser/base/content/test/appUpdate/simple.mar" data-link-type="download">
|
||||
Download
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,360 @@
|
|||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const IS_MACOSX = ("nsILocalFileMac" in Ci);
|
||||
const IS_WIN = ("@mozilla.org/windows-registry-key;1" in Cc);
|
||||
|
||||
const BIN_SUFFIX = (IS_WIN ? ".exe" : "");
|
||||
const FILE_UPDATER_BIN = "updater" + (IS_MACOSX ? ".app" : BIN_SUFFIX);
|
||||
const FILE_UPDATER_BIN_BAK = FILE_UPDATER_BIN + ".bak";
|
||||
|
||||
let gRembemberedPrefs = [];
|
||||
|
||||
const DATA_URI_SPEC = "chrome://mochitests/content/browser/browser/base/content/test/appUpdate/";
|
||||
|
||||
var DEBUG_AUS_TEST = true;
|
||||
var gUseTestUpdater = false;
|
||||
|
||||
const LOG_FUNCTION = info;
|
||||
|
||||
/* import-globals-from testConstants.js */
|
||||
Services.scriptloader.loadSubScript(DATA_URI_SPEC + "testConstants.js", this);
|
||||
/* import-globals-from ../../../../../toolkit/mozapps/update/tests/data/shared.js */
|
||||
Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this);
|
||||
|
||||
var gURLData = URL_HOST + "/" + REL_PATH_DATA;
|
||||
const URL_MANUAL_UPDATE = gURLData + "downloadPage.html";
|
||||
|
||||
const NOTIFICATIONS = [
|
||||
"update-available",
|
||||
"update-manual",
|
||||
"update-restart"
|
||||
];
|
||||
|
||||
/**
|
||||
* Delay for a very short period. Useful for moving the code after this
|
||||
* to the back of the event loop.
|
||||
*
|
||||
* @return A promise which will resolve after a very short period.
|
||||
*/
|
||||
function delay() {
|
||||
return new Promise(resolve => executeSoon(resolve));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the update version info for the update url parameters to send to
|
||||
* update.sjs.
|
||||
*
|
||||
* @param aAppVersion (optional)
|
||||
* The application version for the update snippet. If not specified the
|
||||
* current application version will be used.
|
||||
* @return The url parameters for the application and platform version to send
|
||||
* to update.sjs.
|
||||
*/
|
||||
function getVersionParams(aAppVersion) {
|
||||
let appInfo = Services.appinfo;
|
||||
return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up updates list and the updates directory.
|
||||
*/
|
||||
function cleanUpUpdates() {
|
||||
gUpdateManager.activeUpdate = null;
|
||||
gUpdateManager.saveUpdates();
|
||||
|
||||
removeUpdateDirsAndFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a typical update test. Will set various common prefs for using the
|
||||
* updater doorhanger, runs the provided list of steps, and makes sure
|
||||
* everything is cleaned up afterwards.
|
||||
*
|
||||
* @param updateParams
|
||||
* URL-encoded params which will be sent to update.sjs.
|
||||
* @param checkAttempts
|
||||
* How many times to check for updates. Useful for testing the UI
|
||||
* for check failures.
|
||||
* @param steps
|
||||
* A list of test steps to perform, specifying expected doorhangers
|
||||
* and additional validation/cleanup callbacks.
|
||||
* @return A promise which will resolve once all of the steps have been run
|
||||
* and cleanup has been performed.
|
||||
*/
|
||||
function runUpdateTest(updateParams, checkAttempts, steps) {
|
||||
return Task.spawn(function*() {
|
||||
registerCleanupFunction(() => {
|
||||
gMenuButtonUpdateBadge.uninit();
|
||||
gMenuButtonUpdateBadge.init();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
yield SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
|
||||
[PREF_APP_UPDATE_ENABLED, true],
|
||||
[PREF_APP_UPDATE_IDLETIME, 0],
|
||||
[PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
|
||||
[PREF_APP_UPDATE_LOG, DEBUG_AUS_TEST],
|
||||
]});
|
||||
|
||||
yield setupTestUpdater();
|
||||
|
||||
let url = URL_HTTP_UPDATE_SJS +
|
||||
"?" + updateParams +
|
||||
getVersionParams();
|
||||
|
||||
setUpdateURL(url);
|
||||
|
||||
executeSoon(() => {
|
||||
Task.spawn(function*() {
|
||||
gAUS.checkForBackgroundUpdates();
|
||||
for (var i = 0; i < checkAttempts - 1; i++) {
|
||||
yield waitForEvent("update-error", "check-attempt-failed");
|
||||
gAUS.checkForBackgroundUpdates();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
for (let step of steps) {
|
||||
yield processStep(step);
|
||||
}
|
||||
|
||||
yield finishTestRestoreUpdaterBackup();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a test which processes an update. Similar to runUpdateTest.
|
||||
*
|
||||
* @param updates
|
||||
* A list of updates to process.
|
||||
* @param steps
|
||||
* A list of test steps to perform, specifying expected doorhangers
|
||||
* and additional validation/cleanup callbacks.
|
||||
* @return A promise which will resolve once all of the steps have been run
|
||||
* and cleanup has been performed.
|
||||
*/
|
||||
function runUpdateProcessingTest(updates, steps) {
|
||||
return Task.spawn(function*() {
|
||||
registerCleanupFunction(() => {
|
||||
gMenuButtonUpdateBadge.reset();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS, 0],
|
||||
[PREF_APP_UPDATE_ENABLED, true],
|
||||
[PREF_APP_UPDATE_IDLETIME, 0],
|
||||
[PREF_APP_UPDATE_URL_MANUAL, URL_MANUAL_UPDATE],
|
||||
[PREF_APP_UPDATE_LOG, DEBUG_AUS_TEST],
|
||||
]});
|
||||
|
||||
yield setupTestUpdater();
|
||||
|
||||
writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
|
||||
|
||||
writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
|
||||
writeStatusFile(STATE_FAILED_CRC_ERROR);
|
||||
reloadUpdateManagerData();
|
||||
|
||||
testPostUpdateProcessing();
|
||||
|
||||
for (let step of steps) {
|
||||
yield processStep(step);
|
||||
}
|
||||
|
||||
yield finishTestRestoreUpdaterBackup();
|
||||
});
|
||||
}
|
||||
|
||||
function processStep({notificationId, button, beforeClick, cleanup}) {
|
||||
return Task.spawn(function*() {
|
||||
|
||||
yield BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popupshown");
|
||||
const shownNotification = PanelUI.activeNotification.id;
|
||||
|
||||
is(shownNotification, notificationId, "The right notification showed up.");
|
||||
if (shownNotification != notificationId) {
|
||||
if (cleanup) {
|
||||
yield cleanup();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let notification = document.getElementById(`PanelUI-${notificationId}-notification`);
|
||||
is(notification.hidden, false, `${notificationId} notification is showing`);
|
||||
if (beforeClick) {
|
||||
yield Task.spawn(beforeClick);
|
||||
}
|
||||
|
||||
let buttonEl = document.getAnonymousElementByAttribute(notification, "anonid", button);
|
||||
|
||||
buttonEl.click();
|
||||
|
||||
if (cleanup) {
|
||||
yield cleanup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the specified topic and (optionally) status.
|
||||
* @param topic
|
||||
* String representing the topic to wait for.
|
||||
* @param status
|
||||
* Optional String representing the status on said topic to wait for.
|
||||
* @return A promise which will resolve the first time an event occurs on the
|
||||
* specified topic, and (optionally) with the specified status.
|
||||
*/
|
||||
function waitForEvent(topic, status = null) {
|
||||
return new Promise(resolve => Services.obs.addObserver({
|
||||
observe(subject, innerTopic, innerStatus) {
|
||||
if (!status || status == innerStatus) {
|
||||
Services.obs.removeObserver(this, topic);
|
||||
resolve(innerStatus);
|
||||
}
|
||||
}
|
||||
}, topic, false))
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the "What's new" link with the provided ID is displayed and
|
||||
* matches the url parameter provided. If no URL is provided, it will instead
|
||||
* ensure that the link matches the default link URL.
|
||||
*
|
||||
* @param id
|
||||
* The ID of the "What's new" link element.
|
||||
* @param url (optional)
|
||||
* The URL to check against. If none is provided, a default will be used.
|
||||
*/
|
||||
function checkWhatsNewLink(id, url) {
|
||||
let whatsNewLink = document.getElementById(id);
|
||||
is(whatsNewLink.href,
|
||||
url || URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS",
|
||||
"What's new link points to the test_details URL");
|
||||
is(whatsNewLink.hidden, false, "What's new link is not hidden.");
|
||||
}
|
||||
|
||||
/**
|
||||
* For tests that use the test updater restores the backed up real updater if
|
||||
* it exists and tries again on failure since Windows debug builds at times
|
||||
* leave the file in use. After success moveRealUpdater is called to continue
|
||||
* the setup of the test updater. For tests that don't use the test updater
|
||||
* runTest will be called.
|
||||
*/
|
||||
function setupTestUpdater() {
|
||||
return Task.spawn(function*() {
|
||||
if (gUseTestUpdater) {
|
||||
try {
|
||||
restoreUpdaterBackup();
|
||||
} catch (e) {
|
||||
logTestInfo("Attempt to restore the backed up updater failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
yield delay();
|
||||
yield setupTestUpdater();
|
||||
return;
|
||||
}
|
||||
yield moveRealUpdater();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Backs up the real updater and tries again on failure since Windows debug
|
||||
* builds at times leave the file in use. After success it will call
|
||||
* copyTestUpdater to continue the setup of the test updater.
|
||||
*/
|
||||
function moveRealUpdater() {
|
||||
return Task.spawn(function*() {
|
||||
try {
|
||||
// Move away the real updater
|
||||
let baseAppDir = getAppBaseDir();
|
||||
let updater = baseAppDir.clone();
|
||||
updater.append(FILE_UPDATER_BIN);
|
||||
updater.moveTo(baseAppDir, FILE_UPDATER_BIN_BAK);
|
||||
} catch (e) {
|
||||
logTestInfo("Attempt to move the real updater out of the way failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
yield delay();
|
||||
yield moveRealUpdater();
|
||||
return;
|
||||
}
|
||||
|
||||
yield copyTestUpdater();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the test updater so it can be used by tests and tries again on failure
|
||||
* since Windows debug builds at times leave the file in use. After success it
|
||||
* will call runTest to continue the test.
|
||||
*/
|
||||
function copyTestUpdater() {
|
||||
return Task.spawn(function*() {
|
||||
try {
|
||||
// Copy the test updater
|
||||
let baseAppDir = getAppBaseDir();
|
||||
let testUpdaterDir = Services.dirsvc.get("CurWorkD", Ci.nsILocalFile);
|
||||
let relPath = REL_PATH_DATA;
|
||||
let pathParts = relPath.split("/");
|
||||
for (let i = 0; i < pathParts.length; ++i) {
|
||||
testUpdaterDir.append(pathParts[i]);
|
||||
}
|
||||
|
||||
let testUpdater = testUpdaterDir.clone();
|
||||
testUpdater.append(FILE_UPDATER_BIN);
|
||||
testUpdater.copyToFollowingLinks(baseAppDir, FILE_UPDATER_BIN);
|
||||
} catch (e) {
|
||||
logTestInfo("Attempt to copy the test updater failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
yield delay();
|
||||
yield copyTestUpdater();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the updater that was backed up. This is called in setupTestUpdater
|
||||
* before the backup of the real updater is done in case the previous test
|
||||
* failed to restore the updater, in finishTestDefaultWaitForWindowClosed when
|
||||
* the test has finished, and in test_9999_cleanup.xul after all tests have
|
||||
* finished.
|
||||
*/
|
||||
function restoreUpdaterBackup() {
|
||||
let baseAppDir = getAppBaseDir();
|
||||
let updater = baseAppDir.clone();
|
||||
let updaterBackup = baseAppDir.clone();
|
||||
updater.append(FILE_UPDATER_BIN);
|
||||
updaterBackup.append(FILE_UPDATER_BIN_BAK);
|
||||
if (updaterBackup.exists()) {
|
||||
if (updater.exists()) {
|
||||
updater.remove(true);
|
||||
}
|
||||
updaterBackup.moveTo(baseAppDir, FILE_UPDATER_BIN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a test finishes this will repeatedly attempt to restore the real updater
|
||||
* for tests that use the test updater and then call
|
||||
* finishTestDefaultWaitForWindowClosed after the restore is successful.
|
||||
*/
|
||||
function finishTestRestoreUpdaterBackup() {
|
||||
return Task.spawn(function*() {
|
||||
if (gUseTestUpdater) {
|
||||
try {
|
||||
// Windows debug builds keep the updater file in use for a short period of
|
||||
// time after the updater process exits.
|
||||
restoreUpdaterBackup();
|
||||
} catch (e) {
|
||||
logTestInfo("Attempt to restore the backed up updater failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
|
||||
yield delay();
|
||||
yield finishTestRestoreUpdaterBackup();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
const REL_PATH_DATA = "browser/browser/base/content/test/appUpdate/";
|
||||
const URL_HOST = "http://example.com";
|
||||
const URL_PATH_UPDATE_XML = "/" + REL_PATH_DATA + "update.sjs";
|
||||
const URL_HTTP_UPDATE_SJS = URL_HOST + URL_PATH_UPDATE_XML;
|
|
@ -638,7 +638,6 @@ tags = psm
|
|||
[browser_domFullscreen_fullscreenMode.js]
|
||||
tags = fullscreen
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_menuButtonBadgeManager.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_newTabDrop.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
|
|
|
@ -1,46 +0,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/. */
|
||||
|
||||
var menuButton = document.getElementById("PanelUI-menu-button");
|
||||
|
||||
add_task(function* testButtonActivities() {
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
is(menuButton.hasAttribute("badge"), false, "Should not have the badge attribute set");
|
||||
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_FXA, "fxa-needs-authentication");
|
||||
is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
|
||||
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_APPUPDATE, "update-succeeded");
|
||||
is(menuButton.getAttribute("badge-status"), "update-succeeded", "Should have update-succeeded badge status (update > fxa)");
|
||||
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_APPUPDATE, "update-failed");
|
||||
is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
|
||||
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_DOWNLOAD, "download-severe");
|
||||
is(menuButton.getAttribute("badge-status"), "download-severe", "Should have download-severe badge status");
|
||||
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_DOWNLOAD, "download-warning");
|
||||
is(menuButton.getAttribute("badge-status"), "download-warning", "Should have download-warning badge status");
|
||||
|
||||
gMenuButtonBadgeManager.addBadge("unknownbadge", "attr");
|
||||
is(menuButton.getAttribute("badge-status"), "download-warning", "Should not have changed badge status");
|
||||
|
||||
gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_DOWNLOAD);
|
||||
is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
|
||||
|
||||
gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_APPUPDATE);
|
||||
is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
|
||||
|
||||
gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_FXA);
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
|
||||
yield PanelUI.show();
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status (Hamburger menu opened)");
|
||||
PanelUI.hide();
|
||||
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_FXA, "fxa-needs-authentication");
|
||||
gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_APPUPDATE, "update-succeeded");
|
||||
gMenuButtonBadgeManager.clearBadges();
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status (clearBadges called)");
|
||||
});
|
|
@ -4,10 +4,6 @@
|
|||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
const permissionError = "error: NotAllowedError: The request is not allowed " +
|
||||
"by the user agent or the platform in the current context.";
|
||||
|
||||
|
@ -579,39 +575,6 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
|
||||
// Cleanup before the next test
|
||||
yield expectNoObserverCalled();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests);
|
||||
});
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
var gTests = [
|
||||
|
||||
{
|
||||
|
@ -76,34 +72,6 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests);
|
||||
});
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
var gTests = [
|
||||
|
||||
{
|
||||
|
@ -216,38 +212,6 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
|
||||
// Cleanup before the next test
|
||||
yield expectNoObserverCalled();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
let url = rootDir + "get_user_media.html";
|
||||
content.location = 'data:text/html,<iframe id="frame1" src="' + url + '"></iframe><iframe id="frame2" src="' + url + '"></iframe>'
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests, { relativeURI: "get_user_media_in_frame.html" });
|
||||
});
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
var gTests = [
|
||||
|
||||
{
|
||||
|
@ -118,36 +114,6 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests);
|
||||
});
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
const permissionError = "error: NotAllowedError: The request is not allowed " +
|
||||
"by the user agent or the platform in the current context.";
|
||||
|
||||
|
@ -577,39 +573,6 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
|
||||
// Cleanup before the next test
|
||||
yield expectNoObserverCalled();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests);
|
||||
});
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
var gTests = [
|
||||
|
||||
{
|
||||
|
@ -62,46 +58,12 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 1]]}, runTest);
|
||||
}
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 1]]});
|
||||
|
||||
function runTest() {
|
||||
// An empty tab where we can load the content script without leaving it
|
||||
// behind at the end of the test.
|
||||
gBrowser.addTab();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
|
||||
// Cleanup before the next test
|
||||
yield expectNoObserverCalled();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
await runTests(gTests);
|
||||
});
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
const permissionError = "error: NotAllowedError: The request is not allowed " +
|
||||
"by the user agent or the platform in the current context.";
|
||||
|
||||
|
@ -251,39 +247,6 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
|
||||
// Cleanup before the next test
|
||||
yield expectNoObserverCalled();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests);
|
||||
});
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
const permissionError = "error: NotAllowedError: The request is not allowed " +
|
||||
"by the user agent or the platform in the current context.";
|
||||
|
||||
|
@ -210,37 +206,6 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
|
||||
// Cleanup before the next test
|
||||
yield expectNoObserverCalled();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media_in_frame.html";
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests, { relativeURI: "get_user_media_in_frame.html" });
|
||||
});
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
var gTests = [
|
||||
|
||||
{
|
||||
|
@ -56,46 +52,12 @@ var gTests = [
|
|||
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 1]]}, runTest);
|
||||
}
|
||||
add_task(async function test() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 1]]});
|
||||
|
||||
function runTest() {
|
||||
// An empty tab where we can load the content script without leaving it
|
||||
// behind at the end of the test.
|
||||
gBrowser.addTab();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run();
|
||||
|
||||
// Cleanup before the next test
|
||||
yield expectNoObserverCalled();
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
await runTests(gTests);
|
||||
});
|
||||
|
|
|
@ -6,10 +6,6 @@ Cu.import("resource:///modules/webrtcUI.jsm");
|
|||
|
||||
const ORIGIN = "https://example.com";
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function* tryPeerConnection(browser, expectedError = null) {
|
||||
let errtype = yield ContentTask.spawn(browser, null, function*() {
|
||||
let pc = new content.RTCPeerConnection();
|
||||
|
@ -326,36 +322,11 @@ var gTests = [
|
|||
},
|
||||
];
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.addEventListener("load", function() {
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
Task.spawn(function* () {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of gTests) {
|
||||
info(testCase.desc);
|
||||
yield testCase.run(browser);
|
||||
|
||||
// Make sure the test cleaned up after itself.
|
||||
is(webrtcUI.peerConnectionBlockers.size, 0, "Peer connection blockers list is empty");
|
||||
}
|
||||
}).then(finish, ex => {
|
||||
Cu.reportError(ex);
|
||||
ok(false, "Unexpected Exception: " + ex);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content", ORIGIN);
|
||||
content.location = rootDir + "get_user_media.html";
|
||||
}
|
||||
add_task(async function test() {
|
||||
await runTests(gTests,
|
||||
{ cleanup() {
|
||||
is(webrtcUI.peerConnectionBlockers.size, 0,
|
||||
"Peer connection blockers list is empty");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -520,3 +520,34 @@ function promiseReloadFrame(aFrameId) {
|
|||
.reload();
|
||||
});
|
||||
}
|
||||
|
||||
async function runTests(tests, options = {}) {
|
||||
let leaf = options.relativeURI || "get_user_media.html";
|
||||
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
rootDir = rootDir.replace("chrome://mochitests/content/",
|
||||
"https://example.com/");
|
||||
let absoluteURI = rootDir + leaf;
|
||||
let cleanup = options.cleanup || (() => expectNoObserverCalled());
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, absoluteURI);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
|
||||
|
||||
is(PopupNotifications._currentNotifications.length, 0,
|
||||
"should start the test without any prior popup notification");
|
||||
ok(gIdentityHandler._identityPopup.hidden,
|
||||
"should start the test with the control center hidden");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
|
||||
|
||||
for (let testCase of tests) {
|
||||
info(testCase.desc);
|
||||
await Task.spawn(testCase.run(browser));
|
||||
await cleanup();
|
||||
}
|
||||
|
||||
// Some tests destroy the original tab and leave a new one in its place.
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
'content/test/webrtc/browser.ini',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_UPDATER']:
|
||||
BROWSER_CHROME_MANIFESTS += ['content/test/appUpdate/browser.ini']
|
||||
|
||||
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
|
||||
DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
|
||||
|
||||
|
@ -51,4 +54,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
|
|||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
|
||||
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
|
||||
|
||||
TEST_HARNESS_FILES.testing.mochitest.browser.browser.base.content.test.appUpdate += [
|
||||
'/toolkit/mozapps/update/tests/chrome/update.sjs',
|
||||
'/toolkit/mozapps/update/tests/data/shared.js',
|
||||
'/toolkit/mozapps/update/tests/data/sharedUpdateXML.js',
|
||||
'/toolkit/mozapps/update/tests/data/simple.mar',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
|
|
@ -26,8 +26,8 @@ pref("app.update.url.details", "https://www.mozilla.org/%LOCALE%/firefox/notes")
|
|||
pref("app.update.checkInstallTime.days", 63);
|
||||
|
||||
// Give the user x seconds to reboot before showing a badge on the hamburger
|
||||
// button. default=immediately
|
||||
pref("app.update.badgeWaitTime", 0);
|
||||
// button. default=4 days
|
||||
pref("app.update.badgeWaitTime", 345600);
|
||||
|
||||
// Number of usages of the web console or scratchpad.
|
||||
// If this is less than 5, then pasting code into the web console or scratchpad is disabled
|
||||
|
|
|
@ -17,9 +17,17 @@
|
|||
|
||||
<footer id="PanelUI-footer">
|
||||
<vbox id="PanelUI-footer-addons"></vbox>
|
||||
<toolbarbutton id="PanelUI-update-status"
|
||||
oncommand="gMenuButtonUpdateBadge.onMenuPanelCommand(event);"
|
||||
<toolbarbutton id="PanelUI-update-available-menu-item"
|
||||
wrap="true"
|
||||
label="&updateAvailable.panelUI.label;"
|
||||
hidden="true"/>
|
||||
<toolbarbutton id="PanelUI-update-manual-menu-item"
|
||||
wrap="true"
|
||||
label="&updateManual.panelUI.label;"
|
||||
hidden="true"/>
|
||||
<toolbarbutton id="PanelUI-update-restart-menu-item"
|
||||
wrap="true"
|
||||
label="&updateRestart.panelUI.label;"
|
||||
hidden="true"/>
|
||||
<hbox id="PanelUI-footer-fxa">
|
||||
<hbox id="PanelUI-fxa-status"
|
||||
|
@ -414,3 +422,66 @@
|
|||
id="panic-button-success-closebutton"
|
||||
oncommand="PanicButtonNotifier.close()"/>
|
||||
</panel>
|
||||
|
||||
<panel id="PanelUI-notification-popup"
|
||||
class="popup-notification-panel"
|
||||
type="arrow"
|
||||
position="after_start"
|
||||
hidden="true"
|
||||
orient="vertical"
|
||||
noautofocus="true"
|
||||
noautohide="true"
|
||||
nopreventnavboxhide="true"
|
||||
role="alert">
|
||||
<popupnotification id="PanelUI-update-available-notification"
|
||||
popupid="update-available"
|
||||
label="&updateAvailable.header.message;"
|
||||
buttonlabel="&updateAvailable.acceptButton.label;"
|
||||
buttonaccesskey="&updateAvailable.acceptButton.accesskey;"
|
||||
closebuttonhidden="true"
|
||||
secondarybuttonlabel="&updateAvailable.cancelButton.label;"
|
||||
secondarybuttonaccesskey="&updateAvailable.cancelButton.accesskey;"
|
||||
dropmarkerhidden="true"
|
||||
checkboxhidden="true"
|
||||
hidden="true">
|
||||
<popupnotificationcontent id="update-available-notification-content" orient="vertical">
|
||||
<description id="update-available-description">&updateAvailable.message;
|
||||
<label id="update-available-whats-new" class="text-link" value="&updateAvailable.whatsnew.label;" />
|
||||
</description>
|
||||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
<popupnotification id="PanelUI-update-manual-notification"
|
||||
popupid="update-manual"
|
||||
label="&updateManual.header.message;"
|
||||
buttonlabel="&updateManual.acceptButton.label;"
|
||||
buttonaccesskey="&updateManual.acceptButton.accesskey;"
|
||||
closebuttonhidden="true"
|
||||
secondarybuttonlabel="&updateManual.cancelButton.label;"
|
||||
secondarybuttonaccesskey="&updateManual.cancelButton.accesskey;"
|
||||
dropmarkerhidden="true"
|
||||
checkboxhidden="true"
|
||||
hidden="true">
|
||||
<popupnotificationcontent id="update-manual-notification-content" orient="vertical">
|
||||
<description id="update-manual-description">&updateManual.message;
|
||||
<label id="update-manual-whats-new" class="text-link" value="&updateManual.whatsnew.label;" />
|
||||
</description>
|
||||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
<popupnotification id="PanelUI-update-restart-notification"
|
||||
popupid="update-restart"
|
||||
label="&updateRestart.header.message;"
|
||||
buttonlabel="&updateRestart.acceptButton.label;"
|
||||
buttonaccesskey="&updateRestart.acceptButton.accesskey;"
|
||||
closebuttonhidden="true"
|
||||
secondarybuttonlabel="&updateRestart.cancelButton.label;"
|
||||
secondarybuttonaccesskey="&updateRestart.cancelButton.accesskey;"
|
||||
dropmarkerhidden="true"
|
||||
checkboxhidden="true"
|
||||
hidden="true">
|
||||
<popupnotificationcontent id="update-restart-notification-content" orient="vertical">
|
||||
<description id="update-restart-description">&updateRestart.message;</description>
|
||||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
</panel>
|
||||
|
|
|
@ -32,7 +32,9 @@ const PanelUI = {
|
|||
helpView: "PanelUI-helpView",
|
||||
menuButton: "PanelUI-menu-button",
|
||||
panel: "PanelUI-popup",
|
||||
scroller: "PanelUI-contents-scroller"
|
||||
notificationPanel: "PanelUI-notification-popup",
|
||||
scroller: "PanelUI-contents-scroller",
|
||||
footer: "PanelUI-footer"
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -48,11 +50,23 @@ const PanelUI = {
|
|||
});
|
||||
}
|
||||
|
||||
this.notifications = [];
|
||||
this.menuButton.addEventListener("mousedown", this);
|
||||
this.menuButton.addEventListener("keypress", this);
|
||||
this._overlayScrollListenerBoundFn = this._overlayScrollListener.bind(this);
|
||||
|
||||
Services.obs.addObserver(this, "fullscreen-nav-toolbox", false);
|
||||
Services.obs.addObserver(this, "panelUI-notification-main-action", false);
|
||||
Services.obs.addObserver(this, "panelUI-notification-dismissed", false);
|
||||
|
||||
window.addEventListener("fullscreen", this);
|
||||
window.matchMedia("(-moz-overlay-scrollbars)").addListener(this._overlayScrollListenerBoundFn);
|
||||
CustomizableUI.addListener(this);
|
||||
|
||||
for (let event of this.kEvents) {
|
||||
this.notificationPanel.addEventListener(event, this);
|
||||
}
|
||||
|
||||
this._initialized = true;
|
||||
},
|
||||
|
||||
|
@ -75,7 +89,14 @@ const PanelUI = {
|
|||
uninit() {
|
||||
for (let event of this.kEvents) {
|
||||
this.panel.removeEventListener(event, this);
|
||||
this.notificationPanel.removeEventListener(event, this);
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, "fullscreen-nav-toolbox");
|
||||
Services.obs.removeObserver(this, "panelUI-notification-main-action");
|
||||
Services.obs.removeObserver(this, "panelUI-notification-dismissed");
|
||||
|
||||
window.removeEventListener("fullscreen", this);
|
||||
this.helpView.removeEventListener("ViewShowing", this._onHelpViewShow);
|
||||
this.menuButton.removeEventListener("mousedown", this);
|
||||
this.menuButton.removeEventListener("keypress", this);
|
||||
|
@ -156,16 +177,70 @@ const PanelUI = {
|
|||
resolve();
|
||||
}, {once: true});
|
||||
|
||||
let iconAnchor =
|
||||
document.getAnonymousElementByAttribute(anchor, "class",
|
||||
"toolbarbutton-icon");
|
||||
this.panel.openPopup(iconAnchor || anchor);
|
||||
anchor = this._getPanelAnchor(anchor);
|
||||
this.panel.openPopup(anchor);
|
||||
}, (reason) => {
|
||||
console.error("Error showing the PanelUI menu", reason);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
showNotification(id, mainAction, secondaryActions = [], options = {}) {
|
||||
let notification = new PanelUINotification(id, mainAction, secondaryActions, options);
|
||||
let existingIndex = this.notifications.findIndex(n => n.id == id);
|
||||
if (existingIndex != -1) {
|
||||
this.notifications.splice(existingIndex, 1);
|
||||
}
|
||||
|
||||
// We don't want to clobber doorhanger notifications just to show a badge,
|
||||
// so don't dismiss any of them and the badge will show once the doorhanger
|
||||
// gets resolved.
|
||||
if (!options.badgeOnly && !options.dismissed) {
|
||||
this.notifications.forEach(n => { n.dismissed = true; });
|
||||
}
|
||||
|
||||
// Since notifications are generally somewhat pressing, the ideal case is that
|
||||
// we never have two notifications at once. However, in the event that we do,
|
||||
// it's more likely that the older notification has been sitting around for a
|
||||
// bit, and so we don't want to hide the new notification behind it. Thus,
|
||||
// we want our notifications to behave like a stack instead of a queue.
|
||||
this.notifications.unshift(notification);
|
||||
this._updateNotifications();
|
||||
return notification;
|
||||
},
|
||||
|
||||
showBadgeOnlyNotification(id) {
|
||||
return this.showNotification(id, null, null, { badgeOnly: true });
|
||||
},
|
||||
|
||||
removeNotification(id) {
|
||||
let notifications;
|
||||
if (typeof id == "string") {
|
||||
notifications = this.notifications.filter(n => n.id == id);
|
||||
} else {
|
||||
// If it's not a string, assume RegExp
|
||||
notifications = this.notifications.filter(n => id.test(n.id));
|
||||
}
|
||||
|
||||
notifications.forEach(n => {
|
||||
this._removeNotification(n);
|
||||
});
|
||||
this._updateNotifications();
|
||||
},
|
||||
|
||||
dismissNotification(id) {
|
||||
let notifications;
|
||||
if (typeof id == "string") {
|
||||
notifications = this.notifications.filter(n => n.id == id);
|
||||
} else {
|
||||
// If it's not a string, assume RegExp
|
||||
notifications = this.notifications.filter(n => id.test(n.id));
|
||||
}
|
||||
|
||||
notifications.forEach(n => n.dismissed = true);
|
||||
this._updateNotifications();
|
||||
},
|
||||
|
||||
/**
|
||||
* If the menu panel is being shown, hide it.
|
||||
*/
|
||||
|
@ -177,6 +252,24 @@ const PanelUI = {
|
|||
this.panel.hidePopup();
|
||||
},
|
||||
|
||||
observe(subject, topic, status) {
|
||||
switch (topic) {
|
||||
case "fullscreen-nav-toolbox":
|
||||
this._updateNotifications();
|
||||
break;
|
||||
case "panelUI-notification-main-action":
|
||||
if (subject != window) {
|
||||
this.removeNotification(status);
|
||||
}
|
||||
break;
|
||||
case "panelUI-notification-dismissed":
|
||||
if (subject != window) {
|
||||
this.dismissNotification(status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent(aEvent) {
|
||||
// Ignore context menus and menu button menus showing and hiding:
|
||||
if (aEvent.type.startsWith("popup") &&
|
||||
|
@ -192,6 +285,7 @@ const PanelUI = {
|
|||
case "popuphiding":
|
||||
// Fall through
|
||||
case "popuphidden":
|
||||
this._updateNotifications();
|
||||
this._updatePanelButton(aEvent.target);
|
||||
break;
|
||||
case "mousedown":
|
||||
|
@ -201,6 +295,9 @@ const PanelUI = {
|
|||
case "keypress":
|
||||
this.toggle(aEvent);
|
||||
break;
|
||||
case "fullscreen":
|
||||
this._updateNotifications();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -208,6 +305,22 @@ const PanelUI = {
|
|||
return !!this._isReady;
|
||||
},
|
||||
|
||||
get isNotificationPanelOpen() {
|
||||
let panelState = this.notificationPanel.state;
|
||||
|
||||
return panelState == "showing" || panelState == "open";
|
||||
},
|
||||
|
||||
get activeNotification() {
|
||||
if (this.notifications.length > 0) {
|
||||
const doorhanger =
|
||||
this.notifications.find(n => !n.dismissed && !n.options.badgeOnly);
|
||||
return doorhanger || this.notifications[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Registering the menu panel is done lazily for performance reasons. This
|
||||
* method is exposed so that CustomizationMode can force panel-readyness in the
|
||||
|
@ -393,14 +506,13 @@ const PanelUI = {
|
|||
CustomizableUI.addPanelCloseListeners(tempPanel);
|
||||
tempPanel.addEventListener("popuphidden", panelRemover);
|
||||
|
||||
let iconAnchor =
|
||||
document.getAnonymousElementByAttribute(aAnchor, "class",
|
||||
"toolbarbutton-icon");
|
||||
let anchor = this._getPanelAnchor(aAnchor);
|
||||
|
||||
if (iconAnchor && aAnchor.id) {
|
||||
iconAnchor.setAttribute("consumeanchor", aAnchor.id);
|
||||
if (aAnchor != anchor && aAnchor.id) {
|
||||
anchor.setAttribute("consumeanchor", aAnchor.id);
|
||||
}
|
||||
tempPanel.openPopup(iconAnchor || aAnchor, "bottomcenter topright");
|
||||
|
||||
tempPanel.openPopup(anchor, "bottomcenter topright");
|
||||
}
|
||||
}),
|
||||
|
||||
|
@ -538,6 +650,212 @@ const PanelUI = {
|
|||
ScrollbarSampler.resetSystemScrollbarWidth();
|
||||
this._scrollWidth = null;
|
||||
},
|
||||
|
||||
_hidePopup() {
|
||||
if (this.isNotificationPanelOpen) {
|
||||
this.notificationPanel.hidePopup();
|
||||
}
|
||||
},
|
||||
|
||||
_updateNotifications() {
|
||||
if (!this.notifications.length) {
|
||||
this._clearAllNotifications();
|
||||
this._hidePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.fullScreen && FullScreen.navToolboxHidden) {
|
||||
this._hidePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
let doorhangers =
|
||||
this.notifications.filter(n => !n.dismissed && !n.options.badgeOnly);
|
||||
|
||||
if (this.panel.state == "showing" || this.panel.state == "open") {
|
||||
// If the menu is already showing, then we need to dismiss all notifications
|
||||
// since we don't want their doorhangers competing for attention
|
||||
doorhangers.forEach(n => { n.dismissed = true; })
|
||||
this._hidePopup();
|
||||
this._clearBadge();
|
||||
if (!this.notifications[0].options.badgeOnly) {
|
||||
this._showMenuItem(this.notifications[0]);
|
||||
}
|
||||
} else if (doorhangers.length > 0) {
|
||||
this._clearBadge();
|
||||
this._showNotificationPanel(doorhangers[0]);
|
||||
} else {
|
||||
this._hidePopup();
|
||||
this._showBadge(this.notifications[0]);
|
||||
this._showMenuItem(this.notifications[0]);
|
||||
}
|
||||
},
|
||||
|
||||
_showNotificationPanel(notification) {
|
||||
this._refreshNotificationPanel(notification);
|
||||
|
||||
if (this.isNotificationPanelOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
let anchor = this._getPanelAnchor(this.menuButton);
|
||||
|
||||
this.notificationPanel.hidden = false;
|
||||
this.notificationPanel.openPopup(anchor, "bottomcenter topright");
|
||||
},
|
||||
|
||||
_clearNotificationPanel() {
|
||||
for (let popupnotification of this.notificationPanel.children) {
|
||||
popupnotification.hidden = true;
|
||||
popupnotification.notification = null;
|
||||
}
|
||||
},
|
||||
|
||||
_clearAllNotifications() {
|
||||
this._clearNotificationPanel();
|
||||
this._clearBadge();
|
||||
this._clearMenuItems();
|
||||
},
|
||||
|
||||
_refreshNotificationPanel(notification) {
|
||||
this._clearNotificationPanel();
|
||||
|
||||
let popupnotificationID = this._getPopupId(notification);
|
||||
let popupnotification = document.getElementById(popupnotificationID);
|
||||
|
||||
popupnotification.setAttribute("id", popupnotificationID);
|
||||
popupnotification.setAttribute("buttoncommand", "PanelUI._onNotificationButtonEvent(event, 'buttoncommand');");
|
||||
popupnotification.setAttribute("secondarybuttoncommand", "PanelUI._onNotificationButtonEvent(event, 'secondarybuttoncommand');");
|
||||
|
||||
popupnotification.notification = notification;
|
||||
popupnotification.hidden = false;
|
||||
},
|
||||
|
||||
_showBadge(notification) {
|
||||
let badgeStatus = this._getBadgeStatus(notification);
|
||||
this.menuButton.setAttribute("badge-status", badgeStatus);
|
||||
},
|
||||
|
||||
// "Menu item" here refers to an item in the hamburger panel menu. They will
|
||||
// typically show up as a colored row near the bottom of the panel.
|
||||
_showMenuItem(notification) {
|
||||
this._clearMenuItems();
|
||||
|
||||
let menuItemId = this._getMenuItemId(notification);
|
||||
let menuItem = document.getElementById(menuItemId);
|
||||
if (menuItem) {
|
||||
menuItem.notification = notification;
|
||||
menuItem.setAttribute("oncommand", "PanelUI._onNotificationMenuItemSelected(event)");
|
||||
menuItem.classList.add("PanelUI-notification-menu-item");
|
||||
menuItem.hidden = false;
|
||||
menuItem.fromPanelUINotifications = true;
|
||||
}
|
||||
},
|
||||
|
||||
_clearBadge() {
|
||||
this.menuButton.removeAttribute("badge-status");
|
||||
},
|
||||
|
||||
_clearMenuItems() {
|
||||
for (let child of this.footer.children) {
|
||||
if (child.fromPanelUINotifications) {
|
||||
child.notification = null;
|
||||
child.hidden = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_removeNotification(notification) {
|
||||
// This notification may already be removed, in which case let's just fail
|
||||
// silently.
|
||||
let notifications = this.notifications;
|
||||
if (!notifications)
|
||||
return;
|
||||
|
||||
var index = notifications.indexOf(notification);
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
// Remove the notification
|
||||
notifications.splice(index, 1);
|
||||
},
|
||||
|
||||
_onNotificationButtonEvent(event, type) {
|
||||
let notificationEl = getNotificationFromElement(event.originalTarget);
|
||||
|
||||
if (!notificationEl)
|
||||
throw "PanelUI._onNotificationButtonEvent: couldn't find notification element";
|
||||
|
||||
if (!notificationEl.notification)
|
||||
throw "PanelUI._onNotificationButtonEvent: couldn't find notification";
|
||||
|
||||
let notification = notificationEl.notification;
|
||||
|
||||
let action = notification.mainAction;
|
||||
|
||||
if (type == "secondarybuttoncommand") {
|
||||
action = notification.secondaryActions[0];
|
||||
}
|
||||
|
||||
let dismiss = true;
|
||||
if (action) {
|
||||
try {
|
||||
if (action === notification.mainAction) {
|
||||
action.callback(true);
|
||||
this._notify(notification.id, "main-action");
|
||||
} else {
|
||||
action.callback();
|
||||
}
|
||||
} catch (error) {
|
||||
Cu.reportError(error);
|
||||
}
|
||||
|
||||
dismiss = action.dismiss;
|
||||
}
|
||||
|
||||
if (dismiss) {
|
||||
notification.dismissed = true;
|
||||
this._notify(notification.id, "dismissed");
|
||||
} else {
|
||||
this._removeNotification(notification);
|
||||
}
|
||||
this._updateNotifications();
|
||||
},
|
||||
|
||||
_onNotificationMenuItemSelected(event) {
|
||||
let target = event.originalTarget;
|
||||
if (!target.notification)
|
||||
throw "menucommand target has no associated action/notification";
|
||||
|
||||
event.stopPropagation();
|
||||
|
||||
try {
|
||||
target.notification.mainAction.callback(false);
|
||||
this._notify(target.notification.id, "main-action");
|
||||
} catch (error) {
|
||||
Cu.reportError(error);
|
||||
}
|
||||
|
||||
this._removeNotification(target.notification);
|
||||
this._updateNotifications();
|
||||
},
|
||||
|
||||
_getPopupId(notification) { return "PanelUI-" + notification.id + "-notification"; },
|
||||
|
||||
_getBadgeStatus(notification) { return notification.id; },
|
||||
|
||||
_getMenuItemId(notification) { return "PanelUI-" + notification.id + "-menu-item"; },
|
||||
|
||||
_getPanelAnchor(candidate) {
|
||||
let iconAnchor =
|
||||
document.getAnonymousElementByAttribute(candidate, "class",
|
||||
"toolbarbutton-icon");
|
||||
return iconAnchor || candidate;
|
||||
},
|
||||
|
||||
_notify(status, topic) {
|
||||
Services.obs.notifyObservers(window, "panelUI-notification-" + topic, status);
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineConstant(this, "PanelUI", PanelUI);
|
||||
|
@ -549,3 +867,24 @@ XPCOMUtils.defineConstant(this, "PanelUI", PanelUI);
|
|||
function getLocale() {
|
||||
return Services.locale.getAppLocaleAsLangTag();
|
||||
}
|
||||
|
||||
function PanelUINotification(id, mainAction, secondaryActions = [], options = {}) {
|
||||
this.id = id;
|
||||
this.mainAction = mainAction;
|
||||
this.secondaryActions = secondaryActions;
|
||||
this.options = options;
|
||||
this.dismissed = this.options.dismissed || false;
|
||||
}
|
||||
|
||||
function getNotificationFromElement(aElement) {
|
||||
// Need to find the associated notification object, which is a bit tricky
|
||||
// since it isn't associated with the element directly - this is kind of
|
||||
// gross and very dependent on the structure of the popupnotification
|
||||
// binding's content.
|
||||
let notificationEl;
|
||||
let parent = aElement;
|
||||
while (parent && (parent = aElement.ownerDocument.getBindingParent(parent))) {
|
||||
notificationEl = parent;
|
||||
}
|
||||
return notificationEl;
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ skip-if = os == "mac"
|
|||
[browser_customizemode_contextmenu_menubuttonstate.js]
|
||||
[browser_exit_background_customize_mode.js]
|
||||
[browser_panel_toggle.js]
|
||||
[browser_panelUINotifications.js]
|
||||
[browser_switch_to_customize_mode.js]
|
||||
[browser_synced_tabs_menu.js]
|
||||
[browser_check_tooltips_in_navbar.js]
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests that when we click on the main call-to-action of the doorhanger, the provided
|
||||
* action is called, and the doorhanger removed.
|
||||
*/
|
||||
add_task(function* testMainActionCalled() {
|
||||
let options = {
|
||||
gBrowser: window.gBrowser,
|
||||
url: "about:blank"
|
||||
};
|
||||
|
||||
let extraWindow = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
yield BrowserTestUtils.withNewTab(options, function*(browser) {
|
||||
let doc = browser.ownerDocument;
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
let mainActionCalled = false;
|
||||
let mainAction = {
|
||||
callback: () => { mainActionCalled = true; }
|
||||
};
|
||||
PanelUI.showNotification("update-manual", mainAction);
|
||||
|
||||
let extraMainActionCalled = false;
|
||||
let extraMainAction = {
|
||||
callback: () => { extraMainActionCalled = true; }
|
||||
};
|
||||
extraWindow.PanelUI.showNotification("update-manual", extraMainAction)
|
||||
|
||||
isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
|
||||
let notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
|
||||
is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
|
||||
let doorhanger = notifications[0];
|
||||
is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
|
||||
|
||||
let mainActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "button");
|
||||
mainActionButton.click();
|
||||
|
||||
ok(mainActionCalled, "Main action callback was called");
|
||||
isnot(extraMainActionCalled, true, "Extra window's main action callback was not called");
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
is(extraWindow.PanelUI.notificationPanel.state, "closed", "Extra window's update-manual doorhanger is closed.");
|
||||
is(PanelUI.menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.closeWindow(extraWindow);
|
||||
});
|
||||
|
||||
/**
|
||||
* This tests that when we click the secondary action for a notification,
|
||||
* it will display the badge for that notification on the PanelUI menu button.
|
||||
* Once we click on this button, we should see an item in the menu which will
|
||||
* call our main action.
|
||||
*/
|
||||
add_task(function* testSecondaryActionWorkflow() {
|
||||
let options = {
|
||||
gBrowser: window.gBrowser,
|
||||
url: "about:blank"
|
||||
};
|
||||
|
||||
let extraWindow = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
yield BrowserTestUtils.withNewTab(options, function*(browser) {
|
||||
let doc = browser.ownerDocument;
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
|
||||
let mainActionCalled = false;
|
||||
let mainAction = {
|
||||
callback: () => { mainActionCalled = true; },
|
||||
};
|
||||
PanelUI.showNotification("update-manual", mainAction);
|
||||
|
||||
let extraMainActionCalled = false;
|
||||
let extraMainAction = {
|
||||
callback: () => { extraMainActionCalled = true; }
|
||||
};
|
||||
extraWindow.PanelUI.showNotification("update-manual", extraMainAction)
|
||||
|
||||
isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
|
||||
let notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
|
||||
is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
|
||||
let doorhanger = notifications[0];
|
||||
is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
|
||||
|
||||
let secondaryActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "secondarybutton");
|
||||
secondaryActionButton.click();
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
is(extraWindow.PanelUI.notificationPanel.state, "closed", "Extra window's update-manual doorhanger is closed.");
|
||||
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is displaying on PanelUI button.");
|
||||
|
||||
yield PanelUI.show();
|
||||
isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is hidden on PanelUI button.");
|
||||
let menuItem = doc.getElementById("PanelUI-update-manual-menu-item");
|
||||
is(menuItem.hidden, false, "update-manual menu item is showing.");
|
||||
|
||||
yield PanelUI.hide();
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is shown on PanelUI button.");
|
||||
|
||||
yield PanelUI.show();
|
||||
menuItem.click();
|
||||
ok(mainActionCalled, "Main action callback was called");
|
||||
isnot(extraMainActionCalled, true, "Extra window's main action callback was not called");
|
||||
|
||||
PanelUI.removeNotification(/.*/);
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.closeWindow(extraWindow);
|
||||
});
|
||||
|
||||
/**
|
||||
* We want to ensure a few things with this:
|
||||
* - Adding a doorhanger will make a badge disappear
|
||||
* - once the notification for the doorhanger is resolved (removed, not just dismissed),
|
||||
* then we display any other badges that are remaining.
|
||||
*/
|
||||
add_task(function* testInteractionWithBadges() {
|
||||
yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
|
||||
let doc = browser.ownerDocument;
|
||||
|
||||
PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
|
||||
let mainActionCalled = false;
|
||||
let mainAction = {
|
||||
callback: () => { mainActionCalled = true; },
|
||||
};
|
||||
PanelUI.showNotification("update-manual", mainAction);
|
||||
|
||||
isnot(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is hidden on PanelUI button.");
|
||||
isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
|
||||
let notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
|
||||
is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
|
||||
let doorhanger = notifications[0];
|
||||
is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
|
||||
|
||||
let secondaryActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "secondarybutton");
|
||||
secondaryActionButton.click();
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is displaying on PanelUI button.");
|
||||
|
||||
yield PanelUI.show();
|
||||
isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "Badge is hidden on PanelUI button.");
|
||||
let menuItem = doc.getElementById("PanelUI-update-manual-menu-item");
|
||||
is(menuItem.hidden, false, "update-manual menu item is showing.");
|
||||
|
||||
menuItem.click();
|
||||
ok(mainActionCalled, "Main action callback was called");
|
||||
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
|
||||
PanelUI.removeNotification(/.*/);
|
||||
is(PanelUI.menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This tests that adding a badge will not dismiss any existing doorhangers.
|
||||
*/
|
||||
add_task(function* testAddingBadgeWhileDoorhangerIsShowing() {
|
||||
yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
|
||||
let doc = browser.ownerDocument;
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
let mainActionCalled = false;
|
||||
let mainAction = {
|
||||
callback: () => { mainActionCalled = true; }
|
||||
};
|
||||
PanelUI.showNotification("update-manual", mainAction);
|
||||
PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
|
||||
|
||||
isnot(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is hidden on PanelUI button.");
|
||||
isnot(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is showing.");
|
||||
let notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
|
||||
is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
|
||||
let doorhanger = notifications[0];
|
||||
is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
|
||||
|
||||
let mainActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "button");
|
||||
mainActionButton.click();
|
||||
|
||||
ok(mainActionCalled, "Main action callback was called");
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Fxa badge is shown on PanelUI button.");
|
||||
PanelUI.removeNotification(/.*/);
|
||||
is(PanelUI.menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that badges operate like a stack.
|
||||
*/
|
||||
add_task(function* testMultipleBadges() {
|
||||
yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
|
||||
let doc = browser.ownerDocument;
|
||||
let menuButton = doc.getElementById("PanelUI-menu-button");
|
||||
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
is(menuButton.hasAttribute("badge"), false, "Should not have the badge attribute set");
|
||||
|
||||
PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
|
||||
is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
|
||||
|
||||
PanelUI.showBadgeOnlyNotification("update-succeeded");
|
||||
is(menuButton.getAttribute("badge-status"), "update-succeeded", "Should have update-succeeded badge status (update > fxa)");
|
||||
|
||||
PanelUI.showBadgeOnlyNotification("update-failed");
|
||||
is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
|
||||
|
||||
PanelUI.showBadgeOnlyNotification("download-severe");
|
||||
is(menuButton.getAttribute("badge-status"), "download-severe", "Should have download-severe badge status");
|
||||
|
||||
PanelUI.showBadgeOnlyNotification("download-warning");
|
||||
is(menuButton.getAttribute("badge-status"), "download-warning", "Should have download-warning badge status");
|
||||
|
||||
PanelUI.removeNotification(/^download-/);
|
||||
is(menuButton.getAttribute("badge-status"), "update-failed", "Should have update-failed badge status");
|
||||
|
||||
PanelUI.removeNotification(/^update-/);
|
||||
is(menuButton.getAttribute("badge-status"), "fxa-needs-authentication", "Should have fxa-needs-authentication badge status");
|
||||
|
||||
PanelUI.removeNotification(/^fxa-/);
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
|
||||
yield PanelUI.show();
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status (Hamburger menu opened)");
|
||||
PanelUI.hide();
|
||||
|
||||
PanelUI.showBadgeOnlyNotification("fxa-needs-authentication");
|
||||
PanelUI.showBadgeOnlyNotification("update-succeeded");
|
||||
PanelUI.removeNotification(/.*/);
|
||||
is(menuButton.hasAttribute("badge-status"), false, "Should not have a badge status");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that non-badges also operate like a stack.
|
||||
*/
|
||||
add_task(function* testMultipleNonBadges() {
|
||||
yield BrowserTestUtils.withNewTab("about:blank", function*(browser) {
|
||||
let doc = browser.ownerDocument;
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
|
||||
let updateManualAction = {
|
||||
called: false,
|
||||
callback: () => { updateManualAction.called = true; },
|
||||
};
|
||||
let updateRestartAction = {
|
||||
called: false,
|
||||
callback: () => { updateRestartAction.called = true; },
|
||||
};
|
||||
|
||||
PanelUI.showNotification("update-manual", updateManualAction);
|
||||
|
||||
let notifications;
|
||||
let doorhanger;
|
||||
|
||||
isnot(PanelUI.notificationPanel.state, "closed", "Doorhanger is showing.");
|
||||
notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
|
||||
is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
|
||||
doorhanger = notifications[0];
|
||||
is(doorhanger.id, "PanelUI-update-manual-notification", "PanelUI is displaying the update-manual notification.");
|
||||
|
||||
PanelUI.showNotification("update-restart", updateRestartAction);
|
||||
|
||||
isnot(PanelUI.notificationPanel.state, "closed", "Doorhanger is showing.");
|
||||
notifications = [...PanelUI.notificationPanel.children].filter(n => !n.hidden);
|
||||
is(notifications.length, 1, "PanelUI doorhanger is only displaying one notification.");
|
||||
doorhanger = notifications[0];
|
||||
is(doorhanger.id, "PanelUI-update-restart-notification", "PanelUI is displaying the update-restart notification.");
|
||||
|
||||
let secondaryActionButton = doc.getAnonymousElementByAttribute(doorhanger, "anonid", "secondarybutton");
|
||||
secondaryActionButton.click();
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "update-restart", "update-restart badge is displaying on PanelUI button.");
|
||||
|
||||
let menuItem;
|
||||
|
||||
yield PanelUI.show();
|
||||
isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-restart", "update-restart badge is hidden on PanelUI button.");
|
||||
menuItem = doc.getElementById("PanelUI-update-restart-menu-item");
|
||||
is(menuItem.hidden, false, "update-restart menu item is showing.");
|
||||
|
||||
menuItem.click();
|
||||
ok(updateRestartAction.called, "update-restart main action callback was called");
|
||||
|
||||
is(PanelUI.notificationPanel.state, "closed", "update-manual doorhanger is closed.");
|
||||
is(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "update-manual badge is displaying on PanelUI button.");
|
||||
|
||||
yield PanelUI.show();
|
||||
isnot(PanelUI.menuButton.getAttribute("badge-status"), "update-manual", "update-manual badge is hidden on PanelUI button.");
|
||||
menuItem = doc.getElementById("PanelUI-update-manual-menu-item");
|
||||
is(menuItem.hidden, false, "update-manual menu item is showing.");
|
||||
|
||||
menuItem.click();
|
||||
ok(updateManualAction.called, "update-manual main action callback was called");
|
||||
});
|
||||
});
|
|
@ -507,15 +507,13 @@ const DownloadsIndicatorView = {
|
|||
if (suppressAttention || this._attention == DownloadsCommon.ATTENTION_NONE) {
|
||||
this.indicator.removeAttribute("attention");
|
||||
if (inMenu) {
|
||||
gMenuButtonBadgeManager.removeBadge(
|
||||
gMenuButtonBadgeManager.BADGEID_DOWNLOAD);
|
||||
PanelUI.removeNotification(/^download-/);
|
||||
}
|
||||
} else {
|
||||
this.indicator.setAttribute("attention", this._attention);
|
||||
if (inMenu) {
|
||||
let badgeClass = "download-" + this._attention;
|
||||
gMenuButtonBadgeManager.addBadge(
|
||||
gMenuButtonBadgeManager.BADGEID_DOWNLOAD, badgeClass);
|
||||
PanelUI.showBadgeOnlyNotification(badgeClass);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"properties": {
|
||||
"homepage": {
|
||||
"type": "string",
|
||||
"format": "url",
|
||||
"format": "relativeUrl",
|
||||
"optional": true,
|
||||
"preprocess": "localize"
|
||||
}
|
||||
|
@ -22,4 +22,4 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -182,3 +182,20 @@ add_task(function* test_disable() {
|
|||
is(Preferences.get("browser.startup.homepage"), defaultHomePage,
|
||||
"Home url should be the default");
|
||||
});
|
||||
|
||||
add_task(function* test_local() {
|
||||
let ext1 = ExtensionTestUtils.loadExtension({
|
||||
manifest: {"chrome_settings_overrides": {"homepage": "home.html"}},
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
let prefPromise = promisePrefChangeObserved("browser.startup.homepage");
|
||||
yield ext1.startup();
|
||||
yield prefPromise;
|
||||
|
||||
let homepage = Preferences.get("browser.startup.homepage");
|
||||
ok((homepage.startsWith("moz-extension") && homepage.endsWith("home.html")),
|
||||
"Home url should be relative to extension.");
|
||||
|
||||
yield ext1.unload();
|
||||
});
|
||||
|
|
|
@ -794,6 +794,9 @@ BrowserGlue.prototype = {
|
|||
// With older versions of the extension installed, this load will fail
|
||||
// passively.
|
||||
Services.ppmm.loadProcessScript("resource://pdf.js/pdfjschildbootstrap.js", true);
|
||||
if (PdfJs.enabled) {
|
||||
Services.ppmm.loadProcessScript("resource://pdf.js/pdfjschildbootstrap-enabled.js", true);
|
||||
}
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
// For Windows 7, initialize the jump list module.
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* 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";
|
||||
|
||||
this.actionTypes = [
|
||||
"INIT",
|
||||
"UNINIT",
|
||||
// The line below creates an object like this:
|
||||
// {
|
||||
// INIT: "INIT",
|
||||
// UNINIT: "UNINIT"
|
||||
// }
|
||||
// It prevents accidentally adding a different key/value name.
|
||||
].reduce((obj, type) => { obj[type] = type; return obj; }, {});
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"actionTypes"
|
||||
];
|
|
@ -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/. */
|
||||
"use strict";
|
||||
|
||||
this.INITIAL_STATE = {
|
||||
TopSites: {
|
||||
rows: [
|
||||
{
|
||||
"title": "Facebook",
|
||||
"url": "https://www.facebook.com/"
|
||||
},
|
||||
{
|
||||
"title": "YouTube",
|
||||
"url": "https://www.youtube.com/"
|
||||
},
|
||||
{
|
||||
"title": "Amazon",
|
||||
"url": "http://www.amazon.com/"
|
||||
},
|
||||
{
|
||||
"title": "Yahoo",
|
||||
"url": "https://www.yahoo.com/"
|
||||
},
|
||||
{
|
||||
"title": "eBay",
|
||||
"url": "http://www.ebay.com"
|
||||
},
|
||||
{
|
||||
"title": "Twitter",
|
||||
"url": "https://twitter.com/"
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Handle some real actions here, once we have a TopSites feed working
|
||||
function TopSites(prevState = INITIAL_STATE.TopSites, action) {
|
||||
return prevState;
|
||||
}
|
||||
|
||||
this.reducers = {TopSites};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["reducers", "INITIAL_STATE"];
|
|
@ -5,4 +5,6 @@
|
|||
[features/activity-stream@mozilla.org] chrome.jar:
|
||||
% resource activity-stream %content/
|
||||
content/lib/ (./lib/*)
|
||||
content/common/ (./common/*)
|
||||
content/vendor/Redux.jsm (./vendor/Redux.jsm)
|
||||
content/data/ (./data/*)
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
class ActivityStream {
|
||||
const {utils: Cu} = Components;
|
||||
const {Store} = Cu.import("resource://activity-stream/lib/Store.jsm", {});
|
||||
|
||||
this.ActivityStream = class ActivityStream {
|
||||
|
||||
/**
|
||||
* constructor - Initializes an instance of ActivityStream
|
||||
|
@ -16,13 +19,16 @@ class ActivityStream {
|
|||
constructor(options) {
|
||||
this.initialized = false;
|
||||
this.options = options;
|
||||
this.store = new Store();
|
||||
}
|
||||
init() {
|
||||
this.initialized = true;
|
||||
this.store.init();
|
||||
}
|
||||
uninit() {
|
||||
this.store.uninit();
|
||||
this.initialized = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ActivityStream"];
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/* 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 {utils: Cu} = Components;
|
||||
|
||||
const {redux} = Cu.import("resource://activity-stream/vendor/Redux.jsm", {});
|
||||
const {actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
const {reducers} = Cu.import("resource://activity-stream/common/Reducers.jsm", {});
|
||||
|
||||
/**
|
||||
* Store - This has a similar structure to a redux store, but includes some extra
|
||||
* functionality. It accepts an array of "Feeds" on inititalization, which
|
||||
* can listen for any action that is dispatched through the store.
|
||||
*/
|
||||
this.Store = class Store {
|
||||
|
||||
/**
|
||||
* constructor - The redux store is created here,
|
||||
* but no listeners are added until "init" is called.
|
||||
*/
|
||||
constructor() {
|
||||
this._middleware = this._middleware.bind(this);
|
||||
// Bind each redux method so we can call it directly from the Store. E.g.,
|
||||
// store.dispatch() will call store._store.dispatch();
|
||||
["dispatch", "getState", "subscribe"].forEach(method => {
|
||||
this[method] = function(...args) {
|
||||
return this._store[method](...args);
|
||||
}.bind(this);
|
||||
});
|
||||
this.feeds = new Set();
|
||||
this._store = redux.createStore(
|
||||
redux.combineReducers(reducers),
|
||||
redux.applyMiddleware(this._middleware)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* _middleware - This is redux middleware consumed by redux.createStore.
|
||||
* it calls each feed's .onAction method, if one
|
||||
* is defined.
|
||||
*/
|
||||
_middleware(store) {
|
||||
return next => action => {
|
||||
next(action);
|
||||
this.feeds.forEach(s => s.onAction && s.onAction(action));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* init - Initializes the MessageManager channel, and adds feeds.
|
||||
* After initialization has finished, an INIT action is dispatched.
|
||||
*
|
||||
* @param {array} feeds An array of objects with an optional .onAction method
|
||||
*/
|
||||
init(feeds) {
|
||||
if (feeds) {
|
||||
feeds.forEach(subscriber => {
|
||||
subscriber.store = this;
|
||||
this.feeds.add(subscriber);
|
||||
});
|
||||
}
|
||||
this.dispatch({type: at.INIT});
|
||||
}
|
||||
|
||||
/**
|
||||
* uninit - Clears all feeds, dispatches an UNINIT action
|
||||
*
|
||||
* @return {type} description
|
||||
*/
|
||||
uninit() {
|
||||
this.feeds.clear();
|
||||
this.dispatch({type: at.UNINIT});
|
||||
}
|
||||
};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Store"];
|
|
@ -1720,6 +1720,7 @@ class PPAPIInstance {
|
|||
let mouseEventInit = {
|
||||
altkey: event.altkey,
|
||||
button: event.button,
|
||||
buttons: event.buttons,
|
||||
clientX: event.clientX - rect.left,
|
||||
clientY: event.clientY - rect.top,
|
||||
ctrlKey: event.ctrlKey,
|
||||
|
@ -1820,6 +1821,12 @@ class PPAPIInstance {
|
|||
// We need permission for showing print dialog to get print settings
|
||||
this.mm.sendAsyncMessage("ppapipdf.js:getPrintSettings");
|
||||
break;
|
||||
case 'openLink':
|
||||
this.mm.sendAsyncMessage("ppapipdf.js:openLink", {
|
||||
url: message.url,
|
||||
disposition: message.disposition
|
||||
});
|
||||
break;
|
||||
case 'viewport':
|
||||
case 'rotateClockwise':
|
||||
case 'rotateCounterclockwise':
|
||||
|
@ -3126,25 +3133,37 @@ dump(`callFromJSON: < ${JSON.stringify(call)}\n`);
|
|||
|
||||
if (event instanceof KeyboardInputEvent) {
|
||||
if (event.domEvent.location == event.domEvent.DOM_KEY_LOCATION_NUMPAD) {
|
||||
modifiers &= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISKEYPAD;
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISKEYPAD;
|
||||
} else if (event.domEvent.location & event.domEvent.DOM_KEY_LOCATION_LEFT) {
|
||||
modifiers &= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISLEFT;
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISLEFT;
|
||||
} else if (event.domEvent.location & event.domEvent.DOM_KEY_LOCATION_RIGHT) {
|
||||
modifiers &= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISRIGHT;
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISRIGHT;
|
||||
}
|
||||
|
||||
if (event.domEvent.repeat) {
|
||||
modifiers &= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT;
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT;
|
||||
}
|
||||
} else if (event instanceof MouseInputEvent) {
|
||||
if (event.domEvent.buttons && 0x01) {
|
||||
modifiers &= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN;
|
||||
if (event.domEvent.buttons & 0x01) {
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN;
|
||||
}
|
||||
if (event.domEvent.buttons && 0x04) {
|
||||
modifiers &= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN;
|
||||
if (event.domEvent.buttons & 0x04) {
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN;
|
||||
}
|
||||
if (event.domEvent.buttons && 0x02) {
|
||||
modifiers &= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN;
|
||||
if (event.domEvent.buttons & 0x02) {
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN;
|
||||
}
|
||||
if (event.domEvent.type == 'mouseup') {
|
||||
// mouseup event indicates the key released only in domEvent.button
|
||||
// rather than domEvent.buttons, but PDFium do use modifiers to
|
||||
// determine which button is released. So we make it up here.
|
||||
if (event.domEvent.button == 0) {
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN;
|
||||
} else if (event.domEvent.button == 1) {
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN;
|
||||
} else if (event.domEvent.button == 2) {
|
||||
modifiers |= PP_InputEvent_Modifier.PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -782,6 +782,13 @@ class Viewport {
|
|||
case 'goToPage':
|
||||
this.page = message.page;
|
||||
break;
|
||||
case 'navigate':
|
||||
this._doAction({
|
||||
type: 'openLink',
|
||||
url: message.url,
|
||||
disposition: message.disposition
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,6 +180,31 @@ mm.addMessageListener("ppapipdf.js:printPDF", ({ data }) => {
|
|||
});
|
||||
});
|
||||
|
||||
mm.addMessageListener("ppapipdf.js:openLink", ({data}) => {
|
||||
const PDFIUM_WINDOW_OPEN_DISPOSITION = {
|
||||
CURRENT_TAB: 1,
|
||||
NEW_FOREGROUND_TAB: 3,
|
||||
NEW_BACKGROUND_TAB: 4,
|
||||
NEW_WINDOW: 6,
|
||||
};
|
||||
switch(data.disposition) {
|
||||
case PDFIUM_WINDOW_OPEN_DISPOSITION.CURRENT_TAB:
|
||||
containerWindow.location.href = data.url;
|
||||
break;
|
||||
// We don't support opening in background tab for now. Just open it in
|
||||
// foreground tab.
|
||||
case PDFIUM_WINDOW_OPEN_DISPOSITION.NEW_FOREGROUND_TAB:
|
||||
case PDFIUM_WINDOW_OPEN_DISPOSITION.NEW_BACKGROUND_TAB:
|
||||
containerWindow.open(data.url);
|
||||
break;
|
||||
case PDFIUM_WINDOW_OPEN_DISPOSITION.NEW_WINDOW:
|
||||
containerWindow.open(data.url, "",
|
||||
"noopener=1,menubar=1,toolbar=1," +
|
||||
"location=1,personalbar=1,status=1,resizable");
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
mm.addMessageListener("ppapipdf.js:save", () => {
|
||||
let url = containerWindow.document.location;
|
||||
let filename = "document.pdf";
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 1.7.401
|
||||
Current extension version is: 1.8.173
|
||||
|
|
|
@ -190,9 +190,9 @@ var PdfJs = {
|
|||
|
||||
updateRegistration: function updateRegistration() {
|
||||
if (this.enabled) {
|
||||
this._ensureRegistered();
|
||||
this.ensureRegistered();
|
||||
} else {
|
||||
this._ensureUnregistered();
|
||||
this.ensureUnregistered();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -205,7 +205,7 @@ var PdfJs = {
|
|||
Services.obs.removeObserver(this, TOPIC_PLUGIN_INFO_UPDATED);
|
||||
this._initialized = false;
|
||||
}
|
||||
this._ensureUnregistered();
|
||||
this.ensureUnregistered();
|
||||
},
|
||||
|
||||
_migrate: function migrate() {
|
||||
|
@ -324,7 +324,7 @@ var PdfJs = {
|
|||
return !enabledPluginFound;
|
||||
},
|
||||
|
||||
_ensureRegistered: function _ensureRegistered() {
|
||||
ensureRegistered: function ensureRegistered() {
|
||||
if (this._registered) {
|
||||
return;
|
||||
}
|
||||
|
@ -335,7 +335,7 @@ var PdfJs = {
|
|||
this._registered = true;
|
||||
},
|
||||
|
||||
_ensureUnregistered: function _ensureUnregistered() {
|
||||
ensureUnregistered: function ensureUnregistered() {
|
||||
if (!this._registered) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,9 @@ const MAX_STRING_PREF_LENGTH = 128;
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetworkManager",
|
||||
"resource://pdf.js/PdfJsNetwork.jsm");
|
||||
|
|
|
@ -1292,6 +1292,16 @@ var CustomStyle = function CustomStyleClosure() {
|
|||
};
|
||||
return CustomStyle;
|
||||
}();
|
||||
var RenderingCancelledException = function RenderingCancelledException() {
|
||||
function RenderingCancelledException(msg, type) {
|
||||
this.message = msg;
|
||||
this.type = type;
|
||||
}
|
||||
RenderingCancelledException.prototype = new Error();
|
||||
RenderingCancelledException.prototype.name = 'RenderingCancelledException';
|
||||
RenderingCancelledException.constructor = RenderingCancelledException;
|
||||
return RenderingCancelledException;
|
||||
}();
|
||||
var hasCanvasTypedArrays;
|
||||
hasCanvasTypedArrays = function () {
|
||||
return true;
|
||||
|
@ -1380,6 +1390,8 @@ function getDefaultSetting(id) {
|
|||
return globalSettings ? globalSettings.externalLinkRel : DEFAULT_LINK_REL;
|
||||
case 'enableStats':
|
||||
return !!(globalSettings && globalSettings.enableStats);
|
||||
case 'pdfjsNext':
|
||||
return !!(globalSettings && globalSettings.pdfjsNext);
|
||||
default:
|
||||
throw new Error('Unknown default setting: ' + id);
|
||||
}
|
||||
|
@ -1407,6 +1419,7 @@ exports.isExternalLinkTargetSet = isExternalLinkTargetSet;
|
|||
exports.isValidUrl = isValidUrl;
|
||||
exports.getFilenameFromUrl = getFilenameFromUrl;
|
||||
exports.LinkTarget = LinkTarget;
|
||||
exports.RenderingCancelledException = RenderingCancelledException;
|
||||
exports.hasCanvasTypedArrays = hasCanvasTypedArrays;
|
||||
exports.getDefaultSetting = getDefaultSetting;
|
||||
exports.DEFAULT_LINK_REL = DEFAULT_LINK_REL;
|
||||
|
@ -2068,6 +2081,7 @@ var FontFaceObject = displayFontLoader.FontFaceObject;
|
|||
var FontLoader = displayFontLoader.FontLoader;
|
||||
var CanvasGraphics = displayCanvas.CanvasGraphics;
|
||||
var Metadata = displayMetadata.Metadata;
|
||||
var RenderingCancelledException = displayDOMUtils.RenderingCancelledException;
|
||||
var getDefaultSetting = displayDOMUtils.getDefaultSetting;
|
||||
var DOMCanvasFactory = displayDOMUtils.DOMCanvasFactory;
|
||||
var DOMCMapReaderFactory = displayDOMUtils.DOMCMapReaderFactory;
|
||||
|
@ -3298,7 +3312,7 @@ var InternalRenderTask = function InternalRenderTaskClosure() {
|
|||
cancel: function InternalRenderTask_cancel() {
|
||||
this.running = false;
|
||||
this.cancelled = true;
|
||||
this.callback('cancelled');
|
||||
this.callback(new RenderingCancelledException('Rendering cancelled, page ' + this.pageNumber, 'canvas'));
|
||||
},
|
||||
operatorListChanged: function InternalRenderTask_operatorListChanged() {
|
||||
if (!this.graphicsReady) {
|
||||
|
@ -3363,8 +3377,8 @@ var _UnsupportedManager = function UnsupportedManagerClosure() {
|
|||
}
|
||||
};
|
||||
}();
|
||||
exports.version = '1.7.401';
|
||||
exports.build = '57d9a64c';
|
||||
exports.version = '1.8.173';
|
||||
exports.build = 'c5199d08';
|
||||
exports.getDocument = getDocument;
|
||||
exports.PDFDataRangeTransport = PDFDataRangeTransport;
|
||||
exports.PDFWorker = PDFWorker;
|
||||
|
@ -4331,8 +4345,8 @@ if (!globalScope.PDFJS) {
|
|||
globalScope.PDFJS = {};
|
||||
}
|
||||
var PDFJS = globalScope.PDFJS;
|
||||
PDFJS.version = '1.7.401';
|
||||
PDFJS.build = '57d9a64c';
|
||||
PDFJS.version = '1.8.173';
|
||||
PDFJS.build = 'c5199d08';
|
||||
PDFJS.pdfBug = false;
|
||||
if (PDFJS.verbosity !== undefined) {
|
||||
sharedUtil.setVerbosityLevel(PDFJS.verbosity);
|
||||
|
@ -4392,6 +4406,7 @@ PDFJS.disableWebGL = PDFJS.disableWebGL === undefined ? true : PDFJS.disableWebG
|
|||
PDFJS.externalLinkTarget = PDFJS.externalLinkTarget === undefined ? LinkTarget.NONE : PDFJS.externalLinkTarget;
|
||||
PDFJS.externalLinkRel = PDFJS.externalLinkRel === undefined ? DEFAULT_LINK_REL : PDFJS.externalLinkRel;
|
||||
PDFJS.isEvalSupported = PDFJS.isEvalSupported === undefined ? true : PDFJS.isEvalSupported;
|
||||
PDFJS.pdfjsNext = PDFJS.pdfjsNext === undefined ? false : PDFJS.pdfjsNext;
|
||||
PDFJS.getDocument = displayAPI.getDocument;
|
||||
PDFJS.PDFDataRangeTransport = displayAPI.PDFDataRangeTransport;
|
||||
PDFJS.PDFWorker = displayAPI.PDFWorker;
|
||||
|
@ -6670,8 +6685,8 @@ exports.TilingPattern = TilingPattern;
|
|||
"use strict";
|
||||
|
||||
|
||||
var pdfjsVersion = '1.7.401';
|
||||
var pdfjsBuild = '57d9a64c';
|
||||
var pdfjsVersion = '1.8.173';
|
||||
var pdfjsBuild = 'c5199d08';
|
||||
var pdfjsSharedUtil = __w_pdfjs_require__(0);
|
||||
var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
|
||||
var pdfjsDisplayAPI = __w_pdfjs_require__(3);
|
||||
|
@ -6702,6 +6717,7 @@ exports.createObjectURL = pdfjsSharedUtil.createObjectURL;
|
|||
exports.removeNullCharacters = pdfjsSharedUtil.removeNullCharacters;
|
||||
exports.shadow = pdfjsSharedUtil.shadow;
|
||||
exports.createBlob = pdfjsSharedUtil.createBlob;
|
||||
exports.RenderingCancelledException = pdfjsDisplayDOMUtils.RenderingCancelledException;
|
||||
exports.getFilenameFromUrl = pdfjsDisplayDOMUtils.getFilenameFromUrl;
|
||||
exports.addLinkAttributes = pdfjsDisplayDOMUtils.addLinkAttributes;
|
||||
|
||||
|
|
|
@ -27676,9 +27676,6 @@ var Font = function FontClosure() {
|
|||
}
|
||||
glyphId = offsetIndex < 0 ? j : offsets[offsetIndex + j - start];
|
||||
glyphId = glyphId + delta & 0xFFFF;
|
||||
if (glyphId === 0) {
|
||||
continue;
|
||||
}
|
||||
mappings.push({
|
||||
charCode: j,
|
||||
glyphId: glyphId
|
||||
|
@ -36373,8 +36370,8 @@ exports.Type1Parser = Type1Parser;
|
|||
"use strict";
|
||||
|
||||
|
||||
var pdfjsVersion = '1.7.401';
|
||||
var pdfjsBuild = '57d9a64c';
|
||||
var pdfjsVersion = '1.8.173';
|
||||
var pdfjsBuild = 'c5199d08';
|
||||
var pdfjsCoreWorker = __w_pdfjs_require__(17);
|
||||
;
|
||||
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals Components, PdfJs, Services */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* pdfjschildbootstrap-enabled.js loads into the content process to
|
||||
* take care of initializing our built-in version of pdfjs when
|
||||
* running remote. It will only be run when PdfJs.enable is true.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://pdf.js/PdfJs.jsm");
|
||||
|
||||
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
// register various pdfjs factories that hook us into content loading.
|
||||
PdfJs.ensureRegistered();
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals Components, PdfjsContentUtils, PdfJs, Services */
|
||||
/* globals Components, PdfjsContentUtils */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -21,14 +21,7 @@
|
|||
* initializing our built-in version of pdfjs when running remote.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://pdf.js/PdfJs.jsm");
|
||||
Components.utils.import("resource://pdf.js/PdfjsContentUtils.jsm");
|
||||
|
||||
// init content utils shim pdfjs will use to access privileged apis.
|
||||
PdfjsContentUtils.init();
|
||||
|
||||
if (Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
// register various pdfjs factories that hook us into content loading.
|
||||
PdfJs.updateRegistration();
|
||||
}
|
||||
|
|
|
@ -4944,7 +4944,7 @@ var PDFPageView = function PDFPageViewClosure() {
|
|||
if (paintTask === self.paintTask) {
|
||||
self.paintTask = null;
|
||||
}
|
||||
if (error === 'cancelled') {
|
||||
if (error instanceof pdfjsLib.RenderingCancelledException) {
|
||||
self.error = null;
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
|
|
@ -898,3 +898,31 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
|
||||
<!ENTITY emeLearnMoreContextMenu.label "Learn more about DRM…">
|
||||
<!ENTITY emeLearnMoreContextMenu.accesskey "D">
|
||||
|
||||
<!ENTITY updateAvailable.message "Update your &brandShorterName; for the latest in speed and privacy.">
|
||||
<!ENTITY updateAvailable.whatsnew.label "See what’s new.">
|
||||
<!ENTITY updateAvailable.whatsnew.href "http://www.mozilla.org/">
|
||||
<!ENTITY updateAvailable.header.message "A new &brandShorterName; update is available.">
|
||||
<!ENTITY updateAvailable.acceptButton.label "Download Update">
|
||||
<!ENTITY updateAvailable.acceptButton.accesskey "D">
|
||||
<!ENTITY updateAvailable.cancelButton.label "Not Now">
|
||||
<!ENTITY updateAvailable.cancelButton.accesskey "N">
|
||||
<!ENTITY updateAvailable.panelUI.label "Download &brandShorterName; update">
|
||||
|
||||
<!ENTITY updateManual.message "Download a fresh copy of &brandShorterName; and we’ll help you to install it.">
|
||||
<!ENTITY updateManual.whatsnew.label "See what’s new.">
|
||||
<!ENTITY updateManual.whatsnew.href "http://www.mozilla.org/">
|
||||
<!ENTITY updateManual.header.message "&brandShorterName; can’t update to the latest version.">
|
||||
<!ENTITY updateManual.acceptButton.label "Download &brandShorterName;">
|
||||
<!ENTITY updateManual.acceptButton.accesskey "D">
|
||||
<!ENTITY updateManual.cancelButton.label "Not Now">
|
||||
<!ENTITY updateManual.cancelButton.accesskey "N">
|
||||
<!ENTITY updateManual.panelUI.label "Download a fresh copy of &brandShorterName;">
|
||||
|
||||
<!ENTITY updateRestart.message "After a quick restart, &brandShorterName; will restore all your open tabs and windows.">
|
||||
<!ENTITY updateRestart.header.message "Restart &brandShorterName; to apply update.">
|
||||
<!ENTITY updateRestart.acceptButton.label "Restart and Restore">
|
||||
<!ENTITY updateRestart.acceptButton.accesskey "R">
|
||||
<!ENTITY updateRestart.cancelButton.label "Not Now">
|
||||
<!ENTITY updateRestart.cancelButton.accesskey "N">
|
||||
<!ENTITY updateRestart.panelUI.label "Restart &brandShorterName; to apply update">
|
||||
|
|
|
@ -761,15 +761,6 @@ customizeTips.tip0.learnMore = Learn more
|
|||
# LOCALIZATION NOTE (customizeMode.tabTitle): %S is brandShortName
|
||||
customizeMode.tabTitle = Customize %S
|
||||
|
||||
# LOCALIZATION NOTE(appmenu.*.description, appmenu.*.label): these are used for
|
||||
# the appmenu labels and buttons that appear when an update is staged for
|
||||
# installation or a background update has failed and a manual download is required.
|
||||
# %S is brandShortName
|
||||
appmenu.restartNeeded.description = Restart %S to apply updates
|
||||
appmenu.updateFailed.description = Background update failed, please download update
|
||||
appmenu.restartBrowserButton.label = Restart %S
|
||||
appmenu.downloadUpdateButton.label = Download Update
|
||||
|
||||
# LOCALIZATION NOTE : FILE Reader View is a feature name and therefore typically used as a proper noun.
|
||||
|
||||
readingList.promo.firstUse.readerView.title = Reader View
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ContentWebRTC",
|
||||
"resource:///modules/ContentWebRTC.jsm");
|
||||
|
||||
var gEMEUIObserver = function(subject, topic, data) {
|
||||
let win = subject.top;
|
||||
|
@ -52,3 +56,29 @@ function getMessageManagerForWindow(aContentWindow) {
|
|||
|
||||
Services.obs.addObserver(gEMEUIObserver, "mediakeys-request", false);
|
||||
Services.obs.addObserver(gDecoderDoctorObserver, "decoder-doctor-notification", false);
|
||||
|
||||
|
||||
// ContentWebRTC observer registration.
|
||||
const kWebRTCObserverTopics = ["getUserMedia:request",
|
||||
"recording-device-stopped",
|
||||
"PeerConnection:request",
|
||||
"recording-device-events",
|
||||
"recording-window-ended"];
|
||||
|
||||
function webRTCObserve(aSubject, aTopic, aData) {
|
||||
ContentWebRTC.observe(aSubject, aTopic, aData);
|
||||
}
|
||||
|
||||
for (let topic of kWebRTCObserverTopics) {
|
||||
Services.obs.addObserver(webRTCObserve, topic, false);
|
||||
}
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT)
|
||||
Services.obs.addObserver(processShutdown, "content-child-shutdown", false);
|
||||
|
||||
function processShutdown() {
|
||||
for (let topic of kWebRTCObserverTopics) {
|
||||
Services.obs.removeObserver(webRTCObserve, topic);
|
||||
}
|
||||
Services.obs.removeObserver(processShutdown, "content-child-shutdown");
|
||||
}
|
||||
|
|
|
@ -17,36 +17,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService",
|
|||
const kBrowserURL = "chrome://browser/content/browser.xul";
|
||||
|
||||
this.ContentWebRTC = {
|
||||
_initialized: false,
|
||||
|
||||
init() {
|
||||
if (this._initialized)
|
||||
return;
|
||||
|
||||
this._initialized = true;
|
||||
Services.obs.addObserver(handleGUMRequest, "getUserMedia:request", false);
|
||||
Services.obs.addObserver(handleGUMStop, "recording-device-stopped", false);
|
||||
Services.obs.addObserver(handlePCRequest, "PeerConnection:request", false);
|
||||
Services.obs.addObserver(updateIndicators, "recording-device-events", false);
|
||||
Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false);
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT)
|
||||
Services.obs.addObserver(processShutdown, "content-child-shutdown", false);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(handleGUMRequest, "getUserMedia:request");
|
||||
Services.obs.removeObserver(handleGUMStop, "recording-device-stopped");
|
||||
Services.obs.removeObserver(handlePCRequest, "PeerConnection:request");
|
||||
Services.obs.removeObserver(updateIndicators, "recording-device-events");
|
||||
Services.obs.removeObserver(removeBrowserSpecificIndicator, "recording-window-ended");
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT)
|
||||
Services.obs.removeObserver(processShutdown, "content-child-shutdown");
|
||||
|
||||
this._initialized = false;
|
||||
},
|
||||
|
||||
// Called only for 'unload' to remove pending gUM prompts in reloaded frames.
|
||||
handleEvent(aEvent) {
|
||||
let contentWindow = aEvent.target.defaultView;
|
||||
|
@ -59,6 +29,28 @@ this.ContentWebRTC = {
|
|||
}
|
||||
},
|
||||
|
||||
// This observer is registered in ContentObservers.js to avoid
|
||||
// loading this .jsm when WebRTC is not in use.
|
||||
observe(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "getUserMedia:request":
|
||||
handleGUMRequest(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "recording-device-stopped":
|
||||
handleGUMStop(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "PeerConnection:request":
|
||||
handlePCRequest(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "recording-device-events":
|
||||
updateIndicators(aSubject, aTopic, aData);
|
||||
break;
|
||||
case "recording-window-ended":
|
||||
removeBrowserSpecificIndicator(aSubject, aTopic, aData);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "rtcpeer:Allow":
|
||||
|
@ -410,7 +402,3 @@ function getMessageManagerForWindow(aContentWindow) {
|
|||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function processShutdown() {
|
||||
ContentWebRTC.uninit();
|
||||
}
|
||||
|
|
|
@ -110,14 +110,31 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="update-succeeded"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
#PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
height: 13px;
|
||||
border-radius: 50%;
|
||||
box-shadow: none;
|
||||
border: 1px solid -moz-dialog;
|
||||
/* "!important" is necessary to override the rule in toolbarbutton.css */
|
||||
margin: -9px 0 0 !important;
|
||||
margin-inline-end: -6px !important;
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="update-failed"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
background: #D90000 url(chrome://browser/skin/update-badge-failed.svg) no-repeat center;
|
||||
height: 13px;
|
||||
#PanelUI-update-restart-menu-item::after,
|
||||
#PanelUI-update-available-menu-item::after,
|
||||
#PanelUI-update-manual-menu-item::after {
|
||||
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#PanelUI-update-restart-menu-item,
|
||||
#PanelUI-update-available-menu-item,
|
||||
#PanelUI-update-manual-menu-item {
|
||||
list-style-image: url(chrome://branding/content/icon16.png);
|
||||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="download-warning"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
|
@ -444,11 +461,11 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] > iframe {
|
|||
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .panel-wide-item,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-contents-scroller > #PanelUI-contents > .toolbarbutton-1:not([panel-multiview-anchor="true"]),
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-update-status,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > .PanelUI-notification-menu-item,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-status > #PanelUI-fxa-avatar,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-status > #PanelUI-fxa-label,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-fxa > #PanelUI-fxa-icon,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > toolbarseparator,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-footer-inner > toolbarseparator,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-customize,
|
||||
#PanelUI-multiView[viewtype="subview"] #PanelUI-mainView > #PanelUI-footer > #PanelUI-footer-inner > #PanelUI-help:not([panel-multiview-anchor="true"]) {
|
||||
opacity: .5;
|
||||
|
@ -566,28 +583,15 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
top: 25%;
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status]::after,
|
||||
#PanelUI-footer-addons > toolbarbutton::after {
|
||||
#PanelUI-footer-addons > toolbarbutton::after,
|
||||
.PanelUI-notification-menu-item::after {
|
||||
content: "";
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-inline-end: 16.5px;
|
||||
box-shadow: 0px 1px 0px rgba(255,255,255,.2) inset, 0px -1px 0px rgba(0,0,0,.1) inset, 0px 1px 0px rgba(12,27,38,.2);
|
||||
border-radius: 2px;
|
||||
background-size: contain;
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="succeeded"]::after {
|
||||
background-image: url(chrome://browser/skin/update-badge.svg);
|
||||
background-color: #74BF43;
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="failed"]::after {
|
||||
background-image: url(chrome://browser/skin/update-badge-failed.svg);
|
||||
background-color: #D90000;
|
||||
}
|
||||
|
||||
#PanelUI-footer-addons > toolbarbutton {
|
||||
background-color: #FFEFBF;
|
||||
/* Force border to override `#PanelUI-footer-addons > toolbarbutton` selector below */
|
||||
|
@ -646,7 +650,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
#PanelUI-update-status,
|
||||
.PanelUI-notification-menu-item,
|
||||
#PanelUI-help,
|
||||
#PanelUI-fxa-label,
|
||||
#PanelUI-fxa-icon,
|
||||
|
@ -665,16 +669,13 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
.PanelUI-notification-menu-item {
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
border-bottom: 1px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
#PanelUI-update-status > .toolbarbutton-text {
|
||||
.PanelUI-notification-menu-item > .toolbarbutton-text {
|
||||
width: 0; /* Fancy cropping solution for flexbox. */
|
||||
}
|
||||
|
||||
|
@ -683,7 +684,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
min-width: 46px;
|
||||
}
|
||||
|
||||
#PanelUI-update-status > .toolbarbutton-text,
|
||||
.PanelUI-notification-menu-item > .toolbarbutton-text,
|
||||
#PanelUI-fxa-label > .toolbarbutton-text,
|
||||
#PanelUI-footer-addons > toolbarbutton > .toolbarbutton-text,
|
||||
#PanelUI-customize > .toolbarbutton-text {
|
||||
|
@ -698,7 +699,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#PanelUI-update-status > .toolbarbutton-icon,
|
||||
.PanelUI-notification-menu-item > .toolbarbutton-icon,
|
||||
#PanelUI-fxa-label > .toolbarbutton-icon,
|
||||
#PanelUI-fxa-icon > .toolbarbutton-icon,
|
||||
#PanelUI-customize > .toolbarbutton-icon,
|
||||
|
@ -725,16 +726,14 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
padding-inline-start: 0px;
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
/* descend from #PanelUI-footer to add specificity, or else the
|
||||
padding-inline-start will be overridden */
|
||||
#PanelUI-footer > .PanelUI-notification-menu-item {
|
||||
width: calc(@menuPanelWidth@ + 30px);
|
||||
padding-inline-start: 15px;
|
||||
border-inline-start-style: none;
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
list-style-image: url(chrome://branding/content/icon16.png);
|
||||
}
|
||||
|
||||
#PanelUI-fxa-label,
|
||||
#PanelUI-fxa-icon {
|
||||
list-style-image: url(chrome://browser/skin/sync-horizontalbar.png);
|
||||
|
@ -980,34 +979,19 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
|||
box-shadow: 0 1px 0 hsla(210,4%,10%,.05) inset;
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
.PanelUI-notification-menu-item {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="succeeded"] {
|
||||
background-color: hsla(96,65%,75%,.5);
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="succeeded"]:not([disabled]):hover {
|
||||
.PanelUI-notification-menu-item:not([disabled]):hover {
|
||||
background-color: hsla(96,65%,75%,.8);
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="succeeded"]:not([disabled]):hover:active {
|
||||
.PanelUI-notification-menu-item:not([disabled]):hover:active {
|
||||
background-color: hsl(96,65%,75%);
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="failed"] {
|
||||
background-color: hsla(359,69%,84%,.5);
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="failed"]:not([disabled]):hover {
|
||||
background-color: hsla(359,69%,84%,.8);
|
||||
}
|
||||
|
||||
#PanelUI-update-status[update-status="failed"]:not([disabled]):hover:active {
|
||||
background-color: hsl(359,69%,84%);
|
||||
}
|
||||
|
||||
#PanelUI-quit:not([disabled]):hover {
|
||||
background-color: #d94141;
|
||||
outline-color: #c23a3a;
|
||||
|
@ -1712,7 +1696,9 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
|
|||
linear-gradient(rgba(255,255,255,0.3), transparent);
|
||||
}
|
||||
|
||||
#PanelUI-update-status {
|
||||
#PanelUI-update-restart-menu-item,
|
||||
#PanelUI-update-available-menu-item,
|
||||
#PanelUI-update-manual-menu-item {
|
||||
list-style-image: url(chrome://branding/content/icon32.png);
|
||||
}
|
||||
|
||||
|
@ -1749,7 +1735,7 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
|
|||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
#PanelUI-update-status > .toolbarbutton-icon,
|
||||
.PanelUI-notification-menu-item > .toolbarbutton-icon,
|
||||
#PanelUI-fxa-label > .toolbarbutton-icon,
|
||||
#PanelUI-fxa-icon > .toolbarbutton-icon,
|
||||
#PanelUI-customize > .toolbarbutton-icon,
|
||||
|
|
|
@ -306,3 +306,11 @@ html|*#webRTC-previewVideo {
|
|||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
/* UPDATE */
|
||||
.popup-notification-icon[popupid="update-available"],
|
||||
.popup-notification-icon[popupid="update-manual"],
|
||||
.popup-notification-icon[popupid="update-restart"] {
|
||||
background: #74BF43 url(chrome://browser/skin/notification-icons.svg#update) no-repeat center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,12 @@
|
|||
fill: white;
|
||||
fill-opacity: 1;
|
||||
}
|
||||
|
||||
#update-icon {
|
||||
stroke: #fff;
|
||||
stroke-width: 3px;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
|
@ -62,6 +68,7 @@
|
|||
<path id="plugin-icon" d="m 2,26 a 2,2 0 0 0 2,2 l 24,0 a 2,2 0 0 0 2,-2 l 0,-16 a 2,2 0 0 0 -2,-2 l -24,0 a 2,2 0 0 0 -2,2 z m 2,-20 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z m 14,0 10,0 0,-2 a 2,2 0 0 0 -2,-2 l -6,0 a 2,2 0 0 0 -2,2 z" />
|
||||
<path id="popup-icon" d="m 2,24 a 4,4 0 0 0 4,4 l 8,0 a 10,10 0 0 1 -2,-4 l -4,0 a 2,2 0 0 1 -2,-2 l 0,-12 18,0 0,2 a 10,10 0 0 1 4,2 l 0,-8 a 4,4 0 0 0 -4,-4 l -18,0 a 4,4 0 0 0 -4,4 z m 12,-2.1 a 8,8 0 1 1 0,0.2 m 10.7,-4.3 a 5,5 0 0 0 -6.9,6.9 z m -5.4,8.4 a 5,5 0 0 0 6.9,-6.9 z" />
|
||||
<path id="screen-icon" d="m 2,18 a 2,2 0 0 0 2,2 l 2,0 0,-6 a 4,4 0 0 1 4,-4 l 14,0 0,-6 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z m 6,10 a 2,2 0 0 0 2,2 l 18,0 a 2,2 0 0 0 2,-2 l 0,-14 a 2,2 0 0 0 -2,-2 l -18,0 a 2,2 0 0 0 -2,2 z" />
|
||||
<path id="update-icon" d="M 16,9 L 16,24 M 16,9 L 11,14 M 16,9 L 21,14" />
|
||||
|
||||
<clipPath id="blocked-clipPath">
|
||||
<path d="m 0,0 0,31 31,-31 z m 6,32 26,0 0,-26 z"/>
|
||||
|
@ -109,6 +116,7 @@
|
|||
<use id="screen-sharing" xlink:href="#screen-icon"/>
|
||||
<use id="screen-indicator" xlink:href="#screen-icon"/>
|
||||
<use id="screen-blocked" class="blocked" xlink:href="#screen-icon" />
|
||||
<use id="update" xlink:href="#update-icon" />
|
||||
|
||||
<path id="strikeout" d="m 2,28 2,2 26,-26 -2,-2 z"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 7.1 KiB После Ширина: | Высота: | Размер: 7.3 KiB |
|
@ -2,5 +2,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/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10px" height="10px">
|
||||
<polygon points="4,9 4,5 2,5 5,1 8,5 6,5 6,9" fill="#fff"/>
|
||||
<line x1="5" x2="5" y1="9" y2="2" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<line x1="5" x2="2" y1="2" y2="5" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<line x1="5" x2="8" y1="2" y2="5" stroke="#fff" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 355 B После Ширина: | Высота: | Размер: 577 B |
|
@ -277,7 +277,7 @@ TabTarget.prototype = {
|
|||
return this._form;
|
||||
},
|
||||
|
||||
// Get a promise of the root form returned by a listTabs request. This promise
|
||||
// Get a promise of the root form returned by a getRoot request. This promise
|
||||
// is cached.
|
||||
get root() {
|
||||
if (!this._root) {
|
||||
|
@ -288,7 +288,7 @@ TabTarget.prototype = {
|
|||
|
||||
_getRoot: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.listTabs(response => {
|
||||
this.client.mainRoot.getRoot(response => {
|
||||
if (response.error) {
|
||||
reject(new Error(response.error + ": " + response.message));
|
||||
return;
|
||||
|
|
|
@ -457,10 +457,6 @@ netmonitor.tab.timings=Timings
|
|||
# in the network details pane identifying the stack-trace tab.
|
||||
netmonitor.tab.stackTrace=Stack Trace
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.tab.preview): This is the label displayed
|
||||
# in the network details pane identifying the preview tab.
|
||||
netmonitor.tab.preview=Preview
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.tab.security): This is the label displayed
|
||||
# in the network details pane identifying the security tab.
|
||||
netmonitor.tab.security=Security
|
||||
|
|
|
@ -2,6 +2,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/. */
|
||||
|
||||
@import "chrome://devtools/skin/widgets.css";
|
||||
@import "resource://devtools/client/shared/components/splitter/split-box.css";
|
||||
@import "resource://devtools/client/shared/components/tree/tree-view.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/tabs.css";
|
||||
|
|
|
@ -12,7 +12,6 @@ DevToolsModules(
|
|||
'monitor-panel.js',
|
||||
'network-details-panel.js',
|
||||
'params-panel.js',
|
||||
'preview-panel.js',
|
||||
'properties-view.js',
|
||||
'request-list-content.js',
|
||||
'request-list-empty-notice.js',
|
||||
|
|
|
@ -1,35 +0,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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DOM, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const { div, iframe } = DOM;
|
||||
|
||||
/*
|
||||
* Preview panel component
|
||||
* Display HTML content within a sandbox enabled iframe
|
||||
*/
|
||||
function PreviewPanel({ request }) {
|
||||
const htmlBody = request.responseContent ?
|
||||
request.responseContent.content.text : "";
|
||||
|
||||
return (
|
||||
div({ className: "panel-container" },
|
||||
iframe({
|
||||
sandbox: "",
|
||||
srcDoc: typeof htmlBody === "string" ? htmlBody : "",
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
PreviewPanel.displayName = "PreviewPanel";
|
||||
|
||||
PreviewPanel.propTypes = {
|
||||
request: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
module.exports = PreviewPanel;
|
|
@ -10,7 +10,6 @@ const {
|
|||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const Actions = require("../actions/index");
|
||||
const { Filters } = require("../utils/filter-predicates");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { getSelectedRequest } = require("../selectors/index");
|
||||
|
||||
|
@ -20,7 +19,6 @@ const TabPanel = createFactory(require("devtools/client/shared/components/tabs/t
|
|||
const CookiesPanel = createFactory(require("./cookies-panel"));
|
||||
const HeadersPanel = createFactory(require("./headers-panel"));
|
||||
const ParamsPanel = createFactory(require("./params-panel"));
|
||||
const PreviewPanel = createFactory(require("./preview-panel"));
|
||||
const ResponsePanel = createFactory(require("./response-panel"));
|
||||
const SecurityPanel = createFactory(require("./security-panel"));
|
||||
const StackTracePanel = createFactory(require("./stack-trace-panel"));
|
||||
|
@ -29,7 +27,6 @@ const TimingsPanel = createFactory(require("./timings-panel"));
|
|||
const COOKIES_TITLE = L10N.getStr("netmonitor.tab.cookies");
|
||||
const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
|
||||
const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params");
|
||||
const PREVIEW_TITLE = L10N.getStr("netmonitor.tab.preview");
|
||||
const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
|
||||
const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
|
||||
const STACK_TRACE_TITLE = L10N.getStr("netmonitor.tab.stackTrace");
|
||||
|
@ -100,13 +97,6 @@ function TabboxPanel({
|
|||
},
|
||||
SecurityPanel({ request }),
|
||||
),
|
||||
Filters.html(request) &&
|
||||
TabPanel({
|
||||
id: "preview",
|
||||
title: PREVIEW_TITLE,
|
||||
},
|
||||
PreviewPanel({ request }),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ const {
|
|||
} = require("./index");
|
||||
|
||||
const { getFormatStr } = require("../utils/l10n");
|
||||
const { getToplevelWindow } = require("sdk/window/utils");
|
||||
const { getToplevelWindow } = require("../utils/window");
|
||||
const { Task: { spawn } } = require("devtools/shared/task");
|
||||
const e10s = require("../utils/e10s");
|
||||
const Services = require("Services");
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const flags = require("devtools/shared/flags");
|
||||
const { getToplevelWindow } = require("sdk/window/utils");
|
||||
const { getToplevelWindow } = require("../utils/window");
|
||||
const { DOM: dom, createClass, addons, PropTypes } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const { require } = BrowserLoader({
|
|||
});
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const Telemetry = require("devtools/client/shared/telemetry");
|
||||
const { loadSheet } = require("sdk/stylesheet/utils");
|
||||
const { loadAgentSheet } = require("./utils/css");
|
||||
|
||||
const { createFactory, createElement } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
@ -42,9 +42,10 @@ let bootstrap = {
|
|||
init: Task.async(function* () {
|
||||
// Load a special UA stylesheet to reset certain styles such as dropdown
|
||||
// lists.
|
||||
loadSheet(window,
|
||||
"resource://devtools/client/responsive.html/responsive-ua.css",
|
||||
"agent");
|
||||
loadAgentSheet(
|
||||
window,
|
||||
"resource://devtools/client/responsive.html/responsive-ua.css"
|
||||
);
|
||||
this.telemetry.toolOpened("responsive");
|
||||
let store = this.store = Store();
|
||||
let provider = createElement(Provider, { store }, App());
|
||||
|
|
|
@ -8,8 +8,7 @@ const { Ci } = require("chrome");
|
|||
const promise = require("promise");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { getOwnerWindow } = require("sdk/tabs/utils");
|
||||
const { startup } = require("sdk/window/helpers");
|
||||
const { startup } = require("./utils/window");
|
||||
const message = require("./utils/message");
|
||||
const { swapToInnerBrowser } = require("./browser/swap");
|
||||
const { EmulationFront } = require("devtools/shared/fronts/emulation");
|
||||
|
@ -145,7 +144,7 @@ const ResponsiveUIManager = exports.ResponsiveUIManager = {
|
|||
* @return boolean
|
||||
*/
|
||||
isActiveForWindow(window) {
|
||||
return [...this.activeTabs.keys()].some(t => getOwnerWindow(t) === window);
|
||||
return [...this.activeTabs.keys()].some(t => t.ownerGlobal === window);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -209,7 +208,7 @@ const ResponsiveUIManager = exports.ResponsiveUIManager = {
|
|||
}
|
||||
},
|
||||
|
||||
setMenuCheckFor: Task.async(function* (tab, window = getOwnerWindow(tab)) {
|
||||
setMenuCheckFor: Task.async(function* (tab, window = tab.ownerGlobal) {
|
||||
yield startup(window);
|
||||
|
||||
let menu = window.document.getElementById("menu_responsiveUI");
|
||||
|
|
|
@ -7,18 +7,18 @@
|
|||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,";
|
||||
|
||||
const tabUtils = require("sdk/tabs/utils");
|
||||
const { startup } = require("sdk/window/helpers");
|
||||
const { startup } = require("devtools/client/responsive.html/utils/window");
|
||||
|
||||
const activateTab = (tab) => new Promise(resolve => {
|
||||
let { tabContainer } = tabUtils.getOwnerWindow(tab).gBrowser;
|
||||
let { gBrowser } = tab.ownerGlobal;
|
||||
let { tabContainer } = gBrowser;
|
||||
|
||||
tabContainer.addEventListener("TabSelect", function listener({type}) {
|
||||
tabContainer.removeEventListener(type, listener);
|
||||
resolve();
|
||||
});
|
||||
|
||||
tabUtils.activateTab(tab);
|
||||
gBrowser.selectedTab = tab;
|
||||
});
|
||||
|
||||
const isMenuChecked = () => {
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,";
|
||||
|
||||
const { getMostRecentBrowserWindow } = require("sdk/window/utils");
|
||||
|
||||
const isMenuCheckedFor = ({document}) => {
|
||||
let menu = document.getElementById("menu_responsiveUI");
|
||||
return menu.getAttribute("checked") === "true";
|
||||
|
@ -22,7 +20,7 @@ add_task(function* () {
|
|||
function* (browser) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
|
||||
is(window1, getMostRecentBrowserWindow(),
|
||||
is(window1, Services.wm.getMostRecentWindow("navigator:browser"),
|
||||
"The new window is the active one");
|
||||
|
||||
ok(!isMenuCheckedFor(window1),
|
||||
|
@ -41,7 +39,7 @@ add_task(function* () {
|
|||
|
||||
yield BrowserTestUtils.closeWindow(window1);
|
||||
|
||||
is(window, getMostRecentBrowserWindow(),
|
||||
is(window, Services.wm.getMostRecentWindow("navigator:browser"),
|
||||
"The original window is the active one");
|
||||
|
||||
ok(!isMenuCheckedFor(window),
|
||||
|
|
|
@ -36,7 +36,6 @@ const TEST_URI_ROOT = "http://example.com/browser/devtools/client/responsive.htm
|
|||
const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
|
||||
|
||||
const { _loadPreferredDevices } = require("devtools/client/responsive.html/actions/devices");
|
||||
const { getOwnerWindow } = require("sdk/tabs/utils");
|
||||
const asyncStorage = require("devtools/shared/async-storage");
|
||||
const { addDevice, removeDevice } = require("devtools/client/shared/devices");
|
||||
|
||||
|
@ -72,7 +71,7 @@ const { ResponsiveUIManager } = require("resource://devtools/client/responsivede
|
|||
var openRDM = Task.async(function* (tab) {
|
||||
info("Opening responsive design mode");
|
||||
let manager = ResponsiveUIManager;
|
||||
let ui = yield manager.openIfNeeded(getOwnerWindow(tab), tab);
|
||||
let ui = yield manager.openIfNeeded(tab.ownerGlobal, tab);
|
||||
info("Responsive design mode opened");
|
||||
return { ui, manager };
|
||||
});
|
||||
|
@ -83,7 +82,7 @@ var openRDM = Task.async(function* (tab) {
|
|||
var closeRDM = Task.async(function* (tab, options) {
|
||||
info("Closing responsive design mode");
|
||||
let manager = ResponsiveUIManager;
|
||||
yield manager.closeIfNeeded(getOwnerWindow(tab), tab, options);
|
||||
yield manager.closeIfNeeded(tab.ownerGlobal, tab, options);
|
||||
info("Responsive design mode closed");
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* 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 { getDOMWindowUtils } = require("./window");
|
||||
|
||||
/**
|
||||
* Synchronously loads an agent style sheet from `uri` and adds it to the list of
|
||||
* additional style sheets of the document. The sheets added takes effect immediately,
|
||||
* and only on the document of the `window` given.
|
||||
*/
|
||||
function loadAgentSheet(window, url) {
|
||||
let winUtils = getDOMWindowUtils(window);
|
||||
winUtils.loadSheetUsingURIString(url, winUtils.AGENT_SHEET);
|
||||
}
|
||||
exports.loadAgentSheet = loadAgentSheet;
|
|
@ -5,7 +5,9 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'css.js',
|
||||
'e10s.js',
|
||||
'l10n.js',
|
||||
'message.js',
|
||||
'window.js',
|
||||
)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* 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 { Ci } = require("chrome");
|
||||
const Services = require("Services");
|
||||
|
||||
/**
|
||||
* Returns the `nsIDOMWindow` toplevel window for any child/inner window
|
||||
*/
|
||||
function getToplevelWindow(window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
}
|
||||
exports.getToplevelWindow = getToplevelWindow;
|
||||
|
||||
function getDOMWindowUtils(window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
}
|
||||
exports.getDOMWindowUtils = getDOMWindowUtils;
|
||||
|
||||
/**
|
||||
* Check if the given browser window has finished the startup.
|
||||
* @params {nsIDOMWindow} window
|
||||
*/
|
||||
const isStartupFinished = (window) =>
|
||||
window.gBrowserInit &&
|
||||
window.gBrowserInit.delayedStartupFinished;
|
||||
|
||||
function startup(window) {
|
||||
return new Promise(resolve => {
|
||||
if (isStartupFinished(window)) {
|
||||
resolve(window);
|
||||
return;
|
||||
}
|
||||
Services.obs.addObserver(function listener({ subject }) {
|
||||
if (subject === window) {
|
||||
Services.obs.removeObserver(listener, "browser-delayed-startup-finished");
|
||||
resolve(window);
|
||||
}
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
});
|
||||
}
|
||||
exports.startup = startup;
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 84 KiB |
|
@ -18,7 +18,7 @@ const {getCurrentZoom, getFrameOffsets} = require("devtools/shared/layout/utils"
|
|||
loader.lazyGetter(this, "clipboardHelper",
|
||||
() => Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper));
|
||||
loader.lazyGetter(this, "l10n",
|
||||
() => Services.strings.createBundle("chrome://devtools/locale/eyedropper.properties"));
|
||||
() => Services.strings.createBundle("chrome://devtools-shared/locale/eyedropper.properties"));
|
||||
|
||||
const ZOOM_LEVEL_PREF = "devtools.eyedropper.zoom";
|
||||
const FORMAT_PREF = "devtools.defaultColorUnit";
|
||||
|
|
|
@ -244,84 +244,95 @@ RootActor.prototype = {
|
|||
this._processActors.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the "root" form, which lists all the global actors that affect the entire
|
||||
* browser. This can replace usages of `listTabs` that only wanted the global actors
|
||||
* and didn't actually care about tabs.
|
||||
*/
|
||||
onGetRoot: function () {
|
||||
let reply = {
|
||||
from: this.actorID,
|
||||
};
|
||||
|
||||
// Create global actors
|
||||
if (!this._globalActorPool) {
|
||||
this._globalActorPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._globalActorPool);
|
||||
}
|
||||
this._createExtraActors(this._parameters.globalActorFactories, this._globalActorPool);
|
||||
|
||||
// List the global actors
|
||||
this._appendExtraActors(reply);
|
||||
|
||||
return reply;
|
||||
},
|
||||
|
||||
/* The 'listTabs' request and the 'tabListChanged' notification. */
|
||||
|
||||
/**
|
||||
* Handles the listTabs request. The actors will survive until at least
|
||||
* the next listTabs request.
|
||||
*
|
||||
* ⚠ WARNING ⚠ This can be a very expensive operation, especially if there are many
|
||||
* open tabs. It will cause us to visit every tab, load a frame script, start a
|
||||
* debugger server, and read some data. With lazy tab support (bug 906076), this
|
||||
* would trigger any lazy tabs to be loaded, greatly increasing resource usage. Avoid
|
||||
* this method whenever possible.
|
||||
*/
|
||||
onListTabs: function () {
|
||||
onListTabs: async function () {
|
||||
let tabList = this._parameters.tabList;
|
||||
if (!tabList) {
|
||||
return { from: this.actorID, error: "noTabs",
|
||||
message: "This root actor has no browser tabs." };
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that a client has requested the list of tabs, we reattach the onListChanged
|
||||
* listener in order to be notified if the list of tabs changes again in the future.
|
||||
*/
|
||||
// Now that a client has requested the list of tabs, we reattach the onListChanged
|
||||
// listener in order to be notified if the list of tabs changes again in the future.
|
||||
tabList.onListChanged = this._onTabListChanged;
|
||||
|
||||
/*
|
||||
* Walk the tab list, accumulating the array of tab actors for the
|
||||
* reply, and moving all the actors to a new ActorPool. We'll
|
||||
* replace the old tab actor pool with the one we build here, thus
|
||||
* retiring any actors that didn't get listed again, and preparing any
|
||||
* new actors to receive packets.
|
||||
*/
|
||||
// Walk the tab list, accumulating the array of tab actors for the reply, and moving
|
||||
// all the actors to a new ActorPool. We'll replace the old tab actor pool with the
|
||||
// one we build here, thus retiring any actors that didn't get listed again, and
|
||||
// preparing any new actors to receive packets.
|
||||
let newActorPool = new ActorPool(this.conn);
|
||||
let tabActorList = [];
|
||||
let selected;
|
||||
return tabList.getList().then((tabActors) => {
|
||||
for (let tabActor of tabActors) {
|
||||
if (tabActor.exited) {
|
||||
// Tab actor may have exited while we were gathering the list.
|
||||
continue;
|
||||
}
|
||||
if (tabActor.selected) {
|
||||
selected = tabActorList.length;
|
||||
}
|
||||
tabActor.parentID = this.actorID;
|
||||
newActorPool.addActor(tabActor);
|
||||
tabActorList.push(tabActor);
|
||||
}
|
||||
/* DebuggerServer.addGlobalActor support: create actors. */
|
||||
if (!this._globalActorPool) {
|
||||
this._globalActorPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._globalActorPool);
|
||||
}
|
||||
this._createExtraActors(this._parameters.globalActorFactories,
|
||||
this._globalActorPool);
|
||||
/*
|
||||
* Drop the old actorID -> actor map. Actors that still mattered were
|
||||
* added to the new map; others will go away.
|
||||
*/
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
this._tabActorPool = newActorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
let reply = {
|
||||
"from": this.actorID,
|
||||
"selected": selected || 0,
|
||||
"tabs": tabActorList.map(actor => actor.form())
|
||||
};
|
||||
|
||||
/* If a root window is accessible, include its URL. */
|
||||
if (this.url) {
|
||||
reply.url = this.url;
|
||||
let tabActors = await tabList.getList();
|
||||
for (let tabActor of tabActors) {
|
||||
if (tabActor.exited) {
|
||||
// Tab actor may have exited while we were gathering the list.
|
||||
continue;
|
||||
}
|
||||
if (tabActor.selected) {
|
||||
selected = tabActorList.length;
|
||||
}
|
||||
tabActor.parentID = this.actorID;
|
||||
newActorPool.addActor(tabActor);
|
||||
tabActorList.push(tabActor);
|
||||
}
|
||||
|
||||
/* DebuggerServer.addGlobalActor support: name actors in 'listTabs' reply. */
|
||||
this._appendExtraActors(reply);
|
||||
// Start with the root reply, which includes the global actors for the whole browser.
|
||||
let reply = this.onGetRoot();
|
||||
|
||||
return reply;
|
||||
// Drop the old actorID -> actor map. Actors that still mattered were added to the
|
||||
// new map; others will go away.
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
this._tabActorPool = newActorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
// We'll extend the reply here to also mention all the tabs.
|
||||
Object.assign(reply, {
|
||||
selected: selected || 0,
|
||||
tabs: tabActorList.map(actor => actor.form()),
|
||||
});
|
||||
|
||||
return reply;
|
||||
},
|
||||
|
||||
onGetTab: function (options) {
|
||||
onGetTab: async function (options) {
|
||||
let tabList = this._parameters.tabList;
|
||||
if (!tabList) {
|
||||
return { error: "noTabs",
|
||||
|
@ -331,22 +342,25 @@ RootActor.prototype = {
|
|||
this._tabActorPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
}
|
||||
return tabList.getTab(options)
|
||||
.then(tabActor => {
|
||||
tabActor.parentID = this.actorID;
|
||||
this._tabActorPool.addActor(tabActor);
|
||||
|
||||
return { tab: tabActor.form() };
|
||||
}, error => {
|
||||
if (error.error) {
|
||||
let tabActor;
|
||||
try {
|
||||
tabActor = await tabList.getTab(options);
|
||||
} catch (error) {
|
||||
if (error.error) {
|
||||
// Pipe expected errors as-is to the client
|
||||
return error;
|
||||
}
|
||||
return {
|
||||
error: "noTab",
|
||||
message: "Unexpected error while calling getTab(): " + error
|
||||
};
|
||||
});
|
||||
return error;
|
||||
}
|
||||
return {
|
||||
error: "noTab",
|
||||
message: "Unexpected error while calling getTab(): " + error
|
||||
};
|
||||
}
|
||||
|
||||
tabActor.parentID = this.actorID;
|
||||
this._tabActorPool.addActor(tabActor);
|
||||
|
||||
return { tab: tabActor.form() };
|
||||
},
|
||||
|
||||
onGetWindow: function ({ outerWindowID }) {
|
||||
|
@ -583,16 +597,17 @@ RootActor.prototype = {
|
|||
};
|
||||
|
||||
RootActor.prototype.requestTypes = {
|
||||
"listTabs": RootActor.prototype.onListTabs,
|
||||
"getTab": RootActor.prototype.onGetTab,
|
||||
"getWindow": RootActor.prototype.onGetWindow,
|
||||
"listAddons": RootActor.prototype.onListAddons,
|
||||
"listWorkers": RootActor.prototype.onListWorkers,
|
||||
"listServiceWorkerRegistrations": RootActor.prototype.onListServiceWorkerRegistrations,
|
||||
"listProcesses": RootActor.prototype.onListProcesses,
|
||||
"getProcess": RootActor.prototype.onGetProcess,
|
||||
"echo": RootActor.prototype.onEcho,
|
||||
"protocolDescription": RootActor.prototype.onProtocolDescription
|
||||
getRoot: RootActor.prototype.onGetRoot,
|
||||
listTabs: RootActor.prototype.onListTabs,
|
||||
getTab: RootActor.prototype.onGetTab,
|
||||
getWindow: RootActor.prototype.onGetWindow,
|
||||
listAddons: RootActor.prototype.onListAddons,
|
||||
listWorkers: RootActor.prototype.onListWorkers,
|
||||
listServiceWorkerRegistrations: RootActor.prototype.onListServiceWorkerRegistrations,
|
||||
listProcesses: RootActor.prototype.onListProcesses,
|
||||
getProcess: RootActor.prototype.onGetProcess,
|
||||
echo: RootActor.prototype.onEcho,
|
||||
protocolDescription: RootActor.prototype.onProtocolDescription
|
||||
};
|
||||
|
||||
exports.RootActor = RootActor;
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
|
||||
/* global XPCNativeWrapper */
|
||||
|
||||
const { Cu } = require("chrome");
|
||||
const { Cu, Cc, Ci } = require("chrome");
|
||||
|
||||
const events = require("sdk/event/core");
|
||||
const { on: systemOn, off: systemOff } = require("sdk/system/events");
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const { CallWatcherActor } = require("devtools/server/actors/call-watcher");
|
||||
const { createValueGrip } = require("devtools/server/actors/object");
|
||||
|
@ -19,6 +18,10 @@ const {
|
|||
webAudioSpec
|
||||
} = require("devtools/shared/specs/webaudio");
|
||||
const { WebAudioFront } = require("devtools/shared/fronts/webaudio");
|
||||
|
||||
const observerService = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
|
||||
const AUDIO_NODE_DEFINITION = require("devtools/server/actors/utils/audionodes.json");
|
||||
const ENABLE_AUTOMATION = false;
|
||||
const AUTOMATION_GRANULARITY = 2000;
|
||||
|
@ -413,7 +416,6 @@ exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
|
|||
// to the client in any way.
|
||||
this._nativeToActorID = new Map();
|
||||
|
||||
this._onDestroyNode = this._onDestroyNode.bind(this);
|
||||
this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
|
||||
this._onGlobalCreated = this._onGlobalCreated.bind(this);
|
||||
},
|
||||
|
@ -555,7 +557,13 @@ exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
|
|||
return;
|
||||
}
|
||||
this._initialized = false;
|
||||
systemOff("webaudio-node-demise", this._onDestroyNode);
|
||||
|
||||
try {
|
||||
observerService.removeObserver(this, "webaudio-node-demise");
|
||||
} catch (e) {
|
||||
// Maybe we've shutdown already and it's too late to remove the observer. So avoid
|
||||
// NS_ERROR_FAILURE errors with this silent try/catch.
|
||||
}
|
||||
|
||||
off(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
|
||||
off(this.tabActor, "window-ready", this._onGlobalCreated);
|
||||
|
@ -619,7 +627,7 @@ exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
|
|||
* Called on first audio node creation, signifying audio context usage
|
||||
*/
|
||||
_onStartContext: function () {
|
||||
systemOn("webaudio-node-demise", this._onDestroyNode);
|
||||
observerService.addObserver(this, "webaudio-node-demise", false);
|
||||
emit(this, "start-context");
|
||||
},
|
||||
|
||||
|
@ -677,20 +685,31 @@ exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
|
|||
emit(this, "create-node", actor);
|
||||
},
|
||||
|
||||
/** Called when `webaudio-node-demise` is triggered,
|
||||
* and emits the associated actor to the front if found.
|
||||
/**
|
||||
* Called by the ObserverService when webaudio-node-demise events are emitted.
|
||||
*/
|
||||
_onDestroyNode: function ({data}) {
|
||||
// Cast to integer.
|
||||
let nativeID = ~~data;
|
||||
observe: function (subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "webaudio-node-demise":
|
||||
// Cast the data to an integer.
|
||||
this._handleNodeDestroyed(~~data);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
let actor = this._getActorByNativeID(nativeID);
|
||||
/**
|
||||
* Handles `webaudio-node-demise` events. Emits the associated actor to the front if
|
||||
* found.
|
||||
* @param {Number} nodeNativeID The ID for the audio node.
|
||||
*/
|
||||
_handleNodeDestroyed: function (nodeNativeID) {
|
||||
let actor = this._getActorByNativeID(nodeNativeID);
|
||||
|
||||
// If actorID exists, emit; in the case where we get demise
|
||||
// notifications for a document that no longer exists,
|
||||
// the mapping should not be found, so we do not emit an event.
|
||||
if (actor) {
|
||||
this._nativeToActorID.delete(nativeID);
|
||||
this._nativeToActorID.delete(nodeNativeID);
|
||||
emit(this, "destroy-node", actor);
|
||||
}
|
||||
},
|
||||
|
@ -736,7 +755,7 @@ exports.WebAudioActor = protocol.ActorClassWithSpec(webAudioSpec, {
|
|||
if (this._nativeToActorID) {
|
||||
this._nativeToActorID.clear();
|
||||
}
|
||||
systemOff("webaudio-node-demise", this._onDestroyNode);
|
||||
observerService.removeObserver(this, "webaudio-node-demise");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1652,6 +1652,13 @@ RootClient.prototype = {
|
|||
constructor: RootClient,
|
||||
|
||||
/**
|
||||
* Gets the "root" form, which lists all the global actors that affect the entire
|
||||
* browser. This can replace usages of `listTabs` that only wanted the global actors
|
||||
* and didn't actually care about tabs.
|
||||
*/
|
||||
getRoot: DebuggerClient.requester({ type: "getRoot" }),
|
||||
|
||||
/**
|
||||
* List the open tabs.
|
||||
*
|
||||
* @param function onResponse
|
||||
|
|
|
@ -3143,6 +3143,21 @@ ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
PURLClassifierLocalChild*
|
||||
ContentChild::AllocPURLClassifierLocalChild(const URIParams& aUri,
|
||||
const nsCString& aTables)
|
||||
{
|
||||
return new URLClassifierLocalChild();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPURLClassifierLocalChild(PURLClassifierLocalChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
// The IPC code will call this method asking us to assign an event target to new
|
||||
// actors created by the ContentParent.
|
||||
already_AddRefed<nsIEventTarget>
|
||||
|
|
|
@ -610,6 +610,7 @@ public:
|
|||
return mFontFamilies;
|
||||
}
|
||||
|
||||
// PURLClassifierChild
|
||||
virtual PURLClassifierChild*
|
||||
AllocPURLClassifierChild(const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
|
@ -617,6 +618,13 @@ public:
|
|||
virtual bool
|
||||
DeallocPURLClassifierChild(PURLClassifierChild* aActor) override;
|
||||
|
||||
// PURLClassifierLocalChild
|
||||
virtual PURLClassifierLocalChild*
|
||||
AllocPURLClassifierLocalChild(const URIParams& aUri,
|
||||
const nsCString& aTables) override;
|
||||
virtual bool
|
||||
DeallocPURLClassifierLocalChild(PURLClassifierLocalChild* aActor) override;
|
||||
|
||||
nsTArray<LookAndFeelInt>&
|
||||
LookAndFeelCache() {
|
||||
return mLookAndFeelCache;
|
||||
|
|
|
@ -5158,6 +5158,9 @@ ContentParent::RecvRecordChildEvents(nsTArray<mozilla::Telemetry::ChildEventData
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// PURLClassifierParent
|
||||
|
||||
PURLClassifierParent*
|
||||
ContentParent::AllocPURLClassifierParent(const Principal& aPrincipal,
|
||||
const bool& aUseTrackingProtection,
|
||||
|
@ -5200,6 +5203,48 @@ ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor)
|
|||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// PURLClassifierLocalParent
|
||||
|
||||
PURLClassifierLocalParent*
|
||||
ContentParent::AllocPURLClassifierLocalParent(const URIParams& aURI,
|
||||
const nsCString& aTables)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<URLClassifierLocalParent> actor = new URLClassifierLocalParent();
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvPURLClassifierLocalConstructor(PURLClassifierLocalParent* aActor,
|
||||
const URIParams& aURI,
|
||||
const nsCString& aTables)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
||||
if (!uri) {
|
||||
NS_WARNING("Failed to DeserializeURI");
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
auto* actor = static_cast<URLClassifierLocalParent*>(aActor);
|
||||
return actor->StartClassify(uri, aTables);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPURLClassifierLocalParent(PURLClassifierLocalParent* aActor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
RefPtr<URLClassifierLocalParent> actor =
|
||||
dont_AddRef(static_cast<URLClassifierLocalParent*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvClassifyLocal(const URIParams& aURI, const nsCString& aTables,
|
||||
nsresult *aRv, nsTArray<nsCString>* aResults)
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче