import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,9 @@
#
# 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/.
DEFINES += \
-DCXXFLAGS='$(CXXFLAGS)' \
-DCPPFLAGS='$(CPPFLAGS)' \
$(NULL)

View file

@ -0,0 +1,48 @@
/* 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";
// <video> is used for top-level audio documents as well
let videoElement = document.getElementsByTagName("video")[0];
// 1. Handle fullscreen mode;
// 2. Send keystrokes to the video element if the body element is focused,
// to be received by the event listener in videocontrols.xml.
document.addEventListener("keypress", ev => {
if (ev.synthetic) // prevent recursion
return;
// Maximize the standalone video when pressing F11,
// but ignore audio elements
if (ev.key == "F11" && videoElement.videoWidth != 0 && videoElement.videoHeight != 0) {
// If we're in browser fullscreen mode, it means the user pressed F11
// while browser chrome or another tab had focus.
// Don't break leaving that mode, so do nothing here.
if (window.fullScreen) {
return;
}
// If we're not in broser fullscreen mode, prevent entering into that,
// so we don't end up there after pressing Esc.
ev.preventDefault();
ev.stopPropagation();
if (!document.mozFullScreenElement) {
videoElement.mozRequestFullScreen();
} else {
document.mozCancelFullScreen();
}
return;
}
// Check if the video element is focused, so it already receives
// keystrokes, and don't send it another one from here.
if (document.activeElement == videoElement)
return;
let newEvent = new KeyboardEvent("keypress", ev);
newEvent.synthetic = true;
videoElement.dispatchEvent(newEvent);
});

View file

@ -0,0 +1,7 @@
/* 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/. */
/*
* Moved to C++ implementation in XPConnect. See bug 281988.
*/

32
toolkit/content/about.js Normal file
View file

@ -0,0 +1,32 @@
/* 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/. */
// get release notes and vendor URL from prefs
var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
.getService(Components.interfaces.nsIURLFormatter);
var releaseNotesURL = formatter.formatURLPref("app.releaseNotesURL");
if (releaseNotesURL != "about:blank") {
var relnotes = document.getElementById("releaseNotesURL");
relnotes.setAttribute("href", releaseNotesURL);
relnotes.parentNode.removeAttribute("hidden");
}
var vendorURL = formatter.formatURLPref("app.vendorURL");
if (vendorURL != "about:blank") {
var vendor = document.getElementById("vendorURL");
vendor.setAttribute("href", vendorURL);
}
// insert the version of the XUL application (!= XULRunner platform version)
var versionNum = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo)
.version;
var version = document.getElementById("version");
version.textContent += " " + versionNum;
// append user agent
var ua = navigator.userAgent;
if (ua) {
document.getElementById("buildID").textContent += " " + ua;
}

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % aboutDTD SYSTEM "chrome://global/locale/about.dtd" >
%aboutDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
]>
<!-- 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/. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>About:</title>
<link rel="stylesheet" href="chrome://global/skin/about.css" type="text/css"/>
</head>
<body dir="&locale.dir;">
<div id="aboutLogoContainer">
<a id="vendorURL">
<img src="about:logo" alt="&brandShortName;"/>
<p id="version">&about.version;</p>
</a>
</div>
<ul id="aboutPageList">
<li>&about.credits.beforeLink;<a href="about:credits">&about.credits.linkTitle;</a>&about.credits.afterLink;</li>
<li>&about.license.beforeTheLink;<a href="about:license">&about.license.linkTitle;</a>&about.license.afterTheLink;</li>
<li hidden="true">&about.relnotes.beforeTheLink;<a id="releaseNotesURL">&about.relnotes.linkTitle;</a>&about.relnotes.afterTheLink;</li>
<li>&about.buildconfig.beforeTheLink;<a href="about:buildconfig">&about.buildconfig.linkTitle;</a>&about.buildconfig.afterTheLink;</li>
<li id="buildID">&about.buildIdentifier;</li>
<script type="application/javascript" src="chrome://global/content/about.js"/>
</ul>
</body>
</html>

View file

@ -0,0 +1,47 @@
/* 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 Cc = Components.classes;
var Ci = Components.interfaces;
var gProtocols = [];
var gContainer;
window.onload = function () {
gContainer = document.getElementById("abouts");
findAbouts();
}
function findAbouts() {
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
for (var cid in Cc) {
var result = cid.match(/@mozilla.org\/network\/protocol\/about;1\?what\=(.*)$/);
if (result) {
var aboutType = result[1];
var contract = "@mozilla.org/network/protocol/about;1?what=" + aboutType;
try {
var am = Cc[contract].getService(Ci.nsIAboutModule);
var uri = ios.newURI("about:"+aboutType, null, null);
var flags = am.getURIFlags(uri);
if (!(flags & Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT)) {
gProtocols.push(aboutType);
}
} catch (e) {
// getService might have thrown if the component doesn't actually
// implement nsIAboutModule
}
}
}
gProtocols.sort().forEach(createProtocolListing);
}
function createProtocolListing(aProtocol) {
var uri = "about:" + aProtocol;
var li = document.createElement("li");
var link = document.createElement("a");
var text = document.createTextNode(uri);
link.href = uri;
link.appendChild(text);
li.appendChild(link);
gContainer.appendChild(li);
}

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
<!ENTITY % aboutAboutDTD SYSTEM "chrome://global/locale/aboutAbout.dtd" >
%aboutAboutDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
]>
<!-- 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/. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&aboutAbout.title;</title>
<link rel="stylesheet" href="chrome://global/skin/about.css" type="text/css"/>
<script type="application/javascript" src="chrome://global/content/aboutAbout.js"></script>
</head>
<body dir="&locale.dir;">
<h1>&aboutAbout.title;</h1>
<p><em>&aboutAbout.note;</em></p>
<ul id="abouts" class="columns"></ul>
</body>
</html>

View file

@ -0,0 +1,414 @@
/* 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';
var Ci = Components.interfaces;
var Cc = Components.classes;
var Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
const FileUtils = Cu.import("resource://gre/modules/FileUtils.jsm").FileUtils
const gEnv = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
const gDashboard = Cc['@mozilla.org/network/dashboard;1']
.getService(Ci.nsIDashboard);
const gDirServ = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryServiceProvider);
const gRequestNetworkingData = {
"http": gDashboard.requestHttpConnections,
"sockets": gDashboard.requestSockets,
"dns": gDashboard.requestDNSInfo,
"websockets": gDashboard.requestWebsocketConnections
};
const gDashboardCallbacks = {
"http": displayHttp,
"sockets": displaySockets,
"dns": displayDns,
"websockets": displayWebsockets
};
const REFRESH_INTERVAL_MS = 3000;
function col(element) {
let col = document.createElement('td');
let content = document.createTextNode(element);
col.appendChild(content);
return col;
}
function displayHttp(data) {
let cont = document.getElementById('http_content');
let parent = cont.parentNode;
let new_cont = document.createElement('tbody');
new_cont.setAttribute('id', 'http_content');
for (let i = 0; i < data.connections.length; i++) {
let row = document.createElement('tr');
row.appendChild(col(data.connections[i].host));
row.appendChild(col(data.connections[i].port));
row.appendChild(col(data.connections[i].spdy));
row.appendChild(col(data.connections[i].ssl));
row.appendChild(col(data.connections[i].active.length));
row.appendChild(col(data.connections[i].idle.length));
new_cont.appendChild(row);
}
parent.replaceChild(new_cont, cont);
}
function displaySockets(data) {
let cont = document.getElementById('sockets_content');
let parent = cont.parentNode;
let new_cont = document.createElement('tbody');
new_cont.setAttribute('id', 'sockets_content');
for (let i = 0; i < data.sockets.length; i++) {
let row = document.createElement('tr');
row.appendChild(col(data.sockets[i].host));
row.appendChild(col(data.sockets[i].port));
row.appendChild(col(data.sockets[i].tcp));
row.appendChild(col(data.sockets[i].active));
row.appendChild(col(data.sockets[i].sent));
row.appendChild(col(data.sockets[i].received));
new_cont.appendChild(row);
}
parent.replaceChild(new_cont, cont);
}
function displayDns(data) {
let cont = document.getElementById('dns_content');
let parent = cont.parentNode;
let new_cont = document.createElement('tbody');
new_cont.setAttribute('id', 'dns_content');
for (let i = 0; i < data.entries.length; i++) {
let row = document.createElement('tr');
row.appendChild(col(data.entries[i].hostname));
row.appendChild(col(data.entries[i].family));
let column = document.createElement('td');
for (let j = 0; j < data.entries[i].hostaddr.length; j++) {
column.appendChild(document.createTextNode(data.entries[i].hostaddr[j]));
column.appendChild(document.createElement('br'));
}
row.appendChild(column);
row.appendChild(col(data.entries[i].expiration));
new_cont.appendChild(row);
}
parent.replaceChild(new_cont, cont);
}
function displayWebsockets(data) {
let cont = document.getElementById('websockets_content');
let parent = cont.parentNode;
let new_cont = document.createElement('tbody');
new_cont.setAttribute('id', 'websockets_content');
for (let i = 0; i < data.websockets.length; i++) {
let row = document.createElement('tr');
row.appendChild(col(data.websockets[i].hostport));
row.appendChild(col(data.websockets[i].encrypted));
row.appendChild(col(data.websockets[i].msgsent));
row.appendChild(col(data.websockets[i].msgreceived));
row.appendChild(col(data.websockets[i].sentsize));
row.appendChild(col(data.websockets[i].receivedsize));
new_cont.appendChild(row);
}
parent.replaceChild(new_cont, cont);
}
function requestAllNetworkingData() {
for (let id in gRequestNetworkingData)
requestNetworkingDataForTab(id);
}
function requestNetworkingDataForTab(id) {
gRequestNetworkingData[id](gDashboardCallbacks[id]);
}
function init() {
gDashboard.enableLogging = true;
if (Services.prefs.getBoolPref("network.warnOnAboutNetworking")) {
let div = document.getElementById("warning_message");
div.classList.add("active");
div.hidden = false;
document.getElementById("confpref").addEventListener("click", confirm);
}
requestAllNetworkingData();
let autoRefresh = document.getElementById("autorefcheck");
if (autoRefresh.checked)
setAutoRefreshInterval(autoRefresh);
autoRefresh.addEventListener("click", function() {
let refrButton = document.getElementById("refreshButton");
if (this.checked) {
setAutoRefreshInterval(this);
refrButton.disabled = "disabled";
} else {
clearInterval(this.interval);
refrButton.disabled = null;
}
});
let refr = document.getElementById("refreshButton");
refr.addEventListener("click", requestAllNetworkingData);
if (document.getElementById("autorefcheck").checked)
refr.disabled = "disabled";
// Event delegation on #categories element
let menu = document.getElementById("categories");
menu.addEventListener("click", function click(e) {
if (e.target && e.target.parentNode == menu)
show(e.target);
});
let dnsLookupButton = document.getElementById("dnsLookupButton");
dnsLookupButton.addEventListener("click", function() {
doLookup();
});
let setLogButton = document.getElementById("set-log-file-button");
setLogButton.addEventListener("click", setLogFile);
let setModulesButton = document.getElementById("set-log-modules-button");
setModulesButton.addEventListener("click", setLogModules);
let startLoggingButton = document.getElementById("start-logging-button");
startLoggingButton.addEventListener("click", startLogging);
let stopLoggingButton = document.getElementById("stop-logging-button");
stopLoggingButton.addEventListener("click", stopLogging);
try {
let file = gDirServ.getFile("TmpD", {});
file.append("log.txt");
document.getElementById("log-file").value = file.path;
} catch (e) {
console.error(e);
}
// Update the value of the log file.
updateLogFile();
// Update the active log modules
updateLogModules();
// If we can't set the file and the modules at runtime,
// the start and stop buttons wouldn't really do anything.
if (setLogButton.disabled && setModulesButton.disabled) {
startLoggingButton.disabled = true;
stopLoggingButton.disabled = true;
}
}
function updateLogFile() {
let logPath = "";
// Try to get the environment variable for the log file
logPath = gEnv.get("MOZ_LOG_FILE") || gEnv.get("NSPR_LOG_FILE");
let currentLogFile = document.getElementById("current-log-file");
let setLogFileButton = document.getElementById("set-log-file-button");
// If the log file was set from an env var, we disable the ability to set it
// at runtime.
if (logPath.length > 0) {
currentLogFile.innerText = logPath;
setLogFileButton.disabled = true;
} else {
// There may be a value set by a pref.
currentLogFile.innerText = gDashboard.getLogPath();
}
}
function updateLogModules() {
// Try to get the environment variable for the log file
let logModules = gEnv.get("MOZ_LOG") ||
gEnv.get("MOZ_LOG_MODULES") ||
gEnv.get("NSPR_LOG_MODULES");
let currentLogModules = document.getElementById("current-log-modules");
let setLogModulesButton = document.getElementById("set-log-modules-button");
if (logModules.length > 0) {
currentLogModules.innerText = logModules;
// If the log modules are set by an environment variable at startup, do not
// allow changing them throught a pref. It would be difficult to figure out
// which ones are enabled and which ones are not. The user probably knows
// what he they are doing.
setLogModulesButton.disabled = true;
} else {
let activeLogModules = [];
try {
if (Services.prefs.getBoolPref("logging.config.add_timestamp")) {
activeLogModules.push("timestamp");
}
} catch (e) {}
try {
if (Services.prefs.getBoolPref("logging.config.sync")) {
activeLogModules.push("sync");
}
} catch (e) {}
let children = Services.prefs.getBranch("logging.").getChildList("", {});
for (let pref of children) {
if (pref.startsWith("config.")) {
continue;
}
try {
let value = Services.prefs.getIntPref(`logging.${pref}`);
activeLogModules.push(`${pref}:${value}`);
} catch (e) {
console.error(e);
}
}
currentLogModules.innerText = activeLogModules.join(",");
}
}
function setLogFile() {
let setLogButton = document.getElementById("set-log-file-button");
if (setLogButton.disabled) {
// There's no point trying since it wouldn't work anyway.
return;
}
let logFile = document.getElementById("log-file").value.trim();
Services.prefs.setCharPref("logging.config.LOG_FILE", logFile);
updateLogFile();
}
function clearLogModules() {
// Turn off all the modules.
let children = Services.prefs.getBranch("logging.").getChildList("", {});
for (let pref of children) {
if (!pref.startsWith("config.")) {
Services.prefs.clearUserPref(`logging.${pref}`);
}
}
Services.prefs.clearUserPref("logging.config.add_timestamp");
Services.prefs.clearUserPref("logging.config.sync");
updateLogModules();
}
function setLogModules() {
let setLogModulesButton = document.getElementById("set-log-modules-button");
if (setLogModulesButton.disabled) {
// The modules were set via env var, so we shouldn't try to change them.
return;
}
let modules = document.getElementById("log-modules").value.trim();
// Clear previously set log modules.
clearLogModules();
let logModules = modules.split(",");
for (let module of logModules) {
if (module == "timestamp") {
Services.prefs.setBoolPref("logging.config.add_timestamp", true);
} else if (module == "rotate") {
// XXX: rotate is not yet supported.
} else if (module == "append") {
// XXX: append is not yet supported.
} else if (module == "sync") {
Services.prefs.setBoolPref("logging.config.sync", true);
} else {
let [key, value] = module.split(":");
Services.prefs.setIntPref(`logging.${key}`, parseInt(value, 10));
}
}
updateLogModules();
}
function startLogging() {
setLogFile();
setLogModules();
}
function stopLogging() {
clearLogModules();
// clear the log file as well
Services.prefs.clearUserPref("logging.config.LOG_FILE");
updateLogFile();
}
function confirm () {
let div = document.getElementById("warning_message");
div.classList.remove("active");
div.hidden = true;
let warnBox = document.getElementById("warncheck");
Services.prefs.setBoolPref("network.warnOnAboutNetworking", warnBox.checked);
}
function show(button) {
let current_tab = document.querySelector(".active");
let content = document.getElementById(button.getAttribute("value"));
if (current_tab == content)
return;
current_tab.classList.remove("active");
current_tab.hidden = true;
content.classList.add("active");
content.hidden = false;
let current_button = document.querySelector("[selected=true]");
current_button.removeAttribute("selected");
button.setAttribute("selected", "true");
let autoRefresh = document.getElementById("autorefcheck");
if (autoRefresh.checked) {
clearInterval(autoRefresh.interval);
setAutoRefreshInterval(autoRefresh);
}
let title = document.getElementById("sectionTitle");
title.textContent = button.children[0].textContent;
}
function setAutoRefreshInterval(checkBox) {
let active_tab = document.querySelector(".active");
checkBox.interval = setInterval(function() {
requestNetworkingDataForTab(active_tab.id);
}, REFRESH_INTERVAL_MS);
}
window.addEventListener("DOMContentLoaded", function load() {
window.removeEventListener("DOMContentLoaded", load);
init();
});
function doLookup() {
let host = document.getElementById("host").value;
if (host) {
gDashboard.requestDNSLookup(host, displayDNSLookup);
}
}
function displayDNSLookup(data) {
let cont = document.getElementById("dnslookuptool_content");
let parent = cont.parentNode;
let new_cont = document.createElement("tbody");
new_cont.setAttribute("id", "dnslookuptool_content");
if (data.answer) {
for (let address of data.address) {
let row = document.createElement("tr");
row.appendChild(col(address));
new_cont.appendChild(row);
}
}
else {
new_cont.appendChild(col(data.error));
}
parent.replaceChild(new_cont, cont);
}

View file

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
<!ENTITY % networkingDTD SYSTEM "chrome://global/locale/aboutNetworking.dtd"> %networkingDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&aboutNetworking.title;</title>
<link rel="stylesheet" href="chrome://mozapps/skin/aboutNetworking.css" type="text/css" />
<script type="application/javascript;version=1.7" src="chrome://global/content/aboutNetworking.js" />
</head>
<body id="body">
<div id="warning_message" class="warningBackground" hidden="true">
<div class="container">
<h1 class="title">&aboutNetworking.warning;</h1>
<div class="toggle-container-with-text">
<input id="warncheck" type="checkbox" checked="yes" />
<label for="warncheck">&aboutNetworking.showNextTime;</label>
</div>
<div>
<button id="confpref" class="primary">&aboutNetworking.ok;</button>
</div>
</div>
</div>
<div id="categories">
<div class="category" selected="true" value="http">
<span class="category-name">&aboutNetworking.HTTP;</span>
</div>
<div class="category" value="sockets">
<span class="category-name">&aboutNetworking.sockets;</span>
</div>
<div class="category" value="dns">
<span class="category-name">&aboutNetworking.dns;</span>
</div>
<div class="category" value="websockets">
<span class="category-name">&aboutNetworking.websockets;</span>
</div>
<hr></hr>
<div class="category" value="dnslookuptool">
<span class="category-name">&aboutNetworking.dnsLookup;</span>
</div>
<div class="category" value="logging">
<span class="category-name">&aboutNetworking.logging;</span>
</div>
</div>
<div class="main-content">
<div class="header">
<div id="sectionTitle" class="header-name">
&aboutNetworking.HTTP;
</div>
<div id="refreshDiv" class="toggle-container-with-text">
<button id="refreshButton">&aboutNetworking.refresh;</button>
<input id="autorefcheck" type="checkbox" name="Autorefresh" />
<label for="autorefcheck">&aboutNetworking.autoRefresh;</label>
</div>
</div>
<div id="http" class="tab active">
<table>
<thead>
<tr>
<th>&aboutNetworking.hostname;</th>
<th>&aboutNetworking.port;</th>
<th>&aboutNetworking.spdy;</th>
<th>&aboutNetworking.ssl;</th>
<th>&aboutNetworking.active;</th>
<th>&aboutNetworking.idle;</th>
</tr>
</thead>
<tbody id="http_content" />
</table>
</div>
<div id="sockets" class="tab" hidden="true">
<table>
<thead>
<tr>
<th>&aboutNetworking.host;</th>
<th>&aboutNetworking.port;</th>
<th>&aboutNetworking.tcp;</th>
<th>&aboutNetworking.active;</th>
<th>&aboutNetworking.sent;</th>
<th>&aboutNetworking.received;</th>
</tr>
</thead>
<tbody id="sockets_content" />
</table>
</div>
<div id="dns" class="tab" hidden="true">
<table>
<thead>
<tr>
<th>&aboutNetworking.hostname;</th>
<th>&aboutNetworking.family;</th>
<th>&aboutNetworking.addresses;</th>
<th>&aboutNetworking.expires;</th>
</tr>
</thead>
<tbody id="dns_content" />
</table>
</div>
<div id="websockets" class="tab" hidden="true">
<table>
<thead>
<tr>
<th>&aboutNetworking.hostname;</th>
<th>&aboutNetworking.ssl;</th>
<th>&aboutNetworking.messagesSent;</th>
<th>&aboutNetworking.messagesReceived;</th>
<th>&aboutNetworking.bytesSent;</th>
<th>&aboutNetworking.bytesReceived;</th>
</tr>
</thead>
<tbody id="websockets_content" />
</table>
</div>
<div id="dnslookuptool" class="tab" hidden="true">
&aboutNetworking.dnsDomain;: <input type="text" name="host" id="host"></input>
<button id="dnsLookupButton">&aboutNetworking.dnsLookupButton;</button>
<hr/>
<table>
<thead>
<tr>
<th>&aboutNetworking.dnsLookupTableColumn;</th>
</tr>
</thead>
<tbody id="dnslookuptool_content" />
</table>
</div>
<div id="logging" class="tab" hidden="true">
<div>
&aboutNetworking.logTutorial;
</div>
<br/>
<div>
<button id="start-logging-button"> &aboutNetworking.startLogging; </button>
<button id="stop-logging-button"> &aboutNetworking.stopLogging; </button>
</div>
<br/>
<br/>
<div>
&aboutNetworking.currentLogFile; <div id="current-log-file"></div><br/>
<input type="text" name="log-file" id="log-file"></input>
<button id="set-log-file-button"> &aboutNetworking.setLogFile; </button>
</div>
<div>
&aboutNetworking.currentLogModules; <div id="current-log-modules"></div><br/>
<input type="text" name="log-modules" id="log-modules" value="timestamp,sync,nsHttp:5,nsSocketTransport:5,nsStreamPump:5,nsHostResolver:5"></input>
<button id="set-log-modules-button"> &aboutNetworking.setLogModules; </button>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,339 @@
/* 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 {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/AppConstants.jsm');
XPCOMUtils.defineLazyServiceGetter(
this,
'ProfileService',
'@mozilla.org/toolkit/profile-service;1',
'nsIToolkitProfileService'
);
const bundle = Services.strings.createBundle(
'chrome://global/locale/aboutProfiles.properties');
// nsIToolkitProfileService.selectProfile can be used only during the selection
// of the profile in the ProfileManager. If we are showing about:profiles in a
// tab, the selectedProfile returns the default profile.
// In this function we use the ProfD to find the current profile.
function findCurrentProfile() {
let cpd;
try {
cpd = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties)
.get("ProfD", Ci.nsIFile);
} catch (e) {}
if (cpd) {
let itr = ProfileService.profiles;
while (itr.hasMoreElements()) {
let profile = itr.getNext().QueryInterface(Ci.nsIToolkitProfile);
if (profile.rootDir.path == cpd.path) {
return profile;
}
}
}
// selectedProfile can trow if nothing is selected or if the selected profile
// has been deleted.
try {
return ProfileService.selectedProfile;
} catch (e) {
return null;
}
}
function refreshUI() {
let parent = document.getElementById('profiles');
while (parent.firstChild) {
parent.removeChild(parent.firstChild);
}
let defaultProfile;
try {
defaultProfile = ProfileService.defaultProfile;
} catch (e) {}
let currentProfile = findCurrentProfile() || defaultProfile;
let iter = ProfileService.profiles;
while (iter.hasMoreElements()) {
let profile = iter.getNext().QueryInterface(Ci.nsIToolkitProfile);
display({ profile: profile,
isDefault: profile == defaultProfile,
isCurrentProfile: profile == currentProfile });
}
let createButton = document.getElementById('create-button');
createButton.onclick = createProfileWizard;
let restartSafeModeButton = document.getElementById('restart-in-safe-mode-button');
restartSafeModeButton.onclick = function() { restart(true); }
let restartNormalModeButton = document.getElementById('restart-button');
restartNormalModeButton.onclick = function() { restart(false); }
}
function openDirectory(dir) {
let nsLocalFile = Components.Constructor("@mozilla.org/file/local;1",
"nsILocalFile", "initWithPath");
new nsLocalFile(dir).reveal();
}
function display(profileData) {
let parent = document.getElementById('profiles');
let div = document.createElement('div');
parent.appendChild(div);
let nameStr = bundle.formatStringFromName('name', [profileData.profile.name], 1);
let name = document.createElement('h2');
name.appendChild(document.createTextNode(nameStr));
div.appendChild(name);
if (profileData.isCurrentProfile) {
let currentProfile = document.createElement('h3');
let currentProfileStr = bundle.GetStringFromName('currentProfile');
currentProfile.appendChild(document.createTextNode(currentProfileStr));
div.appendChild(currentProfile);
}
let table = document.createElement('table');
div.appendChild(table);
let tbody = document.createElement('tbody');
table.appendChild(tbody);
function createItem(title, value, dir = false) {
let tr = document.createElement('tr');
tbody.appendChild(tr);
let th = document.createElement('th');
th.setAttribute('class', 'column');
th.appendChild(document.createTextNode(title));
tr.appendChild(th);
let td = document.createElement('td');
td.appendChild(document.createTextNode(value));
tr.appendChild(td);
if (dir) {
td.appendChild(document.createTextNode(' '));
let button = document.createElement('button');
let string = 'openDir';
if (AppConstants.platform == "win") {
string = 'winOpenDir2';
} else if (AppConstants.platform == "macosx") {
string = 'macOpenDir';
}
let buttonText = document.createTextNode(bundle.GetStringFromName(string));
button.appendChild(buttonText);
td.appendChild(button);
button.addEventListener('click', function(e) {
openDirectory(value);
});
}
}
createItem(bundle.GetStringFromName('isDefault'),
profileData.isDefault ? bundle.GetStringFromName('yes') : bundle.GetStringFromName('no'));
createItem(bundle.GetStringFromName('rootDir'), profileData.profile.rootDir.path, true);
if (profileData.profile.localDir.path != profileData.profile.rootDir.path) {
createItem(bundle.GetStringFromName('localDir'), profileData.profile.localDir.path, true);
}
let renameButton = document.createElement('button');
renameButton.appendChild(document.createTextNode(bundle.GetStringFromName('rename')));
renameButton.onclick = function() {
renameProfile(profileData.profile);
};
div.appendChild(renameButton);
if (!profileData.isCurrentProfile) {
let removeButton = document.createElement('button');
removeButton.appendChild(document.createTextNode(bundle.GetStringFromName('remove')));
removeButton.onclick = function() {
removeProfile(profileData.profile);
};
div.appendChild(removeButton);
}
if (!profileData.isDefault) {
let defaultButton = document.createElement('button');
defaultButton.appendChild(document.createTextNode(bundle.GetStringFromName('setAsDefault')));
defaultButton.onclick = function() {
defaultProfile(profileData.profile);
};
div.appendChild(defaultButton);
}
if (!profileData.isCurrentProfile) {
let runButton = document.createElement('button');
runButton.appendChild(document.createTextNode(bundle.GetStringFromName('launchProfile')));
runButton.onclick = function() {
openProfile(profileData.profile);
};
div.appendChild(runButton);
}
let sep = document.createElement('hr');
div.appendChild(sep);
}
function CreateProfile(profile) {
ProfileService.selectedProfile = profile;
ProfileService.flush();
refreshUI();
}
function createProfileWizard() {
// This should be rewritten in HTML eventually.
window.openDialog('chrome://mozapps/content/profile/createProfileWizard.xul',
'', 'centerscreen,chrome,modal,titlebar',
ProfileService);
}
function renameProfile(profile) {
let title = bundle.GetStringFromName('renameProfileTitle');
let msg = bundle.formatStringFromName('renameProfile', [profile.name], 1);
let newName = { value: profile.name };
if (Services.prompt.prompt(window, title, msg, newName, null,
{ value: 0 })) {
newName = newName.value;
if (newName == profile.name) {
return;
}
try {
profile.name = newName;
} catch (e) {
let title = bundle.GetStringFromName('invalidProfileNameTitle');
let msg = bundle.formatStringFromName('invalidProfileName', [newName], 1);
Services.prompt.alert(window, title, msg);
return;
}
ProfileService.flush();
refreshUI();
}
}
function removeProfile(profile) {
let deleteFiles = false;
if (profile.rootDir.exists()) {
let title = bundle.GetStringFromName('deleteProfileTitle');
let msg = bundle.formatStringFromName('deleteProfileConfirm',
[profile.rootDir.path], 1);
let buttonPressed = Services.prompt.confirmEx(window, title, msg,
(Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0) +
(Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1) +
(Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_2),
bundle.GetStringFromName('dontDeleteFiles'),
null,
bundle.GetStringFromName('deleteFiles'),
null, {value:0});
if (buttonPressed == 1) {
return;
}
if (buttonPressed == 2) {
deleteFiles = true;
}
}
// If we are deleting the selected or the default profile we must choose a
// different one.
let isSelected = false;
try {
isSelected = ProfileService.selectedProfile == profile;
} catch (e) {}
let isDefault = false;
try {
isDefault = ProfileService.defaultProfile == profile;
} catch (e) {}
if (isSelected || isDefault) {
let itr = ProfileService.profiles;
while (itr.hasMoreElements()) {
let p = itr.getNext().QueryInterface(Ci.nsIToolkitProfile);
if (profile == p) {
continue;
}
if (isSelected) {
ProfileService.selectedProfile = p;
}
if (isDefault) {
ProfileService.defaultProfile = p;
}
break;
}
}
profile.remove(deleteFiles);
ProfileService.flush();
refreshUI();
}
function defaultProfile(profile) {
ProfileService.defaultProfile = profile;
ProfileService.selectedProfile = profile;
ProfileService.flush();
refreshUI();
}
function openProfile(profile) {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
if (cancelQuit.data) {
return;
}
Services.startup.createInstanceWithProfile(profile);
}
function restart(safeMode) {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
if (cancelQuit.data) {
return;
}
let flags = Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestartNotSameProfile;
if (safeMode) {
Services.startup.restartInSafeMode(flags);
} else {
Services.startup.quit(flags);
}
}
window.addEventListener('DOMContentLoaded', function load() {
window.removeEventListener('DOMContentLoaded', load);
refreshUI();
});

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
<!ENTITY % profilesDTD SYSTEM "chrome://global/locale/aboutProfiles.dtd"> %profilesDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&aboutProfiles.title;</title>
<link rel="icon" type="image/png" id="favicon" href="chrome://branding/content/icon32.png"/>
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://mozapps/skin/aboutProfiles.css" type="text/css" />
<script type="application/javascript;version=1.7" src="chrome://global/content/aboutProfiles.js" />
</head>
<body id="body">
<div id="action-box">
<h3>&aboutProfiles.restart.title;</h3>
<button id="restart-in-safe-mode-button">&aboutProfiles.restart.inSafeMode;</button>
<button id="restart-button">&aboutProfiles.restart.normal;</button>
</div>
<h1>&aboutProfiles.title;</h1>
<div class="page-subtitle">&aboutProfiles.subtitle;</div>
<div>
<button id="create-button">&aboutProfiles.create;</button>
</div>
<div id="profiles" class="tab"></div>
</body>
</html>

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % aboutRightsDTD SYSTEM "chrome://global/locale/aboutRights.dtd">
%aboutRightsDTD;
]>
<!-- 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/. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&rights.pagetitle;</title>
<link rel="stylesheet" href="chrome://global/skin/about.css" type="text/css"/>
</head>
<body id="your-rights" dir="&rights.locale-direction;" class="aboutPageWideContainer">
<h1>&rights.intro-header;</h1>
<p>&rights.intro;</p>
<ul>
<li>&rights.intro-point1a;<a href="http://www.mozilla.org/MPL/">&rights.intro-point1b;</a>&rights.intro-point1c;</li>
<!-- Point 2 discusses Mozilla trademarks, and isn't needed when the build is unbranded.
- Point 3 discusses privacy policy, unbranded builds get a placeholder (for the vendor to replace)
- Point 4 discusses web service terms, unbranded builds gets a placeholder (for the vendor to replace) -->
<li>&rights.intro-point3-unbranded;</li>
<li>&rights.intro-point4a-unbranded;<a href="about:rights#webservices" onclick="showServices();">&rights.intro-point4b-unbranded;</a>&rights.intro-point4c-unbranded;</li>
</ul>
<div id="webservices-container">
<a name="webservices"/>
<h3>&rights2.webservices-header;</h3>
<p>&rights.webservices-unbranded;</p>
<ol>
<!-- Terms only apply to official builds, unbranded builds get a placeholder. -->
<li>&rights.webservices-term1-unbranded;</li>
</ol>
</div>
<script type="application/javascript"><![CDATA[
var servicesDiv = document.getElementById("webservices-container");
servicesDiv.style.display = "none";
function showServices() {
servicesDiv.style.display = "";
}
]]></script>
</body>
</html>

View file

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % securityPrefsDTD SYSTEM "chrome://browser/locale/preferences/security.dtd">
%securityPrefsDTD;
<!ENTITY % aboutRightsDTD SYSTEM "chrome://global/locale/aboutRights.dtd">
%aboutRightsDTD;
]>
<!-- 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/. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&rights.pagetitle;</title>
<link rel="stylesheet" href="chrome://global/skin/about.css" type="text/css"/>
</head>
<body id="your-rights" dir="&rights.locale-direction;" class="aboutPageWideContainer">
<h1>&rights.intro-header;</h1>
<p>&rights.intro;</p>
<ul>
<li>&rights.intro-point1a;<a href="http://www.mozilla.org/MPL/">&rights.intro-point1b;</a>&rights.intro-point1c;</li>
<!-- Point 2 discusses Mozilla trademarks, and isn't needed when the build is unbranded.
- Point 3 discusses privacy policy, unbranded builds get a placeholder (for the vendor to replace)
- Point 4 discusses web service terms, unbranded builds gets a placeholder (for the vendor to replace) -->
<li>&rights.intro-point2-a;<a href="http://www.mozilla.org/foundation/trademarks/policy.html">&rights.intro-point2-b;</a>&rights.intro-point2-c;</li>
<li>&rights.intro-point2.5;</li>
<li>&rights2.intro-point3a;<a href="https://www.mozilla.org/legal/privacy/firefox.html">&rights2.intro-point3b;</a>&rights.intro-point3c;</li>
<li>&rights2.intro-point4a;<a href="about:rights#webservices" onclick="showServices();">&rights.intro-point4b;</a>&rights.intro-point4c;</li>
<li>&rights.intro-point5;</li>
</ul>
<div id="webservices-container">
<a name="webservices"/>
<h3>&rights2.webservices-header;</h3>
<p>&rights2.webservices-a;<a href="about:rights#disabling-webservices" onclick="showDisablingServices();">&rights2.webservices-b;</a>&rights3.webservices-c;</p>
<div id="disabling-webservices-container" style="margin-left:40px;">
<a name="disabling-webservices"/>
<p><strong>&rights.safebrowsing-a;</strong>&rights.safebrowsing-b;</p>
<ul>
<li>&rights.safebrowsing-term1;</li>
<li>&rights.safebrowsing-term2;</li>
<li>&rights2.safebrowsing-term3;</li>
<li>&rights.safebrowsing-term4;</li>
</ul>
<p><strong>&rights.locationawarebrowsing-a;</strong>&rights.locationawarebrowsing-b;</p>
<ul>
<li>&rights.locationawarebrowsing-term1a;<code>&rights.locationawarebrowsing-term1b;</code></li>
<li>&rights.locationawarebrowsing-term2;</li>
<li>&rights.locationawarebrowsing-term3;</li>
<li>&rights.locationawarebrowsing-term4;</li>
</ul>
</div>
<ol>
<!-- Terms only apply to official builds, unbranded builds get a placeholder. -->
<li>&rights2.webservices-term1;</li>
<li>&rights.webservices-term2;</li>
<li>&rights2.webservices-term3;</li>
<li><strong>&rights.webservices-term4;</strong></li>
<li><strong>&rights.webservices-term5;</strong></li>
<li>&rights.webservices-term6;</li>
<li>&rights.webservices-term7;</li>
</ol>
</div>
<script type="application/javascript"><![CDATA[
var servicesDiv = document.getElementById("webservices-container");
servicesDiv.style.display = "none";
function showServices() {
servicesDiv.style.display = "";
}
var disablingServicesDiv = document.getElementById("disabling-webservices-container");
disablingServicesDiv.style.display = "none";
function showDisablingServices() {
disablingServicesDiv.style.display = "";
}
]]></script>
</body>
</html>

View file

@ -0,0 +1,184 @@
/* 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';
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
const bundle = Services.strings.createBundle(
"chrome://global/locale/aboutServiceWorkers.properties");
const brandBundle = Services.strings.createBundle(
"chrome://branding/locale/brand.properties");
var gSWM;
var gSWCount = 0;
function init() {
let enabled = Services.prefs.getBoolPref("dom.serviceWorkers.enabled");
if (!enabled) {
let div = document.getElementById("warning_not_enabled");
div.classList.add("active");
return;
}
gSWM = Cc["@mozilla.org/serviceworkers/manager;1"]
.getService(Ci.nsIServiceWorkerManager);
if (!gSWM) {
dump("AboutServiceWorkers: Failed to get the ServiceWorkerManager service!\n");
return;
}
let data = gSWM.getAllRegistrations();
if (!data) {
dump("AboutServiceWorkers: Failed to retrieve the registrations.\n");
return;
}
let length = data.length;
if (!length) {
let div = document.getElementById("warning_no_serviceworkers");
div.classList.add("active");
return;
}
let ps = undefined;
try {
ps = Cc["@mozilla.org/push/Service;1"]
.getService(Ci.nsIPushService);
} catch (e) {
dump("Could not acquire PushService\n");
}
for (let i = 0; i < length; ++i) {
let info = data.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
if (!info) {
dump("AboutServiceWorkers: Invalid nsIServiceWorkerRegistrationInfo interface.\n");
continue;
}
display(info, ps);
}
}
function display(info, pushService) {
let parent = document.getElementById("serviceworkers");
let div = document.createElement('div');
parent.appendChild(div);
let title = document.createElement('h2');
let titleStr = bundle.formatStringFromName('title', [info.principal.origin], 1);
title.appendChild(document.createTextNode(titleStr));
div.appendChild(title);
if (info.principal.appId) {
let b2gtitle = document.createElement('h3');
let trueFalse = bundle.GetStringFromName(info.principal.isInIsolatedMozBrowserElement ? 'true' : 'false');
let b2gtitleStr =
bundle.formatStringFromName('b2gtitle', [ brandBundle.getString("brandShortName"),
info.principal.appId,
trueFalse], 2);
b2gtitle.appendChild(document.createTextNode(b2gtitleStr));
div.appendChild(b2gtitle);
}
let list = document.createElement('ul');
div.appendChild(list);
function createItem(title, value, makeLink) {
let item = document.createElement('li');
list.appendChild(item);
let bold = document.createElement('strong');
bold.appendChild(document.createTextNode(title + " "));
item.appendChild(bold);
let textNode = document.createTextNode(value);
if (makeLink) {
let link = document.createElement("a");
link.href = value;
link.target = "_blank";
link.appendChild(textNode);
item.appendChild(link);
} else {
item.appendChild(textNode);
}
return textNode;
}
createItem(bundle.GetStringFromName('scope'), info.scope);
createItem(bundle.GetStringFromName('scriptSpec'), info.scriptSpec, true);
let currentWorkerURL = info.activeWorker ? info.activeWorker.scriptSpec : "";
createItem(bundle.GetStringFromName('currentWorkerURL'), currentWorkerURL, true);
let activeCacheName = info.activeWorker ? info.activeWorker.cacheName : "";
createItem(bundle.GetStringFromName('activeCacheName'), activeCacheName);
let waitingCacheName = info.waitingWorker ? info.waitingWorker.cacheName : "";
createItem(bundle.GetStringFromName('waitingCacheName'), waitingCacheName);
let pushItem = createItem(bundle.GetStringFromName('pushEndpoint'), bundle.GetStringFromName('waiting'));
if (pushService) {
pushService.getSubscription(info.scope, info.principal, (status, pushRecord) => {
if (Components.isSuccessCode(status)) {
pushItem.data = JSON.stringify(pushRecord);
} else {
dump("about:serviceworkers - retrieving push registration failed\n");
}
});
}
let updateButton = document.createElement("button");
updateButton.appendChild(document.createTextNode(bundle.GetStringFromName('update')));
updateButton.onclick = function() {
gSWM.propagateSoftUpdate(info.principal.originAttributes, info.scope);
};
div.appendChild(updateButton);
let unregisterButton = document.createElement("button");
unregisterButton.appendChild(document.createTextNode(bundle.GetStringFromName('unregister')));
div.appendChild(unregisterButton);
let loadingMessage = document.createElement('span');
loadingMessage.appendChild(document.createTextNode(bundle.GetStringFromName('waiting')));
loadingMessage.classList.add('inactive');
div.appendChild(loadingMessage);
unregisterButton.onclick = function() {
let cb = {
unregisterSucceeded: function() {
parent.removeChild(div);
if (!--gSWCount) {
let div = document.getElementById("warning_no_serviceworkers");
div.classList.add("active");
}
},
unregisterFailed: function() {
alert(bundle.GetStringFromName('unregisterError'));
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIServiceWorkerUnregisterCallback])
};
loadingMessage.classList.remove('inactive');
gSWM.propagateUnregister(info.principal, cb, info.scope);
};
let sep = document.createElement('hr');
div.appendChild(sep);
++gSWCount;
}
window.addEventListener("DOMContentLoaded", function load() {
window.removeEventListener("DOMContentLoaded", load);
init();
});

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
<!ENTITY % serviceworkersDTD SYSTEM "chrome://global/locale/aboutServiceWorkers.dtd"> %serviceworkersDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&aboutServiceWorkers.title;</title>
<link rel="stylesheet" href="chrome://global/skin/about.css" type="text/css" />
<link rel="stylesheet" href="chrome://mozapps/skin/aboutServiceWorkers.css" type="text/css" />
<script type="application/javascript;version=1.7" src="chrome://global/content/aboutServiceWorkers.js" />
</head>
<body id="body">
<div id="warning_not_enabled" class="warningBackground">
<div class="warningMessage">&aboutServiceWorkers.warning_not_enabled;</div>
</div>
<div id="warning_no_serviceworkers" class="warningBackground">
<div class="warningMessage">&aboutServiceWorkers.warning_no_serviceworkers;</div>
</div>
<div id="serviceworkers" class="tab active">
<h1>&aboutServiceWorkers.maintitle;</h1>
</div>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,555 @@
<?xml version="1.0" encoding="UTF-8"?>
# 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/.
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
<!ENTITY % aboutSupportDTD SYSTEM "chrome://global/locale/aboutSupport.dtd"> %aboutSupportDTD;
<!ENTITY % resetProfileDTD SYSTEM "chrome://global/locale/resetProfile.dtd"> %resetProfileDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&aboutSupport.pageTitle;</title>
<link rel="icon" type="image/png" id="favicon"
href="chrome://branding/content/icon32.png"/>
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css"
type="text/css"/>
<link rel="stylesheet" href="chrome://global/skin/aboutSupport.css"
type="text/css"/>
<script type="application/javascript;version=1.7"
src="chrome://global/content/aboutSupport.js"/>
<script type="application/javascript;version=1.7"
src="chrome://global/content/resetProfile.js"/>
</head>
<body dir="&locale.dir;">
<div id="action-box">
<div id="reset-box">
<h3>&refreshProfile.title;</h3>
<button id="reset-box-button">
&refreshProfile.button.label;
</button>
</div>
<div id="safe-mode-box">
<h3>&aboutSupport.safeModeTitle;</h3>
<button id="restart-in-safe-mode-button">
&aboutSupport.restartInSafeMode.label;
</button>
</div>
</div>
<h1>
&aboutSupport.pageTitle;
</h1>
<div class="page-subtitle">
&aboutSupport.pageSubtitle;
</div>
<div>
<button id="copy-raw-data-to-clipboard">
&aboutSupport.copyRawDataToClipboard.label;
</button>
<button id="copy-to-clipboard">
&aboutSupport.copyTextToClipboard.label;
</button>
</div>
<div id="contents">
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.appBasicsTitle;
</h2>
<table>
<tbody>
<tr>
<th class="column">
&aboutSupport.appBasicsName;
</th>
<td id="application-box">
</td>
</tr>
<tr>
<th class="column">
&aboutSupport.appBasicsVersion;
</th>
<td id="version-box">
</td>
</tr>
<tr>
<th class="column">
&aboutSupport.appBasicsBuildID;
</th>
<td id="buildid-box"></td>
</tr>
#ifndef ANDROID
<tr class="no-copy">
<th class="column">
&aboutSupport.appBasicsUpdateHistory;
</th>
<td>
<button id="show-update-history-button">
&aboutSupport.appBasicsShowUpdateHistory;
</button>
</td>
</tr>
#endif
#ifdef MOZ_UPDATER
<tr>
<th class="column">
&aboutSupport.appBasicsUpdateChannel;
</th>
<td id="updatechannel-box"></td>
</tr>
#endif
<tr>
<th class="column">
&aboutSupport.appBasicsUserAgent;
</th>
<td id="useragent-box">
</td>
</tr>
<tr>
<th class="column">
&aboutSupport.appBasicsOS;
</th>
<td id="os-box">
</td>
</tr>
<tr id="profile-row" class="no-copy">
<th class="column">
#ifdef XP_WIN
&aboutSupport.appBasicsProfileDirWinMac;
#else
#ifdef XP_MACOSX
&aboutSupport.appBasicsProfileDirWinMac;
#else
&aboutSupport.appBasicsProfileDir;
#endif
#endif
</th>
<td>
<button id="profile-dir-button">
#ifdef XP_WIN
&aboutSupport.showWin2.label;
#else
#ifdef XP_MACOSX
&aboutSupport.showMac.label;
#else
&aboutSupport.showDir.label;
#endif
#endif
</button>
</td>
</tr>
<tr class="no-copy">
<th class="column">
&aboutSupport.appBasicsEnabledPlugins;
</th>
<td>
<a href="about:plugins">about:plugins</a>
</td>
</tr>
<tr class="no-copy">
<th class="column">
&aboutSupport.appBasicsBuildConfig;
</th>
<td>
<a href="about:buildconfig">about:buildconfig</a>
</td>
</tr>
<tr class="no-copy">
<th class="column">
&aboutSupport.appBasicsMemoryUse;
</th>
<td>
<a href="about:memory">about:memory</a>
</td>
</tr>
<tr class="no-copy">
<th class="column">
&aboutSupport.appBasicsPerformance;
</th>
<td>
<a href="about:performance">about:performance</a>
</td>
</tr>
<tr class="no-copy">
<th class="column">
&aboutSupport.appBasicsServiceWorkers;
</th>
<td>
<a href="about:serviceworkers">about:serviceworkers</a>
</td>
</tr>
<tr>
<th class="column">
&aboutSupport.appBasicsMultiProcessSupport;
</th>
<td id="multiprocess-box">
</td>
</tr>
<tr>
<th class="column">
&aboutSupport.appBasicsSafeMode;
</th>
<td id="safemode-box">
</td>
</tr>
#ifndef ANDROID
<tr class="no-copy">
<th class="column">
&aboutSupport.appBasicsProfiles;
</th>
<td>
<a href="about:profiles">about:profiles</a>
</td>
</tr>
#endif
</tbody>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
#ifdef MOZ_CRASHREPORTER
<h2 class="major-section" id="crashes-title">
&aboutSupport.crashes.title;
</h2>
<table id="crashes-table">
<thead>
<tr>
<th>
&aboutSupport.crashes.id;
</th>
<th>
&aboutSupport.crashes.sendDate;
</th>
</tr>
</thead>
<tbody id="crashes-tbody">
</tbody>
</table>
<p id="crashes-allReports" class="hidden no-copy">
<a href="about:crashes" id="crashes-allReportsWithPending" class="block">&aboutSupport.crashes.allReports;</a>
</p>
<p id="crashes-noConfig" class="hidden no-copy">&aboutSupport.crashes.noConfig;</p>
#endif
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.extensionsTitle;
</h2>
<table>
<thead>
<tr>
<th>
&aboutSupport.extensionName;
</th>
<th>
&aboutSupport.extensionVersion;
</th>
<th>
&aboutSupport.extensionEnabled;
</th>
<th>
&aboutSupport.extensionId;
</th>
</tr>
</thead>
<tbody id="extensions-tbody">
</tbody>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.graphicsTitle;
</h2>
<table>
<tbody id="graphics-features-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsFeaturesTitle;
</th>
</tr>
</tbody>
<tbody id="graphics-tbody">
</tbody>
<tbody id="graphics-gpu-1-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsGPU1Title;
</th>
</tr>
</tbody>
<tbody id="graphics-gpu-2-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsGPU2Title;
</th>
</tr>
</tbody>
<tbody id="graphics-diagnostics-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsDiagnosticsTitle;
</th>
</tr>
</tbody>
<tbody id="graphics-decisions-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsDecisionLogTitle;
</th>
</tr>
</tbody>
<tbody id="graphics-crashguards-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsCrashGuardsTitle;
</th>
</tr>
</tbody>
<tbody id="graphics-workarounds-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsWorkaroundsTitle;
</th>
</tr>
</tbody>
<tbody id="graphics-failures-tbody">
<tr>
<th colspan="2" class="title-column">
&aboutSupport.graphicsFailureLogTitle;
</th>
</tr>
</tbody>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.modifiedKeyPrefsTitle;
</h2>
<table class="prefs-table">
<thead class="no-copy">
<th class="name">
&aboutSupport.modifiedPrefsName;
</th>
<th class="value">
&aboutSupport.modifiedPrefsValue;
</th>
</thead>
<tbody id="prefs-tbody">
</tbody>
</table>
<section id="prefs-user-js-section" class="hidden no-copy">
<h3>&aboutSupport.userJSTitle;</h3>
<p>&aboutSupport.userJSDescription;</p>
</section>
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.lockedKeyPrefsTitle;
</h2>
<table class="prefs-table">
<thead class="no-copy">
<th class="name">
&aboutSupport.lockedPrefsName;
</th>
<th class="value">
&aboutSupport.lockedPrefsValue;
</th>
</thead>
<tbody id="locked-prefs-tbody">
</tbody>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.placeDatabaseTitle;
</h2>
<table>
<tr class="no-copy">
<th class="column">
&aboutSupport.placeDatabaseIntegrity;
</th>
<td>
<button id="verify-place-integrity-button">
&aboutSupport.placeDatabaseVerifyIntegrity;
</button>
<pre id="verify-place-result" class="hidden no-copy"></pre>
</td>
</tr>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.jsTitle;
</h2>
<table>
<tbody>
<tr>
<th class="column">
&aboutSupport.jsIncrementalGC;
</th>
<td id="javascript-incremental-gc">
</td>
</tr>
</tbody>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.a11yTitle;
</h2>
<table>
<tbody>
<tr>
<th class="column">
&aboutSupport.a11yActivated;
</th>
<td id="a11y-activated">
</td>
</tr>
<tr>
<th class="column">
&aboutSupport.a11yForceDisabled;
</th>
<td id="a11y-force-disabled">
</td>
</tr>
</tbody>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
<h2 class="major-section">
&aboutSupport.libraryVersionsTitle;
</h2>
<table>
<tbody id="libversions-tbody">
</tbody>
</table>
<h2 class="major-section">
&aboutSupport.experimentsTitle;
</h2>
<table>
<thead>
<tr>
<th>
&aboutSupport.experimentName;
</th>
<th>
&aboutSupport.experimentId;
</th>
<th>
&aboutSupport.experimentDescription;
</th>
<th>
&aboutSupport.experimentActive;
</th>
<th>
&aboutSupport.experimentEndDate;
</th>
<th>
&aboutSupport.experimentHomepage;
</th>
<th>
&aboutSupport.experimentBranch;
</th>
</tr>
</thead>
<tbody id="experiments-tbody">
</tbody>
</table>
<!-- - - - - - - - - - - - - - - - - - - - - -->
#if defined(MOZ_SANDBOX)
<h2 class="major-section" id="sandbox">
&aboutSupport.sandboxTitle;
</h2>
<table>
<tbody id="sandbox-tbody">
</tbody>
</table>
#endif
</div>
</body>
</html>

View file

@ -0,0 +1,271 @@
/* 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/. */
.hidden {
display: none;
}
html {
background-color: -moz-Dialog;
color: -moz-DialogText;
font: message-box;
}
body {
padding: 0px;
margin: 0px;
}
h2 {
font-size: medium;
}
#page-description {
border: 1px solid threedshadow;
margin: 0px;
padding: 10px;
}
#settings {
border: 1px solid lightgrey;
padding: 5px;
}
.description-enabled,
.description-disabled {
margin: 0px;
}
.description-enabled > span {
color: green;
}
.description-disabled > span {
color: red;
}
#ping-picker {
margin-top: 10px;
border: 1px solid lightgrey;
padding: 5px;
}
#ping-source-picker {
margin-left: 5px;
margin-bottom: 10px;
}
.data-section,
.data-subsection {
background-color: -moz-Field;
color: -moz-FieldText;
border-top: 1px solid threedshadow;
border-bottom: 1px solid threedshadow;
margin: 0px;
padding: 10px;
}
.data-section:not(.has-data),
.data-subsection:not(.has-subdata) {
color: gray;
}
.section-name {
font-size: x-large;
display: inline;
}
.has-data .section-name {
cursor: pointer;
}
.toggle-caption {
font-style: italic;
cursor: pointer;
}
.data-section:not(.has-data) .toggle-caption,
.data-subsection:not(.has-subdata) .toggle-caption {
display: none;
}
.empty-caption {
font-style: italic;
}
.has-data .empty-caption,
.has-subdata .empty-caption {
display: none; /* invisible when has-data */
}
.data,
.subdata {
margin: 15px;
display: none;
}
.has-data.expanded .data,
.has-subdata.expanded .subdata {
display: block;
}
.stack-title {
font-size: medium;
font-weight: bold;
text-decoration: underline;
}
#histograms, #addon-histograms, #thread-hang-stats>div {
overflow: hidden;
}
.histogram {
float: left;
border: 1px solid gray;
white-space: nowrap;
padding: 10px;
position: relative; /* required for position:absolute of the contained .copy-node */
}
body[dir="rtl"] .histogram {
float: right;
}
.histogram-title {
text-overflow: ellipsis;
width: 100%;
white-space: nowrap;
overflow: hidden;
}
.keyed-histogram {
white-space: nowrap;
padding: 15px;
position: relative; /* required for position:absolute of the contained .copy-node */
display: block;
overflow: hidden;
}
.keyed-histogram-title {
text-overflow: ellipsis;
width: 100%;
margin: 10px;
font-weight: bold;
font-size: 120%;
white-space: nowrap;
}
.bar {
width: 2em;
margin: 2px;
text-align: center;
float: left;
font-family: monospace;
}
body[dir="rtl"] .bar {
float: right;
}
.bar-inner {
background-color: DeepSkyBlue;
border: 1px solid #0000b0;
}
th {
font-weight: bold;
white-space: nowrap;
text-align: left;
}
body[dir="rtl"] th {
text-align: right;
}
caption {
font-weight: bold;
white-space: nowrap;
text-align: left;
font-size: large;
}
body[dir="rtl"] caption {
text-align: right;
}
.copy-node {
visibility: hidden;
position: absolute;
bottom: 1px;
right: 1px;
}
body[dir="rtl"] .copy-node {
left: 1px;
}
.histogram:hover .copy-node {
visibility: visible;
}
.statebox {
display: none;
}
.filter-ui {
padding-inline-start: 10em;
display: none;
}
.has-data.expanded .filter-ui {
display: inline;
}
.processes-ui {
display: none;
}
.has-data.expanded .processes-ui {
display: initial;
}
.filter-blocked {
display: none;
}
#raw-ping-data-section {
width: 100%;
height: 100%;
background-color:-moz-Dialog;
}
#raw-ping-data {
background-color:white;
margin: 0px;
}
#hide-raw-ping {
float: right;
cursor: pointer;
font-size: 20px;
background-color:#d8d8d8;
padding: 5px 10px;
}
/* addon subsection style */
.addon-caption {
font-size: larger;
margin: 5px 0;
}
.process-picker {
margin: 0 0.5em;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,290 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
<!ENTITY % aboutTelemetryDTD SYSTEM "chrome://global/locale/aboutTelemetry.dtd"> %aboutTelemetryDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&aboutTelemetry.pageTitle;</title>
<link rel="stylesheet" href="chrome://global/content/aboutTelemetry.css"
type="text/css"/>
<script type="application/javascript;version=1.7"
src="chrome://global/content/aboutTelemetry.js"/>
</head>
<body dir="&locale.dir;">
<header id="page-description">
<h1>&aboutTelemetry.pageTitle;</h1>
<h2 id="page-subtitle"></h2>
<table id="settings">
<tr>
<td>
<p id="description-upload-enabled" class="description-enabled">&aboutTelemetry.uploadEnabled;</p>
<p id="description-upload-disabled" class="description-disabled">&aboutTelemetry.uploadDisabled;</p>
</td>
<td>
<a href="" class="change-data-choices-link">&aboutTelemetry.changeDataChoices;</a>
</td>
</tr>
<tr>
<td>
<p id="description-extended-recording-enabled" class="description-enabled">&aboutTelemetry.extendedRecordingEnabled;</p>
<p id="description-extended-recording-disabled" class="description-disabled">&aboutTelemetry.extendedRecordingDisabled;</p>
</td>
<td>
<a href="" class="change-data-choices-link">&aboutTelemetry.changeDataChoices;</a>
</td>
</tr>
</table>
<div id="ping-picker">
<div id="ping-source-picker">
&aboutTelemetry.pingDataSource;<br/>
<input type="radio" id="ping-source-current" name="choose-ping-source" value="current" checked="checked" />
&aboutTelemetry.showCurrentPingData;<br />
<input type="radio" id="ping-source-archive" name="choose-ping-source" value="archive" />
&aboutTelemetry.showArchivedPingData;<br />
</div>
<div id="ping-source-picker">
&aboutTelemetry.pingDataDisplay;<br/>
<input type="radio" id="ping-source-structured" name="choose-ping-display" value="structured" checked="checked" />
&aboutTelemetry.structured;<br />
<input type="radio" id="ping-source-raw" name="choose-ping-display" value="raw" />
&aboutTelemetry.raw;<br />
</div>
<div id="current-ping-picker">
<input id="show-subsession-data" type="checkbox" checked="checked" />&aboutTelemetry.showSubsessionData;
</div>
<div id="archived-ping-picker" class="hidden">
&aboutTelemetry.choosePing;<br />
<button id="newer-ping" type="button">&aboutTelemetry.showNewerPing;</button>
<button id="older-ping" type="button">&aboutTelemetry.showOlderPing;</button><br />
<table>
<tr>
<th>&aboutTelemetry.archiveWeekHeader;</th>
<th>&aboutTelemetry.archivePingHeader;</th>
</tr>
<tr>
<td>
<select id="choose-ping-week">
</select>
</td>
<td>
<select id="choose-ping-id">
</select>
</td>
</tr>
</table>
</div>
<table>
<tr>
<th>&aboutTelemetry.payloadChoiceHeader;</th>
</tr>
<tr>
<td>
<select id="choose-payload">
</select>
</td>
</tr>
</table>
</div>
</header>
<div id="raw-ping-data-section" class="hidden">
<pre id="raw-ping-data"></pre>
</div>
<div id="structured-ping-data-section">
<section id="general-data-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.generalDataSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="general-data" class="data">
</div>
</section>
<section id="environment-data-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.environmentDataSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="environment-data" class="data">
</div>
</section>
<section id="session-info-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.sessionInfoSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="session-info" class="data">
</div>
</section>
<section id="scalars-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.scalarsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="scalars" class="data">
</div>
</section>
<section id="keyed-scalars-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.keyedScalarsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="keyed-scalars" class="data">
</div>
</section>
<section id="histograms-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.histogramsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<span class="filter-ui">
&aboutTelemetry.filterText; <input type="text" class="filter" id="histograms-filter" target_id="histograms"/>
</span>
<div class="processes-ui">
<select id="histograms-processes" class="process-picker"></select>
</div>
<div id="histograms" class="data">
</div>
</section>
<section id="keyed-histograms-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.keyedHistogramsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div class="processes-ui">
<select id="keyed-histograms-processes" class="process-picker"></select>
</div>
<div id="keyed-histograms" class="data">
</div>
</section>
<section id="events-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">Events</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="events" class="data">
</div>
</section>
<section id="simple-measurements-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.simpleMeasurementsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="simple-measurements" class="data">
</div>
</section>
<section id="telemetry-log-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.telemetryLogSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="telemetry-log" class="data">
</div>
</section>
<section id="slow-sql-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.slowSqlSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="slow-sql-tables" class="data">
<p id="sql-warning" class="hidden">&aboutTelemetry.fullSqlWarning;</p>
</div>
</section>
<section id="chrome-hangs-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.chromeHangsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="chrome-hangs" class="data">
<a id="chrome-hangs-fetch-symbols" href="#">&aboutTelemetry.fetchSymbols;</a>
<a id="chrome-hangs-hide-symbols" class="hidden" href="#">&aboutTelemetry.hideSymbols;</a>
<br/>
<br/>
<div id="chrome-hangs-data">
</div>
</div>
</section>
<section id="thread-hang-stats-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.threadHangStatsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="thread-hang-stats" class="data">
</div>
</section>
<section id="late-writes-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.lateWritesSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="late-writes" class="data">
<a id="late-writes-fetch-symbols" href="#">&aboutTelemetry.fetchSymbols;</a>
<a id="late-writes-hide-symbols" class="hidden" href="#">&aboutTelemetry.hideSymbols;</a>
<br/>
<br/>
<div id="late-writes-data">
</div>
</div>
</section>
<section id="addon-details-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.addonDetailsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="addon-details" class="data">
</div>
</section>
<section id="addon-histograms-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.addonHistogramsSection;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="addon-histograms" class="data">
</div>
</section>
<section id="raw-payload-section" class="data-section">
<input type="checkbox" class="statebox"/>
<h1 class="section-name">&aboutTelemetry.rawPayload;</h1>
<span class="toggle-caption">&aboutTelemetry.toggle;</span>
<span class="empty-caption">&aboutTelemetry.emptySection;</span>
<div id="raw-payload-data" class="data">
<pre id="raw-payload-data-pre"></pre>
</div>
</section>
</div>
</body>
</html>

View file

@ -0,0 +1,97 @@
/* 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/. */
html {
background-color: #edeceb;
font: message-box;
}
.controls {
font-size: 1.1em;
display: inline-block;
margin: 0 0.5em;
}
.control {
margin: 0.5em 0;
}
.control > button {
margin: 0 0.25em;
}
.message > p {
margin: 0.5em 0.5em;
}
.log p {
font-family: monospace;
padding-left: 2em;
text-indent: -2em;
margin-top: 2px;
margin-bottom: 2px;
}
#content > div {
padding: 1em 2em;
margin: 1em 0;
border: 1px solid #afaca9;
border-radius: 10px;
background: none repeat scroll 0% 0% #fff;
}
.section-heading *
{
display: inline-block;
}
.section-heading > button {
margin-left: 1em;
margin-right: 1em;
}
.peer-connection > h3
{
background-color: #ddd;
}
.peer-connection table {
width: 100%;
text-align: center;
border: none;
}
.peer-connection table th,
.peer-connection table td {
padding: 0.4em;
}
.peer-connection table tr:nth-child(even) {
background-color: #ddd;
}
.info-label {
font-weight: bold;
}
.section-ctrl {
margin: 1em 1.5em;
}
div.fold-trigger {
color: blue;
cursor: pointer;
}
@media screen {
.fold-closed {
display: none !important;
}
}
@media print {
.no-print {
display: none !important;
}
}

View file

@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<!-- 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/. -->
<html>
<head>
<meta charset="utf-8" />
<title>about:webrtc</title>
<link rel="stylesheet" type="text/css" media="all"
href="chrome://global/content/aboutwebrtc/aboutWebrtc.css"/>
<script type="text/javascript;version=1.8"
src="chrome://global/content/aboutwebrtc/aboutWebrtc.js"
defer="defer"></script>
</head>
<body id="body" onload="onLoad()">
<div id="controls" class="no-print"></div>
<div id="content"></div>
</body>
</html>

View file

@ -0,0 +1,841 @@
/* 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";
/* global WebrtcGlobalInformation, document */
var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "FilePicker",
"@mozilla.org/filepicker;1", "nsIFilePicker");
XPCOMUtils.defineLazyGetter(this, "strings", () => {
return Services.strings.createBundle("chrome://global/locale/aboutWebrtc.properties");
});
const getString = strings.GetStringFromName;
const formatString = strings.formatStringFromName;
const LOGFILE_NAME_DEFAULT = "aboutWebrtc.html";
const WEBRTC_TRACE_ALL = 65535;
function getStats() {
return new Promise(resolve =>
WebrtcGlobalInformation.getAllStats(stats => resolve(stats)));
}
function getLog() {
return new Promise(resolve =>
WebrtcGlobalInformation.getLogging("", log => resolve(log)));
}
// Begin initial data queries as page loads. Store returned Promises for
// later use.
var reportsRetrieved = getStats();
var logRetrieved = getLog();
function onLoad() {
document.title = getString("document_title");
let controls = document.querySelector("#controls");
if (controls) {
let set = ControlSet.render();
ControlSet.add(new SavePage());
ControlSet.add(new DebugMode());
ControlSet.add(new AecLogging());
controls.appendChild(set);
}
let contentElem = document.querySelector("#content");
if (!contentElem) {
return;
}
let contentInit = function(data) {
AboutWebRTC.init(onClearStats, onClearLog);
AboutWebRTC.render(contentElem, data);
};
Promise.all([reportsRetrieved, logRetrieved])
.then(([stats, log]) => contentInit({reports: stats.reports, log: log}))
.catch(error => contentInit({error: error}));
}
function onClearLog() {
WebrtcGlobalInformation.clearLogging();
getLog()
.then(log => AboutWebRTC.refresh({log: log}))
.catch(error => AboutWebRTC.refresh({logError: error}));
}
function onClearStats() {
WebrtcGlobalInformation.clearAllStats();
getStats()
.then(stats => AboutWebRTC.refresh({reports: stats.reports}))
.catch(error => AboutWebRTC.refresh({reportError: error}));
}
var ControlSet = {
render: function() {
let controls = document.createElement("div");
let control = document.createElement("div");
let message = document.createElement("div");
controls.className = "controls";
control.className = "control";
message.className = "message";
controls.appendChild(control);
controls.appendChild(message);
this.controlSection = control;
this.messageSection = message;
return controls;
},
add: function(controlObj) {
let [controlElem, messageElem] = controlObj.render();
this.controlSection.appendChild(controlElem);
this.messageSection.appendChild(messageElem);
}
};
function Control() {
this._label = null;
this._message = null;
this._messageHeader = null;
}
Control.prototype = {
render: function () {
let controlElem = document.createElement("button");
let messageElem = document.createElement("p");
this.ctrl = controlElem;
controlElem.onclick = this.onClick.bind(this);
this.msg = messageElem;
this.update();
return [controlElem, messageElem];
},
set label(val) {
return this._labelVal = val || "\xA0";
},
get label() {
return this._labelVal;
},
set message(val) {
return this._messageVal = val;
},
get message() {
return this._messageVal;
},
update: function() {
this.ctrl.textContent = this._label;
if (this._message) {
this.msg.innerHTML =
`<span class="info-label">${this._messageHeader}:</span> ${this._message}`;
} else {
this.msg.innerHTML = null;
}
},
onClick: function(event) {
return true;
}
};
function SavePage() {
Control.call(this);
this._messageHeader = getString("save_page_label");
this._label = getString("save_page_label");
}
SavePage.prototype = Object.create(Control.prototype);
SavePage.prototype.constructor = SavePage;
SavePage.prototype.onClick = function() {
let content = document.querySelector("#content");
if (!content)
return;
FoldEffect.expandAll();
FilePicker.init(window, getString("save_page_dialog_title"), FilePicker.modeSave);
FilePicker.defaultString = LOGFILE_NAME_DEFAULT;
let rv = FilePicker.show();
if (rv == FilePicker.returnOK || rv == FilePicker.returnReplace) {
let fout = FileUtils.openAtomicFileOutputStream(
FilePicker.file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
let nodes = content.querySelectorAll(".no-print");
let noPrintList = [];
for (let node of nodes) {
noPrintList.push(node);
node.style.setProperty("display", "none");
}
fout.write(content.outerHTML, content.outerHTML.length);
FileUtils.closeAtomicFileOutputStream(fout);
for (let node of noPrintList) {
node.style.removeProperty("display");
}
this._message = formatString("save_page_msg", [FilePicker.file.path], 1);
this.update();
}
};
function DebugMode() {
Control.call(this);
this._messageHeader = getString("debug_mode_msg_label");
if (WebrtcGlobalInformation.debugLevel > 0) {
this.onState();
} else {
this._label = getString("debug_mode_off_state_label");
this._message = null;
}
}
DebugMode.prototype = Object.create(Control.prototype);
DebugMode.prototype.constructor = DebugMode;
DebugMode.prototype.onState = function() {
this._label = getString("debug_mode_on_state_label");
try {
let file = Services.prefs.getCharPref("media.webrtc.debug.log_file");
this._message = formatString("debug_mode_on_state_msg", [file], 1);
} catch (e) {
this._message = null;
}
};
DebugMode.prototype.offState = function() {
this._label = getString("debug_mode_off_state_label");
try {
let file = Services.prefs.getCharPref("media.webrtc.debug.log_file");
this._message = formatString("debug_mode_off_state_msg", [file], 1);
} catch (e) {
this._message = null;
}
};
DebugMode.prototype.onClick = function() {
if (WebrtcGlobalInformation.debugLevel > 0) {
WebrtcGlobalInformation.debugLevel = 0;
this.offState();
} else {
WebrtcGlobalInformation.debugLevel = WEBRTC_TRACE_ALL;
this.onState();
}
this.update();
};
function AecLogging() {
Control.call(this);
this._messageHeader = getString("aec_logging_msg_label");
if (WebrtcGlobalInformation.aecDebug) {
this.onState();
} else {
this._label = getString("aec_logging_off_state_label");
this._message = null;
}
}
AecLogging.prototype = Object.create(Control.prototype);
AecLogging.prototype.constructor = AecLogging;
AecLogging.prototype.offState = function () {
this._label = getString("aec_logging_off_state_label");
try {
let file = Services.prefs.getCharPref("media.webrtc.debug.aec_log_dir");
this._message = formatString("aec_logging_off_state_msg", [file], 1);
} catch (e) {
this._message = null;
}
};
AecLogging.prototype.onState = function () {
this._label = getString("aec_logging_on_state_label");
try {
let file = Services.prefs.getCharPref("media.webrtc.debug.aec_log_dir");
this._message = getString("aec_logging_on_state_msg");
} catch (e) {
this._message = null;
}
};
AecLogging.prototype.onClick = function () {
if (WebrtcGlobalInformation.aecDebug) {
WebrtcGlobalInformation.aecDebug = false;
this.offState();
} else {
WebrtcGlobalInformation.aecDebug = true;
this.onState();
}
this.update();
};
var AboutWebRTC = {
_reports: [],
_log: [],
init: function(onClearStats, onClearLog) {
this._onClearStats = onClearStats;
this._onClearLog = onClearLog;
},
render: function(parent, data) {
this._content = parent;
this._setData(data);
if (data.error) {
let msg = document.createElement("h3");
msg.textContent = getString("cannot_retrieve_log");
parent.appendChild(msg);
msg = document.createElement("p");
msg.innerHTML = `${data.error.name}: ${data.error.message}`;
parent.appendChild(msg);
return;
}
this._peerConnections = this.renderPeerConnections();
this._connectionLog = this.renderConnectionLog();
this._content.appendChild(this._peerConnections);
this._content.appendChild(this._connectionLog);
},
_setData: function(data) {
if (data.reports) {
this._reports = data.reports;
}
if (data.log) {
this._log = data.log;
}
},
refresh: function(data) {
this._setData(data);
let pc = this._peerConnections;
this._peerConnections = this.renderPeerConnections();
let log = this._connectionLog;
this._connectionLog = this.renderConnectionLog();
this._content.replaceChild(this._peerConnections, pc);
this._content.replaceChild(this._connectionLog, log);
},
renderPeerConnections: function() {
let connections = document.createElement("div");
connections.className = "stats";
let heading = document.createElement("span");
heading.className = "section-heading";
let elem = document.createElement("h3");
elem.textContent = getString("stats_heading");
heading.appendChild(elem);
elem = document.createElement("button");
elem.textContent = "Clear History";
elem.className = "no-print";
elem.onclick = this._onClearStats;
heading.appendChild(elem);
connections.appendChild(heading);
if (!this._reports || !this._reports.length) {
return connections;
}
let reports = [...this._reports];
reports.sort((a, b) => b.timestamp - a.timestamp);
for (let report of reports) {
let peerConnection = new PeerConnection(report);
connections.appendChild(peerConnection.render());
}
return connections;
},
renderConnectionLog: function() {
let content = document.createElement("div");
content.className = "log";
let heading = document.createElement("span");
heading.className = "section-heading";
let elem = document.createElement("h3");
elem.textContent = getString("log_heading");
heading.appendChild(elem);
elem = document.createElement("button");
elem.textContent = "Clear Log";
elem.className = "no-print";
elem.onclick = this._onClearLog;
heading.appendChild(elem);
content.appendChild(heading);
if (!this._log || !this._log.length) {
return content;
}
let div = document.createElement("div");
let sectionCtrl = document.createElement("div");
sectionCtrl.className = "section-ctrl no-print";
let foldEffect = new FoldEffect(div, {
showMsg: getString("log_show_msg"),
hideMsg: getString("log_hide_msg")
});
sectionCtrl.appendChild(foldEffect.render());
content.appendChild(sectionCtrl);
for (let line of this._log) {
elem = document.createElement("p");
elem.textContent = line;
div.appendChild(elem);
}
content.appendChild(div);
return content;
}
};
function PeerConnection(report) {
this._report = report;
}
PeerConnection.prototype = {
render: function() {
let pc = document.createElement("div");
pc.className = "peer-connection";
pc.appendChild(this.renderHeading());
let div = document.createElement("div");
let sectionCtrl = document.createElement("div");
sectionCtrl.className = "section-ctrl no-print";
let foldEffect = new FoldEffect(div);
sectionCtrl.appendChild(foldEffect.render());
pc.appendChild(sectionCtrl);
div.appendChild(this.renderDesc());
div.appendChild(new ICEStats(this._report).render());
div.appendChild(new SDPStats(this._report).render());
div.appendChild(new RTPStats(this._report).render());
pc.appendChild(div);
return pc;
},
renderHeading: function () {
let pcInfo = this.getPCInfo(this._report);
let heading = document.createElement("h3");
let now = new Date(this._report.timestamp).toTimeString();
heading.textContent =
`[ ${pcInfo.id} ] ${pcInfo.url} ${pcInfo.closed ? `(${getString("connection_closed")})` : ""} ${now}`;
return heading;
},
renderDesc: function() {
let info = document.createElement("div");
let label = document.createElement("span");
let body = document.createElement("span");
label.className = "info-label";
label.textContent = `${getString("peer_connection_id_label")}: `;
info.appendChild(label);
body.className = "info-body";
body.textContent = this._report.pcid;
info.appendChild(body);
return info;
},
getPCInfo: function(report) {
return {
id: report.pcid.match(/id=(\S+)/)[1],
url: report.pcid.match(/url=([^)]+)/)[1],
closed: report.closed
};
}
};
function SDPStats(report) {
this._report = report;
}
SDPStats.prototype = {
render: function() {
let div = document.createElement("div");
let elem = document.createElement("h4");
elem.textContent = getString("sdp_heading");
div.appendChild(elem);
elem = document.createElement("h5");
elem.textContent = getString("local_sdp_heading");
div.appendChild(elem);
elem = document.createElement("pre");
elem.textContent = this._report.localSdp;
div.appendChild(elem);
elem = document.createElement("h5");
elem.textContent = getString("remote_sdp_heading");
div.appendChild(elem);
elem = document.createElement("pre");
elem.textContent = this._report.remoteSdp;
div.appendChild(elem);
return div;
}
};
function RTPStats(report) {
this._report = report;
this._stats = [];
}
RTPStats.prototype = {
render: function() {
let div = document.createElement("div");
let heading = document.createElement("h4");
heading.textContent = getString("rtp_stats_heading");
div.appendChild(heading);
this.generateRTPStats();
for (let statSet of this._stats) {
div.appendChild(this.renderRTPStatSet(statSet));
}
return div;
},
generateRTPStats: function() {
let remoteRtpStats = {};
let rtpStats = [].concat((this._report.inboundRTPStreamStats || []),
(this._report.outboundRTPStreamStats || []));
// Generate an id-to-streamStat index for each streamStat that is marked
// as a remote. This will be used next to link the remote to its local side.
for (let stats of rtpStats) {
if (stats.isRemote) {
remoteRtpStats[stats.id] = stats;
}
}
// If a streamStat has a remoteId attribute, create a remoteRtpStats
// attribute that references the remote streamStat entry directly.
// That is, the index generated above is merged into the returned list.
for (let stats of rtpStats) {
if (stats.remoteId) {
stats.remoteRtpStats = remoteRtpStats[stats.remoteId];
}
}
this._stats = rtpStats;
},
renderAvStats: function(stats) {
let statsString = "";
if (stats.mozAvSyncDelay) {
statsString += `${getString("av_sync_label")}: ${stats.mozAvSyncDelay} ms `;
}
if (stats.mozJitterBufferDelay) {
statsString += `${getString("jitter_buffer_delay_label")}: ${stats.mozJitterBufferDelay} ms`;
}
let line = document.createElement("p");
line.textContent = statsString;
return line;
},
renderCoderStats: function(stats) {
let statsString = "";
let label;
if (stats.bitrateMean) {
statsString += ` ${getString("avg_bitrate_label")}: ${(stats.bitrateMean / 1000000).toFixed(2)} Mbps`;
if (stats.bitrateStdDev) {
statsString += ` (${(stats.bitrateStdDev / 1000000).toFixed(2)} SD)`;
}
}
if (stats.framerateMean) {
statsString += ` ${getString("avg_framerate_label")}: ${(stats.framerateMean).toFixed(2)} fps`;
if (stats.framerateStdDev) {
statsString += ` (${stats.framerateStdDev.toFixed(2)} SD)`;
}
}
if (stats.droppedFrames) {
statsString += ` ${getString("dropped_frames_label")}: ${stats.droppedFrames}`;
}
if (stats.discardedPackets) {
statsString += ` ${getString("discarded_packets_label")}: ${stats.discardedPackets}`;
}
if (statsString) {
label = (stats.packetsReceived ? ` ${getString("decoder_label")}:` : ` ${getString("encoder_label")}:`);
statsString = label + statsString;
}
let line = document.createElement("p");
line.textContent = statsString;
return line;
},
renderTransportStats: function(stats, typeLabel) {
let time = new Date(stats.timestamp).toTimeString();
let statsString = `${typeLabel}: ${time} ${stats.type} SSRC: ${stats.ssrc}`;
if (stats.packetsReceived) {
statsString += ` ${getString("received_label")}: ${stats.packetsReceived} ${getString("packets")}`;
if (stats.bytesReceived) {
statsString += ` (${(stats.bytesReceived / 1024).toFixed(2)} Kb)`;
}
statsString += ` ${getString("lost_label")}: ${stats.packetsLost} ${getString("jitter_label")}: ${stats.jitter}`;
if (stats.mozRtt) {
statsString += ` RTT: ${stats.mozRtt} ms`;
}
} else if (stats.packetsSent) {
statsString += ` ${getString("sent_label")}: ${stats.packetsSent} ${getString("packets")}`;
if (stats.bytesSent) {
statsString += ` (${(stats.bytesSent / 1024).toFixed(2)} Kb)`;
}
}
let line = document.createElement("p");
line.textContent = statsString;
return line;
},
renderRTPStatSet: function(stats) {
let div = document.createElement("div");
let heading = document.createElement("h5");
heading.textContent = stats.id;
div.appendChild(heading);
if (stats.MozAvSyncDelay || stats.mozJitterBufferDelay) {
div.appendChild(this.renderAvStats(stats));
}
div.appendChild(this.renderCoderStats(stats));
div.appendChild(this.renderTransportStats(stats, getString("typeLocal")));
if (stats.remoteId && stats.remoteRtpStats) {
div.appendChild(this.renderTransportStats(stats.remoteRtpStats, getString("typeRemote")));
}
return div;
},
};
function ICEStats(report) {
this._report = report;
}
ICEStats.prototype = {
render: function() {
let tbody = [];
for (let stat of this.generateICEStats()) {
tbody.push([
stat.localcandidate || "",
stat.remotecandidate || "",
stat.state || "",
stat.priority || "",
stat.nominated || "",
stat.selected || ""
]);
}
let statsTable = new SimpleTable(
[getString("local_candidate"), getString("remote_candidate"), getString("ice_state"),
getString("priority"), getString("nominated"), getString("selected")],
tbody);
let div = document.createElement("div");
let heading = document.createElement("h4");
heading.textContent = getString("ice_stats_heading");
div.appendChild(heading);
div.appendChild(statsTable.render());
return div;
},
generateICEStats: function() {
// Create an index based on candidate ID for each element in the
// iceCandidateStats array.
let candidates = new Map();
for (let candidate of this._report.iceCandidateStats) {
candidates.set(candidate.id, candidate);
}
// A component may have a remote or local candidate address or both.
// Combine those with both; these will be the peer candidates.
let matched = {};
let stats = [];
let stat;
for (let pair of this._report.iceCandidatePairStats) {
let local = candidates.get(pair.localCandidateId);
let remote = candidates.get(pair.remoteCandidateId);
if (local) {
stat = {
localcandidate: this.candidateToString(local),
state: pair.state,
priority: pair.priority,
nominated: pair.nominated,
selected: pair.selected
};
matched[local.id] = true;
if (remote) {
stat.remotecandidate = this.candidateToString(remote);
matched[remote.id] = true;
}
stats.push(stat);
}
}
for (let c of candidates.values()) {
if (matched[c.id])
continue;
stat = {};
stat[c.type] = this.candidateToString(c);
stats.push(stat);
}
return stats.sort((a, b) => (b.priority || 0) - (a.priority || 0));
},
candidateToString: function(c) {
if (!c) {
return "*";
}
var type = c.candidateType;
if (c.type == "localcandidate" && c.candidateType == "relayed") {
type = `${c.candidateType}-${c.mozLocalTransport}`;
}
return `${c.ipAddress}:${c.portNumber}/${c.transport}(${type})`;
}
};
function SimpleTable(heading, data) {
this._heading = heading || [];
this._data = data;
}
SimpleTable.prototype = {
renderRow: function(list) {
let row = document.createElement("tr");
for (let elem of list) {
let cell = document.createElement("td");
cell.textContent = elem;
row.appendChild(cell);
}
return row;
},
render: function() {
let table = document.createElement("table");
if (this._heading) {
table.appendChild(this.renderRow(this._heading));
}
for (let row of this._data) {
table.appendChild(this.renderRow(row));
}
return table;
}
};
function FoldEffect(targetElem, options = {}) {
if (targetElem) {
this._showMsg = "\u25BC " + (options.showMsg || getString("fold_show_msg"));
this._showHint = options.showHint || getString("fold_show_hint");
this._hideMsg = "\u25B2 " + (options.hideMsg || getString("fold_hide_msg"));
this._hideHint = options.hideHint || getString("fold_hide_hint");
this._target = targetElem;
}
}
FoldEffect.prototype = {
render: function() {
this._target.classList.add("fold-target");
let ctrl = document.createElement("div");
this._trigger = ctrl;
ctrl.className = "fold-trigger";
ctrl.addEventListener("click", this.onClick.bind(this));
this.close();
FoldEffect._sections.push(this);
return ctrl;
},
onClick: function() {
if (this._target.classList.contains("fold-closed")) {
this.open();
} else {
this.close();
}
return true;
},
open: function() {
this._target.classList.remove("fold-closed");
this._trigger.setAttribute("title", this._hideHint);
this._trigger.textContent = this._hideMsg;
},
close: function() {
this._target.classList.add("fold-closed");
this._trigger.setAttribute("title", this._showHint);
this._trigger.textContent = this._showMsg;
}
};
FoldEffect._sections = [];
FoldEffect.expandAll = function() {
for (let section of this._sections) {
section.open();
}
};
FoldEffect.collapseAll = function() {
for (let section of this._sections) {
section.close();
}
};

View file

@ -0,0 +1,40 @@
/* 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/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
/* Apply crisp rendering for favicons at exactly 2dppx resolution */
@media (resolution: 2dppx) {
.ac-site-icon {
image-rendering: -moz-crisp-edges;
}
}
richlistitem {
-moz-box-orient: horizontal;
overflow: hidden;
}
.ac-title-text,
.ac-tags-text,
.ac-url-text,
.ac-action-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ac-tags[empty] {
display: none;
}
.ac-action[actiontype=searchengine]:not([selected]),
.ac-separator[actiontype=searchengine]:not([selected]) {
display: none;
}
.ac-separator[type=keyword] {
display: none;
}

View file

@ -0,0 +1,625 @@
/* 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 Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/BrowserUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import("resource://gre/modules/RemoteAddonsChild.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbUtils",
"resource://gre/modules/PageThumbUtils.jsm");
if (AppConstants.MOZ_CRASHREPORTER) {
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
"@mozilla.org/xre/app-info;1",
"nsICrashReporter");
}
function makeInputStream(aString) {
let stream = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsISupportsCString);
stream.data = aString;
return stream; // XPConnect will QI this to nsIInputStream for us.
}
var WebProgressListener = {
init: function() {
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(Ci.nsIWebProgress);
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(this._filter, Ci.nsIWebProgress.NOTIFY_ALL);
},
uninit() {
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
webProgress.removeProgressListener(this._filter);
this._filter.removeProgressListener(this);
this._filter = null;
},
_requestSpec: function (aRequest, aPropertyName) {
if (!aRequest || !(aRequest instanceof Ci.nsIChannel))
return null;
return aRequest.QueryInterface(Ci.nsIChannel)[aPropertyName].spec;
},
_setupJSON: function setupJSON(aWebProgress, aRequest) {
let innerWindowID = null;
if (aWebProgress) {
let domWindowID = null;
try {
let utils = aWebProgress.DOMWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
domWindowID = utils.outerWindowID;
innerWindowID = utils.currentInnerWindowID;
} catch (e) {
// If nsDocShell::Destroy has already been called, then we'll
// get NS_NOINTERFACE when trying to get the DOM window.
// If there is no current inner window, we'll get
// NS_ERROR_NOT_AVAILABLE.
}
aWebProgress = {
isTopLevel: aWebProgress.isTopLevel,
isLoadingDocument: aWebProgress.isLoadingDocument,
loadType: aWebProgress.loadType,
DOMWindowID: domWindowID
};
}
return {
webProgress: aWebProgress || null,
requestURI: this._requestSpec(aRequest, "URI"),
originalRequestURI: this._requestSpec(aRequest, "originalURI"),
documentContentType: content.document && content.document.contentType,
innerWindowID,
};
},
_setupObjects: function setupObjects(aWebProgress, aRequest) {
let domWindow;
try {
domWindow = aWebProgress && aWebProgress.DOMWindow;
} catch (e) {
// If nsDocShell::Destroy has already been called, then we'll
// get NS_NOINTERFACE when trying to get the DOM window. Ignore
// that here.
domWindow = null;
}
return {
contentWindow: content,
// DOMWindow is not necessarily the content-window with subframes.
DOMWindow: domWindow,
webProgress: aWebProgress,
request: aRequest,
};
},
_send(name, data, objects) {
if (RemoteAddonsChild.useSyncWebProgress) {
sendRpcMessage(name, data, objects);
} else {
sendAsyncMessage(name, data, objects);
}
},
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
let json = this._setupJSON(aWebProgress, aRequest);
let objects = this._setupObjects(aWebProgress, aRequest);
json.stateFlags = aStateFlags;
json.status = aStatus;
// It's possible that this state change was triggered by
// loading an internal error page, for which the parent
// will want to know some details, so we'll update it with
// the documentURI.
if (aWebProgress && aWebProgress.isTopLevel) {
json.documentURI = content.document.documentURIObject.spec;
json.charset = content.document.characterSet;
json.mayEnableCharacterEncodingMenu = docShell.mayEnableCharacterEncodingMenu;
json.inLoadURI = WebNavigation.inLoadURI;
}
this._send("Content:StateChange", json, objects);
},
onProgressChange: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
let json = this._setupJSON(aWebProgress, aRequest);
let objects = this._setupObjects(aWebProgress, aRequest);
json.curSelf = aCurSelf;
json.maxSelf = aMaxSelf;
json.curTotal = aCurTotal;
json.maxTotal = aMaxTotal;
this._send("Content:ProgressChange", json, objects);
},
onProgressChange64: function onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal) {
this.onProgressChange(aWebProgress, aRequest, aCurSelf, aMaxSelf, aCurTotal, aMaxTotal);
},
onLocationChange: function onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
let json = this._setupJSON(aWebProgress, aRequest);
let objects = this._setupObjects(aWebProgress, aRequest);
json.location = aLocationURI ? aLocationURI.spec : "";
json.flags = aFlags;
// These properties can change even for a sub-frame navigation.
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
json.canGoBack = webNav.canGoBack;
json.canGoForward = webNav.canGoForward;
if (aWebProgress && aWebProgress.isTopLevel) {
json.documentURI = content.document.documentURIObject.spec;
json.title = content.document.title;
json.charset = content.document.characterSet;
json.mayEnableCharacterEncodingMenu = docShell.mayEnableCharacterEncodingMenu;
json.principal = content.document.nodePrincipal;
json.synthetic = content.document.mozSyntheticDocument;
json.inLoadURI = WebNavigation.inLoadURI;
if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
let uri = aLocationURI.clone();
try {
// If the current URI contains a username/password, remove it.
uri.userPass = "";
} catch (ex) { /* Ignore failures on about: URIs. */ }
CrashReporter.annotateCrashReport("URL", uri.spec);
}
}
this._send("Content:LocationChange", json, objects);
},
onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
let json = this._setupJSON(aWebProgress, aRequest);
let objects = this._setupObjects(aWebProgress, aRequest);
json.status = aStatus;
json.message = aMessage;
this._send("Content:StatusChange", json, objects);
},
onSecurityChange: function onSecurityChange(aWebProgress, aRequest, aState) {
let json = this._setupJSON(aWebProgress, aRequest);
let objects = this._setupObjects(aWebProgress, aRequest);
json.state = aState;
json.status = SecurityUI.getSSLStatusAsString();
this._send("Content:SecurityChange", json, objects);
},
onRefreshAttempted: function onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI) {
return true;
},
sendLoadCallResult() {
sendAsyncMessage("Content:LoadURIResult");
},
QueryInterface: function QueryInterface(aIID) {
if (aIID.equals(Ci.nsIWebProgressListener) ||
aIID.equals(Ci.nsIWebProgressListener2) ||
aIID.equals(Ci.nsISupportsWeakReference) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
WebProgressListener.init();
addEventListener("unload", () => {
WebProgressListener.uninit();
});
var WebNavigation = {
init: function() {
addMessageListener("WebNavigation:GoBack", this);
addMessageListener("WebNavigation:GoForward", this);
addMessageListener("WebNavigation:GotoIndex", this);
addMessageListener("WebNavigation:LoadURI", this);
addMessageListener("WebNavigation:SetOriginAttributes", this);
addMessageListener("WebNavigation:Reload", this);
addMessageListener("WebNavigation:Stop", this);
},
get webNavigation() {
return docShell.QueryInterface(Ci.nsIWebNavigation);
},
_inLoadURI: false,
get inLoadURI() {
return this._inLoadURI;
},
receiveMessage: function(message) {
switch (message.name) {
case "WebNavigation:GoBack":
this.goBack();
break;
case "WebNavigation:GoForward":
this.goForward();
break;
case "WebNavigation:GotoIndex":
this.gotoIndex(message.data.index);
break;
case "WebNavigation:LoadURI":
this.loadURI(message.data.uri, message.data.flags,
message.data.referrer, message.data.referrerPolicy,
message.data.postData, message.data.headers,
message.data.baseURI);
break;
case "WebNavigation:SetOriginAttributes":
this.setOriginAttributes(message.data.originAttributes);
break;
case "WebNavigation:Reload":
this.reload(message.data.flags);
break;
case "WebNavigation:Stop":
this.stop(message.data.flags);
break;
}
},
_wrapURIChangeCall(fn) {
this._inLoadURI = true;
try {
fn();
} finally {
this._inLoadURI = false;
WebProgressListener.sendLoadCallResult();
}
},
goBack: function() {
if (this.webNavigation.canGoBack) {
this._wrapURIChangeCall(() => this.webNavigation.goBack());
}
},
goForward: function() {
if (this.webNavigation.canGoForward) {
this._wrapURIChangeCall(() => this.webNavigation.goForward());
}
},
gotoIndex: function(index) {
this._wrapURIChangeCall(() => this.webNavigation.gotoIndex(index));
},
loadURI: function(uri, flags, referrer, referrerPolicy, postData, headers, baseURI) {
if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
let annotation = uri;
try {
let url = Services.io.newURI(uri, null, null);
// If the current URI contains a username/password, remove it.
url.userPass = "";
annotation = url.spec;
} catch (ex) { /* Ignore failures to parse and failures
on about: URIs. */ }
CrashReporter.annotateCrashReport("URL", annotation);
}
if (referrer)
referrer = Services.io.newURI(referrer, null, null);
if (postData)
postData = makeInputStream(postData);
if (headers)
headers = makeInputStream(headers);
if (baseURI)
baseURI = Services.io.newURI(baseURI, null, null);
this._wrapURIChangeCall(() => {
return this.webNavigation.loadURIWithOptions(uri, flags, referrer, referrerPolicy,
postData, headers, baseURI);
});
},
setOriginAttributes: function(originAttributes) {
if (originAttributes) {
this.webNavigation.setOriginAttributesBeforeLoading(originAttributes);
}
},
reload: function(flags) {
this.webNavigation.reload(flags);
},
stop: function(flags) {
this.webNavigation.stop(flags);
}
};
WebNavigation.init();
var SecurityUI = {
getSSLStatusAsString: function() {
let status = docShell.securityUI.QueryInterface(Ci.nsISSLStatusProvider).SSLStatus;
if (status) {
let helper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
status.QueryInterface(Ci.nsISerializable);
return helper.serializeToString(status);
}
return null;
}
};
var ControllerCommands = {
init: function () {
addMessageListener("ControllerCommands:Do", this);
addMessageListener("ControllerCommands:DoWithParams", this);
},
receiveMessage: function(message) {
switch (message.name) {
case "ControllerCommands:Do":
if (docShell.isCommandEnabled(message.data))
docShell.doCommand(message.data);
break;
case "ControllerCommands:DoWithParams":
var data = message.data;
if (docShell.isCommandEnabled(data.cmd)) {
var params = Cc["@mozilla.org/embedcomp/command-params;1"].
createInstance(Ci.nsICommandParams);
for (var name in data.params) {
var value = data.params[name];
if (value.type == "long") {
params.setLongValue(name, parseInt(value.value));
} else {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
}
}
docShell.doCommandWithParams(data.cmd, params);
}
break;
}
}
}
ControllerCommands.init()
addEventListener("DOMTitleChanged", function (aEvent) {
let document = content.document;
switch (aEvent.type) {
case "DOMTitleChanged":
if (!aEvent.isTrusted || aEvent.target.defaultView != content)
return;
sendAsyncMessage("DOMTitleChanged", { title: document.title });
break;
}
}, false);
addEventListener("DOMWindowClose", function (aEvent) {
if (!aEvent.isTrusted)
return;
sendAsyncMessage("DOMWindowClose");
}, false);
addEventListener("ImageContentLoaded", function (aEvent) {
if (content.document instanceof Ci.nsIImageDocument) {
let req = content.document.imageRequest;
if (!req.image)
return;
sendAsyncMessage("ImageDocumentLoaded", { width: req.image.width,
height: req.image.height });
}
}, false);
const ZoomManager = {
get fullZoom() {
return this._cache.fullZoom;
},
get textZoom() {
return this._cache.textZoom;
},
set fullZoom(value) {
this._cache.fullZoom = value;
this._markupViewer.fullZoom = value;
},
set textZoom(value) {
this._cache.textZoom = value;
this._markupViewer.textZoom = value;
},
refreshFullZoom: function() {
return this._refreshZoomValue('fullZoom');
},
refreshTextZoom: function() {
return this._refreshZoomValue('textZoom');
},
/**
* Retrieves specified zoom property value from markupViewer and refreshes
* cache if needed.
* @param valueName Either 'fullZoom' or 'textZoom'.
* @returns Returns true if cached value was actually refreshed.
* @private
*/
_refreshZoomValue: function(valueName) {
let actualZoomValue = this._markupViewer[valueName];
// Round to remove any floating-point error.
actualZoomValue = Number(actualZoomValue.toFixed(2));
if (actualZoomValue != this._cache[valueName]) {
this._cache[valueName] = actualZoomValue;
return true;
}
return false;
},
get _markupViewer() {
return docShell.contentViewer;
},
_cache: {
fullZoom: NaN,
textZoom: NaN
}
};
addMessageListener("FullZoom", function (aMessage) {
ZoomManager.fullZoom = aMessage.data.value;
});
addMessageListener("TextZoom", function (aMessage) {
ZoomManager.textZoom = aMessage.data.value;
});
addEventListener("FullZoomChange", function () {
if (ZoomManager.refreshFullZoom()) {
sendAsyncMessage("FullZoomChange", { value: ZoomManager.fullZoom });
}
}, false);
addEventListener("TextZoomChange", function (aEvent) {
if (ZoomManager.refreshTextZoom()) {
sendAsyncMessage("TextZoomChange", { value: ZoomManager.textZoom });
}
}, false);
addEventListener("ZoomChangeUsingMouseWheel", function () {
sendAsyncMessage("ZoomChangeUsingMouseWheel", {});
}, false);
addMessageListener("UpdateCharacterSet", function (aMessage) {
docShell.charset = aMessage.data.value;
docShell.gatherCharsetMenuTelemetry();
});
/**
* Remote thumbnail request handler for PageThumbs thumbnails.
*/
addMessageListener("Browser:Thumbnail:Request", function (aMessage) {
let snapshot;
let args = aMessage.data.additionalArgs;
let fullScale = args ? args.fullScale : false;
if (fullScale) {
snapshot = PageThumbUtils.createSnapshotThumbnail(content, null, args);
} else {
let snapshotWidth = aMessage.data.canvasWidth;
let snapshotHeight = aMessage.data.canvasHeight;
snapshot =
PageThumbUtils.createCanvas(content, snapshotWidth, snapshotHeight);
PageThumbUtils.createSnapshotThumbnail(content, snapshot, args);
}
snapshot.toBlob(function (aBlob) {
sendAsyncMessage("Browser:Thumbnail:Response", {
thumbnail: aBlob,
id: aMessage.data.id
});
});
});
/**
* Remote isSafeForCapture request handler for PageThumbs.
*/
addMessageListener("Browser:Thumbnail:CheckState", function (aMessage) {
let result = PageThumbUtils.shouldStoreContentThumbnail(content, docShell);
sendAsyncMessage("Browser:Thumbnail:CheckState:Response", {
result: result
});
});
/**
* Remote GetOriginalURL request handler for PageThumbs.
*/
addMessageListener("Browser:Thumbnail:GetOriginalURL", function (aMessage) {
let channel = docShell.currentDocumentChannel;
let channelError = PageThumbUtils.isChannelErrorResponse(channel);
let originalURL;
try {
originalURL = channel.originalURI.spec;
} catch (ex) {}
sendAsyncMessage("Browser:Thumbnail:GetOriginalURL:Response", {
channelError: channelError,
originalURL: originalURL,
});
});
/**
* Remote createAboutBlankContentViewer request handler.
*/
addMessageListener("Browser:CreateAboutBlank", function(aMessage) {
if (!content.document || content.document.documentURI != "about:blank") {
throw new Error("Can't create a content viewer unless on about:blank");
}
let principal = aMessage.data;
principal = BrowserUtils.principalWithMatchingOA(principal, content.document.nodePrincipal);
docShell.createAboutBlankContentViewer(principal);
});
// The AddonsChild needs to be rooted so that it stays alive as long as
// the tab.
var AddonsChild = RemoteAddonsChild.init(this);
if (AddonsChild) {
addEventListener("unload", () => {
RemoteAddonsChild.uninit(AddonsChild);
});
}
addMessageListener("NetworkPrioritizer:AdjustPriority", (msg) => {
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let loadGroup = webNav.QueryInterface(Ci.nsIDocumentLoader)
.loadGroup.QueryInterface(Ci.nsISupportsPriority);
loadGroup.adjustPriority(msg.data.adjustment);
});
addMessageListener("NetworkPrioritizer:SetPriority", (msg) => {
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let loadGroup = webNav.QueryInterface(Ci.nsIDocumentLoader)
.loadGroup.QueryInterface(Ci.nsISupportsPriority);
loadGroup.priority = msg.data.priority;
});
addMessageListener("InPermitUnload", msg => {
let inPermitUnload = docShell.contentViewer && docShell.contentViewer.inPermitUnload;
sendAsyncMessage("InPermitUnload", {id: msg.data.id, inPermitUnload});
});
addMessageListener("PermitUnload", msg => {
sendAsyncMessage("PermitUnload", {id: msg.data.id, kind: "start"});
let permitUnload = true;
if (docShell && docShell.contentViewer) {
permitUnload = docShell.contentViewer.permitUnload();
}
sendAsyncMessage("PermitUnload", {id: msg.data.id, kind: "end", permitUnload});
});
// We may not get any responses to Browser:Init if the browser element
// is torn down too quickly.
var outerWindowID = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
sendAsyncMessage("Browser:Init", {outerWindowID: outerWindowID});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,66 @@
<!DOCTYPE html>
# 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/.
#
#filter substitution
#include @TOPOBJDIR@/source-repo.h
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width; user-scalable=false;">
<title>about:buildconfig</title>
<link rel="stylesheet" href="chrome://global/skin/about.css" type="text/css">
<style type="text/css">
th { text-align: start; }
h2 { margin-top: 1.5em; }
th, td { vertical-align: top; }
</style>
</head>
<body class="aboutPageWideContainer">
<h1>about:buildconfig</h1>
#ifdef MOZ_SOURCE_URL
<h2>Source</h2>
<p>Built from <a href="@MOZ_SOURCE_URL@">@MOZ_SOURCE_URL@</a></p>
#endif
<h2>Build platform</h2>
<table>
<tbody>
<tr>
<th>target</th>
</tr>
<tr>
<td>@target@</td>
</tr>
</tbody>
</table>
<h2>Build tools</h2>
<table>
<tbody>
<tr>
<th>Compiler</th>
<th>Version</th>
<th>Compiler flags</th>
</tr>
<tr>
<td>@CC@</td>
<td>@CC_VERSION@</td>
<td>@CFLAGS@</td>
</tr>
<tr>
<td>@CXX@</td>
<td>@CC_VERSION@</td>
#ifndef BUILD_FASTER
<td>@CXXFLAGS@ @CPPFLAGS@</td>
#endif
</tr>
</tbody>
</table>
<h2>Configure options</h2>
<p>@MOZ_CONFIGURE_OPTIONS@</p>
#ifdef ANDROID
<h2>Package name</h2>
<p>@ANDROID_PACKAGE_NAME@</p>
#endif
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
/* 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/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
@namespace html url("http://www.w3.org/1999/xhtml"); /* namespace for HTML elements */
#palette-box {
overflow: auto;
display: block;
min-height: 3em;
}
#palette-box > toolbarpaletteitem {
width: 110px;
height: 94px;
overflow: hidden;
display: inline-block;
}
.toolbarpaletteitem-box {
-moz-box-pack: center;
-moz-box-flex: 1;
width: 110px;
max-width: 110px;
}
toolbarpaletteitem > label {
text-align: center;
}
#main-box > box {
overflow: hidden;
}
/* Hide the toolbarbutton label because we replicate it on the wrapper */
.toolbarbutton-text {
display: none;
}

View file

@ -0,0 +1,839 @@
/* 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 gToolboxDocument = null;
var gToolbox = null;
var gCurrentDragOverItem = null;
var gToolboxChanged = false;
var gToolboxSheet = false;
var gPaletteBox = null;
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AppConstants.jsm");
function onLoad()
{
if ("arguments" in window && window.arguments[0]) {
InitWithToolbox(window.arguments[0]);
repositionDialog(window);
}
else if (window.frameElement &&
"toolbox" in window.frameElement) {
gToolboxSheet = true;
InitWithToolbox(window.frameElement.toolbox);
repositionDialog(window.frameElement.panel);
}
}
function InitWithToolbox(aToolbox)
{
gToolbox = aToolbox;
dispatchCustomizationEvent("beforecustomization");
gToolboxDocument = gToolbox.ownerDocument;
gToolbox.customizing = true;
forEachCustomizableToolbar(function (toolbar) {
toolbar.setAttribute("customizing", "true");
});
gPaletteBox = document.getElementById("palette-box");
var elts = getRootElements();
for (let i=0; i < elts.length; i++) {
elts[i].addEventListener("dragstart", onToolbarDragStart, true);
elts[i].addEventListener("dragover", onToolbarDragOver, true);
elts[i].addEventListener("dragexit", onToolbarDragExit, true);
elts[i].addEventListener("drop", onToolbarDrop, true);
}
initDialog();
}
function onClose()
{
if (!gToolboxSheet)
window.close();
else
finishToolbarCustomization();
}
function onUnload()
{
if (!gToolboxSheet)
finishToolbarCustomization();
}
function finishToolbarCustomization()
{
removeToolboxListeners();
unwrapToolbarItems();
persistCurrentSets();
gToolbox.customizing = false;
forEachCustomizableToolbar(function (toolbar) {
toolbar.removeAttribute("customizing");
});
notifyParentComplete();
}
function initDialog()
{
if (!gToolbox.toolbarset) {
document.getElementById("newtoolbar").hidden = true;
}
var mode = gToolbox.getAttribute("mode");
document.getElementById("modelist").value = mode;
var smallIconsCheckbox = document.getElementById("smallicons");
smallIconsCheckbox.checked = gToolbox.getAttribute("iconsize") == "small";
if (mode == "text")
smallIconsCheckbox.disabled = true;
// Build up the palette of other items.
buildPalette();
// Wrap all the items on the toolbar in toolbarpaletteitems.
wrapToolbarItems();
}
function repositionDialog(aWindow)
{
// Position the dialog touching the bottom of the toolbox and centered with
// it.
if (!aWindow)
return;
var width;
if (aWindow != window)
width = aWindow.getBoundingClientRect().width;
else if (document.documentElement.hasAttribute("width"))
width = document.documentElement.getAttribute("width");
else
width = parseInt(document.documentElement.style.width);
var screenX = gToolbox.boxObject.screenX
+ ((gToolbox.boxObject.width - width) / 2);
var screenY = gToolbox.boxObject.screenY + gToolbox.boxObject.height;
aWindow.moveTo(screenX, screenY);
}
function removeToolboxListeners()
{
var elts = getRootElements();
for (let i=0; i < elts.length; i++) {
elts[i].removeEventListener("dragstart", onToolbarDragStart, true);
elts[i].removeEventListener("dragover", onToolbarDragOver, true);
elts[i].removeEventListener("dragexit", onToolbarDragExit, true);
elts[i].removeEventListener("drop", onToolbarDrop, true);
}
}
/**
* Invoke a callback on the toolbox to notify it that the dialog is done
* and going away.
*/
function notifyParentComplete()
{
if ("customizeDone" in gToolbox)
gToolbox.customizeDone(gToolboxChanged);
dispatchCustomizationEvent("aftercustomization");
}
function toolboxChanged(aType)
{
gToolboxChanged = true;
if ("customizeChange" in gToolbox)
gToolbox.customizeChange(aType);
dispatchCustomizationEvent("customizationchange");
}
function dispatchCustomizationEvent(aEventName) {
var evt = document.createEvent("Events");
evt.initEvent(aEventName, true, true);
gToolbox.dispatchEvent(evt);
}
/**
* Persist the current set of buttons in all customizable toolbars to
* localstore.
*/
function persistCurrentSets()
{
if (!gToolboxChanged || gToolboxDocument.defaultView.closed)
return;
var customCount = 0;
forEachCustomizableToolbar(function (toolbar) {
// Calculate currentset and store it in the attribute.
var currentSet = toolbar.currentSet;
toolbar.setAttribute("currentset", currentSet);
var customIndex = toolbar.hasAttribute("customindex");
if (customIndex) {
if (!toolbar.hasChildNodes()) {
// Remove custom toolbars whose contents have been removed.
gToolbox.removeChild(toolbar);
} else if (gToolbox.toolbarset) {
// Persist custom toolbar info on the <toolbarset/>
gToolbox.toolbarset.setAttribute("toolbar"+(++customCount),
toolbar.toolbarName + ":" + currentSet);
gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
}
}
if (!customIndex) {
// Persist the currentset attribute directly on hardcoded toolbars.
gToolboxDocument.persist(toolbar.id, "currentset");
}
});
// Remove toolbarX attributes for removed toolbars.
while (gToolbox.toolbarset && gToolbox.toolbarset.hasAttribute("toolbar"+(++customCount))) {
gToolbox.toolbarset.removeAttribute("toolbar"+customCount);
gToolboxDocument.persist(gToolbox.toolbarset.id, "toolbar"+customCount);
}
}
/**
* Wraps all items in all customizable toolbars in a toolbox.
*/
function wrapToolbarItems()
{
forEachCustomizableToolbar(function (toolbar) {
Array.forEach(toolbar.childNodes, function (item) {
if (AppConstants.platform == "macosx") {
if (item.firstChild && item.firstChild.localName == "menubar")
return;
}
if (isToolbarItem(item)) {
let wrapper = wrapToolbarItem(item);
cleanupItemForToolbar(item, wrapper);
}
});
});
}
function getRootElements()
{
return [gToolbox].concat(gToolbox.externalToolbars);
}
/**
* Unwraps all items in all customizable toolbars in a toolbox.
*/
function unwrapToolbarItems()
{
let elts = getRootElements();
for (let i=0; i < elts.length; i++) {
let paletteItems = elts[i].getElementsByTagName("toolbarpaletteitem");
let paletteItem;
while ((paletteItem = paletteItems.item(0)) != null) {
let toolbarItem = paletteItem.firstChild;
restoreItemForToolbar(toolbarItem, paletteItem);
paletteItem.parentNode.replaceChild(toolbarItem, paletteItem);
}
}
}
/**
* Creates a wrapper that can be used to contain a toolbaritem and prevent
* it from receiving UI events.
*/
function createWrapper(aId, aDocument)
{
var wrapper = aDocument.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"toolbarpaletteitem");
wrapper.id = "wrapper-"+aId;
return wrapper;
}
/**
* Wraps an item that has been cloned from a template and adds
* it to the end of the palette.
*/
function wrapPaletteItem(aPaletteItem)
{
var wrapper = createWrapper(aPaletteItem.id, document);
wrapper.appendChild(aPaletteItem);
// XXX We need to call this AFTER the palette item has been appended
// to the wrapper or else we crash dropping certain buttons on the
// palette due to removal of the command and disabled attributes - JRH
cleanUpItemForPalette(aPaletteItem, wrapper);
gPaletteBox.appendChild(wrapper);
}
/**
* Wraps an item that is currently on a toolbar and replaces the item
* with the wrapper. This is not used when dropping items from the palette,
* only when first starting the dialog and wrapping everything on the toolbars.
*/
function wrapToolbarItem(aToolbarItem)
{
var wrapper = createWrapper(aToolbarItem.id, gToolboxDocument);
wrapper.flex = aToolbarItem.flex;
aToolbarItem.parentNode.replaceChild(wrapper, aToolbarItem);
wrapper.appendChild(aToolbarItem);
return wrapper;
}
/**
* Get the list of ids for the current set of items on each toolbar.
*/
function getCurrentItemIds()
{
var currentItems = {};
forEachCustomizableToolbar(function (toolbar) {
var child = toolbar.firstChild;
while (child) {
if (isToolbarItem(child))
currentItems[child.id] = 1;
child = child.nextSibling;
}
});
return currentItems;
}
/**
* Builds the palette of draggable items that are not yet in a toolbar.
*/
function buildPalette()
{
// Empty the palette first.
while (gPaletteBox.lastChild)
gPaletteBox.removeChild(gPaletteBox.lastChild);
// Add the toolbar separator item.
var templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"toolbarseparator");
templateNode.id = "separator";
wrapPaletteItem(templateNode);
// Add the toolbar spring item.
templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"toolbarspring");
templateNode.id = "spring";
templateNode.flex = 1;
wrapPaletteItem(templateNode);
// Add the toolbar spacer item.
templateNode = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"toolbarspacer");
templateNode.id = "spacer";
templateNode.flex = 1;
wrapPaletteItem(templateNode);
var currentItems = getCurrentItemIds();
templateNode = gToolbox.palette.firstChild;
while (templateNode) {
// Check if the item is already in a toolbar before adding it to the palette.
if (!(templateNode.id in currentItems)) {
var paletteItem = document.importNode(templateNode, true);
wrapPaletteItem(paletteItem);
}
templateNode = templateNode.nextSibling;
}
}
/**
* Makes sure that an item that has been cloned from a template
* is stripped of any attributes that may adversely affect its
* appearance in the palette.
*/
function cleanUpItemForPalette(aItem, aWrapper)
{
aWrapper.setAttribute("place", "palette");
setWrapperType(aItem, aWrapper);
if (aItem.hasAttribute("title"))
aWrapper.setAttribute("title", aItem.getAttribute("title"));
else if (aItem.hasAttribute("label"))
aWrapper.setAttribute("title", aItem.getAttribute("label"));
else if (isSpecialItem(aItem)) {
var stringBundle = document.getElementById("stringBundle");
// Remove the common "toolbar" prefix to generate the string name.
var title = stringBundle.getString(aItem.localName.slice(7) + "Title");
aWrapper.setAttribute("title", title);
}
aWrapper.setAttribute("tooltiptext", aWrapper.getAttribute("title"));
// Remove attributes that screw up our appearance.
aItem.removeAttribute("command");
aItem.removeAttribute("observes");
aItem.removeAttribute("type");
aItem.removeAttribute("width");
Array.forEach(aWrapper.querySelectorAll("[disabled]"), function(aNode) {
aNode.removeAttribute("disabled");
});
}
/**
* Makes sure that an item that has been cloned from a template
* is stripped of all properties that may adversely affect its
* appearance in the toolbar. Store critical properties on the
* wrapper so they can be put back on the item when we're done.
*/
function cleanupItemForToolbar(aItem, aWrapper)
{
setWrapperType(aItem, aWrapper);
aWrapper.setAttribute("place", "toolbar");
if (aItem.hasAttribute("command")) {
aWrapper.setAttribute("itemcommand", aItem.getAttribute("command"));
aItem.removeAttribute("command");
}
if (aItem.checked) {
aWrapper.setAttribute("itemchecked", "true");
aItem.checked = false;
}
if (aItem.disabled) {
aWrapper.setAttribute("itemdisabled", "true");
aItem.disabled = false;
}
}
/**
* Restore all the properties that we stripped off above.
*/
function restoreItemForToolbar(aItem, aWrapper)
{
if (aWrapper.hasAttribute("itemdisabled"))
aItem.disabled = true;
if (aWrapper.hasAttribute("itemchecked"))
aItem.checked = true;
if (aWrapper.hasAttribute("itemcommand")) {
let commandID = aWrapper.getAttribute("itemcommand");
aItem.setAttribute("command", commandID);
// XXX Bug 309953 - toolbarbuttons aren't in sync with their commands after customizing
let command = gToolboxDocument.getElementById(commandID);
if (command && command.hasAttribute("disabled"))
aItem.setAttribute("disabled", command.getAttribute("disabled"));
}
}
function setWrapperType(aItem, aWrapper)
{
if (aItem.localName == "toolbarseparator") {
aWrapper.setAttribute("type", "separator");
} else if (aItem.localName == "toolbarspring") {
aWrapper.setAttribute("type", "spring");
} else if (aItem.localName == "toolbarspacer") {
aWrapper.setAttribute("type", "spacer");
} else if (aItem.localName == "toolbaritem" && aItem.firstChild) {
aWrapper.setAttribute("type", aItem.firstChild.localName);
}
}
function setDragActive(aItem, aValue)
{
var node = aItem;
var direction = window.getComputedStyle(aItem, null).direction;
var value = direction == "ltr"? "left" : "right";
if (aItem.localName == "toolbar") {
node = aItem.lastChild;
value = direction == "ltr"? "right" : "left";
}
if (!node)
return;
if (aValue) {
if (!node.hasAttribute("dragover"))
node.setAttribute("dragover", value);
} else {
node.removeAttribute("dragover");
}
}
function addNewToolbar()
{
var promptService = Services.prompt;
var stringBundle = document.getElementById("stringBundle");
var message = stringBundle.getString("enterToolbarName");
var title = stringBundle.getString("enterToolbarTitle");
var name = {};
// Quitting from the toolbar dialog while the new toolbar prompt is up
// can cause things to become unresponsive on the Mac. Until dialog modality
// is fixed (395465), disable the "Done" button explicitly.
var doneButton = document.getElementById("donebutton");
doneButton.disabled = true;
while (true) {
if (!promptService.prompt(window, title, message, name, null, {})) {
doneButton.disabled = false;
return;
}
if (!name.value) {
message = stringBundle.getFormattedString("enterToolbarBlank", [name.value]);
continue;
}
var dupeFound = false;
// Check for an existing toolbar with the same display name
for (let i = 0; i < gToolbox.childNodes.length; ++i) {
var toolbar = gToolbox.childNodes[i];
var toolbarName = toolbar.getAttribute("toolbarname");
if (toolbarName == name.value &&
toolbar.getAttribute("type") != "menubar" &&
toolbar.nodeName == 'toolbar') {
dupeFound = true;
break;
}
}
if (!dupeFound)
break;
message = stringBundle.getFormattedString("enterToolbarDup", [name.value]);
}
gToolbox.appendCustomToolbar(name.value, "");
toolboxChanged();
doneButton.disabled = false;
}
/**
* Restore the default set of buttons to fixed toolbars,
* remove all custom toolbars, and rebuild the palette.
*/
function restoreDefaultSet()
{
// Unwrap the items on the toolbar.
unwrapToolbarItems();
// Remove all of the customized toolbars.
var child = gToolbox.lastChild;
while (child) {
if (child.hasAttribute("customindex")) {
var thisChild = child;
child = child.previousSibling;
thisChild.currentSet = "__empty";
gToolbox.removeChild(thisChild);
} else {
child = child.previousSibling;
}
}
// Restore the defaultset for fixed toolbars.
forEachCustomizableToolbar(function (toolbar) {
var defaultSet = toolbar.getAttribute("defaultset");
if (defaultSet)
toolbar.currentSet = defaultSet;
});
// Restore the default icon size and mode.
document.getElementById("smallicons").checked = (updateIconSize() == "small");
document.getElementById("modelist").value = updateToolbarMode();
// Now rebuild the palette.
buildPalette();
// Now re-wrap the items on the toolbar.
wrapToolbarItems();
toolboxChanged("reset");
}
function updateIconSize(aSize) {
return updateToolboxProperty("iconsize", aSize, "large");
}
function updateToolbarMode(aModeValue) {
var mode = updateToolboxProperty("mode", aModeValue, "icons");
var iconSizeCheckbox = document.getElementById("smallicons");
iconSizeCheckbox.disabled = mode == "text";
return mode;
}
function updateToolboxProperty(aProp, aValue, aToolkitDefault) {
var toolboxDefault = gToolbox.getAttribute("default" + aProp) ||
aToolkitDefault;
gToolbox.setAttribute(aProp, aValue || toolboxDefault);
gToolboxDocument.persist(gToolbox.id, aProp);
forEachCustomizableToolbar(function (toolbar) {
var toolbarDefault = toolbar.getAttribute("default" + aProp) ||
toolboxDefault;
if (toolbar.getAttribute("lock" + aProp) == "true" &&
toolbar.getAttribute(aProp) == toolbarDefault)
return;
toolbar.setAttribute(aProp, aValue || toolbarDefault);
gToolboxDocument.persist(toolbar.id, aProp);
});
toolboxChanged(aProp);
return aValue || toolboxDefault;
}
function forEachCustomizableToolbar(callback) {
Array.filter(gToolbox.childNodes, isCustomizableToolbar).forEach(callback);
Array.filter(gToolbox.externalToolbars, isCustomizableToolbar).forEach(callback);
}
function isCustomizableToolbar(aElt)
{
return aElt.localName == "toolbar" &&
aElt.getAttribute("customizable") == "true";
}
function isSpecialItem(aElt)
{
return aElt.localName == "toolbarseparator" ||
aElt.localName == "toolbarspring" ||
aElt.localName == "toolbarspacer";
}
function isToolbarItem(aElt)
{
return aElt.localName == "toolbarbutton" ||
aElt.localName == "toolbaritem" ||
aElt.localName == "toolbarseparator" ||
aElt.localName == "toolbarspring" ||
aElt.localName == "toolbarspacer";
}
// Drag and Drop observers
function onToolbarDragExit(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
if (gCurrentDragOverItem)
setDragActive(gCurrentDragOverItem, false);
}
function onToolbarDragStart(aEvent)
{
var item = aEvent.target;
while (item && item.localName != "toolbarpaletteitem") {
if (item.localName == "toolbar")
return;
item = item.parentNode;
}
item.setAttribute("dragactive", "true");
var dt = aEvent.dataTransfer;
var documentId = gToolboxDocument.documentElement.id;
dt.setData("text/toolbarwrapper-id/" + documentId, item.firstChild.id);
dt.effectAllowed = "move";
}
function onToolbarDragOver(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
var documentId = gToolboxDocument.documentElement.id;
if (!aEvent.dataTransfer.types.includes("text/toolbarwrapper-id/" + documentId.toLowerCase()))
return;
var toolbar = aEvent.target;
var dropTarget = aEvent.target;
while (toolbar && toolbar.localName != "toolbar") {
dropTarget = toolbar;
toolbar = toolbar.parentNode;
}
// Make sure we are dragging over a customizable toolbar.
if (!toolbar || !isCustomizableToolbar(toolbar)) {
gCurrentDragOverItem = null;
return;
}
var previousDragItem = gCurrentDragOverItem;
if (dropTarget.localName == "toolbar") {
gCurrentDragOverItem = dropTarget;
} else {
gCurrentDragOverItem = null;
var direction = window.getComputedStyle(dropTarget.parentNode, null).direction;
var dropTargetCenter = dropTarget.boxObject.x + (dropTarget.boxObject.width / 2);
var dragAfter;
if (direction == "ltr")
dragAfter = aEvent.clientX > dropTargetCenter;
else
dragAfter = aEvent.clientX < dropTargetCenter;
if (dragAfter) {
gCurrentDragOverItem = dropTarget.nextSibling;
if (!gCurrentDragOverItem)
gCurrentDragOverItem = toolbar;
} else
gCurrentDragOverItem = dropTarget;
}
if (previousDragItem && gCurrentDragOverItem != previousDragItem) {
setDragActive(previousDragItem, false);
}
setDragActive(gCurrentDragOverItem, true);
aEvent.preventDefault();
aEvent.stopPropagation();
}
function onToolbarDrop(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
if (!gCurrentDragOverItem)
return;
setDragActive(gCurrentDragOverItem, false);
var documentId = gToolboxDocument.documentElement.id;
var draggedItemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
if (gCurrentDragOverItem.id == draggedItemId)
return;
var toolbar = aEvent.target;
while (toolbar.localName != "toolbar")
toolbar = toolbar.parentNode;
var draggedPaletteWrapper = document.getElementById("wrapper-"+draggedItemId);
if (!draggedPaletteWrapper) {
// The wrapper has been dragged from the toolbar.
// Get the wrapper from the toolbar document and make sure that
// it isn't being dropped on itself.
let wrapper = gToolboxDocument.getElementById("wrapper-"+draggedItemId);
if (wrapper == gCurrentDragOverItem)
return;
// Don't allow non-removable kids (e.g., the menubar) to move.
if (wrapper.firstChild.getAttribute("removable") != "true")
return;
// Remove the item from its place in the toolbar.
wrapper.parentNode.removeChild(wrapper);
// Determine which toolbar we are dropping on.
var dropToolbar = null;
if (gCurrentDragOverItem.localName == "toolbar")
dropToolbar = gCurrentDragOverItem;
else
dropToolbar = gCurrentDragOverItem.parentNode;
// Insert the item into the toolbar.
if (gCurrentDragOverItem != dropToolbar)
dropToolbar.insertBefore(wrapper, gCurrentDragOverItem);
else
dropToolbar.appendChild(wrapper);
} else {
// The item has been dragged from the palette
// Create a new wrapper for the item. We don't know the id yet.
let wrapper = createWrapper("", gToolboxDocument);
// Ask the toolbar to clone the item's template, place it inside the wrapper, and insert it in the toolbar.
var newItem = toolbar.insertItem(draggedItemId, gCurrentDragOverItem == toolbar ? null : gCurrentDragOverItem, wrapper);
// Prepare the item and wrapper to look good on the toolbar.
cleanupItemForToolbar(newItem, wrapper);
wrapper.id = "wrapper-"+newItem.id;
wrapper.flex = newItem.flex;
// Remove the wrapper from the palette.
if (draggedItemId != "separator" &&
draggedItemId != "spring" &&
draggedItemId != "spacer")
gPaletteBox.removeChild(draggedPaletteWrapper);
}
gCurrentDragOverItem = null;
toolboxChanged();
}
function onPaletteDragOver(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
var documentId = gToolboxDocument.documentElement.id;
if (aEvent.dataTransfer.types.includes("text/toolbarwrapper-id/" + documentId.toLowerCase()))
aEvent.preventDefault();
}
function onPaletteDrop(aEvent)
{
if (isUnwantedDragEvent(aEvent)) {
return;
}
var documentId = gToolboxDocument.documentElement.id;
var itemId = aEvent.dataTransfer.getData("text/toolbarwrapper-id/" + documentId);
var wrapper = gToolboxDocument.getElementById("wrapper-"+itemId);
if (wrapper) {
// Don't allow non-removable kids (e.g., the menubar) to move.
if (wrapper.firstChild.getAttribute("removable") != "true")
return;
var wrapperType = wrapper.getAttribute("type");
if (wrapperType != "separator" &&
wrapperType != "spacer" &&
wrapperType != "spring") {
restoreItemForToolbar(wrapper.firstChild, wrapper);
wrapPaletteItem(document.importNode(wrapper.firstChild, true));
gToolbox.palette.appendChild(wrapper.firstChild);
}
// The item was dragged out of the toolbar.
wrapper.parentNode.removeChild(wrapper);
}
toolboxChanged();
}
function isUnwantedDragEvent(aEvent) {
try {
if (Services.prefs.getBoolPref("toolkit.customization.unsafe_drag_events")) {
return false;
}
} catch (ex) {}
/* Discard drag events that originated from a separate window to
prevent content->chrome privilege escalations. */
let mozSourceNode = aEvent.dataTransfer.mozSourceNode;
// mozSourceNode is null in the dragStart event handler or if
// the drag event originated in an external application.
if (!mozSourceNode) {
return true;
}
let sourceWindow = mozSourceNode.ownerDocument.defaultView;
return sourceWindow != window && sourceWindow != gToolboxDocument.defaultView;
}

View file

@ -0,0 +1,67 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE dialog [
<!ENTITY % customizeToolbarDTD SYSTEM "chrome://global/locale/customizeToolbar.dtd">
%customizeToolbarDTD;
]>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://global/content/customizeToolbar.css" type="text/css"?>
<?xml-stylesheet href="chrome://global/skin/customizeToolbar.css" type="text/css"?>
<window id="CustomizeToolbarWindow"
title="&dialog.title;"
onload="onLoad();"
onunload="onUnload();"
style="&dialog.dimensions;"
persist="width height"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://global/content/customizeToolbar.js"/>
<stringbundle id="stringBundle" src="chrome://global/locale/customizeToolbar.properties"/>
<keyset id="CustomizeToolbarKeyset">
<key id="cmd_close1" keycode="VK_ESCAPE" oncommand="onClose();"/>
<key id="cmd_close2" keycode="VK_RETURN" oncommand="onClose();"/>
</keyset>
<vbox id="main-box" flex="1">
<description id="instructions">
&instructions.description;
</description>
<vbox flex="1" id="palette-box"
ondragstart="onToolbarDragStart(event)"
ondragover="onPaletteDragOver(event)"
ondrop="onPaletteDrop(event)"/>
<box align="center">
<label value="&show.label;"/>
<menulist id="modelist" value="icons" oncommand="updateToolbarMode(this.value);">
<menupopup id="modelistpopup">
<menuitem id="modefull" value="full" label="&iconsAndText.label;"/>
<menuitem id="modeicons" value="icons" label="&icons.label;"/>
<menuitem id="modetext" value="text" label="&text.label;"/>
</menupopup>
</menulist>
<checkbox id="smallicons" oncommand="updateIconSize(this.checked ? 'small' : 'large');" label="&useSmallIcons.label;"/>
<button id="newtoolbar" label="&addNewToolbar.label;" oncommand="addNewToolbar();" icon="add"/>
<button id="restoreDefault" label="&restoreDefaultSet.label;" oncommand="restoreDefaultSet();" icon="revert"/>
</box>
<separator class="groove"/>
<hbox align="center" pack="end">
<button id="donebutton" label="&saveChanges.label;" oncommand="onClose();"
default="true" icon="close"/>
</hbox>
</vbox>
</window>

View file

@ -0,0 +1,13 @@
<!-- 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/. -->
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="chrome://global/locale/intl.css">
</head>
<body>
<window id="target" style="display: none;"></window>
</body>
</html>

View file

@ -0,0 +1,39 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* 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/. */
// update menu items that rely on focus or on the current selection
function goUpdateGlobalEditMenuItems()
{
// Don't bother updating the edit commands if they aren't visible in any way
// (i.e. the Edit menu isn't open, nor is the context menu open, nor have the
// cut, copy, and paste buttons been added to the toolbars) for performance.
// This only works in applications/on platforms that set the gEditUIVisible
// flag, so we check to see if that flag is defined before using it.
if (typeof gEditUIVisible != "undefined" && !gEditUIVisible)
return;
goUpdateCommand("cmd_undo");
goUpdateCommand("cmd_redo");
goUpdateCommand("cmd_cut");
goUpdateCommand("cmd_copy");
goUpdateCommand("cmd_paste");
goUpdateCommand("cmd_selectAll");
goUpdateCommand("cmd_delete");
goUpdateCommand("cmd_switchTextDirection");
}
// update menu items that relate to undo/redo
function goUpdateUndoEditMenuItems()
{
goUpdateCommand("cmd_undo");
goUpdateCommand("cmd_redo");
}
// update menu items that depend on clipboard contents
function goUpdatePasteMenuItems()
{
goUpdateCommand("cmd_paste");
}

View file

@ -0,0 +1,108 @@
<?xml version="1.0"?> <!-- -*- Mode: HTML -*- -->
<!-- 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/. -->
<!DOCTYPE overlay SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
<overlay id="editMenuOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://global/content/editMenuOverlay.js"/>
<commandset id="editMenuCommands">
<commandset id="editMenuCommandSetAll" commandupdater="true" events="focus,select"
oncommandupdate="goUpdateGlobalEditMenuItems()"/>
<commandset id="editMenuCommandSetUndo" commandupdater="true" events="undo"
oncommandupdate="goUpdateUndoEditMenuItems()"/>
<commandset id="editMenuCommandSetPaste" commandupdater="true" events="clipboard"
oncommandupdate="goUpdatePasteMenuItems()"/>
<command id="cmd_undo" oncommand="goDoCommand('cmd_undo')"/>
<command id="cmd_redo" oncommand="goDoCommand('cmd_redo')"/>
<command id="cmd_cut" oncommand="goDoCommand('cmd_cut')"/>
<command id="cmd_copy" oncommand="goDoCommand('cmd_copy')"/>
<command id="cmd_paste" oncommand="goDoCommand('cmd_paste')"/>
<command id="cmd_delete" oncommand="goDoCommand('cmd_delete')"/>
<command id="cmd_selectAll" oncommand="goDoCommand('cmd_selectAll')"/>
<command id="cmd_switchTextDirection" oncommand="goDoCommand('cmd_switchTextDirection');"/>
</commandset>
<!-- These key nodes are here only for show. The real bindings come from
XBL, in platformHTMLBindings.xml. See bugs 57078 and 71779. -->
<keyset id="editMenuKeys">
<key id="key_undo" key="&undoCmd.key;" modifiers="accel" command="cmd_undo"/>
#ifdef XP_UNIX
<key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift" command="cmd_redo"/>
#else
<key id="key_redo" key="&redoCmd.key;" modifiers="accel" command="cmd_redo"/>
#endif
<key id="key_cut" key="&cutCmd.key;" modifiers="accel" command="cmd_cut"/>
<key id="key_copy" key="&copyCmd.key;" modifiers="accel" command="cmd_copy"/>
<key id="key_paste" key="&pasteCmd.key;" modifiers="accel" command="cmd_paste"/>
<key id="key_delete" keycode="VK_DELETE" command="cmd_delete"/>
<key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel" command="cmd_selectAll"/>
<key id="key_find" key="&findCmd.key;" modifiers="accel" command="cmd_find"/>
<key id="key_findAgain" key="&findAgainCmd.key;" modifiers="accel" command="cmd_findAgain"/>
<key id="key_findPrevious" key="&findAgainCmd.key;" modifiers="shift,accel" command="cmd_findPrevious"/>
<key id="key_findAgain2" keycode="&findAgainCmd.key2;" command="cmd_findAgain"/>
<key id="key_findPrevious2" keycode="&findAgainCmd.key2;" modifiers="shift" command="cmd_findPrevious"/>
</keyset>
<!-- Edit Menu -->
<menu id="menu_edit" label="&editMenu.label;"
accesskey="&editMenu.accesskey;"/>
<menuitem id="menu_undo" label="&undoCmd.label;"
key="key_undo" accesskey="&undoCmd.accesskey;"
command="cmd_undo"/>
<menuitem id="menu_redo" label="&redoCmd.label;"
key="key_redo" accesskey="&redoCmd.accesskey;"
command="cmd_redo"/>
<menuitem id="menu_cut" label="&cutCmd.label;"
key="key_cut" accesskey="&cutCmd.accesskey;"
command="cmd_cut"/>
<menuitem id="menu_copy" label="&copyCmd.label;"
key="key_copy" accesskey="&copyCmd.accesskey;"
command="cmd_copy"/>
<menuitem id="menu_paste" label="&pasteCmd.label;"
key="key_paste" accesskey="&pasteCmd.accesskey;"
command="cmd_paste"/>
<menuitem id="menu_delete" label="&deleteCmd.label;"
key="key_delete" accesskey="&deleteCmd.accesskey;"
command="cmd_delete"/>
<menuitem id="menu_selectAll" label="&selectAllCmd.label;"
key="key_selectAll" accesskey="&selectAllCmd.accesskey;"
command="cmd_selectAll"/>
<menuitem id="menu_find" label="&findCmd.label;"
key="key_find" accesskey="&findCmd.accesskey;"
command="cmd_find"/>
<menuitem id="menu_findAgain" label="&findAgainCmd.label;"
key="key_findAgain" accesskey="&findAgainCmd.accesskey;"
command="cmd_findAgain"/>
<menuitem id="menu_findPrevious" label="&findPreviousCmd.label;"
key="key_findPrevious" accesskey="&findPreviousCmd.accesskey;"
command="cmd_findPrevious"/>
<menuitem id="cMenu_undo" label="&undoCmd.label;"
accesskey="&undoCmd.accesskey;" command="cmd_undo"/>
<menuitem id="cMenu_redo" label="&redoCmd.label;"
accesskey="&redoCmd.accesskey;" command="cmd_redo"/>
<menuitem id="cMenu_cut" label="&cutCmd.label;"
accesskey="&cutCmd.accesskey;" command="cmd_cut"/>
<menuitem id="cMenu_copy" label="&copyCmd.label;"
accesskey="&copyCmd.accesskey;" command="cmd_copy"/>
<menuitem id="cMenu_paste" label="&pasteCmd.label;"
accesskey="&pasteCmd.accesskey;" command="cmd_paste"/>
<menuitem id="cMenu_delete" label="&deleteCmd.label;"
accesskey="&deleteCmd.accesskey;" command="cmd_delete"/>
<menuitem id="cMenu_selectAll" label="&selectAllCmd.label;"
accesskey="&selectAllCmd.accesskey;" command="cmd_selectAll"/>
<menuitem id="cMenu_find" label="&findCmd.label;"
accesskey="&findCmd.accesskey;" command="cmd_find"/>
<menuitem id="cMenu_findAgain" label="&findAgainCmd.label;"
accesskey="&findAgainCmd.accesskey;" command="cmd_findAgain"/>
<menuitem id="cMenu_findPrevious" label="&findPreviousCmd.label;"
accesskey="&findPreviousCmd.accesskey;" command="cmd_findPrevious"/>
</overlay>

View file

@ -0,0 +1,12 @@
# 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/.
allFilter=*
htmlFilter=*.html; *.htm; *.shtml; *.xhtml
textFilter=*.txt; *.text
imageFilter=*.jpe; *.jpg; *.jpeg; *.gif; *.png; *.bmp; *.ico; *.svg; *.svgz; *.tif; *.tiff; *.ai; *.drw; *.pct; *.psp; *.xcf; *.psd; *.raw
xmlFilter=*.xml
xulFilter=*.xul
audioFilter=*.aac; *.aif; *.flac; *.iff; *.m4a; *.m4b; *.mid; *.midi; *.mp3; *.mpa; *.mpc; *.oga; *.ogg; *.ra; *.ram; *.snd; *.wav; *.wma
videoFilter=*.avi; *.divx; *.flv; *.m4v; *.mkv; *.mov; *.mp4; *.mpeg; *.mpg; *.ogm; *.ogv; *.ogx; *.rm; *.rmvb; *.smil; *.webm; *.wmv; *.xvid

View file

@ -0,0 +1,111 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
var gFindBundle;
function nsFindInstData() {}
nsFindInstData.prototype =
{
// set the next three attributes on your object to override the defaults
browser : null,
get rootSearchWindow() { return this._root || this.window.content; },
set rootSearchWindow(val) { this._root = val; },
get currentSearchWindow() {
if (this._current)
return this._current;
var focusedWindow = this.window.document.commandDispatcher.focusedWindow;
if (!focusedWindow || focusedWindow == this.window)
focusedWindow = this.window.content;
return focusedWindow;
},
set currentSearchWindow(val) { this._current = val; },
get webBrowserFind() { return this.browser.webBrowserFind; },
init : function() {
var findInst = this.webBrowserFind;
// set up the find to search the focussedWindow, bounded by the content window.
var findInFrames = findInst.QueryInterface(Components.interfaces.nsIWebBrowserFindInFrames);
findInFrames.rootSearchFrame = this.rootSearchWindow;
findInFrames.currentSearchFrame = this.currentSearchWindow;
// always search in frames for now. We could add a checkbox to the dialog for this.
findInst.searchFrames = true;
},
window : window,
_root : null,
_current : null
}
// browser is the <browser> element
// rootSearchWindow is the window to constrain the search to (normally window.content)
// currentSearchWindow is the frame to start searching (can be, and normally, rootSearchWindow)
function findInPage(findInstData)
{
// is the dialog up already?
if ("findDialog" in window && window.findDialog)
window.findDialog.focus();
else
{
findInstData.init();
window.findDialog = window.openDialog("chrome://global/content/finddialog.xul", "_blank", "chrome,resizable=no,dependent=yes", findInstData);
}
}
function findAgainInPage(findInstData, reverse)
{
if ("findDialog" in window && window.findDialog)
window.findDialog.focus();
else
{
// get the find service, which stores global find state, and init the
// nsIWebBrowser find with it. We don't assume that there was a previous
// Find that set this up.
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
var searchString = findService.searchString;
if (searchString.length == 0) {
// no previous find text
findInPage(findInstData);
return;
}
findInstData.init();
var findInst = findInstData.webBrowserFind;
findInst.searchString = searchString;
findInst.matchCase = findService.matchCase;
findInst.wrapFind = findService.wrapFind;
findInst.entireWord = findService.entireWord;
findInst.findBackwards = findService.findBackwards ^ reverse;
var found = findInst.findNext();
if (!found) {
if (!gFindBundle)
gFindBundle = document.getElementById("findBundle");
Services.prompt.alert(window, gFindBundle.getString("notFoundTitle"), gFindBundle.getString("notFoundWarning"));
}
// Reset to normal value, otherwise setting can get changed in find dialog
findInst.findBackwards = findService.findBackwards;
}
}
function canFindAgainInPage()
{
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
return (findService.searchString.length > 0);
}

View file

@ -0,0 +1,151 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/FormHistory.jsm");
var dialog; // Quick access to document/form elements.
var gFindInst; // nsIWebBrowserFind that we're going to use
var gFindInstData; // use this to update the find inst data
function initDialogObject()
{
// Create dialog object and initialize.
dialog = {};
dialog.findKey = document.getElementById("dialog.findKey");
dialog.caseSensitive = document.getElementById("dialog.caseSensitive");
dialog.wrap = document.getElementById("dialog.wrap");
dialog.find = document.getElementById("btnFind");
dialog.up = document.getElementById("radioUp");
dialog.down = document.getElementById("radioDown");
dialog.rg = dialog.up.radioGroup;
dialog.bundle = null;
// Move dialog to center, if it not been shown before
var windowElement = document.getElementById("findDialog");
if (!windowElement.hasAttribute("screenX") || !windowElement.hasAttribute("screenY"))
{
sizeToContent();
moveToAlertPosition();
}
}
function fillDialog()
{
// get the find service, which stores global find state
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
// Set initial dialog field contents. Use the gFindInst attributes first,
// this is necessary for window.find()
dialog.findKey.value = gFindInst.searchString ? gFindInst.searchString : findService.searchString;
dialog.caseSensitive.checked = gFindInst.matchCase ? gFindInst.matchCase : findService.matchCase;
dialog.wrap.checked = gFindInst.wrapFind ? gFindInst.wrapFind : findService.wrapFind;
var findBackwards = gFindInst.findBackwards ? gFindInst.findBackwards : findService.findBackwards;
if (findBackwards)
dialog.rg.selectedItem = dialog.up;
else
dialog.rg.selectedItem = dialog.down;
}
function saveFindData()
{
// get the find service, which stores global find state
var findService = Components.classes["@mozilla.org/find/find_service;1"]
.getService(Components.interfaces.nsIFindService);
// Set data attributes per user input.
findService.searchString = dialog.findKey.value;
findService.matchCase = dialog.caseSensitive.checked;
findService.wrapFind = dialog.wrap.checked;
findService.findBackwards = dialog.up.selected;
}
function onLoad()
{
initDialogObject();
// get the find instance
var arg0 = window.arguments[0];
// If the dialog was opened from window.find(),
// arg0 will be an instance of nsIWebBrowserFind
if (arg0 instanceof Components.interfaces.nsIWebBrowserFind) {
gFindInst = arg0;
} else {
gFindInstData = arg0;
gFindInst = gFindInstData.webBrowserFind;
}
fillDialog();
doEnabling();
if (dialog.findKey.value)
dialog.findKey.select();
dialog.findKey.focus();
}
function onUnload()
{
window.opener.findDialog = 0;
}
function onAccept()
{
if (gFindInstData && gFindInst != gFindInstData.webBrowserFind) {
gFindInstData.init();
gFindInst = gFindInstData.webBrowserFind;
}
// Transfer dialog contents to the find service.
saveFindData();
updateFormHistory();
// set up the find instance
gFindInst.searchString = dialog.findKey.value;
gFindInst.matchCase = dialog.caseSensitive.checked;
gFindInst.wrapFind = dialog.wrap.checked;
gFindInst.findBackwards = dialog.up.selected;
// Search.
var result = gFindInst.findNext();
if (!result)
{
if (!dialog.bundle)
dialog.bundle = document.getElementById("findBundle");
Services.prompt.alert(window, dialog.bundle.getString("notFoundTitle"),
dialog.bundle.getString("notFoundWarning"));
dialog.findKey.select();
dialog.findKey.focus();
}
return false;
}
function doEnabling()
{
dialog.find.disabled = !dialog.findKey.value;
}
function updateFormHistory()
{
if (window.opener.PrivateBrowsingUtils &&
window.opener.PrivateBrowsingUtils.isWindowPrivate(window.opener) ||
!dialog.findKey.value)
return;
if (FormHistory.enabled) {
FormHistory.update({
op: "bump",
fieldname: "find-dialog",
value: dialog.findKey.value
}, {
handleError: function(aError) {
Components.utils.reportError("Saving find to form history failed: " +
aError.message);
}
});
}
}

View file

@ -0,0 +1,58 @@
<?xml version="1.0"?> <!-- -*- Mode: HTML -*- -->
# 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/.
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE window SYSTEM "chrome://global/locale/finddialog.dtd">
<dialog id="findDialog"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
orient="horizontal"
windowtype="findInPage"
onload="onLoad();"
onunload="onUnload();"
ondialogaccept="return onAccept();"
buttons="accept,cancel"
title="&findDialog.title;"
persist="screenX screenY">
<script type="application/javascript" src="chrome://global/content/finddialog.js"/>
<stringbundle id="findBundle" src="chrome://global/locale/finddialog.properties"/>
<hbox>
<vbox>
<hbox align="center">
<label value="&findField.label;" accesskey="&findField.accesskey;" control="dialog.findKey"/>
<textbox id="dialog.findKey" flex="1"
type="autocomplete"
autocompletesearch="form-history"
autocompletesearchparam="find-dialog"
oninput="doEnabling();"/>
</hbox>
<hbox align="center">
<vbox>
<checkbox id="dialog.caseSensitive" label="&caseSensitiveCheckbox.label;" accesskey="&caseSensitiveCheckbox.accesskey;"/>
<checkbox id="dialog.wrap" label="&wrapCheckbox.label;" accesskey="&wrapCheckbox.accesskey;" checked="true"/>
</vbox>
<groupbox orient="horizontal">
<caption label="&direction.label;"/>
<radiogroup orient="horizontal">
<radio id="radioUp" label="&up.label;" accesskey="&up.accesskey;"/>
<radio id="radioDown" label="&down.label;" accesskey="&down.accesskey;" selected="true"/>
</radiogroup>
</groupbox>
</hbox>
</vbox>
<vbox>
<button id="btnFind" label="&findButton.label;" accesskey="&findButton.accesskey;"
dlgtype="accept" icon="find"/>
#ifdef XP_UNIX
<button label="&closeButton.label;" icon="close" dlgtype="cancel"/>
#else
<button label="&cancelButton.label;" icon="cancel" dlgtype="cancel"/>
#endif
</vbox>
</hbox>
</dialog>

View file

@ -0,0 +1,168 @@
/* 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/. */
function closeWindow(aClose, aPromptFunction)
{
let { AppConstants } = Components.utils.import("resource://gre/modules/AppConstants.jsm");
// Closing the last window doesn't quit the application on OS X.
if (AppConstants.platform != "macosx") {
var windowCount = 0;
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var e = wm.getEnumerator(null);
while (e.hasMoreElements()) {
var w = e.getNext();
if (w.closed) {
continue;
}
if (++windowCount == 2)
break;
}
// If we're down to the last window and someone tries to shut down, check to make sure we can!
if (windowCount == 1 && !canQuitApplication("lastwindow"))
return false;
if (windowCount != 1 && typeof(aPromptFunction) == "function" && !aPromptFunction())
return false;
} else if (typeof(aPromptFunction) == "function" && !aPromptFunction()) {
return false;
}
if (aClose) {
window.close();
return window.closed;
}
return true;
}
function canQuitApplication(aData)
{
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
if (!os) return true;
try {
var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
.createInstance(Components.interfaces.nsISupportsPRBool);
os.notifyObservers(cancelQuit, "quit-application-requested", aData || null);
// Something aborted the quit process.
if (cancelQuit.data)
return false;
}
catch (ex) { }
return true;
}
function goQuitApplication()
{
if (!canQuitApplication())
return false;
var appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1'].
getService(Components.interfaces.nsIAppStartup);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
return true;
}
//
// Command Updater functions
//
function goUpdateCommand(aCommand)
{
try {
var controller = top.document.commandDispatcher
.getControllerForCommand(aCommand);
var enabled = false;
if (controller)
enabled = controller.isCommandEnabled(aCommand);
goSetCommandEnabled(aCommand, enabled);
}
catch (e) {
Components.utils.reportError("An error occurred updating the " +
aCommand + " command: " + e);
}
}
function goDoCommand(aCommand)
{
try {
var controller = top.document.commandDispatcher
.getControllerForCommand(aCommand);
if (controller && controller.isCommandEnabled(aCommand))
controller.doCommand(aCommand);
}
catch (e) {
Components.utils.reportError("An error occurred executing the " +
aCommand + " command: " + e);
}
}
function goSetCommandEnabled(aID, aEnabled)
{
var node = document.getElementById(aID);
if (node) {
if (aEnabled)
node.removeAttribute("disabled");
else
node.setAttribute("disabled", "true");
}
}
function goSetMenuValue(aCommand, aLabelAttribute)
{
var commandNode = top.document.getElementById(aCommand);
if (commandNode) {
var label = commandNode.getAttribute(aLabelAttribute);
if (label)
commandNode.setAttribute("label", label);
}
}
function goSetAccessKey(aCommand, aValueAttribute)
{
var commandNode = top.document.getElementById(aCommand);
if (commandNode) {
var value = commandNode.getAttribute(aValueAttribute);
if (value)
commandNode.setAttribute("accesskey", value);
}
}
// this function is used to inform all the controllers attached to a node that an event has occurred
// (e.g. the tree controllers need to be informed of blur events so that they can change some of the
// menu items back to their default values)
function goOnEvent(aNode, aEvent)
{
var numControllers = aNode.controllers.getControllerCount();
var controller;
for (var controllerIndex = 0; controllerIndex < numControllers; controllerIndex++) {
controller = aNode.controllers.getControllerAt(controllerIndex);
if (controller)
controller.onEvent(aEvent);
}
}
function setTooltipText(aID, aTooltipText)
{
var element = document.getElementById(aID);
if (element)
element.setAttribute("tooltiptext", aTooltipText);
}
this.__defineGetter__("NS_ASSERT", function() {
delete this.NS_ASSERT;
var tmpScope = {};
Components.utils.import("resource://gre/modules/debug.js", tmpScope);
return this.NS_ASSERT = tmpScope.NS_ASSERT;
});

View file

@ -0,0 +1,31 @@
{
"vendors": {
"gmp-eme-adobe": {
"platforms": {
"WINNT_x86-msvc-x64": {
"alias": "WINNT_x86-msvc"
},
"WINNT_x86-msvc": {
"fileUrl": "https://cdmdownload.adobe.com/firefox/win/x86/primetime_gmp_win_x86_gmc_40673.zip",
"hashValue": "8aad35fc13814b0f1daacddb0d599eedd685287d5afddc97c2f740c8aea270636ccd75b1d1a57364b84e8eb1b23c9f1c126c057d95f3d8217b331dc4b1d5340f",
"filesize": 3694349
},
"WINNT_x86_64-msvc-x64": {
"alias": "WINNT_x86_64-msvc"
},
"WINNT_x86-msvc-x86": {
"alias": "WINNT_x86-msvc"
},
"WINNT_x86_64-msvc": {
"fileUrl": "https://cdmdownload.adobe.com/firefox/win/x64/primetime_gmp_win_x64_gmc_40673.zip",
"hashValue": "bd1e1a370c5f9dadc247c9f00dd203fab1a75ff3afed8439a0a0bfcc7e1767d0da68497140cbe48daa70e2535dde5f220dd7b344619cecd830a6b685efb9d5a0",
"filesize": 4853103
}
},
"version": "17"
}
},
"hashFunction": "sha512",
"name": "CDM-17",
"schema_version": 1000
}

View file

@ -0,0 +1,67 @@
{
"vendors": {
"gmp-gmpopenh264": {
"platforms": {
"WINNT_x86-msvc-x64": {
"alias": "WINNT_x86-msvc"
},
"Android_x86-gcc3": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-android-x86-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "8ce4d4318aa6ae9ac1376500d5fceecb3df38727aa920efd9f7829c139face4a069cab683d3902e7cdb89daad2a7e928ffba120812ae343f052a833812dad387",
"filesize": 1640053
},
"WINNT_x86-msvc": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-win32-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "991e01c3b95fa13fac52e0512e1936f1edae42ecbbbcc55447a36915eb3ca8f836546cc780343751691e0188872e5bc56fe3ad5f23f3243e90b96a637561b89e",
"filesize": 356940
},
"WINNT_x86-msvc-x86": {
"alias": "WINNT_x86-msvc"
},
"Linux_x86_64-gcc3": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-linux64-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "e1086ee6e4fb60a1aa11b5626594b97695533a8e269d776877cebd5cf29088619e2c164e7bd1eba5486f772c943f2efec723f69cc48478ec84a11d7b61ca1865",
"filesize": 515722
},
"Darwin_x86-gcc3-u-i386-x86_64": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-macosx32-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "64b0e13e6319b7a31ed35a46bea5abcfe6af04ba59a277db07677236cfb685813763731ff6b44b85e03e1489f3b15f8df0128a299a36720531b9f4ba6e1c1f58",
"filesize": 382435
},
"Darwin_x86_64-gcc3": {
"alias": "Darwin_x86_64-gcc3-u-i386-x86_64"
},
"Linux_x86-gcc3": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-linux32-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "19084f0230218c584715861f4723e072b1af02e26995762f368105f670f60ecb4082531bc4e33065a4675dd1296f6872a6cb101547ef2d19ef3e25e2e16d4dc0",
"filesize": 515857
},
"Darwin_x86_64-gcc3-u-i386-x86_64": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-macosx64-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "3b52343070a2f75e91b7b0d3bb33935352237c7e1d2fdc6a467d039ffbbda6a72087f9e0a369fe95e6c4c789ff3052f0c134af721d7273db9ba66d077d85b327",
"filesize": 390308
},
"Android_arm-eabi-gcc3": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-android-arm-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "7a15245c781f32df310ebb88cb8a783512eab934b38ffd889d6420473d40eddbe8a89c17cc60d4e7647c156b04d20030e1ae0081e3f90a0d8f94626ec5f4d817",
"filesize": 1515895
},
"Darwin_x86-gcc3": {
"alias": "Darwin_x86-gcc3-u-i386-x86_64"
},
"WINNT_x86_64-msvc-x64": {
"alias": "WINNT_x86_64-msvc"
},
"WINNT_x86_64-msvc": {
"fileUrl": "http://ciscobinary.openh264.org/openh264-win64-0410d336bb748149a4f560eb6108090f078254b1.zip",
"hashValue": "5030b47065e817db5c40bca9c62ac27292bbf636e24698f45dc67f03fa6420b97bd2f792c1cb39df65776c1e7597c70122ac7abf36fb2ad0603734e9e8ec4ef3",
"filesize": 404355
}
},
"version": "1.6"
}
},
"hashFunction": "sha512",
"name": "OpenH264-1.6",
"schema_version": 1000
}

View file

@ -0,0 +1,49 @@
{
"vendors": {
"gmp-widevinecdm": {
"platforms": {
"WINNT_x86-msvc-x64": {
"alias": "WINNT_x86-msvc"
},
"WINNT_x86-msvc": {
"fileUrl": "https://redirector.gvt1.com/edgedl/widevine-cdm/903-win-ia32.zip",
"hashValue": "d7e10d09c87a157af865f8388ba70ae672bd9e38987bdd94077af52d6b1abaa745b3db92e9f93f607af6420c68210f7cfd518a9d2c99fecf79aed3385cbcbc0b",
"filesize": 2884452
},
"WINNT_x86-msvc-x86": {
"alias": "WINNT_x86-msvc"
},
"Linux_x86_64-gcc3": {
"fileUrl": "https://redirector.gvt1.com/edgedl/widevine-cdm/903-linux-x64.zip",
"hashValue": "1edfb58a44792d2a53694f46fcc698161edafb2a1fe0e5c31b50c1d52408b5e8918d9f33271c62a19a65017694ebeacb4f390fe914688ca7b1952cdb84ed55ec",
"filesize": 2975492
},
"Darwin_x86_64-gcc3-u-i386-x86_64": {
"fileUrl": "https://redirector.gvt1.com/edgedl/widevine-cdm/903-mac-x64.zip",
"hashValue": "1916805e84a49e04748204f4e4c48ae52c8312f7c04afedacacd7dfab2de424412bc988a8c3e5bcb0865f8844b569c0eb9589dae51e74d9bdfe46792c9d1631f",
"filesize": 2155607
},
"Darwin_x86_64-gcc3": {
"alias": "Darwin_x86_64-gcc3-u-i386-x86_64"
},
"Linux_x86-gcc3": {
"fileUrl": "https://redirector.gvt1.com/edgedl/widevine-cdm/903-linux-ia32.zip",
"hashValue": "5c4beb72ea693740a013b60bc5491a042bb82fa5ca6845a2f450579e2e1e465263f19e7ab6d08d91deb8219b30f092ab6e6745300d5adda627f270c95e5a66e0",
"filesize": 3084582
},
"WINNT_x86_64-msvc-x64": {
"alias": "WINNT_x86_64-msvc"
},
"WINNT_x86_64-msvc": {
"fileUrl": "https://redirector.gvt1.com/edgedl/widevine-cdm/903-win-x64.zip",
"hashValue": "33497f3458846e11fa52413f6477bfe1a7f502da262c3a2ce9fe6d773a4a2d023c54228596eb162444b55c87fb126de01f60fa729d897ef5e6eec73b2dfbdc7a",
"filesize": 2853777
}
},
"version": "1.4.8.903"
}
},
"hashFunction": "sha512",
"name": "Widevine-1.4.8.903",
"schema_version": 1000
}

120
toolkit/content/jar.mn Normal file
View file

@ -0,0 +1,120 @@
toolkit.jar:
% content global %content/global/ contentaccessible=yes
% content global-platform %content/global-platform/ platform
* content/global/license.html
content/global/XPCNativeWrapper.js
content/global/minimal-xul.css
* content/global/xul.css
content/global/textbox.css
content/global/menulist.css
content/global/autocomplete.css
content/global/about.js
content/global/about.xhtml
content/global/aboutAbout.js
content/global/aboutAbout.xhtml
#ifdef MOZILLA_OFFICIAL
content/global/aboutRights.xhtml
#else
content/global/aboutRights.xhtml (aboutRights-unbranded.xhtml)
#endif
content/global/aboutNetworking.js
content/global/aboutNetworking.xhtml
#ifndef ANDROID
content/global/aboutProfiles.js
content/global/aboutProfiles.xhtml
#endif
content/global/aboutServiceWorkers.js
content/global/aboutServiceWorkers.xhtml
content/global/aboutwebrtc/aboutWebrtc.css (aboutwebrtc/aboutWebrtc.css)
content/global/aboutwebrtc/aboutWebrtc.js (aboutwebrtc/aboutWebrtc.js)
content/global/aboutwebrtc/aboutWebrtc.html (aboutwebrtc/aboutWebrtc.html)
content/global/aboutSupport.js
* content/global/aboutSupport.xhtml
content/global/aboutTelemetry.js
content/global/aboutTelemetry.xhtml
content/global/aboutTelemetry.css
content/global/directionDetector.html
content/global/plugins.html
content/global/plugins.css
content/global/browser-child.js
content/global/browser-content.js
* content/global/buildconfig.html
content/global/contentAreaUtils.js
#ifndef MOZ_FENNEC
content/global/customizeToolbar.css
content/global/customizeToolbar.js
content/global/customizeToolbar.xul
#endif
#ifndef MOZ_FENNEC
content/global/editMenuOverlay.js
* content/global/editMenuOverlay.xul
content/global/finddialog.js
* content/global/finddialog.xul
content/global/findUtils.js
#endif
content/global/filepicker.properties
content/global/globalOverlay.js
content/global/mozilla.xhtml
content/global/process-content.js
content/global/resetProfile.css
content/global/resetProfile.js
content/global/resetProfile.xul
content/global/resetProfileProgress.xul
content/global/select-child.js
content/global/TopLevelVideoDocument.js
content/global/timepicker.xhtml
content/global/treeUtils.js
content/global/viewZoomOverlay.js
content/global/bindings/autocomplete.xml (widgets/autocomplete.xml)
content/global/bindings/browser.xml (widgets/browser.xml)
content/global/bindings/button.xml (widgets/button.xml)
content/global/bindings/checkbox.xml (widgets/checkbox.xml)
content/global/bindings/colorpicker.xml (widgets/colorpicker.xml)
content/global/bindings/datetimepicker.xml (widgets/datetimepicker.xml)
content/global/bindings/datetimepopup.xml (widgets/datetimepopup.xml)
content/global/bindings/datetimebox.xml (widgets/datetimebox.xml)
content/global/bindings/datetimebox.css (widgets/datetimebox.css)
* content/global/bindings/dialog.xml (widgets/dialog.xml)
content/global/bindings/editor.xml (widgets/editor.xml)
content/global/bindings/expander.xml (widgets/expander.xml)
content/global/bindings/filefield.xml (widgets/filefield.xml)
* content/global/bindings/findbar.xml (widgets/findbar.xml)
content/global/bindings/general.xml (widgets/general.xml)
content/global/bindings/groupbox.xml (widgets/groupbox.xml)
content/global/bindings/listbox.xml (widgets/listbox.xml)
content/global/bindings/menu.xml (widgets/menu.xml)
content/global/bindings/menulist.xml (widgets/menulist.xml)
content/global/bindings/notification.xml (widgets/notification.xml)
content/global/bindings/numberbox.xml (widgets/numberbox.xml)
content/global/bindings/popup.xml (widgets/popup.xml)
* content/global/bindings/preferences.xml (widgets/preferences.xml)
content/global/bindings/progressmeter.xml (widgets/progressmeter.xml)
content/global/bindings/radio.xml (widgets/radio.xml)
content/global/bindings/remote-browser.xml (widgets/remote-browser.xml)
content/global/bindings/resizer.xml (widgets/resizer.xml)
content/global/bindings/richlistbox.xml (widgets/richlistbox.xml)
content/global/bindings/scale.xml (widgets/scale.xml)
content/global/bindings/scrollbar.xml (widgets/scrollbar.xml)
content/global/bindings/scrollbox.xml (widgets/scrollbox.xml)
content/global/bindings/spinner.js (widgets/spinner.js)
content/global/bindings/splitter.xml (widgets/splitter.xml)
content/global/bindings/spinbuttons.xml (widgets/spinbuttons.xml)
content/global/bindings/stringbundle.xml (widgets/stringbundle.xml)
* content/global/bindings/tabbox.xml (widgets/tabbox.xml)
content/global/bindings/text.xml (widgets/text.xml)
* content/global/bindings/textbox.xml (widgets/textbox.xml)
content/global/bindings/timekeeper.js (widgets/timekeeper.js)
content/global/bindings/timepicker.js (widgets/timepicker.js)
content/global/bindings/toolbar.xml (widgets/toolbar.xml)
content/global/bindings/toolbarbutton.xml (widgets/toolbarbutton.xml)
* content/global/bindings/tree.xml (widgets/tree.xml)
content/global/bindings/videocontrols.xml (widgets/videocontrols.xml)
content/global/bindings/videocontrols.css (widgets/videocontrols.css)
* content/global/bindings/wizard.xml (widgets/wizard.xml)
#ifdef XP_MACOSX
content/global/macWindowMenu.js
#endif
content/global/svg/svgBindings.xml (/layout/svg/resources/content/svgBindings.xml)
content/global/gmp-sources/eme-adobe.json (gmp-sources/eme-adobe.json)
content/global/gmp-sources/openh264.json (gmp-sources/openh264.json)
content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json)

5906
toolkit/content/license.html Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
<script type="application/javascript" src="chrome://global/content/macWindowMenu.js"/>
<commandset id="baseMenuCommandSet">
<command id="minimizeWindow"
label="&minimizeWindow.label;"
oncommand="window.minimize();" />
<command id="zoomWindow"
label="&zoomWindow.label;"
oncommand="zoomWindow();" />
</commandset>
<keyset id="baseMenuKeyset">
<key id="key_minimizeWindow"
command="minimizeWindow"
key="&minimizeWindow.key;"
modifiers="accel"/>
</keyset>
<menu id="windowMenu"
label="&windowMenu.label;"
datasources="rdf:window-mediator" ref="NC:WindowMediatorRoot"
onpopupshowing="macWindowMenuDidShow();"
hidden="false">
<template>
<rule>
<menupopup>
<menuitem uri="rdf:*"
label="rdf:http://home.netscape.com/NC-rdf#Name"
type="radio"
name="windowList"
oncommand="ShowWindowFromResource(event.target)"/>
</menupopup>
</rule>
</template>
<menupopup id="windowPopup">
<menuitem command="minimizeWindow" key="key_minimizeWindow"/>
<menuitem command="zoomWindow"/>
<!-- decomment when "BringAllToFront" is implemented
<menuseparator/>
<menuitem label="&bringAllToFront.label;" disabled="true"/> -->
<menuseparator id="sep-window-list"/>
</menupopup>
</menu>

View file

@ -0,0 +1,51 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* 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/. */
function macWindowMenuDidShow()
{
var windowManagerDS =
Components.classes['@mozilla.org/rdf/datasource;1?name=window-mediator']
.getService(Components.interfaces.nsIWindowDataSource);
var sep = document.getElementById("sep-window-list");
// Using double parens to avoid warning
while ((sep = sep.nextSibling)) {
var url = sep.getAttribute('id');
var win = windowManagerDS.getWindowForResource(url);
if (win.document.documentElement.getAttribute("inwindowmenu") == "false")
sep.hidden = true;
else if (win == window)
sep.setAttribute("checked", "true");
}
}
function toOpenWindow( aWindow )
{
// deminiaturize the window, if it's in the Dock
if (aWindow.windowState == STATE_MINIMIZED)
aWindow.restore();
aWindow.document.commandDispatcher.focusedWindow.focus();
}
function ShowWindowFromResource( node )
{
var windowManagerDS =
Components.classes['@mozilla.org/rdf/datasource;1?name=window-mediator']
.getService(Components.interfaces.nsIWindowDataSource);
var desiredWindow = null;
var url = node.getAttribute('id');
desiredWindow = windowManagerDS.getWindowForResource( url );
if (desiredWindow)
toOpenWindow(desiredWindow);
}
function zoomWindow()
{
if (window.windowState == STATE_NORMAL)
window.maximize();
else
window.restore();
}

View file

@ -0,0 +1,11 @@
/* 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/. */
@namespace html url("http://www.w3.org/1999/xhtml"); /* namespace for HTML elements */
html|*.menulist-editable-input {
-moz-appearance: none !important;
background: transparent ! important;
-moz-box-flex: 1;
}

View file

@ -0,0 +1,133 @@
/* 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/. */
/**
* This file should only contain a minimal set of rules for the XUL elements
* that may be implicitly created as part of HTML/SVG documents (e.g.
* scrollbars). Rules for everything else related to XUL can be found in
* xul.css. (This split of the XUL rules is to minimize memory use and improve
* performance in HTML/SVG documents.)
*
* This file should also not contain any app specific styling. Defaults for
* widgets of a particular application should be in that application's style
* sheet. For example style definitions for navigator can be found in
* navigator.css.
*
* THIS FILE IS LOCKED DOWN. YOU ARE NOT ALLOWED TO MODIFY IT WITHOUT FIRST
* HAVING YOUR CHANGES REVIEWED BY enndeakin@gmail.com
*/
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
@namespace html url("http://www.w3.org/1999/xhtml"); /* namespace for HTML elements */
* {
-moz-user-focus: ignore;
-moz-user-select: none;
display: -moz-box;
box-sizing: border-box;
}
:root {
text-rendering: optimizeLegibility;
-moz-binding: url("chrome://global/content/bindings/general.xml#root-element");
-moz-control-character-visibility: visible;
}
:root:-moz-locale-dir(rtl) {
direction: rtl;
}
/* hide the content and destroy the frame */
[hidden="true"] {
display: none;
}
/* hide the content, but don't destroy the frames */
[collapsed="true"],
[moz-collapsed="true"] {
visibility: collapse;
}
/********** label **********/
description {
-moz-binding: url("chrome://global/content/bindings/text.xml#text-base");
}
label {
-moz-binding: url("chrome://global/content/bindings/text.xml#text-label");
}
label.text-link, label[onclick] {
-moz-binding: url("chrome://global/content/bindings/text.xml#text-link");
-moz-user-focus: normal;
}
label[control], label.radio-label, label.checkbox-label, label.toolbarbutton-multiline-text {
-moz-binding: url("chrome://global/content/bindings/text.xml#label-control");
}
html|span.accesskey {
text-decoration: underline;
}
/********** resizer **********/
resizer {
-moz-binding: url("chrome://global/content/bindings/resizer.xml#resizer");
position: relative;
z-index: 2147483647;
}
/********** scrollbar **********/
/* Scrollbars are never flipped even if BiDI kicks in. */
scrollbar[orient="horizontal"] {
direction: ltr;
}
thumb {
-moz-binding: url(chrome://global/content/bindings/scrollbar.xml#thumb);
display: -moz-box !important;
}
.scale-thumb {
-moz-binding: url(chrome://global/content/bindings/scale.xml#scalethumb);
}
scrollbar, scrollbarbutton, scrollcorner, slider, thumb, scale {
-moz-user-select: none;
}
scrollcorner {
display: -moz-box !important;
}
scrollcorner[hidden="true"] {
display: none !important;
}
scrollbar[value="hidden"] {
visibility: hidden;
}
scale {
-moz-binding: url(chrome://global/content/bindings/scale.xml#scale);
}
.scale-slider {
-moz-binding: url(chrome://global/content/bindings/scale.xml#scaleslider);
-moz-user-focus: normal;
}
scrollbarbutton[sbattr="scrollbar-up-top"]:not(:-moz-system-metric(scrollbar-start-backward)),
scrollbarbutton[sbattr="scrollbar-down-top"]:not(:-moz-system-metric(scrollbar-start-forward)),
scrollbarbutton[sbattr="scrollbar-up-bottom"]:not(:-moz-system-metric(scrollbar-end-backward)),
scrollbarbutton[sbattr="scrollbar-down-bottom"]:not(:-moz-system-metric(scrollbar-end-forward)) {
display: none;
}
thumb[sbattr="scrollbar-thumb"]:-moz-system-metric(scrollbar-thumb-proportional) {
-moz-box-flex: 1;
}

34
toolkit/content/moz.build Normal file
View file

@ -0,0 +1,34 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
TEST_DIRS += ['tests']
for var in ('target', 'MOZ_CONFIGURE_OPTIONS', 'CC', 'CC_VERSION', 'CXX'):
DEFINES[var] = CONFIG[var]
DEFINES['CFLAGS'] = CONFIG['OS_CFLAGS']
if CONFIG['OS_TARGET'] == 'Android':
DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
if CONFIG['MOZ_ANDROID_CXX_STL'] == 'libc++':
DEFINES['MOZ_USE_LIBCXX'] = True
if CONFIG['MOZ_BUILD_APP'] == 'mobile/android':
DEFINES['MOZ_FENNEC'] = True
JAR_MANIFESTS += ['jar.mn']
with Files('aboutTelemetry.*'):
BUG_COMPONENT = ('Toolkit', 'Telemetry')
with Files('customizeToolbar.*'):
BUG_COMPONENT = ('Toolkit', 'Toolbars and Toolbar Customization')
with Files('widgets/*'):
BUG_COMPONENT = ('Toolkit', 'XUL Widgets')
DEFINES['TOPOBJDIR'] = TOPOBJDIR

View file

@ -0,0 +1,66 @@
<!DOCTYPE html
[
<!ENTITY % mozillaDTD SYSTEM "chrome://global/locale/mozilla.dtd" >
%mozillaDTD;
<!ENTITY % directionDTD SYSTEM "chrome://global/locale/global.dtd" >
%directionDTD;
]>
<!-- 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/. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset='utf-8' />
<title>&mozilla.title.15.1;</title>
<style>
html {
background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat;
color: white;
font-style: italic;
text-rendering: optimizeLegibility;
min-height: 100%;
}
#moztext {
margin-top: 15%;
font-size: 1.1em;
font-family: serif;
text-align: center;
line-height: 1.5;
}
#from {
font-size: 1.95em;
font-family: serif;
text-align: right;
}
em {
font-size: 1.3em;
line-height: 0;
}
a {
text-decoration: none;
color: white;
}
</style>
</head>
<body dir="&locale.dir;">
<section>
<p id="moztext">
&mozilla.quote.15.1;
</p>
<p id="from">
&mozilla.from.15.1;
</p>
</section>
</body>
</html>

View file

@ -0,0 +1,88 @@
/* 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/. */
/* ===== plugins.css =====================================================
== Styles used by the about:plugins page.
======================================================================= */
body {
background-color: -moz-Field;
color: -moz-FieldText;
font: message-box;
}
div#outside {
text-align: justify;
width: 90%;
margin-left: 5%;
margin-right: 5%;
}
#plugs {
text-align: center;
font-size: xx-large;
font-weight: bold;
}
#noplugs {
font-size: x-large;
font-weight: bold;
}
.plugname {
margin-top: 2em;
margin-bottom: 1em;
font-size: large;
text-align: start;
font-weight: bold;
}
dl {
margin: 0px 0px 3px 0px;
}
table {
background-color: -moz-Dialog;
color: -moz-DialogText;
font: message-box;
text-align: start;
width: 100%;
border: 1px solid ThreeDShadow;
border-spacing: 0px;
}
th, td {
border: none;
padding: 3px;
}
th {
text-align: center;
background-color: Highlight;
color: HighlightText;
}
th + th,
td + td {
border-inline-start: 1px dotted ThreeDShadow;
}
td {
text-align: start;
border-top: 1px dotted ThreeDShadow;
}
th.type, th.suff {
width: 25%;
}
th.desc {
width: 50%;
}
.notice {
background: -moz-cellhighlight;
border: 1px solid ThreeDShadow;
padding: 10px;
}

View file

@ -0,0 +1,217 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!-- 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/. -->
<html>
<head>
<script type="application/javascript">
"use strict";
Components.utils.import("resource://gre/modules/Services.jsm");
var Ci = Components.interfaces;
var strBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
var pluginsbundle = strBundleService.createBundle("chrome://global/locale/plugins.properties");
document.writeln("<title>" + pluginsbundle.GetStringFromName("title_label") + "<\/title>");
</script>
<link rel="stylesheet" type="text/css" href="chrome://global/content/plugins.css">
<link rel="stylesheet" type="text/css" href="chrome://global/skin/plugins.css">
</head>
<body>
<div id="outside">
<script type="application/javascript">
"use strict";
function setDirection() {
var frame = document.getElementById("directionDetector");
var direction = frame.contentDocument
.defaultView
.window
.getComputedStyle(frame.contentDocument.getElementById("target"), "")
.getPropertyValue("direction");
document.body.removeChild(frame);
document.dir = direction;
}
function setupDirection() {
var frame = document.createElement("iframe");
frame.setAttribute("id", "directionDetector");
frame.setAttribute("src", "chrome://global/content/directionDetector.html");
frame.setAttribute("width", "0");
frame.setAttribute("height", "0");
frame.setAttribute("style", "visibility: hidden;");
frame.setAttribute("onload", "setDirection();");
document.body.appendChild(frame);
}
setupDirection();
/* JavaScript to enumerate and display all installed plug-ins
* First, refresh plugins in case anything has been changed recently in
* prefs: (The "false" argument tells refresh not to reload or activate
* any plug-ins that would be active otherwise. In contrast, one would
* use "true" in the case of ASD instead of restarting)
*/
navigator.plugins.refresh(false);
addMessageListener("PluginList", function({ data: aPlugins }) {
var fragment = document.createDocumentFragment();
// "Installed plugins"
var id, label;
if (aPlugins.length > 0) {
id = "plugs";
label = "installedplugins_label";
} else {
id = "noplugs";
label = "nopluginsareinstalled_label";
}
var enabledplugins = document.createElement("h1");
enabledplugins.setAttribute("id", id);
enabledplugins.appendChild(document.createTextNode(pluginsbundle.GetStringFromName(label)));
fragment.appendChild(enabledplugins);
var deprecation = document.createElement("p");
deprecation.setAttribute("class", "notice");
deprecation.textContent = pluginsbundle.GetStringFromName("deprecation_description") + " \u00A0 ";
var deprecationLink = document.createElement("a");
deprecationLink.textContent = pluginsbundle.GetStringFromName("deprecation_learn_more");
deprecationLink.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "npapi";
deprecation.appendChild(deprecationLink);
fragment.appendChild(deprecation);
var stateNames = {};
["STATE_SOFTBLOCKED",
"STATE_BLOCKED",
"STATE_OUTDATED",
"STATE_VULNERABLE_UPDATE_AVAILABLE",
"STATE_VULNERABLE_NO_UPDATE"].forEach(function(label) {
stateNames[Ci.nsIBlocklistService[label]] = label;
});
for (var i = 0; i < aPlugins.length; i++) {
var plugin = aPlugins[i];
if (plugin) {
// "Shockwave Flash"
var plugname = document.createElement("h2");
plugname.setAttribute("class", "plugname");
plugname.appendChild(document.createTextNode(plugin.name));
fragment.appendChild(plugname);
var dl = document.createElement("dl");
fragment.appendChild(dl);
// "File: Flash Player.plugin"
var fileDd = document.createElement("dd");
var file = document.createElement("span");
file.setAttribute("class", "label");
file.appendChild(document.createTextNode(pluginsbundle.GetStringFromName("file_label") + " "));
fileDd.appendChild(file);
fileDd.appendChild(document.createTextNode(plugin.pluginLibraries));
dl.appendChild(fileDd);
// "Path: /usr/lib/mozilla/plugins/libtotem-cone-plugin.so"
var pathDd = document.createElement("dd");
var path = document.createElement("span");
path.setAttribute("class", "label");
path.appendChild(document.createTextNode(pluginsbundle.GetStringFromName("path_label") + " "));
pathDd.appendChild(path);
pathDd.appendChild(document.createTextNode(plugin.pluginFullpath));
dl.appendChild(pathDd);
// "Version: "
var versionDd = document.createElement("dd");
var version = document.createElement("span");
version.setAttribute("class", "label");
version.appendChild(document.createTextNode(pluginsbundle.GetStringFromName("version_label") + " "));
versionDd.appendChild(version);
versionDd.appendChild(document.createTextNode(plugin.version));
dl.appendChild(versionDd);
// "State: "
var stateDd = document.createElement("dd");
var state = document.createElement("span");
state.setAttribute("label", "state");
state.appendChild(document.createTextNode(pluginsbundle.GetStringFromName("state_label") + " "));
stateDd.appendChild(state);
var status = plugin.isActive ? pluginsbundle.GetStringFromName("state_enabled") : pluginsbundle.GetStringFromName("state_disabled");
if (plugin.blocklistState in stateNames) {
status += " (" + stateNames[plugin.blocklistState] + ")";
}
stateDd.appendChild(document.createTextNode(status));
dl.appendChild(stateDd);
// Plugin Description
var descDd = document.createElement("dd");
descDd.appendChild(document.createTextNode(plugin.description));
dl.appendChild(descDd);
// MIME Type table
var mimetypeTable = document.createElement("table");
mimetypeTable.setAttribute("border", "1");
mimetypeTable.setAttribute("class", "contenttable");
fragment.appendChild(mimetypeTable);
var thead = document.createElement("thead");
mimetypeTable.appendChild(thead);
var tr = document.createElement("tr");
thead.appendChild(tr);
// "MIME Type" column header
var typeTh = document.createElement("th");
typeTh.setAttribute("class", "type");
typeTh.appendChild(document.createTextNode(pluginsbundle.GetStringFromName("mimetype_label")));
tr.appendChild(typeTh);
// "Description" column header
var descTh = document.createElement("th");
descTh.setAttribute("class", "desc");
descTh.appendChild(document.createTextNode(pluginsbundle.GetStringFromName("description_label")));
tr.appendChild(descTh);
// "Suffixes" column header
var suffixesTh = document.createElement("th");
suffixesTh.setAttribute("class", "suff");
suffixesTh.appendChild(document.createTextNode(pluginsbundle.GetStringFromName("suffixes_label")));
tr.appendChild(suffixesTh);
var tbody = document.createElement("tbody");
mimetypeTable.appendChild(tbody);
var mimeTypes = plugin.pluginMimeTypes;
for (var j = 0; j < mimeTypes.length; j++) {
var mimetype = mimeTypes[j];
if (mimetype) {
var mimetypeRow = document.createElement("tr");
tbody.appendChild(mimetypeRow);
// "application/x-shockwave-flash"
var typename = document.createElement("td");
typename.appendChild(document.createTextNode(mimetype.type));
mimetypeRow.appendChild(typename);
// "Shockwave Flash"
var description = document.createElement("td");
description.appendChild(document.createTextNode(mimetype.description));
mimetypeRow.appendChild(description);
// "swf"
var suffixes = document.createElement("td");
suffixes.appendChild(document.createTextNode(mimetype.suffixes));
mimetypeRow.appendChild(suffixes);
}
}
}
}
document.getElementById("outside").appendChild(fragment);
});
sendAsyncMessage("RequestPlugins");
</script>
</div>
</body>
</html>

View file

@ -0,0 +1,84 @@
/* 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";
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
// Creates a new PageListener for this process. This will listen for page loads
// and for those that match URLs provided by the parent process will set up
// a dedicated message port and notify the parent process.
Cu.import("resource://gre/modules/RemotePageManager.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const gInContentProcess = Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT;
Services.cpmm.addMessageListener("gmp-plugin-crash", msg => {
let gmpservice = Cc["@mozilla.org/gecko-media-plugin-service;1"]
.getService(Ci.mozIGeckoMediaPluginService);
gmpservice.RunPluginCrashCallbacks(msg.data.pluginID, msg.data.pluginName);
});
if (gInContentProcess) {
let ProcessObserver = {
TOPICS: [
"inner-window-destroyed",
"xpcom-shutdown",
],
init() {
for (let topic of this.TOPICS) {
Services.obs.addObserver(this, topic, false);
Services.cpmm.addMessageListener("Memory:GetSummary", this);
}
},
uninit() {
for (let topic of this.TOPICS) {
Services.obs.removeObserver(this, topic);
Services.cpmm.removeMessageListener("Memory:GetSummary", this);
}
},
receiveMessage(msg) {
if (msg.name != "Memory:GetSummary") {
return;
}
let pid = Services.appinfo.processID;
let memMgr = Cc["@mozilla.org/memory-reporter-manager;1"]
.getService(Ci.nsIMemoryReporterManager);
let rss = memMgr.resident;
let uss = memMgr.residentUnique;
Services.cpmm.sendAsyncMessage("Memory:Summary", {
pid,
summary: {
uss,
rss,
}
});
},
observe(subject, topic, data) {
switch (topic) {
case "inner-window-destroyed": {
// Forward inner-window-destroyed notifications with the
// inner window ID, so that code in the parent that should
// do something when content windows go away can do it
let innerWindowID =
subject.QueryInterface(Ci.nsISupportsPRUint64).data;
Services.cpmm.sendAsyncMessage("Toolkit:inner-window-destroyed",
innerWindowID);
break;
}
case "xpcom-shutdown": {
this.uninit();
break;
}
}
},
};
ProcessObserver.init();
}

View file

@ -0,0 +1,15 @@
/* 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/. */
#migratedItems {
margin-inline-start: 1.5em;
}
#resetProfileFooter {
font-weight: bold;
}
#resetProfileProgressDialog {
padding: 10px;
}

View file

@ -0,0 +1,20 @@
/* 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";
// NB: this file can be loaded from aboutSupport.xhtml or from the
// resetProfile.xul dialog, and so Cu may or may not exist already.
// Proceed with caution:
if (!("Cu" in window)) {
window.Cu = Components.utils;
}
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ResetProfile.jsm");
function onResetProfileAccepted() {
let retVals = window.arguments[0];
retVals.reset = true;
}

View file

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE prefwindow [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % resetProfileDTD SYSTEM "chrome://global/locale/resetProfile.dtd" >
%resetProfileDTD;
]>
<?xml-stylesheet href="chrome://global/skin/"?>
<?xml-stylesheet href="chrome://global/content/resetProfile.css"?>
<dialog id="resetProfileDialog"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&refreshProfile.dialog.title;"
buttons="accept,cancel"
defaultButton="cancel"
buttonlabelaccept="&refreshProfile.dialog.button.label;"
ondialogaccept="return onResetProfileAccepted();"
ondialogcancel="window.close();">
<script type="application/javascript" src="chrome://global/content/resetProfile.js"/>
<description value="&refreshProfile.dialog.description1;"></description>
<label value="&refreshProfile.dialog.description2;"/>
<vbox id="migratedItems">
<label class="migratedLabel" value="&refreshProfile.dialog.items.label1;"/>
<label class="migratedLabel" value="&refreshProfile.dialog.items.label2;"/>
</vbox>
</dialog>

View file

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % resetProfileDTD SYSTEM "chrome://global/locale/resetProfile.dtd" >
%resetProfileDTD;
]>
<?xml-stylesheet href="chrome://global/content/resetProfile.css"?>
<?xml-stylesheet href="chrome://global/skin/"?>
<window id="resetProfileProgressDialog"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&refreshProfile.dialog.title;"
style="min-width: 300px;">
<vbox>
<description>&refreshProfile.cleaning.description;</description>
<progressmeter mode="undetermined"/>
</vbox>
</window>

View file

@ -0,0 +1,26 @@
/* 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/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SelectContentHelper",
"resource://gre/modules/SelectContentHelper.jsm");
addEventListener("mozshowdropdown", event => {
if (!event.isTrusted)
return;
if (!SelectContentHelper.open) {
new SelectContentHelper(event.target, {isOpenedViaTouch: false}, this);
}
});
addEventListener("mozshowdropdown-sourcetouch", event => {
if (!event.isTrusted)
return;
if (!SelectContentHelper.open) {
new SelectContentHelper(event.target, {isOpenedViaTouch: true}, this);
}
});

View file

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"../../../../testing/mochitest/browser.eslintrc.js"
]
};

Binary file not shown.

View file

@ -0,0 +1,75 @@
[DEFAULT]
support-files =
head.js
file_contentTitle.html
audio.ogg
[browser_audioCompeting.js]
tags = audiochannel
support-files =
file_multipleAudio.html
[browser_audioCompeting_onlyForActiveAgent.js]
tags = audiochannel
support-files =
file_multiplePlayingAudio.html
[browser_autoscroll_disabled.js]
[browser_block_autoplay_media.js]
tags = audiochannel
support-files =
file_multipleAudio.html
[browser_bug295977_autoscroll_overflow.js]
[browser_bug451286.js]
skip-if = !e10s
[browser_bug594509.js]
[browser_bug982298.js]
[browser_bug1198465.js]
[browser_contentTitle.js]
[browser_crash_previous_frameloader.js]
run-if = e10s && crashreporter
[browser_default_image_filename.js]
[browser_f7_caret_browsing.js]
[browser_findbar.js]
[browser_label_textlink.js]
[browser_isSynthetic.js]
support-files =
empty.png
[browser_keyevents_during_autoscrolling.js]
[browser_save_resend_postdata.js]
support-files =
common/mockTransfer.js
data/post_form_inner.sjs
data/post_form_outer.sjs
skip-if = e10s # Bug ?????? - test directly manipulates content (gBrowser.contentDocument.getElementById("postForm").submit();)
[browser_content_url_annotation.js]
skip-if = !e10s || !crashreporter
support-files =
file_redirect.html
file_redirect_to.html
[browser_bug1170531.js]
[browser_mediaPlayback.js]
tags = audiochannel
support-files =
file_mediaPlayback.html
file_mediaPlaybackFrame.html
[browser_mediaPlayback_mute.js]
tags = audiochannel
support-files =
file_mediaPlayback2.html
file_mediaPlaybackFrame2.html
[browser_mediaPlayback_suspended.js]
tags = audiochannel
support-files =
file_mediaPlayback2.html
[browser_mediaPlayback_suspended_multipleAudio.js]
tags = audiochannel
support-files =
file_multipleAudio.html
[browser_mute.js]
tags = audiochannel
[browser_mute2.js]
tags = audiochannel
[browser_quickfind_editable.js]
[browser_saveImageURL.js]
support-files =
image.jpg
image_page.html

View file

@ -0,0 +1,115 @@
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multipleAudio.html";
function* wait_for_tab_playing_event(tab, expectPlaying) {
if (tab.soundPlaying == expectPlaying) {
ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
} else {
yield BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
if (event.detail.changed.indexOf("soundplaying") >= 0) {
is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
return true;
}
return false;
});
}
}
function play_audio_from_invisible_tab () {
return new Promise(resolve => {
var autoPlay = content.document.getElementById('autoplay');
if (!autoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.paused, true, "Audio in tab 1 was paused by audio competing.");
autoPlay.play();
autoPlay.onpause = function() {
autoPlay.onpause = null;
ok(true, "Audio in tab 1 can't playback when other tab is playing in foreground.");
resolve();
};
});
}
function audio_should_keep_playing_even_go_to_background () {
var autoPlay = content.document.getElementById('autoplay');
if (!autoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.paused, false, "Audio in tab 2 is still playing in the background.");
}
function play_non_autoplay_audio () {
return new Promise(resolve => {
var autoPlay = content.document.getElementById('autoplay');
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!autoPlay || !nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
is(nonAutoPlay.paused, true, "Non-autoplay audio isn't started playing yet.");
nonAutoPlay.play();
nonAutoPlay.onplay = function() {
nonAutoPlay.onplay = null;
is(nonAutoPlay.paused, false, "Start Non-autoplay audio.");
is(autoPlay.paused, false, "Autoplay audio is still playing.");
resolve();
};
});
}
add_task(function* setup_test_preference() {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["dom.audiochannel.audioCompeting", true],
["dom.ipc.processCount", 1]
]}, resolve);
});
});
add_task(function* cross_tabs_audio_competing () {
info("- open tab 1 in foreground -");
let tab1 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
"about:blank");
tab1.linkedBrowser.loadURI(PAGE);
yield wait_for_tab_playing_event(tab1, true);
info("- open tab 2 in foreground -");
let tab2 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
"about:blank");
tab2.linkedBrowser.loadURI(PAGE);
yield wait_for_tab_playing_event(tab1, false);
info("- open tab 3 in foreground -");
let tab3 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
"about:blank");
yield ContentTask.spawn(tab2.linkedBrowser, null,
audio_should_keep_playing_even_go_to_background);
info("- play audio from background tab 1 -");
yield ContentTask.spawn(tab1.linkedBrowser, null,
play_audio_from_invisible_tab);
info("- remove tabs -");
yield BrowserTestUtils.removeTab(tab1);
yield BrowserTestUtils.removeTab(tab2);
yield BrowserTestUtils.removeTab(tab3);
});
add_task(function* within_one_tab_audio_competing () {
info("- open tab and play audio1 -");
let tab = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
"about:blank");
tab.linkedBrowser.loadURI(PAGE);
yield wait_for_tab_playing_event(tab, true);
info("- play audio2 in the same tab -");
yield ContentTask.spawn(tab.linkedBrowser, null,
play_non_autoplay_audio);
info("- remove tab -");
yield BrowserTestUtils.removeTab(tab);
});

View file

@ -0,0 +1,176 @@
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multiplePlayingAudio.html";
var SuspendedType = {
NONE_SUSPENDED : 0,
SUSPENDED_PAUSE : 1,
SUSPENDED_BLOCK : 2,
SUSPENDED_PAUSE_DISPOSABLE : 3
};
function wait_for_event(browser, event) {
return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
return true;
});
}
function check_all_audio_suspended(suspendedType) {
var audio1 = content.document.getElementById("audio1");
var audio2 = content.document.getElementById("audio2");
if (!audio1 || !audio2) {
ok(false, "Can't get the audio element!");
}
is(audio1.computedSuspended, suspendedType,
"The suspeded state of audio1 is correct.");
is(audio2.computedSuspended, suspendedType,
"The suspeded state of audio2 is correct.");
}
function check_audio1_suspended(suspendedType) {
var audio1 = content.document.getElementById("audio1");
if (!audio1) {
ok(false, "Can't get the audio element!");
}
is(audio1.computedSuspended, suspendedType,
"The suspeded state of audio1 is correct.");
}
function check_audio2_suspended(suspendedType) {
var audio2 = content.document.getElementById("audio2");
if (!audio2) {
ok(false, "Can't get the audio element!");
}
is(audio2.computedSuspended, suspendedType,
"The suspeded state of audio2 is correct.");
}
function check_all_audio_pause_state(expectedPauseState) {
var audio1 = content.document.getElementById("audio1");
var audio2 = content.document.getElementById("audio2");
if (!audio1 | !audio2) {
ok(false, "Can't get the audio element!");
}
is(audio1.paused, expectedPauseState,
"The pause state of audio1 is correct.");
is(audio2.paused, expectedPauseState,
"The pause state of audio2 is correct.");
}
function check_audio1_pause_state(expectedPauseState) {
var audio1 = content.document.getElementById("audio1");
if (!audio1) {
ok(false, "Can't get the audio element!");
}
is(audio1.paused, expectedPauseState,
"The pause state of audio1 is correct.");
}
function check_audio2_pause_state(expectedPauseState) {
var audio2 = content.document.getElementById("audio2");
if (!audio2) {
ok(false, "Can't get the audio element!");
}
is(audio2.paused, expectedPauseState,
"The pause state of audio2 is correct.");
}
function play_audio1_from_page() {
var audio1 = content.document.getElementById("audio1");
if (!audio1) {
ok(false, "Can't get the audio element!");
}
is(audio1.paused, true, "Audio1 is paused.");
audio1.play();
return new Promise(resolve => {
audio1.onplay = function() {
audio1.onplay = null;
ok(true, "Audio1 started playing.");
resolve();
}
});
}
function stop_audio1_from_page() {
var audio1 = content.document.getElementById("audio1");
if (!audio1) {
ok(false, "Can't get the audio element!");
}
is(audio1.paused, false, "Audio1 is playing.");
audio1.pause();
return new Promise(resolve => {
audio1.onpause = function() {
audio1.onpause = null;
ok(true, "Audio1 stopped playing.");
resolve();
}
});
}
function* audio_competing_for_active_agent(url, browser) {
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the default suspended state of all audio should be non-suspened -");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
info("- only pause playing audio in the page -");
browser.pauseMedia(true /* disposable */);
info("- page shouldn't have any playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStopped");
yield ContentTask.spawn(browser, true /* expect for pause */,
check_all_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
check_all_audio_suspended);
info("- resume audio1 from page -");
yield ContentTask.spawn(browser, null,
play_audio1_from_page);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio1_suspended);
info("- audio2 should still be suspended -");
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
check_audio2_suspended);
yield ContentTask.spawn(browser, true /* expect for pause */,
check_audio2_pause_state);
info("- stop audio1 from page -");
yield ContentTask.spawn(browser, null,
stop_audio1_from_page);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio1_suspended);
info("- audio2 should still be suspended -");
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
check_audio2_suspended);
yield ContentTask.spawn(browser, true /* expect for pause */,
check_audio2_pause_state);
}
add_task(function* setup_test_preference() {
yield SpecialPowers.pushPrefEnv({"set": [
["media.useAudioChannelService.testing", true],
["dom.audiochannel.audioCompeting", true],
["dom.audiochannel.audioCompeting.allAgents", true]
]});
});
add_task(function* test_suspended_pause_disposable() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, audio_competing_for_active_agent.bind(this, PAGE));
});

View file

@ -0,0 +1,67 @@
add_task(function* ()
{
const kPrefName_AutoScroll = "general.autoScroll";
Services.prefs.setBoolPref(kPrefName_AutoScroll, false);
let dataUri = 'data:text/html,<html><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
<iframe id="iframe" style="display: none;"></iframe>\
</body></html>';
let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.loadURI(dataUri);
yield loadedPromise;
yield BrowserTestUtils.synthesizeMouse("#i", 50, 50, { button: 1 },
gBrowser.selectedBrowser);
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
var iframe = content.document.getElementById("iframe");
if (iframe) {
var e = new iframe.contentWindow.PageTransitionEvent("pagehide",
{ bubbles: true,
cancelable: true,
persisted: false });
iframe.contentDocument.dispatchEvent(e);
iframe.contentDocument.documentElement.dispatchEvent(e);
}
});
yield BrowserTestUtils.synthesizeMouse("#i", 100, 100,
{ type: "mousemove", clickCount: "0" },
gBrowser.selectedBrowser);
// If scrolling didn't work, we wouldn't do any redraws and thus time out, so
// request and force redraws to get the chance to check for scrolling at all.
yield new Promise(resolve => window.requestAnimationFrame(resolve));
let msg = yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
// Skip the first animation frame callback as it's the same callback that
// the browser uses to kick off the scrolling.
return new Promise(resolve => {
function checkScroll() {
let msg = "";
let elem = content.document.getElementById('i');
if (elem.scrollTop != 0) {
msg += "element should not have scrolled vertically";
}
if (elem.scrollLeft != 0) {
msg += "element should not have scrolled horizontally";
}
resolve(msg);
}
content.requestAnimationFrame(checkScroll);
});
});
ok(!msg, "element scroll " + msg);
// restore the changed prefs
if (Services.prefs.prefHasUserValue(kPrefName_AutoScroll))
Services.prefs.clearUserPref(kPrefName_AutoScroll);
// wait for focus to fix a failure in the next test if the latter runs too soon.
yield SimpleTest.promiseFocus();
});

View file

@ -0,0 +1,87 @@
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multipleAudio.html";
var SuspendedType = {
NONE_SUSPENDED : 0,
SUSPENDED_PAUSE : 1,
SUSPENDED_BLOCK : 2,
SUSPENDED_PAUSE_DISPOSABLE : 3
};
function* wait_for_tab_playing_event(tab, expectPlaying) {
if (tab.soundPlaying == expectPlaying) {
ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
} else {
yield BrowserTestUtils.waitForEvent(tab, "TabAttrModified", false, (event) => {
if (event.detail.changed.indexOf("soundplaying") >= 0) {
is(tab.soundPlaying, expectPlaying, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
return true;
}
return false;
});
}
}
function check_audio_suspended(suspendedType) {
var autoPlay = content.document.getElementById('autoplay');
if (!autoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.computedSuspended, suspendedType,
"The suspeded state of autoplay audio is correct.");
}
add_task(function* setup_test_preference() {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["media.useAudioChannelService.testing", true],
["media.block-autoplay-until-in-foreground", true]
]}, resolve);
});
});
add_task(function* block_autoplay_media() {
info("- open new background tab1 -");
let tab1 = window.gBrowser.addTab("about:blank");
tab1.linkedBrowser.loadURI(PAGE);
yield BrowserTestUtils.browserLoaded(tab1.linkedBrowser);
info("- should block autoplay media for non-visited tab1 -");
yield ContentTask.spawn(tab1.linkedBrowser, SuspendedType.SUSPENDED_BLOCK,
check_audio_suspended);
info("- open new background tab2 -");
let tab2 = window.gBrowser.addTab("about:blank");
tab2.linkedBrowser.loadURI(PAGE);
yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
info("- should block autoplay for non-visited tab2 -");
yield ContentTask.spawn(tab2.linkedBrowser, SuspendedType.SUSPENDED_BLOCK,
check_audio_suspended);
info("- select tab1 as foreground tab -");
yield BrowserTestUtils.switchTab(window.gBrowser, tab1);
info("- media should be unblocked because the tab was visited -");
yield wait_for_tab_playing_event(tab1, true);
yield ContentTask.spawn(tab1.linkedBrowser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
info("- open another new foreground tab3 -");
let tab3 = yield BrowserTestUtils.openNewForegroundTab(window.gBrowser,
"about:blank");
info("- should still play media from tab1 -");
yield wait_for_tab_playing_event(tab1, true);
yield ContentTask.spawn(tab1.linkedBrowser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
info("- should still block media from tab2 -");
yield wait_for_tab_playing_event(tab2, false);
yield ContentTask.spawn(tab2.linkedBrowser, SuspendedType.SUSPENDED_BLOCK,
check_audio_suspended);
info("- remove tabs -");
yield BrowserTestUtils.removeTab(tab1);
yield BrowserTestUtils.removeTab(tab2);
yield BrowserTestUtils.removeTab(tab3);
});

View file

@ -0,0 +1,92 @@
// Test for bug 1170531
// https://bugzilla.mozilla.org/show_bug.cgi?id=1170531
add_task(function* () {
// Get a bunch of DOM nodes
let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
let editMenu = document.getElementById("edit-menu");
let menubar = editMenu.parentNode;
let menuPopup = editMenu.menupopup;
let editMenuIndex = -1;
for (let i = 0; i < menubar.children.length; i++) {
if (menubar.children[i] === editMenu) {
editMenuIndex = i;
break;
}
}
let closeMenu = function(aCallback) {
if (OS.Constants.Sys.Name == "Darwin") {
executeSoon(aCallback);
return;
}
menuPopup.addEventListener("popuphidden", function onPopupHidden() {
menuPopup.removeEventListener("popuphidden", onPopupHidden, false);
executeSoon(aCallback);
}, false);
executeSoon(function() {
editMenu.open = false;
});
};
let openMenu = function(aCallback) {
if (OS.Constants.Sys.Name == "Darwin") {
goUpdateGlobalEditMenuItems();
// On OSX, we have a native menu, so it has to be updated. In single process browsers,
// this happens synchronously, but in e10s, we have to wait for the main thread
// to deal with it for us. 1 second should be plenty of time.
setTimeout(aCallback, 1000);
return;
}
menuPopup.addEventListener("popupshown", function onPopupShown() {
menuPopup.removeEventListener("popupshown", onPopupShown, false);
executeSoon(aCallback);
}, false);
executeSoon(function() {
editMenu.open = true;
});
};
yield BrowserTestUtils.withNewTab({ gBrowser: gBrowser, url: "about:blank" }, function* (browser) {
let menu_cut_disabled, menu_copy_disabled;
yield BrowserTestUtils.loadURI(browser, "data:text/html,<div>hello!</div>");
yield BrowserTestUtils.browserLoaded(browser);
browser.focus();
yield new Promise(resolve => waitForFocus(resolve, window));
yield new Promise(openMenu);
menu_cut_disabled = menuPopup.querySelector("#menu_cut").getAttribute('disabled') == "true";
is(menu_cut_disabled, false, "menu_cut should be enabled");
menu_copy_disabled = menuPopup.querySelector("#menu_copy").getAttribute('disabled') == "true";
is(menu_copy_disabled, false, "menu_copy should be enabled");
yield new Promise(closeMenu);
yield BrowserTestUtils.loadURI(browser, "data:text/html,<div contentEditable='true'>hello!</div>");
yield BrowserTestUtils.browserLoaded(browser);
browser.focus();
yield new Promise(resolve => waitForFocus(resolve, window));
yield new Promise(openMenu);
menu_cut_disabled = menuPopup.querySelector("#menu_cut").getAttribute('disabled') == "true";
is(menu_cut_disabled, false, "menu_cut should be enabled");
menu_copy_disabled = menuPopup.querySelector("#menu_copy").getAttribute('disabled') == "true";
is(menu_copy_disabled, false, "menu_copy should be enabled");
yield new Promise(closeMenu);
yield BrowserTestUtils.loadURI(browser, "about:preferences");
yield BrowserTestUtils.browserLoaded(browser);
browser.focus();
yield new Promise(resolve => waitForFocus(resolve, window));
yield new Promise(openMenu);
menu_cut_disabled = menuPopup.querySelector("#menu_cut").getAttribute('disabled') == "true";
is(menu_cut_disabled, true, "menu_cut should be disabled");
menu_copy_disabled = menuPopup.querySelector("#menu_copy").getAttribute('disabled') == "true";
is(menu_copy_disabled, true, "menu_copy should be disabled");
yield new Promise(closeMenu);
});
});

View file

@ -0,0 +1,75 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
var kPrefName = "accessibility.typeaheadfind.prefillwithselection";
var kEmptyURI = "data:text/html,";
// This pref is false by default in OSX; ensure the test still works there.
Services.prefs.setBoolPref(kPrefName, true);
registerCleanupFunction(function() {
Services.prefs.clearUserPref(kPrefName);
});
add_task(function* () {
let aTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kEmptyURI);
ok(!gFindBarInitialized, "findbar isn't initialized yet");
// Note: the use case here is when the user types directly in the findbar
// _before_ it's prefilled with a text selection in the page.
// So `yield BrowserTestUtils.sendChar()` can't be used here:
// - synthesizing a key in the browser won't actually send it to the
// findbar; the findbar isn't part of the browser content.
// - we need to _not_ wait for _startFindDeferred to be resolved; yielding
// a synthesized keypress on the browser implicitely happens after the
// browser has dispatched its return message with the prefill value for
// the findbar, which essentially nulls these tests.
let findBar = gFindBar;
is(findBar._findField.value, "", "findbar is empty");
// Test 1
// Any input in the findbar should erase a previous search.
findBar._findField.value = "xy";
findBar.startFind();
is(findBar._findField.value, "xy", "findbar should have xy initial query");
is(findBar._findField.mInputField,
document.activeElement,
"findbar is now focused");
EventUtils.sendChar("z", window);
is(findBar._findField.value, "z", "z erases xy");
findBar._findField.value = "";
ok(!findBar._findField.value, "erase findbar after first test");
// Test 2
// Prefilling the findbar should be ignored if a search has been run.
findBar.startFind();
ok(findBar._startFindDeferred, "prefilled value hasn't been fetched yet");
is(findBar._findField.mInputField,
document.activeElement,
"findbar is still focused");
EventUtils.sendChar("a", window);
EventUtils.sendChar("b", window);
is(findBar._findField.value, "ab", "initial ab typed in the findbar");
// This resolves _startFindDeferred if it's still pending; let's just skip
// over waiting for the browser's return message that should do this as it
// doesn't really matter.
findBar.onCurrentSelection("foo", true);
ok(!findBar._startFindDeferred, "prefilled value fetched");
is(findBar._findField.value, "ab", "ab kept instead of prefill value");
EventUtils.sendChar("c", window);
is(findBar._findField.value, "abc", "c is appended after ab");
// Clear the findField value to make the test run successfully
// for multiple runs in the same browser session.
findBar._findField.value = "";
yield BrowserTestUtils.removeTab(aTab);
});

View file

@ -0,0 +1,214 @@
requestLongerTimeout(2);
add_task(function* ()
{
function pushPref(name, value) {
return new Promise(resolve => SpecialPowers.pushPrefEnv({"set": [[name, value]]}, resolve));
}
yield pushPref("general.autoScroll", true);
const expectScrollNone = 0;
const expectScrollVert = 1;
const expectScrollHori = 2;
const expectScrollBoth = 3;
var allTests = [
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body><style type="text/css">div { display: inline-block; }</style>\
<div id="a" style="width: 100px; height: 100px; overflow: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
<div id="b" style="width: 100px; height: 100px; overflow: auto;"><div style="width: 200px; height: 200px;"></div></div>\
<div id="c" style="width: 100px; height: 100px; overflow-x: auto; overflow-y: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
<div id="d" style="width: 100px; height: 100px; overflow-y: auto; overflow-x: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
<select id="e" style="width: 100px; height: 100px;" multiple="multiple"><option>aaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option><option>a</option>\
<option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
<option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
<select id="f" style="width: 100px; height: 100px;"><option>a</option><option>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option>\
<option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
<option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
<div id="g" style="width: 99px; height: 99px; border: 10px solid black; margin: 10px; overflow: auto;"><div style="width: 100px; height: 100px;"></div></div>\
<div id="h" style="width: 100px; height: 100px; overflow: -moz-hidden-unscrollable;"><div style="width: 200px; height: 200px;"></div></div>\
<iframe id="iframe" style="display: none;"></iframe>\
</body></html>'},
{elem: 'a', expected: expectScrollNone},
{elem: 'b', expected: expectScrollBoth},
{elem: 'c', expected: expectScrollHori},
{elem: 'd', expected: expectScrollVert},
{elem: 'e', expected: expectScrollVert},
{elem: 'f', expected: expectScrollNone},
{elem: 'g', expected: expectScrollBoth},
{elem: 'h', expected: expectScrollNone},
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body id="i" style="overflow-y: scroll"><div style="height: 2000px"></div>\
<iframe id="iframe" style="display: none;"></iframe>\
</body></html>'},
{elem: 'i', expected: expectScrollVert}, // bug 695121
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><style>html, body { width: 100%; height: 100%; overflow-x: hidden; overflow-y: scroll; }</style>\
<body id="j"><div style="height: 2000px"></div>\
<iframe id="iframe" style="display: none;"></iframe>\
</body></html>'},
{elem: 'j', expected: expectScrollVert}, // bug 914251
{dataUri: 'data:text/html,<html><head><meta charset="utf-8">\
<style>\
body > div {scroll-behavior: smooth;width: 300px;height: 300px;overflow: scroll;}\
body > div > div {width: 1000px;height: 1000px;}\
</style>\
</head><body><div id="t"><div></div></div></body></html>'},
{elem: 't', expected: expectScrollBoth}, // bug 1308775
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body>\
<div id="k" style="height: 150px; width: 200px; overflow: scroll; border: 1px solid black;">\
<iframe style="height: 200px; width: 300px;"></iframe>\
</div>\
<div id="l" style="height: 150px; width: 300px; overflow: scroll; border: 1px dashed black;">\
<iframe style="height: 200px; width: 200px;" src="data:text/html,<div style=\'border: 5px solid blue; height: 200%; width: 200%;\'></div>"></iframe>\
</div>\
<iframe id="m"></iframe>\
<div style="height: 200%; border: 5px dashed black;">filler to make document overflow: scroll;</div>\
</body></html>'},
{elem: 'k', expected: expectScrollBoth},
{elem: 'k', expected: expectScrollNone, testwindow: true},
{elem: 'l', expected: expectScrollNone},
{elem: 'm', expected: expectScrollVert, testwindow: true},
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body>\
<img width="100" height="100" alt="image map" usemap="%23planetmap">\
<map name="planetmap">\
<area id="n" shape="rect" coords="0,0,100,100" href="javascript:void(null)">\
</map>\
<a href="javascript:void(null)" id="o" style="width: 100px; height: 100px; border: 1px solid black; display: inline-block; vertical-align: top;">link</a>\
<input id="p" style="width: 100px; height: 100px; vertical-align: top;">\
<textarea id="q" style="width: 100px; height: 100px; vertical-align: top;"></textarea>\
<div style="height: 200%; border: 1px solid black;"></div>\
</body></html>'},
{elem: 'n', expected: expectScrollNone, testwindow: true},
{elem: 'o', expected: expectScrollNone, testwindow: true},
{elem: 'p', expected: expectScrollVert, testwindow: true, middlemousepastepref: false},
{elem: 'q', expected: expectScrollVert, testwindow: true, middlemousepastepref: false},
{dataUri: 'data:text/html,<html><head><meta charset="utf-8"></head><body>\
<input id="r" style="width: 100px; height: 100px; vertical-align: top;">\
<textarea id="s" style="width: 100px; height: 100px; vertical-align: top;"></textarea>\
<div style="height: 200%; border: 1px solid black;"></div>\
</body></html>'},
{elem: 'r', expected: expectScrollNone, testwindow: true, middlemousepastepref: true},
{elem: 's', expected: expectScrollNone, testwindow: true, middlemousepastepref: true}
];
for (let test of allTests) {
if (test.dataUri) {
let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.loadURI(test.dataUri);
yield loadedPromise;
continue;
}
let prefsChanged = (test.middlemousepastepref == false || test.middlemousepastepref == true);
if (prefsChanged) {
yield pushPref("middlemouse.paste", test.middlemousepastepref);
}
yield BrowserTestUtils.synthesizeMouse("#" + test.elem, 50, 80, { button: 1 },
gBrowser.selectedBrowser);
// This ensures bug 605127 is fixed: pagehide in an unrelated document
// should not cancel the autoscroll.
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () {
var iframe = content.document.getElementById("iframe");
if (iframe) {
var e = new iframe.contentWindow.PageTransitionEvent("pagehide",
{ bubbles: true,
cancelable: true,
persisted: false });
iframe.contentDocument.dispatchEvent(e);
iframe.contentDocument.documentElement.dispatchEvent(e);
}
});
is(document.activeElement, gBrowser.selectedBrowser, "Browser still focused after autoscroll started");
yield BrowserTestUtils.synthesizeMouse("#" + test.elem, 100, 100,
{ type: "mousemove", clickCount: "0" },
gBrowser.selectedBrowser);
if (prefsChanged) {
yield new Promise(resolve => SpecialPowers.popPrefEnv(resolve));
}
// Start checking for the scroll.
let firstTimestamp = undefined;
let timeCompensation;
do {
let timestamp = yield new Promise(resolve => window.requestAnimationFrame(resolve));
if (firstTimestamp === undefined) {
firstTimestamp = timestamp;
}
// This value is calculated similarly to the value of the same name in
// ClickEventHandler.autoscrollLoop, except here it's cumulative across
// all frames after the first one instead of being based only on the
// current frame.
timeCompensation = (timestamp - firstTimestamp) / 20;
info("timestamp=" + timestamp + " firstTimestamp=" + firstTimestamp +
" timeCompensation=" + timeCompensation);
// Try to wait until enough time has passed to allow the scroll to happen.
// autoscrollLoop incrementally scrolls during each animation frame, but
// due to how its calculations work, when a frame is very close to the
// previous frame, no scrolling may actually occur during that frame.
// After 100ms's worth of frames, timeCompensation will be 1, making it
// more likely that the accumulated scroll in autoscrollLoop will be >= 1,
// although it also depends on acceleration, which here in this test
// should be > 1 due to how it synthesizes mouse events below.
} while (timeCompensation < 5);
// Close the autoscroll popup by synthesizing Esc.
EventUtils.synthesizeKey("VK_ESCAPE", {});
let scrollVert = test.expected & expectScrollVert;
let scrollHori = test.expected & expectScrollHori;
yield ContentTask.spawn(gBrowser.selectedBrowser,
{ scrollVert : scrollVert,
scrollHori: scrollHori,
elemid : test.elem,
checkWindow: test.testwindow },
function* (args) {
let msg = "";
if (args.checkWindow) {
if (!((args.scrollVert && content.scrollY > 0) ||
(!args.scrollVert && content.scrollY == 0))) {
msg += "Failed: ";
}
msg += 'Window for ' + args.elemid + ' should' + (args.scrollVert ? '' : ' not') + ' have scrolled vertically\n';
if (!((args.scrollHori && content.scrollX > 0) ||
(!args.scrollHori && content.scrollX == 0))) {
msg += "Failed: ";
}
msg += ' Window for ' + args.elemid + ' should' + (args.scrollHori ? '' : ' not') + ' have scrolled horizontally\n';
} else {
let elem = content.document.getElementById(args.elemid);
if (!((args.scrollVert && elem.scrollTop > 0) ||
(!args.scrollVert && elem.scrollTop == 0))) {
msg += "Failed: ";
}
msg += ' ' + args.elemid + ' should' + (args.scrollVert ? '' : ' not') + ' have scrolled vertically\n';
if (!((args.scrollHori && elem.scrollLeft > 0) ||
(!args.scrollHori && elem.scrollLeft == 0))) {
msg += "Failed: ";
}
msg += args.elemid + ' should' + (args.scrollHori ? '' : ' not') + ' have scrolled horizontally';
}
Assert.ok(msg.indexOf("Failed") == -1, msg);
}
);
// Before continuing the test, we need to ensure that the IPC
// message that stops autoscrolling has had time to arrive.
yield new Promise(resolve => executeSoon(resolve));
}
// remove 2 tabs that were opened by middle-click on links
while (gBrowser.visibleTabs.length > 1) {
gBrowser.removeTab(gBrowser.visibleTabs[gBrowser.visibleTabs.length - 1]);
}
// wait for focus to fix a failure in the next test if the latter runs too soon.
yield SimpleTest.promiseFocus();
});

View file

@ -0,0 +1,152 @@
Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js", this);
add_task(function*() {
const SEARCH_TEXT = "text";
const DATAURI = "data:text/html," + SEARCH_TEXT;
// Bug 451286. An iframe that should be highlighted
let visible = "<iframe id='visible' src='" + DATAURI + "'></iframe>";
// Bug 493658. An invisible iframe that shouldn't interfere with
// highlighting matches lying after it in the document
let invisible = "<iframe id='invisible' style='display: none;' " +
"src='" + DATAURI + "'></iframe>";
let uri = DATAURI + invisible + SEARCH_TEXT + visible + SEARCH_TEXT;
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
let contentRect = tab.linkedBrowser.getBoundingClientRect();
let noHighlightSnapshot = snapshotRect(window, contentRect);
ok(noHighlightSnapshot, "Got noHighlightSnapshot");
yield openFindBarAndWait();
gFindBar._findField.value = SEARCH_TEXT;
yield findAgainAndWait();
var matchCase = gFindBar.getElement("find-case-sensitive");
if (matchCase.checked)
matchCase.doCommand();
// Turn on highlighting
yield toggleHighlightAndWait(true);
yield closeFindBarAndWait();
// Take snapshot of highlighting
let findSnapshot = snapshotRect(window, contentRect);
ok(findSnapshot, "Got findSnapshot");
// Now, remove the highlighting, and take a snapshot to compare
// to our original state
yield openFindBarAndWait();
yield toggleHighlightAndWait(false);
yield closeFindBarAndWait();
let unhighlightSnapshot = snapshotRect(window, contentRect);
ok(unhighlightSnapshot, "Got unhighlightSnapshot");
// Select the matches that should have been highlighted manually
yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
let doc = content.document;
let win = doc.defaultView;
// Create a manual highlight in the visible iframe to test bug 451286
let iframe = doc.getElementById("visible");
let ifBody = iframe.contentDocument.body;
let range = iframe.contentDocument.createRange();
range.selectNodeContents(ifBody.childNodes[0]);
let ifWindow = iframe.contentWindow;
let ifDocShell = ifWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let ifController = ifDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsISelectionDisplay)
.QueryInterface(Ci.nsISelectionController);
let frameFindSelection =
ifController.getSelection(ifController.SELECTION_FIND);
frameFindSelection.addRange(range);
// Create manual highlights in the main document (the matches that lie
// before/after the iframes
let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsISelectionDisplay)
.QueryInterface(Ci.nsISelectionController);
let docFindSelection =
controller.getSelection(ifController.SELECTION_FIND);
range = doc.createRange();
range.selectNodeContents(doc.body.childNodes[0]);
docFindSelection.addRange(range);
range = doc.createRange();
range.selectNodeContents(doc.body.childNodes[2]);
docFindSelection.addRange(range);
range = doc.createRange();
range.selectNodeContents(doc.body.childNodes[4]);
docFindSelection.addRange(range);
});
// Take snapshot of manual highlighting
let manualSnapshot = snapshotRect(window, contentRect);
ok(manualSnapshot, "Got manualSnapshot");
// Test 1: Were the matches in iframe correctly highlighted?
let res = compareSnapshots(findSnapshot, manualSnapshot, true);
ok(res[0], "Matches found in iframe correctly highlighted");
// Test 2: Were the matches in iframe correctly unhighlighted?
res = compareSnapshots(noHighlightSnapshot, unhighlightSnapshot, true);
ok(res[0], "Highlighting in iframe correctly removed");
yield BrowserTestUtils.removeTab(tab);
});
function toggleHighlightAndWait(shouldHighlight) {
return new Promise((resolve) => {
let listener = {
onFindResult() {},
onHighlightFinished() {
gFindBar.browser.finder.removeResultListener(listener);
resolve();
},
onMatchesCountResult() {}
};
gFindBar.browser.finder.addResultListener(listener);
gFindBar.toggleHighlight(shouldHighlight);
});
}
function findAgainAndWait() {
return new Promise(resolve => {
let listener = {
onFindResult() {
gFindBar.browser.finder.removeResultListener(listener);
resolve();
},
onHighlightFinished() {},
onMatchesCountResult() {}
};
gFindBar.browser.finder.addResultListener(listener);
gFindBar.onFindAgainCommand();
});
}
function* openFindBarAndWait() {
let awaitTransitionEnd = BrowserTestUtils.waitForEvent(gFindBar, "transitionend");
gFindBar.open();
yield awaitTransitionEnd;
}
// This test is comparing snapshots. It is necessary to wait for the gFindBar
// to close before taking the snapshot so the gFindBar does not take up space
// on the new snapshot.
function* closeFindBarAndWait() {
let awaitTransitionEnd = BrowserTestUtils.waitForEvent(gFindBar, "transitionend", false, event => {
return event.propertyName == "visibility";
});
gFindBar.close();
yield awaitTransitionEnd;
}

View file

@ -0,0 +1,9 @@
add_task(function* () {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:rights");
yield ContentTask.spawn(tab.linkedBrowser, null, function* () {
Assert.ok(content.document.getElementById("your-rights"), "about:rights content loaded");
});
yield BrowserTestUtils.removeTab(tab);
});

View file

@ -0,0 +1,70 @@
const scrollHtml =
"<textarea id=\"textarea1\" row=2>Firefox\n\nFirefox\n\n\n\n\n\n\n\n\n\n" +
"</textarea><a href=\"about:blank\">blank</a>";
add_task(function*() {
let url = "data:text/html;base64," + btoa(scrollHtml);
yield BrowserTestUtils.withNewTab({gBrowser, url}, function*(browser) {
let awaitFindResult = new Promise(resolve => {
let listener = {
onFindResult(aData) {
info("got find result");
browser.finder.removeResultListener(listener);
ok(aData.result == Ci.nsITypeAheadFind.FIND_FOUND, "should find string");
resolve();
},
onCurrentSelection() {},
onMatchesCountResult() {}
};
info("about to add results listener, open find bar, and send 'F' string");
browser.finder.addResultListener(listener);
});
gFindBar.onFindCommand();
EventUtils.sendString("F");
info("added result listener and sent string 'F'");
yield awaitFindResult;
let awaitScrollDone = BrowserTestUtils.waitForMessage(browser.messageManager, "ScrollDone");
// scroll textarea to bottom
const scrollTest =
"var textarea = content.document.getElementById(\"textarea1\");" +
"textarea.scrollTop = textarea.scrollHeight;" +
"sendAsyncMessage(\"ScrollDone\", { });"
browser.messageManager.loadFrameScript("data:text/javascript;base64," +
btoa(scrollTest), false);
yield awaitScrollDone;
info("got ScrollDone event");
yield BrowserTestUtils.loadURI(browser, "about:blank");
yield BrowserTestUtils.browserLoaded(browser);
ok(browser.currentURI.spec == "about:blank", "got load event for about:blank");
let awaitFindResult2 = new Promise(resolve => {
let listener = {
onFindResult(aData) {
info("got find result #2");
browser.finder.removeResultListener(listener);
resolve();
},
onCurrentSelection() {},
onMatchesCountResult() {}
};
browser.finder.addResultListener(listener);
info("added result listener");
});
// find again needs delay for crash test
setTimeout(function() {
// ignore exception if occured
try {
info("about to send find again command");
gFindBar.onFindAgainCommand(false);
info("sent find again command");
} catch (e) {
info("got exception from onFindAgainCommand: " + e);
}
}, 0);
yield awaitFindResult2;
});
});

View file

@ -0,0 +1,16 @@
var url = "https://example.com/browser/toolkit/content/tests/browser/file_contentTitle.html";
add_task(function*() {
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
let browser = tab.linkedBrowser;
yield new Promise((resolve) => {
addEventListener("TestLocationChange", function listener() {
removeEventListener("TestLocationChange", listener);
resolve();
}, true, true);
});
is(gBrowser.contentTitle, "Test Page", "Should have the right title.");
gBrowser.removeTab(tab);
});

View file

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* global Services, requestLongerTimeout, TestUtils, BrowserTestUtils,
ok, info, dump, is, Ci, Cu, Components, ctypes, privateNoteIntentionalCrash,
gBrowser, add_task, addEventListener, removeEventListener, ContentTask */
"use strict";
// Running this test in ASAN is slow.
requestLongerTimeout(2);
/**
* Removes a file from a directory. This is a no-op if the file does not
* exist.
*
* @param directory
* The nsIFile representing the directory to remove from.
* @param filename
* A string for the file to remove from the directory.
*/
function removeFile(directory, filename) {
let file = directory.clone();
file.append(filename);
if (file.exists()) {
file.remove(false);
}
}
/**
* Returns the directory where crash dumps are stored.
*
* @return nsIFile
*/
function getMinidumpDirectory() {
let dir = Services.dirsvc.get('ProfD', Ci.nsIFile);
dir.append("minidumps");
return dir;
}
/**
* Checks that the URL is correctly annotated on a content process crash.
*/
add_task(function* test_content_url_annotation() {
let url = "https://example.com/browser/toolkit/content/tests/browser/file_redirect.html";
let redirect_url = "https://example.com/browser/toolkit/content/tests/browser/file_redirect_to.html";
yield BrowserTestUtils.withNewTab({
gBrowser: gBrowser
}, function* (browser) {
ok(browser.isRemoteBrowser, "Should be a remote browser");
// file_redirect.html should send us to file_redirect_to.html
let promise = ContentTask.spawn(browser, {}, function* () {
dump('ContentTask starting...\n');
yield new Promise((resolve) => {
addEventListener("RedirectDone", function listener() {
dump('Got RedirectDone\n');
removeEventListener("RedirectDone", listener);
resolve();
}, true, true);
});
});
browser.loadURI(url);
yield promise;
// Crash the tab
let annotations = yield BrowserTestUtils.crashBrowser(browser);
ok("URL" in annotations, "annotated a URL");
is(annotations.URL, redirect_url,
"Should have annotated the URL after redirect");
});
});

View file

@ -0,0 +1,108 @@
"use strict";
/**
* Cleans up the .dmp and .extra file from a crash.
*
* @param subject (nsISupports)
* The subject passed through the ipc:content-shutdown
* observer notification when a content process crash has
* occurred.
*/
function cleanUpMinidump(subject) {
Assert.ok(subject instanceof Ci.nsIPropertyBag2,
"Subject needs to be a nsIPropertyBag2 to clean up properly");
let dumpID = subject.getPropertyAsAString("dumpID");
Assert.ok(dumpID, "There should be a dumpID");
if (dumpID) {
let dir = Services.dirsvc.get("ProfD", Ci.nsIFile);
dir.append("minidumps");
let file = dir.clone();
file.append(dumpID + ".dmp");
file.remove(true);
file = dir.clone();
file.append(dumpID + ".extra");
file.remove(true);
}
}
/**
* This test ensures that if a remote frameloader crashes after
* the frameloader owner swaps it out for a new frameloader,
* that a oop-browser-crashed event is not sent to the new
* frameloader's browser element.
*/
add_task(function* test_crash_in_previous_frameloader() {
// On debug builds, crashing tabs results in much thinking, which
// slows down the test and results in intermittent test timeouts,
// so we'll pump up the expected timeout for this test.
requestLongerTimeout(2);
if (!gMultiProcessBrowser) {
Assert.ok(false, "This test should only be run in multi-process mode.");
return;
}
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "http://example.com",
}, function*(browser) {
// First, sanity check...
Assert.ok(browser.isRemoteBrowser,
"This browser needs to be remote if this test is going to " +
"work properly.");
// We will wait for the oop-browser-crashed event to have
// a chance to appear. That event is fired when TabParents
// are destroyed, and that occurs _before_ ContentParents
// are destroyed, so we'll wait on the ipc:content-shutdown
// observer notification, which is fired when a ContentParent
// goes away. After we see this notification, oop-browser-crashed
// events should have fired.
let contentProcessGone = TestUtils.topicObserved("ipc:content-shutdown");
let sawTabCrashed = false;
let onTabCrashed = () => {
sawTabCrashed = true;
};
browser.addEventListener("oop-browser-crashed", onTabCrashed);
// The name of the game is to cause a crash in a remote browser,
// and then immediately swap out the browser for a non-remote one.
yield ContentTask.spawn(browser, null, function() {
const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
let dies = function() {
privateNoteIntentionalCrash();
let zero = new ctypes.intptr_t(8);
let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
badptr.contents
};
// When the parent flips the remoteness of the browser, the
// page should receive the pagehide event, which we'll then
// use to crash the frameloader.
addEventListener("pagehide", function() {
dump("\nEt tu, Brute?\n");
dies();
});
});
gBrowser.updateBrowserRemoteness(browser, false);
info("Waiting for content process to go away.");
let [subject, data] = yield contentProcessGone;
// If we don't clean up the minidump, the harness will
// complain.
cleanUpMinidump(subject);
info("Content process is gone!");
Assert.ok(!sawTabCrashed,
"Should not have seen the oop-browser-crashed event.");
browser.removeEventListener("oop-browser-crashed", onTabCrashed);
});
});

View file

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
/**
* TestCase for bug 564387
* <https://bugzilla.mozilla.org/show_bug.cgi?id=564387>
*/
add_task(function* () {
let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.loadURI("data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7");
yield loadPromise;
let popupShownPromise = BrowserTestUtils.waitForEvent(document, "popupshown");
yield BrowserTestUtils.synthesizeMouseAtCenter("img",
{ type: "contextmenu", button: 2 },
gBrowser.selectedBrowser);
yield popupShownPromise;
let showFilePickerPromise = new Promise(resolve => {
MockFilePicker.showCallback = function(fp) {
is(fp.defaultString, "index.gif");
resolve();
}
});
registerCleanupFunction(function () {
MockFilePicker.cleanup();
});
// Select "Save Image As" option from context menu
var saveImageAsCommand = document.getElementById("context-saveimage");
saveImageAsCommand.doCommand();
yield showFilePickerPromise;
let contextMenu = document.getElementById("contentAreaContextMenu");
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
contextMenu.hidePopup();
yield popupHiddenPromise;
});

View file

@ -0,0 +1,227 @@
var gListener = null;
const kURL = "data:text/html;charset=utf-8,Caret browsing is fun.<input id='in'>";
const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret";
const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
var oldPrefs = {};
for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
oldPrefs[pref] = Services.prefs.getBoolPref(pref);
}
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
registerCleanupFunction(function() {
for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
Services.prefs.setBoolPref(pref, oldPrefs[pref]);
}
});
// NB: not using BrowserTestUtils.domWindowOpened here because there's no way to
// undo waiting for a window open. If we don't want the window to be opened, and
// wait for it to verify that it indeed does not open, we need to be able to
// then "stop" waiting so that when we next *do* want it to open, our "old"
// listener doesn't fire and do things we don't want (like close the window...).
let gCaretPromptOpeningObserver;
function promiseCaretPromptOpened() {
return new Promise(resolve => {
function observer(subject, topic, data) {
if (topic == "domwindowopened") {
Services.ww.unregisterNotification(observer);
let win = subject.QueryInterface(Ci.nsIDOMWindow);
BrowserTestUtils.waitForEvent(win, "load", false, e => e.target.location.href != "about:blank").then(() => resolve(win));
gCaretPromptOpeningObserver = null;
}
}
Services.ww.registerNotification(observer);
gCaretPromptOpeningObserver = observer;
});
}
function hitF7(async = true) {
let f7 = () => EventUtils.sendKey("F7");
// Need to not stop execution inside this task:
if (async) {
executeSoon(f7);
} else {
f7();
}
}
function syncToggleCaretNoDialog(expected) {
let openedDialog = false;
promiseCaretPromptOpened().then(function(win) {
openedDialog = true;
win.close(); // This will eventually return focus here and allow the test to continue...
});
// Cause the dialog to appear sync, if it still does.
hitF7(false);
let expectedStr = expected ? "on." : "off.";
ok(!openedDialog, "Shouldn't open a dialog to turn caret browsing " + expectedStr);
// Need to clean up if the dialog wasn't opened, so the observer doesn't get
// re-triggered later on causing "issues".
if (!openedDialog) {
Services.ww.unregisterNotification(gCaretPromptOpeningObserver);
gCaretPromptOpeningObserver = null;
}
let prefVal = Services.prefs.getBoolPref(kPrefCaretBrowsingOn);
is(prefVal, expected, "Caret browsing should now be " + expectedStr);
}
function waitForFocusOnInput(browser)
{
return ContentTask.spawn(browser, null, function* () {
let textEl = content.document.getElementById("in");
return ContentTaskUtils.waitForCondition(() => {
return content.document.activeElement == textEl;
}, "Input should get focused.");
});
}
function focusInput(browser)
{
return ContentTask.spawn(browser, null, function* () {
let textEl = content.document.getElementById("in");
textEl.focus();
});
}
add_task(function* checkTogglingCaretBrowsing() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kURL);
yield focusInput(tab.linkedBrowser);
let promiseGotKey = promiseCaretPromptOpened();
hitF7();
let prompt = yield promiseGotKey;
let doc = prompt.document;
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
doc.documentElement.cancelDialog();
yield promiseDialogUnloaded;
info("Dialog unloaded");
yield waitForFocusOnInput(tab.linkedBrowser);
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
promiseGotKey = promiseCaretPromptOpened();
hitF7();
prompt = yield promiseGotKey;
doc = prompt.document;
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
doc.documentElement.acceptDialog();
yield promiseDialogUnloaded;
info("Dialog unloaded");
yield waitForFocusOnInput(tab.linkedBrowser);
ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should be on after accepting the dialog.");
syncToggleCaretNoDialog(false);
promiseGotKey = promiseCaretPromptOpened();
hitF7();
prompt = yield promiseGotKey;
doc = prompt.document;
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
doc.documentElement.cancelDialog();
yield promiseDialogUnloaded;
info("Dialog unloaded");
yield waitForFocusOnInput(tab.linkedBrowser);
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
yield BrowserTestUtils.removeTab(tab);
});
add_task(function* toggleCheckboxNoCaretBrowsing() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kURL);
yield focusInput(tab.linkedBrowser);
let promiseGotKey = promiseCaretPromptOpened();
hitF7();
let prompt = yield promiseGotKey;
let doc = prompt.document;
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
let checkbox = doc.getElementById("checkbox");
ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
// Check the box:
checkbox.click();
let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
// Say no:
doc.documentElement.getButton("cancel").click();
yield promiseDialogUnloaded;
info("Dialog unloaded");
yield waitForFocusOnInput(tab.linkedBrowser);
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off.");
ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should now be disabled.");
syncToggleCaretNoDialog(false);
ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be disabled.");
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
yield BrowserTestUtils.removeTab(tab);
});
add_task(function* toggleCheckboxWantCaretBrowsing() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, kURL);
yield focusInput(tab.linkedBrowser);
let promiseGotKey = promiseCaretPromptOpened();
hitF7();
let prompt = yield promiseGotKey;
let doc = prompt.document;
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
let checkbox = doc.getElementById("checkbox");
ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
// Check the box:
checkbox.click();
let promiseDialogUnloaded = BrowserTestUtils.waitForEvent(prompt, "unload");
// Say yes:
doc.documentElement.acceptDialog();
yield promiseDialogUnloaded;
info("Dialog unloaded");
yield waitForFocusOnInput(tab.linkedBrowser);
ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should now be on.");
ok(Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be enabled.");
ok(!Services.prefs.getBoolPref(kPrefWarnOnEnable), "Should no longer warn when enabling.");
syncToggleCaretNoDialog(false);
syncToggleCaretNoDialog(true);
syncToggleCaretNoDialog(false);
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
yield BrowserTestUtils.removeTab(tab);
});

View file

@ -0,0 +1,249 @@
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
Components.utils.import("resource://gre/modules/Timer.jsm", this);
const TEST_PAGE_URI = "data:text/html;charset=utf-8,The letter s.";
// Using 'javascript' schema to bypass E10SUtils.canLoadURIInProcess, because
// it does not allow 'data:' URI to be loaded in the parent process.
const E10S_PARENT_TEST_PAGE_URI = "javascript:document.write('The letter s.');";
/**
* Makes sure that the findbar hotkeys (' and /) event listeners
* are added to the system event group and do not get blocked
* by calling stopPropagation on a keypress event on a page.
*/
add_task(function* test_hotkey_event_propagation() {
info("Ensure hotkeys are not affected by stopPropagation.");
// Opening new tab
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
let findbar = gBrowser.getFindBar();
// Pressing these keys open the findbar.
const HOTKEYS = ["/", "'"];
// Checking if findbar appears when any hotkey is pressed.
for (let key of HOTKEYS) {
is(findbar.hidden, true, "Findbar is hidden now.");
gBrowser.selectedTab = tab;
yield SimpleTest.promiseFocus(gBrowser.selectedBrowser);
yield BrowserTestUtils.sendChar(key, browser);
is(findbar.hidden, false, "Findbar should not be hidden.");
yield closeFindbarAndWait(findbar);
}
// Stop propagation for all keyboard events.
let frameScript = () => {
const stopPropagation = e => e.stopImmediatePropagation();
let window = content.document.defaultView;
window.removeEventListener("keydown", stopPropagation);
window.removeEventListener("keypress", stopPropagation);
window.removeEventListener("keyup", stopPropagation);
};
let mm = browser.messageManager;
mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", false);
// Checking if findbar still appears when any hotkey is pressed.
for (let key of HOTKEYS) {
is(findbar.hidden, true, "Findbar is hidden now.");
gBrowser.selectedTab = tab;
yield SimpleTest.promiseFocus(gBrowser.selectedBrowser);
yield BrowserTestUtils.sendChar(key, browser);
is(findbar.hidden, false, "Findbar should not be hidden.");
yield closeFindbarAndWait(findbar);
}
gBrowser.removeTab(tab);
});
add_task(function* test_not_found() {
info("Check correct 'Phrase not found' on new tab");
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
// Search for the first word.
yield promiseFindFinished("--- THIS SHOULD NEVER MATCH ---", false);
let findbar = gBrowser.getFindBar();
is(findbar._findStatusDesc.textContent, findbar._notFoundStr,
"Findbar status text should be 'Phrase not found'");
gBrowser.removeTab(tab);
});
add_task(function* test_found() {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
// Search for a string that WILL be found, with 'Highlight All' on
yield promiseFindFinished("S", true);
ok(!gBrowser.getFindBar()._findStatusDesc.textContent,
"Findbar status should be empty");
gBrowser.removeTab(tab);
});
// Setting first findbar to case-sensitive mode should not affect
// new tab find bar.
add_task(function* test_tabwise_case_sensitive() {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let findbar1 = gBrowser.getFindBar();
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let findbar2 = gBrowser.getFindBar();
// Toggle case sensitivity for first findbar
findbar1.getElement("find-case-sensitive").click();
gBrowser.selectedTab = tab1;
// Not found for first tab.
yield promiseFindFinished("S", true);
is(findbar1._findStatusDesc.textContent, findbar1._notFoundStr,
"Findbar status text should be 'Phrase not found'");
gBrowser.selectedTab = tab2;
// But it didn't affect the second findbar.
yield promiseFindFinished("S", true);
ok(!findbar2._findStatusDesc.textContent, "Findbar status should be empty");
gBrowser.removeTab(tab1);
gBrowser.removeTab(tab2);
});
/**
* Navigating from a web page (for example mozilla.org) to an internal page
* (like about:addons) might trigger a change of browser's remoteness.
* 'Remoteness change' means that rendering page content moves from child
* process into the parent process or the other way around.
* This test ensures that findbar properly handles such a change.
*/
add_task(function* test_reinitialization_at_remoteness_change() {
// This test only makes sence in e10s evironment.
if (!gMultiProcessBrowser) {
info("Skipping this test because of non-e10s environment.");
return;
}
info("Ensure findbar re-initialization at remoteness change.");
// Load a remote page and trigger findbar construction.
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let browser = gBrowser.getBrowserForTab(tab);
let findbar = gBrowser.getFindBar();
// Findbar should operate normally.
yield promiseFindFinished("z", false);
is(findbar._findStatusDesc.textContent, findbar._notFoundStr,
"Findbar status text should be 'Phrase not found'");
yield promiseFindFinished("s", false);
ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
// Moving browser into the parent process and reloading sample data.
ok(browser.isRemoteBrowser, "Browser should be remote now.");
yield promiseRemotenessChange(tab, false);
yield BrowserTestUtils.loadURI(browser, E10S_PARENT_TEST_PAGE_URI);
ok(!browser.isRemoteBrowser, "Browser should not be remote any more.");
// Findbar should keep operating normally after remoteness change.
yield promiseFindFinished("z", false);
is(findbar._findStatusDesc.textContent, findbar._notFoundStr,
"Findbar status text should be 'Phrase not found'");
yield promiseFindFinished("s", false);
ok(!findbar._findStatusDesc.textContent, "Findbar status should be empty");
yield BrowserTestUtils.removeTab(tab);
});
/**
* Ensure that the initial typed characters aren't lost immediately after
* opening the find bar.
*/
add_task(function* () {
// This test only makes sence in e10s evironment.
if (!gMultiProcessBrowser) {
info("Skipping this test because of non-e10s environment.");
return;
}
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PAGE_URI);
let browser = tab.linkedBrowser;
ok(!gFindBarInitialized, "findbar isn't initialized yet");
let findBar = gFindBar;
let initialValue = findBar._findField.value;
EventUtils.synthesizeKey("f", { accelKey: true }, window);
let promises = [
BrowserTestUtils.sendChar("a", browser),
BrowserTestUtils.sendChar("b", browser),
BrowserTestUtils.sendChar("c", browser)
];
isnot(document.activeElement, findBar._findField.inputField,
"findbar is not yet focused");
is(findBar._findField.value, initialValue, "still has initial find query");
yield Promise.all(promises);
is(document.activeElement, findBar._findField.inputField,
"findbar is now focused");
is(findBar._findField.value, "abc", "abc fully entered as find query");
yield BrowserTestUtils.removeTab(tab);
});
function promiseFindFinished(searchText, highlightOn) {
let deferred = Promise.defer();
let findbar = gBrowser.getFindBar();
findbar.startFind(findbar.FIND_NORMAL);
let highlightElement = findbar.getElement("highlight");
if (highlightElement.checked != highlightOn)
highlightElement.click();
executeSoon(() => {
findbar._findField.value = searchText;
let resultListener;
// When highlighting is on the finder sends a second "FOUND" message after
// the search wraps. This causes timing problems with e10s. waitMore
// forces foundOrTimeout wait for the second "FOUND" message before
// resolving the promise.
let waitMore = highlightOn;
let findTimeout = setTimeout(() => foundOrTimedout(null), 2000);
let foundOrTimedout = function(aData) {
if (aData !== null && waitMore) {
waitMore = false;
return;
}
if (aData === null)
info("Result listener not called, timeout reached.");
clearTimeout(findTimeout);
findbar.browser.finder.removeResultListener(resultListener);
deferred.resolve();
}
resultListener = {
onFindResult: foundOrTimedout
};
findbar.browser.finder.addResultListener(resultListener);
findbar._find();
});
return deferred.promise;
}
function promiseRemotenessChange(tab, shouldBeRemote) {
return new Promise((resolve) => {
let browser = gBrowser.getBrowserForTab(tab);
tab.addEventListener("TabRemotenessChange", function listener() {
tab.removeEventListener("TabRemotenessChange", listener);
resolve();
});
gBrowser.updateBrowserRemoteness(browser, shouldBeRemote);
});
}

View file

@ -0,0 +1,72 @@
function LocationChangeListener(browser) {
this.browser = browser;
browser.addProgressListener(this);
}
LocationChangeListener.prototype = {
wasSynthetic: false,
browser: null,
destroy: function() {
this.browser.removeProgressListener(this);
},
onLocationChange: function(webProgress, request, location, flags) {
this.wasSynthetic = this.browser.isSyntheticDocument;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference])
}
const FILES = gTestPath.replace("browser_isSynthetic.js", "")
.replace("chrome://mochitests/content/", "http://example.com/");
function waitForPageShow(browser) {
return ContentTask.spawn(browser, null, function*() {
Cu.import("resource://gre/modules/PromiseUtils.jsm");
yield new Promise(resolve => {
let listener = () => {
removeEventListener("pageshow", listener, true);
resolve();
}
addEventListener("pageshow", listener, true);
});
});
}
add_task(function*() {
let tab = gBrowser.addTab("about:blank");
let browser = tab.linkedBrowser;
yield BrowserTestUtils.browserLoaded(browser);
let listener = new LocationChangeListener(browser);
is(browser.isSyntheticDocument, false, "Should not be synthetic");
let loadPromise = waitForPageShow(browser);
browser.loadURI("data:text/html;charset=utf-8,<html/>");
yield loadPromise;
is(listener.wasSynthetic, false, "Should not be synthetic");
is(browser.isSyntheticDocument, false, "Should not be synthetic");
loadPromise = waitForPageShow(browser);
browser.loadURI(FILES + "empty.png");
yield loadPromise;
is(listener.wasSynthetic, true, "Should be synthetic");
is(browser.isSyntheticDocument, true, "Should be synthetic");
loadPromise = waitForPageShow(browser);
browser.goBack();
yield loadPromise;
is(listener.wasSynthetic, false, "Should not be synthetic");
is(browser.isSyntheticDocument, false, "Should not be synthetic");
loadPromise = waitForPageShow(browser);
browser.goForward();
yield loadPromise;
is(listener.wasSynthetic, true, "Should be synthetic");
is(browser.isSyntheticDocument, true, "Should be synthetic");
listener.destroy();
gBrowser.removeTab(tab);
});

View file

@ -0,0 +1,120 @@
add_task(function * ()
{
const kPrefName_AutoScroll = "general.autoScroll";
Services.prefs.setBoolPref(kPrefName_AutoScroll, true);
const kNoKeyEvents = 0;
const kKeyDownEvent = 1;
const kKeyPressEvent = 2;
const kKeyUpEvent = 4;
const kAllKeyEvents = 7;
var expectedKeyEvents;
var dispatchedKeyEvents;
var key;
var root;
/**
* Encapsulates EventUtils.sendChar().
*/
function sendChar(aChar)
{
key = aChar;
dispatchedKeyEvents = kNoKeyEvents;
EventUtils.sendChar(key);
is(dispatchedKeyEvents, expectedKeyEvents,
"unexpected key events were dispatched or not dispatched: " + key);
}
/**
* Encapsulates EventUtils.sendKey().
*/
function sendKey(aKey)
{
key = aKey;
dispatchedKeyEvents = kNoKeyEvents;
EventUtils.sendKey(key);
is(dispatchedKeyEvents, expectedKeyEvents,
"unexpected key events were dispatched or not dispatched: " + key);
}
function onKey(aEvent)
{
// if (aEvent.target != root && aEvent.target != root.ownerDocument.body) {
// ok(false, "unknown target: " + aEvent.target.tagName);
// return;
// }
var keyFlag;
switch (aEvent.type) {
case "keydown":
keyFlag = kKeyDownEvent;
break;
case "keypress":
keyFlag = kKeyPressEvent;
break;
case "keyup":
keyFlag = kKeyUpEvent;
break;
default:
ok(false, "Unknown events: " + aEvent.type);
return;
}
dispatchedKeyEvents |= keyFlag;
is(keyFlag, expectedKeyEvents & keyFlag, aEvent.type + " fired: " + key);
}
var dataUri = 'data:text/html,<body style="height:10000px;"></body>';
let loadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.loadURI(dataUri);
yield loadedPromise;
yield SimpleTest.promiseFocus(gBrowser.selectedBrowser);
window.addEventListener("keydown", onKey, false);
window.addEventListener("keypress", onKey, false);
window.addEventListener("keyup", onKey, false);
// Test whether the key events are handled correctly under normal condition
expectedKeyEvents = kAllKeyEvents;
sendChar("A");
// Start autoscrolling by middle button click on the page
let shownPromise = BrowserTestUtils.waitForEvent(window, "popupshown", false,
event => event.originalTarget.className == "autoscroller");
yield BrowserTestUtils.synthesizeMouseAtPoint(10, 10, { button: 1 },
gBrowser.selectedBrowser);
yield shownPromise;
// Most key events should be eaten by the browser.
expectedKeyEvents = kNoKeyEvents;
sendChar("A");
sendKey("DOWN");
sendKey("RETURN");
sendKey("RETURN");
sendKey("HOME");
sendKey("END");
sendKey("TAB");
sendKey("RETURN");
// Finish autoscrolling by ESC key. Note that only keydown and keypress
// events are eaten because keyup event is fired *after* the autoscrolling
// is finished.
expectedKeyEvents = kKeyUpEvent;
sendKey("ESCAPE");
// Test whether the key events are handled correctly under normal condition
expectedKeyEvents = kAllKeyEvents;
sendChar("A");
window.removeEventListener("keydown", onKey, false);
window.removeEventListener("keypress", onKey, false);
window.removeEventListener("keyup", onKey, false);
// restore the changed prefs
if (Services.prefs.prefHasUserValue(kPrefName_AutoScroll))
Services.prefs.clearUserPref(kPrefName_AutoScroll);
finish();
});

View file

@ -0,0 +1,38 @@
add_task(function* () {
yield BrowserTestUtils.withNewTab({gBrowser, url: "about:config"}, function*(browser) {
let newTabURL = "http://www.example.com/";
yield ContentTask.spawn(browser, newTabURL, function*(newTabURL) {
let doc = content.document;
let label = doc.createElement("label");
label.href = newTabURL;
label.id = "textlink-test";
label.className = "text-link";
label.textContent = "click me";
doc.documentElement.append(label);
});
// Test that click will open tab in foreground.
let awaitNewTab = BrowserTestUtils.waitForNewTab(gBrowser, newTabURL);
yield BrowserTestUtils.synthesizeMouseAtCenter("#textlink-test", {}, browser);
let newTab = yield awaitNewTab;
is(newTab.linkedBrowser, gBrowser.selectedBrowser, "selected tab should be example page");
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
// Test that ctrl+shift+click/meta+shift+click will open tab in background.
awaitNewTab = BrowserTestUtils.waitForNewTab(gBrowser, newTabURL);
yield BrowserTestUtils.synthesizeMouseAtCenter("#textlink-test",
{ctrlKey: true, metaKey: true, shiftKey: true},
browser);
yield awaitNewTab;
is(gBrowser.selectedBrowser, browser, "selected tab should be original tab");
yield BrowserTestUtils.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
// Middle-clicking should open tab in foreground.
awaitNewTab = BrowserTestUtils.waitForNewTab(gBrowser, newTabURL);
yield BrowserTestUtils.synthesizeMouseAtCenter("#textlink-test",
{button: 1}, browser);
newTab = yield awaitNewTab;
is(newTab.linkedBrowser, gBrowser.selectedBrowser, "selected tab should be example page");
yield BrowserTestUtils.removeTab(gBrowser.tabs[gBrowser.tabs.length - 1]);
});
});

View file

@ -0,0 +1,30 @@
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback.html";
const FRAME = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlaybackFrame.html";
function wait_for_event(browser, event) {
return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
ok(!event.cancelable, "The event should not be cancelable");
return true;
});
}
function* test_on_browser(url, browser) {
browser.loadURI(url);
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
yield wait_for_event(browser, "DOMAudioPlaybackStopped");
}
add_task(function* test_page() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank",
}, test_on_browser.bind(undefined, PAGE));
});
add_task(function* test_frame() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank",
}, test_on_browser.bind(undefined, FRAME));
});

View file

@ -0,0 +1,104 @@
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback2.html";
const FRAME = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlaybackFrame2.html";
function wait_for_event(browser, event) {
return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
return true;
});
}
function* test_audio_in_browser() {
function get_audio_element() {
var doc = content.document;
var list = doc.getElementsByTagName('audio');
if (list.length == 1) {
return list[0];
}
// iframe?
list = doc.getElementsByTagName('iframe');
var iframe = list[0];
list = iframe.contentDocument.getElementsByTagName('audio');
return list[0];
}
var audio = get_audio_element();
return {
computedVolume: audio.computedVolume,
computedMuted: audio.computedMuted
}
}
function* test_on_browser(url, browser) {
browser.loadURI(url);
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
var result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
is(result.computedVolume, 1, "Audio volume is 1");
is(result.computedMuted, false, "Audio is not muted");
ok(!browser.audioMuted, "Audio should not be muted by default");
browser.mute();
ok(browser.audioMuted, "Audio should be muted now");
yield wait_for_event(browser, "DOMAudioPlaybackStopped");
result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
is(result.computedVolume, 0, "Audio volume is 0 when muted");
is(result.computedMuted, true, "Audio is muted");
}
function* test_visibility(url, browser) {
browser.loadURI(url);
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
var result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
is(result.computedVolume, 1, "Audio volume is 1");
is(result.computedMuted, false, "Audio is not muted");
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank",
}, function() {});
ok(!browser.audioMuted, "Audio should not be muted by default");
browser.mute();
ok(browser.audioMuted, "Audio should be muted now");
yield wait_for_event(browser, "DOMAudioPlaybackStopped");
result = yield ContentTask.spawn(browser, null, test_audio_in_browser);
is(result.computedVolume, 0, "Audio volume is 0 when muted");
is(result.computedMuted, true, "Audio is muted");
}
add_task(function*() {
yield new Promise((resolve) => {
SpecialPowers.pushPrefEnv({"set": [
["media.useAudioChannelService.testing", true]
]}, resolve);
});
});
add_task(function* test_page() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank",
}, test_on_browser.bind(undefined, PAGE));
});
add_task(function* test_frame() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank",
}, test_on_browser.bind(undefined, FRAME));
});
add_task(function* test_frame() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank",
}, test_visibility.bind(undefined, PAGE));
});

View file

@ -0,0 +1,191 @@
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback2.html";
var SuspendedType = {
NONE_SUSPENDED : 0,
SUSPENDED_PAUSE : 1,
SUSPENDED_BLOCK : 2,
SUSPENDED_PAUSE_DISPOSABLE : 3
};
function wait_for_event(browser, event) {
return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
return true;
});
}
function check_audio_onplay() {
var list = content.document.getElementsByTagName('audio');
if (list.length != 1) {
ok(false, "There should be only one audio element in page!")
}
var audio = list[0];
return new Promise((resolve, reject) => {
audio.onplay = () => {
ok(needToReceiveOnPlay, "Should not receive play event!");
this.onplay = null;
reject();
};
audio.pause();
audio.play();
setTimeout(() => {
ok(true, "Doesn't receive play event when media was blocked.");
audio.onplay = null;
resolve();
}, 1000)
});
}
function check_audio_suspended(suspendedType) {
var list = content.document.getElementsByTagName('audio');
if (list.length != 1) {
ok(false, "There should be only one audio element in page!")
}
var audio = list[0];
is(audio.computedSuspended, suspendedType,
"The suspended state of MediaElement is correct.");
}
function check_audio_pause_state(expectedPauseState) {
var list = content.document.getElementsByTagName('audio');
if (list.length != 1) {
ok(false, "There should be only one audio element in page!")
}
var audio = list[0];
if (expectedPauseState) {
is(audio.paused, true, "Audio is paused correctly.");
} else {
is(audio.paused, false, "Audio is resumed correctly.");
}
}
function* suspended_pause(url, browser) {
info("### Start test for suspended-pause ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the suspended state of audio should be non-suspened -");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
info("- pause playing audio -");
browser.pauseMedia(false /* non-disposable */);
yield ContentTask.spawn(browser, true /* expect for pause */,
check_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE,
check_audio_suspended);
info("- resume paused audio -");
browser.resumeMedia();
yield ContentTask.spawn(browser, false /* expect for playing */,
check_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
}
function* suspended_pause_disposable(url, browser) {
info("### Start test for suspended-pause-disposable ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the suspended state of audio should be non-suspened -");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
info("- pause playing audio -");
browser.pauseMedia(true /* disposable */);
yield ContentTask.spawn(browser, true /* expect for pause */,
check_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
check_audio_suspended);
info("- resume paused audio -");
browser.resumeMedia();
yield ContentTask.spawn(browser, false /* expect for playing */,
check_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
}
function* suspended_stop_disposable(url, browser) {
info("### Start test for suspended-stop-disposable ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the suspended state of audio should be non-suspened -");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
info("- stop playing audio -");
browser.stopMedia();
yield wait_for_event(browser, "DOMAudioPlaybackStopped");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
}
function* suspended_block(url, browser) {
info("### Start test for suspended-block ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- block playing audio -");
browser.blockMedia();
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK,
check_audio_suspended);
yield ContentTask.spawn(browser, null,
check_audio_onplay);
info("- resume blocked audio -");
browser.resumeMedia();
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_audio_suspended);
}
add_task(function* setup_test_preference() {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["media.useAudioChannelService.testing", true]
]}, resolve);
});
});
add_task(function* test_suspended_pause() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_pause.bind(this, PAGE));
});
add_task(function* test_suspended_pause_disposable() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_pause_disposable.bind(this, PAGE));
});
add_task(function* test_suspended_stop_disposable() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_stop_disposable.bind(this, PAGE));
});
add_task(function* test_suspended_block() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_block.bind(this, PAGE));
});

View file

@ -0,0 +1,311 @@
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multipleAudio.html";
var SuspendedType = {
NONE_SUSPENDED : 0,
SUSPENDED_PAUSE : 1,
SUSPENDED_BLOCK : 2,
SUSPENDED_PAUSE_DISPOSABLE : 3
};
function wait_for_event(browser, event) {
return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
return true;
});
}
function check_all_audio_suspended(suspendedType) {
var autoPlay = content.document.getElementById('autoplay');
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!autoPlay || !nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.computedSuspended, suspendedType,
"The suspeded state of autoplay audio is correct.");
is(nonAutoPlay.computedSuspended, suspendedType,
"The suspeded state of non-autoplay audio is correct.");
}
function check_autoplay_audio_suspended(suspendedType) {
var autoPlay = content.document.getElementById('autoplay');
if (!autoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.computedSuspended, suspendedType,
"The suspeded state of autoplay audio is correct.");
}
function check_nonautoplay_audio_suspended(suspendedType) {
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
is(nonAutoPlay.computedSuspended, suspendedType,
"The suspeded state of non-autoplay audio is correct.");
}
function check_autoplay_audio_pause_state(expectedPauseState) {
var autoPlay = content.document.getElementById('autoplay');
if (!autoPlay) {
ok(false, "Can't get the audio element!");
}
if (autoPlay.paused == expectedPauseState) {
if (expectedPauseState) {
ok(true, "Audio is paused correctly.");
} else {
ok(true, "Audio is resumed correctly.");
}
} else if (expectedPauseState) {
autoPlay.onpause = function () {
autoPlay.onpause = null;
ok(true, "Audio is paused correctly, checking from onpause.");
}
} else {
autoPlay.onplay = function () {
autoPlay.onplay = null;
ok(true, "Audio is resumed correctly, checking from onplay.");
}
}
}
function play_nonautoplay_audio_should_be_paused() {
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
nonAutoPlay.play();
return new Promise(resolve => {
nonAutoPlay.onpause = function () {
nonAutoPlay.onpause = null;
is(nonAutoPlay.ended, false, "Audio can't be playback.");
resolve();
}
});
}
function all_audio_onresume() {
var autoPlay = content.document.getElementById('autoplay');
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!autoPlay || !nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.paused, false, "Autoplay audio is resumed.");
is(nonAutoPlay.paused, false, "Non-AutoPlay audio is resumed.");
}
function all_audio_onpause() {
var autoPlay = content.document.getElementById('autoplay');
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!autoPlay || !nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.paused, true, "Autoplay audio is paused.");
is(nonAutoPlay.paused, true, "Non-AutoPlay audio is paused.");
}
function play_nonautoplay_audio_should_play_until_ended() {
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
nonAutoPlay.play();
return new Promise(resolve => {
nonAutoPlay.onended = function () {
nonAutoPlay.onended = null;
ok(true, "Audio can be playback until ended.");
resolve();
}
});
}
function no_audio_resumed() {
var autoPlay = content.document.getElementById('autoplay');
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!autoPlay || !nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
is(autoPlay.paused && nonAutoPlay.paused, true, "No audio was resumed.");
}
function play_nonautoplay_audio_should_be_blocked(suspendedType) {
var nonAutoPlay = content.document.getElementById('nonautoplay');
if (!nonAutoPlay) {
ok(false, "Can't get the audio element!");
}
nonAutoPlay.play();
ok(nonAutoPlay.paused, "The blocked audio can't be playback.");
}
function* suspended_pause(url, browser) {
info("### Start test for suspended-pause ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the default suspended state of all audio should be non-suspened-");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
info("- pause all audio in the page -");
browser.pauseMedia(false /* non-disposable */);
yield ContentTask.spawn(browser, true /* expect for pause */,
check_autoplay_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE,
check_autoplay_audio_suspended);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_nonautoplay_audio_suspended);
info("- no audio can be playback during suspended-paused -");
yield ContentTask.spawn(browser, null,
play_nonautoplay_audio_should_be_paused);
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE,
check_nonautoplay_audio_suspended);
info("- both audio should be resumed at the same time -");
browser.resumeMedia();
yield ContentTask.spawn(browser, null,
all_audio_onresume);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
info("- both audio should be paused at the same time -");
browser.pauseMedia(false /* non-disposable */);
yield ContentTask.spawn(browser, null, all_audio_onpause);
}
function* suspended_pause_disposable(url, browser) {
info("### Start test for suspended-pause-disposable ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the default suspended state of all audio should be non-suspened -");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
info("- only pause playing audio in the page -");
browser.pauseMedia(true /* non-disposable */);
yield ContentTask.spawn(browser, true /* expect for pause */,
check_autoplay_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE,
check_autoplay_audio_suspended);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_nonautoplay_audio_suspended);
info("- new playing audio should be playback correctly -");
yield ContentTask.spawn(browser, null,
play_nonautoplay_audio_should_play_until_ended);
info("- should only resume one audio -");
browser.resumeMedia();
yield ContentTask.spawn(browser, false /* expect for playing */,
check_autoplay_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
}
function* suspended_stop_disposable(url, browser) {
info("### Start test for suspended-stop-disposable ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the default suspended state of all audio should be non-suspened -");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
info("- only stop playing audio in the page -");
browser.stopMedia();
yield wait_for_event(browser, "DOMAudioPlaybackStopped");
yield ContentTask.spawn(browser, true /* expect for pause */,
check_autoplay_audio_pause_state);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
info("- new playing audio should be playback correctly -");
yield ContentTask.spawn(browser, null,
play_nonautoplay_audio_should_play_until_ended);
info("- no any audio can be resumed by page -");
browser.resumeMedia();
yield ContentTask.spawn(browser, null, no_audio_resumed);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
}
function* suspended_block(url, browser) {
info("### Start test for suspended-block ###");
browser.loadURI(url);
info("- page should have playing audio -");
yield wait_for_event(browser, "DOMAudioPlaybackStarted");
info("- the default suspended state of all audio should be non-suspened-");
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
info("- block autoplay audio -");
browser.blockMedia();
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK,
check_autoplay_audio_suspended);
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_nonautoplay_audio_suspended);
info("- no audio can be playback during suspended-block -");
yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK,
play_nonautoplay_audio_should_be_blocked);
info("- both audio should be resumed at the same time -");
browser.resumeMedia();
yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED,
check_all_audio_suspended);
}
add_task(function* setup_test_preference() {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv({"set": [
["media.useAudioChannelService.testing", true]
]}, resolve);
});
});
add_task(function* test_suspended_pause() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_pause.bind(this, PAGE));
});
add_task(function* test_suspended_pause_disposable() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_pause_disposable.bind(this, PAGE));
});
add_task(function* test_suspended_stop_disposable() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_stop_disposable.bind(this, PAGE));
});
add_task(function* test_suspended_block() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: "about:blank"
}, suspended_block.bind(this, PAGE));
});

View file

@ -0,0 +1,16 @@
const PAGE = "data:text/html,page";
function* test_on_browser(browser) {
ok(!browser.audioMuted, "Audio should not be muted by default");
browser.mute();
ok(browser.audioMuted, "Audio should be muted now");
browser.unmute();
ok(!browser.audioMuted, "Audio should be unmuted now");
}
add_task(function*() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: PAGE,
}, test_on_browser);
});

View file

@ -0,0 +1,26 @@
const PAGE = "data:text/html,page";
function* test_on_browser(browser) {
ok(!browser.audioMuted, "Audio should not be muted by default");
browser.mute();
ok(browser.audioMuted, "Audio should be muted now");
yield BrowserTestUtils.withNewTab({
gBrowser,
url: PAGE,
}, test_on_browser2);
browser.unmute();
ok(!browser.audioMuted, "Audio should be unmuted now");
}
function* test_on_browser2(browser) {
ok(!browser.audioMuted, "Audio should not be muted by default");
}
add_task(function*() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: PAGE,
}, test_on_browser);
});

View file

@ -0,0 +1,47 @@
const PAGE = "data:text/html,<div contenteditable>foo</div><input><textarea></textarea>";
const DESIGNMODE_PAGE = "data:text/html,<body onload='document.designMode=\"on\";'>";
const HOTKEYS = ["/", "'"];
function* test_hotkeys(browser, expected) {
let findbar = gBrowser.getFindBar();
for (let key of HOTKEYS) {
is(findbar.hidden, true, "findbar is hidden");
yield BrowserTestUtils.sendChar(key, gBrowser.selectedBrowser);
is(findbar.hidden, expected, "findbar should" + (expected ? "" : " not") + " be hidden");
if (!expected) {
yield closeFindbarAndWait(findbar);
}
}
}
function* focus_element(browser, query) {
yield ContentTask.spawn(browser, query, function* focus(query) {
let element = content.document.querySelector(query);
element.focus();
});
}
add_task(function* test_hotkey_on_editable_element() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: PAGE
}, function* do_tests(browser) {
yield test_hotkeys(browser, false);
const ELEMENTS = ["div", "input", "textarea"];
for (let elem of ELEMENTS) {
yield focus_element(browser, elem);
yield test_hotkeys(browser, true);
yield focus_element(browser, ":root");
yield test_hotkeys(browser, false);
}
});
});
add_task(function* test_hotkey_on_designMode_document() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: DESIGNMODE_PAGE
}, function* do_tests(browser) {
yield test_hotkeys(browser, true);
});
});

View file

@ -0,0 +1,68 @@
"use strict";
const IMAGE_PAGE = "https://example.com/browser/toolkit/content/tests/browser/image_page.html";
const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser";
MockFilePicker.init(window);
MockFilePicker.returnValue = MockFilePicker.returnCancel;
registerCleanupFunction(function() {
MockFilePicker.cleanup();
});
function waitForFilePicker() {
return new Promise((resolve) => {
MockFilePicker.showCallback = () => {
MockFilePicker.showCallback = null;
ok(true, "Saw the file picker");
resolve();
}
})
}
/**
* Test that saveImageURL works when we pass in the aIsContentWindowPrivate
* argument instead of a document. This is the preferred API.
*/
add_task(function* preferred_API() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: IMAGE_PAGE,
}, function*(browser) {
let url = yield ContentTask.spawn(browser, null, function*() {
let image = content.document.getElementById("image");
return image.href;
});
saveImageURL(url, "image.jpg", null, true, false, null, null, null, null, false);
yield waitForFilePicker();
});
});
/**
* Test that saveImageURL will still work when passed a document instead
* of the aIsContentWindowPrivate argument. This is the deprecated API, and
* will not work in apps using remote browsers having PREF_UNSAFE_FORBIDDEN
* set to true.
*/
add_task(function* deprecated_API() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: IMAGE_PAGE,
}, function*(browser) {
yield pushPrefs([PREF_UNSAFE_FORBIDDEN, false]);
let url = yield ContentTask.spawn(browser, null, function*() {
let image = content.document.getElementById("image");
return image.href;
});
// Now get the document directly from content. If we run this test with
// e10s-enabled, this will be a CPOW, which is forbidden. We'll just
// pass the XUL document instead to test this interface.
let doc = document;
saveImageURL(url, "image.jpg", null, true, false, null, doc, null, null);
yield waitForFilePicker();
});
});

View file

@ -0,0 +1,145 @@
/* 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 MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);
/**
* Test for bug 471962 <https://bugzilla.mozilla.org/show_bug.cgi?id=471962>:
* When saving an inner frame as file only, the POST data of the outer page is
* sent to the address of the inner page.
*
* Test for bug 485196 <https://bugzilla.mozilla.org/show_bug.cgi?id=485196>:
* Web page generated by POST is retried as GET when Save Frame As used, and the
* page is no longer in the cache.
*/
function test() {
waitForExplicitFinish();
gBrowser.loadURI("http://mochi.test:8888/browser/toolkit/content/tests/browser/data/post_form_outer.sjs");
gBrowser.addEventListener("pageshow", function pageShown(event) {
if (event.target.location == "about:blank")
return;
gBrowser.removeEventListener("pageshow", pageShown);
// Submit the form in the outer page, then wait for both the outer
// document and the inner frame to be loaded again.
gBrowser.addEventListener("DOMContentLoaded", handleOuterSubmit);
gBrowser.contentDocument.getElementById("postForm").submit();
});
var framesLoaded = 0;
var innerFrame;
function handleOuterSubmit() {
if (++framesLoaded < 2)
return;
gBrowser.removeEventListener("DOMContentLoaded", handleOuterSubmit);
innerFrame = gBrowser.contentDocument.getElementById("innerFrame");
// Submit the form in the inner page.
gBrowser.addEventListener("DOMContentLoaded", handleInnerSubmit);
innerFrame.contentDocument.getElementById("postForm").submit();
}
function handleInnerSubmit() {
gBrowser.removeEventListener("DOMContentLoaded", handleInnerSubmit);
// Create the folder the page will be saved into.
var destDir = createTemporarySaveDirectory();
var file = destDir.clone();
file.append("no_default_file_name");
MockFilePicker.returnFiles = [file];
MockFilePicker.showCallback = function(fp) {
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
};
mockTransferCallback = onTransferComplete;
mockTransferRegisterer.register();
registerCleanupFunction(function () {
mockTransferRegisterer.unregister();
MockFilePicker.cleanup();
destDir.remove(true);
});
var docToSave = innerFrame.contentDocument;
// We call internalSave instead of saveDocument to bypass the history
// cache.
internalSave(docToSave.location.href, docToSave, null, null,
docToSave.contentType, false, null, null,
docToSave.referrer ? makeURI(docToSave.referrer) : null,
docToSave, false, null);
}
function onTransferComplete(downloadSuccess) {
ok(downloadSuccess, "The inner frame should have been downloaded successfully");
// Read the entire saved file.
var file = MockFilePicker.returnFiles[0];
var fileContents = readShortFile(file);
// Check if outer POST data is found (bug 471962).
is(fileContents.indexOf("inputfield=outer"), -1,
"The saved inner frame does not contain outer POST data");
// Check if inner POST data is found (bug 485196).
isnot(fileContents.indexOf("inputfield=inner"), -1,
"The saved inner frame was generated using the correct POST data");
finish();
}
}
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
this);
function createTemporarySaveDirectory() {
var saveDir = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties)
.get("TmpD", Ci.nsIFile);
saveDir.append("testsavedir");
if (!saveDir.exists())
saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
return saveDir;
}
/**
* Reads the contents of the provided short file (up to 1 MiB).
*
* @param aFile
* nsIFile object pointing to the file to be read.
*
* @return
* String containing the raw octets read from the file.
*/
function readShortFile(aFile) {
var inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
inputStream.init(aFile, -1, 0, 0);
try {
var scrInputStream = Cc["@mozilla.org/scriptableinputstream;1"]
.createInstance(Ci.nsIScriptableInputStream);
scrInputStream.init(inputStream);
try {
// Assume that the file is much shorter than 1 MiB.
return scrInputStream.read(1048576);
}
finally {
// Close the scriptable stream after reading, even if the operation
// failed.
scrInputStream.close();
}
}
finally {
// Close the stream after reading, if it is still open, even if the read
// operation failed.
inputStream.close();
}
}

View file

@ -0,0 +1,67 @@
/* 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/. */
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://mochikit/content/tests/SimpleTest/MockObjects.js", this);
var mockTransferCallback;
/**
* This "transfer" object implementation continues the currently running test
* when the download is completed, reporting true for success or false for
* failure as the first argument of the testRunner.continueTest function.
*/
function MockTransfer() {
this._downloadIsSuccessful = true;
}
MockTransfer.prototype = {
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIWebProgressListener,
Ci.nsIWebProgressListener2,
Ci.nsITransfer,
]),
/* nsIWebProgressListener */
onStateChange: function MTFC_onStateChange(aWebProgress, aRequest,
aStateFlags, aStatus) {
// If at least one notification reported an error, the download failed.
if (!Components.isSuccessCode(aStatus))
this._downloadIsSuccessful = false;
// If the download is finished
if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
(aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK))
// Continue the test, reporting the success or failure condition.
mockTransferCallback(this._downloadIsSuccessful);
},
onProgressChange: function () {},
onLocationChange: function () {},
onStatusChange: function MTFC_onStatusChange(aWebProgress, aRequest, aStatus,
aMessage) {
// If at least one notification reported an error, the download failed.
if (!Components.isSuccessCode(aStatus))
this._downloadIsSuccessful = false;
},
onSecurityChange: function () {},
/* nsIWebProgressListener2 */
onProgressChange64: function () {},
onRefreshAttempted: function () {},
/* nsITransfer */
init: function() {},
setSha256Hash: function() {},
setSignatureInfo: function() {}
};
// Create an instance of a MockObjectRegisterer whose methods can be used to
// temporarily replace the default "@mozilla.org/transfer;1" object factory with
// one that provides the mock implementation above. To activate the mock object
// factory, call the "register" method. Starting from that moment, all the
// transfer objects that are requested will be mock objects, until the
// "unregister" method is called.
var mockTransferRegisterer =
new MockObjectRegisterer("@mozilla.org/transfer;1", MockTransfer);

View file

@ -0,0 +1,31 @@
/* 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/. */
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
function handleRequest(request, response)
{
var body =
'<html>\
<body>\
Inner POST data: ';
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var bytes = [], avail = 0;
while ((avail = bodyStream.available()) > 0)
body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
body +=
'<form id="postForm" action="post_form_inner.sjs" method="post">\
<input type="text" name="inputfield" value="inner">\
<input type="submit">\
</form>\
</body>\
</html>';
response.bodyOutputStream.write(body, body.length);
}

View file

@ -0,0 +1,34 @@
/* 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/. */
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
function handleRequest(request, response)
{
var body =
'<html>\
<body>\
Outer POST data: ';
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var bytes = [], avail = 0;
while ((avail = bodyStream.available()) > 0)
body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
body +=
'<form id="postForm" action="post_form_outer.sjs" method="post">\
<input type="text" name="inputfield" value="outer">\
<input type="submit">\
</form>\
\
<iframe id="innerFrame" src="post_form_inner.sjs" width="400" height="200">\
\
</body>\
</html>';
response.bodyOutputStream.write(body, body.length);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,14 @@
<html>
<head><title>Test Page</title></head>
<body>
<script type="text/javascript">
dump("Script!\n");
addEventListener("load", () => {
// Trigger an onLocationChange event. We want to make sure the title is still correct afterwards.
location.hash = "#x2";
var event = new Event("TestLocationChange");
document.dispatchEvent(event);
}, false);
</script>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<script type="text/javascript">
var audio = new Audio();
audio.oncanplay = function() {
audio.oncanplay = null;
audio.play();
};
audio.src = "audio.ogg";
</script>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script type="text/javascript">
var audio = new Audio();
audio.oncanplay = function() {
audio.oncanplay = null;
audio.play();
};
audio.src = "audio.ogg";
document.body.appendChild(audio);
</script>
</body>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<iframe src="file_mediaPlayback.html"></iframe>

View file

@ -0,0 +1,2 @@
<!DOCTYPE html>
<iframe src="file_mediaPlayback2.html"></iframe>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<audio id="autoplay" src="audio.ogg"></audio>
<audio id="nonautoplay" src="audio.ogg"></audio>
<script type="text/javascript">
// In linux debug on try server, sometimes the download process would fail, so
// we can't activate the "auto-play" or playing after receving "oncanplay".
// Therefore, we just call play here.
var audio = document.getElementById("autoplay");
audio.loop = true;
audio.play();
</script>
</body>

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<audio id="audio1" src="audio.ogg" controls></audio>
<audio id="audio2" src="audio.ogg" controls></audio>
<script type="text/javascript">
// In linux debug on try server, sometimes the download process would fail, so
// we can't activate the "auto-play" or playing after receving "oncanplay".
// Therefore, we just call play here.
var audio1 = document.getElementById("audio1");
audio1.loop = true;
audio1.play();
var audio2 = document.getElementById("audio2");
audio2.loop = true;
audio2.play();
</script>
</body>

Some files were not shown because too many files have changed in this diff Show more