зеркало из https://github.com/mozilla/gecko-dev.git
Merge f-t to m-c, a=merge
This commit is contained in:
Коммит
6dcfd648be
|
@ -15,6 +15,25 @@
|
|||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../states.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
// Front end stuff sometimes likes to stuff things in the hidden window(s)
|
||||
// in which case there's accessibles for that content.
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Force the creation of an accessible for the hidden window's document.
|
||||
var doc = Services.appShell.hiddenDOMWindow.document;
|
||||
gAccRetrieval.getAccessibleFor(doc);
|
||||
|
||||
// The private hidden window will be lazily created that's why we need to do
|
||||
// it here *before* loading '../events.js' or else we'll have a duplicate
|
||||
// reorder event.
|
||||
var privateDoc = Services.appShell.hiddenPrivateDOMWindow.document;
|
||||
|
||||
// Force the creation of an accessible for the private hidden window's doc.
|
||||
gAccRetrieval.getAccessibleFor(privateDoc);
|
||||
</script>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../events.js"></script>
|
||||
|
||||
|
@ -174,6 +193,12 @@
|
|||
var accTree = {
|
||||
role: ROLE_APP_ROOT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_CHROME_WINDOW
|
||||
},
|
||||
{
|
||||
role: ROLE_CHROME_WINDOW
|
||||
},
|
||||
{
|
||||
role: ROLE_CHROME_WINDOW
|
||||
},
|
||||
|
|
|
@ -860,11 +860,7 @@ pref("browser.preferences.instantApply", true);
|
|||
#endif
|
||||
|
||||
// Toggles between the two Preferences implementations, pop-up window and in-content
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
pref("browser.preferences.inContent", true);
|
||||
#else
|
||||
pref("browser.preferences.inContent", false);
|
||||
#endif
|
||||
|
||||
pref("browser.download.show_plugins_in_list", true);
|
||||
pref("browser.download.hide_plugins_without_extensions", true);
|
||||
|
@ -1032,6 +1028,8 @@ pref("browser.rights.3.shown", false);
|
|||
pref("browser.rights.override", true);
|
||||
#endif
|
||||
|
||||
pref("browser.selfsupport.url", "http://self-repair.mozilla.org/%LOCALE%/repair");
|
||||
|
||||
pref("browser.sessionstore.resume_from_crash", true);
|
||||
pref("browser.sessionstore.resume_session_once", false);
|
||||
|
||||
|
|
|
@ -25,15 +25,6 @@ let gEMEHandler = {
|
|||
return "<label class='text-link' href='" + baseURL + "drm-content'>" +
|
||||
text + "</label>";
|
||||
},
|
||||
getDRMLabel: function(keySystem) {
|
||||
if (keySystem.startsWith("com.adobe")) {
|
||||
return "Adobe Primetime";
|
||||
}
|
||||
if (keySystem == "org.w3.clearkey") {
|
||||
return "ClearKey";
|
||||
}
|
||||
return gNavigatorBundle.getString("emeNotifications.unknownDRMSoftware");
|
||||
},
|
||||
onDontAskAgain: function(menuPopupItem) {
|
||||
let button = menuPopupItem.parentNode.anchorNode;
|
||||
let bar = button.parentNode;
|
||||
|
@ -158,12 +149,11 @@ let gEMEHandler = {
|
|||
}
|
||||
|
||||
let msgPrefix = "emeNotifications.drmContentPlaying.";
|
||||
let msgId = msgPrefix + "message";
|
||||
let msgId = msgPrefix + "message2";
|
||||
let btnLabelId = msgPrefix + "button.label";
|
||||
let btnAccessKeyId = msgPrefix + "button.accesskey";
|
||||
|
||||
let drmProvider = this.getDRMLabel(keySystem);
|
||||
let message = gNavigatorBundle.getFormattedString(msgId, [drmProvider, this._brandShortName]);
|
||||
let message = gNavigatorBundle.getFormattedString(msgId, [this._brandShortName]);
|
||||
let anchorId = "eme-notification-icon";
|
||||
|
||||
let mainAction = {
|
||||
|
|
|
@ -91,6 +91,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "RemotePrompt",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "ContentPrefServiceParent",
|
||||
"resource://gre/modules/ContentPrefServiceParent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SelfSupportBackend",
|
||||
"resource:///modules/SelfSupportBackend.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
||||
"resource:///modules/sessionstore/SessionStore.jsm");
|
||||
|
||||
|
@ -627,6 +630,8 @@ BrowserGlue.prototype = {
|
|||
LoginManagerParent.init();
|
||||
ReaderParent.init();
|
||||
|
||||
SelfSupportBackend.init();
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
Services.prefs.addObserver(POLARIS_ENABLED, this, false);
|
||||
#endif
|
||||
|
@ -888,6 +893,8 @@ BrowserGlue.prototype = {
|
|||
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
|
||||
}
|
||||
|
||||
SelfSupportBackend.uninit();
|
||||
|
||||
CustomizationTabPreloader.uninit();
|
||||
WebappManager.uninit();
|
||||
#ifdef NIGHTLY_BUILD
|
||||
|
|
|
@ -344,6 +344,15 @@ this.UITour = {
|
|||
onPageEvent: function(aMessage, aEvent) {
|
||||
let browser = aMessage.target;
|
||||
let window = browser.ownerDocument.defaultView;
|
||||
|
||||
// Does the window have tabs? We need to make sure since windowless browsers do
|
||||
// not have tabs.
|
||||
if (!window.gBrowser) {
|
||||
// When using windowless browsers we don't have a valid |window|. If that's the case,
|
||||
// use the most recent window as a target for UITour functions (see Bug 1111022).
|
||||
window = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
}
|
||||
|
||||
let tab = window.gBrowser.getTabForBrowser(browser);
|
||||
let messageManager = browser.messageManager;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ support-files =
|
|||
uitour.html
|
||||
../UITour-lib.js
|
||||
|
||||
[browser_no_tabs.js]
|
||||
[browser_UITour.js]
|
||||
skip-if = os == "linux" || e10s # Intermittent failures, bug 951965
|
||||
[browser_UITour2.js]
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
/**
|
||||
* Create a frame in the |hiddenDOMWindow| to host a |browser|, then load the URL in the
|
||||
* latter.
|
||||
*
|
||||
* @param aURL
|
||||
* The URL to open in the browser.
|
||||
**/
|
||||
function createHiddenBrowser(aURL) {
|
||||
let deferred = Promise.defer();
|
||||
let hiddenDoc = Services.appShell.hiddenDOMWindow.document;
|
||||
|
||||
// Create a HTML iframe with a chrome URL, then this can host the browser.
|
||||
let iframe = hiddenDoc.createElementNS(HTML_NS, "iframe");
|
||||
iframe.setAttribute("src", "chrome://global/content/mozilla.xhtml");
|
||||
iframe.addEventListener("load", function onLoad() {
|
||||
iframe.removeEventListener("load", onLoad, true);
|
||||
|
||||
let browser = iframe.contentDocument.createElementNS(XUL_NS, "browser");
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("disableglobalhistory", "true");
|
||||
browser.setAttribute("src", aURL);
|
||||
|
||||
iframe.contentDocument.documentElement.appendChild(browser);
|
||||
deferred.resolve({frame: iframe, browser: browser});
|
||||
}, true);
|
||||
|
||||
hiddenDoc.documentElement.appendChild(iframe);
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the browser and the iframe.
|
||||
*
|
||||
* @param aFrame
|
||||
* The iframe to dismiss.
|
||||
* @param aBrowser
|
||||
* The browser to dismiss.
|
||||
*/
|
||||
function destroyHiddenBrowser(aFrame, aBrowser) {
|
||||
// Dispose of the hidden browser.
|
||||
aBrowser.remove();
|
||||
|
||||
// Take care of the frame holding our invisible browser.
|
||||
if (!Cu.isDeadWrapper(aFrame)) {
|
||||
aFrame.remove();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test that UITour works when called when no tabs are available (e.g., when using windowless
|
||||
* browsers).
|
||||
*/
|
||||
add_task(function* test_windowless_UITour(){
|
||||
// Get the URL for the test page.
|
||||
let pageURL = getRootDirectory(gTestPath) + "uitour.html";
|
||||
|
||||
// Allow the URL to use the UITour.
|
||||
info("Adding UITour permission to the test page.");
|
||||
let pageURI = Services.io.newURI(pageURL, null, null);
|
||||
Services.perms.add(pageURI, "uitour", Services.perms.ALLOW_ACTION);
|
||||
|
||||
// UITour's ping will resolve this promise.
|
||||
let deferredPing = Promise.defer();
|
||||
|
||||
// Create a windowless browser and test that UITour works in it.
|
||||
let browserPromise = createHiddenBrowser(pageURL);
|
||||
browserPromise.then(frameInfo => {
|
||||
isnot(frameInfo.browser, null, "The browser must exist and not be null.");
|
||||
|
||||
// Load UITour frame script.
|
||||
frameInfo.browser.messageManager.loadFrameScript(
|
||||
"chrome://browser/content/content-UITour.js", false);
|
||||
|
||||
// When the page loads, try to use UITour API.
|
||||
frameInfo.browser.addEventListener("load", function loadListener() {
|
||||
info("The test page was correctly loaded.");
|
||||
|
||||
frameInfo.browser.removeEventListener("load", loadListener, true);
|
||||
|
||||
// Get a reference to the UITour API.
|
||||
info("Testing access to the UITour API.");
|
||||
let contentWindow = Cu.waiveXrays(frameInfo.browser.contentDocument.defaultView);
|
||||
isnot(contentWindow, null, "The content window must exist and not be null.");
|
||||
|
||||
let uitourAPI = contentWindow.Mozilla.UITour;
|
||||
|
||||
// Test the UITour API with a ping.
|
||||
uitourAPI.ping(function() {
|
||||
info("Ping response received from the UITour API.");
|
||||
|
||||
// Make sure to clean up.
|
||||
destroyHiddenBrowser(frameInfo.frame, frameInfo.browser);
|
||||
|
||||
// Resolve our promise.
|
||||
deferredPing.resolve();
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
|
||||
// Wait for the UITour ping to complete.
|
||||
yield deferredPing.promise;
|
||||
});
|
|
@ -591,8 +591,8 @@ getUserMedia.sharingMenuMicrophoneWindow = %S (microphone and window)
|
|||
# origin for the sharing menu if no readable origin could be deduced from the URL.
|
||||
getUserMedia.sharingMenuUnknownHost = Unknown origin
|
||||
|
||||
# LOCALIZATION NOTE(emeNotifications.drmContentPlaying.message): %1$S is the vendor name of the DRM that's in use, %2$S is brandShortName.
|
||||
emeNotifications.drmContentPlaying.message = Some audio or video on this site uses %1$S DRM software, which may limit what %2$S can let you do with it.
|
||||
# LOCALIZATION NOTE(emeNotifications.drmContentPlaying.message2): %S is brandShortName.
|
||||
emeNotifications.drmContentPlaying.message2 = Some audio or video on this site uses DRM software, which may limit what %S can let you do with it.
|
||||
emeNotifications.drmContentPlaying.button.label = Configure…
|
||||
emeNotifications.drmContentPlaying.button.accesskey = C
|
||||
|
||||
|
@ -614,6 +614,11 @@ emeNotifications.drmContentCDMInsufficientVersion.message = %S is installing upd
|
|||
# LOCALIZATION NOTE(emeNotifications.drmContentCDMInstalling.message): NB: inserted via innerHTML, so please don't use <, > or & in this string. %S is brandShortName
|
||||
emeNotifications.drmContentCDMInstalling.message = %S is installing components needed to play the audio or video on this page. Please try again later.
|
||||
|
||||
# LOCALIZATION NOTE(emeNotifications.drmContentCDMNotSupported.64bit.message): NB: inserted via innerHTML, so please don't use <, > or & in this string. %1$S is brandShortName, %2$S will be the 'learn more' link
|
||||
emeNotifications.drmContentCDMNotSupported.64bit.message = The audio or video on this page requires DRM software that this 64-bit build of %1$S does not support. %2$S
|
||||
# LOCALIZATION NOTE(emeNotifications.drmContentCDMNotSupported.unsupportedOS.message): NB: inserted via innerHTML, so please don't use <, > or & in this string. %1$S is brandShortName, %2$S is the name of the user's OS (Windows, Linux, Mac OS X), %3$S will be the 'learn more' link
|
||||
emeNotifications.drmContentCDMNotSupported.unsupportedOS.message = The audio or video on this page requires DRM software that %1$S does not support on %2$S. %3$S
|
||||
|
||||
emeNotifications.optionsButton.label = Options
|
||||
emeNotifications.optionsButton.accesskey = O
|
||||
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
/* 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.EXPORTED_SYMBOLS = ["SelfSupportBackend"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HiddenFrame",
|
||||
"resource:///modules/HiddenFrame.jsm");
|
||||
|
||||
// Enables or disables the Self Support.
|
||||
const PREF_ENABLED = "browser.selfsupport.enabled";
|
||||
// Url to open in the Self Support browser, in the urlFormatter service format.
|
||||
const PREF_URL = "browser.selfsupport.url";
|
||||
// FHR status.
|
||||
const PREF_FHR_ENABLED = "datareporting.healthreport.service.enabled";
|
||||
// UITour status.
|
||||
const PREF_UITOUR_ENABLED = "browser.uitour.enabled";
|
||||
|
||||
// Controls the interval at which the self support page tries to reload in case of
|
||||
// errors.
|
||||
const RETRY_INTERVAL_MS = 30000;
|
||||
// Maximum number of SelfSupport page load attempts in case of failure.
|
||||
const MAX_RETRIES = 5;
|
||||
// The delay after which to load the self-support, at startup.
|
||||
const STARTUP_DELAY_MS = 5000;
|
||||
|
||||
const LOGGER_NAME = "Browser.SelfSupportBackend";
|
||||
const PREF_BRANCH_LOG = "browser.selfsupport.log.";
|
||||
const PREF_LOG_LEVEL = PREF_BRANCH_LOG + "level";
|
||||
const PREF_LOG_DUMP = PREF_BRANCH_LOG + "dump";
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
const UITOUR_FRAME_SCRIPT = "chrome://browser/content/content-UITour.js";
|
||||
|
||||
let gLogAppenderDump = null;
|
||||
|
||||
this.SelfSupportBackend = Object.freeze({
|
||||
init: function () {
|
||||
SelfSupportBackendInternal.init();
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
SelfSupportBackendInternal.uninit();
|
||||
},
|
||||
});
|
||||
|
||||
let SelfSupportBackendInternal = {
|
||||
// The browser element that will load the SelfSupport page.
|
||||
_browser: null,
|
||||
// The Id of the timer triggering delayed SelfSupport page load.
|
||||
_delayedLoadTimerId: null,
|
||||
// The HiddenFrame holding the _browser element.
|
||||
_frame: null,
|
||||
_log: null,
|
||||
_progressListener: null,
|
||||
|
||||
/**
|
||||
* Initializes the self support backend.
|
||||
*/
|
||||
init: function () {
|
||||
this._configureLogging();
|
||||
|
||||
this._log.trace("init");
|
||||
|
||||
Preferences.observe(PREF_BRANCH_LOG, this._configureLogging, this);
|
||||
|
||||
// Only allow to use SelfSupport if FHR is enabled.
|
||||
let fhrEnabled = Preferences.get(PREF_FHR_ENABLED, false);
|
||||
if (!fhrEnabled) {
|
||||
this._log.config("init - Disabling SelfSupport because Health Report is disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure UITour is enabled.
|
||||
let uiTourEnabled = Preferences.get(PREF_UITOUR_ENABLED, false);
|
||||
if (!uiTourEnabled) {
|
||||
this._log.config("init - Disabling SelfSupport because UITour is disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the preferences to see if we want this to be active.
|
||||
if (!Preferences.get(PREF_ENABLED, true)) {
|
||||
this._log.config("init - SelfSupport is disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(this, "sessionstore-windows-restored", false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shut down the self support backend, if active.
|
||||
*/
|
||||
uninit: function () {
|
||||
this._log.trace("uninit");
|
||||
|
||||
Preferences.ignore(PREF_BRANCH_LOG, this._configureLogging, this);
|
||||
|
||||
// Cancel delayed loading, if still active, when shutting down.
|
||||
clearTimeout(this._delayedLoadTimerId);
|
||||
|
||||
// Dispose of the hidden browser.
|
||||
if (this._browser !== null) {
|
||||
if (this._browser.contentWindow) {
|
||||
this._browser.contentWindow.removeEventListener("DOMWindowClose", this, true);
|
||||
}
|
||||
|
||||
if (this._progressListener) {
|
||||
this._browser.removeProgressListener(this._progressListener);
|
||||
this._progressListener.destroy();
|
||||
this._progressListener = null;
|
||||
}
|
||||
|
||||
this._browser.remove();
|
||||
this._browser = null;
|
||||
}
|
||||
|
||||
if (this._frame) {
|
||||
this._frame.destroy();
|
||||
this._frame = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle notifications. Once all windows are created, we wait a little bit more
|
||||
* since tabs might still be loading. Then, we open the self support.
|
||||
*/
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
this._log.trace("observe - Topic " + aTopic);
|
||||
|
||||
if (aTopic === "sessionstore-windows-restored") {
|
||||
Services.obs.removeObserver(this, "sessionstore-windows-restored");
|
||||
this._delayedLoadTimerId = setTimeout(this._loadSelfSupport.bind(this), STARTUP_DELAY_MS);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Configure the logger based on the preferences.
|
||||
*/
|
||||
_configureLogging: function() {
|
||||
if (!this._log) {
|
||||
this._log = Log.repository.getLogger(LOGGER_NAME);
|
||||
|
||||
// Log messages need to go to the browser console.
|
||||
let consoleAppender = new Log.ConsoleAppender(new Log.BasicFormatter());
|
||||
this._log.addAppender(consoleAppender);
|
||||
}
|
||||
|
||||
// Make sure the logger keeps up with the logging level preference.
|
||||
this._log.level = Log.Level[Preferences.get(PREF_LOG_LEVEL, "Warn")];
|
||||
|
||||
// If enabled in the preferences, add a dump appender.
|
||||
let logDumping = Preferences.get(PREF_LOG_DUMP, false);
|
||||
if (logDumping != !!gLogAppenderDump) {
|
||||
if (logDumping) {
|
||||
gLogAppenderDump = new Log.DumpAppender(new Log.BasicFormatter());
|
||||
this._log.addAppender(gLogAppenderDump);
|
||||
} else {
|
||||
this._log.removeAppender(gLogAppenderDump);
|
||||
gLogAppenderDump = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an hidden frame to host our |browser|, then load the SelfSupport page in it.
|
||||
* @param aURL The URL to load in the browser.
|
||||
*/
|
||||
_makeHiddenBrowser: function(aURL) {
|
||||
this._frame = new HiddenFrame();
|
||||
return this._frame.get().then(aFrame => {
|
||||
let doc = aFrame.document;
|
||||
|
||||
this._browser = doc.createElementNS(XUL_NS, "browser");
|
||||
this._browser.setAttribute("type", "content");
|
||||
this._browser.setAttribute("disableglobalhistory", "true");
|
||||
this._browser.setAttribute("src", aURL);
|
||||
|
||||
doc.documentElement.appendChild(this._browser);
|
||||
});
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
this._log.trace("handleEvent - aEvent.type " + aEvent.type + ", Trusted " + aEvent.isTrusted);
|
||||
|
||||
if (aEvent.type === "DOMWindowClose") {
|
||||
let window = this._browser.contentDocument.defaultView;
|
||||
let target = aEvent.target;
|
||||
|
||||
if (target == window) {
|
||||
// preventDefault stops the default window.close(). We need to do that to prevent
|
||||
// Services.appShell.hiddenDOMWindow from being destroyed.
|
||||
aEvent.preventDefault();
|
||||
|
||||
this.uninit();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the self support page correctly loads.
|
||||
*/
|
||||
_pageSuccessCallback: function() {
|
||||
this._log.debug("_pageSuccessCallback - Page correctly loaded.");
|
||||
this._browser.removeProgressListener(this._progressListener);
|
||||
this._progressListener.destroy();
|
||||
this._progressListener = null;
|
||||
|
||||
// Allow SelfSupportBackend to catch |window.close()| issued by the content.
|
||||
this._browser.contentWindow.addEventListener("DOMWindowClose", this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the self support page fails to load.
|
||||
*/
|
||||
_pageLoadErrorCallback: function() {
|
||||
this._log.info("_pageLoadErrorCallback - Too many failed load attempts. Giving up.");
|
||||
this.uninit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a browser and attach it to an hidden window. The browser will contain the
|
||||
* self support page and attempt to load the page content. If loading fails, try again
|
||||
* after an interval.
|
||||
*/
|
||||
_loadSelfSupport: function() {
|
||||
// Fetch the Self Support URL from the preferences.
|
||||
let unformattedURL = Preferences.get(PREF_URL, null);
|
||||
let url = Services.urlFormatter.formatURL(unformattedURL);
|
||||
|
||||
this._log.config("_loadSelfSupport - URL " + url);
|
||||
|
||||
// Create the hidden browser.
|
||||
this._makeHiddenBrowser(url).then(() => {
|
||||
// Load UITour frame script.
|
||||
this._browser.messageManager.loadFrameScript(UITOUR_FRAME_SCRIPT, true);
|
||||
|
||||
// We need to watch for load errors as well and, in case, try to reload
|
||||
// the self support page.
|
||||
const webFlags = Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION;
|
||||
|
||||
this._progressListener = new ProgressListener(() => this._pageLoadErrorCallback(),
|
||||
() => this._pageSuccessCallback());
|
||||
|
||||
this._browser.addProgressListener(this._progressListener, webFlags);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A progress listener object which notifies of page load error and load success
|
||||
* through callbacks. When the page fails to load, the progress listener tries to
|
||||
* reload it up to MAX_RETRIES times. The page is not loaded again immediately, but
|
||||
* after a timeout.
|
||||
*
|
||||
* @param aLoadErrorCallback Called when a page failed to load MAX_RETRIES times.
|
||||
* @param aLoadSuccessCallback Called when a page correctly loads.
|
||||
*/
|
||||
function ProgressListener(aLoadErrorCallback, aLoadSuccessCallback) {
|
||||
this._loadErrorCallback = aLoadErrorCallback;
|
||||
this._loadSuccessCallback = aLoadSuccessCallback;
|
||||
// The number of page loads attempted.
|
||||
this._loadAttempts = 0;
|
||||
this._log = Log.repository.getLogger(LOGGER_NAME);
|
||||
// The Id of the timer which triggers page load again in case of errors.
|
||||
this._reloadTimerId = null;
|
||||
}
|
||||
|
||||
ProgressListener.prototype = {
|
||||
onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
|
||||
this._log.warn("onLocationChange - There was a problem fetching the SelfSupport URL (attempt " +
|
||||
this._loadAttempts + ").");
|
||||
|
||||
// Increase the number of attempts and bail out if we failed too many times.
|
||||
this._loadAttempts++;
|
||||
if (this._loadAttempts > MAX_RETRIES) {
|
||||
this._loadErrorCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload the page after the retry interval expires. The interval is multiplied
|
||||
// by the number of attempted loads, so that it takes a bit more to try to reload
|
||||
// when frequently failing.
|
||||
this._reloadTimerId = setTimeout(() => {
|
||||
this._log.debug("onLocationChange - Reloading SelfSupport URL in the hidden browser.");
|
||||
aWebProgress.DOMWindow.location.reload();
|
||||
}, RETRY_INTERVAL_MS * this._loadAttempts);
|
||||
}
|
||||
},
|
||||
|
||||
onStateChange: function (aWebProgress, aRequest, aFlags, aStatus) {
|
||||
if (aFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
|
||||
Components.isSuccessCode(aStatus)) {
|
||||
this._loadSuccessCallback();
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
// Make sure we don't try to reload self support when shutting down.
|
||||
clearTimeout(this._reloadTimerId);
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
};
|
|
@ -32,6 +32,7 @@ EXTRA_JS_MODULES += [
|
|||
'ProcessHangMonitor.jsm',
|
||||
'ReaderParent.jsm',
|
||||
'RemotePrompt.jsm',
|
||||
'SelfSupportBackend.jsm',
|
||||
'SitePermissions.jsm',
|
||||
'Social.jsm',
|
||||
'TabCrashReporter.jsm',
|
||||
|
|
|
@ -12,6 +12,10 @@ support-files =
|
|||
contentSearchSuggestions.xml
|
||||
[browser_NetworkPrioritizer.js]
|
||||
skip-if = e10s # Bug 666804 - Support NetworkPrioritizer in e10s
|
||||
[browser_SelfSupportBackend.js]
|
||||
support-files =
|
||||
../../components/uitour/test/uitour.html
|
||||
../../components/uitour/UITour-lib.js
|
||||
[browser_SignInToWebsite.js]
|
||||
skip-if = e10s # Bug 941426 - SignIntoWebsite.jsm not e10s friendly
|
||||
[browser_taskbar_preview.js]
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/* 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";
|
||||
|
||||
// Pass an empty scope object to the import to prevent "leaked window property"
|
||||
// errors in tests.
|
||||
let Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
|
||||
let PromiseUtils = Cu.import("resource://gre/modules/PromiseUtils.jsm", {}).PromiseUtils;
|
||||
let SelfSupportBackend =
|
||||
Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackend;
|
||||
|
||||
const PREF_SELFSUPPORT_ENABLED = "browser.selfsupport.enabled";
|
||||
const PREF_SELFSUPPORT_URL = "browser.selfsupport.url";
|
||||
const PREF_UITOUR_ENABLED = "browser.uitour.enabled";
|
||||
|
||||
const TEST_WAIT_RETRIES = 60;
|
||||
|
||||
const TEST_PAGE_URL = getRootDirectory(gTestPath) + "uitour.html";
|
||||
|
||||
/**
|
||||
* Find a browser, with an IFRAME as parent, who has aURL as the source attribute.
|
||||
*
|
||||
* @param aURL The URL to look for to identify the browser.
|
||||
*
|
||||
* @returns {Object} The browser element or null on failure.
|
||||
*/
|
||||
function findSelfSupportBrowser(aURL) {
|
||||
let frames = Services.appShell.hiddenDOMWindow.document.querySelectorAll('iframe');
|
||||
for (let frame of frames) {
|
||||
try {
|
||||
let browser = frame.contentDocument.getElementById("win").querySelectorAll('browser')[0];
|
||||
let url = browser.getAttribute("src");
|
||||
if (url == aURL) {
|
||||
return browser;
|
||||
}
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for self support page to load.
|
||||
*
|
||||
* @param aURL The URL to look for to identify the browser.
|
||||
*
|
||||
* @returns {Promise} Return a promise which is resolved when SelfSupport page is fully
|
||||
* loaded.
|
||||
*/
|
||||
function promiseSelfSupportLoad(aURL) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Find the SelfSupport browser.
|
||||
let browserPromise = waitForConditionPromise(() => !!findSelfSupportBrowser(aURL),
|
||||
"SelfSupport browser not found.",
|
||||
TEST_WAIT_RETRIES);
|
||||
|
||||
// Once found, append a "load" listener to catch page loads.
|
||||
browserPromise.then(() => {
|
||||
let browser = findSelfSupportBrowser(aURL);
|
||||
if (browser.contentDocument.readyState === "complete") {
|
||||
resolve(browser);
|
||||
} else {
|
||||
let handler = () => {
|
||||
browser.removeEventListener("load", handler, true);
|
||||
resolve(browser);
|
||||
};
|
||||
browser.addEventListener("load", handler, true);
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for self support to close.
|
||||
*
|
||||
* @param aURL The URL to look for to identify the browser.
|
||||
*
|
||||
* @returns {Promise} Return a promise which is resolved when SelfSupport browser cannot
|
||||
* be found anymore.
|
||||
*/
|
||||
function promiseSelfSupportClose(aURL) {
|
||||
return waitForConditionPromise(() => !findSelfSupportBrowser(aURL),
|
||||
"SelfSupport browser is still open.", TEST_WAIT_RETRIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the test environment.
|
||||
*/
|
||||
add_task(function* setupEnvironment() {
|
||||
// We always run the SelfSupportBackend in tests to check for weird behaviours.
|
||||
// Disable it to test its start-up.
|
||||
SelfSupportBackend.uninit();
|
||||
|
||||
// Testing prefs are set via |user_pref|, so we need to get their value in order
|
||||
// to restore them.
|
||||
let selfSupportEnabled = Preferences.get(PREF_SELFSUPPORT_ENABLED, true);
|
||||
let uitourEnabled = Preferences.get(PREF_UITOUR_ENABLED, false);
|
||||
let selfSupportURL = Preferences.get(PREF_SELFSUPPORT_URL, "");
|
||||
|
||||
// Enable the SelfSupport backend and set the page URL. We also make sure UITour
|
||||
// is enabled.
|
||||
Preferences.set(PREF_SELFSUPPORT_ENABLED, true);
|
||||
Preferences.set(PREF_UITOUR_ENABLED, true);
|
||||
Preferences.set(PREF_SELFSUPPORT_URL, TEST_PAGE_URL);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Preferences.set(PREF_SELFSUPPORT_ENABLED, selfSupportEnabled);
|
||||
Preferences.set(PREF_UITOUR_ENABLED, uitourEnabled);
|
||||
Preferences.set(PREF_SELFSUPPORT_URL, selfSupportURL);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that the self support page can use the UITour API and close itself.
|
||||
*/
|
||||
add_task(function* test_selfSupport() {
|
||||
// Initialise the SelfSupport backend and trigger the load.
|
||||
SelfSupportBackend.init();
|
||||
|
||||
// SelfSupportBackend waits for "sessionstore-windows-restored" to start loading. Send it.
|
||||
info("Sending sessionstore-windows-restored");
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
|
||||
|
||||
// Wait for the SelfSupport page to load.
|
||||
info("Waiting for the SelfSupport local page to load.");
|
||||
let selfSupportBrowser = yield promiseSelfSupportLoad(TEST_PAGE_URL);
|
||||
Assert.ok(!!selfSupportBrowser, "SelfSupport browser must exist.");
|
||||
|
||||
// Get a reference to the UITour API.
|
||||
info("Testing access to the UITour API.");
|
||||
let contentWindow =
|
||||
Cu.waiveXrays(selfSupportBrowser.contentDocument.defaultView);
|
||||
let uitourAPI = contentWindow.Mozilla.UITour;
|
||||
|
||||
// Test the UITour API with a ping.
|
||||
let pingPromise = new Promise((resolve) => {
|
||||
uitourAPI.ping(resolve);
|
||||
});
|
||||
yield pingPromise;
|
||||
|
||||
// Close SelfSupport from content.
|
||||
contentWindow.close();
|
||||
|
||||
// Wait until SelfSupport closes.
|
||||
info("Waiting for the SelfSupport to close.");
|
||||
yield promiseSelfSupportClose(TEST_PAGE_URL);
|
||||
|
||||
// Find the SelfSupport browser, again. We don't expect to find it.
|
||||
selfSupportBrowser = findSelfSupportBrowser(TEST_PAGE_URL);
|
||||
Assert.ok(!selfSupportBrowser, "SelfSupport browser must not exist.");
|
||||
|
||||
// We shouldn't need this, but let's keep it to make sure closing SelfSupport twice
|
||||
// doesn't create any problem.
|
||||
SelfSupportBackend.uninit();
|
||||
});
|
|
@ -58,3 +58,6 @@
|
|||
// desired side-effect of preventing our geoip lookup.
|
||||
branch.setBoolPref("browser.search.isUS", true);
|
||||
branch.setCharPref("browser.search.countryCode", "US");
|
||||
|
||||
// Make sure SelfSupport doesn't hit the network.
|
||||
branch.setCharPref("browser.selfsupport.url", "https://%(server)s/selfsupport-dummy/");
|
||||
|
|
|
@ -25,6 +25,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
|
||||
"resource:///modules/ContentSearch.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SelfSupportBackend",
|
||||
"resource:///modules/SelfSupportBackend.jsm");
|
||||
|
||||
const SIMPLETEST_OVERRIDES =
|
||||
["ok", "is", "isnot", "ise", "todo", "todo_is", "todo_isnot", "info", "expectAssertions", "requestCompleteLog"];
|
||||
|
||||
|
@ -523,6 +526,7 @@ Tester.prototype = {
|
|||
gBrowser.getNotificationBox(browser).remove();
|
||||
}
|
||||
|
||||
SelfSupportBackend.uninit();
|
||||
CustomizationTabPreloader.uninit();
|
||||
SocialFlyout.unload();
|
||||
SocialShare.uninit();
|
||||
|
|
|
@ -281,6 +281,9 @@ user_pref("browser.uitour.url", "http://%(server)s/uitour-dummy/tour");
|
|||
user_pref("browser.search.isUS", true);
|
||||
user_pref("browser.search.countryCode", "US");
|
||||
|
||||
// Make sure the self support tab doesn't hit the network.
|
||||
user_pref("browser.selfsupport.url", "https://%(server)s/selfsupport-dummy/");
|
||||
|
||||
user_pref("media.eme.enabled", true);
|
||||
user_pref("media.eme.apiVisible", true);
|
||||
|
||||
|
|
|
@ -1417,5 +1417,6 @@ try {
|
|||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
|
||||
prefs.setCharPref("media.gmp-manager.url.override", "http://%(server)s/dummy-gmp-manager.xml");
|
||||
prefs.setCharPref("browser.selfsupport.url", "https://%(server)s/selfsupport-dummy/");
|
||||
}
|
||||
} catch (e) { }
|
||||
|
|
Загрузка…
Ссылка в новой задаче